Grafoscopio/repository/Grafoscopio/GrafoscopioTextFormatter.cl...

111 lines
3.8 KiB
Smalltalk

"
I am in charge of formatting a document in terms of text.
Our text model does not support break lines or tabbings as text attribute, but as text content. (By example, our header needs to have a line break before and after by default. This kind of things can be done in rubbric by adding the character cr. Still, our pillar AST does not have this breakline for the header, and we do not wan to add it, since it would affect the parsing. No, what we want is to be able to format and modify the text before returning it when being displayed, composed, scanned, etc. So for doing so we add the text formatter.
This text formatter contains a dictionary that allows the user to add as many as needed for each class.
This class provides as extention point:
#formatsFor: anObject > Returning a collection of formats for the given object (the default behaviour stores it by class).
#Redefine the specific visit methods for specific class behaviour.
)
"
Class {
#name : #GrafoscopioTextFormatter,
#superclass : #PRVisitor,
#instVars : [
'formats',
'stack'
],
#classInstVars : [
'default'
],
#category : 'Grafoscopio-Pillar'
}
{ #category : #accessing }
GrafoscopioTextFormatter class >> buildDefault [
| new |
new := self new.
new registerFormat: GrafoscopioFmtDoubleLinebreak instance forClass: PRHeader.
new registerFormat: GrafoscopioFmtAnchorOnTheLeft instance forClass: PRListItem.
new registerFormat: GrafoscopioFmtBeginningLinebreak instance forClass: PRListItem.
" new registerFormat: GrafoscopioFmtEndingLinebreak instance forClass: PRParagraph ."
new registerFormat: GrafoscopioFmtBeginningLinebreak instance forClass: PRList.
new registerFormat: GrafoscopioFmtUrlAsBody instance forClass: PRExternalLink .
new registerFormat: GrafoscopioFmtEndingSpace instance forClass: PRExternalLink.
new registerFormat: GrafoscopioFmtUrlAsBody instance forClass: PRMailLink.
new registerFormat: GrafoscopioFmtEndingSpace instance forClass: PRMailLink.
new registerFormat: GrafoscopioFmtAnchorAsBody instance forClass: PRInternalLink.
new registerFormat: GrafoscopioFmtEndingSpace instance forClass: PRInternalLink.
^ new
]
{ #category : #accessing }
GrafoscopioTextFormatter class >> buildEmpty [
| new |
new := self new.
^ new
]
{ #category : #accessing }
GrafoscopioTextFormatter class >> default [
^ self buildDefault
]
{ #category : #initialization }
GrafoscopioTextFormatter >> format: aNode [
(self formatsFor: aNode) do: [ :f | f beInstalledIn: aNode ].
]
{ #category : #initialization }
GrafoscopioTextFormatter >> formatsFor: aNode [
^ formats at: aNode ifAbsent: [ self formatsForClass: aNode class ]
]
{ #category : #initialization }
GrafoscopioTextFormatter >> formatsForClass: aNodeClass [
^ formats at: aNodeClass ifAbsent: [ Array empty ]
]
{ #category : #initialization }
GrafoscopioTextFormatter >> initialize [
super initialize .
formats := Dictionary new.
stack := Stack new.
]
{ #category : #initialization }
GrafoscopioTextFormatter >> registerFormat: aFormat for: aNode [
^ (formats at: aNode ifAbsentPut: [ OrderedCollection new ])
add: aFormat
]
{ #category : #initialization }
GrafoscopioTextFormatter >> registerFormat: aFormat forClass: aNodeClass [
^ self registerFormat: aFormat for: aNodeClass
]
{ #category : #initialization }
GrafoscopioTextFormatter >> visitDocument: aDocument [
self assert: stack isEmpty.
super visitDocument: aDocument.
self assert: stack isEmpty
]
{ #category : #initialization }
GrafoscopioTextFormatter >> visitDocumentGroup: aNode [
aNode parent: (stack ifNotEmpty: [stack first] ifEmpty:[ nil ]).
self format: aNode.
stack push: aNode.
super visitDocumentGroup: aNode.
stack pop
]
{ #category : #initialization }
GrafoscopioTextFormatter >> visitDocumentItem: anItem [
self format: anItem.
anItem parent: stack first.
]