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