From 5d68e79c2b7c5aa579eab68f9a172b388f3097f4 Mon Sep 17 00:00:00 2001 From: Offray Date: Fri, 18 Dec 2020 09:54:09 -0800 Subject: [PATCH] Improved multiplatform support and adding more replacements for Latin characters. --- .../Grafoscopio-Utils/ExternalApp.class.st | 402 +++++++++--------- .../GrafoscopioDocumentation.class.st | 398 ++++++++--------- .../GrafoscopioDocumentationTest.class.st | 48 +-- .../GrafoscopioUtils.class.st | 328 +++++++------- .../GrafoscopioUtilsTest.class.st | 16 +- .../Grafoscopio-Utils/HedgeDoc.class.st | 226 +++++----- .../Grafoscopio-Utils/Markdeep.class.st | 370 ++++++++-------- .../Grafoscopio-Utils/Markdown.class.st | 338 +++++++-------- .../Grafoscopio-Utils/MarkupFile.class.st | 46 +- repository/Grafoscopio-Utils/OrgMode.class.st | 92 ++-- repository/Grafoscopio-Utils/Pandoc.class.st | 292 ++++++------- .../Grafoscopio-Utils/PandocWork.class.st | 356 ++++++++-------- .../Grafoscopio-Utils/String.extension.st | 73 ++-- repository/Grafoscopio-Utils/package.st | 2 +- 14 files changed, 1495 insertions(+), 1492 deletions(-) diff --git a/repository/Grafoscopio-Utils/ExternalApp.class.st b/repository/Grafoscopio-Utils/ExternalApp.class.st index 8c874d0..faa4841 100644 --- a/repository/Grafoscopio-Utils/ExternalApp.class.st +++ b/repository/Grafoscopio-Utils/ExternalApp.class.st @@ -1,201 +1,201 @@ -" -I provide support for external helper apps for Grafoscopio, publishing, collaboration -and data management. -" -Class { - #name : #ExternalApp, - #superclass : #Object, - #instVars : [ - 'name', - 'url', - 'downloadUrl', - 'description', - 'sha1', - 'md5', - 'binaryLocation' - ], - #category : #'Grafoscopio-Utils' -} - -{ #category : #installation } -ExternalApp class >> compareHashFor: aFileName with: aSHAString [ - - aSHAString = (SHA1 new hashMessage: aFileName asFileReference binaryReadStream contents) hex - ifFalse: [ ^ false ] - ifTrue: [ ^ true ]. -] - -{ #category : #configuration } -ExternalApp class >> configureFossil [ - "Stablish where is located fossil according to the operative system and/or the input of the user" - | fileStream fossil | - - fileStream := UIManager default fileOpen: 'Path to the fossil program binary'. - fileStream isNil ifTrue: [ ^nil ]. - fossil := fileStream name asFileReference fullName. - -] - -{ #category : #configuration } -ExternalApp class >> configurePandoc [ - "Stablish where is located pandoc according to the operative system and/or the input of the user" - | fileStream pandoc | - - fileStream := UIManager default fileOpen: 'Path to pandoc program binary'. - fileStream isNil ifTrue: [ ^nil ]. - pandoc := fileStream name asFileReference fullName. - -] - -{ #category : #installation } -ExternalApp class >> installSQLite32Bits [ - "I dowload the SQLite binary for the hosting platform, uncompress it and made it available as with the name - NBSQLite is wating for" - - | packageUrl sha1 localPath packageZipName unzippedFolder | - - localPath := FileSystem disk workingDirectory parent / 'bin'. - Smalltalk platform name = 'unix' - ifTrue: [ - packageUrl := 'http://sqlite.org/2016/sqlite-tools-linux-x86-3110100.zip'. - sha1 := '21a80cefa91d5de50256996fc55990a027c350fd']. - Smalltalk platform name = 'Win32' - ifTrue: [ - packageUrl := 'http://sqlite.org/2016/sqlite-dll-win32-x86-3110100.zip'. - sha1 := 'cfd6f64ba1fb5de1ccf8321e29764c690c25e0a0']. - Smalltalk platform name = 'Mac OS' - ifTrue: [ - packageUrl := 'http://sqlite.org/2016/sqlite-tools-osx-x86-3110100.zip'. - sha1 := 'c78b3b92bd37554694d2f73dbecfef1902c15ba7']. - self isSQLite32BitsInstalled - ifTrue: [ self inform: 'SQLite ya está instalado en el sistema' ] - ifFalse: [ - GrafoscopioBrowser - downloadingFrom: packageUrl - withMessage: 'Descargando SQLite...' - into: localPath asFileReference. - packageZipName := (packageUrl splitOn: '/') last. - sha1 = (SHA1 new hashMessage: (localPath / packageZipName) asFileReference binaryReadStream contents) hex - ifFalse: [ self inform: 'SQLite: Descarga no exitosa. - Por favor intente el procedimiento de nuevo o manualmente'] - ifTrue: [ - ZipArchive new - readFrom: (localPath / packageZipName); - extractAllTo: localPath asFileReference. - unzippedFolder := packageZipName copyReplaceAll: '.zip' with: ''. - (localPath / unzippedFolder ) children do: - [:file | file moveTo: (localPath / file basenameWithIndicator)]. - (localPath / 'sqlite3') copyTo: (localPath / 'libsqlite3.so'). - (localPath / unzippedFolder ) deleteAll. - self inform: 'SQLite instalado existosammente!' - ]. - "Cleaning leftovers" - (localPath / packageZipName) delete - ] -] - -{ #category : #configuration } -ExternalApp class >> installSQLite32BitsUI [ - "I verify if SQLite for 32 bits is installed in the proper location. If yes, I inform that. If not, - I made the installation" - | install | - install := (UIManager default - confirm: '¿Desea instalar el motor de base de datos (SQLite)?' - label: 'Instalar base de datos?'). - install ifTrue: [self installSQLite32Bits] - -] - -{ #category : #installation } -ExternalApp class >> isSQLite32BitsInstalled [ - "I verify if the SQLite binary for the hosting platform is installed" - - ^ (FileSystem disk workingDirectory parent / 'bin' / 'libsqlite3.so') asFileReference exists - -] - -{ #category : #configuration } -ExternalApp class >> pandoc [ - "I define where the pandoc external app is located" - | app | - app := ExternalApp new - name: 'pandoc'; - url: 'http://pandoc.org'; - description: 'Pandoc is a free and open-source software document converter, widely used as a writing tool (especially by scholars) and as a basis for publishing workflows. It was originally created by John MacFarlane, a philosophy professor at the University of California, Berkeley. (from https://en.wikipedia.org/wiki/Pandoc)'. - app binaryLocation: '/usr/bin/pandoc' asFileReference. - ^ app - - - - -] - -{ #category : #accessing } -ExternalApp >> binaryLocation [ - ^ binaryLocation -] - -{ #category : #accessing } -ExternalApp >> binaryLocation: anObject [ - binaryLocation := anObject -] - -{ #category : #accessing } -ExternalApp >> description [ - ^ description -] - -{ #category : #accessing } -ExternalApp >> description: anObject [ - description := anObject -] - -{ #category : #accessing } -ExternalApp >> downloadUrl [ - ^ downloadUrl -] - -{ #category : #accessing } -ExternalApp >> downloadUrl: anObject [ - downloadUrl := anObject -] - -{ #category : #accessing } -ExternalApp >> md5 [ - ^ md5 -] - -{ #category : #accessing } -ExternalApp >> md5: anObject [ - md5 := anObject -] - -{ #category : #accessing } -ExternalApp >> name [ - ^ name -] - -{ #category : #accessing } -ExternalApp >> name: anObject [ - name := anObject -] - -{ #category : #accessing } -ExternalApp >> sha1 [ - ^ sha1 -] - -{ #category : #accessing } -ExternalApp >> sha1: anObject [ - sha1 := anObject -] - -{ #category : #accessing } -ExternalApp >> url [ - ^ url -] - -{ #category : #accessing } -ExternalApp >> url: anObject [ - url := anObject -] +" +I provide support for external helper apps for Grafoscopio, publishing, collaboration +and data management. +" +Class { + #name : #ExternalApp, + #superclass : #Object, + #instVars : [ + 'name', + 'url', + 'downloadUrl', + 'description', + 'sha1', + 'md5', + 'binaryLocation' + ], + #category : #'Grafoscopio-Utils' +} + +{ #category : #installation } +ExternalApp class >> compareHashFor: aFileName with: aSHAString [ + + aSHAString = (SHA1 new hashMessage: aFileName asFileReference binaryReadStream contents) hex + ifFalse: [ ^ false ] + ifTrue: [ ^ true ]. +] + +{ #category : #configuration } +ExternalApp class >> configureFossil [ + "Stablish where is located fossil according to the operative system and/or the input of the user" + | fileStream fossil | + + fileStream := UIManager default fileOpen: 'Path to the fossil program binary'. + fileStream isNil ifTrue: [ ^nil ]. + fossil := fileStream name asFileReference fullName. + +] + +{ #category : #configuration } +ExternalApp class >> configurePandoc [ + "Stablish where is located pandoc according to the operative system and/or the input of the user" + | fileStream pandoc | + + fileStream := UIManager default fileOpen: 'Path to pandoc program binary'. + fileStream isNil ifTrue: [ ^nil ]. + pandoc := fileStream name asFileReference fullName. + +] + +{ #category : #installation } +ExternalApp class >> installSQLite32Bits [ + "I dowload the SQLite binary for the hosting platform, uncompress it and made it available as with the name + NBSQLite is wating for" + + | packageUrl sha1 localPath packageZipName unzippedFolder | + + localPath := FileSystem disk workingDirectory parent / 'bin'. + Smalltalk platform name = 'unix' + ifTrue: [ + packageUrl := 'http://sqlite.org/2016/sqlite-tools-linux-x86-3110100.zip'. + sha1 := '21a80cefa91d5de50256996fc55990a027c350fd']. + Smalltalk platform name = 'Win32' + ifTrue: [ + packageUrl := 'http://sqlite.org/2016/sqlite-dll-win32-x86-3110100.zip'. + sha1 := 'cfd6f64ba1fb5de1ccf8321e29764c690c25e0a0']. + Smalltalk platform name = 'Mac OS' + ifTrue: [ + packageUrl := 'http://sqlite.org/2016/sqlite-tools-osx-x86-3110100.zip'. + sha1 := 'c78b3b92bd37554694d2f73dbecfef1902c15ba7']. + self isSQLite32BitsInstalled + ifTrue: [ self inform: 'SQLite ya está instalado en el sistema' ] + ifFalse: [ + GrafoscopioBrowser + downloadingFrom: packageUrl + withMessage: 'Descargando SQLite...' + into: localPath asFileReference. + packageZipName := (packageUrl splitOn: '/') last. + sha1 = (SHA1 new hashMessage: (localPath / packageZipName) asFileReference binaryReadStream contents) hex + ifFalse: [ self inform: 'SQLite: Descarga no exitosa. + Por favor intente el procedimiento de nuevo o manualmente'] + ifTrue: [ + ZipArchive new + readFrom: (localPath / packageZipName); + extractAllTo: localPath asFileReference. + unzippedFolder := packageZipName copyReplaceAll: '.zip' with: ''. + (localPath / unzippedFolder ) children do: + [:file | file moveTo: (localPath / file basenameWithIndicator)]. + (localPath / 'sqlite3') copyTo: (localPath / 'libsqlite3.so'). + (localPath / unzippedFolder ) deleteAll. + self inform: 'SQLite instalado existosammente!' + ]. + "Cleaning leftovers" + (localPath / packageZipName) delete + ] +] + +{ #category : #configuration } +ExternalApp class >> installSQLite32BitsUI [ + "I verify if SQLite for 32 bits is installed in the proper location. If yes, I inform that. If not, + I made the installation" + | install | + install := (UIManager default + confirm: '¿Desea instalar el motor de base de datos (SQLite)?' + label: 'Instalar base de datos?'). + install ifTrue: [self installSQLite32Bits] + +] + +{ #category : #installation } +ExternalApp class >> isSQLite32BitsInstalled [ + "I verify if the SQLite binary for the hosting platform is installed" + + ^ (FileSystem disk workingDirectory parent / 'bin' / 'libsqlite3.so') asFileReference exists + +] + +{ #category : #configuration } +ExternalApp class >> pandoc [ + "I define where the pandoc external app is located" + | app | + app := ExternalApp new + name: 'pandoc'; + url: 'http://pandoc.org'; + description: 'Pandoc is a free and open-source software document converter, widely used as a writing tool (especially by scholars) and as a basis for publishing workflows. It was originally created by John MacFarlane, a philosophy professor at the University of California, Berkeley. (from https://en.wikipedia.org/wiki/Pandoc)'. + app binaryLocation: '/usr/bin/pandoc' asFileReference. + ^ app + + + + +] + +{ #category : #accessing } +ExternalApp >> binaryLocation [ + ^ binaryLocation +] + +{ #category : #accessing } +ExternalApp >> binaryLocation: anObject [ + binaryLocation := anObject +] + +{ #category : #accessing } +ExternalApp >> description [ + ^ description +] + +{ #category : #accessing } +ExternalApp >> description: anObject [ + description := anObject +] + +{ #category : #accessing } +ExternalApp >> downloadUrl [ + ^ downloadUrl +] + +{ #category : #accessing } +ExternalApp >> downloadUrl: anObject [ + downloadUrl := anObject +] + +{ #category : #accessing } +ExternalApp >> md5 [ + ^ md5 +] + +{ #category : #accessing } +ExternalApp >> md5: anObject [ + md5 := anObject +] + +{ #category : #accessing } +ExternalApp >> name [ + ^ name +] + +{ #category : #accessing } +ExternalApp >> name: anObject [ + name := anObject +] + +{ #category : #accessing } +ExternalApp >> sha1 [ + ^ sha1 +] + +{ #category : #accessing } +ExternalApp >> sha1: anObject [ + sha1 := anObject +] + +{ #category : #accessing } +ExternalApp >> url [ + ^ url +] + +{ #category : #accessing } +ExternalApp >> url: anObject [ + url := anObject +] diff --git a/repository/Grafoscopio-Utils/GrafoscopioDocumentation.class.st b/repository/Grafoscopio-Utils/GrafoscopioDocumentation.class.st index 4af7809..4157786 100644 --- a/repository/Grafoscopio-Utils/GrafoscopioDocumentation.class.st +++ b/repository/Grafoscopio-Utils/GrafoscopioDocumentation.class.st @@ -1,199 +1,199 @@ -" -I model a documentation object for Grafoscopio. -Documents are stored in a fossil repository and have -relative paths to it. -" -Class { - #name : #GrafoscopioDocumentation, - #superclass : #Object, - #instVars : [ - 'repository', - 'documents', - 'localPlace', - 'name' - ], - #category : #'Grafoscopio-Utils' -} - -{ #category : #updating } -GrafoscopioDocumentation class >> documents [ - ^ self newDefault documents -] - -{ #category : #api } -GrafoscopioDocumentation class >> download: aFileName [ - self newDefault download: aFileName -] - -{ #category : #updating } -GrafoscopioDocumentation class >> listOutdatedDocs [ - ^ self newDefault listOutdatedDocs -] - -{ #category : #updating } -GrafoscopioDocumentation class >> localPlace [ - ^ self newDefault localPlace -] - -{ #category : #'instance creation' } -GrafoscopioDocumentation class >> newDefault [ - ^ self new -] - -{ #category : #updating } -GrafoscopioDocumentation class >> update [ - ^ self newDefault update -] - -{ #category : #updating } -GrafoscopioDocumentation class >> updateAll [ - GfUIHelpers docsCollection do: [ :docs | docs update ] -] - -{ #category : #updating } -GrafoscopioDocumentation class >> updateAllUI [ - "Updates documentation (manual, tutorials) from the official repository for a given documentation." - | update | - update := (UIManager default - confirm: 'Do you wish to update the documentation?' - label: 'Update documentation'). - update - ifTrue: [ self updateAll ] -] - -{ #category : #accessing } -GrafoscopioDocumentation >> addDocument: aFilePath [ - "I add the document contained in aFilePath (a String) to the list of documents that belong - to this collection, taking care of avoiding repetitions" - - (self documents includes: aFilePath) ifFalse: [ self documents add: aFilePath ] -] - -{ #category : #accessing } -GrafoscopioDocumentation >> documents [ - ^ documents ifNil: [ documents := OrderedCollection new ] -] - -{ #category : #accessing } -GrafoscopioDocumentation >> documents: anObject [ - documents := anObject -] - -{ #category : #updating } -GrafoscopioDocumentation >> download: fileNameWithRelativePath [ - | fileName parentFolder sanitized lastVersion | - fileName := (fileNameWithRelativePath splitOn: $/) last. - sanitized := self repository sanitize: fileNameWithRelativePath. - lastVersion := self repository lastVersionPath: fileNameWithRelativePath. - parentFolder := GrafoscopioUtils - ensureCreateDirectory: sanitized into: self localPlace. - GrafoscopioUtils - downloadingFrom: self repository remote asString, lastVersion - withMessage: 'Downloading ', fileName - into: parentFolder -] - -{ #category : #updating } -GrafoscopioDocumentation >> isFileUpdatedFor: relativeFilePath [ - "I compare if the local and remote copies of a relativeFilePath are updated for the current - documentation and return true if they are and false in any other case" - | localFile | - localFile := self localPlace / relativeFilePath. - localFile exists - ifFalse: [ ^ false ] - ifTrue: [ - ^ ExternalApp - compareHashFor: localFile - with: (self repository lastHashNumberFor: relativeFilePath) ] -] - -{ #category : #updating } -GrafoscopioDocumentation >> listOutdatedDocs [ - "I return the list of all documentent where the local copy and the remote copy doesn't match" - ^ self documents reject: [ :doc | (self isFileUpdatedFor: doc) ] -] - -{ #category : #accessing } -GrafoscopioDocumentation >> localPlace [ - ^ localPlace. -] - -{ #category : #accessing } -GrafoscopioDocumentation >> localPlace: aFileDirectory [ - localPlace := aFileDirectory. - self localPlace exists ifFalse: [ self localPlace ensureCreateDirectory ]. - -] - -{ #category : #accessing } -GrafoscopioDocumentation >> name [ - ^ name -] - -{ #category : #accessing } -GrafoscopioDocumentation >> name: anObject [ - name := anObject -] - -{ #category : #accessing } -GrafoscopioDocumentation >> openNotebookAt: index [ - "I open a notebook included with the documentation, located at a given index (anInteger)" - | notebookTemp | - (index between: 1 and: self documents size) - ifFalse: [ ^ self ] - ifTrue: [ - notebookTemp := (self localPlace fullName, '/', (self documents at: index)) asFileReference. - notebookTemp exists - ifTrue: [GrafoscopioNotebook new openFromFile: notebookTemp] - ifFalse: [ self updateUI ]] -] - -{ #category : #updating } -GrafoscopioDocumentation >> registerIntoDockingBar [ - "I detect if any of the documents that are part of my collection contains any metadata - indicating if they should be registered in the main docking bar, and in such case, I add them." - self documents - do: [ :doc | | metadata currentNotebook | - currentNotebook := GrafoscopioNotebook new loadFromFile: self localPlace / doc. - metadata := currentNotebook metadata. - metadata ifNotNil: [ - metadata - at: 'showOnHelp' - ifPresent: [ self error:' missing class grafoscopio docking bar' "GrafoscopioDockingBar addToHelpMenu: currentNotebook" ] ] ] -] - -{ #category : #accessing } -GrafoscopioDocumentation >> repository [ - ^ repository -] - -{ #category : #accessing } -GrafoscopioDocumentation >> repository: aFossilRepo [ - repository := aFossilRepo -] - -{ #category : #updating } -GrafoscopioDocumentation >> update [ - (self listOutdatedDocs) - ifEmpty: [ - self inform: 'All documents in the ', self name,' collection are already updated'. - ^ self ] - ifNotEmpty: [:outdatedDocs | - outdatedDocs do: [ :eachDoc | self download: eachDoc ]. - self inform: 'Updating of ', self name,' documentation finished.' ] -] - -{ #category : #updating } -GrafoscopioDocumentation >> updateDocsPlaceUI [ - self current localPlace: (UIManager default chooseDirectory: 'Path to the documentation folder') -] - -{ #category : #updating } -GrafoscopioDocumentation >> updateUI [ - "Updates documentation (manual, tutorials) from the official repository for a given documentation." - | update | - update := (UIManager default - confirm: 'Do you wish to update the ', self name,' documentation?' - label: 'Update ', self name, ' documentation'). - update ifTrue: [ self update ] -] +" +I model a documentation object for Grafoscopio. +Documents are stored in a fossil repository and have +relative paths to it. +" +Class { + #name : #GrafoscopioDocumentation, + #superclass : #Object, + #instVars : [ + 'repository', + 'documents', + 'localPlace', + 'name' + ], + #category : #'Grafoscopio-Utils' +} + +{ #category : #updating } +GrafoscopioDocumentation class >> documents [ + ^ self newDefault documents +] + +{ #category : #api } +GrafoscopioDocumentation class >> download: aFileName [ + self newDefault download: aFileName +] + +{ #category : #updating } +GrafoscopioDocumentation class >> listOutdatedDocs [ + ^ self newDefault listOutdatedDocs +] + +{ #category : #updating } +GrafoscopioDocumentation class >> localPlace [ + ^ self newDefault localPlace +] + +{ #category : #'instance creation' } +GrafoscopioDocumentation class >> newDefault [ + ^ self new +] + +{ #category : #updating } +GrafoscopioDocumentation class >> update [ + ^ self newDefault update +] + +{ #category : #updating } +GrafoscopioDocumentation class >> updateAll [ + GfUIHelpers docsCollection do: [ :docs | docs update ] +] + +{ #category : #updating } +GrafoscopioDocumentation class >> updateAllUI [ + "Updates documentation (manual, tutorials) from the official repository for a given documentation." + | update | + update := (UIManager default + confirm: 'Do you wish to update the documentation?' + label: 'Update documentation'). + update + ifTrue: [ self updateAll ] +] + +{ #category : #accessing } +GrafoscopioDocumentation >> addDocument: aFilePath [ + "I add the document contained in aFilePath (a String) to the list of documents that belong + to this collection, taking care of avoiding repetitions" + + (self documents includes: aFilePath) ifFalse: [ self documents add: aFilePath ] +] + +{ #category : #accessing } +GrafoscopioDocumentation >> documents [ + ^ documents ifNil: [ documents := OrderedCollection new ] +] + +{ #category : #accessing } +GrafoscopioDocumentation >> documents: anObject [ + documents := anObject +] + +{ #category : #updating } +GrafoscopioDocumentation >> download: fileNameWithRelativePath [ + | fileName parentFolder sanitized lastVersion | + fileName := (fileNameWithRelativePath splitOn: $/) last. + sanitized := self repository sanitize: fileNameWithRelativePath. + lastVersion := self repository lastVersionPath: fileNameWithRelativePath. + parentFolder := GrafoscopioUtils + ensureCreateDirectory: sanitized into: self localPlace. + GrafoscopioUtils + downloadingFrom: self repository remote asString, lastVersion + withMessage: 'Downloading ', fileName + into: parentFolder +] + +{ #category : #updating } +GrafoscopioDocumentation >> isFileUpdatedFor: relativeFilePath [ + "I compare if the local and remote copies of a relativeFilePath are updated for the current + documentation and return true if they are and false in any other case" + | localFile | + localFile := self localPlace / relativeFilePath. + localFile exists + ifFalse: [ ^ false ] + ifTrue: [ + ^ ExternalApp + compareHashFor: localFile + with: (self repository lastHashNumberFor: relativeFilePath) ] +] + +{ #category : #updating } +GrafoscopioDocumentation >> listOutdatedDocs [ + "I return the list of all documentent where the local copy and the remote copy doesn't match" + ^ self documents reject: [ :doc | (self isFileUpdatedFor: doc) ] +] + +{ #category : #accessing } +GrafoscopioDocumentation >> localPlace [ + ^ localPlace. +] + +{ #category : #accessing } +GrafoscopioDocumentation >> localPlace: aFileDirectory [ + localPlace := aFileDirectory. + self localPlace exists ifFalse: [ self localPlace ensureCreateDirectory ]. + +] + +{ #category : #accessing } +GrafoscopioDocumentation >> name [ + ^ name +] + +{ #category : #accessing } +GrafoscopioDocumentation >> name: anObject [ + name := anObject +] + +{ #category : #accessing } +GrafoscopioDocumentation >> openNotebookAt: index [ + "I open a notebook included with the documentation, located at a given index (anInteger)" + | notebookTemp | + (index between: 1 and: self documents size) + ifFalse: [ ^ self ] + ifTrue: [ + notebookTemp := (self localPlace fullName, '/', (self documents at: index)) asFileReference. + notebookTemp exists + ifTrue: [GrafoscopioNotebook new openFromFile: notebookTemp] + ifFalse: [ self updateUI ]] +] + +{ #category : #updating } +GrafoscopioDocumentation >> registerIntoDockingBar [ + "I detect if any of the documents that are part of my collection contains any metadata + indicating if they should be registered in the main docking bar, and in such case, I add them." + self documents + do: [ :doc | | metadata currentNotebook | + currentNotebook := GrafoscopioNotebook new loadFromFile: self localPlace / doc. + metadata := currentNotebook metadata. + metadata ifNotNil: [ + metadata + at: 'showOnHelp' + ifPresent: [ self error:' missing class grafoscopio docking bar' "GrafoscopioDockingBar addToHelpMenu: currentNotebook" ] ] ] +] + +{ #category : #accessing } +GrafoscopioDocumentation >> repository [ + ^ repository +] + +{ #category : #accessing } +GrafoscopioDocumentation >> repository: aFossilRepo [ + repository := aFossilRepo +] + +{ #category : #updating } +GrafoscopioDocumentation >> update [ + (self listOutdatedDocs) + ifEmpty: [ + self inform: 'All documents in the ', self name,' collection are already updated'. + ^ self ] + ifNotEmpty: [:outdatedDocs | + outdatedDocs do: [ :eachDoc | self download: eachDoc ]. + self inform: 'Updating of ', self name,' documentation finished.' ] +] + +{ #category : #updating } +GrafoscopioDocumentation >> updateDocsPlaceUI [ + self current localPlace: (UIManager default chooseDirectory: 'Path to the documentation folder') +] + +{ #category : #updating } +GrafoscopioDocumentation >> updateUI [ + "Updates documentation (manual, tutorials) from the official repository for a given documentation." + | update | + update := (UIManager default + confirm: 'Do you wish to update the ', self name,' documentation?' + label: 'Update ', self name, ' documentation'). + update ifTrue: [ self update ] +] diff --git a/repository/Grafoscopio-Utils/GrafoscopioDocumentationTest.class.st b/repository/Grafoscopio-Utils/GrafoscopioDocumentationTest.class.st index 3f98a8d..37decf3 100644 --- a/repository/Grafoscopio-Utils/GrafoscopioDocumentationTest.class.st +++ b/repository/Grafoscopio-Utils/GrafoscopioDocumentationTest.class.st @@ -1,24 +1,24 @@ -" -A GrafoscopioDocumentationTest is a test class for testing the behavior of GrafoscopioDocumentation -" -Class { - #name : #GrafoscopioDocumentationTest, - #superclass : #TestCase, - #category : #'Grafoscopio-Utils-Tests' -} - -{ #category : #'tests-utility' } -GrafoscopioDocumentationTest >> defaultTestRepo [ - "I create a default documentation repository, that is used for several test." - - | testRepo | - testRepo := GrafoscopioDocumentation new. - testRepo repository: (FossilRepo new remote: 'http://mutabit.com/repos.fossil/grafoscopio'); - localPlace: FileLocator temp asFileReference /'Grafoscopio'; - name: 'test Repo'. - testRepo - addDocument: 'Docs/Es/Tutoriales/tutorial.ston'; - addDocument: 'Docs/En/Books/Manual/manual.ston'; - addDocument: 'Docs/En/Books/DataActivism/techniques-for-datactivism.ston'. - ^ testRepo -] +" +A GrafoscopioDocumentationTest is a test class for testing the behavior of GrafoscopioDocumentation +" +Class { + #name : #GrafoscopioDocumentationTest, + #superclass : #TestCase, + #category : #'Grafoscopio-Utils-Tests' +} + +{ #category : #'tests-utility' } +GrafoscopioDocumentationTest >> defaultTestRepo [ + "I create a default documentation repository, that is used for several test." + + | testRepo | + testRepo := GrafoscopioDocumentation new. + testRepo repository: (FossilRepo new remote: 'http://mutabit.com/repos.fossil/grafoscopio'); + localPlace: FileLocator temp asFileReference /'Grafoscopio'; + name: 'test Repo'. + testRepo + addDocument: 'Docs/Es/Tutoriales/tutorial.ston'; + addDocument: 'Docs/En/Books/Manual/manual.ston'; + addDocument: 'Docs/En/Books/DataActivism/techniques-for-datactivism.ston'. + ^ testRepo +] diff --git a/repository/Grafoscopio-Utils/GrafoscopioUtils.class.st b/repository/Grafoscopio-Utils/GrafoscopioUtils.class.st index 68de372..debaac0 100644 --- a/repository/Grafoscopio-Utils/GrafoscopioUtils.class.st +++ b/repository/Grafoscopio-Utils/GrafoscopioUtils.class.st @@ -1,164 +1,164 @@ -" -I contain simple general functionality used by Grafoscopio, Dataviz -or other related projects. -" -Class { - #name : #GrafoscopioUtils, - #superclass : #Object, - #category : #'Grafoscopio-Utils' -} - -{ #category : #utilities } -GrafoscopioUtils class >> checksumFor: aFileReference [ - ^ (SHA1 new hashMessage: aFileReference binaryReadStream contents) hex. -] - -{ #category : #updating } -GrafoscopioUtils class >> download: fileNameWithRelativePath from: urlString into: aFolder [ - | fileName parentFolder | - fileName := (fileNameWithRelativePath splitOn: $/) last. - parentFolder := self ensureCreateDirectory: fileNameWithRelativePath into: aFolder. - self - downloadingFrom: urlString, fileNameWithRelativePath - withMessage: 'Downloading ', fileName - into: parentFolder -] - -{ #category : #'graphical interface' } -GrafoscopioUtils class >> downloadingFrom: downloadUrl withMessage: aString into: location [ - | fileName | - fileName := (self sanitize: downloadUrl) segments last. - (location / fileName) ensureDelete. - [: bar | - bar title: aString. - [ZnClient new - enforceHttpSuccess: true; - url: downloadUrl; - downloadTo: location; - signalProgress: true - ] - on: HTTPProgress - do: [ :progress | - progress isEmpty ifFalse: [ bar current: progress percentage ]. - progress resume ]. - ] asJob run. - - ^ (location / fileName) asFileReference -] - -{ #category : #utilities } -GrafoscopioUtils class >> ensureCreateDirectory: fileNameWithRelativePath into: aFolder [ - | relativePathFolders parentFolder newPath | - relativePathFolders := (fileNameWithRelativePath splitOn: $/) allButLast. - newPath := aFolder path. - relativePathFolders do: [ :folder | newPath := newPath / folder ]. - parentFolder := newPath asFileReference. - parentFolder ensureCreateDirectory. - ^ parentFolder - -] - -{ #category : #persistence } -GrafoscopioUtils class >> exportAsSton: anObject on: aFileReference [ - aFileReference exists ifTrue: [ aFileReference ensureDelete ]. - aFileReference ensureCreateFile. - aFileReference writeStreamDo: [ :stream | - (STON writer on: stream) - newLine: String crlf; - prettyPrint: true; - keepNewLines: true; - nextPut: anObject ]. - - - -] - -{ #category : #'graphical interface' } -GrafoscopioUtils class >> getContentsFrom: url withMessage: aString [ - | client | - [: bar | - bar title: aString. - [client := ZnClient new - enforceHttpSuccess: true; - get: (url); - signalProgress: true - ] - on: HTTPProgress - do: [ :progress | - progress isEmpty ifFalse: [ bar current: progress percentage ]. - progress resume ]. - ] asJob run. - ^ client contents. -] - -{ #category : #persistence } -GrafoscopioUtils class >> joinLinesFor: aCollection [ - - | joinedLines | - - joinedLines := WriteStream on: ''. - aCollection do: [ :line | joinedLines nextPutAll: line; crlf ]. - ^ joinedLines contents -] - -{ #category : #utilities } -GrafoscopioUtils class >> perform: aString on: anObject [ - - | msg | - msg := self selectorAndArgumentsFrom: aString. - msg - at: 'args' - ifPresent: [ ^ anObject perform: (msg at: 'selector') withArguments: (msg at: 'args') ] - ifAbsent: [ ^ anObject perform: (msg at: 'selector') ] -] - -{ #category : #private } -GrafoscopioUtils class >> sanitize: url [ - "I remove white spaces in url's and prepend 'http://' to urls when it is ommited, so - operations that rely on sane and well formed urls don't throw error messages." - | sanitized modUrl | - modUrl := url. - [modUrl asString endsWith: ' '] - whileTrue: [ modUrl := modUrl copyFrom: 1 to: (modUrl size - 1) ]. - (url asString beginsWith: 'http') "http or https" - ifFalse: [ sanitized := ('http://', modUrl) asUrl ] - ifTrue: [ sanitized := modUrl asUrl ]. - ^ sanitized -] - -{ #category : #utilities } -GrafoscopioUtils class >> selectorAndArgumentsFrom: aString [ - "I return from aString a dictionary that contains a message and an array of arguments used - in such string. Notice that the keyword message must contain spaces between the ':' and its - respective argument. - See GrafoscopioUtilsTest for examples" - | msgArray answer keywords selector args | - answer := OrderedDictionary new. - msgArray := aString splitOn: ':'. - msgArray size = 1 - ifTrue: [ - ^ answer - at: 'selector' put: (msgArray at: 1) asSymbol; - yourself ]. - selector := ''. - args := OrderedCollection new. - aString - splitOn: Character space - do: [ :part | - part endsWithAColon - ifTrue: [ selector := selector, part ] - ifFalse: [ args add: part ] ]. - answer - at: 'selector' put: selector asSymbol; - at: 'args' put: args asArray. - ^ answer -] - -{ #category : #updating } -GrafoscopioUtils class >> update [ - "Updates GrafoscopioUtils with new versions of itself take from the source code repository." - Gofer new - smalltalkhubUser: 'Offray' project: 'Grafoscopio'; - package: 'Grafoscopio-Utils'; - load. -] +" +I contain simple general functionality used by Grafoscopio, Dataviz +or other related projects. +" +Class { + #name : #GrafoscopioUtils, + #superclass : #Object, + #category : #'Grafoscopio-Utils' +} + +{ #category : #utilities } +GrafoscopioUtils class >> checksumFor: aFileReference [ + ^ (SHA1 new hashMessage: aFileReference binaryReadStream contents) hex. +] + +{ #category : #updating } +GrafoscopioUtils class >> download: fileNameWithRelativePath from: urlString into: aFolder [ + | fileName parentFolder | + fileName := (fileNameWithRelativePath splitOn: $/) last. + parentFolder := self ensureCreateDirectory: fileNameWithRelativePath into: aFolder. + self + downloadingFrom: urlString, fileNameWithRelativePath + withMessage: 'Downloading ', fileName + into: parentFolder +] + +{ #category : #'graphical interface' } +GrafoscopioUtils class >> downloadingFrom: downloadUrl withMessage: aString into: location [ + | fileName | + fileName := (self sanitize: downloadUrl) segments last. + (location / fileName) ensureDelete. + [: bar | + bar title: aString. + [ZnClient new + enforceHttpSuccess: true; + url: downloadUrl; + downloadTo: location; + signalProgress: true + ] + on: HTTPProgress + do: [ :progress | + progress isEmpty ifFalse: [ bar current: progress percentage ]. + progress resume ]. + ] asJob run. + + ^ (location / fileName) asFileReference +] + +{ #category : #utilities } +GrafoscopioUtils class >> ensureCreateDirectory: fileNameWithRelativePath into: aFolder [ + | relativePathFolders parentFolder newPath | + relativePathFolders := (fileNameWithRelativePath splitOn: $/) allButLast. + newPath := aFolder path. + relativePathFolders do: [ :folder | newPath := newPath / folder ]. + parentFolder := newPath asFileReference. + parentFolder ensureCreateDirectory. + ^ parentFolder + +] + +{ #category : #persistence } +GrafoscopioUtils class >> exportAsSton: anObject on: aFileReference [ + aFileReference exists ifTrue: [ aFileReference ensureDelete ]. + aFileReference ensureCreateFile. + aFileReference writeStreamDo: [ :stream | + (STON writer on: stream) + newLine: String crlf; + prettyPrint: true; + keepNewLines: true; + nextPut: anObject ]. + + + +] + +{ #category : #'graphical interface' } +GrafoscopioUtils class >> getContentsFrom: url withMessage: aString [ + | client | + [: bar | + bar title: aString. + [client := ZnClient new + enforceHttpSuccess: true; + get: (url); + signalProgress: true + ] + on: HTTPProgress + do: [ :progress | + progress isEmpty ifFalse: [ bar current: progress percentage ]. + progress resume ]. + ] asJob run. + ^ client contents. +] + +{ #category : #persistence } +GrafoscopioUtils class >> joinLinesFor: aCollection [ + + | joinedLines | + + joinedLines := WriteStream on: ''. + aCollection do: [ :line | joinedLines nextPutAll: line; crlf ]. + ^ joinedLines contents +] + +{ #category : #utilities } +GrafoscopioUtils class >> perform: aString on: anObject [ + + | msg | + msg := self selectorAndArgumentsFrom: aString. + msg + at: 'args' + ifPresent: [ ^ anObject perform: (msg at: 'selector') withArguments: (msg at: 'args') ] + ifAbsent: [ ^ anObject perform: (msg at: 'selector') ] +] + +{ #category : #private } +GrafoscopioUtils class >> sanitize: url [ + "I remove white spaces in url's and prepend 'http://' to urls when it is ommited, so + operations that rely on sane and well formed urls don't throw error messages." + | sanitized modUrl | + modUrl := url. + [modUrl asString endsWith: ' '] + whileTrue: [ modUrl := modUrl copyFrom: 1 to: (modUrl size - 1) ]. + (url asString beginsWith: 'http') "http or https" + ifFalse: [ sanitized := ('http://', modUrl) asUrl ] + ifTrue: [ sanitized := modUrl asUrl ]. + ^ sanitized +] + +{ #category : #utilities } +GrafoscopioUtils class >> selectorAndArgumentsFrom: aString [ + "I return from aString a dictionary that contains a message and an array of arguments used + in such string. Notice that the keyword message must contain spaces between the ':' and its + respective argument. + See GrafoscopioUtilsTest for examples" + | msgArray answer keywords selector args | + answer := OrderedDictionary new. + msgArray := aString splitOn: ':'. + msgArray size = 1 + ifTrue: [ + ^ answer + at: 'selector' put: (msgArray at: 1) asSymbol; + yourself ]. + selector := ''. + args := OrderedCollection new. + aString + splitOn: Character space + do: [ :part | + part endsWithAColon + ifTrue: [ selector := selector, part ] + ifFalse: [ args add: part ] ]. + answer + at: 'selector' put: selector asSymbol; + at: 'args' put: args asArray. + ^ answer +] + +{ #category : #updating } +GrafoscopioUtils class >> update [ + "Updates GrafoscopioUtils with new versions of itself take from the source code repository." + Gofer new + smalltalkhubUser: 'Offray' project: 'Grafoscopio'; + package: 'Grafoscopio-Utils'; + load. +] diff --git a/repository/Grafoscopio-Utils/GrafoscopioUtilsTest.class.st b/repository/Grafoscopio-Utils/GrafoscopioUtilsTest.class.st index 76fcf6e..fdb5dd4 100644 --- a/repository/Grafoscopio-Utils/GrafoscopioUtilsTest.class.st +++ b/repository/Grafoscopio-Utils/GrafoscopioUtilsTest.class.st @@ -1,8 +1,8 @@ -" -A GrafoscopioUtilsTest is a test class for testing the behavior of GrafoscopioUtils -" -Class { - #name : #GrafoscopioUtilsTest, - #superclass : #TestCase, - #category : #'Grafoscopio-Utils-Tests' -} +" +A GrafoscopioUtilsTest is a test class for testing the behavior of GrafoscopioUtils +" +Class { + #name : #GrafoscopioUtilsTest, + #superclass : #TestCase, + #category : #'Grafoscopio-Utils-Tests' +} diff --git a/repository/Grafoscopio-Utils/HedgeDoc.class.st b/repository/Grafoscopio-Utils/HedgeDoc.class.st index 341cd2b..de6b229 100644 --- a/repository/Grafoscopio-Utils/HedgeDoc.class.st +++ b/repository/Grafoscopio-Utils/HedgeDoc.class.st @@ -1,113 +1,113 @@ -" -I model the interface between a CodiMD (https://demo.codimd.org) documentation -server and Grafoscopio. -I enable the interaction between Grafoscopio notebooks and CodiMD documents, -so one document can start online (as a CodiMD pad) and continue as a Grafoscopio -notebook or viceversa. -" -Class { - #name : #HedgeDoc, - #superclass : #Object, - #instVars : [ - 'server', - 'pad', - 'contents', - 'url' - ], - #category : #'Grafoscopio-Utils' -} - -{ #category : #'as yet unclassified' } -HedgeDoc class >> newDefault [ - ^ self new - defaultServer. -] - -{ #category : #accessing } -HedgeDoc >> contents [ - ^ contents -] - -{ #category : #accessing } -HedgeDoc >> contents: anObject [ - contents := anObject -] - -{ #category : #'as yet unclassified' } -HedgeDoc >> defaultServer [ - self server: 'https://docutopia.tupale.co'. -] - -{ #category : #'as yet unclassified' } -HedgeDoc >> htmlUrl [ - | link | - link := self url copy. - link segments insert: 's' before: 1. - ^ link -] - -{ #category : #'as yet unclassified' } -HedgeDoc >> importContents [ - self contents: self retrieveContents -] - -{ #category : #accessing } -HedgeDoc >> pad [ - ^ pad -] - -{ #category : #accessing } -HedgeDoc >> pad: anObject [ - pad := anObject -] - -{ #category : #'as yet unclassified' } -HedgeDoc >> retrieveContents [ - self url ifNil: [ ^ self ]. - ^ (self url addPathSegment: 'download') retrieveContents -] - -{ #category : #'as yet unclassified' } -HedgeDoc >> retrieveHtmlContents [ - | htmlContents | - self url ifNil: [ ^ self ]. - htmlContents := self htmlUrl. - ^ htmlContents retrieveContents -] - -{ #category : #'as yet unclassified' } -HedgeDoc >> saveContentsToFile: aFileLocator [ - self url ifNil: [ ^ self ]. - ^ (self url addPathSegment: 'download') saveContentsToFile: aFileLocator -] - -{ #category : #'as yet unclassified' } -HedgeDoc >> saveHtmlContentsToFile: aFileLocator [ - self url ifNil: [ ^ self ]. - ^ self htmlUrl saveContentsToFile: aFileLocator -] - -{ #category : #accessing } -HedgeDoc >> server [ - ^ server -] - -{ #category : #accessing } -HedgeDoc >> server: aUrlString [ - server := aUrlString -] - -{ #category : #accessing } -HedgeDoc >> url [ - ^ url asUrl -] - -{ #category : #accessing } -HedgeDoc >> url: anObject [ - url := anObject -] - -{ #category : #visiting } -HedgeDoc >> visit [ - WebBrowser openOn: self server, '/', self pad. -] +" +I model the interface between a CodiMD (https://demo.codimd.org) documentation +server and Grafoscopio. +I enable the interaction between Grafoscopio notebooks and CodiMD documents, +so one document can start online (as a CodiMD pad) and continue as a Grafoscopio +notebook or viceversa. +" +Class { + #name : #HedgeDoc, + #superclass : #Object, + #instVars : [ + 'server', + 'pad', + 'contents', + 'url' + ], + #category : #'Grafoscopio-Utils' +} + +{ #category : #'as yet unclassified' } +HedgeDoc class >> newDefault [ + ^ self new + defaultServer. +] + +{ #category : #accessing } +HedgeDoc >> contents [ + ^ contents +] + +{ #category : #accessing } +HedgeDoc >> contents: anObject [ + contents := anObject +] + +{ #category : #'as yet unclassified' } +HedgeDoc >> defaultServer [ + self server: 'https://docutopia.tupale.co'. +] + +{ #category : #'as yet unclassified' } +HedgeDoc >> htmlUrl [ + | link | + link := self url copy. + link segments insert: 's' before: 1. + ^ link +] + +{ #category : #'as yet unclassified' } +HedgeDoc >> importContents [ + self contents: self retrieveContents +] + +{ #category : #accessing } +HedgeDoc >> pad [ + ^ pad +] + +{ #category : #accessing } +HedgeDoc >> pad: anObject [ + pad := anObject +] + +{ #category : #'as yet unclassified' } +HedgeDoc >> retrieveContents [ + self url ifNil: [ ^ self ]. + ^ (self url addPathSegment: 'download') retrieveContents +] + +{ #category : #'as yet unclassified' } +HedgeDoc >> retrieveHtmlContents [ + | htmlContents | + self url ifNil: [ ^ self ]. + htmlContents := self htmlUrl. + ^ htmlContents retrieveContents +] + +{ #category : #'as yet unclassified' } +HedgeDoc >> saveContentsToFile: aFileLocator [ + self url ifNil: [ ^ self ]. + ^ (self url addPathSegment: 'download') saveContentsToFile: aFileLocator +] + +{ #category : #'as yet unclassified' } +HedgeDoc >> saveHtmlContentsToFile: aFileLocator [ + self url ifNil: [ ^ self ]. + ^ self htmlUrl saveContentsToFile: aFileLocator +] + +{ #category : #accessing } +HedgeDoc >> server [ + ^ server +] + +{ #category : #accessing } +HedgeDoc >> server: aUrlString [ + server := aUrlString +] + +{ #category : #accessing } +HedgeDoc >> url [ + ^ url asUrl +] + +{ #category : #accessing } +HedgeDoc >> url: anObject [ + url := anObject +] + +{ #category : #visiting } +HedgeDoc >> visit [ + WebBrowser openOn: self server, '/', self pad. +] diff --git a/repository/Grafoscopio-Utils/Markdeep.class.st b/repository/Grafoscopio-Utils/Markdeep.class.st index 10d69f6..4ad4bea 100644 --- a/repository/Grafoscopio-Utils/Markdeep.class.st +++ b/repository/Grafoscopio-Utils/Markdeep.class.st @@ -1,185 +1,185 @@ -" -I model a Mardeep file as described in https://casual-effects.com/markdeep/ -" -Class { - #name : #Markdeep, - #superclass : #Object, - #instVars : [ - 'tocStyle', - 'comments', - 'header', - 'tail', - 'body', - 'language', - 'markdownFile' - ], - #category : #'Grafoscopio-Utils' -} - -{ #category : #'as yet unclassified' } -Markdeep class >> fromMarkdownFile: aFileReference [ - ^ self new fromMarkdownFile: aFileReference. -] - -{ #category : #accessing } -Markdeep >> body [ - ^ body -] - -{ #category : #accessing } -Markdeep >> body: anObject [ - body := anObject -] - -{ #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 : #'instance creation' } -Markdeep >> contents [ - | output | - output := '' writeStream. - output - nextPutAll: self header; crlf; - nextPutAll: self body; crlf; - nextPutAll: self tail; crlf; crlf; - 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 fullName, '.html') asFileReference. - self exportAsFileOn: newFile. -] - -{ #category : #persistence } -Markdeep >> exportAsFileOn: aFileReference [ - aFileReference exists ifFalse: [ aFileReference ensureCreateFile ]. - aFileReference writeStreamDo: [ :stream | - stream nextPutAll: self contents ]. - self inform: 'Exported as: ', String cr, aFileReference fullName -] - -{ #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 >> header [ - ^ self fontAwesomeHeader -] - -{ #category : #accessing } -Markdeep >> header: anObject [ - header := anObject -] - -{ #category : #accessing } -Markdeep >> language [ - ^ language -] - -{ #category : #accessing } -Markdeep >> language: anObject [ - language := anObject -] - -{ #category : #accessing } -Markdeep >> markdownFile [ - ^ markdownFile -] - -{ #category : #accessing } -Markdeep >> markdownFile: aFileReference [ - "I provide information about which Markdown file was used to generate the Markdeep body" - markdownFile := aFileReference -] - -{ #category : #'instance creation' } -Markdeep >> processMarkdownFor: aFileReference [ - "comment stating purpose of message" - | markdownContent | - self markdownFile: aFileReference. - markdownContent := Markdown fromFile: aFileReference. - self body: (markdownContent commentYAMLMetadata contents). -] - -{ #category : #accessing } -Markdeep >> tail [ - "I enable the document tail, which, in turn, enables a Markdeep document" - ^ ' - - - - - - - ' -] - -{ #category : #accessing } -Markdeep >> tail: anObject [ - tail := anObject -] - -{ #category : #accessing } -Markdeep >> tocStyle [ - ^ tocStyle -] - -{ #category : #accessing } -Markdeep >> tocStyle: anObject [ - tocStyle := anObject -] +" +I model a Mardeep file as described in https://casual-effects.com/markdeep/ +" +Class { + #name : #Markdeep, + #superclass : #Object, + #instVars : [ + 'tocStyle', + 'comments', + 'header', + 'tail', + 'body', + 'language', + 'markdownFile' + ], + #category : #'Grafoscopio-Utils' +} + +{ #category : #'as yet unclassified' } +Markdeep class >> fromMarkdownFile: aFileReference [ + ^ self new fromMarkdownFile: aFileReference. +] + +{ #category : #accessing } +Markdeep >> body [ + ^ body +] + +{ #category : #accessing } +Markdeep >> body: anObject [ + body := anObject +] + +{ #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 : #'instance creation' } +Markdeep >> contents [ + | output | + output := '' writeStream. + output + nextPutAll: self header; crlf; + nextPutAll: self body; crlf; + nextPutAll: self tail; crlf; crlf; + 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 fullName, '.html') asFileReference. + self exportAsFileOn: newFile. +] + +{ #category : #persistence } +Markdeep >> exportAsFileOn: aFileReference [ + aFileReference exists ifFalse: [ aFileReference ensureCreateFile ]. + aFileReference writeStreamDo: [ :stream | + stream nextPutAll: self contents ]. + self inform: 'Exported as: ', String cr, aFileReference fullName +] + +{ #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 >> header [ + ^ self fontAwesomeHeader +] + +{ #category : #accessing } +Markdeep >> header: anObject [ + header := anObject +] + +{ #category : #accessing } +Markdeep >> language [ + ^ language +] + +{ #category : #accessing } +Markdeep >> language: anObject [ + language := anObject +] + +{ #category : #accessing } +Markdeep >> markdownFile [ + ^ markdownFile +] + +{ #category : #accessing } +Markdeep >> markdownFile: aFileReference [ + "I provide information about which Markdown file was used to generate the Markdeep body" + markdownFile := aFileReference +] + +{ #category : #'instance creation' } +Markdeep >> processMarkdownFor: aFileReference [ + "comment stating purpose of message" + | markdownContent | + self markdownFile: aFileReference. + markdownContent := Markdown fromFile: aFileReference. + self body: (markdownContent commentYAMLMetadata contents). +] + +{ #category : #accessing } +Markdeep >> tail [ + "I enable the document tail, which, in turn, enables a Markdeep document" + ^ ' + + + + + + + ' +] + +{ #category : #accessing } +Markdeep >> tail: anObject [ + tail := anObject +] + +{ #category : #accessing } +Markdeep >> tocStyle [ + ^ tocStyle +] + +{ #category : #accessing } +Markdeep >> tocStyle: anObject [ + tocStyle := anObject +] diff --git a/repository/Grafoscopio-Utils/Markdown.class.st b/repository/Grafoscopio-Utils/Markdown.class.st index 7ca036b..32e9c6b 100644 --- a/repository/Grafoscopio-Utils/Markdown.class.st +++ b/repository/Grafoscopio-Utils/Markdown.class.st @@ -1,169 +1,169 @@ -" -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 : #Object, - #instVars : [ - 'contents', - 'file' - ], - #category : #'Grafoscopio-Utils' -} - -{ #category : #'instance creation' } -Markdown class >> fromFile: aFileReference [ - ^ self new fromFile: aFileReference -] - -{ #category : #utilities } -Markdown class >> yamlMetadataDelimiter [ - ^ '---' - -] - -{ #category : #operation } -Markdown >> commentYAMLMetadata [ - | newContents | - self detectYAMLMetadata ifFalse: [ ^ self ]. - newContents := '' writeStream. - newContents nextPutAll: ''; crlf. - (self lines copyFrom: self locateYAMLMetadataClosing + 2 to: self lines size) do: [ :line | - newContents nextPutAll: line; crlf ]. - self contents: newContents contents. - ^ self contents -] - -{ #category : #utilities } -Markdown >> containsYAMLMetadataClosing [ - ^ self locateYAMLMetadataClosing > 0 -] - -{ #category : #accessing } -Markdown >> contents [ - ^ contents -] - -{ #category : #accessing } -Markdown >> contents: anObject [ - contents := anObject -] - -{ #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 : #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 yamlMetadataAsString. - ^ exportedFile -] - -{ #category : #operation } -Markdown >> extractYAMLMetadata [ - | output yamlLines | - self detectYAMLMetadata ifFalse: [ ^ nil ]. - yamlLines := self lines copyFrom: 2 to: (self locateYAMLMetadataClosing). - output := '' writeStream. - yamlLines do: [ :line | - output - nextPutAll: line; - nextPut: Character cr. ]. - ^ output contents -] - -{ #category : #accessing } -Markdown >> file [ - ^ file -] - -{ #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 : #utilities } -Markdown >> lines [ - ^ self contents lines. -] - -{ #category : #utilities } -Markdown >> locateYAMLMetadataClosing [ - "I return the line where the closing of the YAML metadata occurs or 0 if no closing is found." - | result | - self startsWithYAMLMetadataDelimiter ifFalse: [ ^ self ]. - result := 0. - self lines allButFirst doWithIndex: [ :currentLine :i | - (currentLine beginsWith: self class yamlMetadataDelimiter) ifTrue: [ result := i ]]. - ^ result - -] - -{ #category : #accessing } -Markdown >> metadata [ - | rawMeta | - rawMeta := PPYAMLGrammar new parse: self extractYAMLMetadata. - rawMeta associationsDo: [ :assoc | - assoc value = 'false' ifTrue: [ assoc value: false ]. - assoc value = 'true' ifTrue: [ assoc value: true ] ]. - ^ rawMeta -] - -{ #category : #utilities } -Markdown >> startsWithYAMLMetadataDelimiter [ - ^ self lines first beginsWith: self class yamlMetadataDelimiter - -] - -{ #category : #utilities } -Markdown >> yamlMetadataAsString [ - | output | - self extractYAMLMetadata ifNil: [ ^ nil ]. - output := String new writeStream. - output nextPutAll: self class yamlMetadataDelimiter; cr. - output nextPutAll: self extractYAMLMetadata. - output nextPutAll: self class yamlMetadataDelimiter; cr. - ^ output contents. -] +" +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 : #Object, + #instVars : [ + 'contents', + 'file' + ], + #category : #'Grafoscopio-Utils' +} + +{ #category : #'instance creation' } +Markdown class >> fromFile: aFileReference [ + ^ self new fromFile: aFileReference +] + +{ #category : #utilities } +Markdown class >> yamlMetadataDelimiter [ + ^ '---' + +] + +{ #category : #operation } +Markdown >> commentYAMLMetadata [ + | newContents | + self detectYAMLMetadata ifFalse: [ ^ self ]. + newContents := '' writeStream. + newContents nextPutAll: ''; crlf. + (self lines copyFrom: self locateYAMLMetadataClosing + 2 to: self lines size) do: [ :line | + newContents nextPutAll: line; crlf ]. + self contents: newContents contents. + ^ self contents +] + +{ #category : #utilities } +Markdown >> containsYAMLMetadataClosing [ + ^ self locateYAMLMetadataClosing > 0 +] + +{ #category : #accessing } +Markdown >> contents [ + ^ contents +] + +{ #category : #accessing } +Markdown >> contents: anObject [ + contents := anObject +] + +{ #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 : #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 yamlMetadataAsString. + ^ exportedFile +] + +{ #category : #operation } +Markdown >> extractYAMLMetadata [ + | output yamlLines | + self detectYAMLMetadata ifFalse: [ ^ nil ]. + yamlLines := self lines copyFrom: 2 to: (self locateYAMLMetadataClosing). + output := '' writeStream. + yamlLines do: [ :line | + output + nextPutAll: line; + nextPut: Character cr. ]. + ^ output contents +] + +{ #category : #accessing } +Markdown >> file [ + ^ file +] + +{ #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 : #utilities } +Markdown >> lines [ + ^ self contents lines. +] + +{ #category : #utilities } +Markdown >> locateYAMLMetadataClosing [ + "I return the line where the closing of the YAML metadata occurs or 0 if no closing is found." + | result | + self startsWithYAMLMetadataDelimiter ifFalse: [ ^ self ]. + result := 0. + self lines allButFirst doWithIndex: [ :currentLine :i | + (currentLine beginsWith: self class yamlMetadataDelimiter) ifTrue: [ result := i ]]. + ^ result + +] + +{ #category : #accessing } +Markdown >> metadata [ + | rawMeta | + rawMeta := PPYAMLGrammar new parse: self extractYAMLMetadata. + rawMeta associationsDo: [ :assoc | + assoc value = 'false' ifTrue: [ assoc value: false ]. + assoc value = 'true' ifTrue: [ assoc value: true ] ]. + ^ rawMeta +] + +{ #category : #utilities } +Markdown >> startsWithYAMLMetadataDelimiter [ + ^ self lines first beginsWith: self class yamlMetadataDelimiter + +] + +{ #category : #utilities } +Markdown >> yamlMetadataAsString [ + | output | + self extractYAMLMetadata ifNil: [ ^ nil ]. + output := String new writeStream. + output nextPutAll: self class yamlMetadataDelimiter; cr. + output nextPutAll: self extractYAMLMetadata. + output nextPutAll: self class yamlMetadataDelimiter; cr. + ^ output contents. +] diff --git a/repository/Grafoscopio-Utils/MarkupFile.class.st b/repository/Grafoscopio-Utils/MarkupFile.class.st index 05a4832..e229d3a 100644 --- a/repository/Grafoscopio-Utils/MarkupFile.class.st +++ b/repository/Grafoscopio-Utils/MarkupFile.class.st @@ -1,23 +1,23 @@ -" -I model common operations made with several markup files. -" -Class { - #name : #MarkupFile, - #superclass : #Object, - #instVars : [ - 'file' - ], - #category : #'Grafoscopio-Utils' -} - -{ #category : #persistence } -MarkupFile class >> exportAsFileOn: aFileReferenceOrFileName containing: text [ - | file | - file := aFileReferenceOrFileName asFileReference. - file ensureDelete. - file exists ifFalse: [ file ensureCreateFile ]. - file writeStreamDo: [ :stream | - stream nextPutAll: text withInternetLineEndings]. - self inform: 'Exported as: ', String cr, file fullName. - ^ file -] +" +I model common operations made with several markup files. +" +Class { + #name : #MarkupFile, + #superclass : #Object, + #instVars : [ + 'file' + ], + #category : #'Grafoscopio-Utils' +} + +{ #category : #persistence } +MarkupFile class >> exportAsFileOn: aFileReferenceOrFileName containing: text [ + | file | + file := aFileReferenceOrFileName asFileReference. + file ensureDelete. + file exists ifFalse: [ file ensureCreateFile ]. + file writeStreamDo: [ :stream | + stream nextPutAll: text withInternetLineEndings]. + self inform: 'Exported as: ', String cr, file fullName. + ^ file +] diff --git a/repository/Grafoscopio-Utils/OrgMode.class.st b/repository/Grafoscopio-Utils/OrgMode.class.st index 4e07529..0e146d3 100644 --- a/repository/Grafoscopio-Utils/OrgMode.class.st +++ b/repository/Grafoscopio-Utils/OrgMode.class.st @@ -1,46 +1,46 @@ -" -I provide some utilites to work with OrgMode files. - -https://orgmode.org/ -" -Class { - #name : #OrgMode, - #superclass : #Object, - #instVars : [ - 'contents', - 'file' - ], - #category : #'Grafoscopio-Utils' -} - -{ #category : #'instance creation' } -OrgMode class >> fromFile: aFileReference [ - ^ self new contents: aFileReference contents. -] - -{ #category : #accessing } -OrgMode >> contents [ - ^ contents -] - -{ #category : #accessing } -OrgMode >> contents: anObject [ - contents := anObject -] - -{ #category : #accessing } -OrgMode >> file [ - ^ file -] - -{ #category : #accessing } -OrgMode >> file: anObject [ - file := anObject -] - -{ #category : #utilities } -OrgMode >> selectHeadlines [ - - ^ self contents lines select: [ :line | - line isOrgModeHeader ] -] +" +I provide some utilites to work with OrgMode files. + +https://orgmode.org/ +" +Class { + #name : #OrgMode, + #superclass : #Object, + #instVars : [ + 'contents', + 'file' + ], + #category : #'Grafoscopio-Utils' +} + +{ #category : #'instance creation' } +OrgMode class >> fromFile: aFileReference [ + ^ self new contents: aFileReference contents. +] + +{ #category : #accessing } +OrgMode >> contents [ + ^ contents +] + +{ #category : #accessing } +OrgMode >> contents: anObject [ + contents := anObject +] + +{ #category : #accessing } +OrgMode >> file [ + ^ file +] + +{ #category : #accessing } +OrgMode >> file: anObject [ + file := anObject +] + +{ #category : #utilities } +OrgMode >> selectHeadlines [ + + ^ self contents lines select: [ :line | + line isOrgModeHeader ] +] diff --git a/repository/Grafoscopio-Utils/Pandoc.class.st b/repository/Grafoscopio-Utils/Pandoc.class.st index 643eed0..8aa86d1 100644 --- a/repository/Grafoscopio-Utils/Pandoc.class.st +++ b/repository/Grafoscopio-Utils/Pandoc.class.st @@ -1,146 +1,146 @@ -" -I model the interaction between Pandoc and Grafoscopio. -" -Class { - #name : #Pandoc, - #superclass : #Object, - #classInstVars : [ - 'executable' - ], - #category : #'Grafoscopio-Utils' -} - -{ #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 : #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 := FileLocator temp / (inputFile basenameWithoutExtension , '.html'). - outputFile ensureDelete. - outputFile ensureCreateFile. - OSSUnixSubprocess new - command: 'pandoc'; - arguments: {'-f'. 'markdown+startnum+task_lists'. '-t'. 'html'. inputFile fullName. - '--output'. outputFile fullName }; - redirectStdout; - redirectStderr; - runAndWaitOnExitDo: [ :process :outString :errString | - process isSuccess - ifTrue: [ ^ outputFile ] - ifFalse: [ ^ inputFile ] - ] -] - -{ #category : #converters } -Pandoc class >> markdownToHtmlOnWindows: inputFile [ - - - ^ LibC resultOfCommand: 'pandoc -f markdown+startnum+task_lists -t html', inputFile fullName. -] +" +I model the interaction between Pandoc and Grafoscopio. +" +Class { + #name : #Pandoc, + #superclass : #Object, + #classInstVars : [ + 'executable' + ], + #category : #'Grafoscopio-Utils' +} + +{ #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 : #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 := FileLocator temp / (inputFile basenameWithoutExtension , '.html'). + outputFile ensureDelete. + outputFile ensureCreateFile. + OSSUnixSubprocess new + command: 'pandoc'; + arguments: {'-f'. 'markdown+startnum+task_lists'. '-t'. 'html'. inputFile fullName. + '--output'. outputFile fullName }; + redirectStdout; + redirectStderr; + runAndWaitOnExitDo: [ :process :outString :errString | + process isSuccess + ifTrue: [ ^ outputFile ] + ifFalse: [ ^ inputFile ] + ] +] + +{ #category : #converters } +Pandoc class >> markdownToHtmlOnWindows: inputFile [ + + "ToDo: This command still doesn't receive any arguments." + ^ (LibC resultOfCommand: 'pandoc ', inputFile fullName) correctAccentedCharacters. +] diff --git a/repository/Grafoscopio-Utils/PandocWork.class.st b/repository/Grafoscopio-Utils/PandocWork.class.st index 4e09828..03d40d3 100644 --- a/repository/Grafoscopio-Utils/PandocWork.class.st +++ b/repository/Grafoscopio-Utils/PandocWork.class.st @@ -1,178 +1,178 @@ -" -I model a work (book, booklet, web page, etc) in Pandoc, its table of contents, its metadata file to -control exportation and other elements. - -I can be used to improve reproductibility of published works that use Pandoc. - -By default it is supposed that a root folder contains the set of folders, organized by -language (following the ISO 639-1 two letters convetion) where the contents of the work -and their translations are located. -Chapters, subchapters, sections and subsections are contained there as Markdown files -and its order is stated as a ordered dictionary for each language. -A YAML metadata block is used in each file to map translations between files and languages -and other sources, synchronizations and meta data. -" -Class { - #name : #PandocWork, - #superclass : #Object, - #instVars : [ - 'language', - 'contents', - 'metadataFiles', - 'rootFolder', - 'manifests' - ], - #category : #'Grafoscopio-Utils' -} - -{ #category : #utilities } -PandocWork >> buildManifestFileForLanguage: anISOCode on: aFileName [ - "anISOCode is the ISO 639-1 two letters language code" - - | manifestFile | - manifestFile := (self rootFolder / anISOCode / 'manifests' / aFileName ) asFileReference ensureCreateFile. - self buildManifestForLanguage: 'es'. - GrafoscopioUtils exportAsSton: (self manifests at: anISOCode) on: manifestFile. - ^ manifestFile -] - -{ #category : #utlity } -PandocWork >> buildManifestForLanguage: anISOCode [ - self - metadataManifestForLanguage: anISOCode; - contentsManifestForLanguage: anISOCode. - ^ self manifests -] - -{ #category : #accessing } -PandocWork >> contents [ - ^ contents -] - -{ #category : #accessing } -PandocWork >> contents: anOrderedDictionary [ - "I model the table of contents of the work. - The key of the dictionary is the folder, inside the language folder (see the language variable) - where the files are stored, and the value is and ordered collection of the files on such folder - which are part ot the exported result, without the file extension (by default is supposed to be '.md')" - contents := anOrderedDictionary -] - -{ #category : #utilities } -PandocWork >> contentsManifest [ - - | checksums | - checksums := OrderedDictionary new. - self contents keysDo: [ :folder | - (self contents at: folder) do: [ :fileName | | keyName contentFile | - keyName := fileName, self defaultFileExtension. - contentFile := self rootFolder / self language / folder / keyName. - checksums at: keyName put: (GrafoscopioUtils checksumFor: contentFile)]. - self manifest at: folder put: checksums ]. - ^ self manifest -] - -{ #category : #utilities } -PandocWork >> contentsManifestForLanguage: anISOCode [ - - | checksums | - checksums := OrderedDictionary new. - self contents keysDo: [ :folder | - (self contents at: folder) do: [ :fileName | | keyName contentFile | - keyName := fileName, self defaultFileExtension. - contentFile := self rootFolder / anISOCode / folder / keyName. - checksums at: keyName put: (GrafoscopioUtils checksumFor: contentFile)]. - (self manifestForLanguage: anISOCode) - add: {folder -> checksums} asOrderedDictionary ]. - ^ self manifests at: anISOCode -] - -{ #category : #utilities } -PandocWork >> defaultFileExtension [ - ^ '.md' - - - -] - -{ #category : #accessing } -PandocWork >> language [ - ^ language -] - -{ #category : #accessing } -PandocWork >> language: aISOLangString [ - "I model the lanaguage of a work as a ISO 639-1 two letters string. - I used to stablish the folder where the content is stored, following the convention a folder - by language." - language := aISOLangString -] - -{ #category : #utlity } -PandocWork >> manifestForLanguage: anISOCode [ - self manifests at: anISOCode ifAbsent: [ - self manifests - at: anISOCode put: OrderedCollection new; - yourself]. - ^ self manifests at: anISOCode -] - -{ #category : #accessing } -PandocWork >> manifests [ - ^ manifests ifNil: [ ^ manifests := OrderedDictionary new ] -] - -{ #category : #accessing } -PandocWork >> manifests: anOrderedDictionary [ - manifests := anOrderedDictionary -] - -{ #category : #accessing } -PandocWork >> metadataFiles [ - ^ metadataFiles -] - -{ #category : #accessing } -PandocWork >> metadataFiles: aCollection [ - "I model the YAML metadata files that are used to control the output of the exportation. - I can have several files, controlling several outputs, one for PDF, one for HTML, one for EPUB - and so on. - This should be stated in the name of the metadatafile and by default will be controlling PDF - output." - metadataFiles := aCollection -] - -{ #category : #utilities } -PandocWork >> metadataManifest [ - - | languageFolder | - languageFolder := self language. - "Could the similar parts of this and contentsManifest be refactored?" - self metadataFiles do: [ :fileName | | contentFile | - contentFile := self rootFolder / languageFolder / fileName. - self manifest at: languageFolder put: {fileName -> (GrafoscopioUtils checksumFor: contentFile)} asOrderedDictionary ]. - ^ self manifest -] - -{ #category : #utilities } -PandocWork >> metadataManifestForLanguage: anISOCode [ - "anISOCode is the ISO 639-1 two letters language code" - - "Could the similar parts of this and contentsManifest be refactored?" - self metadataFiles do: [ :fileName | | contentFile | - contentFile := self rootFolder / anISOCode / fileName. - (self manifestForLanguage: anISOCode) - add: {fileName -> (GrafoscopioUtils checksumFor: contentFile)} asOrderedDictionary]. - ^ self manifests at: anISOCode -] - -{ #category : #accessing } -PandocWork >> rootFolder [ - ^ rootFolder -] - -{ #category : #accessing } -PandocWork >> rootFolder: aFileReference [ - "I model the folder where the Markdown files are located." - rootFolder := aFileReference -] +" +I model a work (book, booklet, web page, etc) in Pandoc, its table of contents, its metadata file to +control exportation and other elements. + +I can be used to improve reproductibility of published works that use Pandoc. + +By default it is supposed that a root folder contains the set of folders, organized by +language (following the ISO 639-1 two letters convetion) where the contents of the work +and their translations are located. +Chapters, subchapters, sections and subsections are contained there as Markdown files +and its order is stated as a ordered dictionary for each language. +A YAML metadata block is used in each file to map translations between files and languages +and other sources, synchronizations and meta data. +" +Class { + #name : #PandocWork, + #superclass : #Object, + #instVars : [ + 'language', + 'contents', + 'metadataFiles', + 'rootFolder', + 'manifests' + ], + #category : #'Grafoscopio-Utils' +} + +{ #category : #utilities } +PandocWork >> buildManifestFileForLanguage: anISOCode on: aFileName [ + "anISOCode is the ISO 639-1 two letters language code" + + | manifestFile | + manifestFile := (self rootFolder / anISOCode / 'manifests' / aFileName ) asFileReference ensureCreateFile. + self buildManifestForLanguage: 'es'. + GrafoscopioUtils exportAsSton: (self manifests at: anISOCode) on: manifestFile. + ^ manifestFile +] + +{ #category : #utlity } +PandocWork >> buildManifestForLanguage: anISOCode [ + self + metadataManifestForLanguage: anISOCode; + contentsManifestForLanguage: anISOCode. + ^ self manifests +] + +{ #category : #accessing } +PandocWork >> contents [ + ^ contents +] + +{ #category : #accessing } +PandocWork >> contents: anOrderedDictionary [ + "I model the table of contents of the work. + The key of the dictionary is the folder, inside the language folder (see the language variable) + where the files are stored, and the value is and ordered collection of the files on such folder + which are part ot the exported result, without the file extension (by default is supposed to be '.md')" + contents := anOrderedDictionary +] + +{ #category : #utilities } +PandocWork >> contentsManifest [ + + | checksums | + checksums := OrderedDictionary new. + self contents keysDo: [ :folder | + (self contents at: folder) do: [ :fileName | | keyName contentFile | + keyName := fileName, self defaultFileExtension. + contentFile := self rootFolder / self language / folder / keyName. + checksums at: keyName put: (GrafoscopioUtils checksumFor: contentFile)]. + self manifest at: folder put: checksums ]. + ^ self manifest +] + +{ #category : #utilities } +PandocWork >> contentsManifestForLanguage: anISOCode [ + + | checksums | + checksums := OrderedDictionary new. + self contents keysDo: [ :folder | + (self contents at: folder) do: [ :fileName | | keyName contentFile | + keyName := fileName, self defaultFileExtension. + contentFile := self rootFolder / anISOCode / folder / keyName. + checksums at: keyName put: (GrafoscopioUtils checksumFor: contentFile)]. + (self manifestForLanguage: anISOCode) + add: {folder -> checksums} asOrderedDictionary ]. + ^ self manifests at: anISOCode +] + +{ #category : #utilities } +PandocWork >> defaultFileExtension [ + ^ '.md' + + + +] + +{ #category : #accessing } +PandocWork >> language [ + ^ language +] + +{ #category : #accessing } +PandocWork >> language: aISOLangString [ + "I model the lanaguage of a work as a ISO 639-1 two letters string. + I used to stablish the folder where the content is stored, following the convention a folder + by language." + language := aISOLangString +] + +{ #category : #utlity } +PandocWork >> manifestForLanguage: anISOCode [ + self manifests at: anISOCode ifAbsent: [ + self manifests + at: anISOCode put: OrderedCollection new; + yourself]. + ^ self manifests at: anISOCode +] + +{ #category : #accessing } +PandocWork >> manifests [ + ^ manifests ifNil: [ ^ manifests := OrderedDictionary new ] +] + +{ #category : #accessing } +PandocWork >> manifests: anOrderedDictionary [ + manifests := anOrderedDictionary +] + +{ #category : #accessing } +PandocWork >> metadataFiles [ + ^ metadataFiles +] + +{ #category : #accessing } +PandocWork >> metadataFiles: aCollection [ + "I model the YAML metadata files that are used to control the output of the exportation. + I can have several files, controlling several outputs, one for PDF, one for HTML, one for EPUB + and so on. + This should be stated in the name of the metadatafile and by default will be controlling PDF + output." + metadataFiles := aCollection +] + +{ #category : #utilities } +PandocWork >> metadataManifest [ + + | languageFolder | + languageFolder := self language. + "Could the similar parts of this and contentsManifest be refactored?" + self metadataFiles do: [ :fileName | | contentFile | + contentFile := self rootFolder / languageFolder / fileName. + self manifest at: languageFolder put: {fileName -> (GrafoscopioUtils checksumFor: contentFile)} asOrderedDictionary ]. + ^ self manifest +] + +{ #category : #utilities } +PandocWork >> metadataManifestForLanguage: anISOCode [ + "anISOCode is the ISO 639-1 two letters language code" + + "Could the similar parts of this and contentsManifest be refactored?" + self metadataFiles do: [ :fileName | | contentFile | + contentFile := self rootFolder / anISOCode / fileName. + (self manifestForLanguage: anISOCode) + add: {fileName -> (GrafoscopioUtils checksumFor: contentFile)} asOrderedDictionary]. + ^ self manifests at: anISOCode +] + +{ #category : #accessing } +PandocWork >> rootFolder [ + ^ rootFolder +] + +{ #category : #accessing } +PandocWork >> rootFolder: aFileReference [ + "I model the folder where the Markdown files are located." + rootFolder := aFileReference +] diff --git a/repository/Grafoscopio-Utils/String.extension.st b/repository/Grafoscopio-Utils/String.extension.st index 39af119..c13d97f 100644 --- a/repository/Grafoscopio-Utils/String.extension.st +++ b/repository/Grafoscopio-Utils/String.extension.st @@ -1,35 +1,38 @@ -Extension { #name : #String } - -{ #category : #'*Grafoscopio-Utils' } -String >> asCapitalizedPhrase [ - "I convert phrases like 'THIS IS A PHRASE' into 'This is a Phrase'." - - ^ Character space join: (self substrings collect: [:each | each asLowercase capitalized ]) -] - -{ #category : #'*Grafoscopio-Utils' } -String >> asDashedLowercase [ - "I convert phrases like 'This is a phrase' into 'this-is-a-phrase'." - - ^ '-' join: (self substrings collect: [:each | each asLowercase ]) -] - -{ #category : #'*Grafoscopio-Utils' } -String >> correctAccentedCharacters [ - - | output | - output := self - copyReplaceAll: 'ó' with: 'ó'. - output := output copyReplaceAll: 'á' with: 'á'. - output := output copyReplaceAll: 'é' with: 'é'. - output := output copyReplaceAll: 'í' with: 'í'. - output := output copyReplaceAll: 'ú' with: 'ú'. - ^ output -] - -{ #category : #'*Grafoscopio-Utils' } -String >> isOrgModeHeader [ - ^ self beginsWithAnyOf: #('* ' '** ' '*** ' '**** ' '***** ' '***** ') - - -] +Extension { #name : #String } + +{ #category : #'*Grafoscopio-Utils' } +String >> asCapitalizedPhrase [ + "I convert phrases like 'THIS IS A PHRASE' into 'This is a Phrase'." + + ^ Character space join: (self substrings collect: [:each | each asLowercase capitalized ]) +] + +{ #category : #'*Grafoscopio-Utils' } +String >> asDashedLowercase [ + "I convert phrases like 'This is a phrase' into 'this-is-a-phrase'." + + ^ '-' join: (self substrings collect: [:each | each asLowercase ]) +] + +{ #category : #'*Grafoscopio-Utils' } +String >> correctAccentedCharacters [ + + | output | + output := self + copyReplaceAll: 'ó' with: 'ó'. + output := output copyReplaceAll: 'á' with: 'á'. + output := output copyReplaceAll: 'é' with: 'é'. + output := output copyReplaceAll: 'í' with: 'í'. + output := output copyReplaceAll: 'ú' with: 'ú'. + output := output copyReplaceAll: 'ñ' with: 'ñ'. + output := output copyReplaceAll: '“' with: '“'. + output := output copyReplaceAll: '”' with: '”'. + ^ output +] + +{ #category : #'*Grafoscopio-Utils' } +String >> isOrgModeHeader [ + ^ self beginsWithAnyOf: #('* ' '** ' '*** ' '**** ' '***** ' '***** ') + + +] diff --git a/repository/Grafoscopio-Utils/package.st b/repository/Grafoscopio-Utils/package.st index 5f58ad1..e7f6405 100644 --- a/repository/Grafoscopio-Utils/package.st +++ b/repository/Grafoscopio-Utils/package.st @@ -1 +1 @@ -Package { #name : #'Grafoscopio-Utils' } +Package { #name : #'Grafoscopio-Utils' }