From 47a9e4bf8f1becaaddc29df0d1d8f3f7fbc54f3c Mon Sep 17 00:00:00 2001 From: Offray Luna Date: Wed, 6 Apr 2016 10:00:57 +0000 Subject: [PATCH] Exporting: Improving PDF exportation via XeLaTeX for unicode support. Still some leftovers proper cleaning needs to be debugged. --- repository/Grafoscopio/ExternalApp.class.st | 89 ++++++++++++++++++- .../Grafoscopio/GrafoscopioBrowser.class.st | 85 +++++++++++------- .../Grafoscopio/GrafoscopioNode.class.st | 71 +++++++++++---- 3 files changed, 198 insertions(+), 47 deletions(-) diff --git a/repository/Grafoscopio/ExternalApp.class.st b/repository/Grafoscopio/ExternalApp.class.st index 8d2624e..852d684 100644 --- a/repository/Grafoscopio/ExternalApp.class.st +++ b/repository/Grafoscopio/ExternalApp.class.st @@ -11,7 +11,8 @@ Class { 'downloadUrl', 'description', 'sha1', - 'md5' + 'md5', + 'binaryLocation' ], #category : #'Grafoscopio-Model' } @@ -106,3 +107,89 @@ ExternalApp class >> isSQLite32BitsInstalled [ ^ (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/GrafoscopioBrowser.class.st b/repository/Grafoscopio/GrafoscopioBrowser.class.st index c2201cf..8eceb70 100644 --- a/repository/Grafoscopio/GrafoscopioBrowser.class.st +++ b/repository/Grafoscopio/GrafoscopioBrowser.class.st @@ -16,17 +16,11 @@ Class { 'mainTree', 'tagsAvailable', 'cacheNode', - 'workingFile', - 'localRepository', - 'remoteRepository', - 'repositoryUser', - 'repositoryPassword' + 'workingFile' ], #classVars : [ 'dockingBar', 'draftsLocation', - 'fossil', - 'pandoc', 'recentTrees' ], #classInstVars : [ @@ -699,23 +693,47 @@ GrafoscopioBrowser >> customKeys [ { #category : #persistence } GrafoscopioBrowser >> exportAsHtml [ - "Exports the current tree to HTML, using the same name but different extension (.html)" + "I exports the current tree to HTML, using the same name but different extension (.html). + IMPORTANT: Pandoc must be installed in your system. In the future Grafoscopio will provide" | markdownFileLocation htmlFileLocation | markdownFileLocation := ((workingFile parent) / workingFile basenameWithoutExtension) fullName, '.markdown'. htmlFileLocation := ((workingFile parent) / workingFile basenameWithoutExtension) fullName, '.html'. - pandoc notNil + ExternalApp pandoc notNil ifTrue:[ (Smalltalk platform name = 'unix') | (Smalltalk platform name = 'Mac OS') ifTrue: [ - OSProcess command: 'exec ', pandoc, ' ', markdownFileLocation , ' --standalone -o ' , htmlFileLocation. + OSProcess command: 'pandoc ', ' ', markdownFileLocation , ' --standalone -o ' , htmlFileLocation. OSProcess command: 'exec echo "exportando como html"'. self inform: 'Archivo exportado como html en: ', htmlFileLocation]. Smalltalk platform name = 'Win32' - ifTrue: [ OSProcess command: pandoc, ' ', markdownFileLocation , ' --standalone -o ' , htmlFileLocation ]] + ifTrue: [ OSProcess command: 'pandoc ', markdownFileLocation , ' --standalone -o ' , htmlFileLocation ]] ifFalse: [GrafoscopioBrowser configureSettings]. +] - self customKeys. - +{ #category : #persistence } +GrafoscopioBrowser >> exportAsLatex [ + "I Export the current tree to LaTeX, using the same name but different extension (.tex). + IMPORTANT: The user needs to have TeX installed with minted support and pygments for syntax highlighting. + More details at: http://ctan.dcc.uchile.cl/macros/latex/contrib/minted/minted.pdf" + | markdownFileLocation latexFileLocation fileName | + fileName := workingFile basenameWithoutExtension. + markdownFileLocation := ((workingFile parent) / fileName) fullName, '.markdown'. + latexFileLocation := ((workingFile parent) / fileName) fullName, '.tex'. + ExternalApp pandoc binaryLocation exists + ifFalse: [ExternalApp configurePandoc] + ifTrue:[ + OSProcess command: + 'pandoc ', markdownFileLocation, + ' -V documentclass:article -V geometry:margin=2cm --standalone -o ' , + fileName, '.tex'. + "Moving the pdf output to the expected location" + latexFileLocation asFileReference exists ifTrue: [latexFileLocation asFileReference ensureDelete ]. + (FileLocator imageDirectory parent / (fileName, '.tex')) + moveTo: latexFileLocation asFileReference. + "Cleaning left overs" + (FileLocator imageDirectory parent / (fileName, '.tex')) ensureDelete. + self inform: 'Archivo exportado como latex en: ', latexFileLocation + ] ] { #category : #persistence } @@ -728,22 +746,28 @@ GrafoscopioBrowser >> exportAsMarkdown: aTree on: locator [ GrafoscopioBrowser >> exportAsPdf [ "Exports the current tree to HTML, using the same name but different extension (.pdf). IMPORTANT: The user needs to have installed TeX to create the pdf." - | markdownFileLocation pdfFileLocation | - markdownFileLocation := ((workingFile parent) / workingFile basenameWithoutExtension) fullName, '.markdown'. - pdfFileLocation := ((workingFile parent) / workingFile basenameWithoutExtension) fullName, '.pdf'. - pandoc notNil - ifTrue:[ - Smalltalk platform name = 'unix' - ifTrue: [ - OSProcess command: 'exec ', pandoc, ' ', markdownFileLocation , ' -o ' , pdfFileLocation. - OSProcess command: 'exec echo "exportando como pdf"'. - self inform: 'Archivo exportado como pdf en: ', pdfFileLocation.]. - Smalltalk platform name = 'Win32' - ifTrue: [ OSProcess command: pandoc, ' ', markdownFileLocation , ' -o ' , pdfFileLocation ]] - ifFalse: [ExternalApp configurePandoc ]. - - self customKeys. - + | latexFileLocation pdfFileLocation fileName | + fileName := workingFile basenameWithoutExtension. + self exportAsLatex. + latexFileLocation := ((workingFile parent) / fileName) fullName, '.tex'. + pdfFileLocation := ((workingFile parent) / fileName) fullName, '.pdf'. + '/usr/bin/xelatex' asFileReference exists + ifTrue: [ + "Generating the pdf" + OSProcess command: 'xelatex --shell-escape ', latexFileLocation. + "Moving the pdf output to the expected location" + pdfFileLocation asFileReference exists ifTrue: [pdfFileLocation asFileReference ensureDelete ]. + (FileLocator imageDirectory parent / (fileName, '.pdf')) + moveTo: pdfFileLocation asFileReference. + "Cleaning left overs" + #('.aux' '.out' '.log') do: [ :fileExension | + (FileLocator imageDirectory parent asFileReference / (fileName, fileExension)) ensureDelete]. + (FileLocator imageDirectory parent asFileReference / ('_minted-', fileName)) deleteAll. + self inform: 'Archivo exportado como pdf en: ', pdfFileLocation] + ifFalse: [ + self inform: + 'Necesita instalar XeLaTeX/TeX más información en:', String cr,' + http://xetex.sourceforge.net/' ]. ] { #category : #persistence } @@ -1122,7 +1146,8 @@ GrafoscopioBrowser >> treeOn: constructor [ "For trees" act: [self saveToFileUI] entitled: 'Guardar como ...' categorized: 'Arbol'; act: [self saveWorkingTree; exportAsHtml] entitled: 'Exportar como HTML' categorized: 'Arbol'; - act: [self saveWorkingTree; exportAsPdf] entitled: 'Exportar como PDF (requiere LaTeX)' categorized: 'Arbol'; + act: [self saveWorkingTree; exportAsLatex] entitled: 'Exportar como LaTeX' categorized: 'Arbol'; + act: [self saveWorkingTree; exportAsPdf] entitled: 'Exportar como PDF' categorized: 'Arbol'; act: [self viewExportedHtml] entitled: 'Ver HTML' categorized: 'Arbol'; act: [self messageNotImplementedYet] entitled: 'Ver PDF' categorized: 'Arbol'; diff --git a/repository/Grafoscopio/GrafoscopioNode.class.st b/repository/Grafoscopio/GrafoscopioNode.class.st index fd83526..cd06e76 100644 --- a/repository/Grafoscopio/GrafoscopioNode.class.st +++ b/repository/Grafoscopio/GrafoscopioNode.class.st @@ -136,6 +136,7 @@ GrafoscopioNode >> asMarkdown [ | markdownOutput | markdownOutput := '' writeStream. + self exportPreambleTo: markdownOutput. (self preorderTraversal) do: [ :eachNode | (eachNode level > 0) ifTrue: [(eachNode hasAncestorTaggedAs: 'invisible') | (eachNode tags = 'invisible') @@ -245,6 +246,37 @@ GrafoscopioNode >> demote [ ] +{ #category : #exporting } +GrafoscopioNode >> exportCodeBlockTo: aStream [ + "I convert the content of a node taged as 'código' (code) as pandoc markdown and put it Into aStream. + The code block is decorated with LaTeX commands for proper syntax highlighting using pygments. + Pdf exportation requires the installation of pygments and minted package for latex" + aStream nextPutAll: ('\begin{minted}{smalltalk}[frame=lines]'); lf. + aStream nextPutAll: (self body contents withInternetLineEndings); lf. + aStream nextPutAll: '\end{minted}';lf;lf. + ^aStream contents +] + +{ #category : #exporting } +GrafoscopioNode >> exportPreambleTo: aStream [ + "comment stating purpose of message" + | configDict | + aStream nextPutAll: '---'; lf. + aStream nextPutAll: 'header-includes:'; lf. + aStream nextPutAll: ' - \usepackage{minted}'; lf. + aStream nextPutAll: ' - \usemintedstyle{friendly}'; lf. + (self header = '%config') + ifTrue: [ + configDict := STON fromString: (self body). + + aStream nextPutAll: 'title: ', (configDict at: 'title'); lf. + aStream nextPutAll: 'author: ', ((configDict at: 'author') at: 'given'), ' ', ((configDict at: 'author') at: 'family'); lf. + aStream nextPutAll: 'bibliography: ', (configDict at: 'bibliography'); lf. + aStream nextPutAll: 'abstract: ', '|'; lf; nextPutAll: (configDict at: 'abstract'); lf. + ]. + aStream nextPutAll: '---'; lf. +] + { #category : #exporting } GrafoscopioNode >> flatten [ "I traverse the tree looking for node bodies containing 'Text' objects and transform them to @@ -355,11 +387,32 @@ GrafoscopioNode >> level: anInteger [ level := anInteger ] +{ #category : #exporting } +GrafoscopioNode >> margin [ + "I define the same margin of the page used for PDF exportations" + + ^'2 cm' +] + +{ #category : #exporting } +GrafoscopioNode >> margins [ + "I define each individual margin of the page used for PDF exportations" + + | margins | + margins := Dictionary new + add: 'top' -> '3 cm'; + add: 'bottom' -> '3 cm'; + add: 'left' -> '2 cm'; + add: 'right' -> '2 cm'; + yourself. + ^ margins +] + { #category : #exporting } GrafoscopioNode >> markdownContent [ "Extracts the markdown of a node using body as content, header as title and level as hierarchical level of the title. If special nodes types are present, converts them into proper markup to be embedded inside markdown" - | markdown configDict embedNodes temporalBody invisibleChildren | + | markdown embedNodes temporalBody invisibleChildren | markdown := '' writeStream. (self class specialWords includes: self header) not & (self class specialWords includes: ((self header findTokens: $ ) at: 1)) not & (self tags = 'código') not ifTrue: [ @@ -380,16 +433,6 @@ GrafoscopioNode >> markdownContent [ ] ]. markdown nextPutAll: (temporalBody contents withInternetLineEndings ); crlf; crlf]. - - (self header = '%config') - ifTrue: [ - configDict := STON fromString: (self body). - markdown nextPutAll: '---'; lf. - markdown nextPutAll: 'title: ', (configDict at: 'title'); lf. - markdown nextPutAll: 'author: ', ((configDict at: 'author') at: 'given'), ' ', ((configDict at: 'author') at: 'family'); lf. - markdown nextPutAll: 'bibliography: ', (configDict at: 'bibliography'); lf. - markdown nextPutAll: 'abstract: ', '|'; lf; nextPutAll: (configDict at: 'abstract'); lf. - markdown nextPutAll: '---'; lf. ]. ((self header findString: '%idea') = 1) ifTrue: [ embedNodes := self children select: [:each | ((each header findTokens: $ ) at: 1) = '%embed']. @@ -407,11 +450,7 @@ GrafoscopioNode >> markdownContent [ ifTrue: [ invisibleChildren := self children. invisibleChildren ifNotNil: [ ] ]. - (self tags = 'código') - ifTrue: [ - markdown nextPutAll: ('\begin{minted}{smalltalk}'); lf. - markdown nextPutAll: (self body contents withInternetLineEndings); lf. - markdown nextPutAll: '\end{minted}';lf]. + (self tags = 'código') ifTrue: [ self exportCodeBlockTo: markdown ]. ^markdown contents ]