Explanation of all uses of the escape character in Unix terminals - unix

I'd like to know all of the special uses of the escape character in Unix terminals, by which I mean the character \e. I know about colors and \ec which clears the screen in a scrollable terminal, what others are there and what do they do? For instance, what does this string do: echo -e "\e[3;12r\e[3H"?

That particular example (both by the way are VT100 escapes where \e is used in some shells to mean the ASCII escape character):
sets scrolling margins to lines 3 through 12 (starting from 1), and
moves the cursor to the beginning of line 3 (putting it at the top of the scrolling margins)
By the way, \ec resets the terminal. Clearing the screen is just one of several things done.
Further reading:
XTerm Control Sequences
vt100.net

Related

How to replace a string pattern with different strings quickly?

For example, I have many HTML tabs to style, they use different classes, and will have different backgrounds. Background images files have names corresponding to class names.
The way I found to do it is yank:
.tab.home {
background: ...home.jpg...
}
then paste, then :s/home/about.
This is to be repeated for a few times. I found that & can be used to repeat last substitute, but only for the same target string. What is the quickest way to repeat a substitute with different target string?
Alternatively, probably there are more efficient ways to do such a thing?
I had a quick play with some vim macro magic and came up with the following idea... I apologise for the length. I thought it best to explain the steps..
First, place the text block you want to repeat into a register (I picked register z), so with the cursor at the beginning of the .tab line I pressed "z3Y (select reg z and yank 3 lines).
Then I entered the series of VIM commands I wanted into the buffer as )"zp:.,%s/home/. (Just press i and type the commands)
This translate to;
) go the end of the current '{}' block,
"zp paste a copy of the text in register z,
.,%s/home/ which has two tricks.
The .,% ensures the substitution applies to everything from the start of the .tab to the end of the closing }, and,
The command is incomplete (ie, does not have a at the end), so vim will prompt me to complete the command.
Note that while %s/// will perform a substitution across every line of the file, it is important to realise that % is an alias for range 1,$. Using 1,% as a range, causes the % to be used as the 'jump to matching parenthesis' operator, resulting in a range from the current line to the end of the % match. (which in this example, is the closing brace in the block)
Then, after placing the cursor on the ) at the beginning of the line, I typed "qy$ which means yank all characters to the end of the line into register q.
This is important, because simply yanking the line with Y will include a carriage return in the register, and will cause the macro to fail.
I then executed the content of register q with #q and I was prompted to complete the s/home/ on the command line.
After typing the replacement text and pressing enter, the pasted block (from register z) appeared in the buffer with the substitutions already applied.
At this point you can repeat the last #qby simple typing ##. You don't even need to move the cursor down to the end of the block because the ) at the start of the macro does that for you.
This effectively reduces the process of yanking the original text, inserting it, and executing two manual replace commands into a simple ##.
You can safely delete the macro string from your edit buffer when done.
This is incredibly vim-ish, and might waste a bit of time getting it right, but it could save you even more when you do.
Vim macro's might be the trick you are looking for.
From the manual, I found :s//new-replacement. Seemed to be too much typing.
Looking for a better answer.

Multiline prompt formatting incorrectly due to date command in zsh

I have the following in my .zshrc:
setopt PROMPT_SUBST
precmd(){
echo""
LEFT="$fg[cyan]$USERNAME#$HOST $fg[green]$PWD"
RIGHT="$fg[yellow]$(date +%I:%M\ %P)"
RIGHTWIDTH=$(($COLUMNS-${#LEFT}))
echo $LEFT${(l:$RIGHTWIDTH:)RIGHT}
}
PROMPT="$ "
This gives me the following screenshot
The time part on the right is always not going all the way to the edge of the terminal, even when resized. I think this is due to the $(date +%I:%M\ %P) Anyone know how to fix this?
EDIT: Zoomed in screenshot
While your idea is commendable, the problem you suffer from is that your LEFT and RIGHT contains ANSI escape sequences (for colors), which should be zero-width characters, but are nevertheless counted toward the length of a string if you naively use $#name, or ${(l:expr:)name}.
Also, as a matter of style, you're better off using Zsh's builtin prompt expansion, which wraps a lot of common things people may want to see in their prompts in short percent escape sequences. In particular, there are builtin sequences for colors, so you don't need to rely on nonstandard $fg[blah].
Below is an approximate of your prompt written in my preferred coding style... Not exactly, I made everything super verbose so as to be understandable (hopefully). The lengths of left and right preprompts are calculated after stripping the escape sequences for colors and performing prompt expansion, which gives the correct display length (I can't possibly whip that up in minutes; I ripped the expression off pure).
precmd(){
local preprompt_left="%F{cyan}%n#%m %F{green}%~"
local preprompt_right="%F{yellow}%D{%I:%M %p}%f"
local preprompt_left_length=${#${(S%%)preprompt_left//(\%([KF1]|)\{*\}|\%[Bbkf])}}
local preprompt_right_length=${#${(S%%)preprompt_right//(\%([KF1]|)\{*\}|\%[Bbkf])}}
local num_filler_spaces=$((COLUMNS - preprompt_left_length - preprompt_right_length))
print -Pr $'\n'"$preprompt_left${(l:$num_filler_spaces:)}$preprompt_right"
}
PROMPT="$ "
Edit: In some terminal emulators, printing exactly $COLUMN characters might wrap the line. In that case, replace the appropriate line with
local num_filler_spaces=$((COLUMNS - preprompt_left_length - preprompt_right_length - 1))
End of edit.
This is very customizable, because you can put almost anything in preprompt_left and preprompt_right and still get the correct lengths — just remember to use prompt escape sequence for zero width sequences, e.g., %F{}%f for colors, %B%b for bold, etc. Again, read the docs on prompt expansion: http://zsh.sourceforge.net/Doc/Release/Prompt-Expansion.html.
Note: You might notice that %D{%I:%M %p} expands to things like 11:35 PM. That's because I would like to use %P to get pm, but not every implementation of strftime supports %P. Worst case scenario: if you really want lowercase but %P is not supported, use your original command subsitution $(date +'%I:%M %P').
Also, I'm using %~ instead of %/, so you'll get ~/Desktop instead of /c/Users/johndoe/Desktop. Some like it, some don't. However, as I said, this is easily customizable.

ZSH prompt substitution issues

I've searched through several answers here and through Google, but I'm still not sure what's going wrong with my prompt.
According to the documentation I've read, this should work
setopt prompt_subst
autoload -U colors && colors
PROMPT="%{[00m[38;5;245m%}test %D%{[00m%}"
My prompt is the following, however:
[00m[38;5;245mtest 15-07-01[00m
Note that the date expansion actually worked, so prompt substitution is working. The ZSH man pages for prompt expansion states that %{...%} should be treated as a raw escape code, but that doesn't seem to be happening. Passing that string to print -P also results in the output above. I've found example prompts on the Internet for ZSH that also seem to indicate that the above syntax should work. See this for one example - the $FG and $FX arrays are populated with escape codes and are defined here. I've tried this example directly by merging both the files above, adding setopt prompt_subst to the beginning just to make sure it's set, then sourcing it and the prompt is a mess of escape codes.
The following works
setopt prompt_subst
autoload -U colors && colors
PROMPT=$'%{\e[00m\e[38;5;245m%}test %D%{\e[00m%}'
I get the expected result of test 15-07-01 in the proper color.
I've tested this on ZSH 5.0.5 in OSX Yosimite, 5.0.7 from MacPorts, and 4.3.17 on Debian, with the same results. I know I have provided a valid solution to my own problem here with the working example, but I'm wondering why the first syntax isn't working as it seems it should.
I think this all has to do with the timeless and perennial problem of escaping. It's worth reminding ourselves what escaping means, briefly: an escape character is an indicator to the computer that what follows should not be output literally.
So there are 2 escaping issues with:
PROMPT="%{[00m[38;5;245m%}test %D%{[00m%}"
Firstly, the colour escape sequences (eg; [00m) should all start with the control character like so \e[00m. You may have also seen it written as ^[00m and \003[00m. What I suspect has happened is one of the variations has suffered the common fate of being inadvertently escaped by either the copy/paste of the author or the website's framework stack, whether that be somewhere in a database, HTTP rendering or JS parsing. The control character (ie, ^, \e or \003), as you probably know, does not have a literal representation, say if you press it on the keyboard. That's why a web stack might decide to not display anything if it sees it in a string. So let's correct that now:
PROMPT="%{\e[00m\e[38;5;245m%}test %D%{\e[00m%}"
This actually nicely segues into the next escaping issue. Somewhat comically \e[ is actually a representation of ESC, it is therefore in itself an escape sequence marker that, yes, is in turn escaped by \. It's a riff on the old \\\\\\\\\\ sort of joke. Now, significantly, we must be clear on the difference between the escape expressions for the terminal and the string substitutions of the prompt, in pseudo code:
PROMPT="%{terminal colour stuff%}test %D%{terminal colour stuff%}"
Now what I suspect is happening, though I can't find any documentation to prove it, is that once ZSH has done its substitutions, or indeed during the substitution process, all literal characters, regardless of escape significations, are promoted to real characters¹. To yet further the farce, this promotion is likely done by escaping all the escape characters. For example if you actually want to print '\e' on the command line, you have to do echo "\\\e". So to overcome this issue, we just need to make sure the 'terminal colour stuff' escape sequences get evaluated before being assigned to PROMPT and that can be done simply with the $'' pattern, like so:
PROMPT=$'%{\e[00m\e[38;5;245m%}test %D%{\e[00m%}'
Note that $'' is of the same ilk as $() and ${}, except that its only function is to interpret escape sequences.
[1] My suspicion for this is based on the fact that you can actually do something like the following:
PROMPT='$(date)'
where $(date) serves the same purpose as %D, by printing a live version of the date for every new prompt output to the screen. What this specific examples serves to demonstrate is that the PROMPT variable should really be thought of as storage for a mini script, not a string (though admittedly there is overlap between the 2 concepts and thus stems confusion). Therefore, as a script, the string is first evaluated and then printed. I haven't looked at ZSH's prompt rendering code, but I assume such evaluation would benefit from native use of escape sequences. For example what if you wanted to pass an escape sequence as an argument to a command (a command that gets run for every prompt render) in the prompt? For example the following is functionally identical to the prompt discussed above:
PROMPT='%{$(print "\e[00m\e[38;5;245m")%}test $(date)%{$(print "\e[00m")%}'
The escape sequences are stored literally and only interpreted at the moment of each prompt rendering.

How to turn off word wrap in iTerm2?

How to turn off word wrap in iTerm2? Is there a specific command to do so or in the preferences? I am trying to avoid having the text run down to the next line. I would rather scroll side to side.
lifted directly from https://apple.stackexchange.com/a/210666/115119
Props to #michid
Disable line wrapping:
tput rmam
Enable line wrapping:
tput smam
It appears that iTerm2 does not have the ability to turn off word wrap. There is an open issue (iTerm2 issue #1790) reported to "Provide toggle to turn on/off line wrapping".
The description of that issue reads:
Looks like a conversation was had in the Google Groups about this but no one ever actually filed a feature request.
http://groups.google.com/group/iterm2-discuss/browse_thread/thread/e0f4e9b552d8acd4
In general I don't like having horizontal scrollbars and prefer to have the lines wrap, but there are occasions...such as looking at long stack traces, that I'd rather just have sequentially indented lines line up and just be forced to scroll to the right to expose all the details. To accomplish this task now, I end up making the text incredibly small so I can read stack traces lined up, but even that doesn't always work.
In October, 2014, the creator of iTerm2 commented regarding the feature request to toggle word wrap, "I'd like to do this but it's a lot of work, so feel free to send a pull request, but don't be [a jerk]."
In April, 2015, the milestone for the feature request was changed to "Future Release".
For me, my issue was purely down to the configuration of my PS1 - not what I had originally expected!
The key for me was surrounding the following with any characters that wouldn't be printed as in your prompt - such as encoding colours. Sourced from https://linoxide.com/how-tos/change-bash-prompt-variable-ps1/
\[ This sequence should appear before a sequence of characters that don’t move the cursor (like color escape sequences). This allows bash to calculate word wrapping correctly.
\] This sequence should appear after a sequence of non-printing characters.

How to fix prettytable to display chinese character properly

from prettytable import PrettyTable
header="乘客姓名,性别,出生日期".split(",")
x = PrettyTable(header)
x.align["乘客姓名"]="l"
table='''HuangTianhui,男,1948/05/28
姜翠云,女,1952/03/27
李红晶,女,1994/12/09
LuiChing,女,1969/08/02
宋飞飞,男,1982/03/01
唐旭东,男,1983/08/03
YangJiabao,女,1988/08/25
买买提江·阿布拉,男,1979/07/10
安文兰,女,1949/10/20
胡偲婠(婴儿),女,2011/02/25
(有待确定姓名),男,1985/07/20
'''
data=[row for row in table.split("\n") if row]
for row in data:
x.add_row(row.strip().split(","))
print(x)
What I want the output format is as the following.
In this example, prettytable.py can not display properly chinese ambiguous width of character · in 买买提江·阿布拉 , the character has ambiguous width. How to fix the bug in prettytable.py?
I have add two lines in def _char_block_width(char) of prettytable.py, but the problem still remains.
if char == 0xb7:
return 2
I have solved it, the file prettytable.py should be installed in my computer d:\python33\Lib\site-packagesdirectly not in as the form of d:\python33\Lib\site-packages\prettytable\prettytable.py
There are many chinese character with ambiguous width, it is stupid for us to add two lines such as the following to fix the bug, if there are 50 ambiguous character,100 lines will be added in the prettytable.py, is there a simple way to do that? Just fix some lines to treat all the ambiguous character?
if char == 0xb7:
return 2
The issue you're running into has to do with the dot character in the incorrectly padded line of your Python output. The dot is Unicode code point U+00B7 · middle dot. This character is considered to have an "ambiguous" width, as it is a narrow character in most non-East-Asian fonts, but is rendered a full-width in most Asian ones. Without context, a program can't tell how wide it will appear on the screen. Unfortunately, Python's Unicode system doesn't appear to have any way to provide that context.
One fix might be to replace the offending dot with one that has an unambiguous width, such as U+30FB katakana middle dot (which is always full width). This way the padding logic will be able to recognize that extra space is needed for that line.
Another solution could be to set your console to use a font with more Western treatment of the middle dot character, rather than the current one that follows the East-Asian style of rendering of it as full-width. This will mean that the existing padding is correct. Your output from R clearly uses a different font that the Python output does, and its font renders the dot as half-width.

Resources