Shout

PluggableShoutMorph
I am a subclass of PluggableTextMorph.
Instances of me are usually created using my #on:text:accept:readSelection:menu: class method.
In order to colour the text, I use an instance of SHTextStylerST80, which I store in my 'styler' instance variable.
When my setText: method is called, I use my styler to ...
a) optionally set all assignments to ansi or leftArrow.
b) Colour my text (immediately, if the text is less than 4096 chars in length, or in a backgroundProcess otherwise)
When my text is changed, my hasUnacceptedEdits: method is called with true, and I ask my styler to re-colour my text. This is performed in a background process so that typing remains responsive regardless of the length of the text.
Just before my styler is about to format/style the text, I send #stylerAboutToStyle: to my model. This gives my model a chance to veto the styling (by answering false), or to initialize the styler with information it needs in order to parse the text correctly (e.g. the class to which a method belongs, or the workspace in which I am contained).
My styler informs me that it has finished styling by triggering the #stylerStyled: and #stylerStyledInBackground: events which I handle. I then update the textAttributes of my text and refresh the display.

My 'unstyledAcceptText' instance variable is used in conjunction with my #acceptTextInModel and #correctFrom:to:with: methods to ensure that when my text is modified during a method compilation (removing unused vars etc), I do not lose those changes.
acceptTextInModel
Inform the model that the receiver's textMorph's text should be accepted.
Answer true if the model accepted ok, false otherwise
classOrMetaClass:
set the classOrMetaClass in the receiver's styler to aBehavior
correctFrom:to:with:
see the comment in #acceptTextInModel
environment:
set the environment in the receiver's styler to anObject
font:
hasUnacceptedEdits:
re-implemented to re-style the text iff aBoolean is true
initialize
initialize the state of the receiver
okToStyle
on:text:accept:readSelection:menu:
setText:
styler
styler:
stylerStyled:
stylerStyledInBackground:
It is possible that the text string has changed since the styling began. Disregard the styles if styledCopyOfText's string differs with the current textMorph contents string
textMorphClass
Answer the class used to create the receiver's textMorph
workspace:
set the workspace in the receiver's styler to anObject
SHParserST80
I am a Smalltalk method / expression parser.
Rather than creating an Abstract Syntax Tree, I create a sequence of SHRanges (in my 'ranges' instance variable), which represent the tokens within the String I am parsing.
I am used by a SHTextStylerST80 to parse method source strings.
I am able to parse incomplete / incorrect methods, and so can be used to parse methods that are being edited.
My 'source' instance variable should be set to the string to be parsed.
My 'classOrMetaClass' instance var must be set to the class or metaClass for the method source so that I can correctly resolve identifiers within the source. If this is nil , I parse the source as an expression (i.e. a doIt expression).
My 'workspace' instance variable can be set to a Workspace, so that I can resolve workspace variables.
My 'environment' instance variable is the global namespace (this is initialized to Smalltalk, but can be set to a different environment).
Example 1.
ranges := SHParserST80 new
classOrMetaClass: Object;
source: 'testMethod ^self';
parse;
ranges
classOrMetaClass:
currentChar
enterBlock
environment:
error
Throw a generic Error exception.
failUnless:
failWhen:
initialize
Subclasses should redefine this method to perform initializations on instance creation
initializeInstanceVariables
isAnsiAssignment
isAssignment
isBigDigit:base:
Answer true if aCharacter is a digit or a capital
letter appropriate for base anInteger
isBinary
isBlockArgName:
Answer true if aString is the name of a block argument, false otherwise
isBlockTempName:
Answer true if aString is the name of a block temporary. false otherwise
isIncompleteBlockArgName:
Answer true if aString is the start of the name of a block argument, false otherwise
isIncompleteBlockTempName:
Answer true if aString is the start of the name of a block temporary. false otherwise
isIncompleteMethodArgName:
Answer true if aString is the start of the name of a method argument, false otherwise.
Does not check whether aString is also a blockArgName
isIncompleteMethodTempName:
Answer true if aString is the start of then name of a method temporary, false otherwise.
isKeyword
isMethodArgName:
Answer true if aString is the name of a method argument, false otherwise.
Does not check whether aString is also a blockArgName
isMethodTempName:
Answer true if aString is the name of a method temporary, false otherwise.
Does not check whether aString is also a block temporary
or argument
isName
isSelectorCharacter:
isTokenExternalFunctionCallingConvention
leaveBlock
new
nextChar
parse
Parse the receiver's text as a Smalltalk method
parse:
Parse the receiver's text. If isAMethod is true
then treat text as a method, if false as an
expression with no message pattern
parseArray
parseBinary
parseBinaryMessagePattern
parseBlock
parseBlockArguments
parseBlockTemporaries
parseBraceArray
parseByteArray
parseCascade
parseCharSymbol
parseExpression
parseExternalCall
parseKeyword
parseKeywordMessagePattern
parseLiteral:
parseLiteralArrayElement
parseMessagePattern
parseMethodTemporaries
parsePragmaBinary
parsePragmaKeyword
parsePragmaSequence
parsePrimitive
parseStatement
parseStatementList
parseStatementListForBraceArray
same as parseStatementList, but does not allow empty statements e.g {...$a...}.
A single terminating . IS allowed e.g. {$a.}
parseString
parseSymbol
parseSymbolIdentifier
parseSymbolSelector
parseSymbolString
parseTerm
parseUnary
parseUnaryMessagePattern
peekChar
pushArgument:
pushTemporary:
rangeType:
rangeType:start:end:
rangesIn:classOrMetaClass:workspace:environment:
resolve:
resolvePartial:
check if any identifier begins with aString
resolvePartialPragmaArgument:
check if any valid pragma argument begins with aString
resolvePragmaArgument:
scanBinary
scanComment
scanIdentifier
scanNext
scanNumber
scanPast:
record rangeType for current token .
record argument and temp declarations.
scan and answer the next token
scanPast:level:
first level adds no suffix to the rangeType.
Suffix from 1 to 7 added in cycles , ((level-2) mod(7) + 1)
scanPast:start:end:
record rangeType for current token from startInteger to endInteger,
and scanNext token
scanWhitespace
skipBigDigits:
skipDigits
source
source:
workspace:
SHRange
I associate a type with a range of characters in a String
I have these instance variables...
start - the one based index of the first character of the range within the String.
end - the one based index of the last character of the range within the String.
type - a Symbol describing the type of the range

A sequence of instances of me are created by an instance of SHParserST80 which can then used by an instance of SHTextStyler to style Text.
asType
end
end:
includesPosition:
isArgument
isAssignment
isBinary
isBlockEnd
isBlockStart
isBlockTemporary
isClassVariable
isComment
isConstant
isGlobal
isInstanceVariable
isKeyword
isOpening
isSelf
isSeparator
isSuper
isTemporaryVariable
isUnfinished
isVariable
isVariablesOnly
length
start
start:
start:end:type:
type
type:
SHTextStyler
I am an Abstract class.
Subclasses of me can create formatted, coloured, and styled copies of Text that is given to them.
They may perform their styling asynchronously, in a background process which I create and manage.
My public interface is...
view: aViewOrMorph - set the view that will receive notifications when styling has completed.

format: aText - modifies aText's string
style: aText - modifies the TextAttributes of aText, but does not change the string, then sends #stylerStyled: to the view.
styleInBackgroundProcess: aText - performs style: in a background process, then sends #stylerStylednBackground: to the view.
styledTextFor: aText - answers a formatted and styled copy of aText
unstyledTextFrom: aText - answers a copy of aText with all TextAttributes removed
Subclasses of me should re-implement...
privateFormat: aText - answer a formatted version of aText; the String may be changed
privateStyle: aText - modify the TextAttributes of aText; but do not change the String


evaluateWithoutStyling:
format:
Answer a copy of <aText> which has been reformatted,
or <aText> if no formatting is to be applied
initialize
Subclasses should redefine this method to perform initializations on instance creation
monitor
new
privateFormat:
privateStyle:
style:
styleInBackgroundProcess:
styledTextFor:
Answer a copy of aText that is both formatted and styled
terminateBackgroundStylingProcess
unstyledTextFrom:
view:
SHTextStylerST80
I style Smalltalk methods and expressions.
My 'styleTable' class instance var holds an array ofArrays which control how each token is styled/coloured. See my defaultStyleTable class method for its structure.
My styleTable can be changed by either modifying the defaultStyleTable class method and then executing SHTextStylerST80 initialize ; or by giving me a new styleTable through my #styleTable: class method.
My 'textAttributesByPixelSize' class instance var contains a dictionary of dictionaries.
The key is a pixelSize and the value a Dictionary from token type Symbol to TextAttribute array.
It is created/maintained automatically.

I also install these 3 preferences when my class initialize method is executed....
#syntaxHighlightingAsYouType - controls whether methods are styled in browsers
#syntaxHighlightingAsYouTypeAnsiAssignment - controls whether assignments are formatted to be :=
#syntaxHighlightingAsYouTypeLeftArrowAssignment - controls whether assignments are formatted to be _
I reimplement #unstyledTextFrom: so that TextActions are preserved in the unstyled text





attributeArrayForColor:emphasis:font:
attributesFor:
attributesFor:pixelHeight:
classOrMetaClass:
defaultStyleTable
environment:
font:
initialTextAttributesForPixelHeight:
initialize
Subclasses should redefine this method to perform initializations on instance creation
initializePreferences
parseableSourceCodeTemplate
pixelHeight
In Morphic the receiver will have been given a code font, in MVC the font will be nil. So when the font is nil, answer the pixelHeight of the MVC Browsers' code font, i.e. TextStyle defaultFont pixelHeight
privateFormat:
Perform any formatting of aText necessary and answer either aText, or a formatted copy of aText
privateStyle:
rangesIn:setWorkspace:
Answer a collection of SHRanges by parsing aText.
When formatting it is not necessary to set the workspace, and this can make the parse take less time, so aBoolean specifies whether the parser should be given the workspace
removeObsoletePreferences
setAttributesIn:fromRanges:
sourceMap:
Deprecated. This method stub is left so that classes that used earlier versions of Shout will continue to function
styleTable
styleTable:
textAttributesByPixelHeight
unstyledTextFrom:
Re-implemented so that TextActions are not removed from aText
workspace:
TextMorphForShout
A TextMorphForShout is xxxxxxxxx.
Instance Variables
editorClass
Answer the class used to create the receiver's editor
TextMorphForShoutEditor
A TextMorphForShoutEditor is xxxxxxxxx.
Instance Variables
inBackTo: <Object>
inBackTo
- xxxxx
backTo:
When backspacing, 2 notifications of the userHasEdited are received.
This then causes a background process to not terminate correctly.
The reason for all this is uncertain, but discarding the superfluous userHasEdited
message received while running backTo: seems to cure the problem
blinkParen
changeEmphasis:
clearParens
userHasEdited
ignore this if generated during backTo:
See comment in backTo: