Bash : Autocompletion, echo and cursor movement - bash

I am trying to code an autocomplete script. It should also outputs some description. I have one function that manage the autocompletation AND the fetching of the description. The autocompletion related part works fine but i have an issue when i want to display the help. In short, this is what i have now :
$> myFunction -myOption1<TAB>
Description for myOption1<CURSOR>
What i woud like :
$> myFunction -myOption1<TAB>
Description for myOption1
$> myFunction -myOption1<CURSOR>
There is no conflict between the autocompletion and the output. The description can only be displayed when the myOption1 is complete. (myOpt will be completed as myOption1 and hence, does not display the description). I made severals attempts to make it work but i guess i am missing a step. The "Description for myOption1" is an 'echo'. I think it's related because compgen is waiting for some value (I give it none for the moment). I tried to trick compgen with some escape characters, spaces : no successes. The autocomplete script should continue to run after this description.
Thanks in advance for the help ;-)
Kol

What I would do:
set COMPREPLY in every case (you don't want to mess with it). (move out of the else)
before messing the screen, I would do a tput sc before the echo, and tput rc afterwards. Note, that will still screw up your screen if your terminal scrolls because of your echo

Related

How can I add a vertical space in 'Terminal' after each command?

I've just started using Terminal (the CLI for Mac OS X).
When I run a command, get some information back, run another command, get more info etc., it is hard (on the eyes) to find a certain point on the screen (e.g. the output for the command before last).
Is there a way of adding a vertical empty space to the end of each output/ after each command is run that has no output?
Each new command that you enter is preceded by a "prompt", and these can be customized (though the exact way to customize depends on the shell). Since you mention Mac OS X I'm assuming you are using the default bash shell, in which case the absolute simplest way to add a blank line is like this: PROMPT_COMMAND=echo. You can run that command to try it out, or add it to a startup file (like .profile in your home folder) to have it done automatically each time.
If you use Bash 4.4 and you want a blank line after your prompt, you could set the PS0 prompt to a newline:
PS0="\n"
Now, this will be inserted every time you run a command:
$ echo "Hello"
Hello
Wondering this too, I've looked at the menu options in Terminal & most of the control characters one can type in and nothing does this on a keystroke. You can however enter an echo command, it alone to leave a single blank line below it before the next prompt. echo \n will add an extra blank line to that, echo \n\n to do 2 extra, ie. 3 blank lines, etc. (you can also do echo;echo;echo getting the same effect)
You can create a shell alias like alias b='echo;echo' (i couldn't seem to get the \n notation to work in a alias), then entering b on a prompt will leave a double-blank line, not bad. Then you gotta figure out how to save aliases in your .profile script.
I tried making an alias for the command ' ' ie. space character, which I though you could type like \ (hmm, stack overflow not formatting this well, that's backslash followed by a space, then return to execute it), but the bash shell doesn't seem to allow an alias with that name. It probably wouldn't allow a function named that either (similar to alias), though I didn't check.
I often use the fish shell, and I found that it does allow a function with that name! Created with function ' '; echo \n; end and indeed it works; at the shell prompt, typing the command \ (again backslash space) leaves a double blank line.
Cool, but.. I tried saving this function using funcsave ' ' (how you save functions in fish, no messing with startup scripts!) and afterwards the function no longer works :^( This is probably a bug in the fish shell. It's in active development right now though, I think I'll report this as a bug since I would kind of like this to work myself.
One could also send Apple a feature request through their bug reporter for an Insert Blank Line menu/keyboard command in Terminal. If someone pays attention to your request it might be implemented in a year maybe.
I wanted to solve exactly the same, and for anyone interested in doing the same, I used what tripleee said in his comment here - I created a .bash_profile (see details here) with the line export PS1="\n\n$ ".
Hopefully that helps someone else too!

OS X Terminal text stacking on top of itself

I'm encountering a strange issue in the Terminal app in Mac OS X Lion. When I enter in a long line of text that should wrap to the next line when it reaches the edge of the Terminal window, it continues to type on top of the text from the line above it.
Here are some screenshots to help illustrate the issue:
Before my text reaches the window edge:
After the text reaches the window edge:
I've also supplied screenshots of my text and window settings in case those might be helpful.
Text settings:
Window settings:
Thanks in advance for any assistance offered. I've had this issue for a while and just never got around to it. It's now really becoming a pain in the ass when I get into things that require big grep commands and long path names.
PS1 environment variable determines what shell's prompt will look like. man bash gives full documentation on it. (There are actually several of them, for different modes).
There are number of files that may be setting it, usually one of ~/.profile, ~/.bashrc, /etc/profile or /etc/bashrc.
If you're going to have color codes or other control sequences inside it, you must wrap them with \[ and \] properly (and NOT wrap normal text), otherwise line editing may become messed up like in your case. I suggest resetting PS1 to the default value then carefully adding coloring back item by item.
For example:
PS1='\[\033[1m\033[32m\]\u#\h \w\[\033[0m\]\$ '
^^^^^^^^^^^^^^^ ^^^^^^^
Coloring commands are underlined. Note how they are surrounded with \[ \].
I have the same problem, i found if you change
Advanced > Emulation > Declare terminal as: ANSI.
This solves colored PS1 problem. With Mac Terminal
BUT creates a strange behavior:
I found a solution to my problem with #koiyu answer.
https://apple.stackexchange.com/questions/37001/strange-behavior-in-terminal-with-custom-bash-profile/37036#37036
I used to have the same issue due to incorrectly using color codes. Here is my PS1 which solved the issue. Also if you use GIT, then this will be also helpful to show git branch you are working on and if your working tree is dirty or not. Put this in your .profile or .bash_profile
# Git branch in prompt.
parse_git_branch() {
git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/'
}
parse_git_dirty() {
st=$(git status 2>/dev/null | tail -n 1)
if [[ $st == "" ]]; then
echo ''
elif [[ $st == "nothing to commit (working directory clean)" ]]; then
echo ''
elif [[ $st == 'nothing added to commit but untracked files present (use "git add" to track)' ]]; then
echo '?'
else
echo '*'
fi
}
# coloring the terminal comman line
SB_GREEN="\[\033[1;32m\]"
SB_BLUE="\[\033[1;34m\]"
SB_RED="\[\033[1;31m\]"
SB_NOCOLOR="\[\033[0m\]"
export PS1="$SB_GREEN\u#\h$SB_NOCOLOR: $SB_BLUE\w$SB_GREEN\$(parse_git_branch)$SB_RED\$(parse_git_dirty)$SB_NOCOLOR $ "
Hope this helps.
With the guidance of hamstergene I was able to figure out how to make it play nice. Using this Geek Stuff guide and this It's Me Tommy tutorial, I was able to define how I wanted my PS1 text to display. Changing this to something much more simplified eliminated the weird overlapping text issue I was running into.
Before:
After:
I simply edited my .bash_profile and added the following line:
export PS1="[\u#\h] > ";
Then I went and changed the window colors for good measure because I can.
The original issue was that there was a new line in the PS1 (FYI for anybody running into this)
Typically its improperly escaped color codes, but if its not that its that you have a new line in your ps1
As others have said, you have to properly wrap your color commands in escaped square brackets. However, for me, this makes the string really, really confusing to look at!
As such, here's a trick I use to always get it right and also make it much more readable.
I first create a shell function called setColor like so...
setColor(){
echo "\[\033[${1}m\]"
}
Then I use it like this...
PS1="$(setColor 92)\u$(setColor 37):$(setColor 96)\w $(setColor)\$ "
That's the same as writing this...
\[\033[92m\]\u\[\033[37m\]:\[\033[96m\]\w \[\033[m\]$
...but as you can see, the former is much clearer and also guarantees everything's properly escaped.
Note, you can specify multiple colors too by using the ; character. The only thing is you have to explicitly escape it, so 92;41 becomes 92\;41, like so...
PS1="$(setColor 92\;41)\u$(setColor 37):$(setColor 96)\w $(setColor)\$ "
Again, still easier to read than this...
\[\033[92;41m\]\u\[\033[37m\]:\[\033[96m\]\w \[\033[m\]$
You can take this a step further by defining constants for the colors, or even 'wrapper' functions with the color names you use most, so you can write this...
PS1="$(setRed)\u$(setBlue):$(setGreen)\w $(resetColor)\$ "
Hope this helps!

ZSH auto-complete screws up command name

When I start doing tab auto-complete of a command, it keeps what I initally typed next to it and the command becomes unreadable. In the example below, I typed 'git che' and hit tab. Once I select 'checkout' the command prompt becomes 'git che git checkout'. The command still works and in my history it stores 'git checkout'. But its pretty annoying visually. Is there anyway to change this behavior. I tried this in 2 different terminal emulators, so I can confirm its ZSH and not the emulator. Thanks
Screenshot
EDIT:
echo $ZSH_VERSION
4.3.10
It doesnt seem to happen with zsh -f. Though its hard to tell since the only autocomplete that works is directories. I'm using 'oh-my-zsh' with this custom theme:
autoload -U add-zsh-hook
add-zsh-hook chpwd do_ls_on_chdir
function do_ls_on_chdir() {
ls;
}
function dirStack(){
OUT='';
NUM=1;
for X in $(dirs | cut -d ' ' -f2-10); do
OUT="$OUT$1%B$NUM:%b$1$X ";
(( NUM=NUM+1 ))
done
echo $OUT;
}
ZSH_THEME_GIT_PROMPT_ADDED=""
ZSH_THEME_GIT_PROMPT_MODIFIED=""
ZSH_THEME_GIT_PROMPT_DELETED=""
ZSH_THEME_GIT_PROMPT_RENAMED=""
ZSH_THEME_GIT_PROMPT_UNMERGED=""
ZSH_THEME_GIT_PROMPT_UNTRACKED=""
ZSH_THEME_GIT_PROMPT_AHEAD="%{$fg_bold[yellow]%}↑"
ZSH_THEME_GIT_PROMPT_PREFIX=""
ZSH_THEME_GIT_PROMPT_SUFFIX=""
ZSH_THEME_GIT_PROMPT_DIRTY=" %{$fg_bold[red]%}✗"
ZSH_THEME_GIT_PROMPT_CLEAN=" %{$fg_bold[green]%}✔"
local user_color='blue'
local back="${BG[237]}"
test $UID -eq 0 && user_color='red'
PROMPT='$(dirStack $back)
$back%B%!%b$back %{$fg_bold[$user_color]%}%~%{$reset_color%}'\
'$back $(git_prompt_status)%{$reset_color%}'\
'$back%{$fg_bold[magenta]%}$(git_prompt_info)%{$reset_color%}'\
'$back$(git_prompt_ahead)$reset_color'\
'$back%(!.#.>)$reset_color '
PROMPT2='%{$fg[red]%}%_ %{$reset_color%}'
PROMPT3='%{$fg[red]%}... %{$reset_color%}'
RPROMPT='%(?..%{$fg_bold[red]%}exit %?%{$reset_color%})'\
' %{$FG[186]%}(%D %*)%{$reset_color%}'
SOLUTION:
NOTE: stackoverflow wont let me answer my own question since I asked it within the past 8 hours. I dont feel like waiting.
So I figured it out. It turns out I wasnt properly escaping the ANSI color codes (I think). Everywhere I had $reset_color in my PROMPT variable, I changed that to %{$reset_color%} and it fixed it.
So I figured it out. It turns out I wasnt properly escaping the ANSI color codes (I think). Everywhere I had $reset_color in my PROMPT variable, I changed that to %{$reset_color%} and it fixed it.
I only discovered this link tonight, after messing with my prompt - I'd always wondered why the ZSH prompt examples seemed so needlessly complex.
When you set up the colors in your zsh prompt, you should escape things with %{ [...] %}, so that 'the shell knows there is no output from these sequences and the cursor hasn't moved'.
If you don't escape this, the shell believes that your cursor has moved (even though it hasn't). This leads to messed up prompts, and rather annoying visual effects when you use tab-completion etc.
Here's some screenshots without escaping the reset-color prompt sequence (PR_NO_COLOUR="%{$terminfo[sgr0]%}", in my prompt settings). As we can see, the cursor starts in the wrong place:
It should be here:
And after trying tab-completion without escaping, the prompt is all confused about where the text is, and where the cursor should be placed:
(The cursor should be placed at the end of the directory, not halfway through).
So the prompt sequences look like this:
PS1="%{$fg[red]%}%n%{$reset_color%}#%{$fg[blue]%}%m %{$fg[yellow]%}%~ %{$reset_color%}%% "
because everything has to be escaped nicely inside %{...%} pairs.

Shell Prompt Line Wrapping Issue

I've done something to break my Bash Shell Prompt in OS X (10.5.7) Terminal.
This is the PS1 that I had configured:
PS1='\[\e[1;32m\]\h\[\e[0m\]:\[\e[1;34m\]\w\[\e[0m\]\$ '
As far as I can tell I have the color commands escaping correctly. However when I scroll up and down in my command history I often get line wrapping issues if the historic commands wrap onto multiple lines.
I simplified my prompts to the following:
PS1='\[\e[1m\]\h:\w\$ \[\e[0m\]'
PS2='> '
And I still see something like:
localhost:~/Library/Application Support/Firefox/Profiles/knpmxpup.Defau
lt/extensions/{1A2D0EC4-75F5-4c91-89C4-3656F6E44B68}$ expocd \{1A2D0EC4-7
5F5-4c91-89C4-3656F6E export PS1="\[
\e[1;32m\]\h\[\e[0m\]: cd Library/Appl
ication\ Support/
I've also tried \033 instead of \e. I just included PS2 up there for information, I haven't changed that from the install default. If I completely remove the color codes then everything works fine, any ideas?
I am now using this PS1 with good effect:
green=$(tput setaf 2)
blue=$(tput setaf 4)
bold=$(tput bold)
reset=$(tput sgr0)
PS1="\[$green$bold\]\h\[$reset\]:\[$blue$bold\]\w\[$reset\]\$ "
Scrolling through my command history appears to handle line wraps now. However in the meantime since this question was asked I have also updated my OS X to 10.6.3
This stackoverflow thread seems relevant. As someone noted in that thread, the Bash FAQ at mywiki.wooledge.org discusses how to properly quote color codes in Bash prompts (FAQ 53), and the proper invocation of terminal colors (FAQ 37).
Line wrapping issues in Bash are nothing new. Your PS1 should work as is but there is a bug in Bash 3.2.49. Consult the mailing list, there's yet another bug regarding this which was confirmed to be fixed in 4.0.
You can't do much more than tagging unprintable characters with \[ and \], the rest must be done by the prompting code.
It seems that you have correctly escaped and enclosed sequences.
A workaround I use anyway it it to add a '\n' at the end. I find it clearer and lessen any problem with wrapping issues. The exact end of my PS1 is :
'\n\[\033[0;30m\]$\[\033[0m\]
An excellent howto you probably know :
Bash prompt howto
I noticed that there are some issues with the prompt cursor positioning even if there are no special character in the PS1 or PROMPT environment variable.
If we output a file that does not have a end-of-line char at the end. It will confuse the prompt.
You can reproduce this by doing:
curl https://gist.githubusercontent.com/martinos/d4aa0a7d4d752b0d0d9f/raw/3198c39f84a080c44227a084a19fb3a0bb661ee5/wrapping_issue.txt
and pressing the up key multiple times and you will see that the prompt get confused.
You can see an example of this in action:
https://asciinema.org/a/9mtjhi9dib6md4ocsbw210cca
When this occurs, just press <CTRL-C> and the prompt will come back to normal.
Note that ZShell does not have this issue.
For future reference, this is what I use:
export PS1="\[\033[0;31m\][\u#Project:\w]$\[\033[0m\] "
This would display my shell prompt as:
[ec2-user#Project:~]$
Helps me distinguish between live and dev sites.
Here's mine: it's the best one I've found, but the site where I originally found it was missing an escape character, leading to the line wrapping issue. I tinkered with it and finally got it working. It shows your user, path, and branch info with good contrast, color-wise.
export PS1='\[\e[1;37m\]\[\e[1;32m\]\u\[\e[0;39m\]:\[\e[1;33m\]\w\[\e[0;39m\]\[\e[1;35m\]$(__git_ps1 " (%s)")\[\e[0;39m\] \[\e[1;37m\]|\[\e[0;39m\]\$'
Also, add
GIT_PS1_SHOWDIRTYSTATE=true
To show a marker when a branch is "dirty" (changes to be committed exist)
export HISTCONTROL=ignoredups
Is also useful to ignore duplicates when scrolling up through bash history.
bind "set completion-ignore-case on"
Helps too.
Lastly,
shopt -s checkwinsize
May be helpful on OSX if issues persist.
'shopt -s checkwinsize' also works for Cygwin wrap problems also
If you're using the title bar trick "\e]2;titlebar\a", make sure to escape that too: "\[\e]2;titlebar\a\]"

Going backwards in a bash prompt

I'd like to have a blank line after my bash prompt and before the output on my Mac. It should look like this would:
echo; ls
Can I add a newline to my bash prompt and then go back up one line to wait for user input? Is there something obvious I'm missing?
I know this is old but for someone like me who came across this while googling for it. This is how you do this...
It's actually pretty simple!
Check out this link --> Cursor Movement
Basically to move up N number of lines:
echo -e "\033[<N>A HELLO WORLD\n"
Just change the "< N >" to however many lines you want to go back...
For instance, to move up 5 lines it would be "/033[5A"
To my knowledge this is not possible unless you delve into more low-level stuff like full-screen emulators like curses.
This is a bit of a stab in the dark, but you may be able to use VT102 terminal codes to control the cursor without having to use Curses. The relevant VT102 commands that you'd be interested in all consist of sending ESC, then [, then the specific command parameters.
For instance, to move the cursor up one line, one needs to output:
ESC [ 1 A
0x1B 0x5B 0x31 0x41
Be warned that the VT102 documentation generally uses octal, so keep an ascii table handy if you're using hex.
All of this advice is given without having tested it -- I don't know if VT102 commands can be embedded into your bash prompt, but I thought it might be worth a shot.
Edit: Yeah -- looks like a lot of people use VT102 formatting codes in their bash prompts. To translate my above example into something Bash would recognize, putting:
\e[1A
into your prompt should move the cursor up one line.
This is very possible. If your bash has C-v set as the readline quoted-insert command, you can simply add the following to your ~/.inputrc:
RETURN: "\C-e\C-v\n\C-v\n\n"
This wil make bash (readline, actually) insert two verbatim newlines before a regular interpreted newline. By default, only one is inserted, which is what causes output to start on the line after the prompt.
You can test if C-v is set to quoted-insert by typing it in bash (that's Ctrl+V) followed by e.g. an up arrow. This should print ^[[A or something similar. If it doesn't, you can bind it in ~/.inputrc too:
C-v: quoted-insert
RETURN: "\C-e\C-v\n\C-v\n\n"
~/.inputrc can be created if it doesn't exist. The changes will not take effect in running bashes unless you issue a readline re-read-init-file command (by default on C-x C-r). Be careful though. If you do something wrong, enter will no longer issue commands, and fixing your mistake could prove to be difficult. If you should do something wrong, C-o will by default also accept the line.
Adding a newline followed by moving the cursor back to the regular prompt (like you described) is possible, but will not have the effect you intend. The newline you inserted would simply be overwritten by the application output, since you moved the cursor back in front of it.
This works:
trap echo DEBUG
It doesn't add an extra newline if you hit return at an empty prompt.
The command above will cause a newline to be output for every member of a pipeline or multi-command line such as:
$ echo foo; echo bar
\n
foo
\n
bar
To prevent that so that only one extra newline is output before all command output:
PROMPT_COMMAND='_nl=true'; trap -- '$_nl && [[ $BASH_COMMAND != $PROMPT_COMMAND ]] && echo; _nl=false' DEBUG
The DEBUG trap is performed before each command so before the first command it checks to see if the flag is true and, if so, outputs a newline. Then it sets the flag to false so each command afterwards on the line doesn't trigger an extra newline.
The contents of $PROMPT_COMMAND are executed before the prompt is output so the flag is set to true - ready for the next cycle.
Because pressing enter on an empty command line still triggers the execution of the contents of $PROMPT_COMMAND the test in the trap also checks for those contents as the current command and doesn't perform the echo if they match.
I believe (but haven't tried) if you put '\n\b' in the prompt string it would do that.
In general, if you want to find out the codes to do anything a terminal can do, read the terminfo man page.
In this case, the cursor up one line code can be determined by:
tput cuu1
If you redirect the tput output to a file, you can see what control characters are used.
Bash also supports the PROMPT_COMMAND variable, allowing you to run arbitrary commands before each prompt is issued.

Resources