Tools__CodeNavigationService.st
author Claus Gittinger <cg@exept.de>
Fri, 08 Jul 2011 13:31:51 +0200
changeset 10291 af5825474e18
parent 10276 068f02c67fd7
child 10361 1443a20ddac2
permissions -rw-r--r--
changed: #highlightLine:fromLine:col:toLine:col: DNU when highlighting

"
 COPYRIGHT (c) 2010 by Jan Vrany, SWING Research Group. CTU in Prague
              All Rights Reserved

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the 'Software'), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
"
"{ Package: 'stx:libtool' }"

"{ NameSpace: Tools }"

CodeViewService subclass:#CodeNavigationService
	instanceVariableNames:'selectorEmphasis variableEmphasis currentEmphasis'
	classVariableNames:''
	poolDictionaries:''
	category:'Interface-CodeView'
!

!CodeNavigationService class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 2010 by Jan Vrany, SWING Research Group. CTU in Prague
              All Rights Reserved

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the 'Software'), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
"
! !

!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>"
!

browser

    ^codeView browserHolder value

    "Created: / 06-03-2010 / 21:14:51 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!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 := codeView implementorsOf: selector.
    impls size = 1 ifTrue:[^codeView browseMethod: impls anyOne].
    menu := codeView implementorsMenu: impls selector: selector.
    self highlightClear.
    menu showAtPointer.

    "Created: / 14-02-2010 / 18:50:13 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 30-06-2011 / 19:34:50 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 07-07-2011 / 17:16:23 / jv"
!

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 := codeView implementorsOf: selector.
    senders size = 1 ifTrue:[^self browseMethod: senders anyOne].
    menu := codeView sendersMenu: senders selector: selector.
    self highlightClear.
    menu showAtPointer.

    "Created: / 14-02-2010 / 18:50:13 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 30-06-2011 / 19:34:43 / 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. ^true].
    ^false

    "Created: / 06-03-2010 / 21:03:59 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 08-07-2011 / 08:40:55 / cg"
! !

!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:'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 invalidate. "/ 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: / 08-07-2011 / 08:50:45 / 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.
    line isEmpty ifTrue:[^self].
    start := lineNo = startLine ifTrue:[
                startCol
            ] ifFalse:[
                line indexOfNonSeparator
            ].
    end := lineNo = endLine ifTrue:[
                endCol
            ] ifFalse:[ line size ].
    line 
        emphasisFrom:(start max: 1)
        to:(end min: line size)
        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>"
    "Modified: / 08-07-2011 / 13:02:51 / cg"
!

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.6 2011-07-08 11:31:51 cg Exp $'
!

version_SVN
    ^ '§Id: Tools__CodeNavigationService.st 7788 2011-06-17 07:57:48Z vranyj1 §'
! !