Closed neogeographica closed 3 years ago
Strawman for var handling: a virtual tool "chaintool-env" that provides a few ways for setting option values that will affect any subsequent commands in a sequence. Easy to whip up some syntax for basic var manipulations since we know that placeholder names have to be alphanum.
So let's say we had a command like this in the sequence:
chaintool-env srcstem=map:stem dstbasestem?=srcstem:basename
...which means to do, in order:
Then a subsequent q3copy could just be something like:
chaintool-copy "{srcstem}.bsp" "{basepath}/{mod}/maps/{dstbasestem}.bsp"
(use shlex.split on the chaintool-copy arguments to find the source path and dest path tokens)
And a subsequent q3launch could be:
{basepath}/{q3exe} +set sv_pure 0 +set fs_game {mod} +devmap "{dstbasestem}"
If I go this route, a useful starting point seems to be to have these virtual tools:
chaintool-copy source dest
(if source != dest, invokes shutil.copy2)chaintool-del file
(invokes os.remove)chaintool-env op op op op
...Each op for chaintool-env is of the form dstname=srcname:modifier
or dstname?=srcname:modifier
, where ?=
means to assign only if dstname is unset (in the runtime-specified args). Currently thinking that assignment from unset srcname will just silently do nothing.
Plausible modifiers:
dirname
(drop the final dirsep and everything after)basename
(drop the final dirsep and everything before)stem
(drop the final period and everything after)Can waffle a bit about what to do in the case of multiple periods, like foo.tar.gz, but eh let's just drop the last one. If you want to drop two you can use stem twice. "Drop all extensions but I don't know how many there are" doesn't seem like an interesting usecase.
One limitation of implementing var stuff as its own command, is that it can only deal with options supplied on the command line, not with options that take their value from the default.
I think that's OK? You know what the default value is (when writing a cmd definition), so if you need to have a version of that elsewhere in the commandline, then you know what that is too. E.g. let's say in some contrived circumstance you wanted to change a file's extension from .ent to .map. The default input filename needs to be "test.ent" but you want to allow overriding the input filename at runtime. You could do it with these two commands:
chaintool-env dststem=src:stem
chaintool-move {src=test.ent} {dststem=test}.map
It's maybe not obvious though that that would be the way to do it.
Did a draft implementation of the above. It works nicely at first glance, but I did notice that of course the source option names in the chaintool-env arguments don't affect things like the output of "print" (or autocomplete). That got me thinking down a path that leads to a slightly more complex but more powerful and consistent approach:
Currently our non-toggle placeholders can be of the form {name}
or {name=default}
. name
is alphanumeric. We could choose a syntax for applying value modifiers there, e.g. {dirname/name}
or even {dirname/name=default}
, which we could then store in the internal format string as {dirname+name}
.
Internally, if there's a modifier like that we can mostly treat it as a new placeholder name, with a new value generated by applying that modifier to that placeholder's value. As far as print and autocomplete are concerned though, it's just an instance of that name
placeholder. Would also have to make sure that the modifier isn't shown in any error message about "placeholders that still need a value".
That would lead to the q3copy+q3launch commands looking like this:
chaintool-env srcstem={stem/map}
chaintool-env dstbasestem?={basename/srcstem}
chaintool-copy "{srcstem}.bsp" "{basepath}/{mod}/maps/{dstbasestem}.bsp"
{basepath}/{q3exe} +set sv_pure 0 +set fs_game {mod} +devmap "{dstbasestem}"
Note that with this approach, it's less straightforward to let earlier args for chaintool-env affect later args, so I used two chaintool-env commands.
However one neat thing that does appear to be straightforward is to allow chaining modifiers, so I could do:
chaintool-env srcstem={stem/map} dstbasestem?={basename/stem/map}
chaintool-copy "{srcstem}.bsp" "{basepath}/{mod}/maps/{dstbasestem}.bsp"
{basepath}/{q3exe} +set sv_pure 0 +set fs_game {mod} +devmap "{dstbasestem}"
If I wasn't trying to support the optional dstbasestem value, then this could be even simpler:
chaintool-copy "{stem/map}.bsp" "{basepath}/{mod}/maps/{basename/stem/map}.bsp"
{basepath}/{q3exe} +set sv_pure 0 +set fs_game {mod} +devmap "{basename/stem/map}"
As another usage example of this approach, the contrived example above of changing file extensions with a default filename would be:
chaintool-move {src=test.ent} {stem/src=test.ent}.map
Cf. the current example "q3copy" and "q3launch" commands (abbreviated here a little for space).
q3copy:
q3launch:
These use shell-specific syntax and (in q3copy) Linux-specific tools to do stuff like:
It's also easy to conceive usefulness of file move/rename/delete operations.
Obviously this stuff can be made to work in a platform-specific way but it makes the cmd definitions less portable. Would be neat to support platform-independent ways to define such operations. (For reference the Trenchbroom compile profile dialog also provides a platform-independent file copy operation.)
As a strawman, if the first word of a cmd definition was "chaintool-copy" then we could treat it as a filecopy operation that takes source and dest arguments -- rather than running it as a subprocess we could implement it internally using shutil.copy2 in Python.
It's easy to think about file operations in that way; the variable manipulations are trickier.