MiniDocs/src/MiniDocs/Markdown.class.st

222 lines
5.4 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',
'title'
],
#category : #'MiniDocs-Core'
}
{ #category : #'instance creation' }
Markdown class >> fromFile: aFileReference [
^ self new fromFile: aFileReference
]
{ #category : #accessing }
Markdown >> asMarkdeep [
^ Markdeep new
body: self body;
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 [
| response |
response := WriteStream on: ''.
response
nextPutAll: '---'; cr;
nextPutAll: self metadataAsYAML; cr;
nextPutAll: '---'; cr;
nextPutAll: self body.
^ response contents
]
{ #category : #accessing }
Markdown >> contents: aString [
body := aString
]
{ #category : #accessing }
Markdown >> documentTree [
| parser|
self contents ifNil: [^ nil].
parser := PPCommonMarkBlockParser new parse: self body.
^ 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 withInternetLineEndings ].
]
{ #category : #accessing }
Markdown >> exportAsHTML [
^ Pandoc markdownToHtml: self file
]
{ #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 / 'temporalMarkdeep.md.html' ]
]
{ #category : #accessing }
Markdown >> file: aFileReference [
"I store the origen/destination of the Markdown contents."
file := aFileReference
]
{ #category : #'instance creation' }
Markdown >> fromFile: aFileReference [
self fromString: aFileReference contents.
self file: aFileReference.
]
{ #category : #'instance creation' }
Markdown >> fromString: markdownString [
(self metadata) at: 'original' put: markdownString yamlMetadata.
self body: markdownString contentsWithoutYAMLMetadata
]
{ #category : #accessing }
Markdown >> gtTextFor: aView [
<gtView>
^ aView textEditor
title: 'Text';
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 }
Markdown >> lines [
self file ifNotNil: [^ self file contents lines ].
^ self contents lines.
]
{ #category : #accessing }
Markdown >> metadata [
^ metadata ifNil: [ metadata := Dictionary new].
]
{ #category : #accessing }
Markdown >> metadata: rawMeta [
metadata := rawMeta
]
{ #category : #accessing }
Markdown >> metadataAsYAML [
self metadata isEmptyOrNil ifTrue: [ ^ '' ].
^ (YQ jsonToYaml: self metadata) accentedCharactersCorrection
]
{ #category : #persistence }
Markdown >> notifyExportAsFileOn: aFileReference [
self exportAsFileOn: aFileReference.
self inform: 'Exported as: ', String cr, aFileReference fullName.
^ aFileReference
]
{ #category : #accessing }
Markdown >> options [
^ self metadata at: 'options' ifAbsentPut: [ self defaultOptions]
]
{ #category : #accessing }
Markdown >> printOn: aStream [
| response |
super printOn: aStream.
response := self title ifNil: [ 'Untitled' ].
aStream
nextPutAll: '( ', response , ' )'
]
{ #category : #accessing }
Markdown >> title [
^ title ifNil: [ title:= self headerAsTitle ]
]