diff --git a/README.md b/README.md index 43349aa6..40794b88 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,16 @@ Microdown is a smaller markdown but it is more extensible. It contains a nice bu Microdown is now the default markup for the Pillar document compilation chain. +## Instal + +```Smalltalk +Metacello new + baseline: 'Microdown'; + repository: 'github://pillar-markup/Microdown:v2.9.3/src'; + load. +``` + + ## Why should you use Microdown? Microdown is a smaller markdown but it is more extensible. @@ -163,12 +173,13 @@ The markup is not interpreted. Codeblock does not support more than four backticks. -## Development in Pharo 12! +## Development in Pharo 13! ### Loading specific version -To load the latest stable version load the master. If you have trouble loading in the latest Pharo just execute the preloading.st script in the .github folder. -This script will remove the existing Microdown package and clear the system. +To load the latest stable version load the master. If you have trouble loading in the latest Pharo just execute the preloading.st script in the .github folder. This script will remove the existing Microdown package and clear the system. +You can also execute the script provided below. + ```Smalltalk Metacello new @@ -178,8 +189,8 @@ Metacello new ``` The process is the following: -- Development in dev -- When stable dev -> in master +- Development happens dev. +- When stable dev -> in master. - When we can build books master is tagged. - Then there is the Pharo integration in dedicated branches. @@ -189,13 +200,7 @@ The process is the following: The following script loads all groups in the Baseline: ```Smalltalk -#( 'Microdown' 'BeautifulComments' 'DocumentBrowser' ) do: [ :name | - (IceRepository repositoryNamed: name) - ifNil: [ self inform: 'Project not found: ' , name ] - ifNotNil: [ :found | - found - unload; - forget ] ]. + Smalltalk globals at: #BaselineOfMicrodown @@ -207,14 +212,38 @@ Metacello new onConflict: [ :ex | ex useIncoming ]; onUpgrade: [ :ex | ex useIncoming ]; load: #('All'). - ``` +``` + +In addition you may want to execute this before. +``` +#( 'Microdown' ) do: [ :name | + (IceRepository repositoryNamed: name) + ifNil: [ self inform: 'Project not found: ' , name ] + ifNotNil: [ :found | + found + unload; + forget ] ]. +``` ## History -We have two sources: Pharo in one hand and Pillar and both are not totally synchronized. +We have two sources: +- Pharo in one hand (a minimal version managed with the pharo* branches) and +- Pillar (eg. all the tools and support for slides and books) and both are not totally synchronized. + +Now we also maintain different versions between Pharo versions. Currently the situation is the following: + +Working with Pharo 13: +- v2.9.2 a little release to support Foliage v2.1.0 and two new release of Pillar (probably one for P13 and one for P13 dropping pillar format). +- v2.9.1 provides a better integration with Pillar (the Microdown visitors were not used before even if they worked) +v2.7.x +- v2.7.2 merge pharo 13 changes / added gitbridge / OCompiler migration / cleaning syntax description / Ready for Pillar and Foliage +- v2.7.1 LatexQuoteblock-should-not-use-verbatim +- v2.7.0 Fix some errors and API/clients of the textualbuilder -Using Pharo 12: v2.5.x +Working with Pharo 12: v2.5.x +- v2.5.6 - Change html visitor and test for annotated paragraph - v2.5.5 - add support for top-level header as slide definition - v2.5.4 - add backward compatible anchor in caption + tonel V3 format - v2.5.1 - add LaTeX math with reference support for Pharo 12 and Pillar development up to v10.0.0 @@ -223,7 +252,8 @@ Using Pharo 12: v2.5.x Watch out v2.6.0 is older than v.2.5.4 -### Pillar History +### Extract of Pillar History + For Pharo 12 - v10.0.0 but with some links problems due to new inline parser using MD v2.5.0 @@ -235,7 +265,10 @@ For Pharo 10 -v8.3.2 fixed baseline and updated readme + + ## Implementation + The parser follows the design mentioned in [https://github.github.com/gfm](https://github.github.com/gfm), in particular the parsing strategy in Appendix A. In short, the strategy is that at any point in time, we might have several children of the root which are ""open"". The deepest in open in the tree is called ""current"". All the parents of the current are open. diff --git a/src/BaselineOfMicrodown/BaselineOfMicrodown.class.st b/src/BaselineOfMicrodown/BaselineOfMicrodown.class.st index c40c2a93..dcb65a28 100644 --- a/src/BaselineOfMicrodown/BaselineOfMicrodown.class.st +++ b/src/BaselineOfMicrodown/BaselineOfMicrodown.class.st @@ -19,15 +19,9 @@ BaselineOfMicrodown >> baseline: spec [ xmlParserHtml: spec; mustache: spec; gitBridge: spec. - " I disable this because against all my best effort, I cannot avoid the fucking pop up to raise - even if I unload all the packages. I get the Microdown-RichTextComposer in conflict." - + spec preLoadDoIt: #'preload:package:'. - - - "I disable this because in a postload - (IceRepository repositoryNamed: 'microdown') is nil and I do not get why" - + spec postLoadDoIt: #'postload:package:'. spec @@ -43,6 +37,7 @@ BaselineOfMicrodown >> baseline: spec [ package: #'Microdown-RichTextComposer' with: [ spec requires: #( #Microdown ) ]; + package: #'Microdown-RichTextComposer-Tests' with: [ spec requires: #( #'Microdown-RichTextComposer' ) ]; @@ -65,12 +60,13 @@ BaselineOfMicrodown >> baseline: spec [ with: [ spec requires: #( #'Microdown-HTMLExporter' 'Microdown-Tests' 'XMLParserHTML') ]; package: #'Microdown-LaTeXExporter' - with: [ spec requires: #( #Microdown ) ]; + with: [ spec requires: #( #Microdown ) ]; package: #'Microdown-LaTeXExporter-Tests' with: [ spec requires: #( #'Microdown-LaTeXExporter' #'Microdown-Tests') ]; - + package: #'Microdown-BeamerExporter' with: [ spec requires: #( #'Microdown-LaTeXExporter' ) ]; + package: #'Microdown-BeamerExporter-Tests' with: [ spec requires: #( #'Microdown-LaTeXExporter-Tests') ]; @@ -93,12 +89,12 @@ BaselineOfMicrodown >> baseline: spec [ package: #'Microdown-Blog-Tests' with: [ spec requires: #( #'Microdown-Blog' 'GitBridge') ]. - "I do not want group without tests for now" spec - group: 'Core' with: #('Microdown'); + group: 'Core' with: #('Microdown' 'Microdown-Tests'); group: 'ForPharo' with: #('Microdown' #'Microdown-BrowserExtensions'); - group: 'Tests' with: #('Core' 'Microdown-Tests'); group: 'RichText' with: #('Core' 'Microdown-RichTextComposer' ); + group: 'Editor' with: #('RichText' #'Microdown-PrettyPrinter' #'Microdown-PrettyPrinter-Tests'); + group: 'LaTeX' with: #('Core' #'Microdown-LaTeXExporter' #'Microdown-LaTeXExporter-Tests'); group: 'Extensions' with: #( #'Microdown-Evaluator' #'Microdown-Evaluator-Tests' @@ -115,9 +111,15 @@ BaselineOfMicrodown >> baseline: spec [ #'Microdown-BookTester-Tests' #'Microdown-Blog' #'Microdown-Blog-Tests' - ); - group: 'All' with: #('Core' #'Microdown-BrowserExtensions' 'Tests' 'Extensions' 'Microdown-Pharo-Tools' 'RichText') ] + group: 'All' with: #('Core' #'Microdown-BrowserExtensions' 'Editor' 'LaTeX' 'Extensions' 'Microdown-Pharo-Tools' 'RichText') + ] + + + + + + ] { #category : 'baselines' } @@ -131,7 +133,7 @@ BaselineOfMicrodown >> mustache: spec [ spec baseline: 'Mustache' with: [ spec - repository: 'github://noha/mustache:v1.0/repository'; + repository: 'github://noha/mustache:v1.3/repository'; loads: #( 'Core' 'Tests' ) ] ] @@ -162,16 +164,21 @@ BaselineOfMicrodown >> preload: loader package: packageSpec [ forget ] ]" | packagesToUnload | - "If we are building the Pharo image, we do not want to unload packages." - SystemBuildInfo current isBuildFinished ifFalse: [ ^ self ]. + + self flag: 'This is necessary to not break the bootstrapping. Microdown makes a cleaning of classes and as Microdown is loaded in the image it can cause conflits.'. + self flag: 'We do not access the class SystemBuildInfo directly because it is only present in Pharo 13 but Microdown works on different Pharo versions. We can simplifly this when Pharo 13 will be the minimal supported version.'. + self class environment at: #SystemBuildInfo ifPresent: [ :info | info + current isBuildFinished ifFalse: [ ^ self ]. ]. "If it is absent it's because we are in the Pharo bootstrap" self class environment at: #IceRepository ifPresent: [ :iceRepositoryClass | - packagesToUnload := ((PackageOrganizer default packages select: [ :each | each name beginsWith: 'Microdown' ]) collect: [ :each | each name ]) reject: [ :each | - #( 'Microdown-RichTextPresenter' 'Microdown-RichTextPresenter-Tests' ) includes: each ]. + | packages | + "The same here, not direct access to PackageOrganizer because it is only for Pharo 13." + packages := self class environment allClasses collect: #package as: Set. + packagesToUnload := ((packages select: [ :each | each name beginsWith: 'Microdown' ]) collect: [ :each | each name ]) reject: [ :each | + #( 'Microdown-RichTextPresenter' 'Microdown-RichTextPresenter-Tests' ) includes: each ]. - "these two are not managed by the microdown repo but the documentation. - I should rename them in the future to avoid confusion" + "these two are not managed by the microdown repo but the documentation. We should rename them in the future to avoid confusion" packagesToUnload do: [ :each | ((iceRepositoryClass repositoryNamed: 'Microdown') packageNamed: each) unload ] ] ] diff --git a/src/Microdown-Blog-Tests/MicBridge.class.st b/src/Microdown-Blog-Tests/MicBridge.class.st index 07b6d832..eab3a43b 100644 --- a/src/Microdown-Blog-Tests/MicBridge.class.st +++ b/src/Microdown-Blog-Tests/MicBridge.class.st @@ -4,8 +4,9 @@ I am a bridge to access resources from Microdown clone Class { #name : 'MicBridge', #superclass : 'GitBridge', - #category : 'Microdown-Blog-Tests', - #package : 'Microdown-Blog-Tests' + #category : 'Microdown-Blog-Tests-Utils', + #package : 'Microdown-Blog-Tests', + #tag : 'Utils' } { #category : 'accessing' } diff --git a/src/Microdown-BookTester-Tests/MicBookTesterVisitorTest.class.st b/src/Microdown-BookTester-Tests/MicCodeBlockValitorTest.class.st similarity index 81% rename from src/Microdown-BookTester-Tests/MicBookTesterVisitorTest.class.st rename to src/Microdown-BookTester-Tests/MicCodeBlockValitorTest.class.st index 7952601d..69320294 100644 --- a/src/Microdown-BookTester-Tests/MicBookTesterVisitorTest.class.st +++ b/src/Microdown-BookTester-Tests/MicCodeBlockValitorTest.class.st @@ -1,12 +1,12 @@ Class { - #name : 'MicBookTesterVisitorTest', + #name : 'MicCodeBlockValitorTest', #superclass : 'TestCase', #category : 'Microdown-BookTester-Tests', #package : 'Microdown-BookTester-Tests' } { #category : 'utilities' } -MicBookTesterVisitorTest >> parseAndTest: docText [ +MicCodeBlockValitorTest >> parseAndTest: docText [ | doc bTester | doc := Microdown parse: docText. bTester := MicCodeBlockValidator new. @@ -15,7 +15,7 @@ MicBookTesterVisitorTest >> parseAndTest: docText [ ] { #category : 'tests - valid book tests' } -MicBookTesterVisitorTest >> testExampleCodeblock [ +MicCodeBlockValitorTest >> testExampleCodeblock [ | docText bTester | docText := '```example=true 3 + 4 @@ -27,7 +27,7 @@ MicBookTesterVisitorTest >> testExampleCodeblock [ ] { #category : 'tests - failing book tests' } -MicBookTesterVisitorTest >> testExampleCodeblockWithFailingTest [ +MicCodeBlockValitorTest >> testExampleCodeblockWithFailingTest [ | docText bTester | docText := '```example=true 3 + ''12'' @@ -40,7 +40,7 @@ MicBookTesterVisitorTest >> testExampleCodeblockWithFailingTest [ ] { #category : 'tests - failing book tests' } -MicBookTesterVisitorTest >> testExampleCodeblockWithFalseTest [ +MicCodeBlockValitorTest >> testExampleCodeblockWithFalseTest [ | docText bTester | docText := '```example=true @@ -54,7 +54,7 @@ MicBookTesterVisitorTest >> testExampleCodeblockWithFalseTest [ ] { #category : 'tests - failing book tests' } -MicBookTesterVisitorTest >> testExampleCodeblockWithNoBrakets [ +MicCodeBlockValitorTest >> testExampleCodeblockWithNoBrakets [ | docText bTester | docText := '```example=true @@ -68,7 +68,7 @@ MicBookTesterVisitorTest >> testExampleCodeblockWithNoBrakets [ ] { #category : 'tests - strange codeblock' } -MicBookTesterVisitorTest >> testExampleCodeblockWithTwoBrackets [ +MicCodeBlockValitorTest >> testExampleCodeblockWithTwoBrackets [ ">> instead of > > > should not work so there is one failed test" | docText bTester | @@ -83,7 +83,7 @@ MicBookTesterVisitorTest >> testExampleCodeblockWithTwoBrackets [ ] { #category : 'tests - strange codeblock' } -MicBookTesterVisitorTest >> testExampleEmptyCodeblockWithTwoBrackets [ +MicCodeBlockValitorTest >> testExampleEmptyCodeblockWithTwoBrackets [ | docText bTester | docText := '```example=true @@ -99,7 +99,7 @@ MicBookTesterVisitorTest >> testExampleEmptyCodeblockWithTwoBrackets [ ] { #category : 'tests - valid book tests' } -MicBookTesterVisitorTest >> testExpectedFailureForAFailure [ +MicCodeBlockValitorTest >> testExpectedFailureForAFailure [ | docText bTester | docText := '```example=true&expectedFailure=true 3 + 4 @@ -112,7 +112,7 @@ MicBookTesterVisitorTest >> testExpectedFailureForAFailure [ ] { #category : 'tests - valid book tests' } -MicBookTesterVisitorTest >> testExpectedFailureForARaisedException [ +MicCodeBlockValitorTest >> testExpectedFailureForARaisedException [ | docText bTester | docText := '```example=true&expectedFailure=true 3 + ''a'' @@ -125,7 +125,7 @@ MicBookTesterVisitorTest >> testExpectedFailureForARaisedException [ ] { #category : 'tests - valid book tests' } -MicBookTesterVisitorTest >> testExplanationIsExceptionCatchedInFailingTest [ +MicCodeBlockValitorTest >> testExplanationIsExceptionCatchedInFailingTest [ | docText bTester | docText := '```example=true 3 + ''12'' @@ -140,7 +140,7 @@ MicBookTesterVisitorTest >> testExplanationIsExceptionCatchedInFailingTest [ ] { #category : 'tests - valid book tests' } -MicBookTesterVisitorTest >> testExplanationIsTestFailedWithoutException [ +MicCodeBlockValitorTest >> testExplanationIsTestFailedWithoutException [ | docText bTester | docText := '```example=true @@ -155,7 +155,7 @@ MicBookTesterVisitorTest >> testExplanationIsTestFailedWithoutException [ ] { #category : 'tests - valid book tests' } -MicBookTesterVisitorTest >> testExplanationIsTestPassed [ +MicCodeBlockValitorTest >> testExplanationIsTestPassed [ | docText bTester | docText := '```example=true @@ -170,7 +170,7 @@ MicBookTesterVisitorTest >> testExplanationIsTestPassed [ ] { #category : 'tests - no example' } -MicBookTesterVisitorTest >> testNoExampleCodeblock [ +MicCodeBlockValitorTest >> testNoExampleCodeblock [ | docText bTester | docText := '``` 3 + 4 @@ -183,7 +183,7 @@ MicBookTesterVisitorTest >> testNoExampleCodeblock [ ] { #category : 'tests - no example' } -MicBookTesterVisitorTest >> testThreeCodeBlocksWithTwoExamples [ +MicCodeBlockValitorTest >> testThreeCodeBlocksWithTwoExamples [ | docText bTester | docText := diff --git a/src/Microdown-BookTester-Tests/MicReferenceCheckerTest.class.st b/src/Microdown-BookTester-Tests/MicReferenceCheckerTest.class.st index de434de3..915d0a8f 100644 --- a/src/Microdown-BookTester-Tests/MicReferenceCheckerTest.class.st +++ b/src/Microdown-BookTester-Tests/MicReferenceCheckerTest.class.st @@ -16,7 +16,7 @@ Class { #package : 'Microdown-BookTester-Tests' } -{ #category : 'as yet unclassified' } +{ #category : 'helpers - anchors & references' } MicReferenceCheckerTest >> anchorNames: checker [ ^ checker results diff --git a/src/Microdown-BookTester/MicAnalysisReportWriter.class.st b/src/Microdown-BookTester/MicAnalysisReportWriter.class.st index e8111e53..e98dd3aa 100644 --- a/src/Microdown-BookTester/MicAnalysisReportWriter.class.st +++ b/src/Microdown-BookTester/MicAnalysisReportWriter.class.st @@ -12,6 +12,26 @@ Class { #tag : 'Analysis' } +{ #category : 'instance creation' } +MicAnalysisReportWriter class >> reportForFolder: folderReference startingFrom: fileReference [ + + | reporter checker validator | + reporter := self new. + + checker := MicReferenceChecker new. + checker fileSystem: folderReference. + checker checkProject: fileReference. + + reporter addResults: checker results. + + validator := MicCodeBlockValidator new. + checker fileSystem: folderReference. + checker checkProject: fileReference. + + reporter addResults: validator results. + ^ reporter +] + { #category : 'adding' } MicAnalysisReportWriter >> addResults: aCollection [ diff --git a/src/Microdown-BookTester/MicBookTesterStrategy.class.st b/src/Microdown-BookTester/MicBookTesterStrategy.class.st deleted file mode 100644 index 48aa3109..00000000 --- a/src/Microdown-BookTester/MicBookTesterStrategy.class.st +++ /dev/null @@ -1,22 +0,0 @@ -Class { - #name : 'MicBookTesterStrategy', - #superclass : 'Object', - #instVars : [ - 'results' - ], - #category : 'Microdown-BookTester-Analysis', - #package : 'Microdown-BookTester', - #tag : 'Analysis' -} - -{ #category : 'hook' } -MicBookTesterStrategy class >> handleKey [ - - ^ self subclassResponsibility - -] - -{ #category : 'accessing' } -MicBookTesterStrategy >> results: aCollection [ - results := aCollection -] diff --git a/src/Microdown-BookTester/MicCodeBlockTesterStrategy.class.st b/src/Microdown-BookTester/MicCodeBlockTesterStrategy.class.st new file mode 100644 index 00000000..2f4f3011 --- /dev/null +++ b/src/Microdown-BookTester/MicCodeBlockTesterStrategy.class.st @@ -0,0 +1,37 @@ +" +I'm the root of book validation strategy. +A strategy is attached to a tag in a codeblock. + +For example, when a codeblock contains the example tag as defined below, then the CodeBlockValidator will execute the strategy associated with it (using handleKey). + +```example + +3 + 2 +>>> 5 + +``` + + +" +Class { + #name : 'MicCodeBlockTesterStrategy', + #superclass : 'Object', + #instVars : [ + 'results' + ], + #category : 'Microdown-BookTester-Analysis', + #package : 'Microdown-BookTester', + #tag : 'Analysis' +} + +{ #category : 'hook' } +MicCodeBlockTesterStrategy class >> handleKey [ + + ^ self subclassResponsibility + +] + +{ #category : 'accessing' } +MicCodeBlockTesterStrategy >> results: aCollection [ + results := aCollection +] diff --git a/src/Microdown-BookTester/MicCodeBlockValidator.class.st b/src/Microdown-BookTester/MicCodeBlockValidator.class.st index 95d98abc..8a39ae25 100644 --- a/src/Microdown-BookTester/MicCodeBlockValidator.class.st +++ b/src/Microdown-BookTester/MicCodeBlockValidator.class.st @@ -1,5 +1,12 @@ " -i visit code blocks and make sure that evaluation is correct +I visit code blocks and make sure that their 'evaluation' is correct. +I generate a list of analysis results (subclasses of `MicResult`) that then will be consumed by the `MicAnalysisReportBuilder`. +This evaluation is specified by a tag. + +- 'example' tag verifies that the code is returning the expected result. +- 'sync' verifies if the code is in sync with the one in the image. + +New code block validation can easily be added by adding subclasses to `MicCodeBlockTesterStrategy`. " Class { #name : 'MicCodeBlockValidator', @@ -7,7 +14,8 @@ Class { #instVars : [ 'strategies', 'results', - 'reportWriter' + 'reportWriter', + 'rootDirectory' ], #category : 'Microdown-BookTester-Analysis', #package : 'Microdown-BookTester', @@ -20,10 +28,23 @@ MicCodeBlockValidator class >> isAbstract [ ^ false ] +{ #category : 'main API' } +MicCodeBlockValidator >> checkProject: aFileReference [ + + | mainMic collector | + mainMic := Microdown parseFile: aFileReference. + collector := MicFileCollector new. + collector + rootDirectory: rootDirectory; + visit: mainMic. + collector visitedFiles do: [ :each | self start: each ]. + +] + { #category : 'initialization' } MicCodeBlockValidator >> collectStrategies [ - MicBookTesterStrategy allSubclasses do: [ :each | + MicCodeBlockTesterStrategy allSubclasses do: [ :each | | strat | strat := each new. strat results: results. @@ -36,6 +57,14 @@ MicCodeBlockValidator >> failedTests [ ^ results select: [ :each | each isFailed ] ] +{ #category : 'accessing' } +MicCodeBlockValidator >> fileSystem: aFileReference [ + + self deprecated: 'use rootDirectory' + transformWith: '`@receiver fileSystem: `@arg' -> '`@receiver rootDirectory: `@arg'. + self rootDirectory: aFileReference. +] + { #category : 'initialization' } MicCodeBlockValidator >> initialize [ @@ -77,6 +106,12 @@ MicCodeBlockValidator >> results: anObject [ results := anObject ] +{ #category : 'accessing' } +MicCodeBlockValidator >> rootDirectory: aFileReference [ + + rootDirectory := aFileReference +] + { #category : 'accessing' } MicCodeBlockValidator >> start: anObject [ anObject accept: self diff --git a/src/Microdown-BookTester/MicExampleTesterStrategy.class.st b/src/Microdown-BookTester/MicExampleTesterStrategy.class.st index c392bc69..a59c909c 100644 --- a/src/Microdown-BookTester/MicExampleTesterStrategy.class.st +++ b/src/Microdown-BookTester/MicExampleTesterStrategy.class.st @@ -1,6 +1,17 @@ +" +I'm responsible to validate that an example in a code block is correct. + +```example +3 + 2 +>>> 5 +``` + +The checking logic should probably be improved looking at the old book tester in old Pillar. +See [PDF explaining book tester](https://github.com/pillar-markup/BookTester/tree/main/ressources/OldBookTester) +" Class { #name : 'MicExampleTesterStrategy', - #superclass : 'MicBookTesterStrategy', + #superclass : 'MicCodeBlockTesterStrategy', #category : 'Microdown-BookTester-Analysis', #package : 'Microdown-BookTester', #tag : 'Analysis' diff --git a/src/Microdown-BookTester/MicBookTesterNullStrategy.class.st b/src/Microdown-BookTester/MicNullTesterStrategy.class.st similarity index 60% rename from src/Microdown-BookTester/MicBookTesterNullStrategy.class.st rename to src/Microdown-BookTester/MicNullTesterStrategy.class.st index 435668ce..71f78a54 100644 --- a/src/Microdown-BookTester/MicBookTesterNullStrategy.class.st +++ b/src/Microdown-BookTester/MicNullTesterStrategy.class.st @@ -2,22 +2,22 @@ When there is no tag other than none or language, does not verify the code block. " Class { - #name : 'MicBookTesterNullStrategy', - #superclass : 'MicBookTesterStrategy', + #name : 'MicNullTesterStrategy', + #superclass : 'MicCodeBlockTesterStrategy', #category : 'Microdown-BookTester-Analysis', #package : 'Microdown-BookTester', #tag : 'Analysis' } { #category : 'hook' } -MicBookTesterNullStrategy class >> handleKey [ +MicNullTesterStrategy class >> handleKey [ ^ #language ] { #category : 'main API' } -MicBookTesterNullStrategy >> verify: aMicCodeBlock [ +MicNullTesterStrategy >> verify: aMicCodeBlock [ diff --git a/src/Microdown-BookTester/MicReferenceChecker.class.st b/src/Microdown-BookTester/MicReferenceChecker.class.st index 7b88031c..178469d9 100644 --- a/src/Microdown-BookTester/MicReferenceChecker.class.st +++ b/src/Microdown-BookTester/MicReferenceChecker.class.st @@ -262,9 +262,9 @@ MicReferenceChecker >> results: anObject [ ] { #category : 'accessing' } -MicReferenceChecker >> rootDirectory: aFileReferemce [ +MicReferenceChecker >> rootDirectory: aFileReference [ - rootDirectory := aFileReferemce + rootDirectory := aFileReference ] { #category : 'internal' } diff --git a/src/Microdown-BookTester/MicSyncTesterStrategy.class.st b/src/Microdown-BookTester/MicSyncTesterStrategy.class.st index d2cc9793..5fd3233b 100644 --- a/src/Microdown-BookTester/MicSyncTesterStrategy.class.st +++ b/src/Microdown-BookTester/MicSyncTesterStrategy.class.st @@ -1,6 +1,6 @@ Class { #name : 'MicSyncTesterStrategy', - #superclass : 'MicBookTesterStrategy', + #superclass : 'MicCodeBlockTesterStrategy', #category : 'Microdown-BookTester-Analysis', #package : 'Microdown-BookTester', #tag : 'Analysis' diff --git a/src/Microdown-BrowserExtensions/Class.extension.st b/src/Microdown-BrowserExtensions/Class.extension.st index 6eb2d249..dd292093 100644 --- a/src/Microdown-BrowserExtensions/Class.extension.st +++ b/src/Microdown-BrowserExtensions/Class.extension.st @@ -53,10 +53,10 @@ Class >> documentExampleCode [ and: [ self documentExampleCodeSelector match: each selector match ] ] ifNone: [ ^ nil ]. - ^ (exampleMethod sourceCode lines + ^ ((exampleMethod sourceCode lines allButFirst "Remove method name" reject: [ :each | each trimLeft beginsWith: '<' ]) "Remove pragmas" - asStringWithCr + joinUsing: Character cr) trimmed ] diff --git a/src/Microdown-HTMLExporter-Tests/MicHTMLExporterTest.class.st b/src/Microdown-HTMLExporter-Tests/MicHTMLExporterTest.class.st index ad9cf2d4..7755fa65 100644 --- a/src/Microdown-HTMLExporter-Tests/MicHTMLExporterTest.class.st +++ b/src/Microdown-HTMLExporter-Tests/MicHTMLExporterTest.class.st @@ -38,14 +38,21 @@ MicHTMLExporterTest >> newLine: aNewLine [ newLine := aNewLine ] +{ #category : 'tests - paragraph' } +MicHTMLExporterTest >> newLines: aString [ + + ^ newLine, '

', aString, '

', newLine +] + { #category : 'utilities' } MicHTMLExporterTest >> parse: aString andCheckWeGet: aResultingString [ - | mic | - + | mic c | mic := parser parse: aString. writer visit: mic. - self assert: writer contents equals: aResultingString + c := writer contents. + self assert: c equals: aResultingString. + ^ c ] { #category : 'utilities' } @@ -58,11 +65,37 @@ MicHTMLExporterTest >> parser: aParser [ parser := aParser new ] +{ #category : 'tests - paragraph' } +MicHTMLExporterTest >> pharoPage [ + + ^ + '{ +"title" : "About Pharo", +"layout" : "index", +"publishDate" : "2025-06-01" +} + +# Pharo + +[Pharo](http://www.pharo.org) is a beautiful dynamically-typed reflective pure object-oriented language that we have been developing since 2008. +It is inspired by Smalltalk (I''m extremely grateful to Alan Kay and Dan Ingalls - they were so visionary and right). Now our vision for Pharo is to reinvent Smalltalk and produce a better system. +From that perspective, I''m used to say that Pharo is what we have and not what we want. +In essence, Pharo is the beginning of the journey and not the final goal. And you can change its future. + +You can check what companies are saying about it: [Video](https://youtu.be/6tdkKNX2g4s) + +There are many aspects I would like to see being explored either by us or by others. +If you want to explore some of the following aspects, please go and let us know. +I''m really interested in any topics that evolve Pharo into a better Pharo. + +' +] + { #category : 'tests - paragraph' } MicHTMLExporterTest >> testAccents [ - self parse: 'éà' andCheckWeGet: newLine, -'

éà

' + self parse: 'éà' andCheckWeGet: (self newLines: +'éà') ] { #category : 'utilities' } @@ -100,8 +133,8 @@ MicHTMLExporterTest >> testFigure [ self parse: factory figureSample - andCheckWeGet: newLine , -'

Foo
Foo

' + andCheckWeGet: (self newLines: +'
Foo
Foo
') ] { #category : 'tests - formats' } @@ -109,8 +142,8 @@ MicHTMLExporterTest >> testFigureBold [ self parse: factory figureBoldSample - andCheckWeGet: newLine , -'

Foo
Foo

' + andCheckWeGet: (self newLines: +'
Foo
Foo
' ) ] { #category : 'tests' } @@ -118,8 +151,8 @@ MicHTMLExporterTest >> testFigureItalic [ self parse: factory figureItalicSample - andCheckWeGet: newLine , -'

Foo
Foo

' + andCheckWeGet: (self newLines: +'
Foo
Foo
') ] { #category : 'tests' } @@ -127,8 +160,8 @@ MicHTMLExporterTest >> testFigureNested [ self parse: factory figureNestedSample - andCheckWeGet: newLine , -'

Foo_
Foo_

' + andCheckWeGet: (self newLines: +'
Foo_
Foo_
') ] { #category : 'tests' } @@ -136,8 +169,8 @@ MicHTMLExporterTest >> testFigureReal [ self parse: factory figureRealSample - andCheckWeGet: newLine , -'

A logo png under figures folder
A logo png under figures folder

' + andCheckWeGet: (self newLines: +'
A logo png under figures folder
A logo png under figures folder
') ] { #category : 'tests' } @@ -145,8 +178,8 @@ MicHTMLExporterTest >> testFigureStrike [ self parse: factory figureStrikeSample - andCheckWeGet: newLine , -'

Foo
Foo

' + andCheckWeGet: (self newLines: +'
Foo
Foo
') ] { #category : 'tests' } @@ -154,8 +187,8 @@ MicHTMLExporterTest >> testFigureWithLabelWithoutSize [ self parse: factory figureWithLabelWithoutSizeSample - andCheckWeGet: newLine , -'

Foo
Foo

' + andCheckWeGet: (self newLines: +'
Foo
Foo
') ] { #category : 'tests' } @@ -163,8 +196,8 @@ MicHTMLExporterTest >> testFigureWithoutCaption [ self parse: factory figureWithoutCaptionSample - andCheckWeGet: newLine , -'

' + andCheckWeGet: (self newLines: +'
') ] { #category : 'tests' } @@ -172,8 +205,8 @@ MicHTMLExporterTest >> testFigureWithoutSizeAndLabel [ self parse: factory figureSampleWithoutSizeAndLabel - andCheckWeGet: newLine , -'

Foo
Foo

' + andCheckWeGet: (self newLines: +'
Foo
Foo
') ] { #category : 'tests' } @@ -181,8 +214,8 @@ MicHTMLExporterTest >> testGoutDeFraise [ self parse: factory figureGoutDeFraise - andCheckWeGet: newLine , -'

Proposition pour le thème :  Un goût de fraise
Proposition pour le thème : Un goût de fraise

' + andCheckWeGet: (self newLines: +'
Proposition pour le thème :  Un goût de fraise
Proposition pour le thème : Un goût de fraise
') ] { #category : 'tests' } @@ -218,21 +251,21 @@ MicHTMLExporterTest >> testMetaDataIsNotIgnored [ { #category : 'tests - paragraph' } MicHTMLExporterTest >> testParagraph [ - self parse: factory paragraphSample andCheckWeGet: newLine ,'

Foo

' + self parse: factory paragraphSample andCheckWeGet: (self newLines: 'Foo') ] { #category : 'tests' } MicHTMLExporterTest >> testParagraphLongWithAccents [ - self parse: factory paragraphOnMultipleLinesSample andCheckWeGet: newLine , -'

Je ne connais pas la peur, car la peur tue l''esprit. La peur est la petite mort qui conduit à l''oblitération totale. J''affonterai ma peur. Je lui permettrais de passer sur moi, au travers de moi. Et lorsqu''elle sera passée, je tournerai mon oeil interieur sur son chemin. Et là où elle sera passée, il n''y aura plus rien, rien que moi.

' + self parse: factory paragraphOnMultipleLinesSample andCheckWeGet: (self newLines: +'Je ne connais pas la peur, car la peur tue l''esprit. La peur est la petite mort qui conduit à l''oblitération totale. J''affonterai ma peur. Je lui permettrais de passer sur moi, au travers de moi. Et lorsqu''elle sera passée, je tournerai mon oeil interieur sur son chemin. Et là où elle sera passée, il n''y aura plus rien, rien que moi.') ] { #category : 'tests - formats' } MicHTMLExporterTest >> testParagraphNestedSample [ - self parse: factory paragraphNestedSample andCheckWeGet: newLine , -'

this is a paragraph

' + self parse: factory paragraphNestedSample andCheckWeGet: (self newLines: +'this is a paragraph') ] { #category : 'tests - formats' } @@ -240,22 +273,33 @@ MicHTMLExporterTest >> testParagraphWithBold [ self parse: factory paragraphBoldSample - andCheckWeGet: newLine , -'

this is a paragraph

' + andCheckWeGet: (self newLines: +'this is a paragraph') ] { #category : 'tests' } MicHTMLExporterTest >> testParagraphWithItalic [ - self parse: factory paragraphItalicSample andCheckWeGet: newLine , -'

this is a paragraph

' + self parse: factory paragraphItalicSample andCheckWeGet: (self newLines: +'this is a paragraph') ] { #category : 'tests - formats' } MicHTMLExporterTest >> testParagraphWithMonospace [ - self parse: factory paragraphMonospaceSample andCheckWeGet: newLine , -'

this is a paragraph

' + self parse: factory paragraphMonospaceSample andCheckWeGet: (self newLines: +'this is a paragraph') +] + +{ #category : 'tests - paragraph' } +MicHTMLExporterTest >> testPharoPage [ + + self parse: self pharoPage andCheckWeGet: newLine, '

Pharo

', newLine, +'

Pharo is a beautiful dynamically-typed reflective pure object-oriented language that we have been developing since 2008.
It is inspired by Smalltalk (I''m extremely grateful to Alan Kay and Dan Ingalls - they were so visionary and right). Now our vision for Pharo is to reinvent Smalltalk and produce a better system.
From that perspective, I''m used to say that Pharo is what we have and not what we want.
In essence, Pharo is the beginning of the journey and not the final goal. And you can change its future.

', newLine, newLine, + +'

You can check what companies are saying about it: Video

', newLine, newLine, + +'

There are many aspects I would like to see being explored either by us or by others.
If you want to explore some of the following aspects, please go and let us know.
I''m really interested in any topics that evolve Pharo into a better Pharo.

', newLine ] { #category : 'tests - formats' } @@ -268,8 +312,8 @@ MicHTMLExporterTest >> testQuote [ { #category : 'tests - formats' } MicHTMLExporterTest >> testStrike [ - self parse: factory strikethroughFormatSample andCheckWeGet: newLine , -'

Foo

' + self parse: factory strikethroughFormatSample andCheckWeGet: (self newLines: +'Foo') ] { #category : 'tests' } diff --git a/src/Microdown-HTMLExporter-Tests/MicHTMLVisitorTest.class.st b/src/Microdown-HTMLExporter-Tests/MicHTMLVisitorTest.class.st index 197c869d..f963f2ba 100644 --- a/src/Microdown-HTMLExporter-Tests/MicHTMLVisitorTest.class.st +++ b/src/Microdown-HTMLExporter-Tests/MicHTMLVisitorTest.class.st @@ -93,12 +93,11 @@ MicHTMLVisitorTest >> testContents [ MicHTMLVisitorTest >> testConvertMicFile [ writer convertMicFile: (fileSystem / 'anExample1.md') asFileReference. - self assert: (fileSystem / 'anExample1.html') asFileReference exists. self assert: (fileSystem / 'anExample1.html') asFileReference contents equals: newLine , '

Foo

' , newLine - , '

Pharo is cool

' , newLine + , (self wrapP: 'Pharo is cool'), newLine , '
this is a code blu blu
' , newLine ] @@ -140,7 +139,7 @@ MicHTMLVisitorTest >> testCreateAnchorWithLink [ | result | self assert: writer contents equals: String empty. result := writer convertMicString: '[Pharo Website](http://pharo.org target=blank&rel=bookmark)'. - self assert: result trimBoth equals: '

Pharo Website

'. + self assert: result trimBoth , newLine equals: (self wrapP: 'Pharo Website'). ] { #category : 'tests' } @@ -154,11 +153,11 @@ MicHTMLVisitorTest >> testCreateAnnotationCompound [ this is another string'. self - assert: result trimBoth + assert: result trimBoth, newLine equals: '

This is a title

' , newLine , 'Body of annotated block' - , newLine , '

this is another string

' + , newLine , (self wrapP: 'this is another string') ] { #category : 'tests' } @@ -183,7 +182,7 @@ MicHTMLVisitorTest >> testCreateCitation [ self assert: writer contents equals: String empty. result := writer convertMicString: '{!citation|ref=Duca99a!}'. - self assert: result trimBoth equals: '

Duca99a

'. + self assert: result trimBoth, newLine equals: (self wrapP: 'Duca99a'). ] @@ -194,10 +193,106 @@ MicHTMLVisitorTest >> testCreateItalic [ self assert: writer contents equals: String empty. result := writer convertMicString: '_Text with italic_'. - self assert: result trimBoth equals: '

Text with italic

'. + self assert: result trimBoth, newLine equals: (self wrapP: 'Text with italic'). + +] + +{ #category : 'tests' } +MicHTMLVisitorTest >> testRawParagraphDivWithArgs [ + + | result source | + self assert: writer contents equals: String empty. + source := +'
', newLine, +'Tintin', newLine, newLine, '
'. + + result := writer convertMicString: source. + self + assert: result trimBoth , newLine + equals: '
', newLine , (self wrapP:'Tintin'), newLine, + '
', newLine. ] +{ #category : 'tests' } +MicHTMLVisitorTest >> testRawParagraphDivWithArgsAndNested [ + + | result source | + + self assert: writer contents equals: String empty. + source := +'
', newLine, +'

', +'We use the <div> tag to group two paragraphs for applying a background to the text, and to add color to this', newLine, newLine, +'', newLine, +'word', newLine, +'', newLine, +'we place it within <span> tag.', +'

', newLine, +'

', newLine, +'Pay attention, that the <div> tag is a block-level element, so a line break is placed before and after it.', newLine, +'

', newLine, +'
'. + + result := writer convertMicString: source. + self + assert: result trimBoth + equals: '
', newLine, +'

', +'We use the <div> tag to group two paragraphs for applying a background to the text, and to add color to this

', newLine, newLine, +'', newLine, +'

word

', newLine, newLine, +'
', newLine, +'

we place it within <span> tag.

', +'

', newLine, newLine, +'

', newLine, +'

Pay attention, that the <div> tag is a block-level element, so a line break is placed before and after it.

', newLine, newLine, +'

', newLine, +'
'. +] + +{ #category : 'tests' } +MicHTMLVisitorTest >> testRawParagraphIframe [ + + | result | + self assert: writer contents equals: String empty. + + result := writer convertMicString: '', newLine, 'Tintin'. + + self assert: result trimBoth, newLine equals: '', newLine, (self wrapP: 'Tintin') + +] + +{ #category : 'tests' } +MicHTMLVisitorTest >> testRawParagraphSimpleDiv [ + + | result source | + self assert: writer contents equals: String empty. + source := '
', newLine , '

', newLine, 'some text', newLine, '

', newLine, +'and', newLine, '
'. + + result := writer convertMicString: source. + self + assert: result trimBoth + equals: '
', newLine , '

', newLine, (self wrapP: 'some text'), newLine, '

', newLine, +(self wrapP: 'and'), newLine, '
'. + +] + +{ #category : 'tests' } +MicHTMLVisitorTest >> testRawParagraphSimpleEmptyDiv [ + + | result | + self assert: writer contents equals: String empty. + + result := writer convertMicString: '
', newLine, +'
'. + self assert: result trimBoth equals: '
', newLine, +'
'. +] + { #category : 'tests' } MicHTMLVisitorTest >> testVisitAnchor [ @@ -207,6 +302,12 @@ MicHTMLVisitorTest >> testVisitAnchor [ ] +{ #category : 'tests' } +MicHTMLVisitorTest >> wrapP: aString [ + + ^ '

', aString , '

', newLine +] + { #category : 'accessing' } MicHTMLVisitorTest >> writer: aWriter [ writer := aWriter new diff --git a/src/Microdown-HTMLExporter/MicHTMLVisitor.class.st b/src/Microdown-HTMLExporter/MicHTMLVisitor.class.st index 2270094f..ad4f3066 100644 --- a/src/Microdown-HTMLExporter/MicHTMLVisitor.class.st +++ b/src/Microdown-HTMLExporter/MicHTMLVisitor.class.st @@ -93,6 +93,11 @@ MicHTMLVisitor class >> serializeToHTMLDoc: aMicrodownString withStyle: aStyleNa ] +{ #category : 'accessing' } +MicHTMLVisitor class >> writerName [ + ^ #html +] + { #category : 'initialization' } MicHTMLVisitor >> canvasClass [ @@ -159,11 +164,16 @@ MicHTMLVisitor >> crlfAsNewLine [ canvas crlfAsNewLine ] -{ #category : 'as yet unclassified' } +{ #category : 'accessing' } MicHTMLVisitor >> doNotIgnoreMetaData [ ignoresMetaData := false ] +{ #category : 'accessing' } +MicHTMLVisitor >> folderName [ + ^ #html +] + { #category : 'accessing' } MicHTMLVisitor >> ignoreMetaData [ ignoresMetaData := true @@ -185,6 +195,12 @@ MicHTMLVisitor >> lfAsNewLine [ canvas lfAsNewLine ] +{ #category : 'accessing' } +MicHTMLVisitor >> mainDocumentTemplateName [ + + ^ 'template' +] + { #category : 'visiting - list' } MicHTMLVisitor >> metaDataFromAssociations: aDictionary [ "Write the receiver's metadata from aDictionary" @@ -209,6 +225,22 @@ MicHTMLVisitor >> stream: aStream [ canvas := self canvasClass on: stream ] +{ #category : 'templating' } +MicHTMLVisitor >> templateForConfiguration: aConfiguration [ + | inputFile templateName | + configuration := aConfiguration. + inputFile := configuration inputFile. + + (configuration hasProperty: #mainDocument) + ifFalse: [ ^ configuration propertyAt: self mainDocumentTemplateName ifAbsent: [ 'main.mustache' ] ]. + + templateName := inputFile fullName + = ((configuration baseDirectory resolve: configuration mainDocument) , 'pillar') fullName + ifTrue: [ self mainDocumentTemplateName ] + ifFalse: [ self chapterTemplateName ]. + ^ configuration propertyAt: templateName +] + { #category : 'initialization' } MicHTMLVisitor >> usedNewLine [ "Return the encoded new line. Useful for tests." @@ -458,7 +490,8 @@ MicHTMLVisitor >> visitParagraph: aParagraph [ canvas newLine. canvas tag name: 'p'; - with: [ super visitParagraph: aParagraph ] + with: [ super visitParagraph: aParagraph. ]. + canvas newLine. ] { #category : 'visiting' } @@ -474,6 +507,29 @@ MicHTMLVisitor >> visitQuote: aQuote [ with: [ super visitQuote: aQuote ] ] +{ #category : 'visiting - html extensions' } +MicHTMLVisitor >> visitRaw: aParagraph [ + + canvas raw: aParagraph bodyString. + canvas newLine +] + +{ #category : 'visiting - html extensions' } +MicHTMLVisitor >> visitRawParagraph: aParagraph [ + + canvas + newLine; + raw: '<' , aParagraph label. + aParagraph hasArguments + ifTrue: [ canvas space; raw: aParagraph argumentString ]. + canvas raw: '>' . + + aParagraph children do: [ :each | each accept: self ]. + canvas + newLine; + raw: aParagraph lineStopMarkup. +] + { #category : 'visiting - inline elements' } MicHTMLVisitor >> visitStrike: aStrike [ @@ -565,6 +621,13 @@ MicHTMLVisitor >> visitUnorderedListItem: anUnorderedListItem [ ] +{ #category : 'writing' } +MicHTMLVisitor >> write: aMicElement [ + "for now for integration with Pillar." + self visit: aMicElement. + ^ self contents +] + { #category : 'visiting' } MicHTMLVisitor >> writeCounter: aCounter [ diff --git a/src/Microdown-LaTeXExporter-Tests/MicAbstractLaTexWriterTest.class.st b/src/Microdown-LaTeXExporter-Tests/MicAbstractLaTexWriterTest.class.st index 877d8809..f45bfdc8 100644 --- a/src/Microdown-LaTeXExporter-Tests/MicAbstractLaTexWriterTest.class.st +++ b/src/Microdown-LaTeXExporter-Tests/MicAbstractLaTexWriterTest.class.st @@ -76,10 +76,12 @@ MicAbstractLaTexWriterTest >> newLine: aNewLine [ { #category : 'tests - formats' } MicAbstractLaTexWriterTest >> parse: aString andCheckWeGet: aResultingString [ - | mic | + | mic c | mic := parser parse: aString. writer visit: mic. - self assert: writer contents equals: aResultingString + c := writer contents. + self assert: c equals: aResultingString. + ^ c ] { #category : 'tests - formats' } diff --git a/src/Microdown-LaTeXExporter/MicDocumentWriter.class.st b/src/Microdown-LaTeXExporter/MicDocumentWriter.class.st index e81d7d80..1a8ac12c 100644 --- a/src/Microdown-LaTeXExporter/MicDocumentWriter.class.st +++ b/src/Microdown-LaTeXExporter/MicDocumentWriter.class.st @@ -70,7 +70,19 @@ MicDocumentWriter >> visit: aMicElement [ { #category : 'writing' } MicDocumentWriter >> write: aMicElement [ - "for now for integration with Pillar." + "Pillar API. + Notice that Pillar is doing the resolution of paths before calling write: + + So there is no need to define write: to call such explicit phase + as includeFilesAndVisit: does it + + includeFilesAndVisit: ast + MicFileIncluder new expandAllInputOf: ast. + self visit: ast. + ^ self contents + + " + self visit: aMicElement. ^ self contents ] diff --git a/src/Microdown-LaTeXExporter/MicLaTeXWriter.class.st b/src/Microdown-LaTeXExporter/MicLaTeXWriter.class.st index a124a611..c953b602 100644 --- a/src/Microdown-LaTeXExporter/MicLaTeXWriter.class.st +++ b/src/Microdown-LaTeXExporter/MicLaTeXWriter.class.st @@ -85,6 +85,17 @@ MicLaTeXWriter >> getStringForAll: aCollection [ ^ visitor contents ] +{ #category : 'public api' } +MicLaTeXWriter >> includeFilesAndVisit: ast [ + "Includes all the input file and convert to LaTeX the resulting document. + Note that to be correctly included the file includer requires ast to know their fromFile. + Please use parseFile: to correctly set that information or set it manually." + + MicFileIncluder new expandAllInputOf: ast. + self visit: ast. + ^ self contents +] + { #category : 'visiting-document' } MicLaTeXWriter >> includeGraphicsFor: aFigure [ diff --git a/src/Microdown-Pharo-Tools/MicElement.extension.st b/src/Microdown-Pharo-Tools/MicElement.extension.st index 14a67581..1445312a 100644 --- a/src/Microdown-Pharo-Tools/MicElement.extension.st +++ b/src/Microdown-Pharo-Tools/MicElement.extension.st @@ -14,3 +14,18 @@ Yes microdown is cool') inspect String streamContents: [ :stream | each displayStringOn: stream ] ]; yourself ] + +{ #category : '*Microdown-Pharo-Tools' } +MicElement >> inspectionMicTree: aBuilder [ + " + (MicroDownParser parse: '# hello +Yes microdown is cool') inspect + " + + ^ aBuilder newTree + roots: { self }; + children: [ :aNode | aNode children ]; + display: [ :each | + String streamContents: [ :stream | each displayStringOn: stream ] ]; + yourself +] diff --git a/src/Microdown-Pillar/MicMicrodownObjectToPillarObjectConverter.class.st b/src/Microdown-Pillar/MicMicrodownObjectToPillarObjectConverter.class.st index 4e40de00..0b669cce 100644 --- a/src/Microdown-Pillar/MicMicrodownObjectToPillarObjectConverter.class.st +++ b/src/Microdown-Pillar/MicMicrodownObjectToPillarObjectConverter.class.st @@ -46,7 +46,10 @@ MicMicrodownObjectToPillarObjectConverter >> visitAnchor: aMicAnchorBlock [ { #category : 'visiting inline' } MicMicrodownObjectToPillarObjectConverter >> visitAnchorReference: aMicAnchorReference [ - ^ PRInternalLink new anchor: aMicAnchorReference substring; yourself + + ^ PRInternalLink new + anchor: aMicAnchorReference bodyString; + yourself ] { #category : 'visiting' } @@ -234,8 +237,10 @@ MicMicrodownObjectToPillarObjectConverter >> visitQuote: aMicQuoteBlock [ { #category : 'visiting inline' } MicMicrodownObjectToPillarObjectConverter >> visitRaw: aMicRaw [ - ^ PRRaw new text: aMicRaw substring ; yourself - + + ^ PRRaw new + text: aMicRaw bodyString; + yourself ] { #category : 'visiting' } diff --git a/src/Microdown-PrettyPrinter-Tests/MicDumperTest.class.st b/src/Microdown-PrettyPrinter-Tests/MicDumperTest.class.st index 9585badb..30aa05a4 100644 --- a/src/Microdown-PrettyPrinter-Tests/MicDumperTest.class.st +++ b/src/Microdown-PrettyPrinter-Tests/MicDumperTest.class.st @@ -13,10 +13,12 @@ Class { { #category : 'tests - section' } MicDumperTest >> parse: aString andCheckWeGet: anExpectedString [ - | mic | + | mic c | mic := parser parse: aString. visitor visit: mic children first. - self assert: visitor contents equals: anExpectedString + c := visitor contents. + self assert: c equals: anExpectedString. + ^ c ] { #category : 'running' } diff --git a/src/Microdown-RichTextComposer-Tests/MicRichTextTableTest.class.st b/src/Microdown-RichTextComposer-Tests/MicRichTextTableTest.class.st new file mode 100644 index 00000000..40ab3ef1 --- /dev/null +++ b/src/Microdown-RichTextComposer-Tests/MicRichTextTableTest.class.st @@ -0,0 +1,74 @@ +" +A MicRichTextTableTest is a test class for testing the behavior of MicRichTextTable +" +Class { + #name : 'MicRichTextTableTest', + #superclass : 'TestCase', + #instVars : [ + 'tableBlock', + 'header', + 'rowShort', + 'row3' + ], + #category : 'Microdown-RichTextComposer-Tests-Table-Support', + #package : 'Microdown-RichTextComposer-Tests', + #tag : 'Table-Support' +} + +{ #category : 'running' } +MicRichTextTableTest >> setUp [ + + super setUp. + + tableBlock := MicTableBlock new. + + header := { 'Header' asText . 'with' asText . '3 columns' asText }. + rowShort := OrderedCollection withAll: { 'Row' asText . 'with 2 columns' asText }. + row3 := { 'Row' asText . 'with' asText . '3 columns' asText }. + +] + +{ #category : 'tests' } +MicRichTextTableTest >> testRowWith2Columns [ + "if one row is shorter (less columns) than the header, add columns to it" + | table | + + table := MicRichTextTable headers: header rows: { rowShort }. + + self assert: table columns size equals: 3. + self assert: table container exposedRows anyOne submorphs size equals: 3 +] + +{ #category : 'tests' } +MicRichTextTableTest >> testRowWith3Columns [ + + | table | + + table := MicRichTextTable headers: header rows: { row3 }. + + self assert: table columns size equals: 3 +] + +{ #category : 'tests' } +MicRichTextTableTest >> testTableHeader [ + + | table | + + table := MicRichTextTable headers: header rows: { row3 }. + + self assert: table columns size equals: 3. + + table columns do: [ :aFTColumn | + self assert: aFTColumn id isNotNil + ] +] + +{ #category : 'tests' } +MicRichTextTableTest >> testTableRows [ + + | table | + + table := MicRichTextTable headers: header rows: { row3 . row3 }. + + self assert: table container exposedRows size equals: 2 +] diff --git a/src/Microdown-RichTextComposer/MicRichTextTable.class.st b/src/Microdown-RichTextComposer/MicRichTextTable.class.st index 146418f1..f911dad8 100644 --- a/src/Microdown-RichTextComposer/MicRichTextTable.class.st +++ b/src/Microdown-RichTextComposer/MicRichTextTable.class.st @@ -23,7 +23,10 @@ MicRichTextTable >> addHeaders: headers with: renderedRows [ totalHeight := 0. 1 to: headers size do:[ :colIndex | |header colRows colWidth colHeight| header := headers at: colIndex. - colRows := renderedRows collect: [ :row | row at: colIndex ]. + colRows := renderedRows collect: [ :row | + (row size >= colIndex) + ifFalse: [ row add: '' asText ]. + row at: colIndex ]. colWidth := (header asTextMorph width) max: (colRows collect: [:cell| cell asTextMorph width]) max. totalWidth := totalWidth + colWidth. diff --git a/src/Microdown-RichTextComposer/MicSemanticAction.class.st b/src/Microdown-RichTextComposer/MicSemanticAction.class.st index bf45f065..5168cbfa 100644 --- a/src/Microdown-RichTextComposer/MicSemanticAction.class.st +++ b/src/Microdown-RichTextComposer/MicSemanticAction.class.st @@ -59,7 +59,7 @@ MicSemanticAction >> computeEntity [ "either 'Point' for a class or #'''System-Caching''' for a package" size = 1 ifTrue: [ self getClassOrNil - ifNil: [self getPackageOrNil ]. + ifNil: [self getPackageOrNil ifNil: [ self getTagOrNil ] ]. ^ self ]. "only 'Point class'" @@ -140,6 +140,21 @@ MicSemanticAction >> getPackageOrNil [ ] +{ #category : 'instance creation' } +MicSemanticAction >> getTagOrNil [ + + | tagName | + tagName := tokens first asSymbol. + self class packageOrganizer packages do: [ :package | + (tagName beginsWith: package name) ifTrue: [ + package tags do: [ :tag | + package name , '-' , tag name = tagName ifTrue: [ + entity := tag. + ^ entity ] ] ] ]. + entity := nil. + ^ entity +] + { #category : 'testing' } MicSemanticAction >> hasEntity [ diff --git a/src/Microdown-Templated/MicAbstractOutputDocumentMaker.class.st b/src/Microdown-Templated/MicAbstractOutputDocumentMaker.class.st index 4c425384..cf8d0a63 100644 --- a/src/Microdown-Templated/MicAbstractOutputDocumentMaker.class.st +++ b/src/Microdown-Templated/MicAbstractOutputDocumentMaker.class.st @@ -29,10 +29,16 @@ MicAbstractOutputDocumentMaker >> basicWriter [ ^ self subclassResponsibility ] +{ #category : 'accessing' } +MicAbstractOutputDocumentMaker >> pathString [ + + ^ Path * '_support' / 'templates' +] + { #category : 'accessing' } MicAbstractOutputDocumentMaker >> templateDirectory [ - ^ self baseDirectory / '_support' / 'templates' / self writer folderName + ^ self baseDirectory / self writer folderName ] { #category : 'accessing' } diff --git a/src/Microdown-Templated/MicLaTeXMaker.class.st b/src/Microdown-Templated/MicLaTeXMaker.class.st deleted file mode 100644 index ea0f790b..00000000 --- a/src/Microdown-Templated/MicLaTeXMaker.class.st +++ /dev/null @@ -1,18 +0,0 @@ -Class { - #name : 'MicLaTeXMaker', - #superclass : 'MicAbstractOutputDocumentMaker', - #category : 'Microdown-Templated', - #package : 'Microdown-Templated' -} - -{ #category : 'accessing' } -MicLaTeXMaker >> basicWriter [ - - ^ MicLaTeXWriter new -] - -{ #category : 'accessing' } -MicLaTeXMaker >> extension [ - - ^ 'tex' -] diff --git a/src/Microdown-Templated/MicTemplatedWriter.class.st b/src/Microdown-Templated/MicTemplatedWriter.class.st index 7ae2fcad..61e63b13 100644 --- a/src/Microdown-Templated/MicTemplatedWriter.class.st +++ b/src/Microdown-Templated/MicTemplatedWriter.class.st @@ -1,9 +1,9 @@ " -I am a pillar document writer that wraps a normal wrapper. +I am document writer that wraps a default writer. When writing one element, I first check if there is a file in the current template that overrides the default writing. If so, I use that file to template the contents. -Otherwise I simply delegate the writing to the wrapped one. +Otherwise I simply delegate the writing to the default one. -I am carefully designed so if an element X is delegated to the wrapped writer, it should delegate the writing of X's children back to myself. +I am carefully designed so if an element X is delegated to the default writer, it should delegate the writing of X's children back to myself. " Class { #name : 'MicTemplatedWriter', @@ -31,7 +31,7 @@ MicTemplatedWriter class >> boldTemplateFileName [ { #category : 'templates' } MicTemplatedWriter class >> codeBlockTemplateFileName [ - + ^ 'codeBlock.mustache' ] @@ -41,12 +41,6 @@ MicTemplatedWriter class >> commentedLineTemplateFileName [ ^ 'commentedLine.mustache' ] -{ #category : 'templates' } -MicTemplatedWriter class >> dataItemTemplateFileName [ - - ^ 'dataItem.mustache' -] - { #category : 'templates' } MicTemplatedWriter class >> defaultAnnotatedParagraphTemplateFileName [ @@ -84,9 +78,9 @@ MicTemplatedWriter class >> headerTemplateFileName [ ] { #category : 'templates' } -MicTemplatedWriter class >> horizontalRuleTemplateFileName [ +MicTemplatedWriter class >> horizontalLineTemplateFileName [ - ^ 'horizontalRule.mustache' + ^ 'horizontalLine.mustache' ] { #category : 'templates' } @@ -197,12 +191,6 @@ MicTemplatedWriter >> currentEnvironmentPath [ ^ RelativePath withAll: (environmentStack collect: [:each | each name]) reversed ] -{ #category : 'accessing - templates' } -MicTemplatedWriter >> dataItemTemplateFileName [ - - ^ self class dataItemTemplateFileName -] - { #category : 'accessing - templates' } MicTemplatedWriter >> defaultAnnotatedParagraphTemplateFileName [ @@ -261,9 +249,9 @@ MicTemplatedWriter >> headerTemplateFileName [ ] { #category : 'accessing - templates' } -MicTemplatedWriter >> horizontalRuleTemplateFileName [ +MicTemplatedWriter >> horizontalLineTemplateFileName [ - ^ self class horizontalRuleTemplateFileName + ^ self class horizontalLineTemplateFileName ] { #category : 'initialization' } @@ -367,7 +355,7 @@ MicTemplatedWriter >> unorderedListTemplateFileName [ ^ self class unorderedListTemplateFileName ] -{ #category : 'visiting' } +{ #category : 'old visiting' } MicTemplatedWriter >> visitAnchor: aPRAnchor [ self @@ -377,7 +365,7 @@ MicTemplatedWriter >> visitAnchor: aPRAnchor [ ifAbsent: [ defaultWriter visitAnchor: aPRAnchor ] ] -{ #category : 'visiting' } +{ #category : 'old visiting' } MicTemplatedWriter >> visitAnnotatedParagraph: anAnnotatedParagraph [ | arguments | @@ -395,7 +383,7 @@ MicTemplatedWriter >> visitAnnotatedParagraph: anAnnotatedParagraph [ ] { #category : 'visiting' } -MicTemplatedWriter >> visitBoldFormat: aPRBoldFormat [ +MicTemplatedWriter >> visitBold: aPRBoldFormat [ self write: aPRBoldFormat @@ -404,16 +392,16 @@ MicTemplatedWriter >> visitBoldFormat: aPRBoldFormat [ ] { #category : 'visiting' } -MicTemplatedWriter >> visitCodeblock: aPRCodeblock [ - +MicTemplatedWriter >> visitCode: aCodeBlock [ + self - writeRawText: aPRCodeblock text + writeRawText: aCodeBlock body withTemplateFileName: self codeBlockTemplateFileName - extraArguments: { 'language' -> (defaultWriter languageForScript: aPRCodeblock) } - ifAbsent: [ defaultWriter visitCodeblock: aPRCodeblock ] + extraArguments: { 'language' -> defaultWriter class name } + ifAbsent: [ defaultWriter visitCode: aCodeBlock ] ] -{ #category : 'visiting' } +{ #category : 'old visiting' } MicTemplatedWriter >> visitCommentedLine: aPRText [ self @@ -422,16 +410,7 @@ MicTemplatedWriter >> visitCommentedLine: aPRText [ ifAbsent: [ defaultWriter visitCommentedLine: aPRText ] ] -{ #category : 'visiting' } -MicTemplatedWriter >> visitDataItem: aPRListItem [ - - self - write: aPRListItem - withTemplateFileName: self dataItemTemplateFileName - ifAbsent: [ defaultWriter visitDataItem: aPRListItem ] -] - -{ #category : 'visiting' } +{ #category : 'old visiting' } MicTemplatedWriter >> visitDefinitionList: aPRList [ self @@ -440,7 +419,7 @@ MicTemplatedWriter >> visitDefinitionList: aPRList [ ifAbsent: [ defaultWriter visitDefinitionList: aPRList ] ] -{ #category : 'visiting' } +{ #category : 'old visiting' } MicTemplatedWriter >> visitEmptyParagraph: anEmptyParagraph [ self @@ -449,7 +428,7 @@ MicTemplatedWriter >> visitEmptyParagraph: anEmptyParagraph [ ifAbsent: [ defaultWriter visitEmptyParagraph: anEmptyParagraph ] ] -{ #category : 'visiting' } +{ #category : 'old visiting' } MicTemplatedWriter >> visitEnvironment: anEnvironment [ self pushEnvironment: anEnvironment. @@ -461,16 +440,6 @@ MicTemplatedWriter >> visitEnvironment: anEnvironment [ self popEnvironment. ] -{ #category : 'visiting' } -MicTemplatedWriter >> visitExternalLink: aPRExternalLink [ - - self - write: aPRExternalLink - withTemplateFileName: self externalLinkTemplateFileName - extraArguments: { 'reference' -> aPRExternalLink reference } - ifAbsent: [ defaultWriter visitExternalLink: aPRExternalLink ] -] - { #category : 'visiting' } MicTemplatedWriter >> visitFigure: aFigure [ @@ -493,7 +462,16 @@ MicTemplatedWriter >> visitHeader: aHeader [ ifAbsent: [ defaultWriter visitHeader: aHeader ] ] -{ #category : 'visiting' } +{ #category : 'old visiting' } +MicTemplatedWriter >> visitHorizontalLine: aPRHorizontalRule [ + + self + writeRawText: '' + withTemplateFileName: self horizontalLineTemplateFileName + ifAbsent: [ defaultWriter visitHorizontalRule: aPRHorizontalRule ] +] + +{ #category : 'old visiting' } MicTemplatedWriter >> visitHorizontalRule: aPRHorizontalRule [ self @@ -503,16 +481,15 @@ MicTemplatedWriter >> visitHorizontalRule: aPRHorizontalRule [ ] { #category : 'visiting' } -MicTemplatedWriter >> visitInternalLink: aPRInternalLink [ - +MicTemplatedWriter >> visitItalic: aPRItalicFormat [ + self - write: aPRInternalLink - withTemplateFileName: self internalLinkTemplateFileName - extraArguments: { 'reference' -> aPRInternalLink reference } - ifAbsent: [ defaultWriter visitInternalLink: aPRInternalLink ] + write: aPRItalicFormat + withTemplateFileName: self italicTemplateFileName + ifAbsent: [ defaultWriter visitItalicFormat: aPRItalicFormat ] ] -{ #category : 'visiting' } +{ #category : 'old visiting' } MicTemplatedWriter >> visitItalicFormat: aPRItalicFormat [ self @@ -521,7 +498,7 @@ MicTemplatedWriter >> visitItalicFormat: aPRItalicFormat [ ifAbsent: [ defaultWriter visitItalicFormat: aPRItalicFormat ] ] -{ #category : 'visiting' } +{ #category : 'old visiting' } MicTemplatedWriter >> visitLineBreak: aPRLineBreak [ self @@ -530,7 +507,7 @@ MicTemplatedWriter >> visitLineBreak: aPRLineBreak [ ifAbsent: [ defaultWriter visitLineBreak: aPRLineBreak ] ] -{ #category : 'visiting' } +{ #category : 'old visiting' } MicTemplatedWriter >> visitListItem: aPRListItem [ self @@ -539,7 +516,7 @@ MicTemplatedWriter >> visitListItem: aPRListItem [ ifAbsent: [ defaultWriter visitListItem: aPRListItem ] ] -{ #category : 'visiting' } +{ #category : 'old visiting' } MicTemplatedWriter >> visitMailLink: aPRMailLink [ self @@ -549,16 +526,16 @@ MicTemplatedWriter >> visitMailLink: aPRMailLink [ ifAbsent: [ defaultWriter visitExternalLink: aPRMailLink ] ] -{ #category : 'visiting' } -MicTemplatedWriter >> visitMonospaceFormat: aPRMonospaceFormat [ +{ #category : 'old visiting' } +MicTemplatedWriter >> visitMonospace: aPRMonospaceFormat [ self write: aPRMonospaceFormat withTemplateFileName: self monospaceTemplateFileName - ifAbsent: [ defaultWriter visitMonospaceFormat: aPRMonospaceFormat ] + ifAbsent: [ defaultWriter visitMonospace: aPRMonospaceFormat ] ] -{ #category : 'visiting' } +{ #category : 'old visiting' } MicTemplatedWriter >> visitOrderedList: aPROrderedList [ self @@ -567,7 +544,7 @@ MicTemplatedWriter >> visitOrderedList: aPROrderedList [ ifAbsent: [ defaultWriter visitOrderedList: aPROrderedList ] ] -{ #category : 'visiting' } +{ #category : 'old visiting' } MicTemplatedWriter >> visitParagraph: aParagraph [ self @@ -576,7 +553,7 @@ MicTemplatedWriter >> visitParagraph: aParagraph [ ifAbsent: [ defaultWriter visitParagraph: aParagraph ] ] -{ #category : 'visiting' } +{ #category : 'old visiting' } MicTemplatedWriter >> visitPreformatted: aPRPreformatted [ self @@ -591,7 +568,7 @@ MicTemplatedWriter >> visitRaw: aPRRaw [ defaultWriter visitRaw: aPRRaw ] -{ #category : 'visiting' } +{ #category : 'old visiting' } MicTemplatedWriter >> visitSection: aPRSection [ self @@ -606,7 +583,7 @@ MicTemplatedWriter >> visitText: aPRText [ defaultWriter visitText: aPRText ] -{ #category : 'visiting' } +{ #category : 'old visiting' } MicTemplatedWriter >> visitUnorderedList: aPRUnorderedList [ self @@ -662,7 +639,7 @@ MicTemplatedWriter >> writeRawText: aText withTemplateFileName: templateFileName templateFile := outputDocument templateDirectory resolve: foundPath / templateFileName. result := templateFile asMustacheTemplate value: ({ 'contents' -> aText value }, arguments) asDictionary. - self visitRaw: (PRRaw content: result type: defaultWriter writerName) + self visitText: (MicTextBlock new bodyString: result) ] { #category : 'writing' } diff --git a/src/Microdown-Templated/MicTemplatedWriterTest.class.st b/src/Microdown-Templated/MicTemplatedWriterTest.class.st index e59deb97..3e975533 100644 --- a/src/Microdown-Templated/MicTemplatedWriterTest.class.st +++ b/src/Microdown-Templated/MicTemplatedWriterTest.class.st @@ -2,12 +2,19 @@ Class { #name : 'MicTemplatedWriterTest', #superclass : 'TestCase', #instVars : [ - 'textDocument' + 'textDocument', + 'fileSystem' ], #category : 'Microdown-Templated', #package : 'Microdown-Templated' } +{ #category : 'running' } +MicTemplatedWriterTest >> addTemplateFiles [ + + fileSystem / 'codeBlock.mustache' writeStreamDo: [ :s | s << self codeBlockContents ]. +] + { #category : 'helpers' } MicTemplatedWriterTest >> assertTemplate: template writesValue: value forNode: node [ @@ -28,16 +35,26 @@ MicTemplatedWriterTest >> assertWritingNode: node writes: contents [ document := MicRootBlock new addChild: node; yourself. - result := textDocument writer write: document. self assert: result equals: contents ] +{ #category : 'running' } +MicTemplatedWriterTest >> codeBlockContents [ + + ^ ' + +{{{contents}}} + +' +] + { #category : 'helpers' } MicTemplatedWriterTest >> createTemplateFileAt: aPath withContents: contents [ | templateFileReference | + templateFileReference := textDocument templateDirectory resolve: aPath. templateFileReference parent ensureCreateDirectory. templateFileReference writeStreamDo: [ :stream | stream nextPutAll: contents ]. @@ -47,18 +64,22 @@ MicTemplatedWriterTest >> createTemplateFileAt: aPath withContents: contents [ MicTemplatedWriterTest >> setUp [ super setUp. + fileSystem := FileSystem memory. textDocument := MicTextDocumentMaker new - baseDirectory: FileSystem memory; + baseDirectory: fileSystem; yourself. + self addTemplateFiles. ] -{ #category : 'tests-templatefiles' } -MicTemplatedWriterTest >> testWriteAnchorUsesAnchorTemplate [ - - self - assertTemplate: 'todo.mustache' - writesValue: 'annotated paragraph' - forNode: (PRAnnotatedParagraph withAll: #() annotation: 'todo') +{ #category : 'tests-setup' } +MicTemplatedWriterTest >> testDirectory [ + + self flag: #comeBack. + "it sucks but I'm always lost in file API" + self + assert: textDocument templateDirectory printString + equals: 'memory:///mic'. + self assert: (fileSystem / 'codeBlock.mustache') exists ] { #category : 'tests-templatefiles' } @@ -85,8 +106,11 @@ MicTemplatedWriterTest >> testWriteCodeBlockUsesCodeBlockTemplate [ self assertTemplate: MicTemplatedWriter codeBlockTemplateFileName - writesValue: 'codeBlockTemplate' - forNode: (PRCodeblock content: '^ self') + writesValue: ' + +^ self +' + forNode: (MicCodeBlock new body: '^ self'; yourself) ] { #category : 'tests-templatefiles' } @@ -98,24 +122,6 @@ MicTemplatedWriterTest >> testWriteCommentedLineUsesCommentedLineTemplate [ forNode: (PRCommentedLine content: 'some comment') ] -{ #category : 'tests-templatefiles' } -MicTemplatedWriterTest >> testWriteDataItemUsesDataItemTemplate [ - - self - assertTemplate: MicTemplatedWriter dataItemTemplateFileName - writesValue: 'dataitem' - forNode: PRDataItem new -] - -{ #category : 'tests-templatefiles' } -MicTemplatedWriterTest >> testWriteDefinitionListUsesDefinitionListTemplate [ - - self - assertTemplate: MicTemplatedWriter definitionListTemplateFileName - writesValue: 'definitionList' - forNode: PRDefinitionList new -] - { #category : 'tests-templatefiles' } MicTemplatedWriterTest >> testWriteEmptyParagraphsUsesEmptyParagraphTemplate [ @@ -167,7 +173,7 @@ MicTemplatedWriterTest >> testWriteFigureUsesFigureTemplate [ self assertTemplate: MicTemplatedWriter figureTemplateFileName writesValue: 'figure' - forNode: (PRFigure reference: 'bla.png') + forNode: (MicFigureBlock new reference: 'bla.png') ] { #category : 'tests-templatefiles' } @@ -176,18 +182,18 @@ MicTemplatedWriterTest >> testWriteHeaderUsesHeaderTemplate [ self assertTemplate: MicTemplatedWriter headerTemplateFileName writesValue: 'aHeader' - forNode: (PRHeader new + forNode: (MicHeaderBlock new level: 2; - add: (PRText content: 'foo')) + add: (MicTextBlock new bodyString: 'foo'; yourself)) ] { #category : 'tests-templatefiles' } MicTemplatedWriterTest >> testWriteHorizontalRuleUsesHorizontalRuleTemplate [ self - assertTemplate: MicTemplatedWriter horizontalRuleTemplateFileName + assertTemplate: MicTemplatedWriter horizontalLineTemplateFileName writesValue: '-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=' - forNode: PRHorizontalRule new + forNode: MicHorizontalLineBlock new ] { #category : 'tests-templatefiles' } @@ -205,16 +211,9 @@ MicTemplatedWriterTest >> testWriteItalicUsesItalicTemplate [ self assertTemplate: MicTemplatedWriter italicTemplateFileName writesValue: 'italicTemplate' - forNode: (PRItalicFormat with: (PRText content: 'Bar')) -] - -{ #category : 'tests-templatefiles' } -MicTemplatedWriterTest >> testWriteLineBreakUsesLineBreakTemplate [ - - self - assertTemplate: MicTemplatedWriter lineBreakTemplateFileName - writesValue: 'line break' - forNode: PRLineBreak new + forNode: (MicItalicFormatBlock new + children: { (MicTextBlock new bodyString: 'Bar') }; + yourself ) ] { #category : 'tests-templatefiles' } @@ -223,7 +222,7 @@ MicTemplatedWriterTest >> testWriteListItemUsesListItemTemplate [ self assertTemplate: MicTemplatedWriter listItemTemplateFileName writesValue: 'list item' - forNode: PRListItem new + forNode: MicListItemBlock new ] { #category : 'tests-templatefiles' } @@ -241,7 +240,7 @@ MicTemplatedWriterTest >> testWriteMonospaceUsesMonospaceTemplate [ self assertTemplate: MicTemplatedWriter monospaceTemplateFileName writesValue: 'monospace' - forNode: (PRMonospaceFormat with: (PRText content: 'Bar')) + forNode: (MicMonospaceFormatBlock new bodyString: 'Bar') ] { #category : 'tests-templatefiles' } @@ -283,7 +282,7 @@ MicTemplatedWriterTest >> testWriteOrderedListUsesOrderedListTemplate [ self assertTemplate: MicTemplatedWriter orderedListTemplateFileName writesValue: 'ordered list' - forNode: PROrderedList new + forNode: MicOrderedListBlock new ] { #category : 'tests-templatefiles' } @@ -304,15 +303,6 @@ MicTemplatedWriterTest >> testWritePreformattedUsesPreformattedTemplate [ forNode: (PRPreformatted with: (PRText content: 'Bar')) ] -{ #category : 'tests-templatefiles' } -MicTemplatedWriterTest >> testWriteSectionUsesSectionTemplate [ - - self - assertTemplate: MicTemplatedWriter sectionTemplateFileName - writesValue: 'section' - forNode: PRSection new -] - { #category : 'tests-templatefiles' } MicTemplatedWriterTest >> testWriteTextInsideEnvironmentLooksUpOutsideEnvironment [ @@ -332,9 +322,9 @@ MicTemplatedWriterTest >> testWriteTextInsideEnvironmentUsesTemplateInsideEnviro self assertTemplatePath: (Path * 'card' / 'paragraph.mustache') writesValue: 'Paragraph in card' - forNode: ((PREnvironment named: 'card') - add: (PRParagraph new - add: (PRText content: 'Foo'); + forNode: ((MicEnvironmentBlock named: 'card') + add: (MicParagraphBlock new + add: (MicTextBlock content: 'Foo'); yourself); yourself) ] diff --git a/src/Microdown-Tests/MicEnvironmentBlockTest.class.st b/src/Microdown-Tests/MicEnvironmentBlockTest.class.st index b1058982..92ab58d7 100644 --- a/src/Microdown-Tests/MicEnvironmentBlockTest.class.st +++ b/src/Microdown-Tests/MicEnvironmentBlockTest.class.st @@ -294,6 +294,57 @@ environment, else we force writer to enter a new line to declare the end of the paragraph.'. ] +{ #category : 'tests' } +MicEnvironmentBlockTest >> testEnvironmentWithSameNestedElementAsParent [ + "' +?> +'" + + | source root env environmentName | + environmentName := 'slide'. + source := EnvironmentOpeningBlockMarkup , environmentName , String cr + , EnvironmentOpeningBlockMarkup , environmentName + , String cr , EnvironmentClosingBlockMarkup , String cr + , EnvironmentClosingBlockMarkup , String cr. + root := parser parse: source. + + self assert: root children size equals: 1. + env := root children first. + self assert: (env isKindOf: MicSlideBlock). + + self assert: env children first class equals: MicSlideBlock +] + +{ #category : 'tests' } +MicEnvironmentBlockTest >> testEnvironmentWithSameNestedElementAsParentWithBody [ + "' +?> +'" + + | source root env environmentName | + environmentName := 'slide'. + source := EnvironmentOpeningBlockMarkup , environmentName , String cr, +'- item 1 +- item 2 + +' + , EnvironmentOpeningBlockMarkup , environmentName + , String cr , '## Here is a slide', String cr, EnvironmentClosingBlockMarkup , String cr + , EnvironmentClosingBlockMarkup , String cr. + root := parser parse: source. + + self assert: root children size equals: 1. + env := root children first. + self assert: (env isKindOf: MicSlideBlock). + + self assert: env children first class equals: MicUnorderedListBlock. + self assert: env children second class equals: MicSlideBlock. +] + { #category : 'tests - extensions' } MicEnvironmentBlockTest >> testExtensionClassWithSpaceAndArgIsCreated [ diff --git a/src/Microdown-Tests/MicFigureBlockTest.class.st b/src/Microdown-Tests/MicFigureBlockTest.class.st index 38b70d13..dbd8ca7d 100644 --- a/src/Microdown-Tests/MicFigureBlockTest.class.st +++ b/src/Microdown-Tests/MicFigureBlockTest.class.st @@ -145,6 +145,14 @@ MicFigureBlockTest >> testFigureCaptionIsReifiedWithNewFormat [ self assert: (fig arguments at: #width) equals: '666' ] +{ #category : 'tests' } +MicFigureBlockTest >> testFigureNoCaption [ + + | figure | + figure := MicFigureBlock new reference: 'bla.png'. + self shouldnt: [ figure printString ] raise: Error +] + { #category : 'tests' } MicFigureBlockTest >> testHasArguments [ | figure | diff --git a/src/Microdown-Tests/MicMetaDataBlockTest.class.st b/src/Microdown-Tests/MicMetaDataBlockTest.class.st index 1fff52a8..2244e4cc 100644 --- a/src/Microdown-Tests/MicMetaDataBlockTest.class.st +++ b/src/Microdown-Tests/MicMetaDataBlockTest.class.st @@ -40,6 +40,21 @@ MicMetaDataBlockTest >> testAtKeyPut [ self assert: (metadata atKey: 'title') equals: 'Pilote'. ] +{ #category : 'tests - parsing' } +MicMetaDataBlockTest >> testAtNoKey [ + + | source root metadata | + source := '{ }'. + root := parser parse: source. + metadata := root children first. + self assert: metadata body size equals: 0. + source := '{ + }'. + root := parser parse: source. + metadata := root children first. + self assert: metadata body size equals: 0. +] + { #category : 'tests' } MicMetaDataBlockTest >> testCorrectJSONMetaDataProducesDictionary [ diff --git a/src/Microdown-Tests/MicMicrodownSnippetFactory.class.st b/src/Microdown-Tests/MicMicrodownSnippetFactory.class.st index 17898013..6c81e734 100644 --- a/src/Microdown-Tests/MicMicrodownSnippetFactory.class.st +++ b/src/Microdown-Tests/MicMicrodownSnippetFactory.class.st @@ -858,6 +858,16 @@ a{{Foo}}b ' ] +{ #category : 'rawParagraph' } +MicMicrodownSnippetFactory >> rawParagraphSimpleDiv [ + + ^ '
+some text +and +more +
' +] + { #category : 'figures' } MicMicrodownSnippetFactory >> realLinkSample [ ^ ' diff --git a/src/Microdown-Tests/MicParagraphBlockTest.class.st b/src/Microdown-Tests/MicParagraphBlockTest.class.st index 8aeac048..143018bb 100644 --- a/src/Microdown-Tests/MicParagraphBlockTest.class.st +++ b/src/Microdown-Tests/MicParagraphBlockTest.class.st @@ -30,6 +30,18 @@ a paragraph on two lines**'. ] +{ #category : 'tests' } +MicParagraphBlockTest >> testASimpleRawParagaaph [ + + | mic | + mic := (parser parse: ' +No idea what it is :) +') children first. + self assert: mic class equals: MicRawParagraphBlock. + self assert: mic label equals: 'title'. + +] + { #category : 'tests' } MicParagraphBlockTest >> testBoldMultipleLinesWithNewLine [ diff --git a/src/Microdown-Tests/MicParserTest.class.st b/src/Microdown-Tests/MicParserTest.class.st index 4c7078cc..4f566b2b 100644 --- a/src/Microdown-Tests/MicParserTest.class.st +++ b/src/Microdown-Tests/MicParserTest.class.st @@ -19,6 +19,40 @@ MicParserTest >> setUp [ parser := MicrodownParser new. ] +{ #category : 'tests' } +MicParserTest >> test [ + + | source root | + source := ' +{ +"title" : "About Pharo", +"layout" : "index", +"publishDate" : "2025-06-01" +} + +# Pharo + +[Pharo](http://www.pharo.org) is a beautiful dynamically-typed reflective pure object-oriented language that we have been developing since 2008. +It is inspired by Smalltalk (I''m extremely grateful to Alan Kay and Dan Ingalls - they were so visionary and right). Now our vision for Pharo is to reinvent Smalltalk and produce a better system. +From that perspective, I''m used to say that Pharo is what we have and not what we want. +In essence, Pharo is the beginning of the journey and not the final goal. And you can change its future. + + +You can check what companies are saying about it: [Video](https://youtu.be/6tdkKNX2g4s) + + +There are many aspects I would like to see being explored either by us or by others. +If you want to explore some of the following aspects, please go and let us know. +I''m really interested in any topics that evolve Pharo into a better Pharo. + +'. + + root := parser parse: source. + + self assert: root children size equals: 5. + +] + { #category : 'tests' } MicParserTest >> testEmpty [ | source root | diff --git a/src/Microdown-Tests/MicRawBlockTest.class.st b/src/Microdown-Tests/MicRawBlockTest.class.st index caea092d..5dc0aa19 100644 --- a/src/Microdown-Tests/MicRawBlockTest.class.st +++ b/src/Microdown-Tests/MicRawBlockTest.class.st @@ -12,23 +12,34 @@ MicRawBlockTest >> subjectClass [ ] { #category : 'tests' } -MicRawBlockTest >> testASimpleRawParagaaph [ - | mic | - mic := (parser parse: ' -No idea what it is :) -') children first. - self assert: mic class equals: MicRawParagraphBlock. - self assert: mic label equals: 'title'. +MicRawBlockTest >> testRawBeginningOfLine [ + | root | + root := parser parse: '{{ +This is a raw paragraph +On two lines +}}'. + + self + assert: root children first children first class + equals: MicRawBlock. + self + assert: root children first children first bodyString + equals: ' +This is a raw paragraph +On two lines +' ] { #category : 'tests' } -MicRawBlockTest >> testRaw [ +MicRawBlockTest >> testRawDoesNotInterpretContents [ | root | root := parser parse: 'it should be in a paragraph {{_Foo_}}'. self assert: root children first class equals: MicParagraphBlock. self assert: root children first children second class - equals: MicRawBlock + equals: MicRawBlock. + self assert: root children first children second bodyString + equals: '_Foo_' ] diff --git a/src/Microdown-Tests/MicRawParagraphBlockTest.class.st b/src/Microdown-Tests/MicRawParagraphBlockTest.class.st index 6c96af98..815c4054 100644 --- a/src/Microdown-Tests/MicRawParagraphBlockTest.class.st +++ b/src/Microdown-Tests/MicRawParagraphBlockTest.class.st @@ -11,6 +11,24 @@ MicRawParagraphBlockTest >> subjectClass [ ^ MicRawParagraphBlock ] +{ #category : 'tests' } +MicRawParagraphBlockTest >> testASimpleDivWithClass [ + | mic | + mic := (parser parse: '
+ +# Contributing to Pharo + +In a giving mood? There are many ways to get involved! + +
+') children first. + self assert: mic class equals: MicRawParagraphBlock. + self assert: mic label equals: 'div'. + self assert: mic children first class equals: MicHeaderBlock. + self assert: mic children second class equals: MicParagraphBlock + +] + { #category : 'tests' } MicRawParagraphBlockTest >> testASimpleRawParagraph [ | mic | @@ -19,6 +37,7 @@ No idea what it is :) ') children first. self assert: mic class equals: MicRawParagraphBlock. self assert: mic label equals: 'title'. + self assert: mic children first class equals: MicParagraphBlock ] @@ -51,7 +70,21 @@ And after we get a paragraph') children. ] { #category : 'tests' } -MicRawParagraphBlockTest >> testRawParagraphCannotBeNested [ +MicRawParagraphBlockTest >> testParagrapWithP [ + | mic | + mic := (parser parse: ' +

+This is a paragraph started normally with

+

+') children first. + self assert: mic class equals: MicRawParagraphBlock. + self assert: mic label equals: 'p'. + self assert: mic children first class equals: MicParagraphBlock + +] + +{ #category : 'tests' } +MicRawParagraphBlockTest >> testRawParagraphCanBeNested [ | children | children := (parser parse: ' No idea what it is :) @@ -63,7 +96,71 @@ hkhkjhkj self assert: children size equals: 1. self assert: children first class equals: MicRawParagraphBlock. self assert: children first label equals: 'title'. - self assertEmpty: children first children + self assert: children first children size equals: 2. + self assert: children first children first class equals: MicParagraphBlock. + self assert: children first children second label equals: 'button'. + self assert: children first children second class equals: MicRawParagraphBlock. +] + +{ #category : 'tests' } +MicRawParagraphBlockTest >> testRawParagraphForP [ + | children | + children := (parser parse: '<p> +No idea what it is :) +</p>') children. + self assert: children size equals: 1. + self assert: children first class equals: MicRawParagraphBlock. + self assert: children first label equals: 'p'. + +] + +{ #category : 'tests' } +MicRawParagraphBlockTest >> testRawParagraphForPNoSpace [ + | children | + children := (parser parse: '<p>WeDoNotLikeSpace +No idea what it is :) +</p>') children. + self assert: children size equals: 1. + self assert: children first class equals: MicRawParagraphBlock. + self assert: children first label equals: 'p'. + +] + +{ #category : 'tests' } +MicRawParagraphBlockTest >> testRawParagraphForPNoSpace2 [ + | children newLine | + newLine := Character cr asString. + children := (MicrodownParser new parse: '<div style="background-color:#8ebf42">', newLine, +'<p>', newLine, +'We use the <div> tag to group two paragraphs for applying a background to the text, and to add color to this', newLine, +'<span style="color:#1c87c9">', newLine, +'word', newLine, +'</span>', newLine, +'we place it within <span> tag.', +'</p>', newLine, +'<p>', newLine, +'Pay attention, that the <div> tag is a block-level element, so a line break is placed before and after it.', newLine, +'</p>', newLine, +'</div>') children. + self assert: children size equals: 1. + self assert: children first class equals: MicRawParagraphBlock. + self assert: children first label equals: 'div'. + self assert: children first children first class equals: MicRawParagraphBlock. + self assert: children first children first label equals: 'p'. + + +] + +{ #category : 'tests' } +MicRawParagraphBlockTest >> testRawParagraphForPNoSpaceAndAttributes [ + | children | + children := (parser parse: '<p src=78>WeDoNotLikeSpace +No idea what it is :) +</p>') children. + self assert: children size equals: 1. + self assert: children first class equals: MicRawParagraphBlock. + self assert: children first label equals: 'p'. + ] { #category : 'tests' } @@ -74,6 +171,6 @@ MicRawParagraphBlockTest >> testThereIsNoValidationIfThetagStartWithAKnowHtml [ mic := (parser parse: '<titleunkniw> No idea what it is :) </titleunkniw>') children first. - self assert: mic class equals: MicRawParagraphBlock. + self assert: mic class equals: MicParagraphBlock. ] diff --git a/src/Microdown-Tests/MicResourceSettingsTest.class.st b/src/Microdown-Tests/MicResourceSettingsTest.class.st index dc81b863..e73283bf 100644 --- a/src/Microdown-Tests/MicResourceSettingsTest.class.st +++ b/src/Microdown-Tests/MicResourceSettingsTest.class.st @@ -139,15 +139,6 @@ MicResourceSettingsTest >> testIsOfflineTrueNotFound [ self assert: (self cacheAt: self imageUrl asZnUrl ) isNil ] -{ #category : 'tests' } -MicResourceSettingsTest >> testOnlyOneMethodInMicrodownDefinesSettings [ - | all | - all :=(Pragma allNamed: #systemsettings) - collect: [ :pragma | pragma methodClass ]. - all := all select: [ :class | class package name beginsWith: 'Microdown' ]. - self assert: all size equals: 1 -] - { #category : 'tests' } MicResourceSettingsTest >> testThereAreTwoSettings [ "I am an approximation, just making sure the two class variables exist" diff --git a/src/Microdown-Tests/MicRootBlockTest.class.st b/src/Microdown-Tests/MicRootBlockTest.class.st index d11ce66d..d6262d04 100644 --- a/src/Microdown-Tests/MicRootBlockTest.class.st +++ b/src/Microdown-Tests/MicRootBlockTest.class.st @@ -24,6 +24,18 @@ MicRootBlockTest >> testRootCanConsumeLine [ self assert: (rootNode canConsumeLine: '- ') ] +{ #category : 'tests' } +MicRootBlockTest >> testRootDebugInfo [ + + | rootNode first | + MicRootBlock resetDebugId. + first := MicRootBlock nextDebugId. + rootNode := MicRootBlock new. + self assert: rootNode debugId equals: first + 1. + rootNode := MicRootBlock new. + self assert: rootNode debugId equals: first + 2. +] + { #category : 'tests - metadata' } MicRootBlockTest >> testRootDoesNotHaveMetaDataElement [ diff --git a/src/Microdown-Tests/MicTableBlockTest.class.st b/src/Microdown-Tests/MicTableBlockTest.class.st new file mode 100644 index 00000000..9d9f5974 --- /dev/null +++ b/src/Microdown-Tests/MicTableBlockTest.class.st @@ -0,0 +1,50 @@ +Class { + #name : 'MicTableBlockTest', + #superclass : 'MicBlockTest', + #category : 'Microdown-Tests-Parser', + #package : 'Microdown-Tests', + #tag : 'Parser' +} + +{ #category : 'tests' } +MicTableBlockTest >> subjectClass [ + ^ MicTableBlock +] + +{ #category : 'tests' } +MicTableBlockTest >> testExtractLine [ + + | checker | + checker := [ :source | | result | + result := MicTableBlock new extractLine: source. + self assert: result size equals: 3. + self assert: result second equals: 'bbb'. + ]. + checker value: '| aaa | bbb | ccc'. + checker value: '| aaa | bbb | ccc '. + checker value: '| aaa | bbb | ccc |'. + checker value: '| aaa | bbb | ccc | '. +] + +{ #category : 'tests' } +MicTableBlockTest >> testTableNoHeader [ + "A header can only contain --- space and |" + + | source | + source := '| AAA | BBB | CCC '. + self deny: (MicTableBlock new isHeader: source). + source := '| AAA | BBB | CCC |'."Nothing after |" + self deny: (MicTableBlock new isHeader: source). +] + +{ #category : 'tests' } +MicTableBlockTest >> testTableWithHeader [ + + | source | + source := '| --- | --- | ---'. + self assert: (MicTableBlock new isHeader: source). + source := '| --- | --- | --- |'. + self assert: (MicTableBlock new isHeader: source). + source := '| --- | --- | --- | '. + self assert: (MicTableBlock new isHeader: source). +] diff --git a/src/Microdown-Tests/MicrodownTest.class.st b/src/Microdown-Tests/MicrodownTest.class.st index c7e78c0a..a3898587 100644 --- a/src/Microdown-Tests/MicrodownTest.class.st +++ b/src/Microdown-Tests/MicrodownTest.class.st @@ -13,6 +13,45 @@ Class { #tag : 'Core' } +{ #category : 'tests - replace' } +MicrodownTest >> rawMicrodownSyntax [ + + ^ ' +# Microdown is quite cool +@anchor + +Here is some code + +```language=Pharo&caption=Beautiful&anchor=Fig1 + 1000 factorial / 999 factorial +``` + +Here is a figure and a link: [http://pharo.org](http://pharo.org). + +![Pharologo](https://files.pharo.org/media/logo/logo.png size=80&anchor=figLogo) + +See *@figLogo@* + +## Lists + +Here is a list: +- item 1 + 1. sub item 1 + 3. sub item 2 +- item 2 + + +**Bold**, _italic_, `monospace` + +In Pharo, Microdown supports hyperlinks to: +- classes e.g., `Point`, +- methodes e.g., `Point class`, `Point>>#setX:setY:`, and +- packages e.g., `#''Microdown-Tests''` (for packages). + +You can edit this file clicking on `ClySyntaxHelpMorph>>#rawMicrodownSyntax`. +' +] + { #category : 'running' } MicrodownTest >> setUp [ super setUp. @@ -142,3 +181,12 @@ MicrodownTest >> testParentLinkIsKeptOnReplaceBy [ self assert: new parent equals: h. ] + +{ #category : 'tests - replace' } +MicrodownTest >> testText [ + + | doc | + doc := Microdown parse: self rawMicrodownSyntax. + self shouldnt: [ Character space join: (doc children allButFirst collect: [ :each | each text ]) ] raise: MessageNotUnderstood + +] diff --git a/src/Microdown-Transformer/MicFileIncluder.class.st b/src/Microdown-Transformer/MicFileIncluder.class.st index 5c79aaaa..176cc82a 100644 --- a/src/Microdown-Transformer/MicFileIncluder.class.st +++ b/src/Microdown-Transformer/MicFileIncluder.class.st @@ -37,17 +37,47 @@ Class { #package : 'Microdown-Transformer' } -{ #category : 'initialization' } +{ #category : 'accessing' } MicFileIncluder >> beRelaxed [ isStrict := false ] +{ #category : 'validation' } +MicFileIncluder >> checkCyclicIncludeOfFile: aFileReference [ + + aFileReference = topFile ifTrue: [ + MicCyclicFileInclusionError new + files: { topFile }; + signal + ]. + + (inProcessFiles includes: aFileReference) + ifTrue: [ MicCyclicFileInclusionError new + files: (inProcessFiles copyWith: aFileReference); + signal ] +] + { #category : 'configuration' } MicFileIncluder >> doNotTransform [ shouldTransform := false ] +{ #category : 'accessing' } +MicFileIncluder >> expandAllInputOf: ast [ + "The argument should know the file it comes from. Usually using fromFile:, or using the topFile: API. + This is important since we need to resolve the path using such an information." + + | path | + path := ast fromFile = 'fakedFile' + ifTrue: [ path := topFile ] + ifFalse: [path := ast fromFile]. + path ifNil: [ self error: 'base is not set for resolution. Please use either parseFile: or topFile: to specificy a file reference' ]. + path asMicResourceReference resolveDocument: ast. + self visit: ast. + +] + { #category : 'accessing' } MicFileIncluder >> inProcessFiles: aCollection [ inProcessFiles := aCollection @@ -74,23 +104,9 @@ MicFileIncluder >> shouldTransform [ { #category : 'accessing' } MicFileIncluder >> topFile: aFileReference [ - - topFile := aFileReference -] - -{ #category : 'validation' } -MicFileIncluder >> validateInclusionOfFile: aFileReference [ + "You may use this API if the document was not created using parseFile: or that its fromFile is empty." - aFileReference = topFile ifTrue: [ - MicCyclicFileInclusionError new - files: { topFile }; - signal - ]. - - (inProcessFiles includes: aFileReference) - ifTrue: [ MicCyclicFileInclusionError new - files: (inProcessFiles copyWith: aFileReference); - signal ] + topFile := aFileReference ] { #category : 'visiting-document' } @@ -104,6 +120,7 @@ MicFileIncluder >> visitInputFile: anInputFileAnnotation [ do: [ :error | isStrict ifFalse: [ ^ self ] ifTrue: [ error pass ]]. + self replaceCurrentNodeBy: inputDoc children ] diff --git a/src/Microdown/MicAbstractBlock.class.st b/src/Microdown/MicAbstractBlock.class.st index 6a16f865..b2013868 100644 --- a/src/Microdown/MicAbstractBlock.class.st +++ b/src/Microdown/MicAbstractBlock.class.st @@ -186,12 +186,13 @@ MicAbstractBlock >> setParser: aParser [ { #category : 'accessing' } MicAbstractBlock >> text [ + | text | self flag: #todo. "what a terrible idea we concatenate the text of children and store. I could understand that we keep the text of the parser element but then we do not modify it after and certainly not change it." text := ''. - children do: [ :each | text := text , each text ]. + children do: [ :each | text := text , each bodyString ]. ^ text ] diff --git a/src/Microdown/MicAbstractCodeBlock.class.st b/src/Microdown/MicAbstractCodeBlock.class.st index 4313c8a6..29ee48d9 100644 --- a/src/Microdown/MicAbstractCodeBlock.class.st +++ b/src/Microdown/MicAbstractCodeBlock.class.st @@ -11,8 +11,19 @@ Class { { #category : 'public' } MicAbstractCodeBlock class >> alternateBlockClassFor: line [ + "This method is an extension point to be able to declare environment subclasses just specifying a tag. + + For example + + <?Foo|title=Stef?> + and a subclass of MicEnvironment with the tag 'Foo' exists then the parser will automatically + create instances of such subclass. + + " + "If there is one subclass with the corresponding tag, returns it, else resturn the current class." + "line is of the form ```tag|title=Schedule - we should use MicArgumentList for parsing, but alas, we do not at the moment" | tag | diff --git a/src/Microdown/MicBlockQuoteBlock.class.st b/src/Microdown/MicBlockQuoteBlock.class.st index b9d41f6e..5f4fff11 100644 --- a/src/Microdown/MicBlockQuoteBlock.class.st +++ b/src/Microdown/MicBlockQuoteBlock.class.st @@ -18,13 +18,14 @@ Class { { #category : 'visiting' } MicBlockQuoteBlock >> accept: aVisitor [ + ^ aVisitor visitQuote: self ] { #category : 'visiting' } MicBlockQuoteBlock >> closeMe [ + super closeMe. - children := self inlineParse: text ] diff --git a/src/Microdown/MicCommentBlock.class.st b/src/Microdown/MicCommentBlock.class.st index b3284b31..597a350c 100644 --- a/src/Microdown/MicCommentBlock.class.st +++ b/src/Microdown/MicCommentBlock.class.st @@ -15,6 +15,7 @@ Class { { #category : 'visiting' } MicCommentBlock >> accept: aVisitor [ + ^ aVisitor visitComment: self ] diff --git a/src/Microdown/MicEnvironmentBlock.class.st b/src/Microdown/MicEnvironmentBlock.class.st index c0af9ac9..b99009d9 100644 --- a/src/Microdown/MicEnvironmentBlock.class.st +++ b/src/Microdown/MicEnvironmentBlock.class.st @@ -44,10 +44,7 @@ This is important for better column support in the future: " Class { #name : 'MicEnvironmentBlock', - #superclass : 'MicStartStopMarkupBlock', - #instVars : [ - 'arguments' - ], + #superclass : 'MicNestedMarkupBlock', #category : 'Microdown-Model', #package : 'Microdown', #tag : 'Model' @@ -92,55 +89,8 @@ MicEnvironmentBlock class >> buildMicroDownUsing: aBuilder withComment: aString { #category : 'visiting' } MicEnvironmentBlock >> accept: aVisitor [ - ^ aVisitor visitEnvironment: self -] - -{ #category : 'handle' } -MicEnvironmentBlock >> addLineAndReturnNextNode: line [ - "add line to this node. - Notice, the action is allowed to create new nodes in the block tree. - Returns the node to handle next line - typically self." - - - | withoutPreTabs | - isClosed - ifTrue: [ ^ self ]. - withoutPreTabs := line withoutPreTabs. - "Here the withoutPreTabs is probably not necessary because handlingPrefixTabOfLine: should do its job." - (self doesLineStartWithStopMarkup: withoutPreTabs) - ifTrue: [ ^ self ]. - firstLine - ifNil: - [ firstLine := self extractFirstLineFrom: withoutPreTabs ] - ifNotNil: [ ^ self bodyFromLine: withoutPreTabs ]. - ^ self -] - -{ #category : 'accessing' } -MicEnvironmentBlock >> arguments [ - - ^ arguments -] -{ #category : 'accessing' } -MicEnvironmentBlock >> body [ - - ^ String streamContents: [:s | self bodyElements do: [ :each | s nextPutAll: each substring ] ] -] - -{ #category : 'accessing' } -MicEnvironmentBlock >> bodyElements [ - - ^ children -] - -{ #category : 'accessing' } -MicEnvironmentBlock >> bodyFromLine: line [ - - | newBlock | - newBlock := (self newBlockFor: line parent: self). - self parser setCurrent: newBlock. - ^ newBlock + ^ aVisitor visitEnvironment: self ] { #category : 'parse support' } @@ -152,17 +102,15 @@ MicEnvironmentBlock >> closeMe [ body := self inlineParse: body ]. children := body" + "Pay attention closeMe is invoked during parse time and some conversions are creating environment without going over the parser + For example the # Header to Slide is a typically case. " + arguments := MicArgumentList split: firstLine defaultArg: #environmentName defaultValue: ''. ] -{ #category : 'accessing' } -MicEnvironmentBlock >> environmentName [ - ^ arguments at: #environmentName -] - { #category : 'accessing' } MicEnvironmentBlock >> extractFirstLineFrom: aLine [ "we got <! env ...x !> foo bar or <! env ...x and we return env ...x " @@ -178,29 +126,3 @@ MicEnvironmentBlock >> extractFirstLineFrom: aLine [ extract trimRight ] ifFalse: [ firstLine ] ] - -{ #category : 'initialization' } -MicEnvironmentBlock >> initialize [ - - super initialize. - arguments := MicArgumentList new - -] - -{ #category : 'markups' } -MicEnvironmentBlock >> lineStartMarkup [ - - ^ EnvironmentOpeningBlockMarkup -] - -{ #category : 'markups' } -MicEnvironmentBlock >> lineStopMarkup [ - - ^ EnvironmentClosingBlockMarkup -] - -{ #category : 'handle' } -MicEnvironmentBlock >> massageLine: aLine [ - - ^ aLine withoutPreTabs -] diff --git a/src/Microdown/MicHeaderBlock.class.st b/src/Microdown/MicHeaderBlock.class.st index d87ae9bc..050fd883 100644 --- a/src/Microdown/MicHeaderBlock.class.st +++ b/src/Microdown/MicHeaderBlock.class.st @@ -89,3 +89,10 @@ MicHeaderBlock >> level: anInteger [ ] + +{ #category : 'printing' } +MicHeaderBlock >> printOn: aStream [ + + super printOn: aStream. + aStream nextPutAll: ' - ', self header +] diff --git a/src/Microdown/MicInlineBlockWithUrl.class.st b/src/Microdown/MicInlineBlockWithUrl.class.st index e2f4f246..38066dc7 100644 --- a/src/Microdown/MicInlineBlockWithUrl.class.st +++ b/src/Microdown/MicInlineBlockWithUrl.class.st @@ -173,6 +173,7 @@ MicInlineBlockWithUrl >> hasLabel [ { #category : 'initialization' } MicInlineBlockWithUrl >> initialize [ super initialize. + children := #(). arguments := OrderedDictionary new. ] @@ -184,7 +185,8 @@ MicInlineBlockWithUrl >> printOn: stream [ ch printOn: stream. stream nextPut: Character space ]. stream << $]. - stream << $( << url << $) + url ifNotNil: [ + stream << $( << url << $) ] ] { #category : 'accessing' } diff --git a/src/Microdown/MicListItemBlock.class.st b/src/Microdown/MicListItemBlock.class.st index 85c395b5..b9e1f961 100644 --- a/src/Microdown/MicListItemBlock.class.st +++ b/src/Microdown/MicListItemBlock.class.st @@ -78,6 +78,12 @@ MicListItemBlock >> addLineAndReturnNextNode: line [ text := text , String cr , normalized ] ] +{ #category : 'accessing' } +MicListItemBlock >> bodyString [ + "I am used to make it easier to write tests" + ^ String streamContents: [ :str | children do: [ :each | str nextPutAll: each bodyString ] ] +] + { #category : 'testing' } MicListItemBlock >> canConsumeLine: line [ "return if this block can consume line" diff --git a/src/Microdown/MicMetaDataBlock.class.st b/src/Microdown/MicMetaDataBlock.class.st index a4a9349f..b85010ce 100644 --- a/src/Microdown/MicMetaDataBlock.class.st +++ b/src/Microdown/MicMetaDataBlock.class.st @@ -37,11 +37,36 @@ MicMetaDataBlock >> accept: aVisitor [ ^ aVisitor visitMetaData: self ] +{ #category : 'accessing' } +MicMetaDataBlock >> at: aString [ + ^ self body at: aString +] + +{ #category : 'accessing' } +MicMetaDataBlock >> at: aString ifAbsent: aBlock [ + ^ self body at: aString ifAbsent: aBlock +] + +{ #category : 'accessing' } +MicMetaDataBlock >> at: aString ifPresent: aPresentBlock ifAbsent: aBlock [ + ^ self body at: aString ifPresent: aPresentBlock ifAbsent: aBlock +] + +{ #category : 'accessing' } +MicMetaDataBlock >> at: aString put: aString2 [ + self body at: aString put: aString2 +] + { #category : 'accessing' } MicMetaDataBlock >> atKey: aString [ ^ self body at: aString ] +{ #category : 'accessing' } +MicMetaDataBlock >> atKey: aString ifAbsent: aBlock [ + ^ self body at: aString ifAbsent: aBlock +] + { #category : 'accessing' } MicMetaDataBlock >> atKey: aString put: aString2 [ self body at: aString put: aString2 @@ -56,6 +81,7 @@ MicMetaDataBlock >> bogusParsing [ { #category : 'markups' } MicMetaDataBlock >> closeMe [ super closeMe. + body ifNil:[ body := '']. body := [ STONJSON fromString: '{', body, '}' ] on: Error do: [ :ex | | dict | bogusParsing := true. diff --git a/src/Microdown/MicMicrodownSharedPool.class.st b/src/Microdown/MicMicrodownSharedPool.class.st deleted file mode 100644 index afd96ce2..00000000 --- a/src/Microdown/MicMicrodownSharedPool.class.st +++ /dev/null @@ -1,7 +0,0 @@ -Class { - #name : 'MicMicrodownSharedPool', - #superclass : 'MicSharedPool', - #category : 'Microdown-Parser', - #package : 'Microdown', - #tag : 'Parser' -} diff --git a/src/Microdown/MicMinimalConfiguration.class.st b/src/Microdown/MicMinimalConfiguration.class.st index d34d2b80..33cee302 100644 --- a/src/Microdown/MicMinimalConfiguration.class.st +++ b/src/Microdown/MicMinimalConfiguration.class.st @@ -40,7 +40,7 @@ MicMinimalConfiguration >> headingLevelOffset: anObject [ { #category : 'initialization' } MicMinimalConfiguration >> initialize [ super initialize. - newLine := String crlf. + self crlfAsNewLine. headingLevelOffset := 0 ] diff --git a/src/Microdown/MicNestedMarkupBlock.class.st b/src/Microdown/MicNestedMarkupBlock.class.st new file mode 100644 index 00000000..1245e49c --- /dev/null +++ b/src/Microdown/MicNestedMarkupBlock.class.st @@ -0,0 +1,93 @@ +Class { + #name : 'MicNestedMarkupBlock', + #superclass : 'MicStartStopMarkupBlock', + #instVars : [ + 'arguments' + ], + #category : 'Microdown-Model', + #package : 'Microdown', + #tag : 'Model' +} + +{ #category : 'handle' } +MicNestedMarkupBlock >> addLineAndReturnNextNode: line [ + "add line to this node. + Notice, the action is allowed to create new nodes in the block tree. + Returns the node to handle next line - typically self." + + + | withoutPreTabs | + isClosed + ifTrue: [ ^ self ]. + withoutPreTabs := line withoutPreTabs. + "Here the withoutPreTabs is probably not necessary because handlingPrefixTabOfLine: should do its job." + firstLine + ifNil: + [ firstLine := self extractFirstLineFrom: withoutPreTabs. + ^ self ]. + (self doesLineStartWithStopMarkup: withoutPreTabs) + ifTrue: [ ^ self ]. + ^ self bodyFromLine: withoutPreTabs +] + +{ #category : 'accessing' } +MicNestedMarkupBlock >> arguments [ + + ^ arguments +] + +{ #category : 'accessing' } +MicNestedMarkupBlock >> body [ + + ^ String streamContents: [:s | self bodyElements do: [ :each | s nextPutAll: each substring ] ] +] + +{ #category : 'accessing' } +MicNestedMarkupBlock >> bodyElements [ + + ^ children +] + +{ #category : 'accessing' } +MicNestedMarkupBlock >> bodyFromLine: line [ + + | newBlock | + newBlock := self newBlockFor: line parent: self. + self parser setCurrent: newBlock. + ^ newBlock +] + +{ #category : 'accessing' } +MicNestedMarkupBlock >> environmentName [ + ^ arguments at: #environmentName +] + +{ #category : 'parse support' } +MicNestedMarkupBlock >> initialize [ + + super initialize. + + "Pay attention closeMe is invoked during parse time and some conversions are creating environment without going over the parser + For example the # Header to Slide is a typically case. Therefore the following initialization is needed even if + on parse time the arguments will get reset with another one." + + arguments := MicArgumentList new +] + +{ #category : 'markups' } +MicNestedMarkupBlock >> lineStartMarkup [ + + ^ EnvironmentOpeningBlockMarkup +] + +{ #category : 'markups' } +MicNestedMarkupBlock >> lineStopMarkup [ + + ^ EnvironmentClosingBlockMarkup +] + +{ #category : 'handle' } +MicNestedMarkupBlock >> massageLine: aLine [ + + ^ aLine withoutPreTabs +] diff --git a/src/Microdown/MicOrderedListBlock.class.st b/src/Microdown/MicOrderedListBlock.class.st index 1ad7d680..15298788 100644 --- a/src/Microdown/MicOrderedListBlock.class.st +++ b/src/Microdown/MicOrderedListBlock.class.st @@ -52,6 +52,12 @@ MicOrderedListBlock >> addLineAndReturnNextNode: line [ ^ super addLineAndReturnNextNode: line ] +{ #category : 'accessing' } +MicOrderedListBlock >> bodyString [ + + ^ String streamContents: [ :str | children do: [ :each | str nextPutAll: each bodyString ] ] +] + { #category : 'testing' } MicOrderedListBlock >> canConsumeLine: line [ "to consume this line there must be a UnorderdListItem start at the right indentation" @@ -68,5 +74,6 @@ MicOrderedListBlock >> startIndex [ { #category : 'accessing' } MicOrderedListBlock >> startIndexFrom: line [ startIndex ifNotNil: [ ^self ]. - startIndex := line asInteger + "an ordered list line starts with the index and after a dot '.' " + startIndex := line microdownExtractPartOfInteger ] diff --git a/src/Microdown/MicParagraphBlock.class.st b/src/Microdown/MicParagraphBlock.class.st index 3dea057f..a37348a6 100644 --- a/src/Microdown/MicParagraphBlock.class.st +++ b/src/Microdown/MicParagraphBlock.class.st @@ -54,7 +54,8 @@ MicParagraphBlock >> canConsumeLine: line [ | unIndented | "if we are closing block that can contain other elements then do not consume their ends." - (line isEmpty or: [ line beginsWith: EnvironmentClosingBlockMarkup]) + + (line isEmpty or: [ (line beginsWith: EnvironmentClosingBlockMarkup) or: [ EndHTMLTags includes: line ]]) ifTrue: [ ^ false ]. (self isRightlyIndented: line) ifFalse: [ ^ false ]. @@ -79,6 +80,13 @@ MicParagraphBlock >> isRightlyIndented: line [ ^ line beginsWith: (' ' repeat: self indent) ] +{ #category : 'printing' } +MicParagraphBlock >> printOn: aStream [ + + super printOn: aStream. + aStream nextPutAll: ' - ', self text +] + { #category : 'accessing' } MicParagraphBlock >> text [ ^ text diff --git a/src/Microdown/MicRawParagraphBlock.class.st b/src/Microdown/MicRawParagraphBlock.class.st index 476307ad..8fa6464c 100644 --- a/src/Microdown/MicRawParagraphBlock.class.st +++ b/src/Microdown/MicRawParagraphBlock.class.st @@ -1,34 +1,65 @@ Class { #name : 'MicRawParagraphBlock', - #superclass : 'MicStartStopMarkupBlock', + #superclass : 'MicNestedMarkupBlock', #instVars : [ - 'label' + 'label', + 'argumentsString' ], - #category : 'Microdown-Extensions', + #category : 'Microdown-Model', #package : 'Microdown', - #tag : 'Extensions' + #tag : 'Model' } +{ #category : 'public' } +MicRawParagraphBlock class >> alternateBlockClassFor: aLine [ + "We do not want to have extention for MicRawParaphTag" + + ^ self +] + { #category : 'visiting' } MicRawParagraphBlock >> accept: aVisitor [ aVisitor visitRawParagraph: self ] +{ #category : 'activation' } +MicRawParagraphBlock >> argumentString [ + ^ argumentsString +] + { #category : 'handle' } -MicRawParagraphBlock >> bodyFromLine: line [ +MicRawParagraphBlock >> extractFirstLineFrom: aLine [ + "we got < tag ...x > foo bar or < tag ...x and we return tag ...x " + + | splits | + firstLine := aLine copyFrom: self lineStartMarkup size to: aLine size. + firstLine := firstLine trimBoth. + firstLine := firstLine copyFrom: 1 to: firstLine size -1. + + splits := firstLine splitOnFirst: $>. + splits second isNotEmpty + ifTrue: [ "here we p>Blo and we discard Blo" + label := splits first ]. + + "now we may have <p src='whatever' so we split again" + splits := splits first splitOnFirst: Character space. + label := splits first. + splits second isNotEmpty + ifTrue: [ argumentsString := splits second ]. + ^ firstLine +] - (self doesLineStartWithStopMarkup: line) - ifTrue: [ isClosed := true ] - ifFalse: [ body := body ifNil: [ line ] ifNotNil: [ body , String cr , line ] ] +{ #category : 'testing' } +MicRawParagraphBlock >> hasArguments [ + ^ argumentsString isNotEmpty ] -{ #category : 'handle' } -MicRawParagraphBlock >> extractFirstLineFrom: line [ - "we cannot know in advance the markup so we have to guess and store it for closing." +{ #category : 'parse support' } +MicRawParagraphBlock >> initialize [ - label := line allButFirst copyUpToSubstring: '>' - + super initialize. + argumentsString := '' ] { #category : 'accessing' } @@ -41,3 +72,12 @@ MicRawParagraphBlock >> lineStopMarkup [ ^ '</', label, '>' ] + +{ #category : 'printing' } +MicRawParagraphBlock >> printOn: aStream [ + + super printOn: aStream. + aStream << '(' ; + << label ; + << ')' +] diff --git a/src/Microdown/MicRootBlock.class.st b/src/Microdown/MicRootBlock.class.st index 146a8167..7d8affe2 100644 --- a/src/Microdown/MicRootBlock.class.st +++ b/src/Microdown/MicRootBlock.class.st @@ -4,11 +4,34 @@ I am the root of the markup tree. Class { #name : 'MicRootBlock', #superclass : 'MicAbstractBlock', + #instVars : [ + 'debugId' + ], + #classVars : [ + 'DebugId' + ], + #classInstVars : [ + 'debugId' + ], #category : 'Microdown-Model', #package : 'Microdown', #tag : 'Model' } +{ #category : 'accessing' } +MicRootBlock class >> nextDebugId [ + + DebugId ifNil: [ DebugId := 0]. + DebugId := DebugId + 1. + ^ DebugId +] + +{ #category : 'accessing' } +MicRootBlock class >> resetDebugId [ + + DebugId := 0 +] + { #category : 'visiting' } MicRootBlock >> accept: aVisitor [ ^ aVisitor visitRoot: self @@ -32,6 +55,17 @@ MicRootBlock >> canConsumeLine: line [ ^ true ] +{ #category : 'debugging' } +MicRootBlock >> debugId [ + ^ debugId +] + +{ #category : 'debugging' } +MicRootBlock >> debugIdGenerator [ + + ^ self class nextDebugId +] + { #category : 'accessing' } MicRootBlock >> fromFile [ ^ self propertyAt: #file ifAbsent: [ 'fakedFile' ] @@ -67,6 +101,13 @@ MicRootBlock >> indent [ ^0 ] +{ #category : 'initialization' } +MicRootBlock >> initialize [ + + super initialize. + debugId := self class nextDebugId. +] + { #category : 'hooks' } MicRootBlock >> massageLine: aLine [ "In some cases an element may want to massage the line such as removing leading tab. By default we delegate to the parent because environments may contain nodes such as code block and this is this nesting that will determine what should be done with the tab. In such a case the environment should remov the tabs. Here on the root we do nothing special." @@ -81,6 +122,15 @@ MicRootBlock >> metaDataElement [ ^ children first ] +{ #category : 'printing' } +MicRootBlock >> printOn: aStream [ + + super printOn: aStream. + debugId ifNotNil: [ + aStream << '[ id:'; <<debugId asString ; << ']' ] + +] + { #category : 'accessing' } MicRootBlock >> properties: aConfigurationForPillar [ "Pay attention the strong hypothesis here is that keys of microdown properties and pillar configuration should not overlap. A possible solution would be to have clever at: and at:put: that check for example for a prefix for microdown properties. diff --git a/src/Microdown/MicSharedPool.class.st b/src/Microdown/MicSharedPool.class.st index e0bc971e..f6e2bf12 100644 --- a/src/Microdown/MicSharedPool.class.st +++ b/src/Microdown/MicSharedPool.class.st @@ -21,6 +21,7 @@ Class { 'CodeblockMarkup', 'CommentedLineMarkup', 'Delimiters', + 'EndHTMLTags', 'EnvironmentClosingBlockMarkup', 'EnvironmentOpeningBlockMarkup', 'FigureNameOpenerMarkup', @@ -57,11 +58,18 @@ Class { #tag : 'Parser' } +{ #category : 'class initialization' } +MicSharedPool class >> endHtmlTags [ + "Pay attention that br is not in this list!" + + ^ #('</a>' '</abbr>' '</address>' '</area>' '</article>' '</aside>' '</audio>' '</b>' '</base>' '</bdi>' '</bdo>' '</blockquote>' '</body>' '</button>' '</canvas>' '</caption>' '</cite>' '</code>' '</col>' '</colgroup>' '</data>' '</datalist>' '</dd>' '</del>' '</details>' '</dfn>' '</dialog>' '</div>' '</dl>' '</dt>' '</em>' '</embed>' '</fieldset>' '</figcaption>' '</figure>' '</footer>' '</form>' '</h1>' '</h2>' '</h3>' '</h4>' '</h5>' '</h6>' '</head>' '</header>' '</hgroup>' '</hr>' '</html>' '</i>' '</iframe>' '</img>' '</input>' '</ins>' '</kbd>' '</label>' '</legend>' '</li>' '</link>' '</main>' '</map>' '</mark>' '</menu>' '</meta>' '</meter>' '</nav>' '</noscript>' '</object>' '</ol>' '</optgroup>' '</option>' '</output>' '</p>' '</param>' '</picture>' '</pre>' '</progress>' '</q>' '</rb>' '</rp>' '</rt>' '</rtc>' '</ruby>' '</s>' '</samp>' '</script>' '</section>' '</select>' '</slot>' '</small>' '</source>' '</span>' '</strong>' '</style>' '</sub>' '</summary>' '</sup>' '</table>' '</tbody>' '</td>' '</template>' '</textarea>' '</tfoot>' '</th>' '</thead>' '</time>' '' '' '' '' '' '' '' '') +] + { #category : 'class initialization' } MicSharedPool class >> htmlTags [ "Pay attention that br is not in this list!" - ^ #('!--' 'a' 'abbr' 'address' 'area' 'article' 'aside' 'audio' 'b' 'base' 'bdi' 'bdo' 'blockquote' 'body' 'button' 'canvas' 'caption' 'cite' 'code' 'col' 'colgroup' 'data' 'datalist' 'dd' 'del' 'details' 'dfn' 'dialog' 'div' 'dl' 'dt' 'em' 'embed' 'fieldset' 'figcaption' 'figure' 'footer' 'form' 'h1' 'h2' 'h3' 'h4' 'h5' 'h6' 'head' 'header' 'hgroup' 'hr' 'html' 'i' 'iframe' 'img' 'input' 'ins' 'kbd' 'label' 'legend' 'li' 'link' 'main' 'map' 'mark' 'menu' 'meta' 'meter' 'nav' 'noscript' 'object' 'ol' 'optgroup' 'option' 'output' 'p' 'param' 'picture' 'pre' 'progress' 'q' 'rb' 'rp' 'rt' 'rtc' 'ruby' 's' 'samp' 'script' 'section' 'select' 'slot' 'small' 'source' 'span' 'strong' 'style' 'sub' 'summary' 'sup' 'table' 'tbody' 'td' 'template' 'textarea' 'tfoot' 'th' 'thead' 'time' 'title' 'tr' 'track' 'u' 'ul' 'var' 'video' 'wbr') + ^ #('!--' 'a' 'abbr' 'address' 'area' 'article' 'aside' 'audio' 'b' 'base' 'bdi' 'bdo' 'blockquote' 'body' 'button' 'canvas' 'caption' 'cite' 'code' 'col' 'colgroup' 'data' 'datalist' 'dd' 'del' 'details' 'dfn' 'dialog' 'div' 'dl' 'dt' 'em' 'embed' 'fieldset' 'figcaption' 'figure' 'footer' 'form' 'h1' 'h2' 'h3' 'h4' 'h5' 'h6' 'head' 'header' 'hgroup' 'hr' 'html' 'i' 'iframe' 'img' 'input' 'ins' 'kbd' 'label' 'legend' 'li' 'link' 'main' 'map' 'mark' 'menu' 'meta' 'meter' 'nav' 'noscript' 'object' 'ol' 'optgroup' 'option' 'output' 'p' 'param' 'picture' 'pre' 'progress' 'q' 'rb' 'rp' 'rt' 'rtc' 'ruby' 's' 'samp' 'script' 'section' 'select' 'slot' 'small' 'source' 'span' 'strong' 'style' 'sub' 'summary' 'sup' 'table' 'tbody' 'td' 'template' 'textarea' 'tfoot' 'th' 'thead' 'time' 'title' 'tr' 'track' 'u' 'ul' 'var' 'video' 'wbr') , #('!-->' 'a>' 'abbr>' 'address>' 'area>' 'article>' 'aside>' 'audio>' 'b>' 'base>' 'bdi>' 'bdo>' 'blockquote>' 'body>' 'button>' 'canvas>' 'caption>' 'cite>' 'code>' 'col>' 'colgroup>' 'data>' 'datalist>' 'dd>' 'del>' 'details>' 'dfn>' 'dialog>' 'div>' 'dl>' 'dt>' 'em>' 'embed>' 'fieldset>' 'figcaption>' 'figure>' 'footer>' 'form>' 'h1>' 'h2>' 'h3>' 'h4>' 'h5>' 'h6>' 'head>' 'header>' 'hgroup>' 'hr>' 'html>' 'i>' 'iframe>' 'img>' 'input>' 'ins>' 'kbd>' 'label>' 'legend>' 'li>' 'link>' 'main>' 'map>' 'mark>' 'menu>' 'meta>' 'meter>' 'nav>' 'noscript>' 'object>' 'ol>' 'optgroup>' 'option>' 'output>' 'p>' 'param>' 'picture>' 'pre>' 'progress>' 'q>' 'rb>' 'rp>' 'rt>' 'rtc>' 'ruby>' 's>' 'samp>' 'script>' 'section>' 'select>' 'slot>' 'small>' 'source>' 'span>' 'strong>' 'style>' 'sub>' 'summary>' 'sup>' 'table>' 'tbody>' 'td>' 'template>' 'textarea>' 'tfoot>' 'th>' 'thead>' 'time>' 'title>' 'tr>' 'track>' 'u>' 'ul>' 'var>' 'video>' 'wbr>') ] { #category : 'class initialization' } @@ -177,7 +185,8 @@ MicSharedPool class >> initializeRawParagraph [ "self initializeRawParagraph" HTMLTags := self htmlTags. - ThreeLettersHTMLTags := self threeLetterhtmlTags + ThreeLettersHTMLTags := self threeLetterhtmlTags. + EndHTMLTags := self endHtmlTags. ] { #category : 'class initialization' } diff --git a/src/Microdown/MicTableBlock.class.st b/src/Microdown/MicTableBlock.class.st index bca273f0..9b611577 100644 --- a/src/Microdown/MicTableBlock.class.st +++ b/src/Microdown/MicTableBlock.class.st @@ -82,17 +82,17 @@ MicTableBlock >> extractLine: line [ For now we have | something | something | or - | something | something" - | unicodeReplacementCharacter | - + | some thing | something" + | unicodeReplacementCharacter backslashLine rowColumn | + "allow pipe symbols to be written as \|" unicodeReplacementCharacter := 16rFFFD asCharacter asString. "By definition this do not appear in any input" - - ^ ((line copyReplaceAll: '\|' with: unicodeReplacementCharacter) findBetweenSubstrings: '|') + + backslashLine := (line copyReplaceAll: '\|' with: unicodeReplacementCharacter) trim. + "remove spaces at the end" + rowColumn := backslashLine findBetweenSubstrings: '|'. + ^ rowColumn collect: [ :each | (each copyReplaceAll: unicodeReplacementCharacter with: '|') trim] - - - ] { #category : 'accessing' } diff --git a/src/Microdown/MicZincPathResolver.class.st b/src/Microdown/MicZincPathResolver.class.st index b5c1edbd..7c053dbf 100644 --- a/src/Microdown/MicZincPathResolver.class.st +++ b/src/Microdown/MicZincPathResolver.class.st @@ -38,6 +38,7 @@ MicZincPathResolver class >> resolve: document withBase: aRef [ { #category : 'accessing' } MicZincPathResolver >> absoluteReference: aReferenceOrString [ + absoluteReference := aReferenceOrString isString ifTrue: [ MicResourceReference fromUri: aReferenceOrString ] ifFalse: [ aReferenceOrString ] @@ -45,17 +46,20 @@ MicZincPathResolver >> absoluteReference: aReferenceOrString [ { #category : 'visiting' } MicZincPathResolver >> resolveDocument: document [ + self visit: document ] { #category : 'private' } MicZincPathResolver >> resolveReferenceIn: aNode [ "currently links, figures and input nodes need to be resolved" + | resolvedUri resolvedReference | aNode reference isRelative ifFalse: [ ^ self ]. resolvedUri := absoluteReference uri withRelativeReference: aNode reference relativePath. resolvedReference := MicResourceReference fromUri: resolvedUri printString. - resolvedReference isMicrodownResourceFileReference ifTrue: [ resolvedReference fileSystem: absoluteReference fileSystem ]. + resolvedReference isMicrodownResourceFileReference + ifTrue: [ resolvedReference fileSystem: absoluteReference fileSystem ]. aNode reference: resolvedReference ] @@ -68,11 +72,11 @@ MicZincPathResolver >> visitFigure: aFigure [ { #category : 'visiting' } MicZincPathResolver >> visitInputFile: anInputFile [ - self resolveReferenceIn: anInputFile ] { #category : 'visiting' } MicZincPathResolver >> visitLink: aLink [ + self resolveReferenceIn: aLink ] diff --git a/src/Microdown/MicroSharedPool.class.st b/src/Microdown/MicroSharedPool.class.st deleted file mode 100644 index a6dea6ed..00000000 --- a/src/Microdown/MicroSharedPool.class.st +++ /dev/null @@ -1,7 +0,0 @@ -Class { - #name : 'MicroSharedPool', - #superclass : 'MicSharedPool', - #category : 'Microdown-Parser', - #package : 'Microdown', - #tag : 'Parser' -} diff --git a/src/Microdown/Microdown.class.st b/src/Microdown/Microdown.class.st index 509de398..6eeaaff9 100644 --- a/src/Microdown/Microdown.class.st +++ b/src/Microdown/Microdown.class.st @@ -153,12 +153,12 @@ Microdown >> parse: aStreamOrString [ { #category : 'facade' } Microdown >> parseFile: aFile [ - - |root| - root := MicrodownParser parse: aFile contents. - root fromFile: aFile. - ^ root - + "Parse and return a document from the argument marking it with the file it is contained in. This is important for path resolution." + + | root | + root := MicrodownParser parse: aFile contents. + root fromFile: aFile. + ^ root ] { #category : 'facade' } diff --git a/src/Microdown/MicrodownParser.class.st b/src/Microdown/MicrodownParser.class.st index 7c90d25a..60e11c10 100644 --- a/src/Microdown/MicrodownParser.class.st +++ b/src/Microdown/MicrodownParser.class.st @@ -212,8 +212,16 @@ MicrodownParser >> blockStarterClassFrom: line [ but this is to try. Once we understand and probably change the environment syntax for now it is , i and i> + This is working p src=800 + " + + (line includes: Character space) + ifTrue: [ HTMLTags includes: ((line allButFirst splitOnFirst: Character space) first) ] + ifFalse: [ HTMLTags includes: ((line allButFirst splitOnFirst: $>) first) ] + ]) ifTrue: [ "we have a rawparagraph block" ^ MicRawParagraphBlock diff --git a/src/Microdown/MyLog.class.st b/src/Microdown/MyLog.class.st new file mode 100644 index 00000000..ecbdf1d0 --- /dev/null +++ b/src/Microdown/MyLog.class.st @@ -0,0 +1,81 @@ +" +I'm responsible for keeping a log of the development actions at the design level. +Too many times I do not remember what I did and why. +" +Class { + #name : 'MyLog', + #superclass : 'Object', + #category : 'Microdown-DevLog', + #package : 'Microdown', + #tag : 'DevLog' +} + +{ #category : 'ui - dialogs' } +MyLog >> l2025_08_08 [ + + ^ ' +## 2025 08 08 + +#### Started this log +#### Fix the rendering of paragraphs. + +The problem was that when two consecutive paragraphs were rendered we could not see the split. +https://github.com/pillar-markup/Microdown/issues/957 +It was due to a lack of

or newline. + +I decided to go for an extra newLine but it can be a bad choice. + +``` +visitParagraph: aParagraph + + canvas newLine. + super visitParagraph: aParagraph. + "Introduce an extra new line to address problem of merged rendered paragraph. + I did not reintroduce the

below because I do not remember why it was + cancel. May be it was generating too many

+ Now it may happen that for intra block element tests

was generated + while in a normal setup (since the intrablock elements will be inside + a large paragraph) it will not be a problem. + + So this issue should be further investigated." + canvas newLine. + "canvas tag + name: ''p''; + with: [ ]" +``` + + ' +] + +{ #category : 'ui - dialogs' } +MyLog >> l2025_08_11 [ + + ^ ' +## 2025 08 11 + +#### Fix the visit of the paragraph + Now it uses

as before. Foliage generation is working. + + ' +] + +{ #category : 'possible todos' } +MyLog >> pt2025_08_16 [ + + ^ ' +## 2025 08 16 + +- Anchor Linker Use - Investigate why it is not used. +- Check with HTML exporter does not inherit from `MicDocumentWriter` +- Check with textualexport does not inherit from `MicDocumentWriter` +- MicCodeBlock API does not support the setting of text +- body: set does not set the lement as children in a parent children relation +- we should revisit all the parent/children and named instance variables + - we have caption and captionElements. This would indicate that + elements are returned using xxxElements + - code:/body: is then expecting a string + - It means that bodyString: and bodyString are not good API. + + +' +] diff --git a/src/Microdown/String.extension.st b/src/Microdown/String.extension.st index c1a8f8d5..64c10a5e 100644 --- a/src/Microdown/String.extension.st +++ b/src/Microdown/String.extension.st @@ -15,6 +15,19 @@ String >> escapeAll [ ^ escaped ] +{ #category : '*Microdown' } +String >> microdownExtractPartOfInteger [ + "Do not use. This method should only be used by microdown." + + | start stream | + start := self findFirst: [:char | char isDigit]. + start isZero ifTrue: [^ nil]. + stream := self readStream position: start - 1. + ((stream position ~= 0) and: [stream peekBack = $-]) + ifTrue: [stream back]. + ^ Integer readFrom: stream +] + { #category : '*Microdown' } String >> resolveDocument: document [ ^ self asMicResourceReference resolveDocument: document.