Indentation fixes for electric-inserted code.
"{ Package: 'jv:smallsense' }"
"{ NameSpace: SmallSense }"
Object subclass:#EditSupport
instanceVariableNames:'service textView backspaceIsUndo completionController snippets'
classVariableNames:''
poolDictionaries:''
category:'SmallSense-Core-Services'
!
!EditSupport class methodsFor:'instance creation'!
forLanguage: aProgrammingLanguage
aProgrammingLanguage notNil ifTrue:[
aProgrammingLanguage isSmalltalk ifTrue:[
^ SmalltalkEditSupport new
].
(aProgrammingLanguage askFor: #isJava) ifTrue:[
^ JavaEditSupport new
].
(aProgrammingLanguage askFor: #isGroovy) ifTrue:[
^ GroovyEditSupport new
]
].
^GenericEditSupport new.
"Created: / 24-07-2013 / 23:20:31 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 04-10-2013 / 08:41:09 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!EditSupport methodsFor:'accessing'!
language
^ self subclassResponsibility.
"Created: / 24-07-2013 / 23:44:51 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
service
^ service
! !
!EditSupport methodsFor:'accessing-classes'!
completionEngineClass
"Returns a code completion engine class or nil, of
no completion is supported"
^ nil
"Created: / 03-10-2013 / 17:43:47 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
scannerClass
"Returns a class to use for scanning lines. If nil, scanning is
not supported and scanLine* methods will return an empty array."
^ nil
"Created: / 22-10-2013 / 00:33:11 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!EditSupport methodsFor:'editing'!
insertDo: aBlock
textView completionSupport notNil ifTrue:[
textView completionSupport
stopCompletionProcess;
closeCompletionView.
].
textView hasSelection ifTrue:[
textView undoableDo:[
textView deleteSelection
].
].
textView undoableDo: [
aBlock value.
].
backspaceIsUndo := true.
"Created: / 17-09-2013 / 23:15:46 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 22-10-2013 / 03:15:25 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
insertElectric: text
self insertElectric:text advanceCursorBy:nil.
"Created: / 22-10-2013 / 11:08:19 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
insertElectric:stringOrLines advanceCursorBy:offsetOrNil
"Insert given stringOrLines. If offsetOrNil is not nil, then
move cursor by `offsetOrNil` character after **begining** of
inserted text.
`stringOrLines` could be either string or collection of strings (lines)
`offsetOrNil` could be either integer (cursor is then advanced by
offsetOrNil characters after **begining** of inserted text)
or point (x,y, cursor is then advanced by x lines after current
line and by y characters after beggining of the inserted text
(if x == 0) or at set at column y (if x ~~ 0)
"
| lineOffset colOffset newCursorCol newCursorLine advanceCursor |
advanceCursor := false.
offsetOrNil notNil ifTrue:[
lineOffset := offsetOrNil isPoint ifTrue:[offsetOrNil x] ifFalse:[0].
colOffset := offsetOrNil isPoint ifTrue:[offsetOrNil y] ifFalse:[offsetOrNil].
newCursorLine := textView cursorLine + lineOffset.
newCursorCol := (lineOffset == 0 ifTrue:[textView cursorCol] ifFalse:[0]) + colOffset.
advanceCursor := true.
].
self
insertDo:[
stringOrLines isString ifTrue:[
"/ Simple string...
textView insertStringAtCursor:stringOrLines.
] ifFalse:[
"/ Couple lines...
textView
insertLines: stringOrLines
withCR: false.
].
advanceCursor ifTrue:[
(textView cursorLine ~~ newCursorLine or:[textView cursorCol ~~ newCursorCol]) ifTrue:[
textView cursorLine: newCursorLine col: newCursorCol.
].
].
].
"Created: / 22-10-2013 / 11:56:43 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 19-11-2013 / 12:30:52 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
insertElectricBlockOpenedBy: openText closedBy: closeText
| indent lines autoIndent |
textView completionSupport notNil ifTrue:[
textView completionSupport
stopCompletionProcess;
closeCompletionView.
].
indent := self indentAtCursorLine.
autoIndent := textView autoIndent.
textView autoIndent: false.
[
textView undoableDo:[
lines := Array
with: openText ? ''
with: ''
with: ((String new:indent withAll:Character space) , closeText ).
self insertElectric: lines advanceCursorBy: 1 @ (indent + 5)
"/ textView insertStringAtCursor: (openText ? '') , Character cr , Character cr, , closeText , Character cr.
"/ line := textView cursorLine - 1.
"/ col := textView cursorCol + 3.
"/ textView cursorLine: line col: col.
].
] ensure:[
textView autoIndent: autoIndent
].
"Created: / 25-07-2013 / 10:41:50 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 19-11-2013 / 12:29:49 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
insertElectricSnippet
^ false
"Created: / 22-10-2013 / 01:54:10 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!EditSupport methodsFor:'event handling'!
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."
key == Character space ifTrue:[
^ self insertElectricSnippet
].
^false
"Created: / 24-07-2013 / 23:31:46 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 22-10-2013 / 01:56:45 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
keyPressSpace
^ self insertElectricSnippet
"Created: / 22-10-2013 / 01:43:46 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!EditSupport methodsFor:'initialization'!
initializeCompletion
self completionEngineClass notNil ifTrue:[
completionController := CompletionController for: service textView.
completionController support: self.
service textView completionSupport: completionController.
].
"Created: / 27-09-2013 / 13:20:30 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 03-10-2013 / 17:44:32 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
initializeForService:aSmallSenseService
service := aSmallSenseService.
textView := aSmallSenseService textView.
backspaceIsUndo := false.
self initializeCompletion.
"Created: / 27-09-2013 / 13:19:20 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 03-10-2013 / 17:44:15 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!EditSupport methodsFor:'private'!
indentAtCursorLine
| line |
line := service textView listAt: service textView cursorLine.
^ line isNil ifTrue:[
(service textView cursorCol - 1) max: 0.
] ifFalse:[
(line indexOfNonSeparator - 1) max: 0.
]
"Created: / 25-07-2013 / 00:13:33 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 25-10-2013 / 18:04:37 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
wordBeforeCursor
| currentLine wordStart wordEnd |
currentLine := textView list at: textView cursorLine.
currentLine isNil ifTrue:[ ^ '' ].
wordEnd := textView cursorCol - 1.
wordEnd > currentLine size ifTrue:[ ^ '' ].
wordEnd ~~ 0 ifTrue:[
wordStart := wordEnd.
[ wordStart > 0 and:[(currentLine at: wordStart) isAlphaNumeric] ] whileTrue:[
wordStart := wordStart - 1.
].
wordStart := wordStart + 1.
wordStart <= wordEnd ifTrue:[
^ currentLine copyFrom: wordStart to: wordEnd.
].
].
^ ''
"Created: / 27-09-2013 / 15:53:40 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 17-10-2013 / 00:48:05 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!EditSupport methodsFor:'private-completion'!
computeCompletion
| completionEngineClass codeView result |
completionEngineClass := self completionEngineClass.
completionEngineClass isNil ifTrue: [ ^ nil ].
codeView := service codeView.
UserInformation
handle: [:ex |
codeView showInfo: (ex messageText).
ex proceed.
]
do: [
result := completionEngineClass new completeFor: codeView
].
^ result.
"Created: / 27-09-2013 / 13:21:52 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 02-10-2013 / 13:31:54 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!EditSupport methodsFor:'private-scanning'!
scanLineAt: lineNumber
"Scans line at given line number.
Returns and array of tokens, **excluding** EOF. Each token is represented
by four subsequent items in the array: token type, token value, start position, end position.
Thus, returned array size is always multiple of 4."
^ self scanLineAt: lineNumber using: self scannerClass
"Created: / 22-10-2013 / 00:34:15 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
scanLineAt: lineNumber using: scannerClass
"Scans line at given line number using given scanner class.
Returns and array of tokens, **excluding** EOF. Each token is represented
by four subsequent items in the array: token type, token value, start position, end position.
Thus, returned array size is always multiple of 4."
| line scanner token tokenLastEndPosition |
scannerClass isNil ifTrue:[ ^ #() ].
line := (service textView listAt: service textView cursorLine).
line isNil ifTrue:[ ^ #() ].
scanner := scannerClass for: line string.
tokenLastEndPosition := 0.
^ OrderedCollection streamContents:[:tokens |
[
[ token := scanner nextToken.token ~~ #EOF ] whileTrue:[
tokens
nextPut: token;
nextPut: (scanner tokenName notNil ifTrue:[scanner tokenName] ifFalse:[ scanner tokenValue printString ]);
nextPut: scanner tokenStartPosition;
nextPut: (tokenLastEndPosition := scanner tokenEndPosition).
].
] on: Error do:[
tokens
nextPut: 'Error';
nextPut: (line copyFrom: tokenLastEndPosition + 1 to: line size);
nextPut: tokenLastEndPosition + 1;
nextPut: line size.
].
].
"Created: / 22-10-2013 / 00:31:02 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 22-10-2013 / 12:01:53 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
scanLineAtCursor
"Scans current cursor line.
Returns and array of tokens, **excluding** EOF. Each token is represented
by four subsequent items in the array: token type, token value, start position, end position.
Thus, returned array size is always multiple of 4."
^ self scanLineAt: service codeView textView cursorLine using: self scannerClass
"Created: / 22-10-2013 / 00:34:47 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!EditSupport class methodsFor:'documentation'!
version_HG
^ '$Changeset: <not expanded> $'
! !