You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

224 lines
15 KiB

[comment {--- punk::docgen generated from inline doctools comments ---}]
[comment {--- punk::docgen DO NOT EDIT DOCS HERE UNLESS YOU REMOVE THESE COMMENT LINES ---}]
[comment {--- punk::docgen overwrites this file ---}]
[manpage_begin punkshell_module_punk::ansi 0 0.1.1]
[copyright "2023"]
[titledesc {Ansi string functions}] [comment {-- Name section and table of contents description --}]
[moddesc {punk Ansi library}] [comment {-- Description at end of page heading --}]
[require punk::ansi]
[keywords module ansi terminal console string]
[description]
[para]Ansi based terminal control string functions
[para]See [package punk::ansi::console] for related functions for controlling a console
[section Overview]
[para] overview of punk::ansi
[para]punk::ansi functions return their values - no implicit emission to console/stdout
[subsection Concepts]
[para]Ansi codes can be used to control most terminals on most platforms in an 'almost' standard manner
[para]There are many differences in terminal implementations - but most should support a core set of features
[para]punk::ansi does not contain any code for direct terminal manipulation via the local system APIs.
[para]Sticking to ansi codes where possible may be better for cross-platform and remote operation where such APIs are unlikely to be useable.
[subsection dependencies]
[para] packages used by punk::ansi
[list_begin itemized]
[item] [package {Tcl 8.6-}]
[item] [package {punk::char}]
[list_end]
[section API]
[subsection {Namespace punk::ansi}]
[para] Core API functions for punk::ansi
[list_begin definitions]
[call [fun a?] [opt {ansicode...}]]
[para]Return an ansi string representing a table of codes and a panel showing the colours
[call [fun a+] [opt {ansicode...}]]
[para]Returns the ansi code to apply those from the supplied list - without any reset being performed first
[para] e.g to set foreground red and bold
[para]punk::ansi::a red bold
[para]to set background red
[para]punk::ansi::a Red
[para]see [cmd punk::ansi::a?] to display a list of codes
[call [fun a] [opt {ansicode...}]]
[para]Returns the ansi code to reset any current settings and apply those from the supplied list
[para] by calling punk::ansi::a with no arguments - the result is a reset to plain text
[para] e.g to set foreground red and bold
[para]punk::ansi::a red bold
[para]to set background red
[para]punk::ansi::a Red
[para]see [cmd punk::ansi::a?] to display a list of codes
[call [fun get_code_name] [arg code]]
[para]for example
[para] get_code_name red will return 31
[para] get_code_name 31 will return red
[call [fun reset]]
[para]reset console
[call [fun reset_soft]]
[call [fun reset_colour]]
[para]reset colour only
[call [fun clear]]
[call [fun clear_above]]
[call [fun clear_below]]
[call [fun cursor_on]]
[call [fun cursor_off]]
[call [fun move] [arg row] [arg col]]
[para]Return an ansi sequence to move to row,col
[para]aka cursor home
[call [fun move_emit] [arg row] [arg col] [arg data] [opt {row col data...}]]
[para]Return an ansi string representing a move to row col with data appended
[para]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
[para]Compare to punk::console::move_emit which calls this function - but writes it to stdout
[para]punk::console::move_emit_return will also return the cursor to the original position
[para]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.
[para]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.
[para]punk::console::move_emit_return does it by emitting that code and starting a loop to read stdin
[para]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.
[para]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:
[para][example {punk::ansi::move_emit 10 10 blah {*}[punk::console::get_cursor_pos_list] DONE}]
[para]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.
[call [fun move_emitblock] [arg row] [arg col] [arg textblock]]
[call [fun move_emitblock] [arg row] [arg col] [arg textblock]]
[call [fun move_forward] [arg n]]
[call [fun move_back] [arg n]]
[call [fun move_up] [arg n]]
[call [fun move_down] [arg n]]
[call [fun move_column] [arg col]]
[call [fun move_row] [arg row]]
[para]VPA - Vertical Line Position Absolute
[call [fun cursor_save]]
[para] equivalent term::ansi::code::ctrl::sc
[para] This is the ANSI/SCO cursor save as opposed to the DECSC version
[para] On many terminals either will work - but cursor_save_dec is shorter and perhaps more widely supported
[call [fun cursor_restore]]
[para] equivalent term::ansi::code::ctrl::rc
[para] ANSI/SCO - see also cursor_restore_dec for the DECRC version
[call [fun cursor_save_dec]]
[para] equivalent term::ansi::code::ctrl::sca
[para] DECSC
[call [fun cursor_restore_attributes]]
[para] equivalent term::ansi::code::ctrl::rca
[para] DECRC
[call [fun enable_line_wrap]]
[para] enable automatic line wrapping when characters entered beyond rightmost column
[para] This will also allow forward movements to move to subsequent lines
[para] This is DECAWM - and is the same sequence output by 'tput smam'
[call [fun disable_line_wrap]]
[para] disable automatic line wrapping
[para] reset DECAWM - same sequence output by 'tput rmam'
tput rmam
[call [fun query_mode_line_wrap]]
[para] DECRQM to query line-wrap state
[para] The punk::ansi::query_mode_ functions just emit the ansi query sequence.
[call [fun erase_line]]
[call [fun erase_sol]]
[para]Erase to start of line, leaving cursor position alone.
[call [fun erase_eol]]
[call [fun scroll_up] [arg n]]
[call [fun scroll_down] [arg n]]
[call [fun insert_spaces] [arg count]]
[call [fun delete_characters] [arg count]]
[call [fun erase_characters] [arg count]]
[call [fun insert_lines] [arg count]]
[call [fun delete_lines] [arg count]]
[call [fun cursor_pos]]
[para]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
[para]The output on screen will look something like ^[lb][lb]47;3R
[para]Use punk::console::get_cursor_pos or punk::console::get_cursor_pos_list instead.
[para]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.
[para]The punk::ansi::cursor_pos function is used by punk::console::get_cursor_pos and punk::console::get_cursor_pos_list
[call [fun request_cursor_information]]
[para]DECRQPSR (DEC Request Presentation State Report) for DECCCIR Cursor Information report
[para]When written to the terminal, this sequence causes the terminal to emit cursor information to stdin
[para]A stdin readloop will need to be in place to read this information
[call [fun request_tabstops]]
[para]DECRQPSR (DEC Request Presentation State Report) for DECTABSR Tab stop report
[para]When written to the terminal, this sequence causes the terminal to emit tabstop information to stdin
[call [fun titleset] [arg windowtitles]]
[para]Returns the code to set the title of the terminal window to windowtitle
[para]This may not work on terminals which have multiple panes/windows
[call [fun ansistrip] [arg text] ]
[para]Return a string with ansi codes stripped out
[para]Alternate graphics chars are replaced with modern unicode equivalents (e.g boxdrawing glyphs)
[call [fun ansistrip2] [arg text] ]
[para]Return a string with ansi codes stripped out
[para]Alternate graphics chars are replaced with modern unicode equivalents (e.g boxdrawing glyphs)
[call [fun ansistripraw] [arg text] ]
[para]Return a string with ansi codes stripped out
[para]Alternate graphics modes will be stripped rather than converted to unicode - exposing the raw ascii characters as they appear without graphics mode.
[para]ie instead of a horizontal line you may see: qqqqqq
[list_end] [comment {--- end definitions namespace punk::ansi ---}]
[subsection {Namespace punk::ansi::codetype}]
[para] API functions for punk::ansi::codetype
[para] Utility functions for processing ansi code sequences
[list_begin definitions]
[call [fun is_sgr_reset] [arg code]]
[para]Return a boolean indicating whether this string has a trailing pure SGR reset
[para]Note that if the reset is not the very last item in the string - it will not be detected.
[para]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.
[call [fun has_sgr_leadingreset] [arg code]]
[para]The reset must be the very first item in code to be detected. Trailing strings/codes ignored.
[list_end] [comment {--- end definitions namespace punk::ansi::codetype ---}]
[subsection {Namespace punk::ansi::ta}]
[para] text ansi functions
[para] based on but not identical to the Perl Text Ansi module:
[para] https://github.com/perlancar/perl-Text-ANSI-Util/blob/master/lib/Text/ANSI/BaseUtil.pm
[list_begin definitions]
[call [fun detect] [arg text]]
[para]Return a boolean indicating whether Ansi codes were detected in text
[para]Important caveat:
[para] When text is a tcl list made from splitting (or lappending) some ansi string - individual elements may be braced or have certain chars escaped. (one example is if a list element contains an unbalanced brace)
[para] This can cause square brackets that form part of the ansi being backslash escaped - and the regexp can fail to match
[call [fun detect_csi] [arg text]]
[para]Return a boolean indicating whether an Ansi Control Sequence Introducer (CSI) was detected in text
[para]The csi is often represented in code as \x1b or \033 followed by a left bracket [lb]
[para]The initial byte or escape is commonly referenced as ESC in Ansi documentation
[para]There is also a multi-byte escape sequence \u009b
[para]This is less commonly used but is also detected here
[para](This function is not in perl ta)
[call [fun detect_sgr] [arg text]]
[para]Return a boolean indicating whether an ansi Select Graphics Rendition code was detected.
[para]This is the set of CSI sequences ending in 'm'
[para]This is most commonly an Ansi colour code - but also things such as underline and italics
[para]An SGR with empty or a single zero argument is a reset of the SGR features - this is also detected.
[para](This function is not in perl ta)
[call [fun strip] [arg text]]
[para]Return text stripped of Ansi codes
[para]This is a tailcall to punk::ansi::ansistrip
[call [fun length] [arg text]]
[para]Return the character length after stripping ansi codes - not the printing length
[list_end] [comment {--- end definitions namespace punk::ansi::ta ---}]
[subsection {Namespace punk::ansi::ansistring}]
[para]punk::ansi::ansistring ensemble - ansi-aware string operations
[para]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
[para]Just as working with other forms of markup such as HTML - you simply need to be aware of the tradeoffs and design accordingly.
[list_begin definitions]
[call [fun VIEW] [arg string]]
[para]Return a string with specific ANSI control characters substituted with visual equivalents frome the appropriate unicode C0 and C1 visualisation sets
[para]For debugging purposes, certain other standard control characters are converted to visual representation, for example backspace (mapped to \\U2408 '\U2408')
[para]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
[para]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.
[call [fun COUNT] [arg string]]
[para]Returns the count of visible graphemes and non-ansi control characters
[para]Incomplete! grapheme clustering support not yet implemented - only diacritics are currently clustered to count as one grapheme.
[para]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.
[para]This is not quite equivalent to calling string length on the result of ansistrip $string due to diacritics and/or grapheme combinations
[para]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
[para]To get the width, use punk::ansi::printing_length instead, which is also ansi aware.
[call [fun index] [arg string] [arg index]]
[para]Takes a string that possibly contains ansi codes such as colour,underline etc (SGR codes)
[para]Returns the character (with applied ansi effect) at position index
[para]The string could contain non SGR ansi codes - and these will (mostly) be ignored, so shouldn't affect the output.
[para]Some terminals don't hide 'privacy message' and other strings within an ESC X ESC ^ or ESC _ sequence (terminated by ST)
[para]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.
[para]If the caller wants just the character - they should use a normal string index after calling ansistrap, or call ansistrip afterwards.
[para]As any operation using end-+<int> will need to strip ansi to precalculate the length anyway; the caller should probably just use ansistrip and standard string index if the ansi coded output isn't required and they are using and end-based index.
[para]In fact, any operation where the ansi info isn't required in the output would probably be slightly more efficiently obtained by using ansistrip and normal string operations on that.
[para]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
[para]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.
[para]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.
[para]This shouldn't make any difference to the visual output - but a possible future enhancement is something to produce the shortest ansi sequence possible
[para]Notes:
[para]This function has to split the whole string into plaintext & ansi codes even for a very low index
[para]Some sort of generator that parses more of the string as required might be more efficient for large chunks.
[para]For end-x operations we have to pre-calculate the content-length by stripping the ansi - which is also potentially sub-optimal
[list_end] [comment {--- end definitions namespace punk::ansi::ta ---}]
[manpage_end]