SmallSense__SmalltalkLintService.st
author Claus Gittinger
Wed, 19 Nov 2014 20:56:59 +0000
changeset 301 c7340c8fe8ad
parent 298 c1d8d35e71fd
child 311 368ff7243ade
child 312 ce4e697a363c
permissions -rw-r--r--
Better variable naming in SmalltalkLintService>>annotationAtLine

"
 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:goodies/smallsense' }"

"{ NameSpace: SmallSense }"

Tools::BackgroundSourceProcessingService subclass:#SmalltalkLintService
	instanceVariableNames:'rulesHolder rules highlighter support'
	classVariableNames:'Debugging'
	poolDictionaries:''
	category:'SmallSense-Smalltalk-Lint'
!

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

!SmalltalkLintService class methodsFor:'accessing'!

debugging
    ^Debugging == true

    "Created: / 17-02-2012 / 00:48:28 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

debugging: aBoolean

    Debugging := aBoolean

    "Created: / 16-02-2012 / 16:22:29 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

label

    "Answers short label - for UI"

    ^'SmallSense - Static Checking'

    "Created: / 07-03-2010 / 14:00:01 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 27-07-2013 / 22:36:48 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

priority
    "Answers a priority of the service. Services with higher priority
     will get the event notification before ones with lower priority.
     Therefore, a lower-priority service might not get the event if high
     priority service processes it"

    ^ 10

    "Created: / 01-02-2012 / 10:29:06 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!SmalltalkLintService class methodsFor:'queries'!

isUsefulFor:aCodeView
    "this filters useful services.
     must be redefined to return true in subclasses (but each class must do it only
     for itself - not for subclasses"

    ^ self == SmalltalkLintService

    "Created: / 24-07-2013 / 11:35:59 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 17-09-2013 / 15:26:20 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!SmalltalkLintService class methodsFor:'testing'!

isAvailable

    ^UserPreferences current smallSenseEnabled

    "Created: / 04-02-2012 / 22:20:03 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!SmalltalkLintService methodsFor:'accessing'!

syntaxHighlighter

    ^highlighter

    "Created: / 05-08-2011 / 10:59:02 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!SmalltalkLintService methodsFor:'aspects'!

rulesHolder
    "return/create the 'rulesHolder' value holder (automatically generated)"

    rulesHolder isNil ifTrue:[
        rulesHolder := ValueHolder new.
        rulesHolder addDependent:self.
    ].
    ^ rulesHolder
!

rulesHolder:something
    "set the 'rulesHolder' value holder (automatically generated)"

    |oldValue newValue|

    rulesHolder notNil ifTrue:[
        oldValue := rulesHolder value.
        rulesHolder removeDependent:self.
    ].
    rulesHolder := something.
    rulesHolder notNil ifTrue:[
        rulesHolder addDependent:self.
    ].
    newValue := rulesHolder value.
    oldValue ~~ newValue ifTrue:[
        self update:#value with:newValue from:rulesHolder.
    ].
! !

!SmalltalkLintService methodsFor:'change & update'!

sourceChanged:force
    | lang |

    rules isNil ifTrue:[ ^ self ].
    ((lang := codeView language) isNil or:[lang isSmalltalk not]) ifTrue:[ ^ self ].
    rules resetResult.
    highlighter reset.
    super sourceChanged:force.

    "Created: / 18-02-2012 / 22:50:05 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

update:something with:aParameter from:changedObject
    "Invoked when an object that I depend upon sends a change notification."

    changedObject == rulesHolder ifTrue:[
        UserPreferences current smallSenseBackgroundLintEnabled ifTrue:[
            | rulesHierarchical ruleList |

            "/xxxx
            rulesHierarchical := rulesHolder value.
            rulesHierarchical notNil ifTrue:[
                ruleList := rulesHierarchical flattened reject:[:each| SmalltalkChecker forceDisabledRules includes: each class name].
                ruleList := ruleList collect:[ :e | e class new ].
                rules := RBCompositeLintRule rules: ruleList.
                highlighter rules: ruleList.
                self process.
            ].
        ].
        ^ self.
    ].

    super update:something with:aParameter from:changedObject

    "Modified (format): / 16-10-2014 / 23:20:18 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!SmalltalkLintService methodsFor:'event handling'!

buttonPress:button x:x y:y in:view 
    |lineNr|

    rules isNil ifTrue:[
        ^ false
    ].
    view == gutterView ifTrue:[
        button == 1 ifTrue:[
            lineNr := textView yVisibleToLineNr:y.
            lineNr notNil ifTrue:[ 
                ^ self showInfoWindowForLine: lineNr 
            ].
            ^ false.
        ].
    ].
    ^ false

    "Created: / 30-01-2012 / 21:04:39 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

viewRealized

    | browser |

    UserPreferences current smallSenseBackgroundLintEnabled ifFalse:[ ^ self ].

    (browser := codeView browser) notNil ifTrue:[
        browser navigationState canvasType ~~ #smallLintByRuleResultBrowserSpec ifTrue:[
            self rulesHolder: (browser perform:#smalllintRulesOrDefaultHolder ifNotUnderstood:[browser smalllintRulesOrAllHolder])
        ].
    ].

    "Created: / 23-01-2012 / 10:43:11 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 28-02-2013 / 22:43:24 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!SmalltalkLintService methodsFor:'initialization'!

initialize

    super initialize.

    highlighter := SmalltalkLintHighlighter new.

    "Created: / 05-08-2011 / 11:53:05 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 17-09-2013 / 15:22:55 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!SmalltalkLintService methodsFor:'private'!

annotationAtLine: lineNo
    | annotations |        

    (annotations := highlighter annotations) isEmptyOrNil ifTrue:[ ^ nil ].
    annotations do:[:annotation|
        | line |

        (line := annotation line) isNil ifTrue:[
            line := codeView lineOfCharacterPosition: annotation startPosition.
            annotation line: line.
        ].
        line > lineNo ifTrue:[ ^ nil ].
        line == lineNo ifTrue:[ ^ annotation ].
    ].
    ^nil

    "Created: / 30-01-2012 / 21:06:25 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

process
    "(Re)starts the processing job. Should be called whenever a source 
     must be (re)processed."

    rules isNil ifTrue:[
        ^self
    ].

    ^super process.

    "Created: / 24-01-2012 / 12:43:55 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

process: delayed
    "Do the real source processing. If delayed is true, actuall data update must
     be done within the event queue using #pushUserEvent:...
    "
    |lang cls env oldCodeList oldCode |

    rules isNil ifTrue:[ ^ self ].
    codeView codeAspect ~~ #method ifTrue:[ ^ self ].
    (lang := codeView language) isNil ifTrue: [ ^ self ].
    lang isSmalltalk ifFalse: [ ^ self ]. 
    done := false.
    modified := false.

    cls := codeView klass.
        cls isNil ifTrue:[^ self ].    


    Delay waitForMilliseconds: 200."Give user some time to write"

    (cls notNil and:[cls isObsolete]) ifTrue:[
        cls isMeta ifTrue:[
            cls := (Smalltalk at:cls theNonMetaclass name) class
        ] ifFalse:[
            cls := Smalltalk at:cls name
        ].
    ].

    "textView" modified ifFalse:[
        oldCodeList := textView list copy.
        oldCodeList isEmptyOrNil ifTrue: [ ^ self ].
        "textView" modified ifFalse:[
            oldCodeList isNil ifFalse:[
                oldCode := oldCodeList asStringWithoutEmphasis.
                oldCode isEmptyOrNil ifTrue:[ ^ self ].
                "textView" modified ifFalse:[
                    Screen currentScreenQuerySignal answer:codeView device
                    do:[
                        Error handle:[:ex |
                            | errMsg |

                            Debugging == true ifTrue:[
                                Debugging := false.    
                                ex pass.
                            ].

"/                            Transcript topView raiseDeiconified.
"/                            Transcript showCR:'ParseError: ', ex description.
                            errMsg := ex description asStringCollection first asString.
                            self showInfo:(('Smalltalk Lint: ',errMsg) colorizeAllWith:Color red).
                        ] do:[
                            env := (SmallSense::SmalltalkUnacceptedMethodEnvironment onClass:cls methodSource: oldCode).
                            SmalltalkChecker runRule: rules onEnvironment: env
                        ].
                        delayed ifTrue:[
                            codeView sensor pushUserEvent:#rehighlight: for:self withArgument: true.
                        ] ifFalse:[
                            self rehighlight: true.
                        ]
                    ]
                ]
            ]
        ]
    ]

    "Created: / 24-01-2012 / 12:44:19 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 16-10-2014 / 01:10:39 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

rehighlight: delayed

    | service |
    service := self service: SmallSense::CodeHighlightingService name.
    service isNil ifTrue:[
        service := self service: Tools::CodeHighlightingService name
    ].
    service notNil ifTrue:[
        service sourceChanged: true.
    ]

    "Created: / 27-01-2012 / 17:06:32 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 23-09-2013 / 22:27:39 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

showInfoWindowForLine: lineNo
    | ann |

    ann := self annotationAtLine: lineNo.
    ann isNil ifTrue:[ ^ false ].

    CriticsWindow new
        rule: ann rule;
        codeView: codeView;
        allButOpen;
        openWindowAt: (Screen current pointerPosition - (20@20)).

    ^true

    "Created: / 30-01-2012 / 21:04:39 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!SmalltalkLintService methodsFor:'redrawing'!

drawLine:lineNo in:view atX:x y:y width:w height:h from:startCol to:endColOrNil with:fg and:bg 
    "Called by both gutterView and textView (well, not yet) to
     allow services to draw custom things on text view.
     Ask JV what the args means if unsure (I'm lazy to document
     them, now it is just an experiment...)"

    | lang annotation |

    ((lang := codeView language) isNil or:[lang isSmalltalk not]) ifTrue:[ ^ self ].

    annotation :=  self annotationAtLine: lineNo.
    annotation notNil ifTrue:[
        self drawAnnotationIcon: (ToolbarIconLibrary smalllintWarning16x16)
                atX: x y: y  width: w height: h.
    ].

    "Created: / 30-01-2012 / 15:11:16 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 07-08-2013 / 00:19:09 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!SmalltalkLintService methodsFor:'registering'!

unregister
    super unregister.
    rulesHolder removeDependent: self.

    "Created: / 14-10-2014 / 22:40:18 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!SmalltalkLintService class methodsFor:'documentation'!

version_HG

    ^ '$Changeset: <not expanded> $'
!

version_SVN
    ^ '$Id: SmallSense__SmalltalkLintService.st,v 1.3 2014/02/26 15:09:30 cg Exp $'
! !