Browse Source

punk::ns and punk::args better processing of ensemble commands with leading parameters, documentation and layout improvements

master
Julian Noble 3 months ago
parent
commit
b368ce51ac
  1. 4
      src/modules/argparsingtest-999999.0a1.0.tm
  2. 6
      src/modules/punk/ansi-999999.0a1.0.tm
  3. 282
      src/modules/punk/args-999999.0a1.0.tm
  4. 2
      src/modules/punk/args-buildversion.txt
  5. 1152
      src/modules/punk/args/moduledoc/tclcore-999999.0a1.0.tm
  6. 4
      src/modules/punk/imap4-999999.0a1.0.tm
  7. 101
      src/modules/punk/lib-999999.0a1.0.tm
  8. 2
      src/modules/punk/lib-buildversion.txt
  9. 59
      src/modules/punk/netbox-999999.0a1.0.tm
  10. 186
      src/modules/punk/ns-999999.0a1.0.tm
  11. 2
      src/modules/punk/path-999999.0a1.0.tm
  12. 17
      src/modules/test/punk/#modpod-args-999999.0a1.0/args-0.1.5_testsuites/args/args.test
  13. 30
      src/modules/test/punk/#modpod-lib-999999.0a1.0/lib-0.1.3_testsuites/lib/compat.test
  14. 79
      src/modules/test/punk/#modpod-lib-999999.0a1.0/lib-0.1.3_testsuites/lib/index_functions.test
  15. 0
      src/modules/test/punk/#modpod-lib-999999.0a1.0/lib-0.1.3_testsuites/tests/compat.test#..+lib+compat.test.fauxlink
  16. 0
      src/modules/test/punk/#modpod-lib-999999.0a1.0/lib-0.1.3_testsuites/tests/index.test#..+lib+index_functions.test.fauxlink
  17. 211
      src/modules/test/punk/#modpod-lib-999999.0a1.0/lib-999999.0a1.0.tm
  18. 3
      src/modules/test/punk/lib-buildversion.txt
  19. 6
      src/modules/textblock-999999.0a1.0.tm

4
src/modules/argparsingtest-999999.0a1.0.tm

@ -297,7 +297,7 @@ namespace eval argparsingtest {
} }
punk::args::define { punk::args::define {
@id -id ::test1_punkargs_by_id @id -id ::argparsingtest::test1_punkargs_by_id
@cmd -name argtest4 -help "test of punk::args::parse comparative performance" @cmd -name argtest4 -help "test of punk::args::parse comparative performance"
@opts -anyopts 0 @opts -anyopts 0
-return -default string -type string -return -default string -type string
@ -314,7 +314,7 @@ namespace eval argparsingtest {
@values @values
} }
proc test1_punkargs_by_id {args} { proc test1_punkargs_by_id {args} {
set argd [punk::args::get_by_id ::test1_punkargs_by_id $args] set argd [punk::args::get_by_id ::argparsingtest::test1_punkargs_by_id $args]
return [tcl::dict::get $argd opts] return [tcl::dict::get $argd opts]
} }

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

@ -3287,6 +3287,7 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
#indent of 1 space is important for clarity in i -return string a+ output #indent of 1 space is important for clarity in i -return string a+ output
dict set SGR_samples $k " [punk::ansi::a+ $k]sample\x1b\[m" dict set SGR_samples $k " [punk::ansi::a+ $k]sample\x1b\[m"
} }
set SGR_help\ set SGR_help\
{SGR code from the list below, or an integer corresponding to the code e.g 31 = red. {SGR code from the list below, or an integer corresponding to the code e.g 31 = red.
A leading capital letter indicates a codename applies to the background colour. A leading capital letter indicates a codename applies to the background colour.
@ -3325,6 +3326,7 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
-choicelabels {%choicelabels%}\ -choicelabels {%choicelabels%}\
-choicecolumns 5 -choiceprefix 0 -choicerestricted 0 -help\ -choicecolumns 5 -choiceprefix 0 -choicerestricted 0 -help\
"%SGR_help%" "%SGR_help%"
#note SGR_help string has same level of indent as placeholder
}]] }]]
lappend PUNKARGS [list { lappend PUNKARGS [list {
@ -8140,7 +8142,7 @@ tcl::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::lindex_resolve / punk::lindex_get for ways to handle tcl list/string indices without parsing them. #see also punk::lib::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]
@ -8169,6 +8171,8 @@ tcl::namespace::eval punk::ansi::ansistring {
} else { } else {
set offset 0 set offset 0
} }
#2025 -BROKEN - doesn't handle indices with both + and -
#see updated punk::lib::lindex_resolve
#by now, if op = + then offset = 0 so we only need to handle the minus case #by now, if op = + then offset = 0 so we only need to handle the minus case
if {$payload_len == -1} { if {$payload_len == -1} {
set payload_len [punk::ansi::ansistring::length $string] ;#a little bit wasteful - but hopefully no big deal set payload_len [punk::ansi::ansistring::length $string] ;#a little bit wasteful - but hopefully no big deal

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

@ -274,7 +274,13 @@ tcl::namespace::eval ::punk::args {}
# Base namespace # Base namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
tcl::namespace::eval punk::args { 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
catch {
namespace import ::punk::assertion::assert
}
punk::assertion::active 1
variable PUNKARGS ;#list of our own punk::args function argument definitions - loaded with punk::args::define at the end. variable PUNKARGS ;#list of our own punk::args function argument definitions - loaded with punk::args::define at the end.
@ -607,6 +613,13 @@ tcl::namespace::eval punk::args {
If <range> allows more than one choice the value is a list If <range> allows more than one choice the value is a list
consisting of items in the choices made available through consisting of items in the choices made available through
entries in -choices/-choicegroups. entries in -choices/-choicegroups.
-unindentedfields {<list>}
for fields with multi-line values, tell the resolver to treat
them as unindented. ie do no indent/unindent processing of
whitespace in the values. In a definition script, these fields
should have their value strings placed with reference to the
left margin in the source code. ie all whitespace in the source
is preserved.
-minsize (type dependant) -minsize (type dependant)
-maxsize (type dependant) -maxsize (type dependant)
-range (type dependant - only valid if -type is a single item) -range (type dependant - only valid if -type is a single item)
@ -651,11 +664,14 @@ tcl::namespace::eval punk::args {
%G%#The following option defines a flag style option (solo)%R% %G%#The following option defines a flag style option (solo)%R%
-flag1 -default 0 -type none -help\ -flag1 -default 0 -type none -help\
"Info about flag1 "Info about flag1
subsequent help lines auto-dedented by whitespace to left subsequent help lines assume indent of 4 spaces with
of corresponding record start (in this case -flag1) reference to the record start (in this case -flag1).
+ first 4 spaces if they are all present.
This line has no extra indent relative to first line 'Info about flag1' This line has no extra indent relative to first line 'Info about flag1'
This line indented a further 6 chars" This line indented a further 6 chars"
%G%#To disable source indent processing, add for example
%G%# -unindentedfields {-help} to the argument line
%G%#This will require aligning the -help text with reference to the left
%G%#margin in the source of the definition.
@values -min 1 -max -1 @values -min 1 -max -1
%G%#Items that don't begin with * or - are value definitions%R% %G%#Items that don't begin with * or - are value definitions%R%
@ -677,6 +693,7 @@ tcl::namespace::eval punk::args {
-choiceprefix 1\ -choiceprefix 1\
-choicerestricted 1\ -choicerestricted 1\
-choicemultiple {1 1}\ -choicemultiple {1 1}\
-unindentedfields {}\
-multiple 0\ -multiple 0\
-regexprepass {}\ -regexprepass {}\
-validationtransform {}\ -validationtransform {}\
@ -692,6 +709,7 @@ tcl::namespace::eval punk::args {
-choiceprefix 1\ -choiceprefix 1\
-choicerestricted 1\ -choicerestricted 1\
-choicemultiple {1 1}\ -choicemultiple {1 1}\
-unindentedfields {}\
-multiple 0\ -multiple 0\
-regexprepass {}\ -regexprepass {}\
-validationtransform {}\ -validationtransform {}\
@ -711,6 +729,7 @@ tcl::namespace::eval punk::args {
-choiceprefix 1\ -choiceprefix 1\
-choicerestricted 1\ -choicerestricted 1\
-choicemultiple {1 1}\ -choicemultiple {1 1}\
-unindentedfields {}\
-multiple 0\ -multiple 0\
-regexprepass {}\ -regexprepass {}\
-validationtransform {}\ -validationtransform {}\
@ -943,18 +962,40 @@ tcl::namespace::eval punk::args {
foreach a $textargs { foreach a $textargs {
lappend normargs [tcl::string::map {\r\n \n} $a] lappend normargs [tcl::string::map {\r\n \n} $a]
} }
set optionspecs [join $normargs \n]
if {[string first \$\{ $optionspecs] > 0} { set optionspecs [list]
foreach block $normargs {
if {[string first \$\{ $block] > 0} {
if {$defspace ne ""} { if {$defspace ne ""} {
#normal/desired case set block [namespace eval $defspace [list punk::args::lib::tstr -return string -eval 1 -allowcommands -undent 1 $block]]
#set optionspecs [namespace eval $defspace [list punk::args::lib::tstr -return string -eval 1 -allowcommands $optionspecs]]
set optionspecs [namespace eval $defspace [list punk::args::lib::tstr -return string -eval 1 -paramindents none -allowcommands $optionspecs]]
} else { } else {
#todo - deprecate/stop from happening?
puts stderr "punk::args::resolve calling tstr for id:$id with no known definition space (-defspace empty)" puts stderr "punk::args::resolve calling tstr for id:$id with no known definition space (-defspace empty)"
set optionspecs [uplevel $LVL [list punk::args::lib::tstr -return string -eval 1 -allowcommands $optionspecs]] set block [uplevel $LVL [list punk::args::lib::tstr -return string -eval 1 -allowcommands $block]]
} }
} }
lappend optionspecs $block
}
set optionspecs [join $optionspecs \n]
#set optionspecs [join $normargs \n]
#if {[string first \$\{ $optionspecs] > 0} {
# if {$defspace ne ""} {
# #normal/desired case
# #JJJ
# #set optionspecs [namespace eval $defspace [list punk::args::lib::tstr -return string -eval 1 -allowcommands $optionspecs]]
# #set optionspecs [namespace eval $defspace [list punk::args::lib::tstr -return string -eval 1 -paramindents none -allowcommands $optionspecs]]
# set optionspecs [namespace eval $defspace [list punk::args::lib::tstr -return string -eval 1 -allowcommands -undent 1 $optionspecs]]
# #set optionspecs [list]
# #foreach spec $optionspecs {
# # set spec [namespace eval $defspace [list punk::args::lib::tstr -return string -eval 1 -allowcommands -undent 1 $spec]]
# # lappend optionspecs $spec
# #}
# } else {
# #todo - deprecate/stop from happening?
# puts stderr "punk::args::resolve calling tstr for id:$id with no known definition space (-defspace empty)"
# set optionspecs [uplevel $LVL [list punk::args::lib::tstr -return string -eval 1 -allowcommands $optionspecs]]
# }
#}
} else { } else {
if {[tcl::dict::exists $argdefcache_unresolved $cache_key]} { if {[tcl::dict::exists $argdefcache_unresolved $cache_key]} {
@ -979,9 +1020,9 @@ tcl::namespace::eval punk::args {
# -arg -choices {${$DYN_CHOICES}} -help "${$RED}important info${$RST}" # -arg -choices {${$DYN_CHOICES}} -help "${$RED}important info${$RST}"
#} #}
if {$defspace ne ""} { if {$defspace ne ""} {
#set optionspecs [namespace eval $defspace [list punk::args::lib::tstr -return string -eval 1 -allowcommands $optionspecs]] set optionspecs [namespace eval $defspace [list punk::args::lib::tstr -return string -eval 1 -allowcommands $optionspecs]]
#JJJ - review #JJJ - review
set optionspecs [namespace eval $defspace [list punk::args::lib::tstr -return string -eval 1 -allowcommands -paramindents none $optionspecs]] #set optionspecs [namespace eval $defspace [list punk::args::lib::tstr -return string -eval 1 -allowcommands -paramindents none $optionspecs]]
} }
#REVIEW - join also serves to unescape things such as \$\{$x\} \$\{[cmd]\} without subst'ing or evaling (?) #REVIEW - join also serves to unescape things such as \$\{$x\} \$\{[cmd]\} without subst'ing or evaling (?)
if {[string first \$\{ $optionspecs] > 0} { if {[string first \$\{ $optionspecs] > 0} {
@ -1023,21 +1064,25 @@ tcl::namespace::eval punk::args {
set linebuild "" set linebuild ""
set linelist [split $optionspecs \n] set linelist [split $optionspecs \n]
set lastindent "" set record_base_indent "" ;#indent of first line in the record e.g a parameter or @directive record which will often have subsequent lines further indented.
#find the first record's base indent
foreach ln $linelist { foreach ln $linelist {
if {[tcl::string::trim $ln] eq ""} {continue} if {[tcl::string::trim $ln] eq ""} {continue}
regexp {(\s*).*} $ln _all lastindent regexp {(\s*).*} $ln _all record_base_indent
break ;#break at first non-empty break ;#break at first non-empty
} }
#puts "indent1:[ansistring VIEW $lastindent]" #puts "indent1:[ansistring VIEW $record_base_indent]"
set in_record 0 set in_record_continuation 0
if {[catch {package require punk::ansi} errM]} { if {[catch {package require punk::ansi} errM]} {
set has_punkansi 0 set has_punkansi 0
} else { } else {
set has_punkansi 1 set has_punkansi 1
} }
set record_id 0
set record_line 0 ;#incremented at each incomplete record, set to zero after processing a complete record
foreach rawline $linelist { foreach rawline $linelist {
set recordsofar [tcl::string::cat $linebuild $rawline] #puts stderr "$record_line $rawline"
set record_so_far [tcl::string::cat $linebuild $rawline]
#ansi colours can stop info complete from working (contain square brackets) #ansi colours can stop info complete from working (contain square brackets)
#review - when exactly are ansi codes allowed/expected in record lines. #review - when exactly are ansi codes allowed/expected in record lines.
# - we might reasonably expect them in default values or choices or help strings # - we might reasonably expect them in default values or choices or help strings
@ -1045,53 +1090,95 @@ tcl::namespace::eval punk::args {
# - eg set line "set x \"a[a+ red]red[a]\"" # - eg set line "set x \"a[a+ red]red[a]\""
# - 'info complete' will report 0, and subst would require -nocommand option or it will complain of missing close-bracket # - 'info complete' will report 0, and subst would require -nocommand option or it will complain of missing close-bracket
if {$has_punkansi} { if {$has_punkansi} {
set test_complete [punk::ansi::ansistrip $recordsofar] set test_record [punk::ansi::ansistrip $record_so_far]
} else { } else {
#review #review
#we only need to strip enough to stop interference with 'info complete' #we only need to strip enough to stop interference with 'info complete'
set test_complete [string map [list \x1b\[ ""] $recordsofar] set test_record [string map [list \x1b\[ ""] $record_so_far]
} }
if {![tcl::info::complete $test_complete]} { if {![tcl::info::complete $test_record]} {
#append linebuild [string trimleft $rawline] \n #append linebuild [string trimleft $rawline] \n
if {$in_record} { if {$in_record_continuation} {
#trim only the whitespace corresponding to last record indent or lastindent + 4 spaces - not all whitespace on left #incr record_line
#if {$record_line == 1} {
# #first continuation line sets the indent
#}
#///
#if {[tcl::string::first "$record_base_indent " $rawline] == 0} {
# set trimmedline [tcl::string::range $rawline [tcl::string::length "$record_base_indent "] end]
# append linebuild $trimmedline \n
#} else {
# append linebuild $rawline \n
#}
if {[tcl::string::first $record_base_indent $rawline] == 0} {
set trimmedline [tcl::string::range $rawline [tcl::string::length $record_base_indent] end]
append linebuild $trimmedline \n
} else {
append linebuild $rawline \n
}
#trim only the whitespace corresponding to last record indent or record_base_indent + 4 spaces - not all whitespace on left
#this allows alignment of multiline help strings to left margin whilst maintaining a visual indent in source form. #this allows alignment of multiline help strings to left margin whilst maintaining a visual indent in source form.
#Aligning subsequent lines with the record, or aligning 4 spaces in are equivalent. #Aligning subsequent lines with the record, or aligning 4 spaces in are equivalent.
#ie to indent lines further - whitespace should be added 4+ columns in from the record-line start position. #ie to indent lines further - whitespace should be added 4+ columns in from the record-line start position.
#(this leaves an oddity if indenting is only 1 2 or 3 spaces mixed with longer indents as we don't check for it.. REVIEW) #(this leaves an oddity if indenting is only 1 2 or 3 spaces mixed with longer indents as we don't check for it.. REVIEW)
#(note string first "" $str is fast and returns -1) #(note string first "" $str is fast and returns -1)
if {[tcl::string::first "$lastindent " $rawline] == 0} { #if {[tcl::string::first "$record_base_indent " $rawline] == 0} {
set trimmedline [tcl::string::range $rawline [tcl::string::length "$lastindent "] end] # set trimmedline [tcl::string::range $rawline [tcl::string::length "$record_base_indent "] end]
append linebuild $trimmedline \n # append linebuild $trimmedline \n
} elseif {[tcl::string::first $lastindent $rawline] == 0} { #} elseif {[tcl::string::first $record_base_indent $rawline] == 0} {
set trimmedline [tcl::string::range $rawline [tcl::string::length $lastindent] end] # set trimmedline [tcl::string::range $rawline [tcl::string::length $record_base_indent] end]
append linebuild $trimmedline \n # append linebuild $trimmedline \n
} else { #} else {
append linebuild $rawline \n # append linebuild $rawline \n
} #}
} else { } else {
set in_record 1 assert {$record_line == 0} punk::args::resolve record_line
regexp {(\s*).*} $rawline _all lastindent regexp {(\s*).*} $rawline _all record_base_indent
#puts "indent: [ansistring VIEW -lf 1 $lastindent]" #puts "indent: [ansistring VIEW -lf 1 $record_base_indent]"
#puts "indent from rawline:$rawline " #puts "indent from rawline:$rawline "
append linebuild $rawline \n append linebuild $rawline \n
set in_record_continuation 1
} }
incr record_line
} else { } else {
set in_record 0 #either we're on a single line record, or last line of multiline record
#trim only the whitespace corresponding to last record indent or lastindent + 4 spaces - not all whitespace on left
if {[tcl::string::first "$lastindent " $rawline] == 0} { if {$record_line != 0} {
set trimmedline [tcl::string::range $rawline [tcl::string::length "$lastindent "] end] #trim only the whitespace corresponding to record_base_indent or record_base_indent + 4 spaces - not all whitespace on left
append linebuild $trimmedline #if {[tcl::string::first "$record_base_indent " $rawline] == 0} {
} elseif {[tcl::string::first $lastindent $rawline] == 0} { # set trimmedline [tcl::string::range $rawline [tcl::string::length "$record_base_indent "] end]
set trimmedline [tcl::string::range $rawline [tcl::string::length $lastindent] end] # append linebuild $trimmedline
#} elseif {[tcl::string::first $record_base_indent $rawline] == 0} {
# set trimmedline [tcl::string::range $rawline [tcl::string::length $record_base_indent] end]
# append linebuild $trimmedline
#} else {
# append linebuild $rawline
#}
if {[tcl::string::first $record_base_indent $rawline] == 0} {
set trimmedline [tcl::string::range $rawline [tcl::string::length $record_base_indent] end]
append linebuild $trimmedline append linebuild $trimmedline
} else { } else {
append linebuild $rawline append linebuild $rawline
} }
} else {
append linebuild $rawline
}
lappend records $linebuild lappend records $linebuild
set linebuild "" set linebuild ""
#prep for next record
set in_record_continuation 0
incr record_id
set record_line 0
} }
} }
#puts stderr 1[lindex $records 1]
#puts stderr 4[lindex $records 4]
#puts stderr 5[lindex $records 5]
#puts stderr 6[lindex $records 6]
set cmd_info {} set cmd_info {}
set package_info {} set package_info {}
set id_info {} ;#e.g -children <list> ?? set id_info {} ;#e.g -children <list> ??
@ -1344,6 +1431,8 @@ tcl::namespace::eval punk::args {
#e.g -name <str> #e.g -name <str>
# -summary <str> # -summary <str>
# -help <str> # -help <str>
#
# -cmdtype <str>
set cmd_info [dict merge $cmd_info $at_specs] set cmd_info [dict merge $cmd_info $at_specs]
} }
doc { doc {
@ -1382,6 +1471,7 @@ tcl::namespace::eval punk::args {
#if no -max explicitly specified, and llength OPT_NAMES == 0 and OPT_ANY == 0 - -max will be set to 0 below. #if no -max explicitly specified, and llength OPT_NAMES == 0 and OPT_ANY == 0 - -max will be set to 0 below.
dict set F $fid OPT_MAX $v dict set F $fid OPT_MAX $v
} }
-unindentedfields -
-minsize - -maxsize - -minsize - -maxsize -
-choices - -choicegroups - -choicemultiple - -choicecolumns - -choicelabels - -choiceinfo - -choices - -choicegroups - -choicemultiple - -choicecolumns - -choicelabels - -choiceinfo -
-choiceprefix - -choiceprefixdenylist - -choiceprefixreservelist - -choicerestricted { -choiceprefix - -choiceprefixdenylist - -choiceprefixreservelist - -choicerestricted {
@ -1485,6 +1575,7 @@ tcl::namespace::eval punk::args {
-any -anyopts -arbitrary -form -minsize -maxsize -choices -choicegroups -choicemultiple -choicecolumns -choicelabels -choiceinfo\ -any -anyopts -arbitrary -form -minsize -maxsize -choices -choicegroups -choicemultiple -choicecolumns -choicelabels -choiceinfo\
-type -range -typeranges -default -defaultdisplaytype -typedefaults -type -range -typeranges -default -defaultdisplaytype -typedefaults
-choiceprefix -choiceprefixdenylist -choiceprefixreservelist -choicerestricted -nocase\ -choiceprefix -choiceprefixdenylist -choiceprefixreservelist -choicerestricted -nocase\
-unindentedfields\
-nominsize -nomaxsize -norange -nochoices -nochoicelabels\ -nominsize -nomaxsize -norange -nochoices -nochoicelabels\
-type -optional -allow_ansi -validate_ansistripped -strip_ansi -multiple -prefix\ -type -optional -allow_ansi -validate_ansistripped -strip_ansi -multiple -prefix\
-regexprepass -regexprefail -regexprefailmsg -validationtransform\ -regexprepass -regexprefail -regexprefailmsg -validationtransform\
@ -1584,6 +1675,7 @@ tcl::namespace::eval punk::args {
-typeranges { -typeranges {
tcl::dict::set tmp_leaderspec_defaults -range $v tcl::dict::set tmp_leaderspec_defaults -range $v
} }
-unindentedfields -
-minsize - -maxsize - -minsize - -maxsize -
-choices - -choicegroups - -choicemultiple - -choicecolumns - -choiceprefixdenylist - -choiceprefixreservelist - -nocase { -choices - -choicegroups - -choicemultiple - -choicecolumns - -choiceprefixdenylist - -choiceprefixreservelist - -nocase {
#review - only apply to certain types? #review - only apply to certain types?
@ -1622,6 +1714,7 @@ tcl::namespace::eval punk::args {
-choices -choicegroups -choicemultiple -choicecolumns -choicelabels -choiceinfo\ -choices -choicegroups -choicemultiple -choicecolumns -choicelabels -choiceinfo\
-choiceprefix -choiceprefixdenylist -choiceprefixreservelist -choicerestricted\ -choiceprefix -choiceprefixdenylist -choiceprefixreservelist -choicerestricted\
-nocase -nominsize -nomaxsize -norange -nochoices -nochoicelabels\ -nocase -nominsize -nomaxsize -norange -nochoices -nochoicelabels\
-unindentedfields\
-type -optional -allow_ansi -validate_ansistripped -strip_ansi -multiple\ -type -optional -allow_ansi -validate_ansistripped -strip_ansi -multiple\
-regexprepass -regexprefail -regexprefailmsg -validationtransform\ -regexprepass -regexprefail -regexprefailmsg -validationtransform\
-unnamed\ -unnamed\
@ -1662,6 +1755,7 @@ tcl::namespace::eval punk::args {
#set val_max $v #set val_max $v
dict set F $fid VAL_MAX $v dict set F $fid VAL_MAX $v
} }
-unindentedfields -
-minsize - -maxsize - -choices - -choicemultiple - -choicecolumns - -minsize - -maxsize - -choices - -choicemultiple - -choicecolumns -
-choicelabels - -choiceprefix - -choiceprefixdenylist - -choiceprefixreservelist - -choicerestricted - -nocase { -choicelabels - -choiceprefix - -choiceprefixdenylist - -choiceprefixreservelist - -choicerestricted - -nocase {
#review - only apply to certain types? #review - only apply to certain types?
@ -1741,6 +1835,7 @@ tcl::namespace::eval punk::args {
-choices -choicegroups -choicemultiple -choicecolumns -choicelabels -choiceinfo\ -choices -choicegroups -choicemultiple -choicecolumns -choicelabels -choiceinfo\
-choiceprefix -choiceprefixdenylist -choiceprefixreservelist -choicerestricted\ -choiceprefix -choiceprefixdenylist -choiceprefixreservelist -choicerestricted\
-nocase\ -nocase\
-unindentedfields\
-nominsize -nomaxsize -norange -nochoices -nochoicelabels\ -nominsize -nomaxsize -norange -nochoices -nochoicelabels\
-optional -allow_ansi -validate_ansistripped -strip_ansi -multiple\ -optional -allow_ansi -validate_ansistripped -strip_ansi -multiple\
-regexprepass -regexprefail -regexprefailmsg -validationtransform\ -regexprepass -regexprefail -regexprefailmsg -validationtransform\
@ -1878,11 +1973,14 @@ tcl::namespace::eval punk::args {
#set all_choices [_resolve_get_record_choices] #set all_choices [_resolve_get_record_choices]
foreach fid $record_form_ids { foreach fid $record_form_ids {
if {[dict get $F $fid argspace] eq "leaders"} { switch -exact -- [dict get $F $fid argspace] {
leaders {
dict set F $fid argspace "options" dict set F $fid argspace "options"
} elseif {[dict get $F $fid argspace] eq "values"} { }
values {
error "punk::args::resolve - invalid placement of line '$rec' - must come before @values (command form:'$fid') @id:$DEF_definition_id" error "punk::args::resolve - invalid placement of line '$rec' - must come before @values (command form:'$fid') @id:$DEF_definition_id"
} }
}
set record_type option set record_type option
dict set F $fid OPT_NAMES [list {*}[dict get $F $fid OPT_NAMES] $argname] dict set F $fid OPT_NAMES [list {*}[dict get $F $fid OPT_NAMES] $argname]
@ -2062,6 +2160,7 @@ tcl::namespace::eval punk::args {
-parsekey - -group { -parsekey - -group {
tcl::dict::set spec_merged -typesynopsis $specval tcl::dict::set spec_merged -typesynopsis $specval
} }
-unindentedfields -
-solo - -solo -
-choices - -choicegroups - -choicemultiple - -choicecolumns - -choices - -choicegroups - -choicemultiple - -choicecolumns -
-choiceprefix - -choiceprefixdenylist - -choiceprefixreservelist - -choicerestricted - -choicelabels - -choiceinfo - -choiceprefix - -choiceprefixdenylist - -choiceprefixreservelist - -choicerestricted - -choicelabels - -choiceinfo -
@ -2169,6 +2268,7 @@ tcl::namespace::eval punk::args {
-default -defaultdisplaytype -typedefaults\ -default -defaultdisplaytype -typedefaults\
-minsize -maxsize -choices -choicegroups\ -minsize -maxsize -choices -choicegroups\
-choicemultiple -choicecolumns -choiceprefix -choiceprefixdenylist -choiceprefixreservelist -choicerestricted\ -choicemultiple -choicecolumns -choiceprefix -choiceprefixdenylist -choiceprefixreservelist -choicerestricted\
-unindentedfields\
-nocase -optional -multiple -validate_ansistripped -allow_ansi -strip_ansi -help\ -nocase -optional -multiple -validate_ansistripped -allow_ansi -strip_ansi -help\
-regexprepass -regexprefail -regexprefailmsg -validationtransform\ -regexprepass -regexprefail -regexprefailmsg -validationtransform\
-ensembleparameter\ -ensembleparameter\
@ -2462,10 +2562,13 @@ tcl::namespace::eval punk::args {
#a definition id must not begin with "-" ??? review #a definition id must not begin with "-" ??? review
for {set i 0} {$i < [llength $args]} {incr i} { for {set i 0} {$i < [llength $args]} {incr i} {
set a [lindex $args $i] set a [lindex $args $i]
if {$a in {-type -types}} { switch -exact -- $a {
-type - -types {
incr i incr i
dict set opts -types [lindex $args $i] dict set opts -types [lindex $args $i]
} elseif {[string match -* $a]} { }
default {
if {[string match -* $a]} {
incr i incr i
dict set opts $a [lindex $args $i] dict set opts $a [lindex $args $i]
} else { } else {
@ -2473,6 +2576,8 @@ tcl::namespace::eval punk::args {
set patterns [lrange $args $i+1 end] set patterns [lrange $args $i+1 end]
break break
} }
}
}
if {$i == [llength $args]-1} { if {$i == [llength $args]-1} {
punk::args::parse $args withid ::punk::args::resolved_def punk::args::parse $args withid ::punk::args::resolved_def
return return
@ -3349,6 +3454,7 @@ tcl::namespace::eval punk::args {
#limit colours to standard 16 so that themes can apply to help output #limit colours to standard 16 so that themes can apply to help output
variable arg_error_isrunning variable arg_error_isrunning
if {$arg_error_isrunning} { if {$arg_error_isrunning} {
set arg_error_isrunning 0
error "arg_error already running - error in arg_error?\n triggering errmsg: $msg" error "arg_error already running - error in arg_error?\n triggering errmsg: $msg"
} }
@ -3518,6 +3624,11 @@ tcl::namespace::eval punk::args {
set cmdname [Dict_getdef $spec_dict cmd_info -name ""] set cmdname [Dict_getdef $spec_dict cmd_info -name ""]
set cmdsummary [Dict_getdef $spec_dict cmd_info -summary ""] set cmdsummary [Dict_getdef $spec_dict cmd_info -summary ""]
set cmdhelp [Dict_getdef $spec_dict cmd_info -help ""] set cmdhelp [Dict_getdef $spec_dict cmd_info -help ""]
#===========
#unindentedfields ?
set maxundent 4
set cmdhelp [punk::lib::undent " $cmdhelp" $maxundent]
#===========
set docname [Dict_getdef $spec_dict doc_info -name "Manual:"] set docname [Dict_getdef $spec_dict doc_info -name "Manual:"]
set docurl [Dict_getdef $spec_dict doc_info -url ""] set docurl [Dict_getdef $spec_dict doc_info -url ""]
@ -3865,6 +3976,13 @@ tcl::namespace::eval punk::args {
set help "" set help ""
if {[dict exists $form_dict OPT_GROUPS $thisgroup -help]} { if {[dict exists $form_dict OPT_GROUPS $thisgroup -help]} {
set help [dict get $form_dict OPT_GROUPS $thisgroup -help] set help [dict get $form_dict OPT_GROUPS $thisgroup -help]
#field in @directiveline was -grouphelp
#review - where to specify -unindentedfields for a group? do we really need it?
#if {"-grouphelp" ni $unindentedfields} {
set maxundent 4
set help " $help"
set help [punk::lib::undent $help $maxundent]
#}
} }
if {$thisgroup_parsekey eq ""} { if {$thisgroup_parsekey eq ""} {
set groupinfo "(documentation group)" set groupinfo "(documentation group)"
@ -3935,6 +4053,7 @@ tcl::namespace::eval punk::args {
} else { } else {
set default "" set default ""
} }
set unindentedfields [Dict_getdef $arginfo -unindentedfields {}]
set help [Dict_getdef $arginfo -help ""] set help [Dict_getdef $arginfo -help ""]
set allchoices_originalcase [list] set allchoices_originalcase [list]
set choices [Dict_getdef $arginfo -choices {}] set choices [Dict_getdef $arginfo -choices {}]
@ -3982,7 +4101,15 @@ tcl::namespace::eval punk::args {
set choicelabeldict [Dict_getdef $arginfo -choicelabels {}] set choicelabeldict [Dict_getdef $arginfo -choicelabels {}]
set choiceinfodict [Dict_getdef $arginfo -choiceinfo {}] set choiceinfodict [Dict_getdef $arginfo -choiceinfo {}]
set formattedchoices [dict create] ;#use dict rather than array to preserve order set formattedchoices [dict create] ;#use dict rather than array to preserve order
if {$help eq ""} {
#first line of help - no included base of 4 indent is the normal state of first help lines in definitions scripts
#align fully left to distinguish from previous argument help text
append help "Choices$prefixmsg$casemsg"
} else {
#we are on a subsequent line of -help. Indent the usual base of 4 + desired offset
#offset of 2 to align with choices table
append help " Choices$prefixmsg$casemsg" append help " Choices$prefixmsg$casemsg"
}
if {$choicemultiple_max > 1 || $choicemultiple_max == -1} { if {$choicemultiple_max > 1 || $choicemultiple_max == -1} {
if {$choicemultiple_max == -1} { if {$choicemultiple_max == -1} {
append help \n " The value can be a list of $choicemultiple_min or more of these choices" append help \n " The value can be a list of $choicemultiple_min or more of these choices"
@ -4006,7 +4133,16 @@ tcl::namespace::eval punk::args {
set cdisplay $c set cdisplay $c
} }
if {[dict exists $choicelabeldict $c]} { if {[dict exists $choicelabeldict $c]} {
append cdisplay \n [dict get $choicelabeldict $c] #append cdisplay \n [dict get $choicelabeldict $c]
if {"-choicelabels" ni $unindentedfields} {
set maxundent 4
set ctext " [dict get $choicelabeldict $c]"
set ctext [punk::lib::undent $ctext $maxundent]
} else {
set ctext [dict get $choicelabeldict $c]
}
append cdisplay \n $ctext
} }
if {[dict exists $parsedvalues $arg] && [dict get $parsedvalues $arg] eq $c} { if {[dict exists $parsedvalues $arg] && [dict get $parsedvalues $arg] eq $c} {
dict lappend formattedchoices $groupname [punk::ansi::ansiwrap reverse $cdisplay] dict lappend formattedchoices $groupname [punk::ansi::ansiwrap reverse $cdisplay]
@ -4082,7 +4218,16 @@ tcl::namespace::eval punk::args {
} }
set cdisplay "$A_PREFIX[ansistring VIEW $prefix]$A_PREFIXEND[ansistring VIEW $tail]$mk" set cdisplay "$A_PREFIX[ansistring VIEW $prefix]$A_PREFIXEND[ansistring VIEW $tail]$mk"
if {[dict exists $choicelabeldict $c]} { if {[dict exists $choicelabeldict $c]} {
append cdisplay \n [dict get $choicelabeldict $c] #append cdisplay \n [dict get $choicelabeldict $c]
#undent
if {"-choicelabels" ni $unindentedfields} {
set maxundent 4
set ctext " [dict get $choicelabeldict $c]"
set ctext [punk::lib::undent $ctext $maxundent]
} else {
set ctext [dict get $choicelabeldict $c]
}
append cdisplay \n $ctext
} }
#puts "-- parsed:$parsedvalues arg:$arg c:$c" #puts "-- parsed:$parsedvalues arg:$arg c:$c"
if {[dict exists $parsedvalues $arg] && [dict get $parsedvalues $arg] eq $c} { if {[dict exists $parsedvalues $arg] && [dict get $parsedvalues $arg] eq $c} {
@ -4202,7 +4347,7 @@ tcl::namespace::eval punk::args {
$obj configure_column $i -blockalign left $obj configure_column $i -blockalign left
incr i incr i
} }
append help \n[textblock::join -- " " [$obj print]] append help \n[textblock::join -- " " [$obj print]] ;#4 for standard source-layout indent + 2
#------------- #-------------
#todo - tests #todo - tests
#see special case double reset at end of content in textblock class table get_column_by_index #see special case double reset at end of content in textblock class table get_column_by_index
@ -4266,6 +4411,14 @@ tcl::namespace::eval punk::args {
} }
} }
# =============================================
#REVIEW
if {"-help" ni $unindentedfields} {
# see punk::args::resolve
set maxundent 4
set help [punk::lib::undent " $help" $maxundent]
}
# =============================================
if {$use_table} { if {$use_table} {
if {$hint ne ""} { if {$hint ne ""} {
set col1 $argshow\n$hint set col1 $argshow\n$hint
@ -4934,7 +5087,7 @@ tcl::namespace::eval punk::args {
set clause_member_optional 0 set clause_member_optional 0
} }
set tp [string trim $tp ?] set tp [string trim $tp ?]
switch -glob $tp { switch -glob -- $tp {
literal* { literal* {
set litinfo [string range $tp 7 end] set litinfo [string range $tp 7 end]
set match [string range $litinfo 1 end-1] set match [string range $litinfo 1 end-1]
@ -6239,7 +6392,7 @@ tcl::namespace::eval punk::args {
#no pass for this clause - fetch first? error and raise #no pass for this clause - fetch first? error and raise
#todo - return error containing clause_indices so we can report more than one failing element at once? #todo - return error containing clause_indices so we can report more than one failing element at once?
foreach e $clauseresult { foreach e $clauseresult {
switch -exact [lindex $e 0] { switch -exact -- [lindex $e 0] {
errorcode { errorcode {
#errorcode <list> msg <string #errorcode <list> msg <string
set errorcode [lindex $e 1] set errorcode [lindex $e 1]
@ -8998,7 +9151,11 @@ tcl::namespace::eval punk::args {
if {$spec eq ""} { if {$spec eq ""} {
return return
} }
if {[dict exists $spec examples_info -help]} {
return [dict get $spec examples_info -help] return [dict get $spec examples_info -help]
} else {
return "no @examples defined for $id"
}
} }
lappend PUNKARGS [list { lappend PUNKARGS [list {
@ -9755,7 +9912,8 @@ tcl::namespace::eval punk::args {
set tp [dict get $cinfo cmdtype] set tp [dict get $cinfo cmdtype]
} }
dict set choiceinfodict $sc [list [list resolved $cmd]] #-resolved-
dict set choiceinfodict $sc [list [list ensemblesubtarget {*}$cmd]]
switch -- $tp { switch -- $tp {
ensemble - native { ensemble - native {
@ -9778,7 +9936,8 @@ tcl::namespace::eval punk::args {
if {[punk::args::id_exists $checkid]} { if {[punk::args::id_exists $checkid]} {
dict lappend choiceinfodict $sc {doctype punkargs} dict lappend choiceinfodict $sc {doctype punkargs}
dict lappend choiceinfodict $sc [list subhelp {*}$checkid] dict lappend choiceinfodict $sc [list subhelp {*}$checkid]
dict set choicelabelsdict $sc [punk::ansi::a+ normal][punk::ns::synopsis $checkid][punk::ansi::a] #dict set choicelabelsdict $sc [punk::ansi::a+ normal][punk::ns::synopsis $checkid][punk::ansi::a]
dict set choicelabelsdict $sc [punk::ansi::a+ normal][punk::args::synopsis $checkid][punk::ansi::a]
break break
} }
} }
@ -9814,7 +9973,9 @@ tcl::namespace::eval punk::args {
dict for {g members} $opt_groupdict { dict for {g members} $opt_groupdict {
append argdef " \"$g\" \{$members\}" \n append argdef " \"$g\" \{$members\}" \n
} }
append argdef " \} -choicecolumns $opt_columns -choicelabels {$choicelabelsdict} -choiceinfo {$choiceinfodict}" \n append argdef " \} -choicecolumns $opt_columns -choicelabels \{" \n
append argdef " $choicelabelsdict" \n
append argdef " \} -choiceinfo \{$choiceinfodict\} -unindentedfields \{-choicelabels\}" \n
#todo -choicelabels #todo -choicelabels
#detect subcommand further info available e.g if oo or ensemble or punk::args id exists.. #detect subcommand further info available e.g if oo or ensemble or punk::args id exists..
@ -10172,16 +10333,23 @@ tcl::namespace::eval punk::args::lib {
#undent left of paramstart only for lines of expression that arent on opening ${..} line #undent left of paramstart only for lines of expression that arent on opening ${..} line
set tail [string range $expression $brk1+1 end] set tail [string range $expression $brk1+1 end]
set leader [string repeat " " [string length $lastline]] set leader [string repeat " " [string length $lastline]]
set undentedtail [punk::args::lib::undentleader $tail $leader] #set undentedtail [punk::args::lib::undentleader $tail $leader]
#set undentedtail [punk::lib::undent [string range $expression $brk1+1 end]] #jjj
set undentedtail [punk::lib::undent [string range $expression $brk1+1 end]]
set expression "[string range $expression 0 $brk1]$undentedtail" set expression "[string range $expression 0 $brk1]$undentedtail"
} }
if {$opt_eval} { if {$opt_eval} {
#puts "-----------------------"
#puts "TSTR"
#puts $expression
#puts "-----------------------"
if {[catch [list uplevel 1 [list ::subst {*}$nocommands $expression]] result]} { if {[catch [list uplevel 1 [list ::subst {*}$nocommands $expression]] result]} {
lappend params [string cat \$\{ $expression \}] lappend params [string cat \$\{ $expression \}]
dict set errors [expr {[llength $params]-1}] $result dict set errors [expr {[llength $params]-1}] $result
} else { } else {
set result [string map [list \n "\n$leader"] $result] #JJJ
# e.g i glob
#set result [string map [list \n "\n$leader"] $result]
lappend params $result lappend params $result
} }
#lappend params [uplevel 1 [list ::subst {*}$nocommands $expression]] #lappend params [uplevel 1 [list ::subst {*}$nocommands $expression]]

2
src/modules/punk/args-buildversion.txt

@ -1,3 +1,3 @@
0.2 0.2.1
#First line must be a semantic version number #First line must be a semantic version number
#all other lines are ignored. #all other lines are ignored.

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

File diff suppressed because it is too large Load Diff

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

@ -2928,7 +2928,7 @@ tcl::namespace::eval punk::imap4 {
@values -min 2 -max 2 @values -min 2 -max 2
mailbox -help\ mailbox -help\
{Mailbox name or empty string {""} for server annotations} {Mailbox name or empty string {""} for server annotations}
annotation -choicerestricted 0 -help\ annotation -choicerestricted 0 -choiceprefix 0 -help\
"May include glob character *"\ "May include glob character *"\
-choices { -choices {
/private/specialuse /private/squat /private/sieve /private/sharedseen /private/comment /private/specialuse /private/squat /private/sieve /private/sharedseen /private/comment
@ -3405,7 +3405,7 @@ tcl::namespace::eval punk::imap4 {
*:3 *:3
1,3,5,7:9 1,3,5,7:9
" "
storetype -default +FLAGS -choicecolumns 1 -choices {+FLAGS +FLAGS.SILENT -FLAGS -FLAGS.SILENT FLAGS FLAGS.SILENT}\ storetype -default +FLAGS -choicecolumns 1 -choiceprefix 0 -choices {+FLAGS +FLAGS.SILENT -FLAGS -FLAGS.SILENT FLAGS FLAGS.SILENT}\
-choicelabels { -choicelabels {
+FLAGS\ +FLAGS\
"Add the supplied flagnames to the flags for the message. "Add the supplied flagnames to the flags for the message.

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

@ -360,7 +360,8 @@ tcl::namespace::eval punk::lib::compat {
set fidx [llength $l] set fidx [llength $l]
} }
default { default {
set pre [lrange $l 0 $first-1] #set pre [lrange $l 0 $first-1]
set pre [lrange $l 0 $fidx-1]
} }
} }
set lidx [punk::lib::lindex_resolve [llength $l] $last] set lidx [punk::lib::lindex_resolve [llength $l] $last]
@ -379,7 +380,8 @@ tcl::namespace::eval punk::lib::compat {
#If last is less than first, then any specified elements will be inserted into the list before the element specified by first with no elements being deleted. #If last is less than first, then any specified elements will be inserted into the list before the element specified by first with no elements being deleted.
set post [lrange $l $fidx end] set post [lrange $l $fidx end]
} else { } else {
set post [lrange $l $last+1 end] #set post [lrange $l $last+1 end]
set post [lrange $l $lidx+1 end]
} }
} }
} }
@ -1526,7 +1528,7 @@ namespace eval punk::lib {
set pnext [string range $pnext 1 end] set pnext [string range $pnext 1 end]
} }
# single type in segment e.g /@@something/ # single type in segment e.g /@@something/
switch -exact $pnext { switch -exact -- $pnext {
"" { "" {
set substructure string set substructure string
} }
@ -2159,7 +2161,7 @@ namespace eval punk::lib {
if {[tcl::string::is integer -strict $expression]} { if {[tcl::string::is integer -strict $expression]} {
return [expr {$expression}] return [expr {$expression}]
} }
if {[regexp {(.*)([+-])(.*)} $expression _match a op b] && [tcl::string::is integer -strict $a] && [tcl::string::is integer -strict $b]} { if {[regexp {([^+-]*)([+-])(.*)} $expression _match a op b] && [tcl::string::is integer -strict $a] && [tcl::string::is integer -strict $b]} {
if {$op eq "-"} { if {$op eq "-"} {
return [expr {$a - $b}] return [expr {$a - $b}]
} else { } else {
@ -2180,7 +2182,18 @@ namespace eval punk::lib {
An indexset consists of a comma delimited list of indexes or index-ranges. An indexset consists of a comma delimited list of indexes or index-ranges.
The indexes are 0-based. The indexes are 0-based.
Ranges must be specified with .. as the separator. The normal 'range' specifier is ..
The range specifier can appear at the beginning, middle or end, or even alone to indicate the entire
range of valid values.
e.g the following are all valid ranges
1..
(index 1 to max)
..10
(index 0 to 10)
2..11
(index 2o to 11)
..
(all indices)
Common whitespace elements space,tab,newlines are ignored. Common whitespace elements space,tab,newlines are ignored.
Each index (or endpoint of an index-range) can be of the forms accepted by Tcl list or string commands, Each index (or endpoint of an index-range) can be of the forms accepted by Tcl list or string commands,
e.g end-2 or 2+2. e.g end-2 or 2+2.
@ -2199,6 +2212,19 @@ namespace eval punk::lib {
foreach r $ranges { foreach r $ranges {
set validateindices [list] set validateindices [list]
set rposn [string first .. $r] set rposn [string first .. $r]
if {$rposn >= 0} {
set sepsize 2
set step 1
} else {
#check for .n. 'stepped' range
set fdot [string first . $r]
set ldot [string last . $r]
set step [string range $r $fdot+1 $ldot-1]
#todo - allow basic mathops for step: 2+1 2+-1 etc same as tcl lindex, lseq
if {![string is integer -strict $step]} {
}
}
if {$rposn >= 0} { if {$rposn >= 0} {
lappend validateindices {*}[string range $r 0 $rposn-1] {*}[string range $r $rposn+2 end] lappend validateindices {*}[string range $r 0 $rposn-1] {*}[string range $r $rposn+2 end]
} else { } else {
@ -2389,16 +2415,22 @@ namespace eval punk::lib {
#[para]For empty lists, end and end+x indices are considered to be out of bounds on the upper side - thus returning -2 #[para]For empty lists, end and end+x indices are considered to be out of bounds on the upper side - thus returning -2
#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 can be resolved 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 can be resolved safely with expr
#if {![llength $list]} {
# #review
# return ??? #REVIEW - we need compat for 1_000 etc to handle things like toml even in 8.6?
#} #A basic string map means we aren't properly validating
if {![string is integer -strict $len]} {
#<0 ?
error "lindex_resolve len must be an integer"
}
set index [tcl::string::map {_ {}} $index] ;#basic forward compatibility with integers such as 1_000 for 8.6
#todo - be stricter about malformations such as 1000_ #todo - be stricter about malformations such as 1000_
if {![string is integer -strict 1_0]} {
#basic forward compatibility with integers such as 1_000 for 8.6.x
set index [tcl::string::map {_ {}} $index]
set len [tcl::string::map {_ {}} $len]
}
if {![string is integer -strict $len] || $len < 0} {
error "lindex_resolve len must be a positive integer"
}
if {[string is integer -strict $index]} { if {[string is integer -strict $index]} {
#can match +i -i #can match +i -i
if {$index < 0} { if {$index < 0} {
@ -2414,40 +2446,42 @@ namespace eval punk::lib {
if {$index ne "end"} { if {$index ne "end"} {
set op [string index $index 3] set op [string index $index 3]
set offset [string range $index 4 end] set offset [string range $index 4 end]
#note - offset could have leading + or -
# 'string is integer -strict +1' ==> true
#e.g end+-1 is valid (end++-1 is not)
if {$op ni {+ -} || ![string is integer -strict $offset]} {error "bad index '$index': must be integer?\[+-\]integer? or end?\[+-\]integer?"} if {$op ni {+ -} || ![string is integer -strict $offset]} {error "bad index '$index': must be integer?\[+-\]integer? or end?\[+-\]integer?"}
if {$op eq "+" && $offset != 0} { if {$offset == 0} {
return -2 #(offset +0, -0 or 0 or 000 0_0 etc)
} #op either + or - is irrelevant
} else {
#index is 'end'
set index [expr {$len-1}] set index [expr {$len-1}]
if {$index < 0} { if {$index < 0} {
#special case - 'end' with empty list - treat end like a positive number out of bounds return -2 ;#special case - equivalent to 'end', with empty list - treat like a positive number out of bounds
return -2
} else { } else {
return $index return $index
} }
} }
if {$offset == 0} {
set index [expr {$len-1}] set index [if {$op eq "+"} {expr {($len-1) + $offset}} else {expr {($len-1) - $offset}}]
if {$index < 0} { if {$index < 0} {
return -2 ;#special case as above return -3
} elseif {$index > $len-1} {
return -2
} else { } else {
return $index return $index
} }
} else { } else {
#by now, if op = + then offset = 0 so we only need to handle the minus case #index is 'end'
set index [expr {($len-1) - $offset}] if {$len == 0} {
#special case - 'end' with empty list - treat end like a positive number out of bounds
return -2
} }
if {$index < 0} { return [expr {$len - 1}]
return -3
} else {
return $index
} }
} else { } else {
#plain +-<int> already handled above. #plain +-<int> already handled above.
#we are trying to avoid evaluating unbraced expr of potentially insecure origin #we are trying to avoid evaluating unbraced expr of potentially insecure origin
if {[regexp {(.*)([+-])(.*)} $index _match a op b]} { #regexp must split a++b to a + +b (not a+ + b) ie first +/- is the op
if {[regexp {([^+-]*)([+-])(.*)} $index _match a op b]} {
if {[string is integer -strict $a] && [string is integer -strict $b]} { if {[string is integer -strict $a] && [string is integer -strict $b]} {
if {$op eq "-"} { if {$op eq "-"} {
set index [expr {$a - $b}] set index [expr {$a - $b}]
@ -3089,7 +3123,7 @@ namespace eval punk::lib {
return [join $result \n] return [join $result \n]
} }
#dedent? #dedent?
proc undent {text} { proc undent {text {max -1}} {
if {$text eq ""} { if {$text eq ""} {
return "" return ""
} }
@ -3110,6 +3144,9 @@ namespace eval punk::lib {
return $text return $text
} }
set len [string length $lcp] set len [string length $lcp]
if {$max != -1} {
set len [expr {min($len,$max)}]
}
set result [list] set result [list]
foreach ln $lines { foreach ln $lines {
if {[string trim $ln] eq ""} { if {[string trim $ln] eq ""} {

2
src/modules/punk/lib-buildversion.txt

@ -1,3 +1,3 @@
0.1.2 0.1.3
#First line must be a semantic version number #First line must be a semantic version number
#all other lines are ignored. #all other lines are ignored.

59
src/modules/punk/netbox-999999.0a1.0.tm

@ -1097,21 +1097,22 @@ tcl::namespace::eval punk::netbox::dcim {
-choices {${[punk::netbox::api_context_names]}} -choices {${[punk::netbox::api_context_names]}}
@opts @opts
-id -type integer -id -type integer
-ID_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_number_filter_help}} -ID_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -unindentedfields {-help} -help\
{${$::punk::netbox::argdoc::_number_filter_help}}
-name -name
-NAME_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_name_filter_help}} -NAME_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -unindentedfields {-help} -help {${$::punk::netbox::argdoc::_name_filter_help}}
-asset_tag -type string -asset_tag -type string
-ASSET_TAG_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_string_filter_help}} -ASSET_TAG_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -unindentedfields {-help} -help {${$::punk::netbox::argdoc::_string_filter_help}}
-face -type string -face -type string
-face__n -type string -face__n -type string
-position -type integer -position -type integer
-POSITION_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_number_filter_help}} -POSITION_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -unindentedfields {-help} -help {${$::punk::netbox::argdoc::_number_filter_help}}
-airflow -type string -airflow -type string
-airflow__n -type string -airflow__n -type string
-vc_position -type integer -vc_position -type integer
-VC_POSITION_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_number_filter_help}} -VC_POSITION_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -unindentedfields {-help} -help {${$::punk::netbox::argdoc::_number_filter_help}}
-vc_priority -type integer -vc_priority -type integer
-VC_PRIORITY_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_number_filter_help}} -VC_PRIORITY_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -unindentedfields {-help} -help {${$::punk::netbox::argdoc::_number_filter_help}}
}\ }\
[set ::punk::netbox::argdoc::_create_update_options]\ [set ::punk::netbox::argdoc::_create_update_options]\
{ {
@ -1155,9 +1156,9 @@ tcl::namespace::eval punk::netbox::dcim {
-status -type string -status -type string
-status__n -type string -status__n -type string
-mac_address -type string -mac_address -type string
-MAC_ADDRESS_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_string_filter_help}} -MAC_ADDRESS_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -unindentedfields {-help} -help {${$::punk::netbox::argdoc::_string_filter_help}}
-serial -type string -serial -type string
-SERIAL_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_string_filter_help}} -SERIAL_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -unindentedfields {-help} -help {${$::punk::netbox::argdoc::_string_filter_help}}
-virtual_chassis_id -type integer -virtual_chassis_id -type integer
-virtual_chassis_id__n -type integer -virtual_chassis_id__n -type integer
}\ }\
@ -1188,14 +1189,14 @@ tcl::namespace::eval punk::netbox::ipam {
-choices {${[punk::netbox::api_context_names]}} -choices {${[punk::netbox::api_context_names]}}
@opts @opts
-id -type integer -id -type integer
-ID_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_number_filter_help}} -ID_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -unindentedfields {-help} -help {${$::punk::netbox::argdoc::_number_filter_help}}
-name -name
-NAME_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_name_filter_help}} -NAME_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -unindentedfields {-help} -help {${$::punk::netbox::argdoc::_name_filter_help}}
-rd -type string -help\ -rd -type string -help\
"Route distinguisher in any format" "Route distinguisher in any format"
-enforce_unique -enforce_unique
-description -type string -help "Exact Match (case sensitive)" -description -type string -help "Exact Match (case sensitive)"
-DESCRIPTION_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_description_filter_help}} -DESCRIPTION_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -unindentedfields {-help} -help {${$::punk::netbox::argdoc::_description_filter_help}}
}\ }\
[set ::punk::netbox::argdoc::_create_update_options]\ [set ::punk::netbox::argdoc::_create_update_options]\
{ {
@ -1261,11 +1262,11 @@ tcl::namespace::eval punk::netbox::ipam {
-choices {${[punk::netbox::api_context_names]}} -choices {${[punk::netbox::api_context_names]}}
@opts @opts
-id -type integer -id -type integer
-ID_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_number_filter_help}} -ID_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -unindentedfields {-help} -help {${$::punk::netbox::argdoc::_number_filter_help}}
-is_pool -is_pool
-mark_utilized -mark_utilized
-description -type string -help "Exact Match (case sensitive)" -description -type string -help "Exact Match (case sensitive)"
-DESCRIPTION_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_description_filter_help}} -DESCRIPTION_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -unindentedfields {-help} -help {${$::punk::netbox::argdoc::_description_filter_help}}
}\ }\
[set ::punk::netbox::argdoc::_create_update_options]\ [set ::punk::netbox::argdoc::_create_update_options]\
{ {
@ -1285,16 +1286,16 @@ tcl::namespace::eval punk::netbox::ipam {
-within_include -within_include
-contains -contains
-depth -depth
-DEPTH_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_number_filter_help}} -DEPTH_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -unindentedfields {-help} -help {${$::punk::netbox::argdoc::_number_filter_help}}
-children -children
-CHILDREN_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_number_filter_help}} -CHILDREN_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -unindentedfields {-help} -help {${$::punk::netbox::argdoc::_number_filter_help}}
-mask_length -mask_length
-mask_length__gte -mask_length__gte
-mask_length__lte -mask_length__lte
-vlan_id -type integer -vlan_id -type integer
-vlan_id__n -type integer -vlan_id__n -type integer
-vlan_vid -type integer -vlan_vid -type integer
-VLAN_VID_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_number_filter_help}} -VLAN_VID_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -unindentedfields {-help} -help {${$::punk::netbox::argdoc::_number_filter_help}}
-vrf_id -vrf_id
-vrf -vrf
-status -status
@ -1508,11 +1509,11 @@ tcl::namespace::eval punk::netbox::ipam {
-choices {${[punk::netbox::api_context_names]}} -choices {${[punk::netbox::api_context_names]}}
@opts @opts
-id -type integer -id -type integer
-ID_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_number_filter_help}} -ID_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -unindentedfields {-help} -help {${$::punk::netbox::argdoc::_number_filter_help}}
-dns_name -dns_name
-DNS_NAME_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_string_filter_help}} -DNS_NAME_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -unindentedfields {-help} -help {${$::punk::netbox::argdoc::_string_filter_help}}
-description -type string -help "Exact Match (case sensitive)" -description -type string -help "Exact Match (case sensitive)"
-DESCRIPTION_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_description_filter_help}} -DESCRIPTION_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -unindentedfields {-help} -help {${$::punk::netbox::argdoc::_description_filter_help}}
}\ }\
[set ::punk::netbox::argdoc::_create_update_options]\ [set ::punk::netbox::argdoc::_create_update_options]\
{ {
@ -1692,13 +1693,13 @@ tcl::namespace::eval punk::netbox::tenancy {
-choices {${[punk::netbox::api_context_names]}} -choices {${[punk::netbox::api_context_names]}}
@opts @opts
-id -type integer -id -type integer
-ID_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_number_filter_help}} -ID_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -unindentedfields {-help} -help {${$::punk::netbox::argdoc::_number_filter_help}}
-name -name
-NAME_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_name_filter_help}} -NAME_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -unindentedfields {-help} -help {${$::punk::netbox::argdoc::_name_filter_help}}
-slug -type string -slug -type string
-SLUG_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_string_filter_help}} -SLUG_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -unindentedfields {-help} -help {${$::punk::netbox::argdoc::_string_filter_help}}
-description -type string -description -type string
-DESCRIPTION_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_string_filter_help}} -DESCRIPTION_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -unindentedfields {-help} -help {${$::punk::netbox::argdoc::_string_filter_help}}
}\ }\
[set ::punk::netbox::argdoc::_create_update_options]\ [set ::punk::netbox::argdoc::_create_update_options]\
{ {
@ -1741,18 +1742,18 @@ tcl::namespace::eval punk::netbox::virtualization {
-choices {${[punk::netbox::api_context_names]}} -choices {${[punk::netbox::api_context_names]}}
@opts @opts
-id -type integer -id -type integer
-ID_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_number_filter_help}} -ID_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -unindentedfields {-help} -help {${$::punk::netbox::argdoc::_number_filter_help}}
-name -name
-NAME_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_name_filter_help}} -NAME_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -unindentedfields {-help} -help {${$::punk::netbox::argdoc::_name_filter_help}}
-cluster -type string -cluster -type string
-cluster_n -type string -cluster_n -type string
-vcpus -type integer -vcpus -type integer
-VCPUS_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_number_filter_help}} -VCPUS_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -unindentedfields {-help} -help {${$::punk::netbox::argdoc::_number_filter_help}}
-memory -type integer -help\ -memory -type integer -help\
"Whole number" "Whole number"
-MEMORY_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_number_filter_help}} -MEMORY_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -unindentedfields {-help} -help {${$::punk::netbox::argdoc::_number_filter_help}}
-disk -type integer -disk -type integer
-DISK_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_number_filter_help}} -DISK_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -unindentedfields {-help} -help {${$::punk::netbox::argdoc::_number_filter_help}}
}\ }\
[set ::punk::netbox::argdoc::_create_update_options]\ [set ::punk::netbox::argdoc::_create_update_options]\
{ {
@ -1782,7 +1783,7 @@ tcl::namespace::eval punk::netbox::virtualization {
-platform -platform
-platform__n -platform__n
-mac_address -mac_address
-MAC_ADDRESS_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_string_filter_help}} -MAC_ADDRESS_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -unindentedfields {-help} -help {${$::punk::netbox::argdoc::_string_filter_help}}
-has_primary_ip -has_primary_ip
}\ }\
[set ::punk::netbox::argdoc::_group_options]\ [set ::punk::netbox::argdoc::_group_options]\

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

@ -491,20 +491,26 @@ tcl::namespace::eval punk::ns {
lassign $cindices cstart cend lassign $cindices cstart cend
append p [string range $nspath $s $cstart-1] append p [string range $nspath $s $cstart-1]
set numcolons [expr {$cend - $cstart + 1}] set numcolons [expr {$cend - $cstart + 1}]
if {$numcolons == 1} { #assert numcolons != 0 due to regexp +
#internal colon switch -exact -- $numcolons {
append p : 2 - 4 {
set s [expr {$cend+1}] #4 is a somewhat common case - could handle with default branch but may as well short circuit here.
continue
} elseif {$numcolons == 2} {
lappend parts $p lappend parts $p
set p "" set p ""
set s [expr {$cend+1}] set s [expr {$cend+1}]
continue #continue
} elseif {($numcolons -1) % 3 == 0} { }
1 {
#internal colon
append p :
set s [expr {$cend+1}]
#continue
}
default {
if {($numcolons -1) %3 == 0} {
set numcolons [expr {$numcolons -2}] set numcolons [expr {$numcolons -2}]
} }
#assert numcolons >=3 and not in 4,7,10,13,16,19,22... sequence #assert numcolons >=4 and not in 7,10,13,16,19,22... sequence
if {$numcolons % 3 == 0} { if {$numcolons % 3 == 0} {
#if numcolons % 3 == 0 we have a leading colon left for next ns #if numcolons % 3 == 0 we have a leading colon left for next ns
#this is the ambiguous case x::::::y -> x: :: : ::y vs x:: : :: :y #this is the ambiguous case x::::::y -> x: :: : ::y vs x:: : :: :y
@ -517,7 +523,7 @@ tcl::namespace::eval punk::ns {
} }
set p ":" set p ":"
set s [expr {$cend+1}] set s [expr {$cend+1}]
continue #continue
} else { } else {
set singlec_count [expr {(($numcolons +1)/3) -1}] set singlec_count [expr {(($numcolons +1)/3) -1}]
if {$singlec_count > 0} { if {$singlec_count > 0} {
@ -529,6 +535,8 @@ tcl::namespace::eval punk::ns {
set s [expr {$cend+1}] set s [expr {$cend+1}]
} }
} }
}
}
if {$cend < ([string length $nspath]-1)} { if {$cend < ([string length $nspath]-1)} {
lappend parts $p[string range $nspath $cend+1 end] lappend parts $p[string range $nspath $cend+1 end]
} else { } else {
@ -695,6 +703,39 @@ tcl::namespace::eval punk::ns {
} }
proc nsglob_as_re {glob} { proc nsglob_as_re {glob} {
#any segment that is not just * must match exactly one segment in the path
set pats [list]
foreach seg [nsparts_cached $glob] {
switch -exact -- $seg {
"" {
lappend pats ""
}
* {
#review - ::g*t will not find ::got:it (won't match single inner colon) - this should be fixed
#lappend pats {[^:]*}
#negative lookahead
#any number of chars not followed by ::, followed by any number of non :
lappend pats {(?:.(?!::))*[^:]*}
}
** {
lappend pats {.*}
}
default {
set seg [string map {. [.]} $seg]
if {[regexp {[*?]} $seg]} {
#set pat [string map [list ** {.*} * {[^:]*} ? {[^:]}] $seg]
set pat [string map [list ** {.*} * {(?:.(?!::))*[^:]*} ? {[^:]}] $seg]
lappend pats "$pat"
} else {
lappend pats "$seg"
}
}
}
}
return "^[join $pats ::]\$"
}
#obsolete
proc nsglob_as_re1 {glob} {
#any segment that is not just * must match exactly one segment in the path #any segment that is not just * must match exactly one segment in the path
set pats [list] set pats [list]
foreach seg [nsparts_cached $glob] { foreach seg [nsparts_cached $glob] {
@ -3042,9 +3083,10 @@ tcl::namespace::eval punk::ns {
@cmd -name "${$objtype}: ${$origin}" -help\ @cmd -name "${$objtype}: ${$origin}" -help\
"Instance of class: ${$class} (info autogenerated by generate_autodef) "Instance of class: ${$class} (info autogenerated by generate_autodef)
(see 'i punk::ns::Cmark' for symbols)" (see 'i punk::ns::Cmark' for symbols)"
@leaders -min 1 @leaders -min 1 -max 1
}] }]
append argdef \n $vline append argdef \n $vline
append argdef \n "@values -unnamed true"
punk::args::define $argdef punk::args::define $argdef
} }
@ -3148,15 +3190,15 @@ tcl::namespace::eval punk::ns {
dict for {sub subwhat} $subcommand_dict { dict for {sub subwhat} $subcommand_dict {
if {[llength $subwhat] > 1} { if {[llength $subwhat] > 1} {
#TODO - resolve using cmdinfo? #TODO - resolve using cmdinfo?
puts stderr "arginfo warning: subcommand $sub points to multiword target $subwhat - TODO" puts stderr "generate_autodef warning: subcommand $sub points to multiword target $subwhat - TODO"
} }
set targetfirstword [lindex $subwhat 0] set targetfirstword [lindex $subwhat 0]
set targetinfo [cmdwhich $targetfirstword] set targetinfo [cmdwhich $targetfirstword]
set targetorigin [dict get $targetinfo origin] set targetorigin [dict get $targetinfo origin]
set targetcmdtype [dict get $targetinfo origintype] set targetcmdtype [dict get $targetinfo origintype]
set nstarget [nsprefix $targetorigin] set nstarget [nsprefix $targetorigin]
# -resolved-
dict set choiceinfodict $sub [list [list resolved $subwhat]] dict set choiceinfodict $sub [list [list ensemblesubtarget {*}$subwhat]]
dict lappend choiceinfodict $sub [list doctype $targetcmdtype] dict lappend choiceinfodict $sub [list doctype $targetcmdtype]
if {[punk::args::id_exists [list $origin $sub]]} { if {[punk::args::id_exists [list $origin $sub]]} {
@ -3190,7 +3232,7 @@ tcl::namespace::eval punk::ns {
} else { } else {
append argdef \n "@leaders -min [expr {[llength $parameters]+1}] -max [expr {[llength $parameters]+1}]" append argdef \n "@leaders -min [expr {[llength $parameters]+1}] -max [expr {[llength $parameters]+1}]"
foreach p $parameters { foreach p $parameters {
append argdef \n "$p -type string -help { (leading ensemble parameter)}" append argdef \n "$p -type string -ensembleparameter 1 -help { (leading ensemble parameter)}"
} }
} }
append argdef \n $vline append argdef \n $vline
@ -3316,7 +3358,7 @@ tcl::namespace::eval punk::ns {
if {[string match (autodef)* $origin]} { if {[string match (autodef)* $origin]} {
set origin [string range $origin 9 end] set origin [string range $origin 9 end]
} }
#puts "->$final neworigin: $origin consumed:$consumed remaining:$remainingargs docid:$docid" puts "->$final neworigin: $origin consumed:$consumed remaining:$remainingargs docid:$docid"
lappend stack [list $origin {*}$consumed] lappend stack [list $origin {*}$consumed]
lappend commands $origin lappend commands $origin
lappend consumed_args {*}$consumed lappend consumed_args {*}$consumed
@ -3326,6 +3368,13 @@ tcl::namespace::eval punk::ns {
set cinfo [cmdwhich $finalcommand] set cinfo [cmdwhich $finalcommand]
set origin [dict get $cinfo origin] set origin [dict get $cinfo origin]
set cmdtype [dict get $cinfo origintype] set cmdtype [dict get $cinfo origintype]
if {$cmdtype eq "notfound" && [llength $finalcommand] > 1} {
#e.g see curried command produced by 'punk::netbox::man <apicontextid> new'
set next [list {*}$finalcommand {*}$remainingargs]
if {$next ne $args} {
return [cmdinfo {*}$next]
}
}
return [list origin $origin cmdtype $cmdtype args_resolved [list [lindex $commands 0] {*}$consumed_args] args_remaining $remainingargs docid $docid stack $stack] return [list origin $origin cmdtype $cmdtype args_resolved [list [lindex $commands 0] {*}$consumed_args] args_remaining $remainingargs docid $docid stack $stack]
} }
proc cmd_traverse {ns formid args} { proc cmd_traverse {ns formid args} {
@ -3494,6 +3543,7 @@ tcl::namespace::eval punk::ns {
#we could at least check for the next level down - allowing a single level of progression beyond undoc'ed subcommand-accepting procs. #we could at least check for the next level down - allowing a single level of progression beyond undoc'ed subcommand-accepting procs.
#(would not support shor-form prefix of subcommand - even if the proc implementation did) #(would not support shor-form prefix of subcommand - even if the proc implementation did)
set docid_exists 0 set docid_exists 0
set eparams [list]
if {[punk::args::id_exists "$origin [lindex $args $i]"]} { if {[punk::args::id_exists "$origin [lindex $args $i]"]} {
set a [lindex $args $i] set a [lindex $args $i]
#review - tests? #review - tests?
@ -3544,6 +3594,12 @@ tcl::namespace::eval punk::ns {
set leadernames [dict get $spec FORMS $fid LEADER_NAMES] set leadernames [dict get $spec FORMS $fid LEADER_NAMES]
set optnames [dict get $spec FORMS $fid OPT_NAMES] set optnames [dict get $spec FORMS $fid OPT_NAMES]
set valnames [dict get $spec FORMS $fid VAL_NAMES] set valnames [dict get $spec FORMS $fid VAL_NAMES]
#review - see 'string is word' vs 'string is wordchar' behaviour due to documented common opts/vals in the parent ensemble-like command '::tcl::string::is'
#we should be preferring the most specific documentation
#Alternatively - we could adjust the 'string is' documentation to have @values -unnamed true
#and put the common info in the help for <unnamed> - but that would give us an inferior synopsis for 'string is'
if {![llength $optnames] && ![llength $valnames]} { if {![llength $optnames] && ![llength $valnames]} {
#set queryargs [lrange $args $i end] #set queryargs [lrange $args $i end]
@ -3575,8 +3631,26 @@ tcl::namespace::eval punk::ns {
if {$is_ensembleparam} { if {$is_ensembleparam} {
lappend resolvedargs $q lappend resolvedargs $q
lpop queryargs_untested 0 lpop queryargs_untested 0
lappend eparams $q
puts stderr "---> cmd_traverse ensembleparam $q ($lname)"
puts stderr "arginfo: $arginfo"
puts stderr "---> eparams: $eparams"
puts stderr "---> existing args: $args"
#ledit queryargs_untested 0 0 #ledit queryargs_untested 0 0
#review - add tests #review - add tests
#todo - put param in untested (multiple ensembleparams??)
#ledit queryargs_untested 1 0 $q ;#(linsert)
#set posn_subcommand [llength $parameters];#ensemble may have '-parameters' list specified - parameters that come before the subcommand
#if {$posn_subcommand > 0} {
# set params [lrange $queryargs 0 $posn_subcommand-1]
# set remaining_queryargs [lrange $queryargs $posn_subcommand end]
#} else {
# set params [list]
# set remaining_queryargs $queryargs
#}
incr i
continue continue
} }
if {![llength $allchoices]} { if {![llength $allchoices]} {
@ -3586,7 +3660,7 @@ tcl::namespace::eval punk::ns {
#ledit queryargs_untested 0 0 #ledit queryargs_untested 0 0
#jjj #jjj
#continue #continue
return [list 3 $origin $resolvedargs $queryargs_untested $docid] return [list 3 $origin $resolvedargs [list {*}$eparams {*}$queryargs_untested] $docid]
break break
} }
set resolved_q [tcl::prefix::match -error "" $allchoices $q] set resolved_q [tcl::prefix::match -error "" $allchoices $q]
@ -3611,9 +3685,9 @@ tcl::namespace::eval punk::ns {
set docid "" set docid ""
foreach inf $cinfo { foreach inf $cinfo {
switch -- [lindex $inf 0] { switch -- [lindex $inf 0] {
"resolved" { "subhelp" {
#punk::args::ensemble_subcommands_definition
set mapped_subcmd [lrange $inf 1 end] set mapped_subcmd [lrange $inf 1 end]
#set mapped_subcmd [lindex $inf 1]
if {![punk::args::id_exists $mapped_subcmd]} { if {![punk::args::id_exists $mapped_subcmd]} {
punk::args::update_definitions [list [namespace qualifiers $mapped_subcmd]] punk::args::update_definitions [list [namespace qualifiers $mapped_subcmd]]
if {![dict exists $autodefined $mapped_subcmd]} { if {![dict exists $autodefined $mapped_subcmd]} {
@ -3631,11 +3705,14 @@ tcl::namespace::eval punk::ns {
} else { } else {
set docid "" set docid ""
} }
#puts stderr "cmd_traverse 'resolved' $mapped_subcmd" #allow subhelp override - todo: review/document rationale/usecases
break
} }
"subhelp" { "ensemblesubtarget" {
# -resolved-
#punk::args::ensemble_subcommands_definition
#This could be a list representing some other ensemble or command with pre-included arguments
set mapped_subcmd [lrange $inf 1 end] set mapped_subcmd [lrange $inf 1 end]
#set mapped_subcmd [lindex $inf 1]
if {![punk::args::id_exists $mapped_subcmd]} { if {![punk::args::id_exists $mapped_subcmd]} {
punk::args::update_definitions [list [namespace qualifiers $mapped_subcmd]] punk::args::update_definitions [list [namespace qualifiers $mapped_subcmd]]
if {![dict exists $autodefined $mapped_subcmd]} { if {![dict exists $autodefined $mapped_subcmd]} {
@ -3653,8 +3730,16 @@ tcl::namespace::eval punk::ns {
} else { } else {
set docid "" set docid ""
} }
#allow subhelp override - todo: review/document rationale/usecases #puts stderr "cmd_traverse 'resolved' $mapped_subcmd"
break }
"doctype" {
set d [lindex $inf 1]
switch -- $d {
"classmethod" {
}
"coremethod" {
}
}
} }
} }
} }
@ -3669,23 +3754,9 @@ tcl::namespace::eval punk::ns {
set mapped_subcmd "$raw_origin $resolved_q" set mapped_subcmd "$raw_origin $resolved_q"
set docid $mapped_subcmd set docid $mapped_subcmd
} else { } else {
#REVIEW - there is no reason to assume a subcommand (even in an ensemble) #NOTE there is no reason to assume a subcommand (even in an ensemble)
#will be located at "${raw_origin}::$resolved_q" #will be located at "${raw_origin}::$resolved_q"
#ensemble -map could point resolved_q somewhere else entirely #ensemble -map could point resolved_q somewhere else entirely
#punk::args::update_definitions [list $raw_origin]
#if {[punk::args::id_exists "${raw_origin}::$resolved_q"]} {
# set mapped_subcmd "${raw_origin}::$resolved_q"
# set docid $mapped_subcmd
#} else {
# if {![punk::args::id_exists "(autodef)${raw_origin}::$resolved_q"]} {
# namespace eval $ns [list punk::ns::generate_autodef "${raw_origin}::$resolved_q"]
# }
# if {[punk::args::id_exists "(autodef)${raw_origin}::$resolved_q"]} {
# set mapped_subcmd ${raw_origin}::$resolved_q
# set docid (autodef)${raw_origin}::$resolved_q
# }
#}
} }
} }
#puts "----------$mapped_subcmd" #puts "----------$mapped_subcmd"
@ -3696,15 +3767,18 @@ tcl::namespace::eval punk::ns {
#punk::args::update_definitions [list [namespace qualifiers $mapped_subcmd]] #punk::args::update_definitions [list [namespace qualifiers $mapped_subcmd]]
if {[llength $queryargs_untested] == 0} { if {[llength $queryargs_untested] == 0} {
return [list 6 $mapped_subcmd $resolvedargs $queryargs_untested $docid] return [list 6 $mapped_subcmd $resolvedargs [list {*}$eparams {*}$queryargs_untested] $docid]
} }
set origin [yield [list 0 $mapped_subcmd $resolvedargs $queryargs_untested $docid]] set origin [yield [list 0 $mapped_subcmd $resolvedargs [list {*}$eparams {*}$queryargs_untested] $docid]]
#set resolvedargs [list] #set resolvedargs [list]
#incr i [expr {-1 * [llength $resolvedargs]+1}] ;#wrong e.g test trace add execution blah enterstep cmd #incr i [expr {-1 * [llength $resolvedargs]+1}] ;#wrong e.g test trace add execution blah enterstep cmd
#JJJ #JJJ
#puts stderr "... yield-result $origin i:$i args: $args" puts stderr "... yield-result $origin i:$i args: $args"
ledit args $i+1 $i {*}$eparams
set eparams [list]
set whichinfo [namespace eval $ns [list punk::ns::cmdwhich $origin]] set whichinfo [namespace eval $ns [list punk::ns::cmdwhich $origin]]
set origin [dict get $whichinfo origin] set origin [dict get $whichinfo origin]
@ -3730,7 +3804,7 @@ tcl::namespace::eval punk::ns {
} ;#end loop foreach q $queryargs lname $leadernames_matched } ;#end loop foreach q $queryargs lname $leadernames_matched
} else { } else {
#?? #??
puts stderr "cmdinfo.cmd_traverse returning 8 $origin $resolvedargs [lrange $args $i end] $docid" puts stderr "cmdinfo.cmd_traverse returning 8 origin: $origin resolved: $resolvedargs remaining: [lrange $args $i end] docid: $docid"
return [list 8 $origin $resolvedargs [lrange $args $i end] $docid] return [list 8 $origin $resolvedargs [lrange $args $i end] $docid]
} }
} else { } else {
@ -3855,7 +3929,30 @@ tcl::namespace::eval punk::ns {
#puts stderr [textblock::frame $syn] #puts stderr [textblock::frame $syn]
#set replaceuntil [expr {[llength $resolved_id]-1}] #set replaceuntil [expr {[llength $resolved_id]-1}]
set replaceuntil [expr {[llength $resolved_id]-1+$excess}] set replaceuntil [expr {[llength $resolved_id]-1+$excess}]
append resultstr [join [lreplace $synline 0 $replaceuntil {*}$resolved_args] " "] \n #append resultstr [join [lreplace $synline 0 $replaceuntil {*}$resolved_args] " "] \n ;#don't use join - will destroy braced sets
#e.g see s dict filter
#treating a somewhat arbitrary string $synline as a list here is a bit risky
#todo - consider always using 'punk::args::synopsis -return dict' and operating on that list to rebuild string - REVIEW
set adjusted_synline [lreplace $synline 0 $replaceuntil {*}$resolved_args] ;#don't use join - will destroy braced sets
#however - we don't want the extra bracing around ansi elements caused by list rep!
#::dict filter {dictionaryValue} script {keyVariable valueVariable} {script}
#vs
#::dict filter dictionaryValue script {keyVariable valueVariable} script
#(due to ansi in dictionaryValue and trailing script)
#manually join based on list length review
set lineout ""
foreach part $adjusted_synline {
if {[llength $part] == 1} {
append lineout " " $part
} else {
append lineout " " [list $part]
}
}
#must be no leading space for tests in test::punk::args synopsis.test
append resultstr [string trim $lineout] \n
} }
} }
set resultstr [string trimright $resultstr \n] set resultstr [string trimright $resultstr \n]
@ -4626,6 +4723,7 @@ tcl::namespace::eval punk::ns {
@values @values
}] }]
set i 0 set i 0
#for 9.1+ can use -integer
foreach a $arglist { foreach a $arglist {
switch -- [llength $a] { switch -- [llength $a] {
1 { 1 {

2
src/modules/punk/path-999999.0a1.0.tm

@ -182,7 +182,7 @@ namespace eval punk::path {
proc normjoin {args} { proc normjoin {args} {
set args [lmap a $args {string map "\\\\ /" $a}] set args [lmap a $args {string map "\\\\ /" $a}]
set path [plainjoin {*}$args] set path [plainjoin {*}$args]
switch -exact $path { switch -exact -- $path {
"" { "" {
return "" return ""
} }

17
src/modules/test/punk/#modpod-args-999999.0a1.0/args-0.1.5_testsuites/args/args.test

@ -22,6 +22,23 @@ namespace eval ::testspace {
x a y b x a y b
] ]
test parse_withdef_auto_change_argspace_from_options_to_values {test first non dashed argdef after option is treated as a value when @values not explicit}\
-setup $common -body {
#test val1 following -opt is automatically placed in 'values' when @values directive is missing
set argd [punk::args::parse {-opt 1 b} withdef -opt val1]
set docid [dict get $argd id]
set vals [dict get $argd values]
set result $vals
}\
-cleanup {
punk::args::undefine $docid 1
}\
-result [list\
val1 b
]
test parse_withdef_option_ordering_defaults {Test ordering of options when some have defaults}\ test parse_withdef_option_ordering_defaults {Test ordering of options when some have defaults}\
-setup $common -body { -setup $common -body {
#for consistency with leaders and values dicts - try to maintain definition order for options too #for consistency with leaders and values dicts - try to maintain definition order for options too

30
src/modules/test/punk/#modpod-lib-999999.0a1.0/lib-0.1.3_testsuites/lib/compat.test

@ -0,0 +1,30 @@
package require tcltest
namespace eval ::testspace {
namespace import ::tcltest::*
variable common {
set result ""
}
test compat_ledit_math_first {test basic mathop in 'first' index}\
-setup $common -body {
set l {a b c d}
lappend result [punk::lib::compat::ledit l 0+1 1 x]
}\
-cleanup {
}\
-result [list\
{a x c d}
]
test compat_ledit_math_last {test basic mathop in 'last' index}\
-setup $common -body {
set l {a b c d}
lappend result [punk::lib::compat::ledit l 1 0+1 x]
}\
-cleanup {
}\
-result [list\
{a x c d}
]
}

79
src/modules/test/punk/#modpod-lib-999999.0a1.0/lib-0.1.3_testsuites/lib/index_functions.test

@ -0,0 +1,79 @@
package require tcltest
namespace eval ::testspace {
namespace import ::tcltest::*
variable common {
set result ""
}
test lindex_resolve_endoffsets {}\
-setup $common -body {
#e.g indices {0 1 2 3 4} n = 5
lappend result [punk::lib::lindex_resolve 5 end] ;# -> 4
lappend result [punk::lib::lindex_resolve 5 end--0] ;# -> 4
lappend result [punk::lib::lindex_resolve 5 end++0] ;# -> 4
lappend result [punk::lib::lindex_resolve 5 end+-0] ;# -> 4
lappend result [punk::lib::lindex_resolve 5 end-+0] ;# -> 4
lappend result [punk::lib::lindex_resolve 5 end-1] ;# -> 3
lappend result [punk::lib::lindex_resolve 5 end-+1] ;# -> 3
lappend result [punk::lib::lindex_resolve 5 end+-1] ;# -> 3
}\
-cleanup {
}\
-result [list\
4 4 4 4 4 3 3 3
]
test lindex_resolve_endoffsets_out_of_range {}\
-setup $common -body {
#e.g indices {0 1 2 3 4} n = 5
lappend result [punk::lib::lindex_resolve 5 end+1] ;# -> -2 out of bounds on upper side
lappend result [punk::lib::lindex_resolve 5 end--1] ;# equiv to +1 -> -2
lappend result [punk::lib::lindex_resolve 5 4--5] ;# -> -2 out of bounds on upper side
lappend result [punk::lib::lindex_resolve 5 end--5] ;# -> -2 out of bounds on upper side
lappend result [punk::lib::lindex_resolve 5 4-5] ;# -> -3 out of bounds on lower side
lappend result [punk::lib::lindex_resolve 5 end-5] ;# -> -3 out of bounds on lower side
lappend result [punk::lib::lindex_resolve 5 4+-5] ;# -> -3 out of bounds on lower side
lappend result [punk::lib::lindex_resolve 5 end+-5] ;# -> -3 out of bounds on lower side
lappend result [punk::lib::lindex_resolve 5 4-+5] ;# -> -3 out of bounds on lower side
lappend result [punk::lib::lindex_resolve 5 end-+5] ;# -> -3 out of bounds on lower side
}\
-cleanup {
}\
-result [list\
-2 -2 -2 -2 -3 -3 -3 -3 -3 -3
]
test lindex_resolve_endoffset_errors {test some end-like offsets that should error}\
-setup $common -body {
#e.g indices {0 1 2 3 4} n = 5
lappend result [catch {[punk::lib::lindex_resolve 5 end-]}] ;#must error
lappend result [catch {[punk::lib::lindex_resolve 5 end+]}] ;#must error
lappend result [catch {[punk::lib::lindex_resolve 5 end+--1]}] ;#must error
lappend result [catch {[punk::lib::lindex_resolve 5 end-++1]}] ;#must error
lappend result [catch {[punk::lib::lindex_resolve 5 end---1]}] ;#must error
lappend result [catch {[punk::lib::lindex_resolve 5 end+++1]}] ;#must error
#should error
# - but we have simplistic backwards compat to strip underscores - REVIEW
#lappend result [catch {[punk::lib::lindex_resolve 5 end_]}] ;#should error
#lappend result [catch {[punk::lib::lindex_resolve 5 end+_1]}] ;#should error
}\
-cleanup {
}\
-result [list\
1 1 1 1 1 1
]
}

0
src/modules/test/punk/#modpod-lib-999999.0a1.0/lib-0.1.3_testsuites/tests/compat.test#..+lib+compat.test.fauxlink

0
src/modules/test/punk/#modpod-lib-999999.0a1.0/lib-0.1.3_testsuites/tests/index.test#..+lib+index_functions.test.fauxlink

211
src/modules/test/punk/#modpod-lib-999999.0a1.0/lib-999999.0a1.0.tm

@ -0,0 +1,211 @@
# -*- tcl -*-
# Maintenance Instruction: leave the 999999.xxx.x as is and use punkshell 'dev make' or bin/punkmake to update from <pkg>-buildversion.txt
# module template: shellspy/src/decktemplates/vendor/punk/modules/template_module-0.0.3.tm
#
# Please consider using a BSD or MIT style license for greatest compatibility with the Tcl ecosystem.
# Code using preferred Tcl licenses can be eligible for inclusion in Tcllib, Tklib and the punk package repository.
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# (C) 2025
#
# @@ Meta Begin
# Application test::punk::lib 999999.0a1.0
# Meta platform tcl
# Meta license MIT
# @@ Meta End
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin shellspy_module_test::punk::lib 0 999999.0a1.0]
#[copyright "2025"]
#[titledesc {Module API}] [comment {-- Name section and table of contents description --}]
#[moddesc {-}] [comment {-- Description at end of page heading --}]
#[require test::punk::lib]
#[keywords module]
#[description]
#[para] -
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[section Overview]
#[para] overview of test::punk::lib
#[subsection Concepts]
#[para] -
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Requirements
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[subsection dependencies]
#[para] packages used by test::punk::lib
#[list_begin itemized]
package require Tcl 8.6-
#*** !doctools
#[item] [package {Tcl 8.6}]
#*** !doctools
#[list_end]
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[section API]
tcl::namespace::eval test::punk::lib {
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# Base namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[subsection {Namespace test::punk::lib}]
#[para] Core API functions for test::punk::lib
#[list_begin definitions]
variable PUNKARGS
variable pkg test::punk::lib
variable version
set version 999999.0a1.0
package require packageTest
packageTest::makeAPI test::punk::lib $version punk::lib; #will package provide test::punk::lib $version
package forget punk::lib
package require punk::lib
#*** !doctools
#[list_end] [comment {--- end definitions namespace test::punk::lib ---}]
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# Secondary API namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# == === === === === === === === === === === === === === ===
# Sample 'about' function with punk::args documentation
# == === === === === === === === === === === === === === ===
tcl::namespace::eval test::punk::lib {
tcl::namespace::export {[a-z]*} ;# Convention: export all lowercase
variable PUNKARGS
variable PUNKARGS_aliases
lappend PUNKARGS [list {
@id -id "(package)test::punk::lib"
@package -name "test::punk::lib" -help\
"Test suites for punk::lib"
}]
namespace eval argdoc {
#namespace for custom argument documentation
proc package_name {} {
return test::punk::lib
}
proc about_topics {} {
#info commands results are returned in an arbitrary order (like array keys)
set topic_funs [info commands [namespace current]::get_topic_*]
set about_topics [list]
foreach f $topic_funs {
set tail [namespace tail $f]
lappend about_topics [string range $tail [string length get_topic_] end]
}
#Adjust this function or 'default_topics' if a different order is required
return [lsort $about_topics]
}
proc default_topics {} {return [list Description *]}
# -------------------------------------------------------------
# get_topic_ functions add more to auto-include in about topics
# -------------------------------------------------------------
proc get_topic_Description {} {
punk::args::lib::tstr [string trim {
package test::punk::lib
test suite for punk::lib
} \n]
}
proc get_topic_License {} {
return "MIT"
}
proc get_topic_Version {} {
return "$::test::punk::lib::version"
}
proc get_topic_Contributors {} {
set authors {{<julian@precisium.com> Julian Noble}}
set contributors ""
foreach a $authors {
append contributors $a \n
}
if {[string index $contributors end] eq "\n"} {
set contributors [string range $contributors 0 end-1]
}
return $contributors
}
proc get_topic_custom-topic {} {
punk::args::lib::tstr -return string {
A custom
topic
etc
}
}
# -------------------------------------------------------------
}
# we re-use the argument definition from punk::args::standard_about and override some items
set overrides [dict create]
dict set overrides @id -id "::test::punk::lib::about"
dict set overrides @cmd -name "test::punk::lib::about"
dict set overrides @cmd -help [string trim [punk::args::lib::tstr {
About test::punk::lib
}] \n]
dict set overrides topic -choices [list {*}[test::punk::lib::argdoc::about_topics] *]
dict set overrides topic -choicerestricted 1
dict set overrides topic -default [test::punk::lib::argdoc::default_topics] ;#if -default is present 'topic' will always appear in parsed 'values' dict
set newdef [punk::args::resolved_def -antiglobs -package_about_namespace -override $overrides ::punk::args::package::standard_about *]
lappend PUNKARGS [list $newdef]
proc about {args} {
package require punk::args
#standard_about accepts additional choices for topic - but we need to normalize any abbreviations to full topic name before passing on
set argd [punk::args::parse $args withid ::test::punk::lib::about]
lassign [dict values $argd] _leaders opts values _received
punk::args::package::standard_about -package_about_namespace ::test::punk::lib::argdoc {*}$opts {*}[dict get $values topic]
}
}
# end of sample 'about' function
# == === === === === === === === === === === === === === ===
# -----------------------------------------------------------------------------
# register namespace(s) to have PUNKARGS,PUNKARGS_aliases variables checked
# -----------------------------------------------------------------------------
# variable PUNKARGS
# variable PUNKARGS_aliases
namespace eval ::punk::args::register {
#use fully qualified so 8.6 doesn't find existing var in global namespace
lappend ::punk::args::register::NAMESPACES ::test::punk::lib
}
# -----------------------------------------------------------------------------
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Ready
package provide test::punk::lib [tcl::namespace::eval test::punk::lib {
variable pkg test::punk::lib
variable version
set version 999999.0a1.0
}]
return
#*** !doctools
#[manpage_end]

3
src/modules/test/punk/lib-buildversion.txt

@ -0,0 +1,3 @@
0.1.3
#First line must be a semantic version number
#all other lines are ignored.

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

@ -5717,6 +5717,7 @@ tcl::namespace::eval textblock {
" "
-ansiresets -type any -default auto -ansiresets -type any -default auto
-- -type none -optional 0 -help "end of options marker -- is mandatory because joined blocks may easily conflict with flags" -- -type none -optional 0 -help "end of options marker -- is mandatory because joined blocks may easily conflict with flags"
@values
blocks -type any -multiple 1 blocks -type any -multiple 1
} }
@ -6095,6 +6096,7 @@ tcl::namespace::eval textblock {
proc welcome_test {} { proc welcome_test {} {
package require punk::ansi package require punk::ansi
package require patternpunk
set ansi [textblock::join -- " " [punk::ansi::ansicat src/testansi/publicdomain/roysac/ROY-WELC.ANS 80x8]] set ansi [textblock::join -- " " [punk::ansi::ansicat src/testansi/publicdomain/roysac/ROY-WELC.ANS 80x8]]
# Ansi art courtesy of Carsten Cumbrowski aka Roy/SAC - roysac.com # Ansi art courtesy of Carsten Cumbrowski aka Roy/SAC - roysac.com
set table [[textblock::spantest] print] set table [[textblock::spantest] print]
@ -6108,6 +6110,7 @@ tcl::namespace::eval textblock {
proc example {args} { proc example {args} {
set opts [tcl::dict::create -forcecolour 0] set opts [tcl::dict::create -forcecolour 0]
package require patternpunk
foreach {k v} $args { foreach {k v} $args {
switch -- $k { switch -- $k {
-forcecolour { -forcecolour {
@ -8917,7 +8920,8 @@ tcl::namespace::eval textblock {
} }
punk::args::define { punk::args::define {
@id -id ::textblock::gcross @id -id ::textblock::gcross
-max_cross_size -default 0 -type integer -help "Largest size cross to use to make up the block -max_cross_size -default 0 -type integer -help\
"Largest size cross to use to make up the block
Only cross sizes that divide the size of the overall block will be used. Only cross sizes that divide the size of the overall block will be used.
e.g if the 'size' chosen is 19 (a prime number) - only 1 or the full size of 19 can be used as the crosses to make up the block. e.g if the 'size' chosen is 19 (a prime number) - only 1 or the full size of 19 can be used as the crosses to make up the block.
Whereas for a block size of 24, -max_cross_size of 1,2,3,4,6,8,12 or 24 will work. (all divisors) Whereas for a block size of 24, -max_cross_size of 1,2,3,4,6,8,12 or 24 will work. (all divisors)

Loading…
Cancel
Save