273 lines
7.0 KiB
Smalltalk
273 lines
7.0 KiB
Smalltalk
"
|
|
I model a Markdown document.
|
|
At some point the idea is to have a full native parser implemented to deal
|
|
with my syntax, but meanwhile I will be collaborating with external parsers,
|
|
particularly the ones provided by Pandoc and/or Lunamark.
|
|
"
|
|
Class {
|
|
#name : #Markdown,
|
|
#superclass : #MarkupFile,
|
|
#instVars : [
|
|
'metadata',
|
|
'body'
|
|
],
|
|
#category : #'MiniDocs-Core'
|
|
}
|
|
|
|
{ #category : #'instance creation' }
|
|
Markdown class >> fromFile: aFileReference [
|
|
^ self new fromFile: aFileReference
|
|
]
|
|
|
|
{ #category : #utilities }
|
|
Markdown class >> yamlMetadataDelimiter [
|
|
^ '---'
|
|
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
Markdown >> asMarkdeep [
|
|
^ Markdeep new
|
|
body: self body;
|
|
markdownFile: self file;
|
|
commentYAMLMetadata
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
Markdown >> body [
|
|
^ body
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
Markdown >> body: aString [
|
|
body := aString
|
|
]
|
|
|
|
{ #category : #operation }
|
|
Markdown >> commentYAMLMetadata [
|
|
| newContents |
|
|
self detectYAMLMetadata ifFalse: [ ^ self ].
|
|
newContents := '' writeStream.
|
|
newContents nextPutAll: '<!--@yaml'; lf.
|
|
newContents nextPutAll: self yamlMetadataString.
|
|
newContents nextPutAll: '-->'; lf; lf.
|
|
(self lines copyFrom: self yamlMetadataClosingLineNumber + 2 to: self lines size) do: [ :line |
|
|
newContents nextPutAll: line; lf ].
|
|
^ newContents contents.
|
|
]
|
|
|
|
{ #category : #utilities }
|
|
Markdown >> containsYAMLMetadataClosing [
|
|
^ self yamlMetadataClosingLineNumber > 0
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
Markdown >> contents [
|
|
^ body
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
Markdown >> contents: anObject [
|
|
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 }
|
|
Markdown >> documentTree [
|
|
| parser|
|
|
parser := PPCommonMarkBlockParser new parse: self contents.
|
|
^ parser accept: CMBlockVisitor new
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
Markdown >> exportAsFile [
|
|
| newFile |
|
|
|
|
newFile := (self file fullName ) asFileReference.
|
|
^ self notifyExportAsFileOn: newFile.
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
Markdown >> exportAsFileOn: aFileReference [
|
|
aFileReference ensureDelete.
|
|
aFileReference exists ifFalse: [ aFileReference ensureCreateFile ].
|
|
aFileReference writeStreamDo: [ :stream |
|
|
stream nextPutAll: self contents ].
|
|
]
|
|
|
|
{ #category : #operation }
|
|
Markdown >> exportMetadataAsJson [
|
|
"TBD: Lua scripts should be checked and installed when missing. Maybe a shared location
|
|
in '.local/share/Grafoscopio/Scripts' should be developed in the near future."
|
|
| output luaScript |
|
|
luaScript := FileLocator home / '.local/share/Brea/scripts/meta-to-json.lua'.
|
|
Smalltalk platformName = 'unix' ifTrue: [
|
|
OSSUnixSubprocess new
|
|
workingDirectory: self file parent fullName;
|
|
command: 'pandoc';
|
|
arguments: { '--lua-filter=', luaScript fullName . self file basename };
|
|
redirectStdout;
|
|
redirectStdin;
|
|
runAndWaitOnExitDo: [ :process :outString :errString |
|
|
output := process isSuccess
|
|
ifTrue: [ outString ]
|
|
ifFalse: [ errString ]
|
|
]].
|
|
^ output correctAccentedCharacters
|
|
]
|
|
|
|
{ #category : #operation }
|
|
Markdown >> exportMetadataAsYaml [
|
|
| exportedFile |
|
|
exportedFile := FileLocator temp / 'metadata.yaml'.
|
|
MarkupFile exportAsFileOn: exportedFile containing: self yamlMetadataStringWithDelimiters.
|
|
^ exportedFile
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
Markdown >> file [
|
|
^ file ifNil: [ file := FileLocator temp / (NanoID generate asLowercase, '.md') ]
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
Markdown >> file: aFileReference [
|
|
"I store the origen/destination of the Markdown contents."
|
|
file := aFileReference
|
|
]
|
|
|
|
{ #category : #'instance creation' }
|
|
Markdown >> fromFile: aFileReference [
|
|
self contents: aFileReference contents.
|
|
self file: aFileReference.
|
|
]
|
|
|
|
{ #category : #'instance creation' }
|
|
Markdown >> fromString: markdownString [
|
|
self contents: markdownString.
|
|
self populateMetadata.
|
|
self contents: self contentsWithoutYAMLMetadata
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
Markdown >> gtTextFor: aView [
|
|
<gtView>
|
|
^ aView textEditor
|
|
title: 'Text';
|
|
text: [ self contents ]
|
|
]
|
|
|
|
{ #category : #utilities }
|
|
Markdown >> lines [
|
|
^ self contents lines.
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
Markdown >> metadata [
|
|
|
|
^ metadata ifNil: [ metadata := Dictionary new].
|
|
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
Markdown >> metadata: rawMeta [
|
|
|
|
metadata := rawMeta
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
Markdown >> notifyExportAsFileOn: aFileReference [
|
|
self exportAsFileOn: aFileReference.
|
|
self inform: 'Exported as: ', String cr, aFileReference fullName.
|
|
^ aFileReference
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
Markdown >> populateMetadata [
|
|
| 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 }
|
|
Markdown >> printOn: aStream [
|
|
super printOn: aStream.
|
|
aStream
|
|
nextPutAll: '( ', (self metadata at: 'title' ifAbsent: ['untitled']), ' )'
|
|
]
|
|
|
|
{ #category : #utilities }
|
|
Markdown >> startsWithYAMLMetadataDelimiter [
|
|
^ self lines first beginsWith: self class yamlMetadataDelimiter
|
|
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
Markdown >> yamlMetadata [
|
|
^ MiniDocs yamlToJson: self yamlMetadataString
|
|
]
|
|
|
|
{ #category : #utilities }
|
|
Markdown >> yamlMetadataClosingLineNumber [
|
|
"I return the line where the closing of the YAML metadata occurs or 0 if no closing is found."
|
|
self startsWithYAMLMetadataDelimiter ifFalse: [ ^ self ].
|
|
self lines allButFirst doWithIndex: [ :currentLine :i |
|
|
(currentLine beginsWith: self class yamlMetadataDelimiter) ifTrue: [ ^ i + 1 ]]
|
|
|
|
]
|
|
|
|
{ #category : #operation }
|
|
Markdown >> yamlMetadataString [
|
|
| output yamlLines |
|
|
self detectYAMLMetadata ifFalse: [ ^ nil ].
|
|
yamlLines := self lines copyFrom: 2 to: self yamlMetadataClosingLineNumber - 1.
|
|
output := '' writeStream.
|
|
yamlLines do: [ :line |
|
|
output
|
|
nextPutAll: line;
|
|
nextPut: Character 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.
|
|
]
|