Zigclc a commandline completing program for the zig compiler

I have been working the last few weeks on extending cligen, a generator for commandline parser code. I reported upon at SYCL 2024 Milan

The initial result of this, is zigclc, a program that can do commandline completion for the zig command (and all of the subcommands, options/arguments for those subcommands (that have help)), and does so for the fish, zsh and bash shell.

zigclc based completion can be installed, by invoking a shell specific line (which is displayed for your login shell if you start the program without parameters). This has zigclc generate a small shell function, which itself again invokes zigclc for feeding the shell with (TAB) completion information.

zigclc parses, and caches, the output from zig build --help to get you the steps, project options and system integrations for completion of zig build.

The zigclc program itself compiles with 0.15.2, but the completion has been analsysed from the 0.16 help output (which differs only slightly from the 0.15 output).

I would appreciate any feedback on actual usage, as I usually work with zsh and tend to wrap zig invocations by some other tool.

Some more details:

  • cligen analyse was implemented to parse the output from zig -h and zig subcommand -h for all subcommands, and generates a YAML specification for zigclc’s subcommands, sub-subcommands (steps), options, arguments. Given the emulation of other commands zig implements, this was non-trivial.
  • The plug-in system for cligen that allows global, user-specific and project specific extensions, was expanded. E.g. _ext/zig_complete_build_steps.yaml in the zigclc source tree holds the zig build parsing code that get inserted in zigclc
  • The updates to cligen for creating zigclc have NOT been committed yet (cligen download | SourceForge.net). You would need those to generate zigclc.zig from the YAML specfication. This needs a bit of cleaning up, and some testing/expanding of the non-completion code generated, which I intend to do next.
  • cligen does only invoke zig when it needs to determine the “dynamic” zig build completions (and help). Your shell will still directly invoke zig when you press Return on the commandline.
  • cligen can be used to generate the “front-end” to a Zig commandline program, handing back a struct with variables that are set (or not) from the commandline or a config file. It could also be used for zig that way, but probably should not do so for the LLVM provided subcommands.
  • zigclc help output is somewhat nicer than that of zig itself, as it determines your terminal width and wraps per column (so no help overflow at the beginning of the next line).
  • I briefly looked at nushell and it looks like you can invoke an external command for the completion, so that seems to be a possible target. I also want to see if powershell could do this.
  • You can have different zigclc completers for different zig version.
  • Some zig subcommands have over a thousand possibilities. That doesn’t really help with trying to select what to type next for a completion. It is in principle possible to have different priorities for the options, that will let you specify something even though it is not offered as a completion.
  • There is no real reason why cligen could not be re-implemented in Zig. However cligen uses far more features of YAML than the average program does, so that would require either a full YAML implementation for Zig, or some equally powerful (tags, anchors/aliases, inclusion) alternative data specification.

Working on a Python program that creates a Zig source, that emits a shell scripts that parses completion information generated by the Zig source, can be confusing at times. At times I had problems keeping else if and elif apart, or when to use # and when // for comments, etc.
Curly braces needed doubling when used in Python’s f-string, etc. Fortunately zig will mostly not compile if you generate something incorrectly.

Having both single and double quoted strings in Python helped a bit in preventing multi-backslash insanity while generating Zig code. But still there is a place where to get a colon escaped for the zsh completion (zsh seperates the completion from its help with a colon), required 8 (eight!) backslashes in the string in the Python code for cligen %-)

5 Likes