¿Cómo puedo resaltar una sesión GAP interactiva así?

¿Cómo puedo resaltar una sesión GAP interactiva así?

Supongamos que quiero componer una sesión de pantalla en algún lenguaje de programación (GAP en mi caso, pero también podría ser Python, BASH o cualquier otro con un mensaje de lectura interactivo). Entonces en mi pantalla, podría tener algo como esto:

gap> for i in [1..10] do
>   Print(i, ":");
> od;
1:2:3:4:5:6:7:8:9:10:
gap> 2^10;
1024
gap> 1/0;
Error, Rational operations: <divisor> must not be zero
not in any function at line 5 of *stdin*
you can replace <divisor> via 'return <divisor>;'
brk> 2^10;
1024
brk>

Es decir, hay un símbolo del sistema gap>, después del cual el usuario ingresa una entrada de varias líneas. Después de eso viene una línea de salida, luego otro mensaje gap>. Esto se repite hasta que un comando genera un error, momento en el que el mensaje cambia a brk>.

Me gustaría usar ellistingspaquete (u otra cosa) a

  1. colorea las indicaciones gap>, >y brk>; digamos, azul y rojo;
  2. resalte palabras clave como for, doy od; digamos, haciéndolos audaces;
  3. perosoloresalte las palabras clave en líneas que comienzan con un mensaje, por lo tanto, no dentro de la salida de mis comandos.

El último punto es el que me está causando problemas. No pude encontrar una manera de hacer eso. El resultado suele ser bastante feo cuando palabras como and, noty inse resaltan como palabras clave en, por ejemplo, un mensaje de error.

Se han hecho preguntas similares antes, pero de las que logré encontrar, ninguna preguntó exactamente esto, respectivamente. Obtuve una respuesta que hace lo que quiero.

Para que conste, aquí está la definición de idioma que estoy usando por ahora:

\lstdefinelanguage{BRECHA}{%
    morekeywords=[2]{y,break,continuar,do,elif,else,end,fail,false,fi,for,%
        función,si,en,local,mod,no,od,o,rec,repetir,retorno,entonces,verdadero,%
        hasta,mientras},%
    moredelim=[s][\color{azul}]{espacio}{>},%
    moredelim=[s][\color{rojo}]{brk}{>},%
    %moredelim=*[l][\color{azul}]{espacio>},%
    %moredelim=*[l][\color{rojo}]{brk>},%
    sensible = verdadero,%
    máscomentario=[l]\#,%
    máscadena=[b]',%
    máscadena=[b]",%
    }%

PD: Para ilustrar lo que quiero, considere esta imagen que muestra cómo se vería mi ejemplo anterior (además de lo que describí anteriormente, también configuro todas las entradas del usuario en cursiva):

ingrese la descripción de la imagen aquí

Respuesta1

Esta listingsrespuesta tiene aproximadamente un año de retraso, pero creo que cubre todos sus requisitos.

Editar: se corrigió un error relacionado con las "palabras clave" que aparecían en medio de una línea.

Salida deseada

salida deseada

Salida obtenida

salida obtenida

Código

\documentclass[a4paper]{article}
\usepackage{xcolor}
\usepackage{textcomp}
\usepackage{listings}

\makeatletter

% switch to remember whether a prompt was found on the current line
\newif\ifprompt@GAP@
% switch to flag whether a prompt `keyword' is an bona fide GAP prompt
\newif\iftoolateforprompt@GAP@

% style of GAP keywords
\definecolor{GAPkeywords}{RGB}{077,145,021}
\newcommand\GAPkeywordstyle{\color{GAPkeywords}}

% font shape of GAP input lines 
\newcommand\GAPinputfshape\slshape

\lstdefinelanguage{GAP}
{%
  basicstyle =\ttfamily,
  alsoletter=>,
  morekeywords=[2]{%
    and,break,continue,do,elif,else,end,fail,false,fi,for,function,if,in,%
    local,mod,not,od,or,rec,repeat,return,then,true,until,while,
  },%
  keywordstyle=[2]\Process@GAP@keywords,
  morekeywords=[3]{gap>,>},
  keywordstyle=[3]\Process@GAP@prompt{blue},
  morekeywords=[4]{brk>},
  keywordstyle=[4]\Process@GAP@prompt{red},
  sensitive=true,%
  upquote=true,% <--- for straight single quotes
  showstringspaces=false,
  morecomment=[l]\#,
  morestring=[b]',
  morestring=[b]",
}%

% only highlight keywords if a prompt has occured on the current line
\newcommand\Process@GAP@keywords{\ifprompt@GAP@\GAPkeywordstyle\fi}

\newcommand\Process@GAP@prompt[1]
{%
  \iftoolateforprompt@GAP@%
  \else%
      \color{#1}\upshape% customise the style of your > and gap> prompts here
      \global\prompt@GAP@true%
      \aftergroup\GAPinputfshape% we trigger slanted shape after > or gap>
  \fi%
}

% Hook into InitVarsEOL (some hook executed right after an EOL) to:
% - reset the \ifprompt@GAP@ and \iftoolateforprompt@GAP@ switches
% - reset the font shape to \upshape
\lst@AddToHook{InitVarsEOL}%
{%
  \global\prompt@GAP@false%
  \global\toolateforprompt@GAP@false%
  \upshape%
}

% Hook into PostOutput to signal that a GAP prompt
% can no occur on the current line
\lst@AddToHook{PostOutput}{\global\toolateforprompt@GAP@true}

\makeatother

\begin{document}
\begin{lstlisting}[language=GAP]
gap> for i in [1..10] do
>   Print(i, ":");
> od;
1:2:3:4:5:6:7:8:9:10:
gap> 2^10;
1024
gap> 1/0;
Error, Rational operations: <divisor> must not be zero
not in any function at line 5 of *stdin*
you can replace <divisor> via 'return <divisor>;'
brk> 2^10;
1024
brk>
\end{lstlisting}
\end{document}

Respuesta2

El único inconveniente es que proceso palabras completas, no subpalabras. Por tanto, od;es una palabra separada de od. Eso se puede superar, pero no en este MWE. Copié el resultado de la sesión sin formato (sin formato) en el archivosesión.eny partí de allí.

\documentclass[12pt]{article}
\makeatletter%
\let\protectededef\protected@edef
\makeatother%

\parindent 0in
\renewcommand{\encodingdefault}{T1}
\usepackage{color}
\usepackage{readarray}
\usepackage{verbatimbox}
\usepackage{ifthen}
\catcode`^=12
\definecolor{darkgreen}{rgb}{0,0.5,0}
\newcounter{rowindex}\newcounter{wordindex}%

\newcommand\displaysource[1]{%
  \sffamily%
  \readdef{#1}{\x}%
  \setcounter{rowindex}{0}%
  \whiledo{\value{rowindex} < \nrecords}{%
    \addtocounter{rowindex}{1}%
    \getargsC{\csname record\roman{rowindex}\endcsname}%
    \ifthenelse{\equal{\argi}{>}  \OR%
                \equal{\argi}{gap>}  \OR%
                \equal{\argi}{brk>}}%
                {\def\userin{\itshape}}{\def\userin{\upshape}}%
    \setcounter{wordindex}{0}%
    \whiledo{\value{wordindex} < \narg}{%
      \addtocounter{wordindex}{1}%
      \protectededef\thisword{\csname arg\roman{wordindex}\endcsname}%
      \ifthenelse{\equal{\thisword}{gap>}  \OR%
                  \equal{\thisword}{>}}%
        {%
          \upshape\textcolor{blue}{\thisword~}%
        }{%
          \ifthenelse{\equal{\thisword}{brk>}}%
            {%
              \textcolor{red}{brk>~}%
            }{%
              \userin%
              \ifthenelse{\equal{\thisword}{for}  \OR%
                          \equal{\thisword}{in}  \OR%
                          \equal{\thisword}{do}  \OR%
                          \equal{\thisword}{od}  \OR%
                          \equal{\thisword}{od;}}%
              {%
                \ifthenelse{\equal{\userin}{\itshape}}%
                  {%
                    \textcolor{darkgreen}{\thisword~}%
                  }{%
                    \thisword~%
                  }%
              }{%
                \thisword~%
              }
            }%
        }%
    }%
    \\%
  }%
  \rmfamily%
}
\begin{document}

\displaysource{session.in}

\end{document}

ingrese la descripción de la imagen aquí

información relacionada