michal-h21 / make4ht

Build system for tex4ht
131 stars 15 forks source link

piton package #118

Closed danielezambelli closed 9 months ago

danielezambelli commented 1 year ago

Dear Michal, Due to the problems given by "minted", I have been looking for another library to handle Python sources.

I found the package "piton" which seems easy and does what I need.

Unfortunately it doesn't seem to be currently supported by make4ht: when I use it I don't get a good result.

Is it possible to support it in make4ht or is there some other Python source display package already supported by make4ht?

An MWE is as follows:

%--8<-------------------------------------
\documentclass[10pt,a4paper]{memoir}
\RequirePackage[italian]{babel}

\RequirePackage[usenames, dvipsnames]{xcolor} 
\usepackage{fontspec}
\setmainfont{STIX}[Ligatures=TeX]
\usepackage[math-style=ISO]{unicode-math}
\setmathfont{STIX Two Math}

\usepackage{piton}
\PitonOptions{line-numbers, auto-gobble, background-color = green!15,
              splittable=3, break-lines-in-Piton, indent-broken-lines,
              }

\begin{document}

Funzione quadrato in Python: \quad
\piton{def square(x): return x*x}

\vspace{3em}
Ambiente per il codice:
\begin{Piton}
def square(x):
"""Compute the square of a number"""
return x*x
\end{Piton}

\vspace{3em}
Codice in un file:
\PitonInputFile[first-line=1, last-line=20]{funzioni.py}

\end{document}
%--8<-------------------------------------

And funzioni.py:

def f_1(x):
  """Restituisce x aumentato di 3."""
  return x + 3

tabella_o(f_1, range(-6, +6))

def f_2(x):
  """Restituisce la meta' 
  di x aumentata di 3."""
  return x / 2 + 3

tabella_o(f_2, range(-8, +7))

def f_3(x):
  """Restituisce il doppio 
  di x aumentato di 3."""
  return 2 * x + 3

tabella_o(f_3, range(-8, +7))

def f_4(x):
  """Restituisce l'opposto 
  di x aumentato di 3."""
  return -x + 3

tabella_o(f_4, range(-8, +7))

Thanks for your attention.

michal-h21 commented 1 year ago

Dear Daniele,

this is a work in progress version of piton.4ht, which seems to work more or less:

\ExplSyntaxOn

\cs_set_protected:Npn \__piton_begin_line: #1 \__piton_end_line:
  {
    \group_begin:
    %\HtmlParOff
    \g__piton_begin_line_hook_tl
    \int_gzero:N \g__piton_indentation_int
     \bool_if:NTF \l__piton_slim_bool
       { \hcoffin_set:Nn \l_tmpa_coffin }
       {
         \clist_if_empty:NTF \l__piton_bg_color_clist
           {
             \vcoffin_set:Nnn \l_tmpa_coffin
               { \dim_eval:n { \linewidth - \l__piton_left_margin_dim } }
           }
           {
             \vcoffin_set:Nnn \l_tmpa_coffin
               { \dim_eval:n { \linewidth - \l__piton_left_margin_dim - 0.5 em } }
           }
       }
       {
         \language = -1
         \raggedright
         \strut
         \HCode{<code>}\NoFonts\__piton_replace_spaces:n { #1 }\EndNoFonts\HCode{</code>}
         %\ifvmode\IgnorePar\fi\EndP\HCode{<code~style="white-space:pre">}\NoFonts\__piton_replace_spaces:n { #1 }\EndNoFonts\HCode{</code>}
         %\__piton_replace_spaces:n { #1 }
         \strut \hfil
       }
    %\ifvmode\IgnorePar\fi\EndP\HCode{<code>}\NoFonts \__piton_replace_spaces:n { #1 }\EndNoFonts\HCode{</code>}
     \hbox_set:Nn \l_tmpa_box
       {
         \skip_horizontal:N \l__piton_left_margin_dim
%\ifvmode\IgnorePar\fi\EndP
\HCode{<span~style="display:none">}
         \bool_if:NT \l__piton_line_numbers_bool
           {
             \bool_if:NF \l__piton_all_line_numbers_bool
               { \tl_if_eq:nnF  { #1 } { \PitonStyle {Prompt}{} } } % corrected 2023/04/10
               \__piton_print_number:
           }
\HCode{</span>}
         \clist_if_empty:NF \l__piton_bg_color_clist
           {
             \dim_compare:nNnT \l__piton_left_margin_dim = \c_zero_dim
                {
                  \bool_if:NF \l__piton_left_margin_auto_bool
                    { \skip_horizontal:n { 0.5 em } }
                }
           }
         \coffin_typeset:Nnnnn \l_tmpa_coffin T l \c_zero_dim \c_zero_dim
       }
     \dim_compare:nNnT { \box_wd:N \l_tmpa_box } > \g__piton_width_dim
       { \dim_gset:Nn \g__piton_width_dim { \box_wd:N \l_tmpa_box } }
     \box_set_dp:Nn \l_tmpa_box { \box_dp:N \l_tmpa_box + 1.25 pt }
     \box_set_ht:Nn \l_tmpa_box { \box_ht:N \l_tmpa_box + 1.25 pt }
     \clist_if_empty:NTF \l__piton_bg_color_clist
       { \box_use_drop:N \l_tmpa_box }
       {
         \vbox_top:n
           {
             % \hbox:n
             %   {
             %     \__piton_color:N \l__piton_bg_color_clist
             %     \vrule height \box_ht:N \l_tmpa_box
             %            depth \box_dp:N \l_tmpa_box
             %            width \l__piton_width_on_aux_dim
             %   }
             \skip_vertical:n { - \box_ht_plus_dp:N \l_tmpa_box }
             \box_set_wd:Nn \l_tmpa_box \l__piton_width_on_aux_dim
             \box_use_drop:N \l_tmpa_box
           }
       }
     \vspace { - 2.5 pt }
% \HtmlParOn
    \group_end:
    \tl_gclear:N \g__piton_begin_line_hook_tl
  }

\NewConfigure{Piton}{2}
\pend:def\__piton_pre_env:{\a:Piton}
\append:def\__piton_width_to_aux:{\b:Piton}

\ExplSyntaxOff

\def\endundeclaredcolor{\HCode{</span>}}
\def\:undeclaredcolor[#1]#2{\o:@undeclaredcolor:[#1]{#2}
\HCode{<span style="color:\##2">}\aftergroup\endundeclaredcolor
}

\Configure{Piton}{\ifvmode\IgnorePar\fi\EndP\HCode{<pre class="piton">}\HtmlParOff\NoFonts\Configure{newline}{\HCode{\Hnewline}}%
\HLet\@undeclaredcolor\:undeclaredcolor%
}
{\EndNoFonts\HCode{</pre>}\HtmlParOn}
%\Css{pre.piton{font-family: monospace,monospace; text-align:left; clear:both; }}
\Hinput{piton}
\endinput

BTW, what problem do you have with Minted?

danielezambelli commented 1 year ago

By putting piton.4ht in the dir: "/usr/share/texlive/texmf-dist/tex/generic/tex4ht/" it is not seen, but if I put it in: "/~/texmf/tex/generic/" it is used.

Compilation with:

make4ht piton.tex -f html5-common_domfilters -c ml_make4ht -l -u -s -d ./html/mathjax "mathjax, 3, sec-filename, fn-in, blind"

raises the following error:

[ERROR] htlatex: Compilation errors in the htlatex run.
[ERROR] htlatex: Filename Line Message.
[ERROR] htlatex: ./piton.tex 28 Undefined control sequence.

The result is quite good, but it does not have the line numbers that, in an instructional text, are used to comment on the code.

Thanks for your work.

michal-h21 commented 1 year ago

Can you post the output with the -a debug -m draft options? I am interested in what control sequence is undefined. This is still pretty unrefined solution, so for example line numbers are hidden intentionally for easier debugging. They will work in the final version.

danielezambelli commented 1 year ago

make4ht piton.tex -f html5-common_domfilters -a debug -m draft -c ml_make4ht -l -u -s -d ./html/mathjax "mathjax, 3, sec-filename, fn-in, blind"

[INFO]    mkparams: Output dir: ./html/mathjax
[INFO]    mkparams: Compiler: dvilualatex
[INFO]    mkparams: Latex options: -jobname='piton'  -shell-escape
[INFO]    mkparams: tex4ht.sty: ml_make4ht,mathjax, 3, sec-filename, fn-in, blind,charset=utf-8
[INFO]    mkparams: tex4ht:  -cmozhtf -utf8
[INFO]    mkparams: build_file: piton.mk4
[INFO]    mkparams: Output format: html5
[INFO]    mkparams: Extension: -common_domfilters
[STATUS]  make4ht: Conversion started
[STATUS]  make4ht: Input file: piton.tex
[INFO]    mkutils: Cannot open config file      piton.mk4
[INFO]    make4ht-lib: setting param correct_exit
[INFO]    make4ht-lib: setting param ext
[INFO]    make4ht-lib: Adding:  ext     dvi
[INFO]    htlatex: LaTeX call: dvilualatex --interaction=errorstopmode -jobname='piton'  -shell-escape '\makeatletter\def\HCode{\futurelet\HCode\HChar}\def\HChar{\ifx"\HCode\def\HCode"##1"{\Link##1}\expandafter\HCode\else\expandafter\Link\fi}\def\Link#1.a.b.c.{\AddToHook{class/before}{\RequirePackage[#1,html]{tex4ht}}\let\HCode\documentstyle\def\documentstyle{\let\documentstyle\HCode\expandafter\def\csname tex4ht\endcsname{#1,html}\def\HCode####1{\documentstyle[tex4ht,}\@ifnextchar[{\HCode}{\documentstyle[tex4ht]}}}\makeatother\HCode ml_make4ht,mathjax, 3, sec-filename, fn-in, blind,charset=utf-8,html5.a.b.c.\input "\detokenize{piton.tex}"'
This is LuaTeX, Version 1.15.0 (TeX Live 2022/Debian) 
 system commands enabled.
LaTeX2e <2022-11-01> patch level 1
L3 programming layer <2023-01-16> (./piton.tex
(/usr/share/texlive/texmf-dist/tex/generic/tex4ht/tex4ht.sty)
(/usr/share/texlive/texmf-dist/tex/latex/memoir/memoir.cls
Document Class: memoir 2022/11/17 v3.7.19 configurable book, report, article do
cument class
(/usr/share/texlive/texmf-dist/tex/generic/tex4ht/usepackage.4ht)

[...]

(/usr/share/texlive/texmf-dist/tex/generic/tex4ht/unicode.4ht)
(/usr/share/texlive/texmf-dist/tex/generic/tex4ht/html4-math.4ht)
(/usr/share/texlive/texmf-dist/tex/generic/tex4ht/html5.4ht)) (./piton.aux)
(/usr/share/texlive/texmf-dist/tex/latex/base/ts1cmr.fd))
(/usr/share/texmf/tex/latex/lm/t1lmtt.fd)
! Undefined control sequence.
\__piton_begin_line: ..._piton_begin_line_hook_tl 
                                                  \int_gzero:N \g__piton_ind...

l.28 \end{Piton}
michal-h21 commented 1 year ago

Ah, so maybe you have an older version of the package? Anyway, here is my current progress. I haven't had much time for it unfortunately, but at least colors seems to work in inline code chunks:

\ExplSyntaxOn

\cs_set_protected:Npn \__piton_begin_line: #1 \__piton_end_line:
% \protected\def\:tempa #1\__piton_end_line:
  {
    \group_begin:
    %\HtmlParOff
    \csname g__piton_begin_line_hook_tl\endcsname
    \int_gzero:N \g__piton_indentation_int
     \bool_if:NTF \l__piton_slim_bool
       { \hcoffin_set:Nn \l_tmpa_coffin }
       {
         \clist_if_empty:NTF \l__piton_bg_color_clist
           {
             \vcoffin_set:Nnn \l_tmpa_coffin
               { \dim_eval:n { \linewidth - \l__piton_left_margin_dim } }
           }
           {
             \vcoffin_set:Nnn \l_tmpa_coffin
               { \dim_eval:n { \linewidth - \l__piton_left_margin_dim - 0.5 em } }
           }
       }
       {
         \language = -1
         \raggedright
         \strut
         \HCode{<code>}\NoFonts\__piton_replace_spaces:n { #1 }\EndNoFonts\HCode{</code>}
         %\ifvmode\IgnorePar\fi\EndP\HCode{<code~style="white-space:pre">}\NoFonts\__piton_replace_spaces:n { #1 }\EndNoFonts\HCode{</code>}
         %\__piton_replace_spaces:n { #1 }
         \strut \hfil
       }
    %\ifvmode\IgnorePar\fi\EndP\HCode{<code>}\NoFonts \__piton_replace_spaces:n { #1 }\EndNoFonts\HCode{</code>}
     \hbox_set:Nn \l_tmpa_box
       {
         \skip_horizontal:N \l__piton_left_margin_dim
%\ifvmode\IgnorePar\fi\EndP
\HCode{<span~style="display:none">}
         \bool_if:NT \l__piton_line_numbers_bool
           {
             \bool_if:NF \l__piton_all_line_numbers_bool
               { \tl_if_eq:nnF  { #1 } { \PitonStyle {Prompt}{} } } % corrected 2023/04/10
               \__piton_print_number:
           }
\HCode{</span>}
         \clist_if_empty:NF \l__piton_bg_color_clist
           {
             \dim_compare:nNnT \l__piton_left_margin_dim = \c_zero_dim
                {
                  \bool_if:NF \l__piton_left_margin_auto_bool
                    { \skip_horizontal:n { 0.5 em } }
                }
           }
         \coffin_typeset:Nnnnn \l_tmpa_coffin T l \c_zero_dim \c_zero_dim
       }
     \dim_compare:nNnT { \box_wd:N \l_tmpa_box } > \g__piton_width_dim
       { \dim_gset:Nn \g__piton_width_dim { \box_wd:N \l_tmpa_box } }
     \box_set_dp:Nn \l_tmpa_box { \box_dp:N \l_tmpa_box + 1.25 pt }
     \box_set_ht:Nn \l_tmpa_box { \box_ht:N \l_tmpa_box + 1.25 pt }
     \clist_if_empty:NTF \l__piton_bg_color_clist
       { \box_use_drop:N \l_tmpa_box }
       {
         \vbox_top:n
           {
             % \hbox:n
             %   {
             %     \__piton_color:N \l__piton_bg_color_clist
             %     \vrule height \box_ht:N \l_tmpa_box
             %            depth \box_dp:N \l_tmpa_box
             %            width \l__piton_width_on_aux_dim
             %   }
             \skip_vertical:n { - \box_ht_plus_dp:N \l_tmpa_box }
             \box_set_wd:Nn \l_tmpa_box \l__piton_width_on_aux_dim
             \box_use_drop:N \l_tmpa_box
           }
       }
     \vspace { - 2.5 pt }
% \HtmlParOn
    \group_end:
    \tl_gclear:N \g__piton_begin_line_hook_tl
  }

\NewConfigure{pitonline}{3}
\NewConfigure{pitonnumber}{2}
\protected\def\:tempa #1\__piton_end_line:{
  \group_begin:
  % we set line in a box, because otherwise lines are collapsed sometimes
  \hbox_set:Nn \l_tmpa_box{
  \a:pitonline
  \a:pitonnumber
  \bool_if:NT \l__piton_line_numbers_bool
  {
    \bool_if:NF \l__piton_all_line_numbers_bool
    { \tl_if_eq:nnF  { #1 } { \PitonStyle {Prompt}{} } } % corrected 2023/04/10
    \__piton_print_number:
  }
  \b:pitonnumber
  \language = -1
  \raggedright
  \strut
  % \HCode{<code>}
  \b:pitonline
  \NoFonts
  \__piton_replace_spaces:n { #1 }
  \EndNoFonts
  % 
  \c:pitonline
  }
  \box_use_drop:N \l_tmpa_box
  \group_end:
}
\HLet\__piton_begin_line:\:tempa

\NewConfigure{piton}{2}
\pend:def\__piton_pre_env:{\a:piton}
\append:def\__piton_width_to_aux:{\b:piton}

\NewDocumentCommand { \:__piton_piton_standard } { m }
  {
    \group_begin:
    \ttfamily
    \a:pitonline\b:pitonline
    \automatichyphenmode = 1
    \cs_set_eq:NN \\ \c_backslash_str
    \cs_set_eq:NN \% \c_percent_str
    \cs_set_eq:NN \{ \c_left_brace_str
    \cs_set_eq:NN \} \c_right_brace_str
    \cs_set_eq:NN \$ \c_dollar_str
    \cs_set_eq:cN { ~ } \space
    \cs_set_protected:Npn \__piton_begin_line: { }
    \cs_set_protected:Npn \__piton_end_line: { }
    \tl_set:Nx \l_tmpa_tl
      {
        \lua_now:e
          { piton.ParseBis('\l__piton_language_str',token.scan_string()) }
          { #1 }
      }
    \bool_if:NTF \l__piton_show_spaces_bool
      { \regex_replace_all:nnN { \x20 } { ␣ } \l_tmpa_tl } % U+2423
      { 
        \bool_if:NT \l__piton_break_lines_in_piton_bool
          { \regex_replace_all:nnN { \x20 } { \x20 } \l_tmpa_tl }
      }
    \l_tmpa_tl
    \c:pitonline
    \group_end:
  }

\HLet\__piton_piton_standard\:__piton_piton_standard

\ExplSyntaxOff

\def\:endundeclaredcolor{\HCode{</span>}}
\def\:undeclaredcolor[#1]#2{\o:@undeclaredcolor:[#1]{#2}
\HCode{<span style="color:\##2">}\aftergroup\:endundeclaredcolor
}

\Configure{piton}{\ifvmode\IgnorePar\fi\EndP\HCode{<pre class="piton">}\HtmlParOff\NoFonts\Configure{newline}{\HCode{\Hnewline}}%
}
{\EndNoFonts\HCode{</pre>}\HtmlParOn}

\Configure{pitonline}{\HLet\@undeclaredcolor\:undeclaredcolor}{\HCode{<code style="white-space:pre">}}{\HCode{</code>}}
\Configure{pitonnumber}{\HCode{<span class="linenumber">}}{\HCode{</span>}}
\Css{pre.piton{font-family: monospace,monospace; font-size:1rem; text-align:left; clear:both; }}
\Css{.piton .linenumber{font-size: small; margin-right: 1em;}}
\Hinput{piton}
\endinput
michal-h21 commented 1 year ago

Here is another version of piton.4ht. It seems to work nicely. It supports syntax highlighting and fixes spurious blank lines:

\ExplSyntaxOn

\NewConfigure{pitonline}{3}
\NewConfigure{pitonnumber}{2}
\protected\def\:tempa #1\__piton_end_line:{
  \:pitonendignorelines\glet\:pitonendignorelines\relax
  \group_begin:
  % we set line in a box, because otherwise lines are collapsed sometimes
  \hbox_set:Nn \l_tmpa_box{
  \a:pitonline
  \a:pitonnumber
  \bool_if:NT \l__piton_line_numbers_bool
  {
    \bool_if:NF \l__piton_all_line_numbers_bool
    { \tl_if_eq:nnF  { #1 } { \PitonStyle {Prompt}{} } } % corrected 2023/04/10
    \__piton_print_number:
  }
  \b:pitonnumber
  \language = -1
  \raggedright
  \strut
  % \HCode{<code>}
  \b:pitonline
  \NoFonts
  \__piton_replace_spaces:n { #1 }
  \EndNoFonts
  % 
  \c:pitonline
  }
  \box_use_drop:N \l_tmpa_box
  \group_end:
}
\HLet\__piton_begin_line:\:tempa

\NewConfigure{piton}{2}

% Piton environments and file input produces extra blank line at the start
% we use TeX4ht specials to remove them
\gdef\:pitonendignorelines{}
\pend:def\__piton_pre_env:{\a:piton
  \ht:special{t4ht@[}% ignore next linebreak, to preven spurious blank line at the beginning of listings
  \gdef\:pitonendignorelines{\ht:special{t4ht@]}}
}
\append:def\__piton_width_to_aux:{\b:piton}

\NewDocumentCommand { \:__piton_piton_standard } { m }
  {
    \group_begin:
    \ttfamily
    \a:pitonline\b:pitonline
    \automatichyphenmode = 1
    \cs_set_eq:NN \\ \c_backslash_str
    \cs_set_eq:NN \% \c_percent_str
    \cs_set_eq:NN \{ \c_left_brace_str
    \cs_set_eq:NN \} \c_right_brace_str
    \cs_set_eq:NN \$ \c_dollar_str
    \cs_set_eq:cN { ~ } \space
    \cs_set_protected:Npn \__piton_begin_line: { }
    \cs_set_protected:Npn \__piton_end_line: { }
    \tl_set:Nx \l_tmpa_tl
      {
        \lua_now:e
          { piton.ParseBis('\l__piton_language_str',token.scan_string()) }
          { #1 }
      }
    \bool_if:NTF \l__piton_show_spaces_bool
      { \regex_replace_all:nnN { \x20 } { ␣ } \l_tmpa_tl } % U+2423
      { 
        \bool_if:NT \l__piton_break_lines_in_piton_bool
          { \regex_replace_all:nnN { \x20 } { \x20 } \l_tmpa_tl }
      }
      % our extra code to remove the space glyph
    \regex_replace_all:nnN { \x20 } { \c { __piton_breakable_space: } } \l_tmpa_tl
    \l_tmpa_tl
    \c:pitonline
    \group_end:
  }

\HLet\__piton_piton_standard\:__piton_piton_standard

\NewDocumentCommand { \:__piton_piton_verbatim } { v }
  {
    \group_begin:
    \ttfamily
    \a:pitonline\b:pitonline
    \automatichyphenmode = 1
    \cs_set_protected:Npn \__piton_begin_line: { }
    \cs_set_protected:Npn \__piton_end_line: { }
    \tl_set:Nx \l_tmpa_tl
      {
        \lua_now:e
          { piton.Parse('\l__piton_language_str',token.scan_string()) }
          { #1 }
      }
    \bool_if:NT \l__piton_show_spaces_bool
      { \regex_replace_all:nnN { \x20 } { ␣ } \l_tmpa_tl } % U+2423
    % our extra code to remove the space glyph
    \regex_replace_all:nnN { \x20 } { \c { __piton_breakable_space: } } \l_tmpa_tl
    \l_tmpa_tl
    \c:pitonline
    \group_end:
  }

\HLet\__piton_piton_verbatim\:__piton_piton_verbatim

\ExplSyntaxOff

% handle \color commands
% piton already uses hexadecimal colors, so we don't need to convert them for use in CSS
\def\:endundeclaredcolor{\HCode{</span>}}
\def\:undeclaredcolor[#1]#2{\o:@undeclaredcolor:[#1]{#2}
\HCode{<span style="color:\##2">}\aftergroup\:endundeclaredcolor
}

\Configure{piton}{%
  \ifvmode\IgnorePar\fi\EndP\HCode{<pre class="piton">}\HtmlParOff\NoFonts%
  \Configure{newline}{\HCode{\Hnewline}}% don't insert any special tags for newlines, only newline characters
}
{\EndNoFonts\HCode{</pre>}\HtmlParOn}

\Configure{pitonline}{\HLet\@undeclaredcolor\:undeclaredcolor}{\HCode{<code style="white-space:pre">}}{\HCode{</code>}}
\Configure{pitonnumber}{\HCode{<span class="linenumber">}}{\HCode{</span>}}
\Css{pre.piton{font-family: monospace,monospace; font-size:1rem; text-align:left; clear:both; }}
\Css{.piton .linenumber{font-size: small; margin-right: 1em;}}
\Hinput{piton}
\endinput