How do I bind C-? in bash? - linux

I want to bind C-? to history-search-backward in bash and/or zsh. I tried the following way
bind '"^?": history-search-backward' # bash
bindkey '^?' history-search-backward # zsh
The binding works fine, but at the same time BS (backspace) stops working correctly. The reason is that BS generates the same code as C-? what one can check with C-v BS and C-v C-?. Thus the final result is that both C-? and BS are bound to history-search-backward what is obviously not what I wanted.
So the question is how can I properly bind C-? without affecting BS?

Which string is sent to the shell when pressing a key or key combination is determined by the terminal.
It seems that a lot (most?) terminal emulators by default send ^? (ASCII 0x7f, Delete) when pressing the backspace key. While the actual backspace character would be ^H (ASCII 0x08, Backspace).
If you can change the behaviour of your terminal emulator to send ^H you should be able to maintain the function of the backspace key while still being able to bind ^? to something else.
Terminal emulators the provide a GUI for configuration (gnome-terminal, roxterm, konsole, ...) should have an option for that.
Others (xterm, urxvt, ...) may have appropriate X resources that may be set in ~/.Xdefaults (or - depending on your distribution - ~/.Xresources).
For xterm you need to set:
XTerm.backarrowKeyIsErase: False
For urxvt set
URxvt.backspacekey: ^H
please note that this is the actual ^H (ASCII 0x08) character and not a two character string consisting of ^ and H.
To load these settings either call xrdb -merge ~/.Xdefaults or close and restart your X session. (The settings will only be enabled for new terminals)

Related

Terminal: send a do-nothing escape sequence or control character

I need my terminal to send an unused control character or escape sequence, one that has no effect at all layers: ignored by shells (bash, ...), ignored by line-editors (readline, ...), and ignored by all applications (vim, less, mutt, ...). I'll then bind this key within tmux, with a user defined key escape sequence if necessary. What control character or escape sequence do I use? More information below:
I want the Control-Shift-c key chord in tmux bound to an action which will copy the tmux selection into the X clipboard selection buffer. That and continue to have Control-Shift-c copy the terminal selection into the X clipboard selection buffer when tmux is not running. Terminal emulators generate the same output for both Control-Shift-key and Control-key inputs, see [1][2]. The first step is to change this:
# Enable fixterms (I think) sequences for all keys:
xterm -xrm "XTerm.vt100.modifyOtherKeys: 2" -xrm "XTerm.vt100.formatOtherKeys: 1"
This instructs xterm to construct an escape sequence for all keys modified by Control, Alt, or Meta. As far as I can tell nothing supports these escape sequence, whether they're formatted using the original xterm sequences or via the new fixterms [3] specifications. Even tmux supports only a subset of these sequences [4], rather than a full-blown CSI-sequence parser [5].
The simplest workaround is to have only Control-Shift-c send a fixterms sequence, as per [6]. Since this sequence isn't supported by tmux, it'll have to be manually defined via the user-keys option. It will also have to be bound in the root key table of tmux rather than one of the copy-mode tables; otherwise if tmux isn't in copy-mode the binding will be ignored and passed through tmux to one of the terminal applications.
# Configure only Control-Shift-c to send a fixterms sequence:
xterm -xrm "XTerm*vt100.translations: #override \n\
Ctrl Shift <Key>c: string(0x1b) string ([67;6u)"
# Recognize (but don't handle) the Control-Shift-c fixterms sequence:
tmux set-option -s user-keys[0] "\e[67;6u"
# Copy the selection to the clipboard buffer only when in copy-mode. If
# there is no selection, nothing will be copied:
tmux bind-key -T root User0 if-shell -Ft= "#{pane_in_mode}"
"send-keys -X copy-pipe 'xsel -i -b'"
All other applications, which don't support fixterms sequences, will receive input junk. Even worse, unknown escape sequences are likely to be misinterpreted and trigger application-specific commands. Initially I considered using tcgetpgrp(3)[7] to get the name of the command currently running within the terminal, much like #{pane_current_command} in tmux[8].
xterm <-> bash <-> command
The terminal binding for Control-Shift-c would first copy the terminal's selection to the clipboard buffer, as usual; then call my external program[9]. If the terminal command isn't currently tmux, nothing happens; otherwise the external command writes the fixterms Control-Shift-c sequence to the terminal's pts. When tmux receives that sequence it will overwrite the clipboard buffer with its own selection.
xterm -xrm "XTerm*vt100.translations: #override \n\
Ctrl Shift <Key>c: copy-selection(PRIMARY) \n\
exec-formatted("~/send_fixterms_sequence_if_tmux.py")
This fails to handle nested terminal emulators, as when running tmux over ssh - which is very common.
xterm <-> bash <-> ssh <-> bash <-> tmux <-> bash <-> command
That's my dilemma and I'm currently considering several alternatives:
Have the terminal send a control character rather than an escape sequence. Control characters are always supported. I'd like there to exist a do-nothing character and was hopeful for Control-# (NUL or ASCII 0), but that character is echoed by the shell and has a significant effect in insert mode in vim. If no such character exists, see #3. Perhaps I could appropriate an uncommon control character, but it would also have to be configured to do nothing, across all layers: xterm, bash, readline, vim, etc.
Have the terminal send an unused or do-nothing escape sequence rather than the Control-Shift-c fixterms sequence. The sequence would need be ignored at all layers: ignored by shells (bash, ...), ignored by line-editors (readline, ...), and ignored by all applications (vim, less, mutt, ...). See #3.
Modify the terminfo entry for my terminal to ensure that at least one of the above (control code, standard escape sequence, or fixterms escape sequence) is ignored at all layers, as per [10]. Then, bind this modified sequence in tmux.
Invoke readline to do something magical. A long-shot as this is unlikely to have any effect on alternate-mode terminal applications.
The idea is to, as before, copy the terminal's selection to the clipboard buffer. Then insert <STRING> as if it had been typed. When tmux receives <STRING> it will overwrite the clipboard buffer with its own selection. Any other application will ignore it: including and especially having nothing printed to the terminal.
xterm -xrm "XTerm*vt100.translations: #override \n\
Ctrl Shift <Key>c: copy-selection(PRIMARY) string(<STRING>)
I'm also planning on extending this to gnome-terminal, so an example of writing the escape sequence or control character to the terminal's pts would be appreciated. I only use xterm as a working example - this question is definitely not xterm-specific.
https://stackoverflow.com/a/14876639
https://unix.stackexchange.com/a/116630
http://www.leonerd.org.uk/hacks/fixterms/
https://github.com/tmux/tmux/blob/master/xterm-keys.c
http://www.leonerd.org.uk/code/libtermkey/
https://stackoverflow.com/a/2179779
http://man7.org/linux/man-pages/man3/tcgetpgrp.3.html
https://github.com/tmux/tmux/blob/master/osdep-linux.c
https://invisible-island.net/xterm/manpage/xterm.html#h2-KEY-BINDINGS
Bind Ctrl+Tab and Ctrl+Shift+Tab in tmux
https://man.openbsd.org/ssh#ESCAPE_CHARACTERS
edit, new idea: SSH provides its own terminal emulator, or at least is hooked up to a pts pair[11]. Does that mean it can handle incoming escape sequences, and perhaps run an external remote command, such as one using tcgetpgrp? Or would that be an insecurity? Rather than configuring a possibly endless series of terminal applications to ignore an escape sequence, I'd prefer to configure only SSH as I would tmux.
All the available sequences will potentially look like a key of some kind to the application receiving it (for example, 0 is C-# and C-Space), there is no sequence that applications are guaranteed to ignore.
If I was you I'd just send the escape sequence for F20 or something and bind that key to do nothing in the other applications you use a lot.

How do I disable the weird characters from "bracketed paste mode" on the Mac OS X default terminal?

I encountered a problem with my terminal where when I paste text, it is prefixed by 00~ and suffixed with 01~.
For example, I will highlight text and push Command-C. I then push Command-V into the terminal and I see those weird characters pop up at the beginning and end of the text.
For example, I can highlight text and paste it into the terminal. I then see 00~text01~.
The text can be from anywhere, even from the Terminal itself. I do not have any copy/paste plugins installed, this is just the normal Copy/Paste. I am using the default Mac Terminal without any modifications.
I did some searching online, apparently the Paste wraps the text in special characters so that certain applications will see that this is pasted text and will handle it properly. However, the terminal is not handling this correctly, and is therefore not removing the weird characters. Apparently this paste mode is called the "Bracketed Paste Mode" http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Bracketed-Paste-Mode
I found another question that gave a solution on how to solve this issue on a linux machine, but after trying that solution I still have that same problem.
Can someone tell me how I can disable bracketed paste mode for the terminal? Or tell me the right way to get rid of these annoying characters?
What happens when text is pasted
Text has made it into the "system" (e.g. X, MacOS/Aqua) copy buffer from somewhere, maybe from the same terminal. The text is not altered here.
The text is pasted into the terminal; that is, "system" sees to that the terminal (e.g. xterm) receives the unaltered character sequence from the copy buffer. The terminal is aware that this is a paste, not keyboard input.
The terminal sends the char sequence in the buffer to the program running in the foreground (a shell, an editor, whatever). To the program the received data is indistinguishable from user input through the keyboard.
Discussion
This transparency (or opaqueness? whatever) is often a good thing much like the Unix paradigm of transparent pipe plumbing in general. But sometimes programs could deal with the data better if they knew it is pasted. For example an editor like vim could switch off auto indent — after all, the code is likely indented already!
Bracketed paste
Enter bracketed paste. For principal reasons the paradigm of transparent data piping cannot be altered; but the data can be decorated with sequences which would ordinarily not appear in terminal input to mark its start and end. If the terminal is so configured — for the xterm the configuration would be to send ESC [ ? 2 0 0 4 h — the pasted data is bracketed with escape sequences: ESC [ 2 0 0 ~ <buffer contents> ESC [ 2 0 1 ~.
The foreground program receives this "decorated" data, and it's up to to the program to handle it. A naive program treats all of it as user input, which is what you see.
A good discussion of bracketed paste can be found in this article.
Remedies
There are two issues in your case: The terminal ends up unexpectedly in bracketed paste mode; and the receiving program — presumably the shell — does not handle it.
One solution is user83536's: Identify the program which leaves the terminal in that state and call it through a wrapper which simply switches bracketed paste mode off again after the program has ended.
The program probably tried to switch bracketed paste mode off but failed. One reason can be that it sends the wrong escape sequence. Try setting the TERMINAL environment variable to the value best describing your terminal.
Try to switch off bracketed paste in the offending application. In vim one would say set t_BE=. That prevents vim from putting the terminal in bracketed paste mode and when it is set in a session, sends the "end bracketed paste mode" to the terminal.
Embrace bracketed paste. It seems to be a good idea. For the bash and other programs using readline one would put set enable-bracketed-paste on. For vim one could follow the suggestions here.
This may not apply directly to your problem, but I found this symptom to probably, in my case, be caused by my editor-of-choice 'mcedit' (Midnight Commander)
To alleviate the bug problem, I added the following function to my .bashrc file:
### vvv 'function mcedit' is a fix-up for the ~0/~1 paste problem
function mcedit() { command mcedit $# ; printf '\e[?2004l' ; }
Then 'source .bashrc'
Now every time I execute 'mcedit', it automatically adds the 'printf "\e[?2004l"' when I close out to reset the "Bracketed Paste Mode"
Works for me, YMMV.
To disable bracketed paste mode in your terminal, run the following command:
printf '\e[?2004l'
To disable bracketed paste globally, on Linux, add this line to ~/.inputrc :
set enable-bracketed-paste 0
To disable only in the current running Xterm (v 372) (running bash shell version 5.1.16 (probably earlier too, but I don't know)):
% bind 'set enable-bracketed-paste 0'
With either of the above two methods, you can re-enable bracketed paste (in the current Xterm) in the obvious way, namely:
% bind 'set enable-bracketed-paste 1'

How to bind multiple keys in gnu screen, specifically using arrow keys

First off, I'm using Opensuse 13.2 64-bit and also Arch_Linux 64-bit
Can't get the bind to work for either of them (well, the binds that I want), but I'm mostly focused on the Arch_Linux. Also, using openbox wm, xfce4-terminal. ( in opensuse using konsole and gnome 3) and my $TERM is set to xterm-256color in my ~/.bashrc and is switched to screen-256color when using screen in opensuse, but strangely is not changed in Arch.
I want to bind C-a down: to focus down, C-a up: to focus up, C-a left: to focus left etc.. Lets just focus on focus down for the moment.
I've tried everything in my ~/.screenrc file
bind "\E[B" focus down
bind "\EOB" focus down
bind "^[[B" focus down
bind "^[OB" focus down
bind "\033[B" focus down
bind "\033OB" focus down
bind "\033\133\102" focus down
bind j focus down # works fine
Nothing catches the down arrow key. I CAN use the following
bind -k kd focus down
however, I also want to bind multiple keys using the arrows and AFAIK the -k option only allows binding 1 key (or shift + left/right) . Actually I'm lucky I can even use the -k option since it is not documented.
Now I've checked my kd (termcap) and kcud1 (terminfo) using infocmp
infocmp -1 | grep kcud1
kcud1=\EOB,
infocmp -1C | grep kd
:kd=\EOB:\
and BTW these symbols can be looked up here for termcap and here for terminfo and its termcap equivelancies (actually I guess you can just use: man terminfo)
when I use Ctrl-v and press down arrow I get
^[[B
showkey -a
^[[B 27 0033 0x1b
91 0133 0x5b
66 0102 0x42
Anyone know how to go about this. I want to know why I can't use bind without the -k termcap_name and/or how to use combo of keys(such as ctrl/alt) and termcap names. Thanks for all and any info.
I've tried setting termcapinfo also with no luck. don't think I'm using it right.
termcapinfo * kd=\EOB
bind "\EOB" focus down
termcapinfo * kd=\E[B
bind "\E[B" focus down
etc...
It appears that GNU screen doesn't permit binding sequences of multiple keys.
Quoting the man page:
bind [-c class] key [command [args]]
Bind a command to a key.
...
The key argument is either a single
character, a two-character sequence of the form "^x" (meaning
"C-x"), a backslash followed by an octal number (specifying
the ASCII code of the character), or a backslash followed by a
second character, such as "\^" or "\". The argument can also
be quoted, if you like.
...
As said in this answer, try:
bindkey "^A^[OB" focus down
The vim trick is really helpful to get the code for the combinations you want (for example, if you wanted the combo Ctrla Ctrldown instead of Ctrla down, this would be ^[[1;5B instead of ^[OB).
Credit should go to koyae for the original answer.

Mapping numeric keypad keys in vim

I'm unable to get this mapping to work in vim inside an xterm terminal.
:map <k0> :echo 'Hello'<CR>
I can get the same mapping to work fine in gvim. If I issue the above command in vim on a terminal, it accepts it, and it shows up correctly when I type :map. But in normal mode, if I press the 0 keypad key, a "0" shows up on the status line, and then disappears with the next keypress.
I'm using the vim that came with Fedora 14 if that matters, and a plain xterm. The keypad keys work fine in insert mode, both with numlock on and off.
What am I missing?
Try to add this line to your ~/.Xdefaults:
xterm*appkeypadDefault: false
and relaunch xterm.
The "Application Keypad Mode" is likely the reason of your troubles.
But I don't think you should do what you are doing. In --NORMAL-- mode, numeric input is used to indicate "count" like in 4dd. Mapping numbers to other commands is going to get you into troubles fast.
You should add a xterm tag to your question.
There's some ambiguity in the question, which may indicate the actual problem. vim accepts that binding for k0 supposing that it is a function key.
Most keyboards that you'll see number function-keys starting at 1, and a few terminal descriptions equate function-key 1 to k0, a few equate it k0 to function-key 10. It's also possible that someone assumes that is part of the numeric keypad, but unlikely (since the keypad uses different character sequences than the function keys).
That's assuming you used a terminal description that knows about the function keys. The vt100 terminal description doesn't do that, since vt100's had no function keys (other than PF1 through PF4 which are or aren't depending who you talk to). But if you had TERM=vt100, then some of the numeric keypad could be recognized on the basis of the terminal description (see for instance the lengthy comment above the vt100+fnkeys description).
It's not in TERM=xterm, however.
What you're overlooking is that vim (helpfully perhaps) amends the terminal description using its built-in termcaps. It recognizes PF1, etc. using table entries like this:
{K_XF1, IF_EB("\033O*P", ESC_STR "O*P")},
{K_XF2, IF_EB("\033O*Q", ESC_STR "O*Q")},
{K_XF3, IF_EB("\033O*R", ESC_STR "O*R")},
{K_XF4, IF_EB("\033O*S", ESC_STR "O*S")},
But there are no entries for the numbered keys; there's no "\033O*p" for the 0 key.
If vim has (in the terminal description) the k0, and you haven't mapped it to anything, vim will treat it as a literal 0. The same happens with k1, etc., in effect treating the function-keys and numeric keypad as the same thing.
For what it's worth, GNU screen does the same thing, but also for the numbered keys. If I run vim inside screen, vim will see only the 0's. A literal 0 in vim doesn't do much in command-mode.

Backspace character weirdness

I wonder why backspace character in common Linux terminals does not actually erase the characters, when printed (which normally works when typed)..
This works as expected:
$ echo -e "abc\b\b\bxyz"
xyz
(\b evaluates to backspace, can be inserted also as Ctrl+V Ctrl+H - rendered as ^H (0x08))
but when there are less characters after the backspaces, the strange behavior is revealed:
$ echo -e "abc\b\b\bx"
xbc
it behaves like left arrow keys instead of backspace:
$ echo -e "abc\e[D\e[D\e[Dx"
xbc
erase line back works normally:
$ echo -e "abc\e[1Kx"
x
In fact, when I type Ctrl+V Backspace in terminal, ^? (0x7f) is yielded instead of ^H, this is Del ascii character, but Ctrl+V Del produces <ESC>[3~, but it is another story..
So can someone explain why printed backspace character does not erase the characters?
(My environment is xterm Linux and some other terminal emulators, $TERM == xterm, tried vt100, Linux as well)
What you are seeing is correct. Backspace or ^H moves the cursor to the left, no erasing. To erase a character, you need to output ^H ^H (Backspace-Space-Backspace).
To answer your comment - Backspace is defined that way in the VT100/ANSI family of terminals, from which a lot of terminal control code sequences borrow. See the VT100 user manual here which defines the function of BS as "Moves cursor to the left one character position, unless it is at the left margin, in which case no action occurs". In other words it's a quirk of history :)
As to why it was defined this way initially - I guess it's more flexible to have a non destructive cursor movement control code, as destructive backspace can be implemented as shown above.

Resources