q3cpma

set website    https://git.sr.ht/~q3cpma/ 
set location   France
set email      [email protected]

My miscellaneous Tcl utilities are here and they contain:

% util::defun f {&whole w req &key k1 {k2 X} {k3 Y k3_supplied}} {
      foreach arg {w req k1 k2 k3 k3_supplied} {
          puts "$arg: [list [set $arg]]"
      }
  }
% f 1
w: 1
req: 1
k1: {}
k2: X
k3: Y
k3_supplied: 0
% f 1 :k3 Y :k2 2 :k1 3
w: {1 :k3 Y :k2 2 :k1 3}
req: 1
k1: 3
k2: 2
k3: Y
k3_supplied: 1
  • atexit : schedule script executions at exit
% util::atexit add {puts "hello world"}
% util::atexit add {puts [clock format [clock seconds]]}
% util::atexit add {global env; puts "env: $env(HOME)"}
% util::atexit del {puts "hello world"}
% exit
Wed Jul 14 14:27:58 CEST 2021
env: /home/user
  • quasiquote : yet another way to selectively expand variables
% set var1 hello
% set {var 2} world
% set var3 {1 2}
% eval [util::quasiquote var4 foobar var5 {[* 5 5]} var6 {[list 6 6]} {
      puts "`,var1` `,{var 2}` `,var3` `\[+ ,@var3\] = [+ ,@var3]` `,var4` `,@var5` `,@var6`"
% }]
`hello` `world` `{1 2}` `[+ 1 2] = 3` `foobar` `25` `6 6`
  • format_paragraph : like textutil::adjust followed by textutil::indent with terminal markup
% puts [util::format_paragraph {**Lorem __ipsum__ dolor** sit --amet--, consectetur adipiscing elit, sed
do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum} indent 4 width 70]
    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
    eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
    ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
    aliquip ex ea commodo consequat. Duis aute irure dolor in
    reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
    pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
    culpa qui officia deserunt mollit anim id est laborum
  • autocli : all-in-one CLI creation handling option parsing and help text creation
% set argv {-opt1 -opt2 foobar myarg}
% set argc 4
% set opts [util::autocli \
    {opt1 {flag "Opt1 description"} opt2 {param default PARAM_NAME "Opt2 description"}} \
    "Program name" \
    "Short description" \
    {{SYNOPSIS1_ARG1 [SYNOPSIS1_ARG2...]} {SYNOPSIS2_ARG1 SYNOPSIS2_ARG2}} \
    {"Long description as a list of indented and formatted paragraphs"
    "    with some **markup**"}]
opt1 1 opt2 foobar
% set argv
foobar
% util::usage stdout
NAME
    Program name - Short description

SYNOPSIS
    Program name [OPTION]... SYNOPSIS1_ARG1 [SYNOPSIS1_ARG2...]
    Program name [OPTION]... SYNOPSIS2_ARG1 SYNOPSIS2_ARG2

DESCRIPTION
    Long description as a list of indented and formatted paragraphs
          with some markup

OPTIONS
    -opt1
        Opt1 description

    -opt2 PARAM_NAME
        Opt2 description
        Defaults to "default".

    -help
        Print this help message and exit.

  • parse : yet another AWK emulation proc, with some niceties here and there (srange to adress line fragments by field number, exit to control the flow with granularity)
# List all mountable hotplugged disks/partitions
% exec lsblk -nproNAME,TYPE,HOTPLUG,FSTYPE,MOUNTPOINT | awk {$2 ~ /^(part|disk)$/ && $3 == 1 && NF == 4 {print $1}}
/dev/sdd1
/dev/sde
/dev/sde2
/dev/sde1
% util::parse [exec lsblk -nproNAME,TYPE,HOTPLUG,FSTYPE,MOUNTPOINT] {
        {[~ {^(part|disk)$} $1] && $2 == 1 && $NF == 4} {
                lappend ret $0
        }
        END {return $ret}
}
/dev/sdd1 /dev/sde /dev/sde2 /dev/sde1
  • wjson : a self-contained, crude JSON writer for people who want something simple enough to understand in a minute and robust enough to not rely on tcl::unsupported::representation (recursive without TCO though, watch your [interp recursionlimit {}]!):
% util::wjson::write stdout \
    [util::wjson::object \
         [dict create \
              foo [util::wjson::string {\bar"}] \
              num [util::wjson::number 123] \
              arr [util::wjson::array \
                       [list \
                            [util::wjson::bool 1] \
                            [util::wjson::bool 0] \
                            [util::wjson::null]]]]]
{
    "foo": "\\bar\"",
    "num": 123,
    "arr": [
        true,
        false,
        null
    ]
}

along with a lot of small but useful stuff (functional, metric/binary unit conversion, terminal emulator formatting, Lispy stuff, dict and list additions, etc...).


Some Tcl based projects:

Other stuff in separate Wiki pages:


Some "problems" I identified during my Tcl journey:

  • Need for a more pinpoint subst, like Lisp quasi-quoting; needed for Tcl style "closures" (cf aforementioned quasiquote).
  • Named parameters (options, in the case of Tcl), my defun is too slow.
  • Fossil instead Git... let's face it, Git won the VCS war a long time ago, and Fossil more than probably detracts a significative population from contributing (probably even more than something like CVS or subversion).
  • Not something I expect to be solved (it's a lot of work, after all), but I've really been spoilt by LSP/SLIME and its lack in Tcl is now jarring to me; related, but tclreadline is missing support for namespaces (both completing namespace eval ns{... and launching the REPL inside a namespace, for those wanting something like CL-USER).
  • event loop: a way to set an after timer instead of cancelling then adding it anew.
  • exec: still not fixed (TIP 424 and 259).
  • trace: add a way to trace all/any variables (including variable creation) and access to unknown variables, provide the previous value during a write, integrate with dicts and lists (dict trace/ltrace?).
  • socket: lacks a well supported UD sockets library, portable way of specifying timeout?
  • string: add a -dict option to compare (ticket ).
  • binary scan: no way to get the cursor position (ticket ), would also like a more FP -inline switch.
  • binary format: option to switch zero padding position to end instead of beginning.
  • namespace ensemble: add extend subcommand.
  • gets: no getdelim equivalent (chan configure -eol?).
  • coroutine: not first class, could be done if apply took an offset (in char or bytecode ops?) and a wrapper to track said offset (the local environment can be tracked through the apply bindings).
  • TclOO: use the GC to handle obj lifetime, currently have to use defer most of the time.

Note: mostly inactive as a serious Tcl programmer since I became infatuated with CL; still using it as a scripting language for its superior string handling, nice dictionary API or event loop.