pax_global_header00006660000000000000000000000064146122166740014523gustar00rootroot0000000000000052 comment=cdfbe116a5cf68754b2a40df5b247f6c0ce7ad38 tml-0.7.0/000077500000000000000000000000001461221667400123235ustar00rootroot00000000000000tml-0.7.0/.github/000077500000000000000000000000001461221667400136635ustar00rootroot00000000000000tml-0.7.0/.github/FUNDING.yml000066400000000000000000000000201461221667400154700ustar00rootroot00000000000000github: [liamg] tml-0.7.0/.gitignore000066400000000000000000000000141461221667400143060ustar00rootroot00000000000000bin .vscode tml-0.7.0/LICENSE000066400000000000000000000022741461221667400133350ustar00rootroot00000000000000 This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to tml-0.7.0/Makefile000066400000000000000000000007321461221667400137650ustar00rootroot00000000000000 default: build build: test mkdir -p bin go build ./tml/ -o bin/tml build-travis: test mkdir -p bin/linux-amd64/tml mkdir -p bin/darwin-amd64/tml GOOS=linux GOARCH=amd64 go build -o bin/linux-amd64/tml -ldflags "-X github.com/liamg/tml/version.Version=${TRAVIS_TAG}" ./tml GOOS=darwin GOARCH=amd64 go build -o bin/darwin-amd64/tml -ldflags "-X github.com/liamg/tml/version.Version=${TRAVIS_TAG}" ./tml test: go vet ./... go test -v ./... .PHONY: build test tml-0.7.0/README.md000066400000000000000000000040711461221667400136040ustar00rootroot00000000000000# tml - Terminal Markup Language [![Build Status](https://travis-ci.org/liamg/tml.svg "Travis CI status")](https://travis-ci.org/liamg/tml) [![GoDoc](https://godoc.org/github.com/liamg/tml?status.svg)](https://godoc.org/github.com/liamg/tml) A Go module (and standalone binary) to make the output of coloured/formatted text in the terminal easier and more readable. You can use it in your Go programs, and bash etc. too. ![Example screenshot](example.png) ## Usage in Go The output of coloured/formatted text is easy using the following syntax: ```go package main import "github.com/liamg/tml" func main() { tml.Printf("this text is red and the following is %s\n", "not red") } ``` ## Usage in Bash First, install tml: Install Go and run the following command. ``` # For Go 1.16+ # Make sure that `$GOPATH/bin` is in your `$PATH`, because that's where this gets installed go install github.com/liamg/tml/tml@latest # For Go <1.16 go get -u github.com/liamg/tml/tml ``` Then you can simply pipe text containing tags to tml: ```bash #!/bin/bash echo "this text is red and the following is not red" | tml ``` ## Format Each tag is enclosed in angle brackets, much like HTML. You can nest tags as deeply as you like. It's not required to close tags you've opened, though it can make for easier reading. ### Available Tags #### Foreground Colours - `` - `` - `` - `` - `` - `` - `` - `` - `` - `` - `` - `` - `` - `` - `` - `` #### Background Colours - `` - `` - `` - `` - `` - `` - `` - `` - `` - `` - `` - `` - `` - `` - `` - `` #### Attributes - `` - `` - `` - `` - `` - `` - `` - `` tml-0.7.0/_examples/000077500000000000000000000000001461221667400143005ustar00rootroot00000000000000tml-0.7.0/_examples/basic/000077500000000000000000000000001461221667400153615ustar00rootroot00000000000000tml-0.7.0/_examples/basic/basic.go000066400000000000000000000003011461221667400167630ustar00rootroot00000000000000package main import ( "github.com/liamg/tml" ) func main() { tml.Printf( "%s %s %s\n", "ERROR", "WARNING", "SUCCESS", ) } tml-0.7.0/disable.go000066400000000000000000000004631461221667400142600ustar00rootroot00000000000000package tml import "sync" var disableFormatting bool var formattingLock sync.RWMutex func DisableFormatting() { formattingLock.Lock() defer formattingLock.Unlock() disableFormatting = true } func EnableFormatting() { formattingLock.Lock() defer formattingLock.Unlock() disableFormatting = false } tml-0.7.0/disable_test.go000066400000000000000000000006231461221667400153150ustar00rootroot00000000000000package tml import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestParseWithFormattingDisabled(t *testing.T) { DisableFormatting() defer EnableFormatting() output, err := Parse("plain red bold red plain green plain") require.Nil(t, err) assert.Equal(t, "plain red bold red plain green plain", output) } tml-0.7.0/example.png000066400000000000000000000406651461221667400144770ustar00rootroot00000000000000PNG  IHDR !sBITO IDATx^|G.Kr``:\ '_.Fr K#! z {Se^#d[e[e)of+}f 1H $.;򲷈 "$M/~@W+[EH @H@{ecH Կ@H \ wl $H +CᎭ"$Pw $pe2ܱU$ $ OW;={qu @H@{ecH K4elDN GIo{@H SPˁAH8]0ʢ n1Ū/#Kya2.?ܢgGZ_ `,M5q$bAW^ئ&h6OKZ̿)-p==ۏ!-a[Yf%fү}$? 8տpd!ժ?36EFSƇ 7[g,%J?,hoMǣ//՛Nl>!i}yU+&lj(ǟdUs+(ߛ9Alzgg&qYk4f @#?lOyR`l4g?GVH4E&sEk$%sQAN _%ϼc3^[$|@>G4P^( $nϿu%<׾n{Q [Bu BH x_#EH u BH x_#EH u BH x !|5'@Ei\47LϖW#Cnn$ rUQ.paj֋םe Ǚ*Ҟ4H0g5OJ=kTRLIh>ۿH4G+(IZnE{7ssg+8UMf-qE\.v7 8ֿ:qO)8uKa7yvμGw+ ~5xO#A-C* x/?x׵E3<yE߽:^^],@='&@H7<9KUSRnW_wEVozu/sYHZglȺ=AHk1ߟt_gd.:Ɣ+K`:Є7( Y c @ xRn s@H+Y?tضнP:*%)mc<|%S>kVhg=;u+>7*OoS(:0A{=kk]s}AN}r`H!ۓv ki~+:(W($?H kN[X /c0|!g)ZL]ԫn򺈧VxVռPZ ́:1P'XBBLBfu g:k`ΚK ӷLDN桃[3ڋ۷4txYF<?έcJgiк|aHqBù:Qѻ aVQl9P*,~b24 zvoNC[i5&I ]ZΗ S|c`f[-(ȿ~}ٲL@`/nVZOL2S3EYv6Ldp͎c2GV AS@`^':c*,E`Pִn 6^x;*2+{=M}t9fh'AhGon2.)*4-\ZdbsUW|$ڿw KMN0EM&#x 7t>I\窅+h9f:$JX|E`~?pm ж\.uϜ oT:uz֘|UEa?vT6mqG*|1wc$jH9 F+β>~Nbo 7~q8B~&pC$o\ş矏S*ڷG3|hX>4XC› ©Ols1?Tpe2 O+;'ߗ}Cct  V_K W1QM7j+1^Iv$X~M7s5*x "֘qH{8ֿ) ';Cqu2AH @ctX $+0v֪͛<Ӯ;>E`$G>|A^=D[W֭اA@u1r!; N}=辭G#r^)ԡⰐ\ؿgL2eAP\M,kۛ5 6n)vےqA i(˨6L{@艙w<, R]uc_/26w r&g!yqޑM"ęEL-yVUw*q-sL(1,6Ǹ#ӎY쬉JN& a{=+1aT2!~ׯH{#3SZw]O/*\c#丸532':kc90;}to0pZkKhפ6VXgg\X[*vm4(Z*v7uҸ$ItB cO~'k"ҳ{&k!_&l-,s[ IJ@= M$Zxj!`q&|\٬oiG CUe=hWH$M7Qz  $TX0;t3chDa3cO)5F_P= ZSKm)Jt3XxqDųۜX;QFjp?D CDXBuMm!kJֱm(V ئ.FWWC\ o: ]N \ve %Y i )Lj>=h" +"쥧t5h̸)׀2UU؜7H6e˅Ҳ8B=zYS]A ^AP|ד\|`KHpjZ(I֝,EGHK! 04kU% g|%',vNnSf3x+0਺R}F푬8oo1yI7hgqv֢G!qC7RVk_Q'fi/V;چQǽYQUV\oҨ-;d\qEH t׺WK_Q08@H5_0 $zIo/bu$@ 8<% 0]K$M C=NX $i=M!$#=NX $i^?'%y.7gނǻmc{HO'a@%7iPNШRS__u 'EG&b^[UUTR63 aRd$\( 0bxxlJrɤ/(,)9=cpTP}apO#<|q-~TQsf/)/i5th4 c'''2Ue^0 1MgA̡G/f?yUġY#$bZ,*+VVyqR|r^ࠐi@cs 567DEݻ\[-}$F?ʬVֿ6mŝ|allJ~Ʀ Oee+7QQ| /DQ)%#c$$*t(ā's矔HT*yCCdEFW^Qp2w!=} CCABMuiC@(t3l&:. .a8gtDtjrzٓU53f/:?bȨڪaGX,=wn۳YU=!*"c@lެYۿvêsHs`'E3cQ?˚e Ғ;ueg U+S3陼Sjj׾GO;'l߳б̥q _vƞ.8o:rN2Y\"@] t¢S:LԖƚH:ЭEphAJzy!Q&o*+KJȰZ,G.oj79e]t˺V@&onnM-S2{ȟ>{c9P 40zym$~٣&Ӯ>.$849>V\^[RV)`wIY7pjvP ':8$8R[`l-TjJ*~~"qU%dvECH6Nâ"L&.gݰ5'6@Ӷ?[O&'M;5",^JW(v*Ro;i,#£ }7 K? [t4aF}κRmҹ A<F7:WPb t'c"vW^2E|2n_fgٹR@wi%6;6 FZ m-b** {J^XκY%44/B`8Ț!4# [V}cd~ ncPE7% #o$l0j"""Xy<*[I^ICJ`TrrfhH`q:kC:(ph>E7Ś[3iONnU9D~cGe)T3'53K@A&xK:\P,.:VE7{ԁ#&N3r4L$0|!E@ \))bx$k/*9&; -ҶE7z]/vow+킢I9fTѨ޺k3#"%W]H|:/v5m[C3b!$߮a>@H@{iT$@WPvE@K"$"tE$hf*3v j,BA#Z%?J|lLSPG 8x2h!&d -FP; e?p9~$Eiu#>j$Ȝam{":Z\n~-_ԗC_î|h>6"f٪> ]Kg:tbZN \ΐBx+ ~͞3zgݴRqQLH2[,viTc鑗 #{w IDATUnLX~@fq {cj OAUi0 kBÌI]b1׀bYs۲ ٴ#Sa+*-d$XclAX^-,ǷE\ lcc @?wTײ0&e/TQ]ϭB b .N)fE`ÿx $]Jkp˫ku0i%GN3ej+,U(k[84RkFG% @dQ@vmu=ȫ'(^Kkd8Yyh90'CH%ZK[=H@w 8ֿ8<}l|.GCRGs)/U&b[x1PjeSR:Tw(m!;)TA T*ck~sv1/bԫ`e$-~UEg vIz Cih+CX}' |hx9 P=GȌ}[\不wR:>:H(ʲ|-(e2@'XJNcPPoӬ Yƹ9 7"4̛l '$`q5%W3'M'"}[]_;iO )V?/}R\2JNcl !$-/a~_a|{`C}!7uV.˞ EzGt˃/>ݽb'/-֖E/xeȬMrC|9[*(^X 0$,lWi:R}7iK[>ZG݂?@[f?aӬ$'Psa.d06b@?#5w\ oO+CXp$buw/qH >xx9ڐ6ǀGM׻GIđqu[PFoW21 $&kFĨI9oM& A{>jՒ$yCMn*=eoXTxs}W//j޿̼u_ 8h0 Do.g \MM?ooĵ~Gw׋f+O[ꛡ⨩cuCtbZ?$/,;vAq GLr{}OgR|߫o湏^b\]Vp%ҧ>g8By#3o Yӓ[3mMUZP֣Ll6sX=GDL5&G_elD47s7f8O^ۖ'ًvx8ni7v.3nٳ=4erzcۑ$ w|mԜIC^i-^t%s(_u-|Ӌ}wM:Oںi?{Y LOרԇ<KL)M 6,ߧo{vON3~[<q⟅F>uצg5O`ՌYONR ז4㩅4|zm[iޠ_,})ݹnZN1Hk1[F x n_Ms3Ni՚U_(ۅit+\SkN?q69dڻqOkSNߴoֳO:nu6Ym`)G'59'XY>. 6bɚZ~[rűG 16Ɂ/@('}}̽mQoeٽa{I^Q\JˆFAtHkgv7ӛw/ j{ 5 ԅ/4*TQ珶& #b#r /9_ Lݪɭ#ahჹQ 1/k Bgp!ܺ*ŷ ;;d'(?%@~X4WzOks9-h"?6ٷBb_C;bVQ.|ا6V}˂7XGvRi=l;b17!&lzO84G$jT}[h3Hҿ?BGiMuMq)mtUWQ뺖-l6wL 8"*6no6ݷ<|g3_sX%F&-&QUZ ayR ULF/n[>Zп0AYo v.)HopX|p4xxw fFE7wH,r"-=Hb_$L }Ðq^e0p ܑ3{K652Y1 l nwiBjd!6b=PSiS_xt }u[n 2`Fs$ݱfkBz? tʍ߽_`g?{O1'Z? x'IyY,q/+`mYIo$4sGή*.,Us&Z +7EVˏ? /,M)9\[ j{K~⇥o}soȂE7͸#e Y2>~9\mX~[UЇ{Wꢳ-[qkua.E_0yէ8oVS؝2'>zrw aݑСW͚Ӓċ^[쪛 ^g`ږ6)d+,&z?=HfXu`Ot`>X}C[{5q%c_+0 Y}'oMiU}U3>P]R#oTXoqq?7ul۷艻>xGXT,5_YoFY p~;:*kڧM߰.R.J E뚺@]{w:N]?s>AH @3nX $[n؜ȡi/T>o(WDaJ*Φc/ L C-@HPz) DH E_ˈ &HBQ 0L &IQ\HcIt`mg# DzDY. ˎb1R+:0?> HUM W7M'ʻ( II JVt'Ȫ?]x',[kiB&TJ l0U/2 0bH8Lj1Y4* [!v "x@X@lGȥ;٨j<_ T54ި1lo 18)/֟5/- 8ֿAɡqUGJ ]Ѐp**[J"AcV,O?yycʄgŴi~ ZfpcsR *]rJ_H H>Ri,.w&P5<| RAD菼~9tަC@5z⅁~yfpc1:ڗGHi[Ԣ`1W,pWg8PhT +lP e 1 ; \P\T&ߙypY1 z!Y&osyY3X耆3UrgvWp; 5,UA)ï8|IK05 `U-XLlM0a}4vt2UV1uv6վE]|15 eԔOG ?J9kr;*|31ebFr|xR;sELA^AǂIgg@f L'0|NUm+wPO05"|O趴F- mk[|[[BE(>yyP( HJ*9Ӎ:8 7KDplu5sYױ[4W&NNBZkL`ǵXss :Ȣ=vy˜c/5 ]x1uc8 ˌt`+-E Ҙ`A_pr|gr+ Z7]SF&ْf+8+A..%>`4 ~@?hnL{̺I[ϺA+Xph$LHsuVa:qDR p;, ̻ۿsP "#6 '0WM|{g`,hQ7()5(?{V8xUoWX YW^¼ <~ƎJf 0]y74'TM\Kbg /1\@zn/ fXJ/y( \q}pʼn`@$>xQ\tM.b@H x_`D!H n@mdX $Nߢ,>U]O"%΂Ce*脘KS2;"Rffo2BPT޺`1eݽ@'D:7UD@!b%+I bN&eLp>Q- MK~T~^4$XBŸςx&+%ӱ٭%<ҙ K)+IgTL"&@ Q[q! 7BJB/Bpw"pf!%T"7 d$,3jt1";)l%XtnÊ%XD?!g󹄄Guп`UZEA~ 4Ivbk TU*D[=Y=AC\$_bkh#TkDR!j՘%+wlho GHV5Rc_ŖRnؽ  E\!7X1`k"fk nL%^> V6c1;lp)X`҄XlV.IX~<Xq)M[DWBBu$cdQ: '=QL:D[\_[cΪyk g%1 8Щ/-M+YaX'%]UkhBI"BDiM,{q07FWÙ[c8+H 8]@f0Qz6mo=Ҵesne./+bf#jQ*+ m<f&D'0Ӧ1 OOBAl۠tl1<:v8V5Z g) TC{س\6)%e`[Z3j ":3aҊk=0*"V^SMXzLQ05GisT<&qx!N% mrL -_ `IMmD`g!t\f6p7˖ȂNvt`bHpJ'+j S=ItlHq"rBk1d߼z+$ЎƟ/Ɵ녽EH8 0@H@{YqccH nEnH \ueV{D`b(w%,<Կgo$@@"m؛O[c`s8g2| Rsn:}@>H7~ۢ'↏O}@^JoM߳"nu/\n']yᄉCWl=OW*a#"61:Jbcï>a6anikߏoE?{L.Yg~p~Mfδq\hҿȤ_}5Ki/a@f*9)`7i+@wps变bSx};o[0}n}˼lAd\ |tBlB[B#C^pkӳL_ezG;tlÕbgN?[ soۚMMݾ`K<?66Dֈlvtn҇d9lӿZ֨玟=t<}HFoxSOKS+UtmXF\Iqrw&q˶2nQ1ఐ7 } 7l/+KIq[ !{.VDK7ɐаWj9q4QQ`3㬭Z6P)Ԓi'IY6 b0O_rbE@Yz pZoi~)hjTtd;`Ɔxu==d 舞zHp KrpAjo1e`/b`PvA^BGc/ڊ^ꌟ!>%1sX&CrF< X tf1_Yl~T*H 8п@Əwۚ͋g1L&ۮEJSUZ۲~±zgqԤ˗|?yѓs`JYm3rLQT@p\cX ϛjq܃'ubY7͵9{bU#'j/.I1SƊ"XX q/޴umMTVP1lzE030zp.dc L/~\I\s swp?,}s8ϽCͫ.f@|[U3zjm LLG>N/;0@+Ų;]ppQ@H#Pz# AH tn# H @G0$@ mdX $= $Moa$GF6ԿF@!a=?pIENDB`tml-0.7.0/go.mod000066400000000000000000000003441461221667400134320ustar00rootroot00000000000000module github.com/liamg/tml go 1.20 require github.com/stretchr/testify v1.8.3 require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) tml-0.7.0/go.sum000066400000000000000000000015611461221667400134610ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= tml-0.7.0/new_line.go000066400000000000000000000001551461221667400144530ustar00rootroot00000000000000package tml // NewLine prints a new line to the terminal with no content func NewLine() { Println("") } tml-0.7.0/parse.go000066400000000000000000000006041461221667400137640ustar00rootroot00000000000000package tml import ( "strings" "bytes" ) // Parse converts the input string (containing TML tags) into a string containing ANSI escape code sequences for output to the terminal. func Parse(input string) (string, error) { output := bytes.NewBufferString("") if err := NewParser(output).Parse(strings.NewReader(input)); err != nil { return "", err } return output.String(), nil } tml-0.7.0/parse_test.go000066400000000000000000000006221461221667400150230ustar00rootroot00000000000000package tml import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestParse(t *testing.T) { output, err := Parse("plain red bold red plain green plain") require.Nil(t, err) assert.Equal(t, "\x1b[0mplain \x1b[31mred \x1b[1mbold red\x1b[0m\x1b[31m\x1b[39m plain \x1b[32mgreen\x1b[39m plain\x1b[0m", output) } tml-0.7.0/parser.go000066400000000000000000000067071461221667400141600ustar00rootroot00000000000000package tml import ( "fmt" "io" "strings" ) // Parser is used to parse a TML string into an output string containing ANSI escape codes type Parser struct { writer io.Writer IncludeLeadingResets bool IncludeTrailingResets bool state parserState } type parserState struct { fg string bg string attrs attrs } type attrs uint8 const ( bold uint8 = 1 << iota dim underline blink reverse hidden italic strikethrough ) var resetAll = "\x1b[0m" var resetFg = "\x1b[39m" var resetBg = "\x1b[49m" var attrMap = map[uint8]string{ bold: "\x1b[1m", dim: "\x1b[2m", italic: "\x1b[3m", underline: "\x1b[4m", blink: "\x1b[5m", reverse: "\x1b[7m", hidden: "\x1b[8m", strikethrough: "\x1b[9m", } func (s *parserState) setFg(esc string) string { if s.fg == esc { return "" } s.fg = esc return esc } func (s *parserState) setBg(esc string) string { if s.bg == esc { return "" } s.bg = esc return esc } func (s *parserState) setAttr(attr int8) string { output := "" if attr < 0 { output = resetAll + s.fg + s.bg } s.attrs = attrs(uint8(s.attrs) + uint8(attr)) for attr, esc := range attrMap { if uint8(s.attrs)&attr > 0 { output += esc } } return output } // NewParser creates a new parser that writes to w func NewParser(w io.Writer) *Parser { return &Parser{ writer: w, IncludeLeadingResets: true, IncludeTrailingResets: true, } } func (p *Parser) handleTag(name string) bool { if strings.HasPrefix(name, "/") { name = name[1:] if _, isFg := fgTags[name]; isFg { if !disableFormatting { p.writer.Write([]byte(p.state.setFg(resetFg))) } return true } else if _, isBg := bgTags[name]; isBg { if !disableFormatting { p.writer.Write([]byte(p.state.setBg(resetBg))) } return true } else if attr, isAttr := attrTags[name]; isAttr { if !disableFormatting { p.writer.Write([]byte(p.state.setAttr(-int8(attr)))) } return true } return false } if esc, ok := fgTags[name]; ok { if !disableFormatting { p.writer.Write([]byte(p.state.setFg(esc))) } return true } if esc, ok := bgTags[name]; ok { if !disableFormatting { p.writer.Write([]byte(p.state.setBg(esc))) } return true } if attr, ok := attrTags[name]; ok { if !disableFormatting { p.writer.Write([]byte(p.state.setAttr(int8(attr)))) } return true } return false } // Parse takes input from the reader and converts any provided tags to the relevant ANSI escape codes for output to parser's writer. func (p *Parser) Parse(reader io.Reader) error { formattingLock.RLock() defer formattingLock.RUnlock() buffer := make([]byte, 1024) if p.IncludeLeadingResets && !disableFormatting { if _, err := p.writer.Write([]byte(resetAll)); err != nil { return err } } var inTag bool var tagName string for { n, err := reader.Read(buffer) if err != nil { if err == io.EOF { break } return err } for _, r := range string(buffer[:n]) { if inTag { if r == '>' { if !p.handleTag(tagName) { p.writer.Write([]byte(fmt.Sprintf("<%s>", tagName))) } tagName = "" inTag = false continue } tagName = fmt.Sprintf("%s%c", tagName, r) continue } if r == '<' { inTag = true continue } p.writer.Write([]byte(string([]rune{r}))) } } if p.IncludeTrailingResets && !disableFormatting { p.writer.Write([]byte(resetAll)) } return nil } tml-0.7.0/parser_test.go000066400000000000000000000017501461221667400152100ustar00rootroot00000000000000package tml import ( "bytes" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestParser(t *testing.T) { testCases := []struct { name string input string output string }{ { name: "no-tags", input: "plain", output: "\x1b[0mplain\x1b[0m", }, { name: "basic", input: "plain red plain", output: "\x1b[0mplain \x1b[31mred\x1b[39m plain\x1b[0m", }, { name: "nesting", input: "plain red bold red plain green plain", output: "\x1b[0mplain \x1b[31mred \x1b[1mbold red\x1b[0m\x1b[31m\x1b[39m plain \x1b[32mgreen\x1b[39m plain\x1b[0m", }, } for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { buffer := bytes.NewBufferString("") parser := NewParser(buffer) err := parser.Parse(strings.NewReader(testCase.input)) require.Nil(t, err) assert.Equal(t, testCase.output, buffer.String()) }) } } tml-0.7.0/printf.go000066400000000000000000000010521461221667400141520ustar00rootroot00000000000000package tml import ( "fmt" "io" "os" ) // Printf works like fmt.Printf, but adds the option of using tags to apply colour or text formatting to the written text. For example "some red text". // A full list of tags is available here: https://github.com/liamg/tml func Printf(input string, a ...interface{}) error { return Fprintf(os.Stdout, input, a...) } func Fprintf(w io.Writer, input string, a ...interface{}) error { format, err := Parse(input) if err != nil { return err } _, err = fmt.Fprintf(w, format, a...) return err } tml-0.7.0/println.go000066400000000000000000000006251461221667400143430ustar00rootroot00000000000000package tml import ( "io" "os" ) // Println works like fmt.Println, but adds the option of using tags to apply colour or text formatting to the written text. For example "some red text". // A full list of tags is available here: https://github.com/liamg/tml func Println(input string) { Fprintln(os.Stdout, input) } func Fprintln(w io.Writer, input string) { Fprintf(w, "%s\n", input) } tml-0.7.0/sprintf.go000066400000000000000000000007061461221667400143420ustar00rootroot00000000000000package tml import "fmt" // Sprintf works like fmt.Sprintf, but adds the option of using tags to apply colour or text formatting to the written text. For example "some red text". // A full list of tags is available here: https://github.com/liamg/tml func Sprintf(input string, a ...interface{}) string { // parsing cannot fail as the reader/writer are simply for local strings format, _ := Parse(input) return fmt.Sprintf(format, a...) } tml-0.7.0/tags.go000066400000000000000000000024421461221667400136120ustar00rootroot00000000000000package tml var fgTags = map[string]string{ "red": "\x1b[31m", "green": "\x1b[32m", "yellow": "\x1b[33m", "blue": "\x1b[34m", "magenta": "\x1b[35m", "cyan": "\x1b[36m", "lightgrey": "\x1b[37m", "darkgrey": "\x1b[90m", "black": "\x1b[30m", "lightred": "\x1b[91m", "lightgreen": "\x1b[92m", "lightyellow": "\x1b[93m", "lightblue": "\x1b[94m", "lightmagenta": "\x1b[95m", "lightcyan": "\x1b[96m", "white": "\x1b[97m", } var bgTags = map[string]string{ "bg-red": "\x1b[41m", "bg-green": "\x1b[42m", "bg-yellow": "\x1b[43m", "bg-blue": "\x1b[44m", "bg-magenta": "\x1b[45m", "bg-cyan": "\x1b[46m", "bg-lightgrey": "\x1b[47m", "bg-darkgrey": "\x1b[40m", "bg-black": "\x1b[40m", "bg-lightred": "\x1b[101m", "bg-lightgreen": "\x1b[102m", "bg-lightyellow": "\x1b[103m", "bg-lightblue": "\x1b[104m", "bg-lightmagenta": "\x1b[105m", "bg-lightcyan": "\x1b[106m", "bg-white": "\x1b[107m", } var attrTags = map[string]uint8{ "bold": bold, "dim": dim, "italic": italic, "underline": underline, "blink": blink, "reverse": reverse, "hidden": hidden, "strikethrough": strikethrough, } tml-0.7.0/tml/000077500000000000000000000000001461221667400131175ustar00rootroot00000000000000tml-0.7.0/tml/main.go000066400000000000000000000003421461221667400143710ustar00rootroot00000000000000package main import ( "fmt" "io/ioutil" "os" "github.com/liamg/tml" ) func main() { input, err := ioutil.ReadAll(os.Stdin) if err != nil { fmt.Printf("Error: %s\n", err) os.Exit(1) } tml.Printf(string(input)) } tml-0.7.0/version/000077500000000000000000000000001461221667400140105ustar00rootroot00000000000000tml-0.7.0/version/version.go000066400000000000000000000001051461221667400160200ustar00rootroot00000000000000package version // Version of tml - set on build var Version = "dev"