Having been dragged into the 21st century by macOS Catalina now defaulting to zsh instead of bash for its shell, I'm trying to restore some of the bash's line editing behavior. Specifically, if I am at the end of the line:
bash$ ls /foo/bar/baz
and I hit Alt-Left Arrow, the cursor jumps to "baz", then "bar", then "foo". It is treating the slash as a word delimiter, as do most environments (such as Safari and apps that use Cocoa text editing features).
In zsh, when I try to do the same thing, the first Alt-Left Arrow jumps the cursor all the way back to the beginning of "/foo/bar/baz", which makes it much less useful for editing parts of a long directly.
Can this be configured in zsh? If so, how?
Characters in zsh variable WORDCHARS are considered part of a word.
You just need to remove / from it
% echo "$WORDCHARS"
*?_-.[]~=/&;!#$%^(){}<>
% WORDCHARS="${WORDCHARS/\//}"
# Now Alt-left-arrow will stop at /
Just be aware that $WORDCHARS is used in other situations as well. See man zshall
Related
I recently added some color to my bash prompt, and now when I type a command the text doesn't wrap properly.
Here is an example:
MacBook-Pro:~ williamgiles$
long commandwilliamgiles$ this is a really long command,this is a really
My original PS1:
\h:\W \u\$
My new one with color:
\e[0;35m\h:\W \u$ \e[m
You need to mark the color-changing sequences as something that does not contribute to the length of the prompt on-screen.
PS1='\[\e[0;35m\]\h:\W \u$ \[\e[m\]'
bash already knows to take the expansion of \h, \W, and \u into account; it has no idea that \e[0;35m is not simply 7 characters that the terminal will display on screen.
Adding to #chepner's answer, I personally use \1 and \2 in my .inputrc
Here's an example:
set vi-ins-mode-string \1\e[38;5;015m\2╰─\1\e[0m\2\1\e[38;2;191;254;33m\2(ins)⫸\1\e[0m\2\1\e[5 q\2\1\e]12;rgb:bf/fe/21\e\\\2
set vi-cmd-mode-string \1\e[38;5;015m\2╰─\1\e[0m\2\1\e[38;2;191;121;33m\2(cmd)⫸\1\e[0m\2\1\e[2 q\2\1\e]12;rgb:bf/79/21\e\\\2
\1 denotes the start of a zero-length section, and \2 denotes the end.
(\001 and \002 also work)
I wrote a blog post about the topic not long ago. You might find it interesting.
What my shell ends up looking like (The top part is possible by using Oh-My-Posh:
When I use my terminal (iTerm 2 Mac) with my PS1 set to "\[\e[38;5;117m\W \e[39;38;5;104m\$\e[39;0m\] " and I use the arrow keys to go through my bash history it sometimes changes my prompt from ~ $ to just the first character of it and whatever command I'm looking at. For example, going to rvim .bashrc from randomDir $ ls. This problem also persists in the default terminal app.
\W and \$ should not go inside the \[...\], since bash will know how much space each takes up on the terminal.
PS1="\[\e[38;5;117m\]\W \[\e[39;38;5;104m\]\$\[\e[39;0m\] "
Only the characters that make up the ANSI escape sequence (which only instruct the terminal to change colors, without displaying a single additional character) are enclosed in \[...\].
Putting them inside \[...\] tells bash to ignore their contribution to the length of the prompt, leading to incorrect redraws.
I'm giving a second try to the fish shell. One thing that really annoys me is the "new" behaviour of Ctrl+w shortcut.
Consider following situation:
$ vim ~/.config/fish/config.fish
...having the cursor at the end of the line.
When you press Ctrl+w, following happens:
in bash: ~/.config/fish/config.fish is deleted
in fish: only config.fish is deleted
How can I make fish delete words that are separated by spaces only?
"\cw" (in fish's notation) is bound to "backward-kill-path-component" (which bind \cw will tell you).
If you wish, you can bind it to something else, including input functions like "backward-kill-word" or any fish script - bind \cw backward-kill-word or bind \cw "commandline -rt ''" (which will remove the entire current token) or bind \cw backward-kill-bigword. See the bind documentation or bind --help for more information.
The difference between "word" and "bigword" here is that "word" will only go to the next non-word-character, which can be a "." or "/" or "-", among others, while "bigword" will truly go to the next whitespace character.
Note that the "bigword" functions have only been introduced in fish 2.3.0.
You can try these incantations in an interactive shell. If you decide to make it permanent, you'll need to add them to a function called fish_user_key_bindings.
When cycling through statements entered to the console, I occasionally find that the text I entered isn't refreshed and the prompt is moved to the right.
My original, intended prompt: http://cl.ly/image/04080N260L1V.
What happens after hitting the Up and Down arrows about a dozen times: http://cl.ly/image/1n3S2K31340R.
In case the screenshots aren't clear, the underlined text (in this case, "vim ~/.bas") is getting "added" to the prompt. I can't delete it out. However, if I delete as much as I can, clearing any text after the prompt, and hit Enter, I'm greeted with my clean, original prompt again: http://cl.ly/image/2O1h1Z2y0n2I.
Here's what ~/.bash_profile contains:
# Simpler bash prompt in Terminal.app
promptColor="\e[1;34m"
endColor="\e[m"
#export PS1='\e[0;36m\w$ \e[0m'
export PS1="$promptColor\w$ $endColor"
# Syntax highlighting for commands like `ls` and such
alias ls="ls -G"
# PATH ammendment to put Homebrew-installed apps in front of system-provided ones
homebrew=/usr/local/bin:/usr/local/sbin:/usr/local/share/npm/bin
export PATH=$homebrew:$PATH
I've narrowed the culprit down to the PS1 variable. (You can see I've tried this a few different ways.) Based on what I've read, I'm using the color codes correctly.
Any help would be fantastic. Thanks.
This is a FAQ. In order for Bash to be able to compute the display length of the prompt correctly, any non-printing sequences such as color codes need to be inside a \[...\] sequence.
I think you want:
promptColor='\e[1;34m'
endColor='\e[m'
export PS1="$promptColor"'\w$ '"$endColor"
(Notice all the subtle changes from double to single-quotes)
The problem is that bash is doing expansion on the following when they need to be interpreted explicitly:
\e[1;34m
\w$
\e[m
Single-quotes and double-quotes mean different things in shell: Strong Quoting vs. Weak Quoting.
I would also just copy and paste the lines with escaped characters and modify them (note that they aren't the same as literal representations)
Okay, I am sure this is simple but it is driving me nuts. I recently went to work on a program where I have had to step back in time a bit and use Redhat 9. When I'm typing on the command line from a standard xterm running KornShell (ksh), and I reach the end of the line the screen slides to the right (cutting off the left side of my command) instead of wrapping the text around to a new line. This makes things difficult for me because I can't easily copy and paste from the previous command straight from the command line. I have to look at the history and paste the command from there. In case you are wondering, I do a lot of command-line awk scripts that cause the line to get quite long.
Is there a way to force the command line to wrap instead of shifting visibility to the right side of the command I am typing?
I have poured through man page options with no luck.
I'm running:
XFree86 4.2.99.903(174)
KSH 5.2.14.
Thanks.
Did you do man ksh?
You want to do a set -o multiline.
Excerpt from man ksh:
multiline:
The built-in editors will use multiple lines on the screen for
lines that are longer than the width of the screen. This may not
work for all terminals.
eval $(resize) should do it.
If possible, try to break the command down to multiple lines by adding \
ie:
$ mycommand -a foo \
-f bar \
-c dif
The simple answer is:
$ set -o multiline
ksh earlier than 5.12, like the ksh shipped with NetBSD 6.1, doesn't have this option. You will have to turn off current Interactive Input Line Editing mode, which is usually emacs:
$ set +o emacs
This turns off a lot of featuers altogether, like tab-completion or the use of 'Up-arrow' key to roll back the previous command.
If you decide to get used to emacs mode somehow, remember ^a goes to the begining of the line ("Home" key won't workk) and ^e goes to the end.
I don't know of a way of forcing the shell to wrap, but I would ask why you'd be writing lines that long. With awk scripts, I simply wrap the script in single quotes, and then break the lines where I want. It only gets tricky if you need single quotes in the script -- and diabolical if you need both single and double quotes. Actually, the rule is simple enough: use single quotes to wrap the whole script, and when you want a single quote in the script, write '\''. The first quote terminates the previous single-quoted string; the backslash-single quote yields a single quote; and the last single quote starts a new single quoted string. It really gets hairy if you need to escape those characters for an eval or something similar.
The other question is - why not launch into an editor. Since I'm a die-hard vim nutcase (ok - I've been using vi for over 20 years, so it is easier for me than the alternatives), I have Korn shell set to vi mode (set -o vi), and can do escape-v to launch the editor on whatever I've typed.
This is kind of a pragmatic answer, but when that's an issue for me I usually do something like:
strings ~/.history | grep COMMAND
or
strings ~/.history | tail
(The history file has a little bit of binary data in it, hence 'strings')