Terminal kos
Jeg holder på med å utvikle et spill — et spill i terminalen. I denne prosessen har jeg lært litt om hvordan man temmer terminalen til å oppføre seg rett.
Up the ANSI
Først ut er ANSI escape
codes. Disse kodene
kan brukes til å manipulere teksten og markørens plass i terminalen. Om
du vil fargelegge noe tekst rødt kan du prefikse teksten med \033[31m
. Prøv
f.eks. å kjøre denne i din foretrukne terminal:
$ echo -e "\033[31mDenne teksten er rød"
-e
sørger for atecho
tolker backslash escapes fremfor å gjengi dem ordrett\033
starter escape sekvensen[..m
forteller terminalen at du vil farge teksten som kommer etter (litt forenklet)31
er fargekoden for rød
\033[0m
nulstiller fargen tilbake til originalen. Om du vil ha det ekstra
gøy kan du prøve denne:
echo -e "Det \033[31msmalt\! \033[34mBukken\033[0m stupte \033[32mbums\033[0m i \033[35mbakken\033[0m."
Fantastisk 🎨
For at spillet mitt skal funke bra må jeg finne en måte å tegne opp linjene på nytt, for å unngå å printe de samme linjene under hverandre og søle til scrollback-bufferet. Tenk på forskjellen i oppførsel mellom git og vim. Jeg ønsker meg samme adferd som i vim — når du lukker programmet ser du ikke noen spor etter å ha kjørt det.
ANSI escape codes lar deg også gjøre nettopp dette! 🎉
\033[?1049h
åpner et alternativt buffer – akkurat det jeg trenger, og
\033[?1049l
tar deg tilbake til det vanlige bufferet. Helmaks! 👌
Men sa du ikke at du må tegne opp linjene på nytt? Dette løser jo ikke problemet 🤨
Helt riktig!
For å rense allerede printet tekst, har vi flere alternativer. Det finnes
escape-koder for å bevege markøren og viske ut tekst relativt til den, men
sammen med det alternative bufferet er det klart enklest å rense hele skjermen
med \033[H\033[2J
.
Interager, da vel!
Vanlig oppførsel i terminalen er å lese input på <ENTER>
. Du må skrive inn
passord — og det er først når du trykker <ENTER>
at inputtet blir sendt til
programmet.
Dette kommer ikke til å funke 🤔 Hvordan skal man få slangen til å bekjempe, ødelegge og rasere uten raske tastetrykk?
stty
til unnsetning 💪
stty
er en kommando for å endre oppførselen til terminalen. Jeg vil særlig
fremheve to flagg: -echo
og -icanon
(lokale moduser). Takk til
Teodor og
bbslideshow for å hjelpe meg på
vei.
-echo
gjør at tastetrykk ikke blir skrevet til bufferet. Så når jeg trykkers
vil det ikke komme ens
i terminalen med dette flagget aktivert. Sagt med andre ord fjerner du terminalens echo-evne.-icanon
endrer måten terminalen leser input. I stedet for å lese input linje for linje, blir inputtet lest tegn for tegn.
stty -icanon -echo
gir oss da de perfekte forholdene for et spill i
terminalen. Vi får ikke unødvendige tegn rundt omkring og vi trenger ikke å
trykke <ENTER>
hver gang vi ønsker å gjøre noe. For å gjenopprette terminalens
daglige kår er det bare å kjøre samme kommando uten strekene: stty icanon echo
.
I spillet mitt har jeg planer om også å bruke ctrl-tastebindinger. Men også her
kommer jeg i veien for terminalens normale oppførsel. Om jeg vil bruke
CTRL-c
f.eks. vil det ha ganske så katastrofale følger for spillet mitt.
Spillet ville bli fortalt om å lukke porten og si farvel til oss dødelige.
Dette må også tas hånd om ✋
Her kan vi også bruke stty
til å rebinde tastebindingene. Vi kan rebinde
CTRL-c
med stty intr ''
. Dette vil i praksis deaktivere muligheten for å
avbryte en prosess – ikke for sarte sjeler. Tilbakestill med stty intr '^C'
.
Med stty -e
får du listet opp alle flagg, kommandoer og bindings.
I spillet mitt kan jeg da kjøre:
$ stty stop '' discard '' intr '' susp '' lnext '' reprint '' werase '' dsusp '' eof '' status '' start '' kill ''
$ stty stop '^S' discard '^O' intr '^C' susp '^Z' lnext '^V' reprint '^R' werase '^W' dsusp '^Y' eof '^D' status '^T' start '^Q' kill '^U'
og forårsake så mye kaos jeg vil 💥❤️🔥😈 — og rydde pent opp etter meg igjen 😇.
Yippie ‼ 🙌
Følg instinktene dine 👀
Noe annet som skurrer for meg, er at markøren er synlig. Den har ikke noen rolle i spillet mitt så da trenger man heller ikke beskue dens eksistens.
tput
er kommandoen for dette 😁 tput civis
skjuler markøren og tput cnorm
visualiserer den på nytt. Tada! 🎉
Oppsummering
\033[..m
fargelegger teksten etter i den angitte fargen\033[?1049h
går til alternativt buffer\033[?1049l
bringer deg tilbake til det vanlige bufferet\033[H\033[2J
renser hele skjermen for skittenskapstty -icanon -echo
leser input tegn for tegnstty icanon echo
leser input linje for linjestty <ctrl> <binding>
rebind tastebindingertput civis
skjuler markørentput cnorm
bringer tilbake markøren
Hederlig omtale
trap <action> <condition>
trap
lar deg innskyte et signal med ekstra kommandoer før det eksekveres eller
endre oppførselen fullstendig. F.eks. trap "exiting..." SIGINT
vil printe ut
strengen "exiting..."
før prosessen blir kansellert.
Man kan da bruke denne til f.eks. å rydde opp i volatile elementer før en prosess avsluttes, eller innskyte kommandoer før et vilkårlig signal blir eksekvert.