[//000000001]: # (punkshell\_module\_punk::ansi \- punk Ansi library) [//000000002]: # (Generated from file '\_module\_ansi\-0\.1\.1\.tm\.man' by tcllib/doctools with format 'markdown') [//000000003]: # (Copyright © 2023) [//000000004]: # (punkshell\_module\_punk::ansi\(0\) 0\.1\.1 doc "punk Ansi library")
[ Main Table Of Contents | Table Of Contents | Keyword Index ]
# NAME punkshell\_module\_punk::ansi \- Ansi string functions # Table Of Contents - [Table Of Contents](#toc) - [Synopsis](#synopsis) - [Description](#section1) - [Overview](#section2) - [Concepts](#subsection1) - [dependencies](#subsection2) - [API](#section3) - [Namespace punk::ansi](#subsection3) - [Namespace punk::ansi::codetype](#subsection4) - [Namespace punk::ansi::ta](#subsection5) - [Namespace punk::ansi::ansistring](#subsection6) - [Keywords](#keywords) - [Copyright](#copyright) # SYNOPSIS package require punk::ansi [__stripansi__ *text*](#1) [__stripansi__ *text*](#2) [__a?__ ?ansicode\.\.\.?](#3) [__a\+__ ?ansicode\.\.\.?](#4) [__a__ ?ansicode\.\.\.?](#5) [__get\_code\_name__ *code*](#6) [__reset__](#7) [__reset\_soft__](#8) [__reset\_colour__](#9) [__clear__](#10) [__clear\_above__](#11) [__clear\_below__](#12) [__cursor\_on__](#13) [__cursor\_off__](#14) [__move__ *row* *col*](#15) [__move\_emit__ *row* *col* *data* ?row col data\.\.\.?](#16) [__move\_forward__ *n*](#17) [__move\_back__ *n*](#18) [__move\_up__ *n*](#19) [__move\_down__ *n*](#20) [__move\_column__ *col*](#21) [__move\_row__ *row*](#22) [__cursor\_save__](#23) [__cursor\_restore__](#24) [__cursor\_save\_dec__](#25) [__cursor\_restore\_attributes__](#26) [__enable\_line\_wrap__](#27) [__disable\_line\_wrap__](#28) [__query\_mode\_line\_wrap__](#29) [__erase\_line__](#30) [__erase\_sol__](#31) [__erase\_eol__](#32) [__scroll\_up__ *n*](#33) [__scroll\_down__ *n*](#34) [__insert\_spaces__ *count*](#35) [__delete\_characters__ *count*](#36) [__erase\_characters__ *count*](#37) [__insert\_lines__ *count*](#38) [__delete\_lines__ *count*](#39) [__cursor\_pos__](#40) [__request\_cursor\_information__](#41) [__request\_tabstops__](#42) [__titleset__ *windowtitles*](#43) [__is\_sgr\_reset__ *code*](#44) [__has\_sgr\_leadingreset__ *code*](#45) [__detect__ *text*](#46) [__detect\_csi__ *text*](#47) [__detect\_sgr__ *text*](#48) [__strip__ *text*](#49) [__length__ *text*](#50) [__VIEW__ *string*](#51) [__COUNT__ *string*](#52) [__index__ *string* *index*](#53) # DESCRIPTION Ansi based terminal control string functions See __punk::ansi::console__ for related functions for controlling a console # Overview overview of punk::ansi punk::ansi functions return their values \- no implicit emission to console/stdout ## Concepts Ansi codes can be used to control most terminals on most platforms in an 'almost' standard manner There are many differences in terminal implementations \- but most should support a core set of features punk::ansi does not contain any code for direct terminal manipulation via the local system APIs\. Sticking to ansi codes where possible may be better for cross\-platform and remote operation where such APIs are unlikely to be useable\. ## dependencies packages used by punk::ansi - __Tcl 8\.6\-__ - __punk::char__ # API ## Namespace punk::ansi Core API functions for punk::ansi - __stripansi__ *text* Return a string with ansi codes stripped out Alternate graphics chars are replaced with modern unicode equivalents \(e\.g boxdrawing glyphs\) - __stripansi__ *text* Return a string with ansi codes stripped out Alternate graphics modes will be stripped \- exposing the raw characters as they appear without graphics mode\. ie instead of a horizontal line you may see: qqqqqq e\.g who is to know that 'Rabbit Paws', 'Forbidden Thrill' and 'Tarsier' refer to a particular shade of pinky\-red? \(code 95\) Perhaps it's an indication that colour naming once we get to 256 colours or more is a fool's errand anyway\. The xterm names are boringly unimaginative \- and also have some oddities such as: DarkSlateGray1 which looks much more like cyan\.\. The greyxx names are spelt with an e \- but the darkslategrayX variants use an a\. Perhaps that's because they are more cyan than grey and the a is a hint? there is no gold or gold2 \- but there is gold1 and gold3 but in general the names bear some resemblance to the colours and are at least somewhat intuitive\. - __a?__ ?ansicode\.\.\.? Return an ansi string representing a table of codes and a panel showing the colours - __a\+__ ?ansicode\.\.\.? Returns the ansi code to apply those from the supplied list \- without any reset being performed first e\.g to set foreground red and bold punk::ansi::a red bold to set background red punk::ansi::a Red see __punk::ansi::a?__ to display a list of codes - __a__ ?ansicode\.\.\.? Returns the ansi code to reset any current settings and apply those from the supplied list by calling punk::ansi::a with no arguments \- the result is a reset to plain text e\.g to set foreground red and bold punk::ansi::a red bold to set background red punk::ansi::a Red see __punk::ansi::a?__ to display a list of codes - __get\_code\_name__ *code* for example get\_code\_name red will return 31 get\_code\_name 31 will return red - __reset__ reset console - __reset\_soft__ - __reset\_colour__ reset colour only - __clear__ - __clear\_above__ - __clear\_below__ - __cursor\_on__ - __cursor\_off__ - __move__ *row* *col* Return an ansi sequence to move to row,col aka cursor home - __move\_emit__ *row* *col* *data* ?row col data\.\.\.? Return an ansi string representing a move to row col with data appended row col data can be repeated any number of times to return a string representing the output of the data elements at all those points Compare to punk::console::move\_emit which calls this function \- but writes it to stdout punk::console::move\_emit\_return will also return the cursor to the original position There is no punk::ansi::move\_emit\_return because in a standard console there is no ansi string which can represent a jump back to starting position\. There is an ansi code to write the current cursor position to stdin \(which will generally display on the console\) \- this is not quite the same thing\. punk::console::move\_emit\_return does it by emitting that code and starting a loop to read stdin punk::ansi could implement a move\_emit\_return using the punk::console mechanism \- but the resulting string would capture the cursor position at the time the string is built \- which is not necessarily when the string is used\. The following example shows how to do this manually, emitting the string blah at screen position 10,10 and emitting DONE back at the line we started: punk::ansi::move_emit 10 10 blah {*}[punk::console::get_cursor_pos_list] DONE A string created by any move\_emit\_return for punk::ansi would not behave in an intuitive manner compared to other punk::ansi move functions \- so is deliberately omitted\. - __move\_forward__ *n* - __move\_back__ *n* - __move\_up__ *n* - __move\_down__ *n* - __move\_column__ *col* - __move\_row__ *row* VPA \- Vertical Line Position Absolute - __cursor\_save__ equivalent term::ansi::code::ctrl::sc This is the ANSI/SCO cursor save as opposed to the DECSC version On many terminals either will work \- but cursor\_save\_dec is shorter and perhaps more widely supported - __cursor\_restore__ equivalent term::ansi::code::ctrl::rc ANSI/SCO \- see also cursor\_restore\_dec for the DECRC version - __cursor\_save\_dec__ equivalent term::ansi::code::ctrl::sca DECSC - __cursor\_restore\_attributes__ equivalent term::ansi::code::ctrl::rca DECRC - __enable\_line\_wrap__ enable automatic line wrapping when characters entered beyond rightmost column This will also allow forward movements to move to subsequent lines This is DECAWM \- and is the same sequence output by 'tput smam' - __disable\_line\_wrap__ disable automatic line wrapping reset DECAWM \- same sequence output by 'tput rmam' tput rmam - __query\_mode\_line\_wrap__ DECRQM to query line\-wrap state The punk::ansi::query\_mode\_ functions just emit the ansi query sequence\. - __erase\_line__ - __erase\_sol__ Erase to start of line, leaving cursor position alone\. - __erase\_eol__ - __scroll\_up__ *n* - __scroll\_down__ *n* - __insert\_spaces__ *count* - __delete\_characters__ *count* - __erase\_characters__ *count* - __insert\_lines__ *count* - __delete\_lines__ *count* - __cursor\_pos__ cursor\_pos unlikely to be useful on it's own like this as when written to the terminal, this sequence causes the terminal to emit the row;col sequence to stdin The output on screen will look something like ^\[\[47;3R Use punk::console::get\_cursor\_pos or punk::console::get\_cursor\_pos\_list instead\. These functions will emit the code \- but read it in from stdin so that it doesn't display, and then return the row and column as a colon\-delimited string or list respectively\. The punk::ansi::cursor\_pos function is used by punk::console::get\_cursor\_pos and punk::console::get\_cursor\_pos\_list - __request\_cursor\_information__ DECRQPSR \(DEC Request Presentation State Report\) for DECCCIR Cursor Information report When written to the terminal, this sequence causes the terminal to emit cursor information to stdin A stdin readloop will need to be in place to read this information - __request\_tabstops__ DECRQPSR \(DEC Request Presentation State Report\) for DECTABSR Tab stop report When written to the terminal, this sequence causes the terminal to emit tabstop information to stdin - __titleset__ *windowtitles* Returns the code to set the title of the terminal window to windowtitle This may not work on terminals which have multiple panes/windows ## Namespace punk::ansi::codetype API functions for punk::ansi::codetype Utility functions for processing ansi code sequences - __is\_sgr\_reset__ *code* Return a boolean indicating whether this string has a trailing pure SGR reset Note that if the reset is not the very last item in the string \- it will not be detected\. This is primarily intended for testing a single ansi code sequence, but code can be any string where the trailing SGR code is to be tested\. - __has\_sgr\_leadingreset__ *code* The reset must be the very first item in code to be detected\. Trailing strings/codes ignored\. ## Namespace punk::ansi::ta text ansi functions based on but not identical to the Perl Text Ansi module: https://github\.com/perlancar/perl\-Text\-ANSI\-Util/blob/master/lib/Text/ANSI/BaseUtil\.pm - __detect__ *text* Return a boolean indicating whether Ansi codes were detected in text - __detect\_csi__ *text* Return a boolean indicating whether an Ansi Control Sequence Introducer \(CSI\) was detected in text The csi is often represented in code as \\x1b or \\033 followed by a left bracket \[ The initial byte or escape is commonly referenced as ESC in Ansi documentation There is also a multi\-byte escape sequence \\u009b This is less commonly used but is also detected here \(This function is not in perl ta\) - __detect\_sgr__ *text* Return a boolean indicating whether an ansi Select Graphics Rendition code was detected\. This is the set of CSI sequences ending in 'm' This is most commonly an Ansi colour code \- but also things such as underline and italics An SGR with empty or a single zero argument is a reset of the SGR features \- this is also detected\. \(This function is not in perl ta\) - __strip__ *text* Return text stripped of Ansi codes This is a tailcall to punk::ansi::stripansi - __length__ *text* Return the character length after stripping ansi codes \- not the printing length ## Namespace punk::ansi::ansistring punk::ansi::ansistring ensemble \- ansi\-aware string operations Working with strings containing ansi in a way that preserves/understands the codes is always going to be significantly slower than working with plain strings Just as working with other forms of markup such as HTML \- you simply need to be aware of the tradeoffs and design accordingly\. - __VIEW__ *string* Return a string with specific ANSI control characters substituted with visual equivalents frome the appropriate unicode C0 and C1 visualisation sets For debugging purposes, certain other standard control characters are converted to visual representation, for example backspace \(mapped to \\\\U2408 '\\U2408'\) Horizontal tab is mapped to \\\\U2409 '\\U2409'\. For many of the punk terminal text operations, tabs have already been mapped to the appropriate number of spaces using textutil::tabify functions As punkshell uses linefeed where possible in preference to crlf even on windows, cr is mapped to \\\\U240D '\\U240D' \- but lf is left as is\. - __COUNT__ *string* Returns the count of visible graphemes and non\-ansi control characters Incomplete\! grapheme clustering support not yet implemented \- only diacritics are currently clustered to count as one grapheme\. This will not count strings hidden inside a 'privacy message' or other ansi codes which may have content between their opening escape and their termination sequence\. This is not quite equivalent to calling string length on the result of stripansi $string due to diacritics and/or grapheme combinations Note that this returns the number of characters in the payload \(after applying combiners\) It is not always the same as the width of the string as rendered on a terminal due to 2wide Unicode characters and the usual invisible control characters such as \\r and \\n To get the width, use punk::ansi::printing\_length instead, which is also ansi aware\. - __index__ *string* *index* Takes a string that possibly contains ansi codes such as colour,underline etc \(SGR codes\) Returns the character \(with applied ansi effect\) at position index The string could contain non SGR ansi codes \- and these will \(mostly\) be ignored, so shouldn't affect the output\. Some terminals don't hide 'privacy message' and other strings within an ESC X ESC ^ or ESC \_ sequence \(terminated by ST\) It's arguable some of these are application specific \- but this function takes the view that they are probably non\-displaying \- so index won't see them\. If the caller wants just the character \- they should use a normal string index after calling stripansi, or call stripansi afterwards\. As any operation using end\-\+ will need to strip ansi to precalculate the length anyway; the caller should probably just use stripansi and standard string index if the ansi coded output isn't required and they are using and end\-based index\. In fact, any operation where the ansi info isn't required in the output would probably be slightly more efficiently obtained by using stripansi and normal string operations on that\. The returned character will \(possibly\) have a leading ansi escape sequence but no trailing escape sequence \- even if the string was taken from a position immediately before a reset or other SGR ansi code The ansi\-code prefix in the returned string is built up by concatenating previous SGR ansi codes seen \- but it is optimised to re\-start the process if any full SGR reset is encountered\. The code sequence doesn't detect individual properties being turned on and then off again, only full resets; so in some cases the ansi\-prefix may not be as short as it could be\. This shouldn't make any difference to the visual output \- but a possible future enhancement is something to produce the shortest ansi sequence possible Notes: This function has to split the whole string into plaintext & ansi codes even for a very low index Some sort of generator that parses more of the string as required might be more efficient for large chunks\. For end\-x operations we have to pre\-calculate the content\-length by stripping the ansi \- which is also potentially sub\-optimal # KEYWORDS [ansi](\.\./\.\./\.\./index\.md\#ansi), [console](\.\./\.\./\.\./index\.md\#console), [module](\.\./\.\./\.\./index\.md\#module), [string](\.\./\.\./\.\./index\.md\#string), [terminal](\.\./\.\./\.\./index\.md\#terminal) # COPYRIGHT Copyright © 2023