Live data from Hacker News

"Rules" that terminal programs follow

jvns.ca

71–80 of 153 posts

Re: "Rules" that terminal programs follow

#71
Some more notes:

- If this is your first time hearing about the readline/emacs keybindings like Ctrl-E and Ctrl-W, you'll be pleased to know that most macOS input sources use these keybindings. If you're on macOS, feel free to try Ctrl-E, Ctrl-W, or Ctrl-U in your browser's address bar right now

- If you're using a command line program that doesn't support _any_ line editing (e.g. no readline keybindings, and no other keybindings), you can install the `rlwrap` program and launch the REPL under rlwrap. For example Standard ML of New Jersey has a REPL but no line editing functionality, but you can recover that via `rlwrap smlnj`

- "don’t use more than 16 colours" — I would go so far as to say "don't use more than 8 colors, or at least make your colors configurable." Many popular color schemes, including Solaraized and the default Base 16 color scheme, use the "bright" colors to hold various shades of gray. What you think is "bright green" might actually be the same shade of gray that normal text is colored.

Re: "Rules" that terminal programs follow

#72
> don’t use more than 16 colours

We aren't in the '80s. Use true color if you want to, modern terminals should support it (built in Linux tty is a weird outlier that should have supported true color years ago).

But that also depends on the context. For example if something implements its own TUI with a lot of elements - it makes more sense to use more colors than the barebones set.

Most programs that do care about colors, check what terminal capabilities are before using them.

Re: "Rules" that terminal programs follow

#73

One that's missing is treating ~ as the home directory. This appears to be a shell thing and not a POSIX API thing. For example, this doesn't work: func main() { if _, err := os.ReadFile("~/.bashrc"); err != nil { log.Fatal(err) } fmt.Println("ok") } Meanwhile over in shell land: $ echo ~/~/~ /home/jrockway/~/~ The behavior is actually kind of amazing. I mention it because while "yourprogram ~/path/to/file" always wo…

Tilde expansion is part of shell word expansion: https://pubs.opengroup.org/onlinepubs/9799919799/utilities/V...

Tilde expansion is the first operation in word expansion:

> The expansions that are performed for a given word shall be performed in the following order: 1) Tilde expansion, parameter expansion, command substitution, and arithmetic expansion shall be performed, beginning to end. 2) Field splitting shall be performed on the portions of the fields generated by step 1. 3) Pathname expansion shall be performed, unless set -f is in effect. 4) Quote removal, if performed, shall always be performed last.

See https://pubs.opengroup.org/onlinepubs/9799919799/utilities/V...

To see the whole shell specification, goto the main page at https://pubs.opengroup.org/onlinepubs/9799919799/. Select "Shell & Utilities" from the top-left frame, then "Shell Command Language" from the bottom-left frame.

Re: "Rules" that terminal programs follow

#74
post #49

Earlier quoted context omitted.

It generally isn't possible for grep to "slurp up" the error output because stderr does not get passed through pipes (by default). This is shell behavior and grep cannot do anything about it. As a side note, some shells have started implementing a shorthand for `foo 2>&1 | grep` which is `foo |& grep`.

Right, the problem is that apparently shells haven't seen user need for selectively redirecting one or the other. Like I might want to see foo's stdout on the terminal, but pipe stderr (and only stderr) to grep, perhaps so I only see some specific error messages that I care about. `2>&1` will send stderr to stdout, and then the pipe will send everything to grep (and I believe `|&` does the same). (To be fair, that do…

Actually, you can. If you run:

    foo 2>&1 >&- | grep ...
then you will grep only the stderr. The stdout will be discarded.

Alternatively, if you only want to grep to see the stderr, but you still want to see stdout, you can swap stderr and stdout like this:

    foo 3>&2 2>&1 1>&3 | grep ...
And in many shells, you can easily split the stdout and stderr into two separate pipelines like this:

    foo > >(grep stdout) 2> >(grep stderr)

Re: "Rules" that terminal programs follow

#75
One thing that I’ve noticed:

On UNIX, expanding globs (*.txt) is the shell’s job.

On Windows, expanding globs is the program’s job.

I used to have a bunch of four-line Python programs to, essentially, run `flac --best --replay-gain *.wav`.

Re: "Rules" that terminal programs follow

#76
post #49

Earlier quoted context omitted.

It generally isn't possible for grep to "slurp up" the error output because stderr does not get passed through pipes (by default). This is shell behavior and grep cannot do anything about it. As a side note, some shells have started implementing a shorthand for `foo 2>&1 | grep` which is `foo |& grep`.

Right, the problem is that apparently shells haven't seen user need for selectively redirecting one or the other. Like I might want to see foo's stdout on the terminal, but pipe stderr (and only stderr) to grep, perhaps so I only see some specific error messages that I care about. `2>&1` will send stderr to stdout, and then the pipe will send everything to grep (and I believe `|&` does the same). (To be fair, that do…

> Like I might want to see foo's stdout on the terminal, but pipe stderr (and only stderr) to grep, perhaps so I only see some specific error messages that I care about

You mean this:

`foo 3>&1 1>&2 2>&3`

The above swaps stdout and stderr, saving + restoring the original stdout through descriptor 3. Shell redirection expressions map directly to dup2 syscalls, except the operands are reversed: 3>&1 is dup2(1, 3). Pipes map fairly simply to fork + exec. At its core the shell is a rather thin wrapper around the core Unix syscalls fork, exec, dup2, open, and close. If you look at the original shell implementation, the command parser more-or-less executes these syscalls as it goes along, left to right.

Re: "Rules" that terminal programs follow

#77

One thing that I’ve noticed: On UNIX, expanding globs (*.txt) is the shell’s job. On Windows, expanding globs is the program’s job. I used to have a bunch of four-line Python programs to, essentially, run `flac --best --replay-gain *.wav`.

On Unix programs get arguments as array of strings. On Windows programs get command line as single string.

Strictly speaking that does not explain where globbing happens, but it does help understanding where they come from.

Re: "Rules" that terminal programs follow

#78
post #42

Additional suggestions: * Respect the user's default foreground and background color. Don't change them without good reason. * If you use colors, make them legible regardless of what the default background and foreground colors are, and regardless of the terminal's color map. * Don't use color as the only indication of something. The user's terminal might not display it, and it probably won't be preserved in copy&pas…

> please provide an easy preference setting for people to opt out of that.

There is some effort to standardize this: https://bixense.com/clicolors/>

Re: "Rules" that terminal programs follow

#79
post #51

The main reason I enjoy CLIs so much more than GUIs (or eves TUIs sometimes) is that it feels so consistent. There are conventions, but following all the conventions in a CLI is a lot easier than designing a good GUI. So they tend to be higher quality as a result. I spend a lot of time thinking how to bring this property to GUIs, but my best answers are still "lots of effort" or "lower your expectations".

A large part of this I think is that other than MacOS, GUI conventions aren’t heavily implemented by the OS and easy to opt into. And because no other OS landed on “meta key for GUI shortcuts” so there are a lot more conflicts (e.g. ctrl-c).

The Application Framework defaults which underly most native macOS application build a lot of common keyboard controls in. Use the default menu bar classes with the default basic commands, and Command O, N, Q, X, C,V and probably others come for free, you just implement the code that you need to for those functions. Use a standard text field and you automatically get Command/Option/Fn Left, Right, Up, Down for navigation. It’s more notabke when a macOS application doesn’t follow convention (e.g. InteliJ uses Shift-Opt up/down to move lines rather than expand the selection by paragraph) than when one does.

Windows does decently well on this front, but ctrl as a default modifier can hurt terminal based app usage and there are a number of UI frameworks even within the OS that appear to get different defaults.

And in the Linux world, I think the only way you could do this would be for someone to design (and a distro to standardize on and port apps to) a full on application framework. The window managers don’t want to be in the business of dictating the behavior of stuff in windows. The GUI toolkits don’t want to be in the business of defining os wide defaults and the DEs and distros don’t want to be in the business of if porting or dictating UI frameworks. And realistically there’s no one “on high” that could make the sort of dictation that for example “hence forth copy and paste will be Meta-C and Meta-V”

Re: "Rules" that terminal programs follow

#80
post #72

> don’t use more than 16 colours We aren't in the '80s. Use true color if you want to, modern terminals should support it (built in Linux tty is a weird outlier that should have supported true color years ago). But that also depends on the context. For example if something implements its own TUI with a lot of elements - it makes more sense to use more colors than the barebones set. Most programs that do care about co…

As Evans explains, its not about technical capability, but about respecting users choice of colors/theme.
Post reply on HN