" 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: ''; 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 [ ^ 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 [ super printOn: aStream. aStream nextPutAll: '( ', self title , ' )' ] { #category : #accessing } Markdown >> title [ ^ title ifNil: [ title:= self headerAsTitle ] ]