Compare commits

..

No commits in common. "master" and "gt-crashes/2" have entirely different histories.

58 changed files with 628 additions and 2652 deletions

View File

@ -11,29 +11,20 @@ BaselineOfMiniDocs >> baseline: spec [
for: #common for: #common
do: [ do: [
"Dependencies" "Dependencies"
self setUpTeapot: spec.
self setUpPetitParser: spec.
self setUpLepiterBuildingBlocs: spec. "working in v1.0.993"
spec spec
baseline: 'Mustache' with: [ spec repository: 'github://noha/mustache' ]; baseline: 'Mustache' with: [ spec repository: 'github://noha/mustache' ];
baseline: 'Temple' with: [ spec repository: 'github://astares/Pharo-Temple/src' ];
baseline: 'Tealight' with: [ spec repository: 'github://astares/Tealight:main/src' ]; baseline: 'Tealight' with: [ spec repository: 'github://astares/Tealight:main/src' ];
baseline: 'DataFrame' with: [ spec repository: 'github://PolyMathOrg/DataFrame/src' ]. baseline: 'PetitParser' with: [
spec
loads: #('Minimal' 'Core' 'Tests' 'Islands');
repository: 'github://moosetechnology/PetitParser:v3.x.x/src'
].
"self fossil: spec." "self fossil: spec."
self xmlParserHTML: spec.
"Packages" "Packages"
spec spec
package: 'PetitMarkdown' with: [ spec requires: #('PetitParser')]; package: 'PetitMarkdown' with: [ spec requires: #('PetitParser')];
package: 'MiniDocs' package: 'MiniDocs' with: [ spec requires: #('Mustache' 'Tealight' 'PetitMarkdown')].
with: [ spec requires: #(
'Mustache' 'Temple' "Templating"
'Teapot' 'Tealight' "Web server"
'PetitMarkdown' 'PetitParser' "Parsers"
'DataFrame' "Tabular data"
'LepiterBuildingBlocs' "Lepiter utilities")].
.
"Groups" "Groups"
@ -46,7 +37,7 @@ BaselineOfMiniDocs >> baseline: spec [
BaselineOfMiniDocs >> fossil: spec [ BaselineOfMiniDocs >> fossil: spec [
| repo | | repo |
repo := ExoRepo new repo := ExoRepo new
repository: 'https://code.sustrato.red/Offray/Fossil'. repository: 'https://code.tupale.co/Offray/Fossil'.
repo load. repo load.
spec baseline: 'Fossil' with: [ spec repository: 'gitlocal://', repo local fullName ] spec baseline: 'Fossil' with: [ spec repository: 'gitlocal://', repo local fullName ]
] ]
@ -56,41 +47,15 @@ BaselineOfMiniDocs >> semanticVersion [
^ '0.2.0' ^ '0.2.0'
] ]
{ #category : #accessing }
BaselineOfMiniDocs >> setUpLepiterBuildingBlocs: spec [
spec
baseline: 'LepiterBuildingBlocs'
with: [spec repository: 'github://botwhytho/LepiterBuildingBlocs:main/src']
]
{ #category : #accessing }
BaselineOfMiniDocs >> setUpPetitParser: spec [
spec
baseline: 'PetitParser'
with: [ spec
repository: 'github://moosetechnology/PetitParser:v3.x.x/src';
loads: #('Minimal' 'Core' 'Tests' 'Islands')];
import: 'PetitParser'
]
{ #category : #accessing }
BaselineOfMiniDocs >> setUpTeapot: spec [
spec
baseline: 'Teapot'
with: [ spec
repository: 'github://zeroflag/Teapot/source';
loads: #('ALL') ];
import: 'Teapot'
]
{ #category : #accessing } { #category : #accessing }
BaselineOfMiniDocs >> xmlParserHTML: spec [ BaselineOfMiniDocs >> xmlParserHTML: spec [
Metacello new
spec baseline: 'XMLParserHTML';
baseline: 'XMLParserHTML' repository: 'github://pharo-contributions/XML-XMLParserHTML/src';
with: [ spec onConflict: [ :ex | ex useLoaded ];
repository: 'github://ruidajo/XML-XMLParserHTML/src'; onUpgrade: [ :ex | ex useLoaded ];
loads: #('ALL')]; onDowngrade: [ :ex | ex useLoaded ];
import: 'XMLParserHTML' onWarningLog;
load.
spec baseline: 'XMLParserHTML' with: [spec repository: 'github://pharo-contributions/XML-XMLParserHTML/src']
] ]

View File

@ -1,18 +0,0 @@
"
I model a possible bridge between TaskWarrior and MiniDocs. (starting DRAFT).
"
Class {
#name : #AcroReport,
#superclass : #Object,
#category : #MiniDocs
}
{ #category : #accessing }
AcroReport class >> project: projectName [
| jsonReport |
jsonReport := (GtSubprocessWithInMemoryOutput new
shellCommand: 'task project:', projectName , ' export';
runAndWait;
stdout).
^ STONJSON fromString: jsonReport
]

View File

@ -1,57 +0,0 @@
Class {
#name : #AlphanumCounter,
#superclass : #Object,
#instVars : [
'letters',
'digits',
'currentLetter',
'currentDigit'
],
#category : #MiniDocs
}
{ #category : #accessing }
AlphanumCounter >> current [
^ self currentLetter asString, self currentDigit asString
]
{ #category : #accessing }
AlphanumCounter >> currentDigit [
^ currentDigit ifNil: [ currentDigit := self digits first ]
]
{ #category : #accessing }
AlphanumCounter >> currentLetter [
^ currentLetter ifNil: [ currentLetter := self letters first ]
]
{ #category : #accessing }
AlphanumCounter >> currentLetterIndex [
^ self letters detectIndex: [:n | n = self currentLetter]
]
{ #category : #accessing }
AlphanumCounter >> digits [
^ digits ifNil: [ digits := 1 to: 9 ]
]
{ #category : #accessing }
AlphanumCounter >> digits: aNumbersArray [
digits := aNumbersArray
]
{ #category : #accessing }
AlphanumCounter >> increase [
(self currentDigit < self digits last)
ifTrue: [ currentDigit := currentDigit + 1 ]
ifFalse: [
currentLetter := self letters at: (self currentLetterIndex + 1).
currentDigit := self digits first
]
]
{ #category : #accessing }
AlphanumCounter >> letters [
^ letters ifNil: [ letters := $A to: $Z ]
]

View File

@ -1,45 +0,0 @@
Extension { #name : #Array }
{ #category : #'*MiniDocs' }
Array >> bagOfWordsFor: sentenceArray [
"An utility machine training little algorithm.
Inspired by https://youtu.be/8qwowmiXANQ?t=1144.
This should be moved probably to [Polyglot](https://github.com/pharo-ai/Polyglot),
but the repository is pretty innactive (with commits 2 or more years old and no reponse to issues).
Meanwhile, it will be in MiniDocs.
Given the sentence := #('hello' 'how' 'are' 'you')
and the testVocabulary := #('hi' 'hello' 'I' 'you' 'bye' 'thank' 'you')
then
testVocabulary bagOfWordsFor: sentence.
Should give: #(0 1 0 1 0 0 0)
"
| bagOfWords |
bagOfWords := Array new: self size.
bagOfWords doWithIndex: [:each :i | bagOfWords at: i put: 0 ].
sentenceArray do: [:token | |index|
index := self indexOf: token.
index > 0
ifTrue: [bagOfWords at: index put: 1]
].
^ bagOfWords
]
{ #category : #'*MiniDocs' }
Array >> replaceWithUniqueNilsAndBooleans [
| response |
(self includesAny: #(true false nil))
ifFalse: [ response := self ]
ifTrue: [ | newItem |
response := OrderedCollection new.
self do: [:item |
(item isBoolean or: [ item isNil ])
ifTrue: [ newItem := item asString, '-', (NanoID generate copyFrom: 1 to: 3) ]
ifFalse: [ newItem := item ].
response add: newItem.
].
].
^ response
]

View File

@ -1,12 +0,0 @@
Extension { #name : #ByteString }
{ #category : #'*MiniDocs' }
ByteString >> asHTMLComment [
^ '<!-- ', self , ' -->'
]
{ #category : #'*MiniDocs' }
ByteString >> email [
"Quick fix for importing Lepiter pages that have a plain ByteString field as email."
^ self
]

View File

@ -1,46 +0,0 @@
Extension { #name : #DataFrame }
{ #category : #'*MiniDocs' }
DataFrame >> asMarkdown [
| response |
response := '' writeStream.
self columnNames do: [ :name | response nextPutAll: '| ' , name , ' ' ].
response
nextPutAll: '|';
cr.
self columns size timesRepeat: [ response nextPutAll: '|---' ].
response
nextPutAll: '|';
cr.
self asArrayOfRows
do: [ :row |
row do: [ :cell | response nextPutAll: '| ' , cell asString , ' ' ].
response
nextPutAll: '|';
cr ].
^ response contents accentedCharactersCorrection withInternetLineEndings.
]
{ #category : #'*MiniDocs' }
DataFrame >> viewDataFor: aView [
<gtView>
| columnedList |
self numberOfRows >= 1 ifFalse: [ ^ aView empty ].
columnedList := aView columnedList
title: 'Data';
items: [ self transposed columns ];
priority: 40.
self columnNames
withIndexDo: [:aName :anIndex |
columnedList
column: aName
text: [:anItem | anItem at: anIndex ]
].
^ columnedList
]
{ #category : #'*MiniDocs' }
DataFrame >> webView [
^ Pandoc convertString: self asMarkdown from: 'markdown' to: 'html'
]

View File

@ -1,6 +0,0 @@
Extension { #name : #Dictionary }
{ #category : #'*MiniDocs' }
Dictionary >> treeView [
^ self asOrderedDictionary treeView
]

View File

@ -1,53 +0,0 @@
Extension { #name : #FileLocator }
{ #category : #'*MiniDocs' }
FileLocator class >> aliases [
| fileAliases |
fileAliases := self fileAliases.
fileAliases exists
ifFalse: [ | initialConfig |
initialConfig := Dictionary new.
fileAliases ensureCreateFile.
MarkupFile exportAsFileOn: fileAliases containing: initialConfig
].
^ STON fromString: fileAliases contents
]
{ #category : #'*MiniDocs' }
FileLocator class >> atAlias: aString put: aFolderOrFile [
| updatedAliases |
updatedAliases:= self aliases
at: aString put: aFolderOrFile;
yourself.
MarkupFile exportAsFileOn: self fileAliases containing: updatedAliases.
^ updatedAliases
]
{ #category : #'*MiniDocs' }
FileLocator >> extractMetadata [
"I package the functionality from [[How to extract meta information using ExifTool]],
from the GToolkit Book.
I depend on the external tool ExifTool."
| process variablesList |
process := GtSubprocessWithInMemoryOutput new
command: 'exiftool';
arguments: { self fullName}.
process errorBlock: [ :proc | ^ self error: 'Failed to run exiftool' ].
process runAndWait.
variablesList := process stdout lines collect: [ :currentLine |
| separatorIndex name value |
separatorIndex := currentLine indexOf: $:.
name := (currentLine copyFrom: 1 to: separatorIndex - 1) trimBoth.
value := (currentLine
copyFrom: separatorIndex + 1
to: currentLine size) trimBoth.
name -> value
].
^ variablesList asOrderedDictionary
]
{ #category : #'*MiniDocs' }
FileLocator class >> fileAliases [
^ MiniDocs appFolder / 'fileAliases.ston'
]

View File

@ -27,14 +27,6 @@ GrafoscopioNode class >> fromFile: aFileReference [
^ (STON fromString: aFileReference contents) first parent ^ (STON fromString: aFileReference contents) first parent
] ]
{ #category : #accessing }
GrafoscopioNode class >> fromLink: aStonLink [
| notebook |
notebook := (STON fromString: aStonLink asUrl retrieveContents utf8Decoded) first parent.
notebook addRemoteLocation: aStonLink.
^ notebook
]
{ #category : #accessing } { #category : #accessing }
GrafoscopioNode >> addRemoteLocation: anURL [ GrafoscopioNode >> addRemoteLocation: anURL [
self remoteLocations add: anURL self remoteLocations add: anURL
@ -61,11 +53,10 @@ GrafoscopioNode >> asLePage [
self root populateTimestamps. self root populateTimestamps.
page := LePage new page := LePage new
initializeTitle: 'Grafoscopio Notebook (imported)'. initializeTitle: 'Grafoscopio Notebook (imported)'.
self nodesInPreorder allButFirst self nodesInPreorder allButFirst do: [:node |
do: [:node | page addSnippet: node asSnippet ]. page addSnippet: node asSnippet ].
page latestEditTime: self root latestEditionDate. page latestEditTime: self root latestEditionDate.
page createTime: self root earliestCreationDate. page createTime: self root earliestCreationDate.
page optionAt: 'remoteLocations' put: self remoteLocations.
^ page. ^ page.
] ]

View File

@ -1,72 +0,0 @@
Extension { #name : #GtGQLSnippet }
{ #category : #'*MiniDocs' }
GtGQLSnippet >> asMarkdeep [
| output |
output := WriteStream on: ''.
(self metadata)
at: 'operation' put: self operation;
at: 'input' put: self input;
at: 'context' put: self context;
yourself.
output
nextPutAll: self metadataDiv;
nextPutAll: self markdeepCustomOpener;
nextPutAll: self asMarkdownString;
nextPut: Character lf;
nextPutAll: self markdeepCustomCloser;
nextPut: Character lf;
nextPutAll: '</div>';
nextPut: Character lf;
nextPut: Character lf.
^ output contents withInternetLineEndings
]
{ #category : #'*MiniDocs' }
GtGQLSnippet >> markdeepCustomCloser [
^ self markdeepCustomOpener
]
{ #category : #'*MiniDocs' }
GtGQLSnippet >> markdeepCustomOpener [
^ '* * *'
]
{ #category : #'*MiniDocs' }
GtGQLSnippet >> metadataDiv [
"PENDING: Shared among several snippets. Should be abstracted further?"
| output |
output := WriteStream on: ''.
output
nextPutAll: '<div st-class="' , self class greaseString , '"';
nextPut: Character lf;
nextPutAll: ' st-data="' , (STON toStringPretty: self metadata) , '">';
nextPut: Character lf.
^ output contents withInternetLineEndings.
]
{ #category : #'*MiniDocs' }
GtGQLSnippet >> metadataUpdate [
| createEmailSanitized editEmailSanitized |
createEmailSanitized := self createEmail asString withoutXMLTagDelimiters.
editEmailSanitized := self editEmail asString withoutXMLTagDelimiters.
^ OrderedDictionary new
at: 'id' put: self uidString;
at: 'parent' put: self parent uid asString36;
at: 'created' put: self createTime asString;
at: 'modified' put: self latestEditTime asString;
at: 'creator' put: createEmailSanitized;
at: 'modifier' put: editEmailSanitized;
yourself
]
{ #category : #'*MiniDocs' }
GtGQLSnippet >> sanitizeMetadata [
self metadata keysAndValuesDo: [:k :v |
(v includesAny: #($< $>))
ifTrue: [
self metadata at: k put: (v copyWithoutAll: #($< $>))
]
]
]

View File

@ -16,52 +16,12 @@ Class {
#category : #'MiniDocs-Core' #category : #'MiniDocs-Core'
} }
{ #category : #accessing }
HedgeDoc class >> fromLink: aUrl [
^ self new fromLink: aUrl
]
{ #category : #'as yet unclassified' } { #category : #'as yet unclassified' }
HedgeDoc class >> newDefault [ HedgeDoc class >> newDefault [
^ self new ^ self new
defaultServer. defaultServer.
] ]
{ #category : #accessing }
HedgeDoc >> asLePage [
| newPage sanitizedMarkdown |
sanitizedMarkdown := self bodyWithoutTitleHeader promoteMarkdownHeaders.
newPage := LePage new
initializeTitle: self title.
sanitizedMarkdown := sanitizedMarkdown markdownSplitted.
sanitizedMarkdown class = OrderedCollection ifTrue: [
sanitizedMarkdown do: [:lines | | snippet |
snippet := LeTextSnippet new
string: lines asStringWithCr;
uid: LeUID new.
newPage
addSnippet: snippet;
yourself
]
].
sanitizedMarkdown class = ByteString ifTrue: [ | snippet |
snippet := LeTextSnippet new
string: sanitizedMarkdown;
uid: LeUID new.
newPage
addSnippet: snippet;
yourself
].
newPage
incomingLinks;
splitAdmonitionSnippets.
newPage editTime: DateAndTime now.
newPage options
at: 'HedgeDoc' at: 'yamlFrontmatter' put: self metadata;
at: 'HedgeDoc' at: 'url' put: self url asString asHTMLComment.
^ newPage
]
{ #category : #accessing } { #category : #accessing }
HedgeDoc >> asMarkdeep [ HedgeDoc >> asMarkdeep [
^ Markdeep new ^ Markdeep new
@ -80,18 +40,9 @@ HedgeDoc >> asMarkdownTiddler [
created: Tiddler nowLocal. created: Tiddler nowLocal.
] ]
{ #category : #accessing }
HedgeDoc >> bodyWithoutTitleHeader [
| headerIndex |
headerIndex := self body lines
detectIndex: [ :line | line includesSubstring: self headerAsTitle ]
ifNone: [ ^ self body].
^ (self body lines copyWithoutIndex: headerIndex) asStringWithCr
]
{ #category : #accessing } { #category : #accessing }
HedgeDoc >> contents [ HedgeDoc >> contents [
^ super contents ^ body
] ]
{ #category : #accessing } { #category : #accessing }
@ -104,12 +55,6 @@ HedgeDoc >> defaultServer [
self server: 'https://docutopia.tupale.co'. self server: 'https://docutopia.tupale.co'.
] ]
{ #category : #accessing }
HedgeDoc >> fromLink: aString [
self url: aString.
self retrieveContents
]
{ #category : #'as yet unclassified' } { #category : #'as yet unclassified' }
HedgeDoc >> htmlUrl [ HedgeDoc >> htmlUrl [
| link | | link |
@ -136,7 +81,7 @@ HedgeDoc >> pad: anObject [
{ #category : #accessing } { #category : #accessing }
HedgeDoc >> retrieveContents [ HedgeDoc >> retrieveContents [
self url ifNil: [ ^ self ]. self url ifNil: [ ^ self ].
self fromString: (self url addPathSegment: 'download') retrieveContents. self contents: (self url addPathSegment: 'download') retrieveContents.
^ self. ^ self.
] ]
@ -172,18 +117,11 @@ HedgeDoc >> server: aUrlString [
{ #category : #accessing } { #category : #accessing }
HedgeDoc >> url [ HedgeDoc >> url [
url ifNotNil: [ ^ url asUrl ] ^ url asUrl
] ]
{ #category : #accessing } { #category : #accessing }
HedgeDoc >> url: anObject [ HedgeDoc >> url: anObject [
| tempUrl html |
tempUrl := anObject asZnUrl.
html := XMLHTMLParser parse: tempUrl retrieveContents.
(html xpath: '//head/meta[@name="application-name"][@content = "HedgeDoc - Ideas grow better together"]') isEmpty
ifTrue: [ self inform: 'Not a hedgedoc url'.
url := nil ].
server := tempUrl host.
url := anObject url := anObject
] ]

View File

@ -7,17 +7,17 @@ Class {
#category : #'MiniDocs-Model' #category : #'MiniDocs-Model'
} }
{ #category : #accessing }
HedgeDocGrammar >> metadataAsYAML [
"I parse the header of the hedgedoc document for YAML metadata."
^ '---' asPParser token, #any asPParser starLazy token, '---' asPParser token
]
{ #category : #accessing } { #category : #accessing }
HedgeDocGrammar >> start [ HedgeDocGrammar >> start [
| any | | any |
any := #any asPParser. any := #any asPParser.
^ (self metadataAsYAML / any starLazy), youtubeEmbeddedLink ^ (self yamlMetadata / any starLazy), youtubeEmbeddedLink
]
{ #category : #accessing }
HedgeDocGrammar >> yamlMetadata [
"I parse the header of the hedgedoc document for YAML metadata."
^ '---' asPParser token, #any asPParser starLazy token, '---' asPParser token
] ]
{ #category : #accessing } { #category : #accessing }

View File

@ -1,26 +0,0 @@
Extension { #name : #LeChangesSnippet }
{ #category : #'*MiniDocs' }
LeChangesSnippet >> metadataUpdate [
| createEmailSanitized editEmailSanitized |
createEmailSanitized := self createEmail asString withoutXMLTagDelimiters.
editEmailSanitized := self editEmail asString withoutXMLTagDelimiters.
^ OrderedDictionary new
at: 'id' put: self uidString;
at: 'parent' put: self parent uuid;
at: 'created' put: self createTime asString;
at: 'modified' put: self latestEditTime asString;
at: 'creator' put: createEmailSanitized;
at: 'modifier' put: editEmailSanitized;
yourself
]
{ #category : #'*MiniDocs' }
LeChangesSnippet >> sanitizeMetadata [
self metadata keysAndValuesDo: [:k :v |
(v includesAny: #($< $>))
ifTrue: [
self metadata at: k put: (v copyWithoutAll: #($< $>))
]
]
]

View File

@ -1,21 +0,0 @@
Extension { #name : #LeCodeSnippet }
{ #category : #'*MiniDocs' }
LeCodeSnippet >> metadataUpdate [
| surrogate |
self parent
ifNil: [ surrogate := nil]
ifNotNil: [
self parent isString
ifTrue: [ surrogate := self parent]
ifFalse: [ 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 withoutXMLTagDelimiters;
at: 'modifier' put: self editEmail asString withoutXMLTagDelimiters;
yourself
]

View File

@ -1,17 +1,28 @@
Extension { #name : #LeDatabase } Extension { #name : #LeDatabase }
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LeDatabase >> addPage2FromMarkdeep: markdeepDocTree withRemote: externalDocLocation [ LeDatabase >> addPageFromMarkdeep: markdeepDocTree withRemote: externalDocLocation [
| newPage | | remoteMetadata divSnippets snippets page |
"^ { snippets . page }" divSnippets := (markdeepDocTree xpath: '//div[@st-class]') asOrderedCollection
"Rebulding partial subtrees" collect: [ :xmlElement | xmlElement postCopy ].
"Adding unrooted subtrees to the page" snippets := divSnippets
"^ newPage" collect: [ :xmlElement |
newPage := self (xmlElement attributes at: 'st-class') = 'LeTextSnippet'
rebuildPageFromMarkdeep: markdeepDocTree ifTrue: [ LeTextSnippet new contentFrom: xmlElement ]
withRemote: externalDocLocation. ifFalse: [ (xmlElement attributes at: 'st-class') = 'LePharoSnippet'
newPage ifTrue: [ LePharoSnippet new contentFrom: xmlElement ] ] ].
childrenDo: [ :snippet | 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: (remoteMetadata at: 'creator');
editEmail: (remoteMetadata at: 'modifier').
snippets do: [ :snippet | page addSnippet: snippet ].
page children
do: [ :snippet |
(self hasBlockUID: snippet uid) (self hasBlockUID: snippet uid)
ifTrue: [ | existingPage | ifTrue: [ | existingPage |
existingPage := self pages existingPage := self pages
@ -20,56 +31,6 @@ LeDatabase >> addPage2FromMarkdeep: markdeepDocTree withRemote: externalDocLocat
^ self ] ^ self ]
ifFalse: [ snippet database: self. ifFalse: [ snippet database: self.
self registerSnippet: snippet ] ]. self registerSnippet: snippet ] ].
self addPage: newPage.
^ newPage
]
{ #category : #'*MiniDocs' }
LeDatabase >> addPageCopy: aLePage [
| pageTitle timestamp shortID page |
timestamp := DateAndTime now asString.
pageTitle := 'Copy of ', aLePage title.
page := aLePage duplicatePageWithNewName: pageTitle, timestamp.
shortID := '(id: ', (page uid asString copyFrom: 1 to: 8), ')'.
page title: (page title copyReplaceAll: timestamp with: shortID).
^ page
]
{ #category : #'*MiniDocs' }
LeDatabase >> addPageFromMarkdeep: markdeepDocTree withRemote: externalDocLocation [
| remoteMetadata divSnippets dataSnippets page |
divSnippets := (markdeepDocTree xpath: '//div[@st-class]') asOrderedCollection
collect: [ :xmlElement | xmlElement postCopy ].
remoteMetadata := Markdeep new metadataFromXML: markdeepDocTree.
"Ensuring remote metadata has consistent data"
remoteMetadata at: 'origin' put: externalDocLocation.
remoteMetadata at: 'title' ifAbsentPut: [ markdeepDocTree detectMarkdeepTitle ].
remoteMetadata at: 'id' ifAbsentPut: [UUID new asString36].
remoteMetadata at: 'created' ifAbsentPut: [ DateAndTime now] .
remoteMetadata at: 'creator' ifAbsentPut: [ 'unknown' ].
remoteMetadata at: 'modified' ifAbsentPut: [ DateAndTime now].
remoteMetadata at: 'modifier' ifAbsentPut: [ 'unknown' ].
dataSnippets := self sanitizeMarkdeepSnippets: divSnippets withMetadata: remoteMetadata.
page := LePage new.
page fromDictionary: remoteMetadata.
dataSnippets do: [:each | | snippet|
snippet := each asLepiterSnippet.
page addSnippet: snippet.
].
page children
do: [ :snippet |
(self hasBlockUID: snippet uid)
ifTrue: [ | existingPage |
existingPage := self pages
detect: [ :pageTemp | pageTemp includesSnippetUid: snippet uid ]
ifFound: [
self importErrorForLocal: existingPage withRemote: externalDocLocation.
^ self
]
ifNone: [ snippet database: self ].
]
ifFalse: [ snippet database: self ]
].
self addPage: page. self addPage: page.
^ page ^ page
] ]
@ -81,7 +42,7 @@ LeDatabase >> addPageFromMarkdeepUrl: aString [
page page
ifNotNil: [ :arg | ifNotNil: [ :arg |
self importErrorForLocal: page withRemote: aString. self importErrorForLocal: page withRemote: aString.
^ self errorCardFor: page uidString ]. ^ self ].
^ self addPageFromMarkdeep: (self docTreeForLink: aString) withRemote: aString ^ self addPageFromMarkdeep: (self docTreeForLink: aString) withRemote: aString
] ]
@ -101,10 +62,10 @@ LeDatabase >> docTreeForLink: aString [
] ]
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LeDatabase >> errorCardFor: errorKey [ LeDatabase >> errorCardFor: error [
| keepButton overwriteButton loadCopyButton errorMessageUI localPage |
| keepButton overwriteButton backupButton errorMessageUI localPage errorKey |
errorKey := error keys first.
localPage := self pageWithID: errorKey. localPage := self pageWithID: errorKey.
keepButton := BrButton new keepButton := BrButton new
aptitude: BrGlamorousButtonWithIconAndLabelAptitude; aptitude: BrGlamorousButtonWithIconAndLabelAptitude;
@ -121,28 +82,22 @@ LeDatabase >> errorCardFor: errorKey [
icon: BrGlamorousVectorIcons edit; icon: BrGlamorousVectorIcons edit;
action: [ :aButton | action: [ :aButton |
self removePage: localPage. self removePage: localPage.
aButton phlow spawnObject: (self addPageFromMarkdeepUrl: (self errors at: errorKey at: 'remote')). aButton phlow spawnObject: (self addPageFromMarkdeepUrl: (error at: errorKey at: 'remote')).
self errors removeKey: errorKey self errors removeKey: errorKey
]; ];
margin: (BlInsets left: 10). margin: (BlInsets left: 10).
loadCopyButton := BrButton new backupButton := BrButton new
aptitude: BrGlamorousButtonWithIconAndLabelAptitude; aptitude: BrGlamorousButtonWithIconAndLabelAptitude;
label: 'Load remote page as a copy'; label: 'Backup local page';
icon: BrGlamorousVectorIcons changes; icon: BrGlamorousVectorIcons changes;
action: [ :aButton | self ]; action: [ :aButton | ];
margin: (BlInsets left: 10). margin: (BlInsets left: 10).
errorMessageUI := BrEditor new errorMessageUI := BrEditor new
aptitude: BrGlamorousRegularEditorAptitude new ; aptitude: BrGlamorousRegularEditorAptitude new ;
text: (self errors at: errorKey at: 'message'); text: (error at: errorKey at: 'message');
vFitContent. vFitContent.
^ BrHorizontalPane new ^ { errorMessageUI. keepButton. overwriteButton. backupButton }
matchParent;
alignCenter;
addChild:errorMessageUI;
addChild: keepButton;
addChild: overwriteButton;
addChild: loadCopyButton
] ]
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
@ -169,34 +124,6 @@ LeDatabase >> gtViewErrorDetailsOn: aView [
]. ].
] ]
{ #category : #'*MiniDocs' }
LeDatabase >> gtViewErrorDetailsOn: aView withKey: erroKey [
<gtView>
^ aView explicit
title: 'Errors beta' 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: erroKey)
].
]
{ #category : #'*MiniDocs' }
LeDatabase >> importDocumentFrom: aURL [
| doc |
"Using file extension in URL as a cheap (non-robuts) way of detecting the kind of document.
Better file type detection should be implemented in the future."
(aURL endsWith: '.md.html') ifTrue: [ ^ self addPageFromMarkdeepUrl: aURL ].
doc := HedgeDoc fromLink: aURL asString.
^ self addPage: doc asLePage
]
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LeDatabase >> importErrorForLocal: page withRemote: externalDocLocation [ LeDatabase >> importErrorForLocal: page withRemote: externalDocLocation [
@ -227,8 +154,7 @@ LeDatabase >> importErrorForLocal: page withRemote: externalDocLocation [
at: 'remote' put: externalDocLocation; at: 'remote' put: externalDocLocation;
at: 'message' put: message ; at: 'message' put: message ;
yourself. yourself.
self errors at: id put: error. self errors at: id put: error
^ self errors at: id.
] ]
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
@ -236,77 +162,3 @@ LeDatabase >> options [
^ options ^ options
] ]
{ #category : #'*MiniDocs' }
LeDatabase >> previewSanitizedPageFromMarkdeep: markdeepDocTree withRemote: externalDocLocation [
| remoteMetadata divSnippets divSnippetsSanitized |
divSnippets := (markdeepDocTree xpath: '//div[@st-class]') asOrderedCollection
collect: [ :xmlElement | xmlElement postCopy ].
remoteMetadata := Markdeep new metadataFromXML: markdeepDocTree.
remoteMetadata at: 'origin' put: externalDocLocation.
divSnippetsSanitized := self sanitizeMarkdeepSnippets: divSnippets withMetadata: remoteMetadata.
^ { divSnippets . divSnippetsSanitized . remoteMetadata }
]
{ #category : #'*MiniDocs' }
LeDatabase >> rebuildPageFromMarkdeep: markdeepDocTree withRemote: externalDocLocation [
| newPage snippets divSnippets remoteMetadata dataSnippets |
divSnippets := (markdeepDocTree xpath: '//div[@st-class]') asOrderedCollection
collect: [ :xmlElement | xmlElement postCopy ].
remoteMetadata := Markdeep new metadataFromXML: markdeepDocTree.
remoteMetadata at: 'origin' put: externalDocLocation.
dataSnippets := self
sanitizeMarkdeepSnippets: divSnippets
withMetadata: remoteMetadata.
snippets := dataSnippets collect: [ :each | each asLepiterSnippet ].
newPage := 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: (remoteMetadata at: 'creator');
editEmail: (remoteMetadata at: 'modifier'). "^ { snippets . page }" "Rebulding partial subtrees"
snippets
do: [ :currentSnippet |
| parentSnippet |
parentSnippet := snippets
detect: [ :item | item uid asString = currentSnippet parent ]
ifNone: [ parentSnippet := 'unrooted' ].
currentSnippet parent: parentSnippet.
parentSnippet class = ByteString
ifFalse: [ parentSnippet children addChild: currentSnippet ] ]. "Adding unrooted subtrees to the page"
"^ { unrooted . newPage }."
snippets
select: [ :each | each parent = 'unrooted' ]
thenDo: [ :unrooted | newPage addSnippet: unrooted ].
^ newPage
]
{ #category : #'*MiniDocs' }
LeDatabase >> sanitizeMarkdeepSnippets: divSnippets withMetadata: remoteMetadata [
^ divSnippets collectWithIndex: [:markdeepDiv :i | | snippetData creationTime modificationTime timestampWarning |
snippetData := markdeepDiv asSnippetDictionary.
creationTime := snippetData at: 'created'.
modificationTime := snippetData at: 'modified'.
timestampWarning := [:timestamp |
'Modified timestamps: ', timestamp ,' date and time was replaced instead of nil value. See "origin" metadata for more historical traceability information.'
].
(creationTime = 'nil' and: [ modificationTime ~= 'nil' ])
ifTrue: [
snippetData redefineTimestampsBefore: modificationTime.
snippetData addErrata: (timestampWarning value: 'creation').
snippetData at: 'origin' put: (remoteMetadata at: 'origin').
].
(creationTime = 'nil' and: [ modificationTime = 'nil' ])
ifTrue: [ | timeDiff |
timeDiff := divSnippets size - i. "Suggesting that last snippets were modified after the first ones."
modificationTime := (remoteMetadata at: 'created') asDateAndTime - timeDiff seconds.
snippetData redefineTimestampsBefore: modificationTime.
snippetData addErrata: (timestampWarning value: 'creation').
snippetData addErrata: (timestampWarning value: 'modification').
snippetData at: 'origin' put: (remoteMetadata at: 'origin').
].
snippetData.
]
]

View File

@ -1,26 +0,0 @@
Extension { #name : #LeDockerSnippet }
{ #category : #'*MiniDocs' }
LeDockerSnippet >> metadataUpdate [
| createEmailSanitized editEmailSanitized |
createEmailSanitized := self createEmail asString withoutXMLTagDelimiters.
editEmailSanitized := self editEmail asString withoutXMLTagDelimiters.
^ OrderedDictionary new
at: 'id' put: self uidString;
at: 'parent' put: self parent uuid;
at: 'created' put: self createTime asString;
at: 'modified' put: self latestEditTime asString;
at: 'creator' put: createEmailSanitized;
at: 'modifier' put: editEmailSanitized;
yourself
]
{ #category : #'*MiniDocs' }
LeDockerSnippet >> sanitizeMetadata [
self metadata keysAndValuesDo: [:k :v |
(v includesAny: #($< $>))
ifTrue: [
self metadata at: k put: (v copyWithoutAll: #($< $>))
]
]
]

View File

@ -5,28 +5,3 @@ LeExampleSnippet >> asMarkdeep [
^ (WriteStream on: '') contents ^ (WriteStream on: '') contents
] ]
{ #category : #'*MiniDocs' }
LeExampleSnippet >> metadataUpdate [
| createEmailSanitized editEmailSanitized |
createEmailSanitized := self createEmail asString withoutXMLTagDelimiters.
editEmailSanitized := self editEmail asString withoutXMLTagDelimiters.
^ OrderedDictionary new
at: 'id' put: self uidString;
at: 'parent' put: self parent uuid;
at: 'created' put: self createTime asString;
at: 'modified' put: self latestEditTime asString;
at: 'creator' put: createEmailSanitized;
at: 'modifier' put: editEmailSanitized;
yourself
]
{ #category : #'*MiniDocs' }
LeExampleSnippet >> sanitizeMetadata [
self metadata keysAndValuesDo: [:k :v |
(v includesAny: #($< $>))
ifTrue: [
self metadata at: k put: (v copyWithoutAll: #($< $>))
]
]
]

View File

@ -1,26 +0,0 @@
Extension { #name : #LeGitHubSnippet }
{ #category : #'*MiniDocs' }
LeGitHubSnippet >> metadataUpdate [
| createEmailSanitized editEmailSanitized |
createEmailSanitized := self createEmail asString withoutXMLTagDelimiters.
editEmailSanitized := self editEmail asString withoutXMLTagDelimiters.
^ OrderedDictionary new
at: 'id' put: self uidString;
at: 'parent' put: self parent uuid;
at: 'created' put: self createTime asString;
at: 'modified' put: self latestEditTime asString;
at: 'creator' put: createEmailSanitized;
at: 'modifier' put: editEmailSanitized;
yourself
]
{ #category : #'*MiniDocs' }
LeGitHubSnippet >> sanitizeMetadata [
self metadata keysAndValuesDo: [:k :v |
(v includesAny: #($< $>))
ifTrue: [
self metadata at: k put: (v copyWithoutAll: #($< $>))
]
]
]

View File

@ -1,8 +0,0 @@
Extension { #name : #LeHeaderNode }
{ #category : #'*MiniDocs' }
LeHeaderNode >> headerFullName [
^ self topParent completeSource
copyFrom: self startPosition
to: self stopPosition
]

View File

@ -1,56 +0,0 @@
Extension { #name : #LeHomeDatabaseHeaderElement }
{ #category : #'*MiniDocs' }
LeHomeDatabaseHeaderElement >> importMinidocsButtonElement [
^ self userData at: 'importMinidocsButtonElement' ifAbsentPut: [ self newImportMiniDocsButton]
]
{ #category : #'*MiniDocs' }
LeHomeDatabaseHeaderElement >> initialize [
super initialize.
self initializeEditableTitleElement.
self initializeButtons.
self addChild: self toolbarElement as: #toolbar.
self toolbarElement
addItem: self editableTitleElement;
addItem: self newAddNewPageButton;
addItem: self removeButtonElement;
addItem: self importButtonElement;
addItem: self exportButtonElement;
addItem: self importMinidocsButtonElement.
self addAptitude: (BrLayoutResizerAptitude new
hInherit;
vAnyToFitContent;
hInherit: self toolbarElement;
vAnyToFitContent: self toolbarElement).
]
{ #category : #'*MiniDocs' }
LeHomeDatabaseHeaderElement >> initializeButtons [
self initializeRemoveButton.
self initializeImportButton.
self initializeExportButton.
self initializeMiniDocsImportButton.
]
{ #category : #'*MiniDocs' }
LeHomeDatabaseHeaderElement >> initializeMiniDocsImportButton [
self userData at: 'importMinidocsButtonElement' put: self newImportMiniDocsButton.
]
{ #category : #'*MiniDocs' }
LeHomeDatabaseHeaderElement >> newImportMiniDocsButton [
^ LeMiniDocsImport new
tooltip: 'Import document from link';
contentExtent: 200 @ 30
]
{ #category : #'*MiniDocs' }
LeHomeDatabaseHeaderElement >> updateToolbarButtons [
self updateRemoveButtonElement.
self exportButtonElement database: self database.
self importButtonElement database: self database.
self importMinidocsButtonElement database: self database.
]

View File

@ -1,26 +0,0 @@
Extension { #name : #LeJenkinsSnippet }
{ #category : #'*MiniDocs' }
LeJenkinsSnippet >> metadataUpdate [
| createEmailSanitized editEmailSanitized |
createEmailSanitized := self createEmail asString withoutXMLTagDelimiters.
editEmailSanitized := self editEmail asString withoutXMLTagDelimiters.
^ OrderedDictionary new
at: 'id' put: self uidString;
at: 'parent' put: self parent uuid;
at: 'created' put: self createTime asString;
at: 'modified' put: self latestEditTime asString;
at: 'creator' put: createEmailSanitized;
at: 'modifier' put: editEmailSanitized;
yourself
]
{ #category : #'*MiniDocs' }
LeJenkinsSnippet >> sanitizeMetadata [
self metadata keysAndValuesDo: [:k :v |
(v includesAny: #($< $>))
ifTrue: [
self metadata at: k put: (v copyWithoutAll: #($< $>))
]
]
]

View File

@ -1,89 +0,0 @@
Class {
#name : #LeMiniDocsImport,
#superclass : #BrButton,
#instVars : [
'contentExtent',
'database'
],
#category : #'MiniDocs-UI'
}
{ #category : #accessing }
LeMiniDocsImport >> contentExtent [
^ contentExtent
]
{ #category : #accessing }
LeMiniDocsImport >> contentExtent: aPoint [
self
assert: [ aPoint isNotNil ]
description: [ 'Extent must be non-nil' ].
contentExtent := aPoint
]
{ #category : #accessing }
LeMiniDocsImport >> createDropdownExpandedHandleButton [
^ BrButton new
icon: BrGlamorousVectorIcons downwards;
label: self tooltip;
aptitude: BrGlamorousButtonWithIconAndLabelAptitude
]
{ #category : #accessing }
LeMiniDocsImport >> createURLeditable [
| base editable |
base := BlElement new
background: (Color white);
size: 200 @ 30;
margin: (BlInsets all: 10);
yourself.
editable := BrEditableLabel new
aptitude: BrGlamorousEditableLabelAptitude new glamorousRegularFontAndSize;
text: 'Document link';
switchToEditor.
editable when: BrEditorAcceptWish do: [ :aWish |
self importDocumentFrom: aWish text asString.
].
base addChild: editable.
^ base
]
{ #category : #accessing }
LeMiniDocsImport >> database [
^ database
]
{ #category : #accessing }
LeMiniDocsImport >> database: aLeDatabase [
database := aLeDatabase
]
{ #category : #accessing }
LeMiniDocsImport >> importDocumentFrom: aURL [
^ self database importDocumentFrom: aURL.
]
{ #category : #accessing }
LeMiniDocsImport >> initialize [
super initialize.
self
icon: BrGlamorousVectorIcons downwards;
label: 'Add MiniDocs';
aptitude: BrGlamorousButtonWithIconAndLabelAptitude.
self addAptitude: (BrGlamorousWithDropdownAptitude
handle: [ self createDropdownExpandedHandleButton ]
content: [ self createURLeditable ]).
self aptitude - BrGlamorousButtonExteriorAptitude.
]
{ #category : #accessing }
LeMiniDocsImport >> tooltip [
^ self label
]
{ #category : #accessing }
LeMiniDocsImport >> tooltip: aString [
self label: aString
]

View File

@ -1,26 +0,0 @@
Extension { #name : #LeMockedSnippet }
{ #category : #'*MiniDocs' }
LeMockedSnippet >> metadataUpdate [
| createEmailSanitized editEmailSanitized |
createEmailSanitized := self createEmail asString withoutXMLTagDelimiters.
editEmailSanitized := self editEmail asString withoutXMLTagDelimiters.
^ OrderedDictionary new
at: 'id' put: self uidString;
at: 'parent' put: self parent uuid;
at: 'created' put: self createTime asString;
at: 'modified' put: self latestEditTime asString;
at: 'creator' put: createEmailSanitized;
at: 'modifier' put: editEmailSanitized;
yourself
]
{ #category : #'*MiniDocs' }
LeMockedSnippet >> sanitizeMetadata [
self metadata keysAndValuesDo: [:k :v |
(v includesAny: #($< $>))
ifTrue: [
self metadata at: k put: (v copyWithoutAll: #($< $>))
]
]
]

View File

@ -3,7 +3,7 @@ Extension { #name : #LePage }
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LePage >> asHtmlFile [ LePage >> asHtmlFile [
self asMarkdownFileWithMetadataWrappers. self asMarkdownFile.
self defaultPandocTemplate exists self defaultPandocTemplate exists
ifFalse: [ MarkupFile installTemplate: 'https://mutabit.com/repos.fossil/mutabit/doc/trunk/plantillas/Pandoc/clean-menu-mod.html' into: self defaultPandocTemplate parent ]. ifFalse: [ MarkupFile installTemplate: 'https://mutabit.com/repos.fossil/mutabit/doc/trunk/plantillas/Pandoc/clean-menu-mod.html' into: self defaultPandocTemplate parent ].
@ -21,23 +21,29 @@ LePage >> asHtmlFile [
LePage >> asMarkdeep [ LePage >> asMarkdeep [
| bodyStream markdeep | | bodyStream markdeep |
bodyStream := '' writeStream. bodyStream := '' writeStream.
bodyStream nextPutAll: self notebookMetadataSnippet asMarkdeep. self preorderTraversal do: [:snippet |
self preorderTraversal bodyStream nextPutAll: snippet asMarkdeep
do: [ :snippet | bodyStream nextPutAll: snippet asMarkdeep ]. ].
markdeep := Markdeep new markdeep := Markdeep new
title: self title; title: self title;
body: bodyStream contents; body: bodyStream contents;
metadata: self metadata; navTop: self navTop.
file: self storage / self markdeepFileName; self metadata keysAndValuesDo: [:k :v |
navTop: self navTop. k = 'lang'
self metadata ifTrue: [
at: 'authors' markdeep head
ifPresent: [ :author | markdeep metadata at: 'authors' put: author ]. add: '<meta lang="', v,'">';
self metadata yourself.
at: 'version' ]
ifPresent: [ :version | markdeep metadata at: 'version' put: version ]. ifFalse: [
markdeep head: nil. markdeep head
^ markdeep 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' } { #category : #'*MiniDocs' }
@ -48,49 +54,27 @@ LePage >> asMarkdeepFile [
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LePage >> asMarkdown [ LePage >> asMarkdown [
"PENDING: to debug the output."
| bodyStream markdown | | bodyStream markdown |
bodyStream := '' writeStream. bodyStream := '' writeStream.
bodyStream bodyStream
nextPutAll: '# ', self title; cr; cr. nextPutAll: '---';
nextPutAll: String lf.
self metadata keysAndValuesDo: [ :k :v |
bodyStream
nextPutAll: k , ': "' , v, '"';
nextPutAll: String lf ].
bodyStream nextPutAll: '---' , String lf , String lf.
self preorderTraversal self preorderTraversal
do: [ :snippet | bodyStream nextPutAll: snippet asMarkdown ]. do: [ :snippet | bodyStream nextPutAll: snippet asMarkdown ].
markdown := Markdown new markdown := Markdown new contents: bodyStream contents.
contents: bodyStream contents promoteMarkdownHeaders;
metadata: (self metadata at: 'original' ifAbsentPut: Dictionary new).
^ markdown ^ markdown
] ]
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LePage >> asMarkdownFileWithMetadataWrappers [ LePage >> asMarkdownFile [
| folder | | folder |
folder := self storage. folder := self storage.
^ MarkupFile exportAsFileOn: folder / self markdownFileName containing: self asMarkdownWithMetadataWrappers contents ^ MarkupFile exportAsFileOn: folder / self markdownFileName containing: self asMarkdown contents
]
{ #category : #'*MiniDocs' }
LePage >> asMarkdownWithMetadataWrappers [
| bodyStream markdown |
bodyStream := '' writeStream.
"bodyStream
nextPut: Character lf;
nextPutAll: '# ', self title; cr; cr."
self preorderTraversal
do: [ :snippet | bodyStream nextPutAll: snippet asMarkdownWithMetadataWrappers ].
markdown := Markdown new
contents: bodyStream contents promoteMarkdownHeaders;
title: self title;
metadata: self metadata.
^ markdown
]
{ #category : #'*MiniDocs' }
LePage >> config [
| configFile |
configFile := self storage / 'config.ston'.
configFile exists
ifTrue: [^ STON fromString: configFile contents ]
ifFalse: [ ^ nil ]
] ]
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
@ -101,52 +85,18 @@ LePage >> defaultPandocTemplate [
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LePage >> detectParentSnippetWithUid: uidString [ LePage >> detectParentSnippetWithUid: uidString [
uidString = self uid asString36 ifTrue: [ ^ self ]. "Answer a boolean indicating whether the supplied uid is present"
^ self preorderTraversal detect: [ :snippet | snippet uidString = uidString ]
]
{ #category : #'*MiniDocs' } ^ self preorderTraversal detect: [ :snippet | snippet uidString = uidString ] ifNone: [ ^ self ]
LePage >> exportMetadataToHead: markdeep [
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 ] ]
] ]
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LePage >> exportedFileName [ LePage >> exportedFileName [
| sanitized titleWords shortTitle | | sanitized |
titleWords := self title splitOn: Character space. sanitized := self title asDashedLowercase romanizeAccents copyWithoutAll: #($/ $:).
(titleWords size > 11)
ifTrue: [
titleWords := titleWords copyFrom: 1 to: 3.
shortTitle := titleWords joinUsing: Character space.
]
ifFalse: [shortTitle := self title].
sanitized := shortTitle asDashedLowercase romanizeAccents copyWithoutAll: #($/ $: $🢒 $,).
^ sanitized , '--' , (self uidString copyFrom: 1 to: 5) ^ sanitized , '--' , (self uidString copyFrom: 1 to: 5)
] ]
{ #category : #'*MiniDocs' }
LePage >> fromDictionary: aDictionary [
self
title: (aDictionary at: 'title');
basicUid: (UUID fromString36: (aDictionary at: 'id'));
createTime: (LeTime new
time: (aDictionary at: 'created') asDateAndTime);
editTime: (LeTime new
time: (aDictionary at: 'modified') asDateAndTime);
latestEditTime: (LeTime new
time: (aDictionary at: 'modified') asDateAndTime);
createEmail: (aDictionary at: 'creator');
editEmail: (aDictionary at: 'modifier').
]
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LePage >> fromMarkdeepUrl: aString [ LePage >> fromMarkdeepUrl: aString [
| docTree pageMetadata | | docTree pageMetadata |
@ -179,11 +129,8 @@ LePage >> latestEditTime: aLeTime [
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LePage >> localHostAddress [ LePage >> localHostAddress [
| localUrl route | | localUrl route |
MiniDocsServer teapot server isRunning ifFalse: [ MiniDocsServer restart ]. MiniDocsServer teapot server isRunning ifFalse: [ MiniDocsServer start ].
route := self storage path segments joinUsing: '/'. route := MiniDocsServer teapot staticRouter prefix joinUsing: '/'.
MiniDocsServer teapot
serveStatic: ('/', route, '/', self markdeepFileName)
from: self storage / self markdeepFileName.
localUrl := MiniDocsServer teapot server localUrl asString. localUrl := MiniDocsServer teapot server localUrl asString.
^ localUrl, route, '/', self markdeepFileName ^ localUrl, route, '/', self markdeepFileName
] ]
@ -202,17 +149,17 @@ LePage >> markdownFileName [
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LePage >> metadata [ LePage >> metadata [
^ self metadataUpdate ^ self options at: 'metadata' ifAbsentPut: [ self metadataInit]
] ]
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LePage >> metadataUpdate [ LePage >> metadataInit [
^ OrderedDictionary new ^ OrderedDictionary new
at: 'id' put: self uidString; at: 'id' put: self uidString;
at: 'title' put: self contentAsString; at: 'title' put: self contentAsString;
at: 'created' put: self createTime greaseString; at: 'created' put: self createTime greaseString;
at: 'modified' put: self getLatestEditTime greaseString; at: 'modified' put: self latestEditTime greaseString;
at: 'creator' put: self createEmail greaseString; at: 'creator' put: self createEmail greaseString;
at: 'modifier' put: self editEmail greaseString; at: 'modifier' put: self editEmail greaseString;
yourself yourself
@ -227,30 +174,6 @@ LePage >> navTop [
ifTrue: [ ^ topNavFile contents ] ifTrue: [ ^ topNavFile contents ]
] ]
{ #category : #'*MiniDocs' }
LePage >> notebookMetadataSnippet [
| response |
response := LeTextSnippet new fromString: '<!-- See this snippet source code for this notebook''s metadata -->'.
response parent: self.
self optionAt: 'HedgeDoc' ifAbsent: [ ^ response ].
(response extra)
at: 'HedgeDoc' put: (self optionAt: 'HedgeDoc').
^ response
]
{ #category : #'*MiniDocs' }
LePage >> olderChild [
"I provide the last edited child node.
I'm useful to recalculate the age of a notebook."
| response|
response := self preorderTraversal first.
self preorderTraversal do: [:current |
current editTime >= response editTime
ifTrue: [ response := current ]
].
^ response
]
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LePage >> options [ LePage >> options [
^ options ^ options
@ -268,11 +191,6 @@ LePage >> removeSnippetsMetadata [
ifTrue: [ snippet options removeKey: 'metadata' ] ] ifTrue: [ snippet options removeKey: 'metadata' ] ]
] ]
{ #category : #'*MiniDocs' }
LePage >> sanitizeMetadata [
self allChildrenDepthFirst do: [:snippet | snippet sanitizeMetadata ]
]
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LePage >> sharedVariablesBindings [ LePage >> sharedVariablesBindings [
| codeSnippets shared | | codeSnippets shared |
@ -297,25 +215,6 @@ LePage >> sharedVariablesBindings [
^ shared asDictionary ^ shared asDictionary
] ]
{ #category : #'*MiniDocs' }
LePage >> splitAdmonitionSnippets [
"I'm used to clean after importing from HedgeDoc to ensure that a snippet contains only admonitions and extra content is put in a new cell."
| admonitionSnippets |
admonitionSnippets := self children select: [:node | node string startsWithMarkdownAdmonition ].
admonitionSnippets ifEmpty: [ ^ self ].
admonitionSnippets do: [:node | | nodeContent |
node ifNotNil: [
nodeContent := node string.
nodeContent startsWithMarkdownAdmonition
ifTrue: [ | snippetCommand |
snippetCommand := node splitSnippetCommandAtPosition: nodeContent admonitionEndingPosition.
snippetCommand execute.
node tagWith: (nodeContent lines first trimBoth withoutPrefix: ':::')
]
]
]
]
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LePage >> storage [ LePage >> storage [
| current | | current |
@ -325,15 +224,6 @@ LePage >> storage [
^ self optionAt: 'storage' ^ self optionAt: 'storage'
] ]
{ #category : #'*MiniDocs' }
LePage >> uiAddCopyButtonFor: anAction [
<lePageAction>
^ anAction button
tooltip: 'Export Page';
icon: BrGlamorousVectorIcons changes;
action: [:aButton | aButton phlow spawnObject: (self page database addPageCopy: self page) ]
]
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LePage >> uiDefineFolderFor: anAction [ LePage >> uiDefineFolderFor: anAction [
<lePageAction> <lePageAction>
@ -369,16 +259,3 @@ LePage >> uiRefreshWebPreviewButtonFor: anAction [
"TODO: If Chrome/Chromium are not installed, I should execute:" "TODO: If Chrome/Chromium are not installed, I should execute:"
"WebBrowser openOn: self page localHostAddress" ] "WebBrowser openOn: self page localHostAddress" ]
] ]
{ #category : #'*MiniDocs' }
LePage >> youngerChild [
"I provide the first create child node.
I'm useful to recalculate the age of a notebook."
| response|
response := self preorderTraversal first.
self preorderTraversal do: [:current |
current createTime <= response createTime
ifTrue: [ response := current ]
].
^ response
]

View File

@ -1,26 +0,0 @@
Extension { #name : #LePharoRewriteSnippet }
{ #category : #'*MiniDocs' }
LePharoRewriteSnippet >> metadataUpdate [
| createEmailSanitized editEmailSanitized |
createEmailSanitized := self createEmail asString withoutXMLTagDelimiters.
editEmailSanitized := self editEmail asString withoutXMLTagDelimiters.
^ OrderedDictionary new
at: 'id' put: self uidString;
at: 'parent' put: self parent uuid;
at: 'created' put: self createTime asString;
at: 'modified' put: self latestEditTime asString;
at: 'creator' put: createEmailSanitized;
at: 'modifier' put: editEmailSanitized;
yourself
]
{ #category : #'*MiniDocs' }
LePharoRewriteSnippet >> sanitizeMetadata [
self metadata keysAndValuesDo: [:k :v |
(v includesAny: #($< $>))
ifTrue: [
self metadata at: k put: (v copyWithoutAll: #($< $>))
]
]
]

View File

@ -9,26 +9,21 @@ LePharoSnippet >> contentAsStringCustomized [
] ]
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LePharoSnippet >> fromDictionary: anOrderedDictionary [ LePharoSnippet >> contentFrom: markdeepDiv [
self
uid: (LeUID new uidString: (anOrderedDictionary at: 'id'));
parent: (anOrderedDictionary at: 'parent');
createTime: (LeTime new time: ((anOrderedDictionary at: 'created')asDateAndTime));
editTime: (LeTime new time: ((anOrderedDictionary at: 'modified') asDateAndTime));
editEmail: (anOrderedDictionary at: 'modifier');
createEmail: (anOrderedDictionary at: 'creator').
]
{ #category : #'*MiniDocs' } | sanitizedStringText metadata joinedText |
LePharoSnippet >> fromMarkdeep: markdeepDiv [ metadata := STON fromString: (markdeepDiv attributes at: 'st-data').
sanitizedStringText := markdeepDiv contentString lines.
^ markdeepDiv asSnippetDictionary asLepiterSnippet sanitizedStringText := sanitizedStringText copyFrom: 4 to: sanitizedStringText size -2.
] joinedText := '' writeStream.
sanitizedStringText do: [ :line | joinedText nextPutAll: line; nextPut: Character lf ].
{ #category : #'*MiniDocs' } self code: joinedText contents allButLast;
LePharoSnippet >> fromString: aString [ uid: (LeUID new uidString: (metadata at: 'id'));
parent: (metadata at: 'parent');
[ self coder forSource: aString ] onErrorDo: [ ] 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' } { #category : #'*MiniDocs' }

View File

@ -2,22 +2,11 @@ Extension { #name : #LePictureSnippet }
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LePictureSnippet >> asMarkdeep [ LePictureSnippet >> asMarkdeep [
| output curatedCaption captionLines | | output |
captionLines := self caption lines.
(captionLines size <= 1)
ifTrue: [ curatedCaption := caption ]
ifFalse: [
curatedCaption := WriteStream on: ''.
curatedCaption nextPutAll: captionLines first.
captionLines allButFirstDo: [:line |
curatedCaption nextPutAll: ' ', line.
curatedCaption := curatedCaption contents.
]
].
output := WriteStream on: ''. output := WriteStream on: ''.
output output
nextPutAll: self metadataDiv; nextPutAll: self metadataDiv;
nextPutAll: '![ ', curatedCaption ,' ](', self urlString, ')'; nextPutAll: '![ ', self caption ,' ](', self urlString, ')';
nextPut: Character lf; nextPut: Character lf;
nextPutAll: '</div>'; nextPutAll: '</div>';
nextPut: Character lf; nextPut: Character lf;
@ -25,60 +14,9 @@ LePictureSnippet >> asMarkdeep [
^ output contents ^ output contents
] ]
{ #category : #'*MiniDocs' }
LePictureSnippet >> asMarkdownWithMetadataWrappers [
^ self asMarkdeep
]
{ #category : #'*MiniDocs' }
LePictureSnippet >> contentFrom: markdeepDiv [
| caption width |
caption := markdeepDiv contentString.
width := (markdeepDiv // 'img' @ 'width') stringValue.
self
optionAt: 'caption' put: caption;
optionAt: 'width' put: width.
self urlString: (markdeepDiv // 'img' @ 'src') stringValue.
]
{ #category : #'*MiniDocs' }
LePictureSnippet >> fromDictionary: anOrderedDictionary [
| sanitizedUrl|
sanitizedUrl := (anOrderedDictionary at: 'url').
sanitizedUrl := sanitizedUrl copyFrom: 5 to: sanitizedUrl size - 3.
self
uid: (LeUID new uidString: (anOrderedDictionary at: 'id'));
parent: (anOrderedDictionary at: 'parent');
createTime: (LeTime new time: ((anOrderedDictionary at: 'created')asDateAndTime));
editTime: (LeTime new time: ((anOrderedDictionary at: 'modified') asDateAndTime));
editEmail: (anOrderedDictionary at: 'modifier');
createEmail: (anOrderedDictionary at: 'creator');
urlString: sanitizedUrl;
caption: (anOrderedDictionary at: 'content') first
]
{ #category : #'*MiniDocs' }
LePictureSnippet >> fromMarkdeep: markdeepDiv [
^ markdeepDiv asSnippetDictionary asLepiterSnippet
]
{ #category : #'*MiniDocs' }
LePictureSnippet >> fromString: aStringArray [
"aStringArray should contain as first element the sanitized string and
as second the full original image Link string, which may contains links in the description."
| args urlTemp |
args := aStringArray second splitOn: ']('.
urlTemp := args last.
urlTemp := urlTemp copyFrom: 1 to: urlTemp size - 1.
self caption: aStringArray first.
self urlString: urlTemp.
^ self
]
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LePictureSnippet >> metadata [ LePictureSnippet >> metadata [
^ self metadataInit ^ self optionAt: 'metadata' ifAbsentPut: [ self metadataInit ]
] ]
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
@ -88,31 +26,13 @@ LePictureSnippet >> metadataDiv [
output output
nextPutAll: '<div st-class="' , self class greaseString , '"'; nextPutAll: '<div st-class="' , self class greaseString , '"';
nextPut: Character lf; nextPut: Character lf;
nextPutAll: ' st-data="' , (STON toStringPretty: self metadata) , '">'; nextPutAll: ' st-data="' , (STON toString: self metadata) , '">'.
nextPut: Character lf. ^ output.
^ output contents withInternetLineEndings.
] ]
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LePictureSnippet >> metadataInit [ LePictureSnippet >> metadataInit [
| surrogate |
self parent
ifNil: [ surrogate := nil]
ifNotNil: [ surrogate := self parent uidString ].
^ OrderedDictionary new
at: 'id' put: self uidString;
at: 'parent' put: surrogate;
at: 'url' put: '<!--',self contentAsString, '-->';
at: 'created' put: self createTime asString;
at: 'modified' put: self latestEditTime asString;
at: 'creator' put: self createEmail asString withoutXMLTagDelimiters;
at: 'modifier' put: self editEmail asString withoutXMLTagDelimiters;
yourself
]
{ #category : #'*MiniDocs' }
LePictureSnippet >> metadataUpdate [
| surrogate | | surrogate |
self parent self parent
ifNil: [ surrogate := nil] ifNil: [ surrogate := nil]
@ -122,17 +42,7 @@ LePictureSnippet >> metadataUpdate [
at: 'parent' put: surrogate; at: 'parent' put: surrogate;
at: 'created' put: self createTime asString; at: 'created' put: self createTime asString;
at: 'modified' put: self latestEditTime asString; at: 'modified' put: self latestEditTime asString;
at: 'creator' put: self createEmail asString withoutXMLTagDelimiters; at: 'creator' put: self createEmail asString;
at: 'modifier' put: self editEmail asString withoutXMLTagDelimiters; at: 'modifier' put: self editEmail asString;
yourself yourself
] ]
{ #category : #'*MiniDocs' }
LePictureSnippet >> sanitizeMetadata [
self metadata keysAndValuesDo: [:k :v |
(v includesAny: #($< $>))
ifTrue: [
self metadata at: k put: (v copyWithoutAll: #($< $>))
]
]
]

View File

@ -1,26 +0,0 @@
Extension { #name : #LeSmaCCRewriteSnippet }
{ #category : #'*MiniDocs' }
LeSmaCCRewriteSnippet >> metadataUpdate [
| createEmailSanitized editEmailSanitized |
createEmailSanitized := self createEmail asString withoutXMLTagDelimiters.
editEmailSanitized := self editEmail asString withoutXMLTagDelimiters.
^ OrderedDictionary new
at: 'id' put: self uidString;
at: 'parent' put: self parent uuid;
at: 'created' put: self createTime asString;
at: 'modified' put: self latestEditTime asString;
at: 'creator' put: createEmailSanitized;
at: 'modifier' put: editEmailSanitized;
yourself
]
{ #category : #'*MiniDocs' }
LeSmaCCRewriteSnippet >> sanitizeMetadata [
self metadata keysAndValuesDo: [:k :v |
(v includesAny: #($< $>))
ifTrue: [
self metadata at: k put: (v copyWithoutAll: #($< $>))
]
]
]

View File

@ -7,26 +7,10 @@ LeSnippet class >> fromMetaMarkdeep: div [
metadata := STON fromString:(div xpath: '@st-data') stringValue. metadata := STON fromString:(div xpath: '@st-data') stringValue.
snippet := className asClass new. snippet := className asClass new.
snippet injectMetadataFrom: metadata. snippet injectMetadataFrom: metadata.
snippet fromMarkdeep: div. snippet contentFrom: div.
^ snippet. ^ snippet.
] ]
{ #category : #'*MiniDocs' }
LeSnippet >> metadata [
| createEmailSanitized editEmailSanitized |
createEmailSanitized := self createEmail asString withoutXMLTagDelimiters.
editEmailSanitized := self editEmail asString withoutXMLTagDelimiters.
self optionAt: 'metadata' ifAbsentPut: [ OrderedDictionary new ].
^ (self optionAt: 'metadata')
at: 'id' put: self uidString;
at: 'parent' put: self parent uid asString36;
at: 'created' put: self createTime asString;
at: 'modified' put: self latestEditTime asString;
at: 'creator' put: createEmailSanitized;
at: 'modifier' put: editEmailSanitized;
yourself
]
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LeSnippet >> moveToPageTitled: pageName [ LeSnippet >> moveToPageTitled: pageName [
| db origin destination thisSnippet | | db origin destination thisSnippet |

View File

@ -1,25 +1,5 @@
Extension { #name : #LeTextCoderSnippetElement } Extension { #name : #LeTextCoderSnippetElement }
{ #category : #'*MiniDocs' }
LeTextCoderSnippetElement >> asLePage [
| currentSnippet newPage |
currentSnippet := self snippet.
newPage := LePage new.
newPage
title: (currentSnippet text asString trimLeft: [:char | char = $# ]) trim.
self page database
addPage: newPage.
currentSnippet allChildrenBreadthFirstDo: [:child |
child moveToPageTitled: newPage title.
].
^ newPage
]
{ #category : #'*MiniDocs' }
LeTextCoderSnippetElement >> asSnippetViewModel [
^ self snippetContent
]
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LeTextCoderSnippetElement >> moveToPageTitled: pageName [ LeTextCoderSnippetElement >> moveToPageTitled: pageName [
| db origin destination | | db origin destination |

View File

@ -2,14 +2,9 @@ Extension { #name : #LeTextSnippet }
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LeTextSnippet >> asLePage [ LeTextSnippet >> asLePage [
| page title currentSnippet | | page |
title := self contentAsString markdownHeaders associations first value.
title := (title trimBoth: [:char | char = $# ]) trimmed.
page := LePage new page := LePage new
initializeTitle: title. initializeTitle: self contentAsString.
currentSnippet := LeTextSnippet new
string: self contentAsString.
page addSnippet: currentSnippet.
self database addPage: page. self database addPage: page.
self childrenDo: [:child | self childrenDo: [:child |
child moveToPageTitled: page title child moveToPageTitled: page title
@ -19,34 +14,39 @@ LeTextSnippet >> asLePage [
] ]
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LeTextSnippet >> fromDictionary: anOrderedDictionary [ LeTextSnippet >> contentFrom: markdeepDiv [
self
uid: (LeUID new uidString: (anOrderedDictionary at: 'id'));
parent: (anOrderedDictionary at: 'parent');
createTime: (LeTime new time: ((anOrderedDictionary at: 'created')asDateAndTime));
editTime: (LeTime new time: ((anOrderedDictionary at: 'modified') asDateAndTime));
editEmail: (anOrderedDictionary at: 'modifier');
createEmail: (anOrderedDictionary at: 'creator')
]
{ #category : #'*MiniDocs' } | sanitizedStringText metadata |
LeTextSnippet >> fromMarkdeep: markdeepDiv [ metadata := STON fromString: (markdeepDiv attributes at: 'st-data').
sanitizedStringText := markdeepDiv contentString.
^ markdeepDiv asSnippetDictionary asLepiterSnippet sanitizedStringText := sanitizedStringText allButFirst.
] sanitizedStringText := sanitizedStringText allButLast.
self string: sanitizedStringText;
{ #category : #'*MiniDocs' } uid: (LeUID new uidString: (metadata at: 'id'));
LeTextSnippet >> fromString: aString [ parent: (metadata at: 'parent');
createTime: (LeTime new time: ((metadata at: 'created')asDateAndTime));
self editTime: (LeTime new time: ((metadata at: 'modified') asDateAndTime));
string: aString; editEmail: (metadata at: 'modifier');
uid: LeUID new. createEmail: (metadata at: 'creator')
] ]
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LeTextSnippet >> metadata [ LeTextSnippet >> metadata [
^ self metadataUpdate ^ 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' } { #category : #'*MiniDocs' }
@ -57,23 +57,11 @@ LeTextSnippet >> options [
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LeTextSnippet >> parentId [ LeTextSnippet >> parentId [
self parent ifNil: [ ^ self ]. self parent ifNil: [ ^ self ].
(self parent isString) ifTrue: [^ self parent].
^ self parent uidString. ^ self parent uidString.
] ]
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LeTextSnippet >> tagWith: aString [ LeTextSnippet >> taggedWith: aString [
self tags add: aString. self metadata at: 'tags' ifPresent: [ (self metadata at: 'tags') add: aString; yourself ] ifAbsentPut: [ Set new ].
] ^ self metadata at: 'tags'
{ #category : #'*MiniDocs' }
LeTextSnippet >> withFollowingSnippets [
"I'm the same method implemented for PharoSnippets,
but present also here as a way to improve moving prose snippets from pages.
"
| snippets stop start |
snippets := self parent children asArray.
start := snippets indexOf: self.
stop := snippets size.
^ snippets copyFrom: start to: stop
] ]

View File

@ -2,62 +2,45 @@ Extension { #name : #LeTextualSnippet }
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LeTextualSnippet >> asMarkdeep [ 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 |
output := WriteStream on: ''. output := WriteStream on: ''.
output output
nextPutAll: self metadataDiv; 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 markdeepCustomOpener;
nextPutAll: self contentAsStringAnnotated; nextPutAll: self contentAsString;
nextPut: Character lf; nextPut: Character lf;
nextPutAll: self markdeepCustomCloser; nextPutAll: self markdeepCustomCloser;
nextPutAll: '</div>'; nextPutAll: '</div>';
nextPut: Character lf; nextPut: Character lf;
nextPut: Character lf. nextPut: Character lf.
^ output contents withInternetLineEndings
]
{ #category : #'*MiniDocs' }
LeTextualSnippet >> asMarkdown [
| output |
output := '' writeStream.
output
nextPutAll: self contentAsStringCustomized; lf.
^ output contents ^ output contents
] ]
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LeTextualSnippet >> asMarkdownWithMetadataWrappers [ LeTextualSnippet >> asMarkdown [
"Inspired by Alpine.js and Assembler CSS 'x-' properties, we are going to use "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." 'st-' properties as a way to extend divs metadata regarding its contents."
| output | | output |
output := '' writeStream. output := '' writeStream.
output output
nextPutAll: self metadataDiv; nextPutAll: '<div st-class="', self class asString, '"'; lf;
nextPutAll: ' st-data="', (STON toString: self metadata), '">'; lf;
nextPutAll: self markdownCustomOpener; nextPutAll: self markdownCustomOpener;
nextPutAll: self contentAsStringCustomized; lf; nextPutAll: self contentAsStringCustomized; lf;
nextPutAll: self markdownCustomCloser; nextPutAll: self markdownCustomCloser;
nextPutAll: '</div>'; lf; lf. nextPutAll: '</div>'; lf; lf.
^ output contents withInternetLineEndings ^ output contents
]
{ #category : #'*MiniDocs' }
LeTextualSnippet >> contentAsStringAnnotated [
self ast ifNotNil: [ ^ self processSnippetAnnotations ].
^ self contentAsString
] ]
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LeTextualSnippet >> contentAsStringCustomized [ LeTextualSnippet >> contentAsStringCustomized [
(self contentAsString beginsWith: '#') ^ self contentAsString
ifTrue: [ ^ '#', self contentAsString ]
ifFalse: [ ^ self contentAsString ]
]
{ #category : #'*MiniDocs' }
LeTextualSnippet >> extra [
^ self optionAt: 'extra' ifAbsentPut: [ Dictionary new ]
] ]
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
@ -83,84 +66,26 @@ LeTextualSnippet >> markdownCustomOpener [
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LeTextualSnippet >> metadata [ LeTextualSnippet >> metadata [
^ self metadataUpdate ^ self optionAt: 'metadata' ifAbsentPut: [ self metadataInit ]
] ]
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LeTextualSnippet >> metadataDiv [ LeTextualSnippet >> metadataInit [
"Inspired by Alpine.js and Assembler CSS 'x-' properties, we are going to use | surrogate |
'st-' properties as a way to extend divs metadata regarding its contents." self parent
"PENDING: this is repeated in several snippets. Can be abstracted up in a common object of the class hierarchy?" ifNil: [ surrogate := nil]
| output | ifNotNil: [ surrogate := self parent uidString ].
output := WriteStream on: ''.
output
nextPutAll: '<div st-class="' , self class greaseString , '"';
nextPut: Character lf;
nextPutAll: ' st-data="' , (STON toStringPretty: self metadata) , '">';
nextPut: Character lf.
^ output contents withInternetLineEndings.
]
{ #category : #'*MiniDocs' }
LeTextualSnippet >> metadataUpdate [
| createEmailSanitized editEmailSanitized |
createEmailSanitized := self createEmail asString withoutXMLTagDelimiters.
editEmailSanitized := self editEmail asString withoutXMLTagDelimiters.
^ OrderedDictionary new ^ OrderedDictionary new
at: 'id' put: self uidString; at: 'id' put: self uidString;
at: 'parent' put: (self parent ifNotNil: [self parent uidString ]); at: 'parent' put: surrogate;
at: 'created' put: self createTime asString; at: 'created' put: self createTime asString;
at: 'modified' put: self latestEditTime asString; at: 'modified' put: self latestEditTime asString;
at: 'creator' put: createEmailSanitized; at: 'creator' put: self createEmail asString;
at: 'modifier' put: editEmailSanitized; at: 'modifier' put: self editEmail asString;
at: 'extra' put: self extra;
yourself yourself
] ]
{ #category : #'*MiniDocs' }
LeTextualSnippet >> processSnippetAnnotations [
| exported substitutions annotations pageConfig |
annotations := self ast parts
select: [ :each | each className includesSubstring: 'AnnotationNode' ].
annotations ifEmpty: [ ^ self contentAsString ].
substitutions := OrderedDictionary new.
pageConfig := self page config.
annotations
do: [ :each |
| key type value color |
key := each source.
type := (key splitOn: ':') first copyWithoutAll: '{{'.
value := key copyFrom: type size + 4 to: key size - 2.
pageConfig
ifNil: [ color := 'default' ]
ifNotNil: [ | colors |
colors := pageConfig at: 'annotationColors' ifAbsent: [ nil ].
colors
ifNotNil: [ color := colors
at: type
ifAbsent: [ colors at: 'defaultColor' ifAbsentPut: [ 'default' ] ] ] ].
substitutions
at: key
put: '<span st-class="' , type , '" style="color:' , color , '">' , value , '</span>' ].
exported := self contentAsString.
substitutions
keysAndValuesDo: [ :k :v | exported := exported copyReplaceAll: k with: v ].
^ exported
]
{ #category : #'*MiniDocs' }
LeTextualSnippet >> sanitizeMetadata [
self options ifNil: [^ self ].
self options removeKey: 'metadata' ifAbsent: [^ self ].
self metadata keysAndValuesDo: [:k :v |
(v asString includesAny: #($< $>))
ifTrue: [
self metadata at: k put: (v asString copyWithoutXMLDelimiters)
]
]
]
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LeTextualSnippet >> tags [ LeTextualSnippet >> tags [
^ self extra at: 'tags' ifAbsentPut: [ Set new ] ^ self metadata at: 'tags' ifAbsentPut: [ Set new ]
] ]

View File

@ -1,21 +0,0 @@
Extension { #name : #LeUnknownSnippet }
{ #category : #'*MiniDocs' }
LeUnknownSnippet >> metadataUpdate [
| surrogate |
self parent
ifNil: [ surrogate := nil]
ifNotNil: [
self parent isString
ifTrue: [ surrogate := self parent]
ifFalse: [ 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
]

View File

@ -1,26 +0,0 @@
Extension { #name : #LeWardleyMapSnippet }
{ #category : #'*MiniDocs' }
LeWardleyMapSnippet >> metadataUpdate [
| createEmailSanitized editEmailSanitized |
createEmailSanitized := self createEmail asString withoutXMLTagDelimiters.
editEmailSanitized := self editEmail asString withoutXMLTagDelimiters.
^ OrderedDictionary new
at: 'id' put: self uidString;
at: 'parent' put: self parent uuid;
at: 'created' put: self createTime asString;
at: 'modified' put: self latestEditTime asString;
at: 'creator' put: createEmailSanitized;
at: 'modifier' put: editEmailSanitized;
yourself
]
{ #category : #'*MiniDocs' }
LeWardleyMapSnippet >> sanitizeMetadata [
self metadata keysAndValuesDo: [:k :v |
(v includesAny: #($< $>))
ifTrue: [
self metadata at: k put: (v copyWithoutAll: #($< $>))
]
]
]

View File

@ -1,26 +0,0 @@
Extension { #name : #LeWordSnippet }
{ #category : #'*MiniDocs' }
LeWordSnippet >> metadataUpdate [
| createEmailSanitized editEmailSanitized |
createEmailSanitized := self createEmail asString withoutXMLTagDelimiters.
editEmailSanitized := self editEmail asString withoutXMLTagDelimiters.
^ OrderedDictionary new
at: 'id' put: self uidString;
at: 'parent' put: self parent uuid;
at: 'created' put: self createTime asString;
at: 'modified' put: self latestEditTime asString;
at: 'creator' put: createEmailSanitized;
at: 'modifier' put: editEmailSanitized;
yourself
]
{ #category : #'*MiniDocs' }
LeWordSnippet >> sanitizeMetadata [
self metadata keysAndValuesDo: [:k :v |
(v includesAny: #($< $>))
ifTrue: [
self metadata at: k put: (v copyWithoutAll: #($< $>))
]
]
]

View File

@ -16,7 +16,7 @@ LeYoutubeReferenceSnippet >> asMarkdeep [
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LeYoutubeReferenceSnippet >> metadata [ LeYoutubeReferenceSnippet >> metadata [
^ self optionAt: 'metadata' ifAbsentPut: [ self metadataUpdate ] ^ self optionAt: 'metadata' ifAbsentPut: [ self metadataInit ]
] ]
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
@ -26,12 +26,12 @@ LeYoutubeReferenceSnippet >> metadataDiv [
output output
nextPutAll: '<div st-class="' , self class greaseString , '"'; nextPutAll: '<div st-class="' , self class greaseString , '"';
nextPut: Character lf; nextPut: Character lf;
nextPutAll: ' st-data="' , (STON toStringPretty: self metadata) , '">'. nextPutAll: ' st-data="' , (STON toString: self metadata) , '">'.
^ output contents withInternetLineEndings. ^ output.
] ]
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
LeYoutubeReferenceSnippet >> metadataUpdate [ LeYoutubeReferenceSnippet >> metadataInit [
| surrogate | | surrogate |
self parent self parent
ifNil: [ surrogate := nil] ifNil: [ surrogate := nil]
@ -45,13 +45,3 @@ LeYoutubeReferenceSnippet >> metadataUpdate [
at: 'modifier' put: self editEmail asString; at: 'modifier' put: self editEmail asString;
yourself yourself
] ]
{ #category : #'*MiniDocs' }
LeYoutubeReferenceSnippet >> sanitizeMetadata [
self metadata keysAndValuesDo: [:k :v |
(v includesAny: #($< $>))
ifTrue: [
self metadata at: k put: (v copyWithoutAll: #($< $>))
]
]
]

View File

@ -1,33 +0,0 @@
Class {
#name : #Logseq,
#superclass : #Object,
#instVars : [
'folder'
],
#category : #'MiniDocs-Model'
}
{ #category : #accessing }
Logseq >> assets [
^ self folder / 'assets'
]
{ #category : #accessing }
Logseq >> folder [
^ folder
]
{ #category : #accessing }
Logseq >> folder: aFolder [
folder := aFolder
]
{ #category : #accessing }
Logseq >> journals [
self folder / 'journals'
]
{ #category : #accessing }
Logseq >> pages [
^self folder/ 'pages'
]

View File

@ -5,6 +5,7 @@ Class {
#name : #Markdeep, #name : #Markdeep,
#superclass : #Markdown, #superclass : #Markdown,
#instVars : [ #instVars : [
'title',
'comments', 'comments',
'tail', 'tail',
'language', 'language',
@ -29,25 +30,16 @@ Markdeep class >> fromPubPubTOC: orderedDictionary folder: folder index: ordina
^ self new fromMarkdownFile: testFile. ^ self new fromMarkdownFile: testFile.
] ]
{ #category : #accessing }
Markdeep >> asMarkdownWithMetadataWrappers [
^ Markdown new
metadata: self metadata;
body: self body;
file: self markdownFile
]
{ #category : #'instance creation' } { #category : #'instance creation' }
Markdeep >> authors [ Markdeep >> authors [
self metadata at: 'authors' ifAbsentPut: [ Dictionary new ]. self metadata at: 'authors' ifPresent: [:k | ^ '**', k, '**' ].
"self metadata at: 'authors' ifNotEmpty: [:k | ^ '**', k, '**' ] ^ ''.
" ^ ''.
] ]
{ #category : #'instance creation' } { #category : #'instance creation' }
Markdeep >> authorsString [ Markdeep >> authorsString [
self authors self authors
ifEmpty: [ ^ '' ] ifNotEmpty: [ ^ ' ', self authors ] ifNil: [ ^ '' ] ifNotNil: [ ^ ' ', self authors ]
] ]
{ #category : #accessing } { #category : #accessing }
@ -65,15 +57,10 @@ Markdeep >> bodyReplaceAll: original with: replacement [
self body: (self body copyReplaceAll: original with: replacement) self body: (self body copyReplaceAll: original with: replacement)
] ]
{ #category : #accessing }
Markdeep >> cleanMetadata [
metadata := nil
]
{ #category : #accessing } { #category : #accessing }
Markdeep >> commentPubPubDelimiters [ Markdeep >> commentPubPubDelimiters [
| commented openners | | commented openners |
openners := #('::: {.pub-body-component}' '::: pub-body-component' '::: {.editor .Prosemirror}' '::: {.pub-notes}'). openners := #('::: {.pub-body-component}' '::: {.editor .Prosemirror}' '::: {.pub-notes}').
commented := self body. commented := self body.
openners do: [:openner | openners do: [:openner |
commented := commented copyReplaceAll: openner with: '<!--@div-open ', openner, '-->' commented := commented copyReplaceAll: openner with: '<!--@div-open ', openner, '-->'
@ -126,9 +113,7 @@ Markdeep >> commentsSupport [
{ #category : #accessing } { #category : #accessing }
Markdeep >> config [ Markdeep >> config [
| configFile |
configFile := self folder / 'config.ston'.
configFile exists ifTrue: [ ^ config := STON fromString: configFile contents ].
^ config ifNil: [ config := Dictionary new] ^ config ifNil: [ config := Dictionary new]
] ]
@ -146,10 +131,10 @@ Markdeep >> contents [
output output
nextPutAll: self headContents; lf; lf; nextPutAll: self headContents; lf; lf;
nextPutAll: ' **', self title trimmed accentedCharactersCorrection, '**'; lf; nextPutAll: ' **', self title trimmed accentedCharactersCorrection, '**'; lf;
nextPutAll: self authorsString ; lf; nextPutAll: self authorsString ; lf;
nextPutAll: '', self version; lf; nextPutAll: '', self version; lf;
nextPutAll: self navTop; lf; lf; nextPutAll: self navTop; lf; lf;
nextPutAll: self body; lf; lf; nextPutAll: self body; lf; lf;
nextPutAll: self tail; lf; lf; lf; lf; nextPutAll: self tail; lf; lf; lf; lf;
nextPutAll: self commentsSupport. nextPutAll: self commentsSupport.
^ output contents. ^ output contents.
@ -171,68 +156,6 @@ Markdeep >> converPubPubFootnoteBetween: footnote and: nextFootnote in: footnote
^ response contents ^ response contents
] ]
{ #category : #accessing }
Markdeep >> extractTitleFrom: docTree [
| tempTitle |
tempTitle := ((docTree children
detect: [ :node | node className = 'PPCMIndentedCode' ]) children
detect: [ :subnode | subnode text trimmed beginsWith: '**' ]) text trimmed.
self title: (tempTitle copyFrom: 3 to: tempTitle size - 2).
^ tempTitle
]
{ #category : #accessing }
Markdeep >> extractYamlMetadataFrom: documentTree [
| yamlComment response |
yamlComment := documentTree children
detect: [:node | node className = 'PPCMHtmlBlock' and: [node text trimmed beginsWith: '<!--@yaml']]
ifNone: [ ^ nil ].
response := '' writeStream.
yamlComment children allButFirst allButLast do: [:each |
response nextPutAll: each text; cr
].
^ {YAML2JSON fromString: response contents . yamlComment }
]
{ #category : #accessing }
Markdeep >> file: aFileReference [
file := aFileReference.
self fillInContentsFrom: aFileReference
]
{ #category : #accessing }
Markdeep >> fillInContentsFrom: aFileReference [
| docTree docTreeChildren headTree bodyStartLine bodyEndLine contentLines rawMetadata |
aFileReference exists ifFalse: [ ^ self ].
docTree := (Markdown new contents: aFileReference contents) documentTree.
docTreeChildren := docTree children.
headTree := docTreeChildren
detect: [ :node |
node className = 'PPCMParagraph'
and: [ (node children detect: [ :subnode | subnode text = '<head>' ]) isNotNil ] ]
ifNone: [ ^self ].
headTree children allButFirst allButLast
do: [ :node | node className = 'PPCMHtml' ifTrue: [ self head add: node text ] ].
self head: self head asSet asOrderedCollection.
rawMetadata := (self extractYamlMetadataFrom: docTree).
rawMetadata ifNotNil: [self metadata: rawMetadata first].
self title ifNil: [
self title: (self metadata at: 'title' ifAbsent: [self extractTitleFrom: docTree]).
self title: (self title trimBoth: [ :char | char = $" ]).
self metadata at: 'title' put: self title].
contentLines := self file contents lines.
bodyStartLine := (contentLines
detectIndex: [ :line | line includesSubstring: '<!--@yaml' ] ifNone: [ ^ self ]) + rawMetadata second children size.
bodyEndLine := contentLines detectIndex: [:line | line includesSubstring: '<!-- Markdeep'] ifNone: [ 0 ].
self body: (contentLines copyFrom: bodyStartLine to: bodyEndLine - 1 ) asStringWithCr.
^ self .
]
{ #category : #accessing }
Markdeep >> folder [
^ self file parent
]
{ #category : #utilities } { #category : #utilities }
Markdeep >> fontAwesomeHeader [ Markdeep >> fontAwesomeHeader [
"I enable the font awesome support in the document header" "I enable the font awesome support in the document header"
@ -244,7 +167,6 @@ Markdeep >> fontAwesomeHeader [
Markdeep >> fromMarkdownFile: aFileReference [ Markdeep >> fromMarkdownFile: aFileReference [
"I create a Markdeep document from a given Markdown file." "I create a Markdeep document from a given Markdown file."
self processMarkdownFor: aFileReference. self processMarkdownFor: aFileReference.
self file: aFileReference, 'html'.
^ self. ^ self.
] ]
@ -269,11 +191,8 @@ Markdeep >> gtTextFor: aView [
{ #category : #accessing } { #category : #accessing }
Markdeep >> head [ Markdeep >> head [
^ head ifNil: [ head := OrderedCollection new.
^ head ifNil: [ head add: self fontAwesomeHeader; yourself ]
head := OrderedCollection new.
head add: self fontAwesomeHeader; yourself.
].
] ]
{ #category : #accessing } { #category : #accessing }
@ -294,11 +213,6 @@ Markdeep >> headContents [
nextPutAll: line; nextPutAll: line;
nextPut: Character lf nextPut: Character lf
]. ].
self metadata keysAndValuesDo: [:k :v |
k = 'lang'
ifTrue: [ stream nextPutAll: ' <meta lang="', v,'">'; cr. ]
ifFalse: [ stream nextPutAll: ' <meta name="', k, '" content="', v,'">'; cr. ]
].
stream stream
nextPutAll: '</head>'; nextPutAll: '</head>';
nextPut: Character lf. nextPut: Character lf.
@ -334,15 +248,12 @@ Markdeep >> markdownFile [
{ #category : #accessing } { #category : #accessing }
Markdeep >> markdownFile: aFileReference [ Markdeep >> markdownFile: aFileReference [
"Where the Mardown file associated with me is stored. Used for sync. and import/export purposes." "Where the Mardown file associated with me is stored. Used for sync. and import/export purposes."
self file: aFileReference, 'html' self config at: 'markdownFile' put: aFileReference
] ]
{ #category : #'instance creation' } { #category : #'instance creation' }
Markdeep >> metadata [ Markdeep >> metadata [
metadata ifNil: [^ metadata := OrderedDictionary new ]. ^ metadata ifNil: [ metadata := OrderedDictionary new ]
(metadata isNil and: [ self file contents isNil ])
ifTrue: [ metadata := OrderedDictionary new ].
^ metadata
] ]
{ #category : #accessing } { #category : #accessing }
@ -383,13 +294,20 @@ Markdeep >> options [
] ]
] ]
{ #category : #printing }
Markdeep >> printOn: aStream [
super printOn: aStream.
aStream
nextPutAll: '( ', self title accentedCharactersCorrection, ' )'
]
{ #category : #'instance creation' } { #category : #'instance creation' }
Markdeep >> processMarkdownFor: aFileReference [ Markdeep >> processMarkdownFor: aFileReference [
"comment stating purpose of message" "comment stating purpose of message"
| markdownContent | | markdownContent |
self file: aFileReference, 'html'. self file: aFileReference, 'html'.
markdownContent := Markdown fromFile: aFileReference. markdownContent := Markdown fromFile: aFileReference.
self metadata: markdownContent metadataAsYAML. self metadata: markdownContent yamlMetadata.
self body: (markdownContent commentYAMLMetadata contents). self body: (markdownContent commentYAMLMetadata contents).
] ]
@ -433,8 +351,7 @@ Markdeep >> pubPubFootnotesLinesRangeFor: contentSection [
| beginningLine endingLine | | beginningLine endingLine |
beginningLine := contentSection lines size + 1. beginningLine := contentSection lines size + 1.
contentSection lines doWithIndex: [:line :i | contentSection lines doWithIndex: [:line :i |
((line includesSubstring: '::: {.pub-notes}') or: [line includesSubstring: '::: pub-notes']) (line includesSubstring: '::: {.pub-notes}') ifTrue: [ beginningLine := i ].
ifTrue: [ beginningLine := i ].
(i > beginningLine and: [ line beginsWith: ':::' ]) (i > beginningLine and: [ line beginsWith: ':::' ])
ifTrue: [ ifTrue: [
endingLine := i. endingLine := i.
@ -548,8 +465,7 @@ please visit the HTML version or download the PDF.
{ #category : #accessing } { #category : #accessing }
Markdeep >> removeCCByLicenseDiv [ Markdeep >> removeCCByLicenseDiv [
| licenseDiv| | licenseDiv|
licenseDiv := ' licenseDiv := '<div>
<div>
**License:** [Creative Commons Attribution 4.0 International License **License:** [Creative Commons Attribution 4.0 International License
(CC-BY 4.0)](https://creativecommons.org/licenses/by/4.0/) (CC-BY 4.0)](https://creativecommons.org/licenses/by/4.0/)
@ -649,7 +565,7 @@ Markdeep >> tail: anObject [
{ #category : #accessing } { #category : #accessing }
Markdeep >> title [ Markdeep >> title [
^ title ^ title ifNil: [ title := self metadata at: 'title' ifAbsent: [ '' ] ]
] ]
{ #category : #accessing } { #category : #accessing }

View File

@ -9,8 +9,7 @@ Class {
#superclass : #MarkupFile, #superclass : #MarkupFile,
#instVars : [ #instVars : [
'metadata', 'metadata',
'body', 'body'
'title'
], ],
#category : #'MiniDocs-Core' #category : #'MiniDocs-Core'
} }
@ -20,22 +19,20 @@ Markdown class >> fromFile: aFileReference [
^ self new fromFile: aFileReference ^ self new fromFile: aFileReference
] ]
{ #category : #utilities }
Markdown class >> yamlMetadataDelimiter [
^ '---'
]
{ #category : #accessing } { #category : #accessing }
Markdown >> asMarkdeep [ Markdown >> asMarkdeep [
^ Markdeep new ^ Markdeep new
body: self body; body: self body;
markdownFile: self file;
commentYAMLMetadata commentYAMLMetadata
] ]
{ #category : #accessing }
Markdown >> asMarkdownTiddler [
^ Tiddler new
title: self title;
text: self contents;
type: 'text/x-markdown';
created: Tiddler nowLocal.
]
{ #category : #accessing } { #category : #accessing }
Markdown >> body [ Markdown >> body [
^ body ^ body
@ -49,7 +46,7 @@ Markdown >> body: aString [
{ #category : #operation } { #category : #operation }
Markdown >> commentYAMLMetadata [ Markdown >> commentYAMLMetadata [
| newContents | | newContents |
self contents detectYAMLMetadata ifFalse: [ ^ self ]. self detectYAMLMetadata ifFalse: [ ^ self ].
newContents := '' writeStream. newContents := '' writeStream.
newContents nextPutAll: '<!--@yaml'; lf. newContents nextPutAll: '<!--@yaml'; lf.
newContents nextPutAll: self yamlMetadataString. newContents nextPutAll: self yamlMetadataString.
@ -66,27 +63,48 @@ Markdown >> containsYAMLMetadataClosing [
{ #category : #accessing } { #category : #accessing }
Markdown >> contents [ Markdown >> contents [
| response metadataString | ^ body
response := WriteStream on: ''.
metadataString := self metadataAsYAML
ifEmpty: [ '' ]
ifNotEmpty: [ '---', String cr, self metadataAsYAML, String cr, '---', String cr ].
response
nextPutAll: metadataString;
nextPutAll: (self body ifNil: [ '' ]).
^ response contents withInternetLineEndings
] ]
{ #category : #accessing } { #category : #accessing }
Markdown >> contents: aString [ Markdown >> contents: anObject [
body := aString body := anObject
]
{ #category : #accessing }
Markdown >> contentsWithoutYAMLMetadata [
| newContents |
self detectYAMLMetadata ifFalse: [ ^ self ].
newContents := '' writeStream.
(self lines copyFrom: self yamlMetadataClosingLineNumber + 2 to: self lines size) do: [ :line |
newContents nextPutAll: line; crlf ].
^ newContents contents.
]
{ #category : #operation }
Markdown >> deleteYAMLMetadata [
| newContents |
self detectYAMLMetadata ifFalse: [ ^ self ].
newContents := '' writeStream.
(self lines copyFrom: self yamlMetadataClosingLineNumber + 1 to: self lines size) do: [ :line |
newContents nextPutAll: line; lf;lf ].
^ newContents contents.
]
{ #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 : #accessing } { #category : #accessing }
Markdown >> documentTree [ Markdown >> documentTree [
| parser| | parser|
self contents ifNil: [^ nil]. parser := PPCommonMarkBlockParser new parse: self contents.
parser := PPCommonMarkBlockParser new parse: self body.
^ parser accept: CMBlockVisitor new ^ parser accept: CMBlockVisitor new
] ]
@ -103,12 +121,7 @@ Markdown >> exportAsFileOn: aFileReference [
aFileReference ensureDelete. aFileReference ensureDelete.
aFileReference exists ifFalse: [ aFileReference ensureCreateFile ]. aFileReference exists ifFalse: [ aFileReference ensureCreateFile ].
aFileReference writeStreamDo: [ :stream | aFileReference writeStreamDo: [ :stream |
stream nextPutAll: self contents withInternetLineEndings ]. stream nextPutAll: self contents ].
]
{ #category : #accessing }
Markdown >> exportAsHTML [
^ Pandoc markdownToHtml: self file
] ]
{ #category : #operation } { #category : #operation }
@ -142,7 +155,7 @@ Markdown >> exportMetadataAsYaml [
{ #category : #accessing } { #category : #accessing }
Markdown >> file [ Markdown >> file [
^ file ifNil: [ file := FileLocator temp / 'temporalMarkdeep.md' ] ^ file ifNil: [ file := FileLocator temp / (NanoID generate asLowercase, '.md') ]
] ]
{ #category : #accessing } { #category : #accessing }
@ -153,24 +166,15 @@ Markdown >> file: aFileReference [
{ #category : #'instance creation' } { #category : #'instance creation' }
Markdown >> fromFile: aFileReference [ Markdown >> fromFile: aFileReference [
self fromString: aFileReference contents. self contents: aFileReference contents.
self file: aFileReference. self file: aFileReference.
] ]
{ #category : #'instance creation' } { #category : #'instance creation' }
Markdown >> fromString: markdownString [ Markdown >> fromString: markdownString [
| yamlMetadataRaw bodyTemp | self contents: markdownString.
yamlMetadataRaw := (YamlHeaderParser parse: markdownString). self populateMetadata.
bodyTemp := '' writeStream. self contents: self contentsWithoutYAMLMetadata
(yamlMetadataRaw removeKey: 'body') do: [:paragraph |
bodyTemp nextPutAll: paragraph; cr; cr
].
self body: bodyTemp contents withInternetLineEndings.
(yamlMetadataRaw sanitizeMultilineValuesWith: markdownString)
ifNotNil: [
self metadata
ifEmpty: [ self metadata: yamlMetadataRaw ]
ifNotEmpty: [ self metadata at: 'hedgeDoc' put: yamlMetadataRaw ]].
] ]
{ #category : #accessing } { #category : #accessing }
@ -181,17 +185,8 @@ Markdown >> gtTextFor: aView [
text: [ self contents ] text: [ self contents ]
] ]
{ #category : #accessing }
Markdown >> headerAsTitle [
| headerNode |
headerNode := self documentTree children
detect: [ :node | node className = 'PPCMHeader' and: [ node level = 1 ] ] ifNone: [ ^ 'Untitled' ].
^ headerNode text
]
{ #category : #utilities } { #category : #utilities }
Markdown >> lines [ Markdown >> lines [
self file ifNotNil: [^ self file contents lines ].
^ self contents lines. ^ self contents lines.
] ]
@ -200,7 +195,6 @@ Markdown >> metadata [
^ metadata ifNil: [ metadata := Dictionary new]. ^ metadata ifNil: [ metadata := Dictionary new].
] ]
{ #category : #accessing } { #category : #accessing }
@ -209,12 +203,6 @@ Markdown >> metadata: rawMeta [
metadata := rawMeta metadata := rawMeta
] ]
{ #category : #accessing }
Markdown >> metadataAsYAML [
self metadata isEmptyOrNil ifTrue: [ ^ '' ].
^ (YQ jsonToYaml: self metadata) accentedCharactersCorrection
]
{ #category : #persistence } { #category : #persistence }
Markdown >> notifyExportAsFileOn: aFileReference [ Markdown >> notifyExportAsFileOn: aFileReference [
self exportAsFileOn: aFileReference. self exportAsFileOn: aFileReference.
@ -223,25 +211,62 @@ Markdown >> notifyExportAsFileOn: aFileReference [
] ]
{ #category : #accessing } { #category : #accessing }
Markdown >> options [ Markdown >> populateMetadata [
^ self metadata at: 'options' ifAbsentPut: [ self defaultOptions] | rawMeta |
rawMeta := MiniDocs yamlToJson: self yamlMetadataString.
rawMeta associationsDo: [ :assoc |
assoc value = 'false' ifTrue: [ assoc value: false ].
assoc value = 'true' ifTrue: [ assoc value: true ] ].
self metadata: rawMeta
] ]
{ #category : #accessing } { #category : #accessing }
Markdown >> printOn: aStream [ Markdown >> printOn: aStream [
| response |
super printOn: aStream. super printOn: aStream.
response := self title ifNil: [ 'Untitled' ].
aStream aStream
nextPutAll: '( ', response , ' )' nextPutAll: '( ', (self metadata at: 'title' ifAbsent: ['untitled']), ' )'
]
{ #category : #utilities }
Markdown >> startsWithYAMLMetadataDelimiter [
^ self lines first beginsWith: self class yamlMetadataDelimiter
] ]
{ #category : #accessing } { #category : #accessing }
Markdown >> title [ Markdown >> yamlMetadata [
^ title ifNil: [ title:= self headerAsTitle ] ^ MiniDocs yamlToJson: self yamlMetadataString
] ]
{ #category : #accessing } { #category : #utilities }
Markdown >> title: aString [ Markdown >> yamlMetadataClosingLineNumber [
title := aString "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 lf. ].
^ 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

@ -11,16 +11,13 @@ Class {
} }
{ #category : #persistence } { #category : #persistence }
MarkupFile class >> exportAsFileOn: aFileReferenceOrFileName containing: anObject [ MarkupFile class >> exportAsFileOn: aFileReferenceOrFileName containing: text [
| file preprocessed | | file |
file := aFileReferenceOrFileName asFileReference. file := aFileReferenceOrFileName asFileReference.
file ensureDelete. file ensureDelete.
file exists ifFalse: [ file ensureCreateFile ]. file exists ifFalse: [ file ensureCreateFile ].
(#('String' 'ByteString' 'WideString') includes: anObject className )
ifTrue: [ preprocessed := anObject ]
ifFalse: [preprocessed := STON toStringPretty: anObject ].
file writeStreamDo: [ :stream | file writeStreamDo: [ :stream |
stream nextPutAll: preprocessed ]. stream nextPutAll: text withUnixLineEndings].
self inform: 'Exported as: ', String cr, file fullName. self inform: 'Exported as: ', String cr, file fullName.
^ file ^ file
] ]

View File

@ -10,7 +10,7 @@ Class {
{ #category : #accessing } { #category : #accessing }
MiniDocs class >> altKeys [ MiniDocs class >> altKeys [
^ BlAlternativeCombination new ^ BlAlternativeCombination new
combination: (BlSingleKeyCombination key:BlKeyboardKey altLeft) key: (BlSingleKeyCombination key:BlKeyboardKey altLeft)
or: (BlSingleKeyCombination key:BlKeyboardKey altRight) or: (BlSingleKeyCombination key:BlKeyboardKey altRight)
] ]
@ -34,17 +34,15 @@ MiniDocs class >> altShiftRightCombo [
{ #category : #accessing } { #category : #accessing }
MiniDocs class >> appFolder [ MiniDocs class >> appFolder [
| tempFolder | | tempFolder userDataFolder |
tempFolder := ExoRepo userDataFolder / 'Mutabit' / 'MiniDocs'. userDataFolder := Smalltalk os isWindows
ifTrue: [ FileLocator home / 'AppData' / 'Local' ]
ifFalse: [ FileLocator userData ].
tempFolder := userDataFolder / 'Mutabit' / 'MiniDocs'.
tempFolder exists ifFalse: [ tempFolder ensureCreateDirectory ]. tempFolder exists ifFalse: [ tempFolder ensureCreateDirectory ].
^ tempFolder ^ tempFolder
] ]
{ #category : #accessing }
MiniDocs class >> exportAsSton: anObject on: aFileReference [
MarkupFile exportAsFileOn: aFileReference containing: (STON toStringPretty: anObject) withInternetLineEndings
]
{ #category : #accessing } { #category : #accessing }
MiniDocs class >> importGrafoscopioFile: aFileReference [ MiniDocs class >> importGrafoscopioFile: aFileReference [
@ -89,7 +87,7 @@ MiniDocs class >> keyboardShortcutsRemapping [
{ #category : #accessing } { #category : #accessing }
MiniDocs class >> shiftKeys [ MiniDocs class >> shiftKeys [
^ BlAlternativeCombination new ^ BlAlternativeCombination new
combination: (BlSingleKeyCombination key:BlKeyboardKey shiftLeft) key: (BlSingleKeyCombination key:BlKeyboardKey shiftLeft)
or: (BlSingleKeyCombination key:BlKeyboardKey shiftRight) or: (BlSingleKeyCombination key:BlKeyboardKey shiftRight)
] ]
@ -97,7 +95,6 @@ MiniDocs class >> shiftKeys [
MiniDocs class >> yamlToJson: yamlString [ MiniDocs class >> yamlToJson: yamlString [
"This method uses a external binary written in Nim, as the native Pharo parser for YAML, written in PetitParser, "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." was less robust and unable to parse correctly the same strings as the external one."
yamlString ifNil: [ ^ Dictionary new ].
self yamlToJsonBinary exists ifFalse: [ self installYamlToJson ]. self yamlToJsonBinary exists ifFalse: [ self installYamlToJson ].
OSSUnixSubprocess new OSSUnixSubprocess new
@ -105,7 +102,7 @@ MiniDocs class >> yamlToJson: yamlString [
arguments: {yamlString}; arguments: {yamlString};
redirectStdout; redirectStdout;
runAndWaitOnExitDo: [ :process :outString | runAndWaitOnExitDo: [ :process :outString |
^ (STONJSON fromString: outString allButFirst accentedCharactersCorrection) first ^ (STONJSON fromString: outString allButFirst) first
] ]
] ]

View File

@ -39,7 +39,7 @@ MiniDocsServer class >> restart [
{ #category : #accessing } { #category : #accessing }
MiniDocsServer class >> singleton [ MiniDocsServer class >> singleton [
^ singleton ifNil: [ singleton := MiniDocsServer teapot ] ^ singleton
] ]
{ #category : #accessing } { #category : #accessing }

View File

@ -0,0 +1,55 @@
"
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..
The `External` tag is related on its dependency on other programming languages and frameworks,
though the dependency should be loaded by just loading a small binary with no dependencies.
"
Class {
#name : #NanoID,
#superclass : #Object,
#category : #'MiniDocs-External'
}
{ #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) moveToPageTitled: MiniDocs appFolder asFileReference.
^ MiniDocs appFolder ]
]
{ #category : #accessing }
NanoID class >> scriptSourceCode [
^ FileLocator image parent / 'pharo-local/iceberg/Offray/MiniDocs/src/nanoIdGen.nim'
]

View File

@ -0,0 +1,82 @@
"
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-External'
}
{ #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;
redirectStderr;
runAndWaitOnExitDo: [ :process :outString :errString |
process isSuccess
ifTrue: [ Transcript show: 'Command exited correctly with output: ', outString. ]
ifFalse: [
^ 'Command exit with error status: ', process exitStatusInterpreter printString, String cr,
'Stderr contents: ', errString.
]
]
]
{ #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 [
Smalltalk os isWindows
ifTrue: [ | process |
process := GtExternalProcessBuilder new
command: 'nimble.exe';
args: #('list' '--installed');
output.
^ process stdout lines ].
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,100 +0,0 @@
Extension { #name : #OrderedDictionary }
{ #category : #'*MiniDocs' }
OrderedDictionary >> addErrata: noteString [
self errata add: noteString
]
{ #category : #'*MiniDocs' }
OrderedDictionary >> asLepiterSnippet [
| response |
self at: 'className' ifAbsent: [ ^ nil ].
response := (self at: 'className') asClass new.
[ response fromDictionary: self ] onErrorDo: [ ].
[ response fromString: (self at: 'content') ] onErrorDo: [ ].
self at: 'origin' ifPresent: [ response metadata at: 'origin' put: (self at: 'origin') ].
self at: 'errata' ifPresent: [ response metadata at: 'errata' put: (self at: 'errata') ].
^ response
]
{ #category : #'*MiniDocs' }
OrderedDictionary >> asYAML [
^ (YQ jsonToYaml: self) accentedCharactersCorrection.
]
{ #category : #'*MiniDocs' }
OrderedDictionary >> errata [
^ self at: 'errata' ifAbsentPut: [ OrderedCollection new]
]
{ #category : #'*MiniDocs' }
OrderedDictionary >> redefineTimestampsBefore: dateAndTime [
self at: 'modified' put: dateAndTime asDateAndTime.
self at: 'created' put: dateAndTime asDateAndTime - 1 second.
]
{ #category : #'*MiniDocs' }
OrderedDictionary >> replaceNilsWith: aCharacter [
self associationsDo: [:each |
each value ifNil: [self at: each key put: aCharacter].
each value isDictionary ifTrue: [each value replaceNilsWith: aCharacter].
each value isArray ifTrue: [ | newArray|
newArray := (each value asDataSeries replaceNilsWith: aCharacter) asArray.
self at: each key put: newArray
]
]
]
{ #category : #'*MiniDocs' }
OrderedDictionary >> replaceWithUniqueNilsAndBooleansStartingAt: anInteger [
| totalNils shortUID |
totalNils := self flattened asDataSeries countNils.
shortUID := [NanoID generate copyFrom: 1 to: 3].
self associations doWithIndex: [:assoc :i | | subIndex |
subIndex := anInteger asString, '-', i asString.
assoc value
ifNil: [ self at: assoc key put: 'nil-', subIndex ].
assoc value isBoolean
ifTrue: [ self at: assoc key put: assoc value asString, '-', subIndex ].
assoc value isDictionary ifTrue: [assoc replaceWithUniqueNilsAndBooleansStartingAt: i].
assoc value isArray
ifTrue: [ self at: assoc key put: (assoc value replaceWithUniqueNilsAndBooleans)]
]
]
{ #category : #'*MiniDocs' }
OrderedDictionary >> sanitizeMultilineValuesWith: aString [
| toSanitize response |
toSanitize := OrderedCollection new.
response := OrderedCollection new.
self keysAndValuesDo: [:k :v |
(v isString and: [v lines size > 1])
ifTrue: [
aString lines
detect: [:line | line includesSubstring: k ]
ifFound: [:line | | sanitized|
sanitized := (line withoutPrefix: k, ':'), String cr,
v indentedWithExtraSpaces: 4.
self at: k put: sanitized ]
]
].
]
{ #category : #'*MiniDocs' }
OrderedDictionary >> treeView [
| view |
view := GtMondrian new.
view nodes
stencil: [ :x |
BlElement new
border: (BlBorder paint: Color black);
geometry: BlEllipseGeometry new;
layout: (BlLinearLayout new alignCenter);
addChild: (BlTextElement text: (x asRopedText fontSize: 10)) ];
with: (self flatCollectAsSet: #yourself) , self keys.
view edges
stencil: [ :x | BlLineElement new border: (BlBorder paint: (Color blue alpha: 0.5) width: 4) ];
connect: self associations from: #key toAll: #value.
view layout tree.
^ view
]

View File

@ -1,162 +0,0 @@
"
I model the interaction between Pandoc and Grafoscopio.
"
Class {
#name : #Pandoc,
#superclass : #Object,
#classInstVars : [
'executable'
],
#category : #'MiniDocs-Core'
}
{ #category : #'*MiniDocs' }
Pandoc class >> convertString: aString from: inputFormat to: outputFormat [
OSSUnixSubprocess new
shellCommand: 'echo "', aString , '" | pandoc -f ', inputFormat,' -t ', outputFormat;
redirectStdout;
runAndWaitOnExitDo: [ :command :outString |
^ outString
].
]
{ #category : #'as yet unclassified' }
Pandoc class >> downloadLuaFilters [
self luaFilters do: [ :filter | | filterUrl |
filterUrl := filter asUrl.
(FileLocator temp asFileReference / (filterUrl segments last)) exists
ifFalse: [
ZnClient new
url: filterUrl;
downloadTo: FileLocator temp ] ]
]
{ #category : #accessing }
Pandoc class >> executable [
^ executable ifNil: [ self executableLocation ]
]
{ #category : #accessing }
Pandoc class >> executable: aFileReference [
executable := aFileReference
]
{ #category : #accessing }
Pandoc class >> executableLocation [
| location |
location := '/usr/bin/pandoc'.
location asFileReference exists
ifTrue: [ ^ location ]
ifFalse: [ self definePandocExecutable ]
]
{ #category : #utility }
Pandoc class >> extractImagesInUnixFor: aFileReference withFilter: aLuaFilter [
"I use Pandoc Lua scripting capabilities to extract al images links in aFileReference"
OSSUnixSubprocess new
command: 'pandoc';
arguments: {aFileReference fullName . '--lua-filter=',aLuaFilter fullName };
redirectStdout;
redirectStderr;
runAndWaitOnExitDo: [ :process :outString :errString |
process isSuccess
ifTrue: [
^ ((Soup fromString: outString) findAllTags: 'td') collect: [ :each | each next ] ]
ifFalse: [
"OSSUnixProcessExitStatus has a nice #printOn: "
Transcript show: 'Command exit with error status: ', process exitStatusInterpreter printString; cr.
Transcript show: 'Stderr contents: ', errString.
]
]
]
{ #category : #accessing }
Pandoc class >> htmlStringToMarkdown: aString [
OSSUnixSubprocess new
shellCommand: 'echo "', aString , '" | pandoc -f markdown -t html';
redirectStdout;
runAndWaitOnExitDo: [ :command :outString |
^ outString
].
]
{ #category : #converters }
Pandoc class >> htmlToMarkdown: inputFile [
| outputFile |
outputFile := FileLocator temp / 'body.md'.
outputFile ensureDelete.
outputFile ensureCreateFile.
OSSUnixSubprocess new
command: 'pandoc';
arguments: {'-f'. 'html'. '-t'. 'markdown'. '--atx-headers'. inputFile fullName.
'--output'. outputFile fullName };
redirectStdout;
redirectStderr;
runAndWaitOnExitDo: [ :process :outString :errString |
process isSuccess
ifTrue: [ ^ outputFile contents ]
ifFalse: [ ^inputFile contents ]
]
]
{ #category : #'as yet unclassified' }
Pandoc class >> listImagesFrom: aFileReference [
"I provide a list of all images contained in aFile."
| filter commandString outputString |
filter := FileLocator temp asFileReference / 'image-links.lua'.
filter exists
ifFalse: [ self downloadLuaFilters ].
commandString := 'pandoc ' , aFileReference fullName
, ' --lua-filter=' , filter fullName.
^ self extractImagesInUnixFor: aFileReference withFilter: filter
]
{ #category : #utility }
Pandoc class >> luaFilters [
"I define the location of set of scripts, that allows to change the default behaviour of Pandoc
and/or the processing of supported markup languages.
For more information about Lua filters see:
https://pandoc.org/lua-filters.html
"
| filters |
filters := OrderedCollection new.
filters
add: 'http://mutabit.com/repos.fossil/dataweek/doc/tip/Artefactos/Scripts/image-links.lua'.
^ filters
]
{ #category : #converters }
Pandoc class >> markdownToHtml: inputFile [
(Smalltalk os isUnix or: [ Smalltalk os isMacOS ]) ifTrue: [ ^ self markdownToHtmlOnUnix: inputFile ].
Smalltalk os isWindows ifTrue: [ ^ self markdownToHtmlOnWindows: inputFile ].
]
{ #category : #converters }
Pandoc class >> markdownToHtmlOnUnix: inputFile [
| outputFile |
outputFile := inputFile parent / (inputFile basenameWithoutExtension , '.html').
outputFile ensureDelete.
outputFile ensureCreateFile.
GtSubprocessWithInMemoryOutput new
shellCommand: 'pandoc -f markdown+startnum+task_lists --standalone -t html ', inputFile fullName, ' --output ', outputFile fullName;
runAndWait;
stdout.
^ outputFile.
]
{ #category : #converters }
Pandoc class >> markdownToHtmlOnWindows: inputFile [
"ToDo: This command still doesn't receive any arguments."
^ (LibC resultOfCommand: 'pandoc ', inputFile fullName) correctAccentedCharacters.
]

View File

@ -1,11 +0,0 @@
Extension { #name : #Pandoc }
{ #category : #'*MiniDocs' }
Pandoc class >> convertString: aString from: inputFormat to: outputFormat [
OSSUnixSubprocess new
shellCommand: 'echo "', aString , '" | pandoc -f ', inputFormat,' -t ', outputFormat;
redirectStdout;
runAndWaitOnExitDo: [ :command :outString |
^ outString
].
]

View File

@ -0,0 +1,139 @@
Class {
#name : #PubPub,
#superclass : #Object,
#instVars : [
'address',
'tableOfContents',
'titles',
'folder',
'currentLanguage',
'languages'
],
#category : #'MiniDocs-Model'
}
{ #category : #accessing }
PubPub >> addTableOfContents: anOrderedDictionary [
self tableOfContents
at: (self currentLanguage) put: anOrderedDictionary;
yourself
]
{ #category : #accessing }
PubPub >> addTitle: aString [
self titles
at: (self currentLanguage) put: aString
]
{ #category : #accessing }
PubPub >> address [
^ address
]
{ #category : #accessing }
PubPub >> address: anUrl [
address := anUrl
]
{ #category : #accessing }
PubPub >> currentLanguage [
^ currentLanguage
]
{ #category : #accessing }
PubPub >> currentLanguage: twoLettersInISO639_1 [
currentLanguage := twoLettersInISO639_1
]
{ #category : #accessing }
PubPub >> defaultTitle [
^ self titles associations first value
]
{ #category : #accessing }
PubPub >> downloadContents [
| workingDirectory |
workingDirectory := self folder / self currentLanguage / 'book'.
self tableOfContents keysAndValuesDo: [ :name :chapterAddress | |currentFileName|
currentFileName := name, '--', chapterAddress, '.md'.
(workingDirectory / currentFileName) asFileReference ensureDelete.
(workingDirectory / 'markdown') asFileReference ensureDelete.
ZnClient new
get: self address, 'pub/', chapterAddress, '/download/markdown';
downloadTo: workingDirectory .
workingDirectory / 'markdown' renameTo: currentFileName
].
^ workingDirectory
]
{ #category : #accessing }
PubPub >> exportMarkdeepFiles [
| markdownFiles markdeepDocs |
markdownFiles := self languageFolder allChildren select: [:file |
file basename endsWith: '.md'
].
markdeepDocs := markdownFiles collect: [:file |
(Markdeep fromMarkdownFile:file)
].
markdeepDocs do: [:each |
each fromPubPubToMarkdeep exportAsFile
].
^ self languageFolder
]
{ #category : #accessing }
PubPub >> extractAllContentsRaw [
^ self frontPage xpath: '//div[@class="layout-pubs-block"]'
]
{ #category : #accessing }
PubPub >> extractRawTableOfContents [
^ self extractAllContentsRaw first xpath: '//div[contains(concat(" ",normalize-space(@class)," "), " pub-preview-component ")]'
]
{ #category : #accessing }
PubPub >> extractTableOfContents [
^ self extractRawTableOfContents collect: [:each |
PubPubContent fromXML: each
]
]
{ #category : #accessing }
PubPub >> folder [
^ folder ensureCreateDirectory
]
{ #category : #accessing }
PubPub >> folder: localDirectory [
folder := localDirectory
]
{ #category : #accessing }
PubPub >> frontPage [
"This should scrap contents of the book's front-page and translate them into Markdeep,
according to our templates."
^ (XMLHTMLParser on: (self address asUrl retrieveContents)) parseDocument
]
{ #category : #accessing }
PubPub >> languageFolder [
^ self folder / self currentLanguage
]
{ #category : #accessing }
PubPub >> printOn: aStream [
super printOn: aStream.
aStream
nextPutAll: '(',self defaultTitle, ' | ', self address, ' )'
]
{ #category : #accessing }
PubPub >> tableOfContents [
tableOfContents ifNil: [^ tableOfContents := Dictionary new].
^ tableOfContents at: self currentLanguage
]
{ #category : #accessing }
PubPub >> titles [
^ titles ifNil: [titles := OrderedDictionary new]
]

View File

@ -5,9 +5,7 @@ Class {
'title', 'title',
'language', 'language',
'url', 'url',
'thumbnail', 'thumbnail'
'work',
'contents'
], ],
#category : #'MiniDocs-Model' #category : #'MiniDocs-Model'
} }
@ -17,40 +15,6 @@ PubPubContent class >> fromXML: anXMLElement [
^ self new fromXML: anXMLElement ^ self new fromXML: anXMLElement
] ]
{ #category : #accessing }
PubPubContent >> asMarkdeepFrontPageElement [
| response anchorName anchorLink markdeepFile |
response := '' writeStream.
anchorName := '[', self title,']'.
markdeepFile := './book/', self shortName,'--',self id,'.md.html'.
anchorLink := '(', markdeepFile,')'.
response
nextPutAll: '<big>', anchorName, anchorLink,'</big><br><br>';
nextPutAll: String lf.
self thumbnail ifNotNil: [ |image|
image := '
<img
src=', self thumbnail,
' width="55%"
style="width: 400px; height: 220px; object-fit: cover;"
/>'.
response nextPutAll: '<a href="',markdeepFile,'">', image, '</a>'
].
response
nextPutAll: String lf, String lf.
^ response contents
]
{ #category : #accessing }
PubPubContent >> contents: anObject [
contents := anObject
]
{ #category : #accessing }
PubPubContent >> fileName [
^ self shortName,'--', self id, '.md'
]
{ #category : #accessing } { #category : #accessing }
PubPubContent >> fromXML: aXMLElement [ PubPubContent >> fromXML: aXMLElement [
| image anchor| | image anchor|
@ -73,23 +37,6 @@ PubPubContent >> id [
^ (self url splitOn: $/) last ^ (self url splitOn: $/) last
] ]
{ #category : #'as yet unclassified' }
PubPubContent >> language: aString [
language := aString
]
{ #category : #accessing }
PubPubContent >> next [
^ self nextInstance
]
{ #category : #accessing }
PubPubContent >> previous [
| index |
index := self work tableOfContents detectIndex: [:pubContent | pubContent = self ] ifNone: [ ^ nil ].
^ self work tableOfContents at: index - 1.
]
{ #category : #accessing } { #category : #accessing }
PubPubContent >> printOn: aStream [ PubPubContent >> printOn: aStream [
super printOn: aStream. super printOn: aStream.
@ -107,11 +54,6 @@ PubPubContent >> shortName [
^ sanitized ^ sanitized
] ]
{ #category : #accessing }
PubPubContent >> thumbnail [
^ thumbnail
]
{ #category : #accessing } { #category : #accessing }
PubPubContent >> thumbnail: anURL [ PubPubContent >> thumbnail: anURL [
thumbnail := anURL thumbnail := anURL
@ -136,13 +78,3 @@ PubPubContent >> url [
PubPubContent >> url: anObject [ PubPubContent >> url: anObject [
url := anObject url := anObject
] ]
{ #category : #accessing }
PubPubContent >> work [
^ work
]
{ #category : #accessing }
PubPubContent >> work: aPubPubWork [
work := aPubPubWork
]

View File

@ -11,7 +11,7 @@ Class {
'footnoteLabel', 'footnoteLabel',
'footnoteContent' 'footnoteContent'
], ],
#category : #'MiniDocs-Model' #category : #MiniDocs
} }
{ #category : #accessing } { #category : #accessing }

View File

@ -1,240 +0,0 @@
Class {
#name : #PubPubWork,
#superclass : #Object,
#instVars : [
'address',
'tableOfContents',
'titles',
'folder',
'currentLanguage',
'languages'
],
#category : #'MiniDocs-Model'
}
{ #category : #accessing }
PubPubWork >> addTableOfContents: anOrderedDictionary [
self tableOfContents
at: (self currentLanguage) put: anOrderedDictionary;
yourself
]
{ #category : #accessing }
PubPubWork >> addTitle: aString [
self titles
at: (self currentLanguage) put: aString
]
{ #category : #accessing }
PubPubWork >> address [
^ address
]
{ #category : #accessing }
PubPubWork >> address: anUrl [
address := anUrl
]
{ #category : #accessing }
PubPubWork >> bookishFolder [
^ { 'en' -> 'book'.
'es' -> 'libro'} asDictionary
]
{ #category : #accessing }
PubPubWork >> currentLanguage [
^ currentLanguage
]
{ #category : #accessing }
PubPubWork >> currentLanguage: twoLettersInISO639_1 [
currentLanguage := twoLettersInISO639_1
]
{ #category : #accessing }
PubPubWork >> defaultOptions [
^ { 'sourceCodeLink' -> true .
'commentsProvider' -> 'Hypothesis' } asDictionary
]
{ #category : #accessing }
PubPubWork >> defaultTitle [
^ self titles associations first value
]
{ #category : #accessing }
PubPubWork >> downloadContents [
| workingDirectory |
workingDirectory := self workingDirectory.
self tableOfContentsDictionary
keysAndValuesDo: [ :name :chapterAddress |
| currentFileName |
currentFileName := name , '--' , chapterAddress , '.md'.
(workingDirectory / currentFileName) asFileReference ensureDelete.
(workingDirectory / 'markdown') asFileReference ensureDelete.
ZnClient new
get: self address , 'pub/' , chapterAddress , '/download/markdown';
downloadTo: workingDirectory.
workingDirectory / 'markdown' renameTo: currentFileName ].
^ workingDirectory
]
{ #category : #accessing }
PubPubWork >> downloadContents2 [
| workingDirectory |
workingDirectory := self folder / self currentLanguage / 'book'.
self tableOfContentsDictionary keysAndValuesDo: [ :name :chapterAddress | |currentFileName|
currentFileName := name, '--', chapterAddress, '.md'.
(workingDirectory / currentFileName) asFileReference ensureDelete.
(workingDirectory / 'markdown') asFileReference ensureDelete.
ZnClient new
get: self address, 'pub/', chapterAddress, '/download/markdown';
downloadTo: workingDirectory .
workingDirectory / 'markdown' renameTo: currentFileName
].
^ workingDirectory
]
{ #category : #accessing }
PubPubWork >> exportToHTML [
self markdownFiles
do: [ :file | | doc |
doc := Markdown new fromFile: file.
doc exportAsHTML ].
^ self markdownFiles first parent
]
{ #category : #accessing }
PubPubWork >> exportToMarkdeep [
| markdeepDocs |
markdeepDocs := self markdownFiles
collect: [ :file | Markdeep fromMarkdownFile: file ].
markdeepDocs do: [ :each | each fromPubPubToMarkdeep exportAsFile ].
^ self languageFolder
]
{ #category : #accessing }
PubPubWork >> extractAllContentsRaw [
^ self frontPage xpath: '//div[@class="layout-pubs-block"]'
]
{ #category : #accessing }
PubPubWork >> extractRawTableOfContents [
^ self extractAllContentsRaw first xpath: '//div[contains(concat(" ",normalize-space(@class)," "), " pub-preview-component ")]'
]
{ #category : #accessing }
PubPubWork >> folder [
^ folder ensureCreateDirectory
]
{ #category : #accessing }
PubPubWork >> folder: localDirectory [
folder := localDirectory
]
{ #category : #accessing }
PubPubWork >> frontPage [
"This should scrap contents of the book's front-page and translate them into Markdeep,
according to our templates."
^ (XMLHTMLParser on: (self address asUrl retrieveContents)) parseDocument
]
{ #category : #accessing }
PubPubWork >> languageFolder [
^ self folder / self currentLanguage
]
{ #category : #accessing }
PubPubWork >> markdeepFrontPage [
| frontPage markdeepIndex |
frontPage := Markdeep new.
frontPage
title: self defaultTitle;
file: self languageFolder / 'frontPage.md.html'.
markdeepIndex := '' writeStream.
self tableOfContents do: [:pubPubContent|
markdeepIndex
nextPutAll: pubPubContent asMarkdeepFrontPageElement
].
frontPage body: markdeepIndex contents.
^ frontPage
]
{ #category : #accessing }
PubPubWork >> markdownFiles [
^ self languageFolder allChildren
select: [ :file | file basename endsWith: '.md' ]
]
{ #category : #accessing }
PubPubWork >> populateContents [
self tableOfContents isEmptyOrNil
ifTrue: [ self populateTableOfContents ].
self workingDirectory children ifEmpty: [self downloadContents].
self tableOfContents do: [:pubPubContent | | contentFile|
contentFile := self workingDirectory / pubPubContent fileName.
contentFile exists
ifTrue: [ pubPubContent contents: (Markdown new fromFile: contentFile) ]
]
]
{ #category : #accessing }
PubPubWork >> populateTableOfContents [
| contentsCollection |
contentsCollection := self extractRawTableOfContents collect: [:each |
(PubPubContent fromXML: each)
language: self currentLanguage;
work: self
].
self addTableOfContents: contentsCollection asOrderedCollection
]
{ #category : #accessing }
PubPubWork >> printOn: aStream [
super printOn: aStream.
aStream
nextPutAll: '(',self defaultTitle, ' | ', self address, ' )'
]
{ #category : #accessing }
PubPubWork >> tableOfContents [
tableOfContents ifNil: [ ^ tableOfContents := Dictionary new].
^ tableOfContents at: self currentLanguage
]
{ #category : #accessing }
PubPubWork >> tableOfContents: anObject [
tableOfContents := anObject
]
{ #category : #accessing }
PubPubWork >> tableOfContentsDictionary [
| response |
response := OrderedDictionary new.
self tableOfContents do: [:content |
response
at: content shortName put: content id
].
^ response
]
{ #category : #accessing }
PubPubWork >> titles [
^ titles ifNil: [titles := OrderedDictionary new]
]
{ #category : #accessing }
PubPubWork >> viewContentsFor: aView [
<gtView>
^ aView list
title: 'Contents';
priority: 10;
items: [ self tableOfContents ]
]
{ #category : #accessing }
PubPubWork >> workingDirectory [
^ self folder / self currentLanguage / (self bookishFolder at: self currentLanguage)
]

View File

@ -4,7 +4,7 @@ Extension { #name : #String }
String >> accentedCharactersCorrection [ String >> accentedCharactersCorrection [
| modified corrections | | modified corrections |
corrections := { corrections := {
'ó' -> 'ó' . “' -> 'Ó' . º' -> 'ú' . 'ñ' -> 'ñ' . 'Ñ' -> 'Ñ' . 'ó' -> 'ó' . º' -> 'ú' . 'ñ' -> 'ñ' .
'í' -> 'í' . 'á' -> 'á' . 'é' -> 'é' . '’' -> $' asString} asDictionary. 'í' -> 'í' . 'á' -> 'á' . 'é' -> 'é' . '’' -> $' asString} asDictionary.
modified := self copy. modified := self copy.
corrections keysAndValuesDo: [ :k :v | corrections keysAndValuesDo: [ :k :v |
@ -13,41 +13,6 @@ String >> accentedCharactersCorrection [
^ modified ^ modified
] ]
{ #category : #'*MiniDocs' }
String >> admonitionBorderLines [
| response |
response := OrderedDictionary new.
self lines doWithIndex: [:line :index |
(self admonitionBorders includes: line trimBoth)
ifTrue: [ response at: index put: line trimBoth ]
].
^ response
]
{ #category : #'*MiniDocs' }
String >> admonitionBorders [
"For the moment I only work with the admonition starting border
as adding the closing one would imply to redo the #markdownSplitted
method implementing a proper parser, which, ATM is overkill."
| response |
response := #('info' 'success' 'warning' 'danger') collect: [ :each | ':::', each ].
^ response "copyWith: ':::'"
]
{ #category : #'*MiniDocs' }
String >> admonitionEndingPosition [
| response |
response := 0.
self startsWithMarkdownAdmonition ifFalse: [ ^ response ].
self lines do: [:line |
response > 0 ifTrue: [ response := response + 1 ].
(line trimBoth = ':::')
ifFalse: [ response := response + line size ]
ifTrue: [ ^ response := response + line size. ]
].
^ response
]
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
String >> asDashedLowercase [ String >> asDashedLowercase [
"I convert phrases like 'This is a phrase' into 'this-is-a-phrase'." "I convert phrases like 'This is a phrase' into 'this-is-a-phrase'."
@ -55,119 +20,6 @@ String >> asDashedLowercase [
^ '-' join: (self substrings collect: [:each | each asLowercase ]) ^ '-' join: (self substrings collect: [:each | each asLowercase ])
] ]
{ #category : #'*MiniDocs' }
String >> asInteger [
"Return the integer present in the receiver, or nil. In case of float, returns the integer part."
"'1' asInteger >>> 1"
"'-1' asInteger >>> -1"
"'10' asInteger >>> 10"
"'a' asInteger >>> nil"
"'1.234' asInteger >>> 1"
^ (self copyWithoutAll: '_') asSignedInteger
]
{ #category : #'*MiniDocs' }
String >> contentsWithoutYAMLMetadata [
| newContents |
self detectYAMLMetadata ifFalse: [ ^ self ].
newContents := '' writeStream.
(self lines copyFrom: self yamlMetadataClosingLineNumber + 2 to: self lines size) do: [ :line |
newContents nextPutAll: line; cr ].
^ newContents contents.
]
{ #category : #'*MiniDocs' }
String >> deleteYAMLMetadata [
| newContents |
self detectYAMLMetadata ifFalse: [ ^ self ].
newContents := '' writeStream.
(self lines copyFrom: self yamlMetadataClosingLineNumber + 1 to: self lines size) do: [ :line |
newContents nextPutAll: line; lf;lf ].
^ newContents contents.
]
{ #category : #'*MiniDocs' }
String >> demoteMarkdownHeaders [
| response |
response := self contents lines.
self markdownHeaders associations allButFirstDo: [ :assoc |
response at: assoc key put: '#', assoc value ].
^ response asStringWithCr withInternetLineEndings
]
{ #category : #'*MiniDocs' }
String >> detectYAMLMetadata [
| lines |
lines := self lines.
^ self startsWithYAMLMetadataDelimiter
and: [ lines allButFirst
detect: [ :currentLine | currentLine beginsWith: self class yamlMetadataDelimiter ]
ifFound: [ ^ true ] ifNone: [ ^ false ] ]
]
{ #category : #'*MiniDocs' }
String >> indentedWithExtraSpaces: spaceNumber [
| response indent |
response := '' writeStream.
indent := String new.
spaceNumber timesRepeat: [ indent := indent, ' ' ].
self lines do: [:line | response nextPutAll: indent, line, String lf ].
^ response contents
]
{ #category : #'*MiniDocs' }
String >> markdownHeaders [
| response headers |
headers := (LeTextSnippet string: self contents) ast // #LeHeaderNode collect: [ :each | each headerFullName asString ].
response := OrderedDictionary new.
self lines doWithIndex: [:line :index |
(line beginsWithAnyOf: headers)
ifTrue: [ response at: index put: line ]
].
^ response
]
{ #category : #'*MiniDocs' }
String >> markdownSplitLines [
"I'm useful for conversions between the HedgeDoc Markdown variant and Lepiter page snippets.
I provide broad places to where semantic breaks should be located in a page,
depending on headers or admonitions to create pages snippets with similar divisions.
Further page splits should be provided manually by the document author."
| response |
response := OrderedDictionary new.
response := response
addAll: self markdownHeaders;
addAll: self admonitionBorderLines;
yourself.
^ (response associations sorted: [ :x :y | x key < y key ]) asOrderedDictionary
]
{ #category : #'*MiniDocs' }
String >> markdownSplitted [
| response lastPart |
self markdownSplitLines ifEmpty: [ ^ self ].
response := OrderedCollection new.
self markdownSplitLines keys allButLast doWithIndex: [:key :index | | nextLine part |
nextLine := (self markdownSplitLines keys at: index + 1) - 1.
part := self lines copyFrom: key to: nextLine.
response add: part.
].
lastPart := self lines
copyFrom: self markdownSplitLines keys last
to: self lines size.
response add: lastPart.
^ response
]
{ #category : #'*MiniDocs' }
String >> promoteMarkdownHeaders [
| response |
response := self contents lines.
self markdownHeaders associationsDo: [ :assoc |
response at: assoc key put: assoc value allButFirst ].
^ response asStringWithCr withInternetLineEndings
]
{ #category : #'*MiniDocs' } { #category : #'*MiniDocs' }
String >> romanizeAccents [ String >> romanizeAccents [
| modified corrections | | modified corrections |
@ -180,61 +32,3 @@ String >> romanizeAccents [
]. ].
^ modified ^ modified
] ]
{ #category : #'*MiniDocs' }
String >> startsWithMarkdownAdmonition [
self lines ifEmpty: [ ^ false ].
^ self admonitionBorders includes: self lines first trimBoth
]
{ #category : #'*MiniDocs' }
String >> startsWithYAMLMetadataDelimiter [
self lines ifEmpty: [^false].
^ self lines first beginsWith: self class yamlMetadataDelimiter
]
{ #category : #'*MiniDocs' }
String >> withoutXMLTagDelimiters [
^ self copyWithoutAll: #($< $>)
]
{ #category : #'*MiniDocs' }
String >> 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 : #'*MiniDocs' }
String class >> yamlMetadataDelimiter [
^ '---'
]
{ #category : #'*MiniDocs' }
String >> yamlMetadataString [
| output yamlLines |
self detectYAMLMetadata ifFalse: [ ^nil ].
self lines ifEmpty: [ ^nil ].
yamlLines := self lines copyFrom: 2 to: self yamlMetadataClosingLineNumber - 1.
output := '' writeStream.
yamlLines do: [ :line |
output
nextPutAll: line;
nextPut: Character lf. ].
^ output contents
]
{ #category : #'*MiniDocs' }
String >> 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,9 +0,0 @@
Extension { #name : #XMLDocument }
{ #category : #'*MiniDocs' }
XMLDocument >> detectMarkdeepTitle [
| titleLine |
titleLine := (self nodesCollect: [:node | node contentString ]) first lines
detect: [:line | line includesSubstring: ' **'] ifNone: ['Untitled'].
^ titleLine trimmed trimBoth: [:char | char = $* ]
]

View File

@ -1,53 +0,0 @@
Extension { #name : #XMLElement }
{ #category : #'*MiniDocs' }
XMLElement >> asSnippetDictionary [
| response |
response := STON fromString: (self attributes at: 'st-data').
response at: 'className' put: (self attributes at: 'st-class').
response at: 'content' put: self sanitizedContent.
^ response
]
{ #category : #'*MiniDocs' }
XMLElement >> extractMarkdownImageLinkData [
| linkParserNodes sanitizedText linkParser |
linkParser := (PPCommonMarkBlockParser parse: (self contentString trimBoth: [:each | each = Character lf]) allButFirst)
accept: CMBlockVisitor new.
linkParserNodes := linkParser children first children.
linkParserNodes size = 1
ifTrue: [ sanitizedText := linkParserNodes first label text ]
ifFalse: [ sanitizedText := '' writeStream.
linkParserNodes allButLast
do: [ :each |
each className = 'PPCMText'
ifTrue: [ sanitizedText nextPutAll: each text allButFirst ].
each className = 'PPCMLink'
ifTrue: [ sanitizedText nextPutAll: each printString ] ].
sanitizedText := sanitizedText contents ].
^ {sanitizedText . self contentString }
]
{ #category : #'*MiniDocs' }
XMLElement >> sanitizedContent [
| className sanitizedText |
className := self attributes at: 'st-class'.
className = 'LeTextSnippet'
ifTrue: [ sanitizedText := self contentString.
sanitizedText := sanitizedText allButFirst.
sanitizedText := sanitizedText allButLast ].
className = 'LePharoSnippet'
ifTrue: [ | joinedText |
sanitizedText := self contentString lines.
sanitizedText := sanitizedText copyFrom: 4 to: sanitizedText size - 2.
joinedText := '' writeStream.
sanitizedText
do: [ :line |
joinedText
nextPutAll: line;
nextPut: Character lf ].
sanitizedText := joinedText contents allButLast ].
className = 'LePictureSnippet'
ifTrue: [ sanitizedText := self extractMarkdownImageLinkData ].
^ sanitizedText
]

29
src/MiniDocs/YQ.class.st Normal file
View File

@ -0,0 +1,29 @@
"
The `External` tag is related on its dependency on other programming languages and frameworks,
though the dependency should be loaded by just loading a small binary with no dependencies.
"
Class {
#name : #YQ,
#superclass : #Object,
#category : #'MiniDocs-External'
}
{ #category : #accessing }
YQ class >> binaryDownloadLinkFor: operativeSystem on: processor [
| binaryName binaryDownloadData |
binaryName := 'yq_', operativeSystem , '_', processor.
binaryDownloadData := ((self lastReleaseData at: 'assets')
select: [:each | (each at: 'name') beginsWith: binaryName ]) first.
^ binaryDownloadData at: 'browser_download_url'
]
{ #category : #accessing }
YQ class >> install [
^ self lastReleaseData
]
{ #category : #accessing }
YQ class >> lastReleaseData [
^ (STONJSON
fromString: 'https://api.github.com/repos/mikefarah/yq/releases' asUrl retrieveContents) first
]

View File

@ -1,10 +0,0 @@
Extension { #name : #ZnConstants }
{ #category : #'*MiniDocs' }
ZnConstants class >> maximumLineLength [
"Return the maximum line length to accept.
Used by ZnLineReader and thus for reading request/status lines as well as headers.
This helps to protect us from malicious content."
^ 5096 "8192"
]

View File

@ -23,8 +23,3 @@ PPCMBlockQuote >> initialize [
PPCMBlockQuote >> isBlockLevel [ PPCMBlockQuote >> isBlockLevel [
^ true ^ true
] ]
{ #category : #accessing }
PPCMBlockQuote >> viewBody [
^ (self className ,' ', self text) asRopedText.
]

View File

@ -39,8 +39,9 @@ PPCMLink >> printOn: aStream [
super initialize. super initialize.
^ aStream ^ aStream
nextPutAll: nextPutAll:
'[',self label text,']', self label text,
'(',self destination,')' ' -> ',
self destination
] ]
{ #category : #accessing } { #category : #accessing }