summaryrefslogtreecommitdiff
path: root/macros/context/contrib/context-filter/tex/context/third/filter/t-filter.mkiv
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/context/contrib/context-filter/tex/context/third/filter/t-filter.mkiv
Initial commit
Diffstat (limited to 'macros/context/contrib/context-filter/tex/context/third/filter/t-filter.mkiv')
-rw-r--r--macros/context/contrib/context-filter/tex/context/third/filter/t-filter.mkiv543
1 files changed, 543 insertions, 0 deletions
diff --git a/macros/context/contrib/context-filter/tex/context/third/filter/t-filter.mkiv b/macros/context/contrib/context-filter/tex/context/third/filter/t-filter.mkiv
new file mode 100644
index 0000000000..408a3d96b3
--- /dev/null
+++ b/macros/context/contrib/context-filter/tex/context/third/filter/t-filter.mkiv
@@ -0,0 +1,543 @@
+%D \module
+%D [ file=t-filter,
+%D version=2018.08.10,
+%D title=\CONTEXT\ User Module,
+%D subtitle=Filter,
+%D author=Aditya Mahajan,
+%D date=\currentdate,
+%D copyright=Aditya Mahajan,
+%D email=adityam <at> ieee <dot> org,
+%D license=Simplified BSD License]
+
+\writestatus{loading}{Filter (ver: 2018.08.10)}
+
+\startmodule [filter]
+\usemodule [module-catcodes]
+\unprotect
+
+% \f!temporaryextension was removed from the core in July 2012.
+\ifx\f!temporaryextension\undefined \def\f!temporaryextension{tmp} \fi
+
+%D \subject {Interface}
+%D
+%D Using interface constants allows one to use \type{\c!filter} etc. in
+%D the module definition, and thereby reduces the risk of a typo.
+%D Currently, only English names are provided. If someone wants a
+%D multi-lingual interface, let me know and I will add other language
+%D names as well,
+
+\startinterface all
+ \setinterfaceconstant {filter} {filter}
+ \setinterfaceconstant {filtercommand} {filtercommand}
+ \setinterfaceconstant {output} {output}
+ \setinterfaceconstant {purge} {purge}
+ \setinterfaceconstant {read} {read}
+ \setinterfaceconstant {write} {write}
+ \setinterfaceconstant {readcommand} {readcommand}
+ \setinterfaceconstant {taglabel} {taglabel}
+\stopinterface
+
+
+%D \subject {Name space}
+%D
+%D We use logical names to easily catch typos.
+
+\def\externalfilter@id {externalfilter}
+
+\def\externalfilter@temp_prefix {temp}
+\def\externalfilter@count {\????externalfilter-\currentexternalfilter-counter}
+
+\definenamespace
+ [externalfilter]
+ [\c!type=module,
+ \c!name=externalfilter,
+ \c!command=\v!yes,
+ setup=\v!list,
+ \c!style=\v!yes,
+ \s!parent=externalfilter]
+
+\appendtoks
+ \externalfilter@show_status{defining filter : \currentexternalfilter}%
+ \doifinset{\externalfilterparameter\c!cache}{\v!yes,\v!force}
+ {\ifcsname\externalfilter@count\endcsname \else
+ \expandafter\newcounter\csname\externalfilter@count\endcsname\fi}%
+ \setuevalue{\e!start\currentexternalfilter}{\externalfilter@start[\currentexternalfilter]}%
+ \setuvalue {\e!stop\currentexternalfilter}{}%
+ \setuevalue{process\currentexternalfilter file}{\externalfilter@process_file[\currentexternalfilter]}%
+ \setuevalue{process\currentexternalfilter buffer}{\externalfilter@process_buffer[\currentexternalfilter]}%
+ \setuevalue{inline\currentexternalfilter}{\externalfilter@inline[\currentexternalfilter]}%
+\to \everydefineexternalfilter
+
+% For backward compatibility
+\let\setupexternalfilters \setupexternalfilter
+
+%D \subject {Messages}
+
+\def\m!externalfilter{t-filter}
+
+\setinterfacemessage\m!externalfilter{title} {\m!externalfilter}
+\setinterfacemessage\m!externalfilter{notfound} {file -- cannot be found}
+\setinterfacemessage\m!externalfilter{missing} {output file missing}
+\setinterfacemessage\m!externalfilter{missing_cache} {cached output file -- missing. Rerunning filter}
+\setinterfacemessage\m!externalfilter{forbidden} {Fatal Error: Cannot use absolute path -- as directory}
+\setinterfacemessage\m!externalfilter{unwriteable} {Fatal Error: Cannot write to file --}
+\setinterfacemessage\m!externalfilter{slash} {Appending / to directory -- }
+\setinterfacemessage\m!externalfilter{reuse} {\c!state=\v!stop : Not running filter on file --}
+\setinterfacemessage\m!externalfilter{writedisabled} {\c!write=\v!no : Not writing output for filter --}
+
+
+%D \subject {Tracing Macros}
+
+\newif\iftraceexternalfilters
+
+\unexpanded\def\traceexternalfilters
+ {\traceexternalfilterstrue
+ \enabletrackers[graphic.runfile]}
+
+\starttexdefinition externalfilter@show_filenames
+ \writestatus\m!externalfilter{current filter : \currentexternalfilter}
+ \writestatus\m!externalfilter{base file : \externalfilter@base_file}
+ \writestatus\m!externalfilter{input file : \externalfilter@input_file}
+ \writestatus\m!externalfilter{output file : \externalfilter@output_file}
+\stoptexdefinition
+
+\starttexdefinition externalfilter@show_status #1
+ \iftraceexternalfilters
+ \writestatus\m!externalfilter{#1}
+ \fi
+\stoptexdefinition
+
+\starttexdefinition externalfilter@show_filtercommand
+ \writestatus\m!externalfilter{command : \externalfilterparameter\c!filtercommand}
+ \writestatus\m!externalfilter{state : \externalfilterparameter\c!state}
+\stoptexdefinition
+
+%D \section {The main user macros}
+
+\unexpanded\def\externalfilter@start
+ {\bgroup\obeylines\dodoubleargument\externalfilter@start_indeed}
+
+\starttexdefinition externalfilter@start_indeed [#1][#2]
+ % #1 = filter
+ % #2 = options
+ \egroup %\bgroup in \externalfilter@start
+
+ \begingroup % to keep assignments local
+ \edef\currentexternalfilter{#1}
+
+ \setupexternalfilter[#1][\c!name=,#2]
+
+ \externalfilter@set_filenames
+
+ % Capture the contents of the buffer
+ \edef\p_strip{\getvalue{\externalfilter@id-\c!strip-\externalfilterparameter\c!strip}}
+ \buff_pickup{\externalfilter@buffer_name}{\e!start#1}{\e!stop#1}{}{\externalfilter@process_filter}{\p_strip}
+\stoptexdefinition
+
+\setvalue{\externalfilter@id-\c!strip-}{\zerocount}
+\setvalue{\externalfilter@id-\c!strip-\v!off}{\zerocount}
+\setvalue{\externalfilter@id-\c!strip-\v!on}{\plusone}
+
+\setvalue{\externalfilter@id-\c!strip-\v!no}{\zerocount}
+\setvalue{\externalfilter@id-\c!strip-\v!yes}{\plusone}
+
+\unexpanded\def\externalfilter@process_file
+ {\dodoubleargument\externalfilter@process_file_indeed}
+
+\starttexdefinition externalfilter@process_file_indeed [#1][#2]#3
+ % #1 = filter
+ % #2 = options
+ % #3 = filename
+ \begingroup
+
+ \edef\currentexternalfilter{#1}
+ \setupexternalfilter[#1][\c!name=,#2]
+
+ \processcommacommand[\externalfilterparameter{\c!filter\c!setups}]\directsetup
+ \externalfilter@set_directory
+
+ \edef\externalfilter@input_file{\externalfilter@any_filename{#3}}
+ \splitfilename{#3}
+ %NOTE: \edef doesn not work because \splitoffname is not expandable
+ \def\externalfilter@base_file {\splitoffname}
+
+ % The output is always in the directory specified by
+ % \c!directory; even if the input is from some other directory
+ \def\externalfilter@output_file{\externalfilter@get_directory\externalfilterparameter\c!output}
+
+ \iftraceexternalfilters \externalfilter@show_filenames \fi
+ \externalfilter@execute_filter
+ \externalfilter@read_processed_file
+
+ \endgroup
+\stoptexdefinition
+
+\unexpanded\def\externalfilter@process_buffer
+ {\dotripleargument\externalfilter@process_buffer_indeed}
+
+\starttexdefinition externalfilter@process_buffer_indeed [#1][#2][#3]
+ % #1 = filter
+ % #2 = options
+ % #3 = buffer
+ \begingroup
+
+ \edef\currentexternalfilter{#1}
+ \ifthirdargument
+ \setupexternalfilter[#1][\c!name=,#2]
+ \fi
+
+ \processcommacommand[\externalfilterparameter{\c!filter\c!setups}]\directsetup
+ \externalfilter@set_directory
+
+ \ifthirdargument
+ \edef\externalfilter@buffer_name{#3}
+ \else
+ \edef\externalfilter@buffer_name{#2}
+ \fi
+
+ \externalfilter@set_filenames_extras
+
+ \iftraceexternalfilters \externalfilter@show_filenames \fi
+
+ \externalfilter@process_filter
+
+\stoptexdefinition
+
+\unexpanded\def\externalfilter@inline
+ {\dodoubleargument\externalfilter@inline_indeed}
+
+\starttexdefinition externalfilter@inline_indeed [#1][#2]
+ \begingroup % to keep assignments local
+ \edef\currentexternalfilter{#1}
+
+ \setupexternalfilter[#1][\c!numbering=,\c!name=,\c!location=\v!text,#2]
+
+ \externalfilter@set_filenames
+ \doifelse{\externalfilterparameter\c!write}\v!no
+ \externalfilter@inline_write_disabled
+ \externalfilter@inline_write_enabled
+\stoptexdefinition
+
+\starttexdefinition externalfilter@inline_write_disabled
+ \iftraceexternalfilters \showmessage\m!externalfilter{writedisabled} \currentexternalfilter \fi
+
+ \externalfilter@execute_filter
+ \endlinechar\minusone %to prevent line break after reading file
+ \externalfilter@read_processed_file
+
+ % Finalization
+ \doifinset{\externalfilterparameter\c!cache}{\v!yes,\v!force}
+ {\doglobal\incrementvalue\externalfilter@count}
+ \endgroup
+\stoptexdefinition
+
+\starttexdefinition externalfilter@inline_write_enabled
+ \pushcatcodetable
+ \futurelet\next\externalfilter@inline_grabcontent
+\stoptexdefinition
+
+%D \subsubject {Write argument to file verbatim}
+%D
+%D Surprisingly, there is nothing in the core to define a function that write its
+%D argument to a file verbatim. I basically copied the \type{\type} macro.
+
+\starttexdefinition externalfilter@inline_grabcontent
+ \ifx\next\bgroup
+ \expandafter\externalfilter@inline_group
+ \else
+ \expandafter\externalfilter@inline_other
+ \fi
+\stoptexdefinition
+
+\starttexdefinition externalfilter@inline_group
+ \setcatcodetable \externalfilter@read_catcodes
+ \externalfilter@process_inline
+\stoptexdefinition
+
+\starttexdefinition externalfilter@inline_other #1
+ \setcatcodetable \externalfilter@verb_catcodes
+
+ \def\next##1#1{\externalfilter@process_inline{##1}}
+ \next
+\stoptexdefinition
+
+\newwrite\externalfilter@write
+
+\starttexdefinition externalfilter@process_inline #1
+ \immediate\openout \externalfilter@write\externalfilter@input_file
+ \immediate\write \externalfilter@write{\detokenize{#1}}
+ \immediate\closeout\externalfilter@write
+
+ \popcatcodetable
+
+ \externalfilter@execute_filter
+ \endlinechar\minusone %to prevent line break after reading file
+ \externalfilter@read_processed_file
+
+ \iftraceexternalfilters \else
+ \doif{\externalfilterparameter\c!purge}\v!yes
+ {\ctxlua{os.remove(\!!bs\externalfilter@input_file\!!es)}}
+ \fi
+ % Finalization
+ \doifinset{\externalfilterparameter\c!cache}{\v!yes,\v!force}
+ {\doglobal\incrementvalue\externalfilter@count}
+ \endgroup
+\stoptexdefinition
+
+
+%D \section {Helper Functions}
+%D
+%D \subsubject {First and last character of a string}
+
+\def\externalfilter@get_first_character#1%
+ {\externalfilter@get_first_character_indeed#1\relax}
+
+\def\externalfilter@get_first_character_indeed#1#2\relax{#1}
+
+\def\externalfilter@get_last_character#1%
+ {\@EA\externalfilter@get_last_character_indeed#1\relax}
+
+\def\externalfilter@get_last_character_indeed#1#2%
+ {\ifx#2\relax#1\else\@EA\externalfilter@get_last_character_indeed\@EA#2\fi}
+
+%D \subsubject {Setting font and color attributes}
+%D I want to use the same interface for MkII and MkIV
+
+\starttexdefinition externalfilter@attributes_start #1#2#3
+ % id style color
+ \getvalue{use#1styleandcolor}{#2}{#3}
+\stoptexdefinition
+
+\def\externalfilter@attributes_stop{}
+
+%D \subsubject {Set the name of output directory}
+
+\starttexdefinition externalfilter@set_directory
+ \edef\externalfilter@get_directory{\externalfilterparameter\c!directory}
+ \doifsomething{\externalfilter@get_directory}\externalfilter@set_directory_indeed
+\stoptexdefinition
+
+\starttexdefinition externalfilter@set_directory_indeed
+ \doif{\externalfilter@get_first_character\externalfilter@get_directory}{/}
+ {\writeline
+ \showmessage\m!externalfilter{forbidden}\externalfilter@get_directory
+ \batchmode
+ \errmessage{}
+ \normalend}
+
+ \doifnot{\externalfilter@get_last_character\externalfilter@get_directory}{/}
+ {\iftraceexternalfilters \showmessage\m!externalfilter{slash}\externalfilter@get_directory \fi
+ \edef\externalfilter@get_directory{\externalfilter@get_directory/}}
+\stoptexdefinition
+
+%D \subsubject {Check if file is writeable}
+
+\starttexdefinition externalfilter@check_writable #1
+
+ \ctxcommand{doifnot(file.is_writable("#1"))}
+ {\showmessage\m!externalfilter{unwriteable}{#1}
+ \batchmode
+ \errmessage{}
+ \normalend}
+\stoptexdefinition
+
+%D \subsubject {Find file name (with search in \usepath)}
+%D
+%D The `\locfilename` macro does not search in the path specified by `\usepath`.
+%D So, we define a macro that is based on `\readfile`.
+
+\def\externalfilter@any_filename#1%
+ {\clf_getreadfilename{any}{.}{#1}}
+
+%D \subsubject {Set file names}
+%D
+%D \type{\externalfilter@base_file} is the name of the temporary file without
+%D extension. Its actual value depends on the state of \type{cache} key as
+%D well as the value of \type{name} key.
+
+\starttexdefinition externalfilter@set_filenames
+ \processcommacommand[\externalfilterparameter{\c!filter\c!setups}]\directsetup
+ \externalfilter@set_directory
+
+ % Set the name of temp file for the filter
+ \doifinsetelse{\externalfilterparameter\c!cache}{\v!yes,\v!force}
+ {\edef\externalfilter@buffer_name{\externalfilter@temp_prefix-\currentexternalfilter-\csname\externalfilter@count\endcsname}}
+ {\edef\externalfilter@buffer_name{\externalfilter@temp_prefix-\currentexternalfilter}}
+ \doifsomething{\externalfilterparameter\c!name}
+ {\edef\externalfilter@buffer_name{\externalfilter@temp_prefix-\currentexternalfilter-\externalfilterparameter\c!name}}
+ \doif{\externalfilterparameter\c!write}\v!no
+ {\edef\externalfilter@buffer_name{\externalfilter@temp_prefix-\currentexternalfilter-\externalfilterparameter{\c!cache\c!option}}}
+
+ \externalfilter@set_filenames_extras
+
+ \iftraceexternalfilters \externalfilter@show_filenames \fi
+\stoptexdefinition
+
+\starttexdefinition externalfilter@set_filenames_extras
+ % The following macros are useful for filter= and filtercommand= options
+ % The basename of the external file
+ \edef\externalfilter@base_file {\jobname-\externalfilter@buffer_name}
+
+ % Append directory name to the name of the input file
+ \edef\externalfilter@input_file {\externalfilter@get_directory\externalfilter@base_file.\f!temporaryextension}
+
+ % Append directory name to the name of the output file
+ \edef\externalfilter@output_file{\externalfilter@get_directory\externalfilterparameter\c!output}
+\stoptexdefinition
+
+
+
+%D \subsubject {Process Filter}
+%D
+%D Execute filter, read the output and do book-keeping if needed.
+
+\starttexdefinition externalfilter@process_filter
+ % By defualt, buffers are in memory in MkIV. So, we save them to disk
+ %
+ % \savebuffer[\externalfilter@buffer_name][\externalfilter@input_file]
+ %
+ % We can also save a list of buffers to a file. The empty
+ % elements of the list are ignored. So, instead we use the following
+ %
+ % \savebuffer[\externalfilterparameter{\c!buffer\c!before},
+ % \externalfilter@buffer_name,
+ % \externalfilterparameter{\c!buffer\c!after}]
+ % [\externalfilter@input_file]}
+ %
+ % but using this method we cannot save the file in another directory.
+ % So, we use the key-value interface for \savebuffer.
+ \externalfilter@check_writable \externalfilter@input_file
+ \savebuffer
+ [
+ \c!list={\externalfilterparameter{\c!buffer\c!before},
+ \externalfilter@buffer_name,
+ \externalfilterparameter{\c!buffer\c!after}},
+ \c!file={\externalfilter@input_file},
+ \c!prefix=\v!no,
+ ]
+ \externalfilter@execute_filter
+ \externalfilter@read_processed_file
+ \iftraceexternalfilters \else
+ \doif{\externalfilterparameter\c!purge}\v!yes
+ {\ctxlua{os.remove(\!!bs\externalfilter@input_file\!!es)}}
+ \fi
+
+ % Finalization
+ \doifinset{\externalfilterparameter\c!cache}{\v!yes,\v!force}
+ {\doglobal\incrementvalue\externalfilter@count}
+
+ \doif{\externalfilterparameter\c!location}\v!paragraph
+ {\useindentnextparameter\externalfilterparameter
+ \aftergroup\dorechecknextindentation}
+ \endgroup
+\stoptexdefinition
+
+%D \subsubject {Execute Filter}
+
+% In MkIV, we use job.files.run to check if a file has changed. This function
+% writes the md5 sum to the tuc file rather than to an external file. So, we
+% must not check for the \type{*first} mode (otherwise the md5 sum is overridden
+% in the next run.
+\starttexdefinition externalfilter@execute_filter
+
+ \externalfilter@check_writable \externalfilter@output_file
+ \iftraceexternalfilters \externalfilter@show_filtercommand \fi
+
+ \doifelsenothing{\externalfilter@input_file}
+ {\showmessage\m!externalfilter{missing}\externalfilter@input_file}
+ {\doifelse{\externalfilterparameter\c!cache}\v!yes
+ {\doifelse{\externalfilterparameter\c!state}\v!stop
+ {\showmessage\m!externalfilter{reuse}\externalfilter@input_file}
+ {\doiffileelse{\externalfilter@output_file}
+ {\doifnot{\externalfilterparameter\c!write}\v!no
+ % When write=no is selected, % base_name=....-cacheoption...
+ % Since there is no input, caching is simply achieved
+ % using the filename.
+ {\ctxlua{job.files.run(\!!bs\externalfilter@input_file\!!es,
+ \!!bs\externalfilterparameter\c!filtercommand\!!es)}}}
+ {\showmessage\m!externalfilter{missing_cache}\externalfilter@output_file
+ \executesystemcommand
+ {\externalfilterparameter\c!filtercommand}}}}
+ {\executesystemcommand
+ {\externalfilterparameter\c!filtercommand}}}
+\stoptexdefinition
+
+%D \subsubject {Read output}
+
+\starttexdefinition externalfilter@read_processed_file
+ \doif{\externalfilterparameter\c!read}\v!yes
+ {\doiffileelse{\externalfilter@output_file}
+ {\externalfilter@read_processed_file_indeed}
+ {\showmessage\m!externalfilter{notfound}\externalfilter@output_file
+ \externalfilter@show_filenames
+ \blank
+ {\tttf [[\getmessage\m!externalfilter{missing}]]}
+ \blank}}
+\stoptexdefinition
+
+\starttexdefinition externalfilter@read_processed_file_indeed
+ \doifelse{\externalfilterparameter\c!location}\v!paragraph
+ {\blank[\externalfilterparameter\c!spacebefore]
+ \usealignparameter\externalfilterparameter
+ \externalfilterparameter\c!before}
+ {\externalfilterparameter\c!left}
+
+ \begingroup
+ \dostarttagged{\externalfilterparameter\c!taglabel}\currentexternalfilter
+ \useexternalfilterstyleandcolor\c!style\c!color
+ \processcommacommand[\externalfilterparameter\c!setups]\directsetup
+ \externalfilterparameter\c!readcommand\externalfilter@output_file
+ \dostoptagged
+ \endgroup
+
+ \doifelse{\externalfilterparameter\c!location}\v!paragraph
+ {\externalfilterparameter\c!after
+ \par\blank[\externalfilterparameter\c!spaceafter]}
+ {\externalfilterparameter\c!right}
+\stoptexdefinition
+
+%D \section {Default Values}
+
+\setupexternalfilters
+ [
+ \c!location=\v!paragraph,
+ \c!before=,
+ \c!after=,
+ \c!left=,
+ \c!right=,
+ \c!spacebefore=,
+ \c!spaceafter=,
+ \c!style=,
+ \c!color=,
+ \c!indentnext=\v!auto,
+ \c!align=,
+ \c!setups=,
+ \c!continue=\v!no,
+ \c!cache=\externalfilterparameter\c!continue, % for backward compatibility
+ \c!cache\c!option=,
+ \c!read=\v!yes,
+ \c!strip=\v!yes,
+ \c!readcommand=\ReadFile,
+ \c!directory=,
+ \c!purge=\v!yes,
+ \c!output=\externalfilterbasefile.tex,
+ \c!filter=,
+ \c!filtercommand={\externalfilterparameter\c!filter\space \externalfilter@input_file},
+ \c!buffer\c!before=,
+ \c!buffer\c!after=,
+ \c!taglabel=\externalfilter@id,
+ ]
+
+\def\externalfilterbasefile {\externalfilter@base_file}
+\def\externalfilterinputfile {\externalfilter@input_file}
+\def\externalfilteroutputfile{\externalfilter@output_file}
+
+% t-syntax-groups still uses this.
+\def\externalfilter@name {\currentexternalfilter}
+
+% Default value
+\def\externalfilter@input_file {}
+\def\externalfilter@output_file{}
+
+\protect
+\stopmodule