#cdexec
Explore tagged Tumblr posts
Text
One of the nice things about having an ability to wrap any shell/REPL with my Emacs and inject my own synced history and line-editing capabilities while keeping the native interactive stuff, is that whenever I get irritated with the limitations/flaws of Eshell, I can now take a break by going back to Zsh.
Eshell is great, but there are definitely situations where I end up fighting it in ways I find very frustrating.
The tab completion. I hate it. One day I'll take the time to understand pcomplete, and how to replace the UI/UX of it with something more to my liking, I'll go mad with power, but right now the most promiment impression of it is: when I hit Tab again I expect it to auto-complete the common prefix of the remaining completion candidates, or select the next candidate - not stubbornly sit there and insist I do some other thing to get what I want selected.
The native in-Emacs implementations... I get it, they're neat, they work on Windows even without proper CLI tools installed, but... look. How do I put this nicely? `env` is supposed to be an exec-chaining program which only incidentally has the feature of printing the environment if you don't give it a command to execute. `echo` redirected into a file is supposed to append a newline. `tar` is not supposed to lock up my entire UI if I'm doing heavy I/O. Let's just say that to me personally, these are unacceptable, and it is only thanks to me always having my exec-chaining programs on-hand (cdexec, umaskexec, ...) and mental fluency with multiply-escaped strings (sh -c 'foo '\''bar qux'\''') that this situation is tolerable, because I can always "break out" of Emacs.
The downside is
0 notes
Text
Aaaaahhhhh! (but in a good way)
cdexec ../some-other-branch git stash
git stash pop
!!!
So smooth and convenient, relative to the many little manual steps you need to do this normally.
(`cdexec` is another thing I made long ago, over here. The way cdexec and git cotrees regularly complement each other like this has been bringing me joy regularly for months.)
Words cannot describe how happy I am with `git-cotree`, and everything that went into `git-cotree --init` so that I can switch a repo from one normal working tree to cotrees with zero mental overhead and zero worry about uncommitted/unstaged/untracked work being lost in the process.
One of the best quality-of-life investments I've made for myself in the last year or two.
6 notes
·
View notes
Text
docerr
A little touch I've started to add to my command-line tools, inspired by docopt, is an "errors" section which is pretty clear to humans, and yet tells you precise API information. For example:
$ cdexec --help Execute a command in the given directory. If no command is given, just check if going into the directory works. Usage: cdexec [--] <directory> [<command> [<argument>]...] cdexec (--help | --version) [<ignored>]... Options: -h --help show this help text -V --version show version information Errors: need directory argument bad option: <option> error writing output: <...> error changing directory: <directory>: <...> error executing command: <command>: <...>
That describes every error this program can have, and those exact words will be the first thing written to standard error as part of the error message when those errors happen (prefixed only by "cdexec: ", since it is a universal convention for command-line programs to prefix their errors with the name they were invoked as).
So if you ever want to use this command in a script or program that handles a specific error, you can capture standard error and check for one of those strings in a rigorous predictable way. But you didn't have to know or think about any of that for that "Errors:" section to still be clear and informative in a "big picture" way.
16 notes
·
View notes
Text
So let's say you execute
$ cdexec foo
but `foo` doesn't exist. What should the error message be?
cdexec: error changing directory: foo: No such file or directory
cdexec: error changing directory: foo: ENOENT: No such file or directory
cdexec: error changing directory: foo: ENOENT
More abstractly, which way is best for reporting errors from the system?
...: <perror output>
...: <errno name>: <perror output>
...: <errno name>
Personally, I prefer the last one, because:
Including the errno name is very important for one of the biggest users of command-line tools: other programs such as scripts. ENOENT is the standard, international name for the error. The error is ENOENT. The output from perror is a localized human-friendly hint.
Ditto for human users who have grown familiar with the underlying system enough - I've seen developers complain about having to try to figure out what error code a `perror` string maps back to. I have a good enough memory that this doesn't trouble me most of the time, but I still waste a memorized lookup table on it.
The human-friendly error string is misleading in the edge-cases. See, when I see "no such file or directory", I know that there might not be any file or directory involved at all. Did you? For example, some APIs in the Linux network stack report ENOENT for things that aren't in the file system - because of course to a kernel developer living in a world which has missed the value of exposing all things on the "file" system, it makes sense that ENOENT means "no such entity" rather than specifically "no such file or directory". So you run an `ip route ...` command and get your time and energy wasted trying to figure out what file could possibly be missing.
To be clear, this is orthogonal to "should my source code just call `perror` or should I consider adding something like `errnoname`?" Because your libc could easily be made to extend or change the perror output to include errno names, based on either a compile-time flag or for example by setting some environment variable. You could also compile with `perror` renamed or relinked to something else. So we could in principle achieve any of these alternatives while still just calling `perror` in your source.
This is also orthogonal to "but for many users (at least in the vast majority of cases), the human-readable error message is helpful". Just because something is good to have, doesn't mean every single program should contain the code to do it. Turning an error into human-friendly guidance sure looks to me like a composable piece of functionality that can be implemented separately and then composed on top of all programs. I'd rather have a shell that can automatically pipe the standard error of my programs through a helper tool which can detect names like `ENOENT` and do whatever helpfulness the user wants and the usecase demands. Meanwhile, the error strings which perror produces don't even do a great job of being human-friendly guidance - new users, and even just busy non-experts in a hurry, benefit from detailed hints, typo-checking, alternative suggestions, and so on.
So when I think about the external error string as an API first, the `errno` name seems essential, and then the `perror` output seems superfluous and worse for parsing.
But I do recognize that the perror output can always be stripped off - if you know the format enough to unambiguously isolate the perror noise from the rest of the error, then yes it's annoying, but it's very surmountable.
I also recognize that in the world we live in right now, users aren't going to run my programs in a shell that automatically translates their errors into something more helpful in a user-configurable way. That doesn't exist yet, I haven't written it yet nor spread the vision, and when we do write it, adoption will lag behind a lot. So when a new user runs a program directly, sees `ENOENT`, and has no idea what it means, it doesn't do them much good for me to say "well this wouldn't be a problem if the rest of your system was set up how I envision". At best I can hope that the error code, combined with my carefully chosen prefixes like "error changing directory", do a good job of getting them to the right answer through Google.
So I find myself on the fence... I want to do the third option - the third option is the best architecture, and the future of CLI is to be even more of an API and less of a UI - but I know the second option would be more helpful for a decent amount of real users right now.
5 notes
·
View notes