Tools__CodeNavigationService.st
changeset 9979 00b306851c88
child 10076 6d9055a907ff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Tools__CodeNavigationService.st	Fri Jul 01 15:20:03 2011 +0200
@@ -0,0 +1,542 @@
+"
+ COPYRIGHT (c) 2006 by eXept Software AG
+	      All Rights Reserved
+
+ 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.
+"
+"{ Package: 'stx:libtool' }"
+
+"{ NameSpace: Tools }"
+
+CodeViewService subclass:#CodeNavigationService
+	instanceVariableNames:'selectorEmphasis variableEmphasis currentEmphasis'
+	classVariableNames:''
+	poolDictionaries:''
+	category:'Interface-CodeView'
+!
+
+!CodeNavigationService class methodsFor:'documentation'!
+
+copyright
+"
+ COPYRIGHT (c) 2006 by eXept Software AG
+	      All Rights Reserved
+
+ 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.
+"
+! !
+
+!CodeNavigationService class methodsFor:'accessing'!
+
+label
+
+    "Answers short label - for UI"
+
+    ^'Semi-modal Code Navigation'
+
+    "Created: / 07-03-2010 / 14:00:43 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!CodeNavigationService class methodsFor:'accessing - defaults'!
+
+defaultSelectorEmphasis
+    ^ Array with:#backgroundColor 
+                -> (Color white blendWith:(Color 
+                                redByte:100
+                                greenByte:180
+                                blueByte:255))
+!
+
+defaultVariableEmphasis
+    ^ Array with:#backgroundColor 
+                -> (Color gray: 90)
+
+    "Created: / 25-06-2010 / 13:56:43 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!CodeNavigationService methodsFor:'code services'!
+
+browseClass: class
+
+    self browser ifNil: [^NewSystemBrowser browseClass:class].
+    (UserPreferences current alwaysOpenNewTabWhenCtrlClick 
+        or:[self browser navigationState modified])  
+        ifTrue:
+            [self browser 
+                spawnFullBrowserInClass: class selector:nil in:#newBuffer]
+        ifFalse:
+            [self browser 
+                switchToClass: class]
+
+    "Created: / 15-02-2010 / 09:36:50 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 25-07-2010 / 11:00:26 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+browseMethod: method
+
+    self browseMethod: method label: nil.
+
+    "Created: / 14-02-2010 / 19:41:46 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+browseMethod: method label: label
+
+    self browser ifNil: [^NewSystemBrowser openInMethod:method].
+    (UserPreferences current alwaysOpenNewTabWhenCtrlClick 
+        or:[self browser navigationState modified])  
+        ifTrue:
+            [self browser 
+                spawnFullBrowserInClass: method mclass 
+                selector:method selector 
+                in:#newBuffer]
+        ifFalse:
+            [self browser 
+                switchToClass: method containingClass 
+                selector: method selector].
+
+    "Modified: / 19-02-2008 / 10:15:17 / janfrog"
+    "Created: / 19-10-2008 / 08:16:17 / Jan Vrany <vranyj1@fel.cvut.cz>"
+    "Modified: / 25-07-2010 / 13:34:27 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+browseMethods: methods label: label
+
+    methods size = 1 ifTrue:
+        [^self browseMethod: methods anyOne label: label].
+
+    self browser 
+        ifNil: [NewSystemBrowser browseMethods: methods title: label]
+        ifNotNil:[self browser spawnMethodBrowserFor:methods in:#newBuffer label:label]
+
+    "Created: / 26-12-2007 / 11:32:04 / janfrog"
+    "Modified: / 19-10-2008 / 08:17:28 / Jan Vrany <vranyj1@fel.cvut.cz>"
+!
+
+browser
+
+    ^codeView browserHolder value
+
+    "Created: / 06-03-2010 / 21:14:51 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+implementorsOf: selector
+
+    selector ifNil:[^#()].
+    ^SystemBrowser
+        findImplementorsOf: selector
+        in: Smalltalk allClasses
+        ignoreCase: false
+
+    "Created: / 26-12-2007 / 11:37:11 / janfrog"
+!
+
+sendersOf: selector
+
+    ^SystemBrowser
+        findSendersOf: selector
+        in: Smalltalk allClasses
+        ignoreCase: false
+
+    "Created: / 26-12-2007 / 11:37:22 / janfrog"
+! !
+
+!CodeNavigationService methodsFor:'event handling'!
+
+button1Press
+
+    codeView syntaxElementSelection ifNil:[^self].
+
+    codeView syntaxElementSelection type == #selector ifTrue:[^self button1PressForSelector: codeView syntaxElementSelection value].
+    codeView syntaxElementSelection type == #class    ifTrue:[^self browseClass:codeView syntaxElementSelection value].
+
+    "Created: / 14-02-2010 / 18:43:03 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 06-03-2010 / 21:11:30 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+button1PressForSelector: selector
+
+    | impls menu |
+    impls := self implementorsOf: selector.
+    impls size = 1 ifTrue:[^self browseMethod: impls anyOne].
+    menu := self implementorsMenu: impls selector: selector.
+    self highlightClear.
+    menu showAtPointer.
+
+    "Created: / 14-02-2010 / 18:50:13 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+button2Press
+
+    | sel |
+    sel := codeView syntaxElementSelection.
+    (sel notNil and:[sel type == #selector]) ifTrue:[^self button2PressForSelector: sel value].
+
+    "Created: / 14-02-2010 / 18:43:04 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 17-06-2011 / 08:58:34 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+button2PressForSelector: selector
+
+    | senders menu |
+    senders := self implementorsOf: selector.
+    senders size = 1 ifTrue:[^self browseMethod: senders anyOne].
+    menu := self sendersMenu: senders selector: selector.
+    self highlightClear.
+    menu showAtPointer.
+
+    "Created: / 14-02-2010 / 18:50:13 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+buttonMotion: button x:x y:y in: view
+
+    "Handles an event in given view (a subview of codeView).
+     If the method returns true, the event will not be processed
+     by the view."
+
+    (view == textView and:[textView sensor ctrlDown]) ifTrue:
+        [self highlightElementAtX:x y:y. ^true].
+    ^false
+
+    "Created: / 06-03-2010 / 20:40:37 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+buttonPress: button x:x y:y in: view
+
+    "Handles an event in given view (a subview of codeView).
+     If the method returns true, the event will not be processed
+     by the view."
+
+    (view == textView) ifTrue:
+        [codeView sensor ctrlDown ifTrue:
+            [button == 1      ifTrue: [self button1Press.^true].
+            button == #paste ifTrue: [self button2Press.^true].   
+            button == 2      ifTrue: [self button2Press.^true]].
+        button == 1 ifTrue:[
+            self highlightVariableAtX:x y:y.
+        ]
+        ].
+    ^false
+
+    "Created: / 06-03-2010 / 21:12:26 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 25-06-2010 / 14:53:36 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+keyPress:key x:x y:y in:view 
+    "Handles an event in given view (a subview of codeView).
+     If the method returns true, the event will not be processed
+     by the view."
+    
+    (view == textView) ifTrue:[
+        (key == #'Control_L' or:[ key == #Ctrl ]) ifTrue:[
+            self highlightElementAtX:x y:y.
+            ^ true
+        ].
+        self highlightVariableAtCursor.
+        ^ false
+    ].
+    ^ false
+
+    "Created: / 06-03-2010 / 20:50:45 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 25-06-2010 / 14:46:10 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+keyRelease: key x:x y:y in: view
+
+    "Handles an event in given view (a subview of codeView).
+     If the method returns true, the event will not be processed
+     by the view."
+
+    (view == textView and:[key == #'Control_L' or:[key == #Ctrl]]) ifTrue:
+        [self highlightClear. textView redraw. ^true].
+    ^false
+
+    "Created: / 06-03-2010 / 21:03:59 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!CodeNavigationService methodsFor:'initialization'!
+
+initialize
+
+    super initialize.
+    selectorEmphasis := self class defaultSelectorEmphasis.
+    variableEmphasis := self class defaultVariableEmphasis.
+
+    "Created: / 25-06-2010 / 14:05:09 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!CodeNavigationService methodsFor:'menus-dynamic'!
+
+implementorsMenu: implementors selector: selector  
+    | menu|
+
+    menu := Menu new.
+    implementors isNilOrEmptyCollection ifTrue:[
+        menu addItem:(MenuItem label:'No implementors found') disable
+    ] ifFalse:[
+        menu addItem:(MenuItem 
+                    label:(selector storeString , (' (all implementors) ') asText allItalic)
+                    value:[
+                        self browseMethods:implementors
+                            label:'Implementors of ' , selector storeString
+                    ]).
+        menu addSeparator.
+        implementors do:[:mth | 
+            menu 
+                addItem:(MenuItem label:(selector storeString 
+                                , (' in ' , mth containingClass name asText allBold))
+                        value:[ self browseMethod:mth label: 'Implementor of ' , selector storeString  ])
+        ]
+    ].
+    ^ menu
+
+    "Modified: / 19-10-2008 / 08:16:50 / Jan Vrany <vranyj1@fel.cvut.cz>"
+    "Created: / 14-02-2010 / 19:39:37 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+sendersMenu: senders  selector: selector  
+    | menu|
+
+    menu := Menu new.
+    senders isNilOrEmptyCollection ifTrue:[
+        menu addItem:(MenuItem label:'No senders found') disable
+    ] ifFalse:[
+        menu addItem:(MenuItem 
+                    label:(selector storeString , (' (all senders)') asText allItalic)
+                    value:[
+                        self browseMethods:senders
+                            label:'Senders of ' , selector storeString
+                    ]).
+        menu addSeparator.
+        senders do:[:mth | 
+            menu 
+                addItem:(MenuItem label:(mth selector storeString 
+                                , (' in ' , mth containingClass name asText allBold))
+                        value:[ self browseMethod:mth label: 'Sender of ' , selector storeString ])
+        ]
+    ].
+    ^ menu
+
+    "Modified: / 19-10-2008 / 08:17:00 / Jan Vrany <vranyj1@fel.cvut.cz>"
+    "Created: / 14-02-2010 / 19:40:10 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 01-08-2010 / 11:09:59 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!CodeNavigationService methodsFor:'private'!
+
+elementAtCursor
+    ^self elementAtLine: textView cursorLine col: textView cursorCol - 1
+
+    "Created: / 25-06-2010 / 14:39:14 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+elementAtLine:line col:col 
+    |characterPosition index element |
+
+    characterPosition := textView characterPositionOfLine:line col:col.
+    index := SortedCollection binarySearch: (codeView syntaxElements) forIndexOf: characterPosition.
+    index > (codeView syntaxElements) size ifTrue:[^nil].
+    element := (codeView syntaxElements) at: index.
+    (characterPosition between: element start and: element stop) ifFalse:[^nil].
+    ^element
+
+    "Created: / 25-06-2010 / 14:40:03 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+elementAtX:x y:y 
+    |visibleLine line col|
+
+    codeView syntaxElements ifNil:[^nil].
+    visibleLine := textView visibleLineOfY:y.
+    col := textView colOfX:x inVisibleLine:visibleLine.
+    line := textView visibleLineToAbsoluteLine:visibleLine.
+    ^self elementAtLine:line col:col
+
+    "Created: / 25-06-2010 / 14:52:39 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 01-08-2010 / 08:50:18 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+highlighEmphasisFor: element
+
+    element ifNil:[^nil].
+
+    element type == #selector ifTrue:[^selectorEmphasis].
+    element type == #variable ifTrue:[^variableEmphasis].
+
+    ^nil
+
+    "Created: / 25-06-2010 / 13:54:42 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+highlightClear
+    |textView|
+
+    codeView syntaxElementSelection == nil ifTrue:[^ self].
+
+    textView := codeView textView.
+    textView list ifNil:[ ^ self ].
+    textView list do:[:line | 
+        line isText ifTrue:[
+            line emphasisAllRemove: currentEmphasis
+        ]
+    ].
+    textView redraw.
+    codeView syntaxElementSelection:nil.
+
+    "Modified: / 26-12-2007 / 12:28:05 / janfrog"
+    "Created: / 25-06-2010 / 14:15:58 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 30-06-2011 / 11:07:05 / cg"
+!
+
+highlightElement: element
+    codeView syntaxElementSelection == element ifTrue:[^ self].
+
+    self highlightClear.
+    currentEmphasis := self highlighEmphasisFor: element.         
+    element 
+       ifNotNil:
+            [|e|
+            codeView syntaxElementSelection: element.
+            e := element.
+            [e isNil] whileFalse:
+                [self highlightWithoutClearFrom: e start to: e stop.
+                e := e next].
+            e := element prev.
+            [e isNil] whileFalse:
+                [self highlightWithoutClearFrom: e start to: e stop.
+                e := e prev]].
+    textView invalidate
+
+    "Created: / 14-02-2010 / 16:18:36 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 25-06-2010 / 14:18:55 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 30-06-2011 / 11:06:42 / cg"
+!
+
+highlightElementAtCursor
+    self highlightElementAtLine: textView cursorLine col: textView cursorCol
+
+    "Created: / 14-02-2010 / 16:17:40 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 06-03-2010 / 19:59:18 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+highlightElementAtLine:line col:col 
+    |characterPosition index element |
+
+
+    characterPosition := textView characterPositionOfLine:line col:col.
+    index := SortedCollection binarySearch: (codeView syntaxElements) forIndexOf: characterPosition.
+    index > (codeView syntaxElements) size ifTrue:[^self highlightElement: nil].
+    element := (codeView syntaxElements) at: index.
+    (characterPosition between: element start and: element stop) ifFalse:[^self highlightElement: nil].
+    self highlightElement:element
+
+    "Created: / 14-02-2010 / 16:17:22 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 01-08-2010 / 08:50:11 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+highlightElementAtX:x y:y 
+    |visibleLine line col|
+
+    codeView syntaxElements ifNil:[^self].
+    visibleLine := textView visibleLineOfY:y.
+    col := textView colOfX:x inVisibleLine:visibleLine.
+    line := textView visibleLineToAbsoluteLine:visibleLine.
+    self highlightElementAtLine:line col:col
+
+    "Created: / 14-02-2010 / 16:12:50 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 06-03-2010 / 20:06:17 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+highlightLine:lineNo fromLine:startLine col:endLine toLine:startCol col:endCol
+    |line start end|
+
+    (lineNo between:startLine and:endLine) ifFalse:[
+        ^ self
+    ].
+    line := textView listAt:lineNo.
+    start := lineNo = startLine ifTrue:[
+                startCol
+            ] ifFalse:[
+                line indexOfNonSeparator
+            ].
+    end := lineNo = endLine ifTrue:[
+                endCol
+            ] ifFalse:[ line size ].
+    line 
+        emphasisFrom:start
+        to:end
+        add: currentEmphasis
+
+    "Created: / 25-06-2010 / 14:15:39 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 03-09-2010 / 22:39:33 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+highlightVariable:e 
+    (e notNil and:[ e type == #variable ]) ifTrue:[
+        self highlightElement:e.
+    ] ifFalse:[
+        self highlightClear.
+    ]
+!
+
+highlightVariableAtCursor
+    |e|
+
+    e := self elementAtCursor.
+    self highlightVariable: e
+
+    "Modified: / 25-06-2010 / 14:53:17 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+highlightVariableAtX:x y:y 
+    |e|
+
+    e := self elementAtX:x y:y.
+    self highlightVariable:e.
+
+    "Created: / 25-06-2010 / 14:52:09 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+highlightWithoutClearFrom: start to: end
+    "Remove underlined emphasis"
+
+    |startLine startCol endLine endCol|
+
+    startLine := textView lineOfCharacterPosition:start.
+    startCol := start - (textView characterPositionOfLine:startLine col:1) + 1.
+    endLine := textView lineOfCharacterPosition:end.
+    endCol := end - (textView characterPositionOfLine:endLine col:1) + 1.
+    self highlightWithoutClearFromLine: startLine col: startCol toLine: endLine col: endCol
+
+    "Created: / 25-06-2010 / 14:15:21 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+highlightWithoutClearFromLine: startLine col: startCol toLine: endLine col: endCol 
+
+    textView list keysAndValuesDo:
+        [:lineNo :line|
+        |start end|
+        line isText ifTrue:
+            [self highlightLine: lineNo fromLine: startLine col: endLine toLine: startCol col: endCol]].
+
+    "Created: / 25-06-2010 / 14:15:08 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!CodeNavigationService class methodsFor:'documentation'!
+
+version_CVS
+    ^ '$Header: /cvs/stx/stx/libtool/Tools__CodeNavigationService.st,v 1.1 2011-07-01 13:20:03 cg Exp $'
+!
+
+version_SVN
+    ^ '§Id: Tools__CodeNavigationService.st 7788 2011-06-17 07:57:48Z vranyj1 §'
+! !