From d4284083a2c21ad4bc7965a0399fe9989437ba3a Mon Sep 17 00:00:00 2001 From: Julian Noble Date: Sat, 26 Jul 2025 17:09:25 +1000 Subject: [PATCH] add punk::args::tclcore to bootsupport, but make it a soft dependency in punk::repl interps --- .../modules/include_modules.config | 1 + .../modules/punk/args/tclcore-0.1.0.tm | 6539 +++++++++++++++++ src/bootsupport/modules/punk/repl-0.1.2.tm | 5 +- src/modules/punk/repl-999999.0a1.0.tm | 5 +- .../modules/include_modules.config | 1 + .../modules/punk/args/tclcore-0.1.0.tm | 6539 +++++++++++++++++ .../bootsupport/modules/punk/repl-0.1.2.tm | 5 +- .../modules/include_modules.config | 1 + .../modules/punk/args/tclcore-0.1.0.tm | 6539 +++++++++++++++++ .../bootsupport/modules/punk/repl-0.1.2.tm | 5 +- .../_vfscommon.vfs/modules/punk/repl-0.1.2.tm | 5 +- 11 files changed, 19630 insertions(+), 15 deletions(-) create mode 100644 src/bootsupport/modules/punk/args/tclcore-0.1.0.tm create mode 100644 src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/args/tclcore-0.1.0.tm create mode 100644 src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/args/tclcore-0.1.0.tm diff --git a/src/bootsupport/modules/include_modules.config b/src/bootsupport/modules/include_modules.config index ef4b719e..08bd00db 100644 --- a/src/bootsupport/modules/include_modules.config +++ b/src/bootsupport/modules/include_modules.config @@ -50,6 +50,7 @@ set bootsupport_modules [list\ modules punk::ansi\ modules punk::assertion\ modules punk::args\ + modules punk::args::tclcore\ modules punk::cap\ modules punk::cap::handlers::caphandler\ modules punk::cap::handlers::scriptlibs\ diff --git a/src/bootsupport/modules/punk/args/tclcore-0.1.0.tm b/src/bootsupport/modules/punk/args/tclcore-0.1.0.tm new file mode 100644 index 00000000..5eb1a6ea --- /dev/null +++ b/src/bootsupport/modules/punk/args/tclcore-0.1.0.tm @@ -0,0 +1,6539 @@ +# -*- tcl -*- +# Maintenance Instruction: leave the 999999.xxx.x as is and use punkshell 'dev make' or bin/punkmake to update from -buildversion.txt +# module template: punkshell/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 punk::args::tclcore 0.1.0 +# Meta platform tcl +# Meta license MIT +# @@ Meta End + + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +# doctools header +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +#*** !doctools +#[manpage_begin punkshell_module_punk::args::tclcore 0 0.1.0] +#[copyright "2025"] +#[titledesc {punk::args definitions for tcl core commands}] [comment {-- Name section and table of contents description --}] +#[moddesc {tcl core argument definitions}] [comment {-- Description at end of page heading --}] +#[require punk::args::tclcore] +#[keywords module] +#[description] +#[para] - + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + +#*** !doctools +#[section Overview] +#[para] overview of punk::args::tclcore +#[subsection Concepts] +#[para] - + + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +## Requirements +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + +#*** !doctools +#[subsection dependencies] +#[para] packages used by punk::args::tclcore +#[list_begin itemized] + +package require Tcl 8.6- +package require punk::args +package require punk::ansi +package require textblock +#*** !doctools +#[item] [package {Tcl 8.6}] +#[item] [package {punk::args}] +#[item] [package {textblock}] + +#*** !doctools +#[list_end] + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ + +#*** !doctools +#[section API] + + +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +# Base namespace +# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +tcl::namespace::eval punk::args::tclcore { + tcl::namespace::export {[a-z]*} ;# Convention: export all lowercase + #variable xyz + + #for tcllib - we can potentially parse the doctools to get this info. + #for tcl core commands - the data is stored in man pages - which are not so easy to parse. + #todo - link to man pages + + + #TODO - + #if we want colour in arg definitions -we need to respect nocolor or change colour to off/ on + #If color included in a definition - it will need to be reloaded when colour toggled(?) + #if {[catch {package require punk::ansi}]} { + # set has_punkansi 0 + # set A_WARN "" + # set A_RST "" + #} else { + # set has_punkansi 1 + # set A_WARN [a+ red] + # set A_RST "\x1b\[0m" + #} + + #we can't just strip ansi as there are non colour codes such as hyperlink that should be maintained whether color is on or off. + #for now we can use reverse - (like underline, is a non-colour attribute that remains effective when color off in punk::ansi) + set A_WARN \x1b\[7m + set A_RST \x1b\[0m + + variable manbase_tcl + variable manbase_ext + set patch [info patchlevel] + lassign [split $patch .] major + if {$major < 9} { + set manbase_tcl "https://tcl.tk/man/tcl/TclCmd" + set manbase_ext .htm + } else { + set manbase_tcl "https://tcl.tk/man/tcl9.0/TclCmd" + set manbase_ext .html + } + proc manpage_tcl {cmd} { + variable manbase_tcl + variable manbase_ext + return ${manbase_tcl}/${cmd}${manbase_ext} + } + + variable PUNKARGS + + namespace eval argdoc { + tcl::namespace::import ::punk::ansi::a+ + tcl::namespace::import ::punk::args::tclcore::manpage_tcl + # -- --- --- --- --- + #non colour SGR codes + # we can use these directly via ${$I} etc without marking a definition with @dynamic + #This is because they don't need to change when colour switched on and off. + set I [a+ italic] + set NI [a+ noitalic] + set B [a+ bold] + set N [a+ normal] + # -- --- --- --- --- + proc example {str} { + set str [string trimleft $str \n] + set block [punk::ansi::ansiwrap Web-gray [textblock::frame -ansibase [a+ Web-gray bold white] -ansiborder [a+ black White] -boxlimits {hl} -type block $str]] + set result [textblock::bookend_lines $block [a] "[a defaultbg] [a]"] + #puts $result + return $result + } + } + + + namespace eval argdoc { + variable PUNKARGS + + lappend PUNKARGS [list { + @id -id ::punk::args::tclcore::argdoc::ensemble_subcommands_definition + @cmd -name ::punk::args::tclcore::argdoc::ensemble_subcommands_definition -help\ + "Helper function to return a punk::args definition snippet for subcommands" + @leaders -max 0 -min 0 + -groupdict -default {} -type dict -help\ + "Dictionary keyed on arbitrary groupname, where value + is a list of known subcommands that should be displayed + by groupname. Each groupname forms the title of a subtable + in the choices list. + Subcommands not assigned to a groupname will appear first + in an untitled subtable." + -columns -default 4 -type integer -help\ + "Max number of columns for all subtables in the choices + display area" + @values -min 1 -max 1 + ensemble -optional 0 -help\ + "Name of ensemble command" + + }] + proc ensemble_subcommands_definition {args} { + #args manually parsed - with use of argdef for unhappy-path only + if {![llength $args]} { + #punk::args::get_by_id ::punk::args::tclcore::argdoc::ensemble_subcommands_definition $args + punk::args::parse $args -errorstyle minimal withid ::punk::args::tclcore::argdoc::ensemble_subcommands_definition + return + } + set ensemble [lindex $args end] + set optlist [lrange $args 0 end-1] + if {[llength $optlist] % 2} { + #punk::args::get_by_id ::punk::args::tclcore::argdoc::ensemble_subcommands_definition $args + punk::args::parse $args -errorstyle minimal withid ::punk::args::tclcore::argdoc::ensemble_subcommands_definition + return + } + set defaults [dict create\ + -groupdict {}\ + -columns 4\ + ] + set optlist [dict merge $defaults $optlist] + dict for {k v} $optlist { + switch -- $k { + -groupdict - -columns {} + default { + #punk::args::get_by_id ::punk::args::tclcore::argdoc::ensemble_subcommands_definition $args + punk::args::parse $args -errorstyle minimal withid ::punk::args::tclcore::argdoc::ensemble_subcommands_definition + return + } + } + } + set opt_groupdict [dict get $optlist -groupdict] + set opt_columns [dict get $optlist -columns] + + package require punk::ns + set subdict [punk::ns::ensemble_subcommands -return dict $ensemble] + set allsubs [dict keys $subdict] + # ---------------------------------------------- + # manually defined group members may have subcommands that are obsoleted/missing + # we choose to make the situation obvious by re-classifying into a corresponding group with the " - MISSING" suffix + set checked_groupdict [dict create] + dict for {g members} $opt_groupdict { + set validmembers {} + set invalidmembers {} + foreach m $members { + if {$m in $allsubs} { + lappend validmembers $m + } else { + lappend invalidmembers $m + } + } + dict set checked_groupdict $g $validmembers + if {[llength $invalidmembers]} { + dict set checked_groupdict "${g}_MISSING" $invalidmembers + } + } + if {[dict exists $checked_groupdict ""]} { + set others [dict get $checked_groupdict ""] + dict unset checked_groupdict "" + } else { + set others [list] + } + + #REVIEW + set debug 0 + if {$debug} { + puts "punk::args::tclcore::argdoc::ensemble_subcommands_definition" + if {[catch { + ::punk::lib::pdict checked_groupdict + } msg]} { + puts stderr "punk::args::tclcore::ensemble_subcommands_definition Cannot call pdict\n$msg" + } + puts -------------------- + puts "$checked_groupdict" + puts -------------------- + } + + set opt_groupdict $checked_groupdict + # ---------------------------------------------- + set allgrouped [list] + dict for {g members} $opt_groupdict { + lappend allgrouped {*}$members + } + set choiceinfodict [dict create] + foreach {sc cmd} $subdict { + if {$sc ni $allgrouped} { + if {$sc ni $others} { + lappend others $sc + } + } + set cinfo [punk::ns::resolve_command {*}$cmd] + set tp [dict get $cinfo cmdtype] + + dict set choiceinfodict $sc [list [list resolved $cmd]] + + switch -- $tp { + ensemble - native { + dict lappend choiceinfodict $sc [list doctype $tp] + } + object { + dict lappend choiceinfodict $sc [list doctype oo] + } + } + + if {[punk::args::id_exists [dict get $cinfo origin]] || [punk::args::id_exists [list $ensemble $sc]]} { + dict lappend choiceinfodict $sc {doctype punkargs} + } + } + + set argdef "" + append argdef "subcommand -choicegroups \{" \n + append argdef " \"\" \{$others\}" \n + dict for {g members} $opt_groupdict { + append argdef " \"$g\" \{$members\}" \n + } + append argdef " \} -choicecolumns $opt_columns -choiceinfo {$choiceinfodict}" \n + + #todo -choicelabels + #detect subcommand further info available e.g if oo or ensemble or punk::args id exists.. + #consider a different mechanism to add a label on rhs of same line as choice (for (i) marker) + + return $argdef + } + } + + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- + # + # library commands loaded via auto_index + # + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + namespace eval argdoc { + lappend PUNKARGS [list { + @id -id ::parray + @cmd -name "Built-in: parray" -help\ + "Prints on standard output the names and values of all the elements in the + array arrayName, or just the names that match pattern (using the matching + rules of string_match) and their values if pattern is given. + ArrayName must be an array accessible to the caller of parray. It may either + be local or global. The result of this command is the empty string. + (loaded via auto_index)" + @values -min 1 -max 2 + arrayName -type string -help\ + "variable name of an array" + pattern -type string -optional 1 -help\ + "Match pattern possibly containing glob characters" + } "@doc -name Manpage: -url [manpage_tcl library]" ] + + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + lappend PUNKARGS [list { + @id -id ::foreachLine + @cmd -name "Built-in: foreachLine" -help\ + "This reads in the text file named ${$I}filename${$NI} one line at a time (using system + defaults for reading text files). It writes that line to the variable named + by ${$I}varName${$NI} and then executes ${$I}body${$NI} for that line. The result value of ${$I}body${$NI} is + ignored, but error, return, break and continue may be used within it to + produce an error, return from the calling context, stop the loop, or go to + the next line respectively. The overall result of ${$B}foreachLine${$N} is the empty + string (assuming no errors from I/O or from evaluating the body of the loop); + the file will be closed prior to the procedure returning." + @values -min 3 -max 3 + varName + fileName + body + } "@doc -name Manpage: -url [manpage_tcl library]" ] + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + lappend PUNKARGS [list { + @id -id ::readFile + @cmd -name "Built-in: readFile" -help\ + "Reads in the file named in ${$I}filename${$NI} and returns its contents. The second + argument says how to read in the file, either as ${$B}text${$N} (using the system + defaults for reading text files) or as ${$B}binary${$N} (as uninterpreted bytes). + The default is ${$B}text${$N}. When read as text, this will include any trailing + newline. The file will be closed prior to the procedure returning." + @values -min 1 -max 2 + fileName + #todo punk::args::synopsis - show prefix highlighting + mode -type literalprefix(text)|literalprefix(binary) -optional 1 + #test + #mode -type {{literalprefix text | literalprefix binary}} + } "@doc -name Manpage: -url [manpage_tcl library]" ] + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + lappend PUNKARGS [list { + @id -id ::writeFile + @cmd -name "Built-in: writeFile" -help\ + "Writes the contents to the file named in ${$I}filename${$NI}. The optional second + argument says how to write to the file, either as ${$B}text${$N} (using the system + defaults for writing text files) or as ${$B}binary${$N} (as uninterpreted bytes). + The default is ${$B}text${$N}. If a trailing newline is required, it will need to + be provided in ${$I}contents${$NI}. The result of this command is the empty string; + the file will be closed prior to the procedure returning." + @values -min 2 -max 3 + fileName + mode -type literalprefix(text)|literalprefix(binary) -optional 1 + contents + } "@doc -name Manpage: -url [manpage_tcl library]" ] + + } + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- + # (end of auto_index commands) + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- + + + namespace eval argdoc { + punk::args::define { + @id -id ::tcl::info::args + @cmd -name "Built-in: tcl::info::args" -help\ + "Returns the names of the parameters to the procedure named ${$I}procname${$NI}." + @values -min 1 -max 1 + procname -type string -optional 0 + } "@doc -name Manpage: -url [punk::args::tclcore::manpage_tcl info]" + + punk::args::define { + @id -id ::tcl::info::body + @cmd -name "Built-in: tcl::info::body" -help\ + "Returns the body procedure named ${$I}procname${$NI}." + @values -min 1 -max 1 + procname -type string -optional 0 + } "@doc -name Manpage: -url [punk::args::tclcore::manpage_tcl info]" + + punk::args::define { + @id -id ::tcl::info::default + @cmd -name "Built-in: tcl::info::default" -help\ + "If the parameter ${$I}parameter${$NI} for the procedure named ${$I}procname${$NI} + has a default value, stores that value in ${$I}varname${$NI} and returns ${$B}1${$N}. + Otherwise, returns ${$B}0${$N}." + @values -min 3 -max 3 + procname -type string -optional 0 + parameter + varname + } "@doc -name Manpage: -url [punk::args::tclcore::manpage_tcl info]" + + punk::args::define { + @id -id ::tcl::info::cmdtype + @cmd -name "Built-in: tcl::info::cmdtype" -help\ + "Returns the type of the command named ${$I}commandName${$NI}. + Built-in types are: + ${$B}alias${$N} + ${$I}commandName${$NI} was created by 'interp alias'. In a safe interpreter an + alias is only visible if both the alias and the target are visible. + ${$B}coroutine${$N} + ${$I}commandName${$NI} was created by 'coroutine'. + ${$B}ensemble${$N} + ${$I}commandName${$NI} was created by 'namespace ensemble'. + ${$B}import${$N} + ${$I}commandName${$NI} was created by 'namespace import'. + ${$B}native${$N} + ${$I}commandName${$NI} was created by the 'Tcl_CreateObjCommand' interface + directly without further registration of the type of command. + ${$B}object${$N} + ${$I}commandName${$NI} is the public comand that represents an instance + of oo::object or one of its subclasses. + ${$B}privateObject${$N} + ${$I}commandName${$NI} is the private command, my by default, + that represents an instance of oo::object or one of its subclasses. + ${$B}proc${$N} + ${$I}commandName${$NI} was created by 'proc'. + ${$B}interp${$N} + ${$I}commandName${$NI} was created by 'interp create'. + ${$B}zlibStream${$N} + ${$I}commandName${$NI} was created by 'zlib stream'. + " + @values -min 1 -max 1 + commandName -type string + } "@doc -name Manpage: -url [punk::args::tclcore::manpage_tcl info]" + + punk::args::define { + @id -id ::oo::InfoObject::call + @cmd -name "Built-in: oo::InfoObject::call" -help\ + "Returns a description of the method implementations that are used to provide + ${$I}object's${$NI} implementation of ${$I}method${$NI}. This consists of a + list of lists of four elements, where each sublist consists of: + element 0: a word that describes the general type of method implementation, being + one of + ${$B}method${$N} for an ordinary method, ${$B}filter${$N} for an applied filter, + ${$B}private${$N} for a private method, and ${$B}unknown${$N} for a method that + is invoked as part of unknown method handling. + element 1: a word giving the name of the particular method invoked (which is always + the same as method for the ${$B}method${$N} type, and \"${$B}unknown${$N}\" + for the ${$B}unknown${$N} type) + element 2: a word giving what defined the method (the fully qualified name of the + class, or the literal string ${$B}object${$N} if the method implementation is on + an instance) + element 3: a word describing the type of method implementation + (see ${$B}info object methodtype${$N} + + Note that there is no inspection of whether the method implementations actually use + ${$B}next${$N} to transfer control along the call chain, and the call chains that + this command files do not actually contain private methods." + @values -min 2 -max 2 + object + method + } "@doc -name Manpage: -url [manpage_tcl info]" + + proc info_subcommands {} { + #package require punk::ns + #set subdict [punk::ns::ensemble_subcommands -return dict info] + #set allsubs [dict keys $subdict] + dict set groups "system" {hostname library nameofexecutable patchlevel script sharedlibextension tclversion} + dict set groups "proc introspection" {args body default} + dict set groups "variables" {constant consts exists globals locals vars} + dict set groups "oo object introspection" {class object} + + return [ensemble_subcommands_definition -groupdict $groups -columns 4 info] + } + set DYN_INFO_SUBCOMMANDS {${[punk::args::tclcore::argdoc::info_subcommands]}} + lappend PUNKARGS [list { + @dynamic + @id -id ::info + @cmd -name "Built-in: info" -help\ + "Information about the state of the Tcl interpreter" + @leaders -min 1 -max 1 + ${$DYN_INFO_SUBCOMMANDS} + @values -min 0 + + } "@doc -name Manpage: -url [punk::args::tclcore::manpage_tcl array]" ] + } + + + + #An idiom for sharing common features - incomplete - todo work out what happens with (default)::id that has leaders,opts,values + #todo @cmd -help+ text (append to existing help that came from a default?) + lappend PUNKARGS [list { + @id -id "(default)::tcl::binary::*::base64" + @cmd -help\ + "The base64 binary encoding is commonly used in mail messages and XML documents, + and uses mostly upper and lower case letters and digits. It has the distinction + of being able to be rewrapped arbitrarily without losing information. + " + } "@doc -name Manpage: -url [manpage_tcl binary]" ] + lappend PUNKARGS [list { + @id -id "::tcl::binary::encode::base64" + @default -id (default)::tcl::binary::*::base64 + @cmd -name "binary encode base64" + -maxlen -type integer -help\ + "Indicates that the output should be split into lines of no more than length + characters. By default, lines are not split." + -wrapchar -type character -default \n -help\ + "Indicates that, when lines are split because of the -maxlen option, character + should be used to separate lines. By default, this is a newline character, \"\\n\"." + @values -min 1 -max 1 + data -type string + } ] + lappend PUNKARGS [list { + @id -id "::tcl::binary::decode::base64" + @default -id (default)::tcl::binary::*::base64 + @cmd -name "binary decode base64" + -strict -type none -help\ + "Instructs the decoder to throw an error if it encounters any characters that + are not strictly part of the encoding itself. Otherwise it ignores them. + RFC 2045 calls for base64 decoders to be non-strict." + @values -min 1 -max 1 + data -type string + } ] + + + lappend PUNKARGS [list { + @id -id "(default)::tcl::binary::*::hex" + @cmd -help\ + "The hex binary encoding converts each byte to a pair of hexadecimal digits + that represent the byte value as a hexadecimal integer. When encoding, lower + characters are used. When decoding, upper and lower characters are accepted." + } "@doc -name Manpage: -url [manpage_tcl binary]" ] + lappend PUNKARGS [list { + @id -id "::tcl::binary::encode::hex" + @default -id (default)::tcl::binary::*::hex + @cmd -name "binary encode hex" + @values -min 1 -max 1 + data -type string + } ] + lappend PUNKARGS [list { + @id -id "::tcl::binary::decode::hex" + @default -id (default)::tcl::binary::*::hex + @cmd -name "binary encode hex" + -strict -type none -help\ + "Instructs the decoder to throw an error if it encounters whitespace + characters. Otherwise it ignores them." + @values -min 1 -max 1 + data -type string + }] + + + lappend PUNKARGS [list { + @id -id "(default)::tcl::binary::*::uuencode" + @cmd -help\ + "The uuencode binary encoding used to be common for transfer of data between Unix + systems and on USENT, but is less common these days, having been largely + superseded by the base64 binary encoding. + Note that neither the encoder nor the decoder handle the header and footer of the + uuencode format." + } "@doc -name Manpage: -url [manpage_tcl binary]" ] + lappend PUNKARGS [list { + @id -id "::tcl::binary::encode::uuencode" + @default -id (default)::tcl::binary::*::uuencode + #todo @cmd -help+ "Changing the options may produce files that other implementations of decoders cannot process" + @cmd -name "binary encode uuencode" + -maxlen -type integer -default 61 -range {5 85} -help\ + "Indicates the maximum number of characters to produce for each encoded line. + The valid range is 5 to 85. Line lengths outside that range cannot be + accommodated by the encoding format." + -wrapchar -type string -default \n -help\ + "Indicates the character(s) to use to mark the end of each encoded line. + Acceptable values are a sequence of zero or more character from the set + { \\x09 (TAB), \\x0B (VT), \\x0C (FF), \\x0D (CR) } followed by zero or + one newline \\x0A (LF). Any other values are rejected because they would + generate encoded text that could not be decoded. The default value is a + single newline. + " + @values -min 1 -max 1 + data -type string + } ] + lappend PUNKARGS [list { + @id -id "::tcl::binary::decode::uuencode" + @default -id (default)::tcl::binary::*::uuencode + @cmd -name "binary decode uuencode" + -strict -type none -help\ + "Instructs the decoder to throw an error if it encounters anything outside + of the standard encoding format. Without this option, the decoder tolerates + some deviations, mostly to forgive reflows of lines between the encoder and + decoder." + @values -min 1 -max 1 + data -type string + } ] + + namespace eval argdoc { + lappend PUNKARGS [list { + @id -id "::tcl::encoding::dirs" + @cmd -name "encoding dirs" -help\ + "Tcl can load encoding data files from the file system that describe + additional encodings for it to work with. This command sets the search + path for ${$B}*.enc${$N} encoding data files to the list of directories + ${$I}directoryList${$NI}. If ${$I}directoryList${$NI} is omitted then the + command returns the current list of directories that make up the search + path. It is an error for ${$I}directoryList${$NI} to not be a valid list. + If, when a search for an encoding data file is happening, an element in + ${$I}directoryList${$NI} does not refer to a readable, searchable + directory, that element is ignored." + @values -min 0 -max 1 + directoryList -optional 1 -type list + } "@doc -name Manpage: -url [manpage_tcl encoding]" ] + } + + lappend PUNKARGS [list { + @id -id ::time + @cmd -name "Built-in: time" -help\ + "Calls the Tcl interpreter count times to evaluate script + (or once if count is not specified). It will then return + a string of the form + 503.2 microseconds per iteration + which indicates the average amount of time required per + iteration, in microseconds. Time is measured in elapsed + time, not CPU time. + (see also: timerate)" + @values -min 1 -max 2 + script -type script + count -type integer -default 1 -optional 1 + } "@doc -name Manpage: -url [manpage_tcl time]" ] + + namespace eval argdoc { + lappend PUNKARGS [list { + @id -id ::tcl::chan::blocked + @cmd -name "Built-in: tcl::chan::blocked" -help\ + "This tests whether the last input operation on the channel called ${$I}channel${$NI} + failed because it would otherwise have caused the process to block, and returns 1 + if that was the case. It returns 0 otherwise. Note that this only ever returns 1 + when the channel has been configured to be non-blocking; all Tcl channels have + blocking turned on by default" + @values -min 1 -max 1 + channel -help \ + "" + } "@doc -name Manpage: -url [manpage_tcl chan]" ] + + lappend PUNKARGS [list { + @id -id ::tcl::chan::close + @cmd -name "Built-in: tcl::chan::close" -help\ + "Close and destroy the channel called channel. Note that this deletes all existing file-events + registered on the channel. If the direction argument (which must be read or write or any + unique abbreviation of them) is present, the channel will only be half-closed, so that it can + go from being read-write to write-only or read-only respectively. If a read-only channel is + closed for reading, it is the same as if the channel is fully closed, and respectively similar + for write-only channels. Without the direction argument, the channel is closed for both reading + and writing (but only if those directions are currently open). It is an error to close a + read-only channel for writing, or a write-only channel for reading. + As part of closing the channel, all buffered output is flushed to the channel's output device + (only if the channel is ceasing to be writable), any buffered input is discarded (only if the + channel is ceasing to be readable), the underlying operating system resource is closed and + channel becomes unavailable for future use (both only if the channel is being completely closed). + + If the channel is blocking and the channel is ceasing to be writable, the command does not return + until all output is flushed. If the channel is non-blocking and there is unflushed output, the + channel remains open and the command returns immediately; output will be flushed in the + background and the channel will be closed when all the flushing is complete. + + If channel is a blocking channel for a command pipeline then chan close waits for the child + processes to complete. + + If the channel is shared between interpreters, then chan close makes channel unavailable in the + invoking interpreter but has no other effect until all of the sharing interpreters have closed the + channel. When the last interpreter in which the channel is registered invokes chan close (or close), + the cleanup actions described above occur. With half-closing, the half-close of the channel only + applies to the current interpreter's view of the channel until all channels have closed it in that + direction (or completely). See the interp command for a description of channel sharing. + + Channels are automatically fully closed when an interpreter is destroyed and when the process exits. + Channels are switched to blocking mode, to ensure that all output is correctly flushed before the + process exits. + + The command returns an empty string, and may generate an error if an error occurs while flushing + output. If a command in a command pipeline created with open returns an error, chan close generates + an error (similar to the exec command.) + + Note that half-closes of sockets and command pipelines can have important side effects because they + result in a shutdown() or close() of the underlying system resource, which can change how other + processes or systems respond to the Tcl program. + + Channels are automatically closed when an interpreter is destroyed and when the process exits. + From 8.6 on (TIP#398), nonblocking channels are no longer switched to blocking mode when exiting; + this guarantees a timely exit even when the peer or a communication channel is stalled. To ensure + proper flushing of stalled nonblocking channels on exit, one must now either (a) actively switch + them back to blocking or (b) use the environment variable TCL_FLUSH_NONBLOCKING_ON_EXIT, which when + set and not equal to “0” restores the previous behavior." + @values -min 1 -max 1 + channel + direction -optional 1 -choices {read write} + } "@doc -name Manpage: -url [manpage_tcl chan]" ] + + lappend PUNKARGS [list { + @id -id ::fconfigure + @cmd -name "Built-in: chan configure" -help\ + "Query or set the configuration options of the channel named ${$I}channel${$NI} + If no ${$I}optionName${$NI} or ${$I}value${$NI} arguments are supplied, the + command returns a list containing alternating option names and values for the + channel. If ${$I}optionName${$NI} is supplied but no ${$I}value${$NI} then the + command returns the current value of the given option. If one or more pairs + of ${$I}optionName${$NI} and ${$I}value${$NI} are supplied, the command sets each + of the named options to the corresponding value; in this case the return + value is an empty string. + + The options described below are supported for all channels. In addition, each + channel type may add options that only it supports. See the manual entry for + the command that creates each type of channel for the options supported by + that specific type of channel. For example, see the manual entry for the + ${$B}socket${$N} command for additional options for sockets, and the ${$B}open${$N} + command for additional options for serial devices. + ${$B}-blocking${$N} ${$I}boolean${$NI} + The ${$B}-blocking${$N} option determines whether I/O operations on the + channel can cause the process to block indefinitely. The value of the + option must be a proper boolean value. Channels are normally in blocking + mode; if a channel is placed into non-blocking mode it will affect the + operation of the ${$B}chan gets, chan read, chan puts, chan flush,${$N} + and ${$B}chan close${$N} commands; see the documentation for those + commands for details. For non-blocking mode to work correctly, the + application must be using the Tcl event loop (e.g. by calling + ${$B}Tcl_DoOneEvent${$N} or invoking the ${$B}vwait${$N} command). + ${$B}-buffering${$N} ${$I}newValue${$NI} + If ${$I}newValue${$NI} is ${$B}full${$N} then the I/O system will buffer output until its + internal buffer is full or until the ${$B}chan flush${$N} command is invoked. If + ${$I}newValue${$NI} is ${$B}line${$N}, then the I/O system will automatically flush output for + the channel whenever a newline character is output. If ${$I}newValue${$NI} is ${$B}none${$N}, + the I/O system will flush automatically after every output operation. The + default is for ${$B}-buffering${$N} to be set to ${$B}full${$N} except for channels that + connect to terminal-like devices; for these channels the initial setting + is ${$B}line${$N}. Additionally, ${$B}stdin${$N} and ${$B}stdout${$N} are initially set to ${$B}line${$N}, and + ${$B}stderr${$N} is set to ${$B}none${$N}. + ${$B}-buffersize${$N} ${$I}newSize${$NI} + ${$I}newSize${$NI} must be an integer; its value is used to set the size of buffers, + in bytes, subsequently allocated for this channel to store input or output. + ${$I}newSize${$NI} must be a number of no more than one million, allowing buffers of + up to one million bytes in size. + ${$B}-encoding${$N} ${$I}name${$NI} + + ${$B}-eofchar${$N} ${$I}char${$NI} + + ${$B}-profile${$N} ${$I}profile${$NI} + + ${$B}-translation${$N} ${$I}translation${$NI}" + + @form -form {getall} + @values -min 1 -max 1 + channel + @form -form {getone} + @values -min 2 -max 2 + channel + optionName + + @form -form {set} + @values -min 3 -max -1 + channel + "optionName value" -type {string any} -typesynopsis {${$I}optionName value${$NI}} -multiple 1 -optional 0 + + } "@doc -name Manpage: -url [manpage_tcl chan]" ] + + + + lappend PUNKARGS [list { + @id -id ::tcl::chan::eof + @cmd -name "Built-in: tcl::chan::eof"\ + -summary\ + "Check for end of file condition on channel"\ + -help\ + "Test whether the last input operation on the channel called ${$I}channel${$NI} + failed because the end of the data stream was reached, returning 1 if end-of-file + was reached, and 0 otherwise." + @values -min 1 -max 1 + channel -help \ + "" + } "@doc -name Manpage: -url [manpage_tcl chan]" ] + + #event + lappend PUNKARGS [list { + @id -id ::tcl::chan::flush + @cmd -name "Built-in: tcl::chan::flush"\ + -summary\ + "Flush pending output."\ + -help\ + "Ensures that all pending output for the channel called channel is written. + If the channel is in blocking mode the command does not return until all the buffered output + has been flushed to the channel. If the channel is in non-blocking mode, the command may + return before all buffered output has been flushed; the remainder will be flushed in the + background as fast as the underlying file or device is able to absorb it." + @values -min 1 -max 1 + channel + } "@doc -name Manpage: -url [manpage_tcl chan]" ] + + lappend PUNKARGS [list { + @id -id ::tcl::chan::gets + @cmd -name "Built-in: tcl::chan::gets"\ + -summary\ + "Read a line from channel."\ + -help\ + "Reads a line from the channel consisting of all characters up to the next end-of-line sequence + or until end of file is seen. The line feed character corresponding to end-of-line sequence is + not included as part of the line. If the varName argument is specified, the line is stored in + the variable of that name and the command returns the length of the line. If varName is not + specified, the command returns the line itself as the result of the command. + If a complete line is not available and the channel is not at EOF, the command will block in the + case of a blocking channel. For non-blocking channels, the command will return the empty string + as the result in the case of varName not specified and -1 if it is. + + If a blocking channel is already at EOF, the command returns an empty string if varName is not + specified. Note an empty string result can also be returned when a blank line (no characters + before the next end of line sequence). The two cases can be distinguished by calling the chan eof + command to check for end of file. If varName is specified, the command returns -1 on end of file. + There is no ambiguity in this case because blank lines result in 0 being returned. + + If a non-blocking channel is already at EOF, the command returns an empty line if varName is not + specified. This can be distinguished from an empty line being returned by either a blank line + being read or a full line not being available through the use of the chan eof and chan blocked + commands. If chan eof returns true, the channel is at EOF. If chan blocked returns true, a full + line was not available. If both commands return false, an empty line was read. If varName was + specified for a non-bocking channel at EOF, the command returns -1. This can be distinguished + from full line not being available either by chan eof or chan blocked as above. Note that when + varName is specified, there is no need to distinguish between eof and blank lines as the latter + will result in the command returning 0. + + If the encoding profile strict is in effect for the channel, the command will raise an exception + with the POSIX error code EILSEQ if any encoding errors are encountered in the channel input data. + The file pointer remains unchanged and it is possible to introspect, and in some cases recover, by + changing the encoding in use" + @values -min 1 -max 2 + channel + varName -optional 1 + } "@doc -name Manpage: -url [manpage_tcl chan]" ] + #isbinary + #names + #pending + lappend PUNKARGS [list { + @id -id ::tcl::chan::pipe + @cmd -name "Built-in: tcl::chan::pipe"\ + -summary\ + "Create a standalone pipe."\ + -help\ + "Creates a standalone pipe whose read- and write-side channels are returned + as a 2-element list, the first element being the read side and the second + write side. Can be useful e.g. to redirect separately ${$B}stderr${$N} and ${$B}stdout${$N} + from a subprocess. To do this spawn with \"2>@\" or \">@\" redirection + operators onto the write side of a pipe, and then immediately close it + in the parent. This is necessary to get an EOF on the read side once the + child has exited or otherwise closed its output. + Note that the pipe buffering semantics can vary at the operating system + level substantially; it is not safe to assume that a write performed on + the output side of the pipe will appear instantly to the input side. + This is a fundamental difference and Tcl cannot conceal it. The overall + stream semantics ${$I}are${$NI} compatible, so blocking reads and writes + will not see most of the differences, but the details of what exactly gets + written when are not. This is most likely to show up when using pipelines + for testing; care should be taken to ensure that deadlocks do not occur + and that potential short reads are allowed for." + @values -min 0 -max 0 + } "@doc -name Manpage: -url [manpage_tcl chan]" ] + + lappend PUNKARGS [list { + @id -id ::tcl::chan::pop + @cmd -name "Built-in: tcl::chan::pop"\ + -summary\ + "Remove topmost channel transform."\ + -help\ + "Removes the topmost transformation from the channel ${$I}channel${$NI}, if there is any. + If there are no transformations added to channel, this is equivalent to + ${$B}chan${$N} close of that channel. The result is normally the empty string, but can + be an error in some situations (i.e. where the underlying system stream is + closed and that results in an error)." + @values -min 1 -max 1 + channel -type string + } "@doc -name Manpage: -url [manpage_tcl chan]" ] + + lappend PUNKARGS [list { + @id -id ::tcl::chan::puts + @cmd -name "Built-in: tcl::chan::puts"\ + -summary\ + "Write to a channel."\ + -help\ + "Writes ${$I}string${$NI} to the channel named ${$I}channel${$NI} followed by a newline character. A + trailing newline character is written unless the optional flag ${$B}-nonewline${$N} is + given. If channel is omitted, the string is written to the standard output + channel, ${$B}stdout${$N}. + Newline characters in the output are translated by ${$B}chan puts${$N} to platform-specific + end-of-line sequences according to the currently configured value of the + ${$B}-translation${$N} option for the channel (for example, on PCs newlines are normally + replaced with carriage-return-linefeed sequences; see ${$B}chan configure${$N} for details). + + Tcl buffers output internally, so characters written with ${$B}chan puts${$N} may not appear + immediately on the output file or device; Tcl will normally delay output until the + buffer is full or the channel is closed. You can force output to appear + immediately with the ${$B}chan flush${$N} command. + + When the output buffer fills up, the ${$B}chan puts${$N} command will normally block until + all the buffered data has been accepted for output by the operating system. If + channel is in non-blocking mode then the ${$B}chan puts${$N} command will not block even if + the operating system cannot accept the data. Instead, Tcl continues to buffer the + data and writes it in the background as fast as the underlying file or device can + accept it. The application must use the Tcl event loop for non-blocking output to + work; otherwise Tcl never finds out that the file or device is ready for more + output data. It is possible for an arbitrarily large amount of data to be buffered + for a channel in non-blocking mode, which could consume a large amount of memory. + To avoid wasting memory, non-blocking I/O should normally be used in an + event-driven fashion with the ${$B}chan event${$N} command (do not invoke ${$B}chan puts${$N} unless + you have recently been notified via a file event that the channel is ready for more + output data). + + The command will raise an error exception with POSIX error code ${$B}EILSEQ${$N} if the + encoding profile ${$B}strict${$N} is in effect for the channel and the output data cannot be + encoded in the encoding configured for the channel. Data may be partially written + to the channel in this case." + @opts -prefix 0 + -nonewline -type none + @values -min 1 -max 2 + channel -type string -optional 1 + string -type string + } "@doc -name Manpage: -url [manpage_tcl chan]" ] + + } + + lappend PUNKARGS [list { + @id -id ::tcl::chan::read + @cmd -name "Built-in: tcl::chan::read"\ + -summary\ + "Read from a channel."\ + -help\ + "In the first form, the result will be the next numChars characters read from the channel named + channel; if numChars is omitted, all characters up to the point when the channel would signal a + failure (whether an end-of-file, blocked or other error condition) are read. In the second form + (i.e. when numChars has been omitted) the flag -nonewline may be given to indicate that any + trailing newline in the string that has been read should be trimmed. + If channel is in non-blocking mode, chan read may not read as many characters as requested: once + all available input has been read, the command will return the data that is available rather + than blocking for more input. If the channel is configured to use a multi-byte encoding, then + there may actually be some bytes remaining in the internal buffers that do not form a complete + character. These bytes will not be returned until a complete character is available or end-of-file + is reached. The -nonewline switch is ignored if the command returns before reaching the end of the + file. + + Chan read translates end-of-line sequences in the input into newline characters according to the + -translation option for the channel (see chan configure above for a discussion on the ways in + which chan configure will alter input). + + When reading from a serial port, most applications should configure the serial port channel to be + non-blocking, like this: + + chan configure channel -blocking 0 + + Then chan read behaves much like described above. Note that most serial ports are comparatively + slow; it is entirely possible to get a readable event for each character read from them. Care + must be taken when using chan read on blocking serial ports: + + chan read channel numChars + In this form chan read blocks until numChars have been received from the serial port. + chan read channel + In this form chan read blocks until the reception of the end-of-file character, see + chan configure -eofchar. If there no end-of-file character has been configured for the + channel, then chan read will block forever. + + If the encoding profile strict is in effect for the channel, the command will raise an exception + with the POSIX error code EILSEQ if any encoding errors are encountered in the channel input data. + If the channel is in blocking mode, the error is thrown after advancing the file pointer to the + beginning of the invalid data. The successfully decoded leading portion of the data prior to the + error location is returned as the value of the -data key of the error option dictionary. If the + channel is in non-blocking mode, the successfully decoded portion of data is returned by the + command without an error exception being raised. A subsequent read will start at the invalid data + and immediately raise a EILSEQ POSIX error exception. Unlike the blocking channel case, the -data + key is not present in the error option dictionary. In the case of exception thrown due to encoding + errors, it is possible to introspect, and in some cases recover, by changing the encoding in use. + See ENCODING ERROR EXAMPLES later." + + @form -form readchars + @values -min 1 -max 2 + channel + numChars -type integer -optional 1 + + @form -form read + @opts + -nonewline -type none + @values -min 1 -max 1 + channel + + } "@doc -name Manpage: -url [manpage_tcl chan]" ] + + lappend PUNKARGS [list { + @id -id ::tcl::chan::seek + @cmd -name "Built-in: tcl::chan::seek"\ + -summary\ + "Set channel access position as byte offset."\ + -help\ + "Sets the current access position within the underlying data stream for the channel named + channel to be offset bytes relative to origin. + Offset must be an integer (which may be negative) + The origin argument defaults to start. + + Chan seek flushes all buffered output for the channel before the command returns, even if the + channel is in non-blocking mode. It also discards any buffered and unread input. This command + returns an empty string. An error occurs if this command is applied to channels whose + underlying file or device does not support seeking. + + Note that offset values are byte offsets, not character offsets. Both chan seek and chan tell + operate in terms of bytes, not characters, unlike chan read." + @values -min 2 -max 3 + channel + offset -type integer + origin -type string\ + -default start\ + -optional 1\ + -choicecolumns 1\ + -choices {start current end}\ + -choicelabels { + start\ + " The new access position will be offset bytes from the start of the underlying file or device." + current\ + " The new access position will be offset bytes from the current access position; a negative + offset moves the access position backwards in the underlying file or device." + enc\ + " The new access position will be offset bytes from the end of the file or device. A negative + offset places the access position before the end of file, and a positive offset places the + access position after the end of file." + } + } "@doc -name Manpage: -url [manpage_tcl chan]" ] + + lappend PUNKARGS [list { + @id -id ::tcl::chan::tell + @cmd -name "Built-in: tcl::chan::tell"\ + -summary\ + "Report channel access position as byte offset."\ + -help\ + "Returns a number giving the current access position within the underlying + data stream for the channel named channel. This value returned is a byte + offset that can be passed to ${[a+ bold]}chan seek${[a+ normal]} in order + to set the channel to a particular position. Note that this value is in + terms of bytes, not characters like ${[a+ bold]}chan read${[a+ normal]}. The + value returned is -1 for channels that do not support seeking." + @values -min 1 -max 1 + channel -help \ + "" + } "@doc -name Manpage: -url [manpage_tcl chan]" ] + + + lappend PUNKARGS [list { + @id -id ::tcl::chan::truncate + @cmd -name "Built-in: tcl::chan::truncate"\ + -summary\ + "Truncate channel to specified length or current byte offset."\ + -help\ + "Sets the byte length of the underlying data stream for the channel to be + length (or to the current byte offset within the underlying data stream if + length is omitted). The channel is flushed before truncation." + #todo - auto synopsis? + #@form -synopsis\ + # "chan truncate channel ?length?" + @values -min 1 -max 2 + channel -help \ + "" + length -optional 1 -type integer + } "@doc -name Manpage: -url [manpage_tcl chan]" ] + + + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + #dict + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + namespace eval argdoc { + lappend PUNKARGS [list { + @id -id ::tcl::dict::append + @cmd -name "Built-in: tcl::dict::append" -help\ + "This appends the given string (or strings) to the value that the given + key maps to in the dictionary value contained in the given variable, + writing the resulting dictionary value back to that variable. Non-existant + keys are treated as if they map to an empty string. The updated dictionary + value is returned." + @values -min 2 -max -1 + dictionaryVariable -type string -help \ + "" + key + string -type string -optional 1 -multiple 1 + } "@doc -name Manpage: -url [manpage_tcl dict]" ] + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + lappend PUNKARGS [list { + @id -id ::tcl::dict::create + @cmd -name "Built-in: tcl::dict::create" -help\ + "Return a new dictionary that contains each of the key/value mappings listed + as arguments (keys and values alternating, with each key being followed by + its associated value)" + @values -min 2 -max -1 + "key value" -type {string string} -typesynopsis {${$I}key${$NI} ${$I}value${$NI}} -optional 1 -multiple 1 + } "@doc -name Manpage: -url [manpage_tcl dict]" ] + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + lappend PUNKARGS [list { + @id -id ::tcl::dict::exists + @cmd -name "Built-in: tcl::dict::exists" -help\ + "This returns a boolean value indicating whether the given key (or path of + keys through a set of nested dictionaries) exists in the given dictionary + value. This returns a true value exactly when ${$B}dict get${$N} on that path will + succeed." + @values -min 2 -max -1 + dictionaryValue -type dict + key -type string -multiple 1 -optional 0 + } "@doc -name Manpage: -url [manpage_tcl dict]" ] + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + lappend PUNKARGS [list { + @id -id ::tcl::dict::for + @cmd -name "Built-in: tcl::dict::for" -help\ + "This command takes three arguments, the first a two-element list of + variable names (for the key and value respectively of each mapping in + the dictionary), the second the dictionary value to iterate across, and + the third a script to be evaluated for each mapping with the key and + value variable set appropriately (in the manner of ${$B}foreach${$N}). + The result of the command is an empty string. If any evlauation of the + body generates a ${$B}TCL_BREAK${$N} result, no further pairs from the + dictionary will be iterated over and the ${$B}dict for${$N} command will + terminate successfully immediately. If any evaluation of the body generates + a ${$B}TCL_CONTINUE${$N} result, this shall be treated exactly like a + normal ${$B}TCL_OK${$N} result. The order of iteration is the order in which + the keys were inserted into the dictionary." + @values -min 3 -max 3 + "{keyVariable valueVariable}" -type list -minsize 2 -maxsize 2 + dictionaryValue -type dict + body -type string -help\ + "Tcl script" + } "@doc -name Manpage: -url [manpage_tcl dict]" ] + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + punk::args::define { + @id -id ::tcl::dict::get + @cmd -name "Built-in: tcl::dict::get" -help\ + "Given a dictionary value (first argument) and a key (second argument), this + will retrieve the value for that key. Where several keys are supplied, the + behaviour of the command shall be as if the result of ${$B}dict get $dictVal $key${$N} + was passed as the first argument to ${$B}dict get${$N} with the remaining + arguments as second (and possibly subsequent) arguments. This facilitates + lookups in nested dictionaries. For example, the following two commands are + equivalent: + ${[punk::args::tclcore::argdoc::example { + dict get $dict foo bar spong + dict get [dict get [dict get $dict foo] bar] spong\ + } + ]} + If no keys are provided, ${$B}dict get${$N} will return a list containing pairs + of elements in a manner similar to ${$B}array get${$N}. That is, the first + element of each pair would be the key and the second element would be the value + for that key. + It is an error to attempt to retrieve a value for a key that is not present in + the dictionary. + " + @values -min 1 -max -1 + dictionaryValue -type dict + key -type string -multiple 1 -optional 1 + } "@doc -name Manpage: -url [manpage_tcl dict]" + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + punk::args::define { + @id -id ::tcl::dict::getdef + @cmd -name "Built-in: tcl::dict::getdef" -help\ + "This behaves the same as ${$B}dict get${$N} (with at least one ${$I}key${$NI} argument), + returning the value that the key path maps to in the dictionary + ${$I}dictionaryValue${$NI}, except that instead of producing an error because the + ${$I}key${$NI} (or one of the ${$I}key${$NI}s on the key path) is absent, it returns the + ${$I}default${$NI} argument instead. + Note that there must always be at least one ${$I}key${$NI} provided, and that ${$B}dict getdef${$N} and + ${$B}dict getwithdefault${$N} are aliases for each other." + @values -min 1 -max -1 + dictionaryValue -type dict + key -type string -multiple 1 -optional 0 + default -type any -optional 0 + } "@doc -name Manpage: -url [manpage_tcl dict]" + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + #use getdef to define getwithdefault + punk::args::define [punk::args::resolved_def -override {@id { + -id ::tcl::dict::getwithdefault + } @cmd { + -name "Built-in: tcl::dict::getwithdefault" + }} ::tcl::dict::getdef] + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + lappend PUNKARGS [list { + @id -id ::tcl::dict::incr + @cmd -name "Built-in: tcl::dict::incr" -help\ + "This adds the given ${$I}increment${$NI} value (an integer that defaults to 1 if + not specified) to the value that the given key maps to in the dictionary + value contained in the given variable, writing the resulting dictionary + value back to that variable. Non-existent keys are treated as if they + map to 0. It is an error to increment a value for an existing key if that + value is not an integer. The updated dictionary value is returned. If + ${$I}dictionaryVariable${$NI} indicates an element that does not exist of an array + that has a default value set, the default value and will be used as the + value of the dictionary prior to the incrementing operation." + @values -min 2 -max 3 + dictionaryVariable -type string + key -type any + increment -type integer -default 1 -optional 1 + } "@doc -name Manpage: -url [manpage_tcl dict]" ] + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + lappend PUNKARGS [list { + @id -id ::tcl::dict::info + @cmd -name "Built-in: tcl::dict::info" -help\ + "This returns information (intended for display to people) about the + given dictionary though the format of this data is dependent on the + implementation of the dictionary. For dictionaries that are implemented + by hash tables, it is expected that this will return the string produced + by ${$B}Tcl_HashStats${$N}, similar to ${$B}array statistics${$N}." + @values -min 1 -max 1 + dictionaryValue -type dict + } "@doc -name Manpage: -url [manpage_tcl dict]" ] + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + lappend PUNKARGS [list { + @id -id ::tcl::dict::keys + @cmd -name "Built-in: tcl::dict::keys" -help\ + "Return a list of all keys in the given dictionary value. If a pattern is + supplied, only those keys that match it (according to the rules of ${$B}string + match${$N}) will be returned. The returned keys will be in the order that they + were inserted into the dictionary." + @values -min 1 -max 2 + dictionaryValue -type dict + globPattern -type string -optional 1 + } "@doc -name Manpage: -url [manpage_tcl dict]" ] + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + lappend PUNKARGS [list { + @id -id ::tcl::dict::lappend + @cmd -name "Built-in: tcl::dict::lappend" -help\ + "This appends the given items to the list value that the given key maps + to in the dictionary value contained in the given variable, writing the + resulting dictionary value back to that variable. Non-existent keys are + treated as if they map to an empty list, and it is legal for there to be + no items to append to the list. It is an error for the value that the key + maps to to not be representable as a list. The updated dictionary value + is returned. If ${$I}dictionaryVariable${$NI} indicates an element that does not + exist of an array that has a default value set, the default value and + will be used as the value of the dictionary prior to the list-appending + operation." + @values -min 2 -max -1 + dictionaryVariable -type dict + key -type any + value -type any -multiple 1 -optional 1 + } "@doc -name Manpage: -url [manpage_tcl dict]" ] + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + lappend PUNKARGS [list { + @id -id ::tcl::dict::map + @cmd -name "Built-in: tcl::dict::map" -help\ + "This command applies a transformation to each element of a dictionary, + returning a new dictionary. It takes three arguments: the first is a + two-element list of variable names (for the key and value respectively of + each mapping in the dictionary), the second the dictionary value to + iterate across, and the third a script to be evaluated for each mapping + with the key and value variables set appropriately (in the manner of ${$B}lmap${$N}). + In an iteration where the evaluated script completes normally (${$B}TCL_OK${$N}, as + opposed to an ${$B}error${$N}, etc.) the result of the script is put into an + accumulator dictionary using the key that is the current contents of the + keyVariable variable at that point. The result of the ${$B}dict map${$N} command is + the accumulator dictionary after all keys have been iterated over. + + If the evaluation of the body for any particular step generates a break, + no further pairs from the dictionary will be iterated over and the ${$B}dict + map${$N} command will terminate successfully immediately. If the evaluation of + the body for a particular step generates a continue result, the current + iteration is aborted and the accumulator dictionary is not modified. The + order of iteration is the natural order of the dictionary (typically the + order in which the keys were added to the dictionary; the order is the + same as that used in ${$B}dict for${$N})." + @values -min 3 -max 3 + "{keyVariable valueVariable}" -type list -minsize 2 -maxsize 2 + dictionaryValue -type dict + body -type script + } "@doc -name Manpage: -url [manpage_tcl dict]" ] + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + lappend PUNKARGS [list { + @id -id ::tcl::dict::merge + @cmd -name "Built-in: tcl::dict::merge" -help\ + "Return a dictionary that contains the contents of each of the + ${$I}dictionaryValue${$NI} arguments. Where two (or more) dictionaries + contain a mapping for the same key, the resulting dictionary maps that + key to the value according to the last dictionary on the command line + containing a mapping for that key." + @values -min 0 -max -1 + dictionaryValue -type dict -optional 1 -multiple 1 + } "@doc -name Manpage: -url [manpage_tcl dict]" ] + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + lappend PUNKARGS [list { + @id -id ::tcl::dict::remove + @cmd -name "Built-in: tcl::dict::remove" -help\ + "Return a new dictionary that is a copy of an old one passed in as first + argument except without mappings for each of the keys listed. It is legal + for there to be no keys to remove, and it also legal for any of the keys + to be removed to not be present in the input dictionary in the first place." + @values -min 1 -max -1 + dictionaryValue -type dict + key -type any -optional 1 -multiple 1 + } "@doc -name Manpage: -url [manpage_tcl dict]" ] + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + lappend PUNKARGS [list { + @id -id ::tcl::dict::replace + @cmd -name "Built-in: tcl::dict::replace" -help\ + "Return a new dictionary that is a copy of an old one passed in as first + argument except with some values different or some extra key/value pairs + added. It is legal for this command to be called with no key/value pairs, + but illegal for this command to be called with a key but no value." + @values -min 1 -max -1 + dictionaryValue -type dict + "key value" -type {any any} -optional 1 -multiple 1 + } "@doc -name Manpage: -url [manpage_tcl dict]" ] + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + lappend PUNKARGS [list { + @id -id ::tcl::dict::set + @cmd -name "Built-in: tcl::dict::set" -help\ + "This operation takes the name of a variable containing a dictionary value + and places an updated dictionary value in that variable containing a + mapping from the given key to the given value. When multiple keys are + present, this operation creates or updates a chain of nested dictionaries. + The updated dictionary value is returned. If ${$I}dictionaryVariable${$NI} indicates + an element that does not exist of an array that has a default value set, + the default value and will be used as the value of the dictionary prior to + the value insert/update operation." + @values -min 3 -max -1 + dictionaryVariable -type string + key -type string -optional 0 -multiple 1 + value -type any + } "@doc -name Manpage: -url [manpage_tcl dict]" ] + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + lappend PUNKARGS [list { + @id -id ::tcl::dict::size + @cmd -name "Built-in: tcl::dict::size" -help\ + "Return the number of key/value mappings in the given dictionary value." + @values -min 1 -max 1 + dictionaryValue -type dict + } "@doc -name Manpage: -url [manpage_tcl dict]" ] + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + lappend PUNKARGS [list { + @id -id ::tcl::dict::unset + @cmd -name "Built-in: tcl::dict::unset" -help\ + "This operation (the companion to ${$B}dict set${$NI}) takes the name of a variable + containing a dictionary value and places an updated dictionary value in + that variable that does not contain a mapping for the given key. Where + multiple keys are present, this describes a path through nested + dictionaries to the mapping to remove. At least one key must be specified, + but the last key on the key-path need not exist. All other components on + the path must exist. The updated dictionary value is returned. If + ${$I}dictionaryVariable${$NI} indicates an element that does not exist of an array + that has a default value set, the default value and will be used as the + value of the dictionary prior to the value remove operation." + @values -min 2 -max -1 + dictionaryVariable -type string + key -type string -optional 0 -multiple 1 + } "@doc -name Manpage: -url [manpage_tcl dict]" ] + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- + lappend PUNKARGS [list { + @id -id ::tcl::dict::update + @cmd -name "Built-in: tcl::dict::update" -help\ + "Execute the Tcl script in ${$I}body${$NI} with the value for each ${$I}key${$NI} (as found by + reading the dictionary value in ${$I}dictionaryVariable${$NI}) mapped to the variable + ${$I}varName${$NI}. There may be multiple ${$I}key/varName${$NI} pairs. If a ${$I}key${$NI} does not have a + mapping, that corresponds to an unset ${$I}varName${$NI}. When ${$I}body${$NI} terminates, any + changes made to the ${$I}varName${$NI}s is reflected back to the dictionary within + ${$I}dictionaryVariable${$NI} (unless ${$I}dictionaryVariable${$NI} itself becomes unreadable, + when all updates are silently discarded), even if the result of ${$I}body${$NI} is an + error or some other kind of exceptional exit. The result of dict update is + (unless some kind of error occurs) the result of the evaluation of ${$I}body${$NI}. + If ${$I}dictionaryVariable${$NI} indicates an element that does not exist of an array + that has a default value set, the default value and will be used as the + value of the dictionary prior to the update operation. + + Each ${$I}varName${$NI} is mapped in the scope enclosing the dict update; it is + recommended that this command only be used in a local scope (${$B}proc${$N}edure, + lambda term for ${$B}apply${$N}, or method). Because of this, the variables set by + ${$B}dict update${$N} will continue to exist after the command finishes (unless + explicitly unset). + + Note that the mapping of values to variables does not use traces; changes + to the ${$I}dictionaryVariable${$NI}'s contents only happen when ${$I}body${$NI} terminates." + @values -min 4 -max -1 + dictionaryVariable -type string + "key varName" -type {any any} -typesynopsis {${$I}key${$NI} ${$I}varName${$NI}} -optional 0 -multiple 1 + body -type script -typesynopsis ${$I}body