someone in the replies elsewhere pointed out that Ctrl+J = 10 in the ASCII table = LF ("line feed") = Enter (because J is the 10th letter of the alphabet)
so Ctrl+J is the same as pressing enter
which I don't have any practical use for but is kind of cool
(edit: some corrections in this reply: https://pgh.social/@ben/112752235264922484)
@[email protected] This isn't quite right in a few ways. LF is decimal 10, ascii 0x0a. It is 10 because it's the 10th letter of the alphabet, though. But it's not the same as pressing enter except in cooked tty modes, where the terminal driver converts the return key (^M, \r, ASCII 13 / 0x0d) to a newline (^J, LF, 10/0xa) which your program then sees as its input.
@b0rk haha yeah I have been doing this a lot longer than 15 years and this is the first time I have really _thought_ about how terminals work
one thing I don't get is: If ^W isn't handled by readline (or friends), what *is* doing it? How do backspace and word-backspace work?
How... does character entry work at all??
⌃W and ⌃U and ⌃Q and ⌃S and so on hide away deep inside: stty all
for example
$ stty -a
...
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>;
swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V;
...
$
macOS
% stty -a
...
cchars: discard = ^O; dsusp = ^Y; eof = ^D; eol = <undef>;
eol2 = <undef>; erase = ^?; intr = ^C; kill = ^U; lnext = ^V;
min = 1; quit = ^\; reprint = ^R; start = ^Q; status = ^T;
stop = ^S; susp = ^Z; time = 0; werase = ^W;
%
part of how you can test for this is to try inside of: cat -
the ⌃W and ⌃U will work there, even when Arrow Keys etc don't work there
<=
macOS lets you spell out 'stty -a' as 'stty all', but Linux doesn't
Linux lets you abbreviate 'stty -a' as 'stty --all', but macOS doesn't
'stty -a' reports the 'stty ixon' vs 'stty -ixon' toggle in a different output line apart from these mentions of ^Q ^S, but you often need to add 'stty -ixon' to make the ⌃S forward-search-history properly undo
the ^R reverse-search-history mentioned
by Bash bind -p |grep C-[rs]
or the ^R history-incremental-search-backward
by Zsh bindkey |grep '\^[RS]'
i can't remember how often Zsh needs this workaround = maybe less often than Bash
@njvack @b0rk In Unix there are parts of the kernel, called "device drivers", that handle device I/O. In this case it's the "terminal driver". The terminal driver gets control when a process issues a `read()` or `write()` call on a file descriptor that has been opened to a device. Also, when the hardware I/O bus signals an I/O interrupt, the kernel transfers control to the appropriate driver the handle the interrupt.
When you type a character on a terminal, there is an I/O interrupt and the kernel asks the terminal driver to handle it. Normally, the driver just copies the character into a per-device buffer, waiting for the next read() call from the user process that has the terminal open. If the character was a control-W, though, the driver instead erases characters out of that buffer back to the last whitespace. Later, when the user process does `read()` to ask the driver for the contents of the buffer, the erased characters will be gone as if they had never been typed.
The driver may also send some delete characters back to the terminal to cause it to backspace and delete the erased word. (Normally, the terminal is in "no echo" mode which means it doesn't display what you type on it, instead it only displays whatever the terminal driver sends back.) If the driver knows you're on a non-backspacing terminal it may send something else to try to indicate that the word was deleted.
This is all in what's called "cooked" mode. Unix terminal devices also have a "raw" mode where the driver just copies stuff into the buffer with no processing. Tools like readline put the terminal into raw mode.
@njvack @b0rk I think this dates back to the days of slow remote serial terminals, or even teletypes? If you put some really basic line editing into the terminal itself and only send the entered text when pressing "enter", the experience feels a lot more responsive - and every program doesn't need to independently write its own implementation of backspace.
But yeah, very interesting legacy thing at this point, even tho many tools still rely on the behaviour.
I think in Linux it's implemented in the kernel's pty layer rather than separately in each terminal app?
@kepstin @b0rk I do know that a lot of this dates back to teletypes and the like. "/dev/tty0" is referring to a teletype, and a pty is a pseudo-teletype, and "vt100" was a "DEC Video Terminal 100" system.
I suspect you could, today, hook a modern linux system up to a teletype over a serial line and have it work correctly with relatively little effort
Then you wouldn't have a "terminal emulator program" — you would have a literal terminal
hmm
@njvack @b0rk ttys are by default in cooked/canonical mode, which does some pre-processing such as handling ^W etc.
In order for a program to do it's own processing, it switches the tty into raw mode. Most terminal applications that supply their own line editing features would be in raw mode (e.g. ncurses, readline, etc).
* This is an over-simplification as what we call "cooked mode" or "raw mode" are actually 15 or so flags that are independently set. One these flags is ICANON. ICANON defines if the tty line-editing facilities are enabled. ICANON is set for cooked mode, and is cleared for raw mode.
You can see an example of how this is implemented in the N_TTY line discipline implementation in Linux: https://github.com/torvalds/linux/blob/4376e966ecb78c520b0faf239d118ecfab42a119/drivers/tty/n_tty.c#L1269C13-L1269C37
From here you can see some basic line-editing facilities implemented, i.e.: ERASE, WERASE, KILL, LNEXT, REPRINT, newline, EOF, EOL, EOL2.
@dcnick3 @njvack @b0rk Historically, terminals were hardware devices. This device is handled with two things: the terminal device driver, and the line discipline. The obvious place to do line discipline was in the kernel, between the user application and the device driver.
Unfortunately, Linux is not a microkernel.
@b0rk yes, this! so so much this!
like, what is this fictitious world in which every aspect of every tool is learned right away? everybody looks at things from a perspective informed by where they are at that moment and what they want to do. sometimes, that puts the spotlight away from (otherwise) foundational tools. sometimes that puts one in positions where memorising 1–2 command variations without fully understanding the entire tool is good enough(tm).
and everybody has these ‘blind spots’ – i.e. things that were more front and centre for somebody else.
it’s silly to pretend otherwise.
@b0rk right? That sort of commentary serves no purpose. And there's always new stuff to learn.
There's probably even a better way to do my go-to readline use case, one I haven't discovered yet:
```
read -s PASS
export PASS
```
@mmeier If it's useful to you, I did notice that ln is symmetric to cp, in that you create a new file from a source (and you can also leave out the new file's name and just specify the containing directory). One command copies the contents, the other just references the source.
But tbh, I just remembered the melody of "target link name" at some point and keep saying it inside my head.
@b0rk there is something particularly juvenile about people assuming there is one particular order or traversal for how people should learn things – that if someone else doesn’t know a particular bit they are BEHIND or BELOW or BASIC.
it’s NORMAL that we all encounter the staggering diversity of technical details at different times and stages and it doesn’t mean something fundamental about your place in the hiearchy.
@b0rk Funny that the J character also looks a bit like the ↵ character :)
And the fact that `j` is VIM key to move the cursor down!
Coincidence? I think not!
@b0rk Also Ctrl-H is the backspace character (no matter what your backspace key enters), Ctrl-I is horizontal tab, and Ctrl-L is form feed.
That's also why Ctrl-L is so often the “clear/reset screen” command.
@Ange @b0rk
And a lot of those "control character quirks" have just become "how things are done" without anyone ever thinking about how it happened.
You can still use Control-D to exit a shell, Control-G sounds a bell and Control-H is either backspace or delete depending on what kind of computer you're using.
@b0rk Not the same combination, but I've used ^[ as escape when I couldn't quickly or easily find a way to press the key itself. You may have already come across it, but such control character combinations feel slightly more reasonable to me when looking at a 4-column ASCII table showing all of them: https://garbagecollected.org/2017/01/31/four-column-ascii/
[Edit: Ooh, this view of the table (from elsewhere in the tree of replies) looks interesting as well: https://mastodon.social/@Ange/112752251139584718]