8e62781dd2c3cad59eee676f1e4d3eb48981dea7
[blog.git] / _posts / 2013-03-13-zsh_config_-_and_prompt.markdown
1 ---
2 layout: post
3 title: zsh config - and prompt
4 date: '2013-03-13 22:33:28 +0000'
5 mt_id: 390
6 blog_id: 1
7 post_id: 390
8 permalink: 2013/03/zsh-config---and-prompt.html
9 categories:
10 - tech
11 ---
12 As most people that are using "that funny grey on black thing with the
13 blinking white box" AKA a commandline, I do have a heavily configured
14 shell. zsh in my case. Some while ago my old configuration for it
15 started to annoy me and so I set out to redo it. With the basic
16 requirement to be flexible and able to adjust to various zsh versions
17 (back as far as Lenny).
18
19 I've set out and looked how others do it and took the (I hope) best
20 bits and put them together in a way I like it. Maybe others want to
21 pick from me, so here I describe a little, maybe someone is
22 interested...
23
24 First - the config is completly inside .zsh. The only thing directly in
25 my $HOME is a symlink from $HOME/.zshenv to $HOME/.zsh/zshenv.home. All
26 in one place, nicer this way. The zshenv just sets ZDOTDIR, so zsh then
27 uses the .zsh itself.
28
29 Next I am using "modules". Well, actually everything is splitted out in
30 small(er) files, so its way easier to maintain. And to overwrite stuff
31 wherever I need to. So my .zshrc just loads those "module" files - and
32 then goes and checks if it finds the same file inside a series of
33 subdirectories. Those subdirectories are based on the hostname, the
34 kernel name, the username, the domain name and the name of the
35 distribution of the system. And a number of combinations of those.
36
37 That system allows me, for example, to have a set of aliases defined
38 only on Debian systems (like those to do with apt-get & co). Or define some
39 extra variables if I login to the host franck, domain debian.org.
40 Or whatever more. I'm also on the way of doing something similar for
41 all my dotfiles.
42
43
44 While I was working at that I finally got fed up with the fact that my prompt, which is based on [Phil!'s](http://aperiodic.net/phil/prompt/) wasn't doing what I wanted it on various of the hosts I access. Thankfully someone pointed me at a change to the [grml zsh config: Frank Terbeck](http://git.grml.org/?p=grml-etc-core.git;a=summary) rewrote their prompt to make use of the zstyle system.
45
46 Now that got me going, I like the idea of having the whole prompt *easily* configurable and changeable. My prompt always has shown slight differences depending on where the shell runs, which meant I had to carefully craft PS1 for every such change, and when one changes something one had to check all the places to adjust them too.
47
48 No longer. I took Franks work and extended it for me. I wanted to still
49 have a design matching my old prompt (minus colors, I changed color
50 themes anyways), but with full flexibility the zstyle system can offer
51 here.
52
53 Now I am at a point where
54
55 - One zstyle call can change the information or order in my prompt.
56 - The prompt automagically leaves out information when the terminal
57 width gets under a limit,
58 - I can have whatever extra information items in the prompt, even if
59 the prompt never defined a default for it. Including running
60 neccessary functions to update those extra items.
61 - the prompt switches between color and black/white mode with one
62 zstyle change,
63 - the prompt draws lines differently, depending on the capabilities of
64 the terminal.
65
66 As an example, on the ftp-master host my prompt, while otherwise being
67 the same as everywhere else, contains one extra item - displaying the
68 current status of the archive (dinstall).
69
70 If you want to try it, the setup file is
71 [available](http://git.ganneff.de/cgi-bin/gitweb.cgi?p=zsh.git;a=blob;f=.zsh/functions/prompt_ganneff_setup;hb=HEAD),
72 but note that I don't give any warranty. :) "Works for me".
73
74 I load it in [my Prompts module](http://git.ganneff.de/cgi-bin/gitweb.cgi?p=zsh.git;a=blob;f=.zsh/20_Prompts.zsh;hb=HEAD),
75 while having the prompt setup file in my function path. The 4 commented
76 lines, my testcase, are a nice example of a custom token, though a real life one,
77 the setup for the ftp-master prompt with the one extra item can be
78 found [over here](http://git.ganneff.de/cgi-bin/gitweb.cgi?p=zsh.git;a=blob;f=.zsh/net:debian.org/host:franck/Prompts.zsh;hb=HEAD).
79
80 Comments? Bugfixes? Enhancements?
81
82 *Update*: Got asked for an example how to use my prompt to "fake" another.
83 So here is what you need to do to use my prompt setup to imitate the prompt clint, as delivered with zsh:
84
85 {% highlight bash %}
86 autoload promptinit && promptinit
87 zstyle ':prompt:ganneff' vcs_info true
88 # Alternatively you can set whatever you like it to be.
89 zstyle ':prompt:ganneff' set_vcs_info_defaults true
90 zstyle ':prompt:ganneff' colors true
91
92 ## no right prompt
93 zstyle ':prompt:ganneff:right:setup' use-rprompt false
94
95 ## color of brackets depending on variable
96 zstyle ':prompt:ganneff:*:items:openbracket' pre '${${SSH_CLIENT+"${PR_YELLOW}"}:-"${PR_RED}"}'
97 zstyle ':prompt:ganneff:*:items:openbracket' post '${PR_NO_COLOR}'
98
99 zstyle ':prompt:ganneff:*:items:closebracket' pre '${${SSH_CLIENT+"${PR_YELLOW}"}:-"${PR_RED}"}'
100 zstyle ':prompt:ganneff:*:items:closebracket' post '${PR_NO_COLOR}'
101
102 zstyle ':prompt:ganneff:*:items:openanglebracket' pre '${${SSH_CLIENT+"${PR_YELLOW}"}:-"${PR_RED}"}'
103 zstyle ':prompt:ganneff:*:items:openanglebracket' post '${PR_NO_COLOR}'
104
105 zstyle ':prompt:ganneff:*:items:closeanglebracket' pre '${${SSH_CLIENT+"${PR_YELLOW}"}:-"${PR_RED}"}'
106 zstyle ':prompt:ganneff:*:items:closeanglebracket' post '${PR_NO_COLOR}'
107
108 ## extra date format, and its color
109 zstyle ':prompt:ganneff:*:items:date' token '%D{ %a %y/%m/%d %R %Z}'
110 zstyle ':prompt:ganneff:*:items:date' pre '${PR_CYAN}'
111
112 ## pts. %l instead of %y, also color again
113 zstyle ':prompt:ganneff:*:items:pts' token '%l'
114 zstyle ':prompt:ganneff:*:items:pts' pre '${PR_GREEN}'
115 zstyle ':prompt:ganneff:*:items:pts' post '${PR_NO_COLOR}'
116
117 ## host ends with :
118 zstyle ':prompt:ganneff:*:items:host' token '%m:'
119
120 ## and a different style for the rc level
121 zstyle ':prompt:ganneff:*:items:rc' token '%(?..[%?%1v] )'
122 zstyle ':prompt:ganneff:*:items:rc' pre ''
123
124 ## change color for other parts that differ to my default
125 zstyle ':prompt:ganneff:*:items:user' pre '${PR_GREEN}'
126 zstyle ':prompt:ganneff:*:items:host' pre '${PR_GREEN}'
127 zstyle ':prompt:ganneff:*:items:at' pre '${PR_GREEN}'
128 zstyle ':prompt:ganneff:*:items:path' pre '${PR_GREEN}'
129 zstyle ':prompt:ganneff:*:items:history' pre ''
130
131 ## Show the shell level in a different way
132 zstyle ':prompt:ganneff:*:items:shell-level' pre ''
133 zstyle ':prompt:ganneff:*:items:shell-level' token 'zsh%(2L./$SHLVL.) '
134
135 ## And history is just a bold number. Lazy here, not using pre and post
136 zstyle ':prompt:ganneff:*:items:history' token '%B%h%b '
137
138 ## And the last part in prompt, a # or % depending on privileges
139 ## Using standard zsh tokens for bold
140 zstyle ':prompt:ganneff:*:items:privileges' pre '%B'
141 zstyle ':prompt:ganneff:*:items:privileges' post '%b'
142
143 ## Now there are two parts not defined by default, so lets create them
144 ## Both are simple existing variables, no need for extra precmd functions
145 ## system info
146 zstyle ':prompt:ganneff:extra:ostype' pre '${PR_CYAN}'
147 zstyle ':prompt:ganneff:extra:ostype' post '${PR_NO_COLOR}'
148 zstyle ':prompt:ganneff:extra:ostype' token "${MACHTYPE}/${OSTYPE}/$(uname -r)"
149
150 ## zsh version
151 zstyle ':prompt:ganneff:extra:zshvers' pre '${PR_CYAN}'
152 zstyle ':prompt:ganneff:extra:zshvers' post '${PR_NO_COLOR}'
153 zstyle ':prompt:ganneff:extra:zshvers' token "${ZSH_VERSION}"
154
155 zstyle ':prompt:ganneff:left:full:setup' items \
156 openbracket date closebracket openbracket pts closebracket openbracket ostype closebracket \
157 openbracket zshvers closebracket newline openanglebracket user at host \
158 path closeanglebracket newline \
159 shell-level space history rc space vcs privileges space
160
161 prompt ganneff
162 {% endhighlight %}
163
164 And if you now tell me "Uh, thats so much more than just saying /prompt
165 clint/", then you are right. But then: This way is flexible. As I wrote
166 above, my prompt on the ftpmaster host is different. Actually, my
167 prompt on all machines inside the domain "debian.org" differs, by having
168
169 zstyle ':prompt:ganneff:*:items:host' pre '${PR_YELLOW}'
170
171 in the Prompts definition for domain:debian.org. And thats enough to show me
172 im on a .debian.org machine by a yellow hostname, instead of my default red.
173
174 On the ftpmaster host I have the additional few lines:
175 # Want one more piece in my prompt here, dinstall status
176 zstyle ':prompt:ganneff:left:full:setup' items \
177 ulcorner line openparentheses user at host pts closeparentheses line history \
178 line dinstall line shell-level line flexline openparentheses path closeparentheses line urcorner newline \
179 llcorner line rc openparentheses time closeparentheses line vcs line change-root pipe space
180
181 zstyle ':prompt:ganneff:extra:dinstall' pre '${PR_CYAN}'
182 zstyle ':prompt:ganneff:extra:dinstall' post '${PR_NO_COLOR}'
183 zstyle ':prompt:ganneff:extra:dinstall' token '$DINSTALL'
184 zstyle ':prompt:ganneff:extra:dinstall' precmd jj_update_dinstall
185
186 zmodload zsh/mapfile
187
188 jj_update_dinstall () {
189 DINSTALL="${${(z)${(f)mapfile[/srv/ftp.debian.org/web/dinstall.status]}[2]}[3,99]}"
190 }
191
192 And woo, thats simple. I think.
193
194 (There ought to be a way to just easily add the item at a defined place
195 in the items zstyle, but meh, too lazy to look).