Fixing data folder for Windows.

This commit is contained in:
Offray Vladimir Luna Cardenas 2022-11-03 16:19:56 -05:00
parent 77404b9b31
commit 06b18c4e50
19 changed files with 1628 additions and 1625 deletions

View File

@ -1,164 +1,164 @@
Extension { #name : #LeDatabase }
{ #category : #'*MiniDocs' }
LeDatabase >> addPageFromMarkdeep: markdeepDocTree withRemote: externalDocLocation [
| remoteMetadata divSnippets snippets page |
divSnippets := (markdeepDocTree xpath: '//div[@st-class]') asOrderedCollection
collect: [ :xmlElement | xmlElement postCopy ].
snippets := divSnippets
collect: [ :xmlElement |
(xmlElement attributes at: 'st-class') = 'LeTextSnippet'
ifTrue: [ LeTextSnippet new contentFrom: xmlElement ]
ifFalse: [ (xmlElement attributes at: 'st-class') = 'LePharoSnippet'
ifTrue: [ LePharoSnippet new contentFrom: xmlElement ] ] ].
remoteMetadata := Markdeep new metadataFromXML: markdeepDocTree.
page := LePage new
title: (remoteMetadata at: 'title');
basicUid: (UUID fromString36: (remoteMetadata at: 'id'));
createTime: (LeTime new time: (remoteMetadata at: 'created') asDateAndTime);
editTime: (LeTime new time: (remoteMetadata at: 'modified') asDateAndTime);
latestEditTime: (LeTime new time: (remoteMetadata at: 'modified') asDateAndTime);
createEmail: (LeEmail new email: (remoteMetadata at: 'creator'));
editEmail: (LeEmail new email: (remoteMetadata at: 'modifier')).
snippets do: [ :snippet | page addSnippet: snippet ].
page children
do: [ :snippet |
(self hasBlockUID: snippet uid)
ifTrue: [ | existingPage |
existingPage := self pages
detect: [ :pageTemp | pageTemp includesSnippetUid: snippet uid ].
self importErrorForLocal: existingPage withRemote: externalDocLocation.
^ self ]
ifFalse: [ snippet database: self.
self registerSnippet: snippet ] ].
self addPage: page.
^ page
]
{ #category : #'*MiniDocs' }
LeDatabase >> addPageFromMarkdeepUrl: aString [
| page |
page := self detectLocalPageForRemote: aString.
page
ifNotNil: [ :arg |
self importErrorForLocal: page withRemote: aString.
^ self ].
^ self addPageFromMarkdeep: (self docTreeForLink: aString) withRemote: aString
]
{ #category : #'*MiniDocs' }
LeDatabase >> detectLocalPageForRemote: markdeepDocUrl [
| markdeepHelper id remoteMetadata docTree |
markdeepHelper := Markdeep new.
docTree := self docTreeForLink: markdeepDocUrl.
remoteMetadata := markdeepHelper metadataFromXML: docTree.
id := remoteMetadata at: 'id' ifAbsent: [ nil ].
^ self pageWithID: id ifAbsent: [ ^ nil ].
]
{ #category : #'*MiniDocs' }
LeDatabase >> docTreeForLink: aString [
^ (XMLHTMLParser on: aString asUrl retrieveContents) parseDocument
]
{ #category : #'*MiniDocs' }
LeDatabase >> errorCardFor: error [
| keepButton overwriteButton backupButton errorMessageUI localPage errorKey |
errorKey := error keys first.
localPage := self pageWithID: errorKey.
keepButton := BrButton new
aptitude: BrGlamorousButtonWithIconAndLabelAptitude;
label: 'Keep existing local page';
icon: BrGlamorousVectorIcons cancel;
margin: (BlInsets left: 10);
action: [ :aButton |
aButton phlow spawnObject: localPage.
self errors removeKey: errorKey
].
overwriteButton := BrButton new
aptitude: BrGlamorousButtonWithIconAndLabelAptitude;
label: 'Overwrite with remote page';
icon: BrGlamorousVectorIcons edit;
action: [ :aButton |
self removePage: localPage.
aButton phlow spawnObject: (self addPageFromMarkdeepUrl: (error at: errorKey at: 'remote')).
self errors removeKey: errorKey
];
margin: (BlInsets left: 10).
backupButton := BrButton new
aptitude: BrGlamorousButtonWithIconAndLabelAptitude;
label: 'Backup local page';
icon: BrGlamorousVectorIcons changes;
action: [ :aButton | ];
margin: (BlInsets left: 10).
errorMessageUI := BrEditor new
aptitude: BrGlamorousRegularEditorAptitude new ;
text: (error at: errorKey at: 'message');
vFitContent.
^ { errorMessageUI. keepButton. overwriteButton. backupButton }
]
{ #category : #'*MiniDocs' }
LeDatabase >> errors [
^ self optionAt: 'errors' ifAbsentPut: [ Dictionary new ]
]
{ #category : #'*MiniDocs' }
LeDatabase >> gtViewErrorDetailsOn: aView [
<gtView>
^ aView explicit
title: 'Errors' translated;
priority: 5;
stencil: [ | container |
container := BlElement new
layout: BlFlowLayout new;
constraintsDo: [ :c |
c vertical fitContent.
c horizontal matchParent ];
padding: (BlInsets all: 10).
container
addChildren: (self errorCardFor: self errors)
].
]
{ #category : #'*MiniDocs' }
LeDatabase >> importErrorForLocal: page withRemote: externalDocLocation [
| message id error |
id := page uidString.
message := String streamContents: [ :stream |
stream
nextPutAll: 'IMPORTATION ERROR: A page with
';
nextPut: Character lf;
nextPutAll: ' id: ' , id;
nextPut: Character lf;
nextPutAll: ' title: ' , page contentAsString;
nextPut: Character lf;
nextPut: Character lf;
nextPutAll: 'already exists in this database and includes overlapping contents';
nextPut: Character lf;
nextPutAll: 'with the page you are trying to import from:
';
nextPut: Character lf;
nextPutAll: externalDocLocation;
nextPut: Character lf;
nextPut: Character lf;
nextPutAll:
'Please choose one of the following options to addres the issue:
' ].
error := Dictionary new
at: 'remote' put: externalDocLocation;
at: 'message' put: message ;
yourself.
self errors at: id put: error
]
{ #category : #'*MiniDocs' }
LeDatabase >> options [
^ options
]
Extension { #name : #LeDatabase }
{ #category : #'*MiniDocs' }
LeDatabase >> addPageFromMarkdeep: markdeepDocTree withRemote: externalDocLocation [
| remoteMetadata divSnippets snippets page |
divSnippets := (markdeepDocTree xpath: '//div[@st-class]') asOrderedCollection
collect: [ :xmlElement | xmlElement postCopy ].
snippets := divSnippets
collect: [ :xmlElement |
(xmlElement attributes at: 'st-class') = 'LeTextSnippet'
ifTrue: [ LeTextSnippet new contentFrom: xmlElement ]
ifFalse: [ (xmlElement attributes at: 'st-class') = 'LePharoSnippet'
ifTrue: [ LePharoSnippet new contentFrom: xmlElement ] ] ].
remoteMetadata := Markdeep new metadataFromXML: markdeepDocTree.
page := LePage new
title: (remoteMetadata at: 'title');
basicUid: (UUID fromString36: (remoteMetadata at: 'id'));
createTime: (LeTime new time: (remoteMetadata at: 'created') asDateAndTime);
editTime: (LeTime new time: (remoteMetadata at: 'modified') asDateAndTime);
latestEditTime: (LeTime new time: (remoteMetadata at: 'modified') asDateAndTime);
createEmail: (LeEmail new email: (remoteMetadata at: 'creator'));
editEmail: (LeEmail new email: (remoteMetadata at: 'modifier')).
snippets do: [ :snippet | page addSnippet: snippet ].
page children
do: [ :snippet |
(self hasBlockUID: snippet uid)
ifTrue: [ | existingPage |
existingPage := self pages
detect: [ :pageTemp | pageTemp includesSnippetUid: snippet uid ].
self importErrorForLocal: existingPage withRemote: externalDocLocation.
^ self ]
ifFalse: [ snippet database: self.
self registerSnippet: snippet ] ].
self addPage: page.
^ page
]
{ #category : #'*MiniDocs' }
LeDatabase >> addPageFromMarkdeepUrl: aString [
| page |
page := self detectLocalPageForRemote: aString.
page
ifNotNil: [ :arg |
self importErrorForLocal: page withRemote: aString.
^ self ].
^ self addPageFromMarkdeep: (self docTreeForLink: aString) withRemote: aString
]
{ #category : #'*MiniDocs' }
LeDatabase >> detectLocalPageForRemote: markdeepDocUrl [
| markdeepHelper id remoteMetadata docTree |
markdeepHelper := Markdeep new.
docTree := self docTreeForLink: markdeepDocUrl.
remoteMetadata := markdeepHelper metadataFromXML: docTree.
id := remoteMetadata at: 'id' ifAbsent: [ nil ].
^ self pageWithID: id ifAbsent: [ ^ nil ].
]
{ #category : #'*MiniDocs' }
LeDatabase >> docTreeForLink: aString [
^ (XMLHTMLParser on: aString asUrl retrieveContents) parseDocument
]
{ #category : #'*MiniDocs' }
LeDatabase >> errorCardFor: error [
| keepButton overwriteButton backupButton errorMessageUI localPage errorKey |
errorKey := error keys first.
localPage := self pageWithID: errorKey.
keepButton := BrButton new
aptitude: BrGlamorousButtonWithIconAndLabelAptitude;
label: 'Keep existing local page';
icon: BrGlamorousVectorIcons cancel;
margin: (BlInsets left: 10);
action: [ :aButton |
aButton phlow spawnObject: localPage.
self errors removeKey: errorKey
].
overwriteButton := BrButton new
aptitude: BrGlamorousButtonWithIconAndLabelAptitude;
label: 'Overwrite with remote page';
icon: BrGlamorousVectorIcons edit;
action: [ :aButton |
self removePage: localPage.
aButton phlow spawnObject: (self addPageFromMarkdeepUrl: (error at: errorKey at: 'remote')).
self errors removeKey: errorKey
];
margin: (BlInsets left: 10).
backupButton := BrButton new
aptitude: BrGlamorousButtonWithIconAndLabelAptitude;
label: 'Backup local page';
icon: BrGlamorousVectorIcons changes;
action: [ :aButton | ];
margin: (BlInsets left: 10).
errorMessageUI := BrEditor new
aptitude: BrGlamorousRegularEditorAptitude new ;
text: (error at: errorKey at: 'message');
vFitContent.
^ { errorMessageUI. keepButton. overwriteButton. backupButton }
]
{ #category : #'*MiniDocs' }
LeDatabase >> errors [
^ self optionAt: 'errors' ifAbsentPut: [ Dictionary new ]
]
{ #category : #'*MiniDocs' }
LeDatabase >> gtViewErrorDetailsOn: aView [
<gtView>
^ aView explicit
title: 'Errors' translated;
priority: 5;
stencil: [ | container |
container := BlElement new
layout: BlFlowLayout new;
constraintsDo: [ :c |
c vertical fitContent.
c horizontal matchParent ];
padding: (BlInsets all: 10).
container
addChildren: (self errorCardFor: self errors)
].
]
{ #category : #'*MiniDocs' }
LeDatabase >> importErrorForLocal: page withRemote: externalDocLocation [
| message id error |
id := page uidString.
message := String streamContents: [ :stream |
stream
nextPutAll: 'IMPORTATION ERROR: A page with
';
nextPut: Character lf;
nextPutAll: ' id: ' , id;
nextPut: Character lf;
nextPutAll: ' title: ' , page contentAsString;
nextPut: Character lf;
nextPut: Character lf;
nextPutAll: 'already exists in this database and includes overlapping contents';
nextPut: Character lf;
nextPutAll: 'with the page you are trying to import from:
';
nextPut: Character lf;
nextPutAll: externalDocLocation;
nextPut: Character lf;
nextPut: Character lf;
nextPutAll:
'Please choose one of the following options to addres the issue:
' ].
error := Dictionary new
at: 'remote' put: externalDocLocation;
at: 'message' put: message ;
yourself.
self errors at: id put: error
]
{ #category : #'*MiniDocs' }
LeDatabase >> options [
^ options
]

View File

@ -1,218 +1,218 @@
Extension { #name : #LePage }
{ #category : #'*MiniDocs' }
LePage >> asHtmlFile [
self asMarkdownFile.
self defaultPandocTemplate exists
ifFalse: [ MarkupFile installTemplate: 'https://mutabit.com/repos.fossil/mutabit/doc/trunk/plantillas/Pandoc/clean-menu-mod.html' into: self defaultPandocTemplate parent ].
OSSUnixSubprocess new
command: 'pandoc' ;
arguments: {
self markdownFileName. '-o'. self htmlFileName .
'--toc' .
'--template=', self defaultPandocTemplate basenameWithoutExtension };
workingDirectory: self storage fullName;
runAndWaitOnExitDo: [ :process :outString | ^ self storage / self htmlFileName].
]
{ #category : #'*MiniDocs' }
LePage >> asMarkdeep [
| bodyStream markdeep |
bodyStream := '' writeStream.
self preorderTraversal do: [:snippet |
bodyStream nextPutAll: snippet asMarkdeep
].
markdeep := Markdeep new
title: self title;
body: bodyStream contents;
navTop: self navTop.
self metadata keysAndValuesDo: [:k :v |
k = 'lang'
ifTrue: [
markdeep head
add: '<meta lang="', v,'">';
yourself.
]
ifFalse: [
markdeep head
add: '<meta name="', k, '" content="', v,'">';
yourself.
]
].
self metadata at: 'authors' ifPresent: [:author | markdeep metadata at: 'authors' put: author ].
self metadata at: 'version' ifPresent: [:version | markdeep metadata at: 'version' put: version ].
^ markdeep.
]
{ #category : #'*MiniDocs' }
LePage >> asMarkdeepFile [
| folder |
folder := self options at: 'storage' ifAbsent: [ FileLocator temp ].
^ self asMarkdeep exportAsFileOn: folder / self markdeepFileName
]
{ #category : #'*MiniDocs' }
LePage >> asMarkdown [
| bodyStream markdown |
bodyStream := '' writeStream.
bodyStream
nextPutAll: '---';
nextPutAll: String lf.
self metadata keysAndValuesDo: [ :k :v |
bodyStream
nextPutAll: k , ': "' , v, '"';
nextPutAll: String lf ].
bodyStream nextPutAll: '---' , String lf , String lf.
self preorderTraversal
do: [ :snippet | bodyStream nextPutAll: snippet asMarkdown ].
markdown := Markdown new contents: bodyStream contents.
^ markdown
]
{ #category : #'*MiniDocs' }
LePage >> asMarkdownFile [
| folder |
folder := self options at: 'storage' ifAbsent: [ FileLocator temp ].
^ MarkupFile exportAsFileOn: folder / self markdownFileName containing: self asMarkdown contents
]
{ #category : #'*MiniDocs' }
LePage >> defaultPandocTemplate [
^ FileLocator home / '.pandoc' / 'templates' / 'clean-menu-mod.html'
]
{ #category : #'*MiniDocs' }
LePage >> detectParentSnippetWithUid: uidString [
"Answer a boolean indicating whether the supplied uid is present"
^ self preorderTraversal detect: [ :snippet | snippet uidString = uidString ] ifNone: [ ^ self ]
]
{ #category : #'*MiniDocs' }
LePage >> exportedFileName [
| sanitized |
sanitized := self title asDashedLowercase copyWithoutAll: #($/).
^ sanitized , '--' , (self uidString copyFrom: 1 to: 5)
]
{ #category : #'*MiniDocs' }
LePage >> fromMarkdeepUrl: aString [
| docTree pageMetadata |
docTree := GrafoscopioUtils xmlFromUrl: aString.
pageMetadata := Markdeep new metadataFromXML: docTree.
self
basicUid: (pageMetadata at: 'id');
title: (pageMetadata at: 'title');
createTime: (pageMetadata at: 'created') asDateAndTime;
editTime: (pageMetadata at: 'modified') asDateAndTime;
createEmail: (pageMetadata at: 'creator');
editEmail: (pageMetadata at: 'modifier');
optionAt: 'metadata' put: pageMetadata.
self populateChildrenFrom: (docTree xpath: '//div')
]
{ #category : #'*MiniDocs' }
LePage >> htmlFileName [
^ self exportedFileName, '.html'
]
{ #category : #'*MiniDocs' }
LePage >> latestEditTime: aLeTime [
"Used for adding a LePage to database from a shared markdeep LePage version."
latestEditTime := aLeTime
]
{ #category : #'*MiniDocs' }
LePage >> markdeepFileName [
^ self markdownFileName , '.html'
]
{ #category : #'*MiniDocs' }
LePage >> markdownFileName [
^ self exportedFileName, '.md'
]
{ #category : #'*MiniDocs' }
LePage >> metadata [
^ self options at: 'metadata' ifAbsentPut: [ self metadataInit]
]
{ #category : #'*MiniDocs' }
LePage >> metadataInit [
^ OrderedDictionary new
at: 'id' put: self uidString;
at: 'title' put: self contentAsString;
at: 'created' put: self createTime greaseString;
at: 'modified' put: self latestEditTime greaseString;
at: 'creator' put: self createEmail greaseString;
at: 'modifier' put: self editEmail greaseString;
yourself
]
{ #category : #'*MiniDocs' }
LePage >> navTop [
| topNavFile |
topNavFile := ((self optionAt: 'storage' ifAbsentPut: [ FileLocator temp ]) / '_navtop.html').
topNavFile exists
ifFalse: [ ^ '' ]
ifTrue: [ ^ topNavFile contents ]
]
{ #category : #'*MiniDocs' }
LePage >> options [
^ options
]
{ #category : #'*MiniDocs' }
LePage >> preorderTraversal [
| output |
output := OrderedCollection new.
self withDeepCollect: [:each | each allChildrenBreadthFirstDo: [:child | output add: child]].
^ output.
]
{ #category : #'*MiniDocs' }
LePage >> removeSnippetsMetadata [
self preorderTraversal do: [ :snippet |
(snippet options isNotNil and: [ snippet options includesKey: 'metadata' ])
ifTrue: [ snippet options removeKey: 'metadata' ] ]
]
{ #category : #'*MiniDocs' }
LePage >> sharedVariablesBindings [
| codeSnippets shared |
codeSnippets := self preorderTraversal select: [:snippet |
snippet class = LePharoSnippet and: [ snippet code includesSubstring: ':=']
].
codeSnippets first in: [:snippet | | context |
context := snippet coder evaluationContext.
snippet coder doItInContext: context.
shared := context bindingStrategy bindings detect: [:each |
each isKindOf: GtSharedVariablesBindings
]
].
codeSnippets asArray allButFirstDo: [:snippet| | context|
context := snippet coder evaluationContext.
context addBindings: shared.
snippet coder doItInContext: context
].
^ shared asDictionary
]
{ #category : #'*MiniDocs' }
LePage >> storage [
^ self optionAt: 'storage'
ifAbsent: [ ^ FileLocator temp ]
]
Extension { #name : #LePage }
{ #category : #'*MiniDocs' }
LePage >> asHtmlFile [
self asMarkdownFile.
self defaultPandocTemplate exists
ifFalse: [ MarkupFile installTemplate: 'https://mutabit.com/repos.fossil/mutabit/doc/trunk/plantillas/Pandoc/clean-menu-mod.html' into: self defaultPandocTemplate parent ].
OSSUnixSubprocess new
command: 'pandoc' ;
arguments: {
self markdownFileName. '-o'. self htmlFileName .
'--toc' .
'--template=', self defaultPandocTemplate basenameWithoutExtension };
workingDirectory: self storage fullName;
runAndWaitOnExitDo: [ :process :outString | ^ self storage / self htmlFileName].
]
{ #category : #'*MiniDocs' }
LePage >> asMarkdeep [
| bodyStream markdeep |
bodyStream := '' writeStream.
self preorderTraversal do: [:snippet |
bodyStream nextPutAll: snippet asMarkdeep
].
markdeep := Markdeep new
title: self title;
body: bodyStream contents;
navTop: self navTop.
self metadata keysAndValuesDo: [:k :v |
k = 'lang'
ifTrue: [
markdeep head
add: '<meta lang="', v,'">';
yourself.
]
ifFalse: [
markdeep head
add: '<meta name="', k, '" content="', v,'">';
yourself.
]
].
self metadata at: 'authors' ifPresent: [:author | markdeep metadata at: 'authors' put: author ].
self metadata at: 'version' ifPresent: [:version | markdeep metadata at: 'version' put: version ].
^ markdeep.
]
{ #category : #'*MiniDocs' }
LePage >> asMarkdeepFile [
| folder |
folder := self options at: 'storage' ifAbsent: [ FileLocator temp ].
^ self asMarkdeep exportAsFileOn: folder / self markdeepFileName
]
{ #category : #'*MiniDocs' }
LePage >> asMarkdown [
| bodyStream markdown |
bodyStream := '' writeStream.
bodyStream
nextPutAll: '---';
nextPutAll: String lf.
self metadata keysAndValuesDo: [ :k :v |
bodyStream
nextPutAll: k , ': "' , v, '"';
nextPutAll: String lf ].
bodyStream nextPutAll: '---' , String lf , String lf.
self preorderTraversal
do: [ :snippet | bodyStream nextPutAll: snippet asMarkdown ].
markdown := Markdown new contents: bodyStream contents.
^ markdown
]
{ #category : #'*MiniDocs' }
LePage >> asMarkdownFile [
| folder |
folder := self options at: 'storage' ifAbsent: [ FileLocator temp ].
^ MarkupFile exportAsFileOn: folder / self markdownFileName containing: self asMarkdown contents
]
{ #category : #'*MiniDocs' }
LePage >> defaultPandocTemplate [
^ FileLocator home / '.pandoc' / 'templates' / 'clean-menu-mod.html'
]
{ #category : #'*MiniDocs' }
LePage >> detectParentSnippetWithUid: uidString [
"Answer a boolean indicating whether the supplied uid is present"
^ self preorderTraversal detect: [ :snippet | snippet uidString = uidString ] ifNone: [ ^ self ]
]
{ #category : #'*MiniDocs' }
LePage >> exportedFileName [
| sanitized |
sanitized := self title asDashedLowercase copyWithoutAll: #($/).
^ sanitized , '--' , (self uidString copyFrom: 1 to: 5)
]
{ #category : #'*MiniDocs' }
LePage >> fromMarkdeepUrl: aString [
| docTree pageMetadata |
docTree := GrafoscopioUtils xmlFromUrl: aString.
pageMetadata := Markdeep new metadataFromXML: docTree.
self
basicUid: (pageMetadata at: 'id');
title: (pageMetadata at: 'title');
createTime: (pageMetadata at: 'created') asDateAndTime;
editTime: (pageMetadata at: 'modified') asDateAndTime;
createEmail: (pageMetadata at: 'creator');
editEmail: (pageMetadata at: 'modifier');
optionAt: 'metadata' put: pageMetadata.
self populateChildrenFrom: (docTree xpath: '//div')
]
{ #category : #'*MiniDocs' }
LePage >> htmlFileName [
^ self exportedFileName, '.html'
]
{ #category : #'*MiniDocs' }
LePage >> latestEditTime: aLeTime [
"Used for adding a LePage to database from a shared markdeep LePage version."
latestEditTime := aLeTime
]
{ #category : #'*MiniDocs' }
LePage >> markdeepFileName [
^ self markdownFileName , '.html'
]
{ #category : #'*MiniDocs' }
LePage >> markdownFileName [
^ self exportedFileName, '.md'
]
{ #category : #'*MiniDocs' }
LePage >> metadata [
^ self options at: 'metadata' ifAbsentPut: [ self metadataInit]
]
{ #category : #'*MiniDocs' }
LePage >> metadataInit [
^ OrderedDictionary new
at: 'id' put: self uidString;
at: 'title' put: self contentAsString;
at: 'created' put: self createTime greaseString;
at: 'modified' put: self latestEditTime greaseString;
at: 'creator' put: self createEmail greaseString;
at: 'modifier' put: self editEmail greaseString;
yourself
]
{ #category : #'*MiniDocs' }
LePage >> navTop [
| topNavFile |
topNavFile := ((self optionAt: 'storage' ifAbsentPut: [ FileLocator temp ]) / '_navtop.html').
topNavFile exists
ifFalse: [ ^ '' ]
ifTrue: [ ^ topNavFile contents ]
]
{ #category : #'*MiniDocs' }
LePage >> options [
^ options
]
{ #category : #'*MiniDocs' }
LePage >> preorderTraversal [
| output |
output := OrderedCollection new.
self withDeepCollect: [:each | each allChildrenBreadthFirstDo: [:child | output add: child]].
^ output.
]
{ #category : #'*MiniDocs' }
LePage >> removeSnippetsMetadata [
self preorderTraversal do: [ :snippet |
(snippet options isNotNil and: [ snippet options includesKey: 'metadata' ])
ifTrue: [ snippet options removeKey: 'metadata' ] ]
]
{ #category : #'*MiniDocs' }
LePage >> sharedVariablesBindings [
| codeSnippets shared |
codeSnippets := self preorderTraversal select: [:snippet |
snippet class = LePharoSnippet and: [ snippet code includesSubstring: ':=']
].
codeSnippets first in: [:snippet | | context |
context := snippet coder evaluationContext.
snippet coder doItInContext: context.
shared := context bindingStrategy bindings detect: [:each |
each isKindOf: GtSharedVariablesBindings
]
].
codeSnippets asArray allButFirstDo: [:snippet| | context|
context := snippet coder evaluationContext.
context addBindings: shared.
snippet coder doItInContext: context
].
^ shared asDictionary
]
{ #category : #'*MiniDocs' }
LePage >> storage [
^ self optionAt: 'storage'
ifAbsent: [ ^ FileLocator temp ]
]

View File

@ -1,15 +1,15 @@
Extension { #name : #LePageHeaderBuilder }
{ #category : #'*MiniDocs' }
LePageHeaderBuilder >> addExportPageButton [
<leHeaderAction>
| newButton |
newButton := BrButton new
aptitude: BrGlamorousButtonWithIconAptitude;
label: 'Export Page';
icon: BrGlamorousVectorIcons down;
action: [ :aButton |
aButton phlow spawnObject: self page asMarkdeepFile ].
self toolbarElement addItem: newButton.
]
Extension { #name : #LePageHeaderBuilder }
{ #category : #'*MiniDocs' }
LePageHeaderBuilder >> addExportPageButton [
<leHeaderAction>
| newButton |
newButton := BrButton new
aptitude: BrGlamorousButtonWithIconAptitude;
label: 'Export Page';
icon: BrGlamorousVectorIcons down;
action: [ :aButton |
aButton phlow spawnObject: self page asMarkdeepFile ].
self toolbarElement addItem: newButton.
]

View File

@ -1,64 +1,64 @@
Extension { #name : #LePharoSnippet }
{ #category : #'*MiniDocs' }
LePharoSnippet >> contentAsStringCustomized [
| thisObject |
(self tags includes: 'output') ifFalse: [ ^ self contentAsString ].
thisObject := ((self page sharedVariablesBindings) at: self detectObject) value.
^ thisObject perform: self detectMessage trimmed asSymbol.
]
{ #category : #'*MiniDocs' }
LePharoSnippet >> contentFrom: markdeepDiv [
| sanitizedStringText metadata joinedText |
metadata := STON fromString: (markdeepDiv attributes at: 'st-data').
sanitizedStringText := markdeepDiv contentString lines.
sanitizedStringText := sanitizedStringText copyFrom: 4 to: sanitizedStringText size -2.
joinedText := '' writeStream.
sanitizedStringText do: [ :line | joinedText nextPutAll: line; nextPut: Character lf ].
self code: joinedText contents allButLast;
uid: (LeUID new uidString: (metadata at: 'id'));
parent: (metadata at: 'parent');
createTime: (LeTime new time: ((metadata at: 'created')asDateAndTime));
editTime: (LeTime new time: ((metadata at: 'modified') asDateAndTime));
editEmail: (metadata at: 'modifier');
createEmail: (metadata at: 'creator')
]
{ #category : #'*MiniDocs' }
LePharoSnippet >> markdeepCustomCloser [
^ String streamContents: [ :stream |
stream
nextPutAll: '~~~'; lf;
nextPutAll: '</script>'; lf.
]
]
{ #category : #'*MiniDocs' }
LePharoSnippet >> markdeepCustomOpener [
^ String streamContents: [ :stream |
stream
nextPutAll: '<script type="preformatted">'; lf;
nextPutAll: '~~~ Smalltalk'; lf
]
]
{ #category : #'*MiniDocs' }
LePharoSnippet >> markdownCustomCloser [
(self tags includes: 'output') ifTrue: [^ String with: Character lf].
^ String streamContents: [:stream |
stream
nextPutAll: '~~~'; lf
]
]
{ #category : #'*MiniDocs' }
LePharoSnippet >> markdownCustomOpener [
(self tags includes: 'output') ifTrue: [ ^ String with: Character lf ].
^ String
streamContents: [ :stream |
stream
nextPutAll: '~~~ Smalltalk';
lf ]
]
Extension { #name : #LePharoSnippet }
{ #category : #'*MiniDocs' }
LePharoSnippet >> contentAsStringCustomized [
| thisObject |
(self tags includes: 'output') ifFalse: [ ^ self contentAsString ].
thisObject := ((self page sharedVariablesBindings) at: self detectObject) value.
^ thisObject perform: self detectMessage trimmed asSymbol.
]
{ #category : #'*MiniDocs' }
LePharoSnippet >> contentFrom: markdeepDiv [
| sanitizedStringText metadata joinedText |
metadata := STON fromString: (markdeepDiv attributes at: 'st-data').
sanitizedStringText := markdeepDiv contentString lines.
sanitizedStringText := sanitizedStringText copyFrom: 4 to: sanitizedStringText size -2.
joinedText := '' writeStream.
sanitizedStringText do: [ :line | joinedText nextPutAll: line; nextPut: Character lf ].
self code: joinedText contents allButLast;
uid: (LeUID new uidString: (metadata at: 'id'));
parent: (metadata at: 'parent');
createTime: (LeTime new time: ((metadata at: 'created')asDateAndTime));
editTime: (LeTime new time: ((metadata at: 'modified') asDateAndTime));
editEmail: (metadata at: 'modifier');
createEmail: (metadata at: 'creator')
]
{ #category : #'*MiniDocs' }
LePharoSnippet >> markdeepCustomCloser [
^ String streamContents: [ :stream |
stream
nextPutAll: '~~~'; lf;
nextPutAll: '</script>'; lf.
]
]
{ #category : #'*MiniDocs' }
LePharoSnippet >> markdeepCustomOpener [
^ String streamContents: [ :stream |
stream
nextPutAll: '<script type="preformatted">'; lf;
nextPutAll: '~~~ Smalltalk'; lf
]
]
{ #category : #'*MiniDocs' }
LePharoSnippet >> markdownCustomCloser [
(self tags includes: 'output') ifTrue: [^ String with: Character lf].
^ String streamContents: [:stream |
stream
nextPutAll: '~~~'; lf
]
]
{ #category : #'*MiniDocs' }
LePharoSnippet >> markdownCustomOpener [
(self tags includes: 'output') ifTrue: [ ^ String with: Character lf ].
^ String
streamContents: [ :stream |
stream
nextPutAll: '~~~ Smalltalk';
lf ]
]

View File

@ -1,15 +1,15 @@
Extension { #name : #LePictureSnippet }
{ #category : #'*MiniDocs' }
LePictureSnippet >> asMarkdeep [
| output |
output := WriteStream on: ''.
output
nextPutAll: self metadataDiv;
nextPutAll: self centeredFigure;
nextPut: Character lf;
nextPutAll: '</div>';
nextPut: Character lf;
nextPut: Character lf.
^ output contents
]
Extension { #name : #LePictureSnippet }
{ #category : #'*MiniDocs' }
LePictureSnippet >> asMarkdeep [
| output |
output := WriteStream on: ''.
output
nextPutAll: self metadataDiv;
nextPutAll: self centeredFigure;
nextPut: Character lf;
nextPutAll: '</div>';
nextPut: Character lf;
nextPut: Character lf.
^ output contents
]

View File

@ -1,12 +1,12 @@
Extension { #name : #LeSnippet }
{ #category : #'*MiniDocs' }
LeSnippet class >> fromMetaMarkdeep: div [
| className metadata snippet |
className := (div xpath: '@st-class') stringValue.
metadata := STON fromString:(div xpath: '@st-data') stringValue.
snippet := className asClass new.
snippet injectMetadataFrom: metadata.
snippet contentFrom: div.
^ snippet.
]
Extension { #name : #LeSnippet }
{ #category : #'*MiniDocs' }
LeSnippet class >> fromMetaMarkdeep: div [
| className metadata snippet |
className := (div xpath: '@st-class') stringValue.
metadata := STON fromString:(div xpath: '@st-data') stringValue.
snippet := className asClass new.
snippet injectMetadataFrom: metadata.
snippet contentFrom: div.
^ snippet.
]

View File

@ -1,54 +1,54 @@
Extension { #name : #LeTextSnippet }
{ #category : #'*MiniDocs' }
LeTextSnippet >> contentFrom: markdeepDiv [
| sanitizedStringText metadata |
metadata := STON fromString: (markdeepDiv attributes at: 'st-data').
sanitizedStringText := markdeepDiv contentString.
sanitizedStringText := sanitizedStringText allButFirst.
sanitizedStringText := sanitizedStringText allButLast.
self string: sanitizedStringText;
uid: (LeUID new uidString: (metadata at: 'id'));
parent: (metadata at: 'parent');
createTime: (LeTime new time: ((metadata at: 'created')asDateAndTime));
editTime: (LeTime new time: ((metadata at: 'modified') asDateAndTime));
editEmail: (metadata at: 'modifier');
createEmail: (metadata at: 'creator')
]
{ #category : #'*MiniDocs' }
LeTextSnippet >> metadata [
^ self optionAt: 'metadata' ifAbsentPut: [ self metadataInit ]
]
{ #category : #'*MiniDocs' }
LeTextSnippet >> metadataInit [
^ OrderedDictionary new
at: 'id' put: self uidString;
at: 'parent' put: self parentId;
at: 'created' put: self createTime asString;
at: 'modified' put: self latestEditTime asString;
at: 'creator' put: self createEmail asString;
at: 'modifier' put: self editEmail asString;
yourself
]
{ #category : #'*MiniDocs' }
LeTextSnippet >> options [
^ options
]
{ #category : #'*MiniDocs' }
LeTextSnippet >> parentId [
self parent ifNil: [ ^ self ].
^ self parent uidString.
]
{ #category : #'*MiniDocs' }
LeTextSnippet >> taggedWith: aString [
self metadata at: 'tags' ifPresent: [ (self metadata at: 'tags') add: aString; yourself ] ifAbsentPut: [ Set new ].
^ self metadata at: 'tags'
]
Extension { #name : #LeTextSnippet }
{ #category : #'*MiniDocs' }
LeTextSnippet >> contentFrom: markdeepDiv [
| sanitizedStringText metadata |
metadata := STON fromString: (markdeepDiv attributes at: 'st-data').
sanitizedStringText := markdeepDiv contentString.
sanitizedStringText := sanitizedStringText allButFirst.
sanitizedStringText := sanitizedStringText allButLast.
self string: sanitizedStringText;
uid: (LeUID new uidString: (metadata at: 'id'));
parent: (metadata at: 'parent');
createTime: (LeTime new time: ((metadata at: 'created')asDateAndTime));
editTime: (LeTime new time: ((metadata at: 'modified') asDateAndTime));
editEmail: (metadata at: 'modifier');
createEmail: (metadata at: 'creator')
]
{ #category : #'*MiniDocs' }
LeTextSnippet >> metadata [
^ self optionAt: 'metadata' ifAbsentPut: [ self metadataInit ]
]
{ #category : #'*MiniDocs' }
LeTextSnippet >> metadataInit [
^ OrderedDictionary new
at: 'id' put: self uidString;
at: 'parent' put: self parentId;
at: 'created' put: self createTime asString;
at: 'modified' put: self latestEditTime asString;
at: 'creator' put: self createEmail asString;
at: 'modifier' put: self editEmail asString;
yourself
]
{ #category : #'*MiniDocs' }
LeTextSnippet >> options [
^ options
]
{ #category : #'*MiniDocs' }
LeTextSnippet >> parentId [
self parent ifNil: [ ^ self ].
^ self parent uidString.
]
{ #category : #'*MiniDocs' }
LeTextSnippet >> taggedWith: aString [
self metadata at: 'tags' ifPresent: [ (self metadata at: 'tags') add: aString; yourself ] ifAbsentPut: [ Set new ].
^ self metadata at: 'tags'
]

View File

@ -1,91 +1,91 @@
Extension { #name : #LeTextualSnippet }
{ #category : #'*MiniDocs' }
LeTextualSnippet >> asMarkdeep [
"Inspired by Alpine.js and Assembler CSS 'x-' properties, we are going to use
'st-' properties as a way to extend divs metadata regarding its contents."
| output |
output := WriteStream on: ''.
output
nextPutAll: '<div st-class="' , self class greaseString , '"';
nextPut: Character lf;
nextPutAll: ' st-data="' , (STON toString: self metadata) , '">';
nextPut: Character lf;
nextPutAll: self markdeepCustomOpener;
nextPutAll: self contentAsString;
nextPut: Character lf;
nextPutAll: self markdeepCustomCloser;
nextPutAll: '</div>';
nextPut: Character lf;
nextPut: Character lf.
^ output contents
]
{ #category : #'*MiniDocs' }
LeTextualSnippet >> asMarkdown [
"Inspired by Alpine.js and Assembler CSS 'x-' properties, we are going to use
'st-' properties as a way to extend divs metadata regarding its contents."
| output |
output := '' writeStream.
output
nextPutAll: '<div st-class="', self class asString, '"'; lf;
nextPutAll: ' st-data="', (STON toString: self metadata), '">'; lf;
nextPutAll: self markdownCustomOpener;
nextPutAll: self contentAsStringCustomized; lf;
nextPutAll: self markdownCustomCloser;
nextPutAll: '</div>'; lf; lf.
^ output contents
]
{ #category : #'*MiniDocs' }
LeTextualSnippet >> contentAsStringCustomized [
^ self contentAsString
]
{ #category : #'*MiniDocs' }
LeTextualSnippet >> markdeepCustomCloser [
^ ''
]
{ #category : #'*MiniDocs' }
LeTextualSnippet >> markdeepCustomOpener [
^ ''
]
{ #category : #'*MiniDocs' }
LeTextualSnippet >> markdownCustomCloser [
^ self markdeepCustomCloser
]
{ #category : #'*MiniDocs' }
LeTextualSnippet >> markdownCustomOpener [
^ self markdeepCustomOpener
]
{ #category : #'*MiniDocs' }
LeTextualSnippet >> metadata [
^ self optionAt: 'metadata' ifAbsentPut: [ self metadataInit ]
]
{ #category : #'*MiniDocs' }
LeTextualSnippet >> metadataInit [
| surrogate |
self parent
ifNil: [ surrogate := nil]
ifNotNil: [ surrogate := self parent uidString ].
^ OrderedDictionary new
at: 'id' put: self uidString;
at: 'parent' put: surrogate;
at: 'created' put: self createTime asString;
at: 'modified' put: self latestEditTime asString;
at: 'creator' put: self createEmail asString;
at: 'modifier' put: self editEmail asString;
yourself
]
{ #category : #'*MiniDocs' }
LeTextualSnippet >> tags [
^ self metadata at: 'tags' ifAbsentPut: [ Set new ]
]
Extension { #name : #LeTextualSnippet }
{ #category : #'*MiniDocs' }
LeTextualSnippet >> asMarkdeep [
"Inspired by Alpine.js and Assembler CSS 'x-' properties, we are going to use
'st-' properties as a way to extend divs metadata regarding its contents."
| output |
output := WriteStream on: ''.
output
nextPutAll: '<div st-class="' , self class greaseString , '"';
nextPut: Character lf;
nextPutAll: ' st-data="' , (STON toString: self metadata) , '">';
nextPut: Character lf;
nextPutAll: self markdeepCustomOpener;
nextPutAll: self contentAsString;
nextPut: Character lf;
nextPutAll: self markdeepCustomCloser;
nextPutAll: '</div>';
nextPut: Character lf;
nextPut: Character lf.
^ output contents
]
{ #category : #'*MiniDocs' }
LeTextualSnippet >> asMarkdown [
"Inspired by Alpine.js and Assembler CSS 'x-' properties, we are going to use
'st-' properties as a way to extend divs metadata regarding its contents."
| output |
output := '' writeStream.
output
nextPutAll: '<div st-class="', self class asString, '"'; lf;
nextPutAll: ' st-data="', (STON toString: self metadata), '">'; lf;
nextPutAll: self markdownCustomOpener;
nextPutAll: self contentAsStringCustomized; lf;
nextPutAll: self markdownCustomCloser;
nextPutAll: '</div>'; lf; lf.
^ output contents
]
{ #category : #'*MiniDocs' }
LeTextualSnippet >> contentAsStringCustomized [
^ self contentAsString
]
{ #category : #'*MiniDocs' }
LeTextualSnippet >> markdeepCustomCloser [
^ ''
]
{ #category : #'*MiniDocs' }
LeTextualSnippet >> markdeepCustomOpener [
^ ''
]
{ #category : #'*MiniDocs' }
LeTextualSnippet >> markdownCustomCloser [
^ self markdeepCustomCloser
]
{ #category : #'*MiniDocs' }
LeTextualSnippet >> markdownCustomOpener [
^ self markdeepCustomOpener
]
{ #category : #'*MiniDocs' }
LeTextualSnippet >> metadata [
^ self optionAt: 'metadata' ifAbsentPut: [ self metadataInit ]
]
{ #category : #'*MiniDocs' }
LeTextualSnippet >> metadataInit [
| surrogate |
self parent
ifNil: [ surrogate := nil]
ifNotNil: [ surrogate := self parent uidString ].
^ OrderedDictionary new
at: 'id' put: self uidString;
at: 'parent' put: surrogate;
at: 'created' put: self createTime asString;
at: 'modified' put: self latestEditTime asString;
at: 'creator' put: self createEmail asString;
at: 'modifier' put: self editEmail asString;
yourself
]
{ #category : #'*MiniDocs' }
LeTextualSnippet >> tags [
^ self metadata at: 'tags' ifAbsentPut: [ Set new ]
]

View File

@ -1,23 +1,23 @@
"
Please describe the package using the class comment of the included manifest class. The manifest class also includes other additional metadata for the package. These meta data are used by other tools such as the SmalllintManifestChecker and the critics Browser
"
Class {
#name : #ManifestMiniDocs,
#superclass : #PackageManifest,
#category : #'MiniDocs-Manifest'
}
{ #category : #'code-critics' }
ManifestMiniDocs class >> ruleCascadedNextPutAllsRuleV1FalsePositive [
^ #(#(#(#RGMethodDefinition #(#LeTextualSnippet #asMarkdeep #false)) #'2022-09-09T12:31:08.106585-05:00') )
]
{ #category : #'code-critics' }
ManifestMiniDocs class >> ruleExcessiveVariablesRuleV1FalsePositive [
^ #(#(#(#RGClassDefinition #(#Markdeep)) #'2022-07-16T12:24:34.695032-05:00') )
]
{ #category : #'code-critics' }
ManifestMiniDocs class >> ruleParseTreeLintRuleV1FalsePositive [
^ #(#(#(#RGPackageDefinition #(#MiniDocs)) #'2022-07-25T09:28:50.156394-05:00') )
]
"
Please describe the package using the class comment of the included manifest class. The manifest class also includes other additional metadata for the package. These meta data are used by other tools such as the SmalllintManifestChecker and the critics Browser
"
Class {
#name : #ManifestMiniDocs,
#superclass : #PackageManifest,
#category : #'MiniDocs-Manifest'
}
{ #category : #'code-critics' }
ManifestMiniDocs class >> ruleCascadedNextPutAllsRuleV1FalsePositive [
^ #(#(#(#RGMethodDefinition #(#LeTextualSnippet #asMarkdeep #false)) #'2022-09-09T12:31:08.106585-05:00') )
]
{ #category : #'code-critics' }
ManifestMiniDocs class >> ruleExcessiveVariablesRuleV1FalsePositive [
^ #(#(#(#RGClassDefinition #(#Markdeep)) #'2022-07-16T12:24:34.695032-05:00') )
]
{ #category : #'code-critics' }
ManifestMiniDocs class >> ruleParseTreeLintRuleV1FalsePositive [
^ #(#(#(#RGPackageDefinition #(#MiniDocs)) #'2022-07-25T09:28:50.156394-05:00') )
]

View File

@ -1,473 +1,473 @@
"
I model a Mardeep file as described in https://casual-effects.com/markdeep/
"
Class {
#name : #Markdeep,
#superclass : #Object,
#instVars : [
'title',
'body',
'comments',
'tail',
'language',
'config',
'metadata',
'head',
'navTop',
'options'
],
#category : #MiniDocs
}
{ #category : #'as yet unclassified' }
Markdeep class >> fromMarkdownFile: aFileReference [
^ self new fromMarkdownFile: aFileReference.
]
{ #category : #accessing }
Markdeep class >> fromPubPubTOC: orderedDictionary folder: folder index: ordinalPossitive [
| contentSection testFile |
contentSection := orderedDictionary associations at: ordinalPossitive.
testFile := folder / (contentSection key,'--', contentSection value),'md'.
^ self new fromMarkdownFile: testFile.
]
{ #category : #'instance creation' }
Markdeep >> authors [
self metadata at: 'authors' ifPresent: [:k | ^ '**', k, '**' ].
^ ''.
]
{ #category : #'instance creation' }
Markdeep >> authorsString [
self authors
ifNil: [ ^ '' ] ifNotNil: [ ^ ' ', self authors ]
]
{ #category : #accessing }
Markdeep >> body [
^ body
]
{ #category : #accessing }
Markdeep >> body: anObject [
body := anObject
]
{ #category : #accessing }
Markdeep >> bodyReplaceAll: original with: replacement [
self body: (self body copyReplaceAll: original with: replacement)
]
{ #category : #accessing }
Markdeep >> commentPubPubDelimiters [
| commented openners |
openners := #('::: {.pub-body-component}' '::: {.editor .Prosemirror}' '::: {.pub-notes}').
commented := self body.
openners do: [:openner |
commented := commented copyReplaceAll: openner with: '<!--@div-open ', openner, '-->'
].
commented := commented
copyReplaceAll: ':::
' with: '<!--@div-close ::: -->
'.
self body: commented
]
{ #category : #accessing }
Markdeep >> comments [
^ comments ifNil: [ ^ comments := true ]
]
{ #category : #accessing }
Markdeep >> comments: aBoolean [
"I tell if comments are enabled by default or not."
comments := aBoolean
]
{ #category : #utilities }
Markdeep >> commentsProvider [
"I return the url of the default service that provides annotation support.
I am used to add such support in the contents of the Markdeep page."
^ 'https://hypothes.is'
]
{ #category : #utilities }
Markdeep >> commentsProviderStrings [
"I associate a comments service provider with the string that is required to be added
to the document to enable such provider."
| providers |
providers := Dictionary new.
providers at: 'https://hypothes.is' put: '<!-- Hypothesis -->
<script src="https://hypothes.is/embed.js" async></script>'.
^ providers
]
{ #category : #utilities }
Markdeep >> commentsSupport [
"I enable comments of the page."
self comments ifFalse: [ ^ self ].
^ self commentsProviderStrings at: self commentsProvider
]
{ #category : #accessing }
Markdeep >> config [
^ config ifNil: [ config := Dictionary new]
]
{ #category : #accessing }
Markdeep >> config: aDictionary [
config := aDictionary
]
{ #category : #'instance creation' }
Markdeep >> contents [
| output |
self title ifNil: [ ^ self body ].
output := '' writeStream.
output
nextPutAll: self headContents; lf; lf;
nextPutAll: ' **', self title, '**'; lf;
nextPutAll: self authorsString ; lf;
nextPutAll: ' ', self version; lf;
nextPutAll: self navTop; lf; lf;
nextPutAll: self body; lf; lf;
nextPutAll: self tail; lf; lf; lf; lf;
nextPutAll: self commentsSupport.
^ output contents.
]
{ #category : #persistence }
Markdeep >> exportAsFile [
| newFile |
self markdownFile ifNil: [ self inform: 'Define an input Markdown file or use #exportAsFileOn: instead.' ].
newFile := (self markdownFile file fullName, '.html') asFileReference.
^ self exportAsFileOn: newFile.
]
{ #category : #persistence }
Markdeep >> exportAsFileOn: aFileReference [
aFileReference ensureDelete.
aFileReference exists ifFalse: [ aFileReference ensureCreateFile ].
aFileReference writeStreamDo: [ :stream |
stream nextPutAll: self contents ].
self inform: 'Exported as: ', String cr, aFileReference fullName.
^ aFileReference
]
{ #category : #utilities }
Markdeep >> fontAwesomeHeader [
"I enable the font awesome support in the document header"
^ '<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">'
]
{ #category : #'instance creation' }
Markdeep >> fromMarkdownFile: aFileReference [
"I create a Markdeep document from a given Markdown file."
self processMarkdownFor: aFileReference.
^ self.
]
{ #category : #accessing }
Markdeep >> gtTextFor: aView [
<gtView>
^ aView textEditor
title: 'Text';
text: [ self contents ]
]
{ #category : #accessing }
Markdeep >> head [
^ head ifNil: [ head := OrderedCollection new.
head add: self fontAwesomeHeader; yourself ]
]
{ #category : #accessing }
Markdeep >> head: anOrderedCollection [
head := anOrderedCollection
]
{ #category : #'instance creation' }
Markdeep >> headContents [
^ String streamContents: [ :stream |
stream
nextPutAll: '<head>';
nextPut: Character lf.
self head do: [ :line |
stream
nextPutAll: ' ';
nextPutAll: line;
nextPut: Character lf
].
stream
nextPutAll: '</head>';
nextPut: Character lf.
].
]
{ #category : #accessing }
Markdeep >> language [
^ language
]
{ #category : #accessing }
Markdeep >> language: anObject [
language := anObject
]
{ #category : #accessing }
Markdeep >> markdeepScriptTag [
^ '<script src="markdeep.min.js" charset="utf-8"></script>
<script
src="https://casual-effects.com/markdeep/latest/markdeep.min.js?"
charset="utf-8">
</script>'
]
{ #category : #accessing }
Markdeep >> markdownFile [
^ Markdown new fromFile: (self config at: 'markdownFile')
]
{ #category : #accessing }
Markdeep >> markdownFile: aFileReference [
"Where the Mardown file associated with me is stored. Used for sync. and import/export purposes."
self config at: 'markdownFile' put: aFileReference
]
{ #category : #'instance creation' }
Markdeep >> metadata [
^ metadata ifNil: [ metadata := OrderedDictionary new ]
]
{ #category : #accessing }
Markdeep >> metadata: anOrderedDictionary [
metadata := anOrderedDictionary
]
{ #category : #utilities }
Markdeep >> metadataFromXML: aXMLDocument [
| metaDict |
metaDict := OrderedDictionary new.
(aXMLDocument xpath: '//meta') do: [ :each |
metaDict at: (each @ 'name') stringValue put: (each @ 'content') stringValue ].
^ metaDict
]
{ #category : #'instance creation' }
Markdeep >> navTop [
^ navTop ifNil: [ navTop := '' ]
]
{ #category : #'as yet unclassified' }
Markdeep >> navTop: aString [
navTop:= aString.
]
{ #category : #accessing }
Markdeep >> options [
^ options ifNil: [
"Setting defaults accoding to: https://casual-effects.com/markdeep/#api"
options := Dictionary new
at: 'mode' put: nil;
at: 'lang' put: nil;
at: 'tocStyle' put: 'auto';
at: 'autoLinkImages' put: true;
yourself
]
]
{ #category : #printing }
Markdeep >> printOn: aStream [
super printOn: aStream.
aStream
nextPutAll: '( ', self title, ' )'
]
{ #category : #'instance creation' }
Markdeep >> processMarkdownFor: aFileReference [
"comment stating purpose of message"
| markdownContent |
self markdownFile: aFileReference.
markdownContent := Markdown fromFile: aFileReference.
self body: (markdownContent commentYAMLMetadata contents).
self metadata: markdownContent yamlMetadata
]
{ #category : #accessing }
Markdeep >> pubPubFootnoteMetadataFromString: string [
| sanitized footnoteData altLine altString id |
(string lines size <= 1) ifTrue: [ ^ nil ].
sanitized := '' writeStream.
altString := string copyReplaceAll: '.footnote' with: ''.
altString := altString copyReplaceAll: ' node-type='
with: '
node-type= '.
altString lines allButFirstDo: [:line |
(line beginsWith: '>')
ifTrue: [ altLine := line allButFirst ]
ifFalse: [ altLine := line ].
sanitized
nextPutAll: altLine trimBoth;
nextPutAll: String lf
].
sanitized := sanitized contents.
sanitized := sanitized copyReplaceAll: 'type=' with: 'type: '.
sanitized := sanitized copyReplaceAll: 'value=' with: 'value: '.
id := (altString lines first) allButFirst trimmed.
footnoteData := { 'id' -> id } asDictionary.
footnoteData addAll: (MiniDocs yamlToJson: sanitized trimmed).
^ footnoteData
]
{ #category : #accessing }
Markdeep >> pubPubFootnoteRawLinks [
^ self selectPubPubLinksWithSize: 2
]
{ #category : #accessing }
Markdeep >> pubPubFootnotesLinesRange [
| beginningLine endingLine |
beginningLine := self contents lines size + 1.
self contents lines doWithIndex: [:line :i |
(line beginsWith: '::: {.pub-notes}') ifTrue: [ beginningLine := i ].
(i > beginningLine and: [ line beginsWith: ':::' ])
ifTrue: [
endingLine := i.
^ {beginningLine . endingLine}
]
]
]
{ #category : #accessing }
Markdeep >> pubPubFootnotesText [
| footnotesLines output |
footnotesLines := self contents lines
copyFrom: self pubPubFootnotesLinesRange first + 3
to: self pubPubFootnotesLinesRange second - 1.
output := '' writeStream.
footnotesLines do: [:line |
output
nextPutAll: line;
nextPutAll: String crlf.
].
^ output contents allButLast
]
{ #category : #accessing }
Markdeep >> pubPubFootnotesToMarkdeep [
| footnotes sanitized cleanedFootnotesText parsedLinks |
footnotes := OrderedDictionary new.
parsedLinks := self pubPubFootnoteRawLinks.
parsedLinks ifEmpty: [ ^self ].
sanitized := self body.
parsedLinks do: [:link | | footnote |
footnote := self pubPubFootnoteMetadataFromString: link second.
footnote ifNotNil: [ | toReplace |
footnotes at: (footnote at: 'id') put: footnote.
toReplace := '[', link first, ']{', link second, '}'.
sanitized := sanitized copyReplaceAll: toReplace with: '[^', (footnote at: 'id'), ']'
]
].
cleanedFootnotesText := '' writeStream.
footnotes keysAndValuesDo: [:k :v |
cleanedFootnotesText
nextPutAll: '[^', k, ']: ';
nextPutAll: (v at: 'data-value'), String lf, String lf.
].
self body: (sanitized copyReplaceAll: self pubPubFootnotesText with: cleanedFootnotesText contents)
]
{ #category : #accessing }
Markdeep >> pubPubImageLinks [
^ self selectPubPubLinksWithSize: 3
]
{ #category : #accessing }
Markdeep >> pubPubImagesToMarkdeep [
| sanitized parsedLinks |
parsedLinks := self pubPubImageLinks.
parsedLinks ifEmpty: [ ^self ].
sanitized := self body.
parsedLinks do: [:link |
sanitized := sanitized copyReplaceAll: '{', link third, '}' with: ''
].
self body: sanitized
]
{ #category : #accessing }
Markdeep >> pubPubRawLinks [
| parser |
parser := PubPubGrammar new document.
^ (parser parse: self body)
]
{ #category : #accessing }
Markdeep >> replaceBackslashBreaklines [
self bodyReplaceAll: '\
' with: '<br>
'
]
{ #category : #accessing }
Markdeep >> selectPubPubLinksWithSize: naturalNumber [
^ self pubPubRawLinks select: [ :each | each size = naturalNumber ]
]
{ #category : #accessing }
Markdeep >> tail [
"I enable the document tail, which, in turn, enables a Markdeep document"
| output |
output := '' writeStream.
output
nextPutAll: '<!-- Markdeep: -->'; lf; lf;
nextPutAll: '<style class="fallback">body{visibility:hidden;white-space:pre;font-family:monospace}</style>'; lf;
nextPutAll: '<script>window.markdeepOptions = {tocStyle: "', self tocStyle,'"}</script>'; lf;
nextPutAll: self markdeepScriptTag; lf;
nextPutAll: '<!--<script>window.alreadyProcessedMarkdeep||(document.body.style.visibility="visible")</script>-->'.
^ output contents
]
{ #category : #accessing }
Markdeep >> tail: anObject [
tail := anObject
]
{ #category : #accessing }
Markdeep >> title [
^ title ifNil: [ title := self metadata at: 'title' ]
]
{ #category : #accessing }
Markdeep >> title: anObject [
title := anObject
]
{ #category : #accessing }
Markdeep >> tocStyle [
^ self options at: 'tocStyle' ifAbsent: [ 'short' ]
]
{ #category : #accessing }
Markdeep >> tocStyle: aString [
"A string can be: 'auto' 'none' 'short' 'medium' or 'long'"
self options at: 'tocStyle' put: aString
]
{ #category : #'instance creation' }
Markdeep >> version [
self metadata at: 'version' ifPresent: [:value | ^ 'v',value ].
^ ''
]
"
I model a Mardeep file as described in https://casual-effects.com/markdeep/
"
Class {
#name : #Markdeep,
#superclass : #Object,
#instVars : [
'title',
'body',
'comments',
'tail',
'language',
'config',
'metadata',
'head',
'navTop',
'options'
],
#category : #MiniDocs
}
{ #category : #'as yet unclassified' }
Markdeep class >> fromMarkdownFile: aFileReference [
^ self new fromMarkdownFile: aFileReference.
]
{ #category : #accessing }
Markdeep class >> fromPubPubTOC: orderedDictionary folder: folder index: ordinalPossitive [
| contentSection testFile |
contentSection := orderedDictionary associations at: ordinalPossitive.
testFile := folder / (contentSection key,'--', contentSection value),'md'.
^ self new fromMarkdownFile: testFile.
]
{ #category : #'instance creation' }
Markdeep >> authors [
self metadata at: 'authors' ifPresent: [:k | ^ '**', k, '**' ].
^ ''.
]
{ #category : #'instance creation' }
Markdeep >> authorsString [
self authors
ifNil: [ ^ '' ] ifNotNil: [ ^ ' ', self authors ]
]
{ #category : #accessing }
Markdeep >> body [
^ body
]
{ #category : #accessing }
Markdeep >> body: anObject [
body := anObject
]
{ #category : #accessing }
Markdeep >> bodyReplaceAll: original with: replacement [
self body: (self body copyReplaceAll: original with: replacement)
]
{ #category : #accessing }
Markdeep >> commentPubPubDelimiters [
| commented openners |
openners := #('::: {.pub-body-component}' '::: {.editor .Prosemirror}' '::: {.pub-notes}').
commented := self body.
openners do: [:openner |
commented := commented copyReplaceAll: openner with: '<!--@div-open ', openner, '-->'
].
commented := commented
copyReplaceAll: ':::
' with: '<!--@div-close ::: -->
'.
self body: commented
]
{ #category : #accessing }
Markdeep >> comments [
^ comments ifNil: [ ^ comments := true ]
]
{ #category : #accessing }
Markdeep >> comments: aBoolean [
"I tell if comments are enabled by default or not."
comments := aBoolean
]
{ #category : #utilities }
Markdeep >> commentsProvider [
"I return the url of the default service that provides annotation support.
I am used to add such support in the contents of the Markdeep page."
^ 'https://hypothes.is'
]
{ #category : #utilities }
Markdeep >> commentsProviderStrings [
"I associate a comments service provider with the string that is required to be added
to the document to enable such provider."
| providers |
providers := Dictionary new.
providers at: 'https://hypothes.is' put: '<!-- Hypothesis -->
<script src="https://hypothes.is/embed.js" async></script>'.
^ providers
]
{ #category : #utilities }
Markdeep >> commentsSupport [
"I enable comments of the page."
self comments ifFalse: [ ^ self ].
^ self commentsProviderStrings at: self commentsProvider
]
{ #category : #accessing }
Markdeep >> config [
^ config ifNil: [ config := Dictionary new]
]
{ #category : #accessing }
Markdeep >> config: aDictionary [
config := aDictionary
]
{ #category : #'instance creation' }
Markdeep >> contents [
| output |
self title ifNil: [ ^ self body ].
output := '' writeStream.
output
nextPutAll: self headContents; lf; lf;
nextPutAll: ' **', self title, '**'; lf;
nextPutAll: self authorsString ; lf;
nextPutAll: ' ', self version; lf;
nextPutAll: self navTop; lf; lf;
nextPutAll: self body; lf; lf;
nextPutAll: self tail; lf; lf; lf; lf;
nextPutAll: self commentsSupport.
^ output contents.
]
{ #category : #persistence }
Markdeep >> exportAsFile [
| newFile |
self markdownFile ifNil: [ self inform: 'Define an input Markdown file or use #exportAsFileOn: instead.' ].
newFile := (self markdownFile file fullName, '.html') asFileReference.
^ self exportAsFileOn: newFile.
]
{ #category : #persistence }
Markdeep >> exportAsFileOn: aFileReference [
aFileReference ensureDelete.
aFileReference exists ifFalse: [ aFileReference ensureCreateFile ].
aFileReference writeStreamDo: [ :stream |
stream nextPutAll: self contents ].
self inform: 'Exported as: ', String cr, aFileReference fullName.
^ aFileReference
]
{ #category : #utilities }
Markdeep >> fontAwesomeHeader [
"I enable the font awesome support in the document header"
^ '<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">'
]
{ #category : #'instance creation' }
Markdeep >> fromMarkdownFile: aFileReference [
"I create a Markdeep document from a given Markdown file."
self processMarkdownFor: aFileReference.
^ self.
]
{ #category : #accessing }
Markdeep >> gtTextFor: aView [
<gtView>
^ aView textEditor
title: 'Text';
text: [ self contents ]
]
{ #category : #accessing }
Markdeep >> head [
^ head ifNil: [ head := OrderedCollection new.
head add: self fontAwesomeHeader; yourself ]
]
{ #category : #accessing }
Markdeep >> head: anOrderedCollection [
head := anOrderedCollection
]
{ #category : #'instance creation' }
Markdeep >> headContents [
^ String streamContents: [ :stream |
stream
nextPutAll: '<head>';
nextPut: Character lf.
self head do: [ :line |
stream
nextPutAll: ' ';
nextPutAll: line;
nextPut: Character lf
].
stream
nextPutAll: '</head>';
nextPut: Character lf.
].
]
{ #category : #accessing }
Markdeep >> language [
^ language
]
{ #category : #accessing }
Markdeep >> language: anObject [
language := anObject
]
{ #category : #accessing }
Markdeep >> markdeepScriptTag [
^ '<script src="markdeep.min.js" charset="utf-8"></script>
<script
src="https://casual-effects.com/markdeep/latest/markdeep.min.js?"
charset="utf-8">
</script>'
]
{ #category : #accessing }
Markdeep >> markdownFile [
^ Markdown new fromFile: (self config at: 'markdownFile')
]
{ #category : #accessing }
Markdeep >> markdownFile: aFileReference [
"Where the Mardown file associated with me is stored. Used for sync. and import/export purposes."
self config at: 'markdownFile' put: aFileReference
]
{ #category : #'instance creation' }
Markdeep >> metadata [
^ metadata ifNil: [ metadata := OrderedDictionary new ]
]
{ #category : #accessing }
Markdeep >> metadata: anOrderedDictionary [
metadata := anOrderedDictionary
]
{ #category : #utilities }
Markdeep >> metadataFromXML: aXMLDocument [
| metaDict |
metaDict := OrderedDictionary new.
(aXMLDocument xpath: '//meta') do: [ :each |
metaDict at: (each @ 'name') stringValue put: (each @ 'content') stringValue ].
^ metaDict
]
{ #category : #'instance creation' }
Markdeep >> navTop [
^ navTop ifNil: [ navTop := '' ]
]
{ #category : #'as yet unclassified' }
Markdeep >> navTop: aString [
navTop:= aString.
]
{ #category : #accessing }
Markdeep >> options [
^ options ifNil: [
"Setting defaults accoding to: https://casual-effects.com/markdeep/#api"
options := Dictionary new
at: 'mode' put: nil;
at: 'lang' put: nil;
at: 'tocStyle' put: 'auto';
at: 'autoLinkImages' put: true;
yourself
]
]
{ #category : #printing }
Markdeep >> printOn: aStream [
super printOn: aStream.
aStream
nextPutAll: '( ', self title, ' )'
]
{ #category : #'instance creation' }
Markdeep >> processMarkdownFor: aFileReference [
"comment stating purpose of message"
| markdownContent |
self markdownFile: aFileReference.
markdownContent := Markdown fromFile: aFileReference.
self body: (markdownContent commentYAMLMetadata contents).
self metadata: markdownContent yamlMetadata
]
{ #category : #accessing }
Markdeep >> pubPubFootnoteMetadataFromString: string [
| sanitized footnoteData altLine altString id |
(string lines size <= 1) ifTrue: [ ^ nil ].
sanitized := '' writeStream.
altString := string copyReplaceAll: '.footnote' with: ''.
altString := altString copyReplaceAll: ' node-type='
with: '
node-type= '.
altString lines allButFirstDo: [:line |
(line beginsWith: '>')
ifTrue: [ altLine := line allButFirst ]
ifFalse: [ altLine := line ].
sanitized
nextPutAll: altLine trimBoth;
nextPutAll: String lf
].
sanitized := sanitized contents.
sanitized := sanitized copyReplaceAll: 'type=' with: 'type: '.
sanitized := sanitized copyReplaceAll: 'value=' with: 'value: '.
id := (altString lines first) allButFirst trimmed.
footnoteData := { 'id' -> id } asDictionary.
footnoteData addAll: (MiniDocs yamlToJson: sanitized trimmed).
^ footnoteData
]
{ #category : #accessing }
Markdeep >> pubPubFootnoteRawLinks [
^ self selectPubPubLinksWithSize: 2
]
{ #category : #accessing }
Markdeep >> pubPubFootnotesLinesRange [
| beginningLine endingLine |
beginningLine := self contents lines size + 1.
self contents lines doWithIndex: [:line :i |
(line beginsWith: '::: {.pub-notes}') ifTrue: [ beginningLine := i ].
(i > beginningLine and: [ line beginsWith: ':::' ])
ifTrue: [
endingLine := i.
^ {beginningLine . endingLine}
]
]
]
{ #category : #accessing }
Markdeep >> pubPubFootnotesText [
| footnotesLines output |
footnotesLines := self contents lines
copyFrom: self pubPubFootnotesLinesRange first + 3
to: self pubPubFootnotesLinesRange second - 1.
output := '' writeStream.
footnotesLines do: [:line |
output
nextPutAll: line;
nextPutAll: String crlf.
].
^ output contents allButLast
]
{ #category : #accessing }
Markdeep >> pubPubFootnotesToMarkdeep [
| footnotes sanitized cleanedFootnotesText parsedLinks |
footnotes := OrderedDictionary new.
parsedLinks := self pubPubFootnoteRawLinks.
parsedLinks ifEmpty: [ ^self ].
sanitized := self body.
parsedLinks do: [:link | | footnote |
footnote := self pubPubFootnoteMetadataFromString: link second.
footnote ifNotNil: [ | toReplace |
footnotes at: (footnote at: 'id') put: footnote.
toReplace := '[', link first, ']{', link second, '}'.
sanitized := sanitized copyReplaceAll: toReplace with: '[^', (footnote at: 'id'), ']'
]
].
cleanedFootnotesText := '' writeStream.
footnotes keysAndValuesDo: [:k :v |
cleanedFootnotesText
nextPutAll: '[^', k, ']: ';
nextPutAll: (v at: 'data-value'), String lf, String lf.
].
self body: (sanitized copyReplaceAll: self pubPubFootnotesText with: cleanedFootnotesText contents)
]
{ #category : #accessing }
Markdeep >> pubPubImageLinks [
^ self selectPubPubLinksWithSize: 3
]
{ #category : #accessing }
Markdeep >> pubPubImagesToMarkdeep [
| sanitized parsedLinks |
parsedLinks := self pubPubImageLinks.
parsedLinks ifEmpty: [ ^self ].
sanitized := self body.
parsedLinks do: [:link |
sanitized := sanitized copyReplaceAll: '{', link third, '}' with: ''
].
self body: sanitized
]
{ #category : #accessing }
Markdeep >> pubPubRawLinks [
| parser |
parser := PubPubGrammar new document.
^ (parser parse: self body)
]
{ #category : #accessing }
Markdeep >> replaceBackslashBreaklines [
self bodyReplaceAll: '\
' with: '<br>
'
]
{ #category : #accessing }
Markdeep >> selectPubPubLinksWithSize: naturalNumber [
^ self pubPubRawLinks select: [ :each | each size = naturalNumber ]
]
{ #category : #accessing }
Markdeep >> tail [
"I enable the document tail, which, in turn, enables a Markdeep document"
| output |
output := '' writeStream.
output
nextPutAll: '<!-- Markdeep: -->'; lf; lf;
nextPutAll: '<style class="fallback">body{visibility:hidden;white-space:pre;font-family:monospace}</style>'; lf;
nextPutAll: '<script>window.markdeepOptions = {tocStyle: "', self tocStyle,'"}</script>'; lf;
nextPutAll: self markdeepScriptTag; lf;
nextPutAll: '<!--<script>window.alreadyProcessedMarkdeep||(document.body.style.visibility="visible")</script>-->'.
^ output contents
]
{ #category : #accessing }
Markdeep >> tail: anObject [
tail := anObject
]
{ #category : #accessing }
Markdeep >> title [
^ title ifNil: [ title := self metadata at: 'title' ]
]
{ #category : #accessing }
Markdeep >> title: anObject [
title := anObject
]
{ #category : #accessing }
Markdeep >> tocStyle [
^ self options at: 'tocStyle' ifAbsent: [ 'short' ]
]
{ #category : #accessing }
Markdeep >> tocStyle: aString [
"A string can be: 'auto' 'none' 'short' 'medium' or 'long'"
self options at: 'tocStyle' put: aString
]
{ #category : #'instance creation' }
Markdeep >> version [
self metadata at: 'version' ifPresent: [:value | ^ 'v',value ].
^ ''
]

View File

@ -1,185 +1,185 @@
"
I model a Markdown document.
At some point the idea is to have a full native parser implemented to deal
with my syntax, but meanwhile I will be collaborating with external parsers,
particularly the ones provided by Pandoc and/or Lunamark.
"
Class {
#name : #Markdown,
#superclass : #Object,
#instVars : [
'contents',
'file'
],
#category : #MiniDocs
}
{ #category : #'instance creation' }
Markdown class >> fromFile: aFileReference [
^ self new fromFile: aFileReference
]
{ #category : #utilities }
Markdown class >> yamlMetadataDelimiter [
^ '---'
]
{ #category : #operation }
Markdown >> commentYAMLMetadata [
| newContents |
self detectYAMLMetadata ifFalse: [ ^ self ].
newContents := '' writeStream.
newContents nextPutAll: '<!--@yaml:'; crlf.
newContents nextPutAll: self yamlMetadataString.
newContents nextPutAll: String cr.
newContents nextPutAll: '-->'; crlf.
(self lines copyFrom: self yamlMetadataClosingLineNumber + 2 to: self lines size) do: [ :line |
newContents nextPutAll: line; crlf ].
^ newContents contents.
]
{ #category : #utilities }
Markdown >> containsYAMLMetadataClosing [
^ self yamlMetadataClosingLineNumber > 0
]
{ #category : #accessing }
Markdown >> contents [
^ contents
]
{ #category : #accessing }
Markdown >> contents: anObject [
contents := anObject
]
{ #category : #utilities }
Markdown >> detectYAMLMetadata [
| lines |
lines := self lines.
^ self startsWithYAMLMetadataDelimiter
and: [ lines allButFirst
detect: [ :currentLine | currentLine beginsWith: self class yamlMetadataDelimiter ]
ifFound: [ ^ true ] ifNone: [ ^ false ] ]
]
{ #category : #operation }
Markdown >> exportMetadataAsJson [
"TBD: Lua scripts should be checked and installed when missing. Maybe a shared location
in '.local/share/Grafoscopio/Scripts' should be developed in the near future."
| output luaScript |
luaScript := FileLocator home / '.local/share/Brea/scripts/meta-to-json.lua'.
Smalltalk platformName = 'unix' ifTrue: [
OSSUnixSubprocess new
workingDirectory: self file parent fullName;
command: 'pandoc';
arguments: { '--lua-filter=', luaScript fullName . self file basename };
redirectStdout;
redirectStdin;
runAndWaitOnExitDo: [ :process :outString :errString |
output := process isSuccess
ifTrue: [ outString ]
ifFalse: [ errString ]
]].
^ output correctAccentedCharacters
]
{ #category : #operation }
Markdown >> exportMetadataAsYaml [
| exportedFile |
exportedFile := FileLocator temp / 'metadata.yaml'.
MarkupFile exportAsFileOn: exportedFile containing: self yamlMetadataStringWithDelimiters.
^ exportedFile
]
{ #category : #accessing }
Markdown >> file [
^ file
]
{ #category : #accessing }
Markdown >> file: aFileReference [
"I store the origen/destination of the Markdown contents."
file := aFileReference
]
{ #category : #'instance creation' }
Markdown >> fromFile: aFileReference [
self contents: aFileReference contents.
self file: aFileReference.
]
{ #category : #accessing }
Markdown >> gtTextFor: aView [
<gtView>
^ aView textEditor
title: 'Text';
text: [ self contents ]
]
{ #category : #utilities }
Markdown >> lines [
^ self contents lines.
]
{ #category : #accessing }
Markdown >> metadata [
| rawMeta |
rawMeta := PPYAMLGrammar new parse: self yamlMetadataString.
rawMeta associationsDo: [ :assoc |
assoc value = 'false' ifTrue: [ assoc value: false ].
assoc value = 'true' ifTrue: [ assoc value: true ] ].
^ rawMeta
]
{ #category : #accessing }
Markdown >> printOn: aStream [
super printOn: aStream.
aStream
nextPutAll: '( ', (self metadata at: 'title'), ' )'
]
{ #category : #utilities }
Markdown >> startsWithYAMLMetadataDelimiter [
^ self lines first beginsWith: self class yamlMetadataDelimiter
]
{ #category : #accessing }
Markdown >> yamlMetadata [
^ MiniDocs yamlToJson: self yamlMetadataString
]
{ #category : #utilities }
Markdown >> yamlMetadataClosingLineNumber [
"I return the line where the closing of the YAML metadata occurs or 0 if no closing is found."
self startsWithYAMLMetadataDelimiter ifFalse: [ ^ self ].
self lines allButFirst doWithIndex: [ :currentLine :i |
(currentLine beginsWith: self class yamlMetadataDelimiter) ifTrue: [ ^ i + 1 ]]
]
{ #category : #operation }
Markdown >> yamlMetadataString [
| output yamlLines |
self detectYAMLMetadata ifFalse: [ ^ nil ].
yamlLines := self lines copyFrom: 2 to: self yamlMetadataClosingLineNumber - 1.
output := '' writeStream.
yamlLines do: [ :line |
output
nextPutAll: line;
nextPut: Character cr. ].
^ output contents
]
{ #category : #utilities }
Markdown >> yamlMetadataStringWithDelimiters [
| output |
self yamlMetadataString ifNil: [ ^ nil ].
output := String new writeStream.
output nextPutAll: self class yamlMetadataDelimiter; cr.
output nextPutAll: self yamlMetadataString.
output nextPutAll: self class yamlMetadataDelimiter; cr.
^ output contents.
]
"
I model a Markdown document.
At some point the idea is to have a full native parser implemented to deal
with my syntax, but meanwhile I will be collaborating with external parsers,
particularly the ones provided by Pandoc and/or Lunamark.
"
Class {
#name : #Markdown,
#superclass : #Object,
#instVars : [
'contents',
'file'
],
#category : #MiniDocs
}
{ #category : #'instance creation' }
Markdown class >> fromFile: aFileReference [
^ self new fromFile: aFileReference
]
{ #category : #utilities }
Markdown class >> yamlMetadataDelimiter [
^ '---'
]
{ #category : #operation }
Markdown >> commentYAMLMetadata [
| newContents |
self detectYAMLMetadata ifFalse: [ ^ self ].
newContents := '' writeStream.
newContents nextPutAll: '<!--@yaml:'; crlf.
newContents nextPutAll: self yamlMetadataString.
newContents nextPutAll: String cr.
newContents nextPutAll: '-->'; crlf.
(self lines copyFrom: self yamlMetadataClosingLineNumber + 2 to: self lines size) do: [ :line |
newContents nextPutAll: line; crlf ].
^ newContents contents.
]
{ #category : #utilities }
Markdown >> containsYAMLMetadataClosing [
^ self yamlMetadataClosingLineNumber > 0
]
{ #category : #accessing }
Markdown >> contents [
^ contents
]
{ #category : #accessing }
Markdown >> contents: anObject [
contents := anObject
]
{ #category : #utilities }
Markdown >> detectYAMLMetadata [
| lines |
lines := self lines.
^ self startsWithYAMLMetadataDelimiter
and: [ lines allButFirst
detect: [ :currentLine | currentLine beginsWith: self class yamlMetadataDelimiter ]
ifFound: [ ^ true ] ifNone: [ ^ false ] ]
]
{ #category : #operation }
Markdown >> exportMetadataAsJson [
"TBD: Lua scripts should be checked and installed when missing. Maybe a shared location
in '.local/share/Grafoscopio/Scripts' should be developed in the near future."
| output luaScript |
luaScript := FileLocator home / '.local/share/Brea/scripts/meta-to-json.lua'.
Smalltalk platformName = 'unix' ifTrue: [
OSSUnixSubprocess new
workingDirectory: self file parent fullName;
command: 'pandoc';
arguments: { '--lua-filter=', luaScript fullName . self file basename };
redirectStdout;
redirectStdin;
runAndWaitOnExitDo: [ :process :outString :errString |
output := process isSuccess
ifTrue: [ outString ]
ifFalse: [ errString ]
]].
^ output correctAccentedCharacters
]
{ #category : #operation }
Markdown >> exportMetadataAsYaml [
| exportedFile |
exportedFile := FileLocator temp / 'metadata.yaml'.
MarkupFile exportAsFileOn: exportedFile containing: self yamlMetadataStringWithDelimiters.
^ exportedFile
]
{ #category : #accessing }
Markdown >> file [
^ file
]
{ #category : #accessing }
Markdown >> file: aFileReference [
"I store the origen/destination of the Markdown contents."
file := aFileReference
]
{ #category : #'instance creation' }
Markdown >> fromFile: aFileReference [
self contents: aFileReference contents.
self file: aFileReference.
]
{ #category : #accessing }
Markdown >> gtTextFor: aView [
<gtView>
^ aView textEditor
title: 'Text';
text: [ self contents ]
]
{ #category : #utilities }
Markdown >> lines [
^ self contents lines.
]
{ #category : #accessing }
Markdown >> metadata [
| rawMeta |
rawMeta := PPYAMLGrammar new parse: self yamlMetadataString.
rawMeta associationsDo: [ :assoc |
assoc value = 'false' ifTrue: [ assoc value: false ].
assoc value = 'true' ifTrue: [ assoc value: true ] ].
^ rawMeta
]
{ #category : #accessing }
Markdown >> printOn: aStream [
super printOn: aStream.
aStream
nextPutAll: '( ', (self metadata at: 'title'), ' )'
]
{ #category : #utilities }
Markdown >> startsWithYAMLMetadataDelimiter [
^ self lines first beginsWith: self class yamlMetadataDelimiter
]
{ #category : #accessing }
Markdown >> yamlMetadata [
^ MiniDocs yamlToJson: self yamlMetadataString
]
{ #category : #utilities }
Markdown >> yamlMetadataClosingLineNumber [
"I return the line where the closing of the YAML metadata occurs or 0 if no closing is found."
self startsWithYAMLMetadataDelimiter ifFalse: [ ^ self ].
self lines allButFirst doWithIndex: [ :currentLine :i |
(currentLine beginsWith: self class yamlMetadataDelimiter) ifTrue: [ ^ i + 1 ]]
]
{ #category : #operation }
Markdown >> yamlMetadataString [
| output yamlLines |
self detectYAMLMetadata ifFalse: [ ^ nil ].
yamlLines := self lines copyFrom: 2 to: self yamlMetadataClosingLineNumber - 1.
output := '' writeStream.
yamlLines do: [ :line |
output
nextPutAll: line;
nextPut: Character cr. ].
^ output contents
]
{ #category : #utilities }
Markdown >> yamlMetadataStringWithDelimiters [
| output |
self yamlMetadataString ifNil: [ ^ nil ].
output := String new writeStream.
output nextPutAll: self class yamlMetadataDelimiter; cr.
output nextPutAll: self yamlMetadataString.
output nextPutAll: self class yamlMetadataDelimiter; cr.
^ output contents.
]

View File

@ -1,37 +1,37 @@
"
I model common operations made with several markup files.
"
Class {
#name : #MarkupFile,
#superclass : #Object,
#instVars : [
'file'
],
#category : #MiniDocs
}
{ #category : #persistence }
MarkupFile class >> exportAsFileOn: aFileReferenceOrFileName containing: text [
| file |
file := aFileReferenceOrFileName asFileReference.
file ensureDelete.
file exists ifFalse: [ file ensureCreateFile ].
file writeStreamDo: [ :stream |
stream nextPutAll: text withUnixLineEndings].
self inform: 'Exported as: ', String cr, file fullName.
^ file
]
{ #category : #accessing }
MarkupFile class >> installTemplate: anUrl into: aFolder [
| fileName |
fileName := anUrl asUrl segments last.
(aFolder / fileName) exists
ifTrue: [ (aFolder / fileName) ensureDeleteFile ]
ifFalse: [ aFolder ensureCreateDirectory ].
ZnClient new
url: anUrl;
downloadTo: aFolder.
^ aFolder
]
"
I model common operations made with several markup files.
"
Class {
#name : #MarkupFile,
#superclass : #Object,
#instVars : [
'file'
],
#category : #MiniDocs
}
{ #category : #persistence }
MarkupFile class >> exportAsFileOn: aFileReferenceOrFileName containing: text [
| file |
file := aFileReferenceOrFileName asFileReference.
file ensureDelete.
file exists ifFalse: [ file ensureCreateFile ].
file writeStreamDo: [ :stream |
stream nextPutAll: text withUnixLineEndings].
self inform: 'Exported as: ', String cr, file fullName.
^ file
]
{ #category : #accessing }
MarkupFile class >> installTemplate: anUrl into: aFolder [
| fileName |
fileName := anUrl asUrl segments last.
(aFolder / fileName) exists
ifTrue: [ (aFolder / fileName) ensureDeleteFile ]
ifFalse: [ aFolder ensureCreateDirectory ].
ZnClient new
url: anUrl;
downloadTo: aFolder.
^ aFolder
]

View File

@ -1,52 +1,55 @@
Class {
#name : #MiniDocs,
#superclass : #Object,
#category : #MiniDocs
}
{ #category : #accessing }
MiniDocs class >> appFolder [
| tempFolder |
tempFolder := FileLocator userData / 'Mutabit' / 'MiniDocs'.
tempFolder exists ifFalse: [ tempFolder ensureCreateDirectory ].
^ tempFolder
]
{ #category : #accessing }
MiniDocs class >> installYamlToJson [
"For the moment, only Gnu/Linux and Mac are supported.
IMPORTANT: Nimble, Nim's package manager should be installed, as this process doesn't verify its proper installation."
self yamlToJsonBinary exists ifTrue: [ ^ MiniDocs appFolder ].
Nimble install: 'commandeer'.
OSSUnixSubprocess new
command: 'nim';
arguments: {'c'. self yamlToJsonSourceCode fullName};
runAndWaitOnExitDo: [ :process :outString |
(self yamlToJsonSourceCode parent / self yamlToJsonSourceCode basenameWithoutExtension) moveTo: MiniDocs appFolder asFileReference.
^ MiniDocs appFolder ]
]
{ #category : #accessing }
MiniDocs class >> yamlToJson: yamlString [
"This method uses a external binary written in Nim, as the native Pharo parser for YAML, written in PetitParser,
was less robust and unable to parse correctly the same strings as the external one."
self yamlToJsonBinary exists ifFalse: [ self installYamlToJson ].
OSSUnixSubprocess new
command: self yamlToJsonBinary fullName;
arguments: {yamlString};
redirectStdout;
runAndWaitOnExitDo: [ :process :outString |
^ (STONJSON fromString: outString allButFirst) first
]
]
{ #category : #accessing }
MiniDocs class >> yamlToJsonBinary [
^ self appFolder / 'yamlToJson'
]
{ #category : #accessing }
MiniDocs class >> yamlToJsonSourceCode [
^ FileLocator image parent / 'pharo-local/iceberg/Offray/MiniDocs/src/yamlToJson.nim'
]
Class {
#name : #MiniDocs,
#superclass : #Object,
#category : #MiniDocs
}
{ #category : #accessing }
MiniDocs class >> appFolder [
| tempFolder userDataFolder |
userDataFolder := Smalltalk os isWindows
ifTrue: [ FileLocator home / 'AppData' / 'Local' ]
ifFalse: [ FileLocator userData ].
tempFolder := userDataFolder / 'Mutabit' / 'MiniDocs'.
tempFolder exists ifFalse: [ tempFolder ensureCreateDirectory ].
^ tempFolder
]
{ #category : #accessing }
MiniDocs class >> installYamlToJson [
"For the moment, only Gnu/Linux and Mac are supported.
IMPORTANT: Nimble, Nim's package manager should be installed, as this process doesn't verify its proper installation."
self yamlToJsonBinary exists ifTrue: [ ^ MiniDocs appFolder ].
Nimble install: 'commandeer'.
OSSUnixSubprocess new
command: 'nim';
arguments: {'c'. self yamlToJsonSourceCode fullName};
runAndWaitOnExitDo: [ :process :outString |
(self yamlToJsonSourceCode parent / self yamlToJsonSourceCode basenameWithoutExtension) moveTo: MiniDocs appFolder asFileReference.
^ MiniDocs appFolder ]
]
{ #category : #accessing }
MiniDocs class >> yamlToJson: yamlString [
"This method uses a external binary written in Nim, as the native Pharo parser for YAML, written in PetitParser,
was less robust and unable to parse correctly the same strings as the external one."
self yamlToJsonBinary exists ifFalse: [ self installYamlToJson ].
OSSUnixSubprocess new
command: self yamlToJsonBinary fullName;
arguments: {yamlString};
redirectStdout;
runAndWaitOnExitDo: [ :process :outString |
^ (STONJSON fromString: outString allButFirst) first
]
]
{ #category : #accessing }
MiniDocs class >> yamlToJsonBinary [
^ self appFolder / 'yamlToJson'
]
{ #category : #accessing }
MiniDocs class >> yamlToJsonSourceCode [
^ FileLocator image parent / 'pharo-local/iceberg/Offray/MiniDocs/src/yamlToJson.nim'
]

View File

@ -1,53 +1,53 @@
"
I'm run an implementation of the [Nano ID](https://github.com/ai/nanoid) tiny, secure URL-friendly unique string ID generator via its [Nim implementation](https://github.com/icyphox/nanoid.nim).
The Nim script has hard coded:
* a [base 58 encoding](https://medium.com/concerning-pharo/understanding-base58-encoding-23e673e37ff6) alphabet to avoid similar looking letter and the use of non-alphanumeric characters.
* a 12 characters length output, which gives [a pretty low probability collision](https://zelark.github.io/nano-id-cc/) for the previous alphabet:
~616 years needed, in order to have a 1% probability of at least one collision at a speed of 1000 IDs per hour.
This is more than enough for our unique IDs applications, mostly in the documentation context,
which consists of hand crafted and/or programmatically produced notes ,
for example in data narratives, book(lets) and TiddlyWiki tiddlers of tens or hundreds of notes at most,
unevenly produced between hours, days and/or weeks..
"
Class {
#name : #NanoID,
#superclass : #Object,
#category : #'MiniDocs-MiniDocs'
}
{ #category : #accessing }
NanoID class >> binaryFile [
^ MiniDocs appFolder / self scriptSourceCode basenameWithoutExtension
]
{ #category : #accessing }
NanoID class >> generate [
self binaryFile exists ifFalse: [ NanoID install].
OSSUnixSubprocess new
command: self binaryFile fullName;
redirectStdout;
redirectStdout;
runAndWaitOnExitDo: [ :process :outString | ^ outString copyWithoutAll: (Character lf asString) ]
]
{ #category : #accessing }
NanoID class >> install [
"For the moment, only Gnu/Linux and Mac are supported.
IMPORTANT: Nimble, Nim's package manager should be installed, as this process doesn't verify its proper installation."
self binaryFile exists ifTrue: [ ^ MiniDocs appFolder ].
Nimble install: 'nanoid'.
OSSUnixSubprocess new
command: 'nim';
arguments: {'c'. self scriptSourceCode fullName};
runAndWaitOnExitDo: [ :process :outString |
(self scriptSourceCode parent / (self scriptSourceCode) basenameWithoutExtension) moveTo: MiniDocs appFolder asFileReference.
^ MiniDocs appFolder ]
]
{ #category : #accessing }
NanoID class >> scriptSourceCode [
^ FileLocator image parent / 'pharo-local/iceberg/Offray/MiniDocs/src/nanoIdGen.nim'
]
"
I'm run an implementation of the [Nano ID](https://github.com/ai/nanoid) tiny, secure URL-friendly unique string ID generator via its [Nim implementation](https://github.com/icyphox/nanoid.nim).
The Nim script has hard coded:
* a [base 58 encoding](https://medium.com/concerning-pharo/understanding-base58-encoding-23e673e37ff6) alphabet to avoid similar looking letter and the use of non-alphanumeric characters.
* a 12 characters length output, which gives [a pretty low probability collision](https://zelark.github.io/nano-id-cc/) for the previous alphabet:
~616 years needed, in order to have a 1% probability of at least one collision at a speed of 1000 IDs per hour.
This is more than enough for our unique IDs applications, mostly in the documentation context,
which consists of hand crafted and/or programmatically produced notes ,
for example in data narratives, book(lets) and TiddlyWiki tiddlers of tens or hundreds of notes at most,
unevenly produced between hours, days and/or weeks..
"
Class {
#name : #NanoID,
#superclass : #Object,
#category : #'MiniDocs-MiniDocs'
}
{ #category : #accessing }
NanoID class >> binaryFile [
^ MiniDocs appFolder / self scriptSourceCode basenameWithoutExtension
]
{ #category : #accessing }
NanoID class >> generate [
self binaryFile exists ifFalse: [ NanoID install].
OSSUnixSubprocess new
command: self binaryFile fullName;
redirectStdout;
redirectStdout;
runAndWaitOnExitDo: [ :process :outString | ^ outString copyWithoutAll: (Character lf asString) ]
]
{ #category : #accessing }
NanoID class >> install [
"For the moment, only Gnu/Linux and Mac are supported.
IMPORTANT: Nimble, Nim's package manager should be installed, as this process doesn't verify its proper installation."
self binaryFile exists ifTrue: [ ^ MiniDocs appFolder ].
Nimble install: 'nanoid'.
OSSUnixSubprocess new
command: 'nim';
arguments: {'c'. self scriptSourceCode fullName};
runAndWaitOnExitDo: [ :process :outString |
(self scriptSourceCode parent / (self scriptSourceCode) basenameWithoutExtension) moveTo: MiniDocs appFolder asFileReference.
^ MiniDocs appFolder ]
]
{ #category : #accessing }
NanoID class >> scriptSourceCode [
^ FileLocator image parent / 'pharo-local/iceberg/Offray/MiniDocs/src/nanoIdGen.nim'
]

View File

@ -1,66 +1,66 @@
"
I'm a helper class modelling the common uses of the Nim's [Nimble package manager](https://github.com/nim-lang/nimble).
This was evolved in the context of the [Grafoscopio](mutabit.com/grafoscopio/en.html) community exploration and prototyping of interactive documentation.
"
Class {
#name : #Nimble,
#superclass : #Object,
#category : #'MiniDocs-MiniDocs'
}
{ #category : #accessing }
Nimble class >> detect: packageName [
^ self installed
detect: [ :dependency | dependency beginsWith: packageName ]
ifFound: [ ^ true ]
ifNone: [ ^ false ]
]
{ #category : #accessing }
Nimble class >> install: packageName [
(self detect: packageName) ifTrue: [ ^ self ].
self installPackagesList.
OSSUnixSubprocess new
command: 'nimble';
arguments: {'install'.
packageName};
redirectStdout;
runAndWaitOnExitDo: [ :process :outString | ^ outString ]
]
{ #category : #accessing }
Nimble class >> installPackagesList [
(FileLocator home / '.nimble' / 'packages_official.json') exists
ifTrue: [ ^ self ].
OSSUnixSubprocess new
command: 'nimble';
arguments: #('refresh');
redirectStdout;
runAndWaitOnExitDo: [ :process :outString | ^ outString ]
]
{ #category : #accessing }
Nimble class >> installed [
| installed |
OSSUnixSubprocess new
command: 'nimble';
arguments: #('list' '--installed');
redirectStdout;
redirectStderr;
runAndWaitOnExitDo: [ :process :outString :errString |
process isSuccess
ifTrue: [ ^ outString lines ];
ifFalse: [ ^ nil ]
]
]
{ #category : #accessing }
Nimble class >> version [
OSSUnixSubprocess new
command: 'nimble';
arguments: #('--version');
redirectStdout;
runAndWaitOnExitDo: [ :process :outString | ^ outString ]
]
"
I'm a helper class modelling the common uses of the Nim's [Nimble package manager](https://github.com/nim-lang/nimble).
This was evolved in the context of the [Grafoscopio](mutabit.com/grafoscopio/en.html) community exploration and prototyping of interactive documentation.
"
Class {
#name : #Nimble,
#superclass : #Object,
#category : #'MiniDocs-MiniDocs'
}
{ #category : #accessing }
Nimble class >> detect: packageName [
^ self installed
detect: [ :dependency | dependency beginsWith: packageName ]
ifFound: [ ^ true ]
ifNone: [ ^ false ]
]
{ #category : #accessing }
Nimble class >> install: packageName [
(self detect: packageName) ifTrue: [ ^ self ].
self installPackagesList.
OSSUnixSubprocess new
command: 'nimble';
arguments: {'install'.
packageName};
redirectStdout;
runAndWaitOnExitDo: [ :process :outString | ^ outString ]
]
{ #category : #accessing }
Nimble class >> installPackagesList [
(FileLocator home / '.nimble' / 'packages_official.json') exists
ifTrue: [ ^ self ].
OSSUnixSubprocess new
command: 'nimble';
arguments: #('refresh');
redirectStdout;
runAndWaitOnExitDo: [ :process :outString | ^ outString ]
]
{ #category : #accessing }
Nimble class >> installed [
| installed |
OSSUnixSubprocess new
command: 'nimble';
arguments: #('list' '--installed');
redirectStdout;
redirectStderr;
runAndWaitOnExitDo: [ :process :outString :errString |
process isSuccess
ifTrue: [ ^ outString lines ];
ifFalse: [ ^ nil ]
]
]
{ #category : #accessing }
Nimble class >> version [
OSSUnixSubprocess new
command: 'nimble';
arguments: #('--version');
redirectStdout;
runAndWaitOnExitDo: [ :process :outString | ^ outString ]
]

View File

@ -1,70 +1,70 @@
Class {
#name : #PubPubGrammar,
#superclass : #PP2CompositeNode,
#instVars : [
'document',
'link',
'linkLabel',
'linkContent',
'imageLinkLabel',
'imageLinkContent',
'alternativeImages',
'imageLink'
],
#category : #'MiniDocs-Model'
}
{ #category : #accessing }
PubPubGrammar >> alternativeImages [
^ self linkContent
]
{ #category : #accessing }
PubPubGrammar >> document [
^ (link / imageLink ) islandInSea star
]
{ #category : #links }
PubPubGrammar >> imageLink [
^ imageLinkLabel, imageLinkContent, alternativeImages
]
{ #category : #links }
PubPubGrammar >> imageLinkContent [
^ '(' asPParser, #any asPParser starLazy flatten, ')' asPParser ==> #second
]
{ #category : #links }
PubPubGrammar >> imageLinkLabel [
^ '![' asPParser, #any asPParser starLazy flatten, $] asPParser ==> #second
]
{ #category : #accessing }
PubPubGrammar >> imageLinkSea [
^ imageLink sea ==> #second
]
{ #category : #links }
PubPubGrammar >> link [
^ linkLabel, linkContent
]
{ #category : #links }
PubPubGrammar >> linkContent [
^ '{' asPParser, #any asPParser starLazy flatten, '}' asPParser ==> #second.
]
{ #category : #links }
PubPubGrammar >> linkLabel [
^ $[ asPParser, #any asPParser starLazy flatten, $] asPParser ==> #second.
]
{ #category : #accessing }
PubPubGrammar >> linkSea [
^ link sea ==> #second
]
{ #category : #accessing }
PubPubGrammar >> start [
^ document
]
Class {
#name : #PubPubGrammar,
#superclass : #PP2CompositeNode,
#instVars : [
'document',
'link',
'linkLabel',
'linkContent',
'imageLinkLabel',
'imageLinkContent',
'alternativeImages',
'imageLink'
],
#category : #'MiniDocs-Model'
}
{ #category : #accessing }
PubPubGrammar >> alternativeImages [
^ self linkContent
]
{ #category : #accessing }
PubPubGrammar >> document [
^ (link / imageLink ) islandInSea star
]
{ #category : #links }
PubPubGrammar >> imageLink [
^ imageLinkLabel, imageLinkContent, alternativeImages
]
{ #category : #links }
PubPubGrammar >> imageLinkContent [
^ '(' asPParser, #any asPParser starLazy flatten, ')' asPParser ==> #second
]
{ #category : #links }
PubPubGrammar >> imageLinkLabel [
^ '![' asPParser, #any asPParser starLazy flatten, $] asPParser ==> #second
]
{ #category : #accessing }
PubPubGrammar >> imageLinkSea [
^ imageLink sea ==> #second
]
{ #category : #links }
PubPubGrammar >> link [
^ linkLabel, linkContent
]
{ #category : #links }
PubPubGrammar >> linkContent [
^ '{' asPParser, #any asPParser starLazy flatten, '}' asPParser ==> #second.
]
{ #category : #links }
PubPubGrammar >> linkLabel [
^ $[ asPParser, #any asPParser starLazy flatten, $] asPParser ==> #second.
]
{ #category : #accessing }
PubPubGrammar >> linkSea [
^ link sea ==> #second
]
{ #category : #accessing }
PubPubGrammar >> start [
^ document
]

View File

@ -1,24 +1,24 @@
Class {
#name : #PubPubGrammarTest,
#superclass : #PP2CompositeNodeTest,
#category : #'MiniDocs-Model'
}
{ #category : #accessing }
PubPubGrammarTest >> parserClass [
^ PubPubGrammar
]
{ #category : #accessing }
PubPubGrammarTest >> testImageLink [
self
parse: '![This is an image label](this/is/an/image/link){this are alternate image sizes}'
rule: #imageLink
]
{ #category : #accessing }
PubPubGrammarTest >> testLink [
self
parse: '[This is a label]{this/is/a/link}'
rule: #link
]
Class {
#name : #PubPubGrammarTest,
#superclass : #PP2CompositeNodeTest,
#category : #'MiniDocs-Model'
}
{ #category : #accessing }
PubPubGrammarTest >> parserClass [
^ PubPubGrammar
]
{ #category : #accessing }
PubPubGrammarTest >> testImageLink [
self
parse: '![This is an image label](this/is/an/image/link){this are alternate image sizes}'
rule: #imageLink
]
{ #category : #accessing }
PubPubGrammarTest >> testLink [
self
parse: '[This is a label]{this/is/a/link}'
rule: #link
]

View File

@ -1,8 +1,8 @@
Extension { #name : #String }
{ #category : #'*MiniDocs' }
String >> asDashedLowercase [
"I convert phrases like 'This is a phrase' into 'this-is-a-phrase'."
^ '-' join: (self substrings collect: [:each | each asLowercase ])
]
Extension { #name : #String }
{ #category : #'*MiniDocs' }
String >> asDashedLowercase [
"I convert phrases like 'This is a phrase' into 'this-is-a-phrase'."
^ '-' join: (self substrings collect: [:each | each asLowercase ])
]

View File

@ -1 +1 @@
Package { #name : #MiniDocs }
Package { #name : #MiniDocs }