stx_goodies_smallsense.st
author Jan Vrany <jan.vrany@fit.cvut.cz>
Sat, 06 Dec 2014 22:27:37 +0000
changeset 364 12e523308dba
parent 362 b34840b66447
parent 311 368ff7243ade
child 365 58f383e9a862
permissions -rw-r--r--
Merged 4fb5823ae8bf and a636cee89de4

"
stx:goodies/smallsense - A productivity plugin for Smalltalk/X IDE
Copyright (C) 2013-2014 Jan Vrany

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
"
"{ Package: 'stx:goodies/smallsense' }"

LibraryDefinition subclass:#stx_goodies_smallsense
	instanceVariableNames:''
	classVariableNames:'Swizzled'
	poolDictionaries:''
	category:'* Projects & Packages *'
!

!stx_goodies_smallsense class methodsFor:'documentation'!

copyright
"
stx:goodies/smallsense - A productivity plugin for Smalltalk/X IDE
Copyright (C) 2013-2014 Jan Vrany

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
"
! !

!stx_goodies_smallsense class methodsFor:'accessing - tests'!

excludedFromTestSuite
    "List of testcases and/or tests excluded from testsuite.
     Entries maybe ClassName or #(ClassName testName)
    "
    ^ #(
        #'SmallSense::BaseTestClass'
        #'SmallSense::TestCase'
        #'SmallSense::FinderTests'
        #'SmallSense::RecognizerTests'
        #'SmallSense::SmalltalkParserTests'
    )

    "Created: / 23-05-2014 / 12:49:17 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!stx_goodies_smallsense class methodsFor:'description'!

excludedFromPreRequisites
    "list all packages which should be ignored in the automatic
     preRequisites scan. See #preRequisites for more."

    ^ #(
    )
!

mandatoryPreRequisites
    "list packages which are mandatory as a prerequisite.
     This are packages containing superclasses of my classes and classes which
     are extended by myself.
     They are mandatory, because we need these packages as a prerequisite for loading and compiling.
     This method is generated automatically,
     by searching along the inheritance chain of all of my classes."

    ^ #(
        #'stx:goodies/refactoryBrowser/helpers'    "BrowserEnvironment - superclass of SmallSense::SmalltalkUnacceptedMethodEnvironment"
        #'stx:goodies/refactoryBrowser/lint'    "RBBasicLintRule - extended"
        #'stx:goodies/refactoryBrowser/parser'    "RBBlockNode - extended"
        #'stx:goodies/regex'    "Regex::RxCharSetParser - superclass of SmallSense::TokenPatternParser::TokenSpecParser"
        #'stx:libbasic'    "Autoload - superclass of SmallSense::AbstractJavaCompletionEngineTests"
        #'stx:libcomp'    "AbstractSyntaxHighlighter - superclass of SmallSense::SmalltalkParser"
        #'stx:libhtml'    "HTMLDocumentFrame - extended"
        #'stx:libtool'    "AbstractSettingsApplication - superclass of SmallSense::SettingsAppl"
        #'stx:libview'    "DisplaySurface - extended"
        #'stx:libview2'    "ApplicationModel - extended"
        #'stx:libwidg'    "DialogBox - extended"
        #'stx:libwidg2'    "HierarchicalItem - superclass of SmallSense::ClassPO"
    )
!

referencedPreRequisites
    "list packages which are a prerequisite, because they contain
     classes which are referenced by my classes.
     We do not need these packages as a prerequisite for loading or compiling.
     This method is generated automatically,
     by searching all classes (and their packages) which are referenced by my classes."

    ^ #(
        #'stx:libbasic2'    "BackgroundJob - referenced by SmallSense::AbstractSearchDialog>>initialize"
        #'stx:libbasic3'    "ChangeSet - referenced by RBContainsSmalltalkXEOLCommentRule>>fixes:"
        #'stx:libjava'    "Java - referenced by SmallSense::JavaCompletionEngine>>complete"
        #'stx:libjava/tools'    "GroovyScanner - referenced by SmallSense::GroovyCompletionEngineSimple>>scannerClass"
    )
!

subProjects
    "list packages which are known as subprojects.
     The generated makefile will enter those and make there as well.
     However: they are not forced to be loaded when a package is loaded;
     for those, redefine requiredPrerequisites"

    ^ #(
    )
! !

!stx_goodies_smallsense class methodsFor:'description - contents'!

classNamesAndAttributes
    "lists the classes which are to be included in the project.
     Each entry in the list may be: a single class-name (symbol),
     or an array-literal consisting of class name and attributes.
     Attributes are: #autoload or #<os> where os is one of win32, unix,..."

    ^ #(
        "<className> or (<className> attributes...) in load order"
        #'SmallSense::AbstractDIalog'
        #'SmallSense::CodeHighlightingService'
        #'SmallSense::CodeNavigationService'
        #'SmallSense::CompletionContext'
        #'SmallSense::CompletionController'
        #'SmallSense::CompletionEngine'
        #'SmallSense::CompletionResult'
        #'SmallSense::CompletionView'
        #'SmallSense::CriticsWindow'
        #'SmallSense::EditService'
        #'SmallSense::EditSupport'
        #'SmallSense::Info'
        #'SmallSense::Manager'
        #'SmallSense::PO'
        #'SmallSense::ParseTreeIndex'
        #'SmallSense::ParseTreeIndexEntry'
        #'SmallSense::ParseTreeInspector'
        #'SmallSense::SelectorNode'
        #'SmallSense::SettingsAppl'
        #'SmallSense::SmalltalkChecker'
        #'SmallSense::SmalltalkInferencerParameters'
        #'SmallSense::SmalltalkLintService'
        #'SmallSense::SmalltalkParseNodeVisitor'
        #'SmallSense::SmalltalkParser'
        #'SmallSense::SmalltalkQuickFixer'
        #'SmallSense::SmalltalkSyntaxHighlighter'
        #'SmallSense::SmalltalkUnacceptedMethodEnvironment'
        #'SmallSense::TokenPatternMatcher'
        #'SmallSense::TokenPatternParser'
        #'SmallSense::TokenPatternToken'
        #'SmallSense::TokenPatternTokenSet'
        #'SmallSense::TokenStream'
        #'SmallSense::Type'
        #'SmallSense::TypeHolder'
        #'stx_goodies_smallsense'
        #'SmallSense::AbstractJavaCompletionEngine'
        #'SmallSense::AbstractSearchDialog'
        #'SmallSense::ClassInfo'
        #'SmallSense::ClassPO'
        #'SmallSense::ClassType'
        #'SmallSense::ConstantPO'
        #'SmallSense::GenericEditSupport'
        #'SmallSense::JavaEditSupport'
        #'SmallSense::JavaImportPO'
        #'SmallSense::MethodBindingPO'
        #'SmallSense::MethodInfo'
        #'SmallSense::MethodPO'
        #'SmallSense::PackagePO'
        #'SmallSense::SmalltalkCompletionEngine'
        #'SmallSense::SmalltalkEditSupport'
        #'SmallSense::SmalltalkInferencer'
        #'SmallSense::SmalltalkParseNodeFinder'
        #'SmallSense::SnippetPO'
        #'SmallSense::UnionType'
        #'SmallSense::UnknownType'
        #'SmallSense::VariableBindingPO'
        #'SmallSense::VariablePO'
        #'SmallSense::AbstractJavaCompletionEngineSimple'
        #'SmallSense::ClassSearchDialog'
        #'SmallSense::GroovyEditSupport'
        #'SmallSense::JavaCompletionEngine'
        #'SmallSense::JavaConstructorPO'
        #'SmallSense::MethodKeywordRestPO'
        #'SmallSense::MethodSearchDialog'
        #'SmallSense::PackageSearchDialog'
        #'SmallSense::JavaCompletionEngineSimple'
        #'SmallSense::GroovyCompletionEngineSimple'
        (#'SmallSense::AbstractJavaCompletionEngineTests' autoload)
        (#'SmallSense::AbstractTestCase' autoload)
        (#'SmallSense::BaseTestClass' autoload)
        (#'SmallSense::CompletionEngineTests' autoload)
        (#'SmallSense::EditSupportTests' autoload)
        (#'SmallSense::FinderTests' autoload)
        (#'SmallSense::GroovyCompletionEngineSimpleTests' autoload)
        (#'SmallSense::JavaCompletionEngineEnvironmentResource' autoload)
        (#'SmallSense::JavaCompletionEngineTests' autoload)
        (#'SmallSense::JavaEditSupportTests' autoload)
        (#'SmallSense::RecognizerTests' autoload)
        (#'SmallSense::SmalltalkCompletionEngineTests' autoload)
        (#'SmallSense::SmalltalkEditSupportTests' autoload)
        (#'SmallSense::SmalltalkParserTests' autoload)
        (#'SmallSense::TestCase' autoload)
        (#'SmallSense::TokenPatternMatcherTests' autoload)
    )
!

extensionMethodNames
    "list class/selector pairs of extensions.
     A correponding method with real names must be present in my concrete subclasses"

    ^ #(
        ParseNode isSelector
        AssignmentNode childNamesAndValuesDo:
        AssignmentNode inferedType
        AssignmentNode inferedType:
        MessageNode childNamesAndValuesDo:
        ParseErrorNode childNamesAndValuesDo:
        ParseNode childNamesAndValuesDo:
        ParseNode inferedType
        ParseNode inferedType:
        PrimaryNode childNamesAndValuesDo:
        StatementNode childNamesAndValuesDo:
        StatementNode inferedType
        StatementNode inferedType:
        UserPreferences smallSenseEnabled
        UserPreferences smallSenseEnabled:
        VariableNode isGlobalOrPrivateClass
        'ConfigurableFeatures class' hasSmallSenseEnabled
        UserPreferences smallSenseBackgroundLintEnabled
        UserPreferences smallSenseBackgroundLintEnabled:
        RBLintRule fixes:
        RBTransformationRule fixes:
        UserPreferences smallSenseBackgroundTypingEnabled
        UserPreferences smallSenseBackgroundTypingEnabled:
        HTMLDocumentView doQuickFix:
        'Tools::CodeHighlightingService class' new
        BlockNode childNamesAndValuesDo:
        'Tools::CodeNavigationService class' new
        ParseNode navigateToUsing:
        MessageNode navigateToUsing:
        VariableNode navigateToUsing:
        EditTextView autoIndent
        #'Tools::NewSystemBrowser' #'searchCompletionBlock_SmallSense'
        #'Tools::NewSystemBrowser' smallSenseSearchCompletion:
        #'Tools::NewSystemBrowser' smallSenseSearchCompletionBlock
        #'Tools::NewSystemBrowser' smallSenseSearchCompletionEntryForClass:showPrefix:
        #'Tools::NewSystemBrowser' smallSenseSearchCompletionNewForClass:
        PrimitiveNode inferedType
        UserPreferences smallSenseCompleteIfUnambiguous
        UserPreferences smallSenseCompleteIfUnambiguous:
        UserPreferences smallSenseCompletionEnabled
        UserPreferences smallSenseCompletionEnabled:
        ReturnNode childNamesAndValuesDo:
        'Tools::NewSystemBrowser class' #'stx_goodies_smallsense_askForClassToSearch:single:msgTail:resources:filter:forBrowser:thenDo:'
        UserPreferences smallSenseNewDialogsEnabled
        UserPreferences smallSenseNewDialogsEnabled:
        UserPreferences smallSenseSmalltalkIndentOnPasteEnabled
        UserPreferences smallSenseSmalltalkIndentOnPasteEnabled:
        EditTextViewCompletionSupport isCompletionViewShown
        #'Tools::NavigationState' #'stx_goodies_smallsense_selectedClasses'
        Method inspector2TabSTXParseTreeInspector
        ParseNode inspector2TabSTXParseTreeInspector
        Parser inspector2TabSTXParseTreeInspector
        Method inspector2TabRBParseTreeInspector
        RBBlockNode childNamesAndValuesDo:
        RBMethodNode childNamesAndValuesDo:
        RBProgramNode childNamesAndValuesDo:
        RBProgramNode endPosition
        RBProgramNode startPosition
        RBContainsSmalltalkXEOLCommentRule fixes:
        'DialogBox class' #'stx_goodies_smallsense_requestProject:from:initialAnswer:suggestions:'
        'Tools::CodeCompletionService class' new
        #'Tools::LintService' buttonPress:x:y:in:
        #'Tools::LintService' showInfoWindowForLine:
    )
! !

!stx_goodies_smallsense class methodsFor:'description - project information'!

applicationIconFileName
    "Return the name (without suffix) of an icon-file (the app's icon); will be included in the rc-resource file"

    ^ nil
    "/ ^ self applicationName
!

companyName
    "Return a companyname which will appear in <lib>.rc"

    ^ 'Jan Vrany'

    "Modified: / 17-07-2014 / 22:57:06 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

description
    "Return a description string which will appear in vc.def / bc.def"

    ^ 'Smalltalk/X IDE Productivity Tool'

    "Modified: / 17-07-2014 / 23:06:20 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

legalCopyright
    "Return a copyright string which will appear in <lib>.rc"

    ^ 'Copyright Jan Vrany 2013-2014'

    "Modified: / 17-07-2014 / 22:57:31 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

productName
    "Return a product name which will appear in <lib>.rc"

    ^ 'SmallSense'

    "Modified: / 17-07-2014 / 23:06:27 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!stx_goodies_smallsense class methodsFor:'description - svn'!

svnRepositoryUrlString
    "Return a SVN repository URL of myself.
     (Generated since 2011-04-08)
    "

    ^ '$URL: https://vranyj1@swing.fit.cvut.cz/svn/stx/libtool/branches/jv/smallsense/stx_goodies_smallsense.st $'
!

svnRevisionNr
    "Return a SVN revision number of myself.
     This number is updated after a commit"

    ^ "$SVN-Revision:"'7962            '"$"
! !

!stx_goodies_smallsense class methodsFor:'swizzling'!

swizzle
    "Swizzle all methods annotated as <swizzle:>"


    Swizzled ifTrue:[ ^ self ].
    ParserFlags initialize.
    self extensionMethods do:[:m |
        [
            self swizzle: m.
        ] on: Error do:[:ex |
            Logger error: 'Cannot swizzle %1: %2' with: m selector with: ex description.
            Debugger enter.
        ].
    ].
    Swizzled := true.


    "
    stx_goodies_smallsense swizzle
    Swizzled := false.

    self extensionMethods select:[:m | m notNil and:[ (m annotationAt: #swizzle:) notNil or:[(m annotationAt: #swizzle:checksum:) notNil ] ] ]
    "

    "Created: / 19-08-2013 / 14:54:25 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified (comment): / 28-11-2014 / 15:31:01 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

swizzle: method
    "Swizzle the method if it is annotated by <swizzle:> annotation"

    | annotation |


    annotation := method annotationAt: #swizzle:.
    annotation notNil ifTrue:[
    	self swizzle: method as: (annotation argumentAt: 1).
        ^ self
    ].
    annotation := method annotationAt: #swizzle:checksum:.
    annotation notNil ifTrue:[
        self swizzle: method as: (annotation argumentAt: 1) checksum: (annotation argumentAt: 2)
    ].

    "Created: / 19-08-2013 / 14:53:45 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 10-05-2014 / 00:23:24 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

swizzle: swizzlingMethod as: selector
    "Given an extension method, swizzle it into method's class
     under given selector."

    ^ self swizzle: swizzlingMethod as: selector checksum: nil

    "Created: / 19-08-2013 / 14:01:44 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 10-05-2014 / 00:24:09 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

swizzle: swizzlingMethod as: selector checksum: expectedSHA
    "Given an extension method, swizzle it into method's class
     under given selector.

     If `expectedSHA` is not nil, compare SHA1 hashes of swizzledMethod
     source and issue a warning when checksum does not match - which
     means somebody changed that method meanwhile and we should
     validate/update swizzlling method"

    | cls shadowedMethod shadowedMethodSHA shadowedMethodProjectDefinition shadowedMethodCopy swizzledForwarderMethodSource swizzledForwarderMethod |

    cls := swizzlingMethod mclass.
    shadowedMethod := cls compiledMethodAt: selector.
    shadowedMethod isNil ifTrue:[
        "/ Oops, method gone?
        self breakPoint: #jv.
        ^ self.
    ].

    self assert: swizzlingMethod numArgs == shadowedMethod numArgs.
    self assert: (swizzlingMethod selector startsWith: self name , '_').

    expectedSHA notNil ifTrue:[
        | src |

        src := shadowedMethod source.
        src notNil ifTrue:[
            shadowedMethodSHA := SHA1Stream new nextPutAll: src; hashValue.
            shadowedMethodSHA = expectedSHA ifFalse:[
                Logger error: 'Overwritten method checksum for: %1 does not match %2' with: shadowedMethod selector with: expectedSHA
            ].
        ].
    ].

    "/ Save shadowedMethod to project...
    shadowedMethodProjectDefinition := ProjectDefinition definitionClassForPackage: shadowedMethod package.
    shadowedMethodProjectDefinition rememberOverwrittenMethod:shadowedMethod inClass: shadowedMethod mclass.


    swizzledForwarderMethodSource := String streamContents:[ :s |
    	| selector keywords |

    	selector := shadowedMethod selector.
    	selector numArgs > 0 ifTrue:[
    	    keywords := selector keywords.
            keywords withIndexDo:[ :keyword :index |
                s nextPutAll: keyword; space; nextPutAll: 'arg'; nextPutAll: index printString; space.
            ].
    	] ifFalse:[
    	    s nextPutAll: selector; cr.
    	].

        s cr.
        s nextPutLine: '    "This method has been swizled by SmallSense, forwarding to SmallSense implementation"'.
        s nextPutAll:  '    ^ self '; nextPutAll: self name; nextPut: $_.
        selector numArgs > 0 ifTrue:[
            keywords withIndexDo:[ :keyword :index |
                s nextPutAll: keyword; space; nextPutAll: 'arg'; nextPutAll: index printString; space
            ].
    	] ifFalse:[
    	    s nextPutAll: selector.
    	].
    	s cr.

    ].

    "/ Stdout nextPutAll: '>>>'; nextPutLine: selector.
    "/ Stdout nextPutLine: '----'.
    "/ Stdout nextPutLine: swizzledForwarderMethodSource.
    "/ Stdout nextPutLine: '----'.


    shadowedMethodCopy := shadowedMethod copy.
    shadowedMethodCopy setPackage: #__swizzled__.
    shadowedMethodCopy setCategory: shadowedMethod category.
    shadowedMethodCopy source: ((shadowedMethod package copyReplaceAll: $: with: $_) replaceAll: $/ with: $_) , '_' , shadowedMethod source.
    shadowedMethod mclass
        basicAddSelector: (((shadowedMethod package copyReplaceAll: $: with: $_) replaceAll: $/ with: $_) , '_' , shadowedMethod selector) asSymbol
        withMethod: shadowedMethodCopy.


    "/ Install the swizzled method
    "/ Stdout nextPutLine: '^^^ Compiling'.
    swizzledForwarderMethod := ByteCodeCompiler compile: swizzledForwarderMethodSource forClass: cls install: false.
    swizzledForwarderMethod category: shadowedMethod category.
    swizzledForwarderMethod package: shadowedMethodCopy package.
    cls basicAddSelector:selector withMethod:swizzledForwarderMethod.

    "/ Stdout nextPutLine: '^^^ Compiled'.

    "Created: / 10-05-2014 / 00:23:24 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 07-10-2014 / 15:09:52 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!stx_goodies_smallsense class methodsFor:'documentation'!

version_HG

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

version_SVN
    ^ '$Id: stx_goodies_smallsense.st,v 1.2 2014/02/12 14:49:29 sr Exp $'
! !