Browse Source

help and documentation additions/fixes

master
Julian Noble 4 months ago
parent
commit
e331ddff11
  1. 746
      src/modules/punk-0.1.tm
  2. 177
      src/modules/punk/ansi-999999.0a1.0.tm
  3. 153
      src/modules/punk/args-999999.0a1.0.tm
  4. 1550
      src/modules/punk/args/moduledoc/tclcore-999999.0a1.0.tm
  5. 315
      src/modules/punk/args/moduledoc/tkcore-999999.0a1.0.tm
  6. 40
      src/modules/punk/assertion-999999.0a1.0.tm
  7. 4
      src/modules/punk/du-999999.0a1.0.tm
  8. 12
      src/modules/punk/lib-999999.0a1.0.tm
  9. 8
      src/modules/punk/mix/commandset/loadedlib-999999.0a1.0.tm
  10. 2328
      src/modules/punk/ns-999999.0a1.0.tm
  11. 58
      src/modules/punk/repl-999999.0a1.0.tm
  12. 4
      src/modules/punk/repl/codethread-999999.0a1.0.tm
  13. 18
      src/modules/punk/unixywindows-999999.0a1.0.tm
  14. 12
      src/modules/punk/winpath-999999.0a1.0.tm
  15. 16
      src/modules/punk/winrun-999999.0a1.0.tm

746
src/modules/punk-0.1.tm

@ -496,23 +496,25 @@ namespace eval punk {
#-----------------------------------------------------------------------------------
#get a copy of the item without affecting internal rep
proc objclone {obj} {
proc valcopy {obj} {
append obj2 $obj {}
}
proc set_clone {varname obj} {
#maintenance: also punk::lib::set_clone
#e.g used by repl's codeinterp. Maintains internal rep, easier to call e.g interp eval code [list punk::set_clone varnmame $val]
proc set_valcopy {varname obj} {
#maintenance: also punk::lib::set_valcopy
#e.g used by repl's codeinterp. Maintains internal rep, easier to call e.g interp eval code [list punk::set_valcopy varnmame $val]
append obj2 $obj {}
uplevel 1 [list set $varname $obj2]
}
interp alias "" strlen "" ::punk::strlen
interp alias "" str_len "" ::punk::strlen
interp alias "" objclone "" ::punk::objclone
interp alias "" valcopy "" ::punk::valcopy
#proc ::strlen {str} {
# string length [append str2 $str {}]
#}
#proc ::objclone {obj} {
#proc ::valcopy {obj} {
# append obj2 $obj {}
#}
@ -629,10 +631,24 @@ namespace eval punk {
-- -type none
@values
pattern -type string -help\
"regex pattern to match in plaintext portion of ANSI string
{regex pattern to match in plaintext portion of ANSI string
The pattern may contain bracketed capturing groups, which
will be highlighted (todo) in the result. If there is no capturing
group, the entire match will be highlighted."
will be highlighted in the result. If there is no capturing
group, the entire match will be highlighted.
Note that if we were to attempt to highlight curly braces based
on the regexp {\{|\}} then the inserted ansi would come between
the backslash and brace in cases where a curly brace is escaped
ie \{ or \}
Depending on how the output is used, this can break the syntactic
structure causing problems.
Instead a pair of regexes such as
{^\{|[^\\](\{+)}
{[^\\](\}+)}
should be used to
exclude braces that are escaped.
(note the capturing groups around each curly brace)
}
string -type string
}
proc grepstr {args} {
@ -706,9 +722,12 @@ namespace eval punk {
}
if {$lineindex in $matched_line_indices} {
set plain_ln [lindex $plainlines $lineindex]
#first test the regexp with a single match to determine number of capturing groups
set matchparts [regexp {*}$nocase -inline -- $pattern $plain_ln] ;#get fullmatch capturegroup...
set numgroups [expr {[llength $matchparts] -1}]
#first - determine the number of capturing groups (subexpressions)
#option 1: test the regexp with a single match
#set testparts [regexp {*}$nocase -inline -- $pattern $plain_ln] ;#get fullmatch capturegroup...
#set numgroups [expr {[llength $testparts] -1}]
#option 2: use the regexp -about flag
set numgroups [lindex [regexp -about $pattern] 0]
set allparts [regexp -all {*}$nocase -indices -inline -- $pattern $plain_ln]
#allparts includes each full match as well as each capturing group
@ -730,9 +749,14 @@ namespace eval punk {
# restrict ourself to just the capture groups, excluding the full match (if there are capture groups)
set highlight_ranges [list]
set i 0
#{-1 -1} returned for non-matching group when there are capture-group alternatives
#e.g {(a)|(b)}
foreach range $allparts {
if {($i % ($numgroups+1)) != 0} {
lappend highlight_ranges $range
lassign $range a b
if {$range ne {-1 -1} & $a <= $b} {
lappend highlight_ranges $range
}
}
incr i
}
@ -917,10 +941,8 @@ namespace eval punk {
return [twapi::new_uuid]
}
}
#get last command result that was run through the repl
proc ::punk::get_runchunk {args} {
set argd [punk::args::parse $args withdef {
namespace eval argdoc {
punk::args::define {
@id -id ::punk::get_runchunk
@cmd -name "punk::get_runchunk" -help\
"experimental"
@ -928,7 +950,19 @@ namespace eval punk {
-1 -optional 1 -type none
-2 -optional 1 -type none
@values -min 0 -max 0
}]
}
}
#get last command result that was run through the repl
proc ::punk::get_runchunk {args} {
#set argd [punk::args::parse $args withdef {
# @id -id ::punk::get_runchunk
# @cmd -name "punk::get_runchunk" -help\
# "experimental"
# @opts
# -1 -optional 1 -type none
# -2 -optional 1 -type none
# @values -min 0 -max 0
#}]
#todo - make this command run without truncating previous runchunks
set runchunks [tsv::array names repl runchunks-*]
@ -4148,7 +4182,7 @@ namespace eval punk {
#pipealias should capture the namespace context of the pipeline so that commands are resolved in the namespace in which the pipealias is created
proc pipealias {targetcmd args} {
set cmdcopy [punk::objclone $args]
set cmdcopy [punk::valcopy $args]
set nscaller [uplevel 1 [list namespace current]]
tailcall interp alias {} $targetcmd {} apply [list args [append cmdcopy " {*}\$args"] $nscaller]
}
@ -4159,7 +4193,7 @@ namespace eval punk {
}
#although the pipealias2 'concat' alias is cleaner in that the original pipeline can be extracted using list commands - it runs much slower
proc pipealias2 {targetcmd args} {
set cmdcopy [punk::objclone $args]
set cmdcopy [punk::valcopy $args]
set nscaller [uplevel 1 [list namespace current]]
tailcall interp alias {} $targetcmd {} apply [list args [concat "\[concat" [list $cmdcopy] "\$args]"] $nscaller]
}
@ -6654,15 +6688,16 @@ namespace eval punk {
#interp alias {} ~ {} file join $::env(HOME) ;#HOME must be capitalized to work cross platform (lowercase home works on windows - but probably not elsewhere)
#interp alias {} ~ {} apply {args {file join $::env(HOME) $args}}
proc ~ {args} {
set hdir [punk::objclone $::env(HOME)]
set hdir [punk::valcopy $::env(HOME)]
file pathtype $hdir
set d $hdir
#use the file join 2-arg optimisation to avoid losing path-rep - probably doesn't give any advantage on all Tcl versions
#review - for what versions does/did the 2-arg version of file join not just return a string?
foreach a $args {
set d [file join $d $a]
}
file pathtype $d
return [punk::objclone $d]
return [punk::valcopy $d]
}
interp alias {} ~ {} punk::~
@ -7789,47 +7824,61 @@ namespace eval punk {
namespace eval argdoc {
punk::args::define {
@id -id ::punk::help_chunks
@cmd -name "punk::help_chunks"\
-summary\
""\
-help\
""
@opts
-- -type none
@values -min 0 -max -1
arg -type any -optional 1 -multiple 1
}
}
proc help {args} {
set chunks [uplevel 1 [list ::punk::help_chunks {*}$args]]
foreach chunk $chunks {
lassign $chunk chan text
puts -nonewline $chan $text
}
}
#return list of {chan chunk} elements
proc help_chunks {args} {
set chunks [list]
set linesep [string repeat - 76]
set mascotblock ""
catch {
package require patternpunk
#lappend chunks [list stderr [>punk . rhs]]
append mascotblock [textblock::frame -checkargs 0 [>punk . banner -title "Punk Shell" -left Tcl -right [package provide Tcl]]]
set argd [punk::args::parse $args withid ::punk::help_chunks]
lassign [dict values $argd] leaders opts values received
if {[dict exists $values arg]} {
set topicparts [dict get $values arg]
} else {
set topicparts [list ""]
}
#set topic [lindex $args end]
#set argopts [lrange $args 0 end-1]
set topic [lindex $args end]
set argopts [lrange $args 0 end-1]
set chunks [list]
set linesep [string repeat - 76]
set warningblock ""
set title "[a+ brightgreen] Punk core navigation commands: "
set I [punk::ansi::a+ italic]
set NI [punk::ansi::a+ noitalic]
#todo - load from source code annotation?
# -------------------------------------------------------
set logoblock ""
if {[catch {
package require patternpunk
#lappend chunks [list stderr [>punk . rhs]]
append logoblock [textblock::frame -title "Punk Shell [package provide punk]" -width 29 -checkargs 0 [>punk . banner -title "" -left Tcl -right [package provide Tcl]]]
}]} {
append logoblock [textblock::frame -title "Punk Shell [package provide punk]" -subtitle "TCL [package provide Tcl]" -width 29 -height 10 -checkargs 0 ""]
}
set title "[a+ brightgreen] Help System: "
set cmdinfo [list]
lappend cmdinfo [list help "?topics?" "This help. To see available subitems type: help topics"]
lappend cmdinfo [list i "cmd ?subcommand...?" "Show usage for a command or ensemble subcommand"]
lappend cmdinfo [list s "cmd ?subcommand...?" "Show synopsis for a command or ensemble subcommand"]
lappend cmdinfo [list eg "cmd ?subcommand...?" "Show example from manpage"]
lappend cmdinfo [list ./ "?subdir?" "view/change directory"]
lappend cmdinfo [list ../ "" "go up one directory"]
lappend cmdinfo [list ./new "subdir" "make new directory and switch to it"]
lappend cmdinfo [list n/ "?glob...?" "view/change namespace\n (accepts ns path globs e.g **::*get* to match comands at any level )"]
lappend cmdinfo [list n// "" "view/change namespace (with command listing)"]
lappend cmdinfo [list "nn/" "" "go up one namespace"]
lappend cmdinfo [list "n/new" "<ns>" "make child namespace and switch to it"]
lappend cmdinfo [list dev "?subcommand?" "(ensemble command to make new projects/modules and to generate docs)"]
lappend cmdinfo [list a? "?subcommand...?" "view ANSI colours\n e.g a? web"]
#set cmds [lsearch -all -inline -index 0 -subindices $cmdinfo *]
#set descr [lsearch -all -inline -index 1 -subindices $cmdinfo *]
#set widest1 [tcl::mathfunc::max {*}[lmap v $cmds {string length $v}]]
#set widest2 [tcl::mathfunc::max {*}[lmap v $descr {string length $v}]]
set t [textblock::class::table new -show_seps 0]
#foreach c $cmds d $descr {
# $t add_row [list $c $d]
#}
lappend cmdinfo [list help "?${I}topic${NI}?" "This help.\nTo see available subitems type:\nhelp topics\n\n\n\n\n"]
set t [textblock::class::table new -minwidth 51 -show_seps 0]
foreach row $cmdinfo {
$t add_row $row
}
@ -7838,272 +7887,387 @@ namespace eval punk {
set width_1 [$t column_datawidth 1]
$t configure_column 1 -minwidth [expr {$width_1 + 1}]
$t configure -title $title
set text ""
append text [$t print]
set warningblock ""
set introblock $mascotblock
append introblock \n $text
#if {[catch {package require textblock} errM]} {
# append warningblock \n "WARNING: textblock package couldn't be loaded. Side-by-side display not available"
#} else {
# set introblock [textblock::join -- " " \n$mascotblock " " $text]
#}
lappend chunks [list stdout $introblock]
if {$topic in [list tcl]} {
if {[punk::lib::check::has_tclbug_script_var]} {
append warningblock \n "minor warning: punk::lib::check::has_tclbug_script_var returned true! (string rep for list variable in script generated when script changed)"
}
if {[punk::lib::check::has_tclbug_safeinterp_compile]} {
set indent " "
append warningblock \n "[a+ web-red]warning: punk::lib::check::has_tclbug_safeinterp returned true!" \n
append warningblock "${indent}(ensemble commands not compiled in safe interps - heavy performance impact in safe interps)" \n
append warningblock "${indent}see [punk::ansi::hyperlink https://core.tcl-lang.org/tcl/tktview/1095bf7f75]"
append warningblock [a]
}
if {[catch {lsearch -stride 2 {a b} b}]} {
set indent " "
append warningblock \n "[a+ web-red]warning: lsearch does not seem to support -stride option" \n
append warningblock "${indent}(Consider upgrading to a late release of tcl 8.6 or tcl 9+ )" \n
append warningblock [a]
} else {
if {[punk::lib::check::has_tclbug_lsearch_strideallinline]} {
set text [$t print]
set introblock [textblock::join -- $logoblock $text]
lappend chunks [list stdout $introblock\n]
# -------------------------------------------------------
switch -- [lindex $topicparts 0] {
"" {
# -------------------------------------------------------
set title "[a+ brightgreen] Filesystem navigation: "
set cmdinfo [list]
lappend cmdinfo [list ./ "?${I}subdir${NI}?" "view/change directory"]
lappend cmdinfo [list ../ "" "go up one directory"]
lappend cmdinfo [list ./new "${I}subdir${NI}" "make new directory and switch to it"]
set t [textblock::class::table new -minwidth 80 -show_seps 0]
foreach row $cmdinfo {
$t add_row $row
}
set width_0 [$t column_datawidth 0]
$t configure_column 0 -minwidth [expr {$width_0 + 2}]
set width_1 [$t column_datawidth 1]
$t configure_column 1 -minwidth [expr {$width_1 + 1}]
$t configure -title $title
set text ""
append text [$t print]
lappend chunks [list stdout $text\n]
# -------------------------------------------------------
# -------------------------------------------------------
set title "[a+ brightgreen] Namespace navigation: "
set cmdinfo [list]
lappend cmdinfo [list n/ "?${I}ns${NI}|${I}glob${NI}?" "view/change namespace\n (accepts ns path globs e.g **::*get* to match\n commands at any level )"]
lappend cmdinfo [list n// "?${I}ns${NI}|${I}glob${NI}?" "view/change namespace (with command listing)"]
lappend cmdinfo [list "nn/" "" "go up one namespace"]
lappend cmdinfo [list "n/new" "${I}ns${NI}" "make child namespace and switch to it"]
set t [textblock::class::table new -minwidth 80 -show_seps 0]
foreach row $cmdinfo {
$t add_row $row
}
set width_0 [$t column_datawidth 0]
$t configure_column 0 -minwidth [expr {$width_0 + 2}]
set width_1 [$t column_datawidth 1]
$t configure_column 1 -minwidth [expr {$width_1 + 1}]
$t configure -title $title
set text ""
append text [$t print]
lappend chunks [list stdout $text\n]
# -------------------------------------------------------
# -------------------------------------------------------
set title "[a+ brightgreen] Command help: "
set cmdinfo [list]
lappend cmdinfo [list i "${I}cmd${NI} ?${I}subcommand${NI}...?" "Show usage for a command or ensemble subcommand"]
lappend cmdinfo [list s "${I}cmd${NI} ?${I}subcommand${NI}...?" "Show synopsis for a command or ensemble subcommand"]
lappend cmdinfo [list eg "${I}cmd${NI} ?${I}subcommand${NI}...?" "Show example from manpage"]
lappend cmdinfo [list corp "${I}proc${NI}" "View proc body and arguments"]
set t [textblock::class::table new -minwidth 80 -show_seps 0]
foreach row $cmdinfo {
$t add_row $row
}
set width_0 [$t column_datawidth 0]
$t configure_column 0 -minwidth [expr {$width_0 + 2}]
set width_1 [$t column_datawidth 1]
$t configure_column 1 -minwidth [expr {$width_1 + 1}]
$t configure -title $title
set text ""
append text [$t print]
lappend chunks [list stdout $text\n]
# -------------------------------------------------------
set title "[a+ brightgreen] Miscellaneous: "
#todo - load from source code annotation?
set cmdinfo [list]
lappend cmdinfo [list dev "?${I}subcommand${NI}?" "(ensemble command to make new projects/modules and\n to generate docs)"]
lappend cmdinfo [list a? "?${I}subcommand${NI}...?" "view ANSI colours\n e.g a? web\n or individual code samples/diagnostics\n e.g a? red bold\n e.g a? underline web-orange Term-purple3"]
lappend cmdinfo [list a+ "?${I}colourcode${NI}...?" "Return ANSI codes\n e.g puts \"\[a+ purple\]purple\[a+ Green\]purple on green\[a\]\"\n [a+ purple]purple[a+ Green]purple on green[a] "]
lappend cmdinfo [list a "?${I}colourcode${NI}...?" "Return ANSI codes (with leading reset)\n e.g puts \"\[a+ purple\]purple\[a Green\]normal on green\[a\]\"\n [a+ purple]purple[a Green]normal on green[a] "]
set t [textblock::class::table new -minwidth 80 -show_seps 0]
foreach row $cmdinfo {
$t add_row $row
}
set width_0 [$t column_datawidth 0]
$t configure_column 0 -minwidth [expr {$width_0 + 2}]
set width_1 [$t column_datawidth 1]
$t configure_column 1 -minwidth [expr {$width_1 + 1}]
$t configure -title $title
set text ""
append text [$t print]
lappend chunks [list stdout $text]
# -------------------------------------------------------
}
tcl {
set text "Tcl Patchlevel: [info patchlevel]"
catch {
append text \n "Tcl build-info: [::tcl::build-info]"
}
if {[punk::lib::check::has_tclbug_script_var]} {
append warningblock \n "minor warning: punk::lib::check::has_tclbug_script_var returned true! (string rep for list variable in script generated when script changed)"
}
if {[punk::lib::check::has_tclbug_safeinterp_compile]} {
set indent " "
append warningblock \n "[a+ web-red]warning: punk::lib::check::has_tclbug_lsearch_strideallinline returned true!" \n
append warningblock "${indent}(lsearch using -stride -all -inline -subindices does not return values corresponding to subindex when a single -index value is used)" \n
append warningblock "${indent}see [punk::ansi::hyperlink https://core.tcl-lang.org/tcl/tktview/5a1aaa201d]"
append warningblock \n "[a+ web-red]warning: punk::lib::check::has_tclbug_safeinterp returned true!" \n
append warningblock "${indent}(ensemble commands not compiled in safe interps - heavy performance impact in safe interps)" \n
append warningblock "${indent}see [punk::ansi::hyperlink https://core.tcl-lang.org/tcl/tktview/1095bf7f75]"
append warningblock [a]
}
}
if {[punk::lib::check::has_tclbug_list_quoting_emptyjoin]} {
set indent " "
append warningblock \n "[a+ web-red]warning: punk::lib::check::has_tclbug_list_quoting returned true!" \n
append warningblock "${indent}lists elements not properly quoted in some cases. e.g 'list {*}[lindex {etc #foo} 1] {*}[list]' (#foo not braced)" \n
append warningblock "${indent}see [punk::ansi::hyperlink https://core.tcl-lang.org/tcl/tktview/e38dce74e2]"
}
}
set text ""
if {$topic in [list env environment]} {
#todo - move to punk::config?
upvar ::punk::config::punk_env_vars_config punkenv_config
upvar ::punk::config::other_env_vars_config otherenv_config
set known_punk [dict keys $punkenv_config]
set known_other [dict keys $otherenv_config]
append text \n
set usetable 1
if {$usetable} {
set t [textblock::class::table new -show_hseps 0 -show_header 1 -ansiborder_header [a+ web-green]]
if {"windows" eq $::tcl_platform(platform)} {
#If any env vars have been set to empty string - this is considered a deletion of the variable on windows.
#The Tcl ::env array is linked to the underlying process view of the environment
#- but info exists ::env(var) can misreport as true if it has been deleted by setting to empty string rather than using unset.
#an 'array get' will resynchronise.
#Even if an env variable didn't exist before - setting it to empty string can get it to this inconsistent state.
array get ::env
}
#do an array read on ::env
foreach {v vinfo} $punkenv_config {
if {[info exists ::env($v)]} {
set c2 [set ::env($v)]
} else {
set c2 "(NOT SET)"
}
set help ""
if {[dict exists $vinfo help]} {
set help [dict get $vinfo help]
if {[catch {lsearch -stride 2 {a b} b}]} {
set indent " "
append warningblock \n "[a+ web-red]warning: lsearch does not seem to support -stride option" \n
append warningblock "${indent}(Consider upgrading to a late release of tcl 8.6 or tcl 9+ )" \n
append warningblock [a]
} else {
if {[punk::lib::check::has_tclbug_lsearch_strideallinline]} {
set indent " "
append warningblock \n "[a+ web-red]warning: punk::lib::check::has_tclbug_lsearch_strideallinline returned true!" \n
append warningblock "${indent}(lsearch using -stride -all -inline -subindices does not return values corresponding to subindex when a single -index value is used)" \n
append warningblock "${indent}see [punk::ansi::hyperlink https://core.tcl-lang.org/tcl/tktview/5a1aaa201d]"
append warningblock [a]
}
$t add_row [list $v $c2 $help]
}
$t configure_column 0 -headers [list "Punk environment vars"]
$t configure_column 0 -minwidth [expr {[$t column_datawidth 0]+4}] -blockalign left -textalign left -header_colspans {any}
if {[punk::lib::check::has_tclbug_list_quoting_emptyjoin]} {
set indent " "
append warningblock \n "[a+ web-red]warning: punk::lib::check::has_tclbug_list_quoting returned true!" \n
append warningblock "${indent}lists elements not properly quoted in some cases. e.g 'list {*}[lindex {etc #foo} 1] {*}[list]' (#foo not braced)" \n
append warningblock "${indent}see [punk::ansi::hyperlink https://core.tcl-lang.org/tcl/tktview/e38dce74e2]"
}
lappend chunks [list stdout $text]
}
env - environment {
set text ""
#todo - move to punk::config?
upvar ::punk::config::punk_env_vars_config punkenv_config
upvar ::punk::config::other_env_vars_config otherenv_config
set known_punk [dict keys $punkenv_config]
set known_other [dict keys $otherenv_config]
append text \n
set usetable 1
if {$usetable} {
set t [textblock::class::table new -show_hseps 0 -show_header 1 -ansiborder_header [a+ web-green]]
if {"windows" eq $::tcl_platform(platform)} {
#If any env vars have been set to empty string - this is considered a deletion of the variable on windows.
#The Tcl ::env array is linked to the underlying process view of the environment
#- but info exists ::env(var) can misreport as true if it has been deleted by setting to empty string rather than using unset.
#an 'array get' will resynchronise.
#Even if an env variable didn't exist before - setting it to empty string can get it to this inconsistent state.
array get ::env
}
#do an array read on ::env
foreach {v vinfo} $punkenv_config {
if {[info exists ::env($v)]} {
set c2 [set ::env($v)]
} else {
set c2 "(NOT SET)"
}
set help ""
if {[dict exists $vinfo help]} {
set help [dict get $vinfo help]
}
$t add_row [list $v $c2 $help]
}
$t configure_column 0 -headers [list "Punk environment vars"]
$t configure_column 0 -minwidth [expr {[$t column_datawidth 0]+4}] -blockalign left -textalign left -header_colspans {any}
set punktable [$t print]
$t destroy
set punktable [$t print]
$t destroy
set t [textblock::class::table new -show_hseps 0 -show_header 1 -ansiborder_header [a+ web-green]]
foreach {v vinfo} $otherenv_config {
if {[info exists ::env($v)]} {
set env_val [set ::env($v)]
if {[string match "*_TM_PATH" $v]} {
set entries [split $env_val $::tcl_platform(pathSeparator)]
set c2 [join $entries \n]
set t [textblock::class::table new -show_hseps 0 -show_header 1 -ansiborder_header [a+ web-green]]
foreach {v vinfo} $otherenv_config {
if {[info exists ::env($v)]} {
set env_val [set ::env($v)]
if {[string match "*_TM_PATH" $v]} {
set entries [split $env_val $::tcl_platform(pathSeparator)]
set c2 [join $entries \n]
} else {
set c2 $::env($v)
}
} else {
set c2 $::env($v)
set c2 "(NOT SET)"
}
} else {
set c2 "(NOT SET)"
$t add_row [list $v $c2]
}
$t add_row [list $v $c2]
}
$t configure_column 0 -headers [list "Other environment vars"]
$t configure_column 0 -minwidth [expr {[$t column_datawidth 0]+4}] -blockalign left -textalign left -header_colspans {any}
$t configure_column 0 -headers [list "Other environment vars"]
$t configure_column 0 -minwidth [expr {[$t column_datawidth 0]+4}] -blockalign left -textalign left -header_colspans {any}
set othertable [$t print]
$t destroy
#append text [textblock::join -- $punktable " " $othertable]\n
append text $punktable\n$othertable\n
} else {
set othertable [$t print]
$t destroy
#append text [textblock::join -- $punktable " " $othertable]\n
append text $punktable\n$othertable\n
} else {
append text $linesep\n
append text "punk environment vars:\n"
append text $linesep\n
set col1 [string repeat " " 25]
set col2 [string repeat " " 50]
foreach v $known_punk {
set c1 [overtype::left $col1 $v]
if {[info exists ::env($v)]} {
set c2 [overtype::left $col2 [set ::env($v)]]
} else {
set c2 [overtype::right $col2 "(NOT SET)"]
}
append text "$c1 $c2\n"
}
append text $linesep\n
}
lappend chunks [list stdout $text]
}
if {$topic in [list console terminal]} {
set indent [string repeat " " [string length "WARNING: "]]
lappend cstring_tests [dict create\
type "PM "\
msg "UN"\
f7 punk::ansi::controlstring_PM\
f7prefix "7bit ESC ^ secret "\
f7suffix "safe"\
f8 punk::ansi::controlstring_PM8\
f8prefix "8bit \\x9e secret "\
f8suffix "safe"\
]
lappend cstring_tests [dict create\
type SOS\
msg "NOT"\
f7 punk::ansi::controlstring_SOS\
f7prefix "7bit ESC X string "\
f7suffix " hidden"\
f8 punk::ansi::controlstring_SOS8\
f8prefix "8bit \\x98 string "\
f8suffix " hidden"\
]
lappend cstring_tests [dict create\
type APC\
msg "NOT"\
f7 punk::ansi::controlstring_APC\
f7prefix "7bit ESC _ APPLICATION PROGRAM COMMAND "\
f7suffix " hidden"\
f8 punk::ansi::controlstring_APC8\
f8prefix "8bit \\x9f APPLICATION PROGRAM COMMAND "\
f8suffix " hidden"\
]
foreach test $cstring_tests {
set m [[dict get $test f7] [dict get $test msg]]
set hidden_width_m [punk::console::test_char_width $m]
set m8 [[dict get $test f8] [dict get $test msg]]
set hidden_width_m8 [punk::console::test_char_width $m8]
if {$hidden_width_m != 0 || $hidden_width_m8 != 0} {
if {$hidden_width_m == 0} {
set d "[a+ green bold][dict get $test f7prefix][a red]${m}[a][a+ green bold][dict get $test f7suffix][a]"
} else {
set d "[a+ yellow bold][dict get $test f7prefix][a red]$m[a][a+ yellow bold][dict get $test f7suffix][a]"
append text $linesep\n
append text "punk environment vars:\n"
append text $linesep\n
set col1 [string repeat " " 25]
set col2 [string repeat " " 50]
foreach v $known_punk {
set c1 [overtype::left $col1 $v]
if {[info exists ::env($v)]} {
set c2 [overtype::left $col2 [set ::env($v)]]
} else {
set c2 [overtype::right $col2 "(NOT SET)"]
}
append text "$c1 $c2\n"
}
append text $linesep\n
}
lappend chunks [list stdout $text]
}
console - term - terminal {
set indent [string repeat " " [string length "WARNING: "]]
lappend cstring_tests [dict create\
type "PM "\
msg "UN"\
f7 punk::ansi::controlstring_PM\
f7prefix "7bit ESC ^ secret "\
f7suffix "safe"\
f8 punk::ansi::controlstring_PM8\
f8prefix "8bit \\x9e secret "\
f8suffix "safe"\
]
lappend cstring_tests [dict create\
type SOS\
msg "NOT"\
f7 punk::ansi::controlstring_SOS\
f7prefix "7bit ESC X string "\
f7suffix " hidden"\
f8 punk::ansi::controlstring_SOS8\
f8prefix "8bit \\x98 string "\
f8suffix " hidden"\
]
lappend cstring_tests [dict create\
type APC\
msg "NOT"\
f7 punk::ansi::controlstring_APC\
f7prefix "7bit ESC _ APPLICATION PROGRAM COMMAND "\
f7suffix " hidden"\
f8 punk::ansi::controlstring_APC8\
f8prefix "8bit \\x9f APPLICATION PROGRAM COMMAND "\
f8suffix " hidden"\
]
foreach test $cstring_tests {
set m [[dict get $test f7] [dict get $test msg]]
set hidden_width_m [punk::console::test_char_width $m]
set m8 [[dict get $test f8] [dict get $test msg]]
set hidden_width_m8 [punk::console::test_char_width $m8]
if {$hidden_width_m != 0 || $hidden_width_m8 != 0} {
if {$hidden_width_m == 0} {
set d "[a+ green bold][dict get $test f7prefix][a red]${m}[a][a+ green bold][dict get $test f7suffix][a]"
} else {
set d "[a+ yellow bold][dict get $test f7prefix][a red]$m[a][a+ yellow bold][dict get $test f7suffix][a]"
}
if {$hidden_width_m8 == 0} {
set d8 "[a+ green ][dict get $test f8prefix][a red]$m8[a][a+ green][dict get $test f8suffix][a]"
} else {
set d8 "[a+ yellow bold][dict get $test f8prefix][a red]$m8[a][a+ yellow bold][dict get $test f8suffix][a]"
}
append warningblock \n "WARNING: terminal doesn't hide all [dict get $test type] control strings: $d $d8"
}
if {$hidden_width_m8 == 0} {
set d8 "[a+ green ][dict get $test f8prefix][a red]$m8[a][a+ green][dict get $test f8suffix][a]"
} else {
set d8 "[a+ yellow bold][dict get $test f8prefix][a red]$m8[a][a+ yellow bold][dict get $test f8suffix][a]"
}
if {![catch {punk::console::check::has_bug_legacysymbolwidth} result]} {
if {$result} {
append warningblock \n "WARNING: terminal has legacysymbolwidth bug - screen position for symbol reports 2 wide but displays 1 wide."
append warningblock \n $indent "Layout using 'legacy symbols for computing' affected."
append warningblock \n $indent "(e.g textblock frametype block2 unsupported)"
append warningblock \n $indent "This can cause extreme layout deformation when ANSI is present"
append warningblock \n $indent "In some cases unwanted spacing effects occur at a distance from the characters causing it"
}
append warningblock \n "WARNING: terminal doesn't hide all [dict get $test type] control strings: $d $d8"
} else {
append warningblock \n "WARNING: terminal unable to check for legacysymbolwidth bug. err:$result"
}
}
if {![catch {punk::console::check::has_bug_legacysymbolwidth} result]} {
if {$result} {
append warningblock \n "WARNING: terminal has legacysymbolwidth bug - screen position for symbol reports 2 wide but displays 1 wide."
append warningblock \n $indent "Layout using 'legacy symbols for computing' affected."
append warningblock \n $indent "(e.g textblock frametype block2 unsupported)"
append warningblock \n $indent "This can cause extreme layout deformation when ANSI is present"
append warningblock \n $indent "In some cases unwanted spacing effects occur at a distance from the characters causing it"
if {![catch {punk::console::check::has_bug_zwsp} result]} {
if {$result} {
append warningblock \n "WARNING: terminal has zero width space (\\u200b) bug - cursor position incremented when it shouldn't be."
append warningblock \n $indent "The zwsp may or may not be displayed. zwsp contributes to line length and wrapping point"
}
} else {
append warningblock \n "WARNING: terminal unable to check for zwsp bug. err:$result"
}
} else {
append warningblock \n "WARNING: terminal unable to check for legacysymbolwidth bug. err:$result"
}
if {![catch {punk::console::check::has_bug_zwsp} result]} {
if {$result} {
append warningblock \n "WARNING: terminal has zero width space (\\u200b) bug - cursor position incremented when it shouldn't be."
append warningblock \n $indent "The zwsp may or may not be displayed. zwsp contributes to line length and wrapping point"
set grapheme_support [punk::console::grapheme_cluster_support]
#mode, 1 = set, 2 = unset. (0 = mode not recognised, 3 = permanently set, 4 = permanently unset)
if {![dict size $grapheme_support] || [dict get $grapheme_support mode] eq "unsupported" } {
append warningblock \n "WARNING: terminal either doesn't support grapheme clusters, or doesn't report so via decmode 2027 query."
if {[dict size $grapheme_support] && [dict get $grapheme_support available]} {
append warningblock \n $indent "(but punk::console::grapheme_cluster_support has determined it is probably available)"
}
} else {
if {![dict get $grapheme_support available]} {
switch -- [dict get $grapheme_support mode] {
"unset" {
append warningblock \n "WARNING: terminal reports via decmode 2027 that grapheme cluster support is off."
}
"permanently_unset" {
append warningblock \n "WARNING: terminal reports via decmode 2027 that grapheme cluster support is permanently off."
}
"BAD_RESPONSE" {
append warningblock \n "WARNING: terminal doesn't seem to recognize decmode 2027 query. No grapheme cluster support."
}
}
}
}
if {![string length $warningblock]} {
set text "No terminal warnings\n"
lappend chunks [list stdout $text]
}
} else {
append warningblock \n "WARNING: terminal unable to check for zwsp bug. err:$result"
}
topics - help {
set text ""
set topics [dict create\
"topics|help" "List help topics"\
"tcl" "Tcl version warnings"\
"env|environment" "punkshell environment vars"\
"console|terminal" "Some console behaviour tests and warnings"\
]
set grapheme_support [punk::console::grapheme_cluster_support]
#mode, 1 = set, 2 = unset. (0 = mode not recognised, 3 = permanently set, 4 = permanently unset)
if {![dict size $grapheme_support] || [dict get $grapheme_support mode] eq "unsupported" } {
append warningblock \n "WARNING: terminal either doesn't support grapheme clusters, or doesn't report so via decmode 2027 query."
if {[dict size $grapheme_support] && [dict get $grapheme_support available]} {
append warningblock \n $indent "(but punk::console::grapheme_cluster_support has determined it is probably available)"
set t [textblock::class::table new -show_seps 0]
$t add_column -headers [list "Topic"]
$t add_column
foreach {k v} $topics {
$t add_row [list $k $v]
}
} else {
if {![dict get $grapheme_support available]} {
switch -- [dict get $grapheme_support mode] {
"unset" {
append warningblock \n "WARNING: terminal reports via decmode 2027 that grapheme cluster support is off."
}
"permanently_unset" {
append warningblock \n "WARNING: terminal reports via decmode 2027 that grapheme cluster support is permanently off."
}
"BAD_RESPONSE" {
append warningblock \n "WARNING: terminal doesn't seem to recognize decmode 2027 query. No grapheme cluster support."
set widest0 [$t column_datawidth 0]
$t configure_column 0 -minwidth [expr {$widest0 + 4}]
append text \n [$t print]
lappend chunks [list stdout $text]
}
default {
set text ""
set cinfo [uplevel 1 [list punk::ns::cmdwhich [lindex $topicparts 0]]]
set wtype [dict get $cinfo whichtype]
if {$wtype eq "notfound"} {
set externalinfo [auto_execok [lindex $topicparts 0]]
if {[string length $externalinfo]} {
set text "$topicparts"
append text \n "Base type: External command"
append text \n "$externalinfo [lrange $topicparts 1 end]"
} else {
set text "$topicparts\n"
append text "No matching internal or external command found"
}
} else {
set text "[dict get $cinfo which] [lrange $topicparts 1 end]"
append text \n "Base type: $wtype"
set synopsis [uplevel 1 [list punk::ns::synopsis {*}$topicparts]]
set synshow ""
foreach sline [split $synopsis \n] {
if {[regexp {\s*#.*} $sline]} {
append synshow [punk::ansi::a+ bold term-darkgreen Term-white]$sline[punk::ansi::a] \n
} else {
append synshow $sline \n
}
}
if {[string index $synshow end] eq "\n"} {
set synshow [string range $synshow 0 end-1]
}
append text \n $synshow
}
lappend chunks [list stdout $text]
}
}
lappend chunks [list stderr $warningblock]
if {$topic in [list topics help]} {
set text ""
set topics [dict create\
"topics|help" "List help topics"\
"tcl" "Tcl version warnings"\
"env|environment" "punkshell environment vars"\
"console|terminal" "Some console behaviour tests and warnings"\
]
set t [textblock::class::table new -show_seps 0]
$t add_column -headers [list "Topic"]
$t add_column
foreach {k v} $topics {
$t add_row [list $k $v]
}
set widest0 [$t column_datawidth 0]
$t configure_column 0 -minwidth [expr {$widest0 + 4}]
append text \n[$t print]
lappend chunks [list stdout $text]
}
lappend chunks [list stderr $warningblock]
return $chunks
}
proc help {args} {
set chunks [help_chunks {*}$args]
foreach chunk $chunks {
lassign $chunk chan text
puts -nonewline $chan $text
}
}
proc mode {{raw_or_line query}} {
package require punk::console
tailcall ::punk::console::mode $raw_or_line

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

@ -340,6 +340,28 @@ tcl::namespace::eval punk::ansi::class {
}
}
tcl::namespace::eval punk::ansi {
namespace eval argdoc {
variable PUNKARGS
# -- --- --- --- ---
#non colour SGR codes
# we can use these directly via ${$I} etc without marking a definition with @dynamic
#This is because they don't need to change when colour switched on and off.
#chicken/egg - need to use literals here
set I "\x1b\[3m" ;# [a+ italic]
set NI "\x1b\[23m" ;# [a+ noitalic]
set B "\x1b\[1m" ;# [a+ bold]
set N "\x1b\[22m" ;# [a+ normal]
set T "\x1b\[1\;4m" ;# [a+ bold underline]
set NT "\x1b\[22\;24m\x1b\[4:0m" ;# [a+ normal nounderline]
set LC \u007b ;#left curly brace
set RC \u007d ;#right curly brace
# -- --- --- --- ---
#namespace import ::punk::args::helpers::*
}
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
tcl::namespace::eval punk::ansi {
@ -2262,59 +2284,74 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
return $displaytable
}
lappend PUNKARGS [list {
@id -id ::punk::ansi::a?
@cmd -name "punk::ansi::a?"\
-summary\
"ANSI colour information"\
-help\
""
@form -form "sgr_overview"
@values -form "sgr_overview" -min 0 -max 0
@form -form "term"
@leaders -form "term" -min 1 -max 1
term -type literal(term) -help\
"256 term colours"
@opts -min 0 -max 0
@values -form "term" -min 0 -max -1
panel -type string -optional 1 -multiple 1 -default {16 main greyscale note}\
-choices {16 main greyscale pastel rainbow note}
@form -form "tk"
@leaders -form "tk" -min 1 -max 1
tk -type literal(tk)|literal(TK) -help\
"Tk colours"
@opts -form "tk"
-merged -type none -help\
"If this flag is supplied - show colour names with the same RGB
values together."
@values -form "tk" -min 0 -max -1
glob -type string -optional 1 -multiple 1 -help\
"A glob string such as *green*.
Multiple glob entries can be provided. The search is case insensitive"
@form -form "web"
@values -form "web" -min 1 -max -1
web -type literal(web) -help\
"Web colours"
panel -type string -optional 1 -multiple 1 -choices {basic pink red orange yellow brown purple blue cyan green white gray}
@form -form "x11"
@values -form "x11" -min 1 -max 1
x11 -type literal(x11) -help\
"x11 colours"
@form -form "sample"
@values -form "sample" -min 1 -max -1
colourcode -type sgr|Sgr|literalprefix(term-)|literalprefix(Term-)|literalprefix(web-)|literalprefix(Web-)|literalprefix(rgb)|literalprefix(Rgb)\
-optional 0\
-multiple 1
}]
namespace eval argdoc {
variable PUNKARGS
lappend PUNKARGS [list {
@id -id ::punk::ansi::a?
@cmd -name "punk::ansi::a?"\
-summary\
"ANSI colour information"\
-help\
"With no arguments - display an overview information panel.
With the first argument one of:
${$B}term tk TK web x11${$N}
Display a more specific panel of colour information.
With arguments of individual colourcodes from any of the above
sets, display a small diagnostic table showing a sample of
the individual and combined effect(s), along with indications
of the raw ANSI codes."
@form -form "sgr_overview"
@values -form "sgr_overview" -min 0 -max 0
@form -form "term"
@leaders -form "term" -min 1 -max 1
term -type literal(term) -help\
"256 term colours"
@opts -min 0 -max 0
@values -form "term" -min 0 -max -1
panel -type string -optional 1 -multiple 1 -default {16 main greyscale note}\
-choices {16 main greyscale pastel rainbow note}
@form -form "tk"
@leaders -form "tk" -min 1 -max 1
tk -type literal(tk)|literal(TK) -help\
"Tk colours"
@opts -form "tk"
-merged -type none -help\
"If this flag is supplied - show colour names with the same RGB
values together."
@values -form "tk" -min 0 -max -1
glob -type string -optional 1 -multiple 1 -help\
"A glob string such as *green*.
Multiple glob entries can be provided. The search is case insensitive"
@form -form "web"
@values -form "web" -min 1 -max -1
web -type literal(web) -help\
"Web colours"
panel -type string -optional 1 -multiple 1 -choices {basic pink red orange yellow brown purple blue cyan green white gray}
@form -form "x11"
@values -form "x11" -min 1 -max 1
x11 -type literal(x11) -help\
"x11 colours"
@form -form "sample"
@values -form "sample" -min 1 -max -1
#review literalprefix is not the right thing here! (literalprefix means a tcl::prefix::match on the value)
#colourcode -type sgr|Sgr|stringstartswith(term-)|stringstartswith(Term-)|stringstartswith(web-)|stringstartswith(Web-)|stringstartswith(rgb)|stringstartswith(Rgb)
colourcode -type string|stringstartswith(term-)|stringstartswith(Term-)|stringstartswith(web-)|stringstartswith(Web-)|stringstartswith(rgb)|stringstartswith(Rgb)\
-typesynopsis {${$I}sgr${$NI}|${$I}Sgr${$NI}|${$I}colourcode${$NI}}\
-optional 0\
-multiple 1
}]
}
proc a? {args} {
#*** !doctools
#[call [fun a?] [opt {ansicode...}]]
@ -2414,8 +2451,8 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
append out \n
append out "[a+ {*}$fc web-white]Combination testing[a]" \n
append out [textblock::join -- $indent "Example: a? red brightgreen underline Tk-slategrey italic"] \n
append out [textblock::join -- $indent "This will show a small table of each applied code and a RESULT row. The 'red' in this case is redundant,"] \n
append out [textblock::join -- $indent "so a final MERGED row displays with an alert 'REDUNDANCIES FOUND'."] \n
append out [textblock::join -- $indent "This will show a small table of each applied code and a RESULT row. The 'red' in this case is redundant, because there are"] \n
append out [textblock::join -- $indent "two foreground colours (lowercase first letter) so a final MERGED row displays with an alert 'REDUNDANCIES FOUND'."] \n
append out [textblock::join -- $indent "The final columns of RESULT and MERGED (showing raw ANSI sequence) will differ if the arguments aren't in canonical order."] \n
append out [textblock::join -- $indent "The MERGED line will only display if there are redundancies or different ordering."] \n
@ -2674,14 +2711,26 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
} else {
set tkcolours [list]
}
foreach c $webcolours {
append info \n web-$c
}
foreach c $x11colours {
append info \n x11-$c
}
foreach c $tkcolours {
append info \n tk-$c
if {[string is upper -strict [string index $pfx 0]]} {
foreach c $webcolours {
append info \n Web-$c
}
foreach c $x11colours {
append info \n X11-$c
}
foreach c $tkcolours {
append info \n Tk-$c
}
} else {
foreach c $webcolours {
append info \n web-$c
}
foreach c $x11colours {
append info \n x11-$c
}
foreach c $tkcolours {
append info \n tk-$c
}
}
$t add_row [list $i "$info" $s [ansistring VIEW $s]]
}
@ -8723,7 +8772,7 @@ interp alias {} ansistring {} ::punk::ansi::ansistring
namespace eval ::punk::args::register {
#use fully qualified so 8.6 doesn't find existing var in global namespace
lappend ::punk::args::register::NAMESPACES ::punk::ansi ::punk::ansi::class ::punk::ansi::ta
lappend ::punk::args::register::NAMESPACES ::punk::ansi ::punk::ansi::argdoc ::punk::ansi::class ::punk::ansi::ta
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++

153
src/modules/punk/args-999999.0a1.0.tm

@ -359,16 +359,22 @@ tcl::namespace::eval ::punk::args::helpers {
#puts $str
#puts stderr -------------------
#rudimentary colourising (not full tcl syntax parsing)
#highlight comments first - so that we can also highlight braces within comments to help with detecting unbalanced braces/square brackets in comments
switch -- $opt_syntax {
tcl {
#rudimentary colourising (not full tcl syntax parsing)
#Note that this can highlight ;# in some places as a comment where it's not appropriate
# e.g inside a regexp
#highlight comments first - so that we can also highlight braces within comments to help with detecting unbalanced braces/square brackets in comments
#result lines often indicated in examples by \u2192 →
#however - it's not present on each line of output, instead indents are used - so we can't so easily highlight all appropriate rows(?)
set str [punk::grepstr -return all -highlight {Term-grey term-darkgreen} {^\s*#.*} $str] ;#Note, will not highlight comments at end of line - like this one
set str [punk::grepstr -return all -highlight {Term-grey term-darkgreen} {;\s*(#.*)} $str]
#TODO - fix grepstr highlighting (bg issues - why?)
set str [punk::grepstr -return all -highlight {Term-grey term-darkblue} {\{|\}} $str]
#Note that if we were to highlight based on the regexp {\{|\}} then the inserted ansi would come between
# the backslash and brace in \{ or \} - this breaks the syntactic structure causing problems.
set str [punk::grepstr -return all -highlight {Term-grey tk-darkblue} {^\{|[^\\](\{+)} $str]
set str [punk::grepstr -return all -highlight {Term-grey tk-darkblue} {[^\\](\}+)} $str]
set str [punk::grepstr -return all -highlight {Term-grey term-orange1} {\[|\]} $str]
#puts stderr -------------------
#puts $str
@ -460,7 +466,7 @@ tcl::namespace::eval ::punk::args::helpers {
tcl::namespace::eval punk::args {
package require punk::assertion
#if 'package forget' was called on this package (e.g when loading test::punk::args) then assert may already exist in the namespace
#procs can be overridden silently, but not imports
#namespace import will fail if target exists
catch {
namespace import ::punk::assertion::assert
}
@ -469,9 +475,9 @@ tcl::namespace::eval punk::args {
variable PUNKARGS ;#list of our own punk::args function argument definitions - loaded with punk::args::define at the end.
tcl::namespace::export {[a-z]*}
variable rawdef_cache
if {![info exists rawdef_cache]} {
set rawdef_cache [tcl::dict::create] ;#key on rawdef list - return dict of {-id <id> -dynamic 0|1}
variable rawdef_cache_about
if {![info exists rawdef_cache_about]} {
set rawdef_cache_about [tcl::dict::create] ;#key on rawdef list - return dict of {-id <id> -dynamic 0|1}
}
variable id_cache_rawdef
if {![info exists id_cache_rawdef]} {
@ -487,9 +493,9 @@ tcl::namespace::eval punk::args {
set argdefcache_unresolved [tcl::dict::create] ;#key = original template list supplied to 'define', value = 2-element list: (tstr-parsed split of template) & (unresolved params)
}
variable argdata_cache
if {![info exists argdata_cache]} {
set argdata_cache [tcl::dict::create]
variable rawdef_cache_argdata
if {![info exists rawdef_cache_argdata]} {
set rawdef_cache_argdata [tcl::dict::create]
}
variable id_counter
@ -979,11 +985,11 @@ tcl::namespace::eval punk::args {
error todo
}
proc define {args} {
variable rawdef_cache
variable rawdef_cache_about
variable id_cache_rawdef
variable argdata_cache
if {[dict exists $rawdef_cache $args]} {
return [dict get [dict get $rawdef_cache $args] -id]
#variable rawdef_cache_argdata
if {[dict exists $rawdef_cache_about $args]} {
return [dict get [dict get $rawdef_cache_about $args] -id]
} else {
set lvl 2
set id [rawdef_id $args $lvl]
@ -991,46 +997,40 @@ tcl::namespace::eval punk::args {
#we seem to be re-creating a previously defined id...
#clear any existing caches for this id
undefine $id 0
##dict unset argdata_cache $prevraw ;#silently does nothing if key not present
#dict for {k v} $argdata_cache {
# if {[dict get $v id] eq $id} {
# dict unset argdata_cache $k
# }
#}
#dict for {k v} $rawdef_cache {
# if {[dict get $v -id] eq $id} {
# dict unset rawdef_cache $k
# }
#}
#dict unset id_cache_rawdef $id
}
set is_dynamic [rawdef_is_dynamic $args]
set defspace [uplevel 1 {::namespace current}]
dict set rawdef_cache $args [dict create -id $id -dynamic $is_dynamic -defspace $defspace]
dict set rawdef_cache_about $args [dict create -id $id -dynamic $is_dynamic -defspace $defspace]
dict set id_cache_rawdef $id $args
return $id
}
}
proc undefine {id {quiet 0}} {
variable rawdef_cache
#review - alias?
variable rawdef_cache_about
variable id_cache_rawdef
variable argdata_cache
variable rawdef_cache_argdata
if {[id_exists $id]} {
if {!$quiet} {
puts stderr "punk::args::undefine clearing existing data for id:$id"
}
dict for {k v} $argdata_cache {
if {[dict get $v id] eq $id} {
dict unset argdata_cache $k
if {[dict exists $id_cache_rawdef $id]} {
set deflist [dict get $id_cache_rawdef $id]
dict unset rawdef_cache_about $deflist
dict unset rawdef_cache_argdata $deflist
dict unset id_cache_rawdef $id
} else {
dict for {k v} $rawdef_cache_argdata {
if {[dict get $v id] eq $id} {
dict unset rawdef_cache_argdata $k
}
}
}
dict for {k v} $rawdef_cache {
if {[dict get $v -id] eq $id} {
dict unset rawdef_cache $k
dict for {k v} $rawdef_cache_about {
if {[dict get $v -id] eq $id} {
dict unset rawdef_cache_about $k
}
}
}
dict unset id_cache_rawdef $id
} else {
if {!$quiet} {
puts stderr "punk::args::undefine unable to find id: '$id'"
@ -1039,17 +1039,26 @@ tcl::namespace::eval punk::args {
}
#'punk::args::parse $args withdef $deflist' can raise parsing error after an autoid was generated
# In this case we don't see the autoid in order to delete it
#proc undefine_deflist {deflist} {
#}
proc undefine_deflist {deflist} {
variable rawdef_cache_about
variable id_cache_rawdef
variable rawdef_cache_argdata
if {[dict exists $rawdef_cache_about $deflist -id]} {
set id [dict get $rawdef_cache_about $deflist -id]
dict unset rawdef_cache_about $deflist
dict unset rawdef_cache_argdata $deflist
dict unset id_cache_rawdef $id
}
}
proc idquery_info {id} {
variable id_cache_rawdef
variable rawdef_cache
variable rawdef_cache_about
if {[dict exists $id_cache_rawdef $id]} {
set sep [string repeat - 40]
set rawdef [dict get $id_cache_rawdef $id]
if {[dict exists $rawdef_cache $rawdef]} {
set idinfo [dict get $rawdef_cache $rawdef]
if {[dict exists $rawdef_cache_about $rawdef]} {
set idinfo [dict get $rawdef_cache_about $rawdef]
} else {
set idinfo ""
}
@ -1060,11 +1069,11 @@ tcl::namespace::eval punk::args {
append result \n "id info:"
append result \n $idinfo
append result \n $sep
variable argdata_cache
variable rawdef_cache_argdata
#lsearch -stride not avail (or buggy) in some 8.6 interps - search manually for now (2025). todo - modernize some time after Tcl 9.0/9.1 more widespread.(2027?)
#check for and report if id is present multiple times
set argdata_records [list]
dict for {k v} $argdata_cache {
dict for {k v} $rawdef_cache_argdata {
if {[dict get $v id] eq $id} {
if {$k eq $rawdef} {
lappend argdata_records [list 1 $k $v]
@ -1100,12 +1109,20 @@ tcl::namespace::eval punk::args {
dict get [resolve {*}$args] id
}
lappend PUNKARGS [list {
@id -id ::punk::args::resolve
@cmd -name punk::args::resolve -help\
""
@values -min 0 -max -1
arg -type any -multiple 1 -help\
"rawdef line block"
}]
proc resolve {args} {
variable rawdef_cache
variable rawdef_cache_about
variable id_cache_rawdef
set defspace ""
if {[dict exists $rawdef_cache $args]} {
set cinfo [dict get $rawdef_cache $args]
if {[dict exists $rawdef_cache_about $args]} {
set cinfo [dict get $rawdef_cache_about $args]
set id [dict get $cinfo -id]
set is_dynamic [dict get $cinfo -dynamic]
if {[dict exists $cinfo -defspace]} {
@ -1116,12 +1133,13 @@ tcl::namespace::eval punk::args {
set id [rawdef_id $args]
puts stderr "Warning: punk::args::resolve called with undefined id:$id"
set is_dynamic [rawdef_is_dynamic $args]
dict set rawdef_cache $args [dict create -id $id -dynamic $is_dynamic]
#-defspace ???
dict set rawdef_cache_about $args [dict create -id $id -dynamic $is_dynamic]
dict set id_cache_rawdef $id $args
}
variable argdata_cache
variable rawdef_cache_argdata
variable argdefcache_unresolved
@ -1155,8 +1173,8 @@ tcl::namespace::eval punk::args {
if {!$is_dynamic} {
#todo - don't use cached version if 'colour off' vs 'colour on' different to when last resolved!
#(e.g example blocks will still have colour if previously resolved)
if {[tcl::dict::exists $argdata_cache $cache_key]} {
return [tcl::dict::get $argdata_cache $cache_key]
if {[tcl::dict::exists $rawdef_cache_argdata $cache_key]} {
return [tcl::dict::get $rawdef_cache_argdata $cache_key]
}
set normargs [list]
foreach a $textargs {
@ -1235,10 +1253,10 @@ tcl::namespace::eval punk::args {
tcl::dict::set argdefcache_unresolved $cache_key $pt_params
}
}
#argdata_cache should be limited in some fashion or will be a big memory leak???
if {[tcl::dict::exists $argdata_cache [list $optionspecs]]} {
#rawdef_cache_argdata should be limited in some fashion or will be a big memory leak???
if {[tcl::dict::exists $rawdef_cache_argdata [list $optionspecs]]} {
#resolved cache version exists
return [tcl::dict::get $argdata_cache [list $optionspecs]]
return [tcl::dict::get $rawdef_cache_argdata [list $optionspecs]]
}
}
@ -2669,10 +2687,12 @@ tcl::namespace::eval punk::args {
form_info $form_info\
]
tcl::dict::set argdata_cache $cache_key $argdata_dict
#REVIEW
tcl::dict::set rawdef_cache_argdata $cache_key $argdata_dict
if {$is_dynamic} {
#also cache resolved version
tcl::dict::set argdata_cache [list $optionspecs] $argdata_dict
tcl::dict::set rawdef_cache_argdata [list $optionspecs] $argdata_dict
}
#tcl::dict::set id_cache_rawdef $DEF_definition_id $args
@ -3094,10 +3114,10 @@ tcl::namespace::eval punk::args {
}
proc is_dynamic {id} {
variable id_cache_rawdef
variable rawdef_cache
variable rawdef_cache_about
set deflist [raw_def $id]
if {[dict exists $rawdef_cache $deflist -dynamic]} {
return [dict get $rawdef_cache $deflist -dynamic]
if {[dict exists $rawdef_cache_about $deflist -dynamic]} {
return [dict get $rawdef_cache_about $deflist -dynamic]
}
return [rawdef_is_dynamic $deflist]
#@dynamic only has meaning as 1st element of a def in the deflist
@ -4008,7 +4028,16 @@ tcl::namespace::eval punk::args {
}
if {$synopsis ne ""} {
if {$use_table} {
$t configure_header $h -colspans $arg_colspans -values [list Synopsis: [punk::ansi::ansiwrap brightwhite $synopsis]]
set form_names [dict get $spec_dict form_names]
set synhelp "Synopsis:"
if {[llength $form_names] > 1} {
set fn 0
foreach fname $form_names {
append synhelp \n " i -form $fn \U2026"
incr fn
}
}
$t configure_header $h -colspans $arg_colspans -values [list $synhelp [punk::ansi::ansiwrap brightwhite $synopsis]]
} else {
#todo
lappend errlines "Synopsis:\n$synopsis"

1550
src/modules/punk/args/moduledoc/tclcore-999999.0a1.0.tm

File diff suppressed because it is too large Load Diff

315
src/modules/punk/args/moduledoc/tkcore-999999.0a1.0.tm

@ -111,6 +111,8 @@ tcl::namespace::eval punk::args::moduledoc::tkcore {
set NI [a+ noitalic]
set B [a+ bold]
set N [a+ normal]
set T [a+ bold underline]
set NT [a+ normal nounderline]
# -- --- --- --- ---
namespace import ::punk::args::helpers::*
@ -512,6 +514,7 @@ tcl::namespace::eval punk::args::moduledoc::tkcore {
punk::args::define {
@id -id (widgetcommand)Class_Button
# ?? (instance)Class_Button ??
@cmd -name "Tk widget: (widgetcommand)Class_Button"\
-summary\
"widgetcommand for Tk class Button"\
@ -531,6 +534,318 @@ tcl::namespace::eval punk::args::moduledoc::tkcore {
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
# ::wm subcommands
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
punk::args::define {
@id -id "::wm aspect"
@cmd -name "Tk Built-in: ::wm aspect"\
-summary\
"Get/set aspect ratio restrictions."\
-help\
"If ${$I}minNumer${$NI}, ${$I}minDenom${$NI}, ${$I}maxNumer${$NI}, and ${$I}maxDenom${$NI} are all specified, then they will be passed to
the window manager and the window manager should use them to enforce a range of acceptable
aspect ratios for window. The aspect ratio of window (width/length) will be constrained to lie
between ${$I}minNumer${$NI}/${$I}minDenom${$NI} and ${$I}maxNumer${$NI}/${$I}maxDenom${$NI}. If ${$I}minNumer${$NI} etc. are all specified as empty
strings, then any existing aspect ratio restrictions are removed. If ${$I}minNumer${$NI} etc. are
specified, then the command returns an empty string. Otherwise, it returns a Tcl list
containing four elements, which are the current values of ${$I}minNumer${$NI}, ${$I}minDenom${$NI}, ${$I}maxNumer${$NI}, and
${$I}maxDenom${$NI} (if no aspect restrictions are in effect, then an empty string is returned)."
@values -min 1
window -type string
#todo - punk::args - way to specify all number or all empty e.g
# -type {(number number number number)|(literal() literal() literal() literal())}
aspectratio\
-type {number|literal() number|literal() number|literal() number|literal()}\
-typesynopsis "${$I}minNumer${$NI} ${$I}minDenom${$NI} ${$I}maxNumer${$NI} ${$I}maxDenom${$NI}"\
-optional 1
} "@doc -name Manpage: -url [manpage wm]"
#attributes
punk::args::define {
@id -id "::wm client"
@cmd -name "Tk Built-in: ::wm client"\
-summary\
"Get/set WM_CLIENT_MACHINE name for the window."\
-help\
"If ${$I}name${$NI} is specified, this command stores ${$I}name${$NI} (which should be the name of the host on which the application
is executing) in ${$I}window${$NI}'s ${$B}WM_CLIENT_MACHINE${$N} property for use by the window manager or session manager. The
command returns an empty string in this case. If ${$I}name${$NI} is not specified, the command returns the last name set
in a wm client command for window. If ${$I}name${$NI} is specified as an empty string, the command deletes the
${$B}WM_CLIENT_MACHINE${$N} property from ${$I}window${$NI}."
@values -min 1 -max 2
window -type string
name\
-type string\
-optional 1
} "@doc -name Manpage: -url [manpage wm]"
#colormapwindows
#command
#deiconify
#focusmodel
punk::args::define {
@id -id "::wm forget"
@cmd -name "Tk Built-in: ::wm forget"\
-summary\
"Unmap/Unmanage window."\
-help\
"The window will be unmapped from the screen and will no longer be managed by ${$B}wm${$N}. Windows created with the
${$B}toplevel${$N} command will be treated like frame windows once they are no longer managed by ${$B}wm${$N}, however, the
${$B}-menu${$N} configuration will be remembered and the menus will return once the widget is managed again."
@values -min 1 -max 1
window -type string
} "@doc -name Manpage: -url [manpage wm]"
punk::args::define {
@id -id "::wm frame"
@cmd -name "Tk Built-in: ::wm frame"\
-summary\
"Identifier of outermost frame containing window."\
-help\
"If ${$I}window${$NI} has been reparented by the window manager into a decorative frame, the command returns the
platform specific window identifier for the outermost frame that contains ${$I}window${$NI} (the window whose parent
is the root or virtual root). If ${$I}window${$NI} has not been reparented by the window manager then the command
returns the platform specific window identifier for ${$I}window${$NI}."
@values -min 1 -max 1
window -type string
} "@doc -name Manpage: -url [manpage wm]"
#geometry
#grid
#group
#iconbadge
#iconbitmap
#iconify
#iconmask
#iconname
#iconphoto
#iconposition
#iconwindow
punk::args::define {
@id -id "::wm manage"
@cmd -name "Tk Built-in: ::wm manage"\
-summary\
"Make frame/labelframe a toplevel."\
-help\
"The ${$I}widget${$NI} specified will become a stand alone top-level window. The window will be decorated with the window
managers title bar, etc. Only frame, labelframe and toplevel widgets can be used with this command. Attempting
to pass any other widget type will raise an error. Attempting to manage a toplevel widget is benign and achieves
nothing. See also ${$B}GEOMETRY MANAGEMENT${$N}."
@values -min 1 -max 1
widget -type string -help\
"frame, labelframe or toplevel"
} "@doc -name Manpage: -url [manpage wm]"
#maxsize
#minsize
#overrideredirect
#positionfrom
#protocol
punk::args::define {
@id -id "::wm resizable"
@cmd -name "Tk Built-in: ::wm resizable"\
-summary\
"Get/Set window width and height resizability."\
-help\
"This command controls whether or not the user may interactively resize a top-level window. If ${$I}width${$NI} and ${$I}height${$NI} are
specified, they are boolean values that determine whether the width and height of window may be modified by the user.
In this case the command returns an empty string. If ${$I}width${$NI} and ${$I}height${$NI} are omitted then the command returns a list
with two 0/1 elements that indicate whether the width and height of window are currently resizable. By default,
windows are resizable in both dimensions. If resizing is disabled, then the window's size will be the size from the
most recent interactive resize or ${$B}wm geometry${$N} command. If there has been no such operation then the window's natural
size will be used."
@values -min 1
window -type string
width_height\
-type {boolean boolean}\
-typesynopsis "${$I}width${$NI} ${$I}height${$NI}"\
-optional 1
} "@doc -name Manpage: -url [manpage wm]"
#sizefrom
#stackorder
punk::args::define {
@id -id "::wm state"
@cmd -name "Tk Built-in: ::wm state"\
-summary\
"Get/set window state."\
-help\
"If newstate is specified, the window will be set to the new state, otherwise it returns the current state of window:
either ${$B}normal${$N}, ${$B}iconic${$N}, ${$B}withdrawn${$N}, ${$B}icon${$N}, or (Windows and macOS only) ${$B}zoomed${$N}. The difference between ${$B}iconic${$N} and ${$B}icon${$N} is
that ${$B}iconic${$N} refers to a window that has been iconified (e.g., with the wm iconify command) while ${$B}icon${$N} refers to a
window whose only purpose is to serve as the icon for some other window (via the ${$B}wm iconwindow${$N} command).
The ${$B}icon${$N} state cannot be set."
@values -min 1 -max 2
window -type string
newstate\
-type string\
-optional 1\
-choices {normal iconic withdrawn zoomed}\
-choicelabels {\
normal\
""
iconic\
""
withdrawn\
""
zoomed\
" (Windows and macOS only)"
}
} "@doc -name Manpage: -url [manpage wm]"
#title
#transient
#withdraw
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
# ::wm
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
set WM_CHOICES [list aspect attributes client colormapwindows command deiconify focusmodel forget frame\
geometry grid group iconbadge iconbitmap iconify iconmask iconname iconphoto iconposition iconwindow\
manage maxsize minsize overrideredirect positionfrom protocol resizable sizefrom stackorder\
state title transient withdraw\
]
#manual synopses for subcommands not yet defined
set WM_CHOICELABELS [subst -novariables {
}]
set WM_CHOICEGROUPS [dict create\
"" {}\
icon {iconbadge iconbitmap iconmask iconphoto iconposition iconwindow}\
]
set WM_GROUPALLOCATED [list]
dict for {g glist} $WM_CHOICEGROUPS {
lappend WM_GROUPALLOCATED {*}$glist
}
foreach sub $WM_CHOICES {
if {$sub ni $WM_GROUPALLOCATED} {
dict lappend WM_CHOICEGROUPS "" $sub
}
}
set WM_CHOICEINFO [dict create]
foreach sub $WM_CHOICES {
#default for all
dict set WM_CHOICEINFO $sub {{doctype native}}
}
foreach id [punk::args::get_ids "::wm *"] {
if {[llength $id] == 2} {
lassign $id _ sub
dict set WM_CHOICEINFO $sub {{doctype native} {doctype punkargs}}
#override manual synopsis entry
#puts stderr "override manual synopsis entry with [punk::ns::synopsis "::wm $sub"]"
dict set WM_CHOICELABELS $sub [punk::ansi::a+ normal][punk::args::synopsis "::wm $sub"]
}
}
punk::args::define {
@id -id ::wm
@cmd -name "Tk Built-in: ::wm"\
-summary\
"Communicate with window manager."\
-help\
"The ${$B}wm${$N} command is used to interact with window managers in order to control such things as the
title for a window, its geometry, or the increments in terms of which it may be resized. The ${$B}wm${$N}
command can take any of a number of different forms, depending on the option argument. All of
the forms expect at least one additional argument, window, which must be the path name of a
top-level window.
${$T}GEOMETRY MANAGMENT${$NT}
By default a top-level window appears on the screen in its natural size, which is the one determined internally
by its widgets and geometry managers. If the natural size of a top-level window changes, then the window's size
changes to match. A top-level window can be given a size other than its natural size in two ways. First, the
user can resize the window manually using the facilities of the window manager, such as resize handles. Second,
the application can request a particular size for a top-level window using the wm geometry command. These two
cases are handled identically by Tk; in either case, the requested size overrides the natural size. You can
return the window to its natural by invoking wm geometry with an empty geometry string.
Normally a top-level window can have any size from one pixel in each dimension up to the size of its screen.
However, you can use the wm minsize and wm maxsize commands to limit the range of allowable sizes. The range
set by wm minsize and wm maxsize applies to all forms of resizing, including the window's natural size as well
as manual resizes and the wm geometry command. You can use any value accepted by Tk_GetPixels. You can also use
the command wm resizable to completely disable interactive resizing in one or both dimensions.
The wm manage and wm forget commands may be used to perform undocking and docking of windows. After a widget is
managed by wm manage command, all other wm subcommands may be used with the widget. Only widgets created using
the toplevel command may have an attached menu via the -menu configure option. A toplevel widget may be used as
a frame and managed with any of the other geometry managers after using the wm forget command. Any menu
associated with a toplevel widget will be hidden when managed by another geometry managers. The menus will
reappear once the window is managed by wm. All custom bindtags for widgets in a subtree that have their top-level
widget changed via a wm manage or wm forget command, must be redone to adjust any top-level widget path in the
bindtags. Bindtags that have not been customized do not have to be redone.
${$T}GRIDDED GEOMETRY MANAGEMENT${$NT}
Gridded geometry management occurs when one of the widgets of an application supports a range of useful sizes.
This occurs, for example, in a text editor where the scrollbars, menus, and other adornments are fixed in size but
the edit widget can support any number of lines of text or characters per line. In this case, it is usually
desirable to let the user specify the number of lines or characters-per-line, either with the wm geometry command
or by interactively resizing the window. In the case of text, and in other interesting cases also, only discrete
sizes of the window make sense, such as integral numbers of lines and characters-per-line; arbitrary pixel sizes
are not useful.
Gridded geometry management provides support for this kind of application. Tk (and the window manager) assume that
there is a grid of some sort within the application and that the application should be resized in terms of grid
units rather than pixels. Gridded geometry management is typically invoked by turning on the setGrid option for a
widget; it can also be invoked with the wm grid command or by calling Tk_SetGrid. In each of these approaches the
particular widget (or sometimes code in the application as a whole) specifies the relationship between integral
grid sizes for the window and pixel sizes. To return to non-gridded geometry management, invoke wm grid with empty
argument strings.
When gridded geometry management is enabled then all the dimensions specified in wm minsize, wm maxsize, and
wm geometry commands are treated as grid units rather than pixel units. Interactive resizing is also carried out in
even numbers of grid units rather than pixels.
${$T}BUGS${$NT}
Most existing window managers appear to have bugs that affect the operation of the ${$B}wm${$N} command. For example,
some changes will not take effect if the window is already active: the window will have to be withdrawn and
de-iconified in order to make the change happen."
@leaders -min 1 -max 1
subcommand -type string\
-choicecolumns 2\
-choicegroups\
{${$WM_CHOICEGROUPS}}\
-unindentedfields {-choicelabels}\
-choicelabels\
{${$WM_CHOICELABELS}}\
-choiceinfo {${$WM_CHOICEINFO}}
@values -unnamed true
} "@doc -name Manpage: -url [manpage wm]"\
{
@examples -help {
A fixed-size window that says that it is fixed-size too:
${[example {
toplevel .fixed
${$B}wm title${$N} .fixed "Fixed-size Window"
${$B}wm resizable${$N} .fixed 0 0
}]}
A simple dialog-like window, centred on the screen:
${[example {
# Create and arrange the dialog contents.
toplevel .msg
label .msg.l -text "This is a very simple dialog demo."
button .msg.ok -text OK -default active -command {destroy .msg}
pack .msg.ok -side bottom -fill x
pack .msg.l -expand 1 -fill both
# Now set the widget up as a centred dialog.
# But first, we need the geometry managers to finish setting
# up the interior of the dialog, for which we need to run the
# event loop with the widget hidden completely...
${$B}wm withdraw${$N} .msg
update
set x [expr {([winfo screenwidth .] - [winfo width .msg]) / 2}]
set y [expr {([winfo screenheight .] - [winfo height .msg]) / 2}]
${$B}wm geometry${$N} .msg +$x+$y
${$B}wm transient${$N} .msg .
${$B}wm title${$N} .msg "Dialog demo"
${$B}wm deiconify${$N} .msg
}]}
}}
}
#*** !doctools

40
src/modules/punk/assertion-999999.0a1.0.tm

@ -66,38 +66,6 @@ package require Tcl 8.6-
#*** !doctools
#[section API]
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# oo::class namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
tcl::namespace::eval punk::assertion::class {
#*** !doctools
#[subsection {Namespace punk::assertion::class}]
#[para] class definitions
if {[tcl::info::commands [tcl::namespace::current]::interface_sample1] eq ""} {
#*** !doctools
#[list_begin enumerated]
# oo::class create interface_sample1 {
# #*** !doctools
# #[enum] CLASS [class interface_sample1]
# #[list_begin definitions]
# method test {arg1} {
# #*** !doctools
# #[call class::interface_sample1 [method test] [arg arg1]]
# #[para] test method
# puts "test: $arg1"
# }
# #*** !doctools
# #[list_end] [comment {-- end definitions interface_sample1}]
# }
#*** !doctools
#[list_end] [comment {--- end class enumeration ---}]
}
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#keep 2 namespaces for assertActive and assertInactive so there is introspection available via namespace origin
tcl::namespace::eval punk::assertion::primary {
@ -149,9 +117,13 @@ tcl::namespace::eval punk::assertion {
proc do_ns_import {} {
uplevel 1 [list tcl::namespace::import ::punk::assertion::primary::assertActive]
}
do_ns_import
#puts --------BBB
rename assertActive assert
if {[catch {
do_ns_import
rename assertActive assert
} errM]} {
puts stderr "punk::assertion error during load - assert/assertActive functions already present?\n$errM"
}
}

4
src/modules/punk/du-999999.0a1.0.tm

@ -961,9 +961,9 @@ namespace eval punk::du {
proc get_vfsmounts_in_folder {folderpath} {
set vfsmounts [list]
if {![llength [package provide vfs]]} {
return [list]
return [list]
}
set fpath [punk::objclone $folderpath]
set fpath [punk::valcopy $folderpath]
set is_rel 0
if {[file pathtype $fpath] ne "absolute"} {
set fpath [file normalize $fpath]

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

@ -4071,11 +4071,11 @@ namespace eval punk::lib {
interp eval $interp [list tcl::tm::add {*}[lreverse [tcl::tm::list]]]
}
proc objclone {obj} {
proc valcopy {obj} {
append obj2 $obj {}
}
proc set_clone {varname obj} {
#used by repl's codeinterp. Maintains internal rep, easier to call e.g interp eval code [list punk::set_clone varnmame $val]
proc set_valcopy {varname obj} {
#used by repl's codeinterp. Maintains internal rep, easier to call e.g interp eval code [list punk::set_valcopy varnmame $val]
append obj2 $obj {}
uplevel 1 [list set $varname $obj2]
}
@ -4095,9 +4095,9 @@ namespace eval punk::lib {
set default_groupsize 3
set results [list]
set nums [objclone $numbers_or_commaformattednumbers] ;#stops single num from getting internal rep of list
set nums [valcopy $numbers_or_commaformattednumbers] ;#stops single num from getting internal rep of list
foreach inputnum $nums {
set number [objclone $inputnum]
set number [valcopy $inputnum]
#also handle tcl 8.7+ underscores in numbers
set number [string map [list _ "" , ""] $number]
#normalize e.g 2e4 -> 20000.0
@ -4145,7 +4145,7 @@ namespace eval punk::lib {
# and possibly containing a decimal point, i.e.: [:space:]*[:digit:]*\.[:digit:]*
proc delimit_number {unformattednumber {delim ","} {GroupSize 3}} {
set number [objclone $unformattednumber]
set number [valcopy $unformattednumber]
set number [string map {_ ""} $number]
#normalize using expr - e.g 2e4 -> 20000.0
set number [expr {$number}]

8
src/modules/punk/mix/commandset/loadedlib-999999.0a1.0.tm

@ -34,7 +34,7 @@ namespace eval punk::mix::commandset::loadedlib {
"(unimplemented) Display only those that are 0:absent 1:present 2:either"
-highlight -type boolean -default 1 -help\
"Highlight which version is present with ansi underline and colour"
-refresh -default 0 -type boolean -help "Re-scan the tm and library folders"
-refresh -type none -help "Re-scan the tm and library folders"
searchstring -default * -multiple 1 -help\
"Names to search for, may contain glob chars (* ?) e.g *lib*
If no glob chars are explicitly specified, the searchstring will be wrapped with star globs.
@ -45,11 +45,11 @@ namespace eval punk::mix::commandset::loadedlib {
}
proc search {args} {
set argd [punk::args::parse $args withid ::punk::mix::commandset::loadedlib::search]
set searchstrings [dict get $argd values searchstring]
set opts [dict get $argd opts]
lassign [dict values $argd] leaders opts values received
set searchstrings [dict get $values searchstring]
set opt_return [dict get $opts -return]
set opt_highlight [dict get $opts -highlight]
set opt_refresh [dict get $opts -refresh]
set opt_refresh [dict exists $received -refresh]
if {$opt_refresh} {
catch {package require frobznodule666} ;#ensure pkg system has loaded/searched for everything REVIEW - this doesn't result in full scans

2328
src/modules/punk/ns-999999.0a1.0.tm

File diff suppressed because it is too large Load Diff

58
src/modules/punk/repl-999999.0a1.0.tm

@ -3177,7 +3177,7 @@ namespace eval repl {
variable errstack {}
variable outstack {}
variable run_command_cache
proc set_clone {varname obj} {
proc set_valcopy {varname obj} {
append obj2 $obj {}
uplevel 1 [list set $varname $obj2]
}
@ -3241,6 +3241,7 @@ namespace eval repl {
#}
set pkgs [list\
punk::ansi::colourmap\
punk::assertion\
punk::args\
punk::pipe\
cmdline\
@ -3256,7 +3257,6 @@ namespace eval repl {
textutil\
punk::encmime\
punk::char\
punk::assertion\
punk::ansi\
punk::lib\
overtype\
@ -3290,37 +3290,41 @@ namespace eval repl {
set prior_infoscript [code eval {info script}] ;#probably empty that's ok
foreach pkg $pkgs {
#puts stderr "---> init_script safe pkg: $pkg"
if {[catch {
set nsquals [namespace qualifiers $pkg]
if {$nsquals ne ""} {
if {![dict exists $ns_scanned $nsquals]} {
catch {package require $pkg 1-0} ;#force scan with nonsatisfiable version
dict set ns_scanned $nsquals 1
#only load from source if not already loaded (perhaps already present from another package loading it)
set vloaded [code eval [list package provide $pkg]]
if {$vloaded eq ""} {
if {[catch {
set nsquals [namespace qualifiers $pkg]
if {$nsquals ne ""} {
if {![dict exists $ns_scanned $nsquals]} {
catch {package require $pkg 1-0} ;#force scan with nonsatisfiable version
dict set ns_scanned $nsquals 1
}
}
}
set versions [lsort -command {package vcompare} [package versions $pkg]]
if {[llength $versions]} {
set v [lindex $versions end]
set path [lindex [package ifneeded $pkg $v] end]
if {[file extension $path] in {.tcl .tm}} {
if {![catch {readFile $path} data]} {
code eval [list info script $path]
code eval $data
code eval [list info script $prior_infoscript]
set versions [lsort -command {package vcompare} [package versions $pkg]]
if {[llength $versions]} {
set v [lindex $versions end]
set path [lindex [package ifneeded $pkg $v] end]
if {[file extension $path] in {.tcl .tm}} {
if {![catch {readFile $path} data]} {
code eval [list info script $path]
code eval $data
code eval [list info script $prior_infoscript]
} else {
error "safe - failed to read $path"
}
} else {
error "safe - failed to read $path"
error "safe - refusing to attempt load of $pkg from $path - (allowed extensions .tcl .tm)"
}
} else {
error "safe - refusing to attempt load of $pkg from $path - (allowed extensions .tcl .tm)"
error "safe - no versions of $pkg found"
}
} errMsg]} {
puts stderr "safe - failed to load package $pkg\n$errMsg\n$::errorInfo"
} else {
error "safe - no versions of $pkg found"
#puts stdout "---> init_script safe - loaded $pkg from $path"
#puts stdout "---> v [code eval [list package provide $pkg]]"
}
} errMsg]} {
puts stderr "safe - failed to load package $pkg\n$errMsg\n$::errorInfo"
} else {
#puts stdout "---> init_script safe - loaded $pkg from $path"
#puts stdout "---> v [code eval [list package provide $pkg]]"
}
}
@ -3337,7 +3341,7 @@ namespace eval repl {
#review
code alias ::shellfilter::stack ::shellfilter::stack
#code alias ::punk::lib::set_clone ::punk::lib::set_clone
#code alias ::punk::lib::set_valcopy ::punk::lib::set_valcopy
#code alias ::aliases ::punk::ns::aliases
code alias ::punk::ns::aliases ::punk::ns::aliases
namespace eval ::codeinterp {}

4
src/modules/punk/repl/codethread-999999.0a1.0.tm

@ -196,8 +196,8 @@ tcl::namespace::eval punk::repl::codethread {
#otherwise when $script goes out of scope - internal rep of vars set in script changes.
#The shimmering may be no big deal(?) - but debug/analysis using tcl::unsupported::representation becomes impossible.
#interp eval code [list ::punk::lib::set_clone ::codeinterp::clonescript $script] ;#like objclone
interp eval code [list ::codeinterp::set_clone ::codeinterp::clonescript $script] ;#like objclone
#interp eval code [list ::punk::lib::set_valcopy ::codeinterp::clonescript $script] ;#like valcopy
interp eval code [list ::codeinterp::set_valcopy ::codeinterp::clonescript $script] ;#like valcopy
interp eval code {lappend ::codeinterp::run_command_cache $::codeinterp::clonescript}

18
src/modules/punk/unixywindows-999999.0a1.0.tm

@ -35,35 +35,35 @@ namespace eval punk::unixywindows {
if {![string length $cachedunixyroot]} {
if {![catch {
set result [exec cygpath -m /] ;# -m gives result with forward-slashes - which is ok for windows paths in a Tcl context.
set cachedunixyroot [punk::objclone $result]
set cachedunixyroot [punk::valcopy $result]
file pathtype $cachedunixyroot; #this call causes the int-rep to be path
#set ::punk::last_run_display [list] ;#hack - review shouldn't really be necessary.. but because we call winpath from ./ - the repl looks for last_run_display
} errM]} {
} else {
puts stderr "Warning: Failed to determine base for unix-like paths - using default of c:/msys2"
file pathtype [set cachedunixyroot [punk::objclone "c:/msys2"]]
file pathtype [set cachedunixyroot [punk::valcopy "c:/msys2"]]
}
}
#will have been shimmered from string to 'path' internal rep by 'file pathtype' call
#let's return a different copy as it's so easy to lose path-rep
set copy [punk::objclone $cachedunixyroot]
set copy [punk::valcopy $cachedunixyroot]
return $copy
}
proc refresh_unixyroot {} {
variable cachedunixyroot
set result [exec cygpath -m /] ;# -m gives result with forward-slashes - which is ok for windows paths in a Tcl context.
set cachedunixyroot [punk::objclone $result]
set cachedunixyroot [punk::valcopy $result]
file pathtype $cachedunixyroot; #this call causes the int-rep to be path
set copy [punk::objclone $cachedunixyroot]
set copy [punk::valcopy $cachedunixyroot]
return $copy
}
proc set_unixyroot {windows_path} {
variable cachedunixyroot
file pathtype $windows_path
set cachedunixyroot [punk::objclone $windows_path]
set cachedunixyroot [punk::valcopy $windows_path]
#return the original - but probably int-rep will have shimmered to path even if started out as string
#- that's probably what we want. Caller can use as string or path without affecting cachedunixyroot
return $windows_path
@ -131,13 +131,13 @@ namespace eval punk::unixywindows {
}
#puts stderr "->$driveletters"
set path [punk::objclone $unixypath] ;#take another copy that we can deliberatley shimmer to path and know is separate to the supplied argument
set path [punk::valcopy $unixypath] ;#take another copy that we can deliberatley shimmer to path and know is separate to the supplied argument
set supplied_pathtype [file pathtype $path] ;#we don't care about the pathtype so much as the act of making this call shimmers to a path internal-rep
#copy of var that we can treat as a string without affecting path rep
#Note that some but not all read operations will lose path rep e.g 'string length $x' will lose any path-rep $x had, (but 'string equal $x something' won't)
#Todo - make int-rep tests to check stability of these behaviours across Tcl versions!
set strcopy_path [punk::objclone $path]
set strcopy_path [punk::valcopy $path]
set str_newpath ""
@ -174,7 +174,7 @@ namespace eval punk::unixywindows {
#dunno - pass through
set pathobj $path
} else {
set pathobj [punk::objclone $str_newpath]
set pathobj [punk::valcopy $str_newpath]
file pathtype $pathobj
}
}

12
src/modules/punk/winpath-999999.0a1.0.tm

@ -30,7 +30,7 @@ namespace eval punk::winpath {
#\\servername\share etc or \\?\UNC\servername\share etc.
proc is_unc_path {path} {
set strcopy_path [punk::winpath::system::objclone $path]
set strcopy_path [punk::winpath::system::valcopy $path]
set strcopy_path [string map {\\ /} $strcopy_path] ;#normalize to forward slashes for testing purposes (and forward slashes seem to be auto-translated by windows anyway)
if {[string first "//" $strcopy_path] == 0} {
#check for "Dos device path" syntax
@ -77,7 +77,7 @@ namespace eval punk::winpath {
#dos device path syntax allows windows api to acces extended-length paths and filenames with illegal path characters such as trailing dots or whitespace
#(can exist on server shares and on NTFS - but standard apps can't access without dos device syntax)
proc is_dos_device_path {path} {
set strcopy_path [punk::winpath::system::objclone $path]
set strcopy_path [punk::winpath::system::valcopy $path]
set strcopy_path [string map {\\ /} $strcopy_path] ;#normalize to forward slashes for testing purposes (and forward slashes seem to be auto-translated by windows anyway)
if {[string range $strcopy_path 0 3] in {//?/ //./}} {
return 1
@ -100,13 +100,13 @@ namespace eval punk::winpath {
proc strip_unc_path_prefix {path} {
if {[is_unc_path_plain $path]} {
#plain unc //server
set strcopy_path [punk::winpath::system::objclone $path]
set strcopy_path [punk::winpath::system::valcopy $path]
set trimmedpath [string range $strcopy_path 2 end]
file pathtype $trimmedpath
return $trimmedpath
} elseif {is_unc_path $path} {
#//?/UNC/server/subpath or //./UNC/server/subpath
set strcopy_path [punk::winpath::system::objclone $path]
set strcopy_path [punk::winpath::system::valcopy $path]
set trimmedpath [string range $strcopy_path 7 end]
file pathtype $trimmedpath ;#shimmer it to path rep
return $trimmedpath
@ -153,7 +153,7 @@ namespace eval punk::winpath {
error $err
}
set strcopy_path [punk::winpath::system::objclone $path]
set strcopy_path [punk::winpath::system::valcopy $path]
#Note: path could still have leading double slash if it is a Dos device path: e.g. //?/c:/etc
@ -339,7 +339,7 @@ namespace eval punk::winpath {
namespace eval punk::winpath::system {
#get a copy of the item without affecting internal rep
proc objclone {obj} {
proc valcopy {obj} {
append obj2 $obj {}
}
}

16
src/modules/punk/winrun-999999.0a1.0.tm

@ -310,7 +310,7 @@ namespace eval punk::winrun {
set tcl_list [list]
set i 0
foreach a $cmdargs {
set copy [internal::objclone $a]
set copy [internal::valcopy $a]
append raw_cmdline "$copy "
lappend tcl_list $copy
if {$i == 0 && !$quiet} {
@ -333,7 +333,7 @@ namespace eval punk::winrun {
#set raw_parts [list]
#foreach range $wordranges {
# set word [string range $raw_cmdline {*}$range]
# lappend raw_parts [internal::objclone $word]
# lappend raw_parts [internal::valcopy $word]
#}
@ -521,7 +521,7 @@ namespace eval punk::winrun {
return "Usage: quote_cmd ?runopt? ... ?--? ?cmd? ?cmdarg? ..."
}
foreach a $cmdargs {
set copy [internal::objclone $a]
set copy [internal::valcopy $a]
append raw_cmdline "$copy "
lappend tcl_list $copy
}
@ -632,7 +632,7 @@ namespace eval punk::winrun {
set verbose [expr {"-verbose" in $runopts}]
#review - may need to force quoting of barewords by quote_win to ensure proper behaviour if bareword contains cmd specials?
#?always treatable as a list? review
set tcl_list [lmap v $cmdargs {internal::objclone $v}]
set tcl_list [lmap v $cmdargs {internal::valcopy $v}]
set meta_chars [list {<} {>} & |] ;#caret-quote when outside of cmd.exe's idea of a quoted section - carets will disappear from passed on string
set cmdline ""
set in_quotes 0
@ -721,7 +721,7 @@ namespace eval punk::winrun {
set allowvars [expr {"-allowvars" in $runopts}]
set verbose [expr {"-verbose" in $runopts}]
set tcl_list [lmap v $cmdargs {internal::objclone $v}]
set tcl_list [lmap v $cmdargs {internal::valcopy $v}]
set meta_chars [list {"} "(" ")" ^ < > & |]
if {!$allowvars} {
lappend meta_chars % !
@ -764,7 +764,7 @@ namespace eval punk::winrun {
set allowvars [expr {"-allowvars" in $runopts}]
set allowquotes [expr {"-allowquotes" in $runopts}]
set verbose [expr {"-verbose" in $runopts}]
set tcl_list [lmap v $cmdargs {internal::objclone $v}]
set tcl_list [lmap v $cmdargs {internal::valcopy $v}]
set cmdline ""
set i 0
set meta_chars [list "(" ")" ^ < > & |]
@ -797,7 +797,7 @@ namespace eval punk::winrun {
proc quote_cmd2 {args} {
set cmdargs $args
set tcl_list [lmap v $cmdargs {internal::objclone $v}]
set tcl_list [lmap v $cmdargs {internal::valcopy $v}]
set cmdline ""
set i 0
@ -906,7 +906,7 @@ namespace eval punk::winrun {
# -- --- ---
#get a copy of the item without affecting internal rep
#this isn't critical for most usecases - but can be of use for example when trying not to shimmer path objects to strings (filesystem performance impact in some cases)
proc objclone {obj} {
proc valcopy {obj} {
append obj2 $obj {}
}
# -- --- ---

Loading…
Cancel
Save