@ -7,7 +7,7 @@
# (C) 2023
# (C) 2023
#
#
# @@ Meta Begin
# @@ Meta Begin
# Application punk::ns 0.9.3
# Application punk::ns 0.11.0
# Meta platform tcl
# Meta platform tcl
# Meta license <unspecified>
# Meta license <unspecified>
# @@ Meta End
# @@ Meta End
@ -4652,7 +4652,35 @@ y" {return quirkykeyscript}
-summary\
-summary\
"Subcommand resolution of ensemble-like tree of commands."\
"Subcommand resolution of ensemble-like tree of commands."\
-help\
-help\
"Return a dict with command resolution info for ensemble-like tree of commands with subcommands"
"Return a dict with command resolution info for ensemble-like tree of commands with subcommands
Result keys:
origin - the resolved command (or the docid path for a
documentation-only landing)
cmdtype - what KIND of executable thing resolution landed on
(proc, native, alias, ensemble, doconly, notfound...)
unavailable - (G-166) empty string, or the canonical
-choiceunavailable name the resolution addressed.
A SEPARATE axis from cmdtype: it describes the
resolved word's availability in this
runtime/context, not the kind of thing found.
Non-empty means the landing is documentation the
current runtime cannot actually run - e.g
'string is dict' on Tcl 8.6.
overridden - (G-176) empty list, or one entry per LIVE
commandstack rename record on the BASE command
(bottom-up): a dict {renamer <string> docids
<list>} where docids are the punk::args ids of
any doc blocks the record attached via
'rename_command -punkargs'. A second axis like
'unavailable': it describes the live override
state of the command, not the kind of thing
resolution landed on. Always empty when the
commandstack package is not loaded.
args_resolved - the command words consumed by resolution
args_remaining- the trailing words resolution did not consume
docid - the punk::args definition id documenting the landing
stack - per-level record of the traversal"
@leaders -min 0 -max 0
@leaders -min 0 -max 0
@opts
@opts
-form -default * -help\
-form -default * -help\
@ -4683,8 +4711,9 @@ y" {return quirkykeyscript}
set commands [list]
set commands [list]
set consumed_args [list]
set consumed_args [list]
set docid ""
set docid ""
set unavailable "" ;#G-166: availability attribution of the FINAL landing (each record overwrites)
while {$final == 0} {
while {$final == 0} {
lassign [$reduce $origin] final origin consumed remainingargs docid
lassign [$reduce $origin] final origin consumed remainingargs docid unavailable
#if {$final != 1} {
#if {$final != 1} {
if {[string match (autodef)* $origin]} {
if {[string match (autodef)* $origin]} {
set origin [string range $origin 9 end]
set origin [string range $origin 9 end]
@ -4715,8 +4744,50 @@ y" {return quirkykeyscript}
#genuinely unknown command. The docid remains authoritative for display.
#genuinely unknown command. The docid remains authoritative for display.
set cmdtype doconly
set cmdtype doconly
}
}
return [list origin $origin cmdtype $cmdtype args_resolved [list [lindex $commands 0] {*}$consumed_args] args_remaining $remainingargs docid $docid stack $stack]
#G-166: 'unavailable' is deliberately a SECOND axis beside cmdtype - cmdtype
#answers what kind of executable thing resolution landed on, availability
#answers whether the resolved word is selectable in this runtime/context.
#Overloading cmdtype (e.g a 'doconly_unavailable' value) would break every
#consumer switching on cmdtype eq "doconly", and the two only co-occur
#incidentally (an unavailable name has no real command behind it today).
#G-176: 'overridden' is a further second-axis key - the live commandstack
#override state of the BASE command word, queried at call time (never
#cached) so it is correct by construction as stacks change.
return [list origin $origin cmdtype $cmdtype unavailable $unavailable overridden [_cmdinfo_overridden [lindex $commands 0]] args_resolved [list [lindex $commands 0] {*}$consumed_args] args_remaining $remainingargs docid $docid stack $stack]
}
}
#G-176: live commandstack override records for a command - one dict
#{renamer <string> docids <list>} per record, bottom-up. docids are the
#punk::args ids of doc blocks the record attached via 'rename_command
#-punkargs' (derived with punk::args::rawdef_id - deflists whose id cannot
#be derived are simply not listed). Guarded: empty list when the
#commandstack package is not loaded - no hard dependency.
proc _cmdinfo_overridden {command} {
if {![llength [info commands ::commandstack::get_stack]]} {
return [list]
}
if {[catch {commandstack::get_stack $command} stackrecords]} {
return [list]
}
set overridden [list]
foreach crec $stackrecords {
if {![dict exists $crec renamer]} {continue}
set docids [list]
if {[dict exists $crec punkargs] && [llength [info commands ::punk::args::rawdef_id]]} {
foreach deflist [dict get $crec punkargs] {
if {![catch {punk::args::rawdef_id $deflist} rawid] && $rawid ne ""} {
lappend docids $rawid
}
}
}
lappend overridden [dict create renamer [dict get $crec renamer] docids $docids]
}
return $overridden
}
#Each record yielded/returned by cmd_traverse is:
# [list <code> <origin> <resolvedargs> <remainingargs> <docid> <unavailable>]
#<unavailable> (G-166) is the canonical -choiceunavailable name this level's
#resolution addressed, or empty. cmdinfo keeps the FINAL record's value - the
#availability of the landing it reports.
proc cmd_traverse {ns formid args} {
proc cmd_traverse {ns formid args} {
set autodefined [dict create]
set autodefined [dict create]
#puts "cmd_traverse args: $args yielding: [info coroutine]"
#puts "cmd_traverse args: $args yielding: [info coroutine]"
@ -4746,7 +4817,7 @@ y" {return quirkykeyscript}
set origin $which ;#Flip our traversal to be on the documented 'which' rather than the actual origin
set origin $which ;#Flip our traversal to be on the documented 'which' rather than the actual origin
if {$whichtype eq "alias"} {
if {$whichtype eq "alias"} {
#*documented* alias
#*documented* alias
return [list 1 $origin {} [lrange $args 1 end] $docid]
return [list 1 $origin {} [lrange $args 1 end] $docid {} ]
}
}
}
}
}
}
@ -4773,10 +4844,10 @@ y" {return quirkykeyscript}
#} else {
#} else {
if {$docid ne "" && ![llength [lrange $args 1 end]]} {
if {$docid ne "" && ![llength [lrange $args 1 end]]} {
return [list 0a $origin {} {} $docid]
return [list 0a $origin {} {} $docid {} ]
}
}
set origin [yield [list 0 $origin {} [lrange $args 1 end] $docid]]
set origin [yield [list 0 $origin {} [lrange $args 1 end] $docid {} ]]
set whichinfo [namespace eval $ns [list punk::ns::cmdwhich $cmd]]
set whichinfo [namespace eval $ns [list punk::ns::cmdwhich $cmd]]
set origin [dict get $whichinfo origin]
set origin [dict get $whichinfo origin]
set origintype [dict get $whichinfo origintype]
set origintype [dict get $whichinfo origintype]
@ -4867,7 +4938,7 @@ y" {return quirkykeyscript}
}
}
#}
#}
if {[llength $args] == 1} {
if {[llength $args] == 1} {
return [list 2 $origin $resolvedargs {} $docid]
return [list 2 $origin $resolvedargs {} $docid {} ]
}
}
set terminate 0
set terminate 0
for {set i 1} {$i < [llength $args]} {incr i} {
for {set i 1} {$i < [llength $args]} {incr i} {
@ -4894,19 +4965,18 @@ y" {return quirkykeyscript}
set docid_exists 0
set docid_exists 0
set eparams [list]
set eparams [list]
set a_spaceform ""
set a_spaceform ""
if {[punk::args::id_exists "$origin [lindex $args $i]"]} {
set a_unavailable "" ;#G-166 availability attribution for this level's landing
set a_spaceform [lindex $args $i]
set a_word [lindex $args $i]
} elseif {$docid ne "" && [punk::args::id_exists $docid]} {
#G-051 space-form docid prefix parity / G-166 availability attribution:
#G-051 space-form docid prefix parity: no space-form id exists for the
#resolve the word against the current level's choices-bearing first leader
#exact word - if the current level's definition has a choices-bearing
#with the same shared resolver argument parsing uses
#first leader, resolve the word with the same shared resolver argument
#(punk::args::choiceword_match - honouring -choiceprefix, -nocase,
#parsing uses (punk::args::choiceword_match - honouring -choiceprefix,
#-choicealiases, -choiceprefixdenylist, -choiceprefixreservelist and
#-nocase, -choicealiases, -choiceprefixdenylist,
#-choiceunavailable). Computed once here because BOTH the exact-word
#-choiceprefixreservelist) and retry the space-form lookup with the
#space-form landing and the prefix retry consult it: the exact landing only
#canonical word - so 'i string is tr' lands on the documentation for
#for the availability verdict, the prefix retry for the canonical word too.
#what 'string is tr' actually executes. No second matching rule: a word
set lvl_matchinfo ""
#parse would reject resolves nothing here either, and a canonical with
if {$docid ne "" && [punk::args::id_exists $docid]} {
#no space-form id falls through to the normal per-level handling.
set pf_spec [punk::args::get_spec $docid]
set pf_spec [punk::args::get_spec $docid]
set pf_fid [lindex [dict get $pf_spec form_names] 0]
set pf_fid [lindex [dict get $pf_spec form_names] 0]
set pf_leaders [dict get $pf_spec FORMS $pf_fid LEADER_NAMES]
set pf_leaders [dict get $pf_spec FORMS $pf_fid LEADER_NAMES]
@ -4917,7 +4987,7 @@ y" {return quirkykeyscript}
lappend pf_allchoices {*}$pf_members
lappend pf_allchoices {*}$pf_members
}
}
if {[llength $pf_allchoices]} {
if {[llength $pf_allchoices]} {
set pf_matchinfo [punk::args::choiceword_match [lindex $args $i] \
set lvl_matchinfo [punk::args::choiceword_match $a_word \
[punk::args::system::Dict_getdef $pf_arginfo -nocase 0]\
[punk::args::system::Dict_getdef $pf_arginfo -nocase 0]\
$pf_allchoices\
$pf_allchoices\
[punk::args::system::Dict_getdef $pf_arginfo -choicealiases {}]\
[punk::args::system::Dict_getdef $pf_arginfo -choicealiases {}]\
@ -4926,15 +4996,46 @@ y" {return quirkykeyscript}
[punk::args::system::Dict_getdef $pf_arginfo -choiceprefixreservelist {}]\
[punk::args::system::Dict_getdef $pf_arginfo -choiceprefixreservelist {}]\
[punk::args::system::Dict_getdef $pf_arginfo -choiceunavailable {}]\
[punk::args::system::Dict_getdef $pf_arginfo -choiceunavailable {}]\
]
]
if {[dict get $pf_matchinfo matched]} {
set pf_canonical [dict get $pf_matchinfo canonical]
if {$pf_canonical ne [lindex $args $i] && [punk::args::id_exists "$origin $pf_canonical"]} {
set a_spaceform $pf_canonical
}
}
}
}
}
}
}
}
if {[punk::args::id_exists "$origin $a_word"]} {
set a_spaceform $a_word
#G-166: the exact word may address a recognised-but-unavailable name.
#Its virtual docid exists by G-073 design (documentation REACHABILITY
#for unavailable words), so resolution succeeds - but the landing is
#attributed so consumers can tell it from a usable one.
if {$lvl_matchinfo ne "" && [dict get $lvl_matchinfo unavailable]} {
set a_unavailable [dict get $lvl_matchinfo canonical]
}
} elseif {$lvl_matchinfo ne "" && [dict get $lvl_matchinfo matched]} {
#retry the space-form lookup with the canonical word - so 'i string is
#tr' lands on the documentation for what 'string is tr' actually
#executes. No second matching rule: a word parse would reject resolves
#nothing here either, and a canonical with no space-form id falls
#through to the normal per-level handling.
set pf_canonical [dict get $lvl_matchinfo canonical]
if {$pf_canonical ne $a_word && [punk::args::id_exists "$origin $pf_canonical"]} {
set a_spaceform $pf_canonical
}
} elseif {$lvl_matchinfo ne "" && [dict get $lvl_matchinfo unavailable]} {
#G-166 DECISION (enacting the G-073 follow-on): a unique prefix landing
#on an unavailable name resolves that name's virtual docid, marked -
#it no longer conservatively resolves nothing. Rationale: documentation
#ADDRESSING and word AVAILABILITY are separate axes (the whole point of
#the attribution added here). Encoding availability as
#resolve-vs-don't-resolve conflated them and made addressing
#inconsistent - 'string is tr' resolved but 'string is dic' did not,
#while exact 'string is true' and 'string is dict' both did. Now every
#form of address that names a documented word resolves it, and the
#availability key (plus cmdhelp's marking) carries the rejection story
#that parse reports for the same word.
set pf_canonical [dict get $lvl_matchinfo canonical]
if {[punk::args::id_exists "$origin $pf_canonical"]} {
set a_spaceform $pf_canonical
set a_unavailable $pf_canonical
}
}
if {$a_spaceform ne ""} {
if {$a_spaceform ne ""} {
set a $a_spaceform
set a $a_spaceform
#review - tests?
#review - tests?
@ -4966,7 +5067,7 @@ y" {return quirkykeyscript}
#review - get_spec needs to resolve if @dynamic
#review - get_spec needs to resolve if @dynamic
#we don't really need the spec if we have no queryargs
#we don't really need the spec if we have no queryargs
if {![llength $queryargs]} {
if {![llength $queryargs]} {
return [list X $origin $resolvedargs $queryargs_untested $docid]
return [list X $origin $resolvedargs $queryargs_untested $docid $a_unavailable ]
}
}
@ -5063,7 +5164,7 @@ y" {return quirkykeyscript}
#ledit queryargs_untested 0 0
#ledit queryargs_untested 0 0
#jjj
#jjj
#continue
#continue
return [list 3 $origin $resolvedargs [list {*}$eparams {*}$queryargs_untested] $docid]
return [list 3 $origin $resolvedargs [list {*}$eparams {*}$queryargs_untested] $docid $a_unavailable ]
break
break
}
}
#G-040: resolve the subcommand word with the same shared resolver argument
#G-040: resolve the subcommand word with the same shared resolver argument
@ -5078,9 +5179,10 @@ y" {return quirkykeyscript}
#doc-only ids without implying the word parses - that is how per-class ids
#doc-only ids without implying the word parses - that is how per-class ids
#like 'string is true' have always documented argument words, and how an
#like 'string is true' have always documented argument words, and how an
#UNAVAILABLE word's virtual id ('string is dict' on 8.6) documents since
#UNAVAILABLE word's virtual id ('string is dict' on 8.6) documents since
#G-073. Consequence: cmdinfo classes both landings 'doconly' with no
#G-073. G-166 settled the surfacing: the addressing branches above resolve
#availability distinction - surfacing that (cmdinfo axis / render marking)
#such landings and cmdinfo reports them on its own 'unavailable' axis,
#is deliberately not decided here.
#while THIS traverse keeps its parity claim intact - an unavailable word
#still identifies no subcommand here, it is only attributed below.
set ct_matchinfo [punk::args::choiceword_match $q\
set ct_matchinfo [punk::args::choiceword_match $q\
[punk::args::system::Dict_getdef $arginfo -nocase 0]\
[punk::args::system::Dict_getdef $arginfo -nocase 0]\
$allchoices\
$allchoices\
@ -5093,7 +5195,14 @@ y" {return quirkykeyscript}
if {![dict get $ct_matchinfo matched]} {
if {![dict get $ct_matchinfo matched]} {
#no match under parse rules (covers: unknown word, ambiguous prefix,
#no match under parse rules (covers: unknown word, ambiguous prefix,
#reserved word, denied prefix, and non-exact word when -choiceprefix 0)
#reserved word, denied prefix, and non-exact word when -choiceprefix 0)
return [list 4 $origin $resolvedargs $queryargs_untested $docid]
#G-166: a landing on a recognised-but-unavailable name is still not a
#subcommand match, but it IS attributed - this is the path taken when
#the unavailable name has no space-form virtual docid to address.
set ct_unavailable ""
if {[dict get $ct_matchinfo unavailable]} {
set ct_unavailable [dict get $ct_matchinfo canonical]
}
return [list 4 $origin $resolvedargs $queryargs_untested $docid $ct_unavailable]
break
break
}
}
set resolved_q [dict get $ct_matchinfo canonical]
set resolved_q [dict get $ct_matchinfo canonical]
@ -5191,10 +5300,10 @@ y" {return quirkykeyscript}
#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 [list {*}$eparams {*}$queryargs_untested] $docid]
return [list 6 $mapped_subcmd $resolvedargs [list {*}$eparams {*}$queryargs_untested] $docid {} ]
}
}
set origin [yield [list 0 $mapped_subcmd $resolvedargs [list {*}$eparams {*}$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
@ -5223,22 +5332,22 @@ y" {return quirkykeyscript}
break ;#out of foreach q $queryargs ...
break ;#out of foreach q $queryargs ...
} else {
} else {
#test with: i namespace which -v x
#test with: i namespace which -v x
return [list 7 $origin $resolvedargs $queryargs_untested $prevdocid]
return [list 7 $origin $resolvedargs $queryargs_untested $prevdocid {} ]
}
}
} ;#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: $origin resolved: $resolvedargs remaining: [lrange $args $i end] docid: $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 $a_unavailable ]
}
}
} else {
} else {
#puts stderr "origin $origin not documented"
#puts stderr "origin $origin not documented"
return [list 9 $origin {} [lrange $args $i end] ""]
return [list 9 $origin {} [lrange $args $i end] "" {} ]
}
}
}
}
#REVIEW!!!
#REVIEW!!!
#puts stderr "cmd_traverse 10 $origin $resolvedargs $queryargs_untested $docid - review"
#puts stderr "cmd_traverse 10 $origin $resolvedargs $queryargs_untested $docid - review"
return [list 10 $origin $resolvedargs $queryargs_untested $docid]
return [list 10 $origin $resolvedargs $queryargs_untested $docid $a_unavailable ]
}
}
@ -5494,12 +5603,18 @@ y" {return quirkykeyscript}
} -help\
} -help\
"Return form of the usage information.
"Return form of the usage information.
'dict' returns a dict with keys origin, docid, cmdtype,
'dict' returns a dict with keys origin, docid, cmdtype,
args_remaining and parsestatus - where parsestatus is the
unavailable, args_remaining and parsestatus - where parsestatus
parse-status structure of the supplied argument words against
is the parse-status structure of the supplied argument words
the resolved definition (see punk::args::parse_status for the
against the resolved definition (see punk::args::parse_status for
documented structure; empty if the command is undocumented).
the documented structure; empty if the command is undocumented).
Its per-argument statuses distinguish a fully-valid, an invalid
Its per-argument statuses distinguish a fully-valid, an invalid
and an incomplete argument set machine-parsably.
and an incomplete argument set machine-parsably.
'unavailable' (G-166) is empty, or the canonical
-choiceunavailable name the resolution addressed - a subject the
current runtime/context documents but cannot run (e.g
'string is dict' on Tcl 8.6). The other return forms carry the
same fact as a visible marking, and never present such a subject
as a cleanly usable command line.
'text' returns plain text with no ANSI codes and no table
'text' returns plain text with no ANSI codes and no table
layout, rendering the argument section of every command form
layout, rendering the argument section of every command form
(or of each form in an explicit -form selection) in a single
(or of each form in an explicit -form selection) in a single
@ -5542,6 +5657,35 @@ y" {return quirkykeyscript}
form (no words, an ambiguous match, or words no form
form (no words, an ambiguous match, or words no form
accepts) keep the whole-command render."
accepts) keep the whole-command render."
}
}
#G-166: the single wording for cmdhelp's recognised-but-unavailable marking, shared
#by the table and text return forms so every surface says the same thing. Vocabulary
#deliberately mirrors punk::args' tailored parse rejection
#(private::unavailable_choice_msg, G-073) - a user who meets both reads one story.
#The runtime-specific WHY is not repeated here: it belongs to the definition, and the
#unavailable subject's own help leads with it (the tclcore virtual ids do since G-166).
proc _cmdhelp_unavailable_marking {name} {
#(wording stays position-neutral: the table/string renderers place the message
#below the usage, the text form leads with it)
return "'$name' is a recognised name here, but is not available in this runtime/context - this command line is not usable here and the usage shown is reference documentation only."
}
#G-176: one-line override-in-place notice from cmdinfo's 'overridden' axis.
#basecmd is the command the records belong to (the cmdhelp subject);
#overridden is the list of {renamer .. docids ..} dicts (bottom-up). Returns
#the bare notice - the table render prefixes 'note: ', -return text prefixes
#'OVERRIDDEN: ' (its machine-facing leading-line convention).
proc _cmdhelp_override_notice {basecmd overridden} {
set renamers [list]
set docids [list]
foreach rec $overridden {
lappend renamers [dict get $rec renamer]
lappend docids {*}[dict get $rec docids]
}
set notice "'$basecmd' is currently overridden/extended via commandstack by: [join $renamers {, }]"
if {[llength $docids]} {
append notice " (override-attached docs: '[join $docids {', '}]')"
}
return $notice
}
proc cmdhelp {args} {
proc cmdhelp {args} {
set nscaller [uplevel 1 [list ::tcl::namespace::current]]
set nscaller [uplevel 1 [list ::tcl::namespace::current]]
lassign [dict values [punk::args::parse $args -cache 1 withid ::punk::ns::cmdhelp]] leaders opts values received
lassign [dict values [punk::args::parse $args -cache 1 withid ::punk::ns::cmdhelp]] leaders opts values received
@ -5589,9 +5733,15 @@ y" {return quirkykeyscript}
#string renderer and the sections are joined below the common header.
#string renderer and the sections are joined below the common header.
set dinfo [uplevel 1 [list ::punk::ns::cmdhelp -return dict -form $opt_form -- $querycommand {*}$queryargs]]
set dinfo [uplevel 1 [list ::punk::ns::cmdhelp -return dict -form $opt_form -- $querycommand {*}$queryargs]]
set docid [dict get $dinfo docid]
set docid [dict get $dinfo docid]
set text_overridden [punk::args::system::Dict_getdef $dinfo overridden {}] ;#G-176
if {$docid eq ""} {
if {$docid eq ""} {
return "Undocumented command [dict get $dinfo origin]. Type: [dict get $dinfo cmdtype]"
set undoc "Undocumented command [dict get $dinfo origin]. Type: [dict get $dinfo cmdtype]"
if {[llength $text_overridden]} {
set undoc "OVERRIDDEN: [_cmdhelp_override_notice $querycommand $text_overridden]\n$undoc"
}
return $undoc
}
}
set unavail [dict get $dinfo unavailable] ;#G-166 (the dict form always carries it)
set spec [punk::args::get_spec $docid]
set spec [punk::args::get_spec $docid]
set pstatus [dict get $dinfo parsestatus]
set pstatus [dict get $dinfo parsestatus]
if {$opt_form ne "*"} {
if {$opt_form ne "*"} {
@ -5632,6 +5782,16 @@ y" {return quirkykeyscript}
}
}
set result [string trimright $result \n]
set result [string trimright $result \n]
}
}
if {[llength $text_overridden]} {
#G-176: override-in-place leading line for the machine/LLM-facing
#surface (sits below UNAVAILABLE when both apply)
set result "OVERRIDDEN: [_cmdhelp_override_notice $querycommand $text_overridden]\n$result"
}
if {$unavail ne ""} {
#G-166: mark the plain-text form too - it is the machine/LLM-facing
#surface, so the marking leads rather than trailing the usage block.
set result "UNAVAILABLE: [_cmdhelp_unavailable_marking $unavail]\n$result"
}
if {$opt_grepstr ne ""} {
if {$opt_grepstr ne ""} {
if {[llength $opt_grepstr] == 1} {
if {[llength $opt_grepstr] == 1} {
set result [punk::ansi::grepstr --ignore-case -return all [lindex $opt_grepstr 0] $result]
set result [punk::ansi::grepstr --ignore-case -return all [lindex $opt_grepstr 0] $result]
@ -5682,13 +5842,19 @@ y" {return quirkykeyscript}
} else {
} else {
dict set nextopts -form [dict get $pstatus form]
dict set nextopts -form [dict get $pstatus form]
}
}
set alias_overridden [punk::args::system::Dict_getdef $testinfo overridden {}] ;#G-176
if {$opt_return eq "dict"} {
if {$opt_return eq "dict"} {
if {$scheme_received} {
if {$scheme_received} {
dict set pstatus scheme [dict get $opts -scheme]
dict set pstatus scheme [dict get $opts -scheme]
}
}
return [dict create origin $rootorigin docid $rootdoc cmdtype $rootorigintype args_remaining $queryargs parsestatus $pstatus]
return [dict create origin $rootorigin docid $rootdoc cmdtype $rootorigintype unavailable [dict get $testinfo unavailable] overridden $alias_overridden args_remaining $queryargs parsestatus $pstatus]
}
}
if {[dict get $pstatus ok]} {
#G-166: an unavailable subject never renders as a cleanly usable
#command line - see the matching site in the main cmdhelp body.
set unavail [dict get $testinfo unavailable]
if {$unavail ne ""} {
set result [punk::args::arg_error [_cmdhelp_unavailable_marking $unavail] [punk::args::get_spec $rootdoc] {*}$nextopts -aserror 0 -parsestatus $pstatus]
} elseif {[dict get $pstatus ok]} {
#show usage - with goodargs marked
#show usage - with goodargs marked
if {!$scheme_received} {
if {!$scheme_received} {
dict set nextopts -scheme info
dict set nextopts -scheme info
@ -5697,6 +5863,10 @@ y" {return quirkykeyscript}
} else {
} else {
set result [punk::args::arg_error [dict get $pstatus message] [punk::args::get_spec $rootdoc] {*}$nextopts -aserror 0 -parsestatus $pstatus]
set result [punk::args::arg_error [dict get $pstatus message] [punk::args::get_spec $rootdoc] {*}$nextopts -aserror 0 -parsestatus $pstatus]
}
}
if {[llength $alias_overridden]} {
#G-176: override-in-place notice leads the render
set result "note: [_cmdhelp_override_notice $querycommand $alias_overridden]\n$result"
}
if {$opt_grepstr ne ""} {
if {$opt_grepstr ne ""} {
if {[llength $opt_grepstr] == 1} {
if {[llength $opt_grepstr] == 1} {
set result [punk::ansi::grepstr --ignore-case -return all [lindex $opt_grepstr 0] $result]
set result [punk::ansi::grepstr --ignore-case -return all [lindex $opt_grepstr 0] $result]
@ -5753,6 +5923,8 @@ y" {return quirkykeyscript}
set origindoc [dict get $cinfo docid]
set origindoc [dict get $cinfo docid]
set args_remaining [dict get $cinfo args_remaining]
set args_remaining [dict get $cinfo args_remaining]
set origintype [dict get $cinfo cmdtype]
set origintype [dict get $cinfo cmdtype]
set unavail [dict get $cinfo unavailable] ;#G-166
set overridden [punk::args::system::Dict_getdef $cinfo overridden {}] ;#G-176
switch -- $origintype {
switch -- $origintype {
script {
script {
@ -5800,9 +5972,21 @@ y" {return quirkykeyscript}
if {$scheme_received} {
if {$scheme_received} {
dict set pstatus scheme [dict get $opts -scheme]
dict set pstatus scheme [dict get $opts -scheme]
}
}
return [dict create origin $origin docid $origindoc cmdtype $origintype args_remaining $args_remaining parsestatus $pstatus]
return [dict create origin $origin docid $origindoc cmdtype $origintype unavailable $unavail overridden $overridden args_remaining $args_remaining parsestatus $pstatus]
}
}
if {[dict get $pstatus ok]} {
#G-166: a recognised-but-unavailable subject is never presented as cleanly
#usable. The advisory parse can succeed against the subject's virtual id
#(the id documents the word, and an argument tail like 'string is dict 5'
#satisfies it) - so an ok parse would otherwise switch to the 'info' scheme
#and mark the words good, rendering exactly like a usable command line. The
#unavailability marking takes precedence over BOTH the ok-parse info render
#and any parse failure message: the subject not existing here is the more
#fundamental report, and it is the one a parse against a virtual id cannot
#make. The parse status is still passed through, so argument positions keep
#their marking under the (non-info) scheme.
if {$unavail ne ""} {
set result [punk::args::arg_error [_cmdhelp_unavailable_marking $unavail] [punk::args::get_spec $origindoc] {*}$nextopts -aserror 0 -parsestatus $pstatus]
} elseif {[dict get $pstatus ok]} {
#show usage - with goodargs marked
#show usage - with goodargs marked
if {!$scheme_received} {
if {!$scheme_received} {
dict set nextopts -scheme info
dict set nextopts -scheme info
@ -5811,6 +5995,10 @@ y" {return quirkykeyscript}
} else {
} else {
set result [punk::args::arg_error [dict get $pstatus message] [punk::args::get_spec $origindoc] {*}$nextopts -aserror 0 -parsestatus $pstatus]
set result [punk::args::arg_error [dict get $pstatus message] [punk::args::get_spec $origindoc] {*}$nextopts -aserror 0 -parsestatus $pstatus]
}
}
if {[llength $overridden]} {
#G-176: override-in-place notice leads the render
set result "note: [_cmdhelp_override_notice $querycommand $overridden]\n$result"
}
if {$opt_grepstr ne ""} {
if {$opt_grepstr ne ""} {
if {[llength $opt_grepstr] == 1} {
if {[llength $opt_grepstr] == 1} {
set result [punk::ansi::grepstr --ignore-case -return all [lindex $opt_grepstr 0] $result]
set result [punk::ansi::grepstr --ignore-case -return all [lindex $opt_grepstr 0] $result]
@ -5821,9 +6009,13 @@ y" {return quirkykeyscript}
return $result
return $result
} else {
} else {
if {$opt_return eq "dict"} {
if {$opt_return eq "dict"} {
return [dict create origin $origin docid "" cmdtype $origintype args_remaining $args_remaining parsestatus {}]
return [dict create origin $origin docid "" cmdtype $origintype unavailable $unavail overridden $overridden args_remaining $args_remaining parsestatus {}]
}
set result "Undocumented command $origin. Type: $origintype"
if {[llength $overridden]} {
set result "note: [_cmdhelp_override_notice $querycommand $overridden]\n$result"
}
}
return "Undocumented command $origin. Type: $origintype"
return $result
}
}
}
}
@ -6746,6 +6938,6 @@ namespace eval ::punk::args::register {
## Ready
## Ready
package provide punk::ns [tcl::namespace::eval punk::ns {
package provide punk::ns [tcl::namespace::eval punk::ns {
variable version
variable version
set version 0.9.3
set version 0.11.0
}]
}]
return
return