Browse Source

textblock::class::table feature and ansi fixes

master
Julian Noble 5 months ago
parent
commit
7c6ca9b532
  1. 2
      src/bootsupport/include_modules.config
  2. 200
      src/bootsupport/modules/oolib-0.1.1.tm
  3. 63
      src/bootsupport/modules/punk/ansi-0.1.1.tm
  4. 17
      src/bootsupport/modules/punk/lib-0.1.1.tm
  5. 3076
      src/bootsupport/modules/textblock-0.1.1.tm
  6. 20
      src/embedded/man/files/punk/_module_lib-0.1.1.tm.n
  7. 122
      src/embedded/md/doc/files/punk/_module_lib-0.1.1.tm.md
  8. 108
      src/embedded/www/doc/files/punk/_module_lib-0.1.1.tm.html
  9. 63
      src/modules/punk/ansi-999999.0a1.0.tm
  10. 17
      src/modules/punk/lib-999999.0a1.0.tm
  11. 2096
      src/modules/textblock-999999.0a1.0.tm

2
src/bootsupport/include_modules.config

@ -53,6 +53,8 @@ set bootsupport_modules [list\
modules punk::repo\ modules punk::repo\
modules punk::tdl\ modules punk::tdl\
modules punk::winpath\ modules punk::winpath\
modules textblock\
modules oolib\
] ]
#each entry - base subpath #each entry - base subpath

200
src/bootsupport/modules/oolib-0.1.1.tm

@ -0,0 +1,200 @@
#JMN - api should be kept in sync with package patternlib where possible
#
package provide oolib [namespace eval oolib {
variable version
set version 0.1.1
}]
namespace eval oolib {
oo::class create collection {
variable o_data ;#dict
variable o_alias
constructor {} {
set o_data [dict create]
}
method info {} {
return [dict info $o_data]
}
method count {} {
return [dict size $o_data]
}
method isEmpty {} {
expr {[dict size $o_data] == 0}
}
method names {{globOrIdx {}}} {
if {[llength $globOrIdx]} {
if {[string is integer -strict $globOrIdx]} {
set idx $globOrIdx
if {$idx < 0} {
set idx "end-[expr {abs($idx + 1)}]"
}
if {[catch {lindex [dict keys $o_data] $idx} result]} {
error "[self object] no such index : '$idx'"
} else {
return $result
}
} else {
#glob
return [lsearch -glob -all -inline [dict keys $o_data] $globOrIdx]
}
} else {
return [dict keys $o_data]
}
}
#like names but without globbing
method keys {} {
dict keys $o_data
}
method key {{posn 0}} {
if {$posn < 0} {
set posn "end-[expr {abs($posn + 1)}]"
}
if {[catch {lindex [dict keys $o_data] $posn} result]} {
error "[self object] no such index : '$posn'"
} else {
return $result
}
}
method hasKey {key} {
dict exists $o_data $key
}
method get {} {
return $o_data
}
method items {} {
return [dict values $o_data]
}
method item {key} {
if {[string is integer -strict $key]} {
if {$key >= 0} {
set valposn [expr {(2*$key) +1}]
return [lindex $o_data $valposn]
} else {
set key "end-[expr {abs($key + 1)}]"
return [lindex $o_data $key]
#return [lindex [dict keys $o_data] $key]
}
}
if {[dict exists $o_data $key]} {
return [dict get $o_data $key]
}
}
#inverse lookup
method itemKeys {value} {
set value_indices [lsearch -all [dict values $o_data] $value]
set keylist [list]
foreach i $value_indices {
set idx [expr {(($i + 1) *2) -2}]
lappend keylist [lindex $o_data $idx]
}
return $keylist
}
method search {value args} {
set matches [lsearch {*}$args [dict values $o_data] $value]
if {"-inline" in $args} {
return $matches
} else {
set keylist [list]
foreach i $matches {
set idx [expr {(($i + 1) *2) -2}]
lappend keylist [lindex $o_data $idx]
}
return $keylist
}
}
#review - see patternlib. Is the intention for aliases to be configurable independent of whether the target exists?
method alias {newAlias existingKeyOrAlias} {
if {[string is integer -strict $newAlias]} {
error "[self object] collection key alias cannot be integer"
}
if {[string length $existingKeyOrAlias]} {
set o_alias($newAlias) $existingKeyOrAlias
} else {
unset o_alias($newAlias)
}
}
method aliases {{key ""}} {
if {[string length $key]} {
set result [list]
foreach {n v} [array get o_alias] {
if {$v eq $key} {
lappend result $n $v
}
}
return $result
} else {
return [array get o_alias]
}
}
#if the supplied index is an alias, return the underlying key; else return the index supplied.
method realKey {idx} {
if {[catch {set o_alias($idx)} key]} {
return $idx
} else {
return $key
}
}
method add {value key} {
if {[string is integer -strict $key]} {
error "[self object] collection key must not be an integer. Use another structure if integer keys required"
}
if {[dict exists $o_data $key]} {
error "[self object] col_processors object error: key '$key' already exists in collection"
}
dict set o_data $key $value
return [expr {[dict size $o_data] - 1}] ;#return index of item
}
method remove {idx {endRange ""}} {
if {[string length $endRange]} {
error "[self object] collection error: ranged removal not yet implemented.. remove one item at a time"
}
if {[string is integer -strict $idx]} {
if {$idx < 0} {
set idx "end-[expr {abs($idx+1)}]"
}
set key [lindex [dict keys $o_data] $idx]
set posn $idx
} else {
set key $idx
set posn [lsearch -exact [dict keys $o_data] $key]
if {$posn < 0} {
error "[self object] no such index: '$idx' in this collection"
}
}
dict unset o_data $key
return
}
method clear {} {
set o_data [dict create]
return
}
method reverse_the_collection {} {
#named slightly obtusely because reversing the data when there may be references held is a potential source of bugs
#the name reverse_the_collection should make it clear that the object is being modified in place as opposed to simply 'reverse' which may imply a view/copy.
#todo - consider implementing a get_reverse which provides an interface to the same collection without affecting original references, yet both allowing delete/edit operations.
set dictnew [dict create]
foreach k [lreverse [dict keys $o_data]] {
dict set dictnew $k [dict get $o_data $k]
}
set o_data $dictnew
return
}
#review - cmd as list vs cmd as script?
method map {cmd} {
set seed [list]
dict for {k v} $o_data {
lappend seed [uplevel #0 [list {*}$cmd $v]]
}
return $seed
}
method objectmap {cmd} {
set seed [list]
dict for {k v} $o_data {
lappend seed [uplevel #0 [list $v {*}$cmd]]
}
return $seed
}
}
}

63
src/bootsupport/modules/punk/ansi-0.1.1.tm

@ -1748,6 +1748,7 @@ namespace eval punk::ansi {
dict set codestate_empty bg "" ;#40-47 + 100-107 dict set codestate_empty bg "" ;#40-47 + 100-107
#misnomer should have been sgr_merge_args ? :/
#as a common case optimisation - it will not merge a single element list, even if that code contains redundant elements #as a common case optimisation - it will not merge a single element list, even if that code contains redundant elements
proc sgr_merge_list {args} { proc sgr_merge_list {args} {
if {[llength $args] == 0} { if {[llength $args] == 0} {
@ -1755,9 +1756,30 @@ namespace eval punk::ansi {
} elseif {[llength $args] == 1} { } elseif {[llength $args] == 1} {
return [lindex $args 0] return [lindex $args 0]
} }
sgr_merge $args
}
#codes *must* already have been split so that one esc per element in codelist
#e.g codelist [a+ Yellow Red underline] [a+ blue] [a+ red] is ok
#but codelist "[a+ Yellow Red underline][a+ blue]" [a+ red] is not
#(use punk::ansi::ta::split_codes_single)
proc sgr_merge {codelist args} {
variable codestate_empty variable codestate_empty
set othercodes [list] set othercodes [list]
set defaults [dict create\
-filter_fg 0\
-filter_bg 0\
]
dict for {k v} $args {
switch -- $k {
-filter_fg - -filter_bg {}
default {
error "sgr_merge unknown option '$k'. Known options [dict keys $defaults]"
}
}
}
set opts [dict merge $defaults $args]
set codestate $codestate_empty set codestate $codestate_empty
set codestate_initial $codestate_empty ;#keep a copy for resets. set codestate_initial $codestate_empty ;#keep a copy for resets.
set did_reset 0 set did_reset 0
@ -1772,7 +1794,7 @@ namespace eval punk::ansi {
#We still output any non SGR codes in the list as they came in - preserving their CSI #We still output any non SGR codes in the list as they came in - preserving their CSI
foreach c $args { foreach c $codelist {
#normalize 8bit to a token of the same length so our string operations on the code are the same and we can maintain a switch statement with literals rather than escapes #normalize 8bit to a token of the same length so our string operations on the code are the same and we can maintain a switch statement with literals rather than escapes
#.. but preserve original c #.. but preserve original c
#set cnorm [string map [list \x9b {8[} ] $c] #set cnorm [string map [list \x9b {8[} ] $c]
@ -1911,7 +1933,7 @@ namespace eval punk::ansi {
dict set codestate hide 28 ;#reveal dict set codestate hide 28 ;#reveal
} }
29 { 29 {
dict set codestate strik 29;#off dict set codestate strike 29;#off
} }
30 - 31 - 32 - 33 - 34 - 35 - 36 - 37 { 30 - 31 - 32 - 33 - 34 - 35 - 36 - 37 {
dict set codestate fg $p ;#foreground colour dict set codestate fg $p ;#foreground colour
@ -2067,13 +2089,38 @@ namespace eval punk::ansi {
} }
set codemerge "" set codemerge ""
dict for {k v} $codestate { if {[dict get $opts -filter_fg] || [dict get $opts -filter_bg]} {
switch -- $v { dict for {k v} $codestate {
"" { switch -- $v {
"" {
}
default {
switch -- $k {
bg {
if {![dict get $opts -filter_bg]} {
append codemerge "${v}\;"
}
}
fg {
if {![dict get $opts -filter_fg]} {
append codemerge "${v}\;"
}
}
default {
append codemerge "${v}\;"
}
}
}
} }
default { }
append codemerge "${v}\;" } else {
dict for {k v} $codestate {
switch -- $v {
"" {}
default {
append codemerge "${v}\;"
}
} }
} }
} }
@ -3963,7 +4010,7 @@ namespace eval punk::ansi::ansistring {
#return empty string for each index that is out of range #return empty string for each index that is out of range
#review - this is possibly too slow to be very useful as is. #review - this is possibly too slow to be very useful as is.
# consider converting to oo and maintaining state of ansisplits so we don't repeat relatively expensive operations for same string # consider converting to oo and maintaining state of ansisplits so we don't repeat relatively expensive operations for same string
#see also punk::list_index_resolve / punk::list_index_get for ways to handle tcl list/string indices without parsing them. #see also punk::lindex_resolve / punk::lindex_get for ways to handle tcl list/string indices without parsing them.
proc INDEXABSOLUTE {string args} { proc INDEXABSOLUTE {string args} {
set payload_len -1 ;# -1 as token to indicate we haven't calculated it yet (only want to call it once at most) set payload_len -1 ;# -1 as token to indicate we haven't calculated it yet (only want to call it once at most)
set testindices [list] set testindices [list]

17
src/bootsupport/modules/punk/lib-0.1.1.tm

@ -211,7 +211,18 @@ namespace eval punk::lib {
#} #}
proc list_index_resolve {list index} { proc lindex_resolve {list index} {
#*** !doctools
#[call [fun lindex_resolve] [arg list] [arg index]]
#[para]Resolve an index which may be of the forms accepted by Tcl list commands such as end-2 or 2+2 to the actual integer index for the supplied list
#[para]Users may define procs which accept a list index and wish to accept the forms understood by Tcl.
#[para]This means the proc may be called with something like $x+2 end-$y etc
#[para]Sometimes the actual integer index is desired.
#[para]We want to resolve the index used, without passing arbitrary expressions into the 'expr' function - which could have security risks.
#[para]lindex_resolve will parse the index expression and return -1 if the supplied index expression is out of bounds for the supplied list.
#[para]Otherwise it will return an integer corresponding to the position in the list.
#[para]Like Tcl list commands - it will produce an error if the form of the
#Note that for an index such as $x+1 - we never see the '$x' as it is substituted in the calling command. We will get something like 10+1 - which we will resolve (hopefully safely) with expr #Note that for an index such as $x+1 - we never see the '$x' as it is substituted in the calling command. We will get something like 10+1 - which we will resolve (hopefully safely) with expr
if {![llength $list]} { if {![llength $list]} {
return -1 return -1
@ -271,7 +282,7 @@ namespace eval punk::lib {
} }
} }
} }
proc list_index_resolve2 {list index} { proc lindex_resolve2 {list index} {
set indices [list] ;#building this may be somewhat expensive in terms of storage and compute for large lists - we could use lseq in Tcl 8.7+ but that's likely unavailable here. set indices [list] ;#building this may be somewhat expensive in terms of storage and compute for large lists - we could use lseq in Tcl 8.7+ but that's likely unavailable here.
for {set i 0} {$i < [llength $list]} {incr i} { for {set i 0} {$i < [llength $list]} {incr i} {
lappend indices $i lappend indices $i
@ -283,7 +294,7 @@ namespace eval punk::lib {
return $idx return $idx
} }
} }
proc list_index_get {list index} { proc lindex_get {list index} {
set resultlist [lrange $list $index $index] set resultlist [lrange $list $index $index]
if {![llength $resultlist]} { if {![llength $resultlist]} {
return -1 return -1

3076
src/bootsupport/modules/textblock-0.1.1.tm

File diff suppressed because it is too large Load Diff

20
src/embedded/man/files/punk/_module_lib-0.1.1.tm.n

@ -280,6 +280,8 @@ package require \fBpunk::lib \fR
.sp .sp
\fBlpop\fR \fIlistvar\fR ?index? \fBlpop\fR \fIlistvar\fR ?index?
.sp .sp
\fBlindex_resolve\fR \fIlist\fR \fIindex\fR
.sp
\fBK\fR \fIx\fR \fIy\fR \fBK\fR \fIx\fR \fIy\fR
.sp .sp
\fBis_utf8_multibyteprefix\fR \fIstr\fR \fBis_utf8_multibyteprefix\fR \fIstr\fR
@ -377,6 +379,24 @@ Forwards compatible lpop for versions 8\&.6 or less to support equivalent 8\&.7
.PP .PP
Core API functions for punk::lib Core API functions for punk::lib
.TP .TP
\fBlindex_resolve\fR \fIlist\fR \fIindex\fR
.sp
Resolve an index which may be of the forms accepted by Tcl list commands such as end-2 or 2+2 to the actual integer index for the supplied list
.sp
Users may define procs which accept a list index and wish to accept the forms understood by Tcl\&.
.sp
This means the proc may be called with something like $x+2 end-$y etc
.sp
Sometimes the actual integer index is desired\&.
.sp
We want to resolve the index used, without passing arbitrary expressions into the 'expr' function - which could have security risks\&.
.sp
lindex_resolve will parse the index expression and return -1 if the supplied index expression is out of bounds for the supplied list\&.
.sp
Otherwise it will return an integer corresponding to the position in the list\&.
.sp
Like Tcl list commands - it will produce an error if the form of the
.TP
\fBK\fR \fIx\fR \fIy\fR \fBK\fR \fIx\fR \fIy\fR
.sp .sp
The K-combinator function - returns the first argument, x and discards y The K-combinator function - returns the first argument, x and discards y

122
src/embedded/md/doc/files/punk/_module_lib-0.1.1.tm.md

@ -48,31 +48,32 @@ package require punk::lib
[__lremove__ *list* ?index \.\.\.?](#1) [__lremove__ *list* ?index \.\.\.?](#1)
[__lpop__ *listvar* ?index?](#2) [__lpop__ *listvar* ?index?](#2)
[__K__ *x* *y*](#3) [__lindex\_resolve__ *list* *index*](#3)
[__is\_utf8\_multibyteprefix__ *str*](#4) [__K__ *x* *y*](#4)
[__is\_utf8\_single__ *1234bytes*](#5) [__is\_utf8\_multibyteprefix__ *str*](#5)
[__get\_utf8\_leading__ *rawbytes*](#6) [__is\_utf8\_single__ *1234bytes*](#6)
[__hex2dec__ ?option value\.\.\.? *list\_largeHex*](#7) [__get\_utf8\_leading__ *rawbytes*](#7)
[__dex2hex__ ?option value\.\.\.? *list\_decimals*](#8) [__hex2dec__ ?option value\.\.\.? *list\_largeHex*](#8)
[__log2__ *x*](#9) [__dex2hex__ ?option value\.\.\.? *list\_decimals*](#9)
[__logbase__ *b* *x*](#10) [__log2__ *x*](#10)
[__factors__ *x*](#11) [__logbase__ *b* *x*](#11)
[__oddFactors__ *x*](#12) [__factors__ *x*](#12)
[__greatestFactorBelow__ *x*](#13) [__oddFactors__ *x*](#13)
[__greatestOddFactorBelow__ *x*](#14) [__greatestFactorBelow__ *x*](#14)
[__greatestOddFactor__ *x*](#15) [__greatestOddFactorBelow__ *x*](#15)
[__gcd__ *n* *m*](#16) [__greatestOddFactor__ *x*](#16)
[__gcd__ *n* *m*](#17) [__gcd__ *n* *m*](#17)
[__commonDivisors__ *x* *y*](#18) [__gcd__ *n* *m*](#18)
[__hasglobs__ *str*](#19) [__commonDivisors__ *x* *y*](#19)
[__trimzero__ *number*](#20) [__hasglobs__ *str*](#20)
[__substring\_count__ *str* *substring*](#21) [__trimzero__ *number*](#21)
[__dict\_merge\_ordered__ *defaults* *main*](#22) [__substring\_count__ *str* *substring*](#22)
[__askuser__ *question*](#23) [__dict\_merge\_ordered__ *defaults* *main*](#23)
[__linesort__ ?sortoption ?val?\.\.\.? *textblock*](#24) [__askuser__ *question*](#24)
[__list\_as\_lines__ ?\-joinchar char? *linelist*](#25) [__linesort__ ?sortoption ?val?\.\.\.? *textblock*](#25)
[__lines\_as\_list__ ?option value \.\.\.? *text*](#26) [__list\_as\_lines__ ?\-joinchar char? *linelist*](#26)
[__opts\_values__ ?option value\.\.\.? *optionspecs* *rawargs*](#27) [__lines\_as\_list__ ?option value \.\.\.? *text*](#27)
[__opts\_values__ ?option value\.\.\.? *optionspecs* *rawargs*](#28)
# <a name='description'></a>DESCRIPTION # <a name='description'></a>DESCRIPTION
@ -124,7 +125,30 @@ class definitions
Core API functions for punk::lib Core API functions for punk::lib
- <a name='3'></a>__K__ *x* *y* - <a name='3'></a>__lindex\_resolve__ *list* *index*
Resolve an index which may be of the forms accepted by Tcl list commands
such as end\-2 or 2\+2 to the actual integer index for the supplied list
Users may define procs which accept a list index and wish to accept the
forms understood by Tcl\.
This means the proc may be called with something like $x\+2 end\-$y etc
Sometimes the actual integer index is desired\.
We want to resolve the index used, without passing arbitrary expressions
into the 'expr' function \- which could have security risks\.
lindex\_resolve will parse the index expression and return \-1 if the supplied
index expression is out of bounds for the supplied list\.
Otherwise it will return an integer corresponding to the position in the
list\.
Like Tcl list commands \- it will produce an error if the form of the
- <a name='4'></a>__K__ *x* *y*
The K\-combinator function \- returns the first argument, x and discards y The K\-combinator function \- returns the first argument, x and discards y
@ -133,7 +157,7 @@ Core API functions for punk::lib
It is used in cases where command\-substitution at the calling\-point performs It is used in cases where command\-substitution at the calling\-point performs
some desired effect\. some desired effect\.
- <a name='4'></a>__is\_utf8\_multibyteprefix__ *str* - <a name='5'></a>__is\_utf8\_multibyteprefix__ *str*
Returns a boolean if str is potentially a prefix for a multibyte utf\-8 Returns a boolean if str is potentially a prefix for a multibyte utf\-8
character character
@ -152,12 +176,12 @@ Core API functions for punk::lib
e\.g using: set head \[get\_utf8\_leading $testbytes\] ; set tail \[string range e\.g using: set head \[get\_utf8\_leading $testbytes\] ; set tail \[string range
$testbytes \[string length $head\] end\] $testbytes \[string length $head\] end\]
- <a name='5'></a>__is\_utf8\_single__ *1234bytes* - <a name='6'></a>__is\_utf8\_single__ *1234bytes*
Tests input of 1,2,3 or 4 bytes and responds with a boolean indicating if it Tests input of 1,2,3 or 4 bytes and responds with a boolean indicating if it
is a valid utf\-8 character \(codepoint\) is a valid utf\-8 character \(codepoint\)
- <a name='6'></a>__get\_utf8\_leading__ *rawbytes* - <a name='7'></a>__get\_utf8\_leading__ *rawbytes*
return the leading portion of rawbytes that is a valid utf8 sequence\. return the leading portion of rawbytes that is a valid utf8 sequence\.
@ -182,7 +206,7 @@ Core API functions for punk::lib
The utf\-8 BOM \\xEF\\xBB\\xBF is a valid UTF8 3\-byte sequence and so can also The utf\-8 BOM \\xEF\\xBB\\xBF is a valid UTF8 3\-byte sequence and so can also
be returned as part of the leading utf8 bytes be returned as part of the leading utf8 bytes
- <a name='7'></a>__hex2dec__ ?option value\.\.\.? *list\_largeHex* - <a name='8'></a>__hex2dec__ ?option value\.\.\.? *list\_largeHex*
Convert a list of \(possibly large\) unprefixed hex strings to their decimal Convert a list of \(possibly large\) unprefixed hex strings to their decimal
values values
@ -199,7 +223,7 @@ Core API functions for punk::lib
Internal whitespace e\.g "F F" is not permitted \- but a completely empty Internal whitespace e\.g "F F" is not permitted \- but a completely empty
element "" is allowed and will return 0 element "" is allowed and will return 0
- <a name='8'></a>__dex2hex__ ?option value\.\.\.? *list\_decimals* - <a name='9'></a>__dex2hex__ ?option value\.\.\.? *list\_decimals*
Convert a list of decimal integers to a list of hex values Convert a list of decimal integers to a list of hex values
@ -208,7 +232,7 @@ Core API functions for punk::lib
\-case upper&#124;lower determines the case of the hex letters in the output \-case upper&#124;lower determines the case of the hex letters in the output
- <a name='9'></a>__log2__ *x* - <a name='10'></a>__log2__ *x*
log base2 of x log base2 of x
@ -218,7 +242,7 @@ Core API functions for punk::lib
\(courtesy of RS \(courtesy of RS
[https://wiki\.tcl\-lang\.org/page/Additional\+math\+functions](https://wiki\.tcl\-lang\.org/page/Additional\+math\+functions)\) [https://wiki\.tcl\-lang\.org/page/Additional\+math\+functions](https://wiki\.tcl\-lang\.org/page/Additional\+math\+functions)\)
- <a name='10'></a>__logbase__ *b* *x* - <a name='11'></a>__logbase__ *b* *x*
log base b of x log base b of x
@ -229,7 +253,7 @@ Core API functions for punk::lib
Use expr's log10\(\) function or tcl::mathfunc::log10 for base 10 Use expr's log10\(\) function or tcl::mathfunc::log10 for base 10
- <a name='11'></a>__factors__ *x* - <a name='12'></a>__factors__ *x*
Return a sorted list of the positive factors of x where x > 0 Return a sorted list of the positive factors of x where x > 0
@ -265,11 +289,11 @@ Core API functions for punk::lib
In other mathematical contexts zero may be considered not to divide In other mathematical contexts zero may be considered not to divide
anything\. anything\.
- <a name='12'></a>__oddFactors__ *x* - <a name='13'></a>__oddFactors__ *x*
Return a list of odd integer factors of x, sorted in ascending order Return a list of odd integer factors of x, sorted in ascending order
- <a name='13'></a>__greatestFactorBelow__ *x* - <a name='14'></a>__greatestFactorBelow__ *x*
Return the largest factor of x excluding itself Return the largest factor of x excluding itself
@ -277,17 +301,17 @@ Core API functions for punk::lib
See Tcllib math::numtheory for more extensive implementations See Tcllib math::numtheory for more extensive implementations
- <a name='14'></a>__greatestOddFactorBelow__ *x* - <a name='15'></a>__greatestOddFactorBelow__ *x*
Return the largest odd integer factor of x excluding x itself Return the largest odd integer factor of x excluding x itself
- <a name='15'></a>__greatestOddFactor__ *x* - <a name='16'></a>__greatestOddFactor__ *x*
Return the largest odd integer factor of x Return the largest odd integer factor of x
For an odd value of x \- this will always return x For an odd value of x \- this will always return x
- <a name='16'></a>__gcd__ *n* *m* - <a name='17'></a>__gcd__ *n* *m*
Return the greatest common divisor of m and n Return the greatest common divisor of m and n
@ -299,19 +323,19 @@ Core API functions for punk::lib
only if c is a common divisor of a and b only if c is a common divisor of a and b
- <a name='17'></a>__gcd__ *n* *m* - <a name='18'></a>__gcd__ *n* *m*
Return the lowest common multiple of m and n Return the lowest common multiple of m and n
Straight from Lars Hellström's math::numtheory library in Tcllib Straight from Lars Hellström's math::numtheory library in Tcllib
- <a name='18'></a>__commonDivisors__ *x* *y* - <a name='19'></a>__commonDivisors__ *x* *y*
Return a list of all the common factors of x and y Return a list of all the common factors of x and y
\(equivalent to factors of their gcd\) \(equivalent to factors of their gcd\)
- <a name='19'></a>__hasglobs__ *str* - <a name='20'></a>__hasglobs__ *str*
Return a boolean indicating whether str contains any of the glob characters: Return a boolean indicating whether str contains any of the glob characters:
\* ? \[ \] \* ? \[ \]
@ -319,17 +343,17 @@ Core API functions for punk::lib
hasglobs uses append to preserve Tcls internal representation for str \- so hasglobs uses append to preserve Tcls internal representation for str \- so
it should help avoid shimmering in the few cases where this may matter\. it should help avoid shimmering in the few cases where this may matter\.
- <a name='20'></a>__trimzero__ *number* - <a name='21'></a>__trimzero__ *number*
Return number with left\-hand\-side zeros trimmed off \- unless all zero Return number with left\-hand\-side zeros trimmed off \- unless all zero
If number is all zero \- a single 0 is returned If number is all zero \- a single 0 is returned
- <a name='21'></a>__substring\_count__ *str* *substring* - <a name='22'></a>__substring\_count__ *str* *substring*
Search str and return number of occurrences of substring Search str and return number of occurrences of substring
- <a name='22'></a>__dict\_merge\_ordered__ *defaults* *main* - <a name='23'></a>__dict\_merge\_ordered__ *defaults* *main*
The standard dict merge accepts multiple dicts with values from dicts to the The standard dict merge accepts multiple dicts with values from dicts to the
right \(2nd argument\) taking precedence\. right \(2nd argument\) taking precedence\.
@ -341,7 +365,7 @@ Core API functions for punk::lib
This function merges the two dicts whilst maintaining the key order of main This function merges the two dicts whilst maintaining the key order of main
followed by defaults\. followed by defaults\.
- <a name='23'></a>__askuser__ *question* - <a name='24'></a>__askuser__ *question*
A basic utility to read an answer from stdin A basic utility to read an answer from stdin
@ -370,7 +394,7 @@ Core API functions for punk::lib
puts "Cancelled by user" puts "Cancelled by user"
} }
- <a name='24'></a>__linesort__ ?sortoption ?val?\.\.\.? *textblock* - <a name='25'></a>__linesort__ ?sortoption ?val?\.\.\.? *textblock*
Sort lines in textblock Sort lines in textblock
@ -379,7 +403,7 @@ Core API functions for punk::lib
options are flags as accepted by lsort ie \-ascii \-command \-decreasing options are flags as accepted by lsort ie \-ascii \-command \-decreasing
\-dictionary \-index \-indices \-integer \-nocase \-real \-stride \-unique \-dictionary \-index \-indices \-integer \-nocase \-real \-stride \-unique
- <a name='25'></a>__list\_as\_lines__ ?\-joinchar char? *linelist* - <a name='26'></a>__list\_as\_lines__ ?\-joinchar char? *linelist*
This simply joines the elements of the list with \-joinchar This simply joines the elements of the list with \-joinchar
@ -391,7 +415,7 @@ Core API functions for punk::lib
lines \- but with more options related to trimming the block and/or each lines \- but with more options related to trimming the block and/or each
line\. line\.
- <a name='26'></a>__lines\_as\_list__ ?option value \.\.\.? *text* - <a name='27'></a>__lines\_as\_list__ ?option value \.\.\.? *text*
Returns a list of possibly trimmed lines depeding on options Returns a list of possibly trimmed lines depeding on options
@ -401,7 +425,7 @@ Core API functions for punk::lib
\- not console lines which may be entirely different due to control \- not console lines which may be entirely different due to control
characters such as vertical tabs or ANSI movements characters such as vertical tabs or ANSI movements
- <a name='27'></a>__opts\_values__ ?option value\.\.\.? *optionspecs* *rawargs* - <a name='28'></a>__opts\_values__ ?option value\.\.\.? *optionspecs* *rawargs*
Parse rawargs as a sequence of zero or more option\-value pairs followed by Parse rawargs as a sequence of zero or more option\-value pairs followed by
zero or more values zero or more values

108
src/embedded/www/doc/files/punk/_module_lib-0.1.1.tm.html

@ -142,31 +142,32 @@
<ul class="doctools_syntax"> <ul class="doctools_syntax">
<li><a href="#1"><b class="function">lremove</b> <i class="arg">list</i> <span class="opt">?index ...?</span></a></li> <li><a href="#1"><b class="function">lremove</b> <i class="arg">list</i> <span class="opt">?index ...?</span></a></li>
<li><a href="#2"><b class="function">lpop</b> <i class="arg">listvar</i> <span class="opt">?index?</span></a></li> <li><a href="#2"><b class="function">lpop</b> <i class="arg">listvar</i> <span class="opt">?index?</span></a></li>
<li><a href="#3"><b class="function">K</b> <i class="arg">x</i> <i class="arg">y</i></a></li> <li><a href="#3"><b class="function">lindex_resolve</b> <i class="arg">list</i> <i class="arg">index</i></a></li>
<li><a href="#4"><b class="function">is_utf8_multibyteprefix</b> <i class="arg">str</i></a></li> <li><a href="#4"><b class="function">K</b> <i class="arg">x</i> <i class="arg">y</i></a></li>
<li><a href="#5"><b class="function">is_utf8_single</b> <i class="arg">1234bytes</i></a></li> <li><a href="#5"><b class="function">is_utf8_multibyteprefix</b> <i class="arg">str</i></a></li>
<li><a href="#6"><b class="function">get_utf8_leading</b> <i class="arg">rawbytes</i></a></li> <li><a href="#6"><b class="function">is_utf8_single</b> <i class="arg">1234bytes</i></a></li>
<li><a href="#7"><b class="function">hex2dec</b> <span class="opt">?option value...?</span> <i class="arg">list_largeHex</i></a></li> <li><a href="#7"><b class="function">get_utf8_leading</b> <i class="arg">rawbytes</i></a></li>
<li><a href="#8"><b class="function">dex2hex</b> <span class="opt">?option value...?</span> <i class="arg">list_decimals</i></a></li> <li><a href="#8"><b class="function">hex2dec</b> <span class="opt">?option value...?</span> <i class="arg">list_largeHex</i></a></li>
<li><a href="#9"><b class="function">log2</b> <i class="arg">x</i></a></li> <li><a href="#9"><b class="function">dex2hex</b> <span class="opt">?option value...?</span> <i class="arg">list_decimals</i></a></li>
<li><a href="#10"><b class="function">logbase</b> <i class="arg">b</i> <i class="arg">x</i></a></li> <li><a href="#10"><b class="function">log2</b> <i class="arg">x</i></a></li>
<li><a href="#11"><b class="function">factors</b> <i class="arg">x</i></a></li> <li><a href="#11"><b class="function">logbase</b> <i class="arg">b</i> <i class="arg">x</i></a></li>
<li><a href="#12"><b class="function">oddFactors</b> <i class="arg">x</i></a></li> <li><a href="#12"><b class="function">factors</b> <i class="arg">x</i></a></li>
<li><a href="#13"><b class="function">greatestFactorBelow</b> <i class="arg">x</i></a></li> <li><a href="#13"><b class="function">oddFactors</b> <i class="arg">x</i></a></li>
<li><a href="#14"><b class="function">greatestOddFactorBelow</b> <i class="arg">x</i></a></li> <li><a href="#14"><b class="function">greatestFactorBelow</b> <i class="arg">x</i></a></li>
<li><a href="#15"><b class="function">greatestOddFactor</b> <i class="arg">x</i></a></li> <li><a href="#15"><b class="function">greatestOddFactorBelow</b> <i class="arg">x</i></a></li>
<li><a href="#16"><b class="function">gcd</b> <i class="arg">n</i> <i class="arg">m</i></a></li> <li><a href="#16"><b class="function">greatestOddFactor</b> <i class="arg">x</i></a></li>
<li><a href="#17"><b class="function">gcd</b> <i class="arg">n</i> <i class="arg">m</i></a></li> <li><a href="#17"><b class="function">gcd</b> <i class="arg">n</i> <i class="arg">m</i></a></li>
<li><a href="#18"><b class="function">commonDivisors</b> <i class="arg">x</i> <i class="arg">y</i></a></li> <li><a href="#18"><b class="function">gcd</b> <i class="arg">n</i> <i class="arg">m</i></a></li>
<li><a href="#19"><b class="function">hasglobs</b> <i class="arg">str</i></a></li> <li><a href="#19"><b class="function">commonDivisors</b> <i class="arg">x</i> <i class="arg">y</i></a></li>
<li><a href="#20"><b class="function">trimzero</b> <i class="arg">number</i></a></li> <li><a href="#20"><b class="function">hasglobs</b> <i class="arg">str</i></a></li>
<li><a href="#21"><b class="function">substring_count</b> <i class="arg">str</i> <i class="arg">substring</i></a></li> <li><a href="#21"><b class="function">trimzero</b> <i class="arg">number</i></a></li>
<li><a href="#22"><b class="function">dict_merge_ordered</b> <i class="arg">defaults</i> <i class="arg">main</i></a></li> <li><a href="#22"><b class="function">substring_count</b> <i class="arg">str</i> <i class="arg">substring</i></a></li>
<li><a href="#23"><b class="function">askuser</b> <i class="arg">question</i></a></li> <li><a href="#23"><b class="function">dict_merge_ordered</b> <i class="arg">defaults</i> <i class="arg">main</i></a></li>
<li><a href="#24"><b class="function">linesort</b> <span class="opt">?sortoption ?val?...?</span> <i class="arg">textblock</i></a></li> <li><a href="#24"><b class="function">askuser</b> <i class="arg">question</i></a></li>
<li><a href="#25"><b class="function">list_as_lines</b> <span class="opt">?-joinchar char?</span> <i class="arg">linelist</i></a></li> <li><a href="#25"><b class="function">linesort</b> <span class="opt">?sortoption ?val?...?</span> <i class="arg">textblock</i></a></li>
<li><a href="#26"><b class="function">lines_as_list</b> <span class="opt">?option value ...?</span> <i class="arg">text</i></a></li> <li><a href="#26"><b class="function">list_as_lines</b> <span class="opt">?-joinchar char?</span> <i class="arg">linelist</i></a></li>
<li><a href="#27"><b class="function">opts_values</b> <span class="opt">?option value...?</span> <i class="arg">optionspecs</i> <i class="arg">rawargs</i></a></li> <li><a href="#27"><b class="function">lines_as_list</b> <span class="opt">?option value ...?</span> <i class="arg">text</i></a></li>
<li><a href="#28"><b class="function">opts_values</b> <span class="opt">?option value...?</span> <i class="arg">optionspecs</i> <i class="arg">rawargs</i></a></li>
</ul> </ul>
</div> </div>
</div> </div>
@ -208,20 +209,29 @@
<div id="subsection5" class="doctools_subsection"><h3><a name="subsection5">Namespace punk::lib</a></h3> <div id="subsection5" class="doctools_subsection"><h3><a name="subsection5">Namespace punk::lib</a></h3>
<p>Core API functions for punk::lib</p> <p>Core API functions for punk::lib</p>
<dl class="doctools_definitions"> <dl class="doctools_definitions">
<dt><a name="3"><b class="function">K</b> <i class="arg">x</i> <i class="arg">y</i></a></dt> <dt><a name="3"><b class="function">lindex_resolve</b> <i class="arg">list</i> <i class="arg">index</i></a></dt>
<dd><p>Resolve an index which may be of the forms accepted by Tcl list commands such as end-2 or 2+2 to the actual integer index for the supplied list</p>
<p>Users may define procs which accept a list index and wish to accept the forms understood by Tcl.</p>
<p>This means the proc may be called with something like $x+2 end-$y etc</p>
<p>Sometimes the actual integer index is desired.</p>
<p>We want to resolve the index used, without passing arbitrary expressions into the 'expr' function - which could have security risks.</p>
<p>lindex_resolve will parse the index expression and return -1 if the supplied index expression is out of bounds for the supplied list.</p>
<p>Otherwise it will return an integer corresponding to the position in the list.</p>
<p>Like Tcl list commands - it will produce an error if the form of the</p></dd>
<dt><a name="4"><b class="function">K</b> <i class="arg">x</i> <i class="arg">y</i></a></dt>
<dd><p>The K-combinator function - returns the first argument, x and discards y</p> <dd><p>The K-combinator function - returns the first argument, x and discards y</p>
<p>see <a href="https://wiki.tcl-lang.org/page/K">https://wiki.tcl-lang.org/page/K</a></p> <p>see <a href="https://wiki.tcl-lang.org/page/K">https://wiki.tcl-lang.org/page/K</a></p>
<p>It is used in cases where command-substitution at the calling-point performs some desired effect.</p></dd> <p>It is used in cases where command-substitution at the calling-point performs some desired effect.</p></dd>
<dt><a name="4"><b class="function">is_utf8_multibyteprefix</b> <i class="arg">str</i></a></dt> <dt><a name="5"><b class="function">is_utf8_multibyteprefix</b> <i class="arg">str</i></a></dt>
<dd><p>Returns a boolean if str is potentially a prefix for a multibyte utf-8 character</p> <dd><p>Returns a boolean if str is potentially a prefix for a multibyte utf-8 character</p>
<p>ie - tests if it is possible that appending more data will result in a utf-8 codepoint</p> <p>ie - tests if it is possible that appending more data will result in a utf-8 codepoint</p>
<p>Will return false for an already complete utf-8 codepoint</p> <p>Will return false for an already complete utf-8 codepoint</p>
<p>It is assumed the incomplete sequence is at the beginning of the bytes argument</p> <p>It is assumed the incomplete sequence is at the beginning of the bytes argument</p>
<p>Suitable input for this might be from the unreturned tail portion of get_utf8_leading $testbytes</p> <p>Suitable input for this might be from the unreturned tail portion of get_utf8_leading $testbytes</p>
<p>e.g using: set head [get_utf8_leading $testbytes] ; set tail [string range $testbytes [string length $head] end]</p></dd> <p>e.g using: set head [get_utf8_leading $testbytes] ; set tail [string range $testbytes [string length $head] end]</p></dd>
<dt><a name="5"><b class="function">is_utf8_single</b> <i class="arg">1234bytes</i></a></dt> <dt><a name="6"><b class="function">is_utf8_single</b> <i class="arg">1234bytes</i></a></dt>
<dd><p>Tests input of 1,2,3 or 4 bytes and responds with a boolean indicating if it is a valid utf-8 character (codepoint)</p></dd> <dd><p>Tests input of 1,2,3 or 4 bytes and responds with a boolean indicating if it is a valid utf-8 character (codepoint)</p></dd>
<dt><a name="6"><b class="function">get_utf8_leading</b> <i class="arg">rawbytes</i></a></dt> <dt><a name="7"><b class="function">get_utf8_leading</b> <i class="arg">rawbytes</i></a></dt>
<dd><p>return the leading portion of rawbytes that is a valid utf8 sequence.</p> <dd><p>return the leading portion of rawbytes that is a valid utf8 sequence.</p>
<p>This will stop at the point at which the bytes can't be interpreted as a complete utf-8 codepoint</p> <p>This will stop at the point at which the bytes can't be interpreted as a complete utf-8 codepoint</p>
<p>e.g It will not return the first byte or 2 of a 3-byte utf-8 character if the last byte is missing, and will return only the valid utf-8 string from before the first byte of the incomplete character.</p> <p>e.g It will not return the first byte or 2 of a 3-byte utf-8 character if the last byte is missing, and will return only the valid utf-8 string from before the first byte of the incomplete character.</p>
@ -229,26 +239,26 @@
<p>Note that while this will return valid utf8 - it has no knowledge of grapheme clusters or diacritics</p> <p>Note that while this will return valid utf8 - it has no knowledge of grapheme clusters or diacritics</p>
<p>This means if it is being used to process bytes split at some arbitrary point - the trailing data that isn't returned could be part of a grapheme cluster that belongs with the last character of the leading string already returned</p> <p>This means if it is being used to process bytes split at some arbitrary point - the trailing data that isn't returned could be part of a grapheme cluster that belongs with the last character of the leading string already returned</p>
<p>The utf-8 BOM \xEF\xBB\xBF is a valid UTF8 3-byte sequence and so can also be returned as part of the leading utf8 bytes</p></dd> <p>The utf-8 BOM \xEF\xBB\xBF is a valid UTF8 3-byte sequence and so can also be returned as part of the leading utf8 bytes</p></dd>
<dt><a name="7"><b class="function">hex2dec</b> <span class="opt">?option value...?</span> <i class="arg">list_largeHex</i></a></dt> <dt><a name="8"><b class="function">hex2dec</b> <span class="opt">?option value...?</span> <i class="arg">list_largeHex</i></a></dt>
<dd><p>Convert a list of (possibly large) unprefixed hex strings to their decimal values</p> <dd><p>Convert a list of (possibly large) unprefixed hex strings to their decimal values</p>
<p>hex2dec accepts and ignores internal underscores in the same manner as Tcl 8.7+ numbers e.g hex2dec FF_FF returns 65535</p> <p>hex2dec accepts and ignores internal underscores in the same manner as Tcl 8.7+ numbers e.g hex2dec FF_FF returns 65535</p>
<p>Leading and trailing underscores are ignored as a matter of implementation convenience - but this shouldn't be relied upon.</p> <p>Leading and trailing underscores are ignored as a matter of implementation convenience - but this shouldn't be relied upon.</p>
<p>Leading or trailing whitespace in each list member is allowed e.g hex2dec &quot; F&quot; returns 15</p> <p>Leading or trailing whitespace in each list member is allowed e.g hex2dec &quot; F&quot; returns 15</p>
<p>Internal whitespace e.g &quot;F F&quot; is not permitted - but a completely empty element &quot;&quot; is allowed and will return 0</p></dd> <p>Internal whitespace e.g &quot;F F&quot; is not permitted - but a completely empty element &quot;&quot; is allowed and will return 0</p></dd>
<dt><a name="8"><b class="function">dex2hex</b> <span class="opt">?option value...?</span> <i class="arg">list_decimals</i></a></dt> <dt><a name="9"><b class="function">dex2hex</b> <span class="opt">?option value...?</span> <i class="arg">list_decimals</i></a></dt>
<dd><p>Convert a list of decimal integers to a list of hex values</p> <dd><p>Convert a list of decimal integers to a list of hex values</p>
<p>-width &lt;int&gt; can be used to make each hex value at least int characters wide, with leading zeroes.</p> <p>-width &lt;int&gt; can be used to make each hex value at least int characters wide, with leading zeroes.</p>
<p>-case upper|lower determines the case of the hex letters in the output</p></dd> <p>-case upper|lower determines the case of the hex letters in the output</p></dd>
<dt><a name="9"><b class="function">log2</b> <i class="arg">x</i></a></dt> <dt><a name="10"><b class="function">log2</b> <i class="arg">x</i></a></dt>
<dd><p>log base2 of x</p> <dd><p>log base2 of x</p>
<p>This uses a 'live' proc body - the divisor for the change of base is computed once at definition time</p> <p>This uses a 'live' proc body - the divisor for the change of base is computed once at definition time</p>
<p>(courtesy of RS <a href="https://wiki.tcl-lang.org/page/Additional+math+functions">https://wiki.tcl-lang.org/page/Additional+math+functions</a>)</p></dd> <p>(courtesy of RS <a href="https://wiki.tcl-lang.org/page/Additional+math+functions">https://wiki.tcl-lang.org/page/Additional+math+functions</a>)</p></dd>
<dt><a name="10"><b class="function">logbase</b> <i class="arg">b</i> <i class="arg">x</i></a></dt> <dt><a name="11"><b class="function">logbase</b> <i class="arg">b</i> <i class="arg">x</i></a></dt>
<dd><p>log base b of x</p> <dd><p>log base b of x</p>
<p>This function uses expr's natural log and the change of base division.</p> <p>This function uses expr's natural log and the change of base division.</p>
<p>This means for example that we can get results like: logbase 10 1000 = 2.9999999999999996</p> <p>This means for example that we can get results like: logbase 10 1000 = 2.9999999999999996</p>
<p>Use expr's log10() function or tcl::mathfunc::log10 for base 10</p></dd> <p>Use expr's log10() function or tcl::mathfunc::log10 for base 10</p></dd>
<dt><a name="11"><b class="function">factors</b> <i class="arg">x</i></a></dt> <dt><a name="12"><b class="function">factors</b> <i class="arg">x</i></a></dt>
<dd><p>Return a sorted list of the positive factors of x where x &gt; 0</p> <dd><p>Return a sorted list of the positive factors of x where x &gt; 0</p>
<p>For x = 0 we return only 0 and 1 as technically any number divides zero and there are an infinite number of factors. (including zero itself in this context)*</p> <p>For x = 0 we return only 0 and 1 as technically any number divides zero and there are an infinite number of factors. (including zero itself in this context)*</p>
<p>This is a simple brute-force implementation that iterates all numbers below the square root of x to check the factors</p> <p>This is a simple brute-force implementation that iterates all numbers below the square root of x to check the factors</p>
@ -261,42 +271,42 @@ but has the disadvantage of being slower for 'small' numbers and using more memo
<p>If the largest factor below x is needed - the greatestOddFactorBelow and GreatestFactorBelow functions are a faster way to get there than computing the whole list, even for small values of x</p> <p>If the largest factor below x is needed - the greatestOddFactorBelow and GreatestFactorBelow functions are a faster way to get there than computing the whole list, even for small values of x</p>
<p>* Taking x=0; Notion of x being divisible by integer y being: There exists an integer p such that x = py</p> <p>* Taking x=0; Notion of x being divisible by integer y being: There exists an integer p such that x = py</p>
<p>In other mathematical contexts zero may be considered not to divide anything.</p></dd> <p>In other mathematical contexts zero may be considered not to divide anything.</p></dd>
<dt><a name="12"><b class="function">oddFactors</b> <i class="arg">x</i></a></dt> <dt><a name="13"><b class="function">oddFactors</b> <i class="arg">x</i></a></dt>
<dd><p>Return a list of odd integer factors of x, sorted in ascending order</p></dd> <dd><p>Return a list of odd integer factors of x, sorted in ascending order</p></dd>
<dt><a name="13"><b class="function">greatestFactorBelow</b> <i class="arg">x</i></a></dt> <dt><a name="14"><b class="function">greatestFactorBelow</b> <i class="arg">x</i></a></dt>
<dd><p>Return the largest factor of x excluding itself</p> <dd><p>Return the largest factor of x excluding itself</p>
<p>factor functions can be useful for console layout calculations</p> <p>factor functions can be useful for console layout calculations</p>
<p>See Tcllib math::numtheory for more extensive implementations</p></dd> <p>See Tcllib math::numtheory for more extensive implementations</p></dd>
<dt><a name="14"><b class="function">greatestOddFactorBelow</b> <i class="arg">x</i></a></dt> <dt><a name="15"><b class="function">greatestOddFactorBelow</b> <i class="arg">x</i></a></dt>
<dd><p>Return the largest odd integer factor of x excluding x itself</p></dd> <dd><p>Return the largest odd integer factor of x excluding x itself</p></dd>
<dt><a name="15"><b class="function">greatestOddFactor</b> <i class="arg">x</i></a></dt> <dt><a name="16"><b class="function">greatestOddFactor</b> <i class="arg">x</i></a></dt>
<dd><p>Return the largest odd integer factor of x</p> <dd><p>Return the largest odd integer factor of x</p>
<p>For an odd value of x - this will always return x</p></dd> <p>For an odd value of x - this will always return x</p></dd>
<dt><a name="16"><b class="function">gcd</b> <i class="arg">n</i> <i class="arg">m</i></a></dt> <dt><a name="17"><b class="function">gcd</b> <i class="arg">n</i> <i class="arg">m</i></a></dt>
<dd><p>Return the greatest common divisor of m and n</p> <dd><p>Return the greatest common divisor of m and n</p>
<p>Straight from Lars Hellstr&ouml;m's math::numtheory library in Tcllib</p> <p>Straight from Lars Hellstr&ouml;m's math::numtheory library in Tcllib</p>
<p>Graphical use:</p> <p>Graphical use:</p>
<p>An a by b rectangle can be covered with square tiles of side-length c,</p> <p>An a by b rectangle can be covered with square tiles of side-length c,</p>
<p>only if c is a common divisor of a and b</p></dd> <p>only if c is a common divisor of a and b</p></dd>
<dt><a name="17"><b class="function">gcd</b> <i class="arg">n</i> <i class="arg">m</i></a></dt> <dt><a name="18"><b class="function">gcd</b> <i class="arg">n</i> <i class="arg">m</i></a></dt>
<dd><p>Return the lowest common multiple of m and n</p> <dd><p>Return the lowest common multiple of m and n</p>
<p>Straight from Lars Hellstr&ouml;m's math::numtheory library in Tcllib</p></dd> <p>Straight from Lars Hellstr&ouml;m's math::numtheory library in Tcllib</p></dd>
<dt><a name="18"><b class="function">commonDivisors</b> <i class="arg">x</i> <i class="arg">y</i></a></dt> <dt><a name="19"><b class="function">commonDivisors</b> <i class="arg">x</i> <i class="arg">y</i></a></dt>
<dd><p>Return a list of all the common factors of x and y</p> <dd><p>Return a list of all the common factors of x and y</p>
<p>(equivalent to factors of their gcd)</p></dd> <p>(equivalent to factors of their gcd)</p></dd>
<dt><a name="19"><b class="function">hasglobs</b> <i class="arg">str</i></a></dt> <dt><a name="20"><b class="function">hasglobs</b> <i class="arg">str</i></a></dt>
<dd><p>Return a boolean indicating whether str contains any of the glob characters: * ? [ ]</p> <dd><p>Return a boolean indicating whether str contains any of the glob characters: * ? [ ]</p>
<p>hasglobs uses append to preserve Tcls internal representation for str - so it should help avoid shimmering in the few cases where this may matter.</p></dd> <p>hasglobs uses append to preserve Tcls internal representation for str - so it should help avoid shimmering in the few cases where this may matter.</p></dd>
<dt><a name="20"><b class="function">trimzero</b> <i class="arg">number</i></a></dt> <dt><a name="21"><b class="function">trimzero</b> <i class="arg">number</i></a></dt>
<dd><p>Return number with left-hand-side zeros trimmed off - unless all zero</p> <dd><p>Return number with left-hand-side zeros trimmed off - unless all zero</p>
<p>If number is all zero - a single 0 is returned</p></dd> <p>If number is all zero - a single 0 is returned</p></dd>
<dt><a name="21"><b class="function">substring_count</b> <i class="arg">str</i> <i class="arg">substring</i></a></dt> <dt><a name="22"><b class="function">substring_count</b> <i class="arg">str</i> <i class="arg">substring</i></a></dt>
<dd><p>Search str and return number of occurrences of substring</p></dd> <dd><p>Search str and return number of occurrences of substring</p></dd>
<dt><a name="22"><b class="function">dict_merge_ordered</b> <i class="arg">defaults</i> <i class="arg">main</i></a></dt> <dt><a name="23"><b class="function">dict_merge_ordered</b> <i class="arg">defaults</i> <i class="arg">main</i></a></dt>
<dd><p>The standard dict merge accepts multiple dicts with values from dicts to the right (2nd argument) taking precedence.</p> <dd><p>The standard dict merge accepts multiple dicts with values from dicts to the right (2nd argument) taking precedence.</p>
<p>When merging with a dict of default values - this means that any default key/vals that weren't in the main dict appear in the output before the main data.</p> <p>When merging with a dict of default values - this means that any default key/vals that weren't in the main dict appear in the output before the main data.</p>
<p>This function merges the two dicts whilst maintaining the key order of main followed by defaults.</p></dd> <p>This function merges the two dicts whilst maintaining the key order of main followed by defaults.</p></dd>
<dt><a name="23"><b class="function">askuser</b> <i class="arg">question</i></a></dt> <dt><a name="24"><b class="function">askuser</b> <i class="arg">question</i></a></dt>
<dd><p>A basic utility to read an answer from stdin</p> <dd><p>A basic utility to read an answer from stdin</p>
<p>The prompt is written to the terminal and then it waits for a user to type something</p> <p>The prompt is written to the terminal and then it waits for a user to type something</p>
<p>stdin is temporarily configured to blocking and then put back in its original state in case it wasn't already so.</p> <p>stdin is temporarily configured to blocking and then put back in its original state in case it wasn't already so.</p>
@ -314,19 +324,19 @@ but has the disadvantage of being slower for 'small' numbers and using more memo
} }
</pre> </pre>
</dd> </dd>
<dt><a name="24"><b class="function">linesort</b> <span class="opt">?sortoption ?val?...?</span> <i class="arg">textblock</i></a></dt> <dt><a name="25"><b class="function">linesort</b> <span class="opt">?sortoption ?val?...?</span> <i class="arg">textblock</i></a></dt>
<dd><p>Sort lines in textblock</p> <dd><p>Sort lines in textblock</p>
<p>Returns another textblock with lines sorted</p> <p>Returns another textblock with lines sorted</p>
<p>options are flags as accepted by lsort ie -ascii -command -decreasing -dictionary -index -indices -integer -nocase -real -stride -unique</p></dd> <p>options are flags as accepted by lsort ie -ascii -command -decreasing -dictionary -index -indices -integer -nocase -real -stride -unique</p></dd>
<dt><a name="25"><b class="function">list_as_lines</b> <span class="opt">?-joinchar char?</span> <i class="arg">linelist</i></a></dt> <dt><a name="26"><b class="function">list_as_lines</b> <span class="opt">?-joinchar char?</span> <i class="arg">linelist</i></a></dt>
<dd><p>This simply joines the elements of the list with -joinchar</p> <dd><p>This simply joines the elements of the list with -joinchar</p>
<p>It is mainly intended for use in pipelines where the primary argument comes at the end - but it can also be used as a general replacement for join $lines &lt;le&gt;</p> <p>It is mainly intended for use in pipelines where the primary argument comes at the end - but it can also be used as a general replacement for join $lines &lt;le&gt;</p>
<p>The sister function lines_as_list takes a block of text and splits it into lines - but with more options related to trimming the block and/or each line.</p></dd> <p>The sister function lines_as_list takes a block of text and splits it into lines - but with more options related to trimming the block and/or each line.</p></dd>
<dt><a name="26"><b class="function">lines_as_list</b> <span class="opt">?option value ...?</span> <i class="arg">text</i></a></dt> <dt><a name="27"><b class="function">lines_as_list</b> <span class="opt">?option value ...?</span> <i class="arg">text</i></a></dt>
<dd><p>Returns a list of possibly trimmed lines depeding on options</p> <dd><p>Returns a list of possibly trimmed lines depeding on options</p>
<p>The concept of lines is raw lines from splitting on newline after crlf is mapped to lf</p> <p>The concept of lines is raw lines from splitting on newline after crlf is mapped to lf</p>
<p>- not console lines which may be entirely different due to control characters such as vertical tabs or ANSI movements</p></dd> <p>- not console lines which may be entirely different due to control characters such as vertical tabs or ANSI movements</p></dd>
<dt><a name="27"><b class="function">opts_values</b> <span class="opt">?option value...?</span> <i class="arg">optionspecs</i> <i class="arg">rawargs</i></a></dt> <dt><a name="28"><b class="function">opts_values</b> <span class="opt">?option value...?</span> <i class="arg">optionspecs</i> <i class="arg">rawargs</i></a></dt>
<dd><p>Parse rawargs as a sequence of zero or more option-value pairs followed by zero or more values</p> <dd><p>Parse rawargs as a sequence of zero or more option-value pairs followed by zero or more values</p>
<p>Returns a dict of the form: opts &lt;options_dict&gt; values &lt;values_dict&gt;</p> <p>Returns a dict of the form: opts &lt;options_dict&gt; values &lt;values_dict&gt;</p>
<p>ARGUMENTS:</p> <p>ARGUMENTS:</p>

63
src/modules/punk/ansi-999999.0a1.0.tm

@ -1748,6 +1748,7 @@ namespace eval punk::ansi {
dict set codestate_empty bg "" ;#40-47 + 100-107 dict set codestate_empty bg "" ;#40-47 + 100-107
#misnomer should have been sgr_merge_args ? :/
#as a common case optimisation - it will not merge a single element list, even if that code contains redundant elements #as a common case optimisation - it will not merge a single element list, even if that code contains redundant elements
proc sgr_merge_list {args} { proc sgr_merge_list {args} {
if {[llength $args] == 0} { if {[llength $args] == 0} {
@ -1755,9 +1756,30 @@ namespace eval punk::ansi {
} elseif {[llength $args] == 1} { } elseif {[llength $args] == 1} {
return [lindex $args 0] return [lindex $args 0]
} }
sgr_merge $args
}
#codes *must* already have been split so that one esc per element in codelist
#e.g codelist [a+ Yellow Red underline] [a+ blue] [a+ red] is ok
#but codelist "[a+ Yellow Red underline][a+ blue]" [a+ red] is not
#(use punk::ansi::ta::split_codes_single)
proc sgr_merge {codelist args} {
variable codestate_empty variable codestate_empty
set othercodes [list] set othercodes [list]
set defaults [dict create\
-filter_fg 0\
-filter_bg 0\
]
dict for {k v} $args {
switch -- $k {
-filter_fg - -filter_bg {}
default {
error "sgr_merge unknown option '$k'. Known options [dict keys $defaults]"
}
}
}
set opts [dict merge $defaults $args]
set codestate $codestate_empty set codestate $codestate_empty
set codestate_initial $codestate_empty ;#keep a copy for resets. set codestate_initial $codestate_empty ;#keep a copy for resets.
set did_reset 0 set did_reset 0
@ -1772,7 +1794,7 @@ namespace eval punk::ansi {
#We still output any non SGR codes in the list as they came in - preserving their CSI #We still output any non SGR codes in the list as they came in - preserving their CSI
foreach c $args { foreach c $codelist {
#normalize 8bit to a token of the same length so our string operations on the code are the same and we can maintain a switch statement with literals rather than escapes #normalize 8bit to a token of the same length so our string operations on the code are the same and we can maintain a switch statement with literals rather than escapes
#.. but preserve original c #.. but preserve original c
#set cnorm [string map [list \x9b {8[} ] $c] #set cnorm [string map [list \x9b {8[} ] $c]
@ -1911,7 +1933,7 @@ namespace eval punk::ansi {
dict set codestate hide 28 ;#reveal dict set codestate hide 28 ;#reveal
} }
29 { 29 {
dict set codestate strik 29;#off dict set codestate strike 29;#off
} }
30 - 31 - 32 - 33 - 34 - 35 - 36 - 37 { 30 - 31 - 32 - 33 - 34 - 35 - 36 - 37 {
dict set codestate fg $p ;#foreground colour dict set codestate fg $p ;#foreground colour
@ -2067,13 +2089,38 @@ namespace eval punk::ansi {
} }
set codemerge "" set codemerge ""
dict for {k v} $codestate { if {[dict get $opts -filter_fg] || [dict get $opts -filter_bg]} {
switch -- $v { dict for {k v} $codestate {
"" { switch -- $v {
"" {
}
default {
switch -- $k {
bg {
if {![dict get $opts -filter_bg]} {
append codemerge "${v}\;"
}
}
fg {
if {![dict get $opts -filter_fg]} {
append codemerge "${v}\;"
}
}
default {
append codemerge "${v}\;"
}
}
}
} }
default { }
append codemerge "${v}\;" } else {
dict for {k v} $codestate {
switch -- $v {
"" {}
default {
append codemerge "${v}\;"
}
} }
} }
} }
@ -3963,7 +4010,7 @@ namespace eval punk::ansi::ansistring {
#return empty string for each index that is out of range #return empty string for each index that is out of range
#review - this is possibly too slow to be very useful as is. #review - this is possibly too slow to be very useful as is.
# consider converting to oo and maintaining state of ansisplits so we don't repeat relatively expensive operations for same string # consider converting to oo and maintaining state of ansisplits so we don't repeat relatively expensive operations for same string
#see also punk::list_index_resolve / punk::list_index_get for ways to handle tcl list/string indices without parsing them. #see also punk::lindex_resolve / punk::lindex_get for ways to handle tcl list/string indices without parsing them.
proc INDEXABSOLUTE {string args} { proc INDEXABSOLUTE {string args} {
set payload_len -1 ;# -1 as token to indicate we haven't calculated it yet (only want to call it once at most) set payload_len -1 ;# -1 as token to indicate we haven't calculated it yet (only want to call it once at most)
set testindices [list] set testindices [list]

17
src/modules/punk/lib-999999.0a1.0.tm

@ -211,7 +211,18 @@ namespace eval punk::lib {
#} #}
proc list_index_resolve {list index} { proc lindex_resolve {list index} {
#*** !doctools
#[call [fun lindex_resolve] [arg list] [arg index]]
#[para]Resolve an index which may be of the forms accepted by Tcl list commands such as end-2 or 2+2 to the actual integer index for the supplied list
#[para]Users may define procs which accept a list index and wish to accept the forms understood by Tcl.
#[para]This means the proc may be called with something like $x+2 end-$y etc
#[para]Sometimes the actual integer index is desired.
#[para]We want to resolve the index used, without passing arbitrary expressions into the 'expr' function - which could have security risks.
#[para]lindex_resolve will parse the index expression and return -1 if the supplied index expression is out of bounds for the supplied list.
#[para]Otherwise it will return an integer corresponding to the position in the list.
#[para]Like Tcl list commands - it will produce an error if the form of the index is not acceptable
#Note that for an index such as $x+1 - we never see the '$x' as it is substituted in the calling command. We will get something like 10+1 - which we will resolve (hopefully safely) with expr #Note that for an index such as $x+1 - we never see the '$x' as it is substituted in the calling command. We will get something like 10+1 - which we will resolve (hopefully safely) with expr
if {![llength $list]} { if {![llength $list]} {
return -1 return -1
@ -271,7 +282,7 @@ namespace eval punk::lib {
} }
} }
} }
proc list_index_resolve2 {list index} { proc lindex_resolve2 {list index} {
set indices [list] ;#building this may be somewhat expensive in terms of storage and compute for large lists - we could use lseq in Tcl 8.7+ but that's likely unavailable here. set indices [list] ;#building this may be somewhat expensive in terms of storage and compute for large lists - we could use lseq in Tcl 8.7+ but that's likely unavailable here.
for {set i 0} {$i < [llength $list]} {incr i} { for {set i 0} {$i < [llength $list]} {incr i} {
lappend indices $i lappend indices $i
@ -283,7 +294,7 @@ namespace eval punk::lib {
return $idx return $idx
} }
} }
proc list_index_get {list index} { proc lindex_get {list index} {
set resultlist [lrange $list $index $index] set resultlist [lrange $list $index $index]
if {![llength $resultlist]} { if {![llength $resultlist]} {
return -1 return -1

2096
src/modules/textblock-999999.0a1.0.tm

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save