├── .gitattributes ├── tests ├── inc.md ├── sample.yaml ├── sample.md ├── sample-pandoc-header.Rmd ├── Makefile ├── sample.tex ├── sample-yaml-header.Rmd └── sample.rst ├── lib ├── yaml │ ├── yaml.tcl │ ├── pkgIndex.tcl │ └── huddle_types.tcl ├── tdot │ ├── pkgIndex.tcl │ ├── tdot-canvas.png │ └── tdot-example.tcl ├── tsvg │ ├── pkgIndex.tcl │ └── Makefile ├── citer │ ├── pkgIndex.tcl │ └── assets │ │ └── literature.bib ├── dgw │ ├── statusbar.tcl │ └── pkgIndex.tcl ├── fview │ ├── demo-dot.png │ ├── demo-pik.png │ ├── demo-dot2.png │ ├── demo-mtex.png │ ├── pkgIndex.tcl │ ├── Makefile │ └── snippets.txt ├── markdown │ └── pkgIndex.tcl ├── tclfilters │ ├── uni.sqlite │ ├── smallcaps.lua │ ├── filter-abc.tcl │ ├── filter-tcrd.tcl │ ├── pkgIndex.tcl │ ├── tikz-tree.tex │ ├── utils.tcl │ ├── xkcd.tex │ ├── header.md │ ├── Makefile │ ├── header.html │ ├── tclfilters.tcl │ ├── filter-rplot.tcl │ ├── filter-mmd.tcl │ ├── filter-emf.tcl │ ├── filter-sqlite.tcl │ ├── filter-eqn.tcl │ ├── filter-tsvg.tcl │ ├── filter-tdot.tcl │ ├── filter-dot.tcl │ ├── filter-julia.tcl │ ├── assets │ │ └── literature.bib │ ├── filter-pic.tcl │ └── filter-kroki.tcl ├── rl_json │ ├── librl_json0.11.0.dll │ ├── librl_json0.11.0.so │ ├── librl_json0.11.1.dylib │ ├── pkgIndex.tcl │ └── mini.css ├── bibtex │ └── pkgIndex.tcl ├── cmdline │ └── pkgIndex.tcl ├── mkdoc │ └── pkgIndex.tcl ├── snit │ ├── pkgIndex.tcl │ ├── snit2.tcl │ ├── snit.tcl │ └── snit_tcl83_utils.tcl └── textutil │ ├── pkgIndex.tcl │ ├── repeat.tcl │ ├── textutil.tcl │ ├── trim.tcl │ ├── string.tcl │ ├── split.tcl │ ├── ithyph.tex │ └── tabify.tcl ├── examples ├── test1.png ├── Makefile └── test1.md ├── user ├── Makefile ├── user-filter.md └── filter-geasy.tcl ├── .github └── workflows │ └── main.yml ├── header.md ├── LICENSE ├── install-unix.sh ├── xml └── emf.xml ├── mini.css └── Makefile /.gitattributes: -------------------------------------------------------------------------------- 1 | *.html linguist-detectable=false 2 | -------------------------------------------------------------------------------- /tests/inc.md: -------------------------------------------------------------------------------- 1 | I am test.md and here some text is written in **bold**. 2 | -------------------------------------------------------------------------------- /lib/yaml/yaml.tcl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mittelmark/pantcl/HEAD/lib/yaml/yaml.tcl -------------------------------------------------------------------------------- /examples/test1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mittelmark/pantcl/HEAD/examples/test1.png -------------------------------------------------------------------------------- /lib/tdot/pkgIndex.tcl: -------------------------------------------------------------------------------- 1 | package ifneeded tdot 0.3.1 [list source [file join $dir tdot.tcl]] 2 | -------------------------------------------------------------------------------- /lib/tsvg/pkgIndex.tcl: -------------------------------------------------------------------------------- 1 | package ifneeded tsvg 0.3.1 [list source [file join $dir tsvg.tcl]] 2 | -------------------------------------------------------------------------------- /examples/Makefile: -------------------------------------------------------------------------------- 1 | default: 2 | tclsh ../pantcl.tcl test1.md test1.html --css ../mini.css -s 3 | -------------------------------------------------------------------------------- /lib/citer/pkgIndex.tcl: -------------------------------------------------------------------------------- 1 | package ifneeded citer 0.1.1 [list source [file join $dir citer.tcl]] 2 | -------------------------------------------------------------------------------- /lib/dgw/statusbar.tcl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mittelmark/pantcl/HEAD/lib/dgw/statusbar.tcl -------------------------------------------------------------------------------- /lib/fview/demo-dot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mittelmark/pantcl/HEAD/lib/fview/demo-dot.png -------------------------------------------------------------------------------- /lib/fview/demo-pik.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mittelmark/pantcl/HEAD/lib/fview/demo-pik.png -------------------------------------------------------------------------------- /lib/fview/demo-dot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mittelmark/pantcl/HEAD/lib/fview/demo-dot2.png -------------------------------------------------------------------------------- /lib/fview/demo-mtex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mittelmark/pantcl/HEAD/lib/fview/demo-mtex.png -------------------------------------------------------------------------------- /lib/fview/pkgIndex.tcl: -------------------------------------------------------------------------------- 1 | package ifneeded fview 0.2 [list source [file join $dir filter-view.tcl]] 2 | -------------------------------------------------------------------------------- /lib/markdown/pkgIndex.tcl: -------------------------------------------------------------------------------- 1 | package ifneeded Markdown 1.1 [list source [file join $dir markdown.tcl]] 2 | -------------------------------------------------------------------------------- /lib/tclfilters/uni.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mittelmark/pantcl/HEAD/lib/tclfilters/uni.sqlite -------------------------------------------------------------------------------- /lib/tdot/tdot-canvas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mittelmark/pantcl/HEAD/lib/tdot/tdot-canvas.png -------------------------------------------------------------------------------- /lib/tclfilters/smallcaps.lua: -------------------------------------------------------------------------------- 1 | function Strong(elem) 2 | return pandoc.SmallCaps(elem.c) 3 | end 4 | 5 | -------------------------------------------------------------------------------- /lib/tclfilters/filter-abc.tcl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mittelmark/pantcl/HEAD/lib/tclfilters/filter-abc.tcl -------------------------------------------------------------------------------- /lib/tclfilters/filter-tcrd.tcl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mittelmark/pantcl/HEAD/lib/tclfilters/filter-tcrd.tcl -------------------------------------------------------------------------------- /lib/tclfilters/pkgIndex.tcl: -------------------------------------------------------------------------------- 1 | package ifneeded tclfilters 0.8.0 [list source [file join $dir tclfilters.tcl]] 2 | -------------------------------------------------------------------------------- /lib/rl_json/librl_json0.11.0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mittelmark/pantcl/HEAD/lib/rl_json/librl_json0.11.0.dll -------------------------------------------------------------------------------- /lib/rl_json/librl_json0.11.0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mittelmark/pantcl/HEAD/lib/rl_json/librl_json0.11.0.so -------------------------------------------------------------------------------- /lib/rl_json/librl_json0.11.1.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mittelmark/pantcl/HEAD/lib/rl_json/librl_json0.11.1.dylib -------------------------------------------------------------------------------- /tests/sample.yaml: -------------------------------------------------------------------------------- 1 | title: This is a test title 2 | author: Detlef Groth, University of Potsdam, Germany 3 | date: 2023-03-10 4 | tcl: 5 | eval: 1 6 | -------------------------------------------------------------------------------- /lib/bibtex/pkgIndex.tcl: -------------------------------------------------------------------------------- 1 | if {![package vsatisfies [package provide Tcl] 8.4]} {return} 2 | package ifneeded bibtex 0.6 [list source [file join $dir bibtex.tcl]] 3 | -------------------------------------------------------------------------------- /lib/cmdline/pkgIndex.tcl: -------------------------------------------------------------------------------- 1 | if {![package vsatisfies [package provide Tcl] 8.2]} {return} 2 | package ifneeded cmdline 1.5 [list source [file join $dir cmdline.tcl]] 3 | -------------------------------------------------------------------------------- /lib/rl_json/pkgIndex.tcl: -------------------------------------------------------------------------------- 1 | # 2 | # Tcl package index file 3 | # 4 | package ifneeded rl_json 0.11.0 \ 5 | [list load [file join $dir librl_json0.11.0[info shared]] rl_json] 6 | -------------------------------------------------------------------------------- /lib/fview/Makefile: -------------------------------------------------------------------------------- 1 | default: 2 | pantcl filter-view.tcl filter-view.html -s 3 | htmlark filter-view.html -o filter-view-out.html 4 | mv filter-view-out.html filter-view.html 5 | -------------------------------------------------------------------------------- /lib/mkdoc/pkgIndex.tcl: -------------------------------------------------------------------------------- 1 | if {![package vsatisfies [package require Tcl] 8.6-]} {return} 2 | package ifneeded mkdoc 0.10.2 [list source [file join $dir mkdoc.tcl]] 3 | package ifneeded mkdoc::mkdoc 0.10.2 [list source [file join $dir mkdoc.tcl]] 4 | -------------------------------------------------------------------------------- /lib/snit/pkgIndex.tcl: -------------------------------------------------------------------------------- 1 | if {[package vsatisfies [package provide Tcl] 8.5]} { 2 | package ifneeded snit 2.3.2 \ 3 | [list source [file join $dir snit2.tcl]] 4 | } 5 | 6 | package ifneeded snit 1.4.2 [list source [file join $dir snit.tcl]] 7 | -------------------------------------------------------------------------------- /lib/tsvg/Makefile: -------------------------------------------------------------------------------- 1 | default: 2 | perl -ne "s/^#' ?(.*)/\$$1/ and print " tsvg.tcl > tsvg.md 3 | pandoc tsvg.md -s \ 4 | --metadata title="tsvg package documentation" \ 5 | -o tsvg-temp.html --filter pantcl \ 6 | --css mini.css --toc 7 | htmlark -o tsvg.html tsvg-temp.html 8 | rm tsvg-temp.html 9 | 10 | -------------------------------------------------------------------------------- /lib/yaml/pkgIndex.tcl: -------------------------------------------------------------------------------- 1 | 2 | if {![package vsatisfies [package provide Tcl] 8.5]} {return} 3 | 4 | package ifneeded yaml 0.4.1 [list source [file join $dir yaml.tcl]] 5 | package ifneeded huddle 0.3 [list source [file join $dir huddle.tcl]] 6 | package ifneeded huddle::json 0.1 [list source [file join $dir json2huddle.tcl]] 7 | -------------------------------------------------------------------------------- /lib/tclfilters/tikz-tree.tex: -------------------------------------------------------------------------------- 1 | \tikzset{ 2 | treenode/.style = {shape=rectangle, rounded corners, 3 | draw, align=center, 4 | top color=white, bottom color=blue!20}, 5 | root/.style = {treenode, font=\Large, bottom color=red!30}, 6 | env/.style = {treenode, font=\ttfamily\normalsize}, 7 | dummy/.style = {circle,draw} 8 | } 9 | -------------------------------------------------------------------------------- /examples/test1.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Test Markdown witch embedded Tcl code. 3 | author: Detlef Groth 4 | date: 2023-01-11 5 | --- 6 | 7 | ## Header 8 | 9 | This is some text. 10 | 11 | ```{.tcl} 12 | set x 1 13 | set x 14 | ``` 15 | 16 | Here some inline Tcl expression x is now `tcl set x`. 17 | 18 | This document was compiled at `tcl clock format [clock seconds] -format "%Y-%m-%d %H:%M:%S"` CET. 19 | -------------------------------------------------------------------------------- /user/Makefile: -------------------------------------------------------------------------------- 1 | filter=geasy 2 | default: 3 | cd .. && tclsh pantcl.tcl user/filter-$(filter).tcl user/filter-$(filter)-out.html \ 4 | -s --css mini.css 5 | cd .. && htmlark user/filter-$(filter)-out.html -o user/filter-$(filter).html 6 | rm filter-$(filter)-out.html 7 | cd .. && tclsh pantcl.tcl user/user-filter.md user/user-filter-out.html \ 8 | -s --css mini.css 9 | cd .. && htmlark user/user-filter-out.html -o user/user-filter.html 10 | rm user-filter-out.html 11 | 12 | 13 | -------------------------------------------------------------------------------- /tests/sample.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: This is a test file 3 | author: NN 4 | date: 2023-03-05 5 | --- 6 | 7 | # Introduction 8 | 9 | This is a sample with some example code chunks. 10 | 11 | # Code chunks 12 | 13 | ```{.tcl} 14 | set x 1 15 | puts $x 16 | ``` 17 | 18 | 19 | This a Tcl variable, x is `tcl set x`. 20 | 21 | 22 | 23 | 24 | Let's try out now `foo @text bar`. 25 | I will write some more text ... 26 | 27 | ```{.tcl} 28 | incr x 29 | ``` 30 | 31 | This is some more text with tcl where x is now: `tcl set x` and let's try to 32 | write 'foo @text bar' again. 33 | 34 | Can I write a @ symbol? 35 | -------------------------------------------------------------------------------- /tests/sample-pandoc-header.Rmd: -------------------------------------------------------------------------------- 1 | % this is a title 2 | % Max Musterman, Unviversity of Musterciy, Germany 3 | % 2023-05-25 4 | 5 | ## Introduction 6 | 7 | Here an R-example: 8 | 9 | Setup for Python within knitr: 10 | 11 | ```{r eval=TRUE} 12 | knitr::knit_engines$set(py = reticulate::eng_python) 13 | ``` 14 | 15 | ```{r eval=TRUE,wait=400} 16 | print("Hello R World!") 17 | ``` 18 | 19 | Here an Python-example: 20 | 21 | ```{python eval=TRUE,terminal=FALSE} 22 | def test(): 23 | print("Python!") 24 | 25 | test() 26 | ``` 27 | 28 | ## Data and Statistical Analysis 29 | 30 | Some text about data 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /tests/Makefile: -------------------------------------------------------------------------------- 1 | rst: 2 | pandoc sample.rst --filter ../pantcl.tcl -o sample-rst.html -s \ 3 | --metadata-file sample.yaml 4 | htmlark sample-rst.html -o sample-out.html 5 | mv sample-out.html sample-rst.html 6 | pandoc sample.rst --filter ../pantcl.tcl -o sample-rst.pdf --metadata documentclass=scrartcl \ 7 | --metadata-file sample.yaml 8 | tex: 9 | pandoc sample.tex --filter ../pantcl.tcl -o sample-tex.pdf \ 10 | --metadata documentclass=scrartcl --metadata-file sample.yaml 11 | rst-standalone: 12 | pandoc sample.rst -o sample-rst.md 13 | tclsh ../pantcl.tcl sample-rst.md sample-rst.html -s --css mini.css \ 14 | --metadata-file sample.yaml --no-pandoc 15 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Makefile CI 2 | on: 3 | workflow_dispatch: 4 | branches: [ master ] 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - uses: actions/checkout@v3 11 | 12 | 13 | #- name: Install dependencies 14 | # run: make 15 | 16 | - name: Make pantcl.tapp 17 | run: | 18 | mkdir pantcl-tapp 19 | make Makefile pantcl-app 20 | mkdir build 21 | cp pantcl-tapp/pantcl.bin build 22 | - name: Step 3 - Use the Upload Artifact GitHub Action 23 | uses: actions/upload-artifact@v3 24 | with: 25 | name: pantcl.bin 26 | path: build/pantcl.bin 27 | -------------------------------------------------------------------------------- /lib/textutil/pkgIndex.tcl: -------------------------------------------------------------------------------- 1 | if {![package vsatisfies [package provide Tcl] 8.2]} { 2 | # FRINK: nocheck 3 | return 4 | } 5 | package ifneeded textutil 0.8 [list source [file join $dir textutil.tcl]] 6 | package ifneeded textutil::adjust 0.7.3 [list source [file join $dir adjust.tcl]] 7 | package ifneeded textutil::split 0.8 [list source [file join $dir split.tcl]] 8 | package ifneeded textutil::trim 0.7 [list source [file join $dir trim.tcl]] 9 | package ifneeded textutil::tabify 0.7 [list source [file join $dir tabify.tcl]] 10 | package ifneeded textutil::repeat 0.7 [list source [file join $dir repeat.tcl]] 11 | package ifneeded textutil::string 0.8 [list source [file join $dir string.tcl]] 12 | package ifneeded textutil::expander 1.3.1 [list source [file join $dir expander.tcl]] 13 | -------------------------------------------------------------------------------- /lib/fview/snippets.txt: -------------------------------------------------------------------------------- 1 | snippet Markdown Main md: 2 | --- 3 | title: %cursor% 4 | author: Your Name 5 | date: 2023-01-01 6 | --- 7 | 8 | ## Introduction 9 | 10 | snippet Markdown dot md: 11 | ```{.dot eval=TRUE} 12 | digraph g { 13 | %cursor% 14 | A -> B ; 15 | } 16 | ``` 17 | 18 | snippet Markdown neato md: 19 | ```{.dot eval=TRUE} 20 | digraph g { 21 | %cursor% 22 | A -> B ; 23 | } 24 | ``` 25 | 26 | snippet Markdown rplot md: 27 | ```{.rplot eval=TRUE} 28 | %cursor% 29 | ``` 30 | 31 | snippet Graphviz Dot dot: 32 | %cursor% 33 | digraph g { 34 | A -> B ; 35 | } 36 | 37 | 38 | snippet Graphviz Neato dot: 39 | %cursor% 40 | graph g { 41 | A -- B ; 42 | } 43 | 44 | snippet Rplot Simple r: 45 | %cursor% 46 | plot(1) 47 | 48 | -------------------------------------------------------------------------------- /lib/snit/snit2.tcl: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------- 2 | # TITLE: 3 | # snit2.tcl 4 | # 5 | # AUTHOR: 6 | # Will Duquette 7 | # 8 | # DESCRIPTION: 9 | # Snit's Not Incr Tcl, a simple object system in Pure Tcl. 10 | # 11 | # Snit 2.x Loader 12 | # 13 | # Copyright (C) 2003-2006 by William H. Duquette 14 | # This code is licensed as described in license.txt. 15 | # 16 | #----------------------------------------------------------------------- 17 | 18 | package require Tcl 8.5 19 | 20 | # Define the snit namespace and save the library directory 21 | 22 | namespace eval ::snit:: { 23 | set library [file dirname [info script]] 24 | } 25 | 26 | # Load the kernel. 27 | source [file join $::snit::library main2.tcl] 28 | 29 | # Load the library of Snit validation types. 30 | source [file join $::snit::library validate.tcl] 31 | 32 | package provide snit 2.3.2 33 | -------------------------------------------------------------------------------- /lib/tclfilters/utils.tcl: -------------------------------------------------------------------------------- 1 | proc getTempDir {} { 2 | if {[file exists /tmp]} { 3 | # standard UNIX 4 | return /tmp 5 | } elseif {[info exists ::env(TMP)]} { 6 | # Windows 7 | return $::env(TMP) 8 | } elseif {[info exists ::env(TEMP)]} { 9 | # Windows 10 | return $::env(TEMP) 11 | } elseif {[info exists ::env(TMPDIR)]} { 12 | # OSX 13 | return $::env(TMPDIR) 14 | } 15 | } 16 | # convert a chunk start to a dictionary 17 | # ```{.mtex packages="sudoku"} 18 | proc chunk2dict {line} { 19 | set dchunk [dict create] 20 | set ind "" 21 | regexp {```\{\.([a-zA-Z0-9]+)\s*(.*).*\}.*} $line -> filt options 22 | foreach {op} [split $options " "] { 23 | foreach {key val} [split $op "="] { 24 | set val [regsub -all {"} $val ""] ;#" 25 | dict set dchunk $key $val 26 | } 27 | } 28 | return $dchunk 29 | } 30 | 31 | 32 | -------------------------------------------------------------------------------- /lib/dgw/pkgIndex.tcl: -------------------------------------------------------------------------------- 1 | # pkgIndex.tcl 2 | # mandatory packages 3 | package ifneeded dgw::dgw 0.7.0 [list source [file join $dir dgw.tcl]] 4 | package ifneeded dgw 0.7.0 [list source [file join $dir dgw.tcl]] 5 | package ifneeded dgw::basegui 0.3 [list source [file join $dir basegui.tcl]] 6 | package ifneeded dgw::combobox 0.2 [list source [file join $dir combobox.tcl]] 7 | package ifneeded dgw::dgwutils 0.3 [list source [file join $dir dgwutils.tcl]] 8 | package ifneeded dgw::drawcanvas 0.1 [list source [file join $dir drawcanvas.tcl]] 9 | package ifneeded dgw::sbuttonbar 0.6 [list source [file join $dir sbuttonbar.tcl]] 10 | package ifneeded dgw::seditor 0.3 [list source [file join $dir seditor.tcl]] 11 | package ifneeded dgw::sfinddialog 0.4 [list source [file join $dir sfinddialog.tcl]] 12 | package ifneeded dgw::statusbar 0.2 [list source [file join $dir statusbar.tcl]] 13 | package ifneeded dgw::tvmixins 0.3 [list source [file join $dir tvmixins.tcl]] 14 | package ifneeded dgw::txmixins 0.3.0 [list source [file join $dir txmixins.tcl]] 15 | 16 | 17 | -------------------------------------------------------------------------------- /header.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | Filters: 4 | [filter-abc](lib/tclfilters/filter-abc.html) - 5 | [filter-cmd](lib/tclfilters/filter-cmd.html) - 6 | [filter-dot](lib/tclfilters/filter-dot.html) - 7 | [filter-eqn](lib/tclfilters/filter-eqn.html) - 8 | [filter-mmd](lib/tclfilters/filter-mmd.html) - 9 | [filter-mtex](lib/tclfilters/filter-mtex.html) - 10 | [filter-pic](lib/tclfilters/filter-pic.html) - 11 | [filter-pik](lib/tclfilters/filter-pik.html) - 12 | [filter-pipe](lib/tclfilters/filter-pipe.html) - 13 | [filter-puml](lib/tclfilters/filter-puml.html) - 14 | [filter-rplot](lib/tclfilters/filter-rplot.html) - 15 | [filter-sqlite](lib/tclfilters/filter-sqlite.html) - 16 | [filter-tcrd](lib/tclfilters/filter-tcrd.html) - 17 | [filter-tcl](lib/tclfilters/filter-tcl.html) - 18 | [filter-tdot](lib/tclfilters/filter-tdot.html) - 19 | [filter-tsvg](lib/tclfilters/filter-tsvg.html)
20 | 21 | Documentation: 22 | [Pantcl documentation](pantcl.html) - 23 | [Pantcl Tutorial](pantcl-tutorial.html) - 24 | [Pantcl Readme](README.html) - 25 | [Pantcl GUI filter viewer](lib/fview/filter-view.html) 26 |
27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /lib/tclfilters/xkcd.tex: -------------------------------------------------------------------------------- 1 | \usepackage{fontspec} 2 | \setmainfont{Humor Sans} 3 | \usepackage{tikz} 4 | \usetikzlibrary{calc,decorations,patterns,arrows,decorations.pathmorphing} 5 | \definecolor{pltblue}{HTML}{1F77B4} 6 | 7 | \makeatletter 8 | \pgfset{ 9 | /pgf/decoration/randomness/.initial=2, 10 | /pgf/decoration/wavelength/.initial=100 11 | } 12 | \pgfdeclaredecoration{sketch}{init}{ 13 | \state{init}[width=0pt,next state=draw,persistent precomputation={ 14 | \pgfmathsetmacro\pgf@lib@dec@sketch@t0 15 | }]{} 16 | \state{draw}[width=\pgfdecorationsegmentlength, 17 | auto corner on length=\pgfdecorationsegmentlength, 18 | persistent precomputation={ 19 | \pgfmathsetmacro\pgf@lib@dec@sketch@t{mod(\pgf@lib@dec@sketch@t+pow(\pgfkeysvalueof{/pgf/decoration/randomness},rand),\pgfkeysvalueof{/pgf/decoration/wavelength})} 20 | }]{ 21 | \pgfmathparse{sin(2*\pgf@lib@dec@sketch@t*pi/\pgfkeysvalueof{/pgf/decoration/wavelength} r)} 22 | \pgfpathlineto{\pgfqpoint{\pgfdecorationsegmentlength}{\pgfmathresult\pgfdecorationsegmentamplitude}} 23 | } 24 | \state{final}{} 25 | } 26 | \tikzset{xkcd/.style={decorate,decoration={sketch,segment length=0.5pt,amplitude=0.5pt}}} 27 | \makeatother 28 | 29 | \pgfmathsetseed{1} 30 | 31 | \pagestyle{empty} 32 | 33 | -------------------------------------------------------------------------------- /lib/snit/snit.tcl: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------- 2 | # TITLE: 3 | # snit.tcl 4 | # 5 | # AUTHOR: 6 | # Will Duquette 7 | # 8 | # DESCRIPTION: 9 | # Snit's Not Incr Tcl, a simple object system in Pure Tcl. 10 | # 11 | # Snit 1.x Loader 12 | # 13 | # Copyright (C) 2003-2006 by William H. Duquette 14 | # This code is licensed as described in license.txt. 15 | # 16 | #----------------------------------------------------------------------- 17 | 18 | package require Tcl 8.3- 19 | 20 | # Define the snit namespace and save the library directory 21 | 22 | namespace eval ::snit:: { 23 | set library [file dirname [info script]] 24 | } 25 | 26 | # Select the implementation based on the version of the Tcl core 27 | # executing this code. For 8.3 we use a backport emulating various 28 | # 8.4 features 29 | 30 | if {[package vsatisfies [package provide Tcl] 8.4]} { 31 | source [file join $::snit::library main1.tcl] 32 | } else { 33 | source [file join $::snit::library main1_83.tcl] 34 | source [file join $::snit::library snit_tcl83_utils.tcl] 35 | } 36 | 37 | # Load the library of Snit validation types. 38 | 39 | source [file join $::snit::library validate.tcl] 40 | 41 | package provide snit 1.4.2 42 | -------------------------------------------------------------------------------- /lib/tclfilters/header.md: -------------------------------------------------------------------------------- 1 |
2 | [filter-abc](../tclfilters/filter-abc.html) - 3 | [filter-cmd](../tclfilters/filter-cmd.html) - 4 | [filter-dot](../tclfilters/filter-dot.html) - 5 | [filter-emf](../tclfilters/filter-emf.html) - 6 | [filter-eqn](../tclfilters/filter-eqn.html) - 7 | [filter-julia](../tclfilters/filter-julia.html) - 8 | [filter-kroki](../tclfilters/filter-kroki.html) - 9 | [filter-mmd](../tclfilters/filter-mmd.html) - 10 | [filter-mtex](../tclfilters/filter-mtex.html) - 11 | [filter-pic/dpic](../tclfilters/filter-pic.html) - 12 | [filter-pik](../tclfilters/filter-pik.html)
13 | [filter-pipe](../tclfilters/filter-pipe.html) - 14 | [filter-puml](../tclfilters/filter-puml.html) - 15 | [filter-rplot](../tclfilters/filter-rplot.html) - 16 | [filter-sqlite](../tclfilters/filter-sqlite.html) - 17 | [filter-tcrd](../tclfilters/filter-tcrd.html) - 18 | [filter-tcl](../tclfilters/filter-tcl.html) - 19 | [filter-tdot](../tclfilters/filter-tdot.html) - 20 | [filter-tsvg](../tclfilters/filter-tsvg.html) 21 | 22 | Documentation: 23 | [Pantcl filter documentation](../../pantcl.html) - 24 | [Pantcl tutorial](../../pantcl-tutorial.html) - 25 | [Pantcl Readme](../../README.html) - 26 | [Pantcl Gui](../fview/filter-view.html) 27 |
28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /lib/tclfilters/Makefile: -------------------------------------------------------------------------------- 1 | filter-docs: filter-abc.html \ 2 | filter-cmd.html \ 3 | filter-dot.html \ 4 | filter-emf.html \ 5 | filter-eqn.html \ 6 | filter-julia.html \ 7 | filter-kroki.html \ 8 | filter-mmd.html \ 9 | filter-mtex.html \ 10 | filter-pic.html \ 11 | filter-pik.html \ 12 | filter-pipe.html \ 13 | filter-puml.html \ 14 | filter-sqlite.html \ 15 | filter-tdot.html \ 16 | filter-tcrd.html \ 17 | filter-tsvg.html \ 18 | filter-rplot.html \ 19 | filter-tcl.html 20 | -rm -f temp* 21 | -rm -f mini*ly mini.p* out.json mini.svg hello* hw* links.md photo* 22 | -rm -f barplot* calc* doplot.R digraph* dot.png eqn.png math.eqn mesh*png file? 23 | -rm -f mini*png octave.png plot.R plotR.png pyhist.png sample* sin* 24 | -rm -f sqlite-?.sqlite test* 25 | %.html: %.tcl mini.css 26 | pandoc header.md -o header.html 27 | # -B header.html 28 | tclsh ../../pantcl.tcl $< temp.md --no-pandoc 29 | pandoc temp.md -o temp.html -s --css mini.css \ 30 | -M date="`date +"%b %d, %Y"`" --syntax-definition ../../xml/emf.xml 31 | htmlark temp.html -o `basename $< .tcl`.html 32 | rm temp.html 33 | 34 | julia: 35 | tclsh ../../pantcl.tcl julia-example.md temp.html -s --css mini.css \ 36 | -M date="`date +"%b %d, %Y"`" --syntax-definition ../../xml/emf.xml 37 | 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2023, D Groth 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /install-unix.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | OS=`uname | grep -Eo '^[A-Za-z]+'` 3 | BASEURL="https://github.com/mittelmark/pantcl/releases/download/v0.10.0/" 4 | KERNEL=`uname -r | grep -Eo '^[0-9]+'` 5 | 6 | if [[ `which tclsh` == "" ]]; then 7 | echo "Error: Tcl (tclsh) is not installed but required please install!" 8 | exit 9 | fi 10 | pantcl=pantcl.bin 11 | if [[ `which pandoc` == "" ]]; then 12 | echo "Missing pandoc, installing standalone application pantcl.mbin" 13 | pantcl=pantcl.mbin 14 | fi 15 | function install-pantcl { 16 | if [ ! -d ~/.local/bin ]; then 17 | mkdir -p ~/.local/bin 18 | fi 19 | # Check if ~/bin is already in the PATH 20 | if [[ ":$PATH:" != *":$HOME/.local/bin:"* ]]; then 21 | # If it's not in the PATH, add it to ~/.bashrc 22 | echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc 23 | # Update the PATH for the current session 24 | export PATH="$HOME/.local/bin:$PATH" 25 | echo "To update the current Bash session with the new PATH variable use: 'source ~/.bashrc'" 26 | fi 27 | URL=${BASEURL}$1 28 | echo "fetching $URL" 29 | curl -fsSL "${URL}" --output ~/.local/bin/pantcl 30 | chmod 755 ~/.local/bin/pantcl 31 | echo "Installation complete." 32 | } 33 | 34 | #/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/mittelmark/microemacs/refs/heads/master/install-linux.sh)" 35 | install-pantcl $pantcl 36 | -------------------------------------------------------------------------------- /lib/tclfilters/header.html: -------------------------------------------------------------------------------- 1 |
2 |

filter-abc - filter-cmd - filter-dot - filter-emf - filter-eqn - filter-julia - filter-kroki - filter-mmd - filter-mtex - filter-pic/dpic - filter-pik
filter-pipe - filter-puml - filter-rplot - filter-sqlite - filter-tcrd - filter-tcl - filter-tdot - filter-tsvg

21 | Documentation: Pantcl filter 22 | documentation - Pantcl 23 | tutorial - Pantcl Readme - Pantcl Gui 25 |
26 | -------------------------------------------------------------------------------- /lib/tclfilters/tclfilters.tcl: -------------------------------------------------------------------------------- 1 | package require Tcl 2 | 3 | package provide tclfilters 0.8.0 4 | 5 | source [file join [file dirname [info script]] utils.tcl] 6 | source [file join [file dirname [info script]] filter-tcl.tcl] 7 | source -encoding iso8859-1 [file join [file dirname [info script]] filter-abc.tcl] 8 | source -encoding ascii [file join [file dirname [info script]] filter-cmd.tcl] 9 | source [file join [file dirname [info script]] filter-dot.tcl] 10 | source [file join [file dirname [info script]] filter-emf.tcl] 11 | source [file join [file dirname [info script]] filter-eqn.tcl] 12 | source [file join [file dirname [info script]] filter-julia.tcl] 13 | source [file join [file dirname [info script]] filter-kroki.tcl] 14 | source [file join [file dirname [info script]] filter-mmd.tcl] 15 | source [file join [file dirname [info script]] filter-mtex.tcl] 16 | source [file join [file dirname [info script]] filter-pic.tcl] 17 | source [file join [file dirname [info script]] filter-pik.tcl] 18 | source [file join [file dirname [info script]] filter-pipe.tcl] 19 | source [file join [file dirname [info script]] filter-puml.tcl] 20 | source [file join [file dirname [info script]] filter-rplot.tcl] 21 | source [file join [file dirname [info script]] filter-sqlite.tcl] 22 | source -encoding iso8859-1 [file join [file dirname [info script]] filter-tcrd.tcl] 23 | source [file join [file dirname [info script]] filter-tdot.tcl] 24 | source [file join [file dirname [info script]] filter-tsvg.tcl] 25 | 26 | -------------------------------------------------------------------------------- /tests/sample.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | \usepackage{fancyvrb} 3 | \renewenvironment{verbatim}{% 4 | \verbatimenvironment 5 | \begin{verbatim}[breaklines,frame=single,gobble=2]% 6 | }{% 7 | \end{verbatim}% 8 | } 9 | \title{A sample LaTeX document} 10 | \author{Detlef Groth, University of Potsdam} 11 | \date{\today} 12 | 13 | \begin{document} 14 | 15 | \maketitle 16 | 17 | Hello LaTeX! 18 | 19 | Here a Tcl example: 20 | 21 | \begin{Verbatim}[filter=tcl,label=test,echo=true,eval=true] 22 | puts "Hello Tcl World!" 23 | set x 1 24 | set x 25 | \end{Verbatim} 26 | 27 | The value of x is \texttt{tcl set x}! 28 | And here a dot example: 29 | 30 | \begin{Verbatim}[filter=dot,eval=true] 31 | digraph g { 32 | rankdir="LR"; 33 | node[style=filled,fillcolor=skyblue,shape=box]; 34 | A -> B 35 | } 36 | \end{Verbatim} 37 | 38 | Now a Pic example: 39 | 40 | \begin{Verbatim}[filter=pic,eval=true] 41 | box wid 1.2 "Hello World!" fill 0.3; 42 | \end{Verbatim} 43 | 44 | This is some more text. 45 | 46 | Let's finish with some ditaa code: 47 | 48 | \begin{Verbatim}[filter=puml,eval=true,ext=png] 49 | @startditaa 50 | +---------+ /---------\ 51 | | cEEF | | cFEE | 52 | | A +----->>----+ B | 53 | | | | | 54 | +---------+ \---------/ 55 | @endditaa 56 | \end{Verbatim} 57 | 58 | We can as well hide the code and only show the figure by using 59 | \texttt{echo=false} as code chunk argument. 60 | 61 | \begin{Verbatim}[filter=puml,eval=true,echo=false] 62 | @startditaa 63 | /---------\ /---------\ 64 | | cEFF | | cFFE | 65 | | A +---<<->>---+ B | 66 | | | | | 67 | \---------/ \---------/ 68 | @endditaa 69 | \end{Verbatim} 70 | 71 | \end{document} 72 | -------------------------------------------------------------------------------- /xml/emf.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | define 6 | macro 7 | !emacro 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /tests/sample-yaml-header.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: this is a title 3 | author: Max Musterman, Unviversity of Musterciy, Germany 4 | date: 2023-05-25 5 | pipe: 6 | eval: 1 7 | --- 8 | 9 | 10 | ## Introduction 11 | 12 | Here an R-example: 13 | 14 | ```{r eval=TRUE,wait=400} 15 | data(iris) 16 | print("Hello R World!") 17 | ``` 18 | 19 | Here some inline text. The iris dataset has `R nrow(iris)` plants. 20 | 21 | Here an Python-example: 22 | 23 | ```{py eval=TRUE,terminal=FALSE} 24 | def test(): 25 | print("Python!") 26 | 27 | y=1 28 | test() 29 | ``` 30 | 31 | Here a Python inline code example - y is: `py y`! 32 | 33 | ## Plots 34 | 35 | ```{r fig=TRUE results="hide"} 36 | png('tests/pie.png') 37 | par(mai=c(0.3,0.3,0.3,0.1)) 38 | pie(4:8,col=rainbow(5)) 39 | dev.off() 40 | ``` 41 | 42 | ![](pie.png) 43 | 44 | ```{py terminal=FALSE,results="hide",wait=1000} 45 | import matplotlib.pyplot as plt 46 | 47 | # die X-Werte: 48 | days = list(range(0, 22, 3)) 49 | print(days) 50 | # die Y-Werte: 51 | celsius_values = [25.6, 24.1, 26.7, 28.3, 27.5, 30.5, 32.8, 33.1] 52 | 53 | plt.plot(days, celsius_values) 54 | plt.savefig("tests/pyplot.png") 55 | ``` 56 | 57 | ![](pyplot.png) 58 | 59 | ## Tables 60 | 61 | ```{r results="asis",terminal=FALSE} 62 | df_2_MD <- function(your_df){ 63 | cn <- as.character(names(your_df)) 64 | headr <- paste0(c("", cn), sep = "|", collapse='') 65 | sepr <- paste0(c('|', rep(paste0(c(rep('-',3), "|"), collapse=''),length(cn))), collapse ='') 66 | st <- "|" 67 | for (i in 1:nrow(your_df)){ 68 | for(j in 1:ncol(your_df)){ 69 | if (j%%ncol(your_df) == 0) { 70 | st <- paste0(st, as.character(your_df[i,j]), "|", "\n", "" , "|", collapse = '') 71 | } else { 72 | st <- paste0(st, as.character(your_df[i,j]), "|", collapse = '') 73 | } 74 | } 75 | } 76 | fin <- paste0(c(headr, sepr, substr(st,1,nchar(st)-1)), collapse="\n") 77 | cat(fin) 78 | } 79 | 80 | 81 | # run function 82 | short_iris <- iris[1:4,1:5] 83 | df_2_MD(short_iris) 84 | write.table(head(iris,10),file="sample.csv",sep=",") 85 | ``` 86 | 87 | Now an example with Python: 88 | 89 | ```{py results="asis",terminal=FALSE} 90 | import pandas as pd 91 | file = 'sample.csv' 92 | df = pd.read_csv(file) 93 | print(df.to_markdown()) 94 | ``` 95 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /lib/textutil/repeat.tcl: -------------------------------------------------------------------------------- 1 | # repeat.tcl -- 2 | # 3 | # Emulation of string repeat for older 4 | # revisions of Tcl. 5 | # 6 | # Copyright (c) 2000 by Ajuba Solutions. 7 | # Copyright (c) 2001-2006 by Andreas Kupries 8 | # 9 | # See the file "license.terms" for information on usage and redistribution 10 | # of this file, and for a DISCLAIMER OF ALL WARRANTIES. 11 | # 12 | # RCS: @(#) $Id: repeat.tcl,v 1.1 2006/04/21 04:42:28 andreas_kupries Exp $ 13 | 14 | # ### ### ### ######### ######### ######### 15 | ## Requirements 16 | 17 | package require Tcl 8.2 18 | 19 | namespace eval ::textutil::repeat {} 20 | 21 | # ### ### ### ######### ######### ######### 22 | 23 | namespace eval ::textutil::repeat { 24 | variable HaveBuiltin [expr {![catch {string repeat a 1}]}] 25 | } 26 | 27 | if {0} { 28 | # Problems with the deactivated code: 29 | # - Linear in 'num'. 30 | # - Tests for 'string repeat' in every call! 31 | # (Ok, just the variable, still a test every call) 32 | # - Fails for 'num == 0' because of undefined 'str'. 33 | 34 | proc textutil::repeat::StrRepeat { char num } { 35 | variable HaveBuiltin 36 | if { $HaveBuiltin == 0 } then { 37 | for { set i 0 } { $i < $num } { incr i } { 38 | append str $char 39 | } 40 | } else { 41 | set str [ string repeat $char $num ] 42 | } 43 | return $str 44 | } 45 | } 46 | 47 | if {$::textutil::repeat::HaveBuiltin} { 48 | proc ::textutil::repeat::strRepeat {char num} { 49 | return [string repeat $char $num] 50 | } 51 | 52 | proc ::textutil::repeat::blank {n} { 53 | return [string repeat " " $n] 54 | } 55 | } else { 56 | proc ::textutil::repeat::strRepeat {char num} { 57 | if {$num <= 0} { 58 | # No replication required 59 | return "" 60 | } elseif {$num == 1} { 61 | # Quick exit for recursion 62 | return $char 63 | } elseif {$num == 2} { 64 | # Another quick exit for recursion 65 | return $char$char 66 | } elseif {0 == ($num % 2)} { 67 | # Halving the problem results in O (log n) complexity. 68 | set result [strRepeat $char [expr {$num / 2}]] 69 | return "$result$result" 70 | } else { 71 | # Uneven length, reduce problem by one 72 | return "$char[strRepeat $char [incr num -1]]" 73 | } 74 | } 75 | 76 | proc ::textutil::repeat::blank {n} { 77 | return [strRepeat " " $n] 78 | } 79 | } 80 | 81 | # ### ### ### ######### ######### ######### 82 | ## Data structures 83 | 84 | namespace eval ::textutil::repeat { 85 | namespace export strRepeat blank 86 | } 87 | 88 | # ### ### ### ######### ######### ######### 89 | ## Ready 90 | 91 | package provide textutil::repeat 0.7 92 | -------------------------------------------------------------------------------- /lib/rl_json/mini.css: -------------------------------------------------------------------------------- 1 | html { 2 | overflow-y: scroll; 3 | } 4 | body { 5 | color: #444; 6 | font-family: Georgia, Palatino, 'Palatino Linotype', Times, 'Times New Roman', serif; 7 | line-height: 1.2; 8 | padding: 1em; 9 | margin: auto; 10 | max-width: 1200px; 11 | } 12 | a { 13 | color: #0645ad; 14 | text-decoration: none; 15 | } 16 | a:visited { 17 | color: #0b0080; 18 | } 19 | a:hover { 20 | color: #06e; 21 | } 22 | a:active { 23 | color: #faa700; 24 | } 25 | a:focus { 26 | outline: thin dotted; 27 | } 28 | p { 29 | margin: 0.5em 0; 30 | } 31 | p.date { 32 | text-align: center; 33 | } 34 | img { 35 | max-width: 100%; 36 | } 37 | 38 | h1, h2, h3, h4, h5, h6 { 39 | color: #111; 40 | line-height: 115%; 41 | margin-top: 1em; 42 | font-weight: normal; 43 | } 44 | h1 { 45 | text-align: center; 46 | } 47 | 48 | h2 { 49 | text-transform: uppercase; 50 | } 51 | pre, blockquote pre { 52 | border-top: 0.1em #9ac solid; 53 | background: #e9f6ff; 54 | padding: 10px; 55 | border-bottom: 0.1em #9ac solid; 56 | } 57 | 58 | blockquote { 59 | margin: 0; 60 | padding-left: 3em; 61 | } 62 | 63 | hr { 64 | display: block; 65 | height: 2px; 66 | border: 0; 67 | border-top: 1px solid #aaa; 68 | border-bottom: 1px solid #eee; 69 | margin: 1em 0; 70 | padding: 0; 71 | } 72 | 73 | pre, code, kbd, samp { 74 | color: #000; 75 | font-family: Monaco, 'courier new', monospace; 76 | font-size: 90%; 77 | } 78 | 79 | pre { 80 | white-space: pre; 81 | white-space: pre-wrap; 82 | word-wrap: break-word; 83 | } 84 | /* fix, do not like bold for every keyword */ 85 | code span.kw { color: #007020; font-weight: normal; } /* Keyword */ 86 | pre.sourceCode { 87 | background: #fff6f6; 88 | } 89 | figure, p.author { 90 | text-align: center; 91 | } 92 | table { 93 | min-width: 300px; 94 | border-spacing: 0; 95 | border-collapse: collapse; 96 | cell-padding: 0px; 97 | cell-spacing: 0px; 98 | } 99 | tr.header { 100 | background: #dddddd; 101 | text-align: center; 102 | } 103 | tr.even { 104 | background: #ddeeff; 105 | } 106 | td, th { 107 | padding: 3px; 108 | text-align: center; 109 | } 110 | -------------------------------------------------------------------------------- /lib/textutil/textutil.tcl: -------------------------------------------------------------------------------- 1 | # textutil.tcl -- 2 | # 3 | # Utilities for manipulating strings, words, single lines, 4 | # paragraphs, ... 5 | # 6 | # Copyright (c) 2000 by Ajuba Solutions. 7 | # Copyright (c) 2000 by Eric Melski 8 | # Copyright (c) 2002 by Joe English 9 | # Copyright (c) 2001-2006 by Andreas Kupries 10 | # 11 | # See the file "license.terms" for information on usage and redistribution 12 | # of this file, and for a DISCLAIMER OF ALL WARRANTIES. 13 | # 14 | # RCS: @(#) $Id: textutil.tcl,v 1.17 2006/09/21 06:46:24 andreas_kupries Exp $ 15 | 16 | # ### ### ### ######### ######### ######### 17 | ## Requirements 18 | 19 | package require Tcl 8.2 20 | 21 | namespace eval ::textutil {} 22 | 23 | # ### ### ### ######### ######### ######### 24 | ## API implementation 25 | ## All through sub-packages imported here. 26 | 27 | package require textutil::string 28 | package require textutil::repeat 29 | package require textutil::adjust 30 | package require textutil::split 31 | package require textutil::tabify 32 | package require textutil::trim 33 | 34 | namespace eval ::textutil { 35 | # Import the miscellaneous string command for public export 36 | 37 | namespace import -force string::chop string::tail 38 | namespace import -force string::cap string::uncap string::capEachWord 39 | namespace import -force string::longestCommonPrefix 40 | namespace import -force string::longestCommonPrefixList 41 | 42 | # Import the repeat commands for public export 43 | 44 | namespace import -force repeat::strRepeat repeat::blank 45 | 46 | # Import the adjust commands for public export 47 | 48 | namespace import -force adjust::adjust adjust::indent adjust::undent 49 | 50 | # Import the split commands for public export 51 | 52 | namespace import -force split::splitx split::splitn 53 | 54 | # Import the trim commands for public export 55 | 56 | namespace import -force trim::trim trim::trimleft trim::trimright 57 | namespace import -force trim::trimPrefix trim::trimEmptyHeading 58 | 59 | # Import the tabify commands for public export 60 | 61 | namespace import -force tabify::tabify tabify::untabify 62 | namespace import -force tabify::tabify2 tabify::untabify2 63 | 64 | # Re-export all the imported commands 65 | 66 | namespace export chop tail cap uncap capEachWord 67 | namespace export longestCommonPrefix longestCommonPrefixList 68 | namespace export strRepeat blank 69 | namespace export adjust indent undent 70 | namespace export splitx splitn 71 | namespace export trim trimleft trimright trimPrefix trimEmptyHeading 72 | namespace export tabify untabify tabify2 untabify2 73 | } 74 | 75 | 76 | # ### ### ### ######### ######### ######### 77 | ## Ready 78 | 79 | package provide textutil 0.8 80 | -------------------------------------------------------------------------------- /mini.css: -------------------------------------------------------------------------------- 1 | html { 2 | overflow-y: scroll; 3 | } 4 | body { 5 | color: #444; 6 | font-family: Georgia, Palatino, 'Palatino Linotype', Times, 'Times New Roman', serif; 7 | line-height: 1.2; 8 | padding: 1em; 9 | margin: auto; 10 | max-width: 900px; 11 | } 12 | a { 13 | color: #0645ad; 14 | text-decoration: none; 15 | } 16 | a:visited { 17 | color: #0b0080; 18 | } 19 | a:hover { 20 | color: #06e; 21 | } 22 | a:active { 23 | color: #faa700; 24 | } 25 | a:focus { 26 | outline: thin dotted; 27 | } 28 | p { 29 | margin: 0.5em 0; 30 | } 31 | p.date { 32 | text-align: center; 33 | } 34 | img { 35 | max-width: 100%; 36 | } 37 | 38 | h1, h2, h3, h4, h5, h6 { 39 | color: #111; 40 | line-height: 115%; 41 | margin-top: 1em; 42 | font-weight: normal; 43 | } 44 | h1 { 45 | text-align: center; 46 | font-size: 120%; 47 | } 48 | h2.author, h2.date { 49 | text-align:center; 50 | font-size: 100% 51 | } 52 | p.author, p.date { 53 | font-size: 110%; 54 | } 55 | 56 | /* h2 { 57 | text-transform: uppercase; 58 | } 59 | */ 60 | pre, blockquote pre { 61 | border-top: 0.1em #9ac solid; 62 | background: #e9f6ff; 63 | padding: 10px; 64 | border-bottom: 0.1em #9ac solid; 65 | } 66 | 67 | blockquote { 68 | margin: 0; 69 | padding-left: 3em; 70 | } 71 | 72 | hr { 73 | display: block; 74 | height: 2px; 75 | border: 0; 76 | border-top: 1px solid #aaa; 77 | border-bottom: 1px solid #eee; 78 | margin: 1em 0; 79 | padding: 0; 80 | } 81 | 82 | pre, code, kbd, samp { 83 | color: #000; 84 | font-family: Monaco, 'courier new', monospace; 85 | font-size: 90%; 86 | } 87 | code.r { 88 | color: #770000; 89 | } 90 | pre:has(code.tclout) { 91 | background: #ffeeee; 92 | } 93 | pre { 94 | white-space: pre; 95 | white-space: pre-wrap; 96 | word-wrap: break-word; 97 | } 98 | /* fix, do not like bold for every keyword */ 99 | code span.kw { color: #007020; font-weight: normal; } /* Keyword */ 100 | pre.sourceCode { 101 | background: #fff6f6; 102 | } 103 | figure, p.author { 104 | text-align: center; 105 | } 106 | table { 107 | border-collapse: collapse; 108 | border-bottom: 2px solid; 109 | border-spacing: 5px; 110 | min-width: 400px; 111 | } 112 | table thead tr th { 113 | background-color: #fde9d9; 114 | text-align: left; 115 | padding: 10px; 116 | border-top: 2px solid; 117 | border-bottom: 2px solid; 118 | } 119 | table td { 120 | background-color: #fff9e9; 121 | 122 | text-align: left; 123 | padding: 10px; 124 | } 125 | -------------------------------------------------------------------------------- /lib/tdot/tdot-example.tcl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env tclsh 2 | ############################################################################## 3 | # 4 | # Author : Dr. Detlef Groth 5 | # Created By : Dr. Detlef Groth 6 | # Created : Sat Sep 25 19:13:12 2021 7 | # Last Modified : <210926.0715> 8 | # 9 | # Description 10 | # 11 | # Notes 12 | # 13 | # History 14 | # 15 | ############################################################################## 16 | # 17 | # Copyright (c) 2021 Dr. Detlef Groth. 18 | # 19 | # License: MIT 20 | # 21 | ############################################################################## 22 | 23 | 24 | package require Tcl 25 | 26 | source [file join [file dirname [info script]] tdot.tcl] 27 | 28 | tdot graph margin=0.3 29 | tdot graph size="8\;7" ;# semikolon must be backslashed 30 | tdot node shape=box style=filled fillcolor=grey width=1 31 | tdot addEdge 1988 -> 1993 -> 1995 -> 1997 -> 1999 \ 32 | -> 2000 -> 2002 -> 2007 -> 2012 -> future 33 | tdot node fillcolor="#ff9999" 34 | tdot edge style=invis 35 | tdot addEdge Tk -> Bytecode -> Unicode -> TEA -> vfs -> \ 36 | Tile -> TclOO -> zipvfs 37 | tdot edge style=filled 38 | tdot node fillcolor="salmon" 39 | tdot addEdge "Tcl/Tk" -> 7.3 -> 7.4 -> 8.0 -> 8.1 -> 8.3 \ 40 | -> 8.4 -> 8.5 -> 8.6 -> 8.7; 41 | tdot node fillcolor=cornsilk 42 | tdot addEdge 7.3 -> Itcl -> 8.6 43 | tdot addEdge Tk -> 7.4 -> Otcl -> XOTcl -> NX 44 | tdot addEdge Otcl -> Thingy -> tdot 45 | tdot addEdge Bytecode -> 8.0 46 | tdot addEdge 8.0 -> Namespace dir=back 47 | tdot addEdge Unicode -> 8.1 48 | tdot addEdge 8.1 -> Wiki 49 | tdot addEdge TEA -> 8.3 50 | tdot addEdge 8.3 -> Tcllib -> Tklib 51 | tdot addEdge 8.4 -> Starkit -> Snit -> Dict -> 8.5 52 | tdot addEdge vfs -> 8.4 53 | tdot addEdge Tile -> 8.5 54 | tdot addEdge TclOO -> 8.6 -> TDBC 55 | tdot addEdge zipvfs -> 8.7 -> Null ;# Null is just a placeholder for the history 56 | tdot block rank=same 1988 "Tcl/Tk" group=g1 57 | tdot block rank=same 1993 7.3 group=g1 Itcl 58 | tdot block rank=same 1995 Tk group=g0 7.4 group=g1 Otcl group=g2 59 | tdot block rank=same 1997 Bytecode group=g0 8.0 group=g1 Namespace 60 | tdot block rank=same 1999 Unicode group=g0 8.1 group=g1 Wiki 61 | tdot block rank=same 2000 TEA group=g0 8.3 group=g1 Tcllib \ 62 | Tklib XOTcl group=g2 63 | tdot block rank=same 2002 vfs group=g0 8.4 group=g1 Starkit Dict Snit 64 | tdot block rank=same 2007 Tile group=g0 8.5 group=g1 65 | tdot block rank=same 2012 TclOO group=g0 8.6 group=g1 TDBC NX group=g2 66 | tdot block rank=same future zipvfs group=g0 8.7 group=g1 Null group=g2 tdot group=g3 67 | 68 | # specific node settings 69 | tdot node History label="History of Tcl/Tk\nand tdot" shape=doubleoctagon color="salmon" penwidth=5 \ 70 | fillcolor="white" fontsize=26 fontname="Monaco" 71 | tdot node Namespace fillcolor="#ff9999" 72 | tdot node future label=2021 73 | tdot node 8.7 label="8.7a5" 74 | # arranging the History in the middle 75 | tdot addEdge 8.7 -> Null style=invis 76 | tdot addEdge Null -> History style=invis 77 | tdot node Null style=invis 78 | tdot write tdot-history.png 79 | -------------------------------------------------------------------------------- /lib/textutil/trim.tcl: -------------------------------------------------------------------------------- 1 | # trim.tcl -- 2 | # 3 | # Various ways of trimming a string. 4 | # 5 | # Copyright (c) 2000 by Ajuba Solutions. 6 | # Copyright (c) 2000 by Eric Melski 7 | # Copyright (c) 2001-2006 by Andreas Kupries 8 | # 9 | # See the file "license.terms" for information on usage and redistribution 10 | # of this file, and for a DISCLAIMER OF ALL WARRANTIES. 11 | # 12 | # RCS: @(#) $Id: trim.tcl,v 1.5 2006/04/21 04:42:28 andreas_kupries Exp $ 13 | 14 | # ### ### ### ######### ######### ######### 15 | ## Requirements 16 | 17 | package require Tcl 8.2 18 | 19 | namespace eval ::textutil::trim {} 20 | 21 | # ### ### ### ######### ######### ######### 22 | ## API implementation 23 | 24 | proc ::textutil::trim::trimleft {text {trim "[ \t]+"}} { 25 | regsub -line -all -- [MakeStr $trim left] $text {} text 26 | return $text 27 | } 28 | 29 | proc ::textutil::trim::trimright {text {trim "[ \t]+"}} { 30 | regsub -line -all -- [MakeStr $trim right] $text {} text 31 | return $text 32 | } 33 | 34 | proc ::textutil::trim::trim {text {trim "[ \t]+"}} { 35 | regsub -line -all -- [MakeStr $trim left] $text {} text 36 | regsub -line -all -- [MakeStr $trim right] $text {} text 37 | return $text 38 | } 39 | 40 | 41 | 42 | # @c Strips from , if found at its start. 43 | # 44 | # @a text: The string to check for . 45 | # @a prefix: The string to remove from . 46 | # 47 | # @r The , but without . 48 | # 49 | # @i remove, prefix 50 | 51 | proc ::textutil::trim::trimPrefix {text prefix} { 52 | if {[string first $prefix $text] == 0} { 53 | return [string range $text [string length $prefix] end] 54 | } else { 55 | return $text 56 | } 57 | } 58 | 59 | 60 | # @c Removes the Heading Empty Lines of . 61 | # 62 | # @a text: The text block to manipulate. 63 | # 64 | # @r The , but without heading empty lines. 65 | # 66 | # @i remove, empty lines 67 | 68 | proc ::textutil::trim::trimEmptyHeading {text} { 69 | regsub -- "^(\[ \t\]*\n)*" $text {} text 70 | return $text 71 | } 72 | 73 | # ### ### ### ######### ######### ######### 74 | ## Helper commands. Internal 75 | 76 | proc ::textutil::trim::MakeStr { string pos } { 77 | variable StrU 78 | variable StrR 79 | variable StrL 80 | 81 | if { "$string" != "$StrU" } { 82 | set StrU $string 83 | set StrR "(${StrU})\$" 84 | set StrL "^(${StrU})" 85 | } 86 | if { "$pos" == "left" } { 87 | return $StrL 88 | } 89 | if { "$pos" == "right" } { 90 | return $StrR 91 | } 92 | 93 | return -code error "Panic, illegal position key \"$pos\"" 94 | } 95 | 96 | # ### ### ### ######### ######### ######### 97 | ## Data structures 98 | 99 | namespace eval ::textutil::trim { 100 | variable StrU "\[ \t\]+" 101 | variable StrR "(${StrU})\$" 102 | variable StrL "^(${StrU})" 103 | 104 | namespace export \ 105 | trim trimright trimleft \ 106 | trimPrefix trimEmptyHeading 107 | } 108 | 109 | # ### ### ### ######### ######### ######### 110 | ## Ready 111 | 112 | package provide textutil::trim 0.7 113 | -------------------------------------------------------------------------------- /tests/sample.rst: -------------------------------------------------------------------------------- 1 | ############# 2 | Rst Example 3 | ############# 4 | 5 | The text below will contain the following examples: 6 | 7 | * Tcl code blocks 8 | * Tcl inline codes 9 | * R code blocks using the pipe filter 10 | * R inline codes 11 | * GraphViz Dot code blocks 12 | * Kroki code blocks 13 | 14 | This document was created using the following command line: 15 | 16 | .. code-block:: bash 17 | 18 | pandoc sample.rst --filter pantcl -o sample-rst.html -s \ 19 | --metadata-file sample.yaml 20 | 21 | For pdf creation we used a command line like this: 22 | 23 | .. code-block:: bash 24 | 25 | pandoc sample.rst --filter ../pantcl.tcl -o sample-rst.pdf --metadata \ 26 | documentclass=scrartcl --metadata-file sample.yaml 27 | 28 | Here the source code of the rst-document: 29 | ``_ 30 | 31 | ************* 32 | Tcl Code 33 | ************* 34 | 35 | Let's now try Tcl code blocks: 36 | 37 | 38 | .. code-block:: tcl 39 | :caption: Tcl-code 40 | :eval: true 41 | 42 | set x 1 43 | puts $x 44 | incr x 45 | 46 | 47 | 48 | Now some more text with inline Tcl x is now ``tcl set x``! 49 | 50 | ************* 51 | R Code 52 | ************* 53 | 54 | Now some R code: 55 | 56 | .. code-block:: rplot 57 | :eval: true 58 | 59 | r = 1 60 | print(r) 61 | plot(1) 62 | 63 | 64 | For more fine tuned output it is recommend to use the pipe filter like this: 65 | 66 | .. code-block:: pipe 67 | :eval: true 68 | :pipe: R 69 | 70 | x=2 71 | png("sample.png") 72 | plot(1:20,pch=1:20,cex=2,col=rainbow(20)) 73 | dev.off() 74 | 75 | 76 | .. image:: sample.png 77 | :width: 400 78 | :alt: Alternative text 79 | 80 | As this filter does not automatically include the image we write here a PNG 81 | file using the ``png`` command. The `pipe` filter allows as well to have a 82 | continued session over all code chunks. Let's access for instance now the x 83 | variable in a next code chunk: 84 | 85 | .. code-block:: pipe 86 | :eval: true 87 | :pipe: R 88 | 89 | print(x) 90 | 91 | 92 | OK, this should display a two even if x was declared in the previous chunk. 93 | 94 | 95 | ******************** 96 | GraphViz dot example 97 | ******************** 98 | 99 | Let's continue with a GraphViz dot example: 100 | 101 | .. code-block:: dot 102 | :caption: GraphViz dot example 103 | :eval: false 104 | 105 | digraph g { 106 | A -> B ; 107 | } 108 | 109 | 110 | 111 | *************** 112 | Kroki example 113 | *************** 114 | 115 | .. code-block:: kroki 116 | :caption: kroki example 117 | :eval: true 118 | 119 | digraph g { 120 | graph[size="8.0,4.0!",scale="3.0!"]; 121 | rankdir="LR"; 122 | node[style=filled,fillcolor=skyblue,shape=box]; 123 | A -> B -> C; 124 | } 125 | 126 | 127 | Now an example where we hide the source code which should be normal if we like 128 | only to show the image but not the code: 129 | 130 | .. code-block:: kroki 131 | :caption: kroki example 132 | :eval: true 133 | :echo: false 134 | 135 | digraph g { 136 | 137 | rankdir="LR"; 138 | node[style=filled,fillcolor=salmon,shape=box]; 139 | A -> B -> C; 140 | } 141 | 142 | 143 | That's the end of this short example on how to use `Rst` files with some of the 144 | `pantcl` filters. 145 | 146 | 147 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | sdx=/home/groth/workspace/delfgroth/mytcl/bin/sdx.kit 2 | default: 3 | echo "Usage: make pantcl-docu" 4 | echo " make pantcl-app" 5 | echo " make install" 6 | 7 | docu: 8 | FILTEREVAL=1 TCLLIBPATH=lib tclsh pantcl.tcl pantcl.tcl pantcl.html --no-pandoc 9 | 10 | pantcl-docu: 11 | pandoc header.md -o header.html 12 | TCLLIBPATH=lib tclsh pantcl.tcl pantcl.tcl pantcl.md --no-pandoc 13 | pandoc pantcl.md -o pantcl.html --css mini.css -s 14 | htmlark pantcl.html -o pantcl-out.html 15 | mv pantcl-out.html pantcl.html 16 | echo done 17 | tclsh pantcl.tcl pantcl-tutorial.md pantcl-tutorial-out.md --no-pandoc 18 | pandoc pantcl-tutorial-out.md -o pantcl-tutorial.html -s --css mini.css --toc \ 19 | --lua-filter=lib/tclfilters/smallcaps.lua 20 | htmlark pantcl-tutorial.html -o pantcl-out.html 21 | mv pantcl-out.html pantcl-tutorial.html 22 | pandoc README.md -o README.html --css mini.css -s --metadata title="Pantcl README" --metadata author="Detlef Groth" --metadata date="`date +%Y-%m-%d`" 23 | htmlark README.html -o temp.html && mv temp.html README.html 24 | 25 | 26 | pantcl-app: 27 | if [ ! -d pantcl-tapp ] ; then mkdir pantcl-tapp ; fi 28 | cp pantcl.tcl pantcl-tapp/ 29 | -rm -rf pantcl-tapp/pantcl.vfs 30 | if [ ! -d pantcl-tapp/pantcl.vfs ] ; then mkdir pantcl-tapp/pantcl.vfs ; fi 31 | echo "lappend auto_path [file normalize [file join [file dirname [info script]] lib]]" > pantcl-tapp/pantcl.vfs/main.tcl 32 | if [ ! -d pantcl-tapp/pantcl.vfs/lib ] ; then mkdir pantcl-tapp/pantcl.vfs/lib ; fi 33 | cp -r lib/* pantcl-tapp/pantcl.vfs/lib/ 34 | rm -f pantcl-tapp/pantcl.vfs/lib/*/*~ 35 | rm -f pantcl-tapp/pantcl.vfs/lib/*/*md 36 | rm -f pantcl-tapp/pantcl.vfs/lib/*/*.ly 37 | rm -f pantcl-tapp/pantcl.vfs/lib/*/*.R 38 | rm -f pantcl-tapp/pantcl.vfs/lib/*/*lua 39 | rm -f pantcl-tapp/pantcl.vfs/lib/*/*.n 40 | rm -f pantcl-tapp/pantcl.vfs/lib/*/*.dot 41 | rm -f pantcl-tapp/pantcl.vfs/lib/*/*.svg 42 | rm -f pantcl-tapp/pantcl.vfs/lib/*/*.png 43 | rm -f pantcl-tapp/pantcl.vfs/lib/*/*.html 44 | rm -f pantcl-tapp/pantcl.vfs/lib/*/*.css 45 | rm -f pantcl-tapp/pantcl.vfs/lib/*/*.pdf 46 | rm -rf pantcl-tapp/pantcl.vfs/lib/tclfilters/figures 47 | rm -rf pantcl-tapp/pantcl.vfs/lib/tclfilters/images 48 | rm -rf pantcl-tapp/pantcl.vfs/lib/tclfilters/out 49 | ## just 100k 50 | #rm pantcl-tapp/pantcl.vfs/lib/snit/main1*.tcl 51 | #perl -i -pe "s/^#'.+//" pantcl-tapp/pantcl.vfs/lib/tclfilters/*.tcl 52 | cd pantcl-tapp && tclsh ../bin/tpack.tcl wrap pantcl.tapp --lz4 53 | ls -lh pantcl-tapp/pantcl.tapp 54 | cp pantcl-tapp/pantcl.tapp pantcl-tapp/pantcl.bin 55 | rm -rf pantcl-tapp/pantcl.vfs/lib/rl_json 56 | cd pantcl-tapp && tclsh ../bin/tpack.tcl wrap pantcl.tapp --lz4 57 | ls -lh pantcl-tapp/pantcl.tapp 58 | cp pantcl-tapp/pantcl.tapp pantcl-tapp/pantcl.mbin 59 | install: pantcl-app 60 | cp pantcl-tapp/pantcl.tapp ~/.local/bin/pantcl 61 | chmod 755 ~/.local/bin/pantcl 62 | 63 | winexe: pantcl-app 64 | cp pantcl.tcl pantcl-tapp/pantcl.vfs/main.tcl 65 | cd pantcl-tapp && tclkit $(sdx) wrap pantcl.exe -runtime tclkit-8.6.12.exe 66 | 67 | starkit: pantcl-app 68 | cp pantcl.tcl pantcl-tapp/pantcl.vfs/main.tcl 69 | cd pantcl-tapp && tclkit $(sdx) wrap pantcl.kit 70 | 71 | tests-docs: 72 | echo "knitr::knit('tests/sample-pandoc-header.Rmd','tests/sample-pandoc-header.md')" | Rscript - 73 | pandoc tests/sample-pandoc-header.md -o tests/sample-pandoc-header.html -s --css mini.css 74 | tclsh pantcl.tcl tests/sample-pandoc-header.Rmd tests/sample-pandoc-header-pantcl.html --no-pandoc 75 | tclsh pantcl.tcl tests/sample-yaml-header.Rmd tests/sample-yaml-header.html --no-pandoc 76 | -------------------------------------------------------------------------------- /lib/textutil/string.tcl: -------------------------------------------------------------------------------- 1 | # string.tcl -- 2 | # 3 | # Utilities for manipulating strings, words, single lines, 4 | # paragraphs, ... 5 | # 6 | # Copyright (c) 2000 by Ajuba Solutions. 7 | # Copyright (c) 2000 by Eric Melski 8 | # Copyright (c) 2002 by Joe English 9 | # Copyright (c) 2001-2014 by Andreas Kupries 10 | # 11 | # See the file "license.terms" for information on usage and redistribution 12 | # of this file, and for a DISCLAIMER OF ALL WARRANTIES. 13 | # 14 | # RCS: @(#) $Id: string.tcl,v 1.2 2008/03/22 16:03:11 mic42 Exp $ 15 | 16 | # ### ### ### ######### ######### ######### 17 | ## Requirements 18 | 19 | package require Tcl 8.2 20 | 21 | namespace eval ::textutil::string {} 22 | 23 | # ### ### ### ######### ######### ######### 24 | ## API implementation 25 | 26 | # @c Removes the last character from the given . 27 | # 28 | # @a string: The string to manipulate. 29 | # 30 | # @r The without its last character. 31 | # 32 | # @i chopping 33 | 34 | proc ::textutil::string::chop {string} { 35 | return [string range $string 0 [expr {[string length $string]-2}]] 36 | } 37 | 38 | # @c Removes the first character from the given . 39 | # @c Convenience procedure. 40 | # 41 | # @a string: string to manipulate. 42 | # 43 | # @r The without its first character. 44 | # 45 | # @i tail 46 | 47 | proc ::textutil::string::tail {string} { 48 | return [string range $string 1 end] 49 | } 50 | 51 | # @c Capitalizes first character of the given . 52 | # @c Complementary procedure to

. 53 | # 54 | # @a string: string to manipulate. 55 | # 56 | # @r The with its first character capitalized. 57 | # 58 | # @i capitalize 59 | 60 | proc ::textutil::string::cap {string} { 61 | return [string toupper [string index $string 0]][string range $string 1 end] 62 | } 63 | 64 | # @c unCapitalizes first character of the given . 65 | # @c Complementary procedure to

. 66 | # 67 | # @a string: string to manipulate. 68 | # 69 | # @r The with its first character uncapitalized. 70 | # 71 | # @i uncapitalize 72 | 73 | proc ::textutil::string::uncap {string} { 74 | return [string tolower [string index $string 0]][string range $string 1 end] 75 | } 76 | 77 | # @c Capitalizes first character of each word of the given . 78 | # 79 | # @a sentence: string to manipulate. 80 | # 81 | # @r The with the first character of each word capitalized. 82 | # 83 | # @i capitalize 84 | 85 | proc ::textutil::string::capEachWord {sentence} { 86 | regsub -all {\S+} [string map {\\ \\\\ \$ \\$} $sentence] {[string toupper [string index & 0]][string range & 1 end]} cmd 87 | return [subst -nobackslashes -novariables $cmd] 88 | } 89 | 90 | # Compute the longest string which is common to all strings given to 91 | # the command, and at the beginning of said strings, i.e. a prefix. If 92 | # only one argument is specified it is treated as a list of the 93 | # strings to look at. If more than one argument is specified these 94 | # arguments are the strings to be looked at. If only one string is 95 | # given, in either form, the string is returned, as it is its own 96 | # longest common prefix. 97 | 98 | proc ::textutil::string::longestCommonPrefix {args} { 99 | return [longestCommonPrefixList $args] 100 | } 101 | 102 | proc ::textutil::string::longestCommonPrefixList {list} { 103 | if {[llength $list] <= 1} { 104 | return [lindex $list 0] 105 | } 106 | 107 | set list [lsort $list] 108 | set min [lindex $list 0] 109 | set max [lindex $list end] 110 | 111 | # Min and max are the two strings which are most different. If 112 | # they have a common prefix, it will also be the common prefix for 113 | # all of them. 114 | 115 | # Fast bailouts for common cases. 116 | 117 | set n [string length $min] 118 | if {$n == 0} {return ""} 119 | if {0 == [string compare $min $max]} {return $min} 120 | 121 | set prefix "" 122 | set i 0 123 | while {[string index $min $i] == [string index $max $i]} { 124 | append prefix [string index $min $i] 125 | if {[incr i] > $n} {break} 126 | } 127 | set prefix 128 | } 129 | 130 | # ### ### ### ######### ######### ######### 131 | ## Data structures 132 | 133 | namespace eval ::textutil::string { 134 | # Export the imported commands 135 | 136 | namespace export chop tail cap uncap capEachWord 137 | namespace export longestCommonPrefix 138 | namespace export longestCommonPrefixList 139 | } 140 | 141 | # ### ### ### ######### ######### ######### 142 | ## Ready 143 | 144 | package provide textutil::string 0.8 145 | -------------------------------------------------------------------------------- /user/user-filter.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Implementing Pandoc filters using the Tcl programming language 3 | shorttitle: user filters 4 | author: Detlef Groth 5 | date: 2023-04-17 6 | --- 7 | 8 | # Adding your own filters 9 | 10 | Since version 0.9.12 it is more easily to add your own filters written in the 11 | Tcl programming language. You can just add in a Markdown file in the 12 | document's YAML header for your code chunk settings a `filter` attribute like this: 13 | 14 | 15 | ``` 16 | --- 17 | title: "filter-geasy.tcl documentation" 18 | author: "Detlef Groth, Caputh-Schwielowsee, Germany" 19 | date: 2023-04-15 20 | geasy: 21 | app: graph-easy 22 | eval: 1 23 | as: ascii 24 | filter: user/filter-geasy.tcl 25 | --- 26 | ``` 27 | 28 | For the actual filter documentation you should read [filter-geasy](filter-geasy.html). 29 | 30 | The attribute `filter` should point using either a relative or an absolute path 31 | to your filter implementation. The relative path should be calculated based on 32 | your working directory where you do your document conversion. 33 | 34 | How should an actual filter implementation look like? Here an example Tcl 35 | procedure outline: 36 | 37 | ``` 38 | proc filter-CHUNKTYPE {cont dict} { 39 | ## do the processing 40 | return [list txt image-path] 41 | } 42 | ``` 43 | 44 | The variable `cont` contains the code chunk code within the triple backticks, 45 | the variable `dict` contains the code chunk arguments as a dictionary (hash) 46 | with key-value pairs for every option given in the code chunk argument. Here 47 | an example: 48 | 49 | ``` 50 | ```{.chunk key1=true key2="hello"} 51 | print("Hello!") 52 | ``` 53 | ``` 54 | 55 | So in the example above you would need a procedure name `filter-chunk` the 56 | string `print("Hello")` would be in the variable `cont` and the keys in the dictionary would be `key1` and `key2`. 57 | 58 | The returns at the end should be a list with two elements first the text you 59 | would like to display from your filter and secondly an image-path pointing to 60 | a possible image generated by your tool. In case your tool does not generate 61 | images you just return an empty string as the second argument. 62 | 63 | Below follows an example for the demonstration of a filter implementation 64 | which supports the [graph-easy](http://bloodgate.com/perl/graph/manual/) 65 | command line application. On a linux system you might simply install this 66 | application using your package manager for instance on my Fedora system I do 67 | this like this: 68 | 69 | ``` 70 | sudo dnf install perl-Graph-Easy 71 | ``` 72 | 73 | Here now the Tcl code with comments: 74 | 75 | ```{.tcl eval=false} 76 | ### file user/filter-geasy.tcl 77 | proc filter-geasy {cont dict} { 78 | # count all code chunk filters 79 | global n 80 | incr n 81 | # default values for the code chunks attributes 82 | set def [dict create results show eval true scriptpath scripts \ 83 | app graph-easy label null as ascii ext svg] 84 | # overwrite them with the current code chunk attributes 85 | set dict [dict merge $def $dict] 86 | # if eval is false return nothing 87 | if {![dict get $dict eval]} { 88 | return [list "" ""] 89 | } 90 | # check if the application is installed at all 91 | if {[auto_execok [dict get $dict app]] eq ""} { 92 | return [list "Error: This filter requires the command line tool [dict get $dict app] - please install it!" ""] 93 | } 94 | # intialize return text 95 | set ret "" 96 | set owd [pwd] 97 | # create a filename for the outputs 98 | if {[dict get $dict label] eq "null"} { 99 | set fname [file join $owd [dict get $dict scriptpath] geasy-$n] 100 | } else { 101 | set fname [file join $owd [dict get $dict scriptpath] [dict get $dict label]] 102 | } 103 | if {![file exists [file join $owd [dict get $dict scriptpath]]]} { 104 | file mkdir [file join $owd [dict get $dict scriptpath]] 105 | } 106 | # write down the code chunk text 107 | set out [open $fname.txt w 0600] 108 | puts $out $cont 109 | close $out 110 | # run the tool 111 | # TODO: error catching 112 | set res [exec -ignorestderr [dict get $dict app] --as=[dict get $dict as] $fname.txt] 113 | # initialize the image variable 114 | set img "" 115 | # do the user like to use the dot tool for image generation? 116 | if {[dict get $dict as] eq "dot"} { 117 | set out [open $fname.dot w 0600] 118 | puts $out $res 119 | close $out 120 | if {[auto_execok dot] eq ""} { 121 | return [list "Error: Dot output requires the command line tool GraphViz dot application - please install GraphViz or add the application sto your PATH variable!" ""] 122 | } 123 | set ext [dict get $dict ext] 124 | exec -ignorestderr dot $fname.dot -T$ext -o $fname.$ext 125 | set img $fname.$ext 126 | } 127 | # check if results should be shown 128 | if {[dict get $dict results] eq "show"} { 129 | set res $res 130 | } else { 131 | set res "" 132 | } 133 | # return text and image path 134 | return [list $res $img] 135 | } 136 | 137 | ``` 138 | 139 | ## See also: 140 | 141 | * [filter-geasy](filter-geasy.html) - the actual filter documentation for our example above 142 | * [pantcl Readme](../README.html) 143 | * [pantcl manual](../pantcl.html) 144 | * [pantcl Tutorial](../pantcl-tutorial.html) 145 | 146 | -------------------------------------------------------------------------------- /lib/tclfilters/filter-rplot.tcl: -------------------------------------------------------------------------------- 1 | #' --- 2 | #' title: "filter-rplot.tcl documentation" 3 | #' author: "Detlef Groth, Caputh-Schwielowsee, Germany" 4 | #' date: 2021-11-29 5 | #' rplot: 6 | #' app: Rscript 7 | #' imagepath: images 8 | #' ext: png 9 | #' eval: 1 10 | #' --- 11 | #' 12 | #' ------ 13 | #' 14 | #' ```{.tcl eval=true results="asis" echo=false} 15 | #' include header.md 16 | #' ``` 17 | #' 18 | #' ------ 19 | #' 20 | #' ## Name 21 | #' 22 | #' _filter-rplot.tcl_ - Filter which can be used to display R plots 23 | #' within a Pandoc processed document using the Tcl filter driver 24 | #' `pantcl.bin`. 25 | #' 26 | #' ## Usage 27 | #' 28 | #' The conversion of the Markdown documents via Pandoc should be done as follows: 29 | #' 30 | #' ``` 31 | #' pandoc input.md --filter pantcl.bin -s -o output.html 32 | #' ``` 33 | #' 34 | #' The file `filter-rplot.tcl` is not used directly but sourced automatically by the `pantcl.bin` file. 35 | #' If code blocks with the `.rplot` marker are found, the contents in the code block is 36 | #' processed via the Rscript interpreter if the chunk option `eval` is set to true or 1. 37 | #' If the interpreter is not in the PATH you might add the application path in your YAML header as shown below. 38 | #' 39 | #' 40 | #' The following options can be given via code chunks options or as defaults in the YAML header. 41 | #' 42 | #' > - app - the application to be called, default: Rscript 43 | #' - eval - should the code in the code block be evaluated, default: false 44 | #' - ext - file file extension, can be png or pdf, default: png 45 | #' - fig - should a figure be created, default: true 46 | #' - height - the figure height, default: 600 47 | #' - imagepath - output imagepath, default: images 48 | #' - include - should the created image be automatically included, default: true 49 | #' - label - the code chunk label used as well for the image name, default: null 50 | #' - results - should the output of the command line application been shown, should be show or hide, default: hide 51 | #' - width - the figure width, default: 600 52 | #' 53 | #' To change the defaults the YAML header can be used. Here an example to change the 54 | #' default Rscript interpreter, the image output path to nfigures and the file extension to pdf 55 | #' (useful for Pdf output of the document). 56 | #' Please note that in the YAML header you can only use 0 or 1 instead of false 57 | #' and true. 58 | #' 59 | #' ``` 60 | #' ---- 61 | #' title: "filter-rplot.tcl documentation" 62 | #' author: "Detlef Groth, Caputh-Schwielowsee, Germany" 63 | #' date: 2021-11-29 64 | #' rplot: 65 | #' app: /path/to/Rscript 66 | #' imagepath: nfigures 67 | #' ext: pdf 68 | #' eval: 1 69 | #' ---- 70 | #' ``` 71 | #' 72 | #' ## Examples 73 | #' 74 | #' Here an example for a pairsplot graph: 75 | #' 76 | #' ``` 77 | #' ```{.rplot eval=true} 78 | #' data(iris) 79 | #' pairs(iris[,1:3],col=as.numeric(iris$Species)+1,pch=19) 80 | #' ``` 81 | #' ``` 82 | #' 83 | #' And here is the output: 84 | #' 85 | #' ```{.rplot eval=true} 86 | #' data(iris) 87 | #' pairs(iris[,1:3],col=as.numeric(iris$Species)+1,pch=19) 88 | #' ``` 89 | #' 90 | #' To supress the message line you can add results="hide" as chunk option like this: `{.rplot results="hide"}` 91 | #' 92 | #' ```{.rplot eval=true results="hide"} 93 | #' boxplot(iris$Sepal.Length ~ iris$Species,col=2:4) 94 | #' ``` 95 | #' 96 | #' ## See also: 97 | #' 98 | #' * [pantcl Readme](../../README.html) 99 | #' * [Pipe filter for R, Python, Octave](filter-pipe.html) 100 | #' 101 | 102 | 103 | proc filter-rplot {cont dict} { 104 | global n 105 | global rplotx 106 | if {[info exists rplotx]} { 107 | incr rplotx 108 | } else { 109 | set rplotx 0 110 | } 111 | incr n 112 | set def [dict create results show eval true fig true width 600 height 600 \ 113 | include true imagepath images app Rscript label null ext png] 114 | set dict [dict merge $def $dict] 115 | if {![dict get $dict eval]} { 116 | return [list "" ""] 117 | } 118 | set ret "" 119 | set owd [pwd] 120 | if {[dict get $dict label] eq "null"} { 121 | set fname [file join $owd [dict get $dict imagepath] rplot-$n] 122 | } else { 123 | set fname [file join $owd [dict get $dict imagepath] [dict get $dict label]] 124 | } 125 | if {![file exists [file join $owd [dict get $dict imagepath]]]} { 126 | file mkdir [file join $owd [dict get $dict imagepath]] 127 | } 128 | set out [open ${fname}.R w 0600] 129 | if {$rplotx == 0} { 130 | if {[file exists ".RData"]} { 131 | file delete .RData 132 | } 133 | } 134 | if {[file exists .RData]} { 135 | puts $out "load('.RData')" 136 | } 137 | if {[dict get $dict fig]} { 138 | set imgfile ${fname}.[dict get $dict ext] 139 | puts $out "[dict get $dict ext]('$imgfile' , width=[dict get $dict width] , height=[dict get $dict height]);" 140 | puts $out $cont 141 | puts $out "dev.off()" 142 | } else { 143 | puts $out $cont 144 | } 145 | puts $out "save.image(file='.RData')" 146 | close $out 147 | # TODO: error catching 148 | if {[dict get $dict eval]} { 149 | set res [exec [dict get $dict app] ${fname}.R] 150 | } else { 151 | set res "" 152 | } 153 | if {[dict get $dict results] eq "show"} { 154 | set res $res 155 | } else { 156 | set res "" 157 | } 158 | set img "" 159 | if {[dict get $dict fig]} { 160 | if {[dict get $dict include]} { 161 | set img $imgfile 162 | } 163 | } 164 | return [list $res $img] 165 | } 166 | -------------------------------------------------------------------------------- /lib/tclfilters/filter-mmd.tcl: -------------------------------------------------------------------------------- 1 | #' --- 2 | #' title: "filter-mmd.tcl documentation" 3 | #' author: "Detlef Groth, Caputh-Schwielowsee, Germany" 4 | #' date: 2021-12-11 5 | #' mmd: 6 | #' app: mmdc 7 | #' imagepath: images 8 | #' ext: png 9 | #' eval: 1 10 | #' --- 11 | # a simple pandoc filter using Tcl 12 | # the script pantcl.tcl 13 | # must be in the in the parent directory of the filter directory 14 | #' 15 | #' ------ 16 | #' 17 | #' ```{.tcl results="asis" echo=false eval=true} 18 | #' include header.md 19 | #' ``` 20 | #' 21 | #' ------ 22 | #' 23 | #' ## Name 24 | #' 25 | #' _filter-mmd.tcl_ - Filter which can be used to display [Mermaid](https://mermaid-js.github.io) 26 | #' diagram files within a Pandoc processed document using the Tcl filter driver `pantcl.bin`. 27 | #' 28 | #' ## Usage 29 | #' 30 | #' The conversion of the Markdown documents via Pandoc should be done as follows: 31 | #' 32 | #' ``` 33 | #' pandoc input.md --filter pantcl.bin -s -o output.html 34 | #' ``` 35 | #' 36 | #' The file `filter-mmd.tcl` is not used directly but sourced automatically by the `pantcl.bin` file. 37 | #' If code blocks with the `.mmd` marker are found, the contents in the code block is processed via one of the Mermaid command line tool. To install this command line tool have 38 | #' a look at: [https://github.com/mermaid-js/mermaid-cli](https://github.com/mermaid-js/mermaid-cli) 39 | #' 40 | #' The following options can be given via code chunks or in the YAML header. 41 | #' 42 | #' > 43 | #' - app - the application to be called, such as mmdc, default: mmdc 44 | #' - background - the background color such as transparent, salmon '#ccffff' (only used for png output), default: white 45 | #' - eval - should the code in the code block be evaluated, default: false 46 | #' - ext - file file extension, can be svg, png, pdf, default: svg 47 | #' - fig - should a figure be created, default: true 48 | #' - height - the image height, default: 600 49 | #' - imagepath - output imagepath, default: images 50 | #' - include - should the created image be automatically included, default: true 51 | #' - results - should the output of the command line application been shown, should be show or hide, default: hide 52 | #' - theme - the image them which can be used, should be either default, forest, dark, default: default 53 | #' - width - the image width, default: 800 54 | #' 55 | #' The options fig, results, include should be normally not used, they are here just for 56 | #' compatibility reasons with the other filters. 57 | #' 58 | #' To change the defaults the YAML header can be used. Here an example to change the 59 | #' default command line application to mmdc-8.10 and the image output path to nfigures 60 | #' and the output image format to png, to activate code evaluation in the complete document 61 | #' use `eval: 1` in the YAML header, do not use 'true' here.. 62 | #' 63 | #' ``` 64 | #' ---- 65 | #' title: "filter-mmd.tcl documentation" 66 | #' author: "Detlef Groth, Caputh-Schwielowsee, Germany" 67 | #' date: 2021-12-11 68 | #' mmd: 69 | #' app: mmdc-8.10 70 | #' imagepath: nfigures 71 | #' ext: png 72 | #' eval: 1 73 | #' ---- 74 | #' ``` 75 | #' 76 | #' ## Examples 77 | #' 78 | #' Here an example for a simple flowchart: 79 | #' 80 | #' ``` 81 | #' ```{.mmd eval=true} 82 | #' graph TD; 83 | #' A-->B; 84 | #' A-->C; 85 | #' B-->D; 86 | #' C-->D; 87 | #' ``` 88 | #' ``` 89 | # 90 | #' And here the output: 91 | #' 92 | #' ```{.mmd eval=true} 93 | #' graph TD; 94 | #' A-->B; 95 | #' A-->C; 96 | #' B-->D; 97 | #' C-->D; 98 | #' ``` 99 | #' 100 | #' Next an example for a sequence diagram with the forest theme and cornsilk background 101 | #' (`{.mmd theme=forest background=cornsilk eval=true}`): 102 | #' 103 | #' ```{.mmd theme=forest background=cornsilk eval=true} 104 | #' sequenceDiagram 105 | #' participant Alice 106 | #' participant Bob 107 | #' Alice->>John: Hello John, how are you? 108 | #' loop Healthcheck 109 | #' John->>John: Fight against hypochondria 110 | #' end 111 | #' Note right of John: Rational thoughts
prevail! 112 | #' John-->>Alice: Great! 113 | #' John->>Bob: How about you? 114 | #' Bob-->>John: Jolly good! 115 | #' ``` 116 | #' 117 | #' ## See also: 118 | #' 119 | #' * [Pantcl Readme](../../README.html) 120 | #' * [GraphViz Filter](filter-dot.html) 121 | #' * [Pikchr Filter](filter-pik.html) 122 | #' * [PlantUML filter](filter-puml.html) 123 | #' 124 | 125 | 126 | proc filter-mmd {cont dict} { 127 | global n 128 | incr n 129 | set def [dict create results show eval true fig true width 800 height 600 \ 130 | include true imagepath images app mmdc label null ext svg theme default background white] 131 | set dict [dict merge $def $dict] 132 | set ret "" 133 | if {[auto_execok [dict get $dict app]] == ""} { 134 | return [list "Error: Command line tool [dict get $dict app] is not installed!" ""] 135 | } 136 | set owd [pwd] 137 | if {[dict get $dict label] eq "null"} { 138 | set fname [file join $owd [dict get $dict imagepath] mmd-$n] 139 | } else { 140 | set fname [file join $owd [dict get $dict imagepath] [dict get $dict label]] 141 | } 142 | if {![file exists [file join $owd [dict get $dict imagepath]]]} { 143 | file mkdir [file join $owd [dict get $dict imagepath]] 144 | } 145 | set out [open $fname.mmd w 0600] 146 | puts $out $cont 147 | close $out 148 | # TODO: error catching 149 | set res [exec -ignorestderr [dict get $dict app] -i $fname.mmd -o $fname.[dict get $dict ext] \ 150 | -w [dict get $dict width] -H [dict get $dict height] -t [dict get $dict theme] \ 151 | -b [dict get $dict background]] 152 | if {[dict get $dict results] eq "show"} { 153 | # should be usually empty 154 | set res $res 155 | } else { 156 | set res "" 157 | } 158 | set img "" 159 | if {[dict get $dict fig]} { 160 | if {[dict get $dict include]} { 161 | set img $fname.[dict get $dict ext] 162 | } 163 | } 164 | return [list $res $img] 165 | } 166 | -------------------------------------------------------------------------------- /lib/tclfilters/filter-emf.tcl: -------------------------------------------------------------------------------- 1 | #' --- 2 | #' title: "filter-emf.tcl documentation" 3 | #' author: "Detlef Groth, Caputh-Schwielowsee, Germany" 4 | #' date: 2023-04-15 5 | #' emf: 6 | #' app: mec 7 | #' eval: 1 8 | #' --- 9 | #' 10 | # A simple pandoc filter using the the MicroEmacs Text Editor macro language. 11 | #' 12 | #' ------ 13 | #' 14 | #' ```{.tcl eval=true results="asis" echo=false} 15 | #' include header.md 16 | #' ``` 17 | #' 18 | #' ------ 19 | #' 20 | #' ## Name 21 | #' 22 | #' _filter-emf.tcl_ - Filter which can be used to evaluate Macro code for the MicroEmacs 23 | #' text editor within a Pandoc processed document using the Tcl filter driver `pantcl.tcl`. 24 | #' The command line mode version of the editor which usually called with the -n arguments 25 | #' is required which can be ususally installed from the website 26 | #' [http://www.jasspa.com/zeroinst.html](http://www.jasspa.com/zeroinst.html). 27 | #' 28 | #' ## Usage 29 | #' 30 | #' MicroEmacs macro language source code is embedded into Markup languages like Markdown like this 31 | #' (remove the spaces at the beginning, they are here just for protecting the evaluation): 32 | #' 33 | #' ``` 34 | #' # code chunk defaults (must be in fact not given): 35 | #' ```{.emf eval=true echo=true} 36 | #' EMF code 37 | #' ``` 38 | #' ``` 39 | #' 40 | #' Where eval and echo are so called chunk options. 41 | #' 42 | #' The conversion of the Markdown documents via Pandoc should be done as follows: 43 | #' 44 | #' ``` 45 | #' pantcl input.md output.html --pantcl-filter filter-emf.tcl --syntax-definition ../../xml/emf.xml -s 46 | #' ``` 47 | #' The file `emf.xml` contains syntax highlighting code for the MicroEmacs macro files. 48 | #' The application file *pantcl* which contains the Tcl filter and all other filters has to be placed in the PATH and the 49 | #' system has to support the Shebang, on Unix this is standard on Windows you need to use tools like Cygwin, Msys, 50 | #' Git-Bash or Cygwin (untested). 51 | #' 52 | #' The arguments after the output file and after the file `filter-emf.tcl` are delegated to pandoc. 53 | #' 54 | #' If code blocks with the `.emf` marker are found, the contents in the code 55 | #' block is processed via the MicroEmacs text editor in command line mode. 56 | #' 57 | #' The following options can be given via code chunks or in the YAML header. 58 | #' 59 | #' > - app - the MicroEmacs application to be called, usually me, default: me 60 | #' - echo - should the EMF source code be shown, default: true 61 | #' - eval - should the code in the code block be evaluated, default: false 62 | #' - results - should the output of the command line application been shown, should be show or hide, default: hide 63 | #' 64 | #' To change the defaults the YAML header can be used. Here an example to change the 65 | #' default application to an other MicroEmacs executable, an updated MicroEmacs from 2023: 66 | #' You should set eval to 1 as shown as well below, the term true 67 | #' might produce an error, so write `eval: 1` 68 | #' 69 | #' ``` 70 | #' ---- 71 | #' title: "filter-emf.tcl documentation" 72 | #' author: "Detlef Groth, Caputh-Schwielowsee, Germany" 73 | #' date: 2023-04-15 74 | #' abc: 75 | #' app: me23 76 | #' eval: 1 77 | #' ---- 78 | #' ``` 79 | #' 80 | #' ## Examples 81 | #' 82 | #' Here an example for a simple Hello World message chunk just contains `{.emf eval=true}`:. 83 | #' 84 | #' ```{.emf} 85 | #' -1 ml-write "Hello MicroEmacs World!" 86 | #' ``` 87 | #' 88 | #' The `-1` at the beginning ensures that we are writing to the terminal, this is required for the embedded code to be shown in our output document but not in the editor 89 | #' message line. 90 | #' 91 | #' Using the option `{.emf eval=true results="hide"}` the output of the command line tool can be hidden. 92 | #' 93 | #' ```{.emf eval=true results="hide"} 94 | #' -1 ml-write "Hello MicroEmacs World!" 95 | #' ``` 96 | #' 97 | #' Believe me, the code above was evaluated but the results is hidden 98 | #' as we used `results="hide"` as code chunk option. 99 | #' 100 | #' Here a more extensive example: 101 | #' 102 | #' ```{.emf results="show" echo=true eval=true} 103 | #' ; semicolons start comments 104 | #' ; $version is a system variable 105 | #' -1 ml-write &cat "This is MicroEmacs " &cat $version "!" 106 | #' ; example for a loop using a global variable %x 107 | #' set-variable %x 1 108 | #' !while &less %x 10 109 | #' -1 ml-write &cat "x is " %x 110 | #' set-variable %x &inc %x 1 111 | #' !done 112 | #' ``` 113 | #' 114 | #' ## See also: 115 | #' 116 | #' * [pantcl Readme](../README.html) 117 | #' 118 | 119 | 120 | proc filter-emf {cont dict} { 121 | global n 122 | incr n 123 | set def [dict create results show eval true scriptpath scripts \ 124 | app me label null] 125 | set dict [dict merge $def $dict] 126 | if {![dict get $dict eval]} { 127 | return [list "" ""] 128 | } 129 | if {[auto_execok [dict get $dict app]] eq ""} { 130 | return [list "Error: This filter requires the command line tool [dict get $dict app] - please install it!" ""] 131 | } 132 | set ret "" 133 | set owd [pwd] 134 | if {[dict get $dict label] eq "null"} { 135 | set fname [file join $owd [dict get $dict scriptpath] emf-$n] 136 | } else { 137 | set fname [file join $owd [dict get $dict scriptpath] [dict get $dict label]] 138 | } 139 | if {![file exists [file join $owd [dict get $dict scriptpath]]]} { 140 | file mkdir [file join $owd [dict get $dict scriptpath]] 141 | } 142 | set out [open $fname.sh w 0600] 143 | puts $out "#!/usr/bin/bash\ntail --lines=+3 \$0 > temp.emf && [dict get $dict app] -n -p \"@temp.emf\" && exit" 144 | puts $out "; - emf - below follows the MicroEmacs code" 145 | puts $out "define-macro test-emf" 146 | puts $out $cont 147 | puts $out "!emacro" 148 | puts $out "!force test-emf" 149 | puts $out "!if ¬ \$status" 150 | puts $out " -1 ml-write \"Error in code chunk!\"" 151 | puts $out "!endif" 152 | puts $out "quick-exit" 153 | close $out 154 | # TODO: error catching 155 | set res [exec -ignorestderr bash $fname.sh] 156 | if {[dict get $dict results] eq "show"} { 157 | # should be usually empty 158 | set res $res 159 | } else { 160 | set res "" 161 | } 162 | return [list $res ""] 163 | } 164 | -------------------------------------------------------------------------------- /lib/textutil/split.tcl: -------------------------------------------------------------------------------- 1 | # split.tcl -- 2 | # 3 | # Various ways of splitting a string. 4 | # 5 | # Copyright (c) 2000 by Ajuba Solutions. 6 | # Copyright (c) 2000 by Eric Melski 7 | # Copyright (c) 2001 by Reinhard Max 8 | # Copyright (c) 2003 by Pat Thoyts 9 | # Copyright (c) 2001-2006 by Andreas Kupries 10 | # 11 | # See the file "license.terms" for information on usage and redistribution 12 | # of this file, and for a DISCLAIMER OF ALL WARRANTIES. 13 | # 14 | # RCS: @(#) $Id: split.tcl,v 1.7 2006/04/21 04:42:28 andreas_kupries Exp $ 15 | 16 | # ### ### ### ######### ######### ######### 17 | ## Requirements 18 | 19 | package require Tcl 8.2 20 | 21 | namespace eval ::textutil::split {} 22 | 23 | ######################################################################## 24 | # This one was written by Bob Techentin (RWT in Tcl'ers Wiki): 25 | # http://www.techentin.net 26 | # mailto:techentin.robert@mayo.edu 27 | # 28 | # Later, he send me an email stated that I can use it anywhere, because 29 | # no copyright was added, so the code is defacto in the public domain. 30 | # 31 | # You can found it in the Tcl'ers Wiki here: 32 | # http://mini.net/cgi-bin/wikit/460.html 33 | # 34 | # Bob wrote: 35 | # If you need to split string into list using some more complicated rule 36 | # than builtin split command allows, use following function. It mimics 37 | # Perl split operator which allows regexp as element separator, but, 38 | # like builtin split, it expects string to split as first arg and regexp 39 | # as second (optional) By default, it splits by any amount of whitespace. 40 | # Note that if you add parenthesis into regexp, parenthesed part of separator 41 | # would be added into list as additional element. Just like in Perl. -- cary 42 | # 43 | # Speed improvement by Reinhard Max: 44 | # Instead of repeatedly copying around the not yet matched part of the 45 | # string, I use [regexp]'s -start option to restrict the match to that 46 | # part. This reduces the complexity from something like O(n^1.5) to 47 | # O(n). My test case for that was: 48 | # 49 | # foreach i {1 10 100 1000 10000} { 50 | # set s [string repeat x $i] 51 | # puts [time {splitx $s .}] 52 | # } 53 | # 54 | 55 | if {[package vsatisfies [package provide Tcl] 8.3]} { 56 | 57 | proc ::textutil::split::splitx {str {regexp {[\t \r\n]+}}} { 58 | # Bugfix 476988 59 | if {[string length $str] == 0} { 60 | return {} 61 | } 62 | if {[string length $regexp] == 0} { 63 | return [::split $str ""] 64 | } 65 | if {[regexp $regexp {}]} { 66 | return -code error \ 67 | "splitting on regexp \"$regexp\" would cause infinite loop" 68 | } 69 | 70 | set list {} 71 | set start 0 72 | while {[regexp -start $start -indices -- $regexp $str match submatch]} { 73 | foreach {subStart subEnd} $submatch break 74 | foreach {matchStart matchEnd} $match break 75 | incr matchStart -1 76 | incr matchEnd 77 | lappend list [string range $str $start $matchStart] 78 | if {$subStart >= $start} { 79 | lappend list [string range $str $subStart $subEnd] 80 | } 81 | set start $matchEnd 82 | } 83 | lappend list [string range $str $start end] 84 | return $list 85 | } 86 | 87 | } else { 88 | # For tcl <= 8.2 we do not have regexp -start... 89 | proc ::textutil::split::splitx [list str [list regexp "\[\t \r\n\]+"]] { 90 | 91 | if {[string length $str] == 0} { 92 | return {} 93 | } 94 | if {[string length $regexp] == 0} { 95 | return [::split $str {}] 96 | } 97 | if {[regexp $regexp {}]} { 98 | return -code error \ 99 | "splitting on regexp \"$regexp\" would cause infinite loop" 100 | } 101 | 102 | set list {} 103 | while {[regexp -indices -- $regexp $str match submatch]} { 104 | lappend list [string range $str 0 [expr {[lindex $match 0] -1}]] 105 | if {[lindex $submatch 0] >= 0} { 106 | lappend list [string range $str [lindex $submatch 0] \ 107 | [lindex $submatch 1]] 108 | } 109 | set str [string range $str [expr {[lindex $match 1]+1}] end] 110 | } 111 | lappend list $str 112 | return $list 113 | } 114 | 115 | } 116 | 117 | # 118 | # splitn -- 119 | # 120 | # splitn splits the string $str into chunks of length $len. These 121 | # chunks are returned as a list. 122 | # 123 | # If $str really contains a ByteArray object (as retrieved from binary 124 | # encoded channels) splitn must honor this by splitting the string 125 | # into chunks of $len bytes. 126 | # 127 | # It is an error to call splitn with a nonpositive $len. 128 | # 129 | # If splitn is called with an empty string, it returns the empty list. 130 | # 131 | # If the length of $str is not an entire multiple of the chunk length, 132 | # the last chunk in the generated list will be shorter than $len. 133 | # 134 | # The implementation presented here was given by Bryan Oakley, as 135 | # part of a ``contest'' I staged on c.l.t in July 2004. I selected 136 | # this version, as it does not rely on runtime generated code, is 137 | # very fast for chunk size one, not too bad in all the other cases, 138 | # and uses [split] or [string range] which have been around for quite 139 | # some time. 140 | # 141 | # -- Robert Suetterlin (robert@mpe.mpg.de) 142 | # 143 | proc ::textutil::split::splitn {str {len 1}} { 144 | 145 | if {$len <= 0} { 146 | return -code error "len must be > 0" 147 | } 148 | 149 | if {$len == 1} { 150 | return [split $str {}] 151 | } 152 | 153 | set result [list] 154 | set max [string length $str] 155 | set i 0 156 | set j [expr {$len -1}] 157 | while {$i < $max} { 158 | lappend result [string range $str $i $j] 159 | incr i $len 160 | incr j $len 161 | } 162 | 163 | return $result 164 | } 165 | 166 | # ### ### ### ######### ######### ######### 167 | ## Data structures 168 | 169 | namespace eval ::textutil::split { 170 | namespace export splitx splitn 171 | } 172 | 173 | # ### ### ### ######### ######### ######### 174 | ## Ready 175 | 176 | package provide textutil::split 0.8 177 | -------------------------------------------------------------------------------- /lib/tclfilters/filter-sqlite.tcl: -------------------------------------------------------------------------------- 1 | #' --- 2 | #' title: "filter-sqlite.tcl documentation" 3 | #' author: "Detlef Groth, Caputh-Schwielowsee, Germany" 4 | #' date: 2021-12-12 5 | #' sqlite: 6 | #' app: sqlite3 7 | #' mode: markdown 8 | #' eval: 1 9 | #' --- 10 | #' 11 | # a simple pandoc filter using Tcl the script pantcl.tcl 12 | # must be in the in the parent directory of the filter directory 13 | #' 14 | #' ------ 15 | #' 16 | #' ```{.tcl eval=true results="asis" echo=false} 17 | #' include header.md 18 | #' ``` 19 | #' 20 | #' ------ 21 | #' 22 | #' ## Name 23 | #' 24 | #' _filter-sqlite.tcl_ - Filter which can be used to execute SQLite3 statements within a Pandoc processed 25 | #' document using the Tcl filter driver `pantcl.bin` and showing the output. 26 | #' 27 | #' ## Usage 28 | #' 29 | #' The conversion of the Markdown documents via Pandoc should be done as follows: 30 | #' 31 | #' ``` 32 | #' pandoc input.md --filter pantcl.bin -s -o output.html 33 | #' ``` 34 | #' 35 | #' The file `filter-sqlite.tcl` is not used directly but sourced automatically by the `pantcl.bin` file. 36 | #' If code blocks with the `.sqlite` marker are found, the contents in the code block is processed via the sqlite3 37 | #' command line application which must be in the path. 38 | #' 39 | #' The following options can be given via code chunks or in the YAML header. 40 | #' 41 | #' > - app - the application to be called, such as sqlite3, default: sqlite3 42 | #' - eval - should the code in the code block be evaluated, default: false 43 | #' - results - should the output of the command line application been shown, should be asis, show or hide, default: asis 44 | #' - mode - the output mode, default: markdown 45 | #' 46 | #' To change the defaults the YAML header can be used. Here an example to change the 47 | #' default command line application to sqlite3-35 and to evaluate all code 48 | #' chunks, `eval: 1`. Please note, that in the chunk options in the YAML header for `true` and `false` 49 | #' you can only use numbers, 1 and 0, whereas in the code chunks you can use as 50 | #' well `true` and `false` instead of 1 and 0: 51 | #' 52 | #' ``` 53 | #' ---- 54 | #' title: "filter-sqlite.tcl documentation" 55 | #' author: "Detlef Groth, Caputh-Schwielowsee, Germany" 56 | #' date: 2021-12-12 57 | #' sqlite: 58 | #' app: sqlite3-35 59 | #' eval: 1 60 | #' ---- 61 | #' ``` 62 | #' 63 | #' ## Examples 64 | #' 65 | #' Here an example for a new database created on the fly and the we check for the created table ({.sqlite results="asis"}). 66 | #' 67 | #' ``` 68 | #' ```{.sqlite results="asis" eval=true} 69 | #' CREATE TABLE contacts ( 70 | #' contact_id INTEGER PRIMARY KEY, 71 | #' first_name TEXT NOT NULL, 72 | #' last_name TEXT NOT NULL, 73 | #' email TEXT NOT NULL UNIQUE, 74 | #' phone TEXT NOT NULL UNIQUE 75 | #' ); 76 | #' INSERT INTO contacts (contact_id, first_name, last_name, email, phone) 77 | #' VALUES (1, "Max", "Musterman", "musterm@mail.de","1234"); 78 | #' INSERT INTO contacts (contact_id, first_name, last_name, email, phone) 79 | #' VALUES (2, "Maxi", "Musterwoman", "musterw@mail.de","1235"); 80 | #' INSERT INTO contacts (contact_id, first_name, last_name, email, phone) 81 | #' VALUES (3, "Fido", "Dogkeeper", "fido@dog.de","1236"); 82 | #' select * from contacts; 83 | #' ``` 84 | #' ``` 85 | #' 86 | #' And here the output (space indentation above is only to avoid interpretation): 87 | #' 88 | #' ```{.sqlite results="asis" eval=true} 89 | #' CREATE TABLE contacts ( 90 | #' contact_id INTEGER PRIMARY KEY, 91 | #' first_name TEXT NOT NULL, 92 | #' last_name TEXT NOT NULL, 93 | #' email TEXT NOT NULL UNIQUE, 94 | #' phone TEXT NOT NULL UNIQUE 95 | #' ); 96 | #' INSERT INTO contacts (contact_id, first_name, last_name, email, phone) 97 | #' VALUES (1, 'Max', 'Musterman', 'musterm@mail.de','1234'); 98 | #' INSERT INTO contacts (contact_id, first_name, last_name, email, phone) 99 | #' VALUES (2, 'Maxi', 'Musterwoman', 'musterw@mail.de','1235'); 100 | #' INSERT INTO contacts (contact_id, first_name, last_name, email, phone) 101 | #' VALUES (3, 'Fido', 'Dogkeeper', 'fido@dog.de','1236'); 102 | #' select * from contacts; 103 | #' ``` 104 | #' 105 | #' And here an example for a existing database ({.sqlite results="asis" file="uni.sqlite"}): 106 | #' 107 | #' ```{.sqlite results="asis" file="uni.sqlite"} 108 | #' select type,name from sqlite_master; 109 | #' ``` 110 | #' 111 | #' Let's query the Student table ({.sqlite results="asis" file="uni.sqlite"}): 112 | #' 113 | #' ```{.sqlite results="asis" file="uni.sqlite"} 114 | #' select * from Student limit 5; 115 | #' ``` 116 | 117 | #' ## See also: 118 | #' 119 | #' * [Pantcl Readme](../../README.html) 120 | #' * [Shell script filter](filter-cmd.html) 121 | #' * [Pikchr filter](filter-pik.html) 122 | #' * [PlantUML filter](filter-puml.html) 123 | #' 124 | 125 | 126 | proc filter-sqlite {cont dict} { 127 | global n 128 | incr n 129 | set def [dict create results asis eval true file null \ 130 | include true app sqlite3 label null mode markdown] 131 | set dict [dict merge $def $dict] 132 | if {![dict get $dict eval]} { 133 | return [list "" ""] 134 | } 135 | set ret "" 136 | set owd [pwd] 137 | if {[auto_execok [dict get $dict app]] eq ""} { 138 | return [list "Error: [dict get $dict app] is not installed, please install it!" ""] 139 | } 140 | set version [exec [dict get $dict app] --version] 141 | if {[regexp {^3.[12]} $version] || [regexp {^3.3[0-2]} $version]} { 142 | return [list "Error: You need at least sqlite3 version 3.33 which supports Markdown mode!" ""] 143 | } 144 | if {[dict get $dict label] eq "null"} { 145 | set cache [pantcl::getCacheDir] 146 | set fname [file join $cache sqlite-$n] 147 | } else { 148 | set fname [file join $owd [dict get $dict label]] 149 | } 150 | set out [open $fname.sqlite w 0600] 151 | puts $out $cont 152 | close $out 153 | 154 | if {[dict get $dict file] eq "null"} { 155 | # TODO: error catching 156 | set res [exec cat $fname.sqlite | [dict get $dict app] -[dict get $dict mode]] 157 | } else { 158 | set res [exec cat $fname.sqlite | [dict get $dict app] [dict get $dict file] -[dict get $dict mode]] 159 | } 160 | if {[dict get $dict results] in [list show asis]} { 161 | # should be usually empty 162 | set res $res 163 | } else { 164 | set res "" 165 | } 166 | #puts stderr $res 167 | return [list $res ""] 168 | } 169 | -------------------------------------------------------------------------------- /lib/tclfilters/filter-eqn.tcl: -------------------------------------------------------------------------------- 1 | #' --- 2 | #' title: "filter-eqn.tcl documentation" 3 | #' author: "Detlef Groth, Caputh-Schwielowsee, Germany" 4 | #' date: 2021-11-20 5 | #' eqn: 6 | #' app: eqn2graph 7 | #' imagepath: images 8 | #' ext: png 9 | ##' eval: 1 10 | #' --- 11 | # a simple pandoc filter using Tcl 12 | # the script pantcl.tcl 13 | # must be in the in the parent directory of the filter directory 14 | #' 15 | #' ------ 16 | #' 17 | #' ```{.tcl eval=true results="asis" echo=false} 18 | #' include header.md 19 | #' ``` 20 | #' 21 | #' ------ 22 | #' 23 | #' ## Name 24 | #' 25 | #' _filter-eqn.tcl_ - Filter which can be used to render eqn data within a Pandoc processed 26 | #' document using the Tcl filter driver `pantcl.bin`. 27 | #' 28 | #' ## Usage 29 | #' 30 | #' The conversion of the Markdown documents via Pandoc should be done as follows: 31 | #' 32 | #' ``` 33 | #' pandoc input.md --filter pantcl.bin -s -o output.html 34 | #' ``` 35 | #' 36 | #' The file `filter-eqn.tcl` is not used directly but sourced automatically by the `pantcl.bin` file. 37 | #' If code blocks with the `.eqn` marker are found, the contents in the code block is processed 38 | #' via the *eqn2graph* equation tool [https://man7.org/linux/man-pages/man1/eqn2graph.1.html](https://man7.org/linux/man-pages/man1/eqn2graph.1.html) which converts 39 | #' convert an eqn equation into a cropped PGN image, see 40 | #' [https://en.wikipedia.org/wiki/Eqn_(software)](https://en.wikipedia.org/wiki/Eqn_(software)) 41 | #' into some graphics format like png or other file formats which can be converted by the the ImageMagick tool *convert*. 42 | #' 43 | #' The following options can be given via code chunks or in the YAML header. 44 | #' 45 | #' - app - the application to process the eqn code, default: eqn2graph 46 | #' - ext - file file extension, can be png or pdf, default: png 47 | #' - eval - should the code in the code block be evaluated, default: false 48 | #' - imagepath - output imagepath, default: images 49 | #' - include - should the created image be automatically included, default: true 50 | #' - results - should the output of the command line application been shown, should be show or hide, default: hide 51 | #' - fig - should a figure be created, default: true 52 | #' 53 | #' To change the defaults the YAML header can be used. Here an example to change the 54 | #' default the image output path to nfigures and to evaluate all code chunks. 55 | #' Please use the value 1 in the YAML header, not the string 'true'. 56 | #' 57 | #' ``` 58 | #' ---- 59 | #' title: "filter-eqn example" 60 | #' author: "Detlef Groth, Caputh-Schwielowsee, Germany" 61 | #' date: 2021-11-20 62 | #' eqn: 63 | #' imagepath: nfigures 64 | #' eval: 1 65 | #' ---- 66 | #' ``` 67 | #' 68 | #' ## Examples 69 | #' 70 | #' Here an example for a simple neat undirected graph: 71 | #' 72 | #' ``` 73 | #' ```{.eqn eval=true} 74 | #' x = {-b +- sqrt{b sup 2 - 4ac}} over 2a 75 | #' ``` 76 | #' ``` 77 | #' 78 | #' And here the output: 79 | #' 80 | #' ```{.eqn eval=true} 81 | #' x = {-b +- sqrt{b sup 2 - 4ac}} over 2a 82 | #' ``` 83 | #' 84 | #' Here some more simple examples: 85 | #' 86 | #' ```{.eqn} 87 | #' x = 1 over 2 88 | #' ``` 89 | #' 90 | #' ```{.eqn} 91 | #' y = 2 x sup 2 + 4x - 2 92 | #' ``` 93 | #' 94 | #' ```{.eqn} 95 | #' y = 4 times sin(x) - cos sup 2 (x) 96 | #' ``` 97 | #' 98 | #' Size can be changed using density: {.eqn density=144}: 99 | #' 100 | #' ```{.eqn density=144} 101 | #' s = sqrt { { sum from i=1 to inf ( x sub i - x bar ) sup 2 } over { N - 1 } } 102 | #' ``` 103 | #' 104 | #' Higher density: {.eqn density=300}: 105 | #' 106 | #' ```{.eqn density=300} 107 | #' s = sqrt { { sum from i=1 to inf ( x sub i - x bar ) sup 2 } over { N - 1 } } 108 | #' ``` 109 | #' 110 | #' Slightly better quality can be achieved by using high density and rescaling the image using Markdown syntax rescaling back to a smaller figure: 111 | #' 112 | #' ``` 113 | #' ```{.eqn label=highq density=600 include=false} 114 | #' s = sqrt { { sum from i=1 to inf ( x sub i - x bar ) sup 2 } over { N - 1 } } 115 | #' ``` 116 | #' 117 | #' ![](images/highq.png){#id width=200px} 118 | #' ``` 119 | #' 120 | #' Here the results: 121 | #' 122 | #' ```{.eqn label=highq density=600 include=false} 123 | #' s = sqrt { { sum from i=1 to inf ( x sub i - x bar ) sup 2 } over { N - 1 } } 124 | #' ``` 125 | #' 126 | #' ![](images/highq.png){#id width=200px} 127 | #' 128 | #' ## See also: 129 | #' 130 | #' * [Pantcl Readme](../../README.html) 131 | #' * [Pandoc documentation](../../pantcl.html) 132 | #' * [Unix Text Processing - EQN chapter](https://www.oreilly.com/library/view/unix-text-processing/9780810462915/Chapter09.html#ch9) 133 | #' * [PIC filter](filter-pic.html) 134 | #' * [LaTeX Math filter](filter-mtex.html) 135 | #' 136 | 137 | 138 | proc filter-eqn {cont dict} { 139 | global n 140 | incr n 141 | set def [dict create results show eval true fig true width 0 height 0 \ 142 | include true imagepath images app eqn2graph label null ext png \ 143 | border 15 density 300 background white] 144 | set dict [dict merge $def $dict] 145 | if {[auto_execok eqn2graph] eq ""} { 146 | return [list "Error: This filter requires the command line tool eqn2graph, please install it!" ""] 147 | } 148 | set ret "" 149 | set owd [pwd] 150 | if {[dict get $dict label] eq "null"} { 151 | set fname [file join $owd [dict get $dict imagepath] eqn-$n] 152 | } else { 153 | set fname [file join $owd [dict get $dict imagepath] [dict get $dict label]] 154 | } 155 | if {![file exists [file join $owd [dict get $dict imagepath]]]} { 156 | file mkdir [file join $owd [dict get $dict imagepath]] 157 | } 158 | set out [open $fname.eqn w 0600] 159 | puts $out $cont 160 | close $out 161 | # TODO: error catching 162 | set res [exec -ignorestderr cat $fname.eqn | [dict get $dict app] -density [dict get $dict density] \ 163 | -format [dict get $dict ext] -background [dict get $dict background] \ 164 | -bordercolor [dict get $dict background] -alpha off -colorspace RGB \ 165 | -border [dict get $dict border] > $fname.[dict get $dict ext]] 166 | if {[dict get $dict results] eq "show"} { 167 | # should be usually empty 168 | set res $res 169 | } else { 170 | set res "" 171 | } 172 | if {[dict get $dict ext] ni [list "pdf" "png"]} { 173 | return [list "Error: unkown extension name '[dict get $dict ext]', valid values are pdf, png" ""] 174 | } 175 | set img "" 176 | if {[dict get $dict fig]} { 177 | if {[dict get $dict include]} { 178 | set img $fname.[dict get $dict ext] 179 | } 180 | } 181 | return [list $res $img] 182 | } 183 | -------------------------------------------------------------------------------- /lib/tclfilters/filter-tsvg.tcl: -------------------------------------------------------------------------------- 1 | #' --- 2 | #' title: "filter-tsvg.tcl documentation" 3 | #' author: "Detlef Groth, Caputh-Schwielowsee, Germany" 4 | #' date: 2023-03-08 5 | #' tsvg: 6 | #' imagepath: images 7 | #' ext: svg 8 | #' results: hide 9 | #' eval: 1 10 | #' --- 11 | #' 12 | #' ------ 13 | #' 14 | #' ```{.tcl eval=true results="asis" echo=false} 15 | #' include header.md 16 | #' ``` 17 | #' 18 | #' ------ 19 | #' 20 | #' ## Name 21 | #' 22 | #' _filter-tsvg.tcl_ - Filter which can be used to display SVG graphics 23 | #' within a Pandoc processed document using the Tcl library [tsvg](https://github.com/mittelmark/DGTcl). 24 | #' together with the `pantcl.bin` application. 25 | #' 26 | #' ## Usage 27 | #' 28 | #' The conversion of the Markdown documents via Pandoc should be done as follows: 29 | #' 30 | #' ``` 31 | #' pandoc input.md --filter pantcl.bin -s -o output.html 32 | #' ``` 33 | #' 34 | #' The file `filter-tsvg.tcl` is not used directly but sourced automatically by the `pantcl.bin` file. 35 | #' If code blocks with the `.tsvg` marker are found, the contents in the code block is 36 | #' processed via the Tcl interpreter using the embedded tsvg library. 37 | #' 38 | #' The following options can be given via code chunks options or as defaults in the YAML header. 39 | #' 40 | #' > - eval - should the code in the code block be evaluated, default: false 41 | #' - ext - file file extension, can be svg, png or pdf, the latter two require the command application 42 | #' cairsvg to be installed default: svg 43 | #' - fig - should a figure be created, default: true 44 | #' - imagepath - output imagepath, default: images 45 | #' - include - should the created image be automatically included, default: true 46 | #' - label - the code chunk label used as well for the image name, default: null 47 | #' - results - should the output of the command line application been shown, should be show or hide, default: show 48 | #' 49 | #' To change the defaults the YAML header can be used. Here an example to change the 50 | #' the image output path to nfigures and the file extension to pdf 51 | #' (useful for Pdf output of the document as in LaTeX mode of pandoc). You should usually always change the 52 | #' options results: to hide. It is as well important to change the default 53 | #' option for code evaluation in the YAML header to 1 as a new default. Without 54 | #' this option you would have to set the `eval` argument for every code chunk 55 | #' again and again to true for code evaluation. This is done for security 56 | #' reasons to avoid running Tcl just by accident. In the YAML header you have 57 | #' to use 0 or 1 as defaults for boolean values instead of false and true. 58 | #' 59 | #' ``` 60 | #' ---- 61 | #' title: "filter-tsvg.tcl documentation" 62 | #' author: "Detlef Groth, Caputh-Schwielowsee, Germany" 63 | #' date: 2021-12-12 64 | #' tsvg: 65 | #' imagepath: nfigures 66 | #' eval: 1 67 | #' ext: pdf 68 | #' results: hide 69 | #' ---- 70 | #' ``` 71 | #' 72 | #' ## Examples 73 | #' 74 | #' Here an example for a simple hello world image: 75 | #' 76 | #' ``` 77 | #' ```{.tsvg eval=true} 78 | #' tsvg set code "" ;# clear 79 | #' tsvg circle -cx 50 -cy 50 -r 45 -stroke black -stroke-width 2 -fill green 80 | #' tsvg text -x 29 -y 45 Hello 81 | #' tsvg text -x 27 -y 65 World! 82 | # ``` 83 | #' ``` 84 | #' 85 | #' Please note that the `eval` setting is not needed if you did `eval: 1` in 86 | #' the YAML header. Here is the output: 87 | #' 88 | #' ```{.tsvg} 89 | #' tsvg set code "" ;# clear 90 | #' tsvg circle -cx 50 -cy 50 -r 45 -stroke black -stroke-width 2 -fill green 91 | #' tsvg text -x 29 -y 45 Hello 92 | #' tsvg text -x 27 -y 65 World! 93 | #' ``` 94 | #' 95 | #' Creating a new image needs cleanup of the current image using `tsvg set code ""`, 96 | #' below we include a font which is only available on our local machine 97 | #' so we set the filetype to png like this: `{.tsvg ext=png}` 98 | #' 99 | #' ```{.tsvg ext=png} 100 | #' tsvg set code "" 101 | #' tsvg set width 100 102 | #' tsvg set height 60 103 | #' tsvg rect -x 0 -y 0 -width 100 -height 100 -fill #F64935 104 | #' tsvg text -x 20 -y 40 -style "font-size:24px;fill:blue;font-family: Alegreya;" tSVG 105 | #' ``` 106 | #' 107 | #' ## See also: 108 | #' 109 | #' * [Pantcl Readme](../../README.html) 110 | #' * [Pantcl Tutorial](../../pantcl-tutorial.html) - which shows how the tsvg package was developed. 111 | #' * [tsvg package documentation](../tsvg/tsvg.html) 112 | #' 113 | 114 | package require tsvg 115 | interp create tsvgi 116 | set apath [tsvgi eval { set auto_path } ] 117 | foreach d $auto_path { 118 | if {[lsearch $apath $d] == -1} { 119 | tsvgi eval "lappend auto_path $d" 120 | } 121 | } 122 | tsvgi eval "package require tsvg" 123 | proc filter-tsvg {cont dict} { 124 | global n 125 | incr n 126 | set def [dict create results hide eval true fig true width 100 height 100 \ 127 | include true label null imagepath images ext svg] 128 | set dict [dict merge $def $dict] 129 | if {![dict get $dict eval]} { 130 | return [list "" ""] 131 | } 132 | set ret "" 133 | set owd [pwd] 134 | if {[dict get $dict label] eq "null"} { 135 | set fname [file join $owd [dict get $dict imagepath] tsvg-$n] 136 | } else { 137 | set fname [file join $owd [dict get $dict imagepath] [dict get $dict label]] 138 | } 139 | if {![file exists [file join $owd [dict get $dict imagepath]]]} { 140 | file mkdir [file join $owd [dict get $dict imagepath]] 141 | } 142 | # protect semicolons in attributes for ending a command 143 | set code [regsub -all {([^ ]);} $cont "\\1\\\\;"] 144 | if {[catch { 145 | set res2 [tsvgi eval $code] 146 | }]} { 147 | set res2 "Error: [regsub {\n +invoked.+} $::errorInfo {}]" 148 | } 149 | 150 | if {[dict get $dict results] eq "show" && $res2 ne ""} { 151 | set res2 $res2 152 | } else { 153 | set res2 "" 154 | } 155 | if {[dict get $dict ext] ni [list "pdf" "png" "svg"]} { 156 | return [list "Error: unkown extension name '[dict get $dict ext]', valid values are svg, pdf, png" ""] 157 | } 158 | if {[dict get $dict ext] in [list "pdf" "png"]} { 159 | if {[auto_execok cairosvg] eq ""} { 160 | return [list "Error: pdf and png conversion needs cairosvg, please install cairosvg https://www.cairosvg.org !" ""] 161 | } 162 | } 163 | set img "" 164 | set imgfile ${fname}.[dict get $dict ext] 165 | if {[dict get $dict fig]} { 166 | tsvgi eval "tsvg write $imgfile" 167 | if {[dict get $dict include]} { 168 | set img $imgfile 169 | } else { 170 | set img "" 171 | } 172 | } 173 | return [list $res2 $img] 174 | } 175 | 176 | 177 | 178 | -------------------------------------------------------------------------------- /lib/tclfilters/filter-tdot.tcl: -------------------------------------------------------------------------------- 1 | #' --- 2 | #' title: "filter-tdot.tcl documentation" 3 | #' author: "Detlef Groth, Caputh-Schwielowsee, Germany" 4 | #' date: 2021-12-15 5 | #' tdot: 6 | #' imagepath: images 7 | #' ext: svg 8 | #' results: hide 9 | #' eval: 1 10 | #' --- 11 | #' 12 | #' ------ 13 | #' 14 | #' ```{.tcl eval=true results="asis" echo=false} 15 | #' include header.md 16 | #' ``` 17 | #' 18 | #' ------ 19 | #' 20 | #' ## Name 21 | #' 22 | #' _filter-tdot.tcl_ - Filter which can be used to display dot/neato diagrams 23 | #' within a Pandoc processed document using the Tcl library [tdot](https://github.com/mittelmark/DGTcl). 24 | #' together with the Pantcl filter application. 25 | #' 26 | #' ## Usage 27 | #' 28 | #' The conversion of the Markdown documents via Pandoc should be done as follows: 29 | #' 30 | #' ``` 31 | #' pandoc input.md --filter pantcl.bin -s -o output.html 32 | #' ``` 33 | #' 34 | #' The file `filter-tdot.tcl` is not used directly but sourced automatically by the `pantcl.bin` file. 35 | #' If code blocks with the `.tdot` marker are found, the contents in the code block is 36 | #' processed via the Tcl interpreter using the embedded tdot library. 37 | #' The filter requires the installation of the GraphViz command line tools dot and neato. See here: 38 | #' 39 | #' The following options can be given via code chunks options or as defaults in the YAML header. 40 | #' 41 | #' > - eval - should the code in the code block be evaluated, default: false 42 | #' - ext - file file extension, can be svg, png or pdf, default: svg 43 | #' - fig - should a figure be created, default: true 44 | #' - imagepath - output imagepath, default: images 45 | #' - include - should the created image be automatically included, default: true 46 | #' - label - the code chunk label used as well for the image name, default: null 47 | #' - results - should the output of the command line application been shown, should be show or hide, default: hide 48 | #' 49 | #' To change the defaults the YAML header can be used. Here an example to change the 50 | #' the image output path to nfigures and the file extension to pdf 51 | #' (useful for Pdf output of the document as in LaTeX mode of pandoc). You should usually always change the 52 | #' options results: to hide and more importantly the option `eval` to 1 (true). 53 | #' For security reasons and to avoid automatic code interpretation this per 54 | #' default is set to 0 (false): 55 | #' 56 | #' ``` 57 | #' ---- 58 | #' title: "filter-tdot.tcl documentation" 59 | #' author: "Detlef Groth, Caputh-Schwielowsee, Germany" 60 | #' date: 2021-12-15 61 | #' tdot: 62 | #' imagepath: nfigures 63 | #' ext: pdf 64 | #' results: hide 65 | #' eval: 1 66 | #' ---- 67 | #' ``` 68 | #' 69 | #' Please note that in the header you can only use 1 and 0 for boolean values, 70 | #' but not true and false. 71 | #' 72 | #' ## Examples 73 | #' 74 | #' Here an example for a simple hello world image: 75 | #' 76 | #' ``` 77 | #' ```{.tdot eval=true} 78 | #' tdot set type "strict digraph G" 79 | #' tdot graph margin=0.2 80 | #' tdot node width=1 height=0.7 style=filled fillcolor=salmon shape=box 81 | #' tdot block rank=same Hello World 82 | #' tdot addEdge Hello -> World 83 | #' ``` 84 | #' ``` 85 | #' 86 | #' And here is the output: 87 | #' 88 | #' ```{.tdot} 89 | #' tdot set type "strict digraph G" 90 | #' tdot graph margin=0.2 91 | #' tdot node width=1 height=0.7 style=filled fillcolor=salmon shape=box 92 | #' tdot block rank=same Hello World 93 | #' tdot addEdge Hello -> World 94 | #' ``` 95 | #' 96 | #' Creating a new image needs cleanup of the current image using `tdot set code ""`, 97 | #' below we include a font which is only available on our local machine 98 | #' so we set the filetype to png like this: `{.tdot ext=png}` 99 | #' 100 | #' ```{.tdot} 101 | #' tdot set code "" 102 | #' tdot graph margin=0.2 103 | #' tdot node width=1 height=0.7 104 | #' tdot addEdge A -> B 105 | #' ``` 106 | #' 107 | #' You might argue what is the advantage of the tdot package in contrast to writing directly dot code. 108 | #' The reason to use tdot would be to create dynamically your graphs using Tcl as the scripting language to do so. 109 | #' Here is an example: 110 | #' 111 | #' ```{.tdot} 112 | #' package require tdot 113 | #' tdot set code "" 114 | #' tdot set type "strict graph G" 115 | #' 116 | #' tdot graph margin=0.2 117 | #' tdot node width=0.5 height=0.5 \ 118 | #' style=filled fillcolor=salmon shape=circle 119 | #' tdot node Hello fillcolor=salmon 120 | #' tdot node fillcolor=skyblue 121 | #' foreach a [list A B C D E F] { 122 | #' tdot addEdge Hello -- $a 123 | #' foreach b [list a b c] { 124 | #' tdot node $a$b fillcolor=cornsilk 125 | #' tdot addEdge $a -- $a$b 126 | #' } 127 | #' } 128 | #' ``` 129 | #' 130 | #' Imagine you would to have to code this dot graphics by hand ... 131 | #' 132 | #' ## See also: 133 | #' 134 | #' * [Pantcl Readme](../../README.html) 135 | #' * [Pantcl docu](../../pantcl.html) 136 | #' * [Graphviz dot filter](filter-dot.html) 137 | #' * [filter-view docu](../fview/filter-view.html) 138 | #' 139 | 140 | package require tdot 141 | interp create tdoti 142 | set apath [tdoti eval { set auto_path } ] 143 | foreach d $auto_path { 144 | if {[lsearch $apath $d] == -1} { 145 | tdoti eval "lappend auto_path $d" 146 | } 147 | } 148 | tdoti eval "package require tdot" 149 | proc filter-tdot {cont dict} { 150 | global n 151 | incr n 152 | set def [dict create results hide eval true fig true width 100 height 100 \ 153 | include true label null imagepath images ext svg] 154 | set dict [dict merge $def $dict] 155 | if {![dict get $dict eval]} { 156 | return [list "" ""] 157 | } 158 | set ret "" 159 | set owd [pwd] 160 | if {[dict get $dict label] eq "null"} { 161 | set fname [file join $owd [dict get $dict imagepath] tdot-$n] 162 | } else { 163 | set fname [file join $owd [dict get $dict imagepath] [dict get $dict label]] 164 | } 165 | if {![file exists [file join $owd [dict get $dict imagepath]]]} { 166 | file mkdir [file join $owd [dict get $dict imagepath]] 167 | } 168 | # protect semicolons in attributes for ending a command 169 | set code [regsub -all {([^ ]);} $cont "\\1\\\\;"] 170 | if {[catch { 171 | set res2 [tdoti eval $code] 172 | }]} { 173 | set res2 "Error: [regsub {\n +invoked.+} $::errorInfo {}]" 174 | } 175 | 176 | if {[dict get $dict results] eq "show" && $res2 ne ""} { 177 | set res2 $res2 178 | } else { 179 | set res2 "" 180 | } 181 | set img "" 182 | set imgfile ${fname}.[dict get $dict ext] 183 | if {[dict get $dict fig]} { 184 | tdoti eval "tdot write $imgfile" 185 | if {[dict get $dict include]} { 186 | set img $imgfile 187 | } else { 188 | set img "" 189 | } 190 | } 191 | return [list $res2 $img] 192 | } 193 | 194 | 195 | 196 | -------------------------------------------------------------------------------- /lib/tclfilters/filter-dot.tcl: -------------------------------------------------------------------------------- 1 | #' --- 2 | #' title: "filter-dot.tcl documentation" 3 | #' author: "Detlef Groth, Caputh-Schwielowsee, Germany" 4 | #' date: 2021-12-12 5 | #' dot: 6 | #' app: dot 7 | #' imagepath: images 8 | #' ext: png 9 | ##' eval: 1 10 | #' --- 11 | #' 12 | # Pandoc filter using Tcl the script pantcl.tcl or the standalone application `pantcl.bin` 13 | # must be in the in the parent directory of the filter directory. 14 | #' 15 | #' ------ 16 | #' 17 | #' ```{.tcl eval=true results="asis" echo=false} 18 | #' include header.md 19 | #' ``` 20 | #' 21 | #' ------ 22 | #' 23 | #' ## Name 24 | #' 25 | #' _filter-dot.tcl_ - Filter which can be used to display GraphViz dot files within a Pandoc processed 26 | #' document using the Tcl filter driver `pantcl.bin`. 27 | #' 28 | #' ## Usage 29 | #' 30 | #' The conversion of the Markdown documents via Pandoc should be done as follows: 31 | #' 32 | #' ``` 33 | #' pandoc input.md --filter pantcl.bin -s -o output.html 34 | #' ``` 35 | #' 36 | #' The file `filter-dot.tcl` is not used directly but sourced automatically by the `pantcl.bin` file. 37 | #' If code blocks with the `.dot` marker are found, the contents in the code block is processed via 38 | #' one of the Graphviz tools if the eval property is set to 1/true. 39 | #' 40 | #' The following options can be given via code chunks or in the YAML header. 41 | #' 42 | #' > - app - the application to be called, such as dot, neato, twopi etc default: dot 43 | #' - ext - file file extension, can be svg, png, pdf, default: svg 44 | #' - echo - should the source code of the code block be shown, default: true 45 | #' - eval - should the code in the code block be evaluated, default: false 46 | #' - fig - should a figure be created, default: true 47 | #' - imagepath - output imagepath, default: images 48 | #' - include - should the created image be automatically included, default: true 49 | #' - results - should the output of the command line application been shown, should be show or hide, default: hide 50 | #' 51 | #' The last three options should be normally not used, they are here just for 52 | #' compatibility reasons with the other filters. 53 | #' 54 | #' To change the defaults the YAML header can be used. Here an example to change the 55 | #' default layout engine to neato and the image output path to nfigures 56 | #' 57 | #' ``` 58 | #' ---- 59 | #' title: "filter-dot.tcl documentation" 60 | #' author: "Detlef Groth, Caputh-Schwielowsee, Germany" 61 | #' date: 2021-08-31 62 | #' dot: 63 | #' app: neato 64 | #' imagepath: nfigures 65 | #' ext: png 66 | #' eval: 1 67 | #' ---- 68 | #' ``` 69 | #' 70 | #' ## Examples 71 | #' 72 | #' Below are a few samples for embedding code for the GraphViz tools dot and 73 | #' neato into Markdown documents. The examples should work as well in other text 74 | #' markup languages like LaTeX, Asciidoc etc. This filter requires a installation of the command line tools of the GraphViz tools. 75 | #' 76 | #' Links: 77 | #' 78 | #' * GraphViz Homepage: [https://graphviz.org/](https://graphviz.org/) 79 | #' * Dot guide: [https://graphviz.org/pdf/dotguide.pdf](https://graphviz.org/pdf/dotguide.pdf) 80 | #' * Neato guide: [https://graphviz.org/pdf/neatoguide.pdf](https://graphviz.org/pdf/neatoguide.pdf) 81 | #' 82 | #' ## Dot graph 83 | #' 84 | #' ``` 85 | #' ```{.dot label=digraph eval=true echo=true} 86 | #' digraph G { 87 | #' main -> parse -> execute; 88 | #' main -> init [dir=none]; 89 | #' main -> cleanup; 90 | #' execute -> make_string; 91 | #' execute -> printf 92 | #' init -> make_string; 93 | #' main -> printf; 94 | #' execute -> compare; 95 | #' } 96 | #' ``` 97 | #' ``` 98 | #' 99 | #' Which will produce the following output: 100 | #' 101 | #' ```{.dot label=digraph eval=true echo=true} 102 | #' digraph G { 103 | #' main -> parse -> execute; 104 | #' main -> init [dir=none]; 105 | #' main -> cleanup; 106 | #' execute -> make_string; 107 | #' execute -> printf 108 | #' init -> make_string; 109 | #' main -> printf; 110 | #' execute -> compare; 111 | #' } 112 | #' ``` 113 | #' 114 | #' ## Neato graphs 115 | #' 116 | #' By using the argument `app=neato` in the code chunk header you can as well 117 | #' create *neato* graphs. Here an example: 118 | #' 119 | #' ``` 120 | #' ```{.dot label=neato-sample eval=true app=neato} 121 | #' graph G { 122 | #' node [shape=box,style=filled,fillcolor=skyblue, 123 | #' color=black,width=0.4,height=0.4]; 124 | #' n0 -- n1 -- n2 -- n3 -- n0; 125 | #' } 126 | #' ``` 127 | #' ``` 128 | #' 129 | #' Here the output. 130 | #' 131 | #' ```{.dot label=neato-sample eval=true app=neato} 132 | #' graph G { 133 | #' node [shape=box,style=filled,fillcolor=skyblue, 134 | #' color=black,width=0.4,height=0.4]; 135 | #' n0 -- n1 -- n2 -- n3 -- n0; 136 | #' } 137 | #' ``` 138 | #' 139 | #' ## Document creation 140 | 141 | #' Assuming that the file pantcl.bin is in your PATH, 142 | #' this document, a Tcl file with embedded Markdown and dot code 143 | #' can be converted into a HTML file for instance using the command line: 144 | #' 145 | #' ``` 146 | #' pantcl.bin filter-dot.tcl filter-dot.html -s --css mini.css 147 | #' ``` 148 | #' 149 | #' Standard Markdown files with embedded dot code can be converted with the same command line: 150 | #' 151 | #' ``` 152 | #' pantcl.bin sample.md sample.html -s 153 | #' ``` 154 | #' 155 | #' ## See also: 156 | #' 157 | #' * [Pantcl Readme](../../README.html) 158 | #' * [Pantcl docu](../../pantcl.html) 159 | #' * [Mermaid filter](filter-mmd.html) 160 | #' * [Pikchr filter](filter-pik.html) 161 | #' * [PlantUML filter](filter-puml.html) 162 | #' 163 | 164 | 165 | proc filter-dot {cont dict} { 166 | global n 167 | incr n 168 | set def [dict create results show eval true fig true width 400 height 400 \ 169 | include true imagepath images app dot label null ext svg] 170 | set dict [dict merge $def $dict] 171 | if {![dict get $dict eval]} { 172 | return [list "" ""] 173 | } 174 | set ret "" 175 | set owd [pwd] 176 | if {[dict get $dict label] eq "null"} { 177 | set fname [file join $owd [dict get $dict imagepath] dot-$n] 178 | } else { 179 | set fname [file join $owd [dict get $dict imagepath] [dict get $dict label]] 180 | } 181 | if {![file exists [file join $owd [dict get $dict imagepath]]]} { 182 | file mkdir [file join $owd [dict get $dict imagepath]] 183 | } 184 | set out [open $fname.dot w 0600] 185 | puts $out $cont 186 | close $out 187 | # TODO: error catching 188 | set res [exec [dict get $dict app] -T[dict get $dict ext] $fname.dot -o $fname.[dict get $dict ext]] 189 | if {[dict get $dict results] eq "show"} { 190 | # should be usually empty 191 | set res $res 192 | } else { 193 | set res "" 194 | } 195 | set img "" 196 | if {[dict get $dict fig]} { 197 | if {[dict get $dict include]} { 198 | set img $fname.[dict get $dict ext] 199 | } 200 | } 201 | return [list $res $img] 202 | } 203 | -------------------------------------------------------------------------------- /lib/snit/snit_tcl83_utils.tcl: -------------------------------------------------------------------------------- 1 | #-------------------------------------------------------------------------- 2 | # TITLE: 3 | # snit_tcl83_utils.tcl 4 | # 5 | # AUTHOR: 6 | # Kenneth Green, 28 Aug 2004 7 | # 8 | # DESCRIPTION: 9 | # Utilities to support the back-port of snit from Tcl 8.4 to 8.3 10 | # 11 | #-------------------------------------------------------------------------- 12 | # Copyright 13 | # 14 | # Copyright (c) 2005 Kenneth Green 15 | # Modified by Andreas Kupries. 16 | # All rights reserved. This code is licensed as described in license.txt. 17 | #-------------------------------------------------------------------------- 18 | # This code is freely distributable, but is provided as-is with 19 | # no warranty expressed or implied. 20 | #-------------------------------------------------------------------------- 21 | # Acknowledgements 22 | # The changes described in this file are made to the awesome 'snit' 23 | # library as provided by William H. Duquette under the terms 24 | # defined in the associated 'license.txt'. 25 | #----------------------------------------------------------------------- 26 | 27 | #----------------------------------------------------------------------- 28 | # Namespace 29 | 30 | namespace eval ::snit83 {} 31 | 32 | #----------------------------------------------------------------------- 33 | # Some Snit83 variables 34 | 35 | namespace eval ::snit83 { 36 | variable cmdTraceTable 37 | array set cmdTraceTable {} 38 | 39 | namespace eval private {} 40 | } 41 | 42 | 43 | #----------------------------------------------------------------------- 44 | # Initialisation 45 | 46 | # 47 | # Override Tcl functions so we can mimic some behaviours. This is 48 | # conditional on not having been done already. Otherwise loading snit 49 | # twice will fail the second time. 50 | # 51 | 52 | if [info exists tk_version] { 53 | if { 54 | ![llength [info procs destroy]] || 55 | ![regexp snit83 [info body destroy]] 56 | } { 57 | rename destroy __destroy__ 58 | } 59 | } 60 | if { 61 | ![llength [info procs namespace]] || 62 | ![regexp snit83 [info body namespace]] 63 | } { 64 | rename namespace __namespace__ 65 | rename rename __rename__ ;# must be last one renamed! 66 | } 67 | 68 | #----------------------------------------------------------------------- 69 | # Global namespace functions 70 | 71 | 72 | # destroy - 73 | # 74 | # Perform delete tracing and then invoke the actual Tk destroy command 75 | 76 | if [info exists tk_version] { 77 | proc destroy { w } { 78 | variable ::snit83::cmdTraceTable 79 | 80 | set index "delete,$w" 81 | if [info exists cmdTraceTable($index)] { 82 | set cmd $cmdTraceTable($index) 83 | ::unset cmdTraceTable($index) ;# prevent recursive tracing 84 | if [catch {eval $cmd $oldName \"$newName\" delete} err] { ; # " 85 | error $err 86 | } 87 | } 88 | 89 | return [__destroy__ $w] 90 | } 91 | } 92 | 93 | # namespace - 94 | # 95 | # Add limited support for 'namespace exists'. Must be a fully 96 | # qualified namespace name (pattern match support not provided). 97 | 98 | proc namespace { cmd args } { 99 | if {[string equal $cmd "exists"]} { 100 | set ptn [lindex $args 0] 101 | return [::snit83::private::NamespaceIsDescendantOf :: $ptn] 102 | } elseif {[string equal $cmd "delete"]} { 103 | if [namespace exists [lindex $args 0]] { 104 | return [uplevel 1 [subst {__namespace__ $cmd $args}]] 105 | } 106 | } else { 107 | return [uplevel 1 [subst {__namespace__ $cmd $args}]] 108 | } 109 | } 110 | 111 | # rename - 112 | # 113 | # Perform rename tracing and then invoke the actual Tcl rename command 114 | 115 | proc rename { oldName newName } { 116 | variable ::snit83::cmdTraceTable 117 | 118 | # Get caller's namespace since rename must be performed 119 | # in the context of the caller's namespace 120 | set callerNs "::" 121 | set callerLevel [expr {[info level] - 1}] 122 | if { $callerLevel > 0 } { 123 | set callerInfo [info level $callerLevel] 124 | set procName [lindex $callerInfo 0] 125 | set callerNs [namespace qualifiers $procName] 126 | } 127 | 128 | #puts "rename: callerNs: $callerNs" 129 | #puts "rename: '$oldName' -> '$newName'" 130 | #puts "rename: rcds - [join [array names cmdTraceTable] "\nrename: rcds - "]" 131 | 132 | set result [namespace eval $callerNs [concat __rename__ [list $oldName $newName]]] 133 | 134 | set index1 "rename,$oldName" 135 | set index2 "rename,::$oldName" 136 | 137 | foreach index [list $index1 $index2] { 138 | if [info exists cmdTraceTable($index)] { 139 | set cmd $cmdTraceTable($index) 140 | 141 | #puts "rename: '$cmd' { $oldName -> $newName }" 142 | 143 | ::unset cmdTraceTable($index) ;# prevent recursive tracing 144 | if {![string equal $newName ""]} { 145 | # Create a new trace record under the new name 146 | set cmdTraceTable(rename,$newName) $cmd 147 | } 148 | if [catch {eval $cmd $oldName \"$newName\" rename} err] { 149 | error $err 150 | } 151 | break 152 | } 153 | } 154 | 155 | return $result 156 | } 157 | 158 | 159 | #----------------------------------------------------------------------- 160 | # Private functions 161 | 162 | proc ::snit83::private::NamespaceIsDescendantOf { parent child } { 163 | set result 0 164 | 165 | foreach ns [__namespace__ children $parent] { 166 | if [string match $ns $child] { 167 | set result 1 168 | break; 169 | } else { 170 | if [set result [NamespaceIsDescendantOf $ns $child]] { 171 | break 172 | } 173 | } 174 | } 175 | return $result 176 | } 177 | 178 | 179 | #----------------------------------------------------------------------- 180 | # Utility functions 181 | 182 | proc ::snit83::traceAddCommand {name ops command} { 183 | variable cmdTraceTable 184 | 185 | #puts "::snit83::traceAddCommand n/$name/ o/$ops/ c/$command/" 186 | #puts "XX [join [array names cmdTraceTable] "\nXX "]" 187 | 188 | foreach op $ops { 189 | set index "$op,$name" 190 | #puts "::snit83::traceAddCommand: index = $index cmd = $command" 191 | 192 | set cmdTraceTable($index) $command 193 | } 194 | } 195 | 196 | proc ::snit83::traceRemoveCommand {name ops command} { 197 | variable cmdTraceTable 198 | 199 | #puts "::snit83::traceRemoveCommand n/$name/ o/$ops/ c/$command/" 200 | #puts "YY [join [array names cmdTraceTable] "\nYY "]" 201 | 202 | foreach op $ops { 203 | set index "$op,$name" 204 | #puts "::snit83::traceRemoveCommand: index = $index cmd = $command" 205 | 206 | catch { ::unset cmdTraceTable($index) } 207 | } 208 | } 209 | 210 | # Add support for 'unset -nocomplain' 211 | proc ::snit83::unset { args } { 212 | 213 | #puts "::snit83::unset - args: '$args'" 214 | 215 | set noComplain 0 216 | if {[string equal [lindex $args 0] "-nocomplain"]} { 217 | set noComplain 1 218 | set args [lrange $args 1 end] 219 | } 220 | if {[string equal [lindex $args 0] "--"]} { 221 | set args [lrange $args 1 end] 222 | } 223 | 224 | if [catch { 225 | uplevel 1 [linsert $args 0 ::unset] 226 | } err] { 227 | if { !$noComplain } { 228 | error $err 229 | } 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /lib/tclfilters/filter-julia.tcl: -------------------------------------------------------------------------------- 1 | #' --- 2 | #' title: "filter-julia.tcl documentation" 3 | #' author: "Detlef Groth, Caputh-Schwielowsee, Germany" 4 | #' date: 2024-11-26 5 | #' julia: 6 | #' results: show 7 | #' eval: 1 8 | #' wait: 500 9 | #' --- 10 | #' 11 | #' ------ 12 | #' 13 | #' ```{.tcl eval=true results="asis" echo=false} 14 | #' set t [clock seconds] 15 | #' include header.md 16 | #' ``` 17 | #' 18 | #' ------ 19 | #' 20 | #' ## Name 21 | #' 22 | #' _filter-julia.tcl_ - Filter which can be used to execute Julia code within code chunks (slow!). 23 | #' 24 | #' ## Usage 25 | #' 26 | #' The conversion of the Markdown documents via Pandoc should be done as follows: 27 | #' 28 | #' ``` 29 | #' pandoc input.md --filter pantcl.bin -s -o output.html 30 | #' ``` 31 | #' 32 | #' The file `filter-julia.tcl` is not used directly but sourced automatically by the `pantcl.bin` file. 33 | #' If code blocks with the `.julia` marker are found, the contents in the code block is processed via the 34 | #' julia interpreter, currently using pipes. Please note that Julia is quite slow at startup, plotting and pipe communication (although it seems that in 2024 it becomes much faster). 35 | #' 36 | #' The following options can be given via code chunks or in the YAML header. 37 | #' 38 | #' > - eval - should the code in the code block be evaluated, default: false (0) 39 | #' - echo - should the input code been shown, default: true 40 | #' - plotengine - the plot engine, default: pyplot 41 | #' - results - should the output of the command line application been shown, should be asis, show or hide, default: show 42 | #' - wait - the timeout (ms) after every code evaluation to wait for the pipe to 43 | #' read, try to decrease the time to get a speedup, increase of you 44 | #' observe output at wrong places, default: 100 45 | #' 46 | #' To change the defaults the YAML header can be used. Here an example to change the 47 | #' to evaluate all Julia code chunks per default. Please note that you 48 | #' should write `eval: 1` and not(!) `eval: true` 49 | #' 50 | #' ``` 51 | #' ---- 52 | #' title: "filter-julia.tcl documentation" 53 | #' author: "Detlef Groth, University of Potsdam, Germany" 54 | #' date: 2023-05-24 55 | #' julia: 56 | #' eval: 1 57 | #' wait: 1000 58 | #' ---- 59 | #' ``` 60 | #' 61 | #' ## Examples 62 | #' 63 | #' ### Julia example 64 | #' 65 | #' ``` 66 | #' ```{.julia eval=true} 67 | #' x=1; 68 | #' l = [1,2,3] 69 | #' 70 | #' for i in l 71 | #' println(i) 72 | #' end 73 | #' 74 | #' println(x+2); 75 | #' x=2 76 | #' ``` 77 | #' ``` 78 | #' 79 | #' Here the output: 80 | #' 81 | #' ```{.julia eval=true} 82 | #' x=1; 83 | #' l = [1,2,3] 84 | #' 85 | #' for i in l 86 | #' println(i) 87 | #' end 88 | #' 89 | #' println(x+2); 90 | #' x=2 91 | #' ``` 92 | #' 93 | #' Now let's create an image try with PyPlot. Creating standard image plots with 94 | #' `using Plots` is quite slow!! Around 20 seconds in 2023 but much faster in 2024!! Julia is probably a fast 95 | #' calculator, but startup and plotting is not ... - chunk options `{.julia fig=true}` 96 | #' 97 | #' ```{.julia fig=true eval=false} 98 | #' t1=time() 99 | #' x = range(0, 1, length=30) 100 | #' y = x .^ 2 101 | #' plot(x, y,linewidth=5,color="salmon") 102 | #' println(round(time()-t1),2) 103 | #' ``` 104 | #' 105 | #' Alternatively you can use the cmd-filter - chunk options `{.cmd eval=true file=test.jl}`: 106 | #' 107 | #' ```{.cmd eval=true file=test.jl} 108 | #' #!/usr/bin/env julia 109 | #' println("Hello Julia World!") 110 | #' ``` 111 | #' 112 | #' Here let's create a plot - chunk options `{.cmd eval=true file=test-plot.jl}`: 113 | #' 114 | #' ```{.cmd eval=true file=test-plot.jl} 115 | #' #!/usr/bin/env julia 116 | #' t1=time() 117 | #' using Plots 118 | #' x = range(0, 10, length=100) 119 | #' y = sin.(x) 120 | #' plot(x, y) 121 | #' savefig("test-plot.png") 122 | #' t2=time() 123 | #' println("running time: ",round(t2-t1)) 124 | #' ``` 125 | #' 126 | #' ![](test-plot.png) 127 | #' 128 | #' 129 | #' Debugging: 130 | #' 131 | #' ```{.tcl eval=true} 132 | #' puts "time for document compilation: [expr {[clock seconds] - $t}]" 133 | #' ``` 134 | #' 135 | #' ## TODO: 136 | #' 137 | #' * terminal mode on/off 138 | #' 139 | #' ## See also: 140 | #' 141 | #' * [Pantcl Readme](../../README.html) 142 | #' * [Tcl filter](../../pantcl.html) 143 | #' * [Rplot filter](filter-rplot.html) 144 | #' 145 | 146 | namespace eval ::jpipe { 147 | variable n 0 148 | variable pipecode "" 149 | variable jpipe "" 150 | variable juliacode "" 151 | variable debug "" 152 | variable pengine "" 153 | } 154 | 155 | proc ::jpipe::piperead {pipe args} { 156 | variable debug 157 | if {![eof $pipe]} { 158 | set got [gets $pipe] 159 | append debug "got: $got" 160 | if {$got ne ""} { 161 | append ::jpipe::pipecode "$got\n" 162 | } 163 | } elseif {[fblocked $pipe]} { 164 | # No output 165 | break 166 | } else { 167 | close $pipe 168 | } 169 | } 170 | 171 | proc ::jpipe::pipeputs {msg} { 172 | append ::jpipe::juliacode "\n$msg" 173 | puts $::jpipe::jpipe $msg 174 | flush $::jpipe::jpipe 175 | } 176 | 177 | # * trace add execution exit enter YourCleanupProc 178 | proc ::jpipe::run-julia {args} { 179 | set out [open julia.jl w 0600] 180 | puts $out "$::jpipe::juliacode" 181 | close $out 182 | #exec julia --threads 1 2>@1 > julia.out 183 | } 184 | 185 | proc filter-julia {cont dict} { 186 | 187 | incr ::jpipe::n 188 | set ::jpipe::pipecode "" 189 | set def [dict create results show eval false label null imagepath images \ 190 | include true terminal true wait 1000 fig false plotengine pyplot] 191 | set dict [dict merge $def $dict] 192 | set img "" 193 | if {[dict get $dict label] eq "null"} { 194 | dict set dict label jpipe-$::jpipe::n 195 | } 196 | append ::jpipe::debug "wait: [dict get $dict wait]" 197 | if {[dict get $dict eval]} { 198 | set wait [list] 199 | if {$::jpipe::jpipe eq ""} { 200 | set ::jpipe::debug "" 201 | set ::jpipe::jpipe [open "|julia 2>@1" r+] 202 | append ::jpipe::debug "running julia" 203 | fconfigure $::jpipe::jpipe -buffering none -blocking false 204 | fileevent $::jpipe::jpipe readable [list ::jpipe::piperead $::jpipe::jpipe] 205 | trace add execution exit enter ::jpipe::run-julia 206 | set ::jpipe::pipecode "" 207 | } 208 | if {[dict get $dict fig] && $::jpipe::pengine eq ""} { 209 | if {[dict get $dict plotengine] eq "pyplot"} { 210 | ::jpipe::pipeputs "using PyPlot;\nioff();" 211 | after 1000 [list append wait ""] 212 | } elseif {[dict get $dict plotengine] eq "plots"} { 213 | ::jpipe::pipeputs "using Plots;" 214 | after 5000 [list append wait ""] 215 | } 216 | vwait wait 217 | set ::jpipe::pengine [dict get $dict plotengine] 218 | } 219 | set term "julia> " 220 | foreach line [split $cont \n] { 221 | # && [string range [dict get $dict pipe] 0 0] ne "R" 222 | if {[dict get $dict terminal]} { 223 | append ::jpipe::pipecode "$term $line\n" 224 | } 225 | ::jpipe::pipeputs "$line" 226 | if {[regexp {^[^\s]} $line]} { 227 | # delay only if first letter is non-whitespace 228 | # to allow to flush output 229 | ::jpipe::pipeputs "" 230 | after [dict get $dict wait] [list append wait ""] 231 | vwait wait 232 | } 233 | } 234 | after [dict get $dict wait] [list append wait ""] 235 | vwait wait 236 | if {[dict get $dict fig]} { 237 | set img [file join [dict get $dict imagepath] [dict get $dict label].png] 238 | ::jpipe::pipeputs "savefig(\"$img\");\n" 239 | 240 | } 241 | after [dict get $dict wait] [list append wait ""] 242 | vwait wait 243 | set out [open julia-[dict get $dict label].jl w 0600] 244 | puts $out "$jpipe::juliacode" 245 | close $out 246 | after [dict get $dict wait] [list append wait ""] 247 | vwait wait 248 | set res $::jpipe::pipecode 249 | } else { 250 | set res "" 251 | } 252 | if {!([dict get $dict results] in [list show asis])} { 253 | set res "" 254 | } 255 | return [list $res $img] 256 | } 257 | -------------------------------------------------------------------------------- /lib/citer/assets/literature.bib: -------------------------------------------------------------------------------- 1 | @article{Sievers2011, 2 | title = {{{F}ast, scalable generation of high-quality protein multiple sequence alignments using {C}lustal {O}mega}}, 3 | author = {Sievers, F. and Wilm, A. and Dineen, D. and Gibson, T. J. and Karplus, K. and Li, W. and Lopez, R. and McWilliam, H. and Remmert, M. and Soding, J. and Thompson, J. D. and Higgins, D. G.}, 4 | year = 2011, 5 | month = {Oct}, 6 | journal = {Mol. Syst. Biol.}, 7 | volume = 7, 8 | pages = 539 9 | } 10 | @article{Yachdav2016, 11 | title = {MSAViewer: interactive JavaScript visualization of multiple sequence alignments}, 12 | author = {Yachdav, Guy and Wilzbach, Sebastian and Rauscher, Benedikt and Sheridan, Robert and Sillitoe, Ian and Procter, James and Lewis, Suzanna E. and Rost, Burkhard and Goldberg, Tatyana}, 13 | year = 2016, 14 | journal = {Bioinformatics}, 15 | volume = 32, 16 | number = 22, 17 | pages = 3501, 18 | doi = {10.1093/bioinformatics/btw474}, 19 | url = {http://dx.doi.org/10.1093/bioinformatics/btw474} 20 | } 21 | @article{Gouy2010, 22 | title = {{{S}ea{V}iew version 4: {A} multiplatform graphical user interface for sequence alignment and phylogenetic tree building}}, 23 | author = {Gouy, M. and Guindon, S. and Gascuel, O. }, 24 | year = 2010, 25 | month = {Feb}, 26 | journal = {Mol. Biol. Evol.}, 27 | volume = 27, 28 | number = 2, 29 | pages = {221--224}, 30 | abstract = {We present SeaView version 4, a multiplatform program designed to facilitate multiple alignment and phylogenetic tree building from molecular sequence data through the use of a graphical user interface. SeaView version 4 combines all the functions of the widely used programs SeaView (in its previous versions) and Phylo_win, and expands them by adding network access to sequence databases, alignment with arbitrary algorithm, maximum-likelihood tree building with PhyML, and display, printing, and copy-to-clipboard of rooted or unrooted, binary or multifurcating phylogenetic trees. In relation to the wide present offer of tools and algorithms for phylogenetic analyses, SeaView is especially useful for teaching and for occasional users of such software. SeaView is freely available at http://pbil.univ-lyon1.fr/software/seaview.} 31 | } 32 | @article{Brown1998, 33 | title = {{{M}{V}iew: a web-compatible database search or multiple alignment viewer}}, 34 | author = {Brown, N. P. and Leroy, C. and Sander, C. }, 35 | year = 1998, 36 | journal = {Bioinformatics}, 37 | volume = 14, 38 | number = 4, 39 | pages = {380--381} 40 | } 41 | @book{Freedman2005, 42 | title = {Statistical Models : Theory and Practice}, 43 | author = {Freedman, David}, 44 | year = 2005, 45 | month = {August}, 46 | publisher = {{Cambridge University Press}}, 47 | isbn = {0521854830}, 48 | abstract = {{Explaining the things you need to know in order to read empirical papers in the social and health sciences, as well as techniques needed to build personal statistical models, this user-friendly volume includes background material on study design, bivariate regression, and matrix algebra. To develop technique, Freedman also includes computer labs, with sample computer programs, and illustrates the principles and pitfalls of modeling. The book is rich in exercises with answers. Target audiences include undergraduates and beginning graduate students in statistics, as well as students and professionals in the social and health sciences.}}, 49 | added-at = {2009-10-28T04:42:52.000+0100}, 50 | biburl = {http://www.bibsonomy.org/bibtex/25c6765fcac39d506906ec3db6e72b1f7/jwbowers}, 51 | citeulike-article-id = 557353, 52 | date-added = {2007-09-03 22:45:16 -0500}, 53 | date-modified = {2007-09-03 22:45:16 -0500}, 54 | howpublished = {Hardcover}, 55 | interhash = {2b337e2f2c8645faa395d6ebc92d5730}, 56 | intrahash = {5c6765fcac39d506906ec3db6e72b1f7}, 57 | keywords = {statistics}, 58 | priority = 5, 59 | timestamp = {2009-10-28T04:42:58.000+0100} 60 | } 61 | @article{Nuzzo2014, 62 | title = {Scientific method: statistical errors}, 63 | author = {Nuzzo, Regina}, 64 | year = 2014, 65 | journal = {Nature News}, 66 | volume = 506, 67 | number = 7487, 68 | pages = 150 69 | } 70 | @misc{Cohen1988, 71 | title = {Statistical power analysis for the behavioral sciences. 2nd}, 72 | author = {Cohen, Jacob}, 73 | year = 1988, 74 | publisher = {Hillsdale, NJ: erlbaum} 75 | } 76 | @manual{vcd1, 77 | title = {vcd: Visualizing Categorical Data}, 78 | author = {David Meyer and Achim Zeileis and Kurt Hornik}, 79 | year = 2017, 80 | note = {R package version 1.4-4} 81 | } 82 | @article{Ioannidis2020, 83 | title = {A fiasco in the making? {A}s the coronavirus pandemic takes hold, we are making decisions without reliable data}, 84 | author = {Ioannidis, J.P.A}, 85 | year = 2020, 86 | journal = {www.statnews.com}, 87 | volume = {March, 17th}, 88 | url = {https://www.statnews.com/2020/03/17/a-fiasco-in-the-making-as-the-coronavirus-pandemic-takes-hold-we-are-making-decisions-without-reliable-data/} 89 | } 90 | @misc{wiki:pvalue, 91 | title = {{Wikipedia{,} The Free Encyclopedia}}, 92 | author = {{{Wikipedia --- p-value}}}, 93 | year = 2020, 94 | url = {https://en.wikipedia.org/wiki/P-value}, 95 | note = {[Online; accessed 01-April-2020]} 96 | } 97 | @misc{wiki:ci, 98 | title = {{Wikipedia{,} The Free Encyclopedia}}, 99 | author = {{{Wikipedia --- Confidence interval}}}, 100 | year = 2020, 101 | url = {https://en.wikipedia.org/wiki/Confidence_interval}, 102 | note = {[Online; accessed 01-April-2020]} 103 | } 104 | @misc{wiki:blast, 105 | title = {{Wikipedia{,} The Free Encyclopedia}}, 106 | author = {{{Wikipedia --- BLAST (biotechnology)}}}, 107 | year = 2020, 108 | url = {https://en.wikipedia.org/wiki/BLAST_(biotechnology)}, 109 | note = {[Online; accessed 02-May-2020]} 110 | } 111 | @article{Altschul1990, 112 | title = {Sequence homology searches done using BLAST}, 113 | author = {Altschul, SF and Gish, W and Miller, W and Myers, EW and Lipman, DJ}, 114 | year = 1990, 115 | journal = {J Mol Biol}, 116 | volume = 215, 117 | pages = {404--415} 118 | } 119 | @article{Chou1974, 120 | title = {Prediction of protein conformation}, 121 | author = {Chou, Peter Y and Fasman, Gerald D}, 122 | year = 1974, 123 | journal = {Biochemistry}, 124 | publisher = {ACS Publications}, 125 | volume = 13, 126 | number = 2, 127 | pages = {222--245} 128 | } 129 | @article{Chou1978, 130 | title = {Empirical predictions of protein conformation}, 131 | author = {Chou, Peter Y and Fasman, Gerald D}, 132 | year = 1978, 133 | journal = {Annual review of biochemistry}, 134 | publisher = {Annual Reviews 4139 El Camino Way, PO Box 10139, Palo Alto, CA 94303-0139, USA}, 135 | volume = 47, 136 | number = 1, 137 | pages = {251--276} 138 | } 139 | @incollection{Groth2013, 140 | title = {Principal Components Analysis}, 141 | author = {Groth, Detlef and Hartmann, Stefanie and Klie, Sebastian and Selbig, Joachim}, 142 | year = 2013, 143 | booktitle = {Computational Toxicology}, 144 | publisher = {Humana Press}, 145 | series = {Methods in Molecular Biology}, 146 | volume = 930, 147 | pages = {527--547}, 148 | isbn = {978-1-62703-058-8}, 149 | url = {http://dx.doi.org/10.1007/978-1-62703-059-5_22}, 150 | editor = {Reisfeld, Brad and Mayeno, Arthur N.}, 151 | keywords = {Principal components analysis; Multivariate data analysis; Metabolite profiling; Codon usage; Dimensionality reduction}, 152 | language = {English} 153 | } 154 | @article{Wilcoxon1945, 155 | title = {Individual comparisons by ranking methods.}, 156 | author = {Wilcoxon, Frank}, 157 | year = 1945, 158 | journal = {Biom. Bull.}, 159 | volume = 1, 160 | pages = {80--93}, 161 | url = {https://sci2s.ugr.es/keel/pdf/algorithm/articulo/wilcoxon1945.pdf} 162 | } 163 | 164 | @article{Spearman1904, 165 | title = {The proof and measurement of association between two things}, 166 | author = {Spearman, Charles}, 167 | journal = {The American Journal of Psychology}, 168 | volume = {15}, 169 | number = {1}, 170 | year = {1904}, 171 | pages = {72--101}, 172 | } 173 | -------------------------------------------------------------------------------- /lib/tclfilters/assets/literature.bib: -------------------------------------------------------------------------------- 1 | @article{Sievers2011, 2 | title = {{{F}ast, scalable generation of high-quality protein multiple sequence alignments using {C}lustal {O}mega}}, 3 | author = {Sievers, F. and Wilm, A. and Dineen, D. and Gibson, T. J. and Karplus, K. and Li, W. and Lopez, R. and McWilliam, H. and Remmert, M. and Soding, J. and Thompson, J. D. and Higgins, D. G.}, 4 | year = 2011, 5 | month = {Oct}, 6 | journal = {Mol. Syst. Biol.}, 7 | volume = 7, 8 | pages = 539 9 | } 10 | @article{Yachdav2016, 11 | title = {MSAViewer: interactive JavaScript visualization of multiple sequence alignments}, 12 | author = {Yachdav, Guy and Wilzbach, Sebastian and Rauscher, Benedikt and Sheridan, Robert and Sillitoe, Ian and Procter, James and Lewis, Suzanna E. and Rost, Burkhard and Goldberg, Tatyana}, 13 | year = 2016, 14 | journal = {Bioinformatics}, 15 | volume = 32, 16 | number = 22, 17 | pages = 3501, 18 | doi = {10.1093/bioinformatics/btw474}, 19 | url = {http://dx.doi.org/10.1093/bioinformatics/btw474} 20 | } 21 | @article{Gouy2010, 22 | title = {{{S}ea{V}iew version 4: {A} multiplatform graphical user interface for sequence alignment and phylogenetic tree building}}, 23 | author = {Gouy, M. and Guindon, S. and Gascuel, O. }, 24 | year = 2010, 25 | month = {Feb}, 26 | journal = {Mol. Biol. Evol.}, 27 | volume = 27, 28 | number = 2, 29 | pages = {221--224}, 30 | abstract = {We present SeaView version 4, a multiplatform program designed to facilitate multiple alignment and phylogenetic tree building from molecular sequence data through the use of a graphical user interface. SeaView version 4 combines all the functions of the widely used programs SeaView (in its previous versions) and Phylo_win, and expands them by adding network access to sequence databases, alignment with arbitrary algorithm, maximum-likelihood tree building with PhyML, and display, printing, and copy-to-clipboard of rooted or unrooted, binary or multifurcating phylogenetic trees. In relation to the wide present offer of tools and algorithms for phylogenetic analyses, SeaView is especially useful for teaching and for occasional users of such software. SeaView is freely available at http://pbil.univ-lyon1.fr/software/seaview.} 31 | } 32 | @article{Brown1998, 33 | title = {{{M}{V}iew: a web-compatible database search or multiple alignment viewer}}, 34 | author = {Brown, N. P. and Leroy, C. and Sander, C. }, 35 | year = 1998, 36 | journal = {Bioinformatics}, 37 | volume = 14, 38 | number = 4, 39 | pages = {380--381} 40 | } 41 | @book{Freedman2005, 42 | title = {Statistical Models : Theory and Practice}, 43 | author = {Freedman, David}, 44 | year = 2005, 45 | month = {August}, 46 | publisher = {{Cambridge University Press}}, 47 | isbn = {0521854830}, 48 | abstract = {{Explaining the things you need to know in order to read empirical papers in the social and health sciences, as well as techniques needed to build personal statistical models, this user-friendly volume includes background material on study design, bivariate regression, and matrix algebra. To develop technique, Freedman also includes computer labs, with sample computer programs, and illustrates the principles and pitfalls of modeling. The book is rich in exercises with answers. Target audiences include undergraduates and beginning graduate students in statistics, as well as students and professionals in the social and health sciences.}}, 49 | added-at = {2009-10-28T04:42:52.000+0100}, 50 | biburl = {http://www.bibsonomy.org/bibtex/25c6765fcac39d506906ec3db6e72b1f7/jwbowers}, 51 | citeulike-article-id = 557353, 52 | date-added = {2007-09-03 22:45:16 -0500}, 53 | date-modified = {2007-09-03 22:45:16 -0500}, 54 | howpublished = {Hardcover}, 55 | interhash = {2b337e2f2c8645faa395d6ebc92d5730}, 56 | intrahash = {5c6765fcac39d506906ec3db6e72b1f7}, 57 | keywords = {statistics}, 58 | priority = 5, 59 | timestamp = {2009-10-28T04:42:58.000+0100} 60 | } 61 | @article{Nuzzo2014, 62 | title = {Scientific method: statistical errors}, 63 | author = {Nuzzo, Regina}, 64 | year = 2014, 65 | journal = {Nature News}, 66 | volume = 506, 67 | number = 7487, 68 | pages = 150 69 | } 70 | @misc{Cohen1988, 71 | title = {Statistical power analysis for the behavioral sciences. 2nd}, 72 | author = {Cohen, Jacob}, 73 | year = 1988, 74 | publisher = {Hillsdale, NJ: erlbaum} 75 | } 76 | @manual{vcd1, 77 | title = {vcd: Visualizing Categorical Data}, 78 | author = {David Meyer and Achim Zeileis and Kurt Hornik}, 79 | year = 2017, 80 | note = {R package version 1.4-4} 81 | } 82 | @article{Ioannidis2020, 83 | title = {A fiasco in the making? {A}s the coronavirus pandemic takes hold, we are making decisions without reliable data}, 84 | author = {Ioannidis, J.P.A}, 85 | year = 2020, 86 | journal = {www.statnews.com}, 87 | volume = {March, 17th}, 88 | url = {https://www.statnews.com/2020/03/17/a-fiasco-in-the-making-as-the-coronavirus-pandemic-takes-hold-we-are-making-decisions-without-reliable-data/} 89 | } 90 | @misc{wiki:pvalue, 91 | title = {{Wikipedia{,} The Free Encyclopedia}}, 92 | author = {{{Wikipedia --- p-value}}}, 93 | year = 2020, 94 | url = {https://en.wikipedia.org/wiki/P-value}, 95 | note = {[Online; accessed 01-April-2020]} 96 | } 97 | @misc{wiki:ci, 98 | title = {{Wikipedia{,} The Free Encyclopedia}}, 99 | author = {{{Wikipedia --- Confidence interval}}}, 100 | year = 2020, 101 | url = {https://en.wikipedia.org/wiki/Confidence_interval}, 102 | note = {[Online; accessed 01-April-2020]} 103 | } 104 | @misc{wiki:blast, 105 | title = {{Wikipedia{,} The Free Encyclopedia}}, 106 | author = {{{Wikipedia --- BLAST (biotechnology)}}}, 107 | year = 2020, 108 | url = {https://en.wikipedia.org/wiki/BLAST_(biotechnology)}, 109 | note = {[Online; accessed 02-May-2020]} 110 | } 111 | @article{Altschul1990, 112 | title = {Sequence homology searches done using BLAST}, 113 | author = {Altschul, SF and Gish, W and Miller, W and Myers, EW and Lipman, DJ}, 114 | year = 1990, 115 | journal = {J Mol Biol}, 116 | volume = 215, 117 | pages = {404--415} 118 | } 119 | @article{Chou1974, 120 | title = {Prediction of protein conformation}, 121 | author = {Chou, Peter Y and Fasman, Gerald D}, 122 | year = 1974, 123 | journal = {Biochemistry}, 124 | publisher = {ACS Publications}, 125 | volume = 13, 126 | number = 2, 127 | pages = {222--245} 128 | } 129 | @article{Chou1978, 130 | title = {Empirical predictions of protein conformation}, 131 | author = {Chou, Peter Y and Fasman, Gerald D}, 132 | year = 1978, 133 | journal = {Annual review of biochemistry}, 134 | publisher = {Annual Reviews 4139 El Camino Way, PO Box 10139, Palo Alto, CA 94303-0139, USA}, 135 | volume = 47, 136 | number = 1, 137 | pages = {251--276} 138 | } 139 | @incollection{Groth2013, 140 | title = {Principal Components Analysis}, 141 | author = {Groth, Detlef and Hartmann, Stefanie and Klie, Sebastian and Selbig, Joachim}, 142 | year = 2013, 143 | booktitle = {Computational Toxicology}, 144 | publisher = {Humana Press}, 145 | series = {Methods in Molecular Biology}, 146 | volume = 930, 147 | pages = {527--547}, 148 | isbn = {978-1-62703-058-8}, 149 | url = {http://dx.doi.org/10.1007/978-1-62703-059-5_22}, 150 | editor = {Reisfeld, Brad and Mayeno, Arthur N.}, 151 | keywords = {Principal components analysis; Multivariate data analysis; Metabolite profiling; Codon usage; Dimensionality reduction}, 152 | language = {English} 153 | } 154 | @article{Wilcoxon1945, 155 | title = {Individual comparisons by ranking methods.}, 156 | author = {Wilcoxon, Frank}, 157 | year = 1945, 158 | journal = {Biom. Bull.}, 159 | volume = 1, 160 | pages = {80--93}, 161 | url = {https://sci2s.ugr.es/keel/pdf/algorithm/articulo/wilcoxon1945.pdf} 162 | } 163 | 164 | @article{Spearman1904, 165 | title = {The proof and measurement of association between two things}, 166 | author = {Spearman, Charles}, 167 | journal = {The American journal of psychology}, 168 | volume = {15}, 169 | number = {1}, 170 | year = {1904}, 171 | pages = {72--101}, 172 | } 173 | -------------------------------------------------------------------------------- /user/filter-geasy.tcl: -------------------------------------------------------------------------------- 1 | #' --- 2 | #' title: "filter-geasy.tcl documentation" 3 | #' author: "Detlef Groth, Caputh-Schwielowsee, Germany" 4 | #' date: 2023-04-17 5 | #' geasy: 6 | #' app: graph-easy 7 | #' eval: 1 8 | #' as: ascii 9 | #' filter: user/filter-geasy.tcl 10 | #' --- 11 | #' 12 | # A simple pandoc filter for the [graph-easy](http://bloodgate.com/perl/graph/manual/) application to demonstrate the use of user programmed filters. 13 | #' 14 | #' 15 | #' ## Name 16 | #' 17 | #' _filter-geasy.tcl_ - Filter which can be used to evaluate [Graph-Easy](http://bloodgate.com/perl/graph/manual/) code 18 | #' within a Pandoc processed document using the Tcl filter driver `pantcl` using user 19 | #' provided filter written in Tcl. 20 | #' 21 | #' ## Description 22 | #' 23 | #' This is a filter supporting an easy to use command line based diagramming tool. The `graph-easy` command line application can be installed using your 24 | #' package manager on Unix system like this on Fedora Linux `sudo dnf install perl-Graph-Easy` or on 25 | #' Ubuntu/Debian `sudo apt-get install -y libgraph-easy-perl`. 26 | #' 27 | #' Please note that this filter mainly exists mainly to demonstrate how to use an external pandoc 28 | #' filter written in the Tcl programming without adding it directly to the pantcl executable. 29 | #' For more documentation on how to implement your own filter see the [user-filter](user-filter.html). 30 | #' 31 | #' ## Usage 32 | #' 33 | #' Graph-Easy code is embedded into Markup languages like Markdown like this 34 | #' (remove the spaces at the beginning, they are here just for protecting the evaluation): 35 | #' 36 | #' ``` 37 | #' # code chunk defaults (must be in fact not given): 38 | #' ```{.geasy eval=true echo=true} 39 | #' [Bonn] - car -> [Berlin] 40 | #' ``` 41 | #' ``` 42 | #' 43 | #' Where `eval` and `echo` are so called chunk options. Please note that this is an external filter, 44 | #' to use the filter your actual need to point in your YAML header to the filter implementation, see below for more informatian. 45 | #' 46 | #' The conversion of the Markdown documents via Pandoc should be then done as follows: 47 | #' 48 | #' ``` 49 | #' pantcl input.md output.html -s 50 | #' ``` 51 | #' 52 | #' The application file *pantcl* which contains the Tcl filter and all other filters has to be placed in the PATH and the 53 | #' system has to support the Shebang, on Unix this is standard on Windows you need to use tools like Cygwin, Msys, 54 | #' Git-Bash or Cygwin (untested). 55 | #' 56 | #' The arguments after the output file are delegated to pandoc. 57 | #' 58 | #' If code blocks with the `.geasy` marker are found, the contents in the code 59 | #' block is processed via the graph-easy command line application. 60 | #' 61 | #' The following options can be given via code chunks or in the YAML header. 62 | #' 63 | #' > - _app_ - the command line application to be called, usually `graph-easy`, default: `graph-easy` 64 | #' - _as_ - the output format default, ascii, other options are boxart, dot, default: ascii 65 | #' - _echo_ - should the graph easy source code be shown, default: true|1 66 | #' - _eval_ - should the code in the code block be evaluated, default: false|0 67 | #' - _ext_ - the image filetype to be generated if output `as` is `dot`, either png, pdf, svg usually, default: svg 68 | #' - _results_ - should the output of the command line application been shown, should be show or hide, default: "show" 69 | #' 70 | #' To change the defaults the YAML header can be used. Here an example to change the 71 | #' You should set eval to 1 as shown as well below, the term true 72 | #' might produce an error, so write `eval: 1` 73 | #' 74 | #' ``` 75 | #' ---- 76 | #' title: "filter-geasy.tcl documentation" 77 | #' author: "Detlef Groth, Caputh-Schwielowsee, Germany" 78 | #' date: 2023-04-15 79 | #' geasy: 80 | #' app: graph-easy 81 | #' eval: 1 82 | #' filter: user/filter-geasy.tcl 83 | #' ext: svg 84 | #' ---- 85 | #' ``` 86 | #' 87 | #' ## Examples 88 | #' 89 | #' Here an example for a simple diagram with chunk options `{.geasy eval=true}`:. 90 | #' 91 | #' ```{.geasy eval=true} 92 | #' [Bonn] - car -> [Berlin] 93 | #' ``` 94 | #' 95 | #' Using the option `{.geasy eval=true results="hide"}` the output of the command line tool can be hidden. 96 | #' 97 | #' ```{.geasy eval=true results="hide"} 98 | #' [Bonn] - car -> [Berlin] 99 | #' ``` 100 | #' 101 | #' Using the option `{.geasy eval=true as="boxart"}` we can try to use Unicode boxart characters. 102 | #' 103 | #' ```{.geasy eval=true as="boxart"} 104 | #' [Bonn] - car -> [Berlin] 105 | #' ``` 106 | #' 107 | #' Using the option `{.geasy eval=true as="dot"}` we can as well output a SVG graphic. Please 108 | #' note that this needs an installed GraphViz dot interpreter which must be in the PATH. 109 | #' 110 | #' ```{.geasy eval=true as="dot"} 111 | #' [Bonn] - car -> [Berlin] 112 | #' ``` 113 | #' 114 | #' In this case we usually like to hide the digraph code output we can to this by writing results="hide" as code chunk option. 115 | #' Consulting the tutorial page for graph-easy syntax we can as well see that we can set 116 | #' some display options for nodes etc. the code chunk options here are: `{.geasy eval=true as="dot" results="hide"}` 117 | #' 118 | #' ```{.geasy eval=true as="dot" results="hide"} 119 | #' [ Paris ] { shape: ellipse; fill: salmon; } 120 | #' -- Flight --> 121 | #' [ Bonn ] { shape: circle; fill: skyblue; } 122 | #' -- Car --> { color: red; } 123 | #' [ Berlin ] { fill: rgb(255,228,221); } 124 | #' ``` 125 | #' 126 | #' The default filetype is svg, but we can as well change this to png by using the chunk option `ext=png`. 127 | #' 128 | #' ```{.geasy eval=true as="dot" results="hide" ext=png} 129 | #' [ PNG-Output ] 130 | #' [ Paris ] { shape: ellipse; fill: salmon; } 131 | #' -- Flight --> 132 | #' [ Bonn ] { shape: circle; fill: skyblue; } 133 | #' -- Car --> { color: red; } 134 | #' [ Berlin ] { fill: rgb(255,228,221); } 135 | #' ``` 136 | #' 137 | #' ## See also: 138 | #' 139 | #' * [user-filter](user-filter.html) - more information on how to create your own filter using Tcl 140 | #' * [pantcl Readme](../README.html) 141 | #' * [pantcl manual](../pantcl.html) 142 | #' * [pantcl Tutorial](../pantcl-tutorial.html) 143 | #' 144 | 145 | 146 | proc filter-geasy {cont dict} { 147 | # count all code chunk filters 148 | global n 149 | incr n 150 | # default values for the code chunks attributes 151 | set def [dict create results show eval true scriptpath scripts \ 152 | app graph-easy label null as ascii ext svg] 153 | # overwrite them with the current code chunk attributes 154 | set dict [dict merge $def $dict] 155 | # if eval is false return nothing 156 | if {![dict get $dict eval]} { 157 | return [list "" ""] 158 | } 159 | # check if the application is installed at all 160 | if {[auto_execok [dict get $dict app]] eq ""} { 161 | return [list "Error: This filter requires the command line tool [dict get $dict app] - please install it!" ""] 162 | } 163 | # intialize return text 164 | set ret "" 165 | set owd [pwd] 166 | 167 | # create a filename for the outputs 168 | if {[dict get $dict label] eq "null"} { 169 | set fname [file join $owd [dict get $dict scriptpath] geasy-$n] 170 | } else { 171 | set fname [file join $owd [dict get $dict scriptpath] [dict get $dict label]] 172 | } 173 | if {![file exists [file join $owd [dict get $dict scriptpath]]]} { 174 | file mkdir [file join $owd [dict get $dict scriptpath]] 175 | } 176 | # write down the code chunk text 177 | set out [open $fname.txt w 0600] 178 | puts $out $cont 179 | close $out 180 | # run the tool 181 | # TODO: error catching 182 | set res [exec -ignorestderr [dict get $dict app] --as=[dict get $dict as] $fname.txt] 183 | # initialize the image variable 184 | set img "" 185 | # do the user like to use the dot tool for image generation? 186 | if {[dict get $dict as] eq "dot"} { 187 | set out [open $fname.dot w 0600] 188 | puts $out $res 189 | close $out 190 | if {[auto_execok dot] eq ""} { 191 | return [list "Error: Dot output requires the command line tool GraphViz dot application - please install GraphViz or add the application sto your PATH variable!" ""] 192 | } 193 | set ext [dict get $dict ext] 194 | exec -ignorestderr dot $fname.dot -T$ext -o $fname.$ext 195 | set img $fname.$ext 196 | } 197 | # check if results should be shown 198 | if {[dict get $dict results] eq "show"} { 199 | set res $res 200 | } else { 201 | set res "" 202 | } 203 | # return text and image path 204 | return [list $res $img] 205 | } 206 | -------------------------------------------------------------------------------- /lib/yaml/huddle_types.tcl: -------------------------------------------------------------------------------- 1 | namespace eval ::huddle::types { 2 | namespace export * 3 | 4 | namespace eval dict { 5 | variable settings 6 | 7 | # type definition 8 | set settings { 9 | publicMethods {create keys} 10 | tag D 11 | isContainer yes 12 | map {set Set} } 13 | 14 | 15 | proc get_subnode {src key} { 16 | # get a sub-node specified by "key" from the tagged-content 17 | return [dict get $src $key] 18 | } 19 | 20 | # strip from the tagged-content 21 | proc strip {src} { 22 | foreach {key subnode} $src { 23 | lappend result $key [strip_node $subnode] 24 | } 25 | return $result 26 | } 27 | 28 | # set a sub-node from the tagged-content 29 | proc Set {src_var key value} { 30 | upvar 1 $src_var src 31 | 32 | ::dict set src $key $value 33 | } 34 | 35 | proc items {src} { 36 | set result {} 37 | dict for {key subnode} $src { 38 | lappend result [list $key $subnode] 39 | } 40 | return $result 41 | } 42 | 43 | 44 | # remove a sub-node from the tagged-content 45 | proc remove {src_var key} { 46 | upvar 1 $src_var src 47 | dict unset src $key 48 | } 49 | 50 | 51 | proc delete_subnode_but_not_key {src_var key} { 52 | upvar 1 $src_var src 53 | return [dict set src $key ""] 54 | } 55 | 56 | # check equal for each node 57 | proc equal {src1 src2} { 58 | if {[llength $src1] != [llength $src2]} {return 0} 59 | foreach {key1 subnode1} $src1 { 60 | if {![dict exists $src2 $key1]} {return 0} 61 | if {![are_equal_nodes $subnode1 [dict get $src2 $key1]]} {return 0} 62 | } 63 | return 1 64 | } 65 | 66 | proc append_subnodes {tag src list} { 67 | if {[llength $list] % 2} {error {wrong # args: should be "huddle append objvar ?key value ...?"}} 68 | set resultL $src 69 | foreach {key value} $list { 70 | if {$tag ne ""} { 71 | lappend resultL $key [argument_to_node $value $tag] 72 | } else { 73 | lappend resultL $key $value 74 | } 75 | } 76 | return [dict create {*}$resultL] 77 | } 78 | 79 | # $args: all arguments after "huddle create" 80 | proc create {args} { 81 | if {[llength $args] % 2} {error {wrong # args: should be "huddle create ?key value ...?"}} 82 | set resultL [dict create] 83 | 84 | foreach {key value} $args { 85 | if {[isHuddle $key]} { 86 | foreach {tag src} [unwrap $key] break 87 | if {$tag ne "string"} {error "The key '$key' must a string literal or huddle string" } 88 | set key $src 89 | } 90 | dict set resultL $key [argument_to_node $value] 91 | } 92 | return [wrap [list D $resultL]] 93 | } 94 | 95 | proc keys {huddle_object} { 96 | return [dict keys [get_src $huddle_object]] 97 | } 98 | 99 | proc exists {src key} { 100 | return [dict exists $src $key] 101 | } 102 | } 103 | 104 | 105 | namespace eval list { 106 | variable settings 107 | 108 | # type definition 109 | set settings { 110 | publicMethods {list llength} 111 | tag L 112 | isContainer yes 113 | map {list List set Set llength Llength} } 114 | 115 | proc get_subnode {src index} { 116 | return [lindex $src $index] 117 | } 118 | 119 | proc items {src} { 120 | set result {} 121 | for {set i 0} {$i < [llength $src]} {incr i} { 122 | lappend result [list $i [lindex $src $i]] 123 | } 124 | return $result 125 | } 126 | 127 | proc strip {src} { 128 | set result {} 129 | foreach {subnode} $src { 130 | lappend result [strip_node $subnode] 131 | } 132 | return $result 133 | } 134 | 135 | if {[package vcompare [package present Tcl] 8.6] > 0} { 136 | proc Set {src_var index value} { 137 | upvar 1 $src_var src 138 | lset src $index $value 139 | } 140 | } else { 141 | proc Set {src_var index value} { 142 | upvar 1 $src_var src 143 | # Manual handling of lset at end of list. 144 | if {$index == [llength $src]} { 145 | lappend src $value 146 | } else { 147 | lset src $index $value 148 | } 149 | } 150 | } 151 | 152 | proc remove {src_var index} { 153 | upvar 1 $src_var src 154 | set src [lreplace $src $index $index] 155 | } 156 | 157 | 158 | proc delete_subnode_but_not_key {src_var index} { 159 | upvar 1 $src_var src 160 | return [lset src $index ""] 161 | } 162 | 163 | proc equal {src1 src2} { 164 | if {[llength $src1] != [llength $src2]} {return 0} 165 | 166 | for {set i 0} {$i < [llength $src1]} {incr i} { 167 | if {![are_equal_nodes [lindex $src1 $i] [lindex $src2 $i]]} { 168 | return 0 169 | } 170 | } 171 | 172 | return 1 173 | } 174 | 175 | proc append_subnodes {tag src list} { 176 | set resultL $src 177 | foreach {value} $list { 178 | if {$tag ne ""} { 179 | lappend resultL [argument_to_node $value $tag] 180 | } else { 181 | lappend resultL $value 182 | } 183 | } 184 | return $resultL 185 | } 186 | 187 | proc List {args} { 188 | 189 | set resultL {} 190 | foreach {value} $args { 191 | lappend resultL [argument_to_node $value] 192 | } 193 | return [wrap [list L $resultL]] 194 | } 195 | 196 | proc Llength {huddle_object} { 197 | return [llength [get_src $huddle_object] ] 198 | } 199 | 200 | proc exists {src key} { 201 | return [expr {$key >=0 && $key < [llength $src]}] 202 | } 203 | } 204 | 205 | namespace eval string { 206 | variable settings 207 | 208 | # type definition 209 | set settings { 210 | publicMethods {string} 211 | tag s 212 | isContainer no 213 | map {string String} } 214 | 215 | proc String {src} { 216 | return [wrap [list s $src]] 217 | } 218 | 219 | proc equal {string1 string2} { 220 | return [expr {$string1 eq $string2}] 221 | } 222 | } 223 | 224 | 225 | namespace eval number { 226 | variable settings 227 | 228 | # type definition 229 | set settings { 230 | publicMethods {number} 231 | tag num 232 | isContainer no } 233 | 234 | proc number {src} { 235 | if {[string is double -strict $src]} { 236 | return [wrap [list num $src]] 237 | } else { 238 | error "Argument '$src' is not a number" 239 | } 240 | } 241 | 242 | proc equal {number1 number2} { 243 | return [expr {$number1 == $number2}] 244 | } 245 | } 246 | 247 | namespace eval boolean { 248 | variable settings 249 | 250 | # type definition 251 | set settings { 252 | publicMethods {boolean true false} 253 | tag b 254 | isContainer no } 255 | 256 | proc boolean {boolean_expresion} { 257 | 258 | if {$boolean_expresion} { 259 | return [wrap [list b true]] 260 | } else { 261 | return [wrap [list b false]] 262 | } 263 | } 264 | 265 | proc true {} { 266 | return [::huddle::wrap [list b true]] 267 | } 268 | 269 | proc false {} { 270 | return [wrap [list b false]] 271 | } 272 | 273 | 274 | proc equal {bool1 bool2} { 275 | return [expr {$bool1 eq $bool2}] 276 | } 277 | } 278 | 279 | namespace eval null { 280 | variable settings 281 | 282 | # type definition 283 | set settings { 284 | publicMethods {null} 285 | tag null 286 | isContainer no } 287 | 288 | proc null {} { 289 | return [wrap [list null]] 290 | } 291 | 292 | proc equal {null1 null2} { 293 | return 1 294 | } 295 | } 296 | } 297 | -------------------------------------------------------------------------------- /lib/tclfilters/filter-pic.tcl: -------------------------------------------------------------------------------- 1 | #' --- 2 | #' title: "filter-pic.tcl documentation" 3 | #' author: "Detlef Groth, Caputh-Schwielowsee, Germany" 4 | #' date: 2021-11-19 5 | #' pic: 6 | #' app: pic2graph 7 | #' imagepath: images 8 | #' ext: png 9 | #' eval: 1 10 | #' --- 11 | # a simple pandoc filter using Tcl 12 | # the script pantcl.tcl 13 | # must be in the in the parent directory of the filter directory 14 | #' 15 | #' ------ 16 | #' 17 | #' ```{.tcl eval=true results="asis" echo=false} 18 | #' include header.md 19 | #' ``` 20 | #' 21 | #' ------ 22 | #' 23 | #' ## Name 24 | #' 25 | #' _filter-pic.tcl_ - Filter which can be used to display pic files within a Pandoc processed 26 | #' document using the Tcl filter driver `pantcl.bin`. 27 | #' 28 | #' ## Usage 29 | #' 30 | #' The conversion of the Markdown documents via Pandoc should be done as follows: 31 | #' 32 | #' ``` 33 | #' pandoc input.md --filter pantcl.bin -s -o output.html 34 | #' ``` 35 | #' 36 | #' The file `filter-pic.tcl` is not used directly but sourced automatically by the `pantcl.bin` file. 37 | #' If code blocks with the `.pic` marker are found, the contents in the code block is processed 38 | #' via the *pic2graph* diagram tool [https://man7.org/linux/man-pages/man1/pic2graph.1.html](https://man7.org/linux/man-pages/man1/pic2graph.1.html) which converts 39 | #' PIC files, see [https://en.wikipedia.org/wiki/PIC_(markup_language)](https://en.wikipedia.org/wiki/PIC_(markup_language)) into some graphics format like png or other file formats which can be converted by the the ImageMagick tool *convert*. 40 | #' 41 | #' Alternatively you can use as well the dpic command line application which supports native PDF, SVG and TikZ-LaTeX output. 42 | #' The sources for this application can be found here [https://gitlab.com/aplevich/dpic](https://gitlab.com/aplevich/dpic). 43 | #' 44 | #' The following options can be given via code chunks or in the YAML header. 45 | #' 46 | #' - app - the application to process the pic code, usually pic2graph or dpic, default: pic2graph 47 | #' - ext - file file extension, can be png or pdf for pic2graph and pdf, svg and tikz for dpic, default: png 48 | #' - eval - should the code in the code block be evaluated, default: false 49 | #' - fig - should a figure be created, default: true 50 | #' - imagepath - output imagepath, default: images 51 | #' - include - should the created image be automatically included, default: true 52 | #' - results - should the output of the command line application been shown, should be show or hide, default: hide 53 | #' 54 | #' To change the defaults the YAML header can be used. Here an example to change the 55 | #' default the image output path to nfigures, the default file format to svg and the application to dpic. 56 | #' 57 | #' ``` 58 | #' ---- 59 | #' title: "filter-pic example" 60 | #' author: "Detlef Groth, Caputh-Schwielowsee, Germany" 61 | #' date: 2021-11-18 62 | #' pic: 63 | #' app: dpic 64 | #' imagepath: nfigures 65 | #' ext: svg 66 | #' eval: 1 67 | #' ---- 68 | #' ``` 69 | #' 70 | #' ## Examples 71 | #' 72 | #' Let's start with the usual "Hello World!" script: 73 | #' 74 | #' ``` 75 | #' ```{.pic eval=true} 76 | #' box wid 1.2 "Hello World!" fill 0.3; 77 | #' ``` 78 | #' ``` 79 | #' 80 | #' And here the output: 81 | #' 82 | #' ```{.pic} 83 | #' box wid 1.2 "Hello World!" fill 0.3; 84 | #' ``` 85 | #' 86 | #' Here some simple basic shapes: 87 | #' 88 | #' ```{.pic} 89 | #' circle "A"; line; box "B" 90 | #' circle "A"; line; box "B 2" 91 | #' move ; move ; move 92 | #' {arrow down; move; "S" } 93 | #' {arrow up; move; "N" } 94 | #' {arrow left; move; "W" } 95 | #' {arrow right; move; "E" } 96 | #' ``` 97 | #' 98 | #' Let's finish with an example for filled grey backgrounds: 99 | #' 100 | #' ```{.pic} 101 | #' circle "circle" rad 0.5 fill 0.3; arrow ; 102 | #' ellipse "ellipse" wid 1.4 ht 1 fill 0.1 ; line; 103 | #' box wid 1 ht 1 fill 0.05 "A"; 104 | #' spline; 105 | #' box wid 0.4 ht 0.4 fill 0.05 "B"; 106 | #' arc; 107 | #' box wid 0.2 ht 0.2 fill 0.05 "C"; 108 | #' ``` 109 | #' 110 | #' There is an other implementation of the PIC language, dpic which supports direct PDF, TeX and SVG output. 111 | #' Here an example for the dpic application [https://gitlab.com/aplevich/dpic/](https://gitlab.com/aplevich/dpic/): 112 | #' 113 | #' ``` 114 | #' ```{.dpic ext=svg eval=true} 115 | #' [ 116 | #' box dashed wid 1.2 "Hello World" ; move ; 117 | #' circle "circle" rad 0.5 fill 0.7; move ; arrow ; move ; 118 | #' ellipse "ellipse" wid 1.4 ht 1 fill 0.8 ; 119 | #' ] scaled 1.2 120 | #' ``` 121 | #' ``` 122 | #' 123 | #' Here is the output: 124 | #' 125 | #' ```{.dpic ext=svg eval=true} 126 | #' [ 127 | #' box dashed wid 1.2 "Hello World" ; move ; 128 | #' circle "circle" rad 0.5 fill 0.7; move ; arrow ; move ; 129 | #' ellipse "ellipse" wid 1.4 ht 1 fill 0.8 ; 130 | #' ] scaled 1.2 131 | #' ``` 132 | #' 133 | #' Dpic understands PIC syntax but offers other output formats such as TikZ-LaTeX, PDF, SVG. 134 | #' 135 | #' ## See also: 136 | #' 137 | #' * [Pantcl Readme](../../README.html) 138 | #' * [Pantcl documentation](../../pantcl.html) 139 | #' * [Pantcl tutorial](../../pantcl-tutorial.html) 140 | #' * [Unix Text Processing](https://www.oreilly.com/library/view/unix-text-processing/9780810462915/Chapter10.html) 141 | #' * [Gnu PIC manual](https://pikchr.org/home/uv/gpic.pdf) 142 | #' * [Dpic by Dwight Aplevich](https://gitlab.com/aplevich/dpic/) 143 | #' * [Pikchr filter](filter-pik.html) 144 | #' 145 | 146 | proc filter-dpic {cont dict} { 147 | global n 148 | incr n 149 | set owd [pwd] 150 | set def [dict create results show eval true fig true \ 151 | include true imagepath images app dpic label null \ 152 | ext svg border 15 density 150 background white] 153 | set dict [dict merge $def $dict] 154 | if {![dict get $dict eval]} { 155 | return [list "" ""] 156 | } 157 | if {[auto_execok [dict get $dict app]] eq ""} { 158 | return [list "Error: This filter requires the command line tool dpic https://gitlab.com/aplevich/dpic - please install it!" ""] 159 | } 160 | if {[dict get $dict label] eq "null"} { 161 | set fname [file join $owd [dict get $dict imagepath] pic-$n] 162 | } else { 163 | set fname [file join $owd [dict get $dict imagepath] [dict get $dict label]] 164 | } 165 | if {![file exists [file join $owd [dict get $dict imagepath]]]} { 166 | file mkdir [file join $owd [dict get $dict imagepath]] 167 | } 168 | set out [open $fname.pic w 0600] 169 | puts $out ".PS" 170 | puts $out $cont 171 | puts $out ".PE" 172 | close $out 173 | set formats [dict create pdf -d tikz -f svg -v tex ""] 174 | if {[catch { 175 | set res [exec -ignorestderr cat $fname.pic | [dict get $dict app] \ 176 | [dict get $formats [dict get $dict ext]] 2> /dev/null > $fname.[dict get $dict ext]] 177 | }]} { 178 | return [list $::errorInfo ""] 179 | } 180 | if {[dict get $dict results] eq "show"} { 181 | # should be usually empty 182 | set res $res 183 | } else { 184 | set res "" 185 | } 186 | if {[dict get $dict ext] ni [list "pdf" "svg" "tikz" "tex"]} { 187 | return [list "Error: unkown extension name '[dict get $dict ext]', valid values are pdf, svg, tikz, tex" ""] 188 | } 189 | set img "" 190 | if {[dict get $dict fig]} { 191 | if {[dict get $dict include]} { 192 | set img $fname.[dict get $dict ext] 193 | } 194 | } 195 | return [list $res $img] 196 | } 197 | proc filter-pic {cont dict} { 198 | set def [dict create results show eval true fig true width 0 height 0 \ 199 | include true imagepath images app pic2graph label null ext png \ 200 | border 15 density 150 background white] 201 | set dict [dict merge $def $dict] 202 | if {![dict get $dict eval]} { 203 | return [list "" ""] 204 | } 205 | if {[regexp {^dpic} [dict get $dict app]]} { 206 | return [filter-dpic $cont $dict] 207 | } 208 | global n 209 | incr n 210 | 211 | if {[auto_execok pic2graph] eq ""} { 212 | return [list "Error: This filter requires the command line tool pic2graph, please install it!" ""] 213 | } 214 | set ret "" 215 | set owd [pwd] 216 | if {[dict get $dict label] eq "null"} { 217 | set fname [file join $owd [dict get $dict imagepath] pic-$n] 218 | } else { 219 | set fname [file join $owd [dict get $dict imagepath] [dict get $dict label]] 220 | } 221 | if {![file exists [file join $owd [dict get $dict imagepath]]]} { 222 | file mkdir [file join $owd [dict get $dict imagepath]] 223 | } 224 | set out [open $fname.pic w 0600] 225 | puts $out $cont 226 | close $out 227 | # TODO: error catching 228 | if {[catch { 229 | set res [exec -ignorestderr cat $fname.pic | [dict get $dict app] -density [dict get $dict density] \ 230 | -format [dict get $dict ext] -background [dict get $dict background] \ 231 | -bordercolor [dict get $dict background] -alpha off -colorspace RGB \ 232 | -border [dict get $dict border] > $fname.[dict get $dict ext]] 233 | }]} { 234 | return [list $::errorInfo ""] 235 | } 236 | if {[dict get $dict results] eq "show"} { 237 | # should be usually empty 238 | set res $res 239 | } else { 240 | set res "" 241 | } 242 | if {[dict get $dict ext] ni [list "pdf" "png"]} { 243 | return [list "Error: unkown extension name '[dict get $dict ext]', valid values are pdf, png" ""] 244 | } 245 | set img "" 246 | if {[dict get $dict fig]} { 247 | if {[dict get $dict include]} { 248 | set img $fname.[dict get $dict ext] 249 | } 250 | } 251 | return [list $res $img] 252 | } 253 | -------------------------------------------------------------------------------- /lib/textutil/ithyph.tex: -------------------------------------------------------------------------------- 1 | 2 | %%%%%%%%%%%%%%%%%%%% file ithyph.tex 3 | 4 | %%%%%%%%%%%%%%%%%%%%%%%%%%% file ithyph.tex %%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5 | % 6 | % Prepared by Claudio Beccari e-mail beccari@polito.it 7 | % 8 | % Dipartimento di Elettronica 9 | % Politecnico di Torino 10 | % Corso Duca degli Abruzzi, 24 11 | % 10129 TORINO 12 | % 13 | % Copyright 1998, 2001 Claudio Beccari 14 | % 15 | % This program can be redistributed and/or modified under the terms 16 | % of the LaTeX Project Public License Distributed from CTAN 17 | % archives in directory macros/latex/base/lppl.txt; either 18 | % version 1 of the License, or any later version. 19 | % 20 | % \versionnumber{4.8d} \versiondate{2001/11/21} 21 | % 22 | % These hyphenation patterns for the Italian language are supposed to comply 23 | % with the Reccomendation UNI 6461 on hyphenation issued by the Italian 24 | % Standards Institution (Ente Nazionale di Unificazione UNI). No guarantee 25 | % or declaration of fitness to any particular purpose is given and any 26 | % liability is disclaimed. 27 | % 28 | % See comments and loading instructions at the end of the file after the 29 | % \endinput line 30 | % 31 | {\lccode`\'=`\' % Apostrophe has its own lccode so that it is treated 32 | % as a letter 33 | %>> 1998/04/14 inserted grouping 34 | % 35 | %\lccode23=23 % Compound word mark is a letter in encoding T1 36 | %\def\W{^^W} % ^^W =\char23 = \char"17 =\char'27 37 | % 38 | \patterns{ 39 | .a3p2n % After the Garzanti dictionary: a-pnea, a-pnoi-co,... 40 | .anti1 .anti3m2n 41 | .bio1 42 | .ca4p3s 43 | .circu2m1 44 | .di2s3cine 45 | %.e2x 46 | .fran2k3 47 | .free3 48 | .narco1 49 | .opto1 50 | .orto3p2 51 | .para1 52 | .poli3p2 53 | .pre1 54 | .p2s 55 | %.ri1a2 .ri1e2 .re1i2 .ri1o2 .ri1u2 56 | .sha2re3 57 | .tran2s3c .tran2s3d .tran2s3f .tran2s3l .tran2s3n .tran2s3p .tran2s3r .tran2s3t 58 | .su2b3lu .su2b3r 59 | .wa2g3n 60 | .wel2t1 61 | a1ia a1ie a1io a1iu a1uo a1ya 2at. 62 | e1iu e2w 63 | o1ia o1ie o1io o1iu 64 | %u1u 65 | % 66 | %1\W0a2 1\W0e2 1\W0i2 1\W0o2 1\W0u2 67 | '2 68 | 1b 2bb 2bc 2bd 2bf 2bm 2bn 2bp 2bs 2bt 2bv 69 | b2l b2r 2b. 2b'. 2b'' 70 | 1c 2cb 2cc 2cd 2cf 2ck 2cm 2cn 2cq 2cs 2ct 2cz 71 | 2chh c2h 2chb ch2r 2chn c2l c2r 2c. 2c'. 2c'' .c2 72 | 1d 2db 2dd 2dg 2dl 2dm 2dn 2dp d2r 2ds 2dt 2dv 2dw 73 | 2d. 2d'. 2d'' .d2 74 | 1f 2fb 2fg 2ff 2fn f2l f2r 2fs 2ft 2f. 2f'. 2f'' 75 | 1g 2gb 2gd 2gf 2gg g2h g2l 2gm g2n 2gp g2r 2gs 2gt 76 | 2gv 2gw 2gz 2gh2t 2g. 2g'. 2g'' 77 | 1h 2hb 2hd 2hh hi3p2n h2l 2hm 2hn 2hr 2hv 2h. 2h'. 2h'' 78 | 1j 2j. 2j'. 2j'' 79 | 1k 2kg 2kf k2h 2kk k2l 2km k2r 2ks 2kt 2k. 2k'. 2k'' 80 | 1l 2lb 2lc 2ld 2l3f2 2lg l2h 2lk 2ll 2lm 2ln 2lp 81 | 2lq 2lr 2ls 2lt 2lv 2lw 2lz 2l. 2l'. 2l'' 82 | 1m 2mb 2mc 2mf 2ml 2mm 2mn 2mp 2mq 2mr 2ms 2mt 2mv 2mw 83 | 2m. 2m'. 2m'' 84 | 1n 2nb 2nc 2nd 2nf 2ng 2nk 2nl 2nm 2nn 2np 2nq 2nr 85 | 2ns 2nt 2nv 2nz n2g3n 2nheit. 2n. 2n' 2n'' 86 | 1p 2pd p2h p2l 2pn 3p2ne 2pp p2r 2ps 3p2sic 2pt 2pz 2p. 2p'. 2p'' 87 | 1q 2qq 2q. 2q'. 2q'' 88 | 1r 2rb 2rc 2rd 2rf r2h 2rg 2rk 2rl 2rm 2rn 2rp 89 | 2rq 2rr 2rs 2rt rt2s3 2rv 2rx 2rw 2rz 2r. 2r'. 2r'' 90 | 1s2 2shm 2s3s s4s3m 2s3p2n 2stb 2stc 2std 2stf 2stg 2stm 2stn 91 | 2stp 2sts 2stt 2stv 2sz 4s. 4s'. 4s'' 92 | 1t 2tb 2tc 2td 2tf 2tg t2h t2l 2tm 2tn 2tp t2r 2ts 93 | 3t2sch 2tt 2tv 2tw t2z 2tzk 2tzs 2t. 2t'. 2t'' 94 | 1v 2vc v2l v2r 2vv 2v. 2v'. 2v'' 95 | 1w w2h wa2r 2w1y 2w. 2w'. 2w'' 96 | 1x 2xt 2xw 2x. 2x'. 2x'' 97 | y1ou y1i 98 | 1z 2zb 2zd 2zl 2zn 2zp 2zt 2zs 2zv 2zz 2z. 2z'. 2z'' .z2 99 | }} % Pattern end 100 | 101 | \endinput 102 | 103 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Information %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 104 | 105 | 106 | LOADING THESE PATTERNS 107 | 108 | These patterns, as well as those for any other language, do not become 109 | effective until they are loaded in a special form into a format file; this 110 | task is performed by the TeX initializer; any TeX system has its own 111 | initializer with its special way of being activated. Before loading these 112 | patterns, then, it is necessary to read very carefully the instructions that 113 | come with your TeX system. 114 | 115 | Here I describe how to load the patterns with the freeware TeX system named 116 | MiKTeX version 2.x for Windows 9x, NT, 2000, XP; with minor changes the 117 | whole procedure is applicable with other TeX systems, but the details must 118 | be deduced from your TeX system documentation at the section/chapter "How to 119 | build or to rebuild a format file". 120 | 121 | With MikTeX: 122 | 123 | a) copy this file and replace the existing file ithyph.tex in the directory 124 | \texmf\tex\generic\hyphen if the existing one has an older version date 125 | and number. 126 | b) select Start|Programs|MiKTeX|MiKTeX options. 127 | c) in the Language tab add a check mark to the line concerning the Italian 128 | language. 129 | d) in the Geneal tab click "Update format files". 130 | e) That's all! 131 | 132 | For the activation of these patterns with the specific Italian typesetting 133 | features, use the babel package as this: 134 | 135 | \documentclass{article} % Or whatever other class 136 | \usepackage[italian]{babel} 137 | ... 138 | \begin{document} 139 | ... 140 | \end{document} 141 | 142 | 143 | ON ITALIAN HYPHENATION 144 | 145 | I have been working on patterns for the Italian language since 1987; in 1992 146 | I published 147 | 148 | C. Beccari, "Computer aided hyphenation for Italian and Modern 149 | Latin", TUG vol. 13, n. 1, pp. 23-33 (1992) 150 | 151 | which contained a set of patterns that allowed hyphenation for both Italian 152 | and Latin; a slightly modified version of the patterns published in the 153 | above paper is contained in LAHYPH.TEX available on the CTAN archives. 154 | 155 | From the above patterns I extracted the minimum set necessary for 156 | hyphenating Italian that was made available on the CTAN archives with the 157 | name ITHYPH.tex the version number 3.5 on the 16th of August 1994. 158 | 159 | The original pattern set required 37 ops; being interested in a local 160 | version of TeX/LaTeX capable of dealing with half a dozen languages, I 161 | wanted to reduce memory occupation and therefore the number of ops. 162 | 163 | Th new version (4.0 released in 1996) of ITHYPH.TEX is much simpler than 164 | version 3.5 and requires just 29 ops while it retains all the power of 165 | version 3.5; it contains many more new patterns that allow to hyphenate 166 | unusual words that generally have a root borrowed from a foreign language. 167 | Updated versions 4.x contain minor additions and the number of ops is 168 | increased to 30 (version 4.7 of 1998/06/01). 169 | 170 | This new pattern set has been tested with the same set of difficult Italian 171 | words that was used to test version 3.5 and it yields the same results (a 172 | part a minor change that was deliberately introduced so as to reduce the 173 | typographical hyphenation with hyathi, since hyphenated hyathi are not 174 | appreciated by Italian readers). A new enlarged word set for testing 175 | purposes gets correct hyphen points that were missed or wrongly placed with 176 | version 3.5, although no error had been reported, because such words are of 177 | very specialized nature and are seldom used. 178 | 179 | As the previous version, this new set of patterns does not contain any 180 | accented character so that the hyphenation algorithm behaves properly in 181 | both cases, that is with cm and with dc/ec fonts. With LaTeXe terminology 182 | the difference is between OT1 and T1 encodings; with the former encoding 183 | fonts do not contain accented characters, while with the latter accented 184 | characters are present and sequences such as \`a map directly to slot "E0 185 | that contains "agrave". 186 | 187 | Of course if you use dc/ec fonts (or any other real or virtual font with T1 188 | encoding) you get the full power of the hyphenation algorithm, while if you 189 | use cm fonts (or any other real or virtual font with OT1 encoding) you miss 190 | some possible break points; this is not a big inconvenience in Italian 191 | because: 192 | 193 | 1) The Regulation UNI 6015 on accents specifies that compulsory accents 194 | appear only on the ending vowel of oxitone words; this means that it is 195 | almost indifferent to have or to miss the dc/ec fonts because the only 196 | difference consists in how TeX evaluates the end of the word; in practice 197 | if you have these special facilities you get "qua-li-t\`a", while if you 198 | miss them, you get "qua-lit\`a" (assuming that \righthyphenmin > 1). 199 | 200 | 2) Optional accents are so rare in Italian, that if you absolutely want to 201 | use them in those rare instances, and you miss the T1 encoding 202 | facilities, you should also provide explicit discretionary hyphens as in 203 | "s\'e\-gui\-to". 204 | 205 | There is no explicit hyphenation exception list because these patterns 206 | proved to hyphenate correctly a very large set of words suitably chosen in 207 | order to test them in the most heavy circumstances; these patterns were used 208 | in the preparation of a number of books and no errors were discovered. 209 | 210 | Nevertheless if you frequently use technical terms that you want hyphenated 211 | differently from what is normally done (for example if you prefer 212 | etymological hyphenation of prefixed and/or suffixed words) you should 213 | insert a specific hyphenation list in the preamble of your document, for 214 | example: 215 | 216 | \hyphenation{su-per-in-dut-to-re su-per-in-dut-to-ri} 217 | 218 | Should you find any word that gets hyphenated in a wrong way, please, AFTER 219 | CHECKING ON A RELIABLE MODERN DICTIONARY, report to the author, preferably 220 | by e-mail. 221 | 222 | 223 | Happy multilingual typesetting ! 224 | -------------------------------------------------------------------------------- /lib/tclfilters/filter-kroki.tcl: -------------------------------------------------------------------------------- 1 | #' --- 2 | #' title: "filter-kroki.tcl documentation" 3 | #' author: "Detlef Groth, Caputh-Schwielowsee, Germany" 4 | #' date: 2022-02-18 5 | #' kroki: 6 | #' app: curl 7 | #' imagepath: images 8 | #' ext: svg 9 | #' eval: 1 10 | #' --- 11 | #' 12 | # a simple pandoc filter using Tcl the script pantcl.tcl 13 | # must be in the in the parent directory of the filter directory 14 | #' 15 | #' ------ 16 | #' 17 | #' ```{.tcl eval=true results="asis" echo=false} 18 | #' include header.md 19 | #' ``` 20 | #' 21 | #' ------ 22 | #' 23 | #' ## Name 24 | #' 25 | #' _filter-kroki.tcl_ - Filter using the [https://kroki.io](https://kroki.io) webservice to 26 | #' display diagram images using many diagram generators. 27 | #' 28 | #' ## Usage 29 | #' 30 | #' The conversion of the Markdown documents via Pandoc should be done as follows: 31 | #' 32 | #' ``` 33 | #' pandoc input.md --filter pantcl.bin -s -o output.html 34 | #' ``` 35 | #' 36 | #' The file `filter-kroki.tcl` is not used directly but sourced automatically by the `pantcl.bin` file. 37 | #' If code blocks with the `.kroki` marker are found, the contents in the code block is processed to the 38 | #' Kroki webservices and optionally download locally the file using wget. 39 | #' 40 | #' The following options can be given via code chunks or in the YAML header. 41 | #' 42 | #' > - app - the application to do the download, if none images are just displayed inline, 43 | #' currently only curl or wget are supported: default: wget 44 | #' - ext - file file extension, can be svg, png, pdf, default: svg 45 | #' - dia - the diagram tool, graphviz, plantuml, pikchr, mermaid etc, default: graphviz 46 | #' - eval - should the code in the code block be evaluated, default: false 47 | #' - fig - should a figure be created, default: true 48 | #' - imagepath - output imagepath, default: images 49 | #' - include - should the created image be automatically included, default: true 50 | #' - results - should the output of the command line application been shown, should be show or hide, default: hide 51 | #' 52 | #' To change the defaults the YAML header can be used. Here an example to change the 53 | #' default layout engine to neato and the image output path to nfigures 54 | #' 55 | #' ``` 56 | #' ---- 57 | #' title: "filter-kroki.tcl documentation" 58 | #' author: "Detlef Groth, Caputh-Schwielowsee, Germany" 59 | #' date: 2022-02-18 60 | #' dot: 61 | #' app: wget 62 | #' imagepath: nfigures 63 | #' ext: svg 64 | #' eval: 1 65 | #' ---- 66 | #' ``` 67 | #' 68 | #' ## Examples 69 | #' 70 | #' Below are a few samples for embedding code for the GraphViz tool dot, for Pikchr and for Plantuml. 71 | #' This filter does just need a working Tcl installation and a connection to the internat for rendering the images. 72 | #' 73 | #' Links: 74 | #' 75 | #' * Kroki Homepage: [https://kroki.io/](https://kroki.io/) 76 | #' 77 | #' ## Dot graph 78 | #' 79 | #' ``` 80 | #' ```{.kroki label=digraph eval=true echo=true} 81 | #' digraph G { 82 | #' main -> parse -> execute; 83 | #' main -> init [dir=none]; 84 | #' main -> cleanup; 85 | #' execute -> make_string; 86 | #' execute -> printf 87 | #' init -> make_string; 88 | #' main -> printf; 89 | #' execute -> compare; 90 | #' } 91 | #' ``` 92 | #' ``` 93 | #' 94 | #' Which will produce the following output: 95 | #' 96 | #' ```{.kroki label=digraph echo=true} 97 | #' digraph G { 98 | #' main -> parse -> execute; 99 | #' main -> init [dir=none]; 100 | #' main -> cleanup; 101 | #' execute -> make_string; 102 | #' execute -> printf 103 | #' init -> make_string; 104 | #' main -> printf; 105 | #' execute -> compare; 106 | #' } 107 | #' ``` 108 | #' 109 | #' Here a ditaa diagram `{.kroki label=ditaa eval=true echo=true dia=ditaa}`: 110 | #' 111 | #' ```{.kroki label=ditaa echo=true dia=ditaa} 112 | #' +----------------------------------------+ 113 | #' | File | Help cEEE | 114 | #' +-------------+--------------------------+ 115 | #' | ttk.Button | ttk.Combobox | 116 | #' +-------------+--------------------------+ 117 | #' | | | 118 | #' | tk.Listbox | tk.Text | 119 | #' | | | 120 | #' | <+> | 121 | #' | | | 122 | #' | | | 123 | #' | | | 124 | #' +-------------+--------+-----------------+ 125 | #' | ttk.Label | ttk.Progressbar | 126 | #' +----------------------+-----------------+ 127 | #' ``` 128 | #' 129 | #' Support for UniCode is there as well where the monospaced front has some problems in aligning (`{.kroki label=ditaauc eval=true dia=ditaa}`): 130 | #' 131 | #' ```{.kroki label=ditaauc dia=ditaa} 132 | #' A₀ ---> A₁ ---> A₂ ---> A₃ ---> A₄ 133 | #' 134 | #' | | | | | 135 | #' | f₀ | f₁ | f₂ | f₃ | f₄ 136 | #' | | | | | 137 | #' v v v v v 138 | #' 139 | #' B₀ ---> B₁ ---> B₂ ---> B₃ ---> B₄ 140 | #' ```` 141 | #' 142 | #' A nonoml example `{.kroki label=nomnoml ext=svg eval=true dia=nomnoml}`: 143 | #' 144 | #' ```{.kroki label=nomnoml ext=svg dia=nomnoml} 145 | #' [Pirate|eyeCount: Int|raid();pillage()| 146 | #' [beard]--[parrot] 147 | #' [beard]-:>[foul mouth] 148 | #' ] 149 | #' 150 | #' [mischief | bawl | sing || yell | drink] 151 | #' 152 | #' [Marauder]<:--[Pirate] 153 | #' [Pirate]- 0..7[mischief] 154 | #' [jollyness]->[Pirate] 155 | #' [jollyness]->[rum] 156 | #' [jollyness]->[singing] 157 | #' [Pirate]-> *[rum|tastiness: Int|swig()] 158 | #' [Pirate]->[singing] 159 | #' [singing]<->[rum] 160 | #' 161 | #' [st]->[plunder] 162 | #' [plunder]->[more loot] 163 | #' [more loot]->[st] 164 | #' [more loot] no ->[e] 165 | #' 166 | #' [Sailor] - [shiver me;timbers] 167 | #' ``` 168 | #' 169 | #' ### Svgbob example `{.kroki label=svgbob dia=svgbob eval=true}`: 170 | #' 171 | #' ```{.kroki label=svgbob dia=svgbob} 172 | #' 0 3 173 | #' *-------* +y 174 | #' 1 /| 2 /| ^ 175 | #' *-+-----* | | 176 | #' | |4 | |7 | ?? 177 | #' | *-----|-* ? +-----> +x 178 | #' |/ |/ / ? 179 | #' *-------* v 180 | #' 5 6 +z 181 | #' 182 | #' .-------. .-------. 183 | #' | {red} | | | 184 | #' | A | --> | B | 185 | #' | | | | 186 | #' '-------' '-------' 187 | #' 188 | #' +-------+ 189 | #' | {r1} | 190 | #' | | 191 | #' +-------+ 192 | #' 193 | #' "F-Dur" 194 | #' o +---+---+---+---+ 195 | #' +-*-+---+---+---+ 196 | #' o +---+---+---+---+ 197 | #' +---+-*-+---+---+ 198 | #' 199 | #' ^ .- - - - - 200 | #' | : 201 | #' | : 202 | #' Uin | .--------------+--------- 203 | #' | | 204 | #' | | 205 | #' *---'------------------------> 206 | #' 207 | #' .-------. 208 | #' | ... | 209 | #' | .... | 210 | #' +-------+ 211 | #' /// ___ \\\ 212 | #' '-----------' 213 | #' 214 | #' # Legend: 215 | #' r1 = { 216 | #' fill: papayawhip; 217 | #' } 218 | #' red = { 219 | #' fill: salmon; 220 | #' stroke: crimson; 221 | #' } 222 | #' ``` 223 | #' 224 | #' ### ERD example `{.kroki label=erd dia=erd eval=true}` 225 | #' 226 | #' ```{.kroki label=erd dia=erd} 227 | #' [Person] 228 | #' *name 229 | #' height 230 | #' weight 231 | #' +birth_location_id 232 | #' 233 | #' [Location] 234 | #' *id 235 | #' city 236 | #' state 237 | #' country 238 | # 239 | #' Person *--1 Location 240 | #' ``` 241 | #' 242 | #' ## Document creation 243 | 244 | #' Assuming that the file pantcl.bin is in your PATH, 245 | #' this document, a Tcl file with embedded Markdown and kroki code 246 | #' can be converted into a HTML file for instance using the command line: 247 | #' 248 | #' ``` 249 | #' pantcl.bin filter-kroki.tcl filter-kroki.html -s --css mini.css 250 | #' ``` 251 | #' 252 | #' Standard Markdown files with embedded kroki code can be converted with the same command line: 253 | #' 254 | #' ``` 255 | #' pantcl.bin sample.md sample.html -s 256 | #' ``` 257 | #' 258 | #' ## See also: 259 | #' 260 | #' * [Pantcl Readme](../../README.html) 261 | #' * [Pantcl documentation](../../pantcl.html) 262 | #' * [Mermaid filter](filter-mmd.html) 263 | #' * [Pikchr filter](filter-pik.html) 264 | #' * [PlantUML filter](filter-puml.html) 265 | #' * [GraphViz filter](filter-dot.html) 266 | #' 267 | 268 | proc dia2kroki {text {dia graphviz} {ext svg}} { 269 | set b64 [string map {+ - / _ = ""} [binary encode base64 [zlib compress [encoding convertto utf-8 $text]]]] 270 | set uri https://kroki.io//$dia/$ext/$b64 271 | } 272 | 273 | 274 | 275 | proc filter-kroki {cont dict} { 276 | global n 277 | incr n 278 | set def [dict create results show eval true fig true dia graphviz width 400 height 400 \ 279 | include true imagepath images app wget label null ext svg] 280 | set dict [dict merge $def $dict] 281 | set ret "" 282 | set owd [pwd] 283 | if {[dict get $dict label] eq "null"} { 284 | set fname [file join $owd [dict get $dict imagepath] kroki-$n] 285 | } else { 286 | set fname [file join $owd [dict get $dict imagepath] [dict get $dict label]] 287 | } 288 | if {![file exists [file join $owd [dict get $dict imagepath]]]} { 289 | file mkdir [file join $owd [dict get $dict imagepath]] 290 | } 291 | set url [dia2kroki $cont [dict get $dict dia] [dict get $dict ext]] 292 | if {[dict get $dict app] eq "wget"} { 293 | if { [catch { set res [exec -ignorestderr wget --connect-timeout 10 -q $url -O $fname.[dict get $dict ext]] }] } { 294 | set res [list "Could not fetch image for '[dict get $dict label]'" ""] 295 | } 296 | } elseif {[dict get $dict app] eq "curl"} { 297 | if { [catch { set res [exec -ignorestderr curl $url --connect-timeout 10 -s --output $fname.[dict get $dict ext]] }] } { 298 | set res [list "Could not fetch image for '[dict get $dict label]'" ""] 299 | } 300 | } 301 | if {[dict get $dict results] eq "show"} { 302 | # should be usually empty 303 | set res $res 304 | } else { 305 | set res "" 306 | } 307 | set img "" 308 | if {[dict get $dict fig]} { 309 | if {[dict get $dict include]} { 310 | if {[dict get $dict app] in [list wget curl]} { 311 | set img $fname.[dict get $dict ext] 312 | } else { 313 | set img $url 314 | } 315 | } 316 | } 317 | return [list $res $img] 318 | } 319 | -------------------------------------------------------------------------------- /lib/textutil/tabify.tcl: -------------------------------------------------------------------------------- 1 | # 2 | # As the author of the procs 'tabify2' and 'untabify2' I suggest that the 3 | # comments explaining their behaviour be kept in this file. 4 | # 1) Beginners in any programming language (I am new to Tcl so I know what I 5 | # am talking about) can profit enormously from studying 'correct' code. 6 | # Of course comments will help a lot in this regard. 7 | # 2) Many problems newbies face can be solved by directing them towards 8 | # available libraries - after all, libraries have been written to solve 9 | # recurring problems. Then they can just use them, or have a closer look 10 | # to see and to discover how things are done the 'Tcl way'. 11 | # 3) And if ever a proc from a library should be less than perfect, having 12 | # comments explaining the behaviour of the code will surely help. 13 | # 14 | # This said, I will welcome any error reports or suggestions for improvements 15 | # (especially on the 'doing things the Tcl way' aspect). 16 | # 17 | # Use of these sources is licensed under the same conditions as is Tcl. 18 | # 19 | # June 2001, Helmut Giese (hgiese@ratiosoft.com) 20 | # 21 | # ---------------------------------------------------------------------------- 22 | # 23 | # The original procs 'tabify' and 'untabify' each work with complete blocks 24 | # of $num spaces ('num' holding the tab size). While this is certainly useful 25 | # in some circumstances, it does not reflect the way an editor works: 26 | # Counting columns from 1, assuming a tab size of 8 and entering '12345' 27 | # followed by a tab, you expect to advance to column 9. Your editor might 28 | # put a tab into the file or 3 spaces, depending on its configuration. 29 | # Now, on 'tabifying' you will expect to see those 3 spaces converted to a 30 | # tab (and on the other hand expect the tab *at this position* to be 31 | # converted to 3 spaces). 32 | # 33 | # This behaviour is mimicked by the new procs 'tabify2' and 'untabify2'. 34 | # Both have one feature in common: They accept multi-line strings (a whole 35 | # file if you want to) but in order to make life simpler for the programmer, 36 | # they split the incoming string into individual lines and hand each line to 37 | # a proc that does the real work. 38 | # 39 | # One design decision worth mentioning here: 40 | # A single space is never converted to a tab even if its position would 41 | # allow to do so. 42 | # Single spaces occur very often, say in arithmetic expressions like 43 | # [expr (($a + $b) * $c) < $d]. If we didn't follow the above rule we might 44 | # need to replace one or more of them to tabs. However if the tab size gets 45 | # changed, this expression would be formatted quite differently - which is 46 | # probably not a good idea. 47 | # 48 | # 'untabifying' on the other hand might need to replace a tab with a single 49 | # space: If the current position requires it, what else to do? 50 | # As a consequence those two procs are unsymmetric in this aspect, but I 51 | # couldn't think of a better solution. Could you? 52 | # 53 | # ---------------------------------------------------------------------------- 54 | # 55 | 56 | # ### ### ### ######### ######### ######### 57 | ## Requirements 58 | 59 | package require Tcl 8.2 60 | package require textutil::repeat 61 | 62 | namespace eval ::textutil::tabify {} 63 | 64 | # ### ### ### ######### ######### ######### 65 | ## API implementation 66 | 67 | namespace eval ::textutil::tabify { 68 | namespace import -force ::textutil::repeat::strRepeat 69 | } 70 | 71 | proc ::textutil::tabify::tabify { string { num 8 } } { 72 | return [string map [list [MakeTabStr $num] \t] $string] 73 | } 74 | 75 | proc ::textutil::tabify::untabify { string { num 8 } } { 76 | return [string map [list \t [MakeTabStr $num]] $string] 77 | } 78 | 79 | proc ::textutil::tabify::MakeTabStr { num } { 80 | variable TabStr 81 | variable TabLen 82 | 83 | if { $TabLen != $num } then { 84 | set TabLen $num 85 | set TabStr [strRepeat " " $num] 86 | } 87 | 88 | return $TabStr 89 | } 90 | 91 | # ---------------------------------------------------------------------------- 92 | # 93 | # tabifyLine: Works on a single line of text, replacing 'spaces at correct 94 | # positions' with tabs. $num is the requested tab size. 95 | # Returns the (possibly modified) line. 96 | # 97 | # 'spaces at correct positions': Only spaces which 'fill the space' between 98 | # an arbitrary position and the next tab stop can be replaced. 99 | # Example: With tab size 8, spaces at positions 11 - 13 will *not* be replaced, 100 | # because an expansion of a tab at position 11 will jump up to 16. 101 | # See also the comment at the beginning of this file why single spaces are 102 | # *never* replaced by a tab. 103 | # 104 | # The proc works backwards, from the end of the string up to the beginning: 105 | # - Set the position to start the search from ('lastPos') to 'end'. 106 | # - Find the last occurrence of ' ' in 'line' with respect to 'lastPos' 107 | # ('currPos' below). This is a candidate for replacement. 108 | # - Find to 'currPos' the following tab stop using the expression 109 | # set nextTab [expr ($currPos + $num) - ($currPos % $num)] 110 | # and get the previous tab stop as well (this will be the starting 111 | # point for the next iteration). 112 | # - The ' ' at 'currPos' is only a candidate for replacement if 113 | # 1) it is just one position before a tab stop *and* 114 | # 2) there is at least one space at its left (see comment above on not 115 | # touching an isolated space). 116 | # Continue, if any of these conditions is not met. 117 | # - Determine where to put the tab (that is: how many spaces to replace?) 118 | # by stepping up to the beginning until 119 | # -- you hit a non-space or 120 | # -- you are at the previous tab position 121 | # - Do the replacement and continue. 122 | # 123 | # This algorithm only works, if $line does not contain tabs. Otherwise our 124 | # interpretation of any position beyond the tab will be wrong. (Imagine you 125 | # find a ' ' at position 4 in $line. If you got 3 leading tabs, your *real* 126 | # position might be 25 (tab size of 8). Since in real life some strings might 127 | # already contain tabs, we test for it (and eventually call untabifyLine). 128 | # 129 | 130 | proc ::textutil::tabify::tabifyLine { line num } { 131 | if { [string first \t $line] != -1 } { 132 | # assure array 'Spaces' is set up 'comme il faut' 133 | checkArr $num 134 | # remove existing tabs 135 | set line [untabifyLine $line $num] 136 | } 137 | 138 | set lastPos end 139 | 140 | while { $lastPos > 0 } { 141 | set currPos [string last " " $line $lastPos] 142 | if { $currPos == -1 } { 143 | # no more spaces 144 | break; 145 | } 146 | 147 | set nextTab [expr {($currPos + $num) - ($currPos % $num)}] 148 | set prevTab [expr {$nextTab - $num}] 149 | 150 | # prepare for next round: continue at 'previous tab stop - 1' 151 | set lastPos [expr {$prevTab - 1}] 152 | 153 | if { ($currPos + 1) != $nextTab } { 154 | continue ;# crit. (1) 155 | } 156 | 157 | if { [string index $line [expr {$currPos - 1}]] != " " } { 158 | continue ;# crit. (2) 159 | } 160 | 161 | # now step backwards while there are spaces 162 | for {set pos [expr {$currPos - 2}]} {$pos >= $prevTab} {incr pos -1} { 163 | if { [string index $line $pos] != " " } { 164 | break; 165 | } 166 | } 167 | 168 | # ... and replace them 169 | set line [string replace $line [expr {$pos + 1}] $currPos \t] 170 | } 171 | return $line 172 | } 173 | 174 | # 175 | # Helper proc for 'untabifyLine': Checks if all needed elements of array 176 | # 'Spaces' exist and creates the missing ones if needed. 177 | # 178 | 179 | proc ::textutil::tabify::checkArr { num } { 180 | variable TabLen2 181 | variable Spaces 182 | 183 | if { $num > $TabLen2 } { 184 | for { set i [expr {$TabLen2 + 1}] } { $i <= $num } { incr i } { 185 | set Spaces($i) [strRepeat " " $i] 186 | } 187 | set TabLen2 $num 188 | } 189 | } 190 | 191 | 192 | # untabifyLine: Works on a single line of text, replacing tabs with enough 193 | # spaces to get to the next tab position. 194 | # Returns the (possibly modified) line. 195 | # 196 | # The procedure is straight forward: 197 | # - Find the next tab. 198 | # - Calculate the next tab position following it. 199 | # - Delete the tab and insert as many spaces as needed to get there. 200 | # 201 | 202 | proc ::textutil::tabify::untabifyLine { line num } { 203 | variable Spaces 204 | 205 | set currPos 0 206 | while { 1 } { 207 | set currPos [string first \t $line $currPos] 208 | if { $currPos == -1 } { 209 | # no more tabs 210 | break 211 | } 212 | 213 | # how far is the next tab position ? 214 | set dist [expr {$num - ($currPos % $num)}] 215 | # replace '\t' at $currPos with $dist spaces 216 | set line [string replace $line $currPos $currPos $Spaces($dist)] 217 | 218 | # set up for next round (not absolutely necessary but maybe a trifle 219 | # more efficient) 220 | incr currPos $dist 221 | } 222 | return $line 223 | } 224 | 225 | # tabify2: Replace all 'appropriate' spaces as discussed above with tabs. 226 | # 'string' might hold any number of lines, 'num' is the requested tab size. 227 | # Returns (possibly modified) 'string'. 228 | # 229 | proc ::textutil::tabify::tabify2 { string { num 8 } } { 230 | 231 | # split string into individual lines 232 | set inLst [split $string \n] 233 | 234 | # now work on each line 235 | set outLst [list] 236 | foreach line $inLst { 237 | lappend outLst [tabifyLine $line $num] 238 | } 239 | 240 | # return all as one string 241 | return [join $outLst \n] 242 | } 243 | 244 | 245 | # untabify2: Replace all tabs with the appropriate number of spaces. 246 | # 'string' might hold any number of lines, 'num' is the requested tab size. 247 | # Returns (possibly modified) 'string'. 248 | # 249 | proc ::textutil::tabify::untabify2 { string { num 8 } } { 250 | 251 | # assure array 'Spaces' is set up 'comme il faut' 252 | checkArr $num 253 | 254 | set inLst [split $string \n] 255 | 256 | set outLst [list] 257 | foreach line $inLst { 258 | lappend outLst [untabifyLine $line $num] 259 | } 260 | 261 | return [join $outLst \n] 262 | } 263 | 264 | 265 | 266 | # ### ### ### ######### ######### ######### 267 | ## Data structures 268 | 269 | namespace eval ::textutil::tabify { 270 | variable TabLen 8 271 | variable TabStr [strRepeat " " $TabLen] 272 | 273 | namespace export tabify untabify tabify2 untabify2 274 | 275 | # The proc 'untabify2' uses the following variables for efficiency. 276 | # Since a tab can be replaced by one up to 'tab size' spaces, it is handy 277 | # to have the appropriate 'space strings' available. This is the use of 278 | # the array 'Spaces', where 'Spaces(n)' contains just 'n' spaces. 279 | # The variable 'TabLen2' remembers the biggest tab size used. 280 | 281 | variable TabLen2 0 282 | variable Spaces 283 | array set Spaces {0 ""} 284 | } 285 | 286 | # ### ### ### ######### ######### ######### 287 | ## Ready 288 | 289 | package provide textutil::tabify 0.7 290 | --------------------------------------------------------------------------------