tools/JavaSyntaxHighlighter.st
changeset 3126 4eaeba9fa910
parent 3103 a7d69709920f
child 3183 a725721c7855
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/JavaSyntaxHighlighter.st	Wed Jun 25 13:58:21 2014 +0100
@@ -0,0 +1,503 @@
+"
+ COPYRIGHT (c) 1996-2011 by Claus Gittinger
+
+ New code and modifications done at SWING Research Group [1]:
+
+ COPYRIGHT (c) 2010-2011 by Jan Vrany, Jan Kurs and Marcel Hlopko
+                            SWING Research Group, Czech Technical University in Prague
+
+ This software is furnished under a license and may be used
+ only in accordance with the terms of that license and with the
+ inclusion of the above copyright notice.   This software may not
+ be provided or otherwise made available to, or used by, any
+ other person.  No title to or ownership of the software is
+ hereby transferred.
+
+ [1] Code written at SWING Research Group contains a signature
+     of one of the above copright owners. For exact set of such code,
+     see the differences between this version and version stx:libjava
+     as of 1.9.2010
+"
+"{ Package: 'stx:libjava/tools' }"
+
+JavaAbstractSourceHighlighter subclass:#JavaSyntaxHighlighter
+	instanceVariableNames:''
+	classVariableNames:''
+	poolDictionaries:''
+	category:'Languages-Java-Tools-Source'
+!
+
+Object subclass:#Indexer
+	instanceVariableNames:'index types fields locals'
+	classVariableNames:''
+	poolDictionaries:''
+	privateIn:JavaSyntaxHighlighter
+!
+
+Object subclass:#Marker
+	instanceVariableNames:'highlighter'
+	classVariableNames:'MARK_KEYWORD MARK_NUMBER MARK_STRING MARK_CHARACTER MARK_COMMENT
+		MARK_JAVADOC MARK_KEYWORD_FLOW MARK_SELECTOR MARK_FIELD
+		MARK_FIELD_ASSIGNED MARK_LOCAL MARK_CLASS'
+	poolDictionaries:''
+	privateIn:JavaSyntaxHighlighter
+!
+
+!JavaSyntaxHighlighter class methodsFor:'documentation'!
+
+copyright
+"
+ COPYRIGHT (c) 1996-2011 by Claus Gittinger
+
+ New code and modifications done at SWING Research Group [1]:
+
+ COPYRIGHT (c) 2010-2011 by Jan Vrany, Jan Kurs and Marcel Hlopko
+                            SWING Research Group, Czech Technical University in Prague
+
+ This software is furnished under a license and may be used
+ only in accordance with the terms of that license and with the
+ inclusion of the above copyright notice.   This software may not
+ be provided or otherwise made available to, or used by, any
+ other person.  No title to or ownership of the software is
+ hereby transferred.
+
+ [1] Code written at SWING Research Group contains a signature
+     of one of the above copright owners. For exact set of such code,
+     see the differences between this version and version stx:libjava
+     as of 1.9.2010
+
+"
+!
+
+documentation
+"
+    A syntax highligter for Java. Unlike JavaLexicalHighlighter,
+    this one does full parsing (using eclipse compiler) so it is
+    slower (expecially when classes are not loader).
+
+    To avoid this initial lag, which is very annoying from UX point
+    of view, it temporarily bails out to lexical highlighting.
+
+    [author:]
+        Jan Vrany <jan.vrany@fit.cvut.cz>
+
+    [instance variables:]
+
+    [class variables:]
+
+    [see also:]
+
+"
+! !
+
+!JavaSyntaxHighlighter methodsFor:'formatting'!
+
+formatClassDefinition:source in:class
+    | marker cacheIt document sourceUnit parser tree resolve loader |
+
+    "Optimization - if full class source is to be formatted,
+     consult cache - when browsing the code or debugging, very 
+     often same same source is to be highlighted"
+
+    preferences isNil ifTrue:[
+        preferences := UserPreferences current.
+    ].
+    JavaVM booted ifFalse:[
+        ^ self format: source string.
+    ].
+
+    cacheIt := class notNil and: [class isBehavior and:[class theNonMetaclass isJavaClass]].
+    cacheIt ifTrue:[
+        document := JavaSourceDocument cachedDocumentFor: class theNonMetaclass.
+        document notNil ifTrue:[
+            (document sourceText notNil and:[document sourceText string = source]) ifTrue:[
+                (sourceIndex notNil and:[document sourceTreeIndex notNil]) ifTrue:[
+                     sourceIndex addAll: document sourceTreeIndex.
+                     sourceIndex tree:  document sourceTreeIndex tree.
+                     sourceIndex source: document sourceText.
+                ].
+                ^ document sourceText copy.
+            ].
+        ] ifFalse:[
+            document := JavaSourceDocument for: class theNonMetaclass.
+            (sourceIndex isNil and:[SmallSense::ParseTreeIndex notNil]) ifTrue:[
+                 sourceIndex := SmallSense::ParseTreeIndex new.
+            ].
+            JavaSourceDocument cachedDocumentFor: class theNonMetaclass put: document.  
+            ^ self format: source.
+        ].
+    ].
+    marker := Marker new.
+    marker highlighter: self.
+
+    sourceText := source isText 
+                    ifTrue:[source copy] 
+                    ifFalse:[source asText].
+
+    self doLexicalHighlightingOnly ifTrue:[          
+        sourceText := self format: source string.
+    ] ifFalse:[
+
+        sourceUnit := (Java classForName:'stx.libjava.tools.Source') new.
+        sourceUnit setContents: source string.
+        parser := (Java classForName:'stx.libjava.tools.text.Highlighter') new.
+        parser setMarker: marker.
+        (sourceIndex notNil and:[sourceIndex isKindOf: SmallSense::ParseTreeIndex]) ifTrue:[
+            | indexer |
+
+            indexer := Indexer new.
+            indexer index: sourceIndex.
+            parser setIndexer: indexer.
+        ].
+
+        "/ Following is support JImport expecco plugin. For classes loaded by
+        "/ JImport plugin, do not resolve classes. The LookupEnvironment cannot
+        "/ find them as they are not installed in class registry...
+        resolve := class isNil or:[ (loader := class theNonMetaclass classLoader isNil) or:[loader isJavaObject] ] .
+
+        tree := parser parse: sourceUnit diet: false resolve: resolve.
+        (sourceIndex notNil and:[sourceIndex isKindOf: SmallSense::ParseTreeIndex]) ifTrue:[
+            sourceIndex tree: tree. 
+            sourceIndex source: sourceText.
+        ].
+    ].
+
+    ^ cacheIt ifTrue:[
+        document sourceText: sourceText.
+        document sourceTreeIndex: sourceIndex.
+        sourceText copy
+    ] ifFalse:[
+        sourceText
+    ]
+
+    "Created: / 04-08-2011 / 23:44:52 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 25-06-2014 / 13:23:32 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+formatMethod:mth source:source in:class using: prefs
+    preferences := prefs.
+    preferences isNil ifTrue:[
+        preferences := UserPreferences current.
+    ].
+
+    JavaMethod showFullSource ifTrue:[
+        ^self formatClassDefinition: source in: class
+    ].   
+
+    sourceText := source asText.
+
+    self doLexicalHighlightingOnly ifTrue:[
+        sourceText := self format: source
+    ] ifFalse:[
+        | document type parser marker nodes debug |
+
+        JavaVM booted ifFalse:[JavaVM boot].
+        document := JavaSourceDocument cachedDocumentFor: class theNonMetaclass.
+        document isNil ifTrue:[
+            document := JavaSourceDocument for: class theNonMetaclass.
+            JavaSourceDocument cachedDocumentFor: class theNonMetaclass put: document.  
+        ].
+
+
+        document resolve.
+        type := document sourceTreeForClass: class theNonMetaclass.
+        marker := Marker new.
+        marker highlighter: self. 
+        JavaCompiler synchronized:[
+            parser := (Java classForName:'stx.libjava.tools.text.Highlighter') new.
+        ].
+        parser setMarker: marker.
+
+        debug :=  false.
+        nodes := parser parseClassBodyDeclarations: source string unit: document sourceTree copy type: type copy resolve: debug.
+        debug ifTrue:[
+            nodes inspect.
+        ]
+    ].
+    ^ sourceText
+
+    "Created: / 04-08-2011 / 23:45:10 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified (format): / 26-11-2013 / 23:04:31 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+formatMethod:mthd source:newCode line: line number: lnr in:cls using:syntaxPreferences
+
+    ^ JavaLexicalHighlighter formatMethod:mthd source:newCode line: line number: lnr in:cls using:syntaxPreferences
+
+    "Created: / 25-06-2014 / 12:49:51 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!JavaSyntaxHighlighter methodsFor:'formatting-private'!
+
+format: source
+    ^ JavaLexicalHighlighter new format: source
+
+    "Created: / 25-06-2014 / 11:56:08 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!JavaSyntaxHighlighter methodsFor:'queries'!
+
+doLexicalHighlightingOnly
+    "/ For now, in debugger always use lexical highlighting. Makes highlighter debugging easier"
+
+    | process wgroups |
+
+    process := Processor activeProcess.
+    wgroups := WindowGroup scheduledWindowGroups.
+    [ process notNil ] whileTrue:[
+        | groups wg application |
+        groups := wgroups select:[:wg | wg process == process ].
+        groups notEmpty ifTrue:[
+            wg := groups detect:[:wg | wg isModal] ifNone:nil.
+            wg isNil ifTrue:[
+                wg := groups anElement
+            ].
+            (wg mainView class == DebugView) ifTrue:[ ^ true ].
+            (wg mainView notNil and:[(application := wg mainView application) notNil]) ifTrue:[
+                application class == (Smalltalk at: #'JDI::DebuggerApplication') ifTrue:[ ^ true ].
+                application class == Tools::NewSystemBrowser ifTrue:[ ^ false ].
+            ]
+        ].
+        process := process parentProcess.                    
+    ].
+    ^ false
+
+    "Created: / 09-09-2013 / 02:25:39 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 25-03-2014 / 13:32:46 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!JavaSyntaxHighlighter::Indexer class methodsFor:'initialization'!
+
+initialize
+    "Invoked at system start or when the class is dynamically loaded."
+
+    self lookupObject: JavaLookup instance.
+
+
+    "/ please change as required (and remove this comment)
+
+    "Modified: / 17-09-2013 / 01:33:52 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+
+!JavaSyntaxHighlighter::Indexer methodsFor:'accessing'!
+
+index
+    ^ index
+!
+
+index:aParseTreeIndex
+    index := aParseTreeIndex.
+    types := Dictionary new.
+    fields := Dictionary new.
+    locals := Dictionary new.
+
+    "Modified: / 24-09-2013 / 02:32:09 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!JavaSyntaxHighlighter::Indexer methodsFor:'indexing'!
+
+add: node from: start to: stop
+    | element |
+
+    index add: (element := index newElementFor: node).
+    element start: start + 1; stop: stop + 1.
+    ^ element
+
+    "Created: / 01-10-2013 / 10:30:53 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+addFieldDeclaration: node from: start to: stop
+    | element binding fname previous |
+
+    element := self add: node from: start to: stop.
+    binding := node binding.
+    binding notNil ifTrue:[
+        fname := (binding declaringClass compoundName asStringWith:$/) , '.' , binding name.
+        previous := fields at: fname ifAbsent: nil.
+        previous notNil ifTrue:[
+            previous next: element.
+        ].
+        fields at: fname put: element.
+    ].
+
+    "Created: / 01-10-2013 / 10:33:17 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 08-10-2013 / 17:18:10 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+addLocalDeclaration: node from: start to: stop
+    | element fname previous |
+
+    element := self add: node from: start to: stop.
+    fname := node name.
+    previous := locals at: fname ifAbsent: nil.
+    previous notNil ifTrue:[
+        previous next: element.
+    ].
+    locals at: fname put: element.
+
+    "Created: / 01-10-2013 / 11:44:02 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+addMessageSend: node from: start to: stop
+    self add: node from: start to: stop
+
+    "Created: / 01-10-2013 / 10:30:06 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+addTypeReference: node from: start to: stop
+    | element tname previous |
+
+    element := self add: node from: start to: stop.
+    tname := node getTypeName asStringWith: $/.
+    previous := types at: tname ifAbsent: nil.
+    previous notNil ifTrue:[
+        previous next: element.
+    ].
+    types at: tname put: element.
+
+    "Created: / 01-10-2013 / 10:33:41 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+addVariableReference: node from: start to: stop
+    | element binding name previous |
+
+    element := self add: node from: start to: stop.
+    binding := node binding.
+    binding isNil ifTrue:[ ^ self ].
+    "/ ProblemBinding, treat is as a local
+    binding problemId ~~ 0 ifTrue:[
+        name := binding name.
+        previous := locals at: name ifAbsent: nil.
+        previous notNil ifTrue:[
+            previous next: element.
+        ].
+        locals at: name put: element.  
+        ^ self.              
+    ].
+    (binding kind bitAnd: 2r100) == 2r100 "TYPE" ifTrue:[
+        name := binding compoundName asStringWith: $/.
+        previous := types at: name ifAbsent: nil.
+        previous notNil ifTrue:[
+            previous next: element.
+        ].
+        types at: name put: element.   
+        ^ self.
+    ].
+
+    binding kind == 2r001 "FIELD" ifTrue:[
+        binding declaringClass isNil ifTrue:[
+            name := '???.' , binding name
+        ] ifFalse:[
+            name := (binding declaringClass compoundName asStringWith:$/) , '.' , binding name.
+        ].
+        previous := fields at: name ifAbsent: nil.
+        previous notNil ifTrue:[
+            previous next: element.
+        ].
+        fields at: name put: element.  
+        ^ self.
+    ].
+
+    binding kind == 2r010 "LOCAL" ifTrue:[
+        name := binding name.
+        previous := locals at: name ifAbsent: nil.
+        previous notNil ifTrue:[
+            previous next: element.
+        ].
+        locals at: name put: element.  
+        ^ self.   
+    ].
+
+    self error: 'Should not happen'
+
+    "Created: / 01-10-2013 / 10:33:30 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 26-10-2013 / 21:27:56 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+methodEnter: node
+    locals := Dictionary new
+
+    "Created: / 01-10-2013 / 10:44:24 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+methodLeave: node
+
+    "Created: / 01-10-2013 / 10:44:32 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!JavaSyntaxHighlighter::Marker class methodsFor:'initialization'!
+
+initialize
+    "Invoked at system start or when the class is dynamically loaded."
+
+    "
+    !!!! IMPORTANT !!!!!!
+    When changing / adding constants, make sure they
+    are in sync with those defined in Smaltalk
+    stx.libjava.tools.source.JavaSourceMarker !!!!!!
+    "
+
+    self lookupObject: JavaLookup instance.
+    
+    MARK_KEYWORD        := 1.
+    MARK_NUMBER         := 2.
+    MARK_STRING         := 3.
+    MARK_CHARACTER      := 4.
+    MARK_COMMENT        := 5.
+    MARK_JAVADOC        := 6.
+    MARK_KEYWORD_FLOW   := 7.
+    MARK_SELECTOR       := 8.
+    MARK_FIELD          := 9.
+    MARK_FIELD_ASSIGNED := 10.
+    MARK_LOCAL          := 11.
+    MARK_CLASS          := 12.
+
+    "Modified: / 11-09-2013 / 01:45:59 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+
+!JavaSyntaxHighlighter::Marker methodsFor:'accessing'!
+
+highlighter:aJavaSourceHighlighter
+    highlighter := aJavaSourceHighlighter.
+! !
+
+!JavaSyntaxHighlighter::Marker methodsFor:'syntax detection'!
+
+mark: kind from:pos1 to:pos2
+
+    kind == MARK_KEYWORD        ifTrue:[ ^ highlighter markKeywordFrom: pos1 + 1 to: pos2 + 1].
+    kind == MARK_KEYWORD_FLOW   ifTrue:[ ^ highlighter markKeywordFlowFrom: pos1 + 1 to: pos2 + 1 ].
+
+    kind == MARK_NUMBER         ifTrue:[ ^ highlighter markConstantFrom: pos1 + 1 to: pos2 + 1 ].
+    kind == MARK_STRING         ifTrue:[ ^ highlighter markConstantFrom: pos1 + 1 to: pos2 + 1 ].
+    kind == MARK_CHARACTER      ifTrue:[ ^ highlighter markConstantFrom: pos1 + 1 to: pos2 + 1 ].
+
+    kind == MARK_COMMENT        ifTrue:[ ^ highlighter markCommentFrom: pos1 + 1 to: pos2 + 1 ].
+    kind == MARK_JAVADOC        ifTrue:[ ^ highlighter markCommentFrom: pos1 + 1 to: pos2 + 1 ].
+
+    kind == MARK_SELECTOR      ifTrue:[ ^ highlighter markSelectorFrom: pos1 + 1 to: pos2 + 1 ].
+
+    "Created: / 05-09-2013 / 03:03:46 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 11-09-2013 / 01:48:16 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!JavaSyntaxHighlighter class methodsFor:'documentation'!
+
+version_CVS
+    ^ '$Header: /cvs/stx/stx/libjava/tools/JavaSyntaxHighlighter.st,v 1.2 2013-02-25 11:15:35 vrany Exp $'
+!
+
+version_HG
+
+    ^ '$Changeset: <not expanded> $'
+!
+
+version_SVN
+    ^ 'Id'
+! !
+
+
+JavaSyntaxHighlighter::Indexer initialize!
+JavaSyntaxHighlighter::Marker initialize!