writing-a-tui-in-bash How to write a TUI in BASH开源项目

我要开发同款
匿名用户2021年11月09日
42阅读
开发技术SHELL
所属分类终端/远程登录、应用工具
授权协议MIT License

作品详情

WritingaTUIinBASH[WIP]

ThroughmytravelsI'vediscoveredit'spossibletowriteafullyfunctionalTerminalUserInterfaceinBASH.Theobjectofthisguideistodocumentandteachtheconceptsinasimpleway.Tomyknowledgetheyaren'tdocumentedanywheresothisisessential.

ThebenefitofusingBASHisthelackofneededdependencies.IfthesystemhasBASHavailable,theprogramwillrun.NowtherearecasesagainstusingBASHandthey'remostofthetimevalid.However,therearecaseswhereBASHistheonlythingavailableandthat'swherethisguidecomesin.

ThisguidecoversBASH3.2+whichcoversprettymucheveryOSyou'llcomeacross.OneofthemajorreasonsforcoveringthisversionismacOSwhichwillbeforeverstuckonBASH3.

TodateIhavewritten3differentprogramsusingthismethod.ThebestexampleofaTUIthatcoversmostvitalfeaturesisfffwhichisaTerminalFilemanager.

TableofContentsOperatingSystemsIdentifytheOperatingSystem.Documented$OSTYPEvalues.Gettingthewindowsize.UsingcursorpositionUsingcheckwinsizeUsingsttyReactingtowindowsizechanges.EscapeSequencesHidingandShowingthecursorLinewrappingMovingthecursortospecificcoordinatesMovingthecursortothebottomoftheterminal.MovingthecursorrelativelyCursorUpCursorDownCursorLeftCursorRightClearingthescreenSettingthescrollarea.SavingandRestoringtheuser'sterminalscreen.ReferencesOperatingSystemsIdentifytheOperatingSystem.

ThequickestwaytodeterminethecurrentOperatingSystemisthe$OSTYPEvariable.ThisvariableissetatcompiletimeinbashandtypicallystoresthenameoftherunningkernelorthenameoftheOSitself.

YoucanalsousethecommandunametoidentifywhichOSisrunning.TheunamecommandisPOSIXandshouldbeavailableeverywhere.Theoutputfromunamedoesdifferfrom$OSTYPEbutthere'savastamountofdocumentedinformationaboutit.[1][2]

get_os(){#Figureoutthecurrentoperatingsystemtohandlesome#OSspecificbehavior.#'$OSTYPE'typicallystoresthenameoftheOSkernel.case"$OSTYPE"inlinux*)#...;;#MacOSX/macOS.darwin*)#...;;openbsd*)#...;;#Everythingelse.*)#...;;esac}Documented$OSTYPEvalues.

Thetablebelowwaspopulatedbyuserssubmittingthevalueofthe$OSTYPEvariableusingthefollowingcommand.Ifyou'rerunninganOSnotmentionedbelowortheoutputdiffers,pleaseopenanissuewiththecorrectvalue.

bash-c"echo$OSTYPE"OS$OSTYPELinuxwithglibclinux-gnuLinuxwithmusllinux-muslCygwincygwinBashonWindows10linux-gnuMsysmsysMingw64msysMingw32msysOpenBSDopenbsd*FreeBSDfreebsd*NetBSDnetbsdmacOSdarwin*iOSdarwin9Solarissolaris*Android(Termux)linux-androidAndroidlinux-gnuHaikuhaikuGettingthewindowsize.Usingcursorposition

Thisfunctionfiguresouttheterminalwindowsizebymovingthecursortothebottomrightcornerandthenqueryingtheterminalforthecursor'sposition.Astheterminalismadeupofcellsthebottomrightcornerisequaltotheterminal'ssize.

get_term_size(){#'\e7':Savethecurrentcursorposition.#'\e[9999;9999H':Movethecursortothebottomrightcorner.#'\e[6n':Getthecursorposition(windowsize).#'\e8':Restorethecursortoitspreviousposition.IFS='[;'read-sp$'\e7\e[9999;9999H\e[6n\e8'-dR-rs_LINESCOLUMNS}Usingcheckwinsize

Note:Thisonlyworksinbash4+.

Whencheckwinsizeisenabledandbashreceivesacommand,theLINESandCOLUMNSvariablesarepopulatedwiththeterminalwindowsize.The(:;:)snippetworksasapseudocommand,populatingthevariableswithoutrunninganythingexternal.

get_term_size(){shopt-scheckwinsize;(:;:)}Usingstty

Thisfunctioncallssttysizetoquerytheterminalforitssize.ThesttycommandisPOSIXandshouldbeavailableeverywherewhichmakesitaviablealternativetothepurebashsolutions.

get_term_size(){#Getterminalsize('stty'isPOSIXandalwaysavailable).#Thiscan'tbedonereliablyacrossallbashversionsinpurebash.read-rLINESCOLUMNS<<(sttysize)}Reactingtowindowsizechanges.

Usingtrapallowsustocaptureandreacttospecificsignalssenttotherunningprogram.Inthiscasewe'retrappingtheSIGWINCHsignalwhichissenttotheterminalandtherunningshellonwindowresize.

We'rereactingtothesignalbyrunningtheaboveget_term_size()function.Thevariables$LINESand$COLUMNSwillbeupdatedwiththenewterminalsizereadytouseelsewhereintheprogram.

#Trapthewindowresizesignal(handlewindowresizeevents).#See:'mantrap'and'trap-l'trap'get_term_size'WINCHEscapeSequences

Forthepurposesofthisresourcewewon'tbeusingtput.Thetputcommandhasalotofoverhead(10-15msperinvocation)andwon'tmaketheprogramanymoreportablethanstickingtostandardVT100escapesequences.Usingtputalsoaddsadependencyonncurseswhichdefeatsthewholepurposeofdoingthisinbash.

HidingandShowingthecursor

See:

https://vt100.net/docs/vt510-rm/DECTCEM.html#Hidingthecursor.printf'\e[?25l'#Showingthecursor.printf'\e[?25h'Linewrapping

See:

https://vt100.net/docs/vt510-rm/DECAWM.html#Disablinglinewrapping.printf'\e[?7l'#Enablinglinewrapping.printf'\e[?7h'Movingthecursortospecificcoordinates

See:

https://vt100.net/docs/vt510-rm/CUP.html#Movethecursorto0,0.printf'\e[H'#Movethecursortoline3,column10.printf'\e[3;10H'#Movethecursortoline5.printf'\e[5H'Movingthecursortothebottomoftheterminal.

See:

getting-the-window-sizehttps://vt100.net/docs/vt510-rm/CUP.html#Usingterminalsize,movecursortobottom.printf'\e[%sH'"$LINES"Movingthecursorrelatively

Whenusingtheseescapesequencesandthecursorhitstheedgeofthewindowitstops.

CursorUp

See:

https://vt100.net/docs/vt510-rm/CUU.html#Movethecursorupaline.printf'\e[A'#Movethecursorup10lines.printf'\e[10A'CursorDown

See:

https://vt100.net/docs/vt510-rm/CUD.html#Movethecursordownaline.printf'\e[B'#Movethecursordown10lines.printf'\e[10B'CursorLeft

See:

https://vt100.net/docs/vt510-rm/CUB.html#Movethecursorbackacolumn.printf'\e[D'#Movethecursorback10columns.printf'\e[10D'CursorRight

See:

https://vt100.net/docs/vt510-rm/CUF.html#Movethecursorforwardacolumn.printf'\e[C'#Movethecursorforward10columns.printf'\e[10C'Clearingthescreen

See:

https://vt100.net/docs/vt510-rm/ED.htmlhttps://vt100.net/docs/vt510-rm/CUP.html#Clearthescreen.printf'\e[2J'#Clearthescreenandmovecursorto(0,0).#Thismimicsthe'clear'command.printf'\e[2J\e[H'Settingthescrollarea.

Thissequenceallowyoutolimittheterminal'sverticalscrollingareabetweentwopoints.Thiscomesinhandywhenyouneedtoreserveportionsofthescreenforatoporbottomstatus-line(youdon'twantthemtoscroll).

Thissequencealsohastheside-effectofmovingthecursortothetop-leftoftheboundaries.Thismeansyoucanuseitdirectlyafterascreenclearinsteadof\e[H(\e[2J\e[0;10r).

See:

https://vt100.net/docs/vt510-rm/DECSTBM.html#Limitscrollingfromline0toline10.printf'\e[0;10r'#Setscrollingmarginsbacktodefault.printf'\e[;r'SavingandRestoringtheuser'sterminalscreen.

ThisistheonlynonVT100sequencesI'llbecovering.Thissequenceallowsyoutosaveandrestoretheuser'sterminalscreenwhenrunningyourprogram.Whentheuserexitstheprogram,theircommand-linewillberestoredasitwasbeforerunningtheprogram.

WhilethissequenceisXTermspecific,itiscoveredbyalmostallmodernterminalemulatorsandsimplyignoredinolderones.ThereisalsoDECCRAwhichmayormaynotbemorewidelysupportedthantheXTermsequencebutIhaven'tdonemuchtesting.

#Savetheuser'sterminalscreen.printf'\e[?1049h'#Restoretheuser'sterminalscreen.printf'\e[?1049l'References[1]:https://github.com/dylanaraps/neofetch/blob/415ef5d4aeb1cced7afcf9fd1223dd09c3306b9c/neofetch#L814-L845[2]:https://en.wikipedia.org/wiki/Uname
声明:本文仅代表作者观点,不代表本站立场。如果侵犯到您的合法权益,请联系我们删除侵权资源!如果遇到资源链接失效,请您通过评论或工单的方式通知管理员。未经允许,不得转载,本站所有资源文章禁止商业使用运营!
下载安装【程序员客栈】APP
实时对接需求、及时收发消息、丰富的开放项目需求、随时随地查看项目状态

评论