--- /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 §'
+! !