Environment di linea verbatim

  • Creatore
    Topic
  • #119840
    robitex
    Amministratore del forum
      Up
      0
      Down
      ::


      Ciao a tutti.
      Tempo fa scrissi un paio di macro con lo scopo di raccogliere linea per linea l’input dell’utente.
      Le varie linee sono memorizzate all’interno di un array Lua e processate in seguito.
      All’epoca studiai il TeX by Topic per creare un ambiente verbatim come quello descritto, ma non riuscii a creare il vero ambiente LaTeX ma solamente le macro di apertura \lines e di chiusura \endlines.
      Ora mi sono accorto che il codice ha un bug perché raccoglie una prima linea vuota che non dovrebbe esserci.
      Veniamo al codice:
      `% !TeX program = LuaLaTeX
      \documentclass{article}
      \def\mkchar#1{\catcode`#1=12 }
      \def\lines{%
      \directlua{
      lines = {}
      contatore = 0
      }\begingroup
      \let\do=\mkchar \dospecials
      \endlinechar`\^^M \catcode`\^^M=12 \xlines}

      {\catcode`\^^M=12 \endlinechar=-1 %
      \gdef\xlines#1^^M{%
      \def\test{#1}
      \ifx\test\endlines
      \let\next\endgroup
      \else
      \directlua{
      if contatore == 0 then contatore = 1 else
      ;lines[contatore] = [==[#1]==];
      contatore = contatore + 1; end
      }%
      \let\next\xlines \fi \next}
      }

      {\escapechar=-1
      \xdef\endlines{\string\\endlines}
      }

      \begin{document}
      \lines
      uno
      due
      tre
      \endlines
      \directlua{tex.print(“|”..table.concat(lines, “, “)..”|”)}
      \end{document}
      `

      Come potete constatare il codice funziona perché ho inserito l’artificio di eliminare la prima riga.
      Il codice Lua di acquisizione linee “naturale” dovrebbe essere infatti il più semplice:
      `…
      \else
      \directlua{
      contatore = contatore + 1;
      lines[contatore] = [==[#1]==];
      }%
      \let\next\xlines \fi \next}
      …`

      Si potrebbe fare a meno della variabile contatore ma dovrei inserire l’operatore di lunghezza che è il carattere #. Evitiamo altri guai.

      Se sostituisco il codice “naturale” nel sorgente ottengo una virgola in più, e questo è il bug.
      Il mio codice raccoglie quindi una riga iniziale vuota.

      Le domande:
      1) è possibile risolvere il bug senza applicare l’artificio?
      2) come creare l’ambiente \begin{lines} \end{lines} al posto delle macro \lines e \endlines?
      3) in LaTeX3 esiste un modo per risolvere brillantemente il quesito 2?

      Grazie mille.
      R.

    Visualizzazione 7 filoni di risposte
    • Autore
      Risposte
      • #119841
        OldClaudio
        Partecipante
          Up
          0
          Down
          ::


          Sollevi un problema noto; certamente il file fancyvrb contien la definziione di n ambiente che legge verbatim.
          Inolre xparse (i cui comandi sono già inseriti nel corpo di LaTeX, quindi non è necessario caricare il pacchetto xparse, ma è utile leggerne la documentazione) contien un descrittore di argomento[tt]+b[/tt] che serve per acquisire in modo verbatim il corpo di un ambiente; Io l’ho usato nella costruzione del mio pacchetto widetable e devo dire che per il mio scopo funzionava benissimo; mi ha permesso di passare da più di 150 rige di codice (quando non lo usavo) a circa 50 righe di codice e la nuova versione di widetable fa di più della precedente. Comunque l’utilità di [tt]+b[/tt] e di fancyverb dipende da che cosa vuoi fare una volta acquisito il contenuto dell’ambiente in modo verbatim. C’è anche la possibilità con xparse di racchiudere tutto il contenuto dell’ambiente fra graffe e farlo leggere dal comando d’apertura con il descrittore v; in modo che il comando di apertura legga solo l’argomento di tipo v, e il comando di chiusura ne faccia l’uso richiesto dal compositore.

          Forse non sono stato chiaro, ma ci sono da leggere la documentazione di xparse; il file interface3 (sempre con texdoc) e, volendo, la documentazione di widetable dal paragrafo 7 in poi c’è il codice commentato.

        • #119842
          robitex
          Amministratore del forum
            Up
            0
            Down
            ::


            Ciao Claudio grazie per la risposta.
            Avevo già guardato il codice di fancyvrb ma senza poterlo riutilizzare perché non credo ci avessi capito un granché 😀
            Le tue indicazioni su L3 sono per me più interessanti, grazie.
            Quanto allo scopo di raccogliere linea per linea del materiale verbatim è presto detto. Il materiale è codice Lua. Ho scritto un pacchetto (in Lua) in grado di leggere codice Lua da varie fonti (file oppure codice nel sorgente stesso), eseguirlo, raccogliere l’output di console e stampare tutto nel documento. Questo grazie a una particolare funzione che conosco da anni e che mi fu segnalata da Luigi Scarso.

            Per esempio se scrivo:
            `\lines
            print(“Ciao”)
            \endlines
            \sourcecode(from_lines():run())`

            Nel documento trovo il codice Lua con sintassi evidenziata e sotto separata da un filetto la parola Ciao.
            Il codice Lua può essere qualsiasi.
            Per risolvere il bug con quel workaround di eliminare la prima riga, ho riletto il codice del pacchetto.
            Risultato: non ne vado fiero. Vorrei riscriverlo da zero. Tuttavia, funziona e ci sono cose più urgenti a cui dedicarsi.
            Per chi è interessato cercare il file sourcecode.sty e sourcecode.lua a questo link (la guidalua)
            https://github.com/GuITeX/guidalua

            Ciao.
            Alla prossima
            R.

          • #119843
            Up
            0
            Down
            ::


            Devi eliminare il fine riga dopo [tt]\lines[/tt]. Ho fatto anche qualche altro piccolo cambiamento.

            `
            \documentclass{article}

            \makeatletter
            \def\lines{%
            \directlua{
            lines = {}
            contatore = 1
            }%
            \begingroup
            \let\do=\@makeother
            \dospecials
            \catcode`\^^M=12
            \xlinesfirst
            }
            \def\xlinesfirst#1{\xlines}

            {\catcode`\^^M=12 \endlinechar=-1 %
            \gdef\xlines#1^^M{%
            \def\test{#1}%
            \ifx\test\endlines
            \let\next\endgroup
            \else
            \directlua{
            lines[contatore] = [==[#1]==];
            contatore = contatore + 1;
            }%
            \let\next\xlines \fi \next}
            }

            {\escapechar=-1
            \xdef\endlines{\string\\endlines}
            }
            \makeatother

            \begin{document}
            \lines
            uno
            due
            tre
            \endlines
            \directlua{tex.print(“|”..table.concat(lines, “, “)..”|”)}
            \end{document}
            `

            Ciao
            Enrico

          • #119844
            robitex
            Amministratore del forum
              Up
              0
              Down
              ::

              egreg9″ post=120318Devi eliminare il fine riga dopo [tt]\lines[/tt]. Ho fatto anche qualche altro piccolo cambiamento.

              `
              \documentclass{article}

              \makeatletter
              \def\lines{%
              \directlua{
              lines = {}
              contatore = 1
              }%
              \begingroup
              \let\do=\@makeother
              \dospecials
              \catcode`\^^M=12
              \xlinesfirst
              }
              \def\xlinesfirst#1{\xlines}

              {\catcode`\^^M=12 \endlinechar=-1 %
              \gdef\xlines#1^^M{%
              \def\test{#1}%
              \ifx\test\endlines
              \let\next\endgroup
              \else
              \directlua{
              lines[contatore] = [==[#1]==];
              contatore = contatore + 1;
              }%
              \let\next\xlines \fi \next}
              }

              {\escapechar=-1
              \xdef\endlines{\string\\endlines}
              }
              \makeatother

              \begin{document}
              \lines
              uno
              due
              tre
              \endlines
              \directlua{tex.print(“|”..table.concat(lines, “, “)..”|”)}
              \end{document}
              `

              Ciao
              Enrico

              Grazie Enrico.
              Non riesco a individuare la fine riga di troppo nel mio codice.
              Ho poco tempo per approfondire.
              Mi rifarò sentire sull’argomento.
              Alla prossima.

            • #119845
              Up
              0
              Down
              ::

              robitex” post=120321

              […]

              Grazie Enrico.
              Non riesco a individuare la fine riga di troppo nel mio codice.
              Ho poco tempo per approfondire.
              Mi rifarò sentire sull’argomento.
              Alla prossima.

              Dopo [tt]\lines[/tt] c’è un fine riga, no? Ecco, è quello!

              Con il tuo codice, [tt]\lines[/tt] esegue alcune impostazioni e alla fine chiama [tt]\xlines[/tt], che è un comando con argomento delimitato dal carattere [tt]^^M[/tt] (fine riga), reso di categoria 12. La prima esecuzione di [tt]\xlines[/tt] trova [tt]^^M[/tt] preceduto da niente e quindi il primo elemento della tua lista è vuoto.

              Che faccio io, invece? La macro [tt]\lines[/tt] finisce con [tt]\xlinesfirst[/tt] il cui unico scopo è di prendere [tt]^^M[/tt] come argomento per scartarlo e chiamare [tt]\xlines[/tt].

              Ciao
              Enrico

            • #119846
              robitex
              Amministratore del forum
                Up
                0
                Down
                ::

                egreg9″ post=120357

                […]

                Grazie Enrico.
                Non riesco a individuare la fine riga di troppo nel mio codice.
                Ho poco tempo per approfondire.
                Mi rifarò sentire sull’argomento.
                Alla prossima.

                Dopo [tt]\lines[/tt] c’è un fine riga, no? Ecco, è quello!

                Con il tuo codice, [tt]\lines[/tt] esegue alcune impostazioni e alla fine chiama [tt]\xlines[/tt], che è un comando con argomento delimitato dal carattere [tt]^^M[/tt] (fine riga), reso di categoria 12. La prima esecuzione di [tt]\xlines[/tt] trova [tt]^^M[/tt] preceduto da niente e quindi il primo elemento della tua lista è vuoto.

                Che faccio io, invece? La macro [tt]\lines[/tt] finisce con [tt]\xlinesfirst[/tt] il cui unico scopo è di prendere [tt]^^M[/tt] come argomento per scartarlo e chiamare [tt]\xlines[/tt].

                Ciao
                Enrico

                Ciao Enrico,
                ho sempre pensato che il carattere percento annullasse anche il fine riga.
                Evidentemente no,
                Grazie.
                R.

              • #119847
                Up
                0
                Down
                ::

                robitex” post=120358
                Ciao Enrico,
                ho sempre pensato che il carattere percento annullasse anche il fine riga.
                Evidentemente no,
                Grazie.
                R.

                Quale [tt]%[/tt]? Non ne hai! Magari così è più chiaro: il fine riga è nel codice da elaborare, non nelle definizioni delle macro.
                `
                \lines
                print(“Ciao”)

                \endlines

                `
                Ora lo vedi?

                TeX legge una riga alla volta, ma costruisce i suoi token solo quando gliene servono. Una volta letto [tt]\[/tt], TeX sa che deve costruire una sequenza di controllo ed esamina un carattere alla volta (senza costruire token); siccome c’è una [tt]l[/tt], è una parola di controllo, quindi va avanti finché trova caratteri alfabetici. Dopo [tt]s[/tt] non c’è un carattere alfabetico, ma il fine riga (o spazi invisibili, non importa), quindi termina la costruzione del token [tt]\lines[/tt] ed entra in stato S (skipping blanks). Il token è una macro che quindi viene espansa e parte di questo processo potrebbe richiedere altri token (se la macro ha argomenti). L’espansione viene inserita e il processo di espansione ricomincia dal primo token.

                In questo caso il fine riga viene esaminato solo dopo che nel processo di elaborazione delle macro tocca a [tt]\xlines[/tt]. Questa è una macro con un argomento delimitato, quindi TeX lo cerca e solo a questo punto il fine riga diventa un token, precisamente [tt]^^M[/tt] di categoria 12; l’argomento è vuoto. Ora sai di preciso perché con il tuo codice appare un elemento vuoto nella tabella Lua che costruisci. Con il mio invece no, perché [tt]\xlinesfirst[/tt] ha un argomento, che in questo caso è l’unico token [tt]^^M[/tt] di categoria 12; siccome l’espansione è [tt]\xlines[/tt] quel token sparisce senza lasciare traccia.

                Ciao
                Enrico

              • #119848
                robitex
                Amministratore del forum
                  Up
                  0
                  Down
                  ::


                  Ciao Enrico,
                  caspita, non avevo pensato a cercare fine riga nell’ambiente ma solo nella definizione delle macro di apertura/chiusura (come hai capito).
                  Grazie per l’aiuto e la spiegazione.
                  R.

              Visualizzazione 7 filoni di risposte
              • Devi essere connesso per rispondere a questo topic.

              Go to top