Skip to content

Inserire il testo con le sequenze di escape del colore del terminale

Se trovi qualcosa che non capisci puoi lasciarlo nella sezione commenti e ti risponderemo il prima possibile.

Soluzione:

Ecco un'approssimazione di quanto richiesto.

TeX non fornisce un modo per inserire file binari in modo affidabile, ma per pdfTeX c'è l'opzione pdffiledump che permette di leggere un file binario, espresso come una sequenza di numeri esadecimali. Per prima cosa dobbiamo preprocessare questa stringa per ottenere una sequenza di caratteri, ciascuno di codice 12 ([email protected]).

Poi analizziamo questa stringa di input ([email protected]), costruendo la riga di uscita corrente in un elenco di token [email protected] (per ragioni tecniche in ordine inverso). A seconda del carattere di ingresso corrente, gli elementi dell'elenco di token in uscita vengono aggiunti, rimossi o stampati e ne viene avviato uno nuovo.

Ogni volta che un carattere di escape (x1B), il carattere successivo determina il tipo di sequenza di escape. Se si tratta di un carattere [segue una serie di numeri di parametri e un carattere finale che specifica il tipo di uscita del terminale. Si passa quindi a questo tipo e al numero di parametro dato per modificare le variabili globali per gli attributi di visualizzazione correnti ([email protected]@termout). Queste ultime vengono prese in considerazione ogni volta che viene aggiunto un nuovo carattere alla riga di uscita corrente.

Il codice completo:

documentclass{article}

usepackage{xcolor}
usepackage{pdftexcmds}
usepackage{mdframed}
usepackage[utf8]{inputenc}
usepackage{textcomp}

makeatletter
endlinechar=-1

% Manipulation of current output line

newif[email protected]@

def[email protected]{}

def[email protected]@push#1{
    [email protected]@
        def[email protected]{}
    fi
    xdef[email protected]{
        {{noexpandstrut
          noexpandcolor{[email protected][email protected]@!75!whitefi}
          unexpanded{#1}}}
        unexpandedexpandafter{[email protected]}
    }
    [email protected]@false
}

def[email protected]@pop{
    xdef[email protected]{expandafterunexpandedexpandafterexpandafterexpandafter
        {expandafter@gobble[email protected]}}
    [email protected]@false
}

def[email protected]@print{
    leavevmode
    expandafter[email protected]@reverseexpandafter@sep[email protected]{}@end
}
def[email protected]@reverse#1@sep#2#3@end{
    [email protected]{#3}{
        #2#1
    }{
        [email protected]@reverse#2#1@sep#3@end
    }
}

% Display attributes

def[email protected]{}
def[email protected]@fgcolor{lightgray}
newif[email protected]@

% Input parsing

newcount[email protected]@a
newcount[email protected]@b

begingroup
count0=0relax
loop
    lccode`*=count0relax
    lowercase{
        expandaftergdefcsname [email protected]@[email protected]numbercount0endcsname{*}
    }
    advancecount0 by 1relax
ifnumcount0<256relax
repeat
endgroup

def[email protected]#1#2{
    [email protected]{#1}{}{
        csname [email protected]@[email protected]number"#1#2endcsname
        [email protected]
    }
}

def[email protected]#1{
    % End of input
    [email protected]@eq#1relax{
        @@par
        [email protected]{}
    }{}
    % Escape sequence
    [email protected]@eq#1[email protected]@char{
        [email protected][email protected]@esc
    }{}
    % Newline
    [email protected]@eq#1[email protected]@char{
        [email protected]@print
        @@par
        [email protected][email protected]
    }{}
    % Carriage return
    [email protected]@eq#1[email protected]@char{
        [email protected]@true
        [email protected][email protected]
    }{}
    [email protected]@eq#1[email protected]@char{
        [email protected]@pop
        [email protected][email protected]
    }{}
    [email protected]@eq#1[email protected]@char{
        [email protected]@push{ }
        [email protected][email protected]
    }{}
    [email protected]@range{`#1}{194}{223}{
        [email protected]{[email protected]@[email protected]#1}
    }{}
    [email protected]@range{`#1}{224}{239}{
        [email protected]{[email protected]@[email protected]#1}
    }{}
    [email protected]@range{`#1}{240}{244}{
        [email protected]{[email protected]@[email protected]#1}
    }{}
    [email protected]{
        [email protected]@push{#1}
        [email protected]
    }
}

def[email protected]@esc#1{
    [email protected]@eq#1[{
        [email protected]@csi
    }{
        GenericWarning{}{Warning: Ignored unknown escape sequence of type `#1'}
        [email protected]
    }
}

def[email protected]@csi#1{
    [email protected]@b=-1relax
    % Is private sequence?
    [email protected]@eq#1?{
        afterassignment[email protected]@[email protected]
        [email protected]@a=0
    }{
        afterassignment[email protected]@[email protected]
        [email protected]@a=0#1
    }
}

def[email protected]@[email protected]#1{
    % Check for second parameter
    [email protected]@eq#1;{
        afterassignment[email protected]@termout
        [email protected]@b=0
    }{
        [email protected]@termout #1
    }
}

def[email protected]@termout#1{
    % SGR parameter
    [email protected]@eq#1m{
        [email protected]@sgr[email protected]@a
        ifnum[email protected]@b<0else
            [email protected]@sgr[email protected]@b
        fi
        [email protected]{}
    }{}
    [email protected]{
%        GenericWarning{}{Warning: Ignored unknown terminal output sequence of type `#1'}
    }
    [email protected]
}

def[email protected]@sgr#1{
    % Reset
    [email protected]@eq{#1}{0}{
        let[email protected]=[email protected]@fgcolor
        [email protected]@false
        [email protected]{}
    }{}

    % Bold/intense
    [email protected]@eq{#1}{1}{
        [email protected]@true
        [email protected]{}
    }{}

    % Standard colors
    [email protected]@eq{#1}{30}{
        def[email protected]{black}
        [email protected]{}
    }{}
    [email protected]@eq{#1}{31}{
        def[email protected]{red}
        [email protected]{}
    }{}
    [email protected]@eq{#1}{32}{
        def[email protected]{green}
        [email protected]{}
    }{}
    [email protected]@eq{#1}{33}{
        def[email protected]{yellow}
        [email protected]{}
    }{}
    [email protected]@eq{#1}{34}{
        def[email protected]{blue}
        [email protected]{}
    }{}
    [email protected]@eq{#1}{35}{
        def[email protected]{magenta}
        [email protected]{}
    }{}
    [email protected]@eq{#1}{36}{
        def[email protected]{cyan}
        [email protected]{}
    }{}
    [email protected]@eq{#1}{37}{
        def[email protected]{white}
        [email protected]{}
    }{}
    [email protected]{}
}

% n-byte Unicode sequences

def[email protected]@[email protected]#1#2{
    scantokens{csname [email protected]@pushendcsname{#1#2}}
    [email protected]
}

def[email protected]@[email protected]#1#2#3{
    scantokens{csname [email protected]@pushendcsname{#1#2#3}}
    [email protected]
}

def[email protected]@[email protected]#1#2#3#4{
    scantokens{csname [email protected]@pushendcsname{#1#2#3#4}}
    [email protected]
}

% Helper macros

def[email protected]#1{
    ifrelaxdetokenize{#1}relax
        expandafter@firstoftwo
    else
        expandafter@secondoftwo
    fi
}

def[email protected]@eq#1#2{
    if#1#2%
        expandafter@firstoftwo
    else
        expandafter@secondoftwo
    fi
}

def[email protected]@eq#1#2{
    ifnum#1=#2 %
        expandafter@firstoftwo
    else
        expandafter@secondoftwo
    fi
}

def[email protected]@range#1#2#3{
    ifnum#1<#2 %
        expandafter@firstoftwo
    else
        expandafter@secondoftwo
    fi
    {
        @secondoftwo
    }{
        ifnum#1>#3 %
            expandafter@secondoftwo
        else
            expandafter@firstoftwo
        fi
    }
}

def[email protected]#1#2[email protected]#3{#1}
def[email protected]#1{#1}

def@temp#1#2{
    begingroup
    lccode`*=`#2
    lowercase{globallet#1=*}
    endgroup
}
@temp[email protected]@char ^^H
@temp[email protected]@char        ^^J
@temp[email protected]@char        ^^M
@temp[email protected]@char    ^^[
@temp[email protected]@char      %

% User macros

% Print terminal session stored in #1
newcommandterminalinput[1]{
    begin{mdframed}[
        backgroundcolor=black,
        innerleftmargin=0pt,
        innerrightmargin=0pt,
        innertopmargin=0pt,
        innerbottommargin=0pt
    ]
    begingroup
    parindent=0pt
    frenchspacing
    ttfamily
    fboxsep=0pt
    [email protected]@sgr{0}

    xdef@temp{[email protected]{0}{[email protected]{#1}}{#1}}
    expandafterxdefexpandafter[email protected]expandafter{
        expandafter[email protected]@temp{}{}
    }
    expandafter[email protected][email protected]relax
    endgroup
    end{mdframed}
}

endlinechar=`^^M
makeatother

DeclareUnicodeCharacter{279C}{textrightarrow}

begin{document}
terminalinput{typescript.bin}
end{document}

uscite

enter image description here

Ci sono ancora diversi problemi con l'attuale implementazione:

  • Il codice funziona solo con l'opzione pdflatex o lualatex perché si basa sul compilatore pdffiledump o sulla sua reimplementazione in codice Lua, rispettivamente.
  • Attualmente non sono supportati i caratteri Unicode, perché il file viene decodificato come un flusso a singolo byte. I caratteri al di fuori dell'intervallo ASCII stampabile sono per ora ignorati.
    EDIT: I caratteri Unicode sono ora supportati. Ogni volta che viene incontrata una sequenza UTF-8 a 2/3/4 byte, i byte vengono rimappati ai loro codici di categoria standard tramite scantokens in modo tale che inputenc possa svolgere normalmente il suo lavoro. Nuove mappature di caratteri possono essere aggiunte tramite DeclareUnicodeCharacter.
  • Attualmente la "finestra del terminale" è solo una scatola nera che copre l'intera larghezza del testo.
  • L'implementazione attuale copre solo un piccolo sottoinsieme di tutte le sequenze di escape/uscita del terminale disponibili. In particolare, i colori di sfondo non sono gestiti affatto, c'è solo una tiepida gestione dei colori grassetto/intenso (aggiungendo !75!white al colore corrente), sono implementati solo gli otto colori standard (codici 30-37), ecc.
  • Anche il posizionamento del cursore non è gestito correttamente, ad esempio il ritorno a capo (x0D) cancella l'intera riga invece di spostare il cursore solo all'inizio della riga.
  • Nelle sequenze di output del terminale, sono supportati solo uno o due numeri di parametri, mentre dovrebbe essere supportato qualsiasi numero di parametri.
  • Il codice non è stato testato bene, in realtà solo con il file di esempio fornito. 😉

Come questo, per esempio.

documentclass{article}
usepackage{fancyvrb}
usepackage{color}

defdefaultcode{[0}
defbluecode{[1;34}
defredcode{[1;31}
makeatletter
defe#1m{%                                                                                                                                                                   
defcolcode{#1}%                                                                                                                                                             
ifxcolcodedefaultcodecolor{black}%
elseifxcolcodebluecodecolor{blue}%
elseifxcolcoderedcodecolor{red}%
fififi}
makeatother

begin{document}
begin{Verbatim}[commandchars=\{}]
echo -e 'e[1;34mBLUE TEXTe[0m'
echo -e 'e[1;31mRED TEXTe[0m'
echo -e 'DEFAULT COLOURED TEXT'
end{Verbatim}
end{document}

enter image description here

L'idea è che i codici di controllo inizino con e e finiscono con m. Pertanto, raccogliamo tutto ciò che si trova nel mezzo e lo confrontiamo con alcuni codici predefiniti. È facile aggiungere altri codici, ad esempio il verde sarebbe supportato da

defgreencode{[1;32}

e poi

elseifxcolcodegreencodecolor{green}

con un altro fi alla fine. Dopodiché, è sufficiente un ambiente verbatim che permetta le macro. Qui ho usato il pacchetto fancyvrb. Si noti che è necessario cambiare il colore in

ifxcolcodedefaultcodecolor{black}

se il colore predefinito non è il nero.

Qui puoi vedere i commenti e le valutazioni dei lettori

Se hai qualche dubbio su come perfezionare il nostro saggio puoi lasciare una recensione e lo leggeremo volentieri.



Utilizzate il nostro motore di ricerca

Ricerca
Generic filters

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.