% MIT License % % Copyright (c) 2019 Magnus Lie Hetland % % Permission is hereby granted, free of charge, to any person obtaining a copy % of this software and associated documentation files (the "Software"), to deal % in the Software without restriction, including without limitation the rights % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell % copies of the Software, and to permit persons to whom the Software is % furnished to do so, subject to the following conditions: % % The above copyright notice and this permission notice shall be included in all % copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE % SOFTWARE. % \def \pseudoversion {1.1.3} \def \pseudodate {2019/10/30} \RequirePackage{expl3} \ProvidesExplPackage {pseudo} {\pseudodate} {\pseudoversion} {Straightforward pseudocode} \RequirePackage{xparse} \RequirePackage{array, xcolor, colortbl} \RequirePackage{l3keys2e} \RequirePackage{aliascnt} \bool_new:N \c__pseudo_beamer_bool \@ifclassloaded{beamer} {\bool_set_true:N \c__pseudo_beamer_bool} {\bool_set_false:N \c__pseudo_beamer_bool} \newcounter{pseudoenv} \newcounter{pseudoline}[pseudoenv] \int_new:N \g__pseudo_last_saved_line_int \dim_new:N \pseudoindentlength \int_new:N \g__pseudo_indent_level_int \int_new:N \l__pseudo_initial_indent_level_int \cs_generate_variant:Nn \quark_if_no_value:nTF { VTF } \cs_generate_variant:Nn \tl_set:Nn { Ne } \cs_new:Nn \__pseudo_undef_col:n { \tl_set_eq:cN { NC@find@ \token_to_str:N #1 } \scan_stop: } \cs_new:Nn \__pseudo_def_col:nn { \__pseudo_undef_col:n { #1 } \newcolumntype { #1 } { #2 } } \cs_new:Nn \__pseudo_meta_new_cmd:NNnn { \tl_set:Nn \l_tmpa_tl {pseudo \cs_to_str:N #2} \exp_args:Nc #1 \l_tmpa_tl #3 {#4} \cs_if_free:NT #2 {\cs_gset_eq:Nc #2 \l_tmpa_tl} } \cs_new:Nn \__pseudo_new_cmd:Nnn { \__pseudo_meta_new_cmd:NNnn \NewDocumentCommand #1 {{#2}} { #3 } } \cs_new:Nn \__pseudo_new_ecmd:Nnn { \__pseudo_meta_new_cmd:NNnn \def #1 {#2} { #3 } } \cs_new:Nn \__pseudo_new_dec:nn { \tl_set:Nn \l_tmpa_tl { DeclarePseudo #1 } \exp_args:Nc \DeclareDocumentCommand \l_tmpa_tl { mm } { \DeclareDocumentCommand ##1 { } { \use:c { #2 } { ##2 } } } } \cs_new:Nn \__pseudo_per_char:nnn { \peek_charcode_remove:NTF { #1 } { #2 \__pseudo_per_char:nnn{#1}{#2}{#3} } { #3 } } \cs_new:Nn \__pseudo_set_indent_length: { \quark_if_no_value:VTF \l__pseudo_indent_length_tl { \hbox_set:Nn \l_tmpa_box { \l__pseudo_indent_text_tl } \dim_set:Nn \pseudoindentlength { \box_wd:N \l_tmpa_box } } { \dim_set:Nn \pseudoindentlength \l__pseudo_indent_length_tl } } \cs_new:Nn \__pseudo_indent:N { \skip_horizontal:n{ \pseudoindentlength * #1 } \ignorespaces } \cs_new:Nn \__pseudo_drop_ctr:n { \cs_undefine:c { c@ #1 } } \cs_new:Nn \__pseudo_copy_ctr:nn { \__pseudo_drop_ctr:n { #1 } \newaliascnt { #1 } { #2 } } \cs_new:Nn \__pseudo_star_setup: { \cs_if_exist:cT { c@ * } { \__pseudo_copy_ctr:nn { __pseudo_orig_* } { * } } \__pseudo_copy_ctr:nn { * } { pseudoline } \group_insert_after:N \__pseudo_star_reset: } \cs_new:Nn \__pseudo_star_reset: { \cs_if_exist:cT { c@ __pseudo_orig_* } { \__pseudo_copy_ctr:nn { * } { __pseudo_orig_* } \cs_undefine:c { c@ __pseudo_orig_* } } } \cs_new:Nn \__pseudo_save_label: { \int_set:Nn \l_tmpa_int {\arabic{pseudoline}} \int_compare:nF {\l_tmpa_int = \g__pseudo_last_saved_line_int} { \addtocounter{pseudoline}{-1} \refstepcounter{pseudoline} \int_gset_eq:NN \g__pseudo_last_saved_line_int \l_tmpa_int } } \DeclareDocumentCommand \pseudosavelabel { } { \__pseudo_save_label: } \cs_new:Nn \__pseudo_gsave_as:NN { \cs_gset_eq:NN #2 #1 \group_insert_after:N \cs_gset_eq:NN \group_insert_after:N #1 \group_insert_after:N #2 } \__pseudo_new_cmd:Nnn \nf { } { \normalfont } \__pseudo_new_cmd:Nnn \tn { m } { \textnormal { #1 } } \__pseudo_new_cmd:Nnn \kw { m } { \textnormal {\kwfont { #1 } } } \__pseudo_new_cmd:Nnn \cn { m } { \textnormal {\cnfont { #1 } } } \__pseudo_new_cmd:Nnn \id { m } { \textnormal {\idfont { #1 } } } \cs_new:Nn \__pseudo_b_or_bx: { \group_begin: \cs_if_exist:NT \@defaultsubs { \__pseudo_gsave_as:NN \@defaultsubs \__pseudo_defaultsubs \cs_gset_eq:NN \@defaultsubs \relax } \cs_gset:Nn \__pseudo_b_or_bx: { \fontseries{b}\selectfont } \__pseudo_b_or_bx: \cs_if_exist:NT \@defaultsubs { \cs_gset_eq:NN \__pseudo_b_or_bx: \bfseries } \group_end: \__pseudo_b_or_bx: } \cs_new:Nn \__pseudo_fmt_pr:n { \textnormal{\prfont{ #1 }} } \NewDocumentCommand \__pseudo_parse_paren_args { +d() } { \IfNoValueF { #1 } { \ensuremath{ ( #1 ) } } } \NewDocumentCommand \__pseudo_parse_bracket_or_paren_args { +o } { \IfNoValueTF { #1 } { \__pseudo_parse_paren_args } { \ensuremath{ [ #1 ] } } } \__pseudo_new_cmd:Nnn \pr { m } { \__pseudo_fmt_pr:n { #1 } \peek_catcode:NTF { ~ } { } { \__pseudo_parse_paren_args } } \cs_new:Nn \__pseudo_fmt_fn:n { \textnormal{\fnfont{ #1 }} } \__pseudo_new_cmd:Nnn \fn { m } { \__pseudo_fmt_fn:n { #1 } \peek_catcode:NTF { ~ } { } { \__pseudo_parse_bracket_or_paren_args } } \__pseudo_new_ecmd:Nnn \hd { #1 ( #2 ) } { \multicolumn{2} {\__pseudo_hd_preamble} {\__pseudo_fmt_pr:n{#1}\ensuremath{(#2)}} } \__pseudo_new_cmd:Nnn \st { +m } { \textnormal { \l__pseudo_st_left_tl {\stfont{#1}} \l__pseudo_st_right_tl } } \__pseudo_new_cmd:Nnn \ct { +m } { \textnormal { \l__pseudo_ct_left_tl {\ctfont{#1}} \l__pseudo_ct_right_tl } } \def \pseudohl { \rowcolor{\pseudohlcolor} } \__pseudo_new_dec:nn { Comment } { ct } \__pseudo_new_dec:nn { Constant } { cn } \__pseudo_new_dec:nn { Function } { fn } \__pseudo_new_dec:nn { Identifier } { id } \__pseudo_new_dec:nn { Keyword } { kw } \__pseudo_new_dec:nn { Normal } { tn } \__pseudo_new_dec:nn { Procedure } { pr } \__pseudo_new_dec:nn { String } { st } \NewDocumentCommand \eqs { } { \group_begin: \muskip_set:Nn \l_tmpa_muskip \l__pseudo_eqs_pad_tl \muskip_set:Nn \l_tmpb_muskip \l__pseudo_eqs_sep_tl \hbox_set:Nn \l_tmpa_box {\(=\)} \box_scale:Nnn \l_tmpa_box {\l__pseudo_eqs_scale_fp}{1} \mathrel{ \tex_mskip:D \l_tmpa_muskip \box_use:N \l_tmpa_box \tex_mskip:D \l_tmpb_muskip \box \l_tmpa_box \tex_mskip:D \l_tmpa_muskip } \group_end: } \cs_gset_eq:NN \c__pseudo_orig_eq_cs \= \DeclareDocumentCommand \= { m } { \tl_if_eq:nnTF { #1 } { = } { \eqs } { \c__pseudo_orig_eq_cs{#1} } } \cs_gset_eq:NN \__pseudo_eq: \= \cs_new:Nn \__pseudo_dts: { \mathinner { \ldotp \ldotp } } \NewDocumentCommand \dts { } { \__pseudo_dts: } \cs_gset_eq:NN \c__pseudo_dot_cs \. \DeclareDocumentCommand \. { m } { \tl_if_eq:nnTF { #1 } { . } { \dts } { \c__pseudo_dot_cs{#1} } } \keys_define:nn { pseudo/package } { kw .bool_gset:N = \g__pseudo_kw_bool, kw .default:n = true } \ProcessKeysOptions{ pseudo/package } \keys_define:nn { pseudo } { font .tl_set:N = \pseudofont, font .initial:n = \normalfont, hpad .tl_set:N = \l__pseudo_hpad_tl, hpad .initial:n = 0.0em, hpad .default:n = 0.3em, hsep .tl_set:N = \l__pseudo_hsep_tl, hsep .initial:n = .75em, left-margin .tl_set:N = \l__pseudo_left_margin_tl, left-margin .initial:n = 0pt, label .tl_set:N = \l__pseudo_label_tl, label .initial:n = \arabic*, label-align .code:n = \__pseudo_def_col:nn{ \pseudolabelalign }{#1}, label-align .initial:n = r, ref .tl_set:N = \thepseudoline, ref .default:n = \l__pseudo_label_tl, indent-length .tl_set:N = \l__pseudo_indent_length_tl, indent-length .initial:V = \q_no_value, indent-text .tl_set:N = \l__pseudo_indent_text_tl, indent-text .initial:n = { \pseudofont\kw{else}\ }, indent-level .int_set:N = \l__pseudo_initial_indent_level_int, kwfont .tl_set:N = \kwfont, kwfont .initial:n = \__pseudo_b_or_bx:, kw .meta:n = { font = \kwfont }, kw .value_forbidden:n = true, hl .meta:n = { bol-prepend = \pseudohl }, hl .value_forbidden:n = true, bol .tl_set:N = \l__pseudo_bol_tl, bol-append .code:n = { \tl_put_right:Nn \l__pseudo_bol_tl {#1} }, bol-prepend .code:n = { \tl_put_left:Nn \l__pseudo_bol_tl {#1} }, eol .tl_set:N = \l__pseudo_eol_tl, eol-append .code:n = { \tl_put_right:Nn \l__pseudo_eol_tl {#1} }, eol-prepend .code:n = { \tl_put_left:Nn \l__pseudo_eol_tl {#1} }, pause .meta:n = , pause .value_forbidden:n = true, cnfont .tl_set:N = \cnfont, cnfont .initial:n = \textsc, idfont .tl_set:N = \idfont, idfont .initial:n = \textit, stfont .tl_set:N = \stfont, stfont .initial:n = \textnormal, st-left .tl_set:N = \l__pseudo_st_left_tl, st-left .initial:n = ``, st-right .tl_set:N = \l__pseudo_st_right_tl, st-right .initial:n = '', prfont .tl_set:N = \prfont, prfont .initial:n = \cnfont, fnfont .tl_set:N = \fnfont, fnfont .initial:n = \idfont, ctfont .tl_set:N = \ctfont, ctfont .initial:n = \textit, ct-left .tl_set:N = \l__pseudo_ct_left_tl, ct-left .initial:n = (, ct-right .tl_set:N = \l__pseudo_ct_right_tl, ct-right .initial:n = ), hl-color .tl_set:N = \pseudohlcolor, hl-color .initial:n = black!12, dim-color .tl_set:N = \pseudodimcolor, dim-color .initial:n = \pseudohlcolor, dim .meta:n = { bol-append = \color{\pseudodimcolor}, setup-append = \color{\pseudodimcolor} }, line-height .fp_set:N = \l__pseudo_line_height_fp, line-height .initial:n = 1, start .tl_set:N = \l__pseudo_start_tl, start .initial:n = 1, preamble .code:n = \__pseudo_def_col:nn{ \pseudopreamble }{#1}, preamble .initial:n = { >{ \pseudohpad } \pseudolabelalign >{ \pseudosetup } l <{ \pseudohpad } }, setup .tl_set:N = \l__pseudo_setup_tl, setup .initial:n = { \pseudoindent \pseudofont \pseudosavelabel }, setup-append .code:n = { \tl_put_right:Nn \l__pseudo_setup_tl {#1} }, setup-prepend .code:n = { \tl_put_left:Nn \l__pseudo_setup_tl {#1} }, hd-preamble .code:n = \__pseudo_def_col:nn{ \__pseudo_hd_preamble }{#1}, hd-preamble .initial:n = { >{\pseudohpad} l <{\pseudohpad} }, prefix .tl_set:N = \pseudoprefix, prefix .initial:n = { \pseudobol \stepcounter* \pseudolabel & }, begin-tabular .tl_set:N = \l__pseudo_begin_tabular_tl, begin-tabular .initial:n = \begin{tabular}{\pseudopreamble}, end-tabular .tl_set:N = \l__pseudo_end_tabular_tl, end-tabular .initial:n = \end{tabular}, topsep .tl_set:N = \l__pseudo_topsep_tl, topsep .initial:n = { \topsep }, parskip .tl_set:N = \l__pseudo_parskip_tl, parskip .initial:n = { \parskip }, partopsep .tl_set:N = \l__pseudo_partopsep_tl, partopsep .initial:n = { \partopsep }, compact .meta:n = { compact-val = #1, compact-def = true, }, compact .default:n = true, compact-val .bool_set:N = \l__pseudo_compact_bool, compact-def .bool_set:N = \l__pseudo_compact_def_bool, eqs-scale .fp_set:N = \l__pseudo_eqs_scale_fp, eqs-scale .initial:n = 0.6785, eqs-sep .tl_set:N = \l__pseudo_eqs_sep_tl, eqs-sep .initial:n = 0.63mu, eqs-pad .tl_set:N = \l__pseudo_eqs_pad_tl, eqs-pad .initial:n = 0.28mu, } \bool_if:NT \g__pseudo_kw_bool { \keys_set:nn { pseudo } { kw } } \bool_if:NT \c__pseudo_beamer_bool { \keys_define:nn { pseudo } { pause .meta:n = { eol-append = \pause } } } \cs_new:Nn \__pseudo_keys_set_overlay:nnn { \bool_if:NT \c__pseudo_beamer_bool { \only<#1>{ \keys_set:nn { #2 } { #3 } } } } \cs_generate_variant:Nn \__pseudo_keys_set_overlay:nnn { VnV } \msg_new:nnn { pseudo } { unknown-key } { Unknown~key~'#1'~ignored. } \tl_new:N \l__pseudo_overlay_tl \keys_define:nn { pseudo } { unknown .code:n = { \group_begin: \tl_map_inline:Nn \l_keys_key_tl { \tl_if_eq:nnTF { ##1 } { < } { \int_incr:N \l_tmpa_int \int_compare:nF { \l_tmpb_int == 0 } { \int_incr:N \l_tmpa_int } \tl_set_eq:NN \l_tmpb_tl \l_tmpa_tl \tl_clear:N \l_tmpa_tl } { \tl_if_eq:nnTF { ##1 } { > } { \int_incr:N \l_tmpb_int \tl_set_eq:NN \l__pseudo_overlay_tl \l_tmpa_tl \tl_clear:N \l_tmpa_tl } { \tl_put_right:Nn \l_tmpa_tl { ##1 } } } } \bool_if:nTF { \int_compare_p:n { \l_tmpa_int == \l_tmpb_int == 1 } && \tl_if_empty_p:N \l_tmpa_tl }{ \tl_if_blank:nF{#1} { \tl_put_right:Nn \l_tmpb_tl {= #1} } \__pseudo_keys_set_overlay:VnV \l__pseudo_overlay_tl { pseudo } \l_tmpb_tl } { \msg_error:nnx { pseudo } { unknown-key } { \l_keys_path_tl } } \group_end: } } \cs_new:Nn \__pseudo_set:n { \keys_set:nn { pseudo } { #1 } } \cs_new:Nn \__pseudo_inc_indent: { \int_gincr:N \g__pseudo_indent_level_int } \cs_new:Nn \__pseudo_dec_indent: { \int_compare:nNnT \g__pseudo_indent_level_int > 0 { \int_gdecr:N \g__pseudo_indent_level_int } } \cs_new:Nn \__pseudo_eol_handle_args:nnn { \__pseudo_keys_set_overlay:nnn { #2 } { pseudo } { hl } \keys_set:nn { pseudo } { #3 } \tl_gset_eq:NN \pseudolabel \l__pseudo_label_tl \tl_gset_eq:NN \pseudobol \l__pseudo_bol_tl \tl_gset_eq:NN \pseudoeol \l__pseudo_eol_tl \tl_gset_eq:NN \pseudosetup \l__pseudo_setup_tl \IfBooleanTF { #1 } { \tl_gclear:N \g__pseudo_cur_prefix_tl } { \tl_gset_eq:NN \g__pseudo_cur_prefix_tl \pseudoprefix } } \NewDocumentCommand \__pseudo_eol_tail { s d<> +O{ } } { \__pseudo_eol_handle_args:nnn{#1}{#2}{#3} \peek_meaning_ignore_spaces:NF \end { \pseudoeol \tabularnewline \__pseudo_bol: } } \cs_new:Nn \__pseudo_eol: { \__pseudo_per_char:nnn { + } { \__pseudo_inc_indent: } { \__pseudo_per_char:nnn { - } { \__pseudo_dec_indent: } { \__pseudo_eol_tail } } } \cs_new:Nn \__pseudo_bol: { \g__pseudo_cur_prefix_tl } \NewDocumentCommand \pseudohpad { } { \skip_horizontal:n { \l__pseudo_hpad_tl - \tabcolsep } } \NewDocumentCommand \pseudoindent { } { \__pseudo_indent:N { \g__pseudo_indent_level_int } } \NewDocumentCommand \pseudoslash { } { \cs_gset_eq:NN \\ \__pseudo_eol: } \NewDocumentCommand \pseudoeq { } { \cs_gset_eq:NN \= \__pseudo_eq: } \NewDocumentCommand \pseudoset { +m } { \__pseudo_set:n { #1 } } \NewDocumentCommand \pseudodefinestyle { m +m } { \keys_define:nn { pseudo } { #1 .meta:n = { #2 } } } \NewDocumentEnvironment { pseudo } { +o s d<> +O{ } } { \group_begin: \__pseudo_gsave_as:NN \\ \c__pseudo_saved_cr_cs \__pseudo_gsave_as:NN \= \c__pseudo_saved_eq_cs \pseudoeq \int_set:Nn \g__pseudo_last_saved_line_int {\arabic{pseudoline}} \__pseudo_star_setup: \IfNoValueF { #1 } { \pseudoset { #1 } } \__pseudo_set_indent_length: \bool_if:NF \l__pseudo_compact_def_bool { \bool_set:Nn \l__pseudo_compact_bool { \mode_if_horizontal_p: && \mode_if_inner_p: } } \bool_if:nF { \l__pseudo_compact_bool } { \skip_set:Nn \l_tmpa_skip { \l__pseudo_topsep_tl + \l__pseudo_parskip_tl } \mode_if_vertical:TF { \skip_add:Nn \l_tmpa_skip { \l__pseudo_partopsep_tl } } { \unskip \par } \addvspace { \l_tmpa_skip } \noindent \skip_horizontal:n{ \dim_eval:n { \l__pseudo_left_margin_tl } } } \dim_set:Nn \tabcolsep { \l__pseudo_hsep_tl / 2 } \tl_set:Nn \arraystretch { \fp_to_decimal:n { \l__pseudo_line_height_fp } } \stepcounter{pseudoenv} \setcounter{pseudoline}{\l__pseudo_start_tl} \addtocounter{pseudoline}{-1} \tl_use:N \l__pseudo_begin_tabular_tl \tex_noalign:D { \pseudoslash \int_gset_eq:NN \g__pseudo_indent_level_int \l__pseudo_initial_indent_level_int \__pseudo_eol_handle_args:nnn{#2}{#3}{#4} } \__pseudo_bol: } { \tl_use:N \l__pseudo_end_tabular_tl \bool_if:nF { \l__pseudo_compact_bool } { \mode_if_vertical:F { \unskip \par \group_insert_after:N \@endparenv } \addvspace{ \l_tmpa_skip } } \group_end: } \pseudodefinestyle{starred}{ preamble={ >{\pseudohpad\pseudoindent\pseudofont} l <{\pseudohpad} }, prefix={\pseudobol}, } \NewDocumentEnvironment { pseudo* } { +O{} } { \begin{pseudo}[starred, #1] } { \end{pseudo} }