Как можно выделить интерактивную сессию GAP таким образом?

Как можно выделить интерактивную сессию GAP таким образом?

Предположим, я хочу набрать сеанс экрана на каком-то языке программирования (в моем случае это GAP, но это может быть Python, BASH или что-то еще с интерактивным приглашением для чтения). Таким образом, на моем экране может быть что-то вроде этого:

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>

То есть, есть командная строка gap>, после которой пользователь вводит многострочный ввод. После этого следует строка вывода, затем еще одна строка приглашения gap>. Это повторяется, пока команда не вызовет ошибку, после чего приглашение изменится на brk>.

Я хотел бы использоватьlistingsпакет (или что-то еще) для

  1. раскрасьте подсказки gap>, >, и brk>; скажем, синим и красным;
  2. выделите ключевые слова, например for, do, и od; например, сделав их жирным шрифтом;
  3. нотольковыделить ключевые слова в строках, начинающихся с подсказки, следовательно, не внутри вывода моих команд.

Последний пункт — это тот, который вызывает у меня проблемы. Я не смог придумать, как это сделать. Результат часто бывает довольно уродливым, когда слова типа and, not, и inвыделяются как ключевые слова, например, в сообщении об ошибке.

Похожие вопросы уже задавались, но из тех, что мне удалось найти, ни один не содержал именно этого, соответственно, ни один не получил ответа, который делает то, что мне нужно.

Для справки, вот определение языка, которое я сейчас использую:

\lstdefinelanguage{GAP}{%
    morekeywords=[2]{и,прервать,продолжить,сделать,elif,иначе,конец,неудача,ложь,fi,для,%
        функция, если, в, локальном, mod, не, od, или, rec, повтор, возврат, то, истина, %
        пока},%
    moredelim=[s][\color{blue}]{gap}{>},%
    moredelim=[s][\color{red}]{brk}{>},%
    %moredelim=*[l][\color{blue}]{gap>},%
    %moredelim=*[l][\color{red}]{brk>},%
    чувствительный=истина,%
    morecomment=[l]\#,%
    больше строк=[b]',%
    больше строк=[b]",%
    }%

PS: Чтобы проиллюстрировать то, что я хочу, рассмотрите это изображение, показывающее, как может выглядеть мой пример сверху (в дополнение к тому, что я описал выше, я также выделил все пользовательские вводы курсивом):

введите описание изображения здесь

решение1

Этот listingsответ запоздал примерно на год, но я считаю, что он охватывает все ваши требования.

Редактировать: исправлена ​​ошибка, связанная с появлением подсказок «ключевые слова» в середине строки.

Желаемый результат

желаемый результат

Выход получен

выход получен

Код

\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}

решение2

Единственный недостаток в том, что я обрабатываю целые слова, а не подслова. Таким образом, od;это отдельное слово изod . Это можно преодолеть, но не в этом MWE. Я скопировал ваш сырой (неотформатированный) вывод сеанса в файлсессия.ви пошло оттуда.

\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}

введите описание изображения здесь

Связанный контент