Последняя активность 1765272910

Modified .zshrc files based on Grml's defaults

.zshrc Исходник
1# Filename: /etc/zsh/zshrc
2# Purpose: config file for zsh (z shell)
3# Authors: grml-team (grml.org), (c) Michael Prokop <[email protected]>
4# Bug-Reports: see http://grml.org/bugs/
5# License: This file is licensed under the GPL v2.
6################################################################################
7# This file is sourced only for interactive shells. It
8# should contain commands to set up aliases, functions,
9# options, key bindings, etc.
10#
11# Global Order: zshenv, zprofile, zshrc, zlogin
12################################################################################
13
14# USAGE
15# If you are using this file as your ~/.zshrc file, please use ~/.zshrc.pre
16# and ~/.zshrc.local for your own customisations. The former file is read
17# before ~/.zshrc, the latter is read after it. Also, consider reading the
18# refcard and the reference manual for this setup, both available from:
19# <http://grml.org/zsh/>
20
21# Contributing:
22# If you want to help to improve grml's zsh setup, clone the grml-etc-core
23# repository from git.grml.org:
24# git clone git://git.grml.org/grml-etc-core.git
25#
26# Make your changes, commit them; use 'git format-patch' to create a series
27# of patches and send those to the following address via 'git send-email':
28# [email protected]
29#
30# Doing so makes sure the right people get your patches for review and
31# possibly inclusion.
32
33# zsh-refcard-tag documentation:
34# You may notice strange looking comments in this file.
35# These are there for a purpose. grml's zsh-refcard can now be
36# automatically generated from the contents of the actual configuration
37# file. However, we need a little extra information on which comments
38# and what lines of code to take into account (and for what purpose).
39#
40# Here is what they mean:
41#
42# List of tags (comment types) used:
43# #a# Next line contains an important alias, that should
44# be included in the grml-zsh-refcard.
45# (placement tag: @@INSERT-aliases@@)
46# #f# Next line contains the beginning of an important function.
47# (placement tag: @@INSERT-functions@@)
48# #v# Next line contains an important variable.
49# (placement tag: @@INSERT-variables@@)
50# #k# Next line contains an important keybinding.
51# (placement tag: @@INSERT-keybindings@@)
52# #d# Hashed directories list generation:
53# start denotes the start of a list of 'hash -d'
54# definitions.
55# end denotes its end.
56# (placement tag: @@INSERT-hasheddirs@@)
57# #A# Abbreviation expansion list generation:
58# start denotes the beginning of abbreviations.
59# end denotes their end.
60# Lines within this section that end in '#d .*' provide
61# extra documentation to be included in the refcard.
62# (placement tag: @@INSERT-abbrev@@)
63# #m# This tag allows you to manually generate refcard entries
64# for code lines that are hard/impossible to parse.
65# Example:
66# #m# k ESC-h Call the run-help function
67# That would add a refcard entry in the keybindings table
68# for 'ESC-h' with the given comment.
69# So the syntax is: #m# <section> <argument> <comment>
70# #o# This tag lets you insert entries to the 'other' hash.
71# Generally, this should not be used. It is there for
72# things that cannot be done easily in another way.
73# (placement tag: @@INSERT-other-foobar@@)
74#
75# All of these tags (except for m and o) take two arguments, the first
76# within the tag, the other after the tag:
77#
78# #<tag><section># <comment>
79#
80# Where <section> is really just a number, which are defined by the
81# @secmap array on top of 'genrefcard.pl'. The reason for numbers
82# instead of names is, that for the reader, the tag should not differ
83# much from a regular comment. For zsh, it is a regular comment indeed.
84# The numbers have got the following meanings:
85# 0 -> "default"
86# 1 -> "system"
87# 2 -> "user"
88# 3 -> "debian"
89# 4 -> "search"
90# 5 -> "shortcuts"
91# 6 -> "services"
92#
93# So, the following will add an entry to the 'functions' table in the
94# 'system' section, with a (hopefully) descriptive comment:
95# #f1# Edit an alias via zle
96# edalias() {
97#
98# It will then show up in the @@INSERT-aliases-system@@ replacement tag
99# that can be found in 'grml-zsh-refcard.tex.in'.
100# If the section number is omitted, the 'default' section is assumed.
101# Furthermore, in 'grml-zsh-refcard.tex.in' @@INSERT-aliases@@ is
102# exactly the same as @@INSERT-aliases-default@@. If you want a list of
103# *all* aliases, for example, use @@INSERT-aliases-all@@.
104
105# zsh profiling
106# just execute 'ZSH_PROFILE_RC=1 zsh' and run 'zprof' to get the details
107if [[ $ZSH_PROFILE_RC -gt 0 ]] ; then
108 zmodload zsh/zprof
109fi
110
111typeset -A GRML_STATUS_FEATURES
112
113function grml_status_feature () {
114 emulate -L zsh
115 local f=$1
116 local -i success=$2
117 if (( success == 0 )); then
118 GRML_STATUS_FEATURES[$f]=success
119 else
120 GRML_STATUS_FEATURES[$f]=failure
121 fi
122 return 0
123}
124
125function grml_status_features () {
126 emulate -L zsh
127 local mode=${1:-+-}
128 local this
129 if [[ $mode == -h ]] || [[ $mode == --help ]]; then
130 cat <<EOF
131grml_status_features [-h|--help|-|+|+-|FEATURE]
132
133Prints a summary of features the grml setup is trying to load. The
134result of loading a feature is recorded. This function lets you query
135the result.
136
137The function takes one argument: "-h" or "--help" to display this help
138text, "+" to display a list of all successfully loaded features, "-" for
139a list of all features that failed to load. "+-" to show a list of all
140features with their statuses.
141
142Any other word is considered to by a feature and prints its status.
143
144The default mode is "+-".
145EOF
146 return 0
147 fi
148 if [[ $mode != - ]] && [[ $mode != + ]] && [[ $mode != +- ]]; then
149 this="${GRML_STATUS_FEATURES[$mode]}"
150 if [[ -z $this ]]; then
151 printf 'unknown\n'
152 return 1
153 else
154 printf '%s\n' $this
155 fi
156 return 0
157 fi
158 for key in ${(ok)GRML_STATUS_FEATURES}; do
159 this="${GRML_STATUS_FEATURES[$key]}"
160 if [[ $this == success ]] && [[ $mode == *+* ]]; then
161 printf '%-16s %s\n' $key $this
162 fi
163 if [[ $this == failure ]] && [[ $mode == *-* ]]; then
164 printf '%-16s %s\n' $key $this
165 fi
166 done
167 return 0
168}
169
170# load .zshrc.pre to give the user the chance to overwrite the defaults
171[[ -r ${ZDOTDIR:-${HOME}}/.zshrc.pre ]] && source ${ZDOTDIR:-${HOME}}/.zshrc.pre
172
173#f1# Checks whether or not you're running grml
174function isgrml () {
175 [[ -f /etc/grml_version ]] && return 0
176 return 1
177}
178
179#f1# Checks whether or not you're running a grml cd
180function isgrmlcd () {
181 [[ -f /etc/grml_cd ]] && return 0
182 return 1
183}
184
185if isgrml ; then
186#f1# Checks whether or not you're running grml-small
187 function isgrmlsmall () {
188 if [[ ${${${(f)"$(</etc/grml_version)"}%% *}##*-} == 'small' ]]; then
189 return 0
190 fi
191 return 1
192 }
193else
194 function isgrmlsmall () { return 1 }
195fi
196
197GRML_OSTYPE=$(uname -s)
198
199function islinux () {
200 [[ $GRML_OSTYPE == "Linux" ]]
201}
202
203function isdarwin () {
204 [[ $GRML_OSTYPE == "Darwin" ]]
205}
206
207function isfreebsd () {
208 [[ $GRML_OSTYPE == "FreeBSD" ]]
209}
210
211function isopenbsd () {
212 [[ $GRML_OSTYPE == "OpenBSD" ]]
213}
214
215#f1# are we running within an utf environment?
216function isutfenv () {
217 case "$LANG $CHARSET $LANGUAGE" in
218 *utf*) return 0 ;;
219 *UTF*) return 0 ;;
220 *) return 1 ;;
221 esac
222}
223
224# check for user, if not running as root set $SUDO to sudo
225(( EUID != 0 )) && SUDO='sudo' || SUDO=''
226
227# check for zsh v5.1+
228
229if ! [[ ${ZSH_VERSION} == 5.<1->* \
230 || ${ZSH_VERSION} == <6->.<->* ]] ; then
231
232 printf '-!-\n'
233 printf '-!- In this configuration we try to make use of features, that\n'
234 printf '-!- require version 5.1 of the shell; That way this setup can be\n'
235 printf '-!- used with a wide range of zsh versions, while using fairly\n'
236 printf '-!- advanced features in all supported versions.\n'
237 printf '-!-\n'
238 printf '-!- However, you are running zsh version %s.\n' "$ZSH_VERSION"
239 printf '-!-\n'
240 printf '-!- While this *may* work, it might as well fail.\n'
241 printf '-!- Please consider updating to at least version 5.1 of zsh.\n'
242 printf '-!-\n'
243 printf '-!- DO NOT EXPECT THIS TO WORK FLAWLESSLY!\n'
244 printf '-!- If it does today, you'\''ve been lucky.\n'
245 printf '-!-\n'
246 printf '-!- Ye been warned!\n'
247 printf '-!-\n'
248
249 function zstyle () { : }
250fi
251
252# autoload wrapper - use this one instead of autoload directly
253# We need to define this function as early as this, because autoloading
254# 'is-at-least()' needs it.
255function zrcautoload () {
256 emulate -L zsh
257 setopt extended_glob
258 local fdir ffile
259 local -i ffound
260
261 ffile=$1
262 (( ffound = 0 ))
263 for fdir in ${fpath} ; do
264 [[ -e ${fdir}/${ffile} ]] && (( ffound = 1 ))
265 done
266
267 (( ffound == 0 )) && return 1
268 autoload -U ${ffile} || return 1
269 return 0
270}
271
272# Autoload zsh's hook system early, so we can use it whenever we need.
273zrcautoload add-zsh-hook || add-zsh-hook () { :; }
274
275# Load is-at-least() for more precise version checks Note that this test will
276# *always* fail, if the is-at-least function could not be marked for
277# autoloading.
278zrcautoload is-at-least || function is-at-least () { return 1 }
279
280# set some important options (as early as possible)
281
282# append history list to the history file; this is the default but we make sure
283# because it's required for share_history.
284setopt append_history
285
286# import new commands from the history file also in other zsh-session
287setopt share_history
288
289# save each command's beginning timestamp and the duration to the history file
290setopt extended_history
291
292# remove command lines from the history list when the first character on the
293# line is a space
294setopt histignorespace
295
296# if a command is issued that can't be executed as a normal command, and the
297# command is the name of a directory, perform the cd command to that directory.
298setopt auto_cd
299
300# in order to use #, ~ and ^ for filename generation grep word
301# *~(*.gz|*.bz|*.bz2|*.zip|*.Z) -> searches for word not in compressed files
302# don't forget to quote '^', '~' and '#'!
303setopt extended_glob
304
305# display PID when suspending processes as well
306setopt longlistjobs
307
308# report the status of backgrounds jobs immediately
309setopt notify
310
311# whenever a command completion is attempted, make sure the entire command path
312# is hashed first.
313setopt hash_list_all
314
315# not just at the end
316setopt completeinword
317
318# Don't send SIGHUP to background processes when the shell exits.
319setopt nohup
320
321# make cd push the old directory onto the directory stack.
322setopt auto_pushd
323
324# avoid "beep"ing
325setopt nobeep
326
327# don't push the same dir twice.
328setopt pushd_ignore_dups
329
330# * shouldn't match dotfiles. ever.
331setopt noglobdots
332
333# use zsh style word splitting
334setopt noshwordsplit
335
336# don't error out when unset parameters are used
337setopt unset
338
339# setting some default values
340NOCOR=${NOCOR:-0}
341NOETCHOSTS=${NOETCHOSTS:-0}
342NOMENU=${NOMENU:-0}
343NOPATHHELPER=${NOPATHHELPER:-0}
344NOPRECMD=${NOPRECMD:-0}
345COMMAND_NOT_FOUND=${COMMAND_NOT_FOUND:-0}
346GRML_ZSH_CNF_HANDLER=${GRML_ZSH_CNF_HANDLER:-/usr/share/command-not-found/command-not-found}
347GRML_DISPLAY_BATTERY=${GRML_DISPLAY_BATTERY:-${BATTERY:-0}}
348GRMLSMALL_SPECIFIC=${GRMLSMALL_SPECIFIC:-1}
349ZSH_NO_DEFAULT_LOCALE=${ZSH_NO_DEFAULT_LOCALE:-0}
350
351typeset -ga ls_options
352typeset -ga grep_options
353
354# Colors on GNU ls(1)
355if ls --color=auto / >/dev/null 2>&1; then
356 ls_options+=( --color=auto )
357# Colors on FreeBSD and OSX ls(1)
358elif ls -G / >/dev/null 2>&1; then
359 ls_options+=( -G )
360fi
361
362# Natural sorting order on GNU ls(1)
363# OSX and IllumOS have a -v option that is not natural sorting
364if ls --version |& grep -q 'GNU' >/dev/null 2>&1 && ls -v / >/dev/null 2>&1; then
365 ls_options+=( -v )
366fi
367
368# Color on GNU and FreeBSD grep(1)
369if grep --color=auto -q "a" <<< "a" >/dev/null 2>&1; then
370 grep_options+=( --color=auto )
371fi
372
373# utility functions
374# this function checks if a command exists and returns either true
375# or false. This avoids using 'which' and 'whence', which will
376# avoid problems with aliases for which on certain weird systems. :-)
377# Usage: check_com [-c|-g] word
378# -c only checks for external commands
379# -g does the usual tests and also checks for global aliases
380function check_com () {
381 emulate -L zsh
382 local -i comonly gatoo
383 comonly=0
384 gatoo=0
385
386 if [[ $1 == '-c' ]] ; then
387 comonly=1
388 shift 1
389 elif [[ $1 == '-g' ]] ; then
390 gatoo=1
391 shift 1
392 fi
393
394 if (( ${#argv} != 1 )) ; then
395 printf 'usage: check_com [-c|-g] <command>\n' >&2
396 return 1
397 fi
398
399 if (( comonly > 0 )) ; then
400 (( ${+commands[$1]} )) && return 0
401 return 1
402 fi
403
404 if (( ${+commands[$1]} )) \
405 || (( ${+functions[$1]} )) \
406 || (( ${+aliases[$1]} )) \
407 || (( ${+reswords[(r)$1]} )) ; then
408 return 0
409 fi
410
411 if (( gatoo > 0 )) && (( ${+galiases[$1]} )) ; then
412 return 0
413 fi
414
415 return 1
416}
417
418# creates an alias and precedes the command with
419# sudo if $EUID is not zero.
420function salias () {
421 emulate -L zsh
422 local only=0 ; local multi=0
423 local key val
424 while getopts ":hao" opt; do
425 case $opt in
426 o) only=1 ;;
427 a) multi=1 ;;
428 h)
429 printf 'usage: salias [-hoa] <alias-expression>\n'
430 printf ' -h shows this help text.\n'
431 printf ' -a replace '\'' ; '\'' sequences with '\'' ; sudo '\''.\n'
432 printf ' be careful using this option.\n'
433 printf ' -o only sets an alias if a preceding sudo would be needed.\n'
434 return 0
435 ;;
436 *) salias -h >&2; return 1 ;;
437 esac
438 done
439 shift "$((OPTIND-1))"
440
441 if (( ${#argv} > 1 )) ; then
442 printf 'Too many arguments %s\n' "${#argv}"
443 return 1
444 fi
445
446 key="${1%%\=*}" ; val="${1#*\=}"
447 if (( EUID == 0 )) && (( only == 0 )); then
448 alias -- "${key}=${val}"
449 elif (( EUID > 0 )) ; then
450 (( multi > 0 )) && val="${val// ; / ; sudo }"
451 alias -- "${key}=sudo ${val}"
452 fi
453
454 return 0
455}
456
457# Check if we can read given files and source those we can.
458function xsource () {
459 if (( ${#argv} < 1 )) ; then
460 printf 'usage: xsource FILE(s)...\n' >&2
461 return 1
462 fi
463
464 while (( ${#argv} > 0 )) ; do
465 [[ -r "$1" ]] && source "$1"
466 shift
467 done
468 return 0
469}
470
471# Check if we can read a given file and 'cat(1)' it.
472function xcat () {
473 emulate -L zsh
474 if (( ${#argv} != 1 )) ; then
475 printf 'usage: xcat FILE\n' >&2
476 return 1
477 fi
478
479 [[ -r $1 ]] && cat $1
480 return 0
481}
482
483# this allows us to stay in sync with grml's zshrc and put own
484# modifications in ~/.zshrc.local
485function zrclocal () {
486 xsource "/etc/zsh/zshrc.local"
487 xsource "${ZDOTDIR:-${HOME}}/.zshrc.local"
488 return 0
489}
490
491# locale setup
492if (( ZSH_NO_DEFAULT_LOCALE == 0 )); then
493 xsource "/etc/default/locale"
494fi
495
496for var in LANG LANGUAGE LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE LC_TIME ; do
497 [[ -n ${(P)var} ]] && export $var
498done
499builtin unset -v var
500
501# set some variables
502if check_com -c vim ; then
503#v#
504 export EDITOR=${EDITOR:-vim}
505else
506 export EDITOR=${EDITOR:-vi}
507fi
508
509#v#
510export PAGER=${PAGER:-less}
511
512#v#
513export MAIL=${MAIL:-/var/mail/$USER}
514
515# color setup for ls:
516check_com -c dircolors && eval $(dircolors -b)
517
518# Setup PATH from system defaults on macOS.
519if [[ -x /usr/libexec/path_helper ]] && [[ "$NOPATHHELPER" -eq 0 ]] ; then
520 eval $(/usr/libexec/path_helper -s)
521fi
522# Add MacPorts PATH on darwin/macOS.
523if isdarwin && [[ -d /opt/local ]]; then
524 PATH="/opt/local/bin:/opt/local/sbin:$PATH"
525 MANPATH="/opt/local/share/man:$MANPATH"
526fi
527
528# load our function and completion directories
529for fdir in /usr/share/grml/zsh/completion /usr/share/grml/zsh/functions; do
530 fpath=( ${fdir} ${fdir}/**/*(/N) ${fpath} )
531done
532typeset -aU ffiles
533ffiles=(/usr/share/grml/zsh/functions/**/[^_]*[^~](N.:t))
534(( ${#ffiles} > 0 )) && autoload -U "${ffiles[@]}"
535unset -v fdir ffiles
536
537# support colors in less
538export LESS_TERMCAP_mb=$'\E[01;31m'
539export LESS_TERMCAP_md=$'\E[01;31m'
540export LESS_TERMCAP_me=$'\E[0m'
541export LESS_TERMCAP_se=$'\E[0m'
542export LESS_TERMCAP_so=$'\E[01;44;33m'
543export LESS_TERMCAP_ue=$'\E[0m'
544export LESS_TERMCAP_us=$'\E[01;32m'
545
546# mailchecks
547MAILCHECK=30
548
549# report about cpu-/system-/user-time of command if running longer than
550# 5 seconds
551REPORTTIME=5
552
553# watch for everyone but me and root
554watch=(notme root)
555
556# automatically remove duplicates from these arrays
557typeset -U path PATH cdpath CDPATH fpath FPATH manpath MANPATH
558
559# Load a few modules
560for mod in parameter complist deltochar mathfunc ; do
561 zmodload -i zsh/${mod} 2>/dev/null
562 grml_status_feature mod:$mod $?
563done && builtin unset -v mod
564
565# autoload zsh modules when they are referenced
566zmodload -a zsh/stat zstat
567zmodload -a zsh/zpty zpty
568zmodload -ap zsh/mapfile mapfile
569
570# completion system
571COMPDUMPFILE=${COMPDUMPFILE:-${ZDOTDIR:-${HOME}}/.zcompdump}
572if zrcautoload compinit ; then
573 typeset -a tmp
574 zstyle -a ':grml:completion:compinit' arguments tmp
575 compinit -d ${COMPDUMPFILE} "${tmp[@]}"
576 grml_status_feature compinit $?
577 unset tmp
578else
579 grml_status_feature compinit 1
580 function compdef { }
581fi
582
583# completion system
584
585# called later (via grmlcomp)
586# note: use 'zstyle' for getting current settings
587# press ^xh (control-x h) for getting tags in context; ^x? (control-x ?) to run complete_debug with trace output
588function grmlcomp () {
589 # TODO: This could use some additional information
590
591 # Make sure the completion system is initialised
592 (( ${+_comps} )) || return 1
593
594 # allow one error for every three characters typed in approximate completer
595 zstyle ':completion:*:approximate:' max-errors 'reply=( $((($#PREFIX+$#SUFFIX)/3 )) numeric )'
596
597 # don't complete backup files as executables
598 zstyle ':completion:*:complete:-command-::commands' ignored-patterns '(aptitude-*|*\~)'
599
600 # start menu completion only if it could find no unambiguous initial string
601 zstyle ':completion:*:correct:*' insert-unambiguous true
602 zstyle ':completion:*:corrections' format $'%{\e[0;31m%}%d (errors: %e)%{\e[0m%}'
603 zstyle ':completion:*:correct:*' original true
604
605 # activate color-completion
606 zstyle ':completion:*:default' list-colors ${(s.:.)LS_COLORS}
607
608 # format on completion
609 zstyle ':completion:*:descriptions' format $'%{\e[0;31m%}completing %B%d%b%{\e[0m%}'
610
611 # automatically complete 'cd -<tab>' and 'cd -<ctrl-d>' with menu
612 # zstyle ':completion:*:*:cd:*:directory-stack' menu yes select
613
614 # insert all expansions for expand completer
615 zstyle ':completion:*:expand:*' tag-order all-expansions
616 zstyle ':completion:*:history-words' list false
617
618 # activate menu
619 zstyle ':completion:*:history-words' menu yes
620
621 # ignore duplicate entries
622 zstyle ':completion:*:history-words' remove-all-dups yes
623 zstyle ':completion:*:history-words' stop yes
624
625 # match uppercase from lowercase
626 zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}'
627
628 # separate matches into groups
629 zstyle ':completion:*:matches' group 'yes'
630 zstyle ':completion:*' group-name ''
631
632 if [[ "$NOMENU" -eq 0 ]] ; then
633 # if there are more than 5 options allow selecting from a menu
634 zstyle ':completion:*' menu select=5
635 else
636 # don't use any menus at all
637 setopt no_auto_menu
638 fi
639
640 zstyle ':completion:*:messages' format '%d'
641 zstyle ':completion:*:options' auto-description '%d'
642
643 # describe options in full
644 zstyle ':completion:*:options' description 'yes'
645
646 # on processes completion complete all user processes
647 zstyle ':completion:*:processes' command 'ps -au$USER'
648
649 # offer indexes before parameters in subscripts
650 zstyle ':completion:*:*:-subscript-:*' tag-order indexes parameters
651
652 # provide verbose completion information
653 zstyle ':completion:*' verbose true
654
655 # recent (as of Dec 2007) zsh versions are able to provide descriptions
656 # for commands (read: 1st word in the line) that it will list for the user
657 # to choose from. The following disables that, because it's not exactly fast.
658 zstyle ':completion:*:-command-:*:' verbose false
659
660 # set format for warnings
661 zstyle ':completion:*:warnings' format $'%{\e[0;31m%}No matches for:%{\e[0m%} %d'
662
663 # define files to ignore for zcompile
664 zstyle ':completion:*:*:zcompile:*' ignored-patterns '(*~|*.zwc)'
665 zstyle ':completion:correct:' prompt 'correct to: %e'
666
667 # Ignore completion functions for commands you don't have:
668 zstyle ':completion::(^approximate*):*:functions' ignored-patterns '_*'
669
670 # Provide more processes in completion of programs like killall:
671 zstyle ':completion:*:processes-names' command 'ps c -u ${USER} -o command | uniq'
672
673 # complete manual by their section
674 zstyle ':completion:*:manuals' separate-sections true
675 zstyle ':completion:*:manuals.*' insert-sections true
676 zstyle ':completion:*:man:*' menu yes select
677
678 # Search path for sudo completion
679 zstyle ':completion:*:sudo:*' command-path /usr/local/sbin \
680 /usr/local/bin \
681 /usr/sbin \
682 /usr/bin \
683 /sbin \
684 /bin \
685 /usr/X11R6/bin
686
687 # provide .. as a completion
688 zstyle ':completion:*' special-dirs ..
689
690 # run rehash on completion so new installed program are found automatically:
691 function _force_rehash () {
692 (( CURRENT == 1 )) && rehash
693 return 1
694 }
695
696 ## correction
697 # some people don't like the automatic correction - so run 'NOCOR=1 zsh' to deactivate it
698 if [[ "$NOCOR" -gt 0 ]] ; then
699 zstyle ':completion:*' completer _oldlist _expand _force_rehash _complete _files _ignored
700 setopt nocorrect
701 else
702 # try to be smart about when to use what completer...
703 setopt correct
704 zstyle -e ':completion:*' completer '
705 if [[ $_last_try != "$HISTNO$BUFFER$CURSOR" ]] ; then
706 _last_try="$HISTNO$BUFFER$CURSOR"
707 reply=(_complete _match _ignored _prefix _files)
708 else
709 if [[ $words[1] == (rm|mv) ]] ; then
710 reply=(_complete _files)
711 else
712 reply=(_oldlist _expand _force_rehash _complete _ignored _correct _approximate _files)
713 fi
714 fi'
715 fi
716
717 # command for process lists, the local web server details and host completion
718 zstyle ':completion:*:urls' local 'www' '/var/www/' 'public_html'
719
720 # Some functions, like _apt and _dpkg, are very slow. We can use a cache in
721 # order to speed things up
722 if [[ ${GRML_COMP_CACHING:-yes} == yes ]]; then
723 GRML_COMP_CACHE_DIR=${GRML_COMP_CACHE_DIR:-${ZDOTDIR:-$HOME}/.cache}
724 if [[ ! -d ${GRML_COMP_CACHE_DIR} ]]; then
725 command mkdir -p "${GRML_COMP_CACHE_DIR}"
726 fi
727 zstyle ':completion:*' use-cache yes
728 zstyle ':completion:*:complete:*' cache-path "${GRML_COMP_CACHE_DIR}"
729 fi
730
731 # host completion
732 _ssh_config_hosts=()
733 if [[ -r ~/.ssh/config ]] ; then
734 _ssh_config_hosts=(${${(s: :)${(ps:\t:)${${(@M)${(f)"$(<$HOME/.ssh/config)"}:#Host *}#Host }}}:#*[*?]*})
735 fi
736 _ssh_hosts=()
737 if [[ -r ~/.ssh/known_hosts ]] ; then
738 _ssh_hosts=(${${${${(f)"$(<$HOME/.ssh/known_hosts)"}:#[\|]*}%%\ *}%%,*})
739 fi
740 _etc_hosts=()
741 if [[ -r /etc/hosts ]] && [[ "$NOETCHOSTS" -eq 0 ]] ; then
742 : ${(A)_etc_hosts:=${(s: :)${(ps:\t:)${${(f)~~"$(grep -v '^0\.0\.0\.0\|^127\.0\.0\.1\|^::1 ' /etc/hosts)"}%%\#*}##[:blank:]#[^[:blank:]]#}}}
743 fi
744
745 hosts=(
746 "$HOST"
747 "$_ssh_config_hosts[@]"
748 "$_ssh_hosts[@]"
749 "$_etc_hosts[@]"
750 localhost
751 )
752 zstyle ':completion:*:hosts' hosts $hosts
753 # TODO: so, why is this here?
754 # zstyle '*' hosts $hosts
755
756 # use generic completion system for programs not yet defined; (_gnu_generic works
757 # with commands that provide a --help option with "standard" gnu-like output.)
758 for compcom in cp deborphan df feh fetchipac gpasswd head hnb ipacsum mv \
759 pal stow uname ; do
760 [[ -z ${_comps[$compcom]} ]] && compdef _gnu_generic ${compcom}
761 done; unset compcom
762
763 # see upgrade function in this file
764 compdef _hosts upgrade
765}
766
767# Keyboard setup: The following is based on the same code, we wrote for
768# debian's setup. It ensures the terminal is in the right mode, when zle is
769# active, so the values from $terminfo are valid. Therefore, this setup should
770# work on all systems, that have support for `terminfo'. It also requires the
771# zsh in use to have the `zsh/terminfo' module built.
772#
773# If you are customising your `zle-line-init()' or `zle-line-finish()'
774# functions, make sure you call the following utility functions in there:
775#
776# - zle-line-init(): zle-smkx
777# - zle-line-finish(): zle-rmkx
778
779# Use emacs-like key bindings by default:
780bindkey -e
781
782# Custom widgets:
783
784## beginning-of-line OR beginning-of-buffer OR beginning of history
785## by: Bart Schaefer <[email protected]>, Bernhard Tittelbach
786function beginning-or-end-of-somewhere () {
787 local hno=$HISTNO
788 if [[ ( "${LBUFFER[-1]}" == $'\n' && "${WIDGET}" == beginning-of* ) || \
789 ( "${RBUFFER[1]}" == $'\n' && "${WIDGET}" == end-of* ) ]]; then
790 zle .${WIDGET:s/somewhere/buffer-or-history/} "$@"
791 else
792 zle .${WIDGET:s/somewhere/line-hist/} "$@"
793 if (( HISTNO != hno )); then
794 zle .${WIDGET:s/somewhere/buffer-or-history/} "$@"
795 fi
796 fi
797}
798zle -N beginning-of-somewhere beginning-or-end-of-somewhere
799zle -N end-of-somewhere beginning-or-end-of-somewhere
800
801# add a command line to the shells history without executing it
802function commit-to-history () {
803 print -rs ${(z)BUFFER}
804 zle send-break
805}
806zle -N commit-to-history
807
808# only slash should be considered as a word separator:
809function slash-backward-kill-word () {
810 local WORDCHARS="${WORDCHARS:s@/@}"
811 # zle backward-word
812 zle backward-kill-word
813}
814zle -N slash-backward-kill-word
815
816# a generic accept-line wrapper
817
818# This widget can prevent unwanted autocorrections from command-name
819# to _command-name, rehash automatically on enter and call any number
820# of builtin and user-defined widgets in different contexts.
821#
822# For a broader description, see:
823# <http://bewatermyfriend.org/posts/2007/12-26.11-50-38-tooltime.html>
824#
825# The code is imported from the file 'zsh/functions/accept-line' from
826# <http://ft.bewatermyfriend.org/comp/zsh/zsh-dotfiles.tar.bz2>, which
827# distributed under the same terms as zsh itself.
828
829# A newly added command will may not be found or will cause false
830# correction attempts, if you got auto-correction set. By setting the
831# following style, we force accept-line() to rehash, if it cannot
832# find the first word on the command line in the $command[] hash.
833zstyle ':acceptline:*' rehash true
834
835function Accept-Line () {
836 setopt localoptions noksharrays
837 local -a subs
838 local -xi aldone
839 local sub
840 local alcontext=${1:-$alcontext}
841
842 zstyle -a ":acceptline:${alcontext}" actions subs
843
844 (( ${#subs} < 1 )) && return 0
845
846 (( aldone = 0 ))
847 for sub in ${subs} ; do
848 [[ ${sub} == 'accept-line' ]] && sub='.accept-line'
849 zle ${sub}
850
851 (( aldone > 0 )) && break
852 done
853}
854
855function Accept-Line-getdefault () {
856 emulate -L zsh
857 local default_action
858
859 zstyle -s ":acceptline:${alcontext}" default_action default_action
860 case ${default_action} in
861 ((accept-line|))
862 printf ".accept-line"
863 ;;
864 (*)
865 printf ${default_action}
866 ;;
867 esac
868}
869
870function Accept-Line-HandleContext () {
871 zle Accept-Line
872
873 default_action=$(Accept-Line-getdefault)
874 zstyle -T ":acceptline:${alcontext}" call_default \
875 && zle ${default_action}
876}
877
878function accept-line () {
879 setopt localoptions noksharrays
880 local -a cmdline
881 local -x alcontext
882 local buf com fname format msg default_action
883
884 alcontext='default'
885 buf="${BUFFER}"
886 cmdline=(${(z)BUFFER})
887 com="${cmdline[1]}"
888 fname="_${com}"
889
890 Accept-Line 'preprocess'
891
892 zstyle -t ":acceptline:${alcontext}" rehash \
893 && [[ -z ${commands[$com]} ]] \
894 && rehash
895
896 if [[ -n ${com} ]] \
897 && [[ -n ${reswords[(r)$com]} ]] \
898 || [[ -n ${aliases[$com]} ]] \
899 || [[ -n ${functions[$com]} ]] \
900 || [[ -n ${builtins[$com]} ]] \
901 || [[ -n ${commands[$com]} ]] ; then
902
903 # there is something sensible to execute, just do it.
904 alcontext='normal'
905 Accept-Line-HandleContext
906
907 return
908 fi
909
910 if [[ -o correct ]] \
911 || [[ -o correctall ]] \
912 && [[ -n ${functions[$fname]} ]] ; then
913
914 # nothing there to execute but there is a function called
915 # _command_name; a completion widget. Makes no sense to
916 # call it on the commandline, but the correct{,all} options
917 # will ask for it nevertheless, so warn the user.
918 if [[ ${LASTWIDGET} == 'accept-line' ]] ; then
919 # Okay, we warned the user before, he called us again,
920 # so have it his way.
921 alcontext='force'
922 Accept-Line-HandleContext
923
924 return
925 fi
926
927 if zstyle -t ":acceptline:${alcontext}" nocompwarn ; then
928 alcontext='normal'
929 Accept-Line-HandleContext
930 else
931 # prepare warning message for the user, configurable via zstyle.
932 zstyle -s ":acceptline:${alcontext}" compwarnfmt msg
933
934 if [[ -z ${msg} ]] ; then
935 msg="%c will not execute and completion %f exists."
936 fi
937
938 zformat -f msg "${msg}" "c:${com}" "f:${fname}"
939
940 zle -M -- "${msg}"
941 fi
942 return
943 elif [[ -n ${buf//[$' \t\n']##/} ]] ; then
944 # If we are here, the commandline contains something that is not
945 # executable, which is neither subject to _command_name correction
946 # and is not empty. might be a variable assignment
947 alcontext='misc'
948 Accept-Line-HandleContext
949
950 return
951 fi
952
953 # If we got this far, the commandline only contains whitespace, or is empty.
954 alcontext='empty'
955 Accept-Line-HandleContext
956}
957
958zle -N accept-line
959zle -N Accept-Line
960zle -N Accept-Line-HandleContext
961
962# power completion / abbreviation expansion / buffer expansion
963# see http://zshwiki.org/home/examples/zleiab for details
964# less risky than the global aliases but powerful as well
965# just type the abbreviation key and afterwards 'ctrl-x .' to expand it
966declare -A abk
967setopt extendedglob
968setopt interactivecomments
969abk=(
970# key # value (#d additional doc string)
971#A# start
972 '...' '../..'
973 '....' '../../..'
974 'BG' '& exit'
975 'C' '| wc -l'
976 'G' '|& grep '${grep_options:+"${grep_options[*]}"}
977 'H' '| head'
978 'Hl' ' --help |& less -r' #d (Display help in pager)
979 'J' '| jq'
980 'K' '| keep'
981 'L' '| less'
982 'LL' '|& less -r'
983 'M' '| most'
984 'N' '&>/dev/null' #d (No Output)
985 'R' '| tr A-z N-za-m' #d (ROT13)
986 'SL' '| sort | less'
987 'S' '| sort -u'
988 'T' '| tail'
989 'TS' '| ts "%F %H:%M:%.S"'
990 'V' '|& vim -'
991#A# end
992 'co' './configure && make && sudo make install'
993)
994
995function zleiab () {
996 emulate -L zsh
997 setopt extendedglob
998 local MATCH
999
1000 LBUFFER=${LBUFFER%%(#m)[.\-+:|_a-zA-Z0-9]#}
1001 LBUFFER+=${abk[$MATCH]:-$MATCH}
1002}
1003
1004zle -N zleiab
1005
1006function help-show-abk () {
1007 zle -M "$(print "Available abbreviations for expansion:"; print -a -C 2 ${(kv)abk})"
1008}
1009
1010zle -N help-show-abk
1011
1012# press "ctrl-x d" to insert the actual date in the form yyyy-mm-dd
1013function insert-datestamp () { LBUFFER+=${(%):-'%D{%Y-%m-%d}'}; }
1014zle -N insert-datestamp
1015
1016# press esc-m for inserting last typed word again (thanks to caphuso!)
1017function insert-last-typed-word () { zle insert-last-word -- 0 -1 };
1018zle -N insert-last-typed-word;
1019
1020function grml-zsh-fg () {
1021 if (( ${#jobstates} )); then
1022 zle .push-input
1023 [[ -o hist_ignore_space ]] && BUFFER=' ' || BUFFER=''
1024 BUFFER="${BUFFER}fg"
1025 zle .accept-line
1026 else
1027 zle -M 'No background jobs. Doing nothing.'
1028 fi
1029}
1030zle -N grml-zsh-fg
1031
1032# run command line as user root via sudo:
1033function sudo-command-line () {
1034 [[ -z $BUFFER ]] && zle up-history
1035 local cmd="sudo "
1036 if [[ ${BUFFER} == ${cmd}* ]]; then
1037 CURSOR=$(( CURSOR-${#cmd} ))
1038 BUFFER="${BUFFER#$cmd}"
1039 else
1040 BUFFER="${cmd}${BUFFER}"
1041 CURSOR=$(( CURSOR+${#cmd} ))
1042 fi
1043 zle reset-prompt
1044}
1045zle -N sudo-command-line
1046
1047### jump behind the first word on the cmdline.
1048### useful to add options.
1049function jump_after_first_word () {
1050 local words
1051 words=(${(z)BUFFER})
1052
1053 if (( ${#words} <= 1 )) ; then
1054 CURSOR=${#BUFFER}
1055 else
1056 CURSOR=${#${words[1]}}
1057 fi
1058}
1059zle -N jump_after_first_word
1060
1061#f5# Create directory under cursor or the selected area
1062function inplaceMkDirs () {
1063 # Press ctrl-xM to create the directory under the cursor or the selected area.
1064 # To select an area press ctrl-@ or ctrl-space and use the cursor.
1065 # Use case: you type "mv abc ~/testa/testb/testc/" and remember that the
1066 # directory does not exist yet -> press ctrl-XM and problem solved
1067 local PATHTOMKDIR
1068 if ((REGION_ACTIVE==1)); then
1069 local F=$MARK T=$CURSOR
1070 if [[ $F -gt $T ]]; then
1071 F=${CURSOR}
1072 T=${MARK}
1073 fi
1074 # get marked area from buffer and eliminate whitespace
1075 PATHTOMKDIR=${BUFFER[F+1,T]%%[[:space:]]##}
1076 PATHTOMKDIR=${PATHTOMKDIR##[[:space:]]##}
1077 else
1078 local bufwords iword
1079 bufwords=(${(z)LBUFFER})
1080 iword=${#bufwords}
1081 bufwords=(${(z)BUFFER})
1082 PATHTOMKDIR="${(Q)bufwords[iword]}"
1083 fi
1084 [[ -z "${PATHTOMKDIR}" ]] && return 1
1085 PATHTOMKDIR=${~PATHTOMKDIR}
1086 if [[ -e "${PATHTOMKDIR}" ]]; then
1087 zle -M " path already exists, doing nothing"
1088 else
1089 zle -M "$(mkdir -p -v "${PATHTOMKDIR}")"
1090 zle end-of-line
1091 fi
1092}
1093
1094zle -N inplaceMkDirs
1095
1096#v1# set number of lines to display per page
1097HELP_LINES_PER_PAGE=20
1098#v1# set location of help-zle cache file
1099HELP_ZLE_CACHE_FILE=~/.cache/zsh_help_zle_lines.zsh
1100# helper function for help-zle, actually generates the help text
1101function help_zle_parse_keybindings () {
1102 emulate -L zsh
1103 setopt extendedglob
1104 unsetopt ksharrays #indexing starts at 1
1105
1106 #v1# choose files that help-zle will parse for keybindings
1107 ((${+HELPZLE_KEYBINDING_FILES})) || HELPZLE_KEYBINDING_FILES=( /etc/zsh/zshrc ~/.zshrc.pre ~/.zshrc ~/.zshrc.local )
1108
1109 if [[ -r $HELP_ZLE_CACHE_FILE ]]; then
1110 local load_cache=0
1111 local f
1112 for f ($HELPZLE_KEYBINDING_FILES) [[ $f -nt $HELP_ZLE_CACHE_FILE ]] && load_cache=1
1113 [[ $load_cache -eq 0 ]] && . $HELP_ZLE_CACHE_FILE && return
1114 fi
1115
1116 #fill with default keybindings, possibly to be overwritten in a file later
1117 #Note that due to zsh inconsistency on escaping assoc array keys, we encase the key in '' which we will remove later
1118 local -A help_zle_keybindings
1119 help_zle_keybindings['<Ctrl>@']="set MARK"
1120 help_zle_keybindings['<Ctrl>x<Ctrl>j']="vi-join lines"
1121 help_zle_keybindings['<Ctrl>x<Ctrl>b']="jump to matching brace"
1122 help_zle_keybindings['<Ctrl>x<Ctrl>u']="undo"
1123 help_zle_keybindings['<Ctrl>_']="undo"
1124 help_zle_keybindings['<Ctrl>x<Ctrl>f<c>']="find <c> in cmdline"
1125 help_zle_keybindings['<Ctrl>a']="goto beginning of line"
1126 help_zle_keybindings['<Ctrl>e']="goto end of line"
1127 help_zle_keybindings['<Ctrl>t']="transpose charaters"
1128 help_zle_keybindings['<Alt>t']="transpose words"
1129 help_zle_keybindings['<Alt>s']="spellcheck word"
1130 help_zle_keybindings['<Ctrl>k']="backward kill buffer"
1131 help_zle_keybindings['<Ctrl>u']="forward kill buffer"
1132 help_zle_keybindings['<Ctrl>y']="insert previously killed word/string"
1133 help_zle_keybindings["<Alt>'"]="quote line"
1134 help_zle_keybindings['<Alt>"']="quote from mark to cursor"
1135 help_zle_keybindings['<Alt><arg>']="repeat next cmd/char <arg> times (<Alt>-<Alt>1<Alt>0a -> -10 times 'a')"
1136 help_zle_keybindings['<Alt>u']="make next word Uppercase"
1137 help_zle_keybindings['<Alt>l']="make next word lowercase"
1138 help_zle_keybindings['<Ctrl>xG']="preview expansion under cursor"
1139 help_zle_keybindings['<Alt>q']="push current CL into background, freeing it. Restore on next CL"
1140 help_zle_keybindings['<Alt>.']="insert (and interate through) last word from prev CLs"
1141 help_zle_keybindings['<Alt>,']="complete word from newer history (consecutive hits)"
1142 help_zle_keybindings['<Alt>m']="repeat last typed word on current CL"
1143 help_zle_keybindings['<Ctrl>v']="insert next keypress symbol literally (e.g. for bindkey)"
1144 help_zle_keybindings['!!:n*<Tab>']="insert last n arguments of last command"
1145 help_zle_keybindings['!!:n-<Tab>']="insert arguments n..N-2 of last command (e.g. mv s s d)"
1146 help_zle_keybindings['<Alt>h']="show help/manpage for current command"
1147
1148 #init global variables
1149 unset help_zle_lines help_zle_sln
1150 typeset -g -a help_zle_lines
1151 typeset -g help_zle_sln=1
1152
1153 local k v f cline
1154 local lastkeybind_desc contents #last description starting with #k# that we found
1155 local num_lines_elapsed=0 #number of lines between last description and keybinding
1156 #search config files in the order they a called (and thus the order in which they overwrite keybindings)
1157 for f in $HELPZLE_KEYBINDING_FILES; do
1158 [[ -r "$f" ]] || continue #not readable ? skip it
1159 contents="$(<$f)"
1160 for cline in "${(f)contents}"; do
1161 #zsh pattern: matches lines like: #k# ..............
1162 if [[ "$cline" == (#s)[[:space:]]#\#k\#[[:space:]]##(#b)(*)[[:space:]]#(#e) ]]; then
1163 lastkeybind_desc="$match[*]"
1164 num_lines_elapsed=0
1165 #zsh pattern: matches lines that set a keybinding using bind2map, bindkey or compdef -k
1166 # ignores lines that are commentend out
1167 # grabs first in '' or "" enclosed string with length between 1 and 6 characters
1168 elif [[ "$cline" == [^#]#(bind2maps[[:space:]](*)-s|bindkey|compdef -k)[[:space:]](*)(#b)(\"((?)(#c1,6))\"|\'((?)(#c1,6))\')(#B)(*) ]]; then
1169 #description previously found ? description not more than 2 lines away ? keybinding not empty ?
1170 if [[ -n $lastkeybind_desc && $num_lines_elapsed -lt 2 && -n $match[1] ]]; then
1171 #substitute keybinding string with something readable
1172 k=${${${${${${${match[1]/\\e\^h/<Alt><BS>}/\\e\^\?/<Alt><BS>}/\\e\[5~/<PageUp>}/\\e\[6~/<PageDown>}//(\\e|\^\[)/<Alt>}//\^/<Ctrl>}/3~/<Alt><Del>}
1173 #put keybinding in assoc array, possibly overwriting defaults or stuff found in earlier files
1174 #Note that we are extracting the keybinding-string including the quotes (see Note at beginning)
1175 help_zle_keybindings[${k}]=$lastkeybind_desc
1176 fi
1177 lastkeybind_desc=""
1178 else
1179 ((num_lines_elapsed++))
1180 fi
1181 done
1182 done
1183 unset contents
1184 #calculate length of keybinding column
1185 local kstrlen=0
1186 for k (${(k)help_zle_keybindings[@]}) ((kstrlen < ${#k})) && kstrlen=${#k}
1187 #convert the assoc array into preformated lines, which we are able to sort
1188 for k v in ${(kv)help_zle_keybindings[@]}; do
1189 #pad keybinding-string to kstrlen chars and remove outermost characters (i.e. the quotes)
1190 help_zle_lines+=("${(r:kstrlen:)k[2,-2]}${v}")
1191 done
1192 #sort lines alphabetically
1193 help_zle_lines=("${(i)help_zle_lines[@]}")
1194 [[ -d ${HELP_ZLE_CACHE_FILE:h} ]] || mkdir -p "${HELP_ZLE_CACHE_FILE:h}"
1195 echo "help_zle_lines=(${(q)help_zle_lines[@]})" >| $HELP_ZLE_CACHE_FILE
1196 zcompile $HELP_ZLE_CACHE_FILE
1197}
1198typeset -g help_zle_sln
1199typeset -g -a help_zle_lines
1200
1201# Provides (partially autogenerated) help on keybindings and the zsh line editor
1202function help-zle () {
1203 emulate -L zsh
1204 unsetopt ksharrays #indexing starts at 1
1205 #help lines already generated ? no ? then do it
1206 [[ ${+functions[help_zle_parse_keybindings]} -eq 1 ]] && {help_zle_parse_keybindings && unfunction help_zle_parse_keybindings}
1207 #already displayed all lines ? go back to the start
1208 [[ $help_zle_sln -gt ${#help_zle_lines} ]] && help_zle_sln=1
1209 local sln=$help_zle_sln
1210 #note that help_zle_sln is a global var, meaning we remember the last page we viewed
1211 help_zle_sln=$((help_zle_sln + HELP_LINES_PER_PAGE))
1212 zle -M "${(F)help_zle_lines[sln,help_zle_sln-1]}"
1213}
1214zle -N help-zle
1215
1216## complete word from currently visible Screen or Tmux buffer.
1217if check_com -c screen || check_com -c tmux; then
1218 function _complete_screen_display () {
1219
1220 local TMPFILE=$(mktemp)
1221 local -U -a _screen_display_wordlist
1222 trap "rm -f $TMPFILE" EXIT
1223
1224 # fill array with contents from screen hardcopy
1225 if ((${+TMUX})); then
1226 #works, but crashes tmux below version 1.4
1227 #luckily tmux -V option to ask for version, was also added in 1.4
1228 tmux -V &>/dev/null || return
1229 tmux -q capture-pane -b 0 \; save-buffer -b 0 $TMPFILE \; delete-buffer -b 0
1230 else
1231 [[ "$TERM" != "screen" ]] && return
1232 screen -X hardcopy $TMPFILE
1233 # screen sucks, it dumps in latin1, apparently always. so recode it
1234 # to system charset
1235 check_com recode && recode latin1 $TMPFILE
1236 fi
1237 _screen_display_wordlist=( ${(QQ)$(<$TMPFILE)} )
1238 # remove PREFIX to be completed from that array
1239 _screen_display_wordlist[${_screen_display_wordlist[(i)$PREFIX]}]=""
1240 compadd -a _screen_display_wordlist
1241 }
1242 #m# k CTRL-x\,\,\,S Complete word from GNU screen buffer
1243 bindkey -r "^xS"
1244 compdef -k _complete_screen_display complete-word '^xS'
1245fi
1246
1247# Load a few more functions and tie them to widgets, so they can be bound:
1248
1249function zrcautozle () {
1250 emulate -L zsh
1251 local fnc=$1
1252 zrcautoload $fnc && zle -N $fnc
1253}
1254
1255function zrcgotwidget () {
1256 (( ${+widgets[$1]} ))
1257}
1258
1259function zrcgotkeymap () {
1260 [[ -n ${(M)keymaps:#$1} ]]
1261}
1262
1263zrcautozle insert-files
1264zrcautozle edit-command-line
1265zrcautozle insert-unicode-char
1266if zrcautoload history-search-end; then
1267 zle -N history-beginning-search-backward-end history-search-end
1268 zle -N history-beginning-search-forward-end history-search-end
1269fi
1270zle -C hist-complete complete-word _generic
1271zstyle ':completion:hist-complete:*' completer _history
1272
1273# The actual terminal setup hooks and bindkey-calls:
1274
1275# An array to note missing features to ease diagnosis in case of problems.
1276typeset -ga grml_missing_features
1277
1278function zrcbindkey () {
1279 if (( ARGC )) && zrcgotwidget ${argv[-1]}; then
1280 bindkey "$@"
1281 fi
1282}
1283
1284function bind2maps () {
1285 local i sequence widget
1286 local -a maps
1287
1288 while [[ "$1" != "--" ]]; do
1289 maps+=( "$1" )
1290 shift
1291 done
1292 shift
1293
1294 if [[ "$1" == "-s" ]]; then
1295 shift
1296 sequence="$1"
1297 else
1298 sequence="${key[$1]}"
1299 fi
1300 widget="$2"
1301
1302 [[ -z "$sequence" ]] && return 1
1303
1304 for i in "${maps[@]}"; do
1305 zrcbindkey -M "$i" "$sequence" "$widget"
1306 done
1307}
1308
1309if (( ${+terminfo[smkx]} )) && (( ${+terminfo[rmkx]} )); then
1310 function zle-smkx () {
1311 emulate -L zsh
1312 printf '%s' ${terminfo[smkx]}
1313 }
1314 function zle-rmkx () {
1315 emulate -L zsh
1316 printf '%s' ${terminfo[rmkx]}
1317 }
1318 function zle-line-init () {
1319 zle-smkx
1320 }
1321 function zle-line-finish () {
1322 zle-rmkx
1323 }
1324 zle -N zle-line-init
1325 zle -N zle-line-finish
1326else
1327 for i in {s,r}mkx; do
1328 (( ${+terminfo[$i]} )) || grml_missing_features+=($i)
1329 done
1330 unset i
1331fi
1332
1333typeset -A key
1334key=(
1335 Home "${terminfo[khome]}"
1336 End "${terminfo[kend]}"
1337 Insert "${terminfo[kich1]}"
1338 Delete "${terminfo[kdch1]}"
1339 Up "${terminfo[kcuu1]}"
1340 Down "${terminfo[kcud1]}"
1341 Left "${terminfo[kcub1]}"
1342 Right "${terminfo[kcuf1]}"
1343 PageUp "${terminfo[kpp]}"
1344 PageDown "${terminfo[knp]}"
1345 BackTab "${terminfo[kcbt]}"
1346)
1347
1348# Guidelines for adding key bindings:
1349#
1350# - Do not add hardcoded escape sequences, to enable non standard key
1351# combinations such as Ctrl-Meta-Left-Cursor. They are not easily portable.
1352#
1353# - Adding Ctrl characters, such as '^b' is okay; note that '^b' and '^B' are
1354# the same key.
1355#
1356# - All keys from the $key[] mapping are obviously okay.
1357#
1358# - Most terminals send "ESC x" when Meta-x is pressed. Thus, sequences like
1359# '\ex' are allowed in here as well.
1360
1361bind2maps emacs -- Home beginning-of-somewhere
1362bind2maps viins vicmd -- Home vi-beginning-of-line
1363bind2maps emacs -- End end-of-somewhere
1364bind2maps viins vicmd -- End vi-end-of-line
1365bind2maps emacs viins -- Insert overwrite-mode
1366bind2maps vicmd -- Insert vi-insert
1367bind2maps emacs -- Delete delete-char
1368bind2maps viins vicmd -- Delete vi-delete-char
1369bind2maps emacs viins vicmd -- Up up-line-or-search
1370bind2maps emacs viins vicmd -- Down down-line-or-search
1371bind2maps emacs -- Left backward-char
1372bind2maps viins vicmd -- Left vi-backward-char
1373bind2maps emacs -- Right forward-char
1374bind2maps viins vicmd -- Right vi-forward-char
1375#k# Perform abbreviation expansion
1376bind2maps emacs viins -- -s '^x.' zleiab
1377#k# Display list of abbreviations that would expand
1378bind2maps emacs viins -- -s '^xb' help-show-abk
1379#k# mkdir -p <dir> from string under cursor or marked area
1380bind2maps emacs viins -- -s '^xM' inplaceMkDirs
1381#k# display help for keybindings and ZLE
1382bind2maps emacs viins -- -s '^xz' help-zle
1383#k# Insert files and test globbing
1384bind2maps emacs viins -- -s "^xf" insert-files
1385#k# Edit the current line in \kbd{\$EDITOR}
1386bind2maps emacs viins -- -s '\ee' edit-command-line
1387#k# search history backward for entry beginning with typed text
1388bind2maps emacs viins -- -s '^xp' history-beginning-search-backward-end
1389#k# search history forward for entry beginning with typed text
1390bind2maps emacs viins -- -s '^xP' history-beginning-search-forward-end
1391#k# search history backward for entry beginning with typed text
1392bind2maps emacs viins -- PageUp history-beginning-search-backward-end
1393#k# search history forward for entry beginning with typed text
1394bind2maps emacs viins -- PageDown history-beginning-search-forward-end
1395bind2maps emacs viins -- -s "^x^h" commit-to-history
1396#k# Kill left-side word or everything up to next slash
1397bind2maps emacs viins -- -s '\ev' slash-backward-kill-word
1398#k# Kill left-side word or everything up to next slash
1399bind2maps emacs viins -- -s '\e^h' slash-backward-kill-word
1400#k# Kill left-side word or everything up to next slash
1401bind2maps emacs viins -- -s '\e^?' slash-backward-kill-word
1402# Do history expansion on space:
1403bind2maps emacs viins -- -s ' ' magic-space
1404#k# Trigger menu-complete
1405bind2maps emacs viins -- -s '\ei' menu-complete # menu completion via esc-i
1406#k# Insert a timestamp on the command line (yyyy-mm-dd)
1407bind2maps emacs viins -- -s '^xd' insert-datestamp
1408#k# Insert last typed word
1409bind2maps emacs viins -- -s "\em" insert-last-typed-word
1410#k# A smart shortcut for \kbd{fg<enter>}
1411bind2maps emacs viins -- -s '^z' grml-zsh-fg
1412#k# prepend the current command with "sudo"
1413bind2maps emacs viins -- -s "^os" sudo-command-line
1414#k# jump to after first word (for adding options)
1415bind2maps emacs viins -- -s '^x1' jump_after_first_word
1416#k# complete word from history with menu
1417bind2maps emacs viins -- -s "^x^x" hist-complete
1418
1419# insert unicode character
1420# usage example: 'ctrl-x i' 00A7 'ctrl-x i' will give you an §
1421# See for example http://unicode.org/charts/ for unicode characters code
1422#k# Insert Unicode character
1423bind2maps emacs viins -- -s '^xi' insert-unicode-char
1424
1425# use the new *-pattern-* widgets for incremental history search
1426if zrcgotwidget history-incremental-pattern-search-backward; then
1427 for seq wid in '^r' history-incremental-pattern-search-backward \
1428 '^s' history-incremental-pattern-search-forward
1429 do
1430 bind2maps emacs viins vicmd -- -s $seq $wid
1431 done
1432 builtin unset -v seq wid
1433fi
1434
1435if zrcgotkeymap menuselect; then
1436 #m# k Shift-tab Perform backwards menu completion
1437 bind2maps menuselect -- BackTab reverse-menu-complete
1438
1439 #k# menu selection: pick item but stay in the menu
1440 bind2maps menuselect -- -s '\e^M' accept-and-menu-complete
1441 # also use + and INSERT since it's easier to press repeatedly
1442 bind2maps menuselect -- -s '+' accept-and-menu-complete
1443 bind2maps menuselect -- Insert accept-and-menu-complete
1444
1445 # accept a completion and try to complete again by using menu
1446 # completion; very useful with completing directories
1447 # by using 'undo' one's got a simple file browser
1448 bind2maps menuselect -- -s '^o' accept-and-infer-next-history
1449fi
1450
1451# Finally, here are still a few hardcoded escape sequences; Special sequences
1452# like Ctrl-<Cursor-key> etc do suck a fair bit, because they are not
1453# standardised and most of the time are not available in a terminals terminfo
1454# entry.
1455#
1456# While we do not encourage adding bindings like these, we will keep these for
1457# backward compatibility.
1458
1459## use Ctrl-left-arrow and Ctrl-right-arrow for jumping to word-beginnings on
1460## the command line.
1461# URxvt sequences:
1462bind2maps emacs viins vicmd -- -s '\eOc' forward-word
1463bind2maps emacs viins vicmd -- -s '\eOd' backward-word
1464# These are for xterm:
1465bind2maps emacs viins vicmd -- -s '\e[1;5C' forward-word
1466bind2maps emacs viins vicmd -- -s '\e[1;5D' backward-word
1467## the same for alt-left-arrow and alt-right-arrow
1468# URxvt again:
1469bind2maps emacs viins vicmd -- -s '\e\e[C' forward-word
1470bind2maps emacs viins vicmd -- -s '\e\e[D' backward-word
1471# Xterm again:
1472bind2maps emacs viins vicmd -- -s '^[[1;3C' forward-word
1473bind2maps emacs viins vicmd -- -s '^[[1;3D' backward-word
1474# Also try ESC Left/Right:
1475bind2maps emacs viins vicmd -- -s '\e'${key[Right]} forward-word
1476bind2maps emacs viins vicmd -- -s '\e'${key[Left]} backward-word
1477
1478# autoloading
1479
1480zrcautoload zmv
1481zrcautoload zed
1482
1483# we don't want to quote/espace URLs on our own...
1484# if autoload -U url-quote-magic ; then
1485# zle -N self-insert url-quote-magic
1486# zstyle ':url-quote-magic:*' url-metas '*?[]^()~#{}='
1487# else
1488# print 'Notice: no url-quote-magic available :('
1489# fi
1490alias url-quote='autoload -U bracketed-paste-magic url-quote-magic;
1491 zle -N bracketed-paste bracketed-paste-magic; zle -N self-insert url-quote-magic'
1492
1493#m# k ESC-h Call \kbd{run-help} for the 1st word on the command line
1494alias run-help >&/dev/null && unalias run-help
1495for rh in run-help{,-git,-ip,-openssl,-p4,-sudo,-svk,-svn}; do
1496 zrcautoload $rh
1497done; unset rh
1498
1499# command not found handling
1500
1501(( ${COMMAND_NOT_FOUND} == 1 )) &&
1502function command_not_found_handler () {
1503 emulate -L zsh
1504 if [[ -x ${GRML_ZSH_CNF_HANDLER} ]] ; then
1505 ${GRML_ZSH_CNF_HANDLER} $1
1506 fi
1507 return 1
1508}
1509
1510# history
1511
1512#v#
1513HISTFILE=${HISTFILE:-${ZDOTDIR:-${HOME}}/.zsh_history}
1514# override settings only if the defaults from zsh are in place
1515if [[ -z $HISTSIZE || $HISTSIZE -eq 30 ]] ; then
1516 HISTSIZE=5000
1517 SAVEHIST=10000 # useful for setopt append_history
1518fi
1519
1520# dirstack handling
1521
1522DIRSTACKSIZE=${DIRSTACKSIZE:-20}
1523DIRSTACKFILE=${DIRSTACKFILE:-${ZDOTDIR:-${HOME}}/.zdirs}
1524
1525if zstyle -T ':grml:chpwd:dirstack' enable; then
1526 typeset -gaU GRML_PERSISTENT_DIRSTACK
1527 function grml_dirstack_filter () {
1528 local -a exclude
1529 local filter entry
1530 if zstyle -s ':grml:chpwd:dirstack' filter filter; then
1531 $filter $1 && return 0
1532 fi
1533 if zstyle -a ':grml:chpwd:dirstack' exclude exclude; then
1534 for entry in "${exclude[@]}"; do
1535 [[ $1 == ${~entry} ]] && return 0
1536 done
1537 fi
1538 return 1
1539 }
1540
1541 function chpwd () {
1542 (( ZSH_SUBSHELL )) && return
1543 [[ -z $DIRSTACKSIZE ]] && return
1544 (( $DIRSTACKSIZE <= 0 )) && return
1545 [[ -z $DIRSTACKFILE ]] && return
1546 grml_dirstack_filter $PWD && return
1547 GRML_PERSISTENT_DIRSTACK=(
1548 $PWD "${(@)GRML_PERSISTENT_DIRSTACK[1,$DIRSTACKSIZE]}"
1549 )
1550 builtin print -l ${GRML_PERSISTENT_DIRSTACK} >! ${DIRSTACKFILE}
1551 }
1552
1553 if [[ -f ${DIRSTACKFILE} ]]; then
1554 # Enabling NULL_GLOB via (N) weeds out any non-existing
1555 # directories from the saved dir-stack file.
1556 dirstack=( ${(f)"$(< $DIRSTACKFILE)"}(N) )
1557 # "cd -" won't work after login by just setting $OLDPWD, so
1558 [[ -d $dirstack[1] ]] && cd -q $dirstack[1] && cd -q $OLDPWD
1559 fi
1560
1561 if zstyle -t ':grml:chpwd:dirstack' filter-on-load; then
1562 for i in "${dirstack[@]}"; do
1563 if ! grml_dirstack_filter "$i"; then
1564 GRML_PERSISTENT_DIRSTACK=(
1565 "${GRML_PERSISTENT_DIRSTACK[@]}"
1566 $i
1567 )
1568 fi
1569 done
1570 else
1571 GRML_PERSISTENT_DIRSTACK=( "${dirstack[@]}" )
1572 fi
1573fi
1574
1575# directory based profiles
1576
1577# chpwd_profiles(): Directory Profiles, Quickstart:
1578#
1579# In .zshrc.local:
1580#
1581# zstyle ':chpwd:profiles:/usr/src/grml(|/|/*)' profile grml
1582# zstyle ':chpwd:profiles:/usr/src/debian(|/|/*)' profile debian
1583# chpwd_profiles
1584#
1585# For details see the `grmlzshrc.5' manual page.
1586function chpwd_profiles () {
1587 local profile context
1588 local -i reexecute
1589
1590 context=":chpwd:profiles:$PWD"
1591 zstyle -s "$context" profile profile || profile='default'
1592 zstyle -T "$context" re-execute && reexecute=1 || reexecute=0
1593
1594 if (( ${+parameters[CHPWD_PROFILE]} == 0 )); then
1595 typeset -g CHPWD_PROFILE
1596 local CHPWD_PROFILES_INIT=1
1597 (( ${+functions[chpwd_profiles_init]} )) && chpwd_profiles_init
1598 elif [[ $profile != $CHPWD_PROFILE ]]; then
1599 (( ${+functions[chpwd_leave_profile_$CHPWD_PROFILE]} )) \
1600 && chpwd_leave_profile_${CHPWD_PROFILE}
1601 fi
1602 if (( reexecute )) || [[ $profile != $CHPWD_PROFILE ]]; then
1603 (( ${+functions[chpwd_profile_$profile]} )) && chpwd_profile_${profile}
1604 fi
1605
1606 CHPWD_PROFILE="${profile}"
1607 return 0
1608}
1609
1610chpwd_functions=( ${chpwd_functions} chpwd_profiles )
1611
1612# Prompt setup for grml:
1613
1614# set colors for use in prompts.
1615BLUE="%F{blue}"
1616RED="%F{red}"
1617GREEN="%F{green}"
1618CYAN="%F{cyan}"
1619MAGENTA="%F{magenta}"
1620YELLOW="%F{yellow}"
1621WHITE="%F{white}"
1622NO_COLOR="%f"
1623
1624# First, the easy ones: PS2..4:
1625
1626# secondary prompt, printed when the shell needs more information to complete a
1627# command.
1628PS2='\`%_> '
1629# selection prompt used within a select loop.
1630PS3='?# '
1631# the execution trace prompt (setopt xtrace). default: '+%N:%i>'
1632PS4='+%N:%i:%_> '
1633
1634# Some additional features to use with our prompt:
1635#
1636# - battery status
1637# - debian_chroot
1638# - vcs_info setup and version specific fixes
1639
1640# display battery status on right side of prompt using 'GRML_DISPLAY_BATTERY=1' in .zshrc.pre
1641
1642function battery () {
1643if [[ $GRML_DISPLAY_BATTERY -gt 0 ]] ; then
1644 if islinux ; then
1645 batterylinux
1646 elif isopenbsd ; then
1647 batteryopenbsd
1648 elif isfreebsd ; then
1649 batteryfreebsd
1650 elif isdarwin ; then
1651 batterydarwin
1652 else
1653 #not yet supported
1654 GRML_DISPLAY_BATTERY=0
1655 fi
1656fi
1657}
1658
1659function batterylinux () {
1660GRML_BATTERY_LEVEL=''
1661local batteries bat capacity
1662batteries=( /sys/class/power_supply/BAT*(N) )
1663if (( $#batteries > 0 )) ; then
1664 for bat in $batteries ; do
1665 if [[ -e $bat/capacity ]]; then
1666 capacity=$(< $bat/capacity)
1667 else
1668 typeset -F energy_full=$(< $bat/energy_full)
1669 typeset -F energy_now=$(< $bat/energy_now)
1670 typeset -i capacity=$(( 100 * $energy_now / $energy_full))
1671 fi
1672 case $(< $bat/status) in
1673 Charging)
1674 GRML_BATTERY_LEVEL+=" ^"
1675 ;;
1676 Discharging)
1677 if (( capacity < 20 )) ; then
1678 GRML_BATTERY_LEVEL+=" !v"
1679 else
1680 GRML_BATTERY_LEVEL+=" v"
1681 fi
1682 ;;
1683 *) # Full, Unknown
1684 GRML_BATTERY_LEVEL+=" ="
1685 ;;
1686 esac
1687 GRML_BATTERY_LEVEL+="${capacity}%%"
1688 done
1689fi
1690}
1691
1692function batteryopenbsd () {
1693GRML_BATTERY_LEVEL=''
1694local bat batfull batwarn batnow num
1695for num in 0 1 ; do
1696 bat=$(sysctl -n hw.sensors.acpibat${num} 2>/dev/null)
1697 if [[ -n $bat ]]; then
1698 batfull=${"$(sysctl -n hw.sensors.acpibat${num}.amphour0)"%% *}
1699 batwarn=${"$(sysctl -n hw.sensors.acpibat${num}.amphour1)"%% *}
1700 batnow=${"$(sysctl -n hw.sensors.acpibat${num}.amphour3)"%% *}
1701 case "$(sysctl -n hw.sensors.acpibat${num}.raw0)" in
1702 *" discharging"*)
1703 if (( batnow < batwarn )) ; then
1704 GRML_BATTERY_LEVEL+=" !v"
1705 else
1706 GRML_BATTERY_LEVEL+=" v"
1707 fi
1708 ;;
1709 *" charging"*)
1710 GRML_BATTERY_LEVEL+=" ^"
1711 ;;
1712 *)
1713 GRML_BATTERY_LEVEL+=" ="
1714 ;;
1715 esac
1716 GRML_BATTERY_LEVEL+="${$(( 100 * batnow / batfull ))%%.*}%%"
1717 fi
1718done
1719}
1720
1721function batteryfreebsd () {
1722GRML_BATTERY_LEVEL=''
1723local num
1724local -A table
1725for num in 0 1 ; do
1726 table=( ${=${${${${${(M)${(f)"$(acpiconf -i $num 2>&1)"}:#(State|Remaining capacity):*}%%( ##|%)}//:[ $'\t']##/@}// /-}//@/ }} )
1727 if [[ -n $table ]] && [[ $table[State] != "not-present" ]] ; then
1728 case $table[State] in
1729 *discharging*)
1730 if (( $table[Remaining-capacity] < 20 )) ; then
1731 GRML_BATTERY_LEVEL+=" !v"
1732 else
1733 GRML_BATTERY_LEVEL+=" v"
1734 fi
1735 ;;
1736 *charging*)
1737 GRML_BATTERY_LEVEL+=" ^"
1738 ;;
1739 *)
1740 GRML_BATTERY_LEVEL+=" ="
1741 ;;
1742 esac
1743 GRML_BATTERY_LEVEL+="$table[Remaining-capacity]%%"
1744 fi
1745done
1746}
1747
1748function batterydarwin () {
1749GRML_BATTERY_LEVEL=''
1750local -a table
1751table=( ${$(pmset -g ps)[(w)8,9]%%(\%|);} )
1752if [[ -n $table[2] ]] ; then
1753 case $table[2] in
1754 charging)
1755 GRML_BATTERY_LEVEL+=" ^"
1756 ;;
1757 discharging)
1758 if (( $table[1] < 20 )) ; then
1759 GRML_BATTERY_LEVEL+=" !v"
1760 else
1761 GRML_BATTERY_LEVEL+=" v"
1762 fi
1763 ;;
1764 *)
1765 GRML_BATTERY_LEVEL+=" ="
1766 ;;
1767 esac
1768 GRML_BATTERY_LEVEL+="$table[1]%%"
1769fi
1770}
1771
1772# set variable debian_chroot if running in a chroot with /etc/debian_chroot
1773if [[ -z "$debian_chroot" ]] && [[ -r /etc/debian_chroot ]] ; then
1774 debian_chroot=$(</etc/debian_chroot)
1775fi
1776
1777# gather version control information for inclusion in a prompt
1778
1779if zrcautoload vcs_info; then
1780 zstyle ':vcs_info:*' max-exports 2
1781
1782 if [[ -o restricted ]]; then
1783 zstyle ':vcs_info:*' enable NONE
1784 fi
1785fi
1786
1787typeset -A grml_vcs_coloured_formats
1788typeset -A grml_vcs_plain_formats
1789
1790grml_vcs_plain_formats=(
1791 format "(%s%)-[%b] " "zsh: %r"
1792 actionformat "(%s%)-[%b|%a] " "zsh: %r"
1793 rev-branchformat "%b:%r"
1794)
1795
1796grml_vcs_coloured_formats=(
1797 format "${MAGENTA}(${NO_COLOR}%s${MAGENTA})${YELLOW}-${MAGENTA}[${GREEN}%b${MAGENTA}]${NO_COLOR} "
1798 actionformat "${MAGENTA}(${NO_COLOR}%s${MAGENTA})${YELLOW}-${MAGENTA}[${GREEN}%b${YELLOW}|${RED}%a${MAGENTA}]${NO_COLOR} "
1799 rev-branchformat "%b${RED}:${YELLOW}%r"
1800)
1801
1802typeset GRML_VCS_COLOUR_MODE=xxx
1803
1804function grml_vcs_info_toggle_colour () {
1805 emulate -L zsh
1806 if [[ $GRML_VCS_COLOUR_MODE == plain ]]; then
1807 grml_vcs_info_set_formats coloured
1808 else
1809 grml_vcs_info_set_formats plain
1810 fi
1811 return 0
1812}
1813
1814function grml_vcs_info_set_formats () {
1815 emulate -L zsh
1816 #setopt localoptions xtrace
1817 local mode=$1 AF F BF
1818 if [[ $mode == coloured ]]; then
1819 AF=${grml_vcs_coloured_formats[actionformat]}
1820 F=${grml_vcs_coloured_formats[format]}
1821 BF=${grml_vcs_coloured_formats[rev-branchformat]}
1822 GRML_VCS_COLOUR_MODE=coloured
1823 else
1824 AF=${grml_vcs_plain_formats[actionformat]}
1825 F=${grml_vcs_plain_formats[format]}
1826 BF=${grml_vcs_plain_formats[rev-branchformat]}
1827 GRML_VCS_COLOUR_MODE=plain
1828 fi
1829
1830 zstyle ':vcs_info:*' actionformats "$AF" "zsh: %r"
1831 zstyle ':vcs_info:*' formats "$F" "zsh: %r"
1832 zstyle ':vcs_info:(sv[nk]|bzr):*' branchformat "$BF"
1833 return 0
1834}
1835
1836# Change vcs_info formats for the grml prompt. The 2nd format sets up
1837# $vcs_info_msg_1_ to contain "zsh: repo-name" used to set our screen title.
1838if [[ "$TERM" == dumb ]] ; then
1839 grml_vcs_info_set_formats plain
1840else
1841 grml_vcs_info_set_formats coloured
1842fi
1843
1844# Now for the fun part: The grml prompt themes in `promptsys' mode of operation
1845
1846# This actually defines three prompts:
1847#
1848# - grml
1849# - grml-large
1850# - grml-chroot
1851#
1852# They all share the same code and only differ with respect to which items they
1853# contain. The main source of documentation is the `prompt_grml_help' function
1854# below, which gets called when the user does this: prompt -h grml
1855
1856function prompt_grml_help () {
1857 <<__EOF0__
1858 prompt grml
1859
1860 This is the prompt as used by the grml-live system <http://grml.org>. It is
1861 a rather simple one-line prompt, that by default looks something like this:
1862
1863 <user>@<host> <current-working-directory>[ <vcs_info-data>]%
1864
1865 The prompt itself integrates with zsh's prompt themes system (as you are
1866 witnessing right now) and is configurable to a certain degree. In
1867 particular, these aspects are customisable:
1868
1869 - The items used in the prompt (e.g. you can remove \`user' from
1870 the list of activated items, which will cause the user name to
1871 be omitted from the prompt string).
1872
1873 - The attributes used with the items are customisable via strings
1874 used before and after the actual item.
1875
1876 The available items are: at, battery, change-root, date, grml-chroot,
1877 history, host, jobs, newline, path, percent, rc, rc-always, sad-smiley,
1878 shell-level, time, user, vcs
1879
1880 The actual configuration is done via zsh's \`zstyle' mechanism. The
1881 context, that is used while looking up styles is:
1882
1883 ':prompt:grml:<left-or-right>:<subcontext>'
1884
1885 Here <left-or-right> is either \`left' or \`right', signifying whether the
1886 style should affect the left or the right prompt. <subcontext> is either
1887 \`setup' or 'items:<item>', where \`<item>' is one of the available items.
1888
1889 The styles:
1890
1891 - use-rprompt (boolean): If \`true' (the default), print a sad smiley
1892 in $RPROMPT if the last command a returned non-successful error code.
1893 (This in only valid if <left-or-right> is "right"; ignored otherwise)
1894
1895 - items (list): The list of items used in the prompt. If \`vcs' is
1896 present in the list, the theme's code invokes \`vcs_info'
1897 accordingly. Default (left): rc change-root user at host path vcs
1898 percent; Default (right): sad-smiley
1899
1900 - strip-sensitive-characters (boolean): If the \`prompt_subst' option
1901 is active in zsh, the shell performs lots of expansions on prompt
1902 variable strings, including command substitution. So if you don't
1903 control where some of your prompt strings is coming from, this is
1904 an exploitable weakness. Grml's zsh setup does not set this option
1905 and it is off in the shell in zsh-mode by default. If it *is* turned
1906 on however, this style becomes active, and there are two flavours of
1907 it: On per default is a global variant in the '*:setup' context. This
1908 strips characters after the whole prompt string was constructed. There
1909 is a second variant in the '*:items:<item>', that is off by default.
1910 It allows fine grained control over which items' data is stripped.
1911 The characters that are stripped are: \$ and \`.
1912
1913 Available styles in 'items:<item>' are: pre, post. These are strings that
1914 are inserted before (pre) and after (post) the item in question. Thus, the
1915 following would cause the user name to be printed in red instead of the
1916 default blue:
1917
1918 zstyle ':prompt:grml:*:items:user' pre '%F{red}'
1919
1920 Note, that the \`post' style may remain at its default value, because its
1921 default value is '%f', which turns the foreground text attribute off (which
1922 is exactly, what is still required with the new \`pre' value).
1923__EOF0__
1924}
1925
1926function prompt_grml-chroot_help () {
1927 <<__EOF0__
1928 prompt grml-chroot
1929
1930 This is a variation of the grml prompt, see: prompt -h grml
1931
1932 The main difference is the default value of the \`items' style. The rest
1933 behaves exactly the same. Here are the defaults for \`grml-chroot':
1934
1935 - left: grml-chroot user at host path percent
1936 - right: (empty list)
1937__EOF0__
1938}
1939
1940function prompt_grml-large_help () {
1941 <<__EOF0__
1942 prompt grml-large
1943
1944 This is a variation of the grml prompt, see: prompt -h grml
1945
1946 The main difference is the default value of the \`items' style. In
1947 particular, this theme uses _two_ lines instead of one with the plain
1948 \`grml' theme. The rest behaves exactly the same. Here are the defaults
1949 for \`grml-large':
1950
1951 - left: rc jobs history shell-level change-root time date newline user
1952 at host path vcs percent
1953 - right: sad-smiley
1954__EOF0__
1955}
1956
1957function grml_prompt_setup () {
1958 emulate -L zsh
1959 autoload -Uz vcs_info
1960 add-zsh-hook precmd prompt_$1_precmd
1961}
1962
1963function prompt_grml_setup () {
1964 grml_prompt_setup grml
1965}
1966
1967function prompt_grml-chroot_setup () {
1968 grml_prompt_setup grml-chroot
1969}
1970
1971function prompt_grml-large_setup () {
1972 grml_prompt_setup grml-large
1973}
1974
1975# These maps define default tokens and pre-/post-decoration for items to be
1976# used within the themes. All defaults may be customised in a context sensitive
1977# matter by using zsh's `zstyle' mechanism.
1978typeset -gA grml_prompt_pre_default \
1979 grml_prompt_post_default \
1980 grml_prompt_token_default \
1981 grml_prompt_token_function
1982
1983grml_prompt_pre_default=(
1984 at ''
1985 battery ' '
1986 change-root ''
1987 date '%F{blue}'
1988 grml-chroot '%F{red}'
1989 history '%F{green}'
1990 host ''
1991 jobs '%F{cyan}'
1992 newline ''
1993 path '%B'
1994 percent ''
1995 rc '%B%F{red}'
1996 rc-always ''
1997 sad-smiley ''
1998 shell-level '%F{red}'
1999 time '%F{blue}'
2000 user '%B%F{blue}'
2001 vcs ''
2002)
2003
2004grml_prompt_post_default=(
2005 at ''
2006 battery ''
2007 change-root ''
2008 date '%f'
2009 grml-chroot '%f '
2010 history '%f'
2011 host ''
2012 jobs '%f'
2013 newline ''
2014 path '%b'
2015 percent ''
2016 rc '%f%b'
2017 rc-always ''
2018 sad-smiley ''
2019 shell-level '%f'
2020 time '%f'
2021 user '%f%b'
2022 vcs ''
2023)
2024
2025grml_prompt_token_default=(
2026 at '@'
2027 battery 'GRML_BATTERY_LEVEL'
2028 change-root 'debian_chroot'
2029 date '%D{%Y-%m-%d}'
2030 grml-chroot 'GRML_CHROOT'
2031 history '{history#%!} '
2032 host '%m '
2033 jobs '[%j running job(s)] '
2034 newline $'\n'
2035 path '%40<..<%~%<< '
2036 percent '%# '
2037 rc '%(?..%? )'
2038 rc-always '%?'
2039 sad-smiley '%(?..:()'
2040 shell-level '%(3L.+ .)'
2041 time '%D{%H:%M:%S} '
2042 user '%n'
2043 vcs '0'
2044)
2045
2046function grml_theme_has_token () {
2047 if (( ARGC != 1 )); then
2048 printf 'usage: grml_theme_has_token <name>\n'
2049 return 1
2050 fi
2051 (( ${+grml_prompt_token_default[$1]} ))
2052}
2053
2054function GRML_theme_add_token_usage () {
2055 <<__EOF0__
2056 Usage: grml_theme_add_token <name> [-f|-i] <token/function> [<pre> <post>]
2057
2058 <name> is the name for the newly added token. If the \`-f' or \`-i' options
2059 are used, <token/function> is the name of the function (see below for
2060 details). Otherwise it is the literal token string to be used. <pre> and
2061 <post> are optional.
2062
2063 Options:
2064
2065 -f <function> Use a function named \`<function>' each time the token
2066 is to be expanded.
2067
2068 -i <function> Use a function named \`<function>' to initialise the
2069 value of the token _once_ at runtime.
2070
2071 The functions are called with one argument: the token's new name. The
2072 return value is expected in the \$REPLY parameter. The use of these
2073 options is mutually exclusive.
2074
2075 There is a utility function \`grml_theme_has_token', which you can use
2076 to test if a token exists before trying to add it. This can be a guard
2077 for situations in which a \`grml_theme_add_token' call may happen more
2078 than once.
2079
2080 Example:
2081
2082 To add a new token \`day' that expands to the current weekday in the
2083 current locale in green foreground colour, use this:
2084
2085 grml_theme_add_token day '%D{%A}' '%F{green}' '%f'
2086
2087 Another example would be support for \$VIRTUAL_ENV:
2088
2089 function virtual_env_prompt () {
2090 REPLY=\${VIRTUAL_ENV+\${VIRTUAL_ENV:t} }
2091 }
2092 grml_theme_add_token virtual-env -f virtual_env_prompt
2093
2094 After that, you will be able to use a changed \`items' style to
2095 assemble your prompt.
2096__EOF0__
2097}
2098
2099function grml_theme_add_token () {
2100 emulate -L zsh
2101 local name token pre post
2102 local -i init funcall
2103
2104 if (( ARGC == 0 )); then
2105 GRML_theme_add_token_usage
2106 return 0
2107 fi
2108
2109 init=0
2110 funcall=0
2111 pre=''
2112 post=''
2113 name=$1
2114 shift
2115 if [[ $1 == '-f' ]]; then
2116 funcall=1
2117 shift
2118 elif [[ $1 == '-i' ]]; then
2119 init=1
2120 shift
2121 fi
2122
2123 if (( ARGC == 0 )); then
2124 printf '
2125grml_theme_add_token: No token-string/function-name provided!\n\n'
2126 GRML_theme_add_token_usage
2127 return 1
2128 fi
2129 token=$1
2130 shift
2131 if (( ARGC != 0 && ARGC != 2 )); then
2132 printf '
2133grml_theme_add_token: <pre> and <post> need to by specified _both_!\n\n'
2134 GRML_theme_add_token_usage
2135 return 1
2136 fi
2137 if (( ARGC )); then
2138 pre=$1
2139 post=$2
2140 shift 2
2141 fi
2142
2143 if grml_theme_has_token $name; then
2144 printf '
2145grml_theme_add_token: Token `%s'\'' exists! Giving up!\n\n' $name
2146 GRML_theme_add_token_usage
2147 return 2
2148 fi
2149 if (( init )); then
2150 REPLY=''
2151 $token $name
2152 token=$REPLY
2153 fi
2154 grml_prompt_pre_default[$name]=$pre
2155 grml_prompt_post_default[$name]=$post
2156 if (( funcall )); then
2157 grml_prompt_token_function[$name]=$token
2158 grml_prompt_token_default[$name]=23
2159 else
2160 grml_prompt_token_default[$name]=$token
2161 fi
2162}
2163
2164function grml_wrap_reply () {
2165 emulate -L zsh
2166 local target="$1"
2167 local new="$2"
2168 local left="$3"
2169 local right="$4"
2170
2171 if (( ${+parameters[$new]} )); then
2172 REPLY="${left}${(P)new}${right}"
2173 else
2174 REPLY=''
2175 fi
2176}
2177
2178function grml_prompt_addto () {
2179 emulate -L zsh
2180 local target="$1"
2181 local lr it apre apost new v REPLY
2182 local -a items
2183 shift
2184
2185 [[ $target == PS1 ]] && lr=left || lr=right
2186 zstyle -a ":prompt:${grmltheme}:${lr}:setup" items items || items=( "$@" )
2187 typeset -g "${target}="
2188 for it in "${items[@]}"; do
2189 zstyle -s ":prompt:${grmltheme}:${lr}:items:$it" pre apre \
2190 || apre=${grml_prompt_pre_default[$it]}
2191 zstyle -s ":prompt:${grmltheme}:${lr}:items:$it" post apost \
2192 || apost=${grml_prompt_post_default[$it]}
2193 zstyle -s ":prompt:${grmltheme}:${lr}:items:$it" token new \
2194 || new=${grml_prompt_token_default[$it]}
2195 if (( ${+grml_prompt_token_function[$it]} )); then
2196 REPLY=''
2197 ${grml_prompt_token_function[$it]} $it
2198 else
2199 case $it in
2200 battery)
2201 grml_wrap_reply $target $new '' ''
2202 ;;
2203 change-root)
2204 grml_wrap_reply $target $new '(' ')'
2205 ;;
2206 grml-chroot)
2207 if [[ -n ${(P)new} ]]; then
2208 REPLY="$CHROOT"
2209 else
2210 REPLY=''
2211 fi
2212 ;;
2213 vcs)
2214 v="vcs_info_msg_${new}_"
2215 if (( ! vcscalled )); then
2216 vcs_info
2217 vcscalled=1
2218 fi
2219 if (( ${+parameters[$v]} )) && [[ -n "${(P)v}" ]]; then
2220 REPLY="${(P)v}"
2221 else
2222 REPLY=''
2223 fi
2224 ;;
2225 *) REPLY="$new" ;;
2226 esac
2227 fi
2228 # Strip volatile characters per item. This is off by default. See the
2229 # global stripping code a few lines below for details.
2230 if [[ -o prompt_subst ]] && zstyle -t ":prompt:${grmltheme}:${lr}:items:$it" \
2231 strip-sensitive-characters
2232 then
2233 REPLY="${REPLY//[$\`]/}"
2234 fi
2235 typeset -g "${target}=${(P)target}${apre}${REPLY}${apost}"
2236 done
2237
2238 # Per default, strip volatile characters (in the prompt_subst case)
2239 # globally. If the option is off, the style has no effect. For more
2240 # control, this can be turned off and stripping can be configured on a
2241 # per-item basis (see above).
2242 if [[ -o prompt_subst ]] && zstyle -T ":prompt:${grmltheme}:${lr}:setup" \
2243 strip-sensitive-characters
2244 then
2245 typeset -g "${target}=${${(P)target}//[$\`]/}"
2246 fi
2247}
2248
2249function prompt_grml_precmd () {
2250 emulate -L zsh
2251 local grmltheme=grml
2252 local -a left_items right_items
2253 left_items=(rc change-root user at host path vcs percent)
2254 right_items=(sad-smiley)
2255
2256 prompt_grml_precmd_worker
2257}
2258
2259function prompt_grml-chroot_precmd () {
2260 emulate -L zsh
2261 local grmltheme=grml-chroot
2262 local -a left_items right_items
2263 left_items=(grml-chroot user at host path percent)
2264 right_items=()
2265
2266 prompt_grml_precmd_worker
2267}
2268
2269function prompt_grml-large_precmd () {
2270 emulate -L zsh
2271 local grmltheme=grml-large
2272 local -a left_items right_items
2273 left_items=(rc jobs history shell-level change-root time date newline
2274 user at host path vcs percent)
2275 right_items=(sad-smiley)
2276
2277 prompt_grml_precmd_worker
2278}
2279
2280function prompt_grml_precmd_worker () {
2281 emulate -L zsh
2282 local -i vcscalled=0
2283
2284 grml_prompt_addto PS1 "${left_items[@]}"
2285 if zstyle -T ":prompt:${grmltheme}:right:setup" use-rprompt; then
2286 grml_prompt_addto RPS1 "${right_items[@]}"
2287 fi
2288}
2289
2290function grml_prompt_fallback () {
2291 setopt prompt_subst
2292 local p0 p1
2293
2294 p0="${RED}%(?..%? )${WHITE}${debian_chroot:+($debian_chroot)}"
2295 p1="${BLUE}%n${NO_COLOR}@%m %40<...<%B%~%b%<< "'${vcs_info_msg_0_}'"%# "
2296 if (( EUID == 0 )); then
2297 PROMPT="${BLUE}${p0}${RED}${p1}"
2298 else
2299 PROMPT="${RED}${p0}${BLUE}${p1}"
2300 fi
2301}
2302
2303if zrcautoload promptinit && promptinit 2>/dev/null ; then
2304 grml_status_feature promptinit 0
2305 # Since we define the required functions in here and not in files in
2306 # $fpath, we need to stick the theme's name into `$prompt_themes'
2307 # ourselves, since promptinit does not pick them up otherwise.
2308 prompt_themes+=( grml grml-chroot grml-large )
2309 # Also, keep the array sorted...
2310 prompt_themes=( "${(@on)prompt_themes}" )
2311else
2312 grml_status_feature promptinit 1
2313 grml_prompt_fallback
2314 function precmd () { (( ${+functions[vcs_info]} )) && vcs_info; }
2315fi
2316
2317if [[ $GRML_DISPLAY_BATTERY -gt 0 ]]; then
2318 zstyle ':prompt:grml:right:setup' items sad-smiley battery
2319 add-zsh-hook precmd battery
2320fi
2321if [[ "$TERM" == dumb ]] ; then
2322 zstyle ":prompt:grml(|-large|-chroot):*:items:grml-chroot" pre ''
2323 zstyle ":prompt:grml(|-large|-chroot):*:items:grml-chroot" post ' '
2324 for i in rc user path jobs history date time shell-level; do
2325 zstyle ":prompt:grml(|-large|-chroot):*:items:$i" pre ''
2326 zstyle ":prompt:grml(|-large|-chroot):*:items:$i" post ''
2327 done
2328 unset i
2329 zstyle ':prompt:grml(|-large|-chroot):right:setup' use-rprompt false
2330elif (( EUID == 0 )); then
2331 zstyle ':prompt:grml(|-large|-chroot):*:items:user' pre '%B%F{red}'
2332fi
2333
2334# Finally enable one of the prompts.
2335if [[ -n $GRML_CHROOT ]]; then
2336 prompt grml-chroot
2337elif [[ $GRMLPROMPT -gt 0 ]]; then
2338 prompt grml-large
2339else
2340 prompt grml
2341fi
2342
2343# make sure to use right prompt only when not running a command
2344setopt transient_rprompt
2345
2346# Terminal-title wizardry
2347
2348function ESC_print () {
2349 info_print $'\ek' $'\e\\' "$@"
2350}
2351function set_title () {
2352 info_print $'\e]0;' $'\a' "$@"
2353}
2354
2355function info_print () {
2356 local esc_begin esc_end
2357 esc_begin="$1"
2358 esc_end="$2"
2359 shift 2
2360 printf '%s' ${esc_begin}
2361 printf '%s' "$*"
2362 printf '%s' "${esc_end}"
2363}
2364
2365function grml_reset_screen_title () {
2366 # adjust title of xterm
2367 # see http://www.faqs.org/docs/Linux-mini/Xterm-Title.html
2368 [[ ${NOTITLE:-} -gt 0 ]] && return 0
2369 case $TERM in
2370 (xterm*|rxvt*|alacritty|foot)
2371 set_title ${(%):-"%n@%m: %~"}
2372 ;;
2373 esac
2374}
2375
2376function grml_vcs_to_screen_title () {
2377 if [[ $TERM == screen* ]] ; then
2378 if [[ -n ${vcs_info_msg_1_} ]] ; then
2379 ESC_print ${vcs_info_msg_1_}
2380 else
2381 ESC_print "zsh"
2382 fi
2383 fi
2384}
2385
2386function grml_cmd_to_screen_title () {
2387 # get the name of the currently running program to set screen window title
2388 # if running in a screen.
2389 if [[ "$TERM" == screen* ]] ; then
2390 local CMD="${1[(wr)^(*=*|sudo|ssh|-*)]}"
2391 ESC_print ${CMD}
2392 fi
2393}
2394
2395function grml_control_xterm_title () {
2396 case $TERM in
2397 (xterm*|rxvt*|alacritty|foot)
2398 set_title "${(%):-"%n@%m:"}" "$2"
2399 ;;
2400 esac
2401}
2402
2403if [[ $NOPRECMD -eq 0 ]]; then
2404 add-zsh-hook precmd grml_reset_screen_title
2405 add-zsh-hook precmd grml_vcs_to_screen_title
2406 add-zsh-hook preexec grml_cmd_to_screen_title
2407 if [[ $NOTITLE -eq 0 ]]; then
2408 add-zsh-hook preexec grml_control_xterm_title
2409 fi
2410fi
2411
2412# 'hash' some often used directories
2413#d# start
2414hash -d deb=/var/cache/apt/archives
2415hash -d doc=/usr/share/doc
2416hash -d linux=/lib/modules/$(command uname -r)/build/
2417hash -d log=/var/log
2418hash -d slog=/var/log/syslog
2419hash -d src=/usr/src
2420hash -d www=/var/www
2421#d# end
2422
2423# some aliases
2424if check_com -c screen ; then
2425 if [[ $UID -eq 0 ]] ; then
2426 if [[ -r /etc/grml/screenrc ]]; then
2427 alias screen='screen -c /etc/grml/screenrc'
2428 fi
2429 elif [[ ! -r $HOME/.screenrc ]] ; then
2430 if [[ -r /etc/grml/screenrc_grml ]]; then
2431 alias screen='screen -c /etc/grml/screenrc_grml'
2432 else
2433 if [[ -r /etc/grml/screenrc ]]; then
2434 alias screen='screen -c /etc/grml/screenrc'
2435 fi
2436 fi
2437 fi
2438fi
2439
2440# do we have GNU ls with color-support?
2441if [[ "$TERM" != dumb ]]; then
2442 #a1# List files with colors (\kbd{ls \ldots})
2443 alias ls="command ls ${ls_options:+${ls_options[*]}}"
2444 #a1# List all files, with colors (\kbd{ls -la \ldots})
2445 alias la="command ls -la ${ls_options:+${ls_options[*]}}"
2446 #a1# List files with long colored list, without dotfiles (\kbd{ls -l \ldots})
2447 alias ll="command ls -l ${ls_options:+${ls_options[*]}}"
2448 #a1# List files with long colored list, human readable sizes (\kbd{ls -hAl \ldots})
2449 alias lh="command ls -hAl ${ls_options:+${ls_options[*]}}"
2450 #a1# List files with long colored list, append qualifier to filenames (\kbd{ls -l \ldots})\\&\quad(\kbd{/} for directories, \kbd{@} for symlinks ...)
2451 alias l="command ls -l ${ls_options:+${ls_options[*]}}"
2452else
2453 alias la='command ls -la'
2454 alias ll='command ls -l'
2455 alias lh='command ls -hAl'
2456 alias l='command ls -l'
2457fi
2458
2459# use ip from iproute2 with color support
2460if ip -color=auto addr show dev lo >/dev/null 2>&1; then
2461 alias ip='command ip -color=auto'
2462fi
2463
2464if [[ -r /proc/mdstat ]]; then
2465 alias mdstat='cat /proc/mdstat'
2466fi
2467
2468alias ...='cd ../../'
2469
2470# generate alias named "$KERNELVERSION-reboot" so you can use boot with kexec:
2471if [[ -x /sbin/kexec ]] && [[ -r /proc/cmdline ]] ; then
2472 alias "$(uname -r)-reboot"="kexec -l --initrd=/boot/initrd.img-"$(uname -r)" --command-line=\"$(cat /proc/cmdline)\" /boot/vmlinuz-"$(uname -r)""
2473fi
2474
2475#f1# Hints for the use of zsh on grml
2476function zsh-help () {
2477 print "$bg[white]$fg[black]
2478zsh-help - hints for use of zsh on grml
2479=======================================$reset_color"
2480
2481 print '
2482Main configuration of zsh happens in /etc/zsh/zshrc.
2483That file is part of the package grml-etc-core, if you want to
2484use them on a non-grml-system just get the tar.gz from
2485http://deb.grml.org/ or (preferably) get it from the git repository:
2486
2487 http://git.grml.org/f/grml-etc-core/etc/zsh/zshrc
2488
2489This version of grml'\''s zsh setup does not use skel/.zshrc anymore.
2490The file is still there, but it is empty for backwards compatibility.
2491
2492For your own changes use these two files:
2493 $HOME/.zshrc.pre
2494 $HOME/.zshrc.local
2495
2496The former is sourced very early in our zshrc, the latter is sourced
2497very lately.
2498
2499System wide configuration without touching configuration files of grml
2500can take place in /etc/zsh/zshrc.local.
2501
2502For information regarding zsh start at http://grml.org/zsh/
2503
2504Take a look at grml'\''s zsh refcard:
2505% xpdf =(zcat /usr/share/doc/grml-docs/zsh/grml-zsh-refcard.pdf.gz)
2506
2507Check out the main zsh refcard:
2508% '$BROWSER' http://www.bash2zsh.com/zsh_refcard/refcard.pdf
2509
2510And of course visit the zsh-lovers:
2511% man zsh-lovers
2512
2513You can adjust some options through environment variables when
2514invoking zsh without having to edit configuration files.
2515Basically meant for bash users who are not used to the power of
2516the zsh yet. :)
2517
2518 "NOCOR=1 zsh" => deactivate automatic correction
2519 "NOMENU=1 zsh" => do not use auto menu completion
2520 (note: use ctrl-d for completion instead!)
2521 "NOPRECMD=1 zsh" => disable the precmd + preexec commands (set GNU screen title)
2522 "NOTITLE=1 zsh" => disable setting the title of xterms without disabling
2523 preexec() and precmd() completely
2524 "GRML_DISPLAY_BATTERY=1 zsh"
2525 => activate battery status on right side of prompt (WIP)
2526 "COMMAND_NOT_FOUND=1 zsh"
2527 => Enable a handler if an external command was not found
2528 The command called in the handler can be altered by setting
2529 the GRML_ZSH_CNF_HANDLER variable, the default is:
2530 "/usr/share/command-not-found/command-not-found"
2531
2532A value greater than 0 is enables a feature; a value equal to zero
2533disables it. If you like one or the other of these settings, you can
2534add them to ~/.zshrc.pre to ensure they are set when sourcing grml'\''s
2535zshrc.'
2536
2537 print "
2538$bg[white]$fg[black]
2539Please report wishes + bugs to the grml-team: http://grml.org/bugs/
2540Enjoy your grml system with the zsh!$reset_color"
2541}
2542
2543# debian stuff
2544if [[ -r /etc/debian_version ]] ; then
2545 if [[ -z "$GRML_NO_APT_ALIASES" ]]; then
2546 #a3# Execute \kbd{apt-cache policy}
2547 alias acp='apt-cache policy'
2548 if check_com -c apt ; then
2549 #a3# Execute \kbd{apt search}
2550 alias acs='apt search'
2551 #a3# Execute \kbd{apt show}
2552 alias acsh='apt show'
2553 #a3# Execute \kbd{apt dist-upgrade}
2554 salias adg="apt dist-upgrade"
2555 #a3# Execute \kbd{apt upgrade}
2556 salias ag="apt upgrade"
2557 #a3# Execute \kbd{apt install}
2558 salias agi="apt install"
2559 #a3# Execute \kbd{apt update}
2560 salias au="apt update"
2561 else
2562 alias acs='apt-cache search'
2563 alias acsh='apt-cache show'
2564 salias adg="apt-get dist-upgrade"
2565 salias ag="apt-get upgrade"
2566 salias agi="apt-get install"
2567 salias au="apt-get update"
2568 fi
2569 if check_com -c aptitude ; then
2570 #a3# Execute \kbd{aptitude install}
2571 salias ati="aptitude install"
2572 #a3# Execute \kbd{aptitude update ; aptitude safe-upgrade}
2573 salias -a up="aptitude update ; aptitude safe-upgrade"
2574 fi
2575 if check_com -c dpkg-buildpackage ; then
2576 #a3# Execute \kbd{dpkg-buildpackage}
2577 alias dbp='dpkg-buildpackage'
2578 fi
2579 if check_com -c grep-excuses ; then
2580 #a3# Execute \kbd{grep-excuses}
2581 alias ge='grep-excuses'
2582 fi
2583 if check_com -c apt-file ; then
2584 alias afs='apt-file search'
2585 alias afl='apt-file list'
2586 fi
2587 fi
2588
2589 # get a root shell as normal user in live-cd mode:
2590 if isgrmlcd && [[ $UID -ne 0 ]] ; then
2591 alias su="sudo su"
2592 fi
2593
2594fi
2595
2596# use /var/log/syslog iff present, fallback to journalctl otherwise
2597if [ -e /var/log/syslog ] ; then
2598 #a1# Take a look at the syslog: \kbd{\$PAGER /var/log/syslog || journalctl}
2599 salias llog="$PAGER /var/log/syslog" # take a look at the syslog
2600 #a1# Take a look at the syslog: \kbd{tail -f /var/log/syslog || journalctl}
2601 salias tlog="tail --follow=name /var/log/syslog" # follow the syslog
2602elif check_com -c journalctl ; then
2603 salias llog="journalctl"
2604 salias tlog="journalctl -f"
2605fi
2606
2607# sort installed Debian-packages by size
2608if check_com -c dpkg-query ; then
2609 #a3# List installed Debian-packages sorted by size
2610 alias debs-by-size="dpkg-query -Wf 'x \${Installed-Size} \${Package} \${Status}\n' | sed -ne '/^x /d' -e '/^x \(.*\) install ok installed$/s//\1/p' | sort -nr"
2611fi
2612
2613if isgrmlcd; then
2614 # No core dumps: important for a live-cd-system
2615 limit -s core 0
2616fi
2617
2618# grmlstuff
2619function grmlstuff () {
2620 if [ -r /etc/grml_version ]; then
2621 #a1# Output version of running grml
2622 alias grml-version='cat /etc/grml_version'
2623 fi
2624
2625 if check_com -c grml-debootstrap ; then
2626 function debian2hd () {
2627 echo "Installing debian to harddisk is possible by using grml-debootstrap."
2628 return 1
2629 }
2630 fi
2631
2632 if check_com -c tmate && check_com -c qrencode ; then
2633 function grml-remote-support() {
2634 tmate -L grml-remote-support new -s grml-remote-support -d
2635 tmate -L grml-remote-support wait tmate-ready
2636 tmate -L grml-remote-support display -p '#{tmate_ssh}' | qrencode -t ANSI
2637 echo "tmate session: $(tmate -L grml-remote-support display -p '#{tmate_ssh}')"
2638 echo
2639 echo "Scan this QR code and send it to your support team."
2640 }
2641 fi
2642}
2643
2644# now run the functions
2645isgrml && grmlstuff
2646grmlcomp
2647
2648# keephack
2649xsource "/etc/zsh/keephack"
2650
2651# wonderful idea of using "e" glob qualifier by Peter Stephenson
2652# You use it as follows:
2653# $ NTREF=/reference/file
2654# $ ls -l *(e:nt:)
2655# This lists all the files in the current directory newer than the reference file.
2656# You can also specify the reference file inline; note quotes:
2657# $ ls -l *(e:'nt ~/.zshenv':)
2658function nt () {
2659 if [[ -n $1 ]] ; then
2660 local NTREF=${~1}
2661 fi
2662 [[ $REPLY -nt $NTREF ]]
2663}
2664
2665# shell functions
2666
2667#f1# Reload an autoloadable function
2668function freload () { while (( $# )); do; unfunction $1; autoload -U $1; shift; done }
2669compdef _functions freload
2670
2671#
2672# Usage:
2673#
2674# e.g.: a -> b -> c -> d ....
2675#
2676# sll a
2677#
2678#
2679# if parameter is given with leading '=', lookup $PATH for parameter and resolve that
2680#
2681# sll =java
2682#
2683# Note: limit for recursive symlinks on linux:
2684# http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/fs/namei.c?id=refs/heads/master#l808
2685# This limits recursive symlink follows to 8,
2686# while limiting consecutive symlinks to 40.
2687#
2688# When resolving and displaying information about symlinks, no check is made
2689# that the displayed information does make any sense on your OS.
2690# We leave that decission to the user.
2691#
2692# The zstat module is used to detect symlink loops.
2693# When a symlink loop is detected, a warning ist printed and further processing is stopped.
2694#
2695# Module zstat is loaded by default in grml zshrc, no extra action needed for that.
2696#
2697# Known bugs:
2698# If you happen to come across a symlink that points to a destination on another partition
2699# with the same inode number, that will be marked as symlink loop though it is not.
2700# Two hints for this situation:
2701# I) Play lottery the same day, as you seem to be rather lucky right now.
2702# II) Send patches.
2703#
2704# return status:
2705# 0 upon success
2706# 1 file/dir not accesible
2707# 2 symlink loop detected
2708#
2709#f1# List symlinks in detail (more detailed version of 'readlink -f', 'whence -s' and 'namei -l')
2710function sll () {
2711 if [[ -z ${1} ]] ; then
2712 printf 'Usage: %s <symlink(s)>\n' "${0}"
2713 return 1
2714 fi
2715
2716 local file jumpd curdir
2717 local -i 10 RTN LINODE i
2718 local -a SEENINODES
2719 curdir="${PWD}"
2720 RTN=0
2721
2722 for file in "${@}" ; do
2723 SEENINODES=()
2724 ls -l "${file:a}" || RTN=1
2725
2726 while [[ -h "$file" ]] ; do
2727 LINODE=$(zstat -L +inode "${file}")
2728 for i in ${SEENINODES} ; do
2729 if (( ${i} == ${LINODE} )) ; then
2730 builtin cd -q "${curdir}"
2731 print 'link loop detected, aborting!'
2732 return 2
2733 fi
2734 done
2735 SEENINODES+=${LINODE}
2736
2737 jumpd="${file:h}"
2738 file="${file:t}"
2739
2740 if [[ -d ${jumpd} ]] ; then
2741 builtin cd -q "${jumpd}" || RTN=1
2742 fi
2743 file=$(readlink "$file")
2744
2745 jumpd="${file:h}"
2746 file="${file:t}"
2747
2748 if [[ -d ${jumpd} ]] ; then
2749 builtin cd -q "${jumpd}" || RTN=1
2750 fi
2751
2752 ls -l "${PWD}/${file}" || RTN=1
2753 done
2754 shift 1
2755 if (( ${#} >= 1 )) ; then
2756 print ""
2757 fi
2758 builtin cd -q "${curdir}"
2759 done
2760 return ${RTN}
2761}
2762
2763if check_com -c $PAGER ; then
2764 #f3# View Debian's changelog of given package(s)
2765 function dchange () {
2766 emulate -L zsh
2767 [[ -z "$1" ]] && printf 'Usage: %s <package_name(s)>\n' "$0" && return 1
2768
2769 local package
2770
2771 # `less` as $PAGER without e.g. `|lesspipe %s` inside $LESSOPEN can't properly
2772 # read *.gz files, try to detect this to use vi instead iff available
2773 local viewer
2774
2775 if [[ ${$(typeset -p PAGER)[2]} = -a ]] ; then
2776 viewer=($PAGER) # support PAGER=(less -Mr) but leave array untouched
2777 else
2778 viewer=(${=PAGER}) # support PAGER='less -Mr'
2779 fi
2780
2781 if [[ ${viewer[1]:t} = less ]] && [[ -z "${LESSOPEN}" ]] && check_com vi ; then
2782 viewer='vi'
2783 fi
2784
2785 for package in "$@" ; do
2786 if [[ -r /usr/share/doc/${package}/changelog.Debian.gz ]] ; then
2787 $viewer /usr/share/doc/${package}/changelog.Debian.gz
2788 elif [[ -r /usr/share/doc/${package}/changelog.gz ]] ; then
2789 $viewer /usr/share/doc/${package}/changelog.gz
2790 elif [[ -r /usr/share/doc/${package}/changelog ]] ; then
2791 $viewer /usr/share/doc/${package}/changelog
2792 else
2793 if check_com -c aptitude ; then
2794 echo "No changelog for package $package found, using aptitude to retrieve it."
2795 aptitude changelog "$package"
2796 elif check_com -c apt-get ; then
2797 echo "No changelog for package $package found, using apt-get to retrieve it."
2798 apt-get changelog "$package"
2799 else
2800 echo "No changelog for package $package found, sorry."
2801 fi
2802 fi
2803 done
2804 }
2805 function _dchange () { _files -W /usr/share/doc -/ }
2806 compdef _dchange dchange
2807
2808 #f3# View Debian's NEWS of a given package
2809 function dnews () {
2810 emulate -L zsh
2811 if [[ -r /usr/share/doc/$1/NEWS.Debian.gz ]] ; then
2812 $PAGER /usr/share/doc/$1/NEWS.Debian.gz
2813 else
2814 if [[ -r /usr/share/doc/$1/NEWS.gz ]] ; then
2815 $PAGER /usr/share/doc/$1/NEWS.gz
2816 else
2817 echo "No NEWS file for package $1 found, sorry."
2818 return 1
2819 fi
2820 fi
2821 }
2822 function _dnews () { _files -W /usr/share/doc -/ }
2823 compdef _dnews dnews
2824
2825 #f3# View Debian's copyright of a given package
2826 function dcopyright () {
2827 emulate -L zsh
2828 if [[ -r /usr/share/doc/$1/copyright ]] ; then
2829 $PAGER /usr/share/doc/$1/copyright
2830 else
2831 echo "No copyright file for package $1 found, sorry."
2832 return 1
2833 fi
2834 }
2835 function _dcopyright () { _files -W /usr/share/doc -/ }
2836 compdef _dcopyright dcopyright
2837
2838 #f3# View upstream's changelog of a given package
2839 function uchange () {
2840 emulate -L zsh
2841 if [[ -r /usr/share/doc/$1/changelog.gz ]] ; then
2842 $PAGER /usr/share/doc/$1/changelog.gz
2843 else
2844 echo "No changelog for package $1 found, sorry."
2845 return 1
2846 fi
2847 }
2848 function _uchange () { _files -W /usr/share/doc -/ }
2849 compdef _uchange uchange
2850fi
2851
2852# zsh profiling
2853function profile () {
2854 ZSH_PROFILE_RC=1 zsh "$@"
2855}
2856
2857#f1# Edit an alias via zle
2858function edalias () {
2859 [[ -z "$1" ]] && { echo "Usage: edalias <alias_to_edit>" ; return 1 } || vared aliases'[$1]' ;
2860}
2861compdef _aliases edalias
2862
2863#f1# Edit a function via zle
2864function edfunc () {
2865 [[ -z "$1" ]] && { echo "Usage: edfunc <function_to_edit>" ; return 1 } || zed -f "$1" ;
2866}
2867compdef _functions edfunc
2868
2869# use it e.g. via 'Restart apache2'
2870#m# f6 Start() \kbd{service \em{process}}\quad\kbd{start}
2871#m# f6 Restart() \kbd{service \em{process}}\quad\kbd{restart}
2872#m# f6 Stop() \kbd{service \em{process}}\quad\kbd{stop}
2873#m# f6 Reload() \kbd{service \em{process}}\quad\kbd{reload}
2874#m# f6 Force-Reload() \kbd{service \em{process}}\quad\kbd{force-reload}
2875#m# f6 Status() \kbd{service \em{process}}\quad\kbd{status}
2876if [[ -d /etc/init.d ]] ; then
2877 function __start_stop () {
2878 local action_="${1:l}" # e.g Start/Stop/Restart
2879 local service_="$2"
2880 local param_="$3"
2881
2882 if check_com -c service ; then
2883 $SUDO service "$service_" "${action_}" "$param_"
2884 else
2885 $SUDO "/etc/init.d/$service_" "${action_}" "$param_"
2886 fi
2887 }
2888
2889 function _grmlinitd () {
2890 local -a scripts
2891 scripts=( /etc/init.d/*(x:t) )
2892 _describe "service startup script" scripts
2893 }
2894
2895 for i in Start Restart Stop Force-Reload Reload Status ; do
2896 eval "function $i () { __start_stop $i \"\$1\" \"\$2\" ; }"
2897 compdef _grmlinitd $i
2898 done
2899 builtin unset -v i
2900fi
2901
2902#f1# Provides useful information on globbing
2903function H-Glob () {
2904 echo -e "
2905 / directories
2906 . plain files
2907 @ symbolic links
2908 = sockets
2909 p named pipes (FIFOs)
2910 * executable plain files (0100)
2911 % device files (character or block special)
2912 %b block special files
2913 %c character special files
2914 r owner-readable files (0400)
2915 w owner-writable files (0200)
2916 x owner-executable files (0100)
2917 A group-readable files (0040)
2918 I group-writable files (0020)
2919 E group-executable files (0010)
2920 R world-readable files (0004)
2921 W world-writable files (0002)
2922 X world-executable files (0001)
2923 s setuid files (04000)
2924 S setgid files (02000)
2925 t files with the sticky bit (01000)
2926
2927 print *(m-1) # Files modified up to a day ago
2928 print *(a1) # Files accessed a day ago
2929 print *(@) # Just symlinks
2930 print *(Lk+50) # Files bigger than 50 kilobytes
2931 print *(Lk-50) # Files smaller than 50 kilobytes
2932 print **/*.c # All *.c files recursively starting in \$PWD
2933 print **/*.c~file.c # Same as above, but excluding 'file.c'
2934 print (foo|bar).* # Files starting with 'foo' or 'bar'
2935 print *~*.* # All Files that do not contain a dot
2936 chmod 644 *(.^x) # make all plain non-executable files publically readable
2937 print -l *(.c|.h) # Lists *.c and *.h
2938 print **/*(g:users:) # Recursively match all files that are owned by group 'users'
2939 echo /proc/*/cwd(:h:t:s/self//) # Analogous to >ps ax | awk '{print \$1}'<"
2940}
2941alias help-zshglob=H-Glob
2942
2943# grep for running process, like: 'any vim'
2944function any () {
2945 emulate -L zsh
2946 unsetopt KSH_ARRAYS
2947 if [[ -z "$1" ]] ; then
2948 echo "any - grep for process(es) by keyword" >&2
2949 echo "Usage: any <keyword>" >&2 ; return 1
2950 else
2951 ps xauwww | grep -i "${grep_options[@]}" "[${1[1]}]${1[2,-1]}"
2952 fi
2953}
2954
2955
2956# After resuming from suspend, system is paging heavily, leading to very bad interactivity.
2957# taken from $LINUX-KERNELSOURCE/Documentation/power/swsusp.txt
2958[[ -r /proc/1/maps ]] && \
2959function deswap () {
2960 print 'Reading /proc/[0-9]*/maps and sending output to /dev/null, this might take a while.'
2961 cat $(sed -ne 's:.* /:/:p' /proc/[0-9]*/maps | sort -u | grep -v '^/dev/') > /dev/null
2962 print 'Finished, running "swapoff -a; swapon -a" may also be useful.'
2963}
2964
2965# a wrapper for vim, that deals with title setting
2966# VIM_OPTIONS
2967# set this array to a set of options to vim you always want
2968# to have set when calling vim (in .zshrc.local), like:
2969# VIM_OPTIONS=( -p )
2970# This will cause vim to send every file given on the
2971# commandline to be send to it's own tab (needs vim7).
2972if check_com vim; then
2973 function vim () {
2974 VIM_PLEASE_SET_TITLE='yes' command vim ${VIM_OPTIONS} "$@"
2975 }
2976fi
2977
2978ssl_hashes=( sha512 sha256 sha1 md5 )
2979
2980for sh in ${ssl_hashes}; do
2981 eval 'ssl-cert-'${sh}'() {
2982 emulate -L zsh
2983 if [[ -z $1 ]] ; then
2984 printf '\''usage: %s <file>\n'\'' "ssh-cert-'${sh}'"
2985 return 1
2986 fi
2987 openssl x509 -noout -fingerprint -'${sh}' -in $1
2988 }'
2989done; unset sh
2990
2991function ssl-cert-fingerprints () {
2992 emulate -L zsh
2993 local i
2994 if [[ -z $1 ]] ; then
2995 printf 'usage: ssl-cert-fingerprints <file>\n'
2996 return 1
2997 fi
2998 for i in ${ssl_hashes}
2999 do ssl-cert-$i $1;
3000 done
3001}
3002
3003function ssl-cert-info () {
3004 emulate -L zsh
3005 if [[ -z $1 ]] ; then
3006 printf 'usage: ssl-cert-info <file>\n'
3007 return 1
3008 fi
3009 openssl x509 -noout -text -in $1
3010 ssl-cert-fingerprints $1
3011}
3012
3013# make sure our environment is clean regarding colors
3014builtin unset -v BLUE RED GREEN CYAN YELLOW MAGENTA WHITE NO_COLOR
3015
3016# "persistent history"
3017# just write important commands you always need to $GRML_IMPORTANT_COMMANDS
3018# defaults for backward compatibility to ~/.important_commands
3019if [[ -r ~/.important_commands ]] ; then
3020 GRML_IMPORTANT_COMMANDS=~/.important_commands
3021else
3022 GRML_IMPORTANT_COMMANDS=${GRML_IMPORTANT_COMMANDS:-${ZDOTDIR:-${HOME}}/.important_commands}
3023fi
3024[[ -r ${GRML_IMPORTANT_COMMANDS} ]] && builtin fc -R ${GRML_IMPORTANT_COMMANDS}
3025
3026# load the lookup subsystem if it's available on the system
3027zrcautoload lookupinit && lookupinit
3028
3029# variables
3030
3031# set terminal property (used e.g. by msgid-chooser)
3032case "${COLORTERM}" in
3033 truecolor)
3034 # do not overwrite
3035 ;;
3036 *)
3037 export COLORTERM="yes"
3038 ;;
3039esac
3040
3041# aliases
3042
3043# general
3044#a2# Execute \kbd{du -sch}
3045[[ -n "$GRML_NO_SMALL_ALIASES" ]] || alias da='du -sch'
3046
3047# listing stuff
3048#a2# Execute \kbd{ls -lSrah}
3049alias dir="command ls -lSrah"
3050#a2# Only show dot-directories
3051alias lad='command ls -d .*(/)'
3052#a2# Only show dot-files
3053alias lsa='command ls -a .*(.)'
3054#a2# Only files with setgid/setuid/sticky flag
3055alias lss='command ls -l *(s,S,t)'
3056#a2# Only show symlinks
3057alias lsl='command ls -l *(@)'
3058#a2# Display only executables
3059alias lsx='command ls -l *(*)'
3060#a2# Display world-{readable,writable,executable} files
3061alias lsw='command ls -ld *(R,W,X.^ND/)'
3062#a2# Display the ten biggest files
3063alias lsbig="command ls -flh *(.OL[1,10])"
3064#a2# Only show directories
3065alias lsd='command ls -d *(/)'
3066#a2# Only show empty directories
3067alias lse='command ls -d *(/^F)'
3068#a2# Display the ten newest files
3069alias lsnew="command ls -rtlh *(D.om[1,10])"
3070#a2# Display the ten oldest files
3071alias lsold="command ls -rtlh *(D.Om[1,10])"
3072#a2# Display the ten smallest files
3073alias lssmall="command ls -Srl *(.oL[1,10])"
3074#a2# Display the ten newest directories and ten newest .directories
3075alias lsnewdir="command ls -rthdl *(/om[1,10]) .*(D/om[1,10])"
3076#a2# Display the ten oldest directories and ten oldest .directories
3077alias lsolddir="command ls -rthdl *(/Om[1,10]) .*(D/Om[1,10])"
3078
3079# some useful aliases
3080#a2# Remove current empty directory. Execute \kbd{cd ..; rmdir \$OLDCWD}
3081alias rmcdir='cd ..; rmdir $OLDPWD || cd $OLDPWD'
3082
3083#a2# ssh with StrictHostKeyChecking=no \\&\quad and UserKnownHostsFile unset
3084alias insecssh='ssh -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null"'
3085#a2# scp with StrictHostKeyChecking=no \\&\quad and UserKnownHostsFile unset
3086alias insecscp='scp -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null"'
3087
3088#a2# lsblk (list block devices) with the most useful columns
3089alias llblk="lsblk -o +LABEL,PARTLABEL,UUID,FSTYPE,SERIAL"
3090
3091# useful functions
3092
3093#f5# Backup \kbd{file_or_folder {\rm to} file_or_folder\_timestamp}
3094function bk () {
3095 emulate -L zsh
3096 local current_date=$(date -u "+%Y%m%dT%H%M%SZ")
3097 local clean keep move verbose result all to_bk
3098 setopt extended_glob
3099 keep=1
3100 while getopts ":hacmrv" opt; do
3101 case $opt in
3102 a) (( all++ ));;
3103 c) unset move clean && (( ++keep ));;
3104 m) unset keep clean && (( ++move ));;
3105 r) unset move keep && (( ++clean ));;
3106 v) verbose="-v";;
3107 h) <<__EOF0__
3108bk [-hcmv] FILE [FILE ...]
3109bk -r [-av] [FILE [FILE ...]]
3110Backup a file or folder in place and append the timestamp
3111Remove backups of a file or folder, or all backups in the current directory
3112
3113Usage:
3114-h Display this help text
3115-c Keep the file/folder as is, create a copy backup using cp(1) (default)
3116-m Move the file/folder, using mv(1)
3117-r Remove backups of the specified file or directory, using rm(1). If none
3118 is provided, remove all backups in the current directory.
3119-a Remove all (even hidden) backups.
3120-v Verbose
3121
3122The -c, -r and -m options are mutually exclusive. If specified at the same time,
3123the last one is used.
3124
3125The return code is the sum of all cp/mv/rm return codes.
3126__EOF0__
3127return 0;;
3128 \?) bk -h >&2; return 1;;
3129 esac
3130 done
3131 shift "$((OPTIND-1))"
3132 if (( keep > 0 )); then
3133 if islinux || isfreebsd; then
3134 for to_bk in "$@"; do
3135 cp $verbose -a "${to_bk%/}" "${to_bk%/}_$current_date"
3136 (( result += $? ))
3137 done
3138 else
3139 for to_bk in "$@"; do
3140 cp $verbose -pR "${to_bk%/}" "${to_bk%/}_$current_date"
3141 (( result += $? ))
3142 done
3143 fi
3144 elif (( move > 0 )); then
3145 while (( $# > 0 )); do
3146 mv $verbose "${1%/}" "${1%/}_$current_date"
3147 (( result += $? ))
3148 shift
3149 done
3150 elif (( clean > 0 )); then
3151 if (( $# > 0 )); then
3152 for to_bk in "$@"; do
3153 rm $verbose -rf "${to_bk%/}"_[0-9](#c8)T([0-1][0-9]|2[0-3])([0-5][0-9])(#c2)Z
3154 (( result += $? ))
3155 done
3156 else
3157 if (( all > 0 )); then
3158 rm $verbose -rf *_[0-9](#c8)T([0-1][0-9]|2[0-3])([0-5][0-9])(#c2)Z(D)
3159 else
3160 rm $verbose -rf *_[0-9](#c8)T([0-1][0-9]|2[0-3])([0-5][0-9])(#c2)Z
3161 fi
3162 (( result += $? ))
3163 fi
3164 fi
3165 return $result
3166}
3167
3168#f5# cd to directory and list files
3169function cl () {
3170 emulate -L zsh
3171 cd $1 && ls -a
3172}
3173
3174# smart cd function, allows switching to /etc when running 'cd /etc/fstab'
3175function cd () {
3176 if (( ${#argv} == 1 )) && [[ -f ${1} ]]; then
3177 [[ ! -e ${1:h} ]] && return 1
3178 print "Correcting ${1} to ${1:h}"
3179 builtin cd ${1:h}
3180 else
3181 builtin cd "$@"
3182 fi
3183}
3184
3185#f5# Create Directory and \kbd{cd} to it
3186function mkcd () {
3187 if (( ARGC != 1 )); then
3188 printf 'usage: mkcd <new-directory>\n'
3189 return 1;
3190 fi
3191 if [[ ! -d "$1" ]]; then
3192 command mkdir -p "$1"
3193 else
3194 printf '`%s'\'' already exists: cd-ing.\n' "$1"
3195 fi
3196 builtin cd "$1"
3197}
3198
3199#f5# Create temporary directory and \kbd{cd} to it
3200function cdt () {
3201 local -a cdttemplate
3202 if [ "$#" -eq 1 ]; then
3203 if isfreebsd; then
3204 # mktemp(1) on FreeBSD doesn't behave the same, cf.
3205 # https://man.freebsd.org/cgi/man.cgi?query=mktemp#OPTIONS
3206 cdttemplate=(-t "$1")
3207 else
3208 cdttemplate=(-t "$1".XXXXXXX)
3209 fi
3210 fi
3211 builtin cd "$(mktemp -d ${cdttemplate[@]})"
3212 builtin pwd
3213}
3214
3215#f5# List files which have been accessed within the last {\it n} days, {\it n} defaults to 1
3216function accessed () {
3217 emulate -L zsh
3218 print -l -- *(a-${1:-1})
3219}
3220
3221#f5# List files which have been changed within the last {\it n} days, {\it n} defaults to 1
3222function changed () {
3223 emulate -L zsh
3224 print -l -- *(c-${1:-1})
3225}
3226
3227#f5# List files which have been modified within the last {\it n} days, {\it n} defaults to 1
3228function modified () {
3229 emulate -L zsh
3230 print -l -- *(m-${1:-1})
3231}
3232# modified() was named new() in earlier versions, add an alias for backwards compatibility
3233check_com new || alias new=modified
3234
3235# use colors when GNU grep with color-support
3236if (( $#grep_options > 0 )); then
3237 o=${grep_options:+"${grep_options[*]}"}
3238 #a2# Execute \kbd{grep -{}-color=auto}
3239 alias grep='grep '$o
3240 alias egrep='egrep '$o
3241 unset o
3242fi
3243
3244# Translate DE<=>EN
3245# 'translate' looks up a word in a file with language-to-language
3246# translations (field separator should be " : "). A typical wordlist looks
3247# like the following:
3248# | english-word : german-translation
3249# It's also only possible to translate english to german but not reciprocal.
3250# Use the following oneliner to reverse the sort order:
3251# $ awk -F ':' '{ print $2" : "$1" "$3 }' \
3252# /usr/local/lib/words/en-de.ISO-8859-1.vok > ~/.translate/de-en.ISO-8859-1.vok
3253#f5# Translates a word
3254if ! check_com -c trans; then
3255 function trans () {
3256 emulate -L zsh
3257 case "$1" in
3258 -[dD]*)
3259 translate -l de-en $2
3260 ;;
3261 -[eE]*)
3262 translate -l en-de $2
3263 ;;
3264 *)
3265 echo "Usage: $0 { -D | -E }"
3266 echo " -D == German to English"
3267 echo " -E == English to German"
3268 esac
3269 }
3270fi
3271
3272# Usage: simple-extract <file>
3273# Using option -d deletes the original archive file.
3274#f5# Smart archive extractor
3275function simple-extract () {
3276 emulate -L zsh
3277 setopt extended_glob noclobber
3278 local ARCHIVE DELETE_ORIGINAL DECOMP_CMD USES_STDIN USES_STDOUT GZTARGET WGET_CMD
3279 local RC=0
3280 zparseopts -D -E "d=DELETE_ORIGINAL"
3281 for ARCHIVE in "${@}"; do
3282 case $ARCHIVE in
3283 *(tar.bz2|tbz2|tbz))
3284 DECOMP_CMD="tar -xvjf -"
3285 USES_STDIN=true
3286 USES_STDOUT=false
3287 ;;
3288 *(tar.gz|tgz))
3289 DECOMP_CMD="tar -xvzf -"
3290 USES_STDIN=true
3291 USES_STDOUT=false
3292 ;;
3293 *(tar.xz|txz|tar.lzma))
3294 DECOMP_CMD="tar -xvJf -"
3295 USES_STDIN=true
3296 USES_STDOUT=false
3297 ;;
3298 *tar.zst)
3299 DECOMP_CMD="tar --zstd -xvf -"
3300 USES_STDIN=true
3301 USES_STDOUT=false
3302 ;;
3303 *tar.lrz)
3304 DECOMP_CMD="lrzuntar"
3305 USES_STDIN=false
3306 USES_STDOUT=false
3307 ;;
3308 *tar)
3309 DECOMP_CMD="tar -xvf -"
3310 USES_STDIN=true
3311 USES_STDOUT=false
3312 ;;
3313 *rar)
3314 DECOMP_CMD="unrar x"
3315 USES_STDIN=false
3316 USES_STDOUT=false
3317 ;;
3318 *lzh)
3319 DECOMP_CMD="lha x"
3320 USES_STDIN=false
3321 USES_STDOUT=false
3322 ;;
3323 *7z)
3324 DECOMP_CMD="7z x"
3325 USES_STDIN=false
3326 USES_STDOUT=false
3327 ;;
3328 *(zip|jar))
3329 DECOMP_CMD="unzip"
3330 USES_STDIN=false
3331 USES_STDOUT=false
3332 ;;
3333 *deb)
3334 DECOMP_CMD="ar -x"
3335 USES_STDIN=false
3336 USES_STDOUT=false
3337 ;;
3338 *bz2)
3339 DECOMP_CMD="bzip2 -d -c -"
3340 USES_STDIN=true
3341 USES_STDOUT=true
3342 ;;
3343 *(gz|Z))
3344 DECOMP_CMD="gzip -d -c -"
3345 USES_STDIN=true
3346 USES_STDOUT=true
3347 ;;
3348 *(xz|lzma))
3349 DECOMP_CMD="xz -d -c -"
3350 USES_STDIN=true
3351 USES_STDOUT=true
3352 ;;
3353 *zst)
3354 DECOMP_CMD="zstd -d -c -"
3355 USES_STDIN=true
3356 USES_STDOUT=true
3357 ;;
3358 *lrz)
3359 DECOMP_CMD="lrunzip -"
3360 USES_STDIN=true
3361 USES_STDOUT=true
3362 ;;
3363 *)
3364 print "ERROR: '$ARCHIVE' has unrecognized archive type." >&2
3365 RC=$((RC+1))
3366 continue
3367 ;;
3368 esac
3369
3370 if ! check_com ${DECOMP_CMD[(w)1]}; then
3371 echo "ERROR: ${DECOMP_CMD[(w)1]} not installed." >&2
3372 RC=$((RC+2))
3373 continue
3374 fi
3375
3376 GZTARGET="${ARCHIVE:t:r}"
3377 if [[ -f $ARCHIVE ]] ; then
3378
3379 print "Extracting '$ARCHIVE' ..."
3380 if $USES_STDIN; then
3381 if $USES_STDOUT; then
3382 ${=DECOMP_CMD} < "$ARCHIVE" > $GZTARGET
3383 else
3384 ${=DECOMP_CMD} < "$ARCHIVE"
3385 fi
3386 else
3387 if $USES_STDOUT; then
3388 ${=DECOMP_CMD} "$ARCHIVE" > $GZTARGET
3389 else
3390 ${=DECOMP_CMD} "$ARCHIVE"
3391 fi
3392 fi
3393 [[ $? -eq 0 && -n "$DELETE_ORIGINAL" ]] && rm -f "$ARCHIVE"
3394
3395 elif [[ "$ARCHIVE" == (#s)(https|http|ftp)://* ]] ; then
3396 if check_com curl; then
3397 WGET_CMD="curl -L -s -o -"
3398 elif check_com wget; then
3399 WGET_CMD="wget -q -O -"
3400 elif check_com fetch; then
3401 WGET_CMD="fetch -q -o -"
3402 else
3403 print "ERROR: neither wget, curl nor fetch is installed" >&2
3404 RC=$((RC+4))
3405 continue
3406 fi
3407 print "Downloading and Extracting '$ARCHIVE' ..."
3408 if $USES_STDIN; then
3409 if $USES_STDOUT; then
3410 ${=WGET_CMD} "$ARCHIVE" | ${=DECOMP_CMD} > $GZTARGET
3411 RC=$((RC+$?))
3412 else
3413 ${=WGET_CMD} "$ARCHIVE" | ${=DECOMP_CMD}
3414 RC=$((RC+$?))
3415 fi
3416 else
3417 if $USES_STDOUT; then
3418 ${=DECOMP_CMD} =(${=WGET_CMD} "$ARCHIVE") > $GZTARGET
3419 else
3420 ${=DECOMP_CMD} =(${=WGET_CMD} "$ARCHIVE")
3421 fi
3422 fi
3423
3424 else
3425 print "ERROR: '$ARCHIVE' is neither a valid file nor a supported URI." >&2
3426 RC=$((RC+8))
3427 fi
3428 done
3429 return $RC
3430}
3431
3432function __archive_or_uri () {
3433 _alternative \
3434 'files:Archives:_files -g "*.(#l)(tar.bz2|tbz2|tbz|tar.gz|tgz|tar.xz|txz|tar.lzma|tar|rar|lzh|7z|zip|jar|deb|bz2|gz|Z|xz|lzma)"' \
3435 '_urls:Remote Archives:_urls'
3436}
3437
3438function _simple_extract () {
3439 _arguments \
3440 '-d[delete original archivefile after extraction]' \
3441 '*:Archive Or Uri:__archive_or_uri'
3442}
3443compdef _simple_extract simple-extract
3444[[ -n "$GRML_NO_SMALL_ALIASES" ]] || alias se=simple-extract
3445
3446#f5# Change the xterm title from within GNU-screen
3447function xtrename () {
3448 emulate -L zsh
3449 if [[ $1 != "-f" ]] ; then
3450 if [[ -z ${DISPLAY} ]] ; then
3451 printf 'xtrename only makes sense in X11.\n'
3452 return 1
3453 fi
3454 else
3455 shift
3456 fi
3457 if [[ -z $1 ]] ; then
3458 printf 'usage: xtrename [-f] "title for xterm"\n'
3459 printf ' renames the title of xterm from _within_ screen.\n'
3460 printf ' also works without screen.\n'
3461 printf ' will not work if DISPLAY is unset, use -f to override.\n'
3462 return 0
3463 fi
3464 print -n "\eP\e]0;${1}\C-G\e\\"
3465 return 0
3466}
3467
3468#f2# Find history events by search pattern and list them by date.
3469function whatwhen () {
3470 emulate -L zsh
3471 local usage help ident format_l format_s first_char remain first last
3472 usage='USAGE: whatwhen [options] <searchstring> <search range>'
3473 help='Use `whatwhen -h'\'' for further explanations.'
3474 ident=${(l,${#${:-Usage: }},, ,)}
3475 format_l="${ident}%s\t\t\t%s\n"
3476 format_s="${format_l//(\\t)##/\\t}"
3477 # Make the first char of the word to search for case
3478 # insensitive; e.g. [aA]
3479 first_char=[${(L)1[1]}${(U)1[1]}]
3480 remain=${1[2,-1]}
3481 # Default search range is `-100'.
3482 first=${2:-\-100}
3483 # Optional, just used for `<first> <last>' given.
3484 last=$3
3485 case $1 in
3486 ("")
3487 printf '%s\n\n' 'ERROR: No search string specified. Aborting.'
3488 printf '%s\n%s\n\n' ${usage} ${help} && return 1
3489 ;;
3490 (-h)
3491 printf '%s\n\n' ${usage}
3492 print 'OPTIONS:'
3493 printf $format_l '-h' 'show help text'
3494 print '\f'
3495 print 'SEARCH RANGE:'
3496 printf $format_l "'0'" 'the whole history,'
3497 printf $format_l '-<n>' 'offset to the current history number; (default: -100)'
3498 printf $format_s '<[-]first> [<last>]' 'just searching within a give range'
3499 printf '\n%s\n' 'EXAMPLES:'
3500 printf ${format_l/(\\t)/} 'whatwhen grml' '# Range is set to -100 by default.'
3501 printf $format_l 'whatwhen zsh -250'
3502 printf $format_l 'whatwhen foo 1 99'
3503 ;;
3504 (\?)
3505 printf '%s\n%s\n\n' ${usage} ${help} && return 1
3506 ;;
3507 (*)
3508 # -l list results on stout rather than invoking $EDITOR.
3509 # -i Print dates as in YYYY-MM-DD.
3510 # -m Search for a - quoted - pattern within the history.
3511 fc -li -m "*${first_char}${remain}*" $first $last
3512 ;;
3513 esac
3514}
3515
3516# mercurial related stuff
3517if check_com -c hg ; then
3518 # gnu like diff for mercurial
3519 # http://www.selenic.com/mercurial/wiki/index.cgi/TipsAndTricks
3520 #f5# GNU like diff for mercurial
3521 function hgdi () {
3522 emulate -L zsh
3523 local i
3524 for i in $(hg status -marn "$@") ; diff -ubwd <(hg cat "$i") "$i"
3525 }
3526
3527 # execute commands on the versioned patch-queue from the current repos
3528 [[ -n "$GRML_NO_SMALL_ALIASES" ]] || alias mq='hg -R $(readlink -f $(hg root)/.hg/patches)'
3529
3530 # diffstat for specific version of a mercurial repository
3531 # hgstat => display diffstat between last revision and tip
3532 # hgstat 1234 => display diffstat between revision 1234 and tip
3533 #f5# Diffstat for specific version of a mercurial repos
3534 function hgstat () {
3535 emulate -L zsh
3536 [[ -n "$1" ]] && hg diff -r $1 -r tip | diffstat || hg export tip | diffstat
3537 }
3538
3539fi # end of check whether we have the 'hg'-executable
3540
3541# disable bracketed paste mode for dumb terminals
3542[[ "$TERM" == dumb ]] && unset zle_bracketed_paste
3543
3544# grml-small cleanups and workarounds
3545
3546# The following is used to remove zsh-config-items that do not work
3547# in grml-small by default.
3548# If you do not want these adjustments (for whatever reason), set
3549# $GRMLSMALL_SPECIFIC to 0 in your .zshrc.pre file (which this configuration
3550# sources if it is there).
3551
3552if (( GRMLSMALL_SPECIFIC > 0 )) && isgrmlsmall ; then
3553
3554 # Clean up
3555
3556 unset "abk[V]"
3557 unalias 'V' &> /dev/null
3558 unfunction vman &> /dev/null
3559 unfunction viless &> /dev/null
3560 unfunction 2html &> /dev/null
3561
3562 # manpages are not in grmlsmall
3563 unfunction manzsh &> /dev/null
3564 unfunction man2 &> /dev/null
3565
3566 # Workarounds
3567
3568 # See https://github.com/grml/grml/issues/56
3569 if ! [[ -x ${commands[dig]} ]]; then
3570 function dig_after_all () {
3571 unfunction dig
3572 unfunction _dig
3573 autoload -Uz _dig
3574 unfunction dig_after_all
3575 }
3576 function dig () {
3577 if [[ -x ${commands[dig]} ]]; then
3578 dig_after_all
3579 command dig "$@"
3580 return "$!"
3581 fi
3582 printf 'This installation does not include `dig'\'' for size reasons.\n'
3583 printf 'Try `drill'\'' as a light weight alternative.\n'
3584 return 0
3585 }
3586 function _dig () {
3587 if [[ -x ${commands[dig]} ]]; then
3588 dig_after_all
3589 zle -M 'Found `dig'\'' installed. '
3590 else
3591 zle -M 'Try `drill'\'' instead of `dig'\''.'
3592 fi
3593 }
3594 compdef _dig dig
3595 fi
3596fi
3597
3598zrclocal
3599
3600unfunction grml_status_feature
3601
3602## genrefcard.pl settings
3603
3604### doc strings for external functions from files
3605#m# f5 grml-wallpaper() Sets a wallpaper (try completion for possible values)
3606
3607### example: split functions-search 8,16,24,32
3608#@# split functions-search 8
3609
3610## END OF FILE #################################################################
3611# vim:filetype=zsh foldmethod=marker autoindent expandtab shiftwidth=4
3612# Local variables:
3613# mode: sh
3614# End:
3615
3616# History configuration
3617HISTFILE=~/.histfile
3618HISTSIZE=3000
3619SAVEHIST=5000
3620
3621# ZSH plugins
3622source /usr/share/zsh/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
3623source /usr/share/zsh/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh
3624
3625# Make Flatpaks accessible via the shell
3626export PATH="$PATH:/var/lib/flatpak/exports/bin"
3627
3628# Reset prompt to default
3629prompt default
3630PROMPT='%# '
3631
3632# Load Headline ZSH theme
3633source ~/.config/headline.zsh-theme
3634
3635fastfetch
3636fortune | cowsay -f tux
3637
.zshrc-solus Исходник
1# Filename: /etc/zsh/zshrc
2# Purpose: config file for zsh (z shell)
3# Authors: grml-team (grml.org), (c) Michael Prokop <[email protected]>
4# Bug-Reports: see http://grml.org/bugs/
5# License: This file is licensed under the GPL v2.
6################################################################################
7# This file is sourced only for interactive shells. It
8# should contain commands to set up aliases, functions,
9# options, key bindings, etc.
10#
11# Global Order: zshenv, zprofile, zshrc, zlogin
12################################################################################
13
14# USAGE
15# If you are using this file as your ~/.zshrc file, please use ~/.zshrc.pre
16# and ~/.zshrc.local for your own customisations. The former file is read
17# before ~/.zshrc, the latter is read after it. Also, consider reading the
18# refcard and the reference manual for this setup, both available from:
19# <http://grml.org/zsh/>
20
21# Contributing:
22# If you want to help to improve grml's zsh setup, clone the grml-etc-core
23# repository from git.grml.org:
24# git clone git://git.grml.org/grml-etc-core.git
25#
26# Make your changes, commit them; use 'git format-patch' to create a series
27# of patches and send those to the following address via 'git send-email':
28# [email protected]
29#
30# Doing so makes sure the right people get your patches for review and
31# possibly inclusion.
32
33# zsh-refcard-tag documentation:
34# You may notice strange looking comments in this file.
35# These are there for a purpose. grml's zsh-refcard can now be
36# automatically generated from the contents of the actual configuration
37# file. However, we need a little extra information on which comments
38# and what lines of code to take into account (and for what purpose).
39#
40# Here is what they mean:
41#
42# List of tags (comment types) used:
43# #a# Next line contains an important alias, that should
44# be included in the grml-zsh-refcard.
45# (placement tag: @@INSERT-aliases@@)
46# #f# Next line contains the beginning of an important function.
47# (placement tag: @@INSERT-functions@@)
48# #v# Next line contains an important variable.
49# (placement tag: @@INSERT-variables@@)
50# #k# Next line contains an important keybinding.
51# (placement tag: @@INSERT-keybindings@@)
52# #d# Hashed directories list generation:
53# start denotes the start of a list of 'hash -d'
54# definitions.
55# end denotes its end.
56# (placement tag: @@INSERT-hasheddirs@@)
57# #A# Abbreviation expansion list generation:
58# start denotes the beginning of abbreviations.
59# end denotes their end.
60# Lines within this section that end in '#d .*' provide
61# extra documentation to be included in the refcard.
62# (placement tag: @@INSERT-abbrev@@)
63# #m# This tag allows you to manually generate refcard entries
64# for code lines that are hard/impossible to parse.
65# Example:
66# #m# k ESC-h Call the run-help function
67# That would add a refcard entry in the keybindings table
68# for 'ESC-h' with the given comment.
69# So the syntax is: #m# <section> <argument> <comment>
70# #o# This tag lets you insert entries to the 'other' hash.
71# Generally, this should not be used. It is there for
72# things that cannot be done easily in another way.
73# (placement tag: @@INSERT-other-foobar@@)
74#
75# All of these tags (except for m and o) take two arguments, the first
76# within the tag, the other after the tag:
77#
78# #<tag><section># <comment>
79#
80# Where <section> is really just a number, which are defined by the
81# @secmap array on top of 'genrefcard.pl'. The reason for numbers
82# instead of names is, that for the reader, the tag should not differ
83# much from a regular comment. For zsh, it is a regular comment indeed.
84# The numbers have got the following meanings:
85# 0 -> "default"
86# 1 -> "system"
87# 2 -> "user"
88# 3 -> "debian"
89# 4 -> "search"
90# 5 -> "shortcuts"
91# 6 -> "services"
92#
93# So, the following will add an entry to the 'functions' table in the
94# 'system' section, with a (hopefully) descriptive comment:
95# #f1# Edit an alias via zle
96# edalias() {
97#
98# It will then show up in the @@INSERT-aliases-system@@ replacement tag
99# that can be found in 'grml-zsh-refcard.tex.in'.
100# If the section number is omitted, the 'default' section is assumed.
101# Furthermore, in 'grml-zsh-refcard.tex.in' @@INSERT-aliases@@ is
102# exactly the same as @@INSERT-aliases-default@@. If you want a list of
103# *all* aliases, for example, use @@INSERT-aliases-all@@.
104
105# zsh profiling
106# just execute 'ZSH_PROFILE_RC=1 zsh' and run 'zprof' to get the details
107if [[ $ZSH_PROFILE_RC -gt 0 ]] ; then
108 zmodload zsh/zprof
109fi
110
111typeset -A GRML_STATUS_FEATURES
112
113function grml_status_feature () {
114 emulate -L zsh
115 local f=$1
116 local -i success=$2
117 if (( success == 0 )); then
118 GRML_STATUS_FEATURES[$f]=success
119 else
120 GRML_STATUS_FEATURES[$f]=failure
121 fi
122 return 0
123}
124
125function grml_status_features () {
126 emulate -L zsh
127 local mode=${1:-+-}
128 local this
129 if [[ $mode == -h ]] || [[ $mode == --help ]]; then
130 cat <<EOF
131grml_status_features [-h|--help|-|+|+-|FEATURE]
132
133Prints a summary of features the grml setup is trying to load. The
134result of loading a feature is recorded. This function lets you query
135the result.
136
137The function takes one argument: "-h" or "--help" to display this help
138text, "+" to display a list of all successfully loaded features, "-" for
139a list of all features that failed to load. "+-" to show a list of all
140features with their statuses.
141
142Any other word is considered to by a feature and prints its status.
143
144The default mode is "+-".
145EOF
146 return 0
147 fi
148 if [[ $mode != - ]] && [[ $mode != + ]] && [[ $mode != +- ]]; then
149 this="${GRML_STATUS_FEATURES[$mode]}"
150 if [[ -z $this ]]; then
151 printf 'unknown\n'
152 return 1
153 else
154 printf '%s\n' $this
155 fi
156 return 0
157 fi
158 for key in ${(ok)GRML_STATUS_FEATURES}; do
159 this="${GRML_STATUS_FEATURES[$key]}"
160 if [[ $this == success ]] && [[ $mode == *+* ]]; then
161 printf '%-16s %s\n' $key $this
162 fi
163 if [[ $this == failure ]] && [[ $mode == *-* ]]; then
164 printf '%-16s %s\n' $key $this
165 fi
166 done
167 return 0
168}
169
170# load .zshrc.pre to give the user the chance to overwrite the defaults
171[[ -r ${ZDOTDIR:-${HOME}}/.zshrc.pre ]] && source ${ZDOTDIR:-${HOME}}/.zshrc.pre
172
173#f1# Checks whether or not you're running grml
174function isgrml () {
175 [[ -f /etc/grml_version ]] && return 0
176 return 1
177}
178
179#f1# Checks whether or not you're running a grml cd
180function isgrmlcd () {
181 [[ -f /etc/grml_cd ]] && return 0
182 return 1
183}
184
185if isgrml ; then
186#f1# Checks whether or not you're running grml-small
187 function isgrmlsmall () {
188 if [[ ${${${(f)"$(</etc/grml_version)"}%% *}##*-} == 'small' ]]; then
189 return 0
190 fi
191 return 1
192 }
193else
194 function isgrmlsmall () { return 1 }
195fi
196
197GRML_OSTYPE=$(uname -s)
198
199function islinux () {
200 [[ $GRML_OSTYPE == "Linux" ]]
201}
202
203function isdarwin () {
204 [[ $GRML_OSTYPE == "Darwin" ]]
205}
206
207function isfreebsd () {
208 [[ $GRML_OSTYPE == "FreeBSD" ]]
209}
210
211function isopenbsd () {
212 [[ $GRML_OSTYPE == "OpenBSD" ]]
213}
214
215#f1# are we running within an utf environment?
216function isutfenv () {
217 case "$LANG $CHARSET $LANGUAGE" in
218 *utf*) return 0 ;;
219 *UTF*) return 0 ;;
220 *) return 1 ;;
221 esac
222}
223
224# check for user, if not running as root set $SUDO to sudo
225(( EUID != 0 )) && SUDO='sudo' || SUDO=''
226
227# check for zsh v5.1+
228
229if ! [[ ${ZSH_VERSION} == 5.<1->* \
230 || ${ZSH_VERSION} == <6->.<->* ]] ; then
231
232 printf '-!-\n'
233 printf '-!- In this configuration we try to make use of features, that\n'
234 printf '-!- require version 5.1 of the shell; That way this setup can be\n'
235 printf '-!- used with a wide range of zsh versions, while using fairly\n'
236 printf '-!- advanced features in all supported versions.\n'
237 printf '-!-\n'
238 printf '-!- However, you are running zsh version %s.\n' "$ZSH_VERSION"
239 printf '-!-\n'
240 printf '-!- While this *may* work, it might as well fail.\n'
241 printf '-!- Please consider updating to at least version 5.1 of zsh.\n'
242 printf '-!-\n'
243 printf '-!- DO NOT EXPECT THIS TO WORK FLAWLESSLY!\n'
244 printf '-!- If it does today, you'\''ve been lucky.\n'
245 printf '-!-\n'
246 printf '-!- Ye been warned!\n'
247 printf '-!-\n'
248
249 function zstyle () { : }
250fi
251
252# autoload wrapper - use this one instead of autoload directly
253# We need to define this function as early as this, because autoloading
254# 'is-at-least()' needs it.
255function zrcautoload () {
256 emulate -L zsh
257 setopt extended_glob
258 local fdir ffile
259 local -i ffound
260
261 ffile=$1
262 (( ffound = 0 ))
263 for fdir in ${fpath} ; do
264 [[ -e ${fdir}/${ffile} ]] && (( ffound = 1 ))
265 done
266
267 (( ffound == 0 )) && return 1
268 autoload -U ${ffile} || return 1
269 return 0
270}
271
272# Autoload zsh's hook system early, so we can use it whenever we need.
273zrcautoload add-zsh-hook || add-zsh-hook () { :; }
274
275# Load is-at-least() for more precise version checks Note that this test will
276# *always* fail, if the is-at-least function could not be marked for
277# autoloading.
278zrcautoload is-at-least || function is-at-least () { return 1 }
279
280# set some important options (as early as possible)
281
282# append history list to the history file; this is the default but we make sure
283# because it's required for share_history.
284setopt append_history
285
286# import new commands from the history file also in other zsh-session
287setopt share_history
288
289# save each command's beginning timestamp and the duration to the history file
290setopt extended_history
291
292# remove command lines from the history list when the first character on the
293# line is a space
294setopt histignorespace
295
296# if a command is issued that can't be executed as a normal command, and the
297# command is the name of a directory, perform the cd command to that directory.
298setopt auto_cd
299
300# in order to use #, ~ and ^ for filename generation grep word
301# *~(*.gz|*.bz|*.bz2|*.zip|*.Z) -> searches for word not in compressed files
302# don't forget to quote '^', '~' and '#'!
303setopt extended_glob
304
305# display PID when suspending processes as well
306setopt longlistjobs
307
308# report the status of backgrounds jobs immediately
309setopt notify
310
311# whenever a command completion is attempted, make sure the entire command path
312# is hashed first.
313setopt hash_list_all
314
315# not just at the end
316setopt completeinword
317
318# Don't send SIGHUP to background processes when the shell exits.
319setopt nohup
320
321# make cd push the old directory onto the directory stack.
322setopt auto_pushd
323
324# avoid "beep"ing
325setopt nobeep
326
327# don't push the same dir twice.
328setopt pushd_ignore_dups
329
330# * shouldn't match dotfiles. ever.
331setopt noglobdots
332
333# use zsh style word splitting
334setopt noshwordsplit
335
336# don't error out when unset parameters are used
337setopt unset
338
339# setting some default values
340NOCOR=${NOCOR:-0}
341NOETCHOSTS=${NOETCHOSTS:-0}
342NOMENU=${NOMENU:-0}
343NOPATHHELPER=${NOPATHHELPER:-0}
344NOPRECMD=${NOPRECMD:-0}
345COMMAND_NOT_FOUND=${COMMAND_NOT_FOUND:-0}
346GRML_ZSH_CNF_HANDLER=${GRML_ZSH_CNF_HANDLER:-/usr/share/command-not-found/command-not-found}
347GRML_DISPLAY_BATTERY=${GRML_DISPLAY_BATTERY:-${BATTERY:-0}}
348GRMLSMALL_SPECIFIC=${GRMLSMALL_SPECIFIC:-1}
349ZSH_NO_DEFAULT_LOCALE=${ZSH_NO_DEFAULT_LOCALE:-0}
350
351typeset -ga ls_options
352typeset -ga grep_options
353
354# Colors on GNU ls(1)
355if ls --color=auto / >/dev/null 2>&1; then
356 ls_options+=( --color=auto )
357# Colors on FreeBSD and OSX ls(1)
358elif ls -G / >/dev/null 2>&1; then
359 ls_options+=( -G )
360fi
361
362# Natural sorting order on GNU ls(1)
363# OSX and IllumOS have a -v option that is not natural sorting
364if ls --version |& grep -q 'GNU' >/dev/null 2>&1 && ls -v / >/dev/null 2>&1; then
365 ls_options+=( -v )
366fi
367
368# Color on GNU and FreeBSD grep(1)
369if grep --color=auto -q "a" <<< "a" >/dev/null 2>&1; then
370 grep_options+=( --color=auto )
371fi
372
373# utility functions
374# this function checks if a command exists and returns either true
375# or false. This avoids using 'which' and 'whence', which will
376# avoid problems with aliases for which on certain weird systems. :-)
377# Usage: check_com [-c|-g] word
378# -c only checks for external commands
379# -g does the usual tests and also checks for global aliases
380function check_com () {
381 emulate -L zsh
382 local -i comonly gatoo
383 comonly=0
384 gatoo=0
385
386 if [[ $1 == '-c' ]] ; then
387 comonly=1
388 shift 1
389 elif [[ $1 == '-g' ]] ; then
390 gatoo=1
391 shift 1
392 fi
393
394 if (( ${#argv} != 1 )) ; then
395 printf 'usage: check_com [-c|-g] <command>\n' >&2
396 return 1
397 fi
398
399 if (( comonly > 0 )) ; then
400 (( ${+commands[$1]} )) && return 0
401 return 1
402 fi
403
404 if (( ${+commands[$1]} )) \
405 || (( ${+functions[$1]} )) \
406 || (( ${+aliases[$1]} )) \
407 || (( ${+reswords[(r)$1]} )) ; then
408 return 0
409 fi
410
411 if (( gatoo > 0 )) && (( ${+galiases[$1]} )) ; then
412 return 0
413 fi
414
415 return 1
416}
417
418# creates an alias and precedes the command with
419# sudo if $EUID is not zero.
420function salias () {
421 emulate -L zsh
422 local only=0 ; local multi=0
423 local key val
424 while getopts ":hao" opt; do
425 case $opt in
426 o) only=1 ;;
427 a) multi=1 ;;
428 h)
429 printf 'usage: salias [-hoa] <alias-expression>\n'
430 printf ' -h shows this help text.\n'
431 printf ' -a replace '\'' ; '\'' sequences with '\'' ; sudo '\''.\n'
432 printf ' be careful using this option.\n'
433 printf ' -o only sets an alias if a preceding sudo would be needed.\n'
434 return 0
435 ;;
436 *) salias -h >&2; return 1 ;;
437 esac
438 done
439 shift "$((OPTIND-1))"
440
441 if (( ${#argv} > 1 )) ; then
442 printf 'Too many arguments %s\n' "${#argv}"
443 return 1
444 fi
445
446 key="${1%%\=*}" ; val="${1#*\=}"
447 if (( EUID == 0 )) && (( only == 0 )); then
448 alias -- "${key}=${val}"
449 elif (( EUID > 0 )) ; then
450 (( multi > 0 )) && val="${val// ; / ; sudo }"
451 alias -- "${key}=sudo ${val}"
452 fi
453
454 return 0
455}
456
457# Check if we can read given files and source those we can.
458function xsource () {
459 if (( ${#argv} < 1 )) ; then
460 printf 'usage: xsource FILE(s)...\n' >&2
461 return 1
462 fi
463
464 while (( ${#argv} > 0 )) ; do
465 [[ -r "$1" ]] && source "$1"
466 shift
467 done
468 return 0
469}
470
471# Check if we can read a given file and 'cat(1)' it.
472function xcat () {
473 emulate -L zsh
474 if (( ${#argv} != 1 )) ; then
475 printf 'usage: xcat FILE\n' >&2
476 return 1
477 fi
478
479 [[ -r $1 ]] && cat $1
480 return 0
481}
482
483# this allows us to stay in sync with grml's zshrc and put own
484# modifications in ~/.zshrc.local
485function zrclocal () {
486 xsource "/etc/zsh/zshrc.local"
487 xsource "${ZDOTDIR:-${HOME}}/.zshrc.local"
488 return 0
489}
490
491# locale setup
492if (( ZSH_NO_DEFAULT_LOCALE == 0 )); then
493 xsource "/etc/default/locale"
494fi
495
496for var in LANG LANGUAGE LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE LC_TIME ; do
497 [[ -n ${(P)var} ]] && export $var
498done
499builtin unset -v var
500
501# set some variables
502if check_com -c vim ; then
503#v#
504 export EDITOR=${EDITOR:-vim}
505else
506 export EDITOR=${EDITOR:-vi}
507fi
508
509#v#
510export PAGER=${PAGER:-less}
511
512#v#
513export MAIL=${MAIL:-/var/mail/$USER}
514
515# color setup for ls:
516check_com -c dircolors && eval $(dircolors -b)
517
518# Setup PATH from system defaults on macOS.
519if [[ -x /usr/libexec/path_helper ]] && [[ "$NOPATHHELPER" -eq 0 ]] ; then
520 eval $(/usr/libexec/path_helper -s)
521fi
522# Add MacPorts PATH on darwin/macOS.
523if isdarwin && [[ -d /opt/local ]]; then
524 PATH="/opt/local/bin:/opt/local/sbin:$PATH"
525 MANPATH="/opt/local/share/man:$MANPATH"
526fi
527
528# load our function and completion directories
529for fdir in /usr/share/grml/zsh/completion /usr/share/grml/zsh/functions; do
530 fpath=( ${fdir} ${fdir}/**/*(/N) ${fpath} )
531done
532typeset -aU ffiles
533ffiles=(/usr/share/grml/zsh/functions/**/[^_]*[^~](N.:t))
534(( ${#ffiles} > 0 )) && autoload -U "${ffiles[@]}"
535unset -v fdir ffiles
536
537# support colors in less
538export LESS_TERMCAP_mb=$'\E[01;31m'
539export LESS_TERMCAP_md=$'\E[01;31m'
540export LESS_TERMCAP_me=$'\E[0m'
541export LESS_TERMCAP_se=$'\E[0m'
542export LESS_TERMCAP_so=$'\E[01;44;33m'
543export LESS_TERMCAP_ue=$'\E[0m'
544export LESS_TERMCAP_us=$'\E[01;32m'
545
546# mailchecks
547MAILCHECK=30
548
549# report about cpu-/system-/user-time of command if running longer than
550# 5 seconds
551REPORTTIME=5
552
553# watch for everyone but me and root
554watch=(notme root)
555
556# automatically remove duplicates from these arrays
557typeset -U path PATH cdpath CDPATH fpath FPATH manpath MANPATH
558
559# Load a few modules
560for mod in parameter complist deltochar mathfunc ; do
561 zmodload -i zsh/${mod} 2>/dev/null
562 grml_status_feature mod:$mod $?
563done && builtin unset -v mod
564
565# autoload zsh modules when they are referenced
566zmodload -a zsh/stat zstat
567zmodload -a zsh/zpty zpty
568zmodload -ap zsh/mapfile mapfile
569
570# completion system
571COMPDUMPFILE=${COMPDUMPFILE:-${ZDOTDIR:-${HOME}}/.zcompdump}
572if zrcautoload compinit ; then
573 typeset -a tmp
574 zstyle -a ':grml:completion:compinit' arguments tmp
575 compinit -d ${COMPDUMPFILE} "${tmp[@]}"
576 grml_status_feature compinit $?
577 unset tmp
578else
579 grml_status_feature compinit 1
580 function compdef { }
581fi
582
583# completion system
584
585# called later (via grmlcomp)
586# note: use 'zstyle' for getting current settings
587# press ^xh (control-x h) for getting tags in context; ^x? (control-x ?) to run complete_debug with trace output
588function grmlcomp () {
589 # TODO: This could use some additional information
590
591 # Make sure the completion system is initialised
592 (( ${+_comps} )) || return 1
593
594 # allow one error for every three characters typed in approximate completer
595 zstyle ':completion:*:approximate:' max-errors 'reply=( $((($#PREFIX+$#SUFFIX)/3 )) numeric )'
596
597 # don't complete backup files as executables
598 zstyle ':completion:*:complete:-command-::commands' ignored-patterns '(aptitude-*|*\~)'
599
600 # start menu completion only if it could find no unambiguous initial string
601 zstyle ':completion:*:correct:*' insert-unambiguous true
602 zstyle ':completion:*:corrections' format $'%{\e[0;31m%}%d (errors: %e)%{\e[0m%}'
603 zstyle ':completion:*:correct:*' original true
604
605 # activate color-completion
606 zstyle ':completion:*:default' list-colors ${(s.:.)LS_COLORS}
607
608 # format on completion
609 zstyle ':completion:*:descriptions' format $'%{\e[0;31m%}completing %B%d%b%{\e[0m%}'
610
611 # automatically complete 'cd -<tab>' and 'cd -<ctrl-d>' with menu
612 # zstyle ':completion:*:*:cd:*:directory-stack' menu yes select
613
614 # insert all expansions for expand completer
615 zstyle ':completion:*:expand:*' tag-order all-expansions
616 zstyle ':completion:*:history-words' list false
617
618 # activate menu
619 zstyle ':completion:*:history-words' menu yes
620
621 # ignore duplicate entries
622 zstyle ':completion:*:history-words' remove-all-dups yes
623 zstyle ':completion:*:history-words' stop yes
624
625 # match uppercase from lowercase
626 zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}'
627
628 # separate matches into groups
629 zstyle ':completion:*:matches' group 'yes'
630 zstyle ':completion:*' group-name ''
631
632 if [[ "$NOMENU" -eq 0 ]] ; then
633 # if there are more than 5 options allow selecting from a menu
634 zstyle ':completion:*' menu select=5
635 else
636 # don't use any menus at all
637 setopt no_auto_menu
638 fi
639
640 zstyle ':completion:*:messages' format '%d'
641 zstyle ':completion:*:options' auto-description '%d'
642
643 # describe options in full
644 zstyle ':completion:*:options' description 'yes'
645
646 # on processes completion complete all user processes
647 zstyle ':completion:*:processes' command 'ps -au$USER'
648
649 # offer indexes before parameters in subscripts
650 zstyle ':completion:*:*:-subscript-:*' tag-order indexes parameters
651
652 # provide verbose completion information
653 zstyle ':completion:*' verbose true
654
655 # recent (as of Dec 2007) zsh versions are able to provide descriptions
656 # for commands (read: 1st word in the line) that it will list for the user
657 # to choose from. The following disables that, because it's not exactly fast.
658 zstyle ':completion:*:-command-:*:' verbose false
659
660 # set format for warnings
661 zstyle ':completion:*:warnings' format $'%{\e[0;31m%}No matches for:%{\e[0m%} %d'
662
663 # define files to ignore for zcompile
664 zstyle ':completion:*:*:zcompile:*' ignored-patterns '(*~|*.zwc)'
665 zstyle ':completion:correct:' prompt 'correct to: %e'
666
667 # Ignore completion functions for commands you don't have:
668 zstyle ':completion::(^approximate*):*:functions' ignored-patterns '_*'
669
670 # Provide more processes in completion of programs like killall:
671 zstyle ':completion:*:processes-names' command 'ps c -u ${USER} -o command | uniq'
672
673 # complete manual by their section
674 zstyle ':completion:*:manuals' separate-sections true
675 zstyle ':completion:*:manuals.*' insert-sections true
676 zstyle ':completion:*:man:*' menu yes select
677
678 # Search path for sudo completion
679 zstyle ':completion:*:sudo:*' command-path /usr/local/sbin \
680 /usr/local/bin \
681 /usr/sbin \
682 /usr/bin \
683 /sbin \
684 /bin \
685 /usr/X11R6/bin
686
687 # provide .. as a completion
688 zstyle ':completion:*' special-dirs ..
689
690 # run rehash on completion so new installed program are found automatically:
691 function _force_rehash () {
692 (( CURRENT == 1 )) && rehash
693 return 1
694 }
695
696 ## correction
697 # some people don't like the automatic correction - so run 'NOCOR=1 zsh' to deactivate it
698 if [[ "$NOCOR" -gt 0 ]] ; then
699 zstyle ':completion:*' completer _oldlist _expand _force_rehash _complete _files _ignored
700 setopt nocorrect
701 else
702 # try to be smart about when to use what completer...
703 setopt correct
704 zstyle -e ':completion:*' completer '
705 if [[ $_last_try != "$HISTNO$BUFFER$CURSOR" ]] ; then
706 _last_try="$HISTNO$BUFFER$CURSOR"
707 reply=(_complete _match _ignored _prefix _files)
708 else
709 if [[ $words[1] == (rm|mv) ]] ; then
710 reply=(_complete _files)
711 else
712 reply=(_oldlist _expand _force_rehash _complete _ignored _correct _approximate _files)
713 fi
714 fi'
715 fi
716
717 # command for process lists, the local web server details and host completion
718 zstyle ':completion:*:urls' local 'www' '/var/www/' 'public_html'
719
720 # Some functions, like _apt and _dpkg, are very slow. We can use a cache in
721 # order to speed things up
722 if [[ ${GRML_COMP_CACHING:-yes} == yes ]]; then
723 GRML_COMP_CACHE_DIR=${GRML_COMP_CACHE_DIR:-${ZDOTDIR:-$HOME}/.cache}
724 if [[ ! -d ${GRML_COMP_CACHE_DIR} ]]; then
725 command mkdir -p "${GRML_COMP_CACHE_DIR}"
726 fi
727 zstyle ':completion:*' use-cache yes
728 zstyle ':completion:*:complete:*' cache-path "${GRML_COMP_CACHE_DIR}"
729 fi
730
731 # host completion
732 _ssh_config_hosts=()
733 if [[ -r ~/.ssh/config ]] ; then
734 _ssh_config_hosts=(${${(s: :)${(ps:\t:)${${(@M)${(f)"$(<$HOME/.ssh/config)"}:#Host *}#Host }}}:#*[*?]*})
735 fi
736 _ssh_hosts=()
737 if [[ -r ~/.ssh/known_hosts ]] ; then
738 _ssh_hosts=(${${${${(f)"$(<$HOME/.ssh/known_hosts)"}:#[\|]*}%%\ *}%%,*})
739 fi
740 _etc_hosts=()
741 if [[ -r /etc/hosts ]] && [[ "$NOETCHOSTS" -eq 0 ]] ; then
742 : ${(A)_etc_hosts:=${(s: :)${(ps:\t:)${${(f)~~"$(grep -v '^0\.0\.0\.0\|^127\.0\.0\.1\|^::1 ' /etc/hosts)"}%%\#*}##[:blank:]#[^[:blank:]]#}}}
743 fi
744
745 hosts=(
746 "$HOST"
747 "$_ssh_config_hosts[@]"
748 "$_ssh_hosts[@]"
749 "$_etc_hosts[@]"
750 localhost
751 )
752 zstyle ':completion:*:hosts' hosts $hosts
753 # TODO: so, why is this here?
754 # zstyle '*' hosts $hosts
755
756 # use generic completion system for programs not yet defined; (_gnu_generic works
757 # with commands that provide a --help option with "standard" gnu-like output.)
758 for compcom in cp deborphan df feh fetchipac gpasswd head hnb ipacsum mv \
759 pal stow uname ; do
760 [[ -z ${_comps[$compcom]} ]] && compdef _gnu_generic ${compcom}
761 done; unset compcom
762
763 # see upgrade function in this file
764 compdef _hosts upgrade
765}
766
767# Keyboard setup: The following is based on the same code, we wrote for
768# debian's setup. It ensures the terminal is in the right mode, when zle is
769# active, so the values from $terminfo are valid. Therefore, this setup should
770# work on all systems, that have support for `terminfo'. It also requires the
771# zsh in use to have the `zsh/terminfo' module built.
772#
773# If you are customising your `zle-line-init()' or `zle-line-finish()'
774# functions, make sure you call the following utility functions in there:
775#
776# - zle-line-init(): zle-smkx
777# - zle-line-finish(): zle-rmkx
778
779# Use emacs-like key bindings by default:
780bindkey -e
781
782# Custom widgets:
783
784## beginning-of-line OR beginning-of-buffer OR beginning of history
785## by: Bart Schaefer <[email protected]>, Bernhard Tittelbach
786function beginning-or-end-of-somewhere () {
787 local hno=$HISTNO
788 if [[ ( "${LBUFFER[-1]}" == $'\n' && "${WIDGET}" == beginning-of* ) || \
789 ( "${RBUFFER[1]}" == $'\n' && "${WIDGET}" == end-of* ) ]]; then
790 zle .${WIDGET:s/somewhere/buffer-or-history/} "$@"
791 else
792 zle .${WIDGET:s/somewhere/line-hist/} "$@"
793 if (( HISTNO != hno )); then
794 zle .${WIDGET:s/somewhere/buffer-or-history/} "$@"
795 fi
796 fi
797}
798zle -N beginning-of-somewhere beginning-or-end-of-somewhere
799zle -N end-of-somewhere beginning-or-end-of-somewhere
800
801# add a command line to the shells history without executing it
802function commit-to-history () {
803 print -rs ${(z)BUFFER}
804 zle send-break
805}
806zle -N commit-to-history
807
808# only slash should be considered as a word separator:
809function slash-backward-kill-word () {
810 local WORDCHARS="${WORDCHARS:s@/@}"
811 # zle backward-word
812 zle backward-kill-word
813}
814zle -N slash-backward-kill-word
815
816# a generic accept-line wrapper
817
818# This widget can prevent unwanted autocorrections from command-name
819# to _command-name, rehash automatically on enter and call any number
820# of builtin and user-defined widgets in different contexts.
821#
822# For a broader description, see:
823# <http://bewatermyfriend.org/posts/2007/12-26.11-50-38-tooltime.html>
824#
825# The code is imported from the file 'zsh/functions/accept-line' from
826# <http://ft.bewatermyfriend.org/comp/zsh/zsh-dotfiles.tar.bz2>, which
827# distributed under the same terms as zsh itself.
828
829# A newly added command will may not be found or will cause false
830# correction attempts, if you got auto-correction set. By setting the
831# following style, we force accept-line() to rehash, if it cannot
832# find the first word on the command line in the $command[] hash.
833zstyle ':acceptline:*' rehash true
834
835function Accept-Line () {
836 setopt localoptions noksharrays
837 local -a subs
838 local -xi aldone
839 local sub
840 local alcontext=${1:-$alcontext}
841
842 zstyle -a ":acceptline:${alcontext}" actions subs
843
844 (( ${#subs} < 1 )) && return 0
845
846 (( aldone = 0 ))
847 for sub in ${subs} ; do
848 [[ ${sub} == 'accept-line' ]] && sub='.accept-line'
849 zle ${sub}
850
851 (( aldone > 0 )) && break
852 done
853}
854
855function Accept-Line-getdefault () {
856 emulate -L zsh
857 local default_action
858
859 zstyle -s ":acceptline:${alcontext}" default_action default_action
860 case ${default_action} in
861 ((accept-line|))
862 printf ".accept-line"
863 ;;
864 (*)
865 printf ${default_action}
866 ;;
867 esac
868}
869
870function Accept-Line-HandleContext () {
871 zle Accept-Line
872
873 default_action=$(Accept-Line-getdefault)
874 zstyle -T ":acceptline:${alcontext}" call_default \
875 && zle ${default_action}
876}
877
878function accept-line () {
879 setopt localoptions noksharrays
880 local -a cmdline
881 local -x alcontext
882 local buf com fname format msg default_action
883
884 alcontext='default'
885 buf="${BUFFER}"
886 cmdline=(${(z)BUFFER})
887 com="${cmdline[1]}"
888 fname="_${com}"
889
890 Accept-Line 'preprocess'
891
892 zstyle -t ":acceptline:${alcontext}" rehash \
893 && [[ -z ${commands[$com]} ]] \
894 && rehash
895
896 if [[ -n ${com} ]] \
897 && [[ -n ${reswords[(r)$com]} ]] \
898 || [[ -n ${aliases[$com]} ]] \
899 || [[ -n ${functions[$com]} ]] \
900 || [[ -n ${builtins[$com]} ]] \
901 || [[ -n ${commands[$com]} ]] ; then
902
903 # there is something sensible to execute, just do it.
904 alcontext='normal'
905 Accept-Line-HandleContext
906
907 return
908 fi
909
910 if [[ -o correct ]] \
911 || [[ -o correctall ]] \
912 && [[ -n ${functions[$fname]} ]] ; then
913
914 # nothing there to execute but there is a function called
915 # _command_name; a completion widget. Makes no sense to
916 # call it on the commandline, but the correct{,all} options
917 # will ask for it nevertheless, so warn the user.
918 if [[ ${LASTWIDGET} == 'accept-line' ]] ; then
919 # Okay, we warned the user before, he called us again,
920 # so have it his way.
921 alcontext='force'
922 Accept-Line-HandleContext
923
924 return
925 fi
926
927 if zstyle -t ":acceptline:${alcontext}" nocompwarn ; then
928 alcontext='normal'
929 Accept-Line-HandleContext
930 else
931 # prepare warning message for the user, configurable via zstyle.
932 zstyle -s ":acceptline:${alcontext}" compwarnfmt msg
933
934 if [[ -z ${msg} ]] ; then
935 msg="%c will not execute and completion %f exists."
936 fi
937
938 zformat -f msg "${msg}" "c:${com}" "f:${fname}"
939
940 zle -M -- "${msg}"
941 fi
942 return
943 elif [[ -n ${buf//[$' \t\n']##/} ]] ; then
944 # If we are here, the commandline contains something that is not
945 # executable, which is neither subject to _command_name correction
946 # and is not empty. might be a variable assignment
947 alcontext='misc'
948 Accept-Line-HandleContext
949
950 return
951 fi
952
953 # If we got this far, the commandline only contains whitespace, or is empty.
954 alcontext='empty'
955 Accept-Line-HandleContext
956}
957
958zle -N accept-line
959zle -N Accept-Line
960zle -N Accept-Line-HandleContext
961
962# power completion / abbreviation expansion / buffer expansion
963# see http://zshwiki.org/home/examples/zleiab for details
964# less risky than the global aliases but powerful as well
965# just type the abbreviation key and afterwards 'ctrl-x .' to expand it
966declare -A abk
967setopt extendedglob
968setopt interactivecomments
969abk=(
970# key # value (#d additional doc string)
971#A# start
972 '...' '../..'
973 '....' '../../..'
974 'BG' '& exit'
975 'C' '| wc -l'
976 'G' '|& grep '${grep_options:+"${grep_options[*]}"}
977 'H' '| head'
978 'Hl' ' --help |& less -r' #d (Display help in pager)
979 'J' '| jq'
980 'K' '| keep'
981 'L' '| less'
982 'LL' '|& less -r'
983 'M' '| most'
984 'N' '&>/dev/null' #d (No Output)
985 'R' '| tr A-z N-za-m' #d (ROT13)
986 'SL' '| sort | less'
987 'S' '| sort -u'
988 'T' '| tail'
989 'TS' '| ts "%F %H:%M:%.S"'
990 'V' '|& vim -'
991#A# end
992 'co' './configure && make && sudo make install'
993)
994
995function zleiab () {
996 emulate -L zsh
997 setopt extendedglob
998 local MATCH
999
1000 LBUFFER=${LBUFFER%%(#m)[.\-+:|_a-zA-Z0-9]#}
1001 LBUFFER+=${abk[$MATCH]:-$MATCH}
1002}
1003
1004zle -N zleiab
1005
1006function help-show-abk () {
1007 zle -M "$(print "Available abbreviations for expansion:"; print -a -C 2 ${(kv)abk})"
1008}
1009
1010zle -N help-show-abk
1011
1012# press "ctrl-x d" to insert the actual date in the form yyyy-mm-dd
1013function insert-datestamp () { LBUFFER+=${(%):-'%D{%Y-%m-%d}'}; }
1014zle -N insert-datestamp
1015
1016# press esc-m for inserting last typed word again (thanks to caphuso!)
1017function insert-last-typed-word () { zle insert-last-word -- 0 -1 };
1018zle -N insert-last-typed-word;
1019
1020function grml-zsh-fg () {
1021 if (( ${#jobstates} )); then
1022 zle .push-input
1023 [[ -o hist_ignore_space ]] && BUFFER=' ' || BUFFER=''
1024 BUFFER="${BUFFER}fg"
1025 zle .accept-line
1026 else
1027 zle -M 'No background jobs. Doing nothing.'
1028 fi
1029}
1030zle -N grml-zsh-fg
1031
1032# run command line as user root via sudo:
1033function sudo-command-line () {
1034 [[ -z $BUFFER ]] && zle up-history
1035 local cmd="sudo "
1036 if [[ ${BUFFER} == ${cmd}* ]]; then
1037 CURSOR=$(( CURSOR-${#cmd} ))
1038 BUFFER="${BUFFER#$cmd}"
1039 else
1040 BUFFER="${cmd}${BUFFER}"
1041 CURSOR=$(( CURSOR+${#cmd} ))
1042 fi
1043 zle reset-prompt
1044}
1045zle -N sudo-command-line
1046
1047### jump behind the first word on the cmdline.
1048### useful to add options.
1049function jump_after_first_word () {
1050 local words
1051 words=(${(z)BUFFER})
1052
1053 if (( ${#words} <= 1 )) ; then
1054 CURSOR=${#BUFFER}
1055 else
1056 CURSOR=${#${words[1]}}
1057 fi
1058}
1059zle -N jump_after_first_word
1060
1061#f5# Create directory under cursor or the selected area
1062function inplaceMkDirs () {
1063 # Press ctrl-xM to create the directory under the cursor or the selected area.
1064 # To select an area press ctrl-@ or ctrl-space and use the cursor.
1065 # Use case: you type "mv abc ~/testa/testb/testc/" and remember that the
1066 # directory does not exist yet -> press ctrl-XM and problem solved
1067 local PATHTOMKDIR
1068 if ((REGION_ACTIVE==1)); then
1069 local F=$MARK T=$CURSOR
1070 if [[ $F -gt $T ]]; then
1071 F=${CURSOR}
1072 T=${MARK}
1073 fi
1074 # get marked area from buffer and eliminate whitespace
1075 PATHTOMKDIR=${BUFFER[F+1,T]%%[[:space:]]##}
1076 PATHTOMKDIR=${PATHTOMKDIR##[[:space:]]##}
1077 else
1078 local bufwords iword
1079 bufwords=(${(z)LBUFFER})
1080 iword=${#bufwords}
1081 bufwords=(${(z)BUFFER})
1082 PATHTOMKDIR="${(Q)bufwords[iword]}"
1083 fi
1084 [[ -z "${PATHTOMKDIR}" ]] && return 1
1085 PATHTOMKDIR=${~PATHTOMKDIR}
1086 if [[ -e "${PATHTOMKDIR}" ]]; then
1087 zle -M " path already exists, doing nothing"
1088 else
1089 zle -M "$(mkdir -p -v "${PATHTOMKDIR}")"
1090 zle end-of-line
1091 fi
1092}
1093
1094zle -N inplaceMkDirs
1095
1096#v1# set number of lines to display per page
1097HELP_LINES_PER_PAGE=20
1098#v1# set location of help-zle cache file
1099HELP_ZLE_CACHE_FILE=~/.cache/zsh_help_zle_lines.zsh
1100# helper function for help-zle, actually generates the help text
1101function help_zle_parse_keybindings () {
1102 emulate -L zsh
1103 setopt extendedglob
1104 unsetopt ksharrays #indexing starts at 1
1105
1106 #v1# choose files that help-zle will parse for keybindings
1107 ((${+HELPZLE_KEYBINDING_FILES})) || HELPZLE_KEYBINDING_FILES=( /etc/zsh/zshrc ~/.zshrc.pre ~/.zshrc ~/.zshrc.local )
1108
1109 if [[ -r $HELP_ZLE_CACHE_FILE ]]; then
1110 local load_cache=0
1111 local f
1112 for f ($HELPZLE_KEYBINDING_FILES) [[ $f -nt $HELP_ZLE_CACHE_FILE ]] && load_cache=1
1113 [[ $load_cache -eq 0 ]] && . $HELP_ZLE_CACHE_FILE && return
1114 fi
1115
1116 #fill with default keybindings, possibly to be overwritten in a file later
1117 #Note that due to zsh inconsistency on escaping assoc array keys, we encase the key in '' which we will remove later
1118 local -A help_zle_keybindings
1119 help_zle_keybindings['<Ctrl>@']="set MARK"
1120 help_zle_keybindings['<Ctrl>x<Ctrl>j']="vi-join lines"
1121 help_zle_keybindings['<Ctrl>x<Ctrl>b']="jump to matching brace"
1122 help_zle_keybindings['<Ctrl>x<Ctrl>u']="undo"
1123 help_zle_keybindings['<Ctrl>_']="undo"
1124 help_zle_keybindings['<Ctrl>x<Ctrl>f<c>']="find <c> in cmdline"
1125 help_zle_keybindings['<Ctrl>a']="goto beginning of line"
1126 help_zle_keybindings['<Ctrl>e']="goto end of line"
1127 help_zle_keybindings['<Ctrl>t']="transpose charaters"
1128 help_zle_keybindings['<Alt>t']="transpose words"
1129 help_zle_keybindings['<Alt>s']="spellcheck word"
1130 help_zle_keybindings['<Ctrl>k']="backward kill buffer"
1131 help_zle_keybindings['<Ctrl>u']="forward kill buffer"
1132 help_zle_keybindings['<Ctrl>y']="insert previously killed word/string"
1133 help_zle_keybindings["<Alt>'"]="quote line"
1134 help_zle_keybindings['<Alt>"']="quote from mark to cursor"
1135 help_zle_keybindings['<Alt><arg>']="repeat next cmd/char <arg> times (<Alt>-<Alt>1<Alt>0a -> -10 times 'a')"
1136 help_zle_keybindings['<Alt>u']="make next word Uppercase"
1137 help_zle_keybindings['<Alt>l']="make next word lowercase"
1138 help_zle_keybindings['<Ctrl>xG']="preview expansion under cursor"
1139 help_zle_keybindings['<Alt>q']="push current CL into background, freeing it. Restore on next CL"
1140 help_zle_keybindings['<Alt>.']="insert (and interate through) last word from prev CLs"
1141 help_zle_keybindings['<Alt>,']="complete word from newer history (consecutive hits)"
1142 help_zle_keybindings['<Alt>m']="repeat last typed word on current CL"
1143 help_zle_keybindings['<Ctrl>v']="insert next keypress symbol literally (e.g. for bindkey)"
1144 help_zle_keybindings['!!:n*<Tab>']="insert last n arguments of last command"
1145 help_zle_keybindings['!!:n-<Tab>']="insert arguments n..N-2 of last command (e.g. mv s s d)"
1146 help_zle_keybindings['<Alt>h']="show help/manpage for current command"
1147
1148 #init global variables
1149 unset help_zle_lines help_zle_sln
1150 typeset -g -a help_zle_lines
1151 typeset -g help_zle_sln=1
1152
1153 local k v f cline
1154 local lastkeybind_desc contents #last description starting with #k# that we found
1155 local num_lines_elapsed=0 #number of lines between last description and keybinding
1156 #search config files in the order they a called (and thus the order in which they overwrite keybindings)
1157 for f in $HELPZLE_KEYBINDING_FILES; do
1158 [[ -r "$f" ]] || continue #not readable ? skip it
1159 contents="$(<$f)"
1160 for cline in "${(f)contents}"; do
1161 #zsh pattern: matches lines like: #k# ..............
1162 if [[ "$cline" == (#s)[[:space:]]#\#k\#[[:space:]]##(#b)(*)[[:space:]]#(#e) ]]; then
1163 lastkeybind_desc="$match[*]"
1164 num_lines_elapsed=0
1165 #zsh pattern: matches lines that set a keybinding using bind2map, bindkey or compdef -k
1166 # ignores lines that are commentend out
1167 # grabs first in '' or "" enclosed string with length between 1 and 6 characters
1168 elif [[ "$cline" == [^#]#(bind2maps[[:space:]](*)-s|bindkey|compdef -k)[[:space:]](*)(#b)(\"((?)(#c1,6))\"|\'((?)(#c1,6))\')(#B)(*) ]]; then
1169 #description previously found ? description not more than 2 lines away ? keybinding not empty ?
1170 if [[ -n $lastkeybind_desc && $num_lines_elapsed -lt 2 && -n $match[1] ]]; then
1171 #substitute keybinding string with something readable
1172 k=${${${${${${${match[1]/\\e\^h/<Alt><BS>}/\\e\^\?/<Alt><BS>}/\\e\[5~/<PageUp>}/\\e\[6~/<PageDown>}//(\\e|\^\[)/<Alt>}//\^/<Ctrl>}/3~/<Alt><Del>}
1173 #put keybinding in assoc array, possibly overwriting defaults or stuff found in earlier files
1174 #Note that we are extracting the keybinding-string including the quotes (see Note at beginning)
1175 help_zle_keybindings[${k}]=$lastkeybind_desc
1176 fi
1177 lastkeybind_desc=""
1178 else
1179 ((num_lines_elapsed++))
1180 fi
1181 done
1182 done
1183 unset contents
1184 #calculate length of keybinding column
1185 local kstrlen=0
1186 for k (${(k)help_zle_keybindings[@]}) ((kstrlen < ${#k})) && kstrlen=${#k}
1187 #convert the assoc array into preformated lines, which we are able to sort
1188 for k v in ${(kv)help_zle_keybindings[@]}; do
1189 #pad keybinding-string to kstrlen chars and remove outermost characters (i.e. the quotes)
1190 help_zle_lines+=("${(r:kstrlen:)k[2,-2]}${v}")
1191 done
1192 #sort lines alphabetically
1193 help_zle_lines=("${(i)help_zle_lines[@]}")
1194 [[ -d ${HELP_ZLE_CACHE_FILE:h} ]] || mkdir -p "${HELP_ZLE_CACHE_FILE:h}"
1195 echo "help_zle_lines=(${(q)help_zle_lines[@]})" >| $HELP_ZLE_CACHE_FILE
1196 zcompile $HELP_ZLE_CACHE_FILE
1197}
1198typeset -g help_zle_sln
1199typeset -g -a help_zle_lines
1200
1201# Provides (partially autogenerated) help on keybindings and the zsh line editor
1202function help-zle () {
1203 emulate -L zsh
1204 unsetopt ksharrays #indexing starts at 1
1205 #help lines already generated ? no ? then do it
1206 [[ ${+functions[help_zle_parse_keybindings]} -eq 1 ]] && {help_zle_parse_keybindings && unfunction help_zle_parse_keybindings}
1207 #already displayed all lines ? go back to the start
1208 [[ $help_zle_sln -gt ${#help_zle_lines} ]] && help_zle_sln=1
1209 local sln=$help_zle_sln
1210 #note that help_zle_sln is a global var, meaning we remember the last page we viewed
1211 help_zle_sln=$((help_zle_sln + HELP_LINES_PER_PAGE))
1212 zle -M "${(F)help_zle_lines[sln,help_zle_sln-1]}"
1213}
1214zle -N help-zle
1215
1216## complete word from currently visible Screen or Tmux buffer.
1217if check_com -c screen || check_com -c tmux; then
1218 function _complete_screen_display () {
1219
1220 local TMPFILE=$(mktemp)
1221 local -U -a _screen_display_wordlist
1222 trap "rm -f $TMPFILE" EXIT
1223
1224 # fill array with contents from screen hardcopy
1225 if ((${+TMUX})); then
1226 #works, but crashes tmux below version 1.4
1227 #luckily tmux -V option to ask for version, was also added in 1.4
1228 tmux -V &>/dev/null || return
1229 tmux -q capture-pane -b 0 \; save-buffer -b 0 $TMPFILE \; delete-buffer -b 0
1230 else
1231 [[ "$TERM" != "screen" ]] && return
1232 screen -X hardcopy $TMPFILE
1233 # screen sucks, it dumps in latin1, apparently always. so recode it
1234 # to system charset
1235 check_com recode && recode latin1 $TMPFILE
1236 fi
1237 _screen_display_wordlist=( ${(QQ)$(<$TMPFILE)} )
1238 # remove PREFIX to be completed from that array
1239 _screen_display_wordlist[${_screen_display_wordlist[(i)$PREFIX]}]=""
1240 compadd -a _screen_display_wordlist
1241 }
1242 #m# k CTRL-x\,\,\,S Complete word from GNU screen buffer
1243 bindkey -r "^xS"
1244 compdef -k _complete_screen_display complete-word '^xS'
1245fi
1246
1247# Load a few more functions and tie them to widgets, so they can be bound:
1248
1249function zrcautozle () {
1250 emulate -L zsh
1251 local fnc=$1
1252 zrcautoload $fnc && zle -N $fnc
1253}
1254
1255function zrcgotwidget () {
1256 (( ${+widgets[$1]} ))
1257}
1258
1259function zrcgotkeymap () {
1260 [[ -n ${(M)keymaps:#$1} ]]
1261}
1262
1263zrcautozle insert-files
1264zrcautozle edit-command-line
1265zrcautozle insert-unicode-char
1266if zrcautoload history-search-end; then
1267 zle -N history-beginning-search-backward-end history-search-end
1268 zle -N history-beginning-search-forward-end history-search-end
1269fi
1270zle -C hist-complete complete-word _generic
1271zstyle ':completion:hist-complete:*' completer _history
1272
1273# The actual terminal setup hooks and bindkey-calls:
1274
1275# An array to note missing features to ease diagnosis in case of problems.
1276typeset -ga grml_missing_features
1277
1278function zrcbindkey () {
1279 if (( ARGC )) && zrcgotwidget ${argv[-1]}; then
1280 bindkey "$@"
1281 fi
1282}
1283
1284function bind2maps () {
1285 local i sequence widget
1286 local -a maps
1287
1288 while [[ "$1" != "--" ]]; do
1289 maps+=( "$1" )
1290 shift
1291 done
1292 shift
1293
1294 if [[ "$1" == "-s" ]]; then
1295 shift
1296 sequence="$1"
1297 else
1298 sequence="${key[$1]}"
1299 fi
1300 widget="$2"
1301
1302 [[ -z "$sequence" ]] && return 1
1303
1304 for i in "${maps[@]}"; do
1305 zrcbindkey -M "$i" "$sequence" "$widget"
1306 done
1307}
1308
1309if (( ${+terminfo[smkx]} )) && (( ${+terminfo[rmkx]} )); then
1310 function zle-smkx () {
1311 emulate -L zsh
1312 printf '%s' ${terminfo[smkx]}
1313 }
1314 function zle-rmkx () {
1315 emulate -L zsh
1316 printf '%s' ${terminfo[rmkx]}
1317 }
1318 function zle-line-init () {
1319 zle-smkx
1320 }
1321 function zle-line-finish () {
1322 zle-rmkx
1323 }
1324 zle -N zle-line-init
1325 zle -N zle-line-finish
1326else
1327 for i in {s,r}mkx; do
1328 (( ${+terminfo[$i]} )) || grml_missing_features+=($i)
1329 done
1330 unset i
1331fi
1332
1333typeset -A key
1334key=(
1335 Home "${terminfo[khome]}"
1336 End "${terminfo[kend]}"
1337 Insert "${terminfo[kich1]}"
1338 Delete "${terminfo[kdch1]}"
1339 Up "${terminfo[kcuu1]}"
1340 Down "${terminfo[kcud1]}"
1341 Left "${terminfo[kcub1]}"
1342 Right "${terminfo[kcuf1]}"
1343 PageUp "${terminfo[kpp]}"
1344 PageDown "${terminfo[knp]}"
1345 BackTab "${terminfo[kcbt]}"
1346)
1347
1348# Guidelines for adding key bindings:
1349#
1350# - Do not add hardcoded escape sequences, to enable non standard key
1351# combinations such as Ctrl-Meta-Left-Cursor. They are not easily portable.
1352#
1353# - Adding Ctrl characters, such as '^b' is okay; note that '^b' and '^B' are
1354# the same key.
1355#
1356# - All keys from the $key[] mapping are obviously okay.
1357#
1358# - Most terminals send "ESC x" when Meta-x is pressed. Thus, sequences like
1359# '\ex' are allowed in here as well.
1360
1361bind2maps emacs -- Home beginning-of-somewhere
1362bind2maps viins vicmd -- Home vi-beginning-of-line
1363bind2maps emacs -- End end-of-somewhere
1364bind2maps viins vicmd -- End vi-end-of-line
1365bind2maps emacs viins -- Insert overwrite-mode
1366bind2maps vicmd -- Insert vi-insert
1367bind2maps emacs -- Delete delete-char
1368bind2maps viins vicmd -- Delete vi-delete-char
1369bind2maps emacs viins vicmd -- Up up-line-or-search
1370bind2maps emacs viins vicmd -- Down down-line-or-search
1371bind2maps emacs -- Left backward-char
1372bind2maps viins vicmd -- Left vi-backward-char
1373bind2maps emacs -- Right forward-char
1374bind2maps viins vicmd -- Right vi-forward-char
1375#k# Perform abbreviation expansion
1376bind2maps emacs viins -- -s '^x.' zleiab
1377#k# Display list of abbreviations that would expand
1378bind2maps emacs viins -- -s '^xb' help-show-abk
1379#k# mkdir -p <dir> from string under cursor or marked area
1380bind2maps emacs viins -- -s '^xM' inplaceMkDirs
1381#k# display help for keybindings and ZLE
1382bind2maps emacs viins -- -s '^xz' help-zle
1383#k# Insert files and test globbing
1384bind2maps emacs viins -- -s "^xf" insert-files
1385#k# Edit the current line in \kbd{\$EDITOR}
1386bind2maps emacs viins -- -s '\ee' edit-command-line
1387#k# search history backward for entry beginning with typed text
1388bind2maps emacs viins -- -s '^xp' history-beginning-search-backward-end
1389#k# search history forward for entry beginning with typed text
1390bind2maps emacs viins -- -s '^xP' history-beginning-search-forward-end
1391#k# search history backward for entry beginning with typed text
1392bind2maps emacs viins -- PageUp history-beginning-search-backward-end
1393#k# search history forward for entry beginning with typed text
1394bind2maps emacs viins -- PageDown history-beginning-search-forward-end
1395bind2maps emacs viins -- -s "^x^h" commit-to-history
1396#k# Kill left-side word or everything up to next slash
1397bind2maps emacs viins -- -s '\ev' slash-backward-kill-word
1398#k# Kill left-side word or everything up to next slash
1399bind2maps emacs viins -- -s '\e^h' slash-backward-kill-word
1400#k# Kill left-side word or everything up to next slash
1401bind2maps emacs viins -- -s '\e^?' slash-backward-kill-word
1402# Do history expansion on space:
1403bind2maps emacs viins -- -s ' ' magic-space
1404#k# Trigger menu-complete
1405bind2maps emacs viins -- -s '\ei' menu-complete # menu completion via esc-i
1406#k# Insert a timestamp on the command line (yyyy-mm-dd)
1407bind2maps emacs viins -- -s '^xd' insert-datestamp
1408#k# Insert last typed word
1409bind2maps emacs viins -- -s "\em" insert-last-typed-word
1410#k# A smart shortcut for \kbd{fg<enter>}
1411bind2maps emacs viins -- -s '^z' grml-zsh-fg
1412#k# prepend the current command with "sudo"
1413bind2maps emacs viins -- -s "^os" sudo-command-line
1414#k# jump to after first word (for adding options)
1415bind2maps emacs viins -- -s '^x1' jump_after_first_word
1416#k# complete word from history with menu
1417bind2maps emacs viins -- -s "^x^x" hist-complete
1418
1419# insert unicode character
1420# usage example: 'ctrl-x i' 00A7 'ctrl-x i' will give you an §
1421# See for example http://unicode.org/charts/ for unicode characters code
1422#k# Insert Unicode character
1423bind2maps emacs viins -- -s '^xi' insert-unicode-char
1424
1425# use the new *-pattern-* widgets for incremental history search
1426if zrcgotwidget history-incremental-pattern-search-backward; then
1427 for seq wid in '^r' history-incremental-pattern-search-backward \
1428 '^s' history-incremental-pattern-search-forward
1429 do
1430 bind2maps emacs viins vicmd -- -s $seq $wid
1431 done
1432 builtin unset -v seq wid
1433fi
1434
1435if zrcgotkeymap menuselect; then
1436 #m# k Shift-tab Perform backwards menu completion
1437 bind2maps menuselect -- BackTab reverse-menu-complete
1438
1439 #k# menu selection: pick item but stay in the menu
1440 bind2maps menuselect -- -s '\e^M' accept-and-menu-complete
1441 # also use + and INSERT since it's easier to press repeatedly
1442 bind2maps menuselect -- -s '+' accept-and-menu-complete
1443 bind2maps menuselect -- Insert accept-and-menu-complete
1444
1445 # accept a completion and try to complete again by using menu
1446 # completion; very useful with completing directories
1447 # by using 'undo' one's got a simple file browser
1448 bind2maps menuselect -- -s '^o' accept-and-infer-next-history
1449fi
1450
1451# Finally, here are still a few hardcoded escape sequences; Special sequences
1452# like Ctrl-<Cursor-key> etc do suck a fair bit, because they are not
1453# standardised and most of the time are not available in a terminals terminfo
1454# entry.
1455#
1456# While we do not encourage adding bindings like these, we will keep these for
1457# backward compatibility.
1458
1459## use Ctrl-left-arrow and Ctrl-right-arrow for jumping to word-beginnings on
1460## the command line.
1461# URxvt sequences:
1462bind2maps emacs viins vicmd -- -s '\eOc' forward-word
1463bind2maps emacs viins vicmd -- -s '\eOd' backward-word
1464# These are for xterm:
1465bind2maps emacs viins vicmd -- -s '\e[1;5C' forward-word
1466bind2maps emacs viins vicmd -- -s '\e[1;5D' backward-word
1467## the same for alt-left-arrow and alt-right-arrow
1468# URxvt again:
1469bind2maps emacs viins vicmd -- -s '\e\e[C' forward-word
1470bind2maps emacs viins vicmd -- -s '\e\e[D' backward-word
1471# Xterm again:
1472bind2maps emacs viins vicmd -- -s '^[[1;3C' forward-word
1473bind2maps emacs viins vicmd -- -s '^[[1;3D' backward-word
1474# Also try ESC Left/Right:
1475bind2maps emacs viins vicmd -- -s '\e'${key[Right]} forward-word
1476bind2maps emacs viins vicmd -- -s '\e'${key[Left]} backward-word
1477
1478# autoloading
1479
1480zrcautoload zmv
1481zrcautoload zed
1482
1483# we don't want to quote/espace URLs on our own...
1484# if autoload -U url-quote-magic ; then
1485# zle -N self-insert url-quote-magic
1486# zstyle ':url-quote-magic:*' url-metas '*?[]^()~#{}='
1487# else
1488# print 'Notice: no url-quote-magic available :('
1489# fi
1490alias url-quote='autoload -U bracketed-paste-magic url-quote-magic;
1491 zle -N bracketed-paste bracketed-paste-magic; zle -N self-insert url-quote-magic'
1492
1493#m# k ESC-h Call \kbd{run-help} for the 1st word on the command line
1494alias run-help >&/dev/null && unalias run-help
1495for rh in run-help{,-git,-ip,-openssl,-p4,-sudo,-svk,-svn}; do
1496 zrcautoload $rh
1497done; unset rh
1498
1499# command not found handling
1500
1501(( ${COMMAND_NOT_FOUND} == 1 )) &&
1502function command_not_found_handler () {
1503 emulate -L zsh
1504 if [[ -x ${GRML_ZSH_CNF_HANDLER} ]] ; then
1505 ${GRML_ZSH_CNF_HANDLER} $1
1506 fi
1507 return 1
1508}
1509
1510# history
1511
1512#v#
1513HISTFILE=${HISTFILE:-${ZDOTDIR:-${HOME}}/.zsh_history}
1514# override settings only if the defaults from zsh are in place
1515if [[ -z $HISTSIZE || $HISTSIZE -eq 30 ]] ; then
1516 HISTSIZE=5000
1517 SAVEHIST=10000 # useful for setopt append_history
1518fi
1519
1520# dirstack handling
1521
1522DIRSTACKSIZE=${DIRSTACKSIZE:-20}
1523DIRSTACKFILE=${DIRSTACKFILE:-${ZDOTDIR:-${HOME}}/.zdirs}
1524
1525if zstyle -T ':grml:chpwd:dirstack' enable; then
1526 typeset -gaU GRML_PERSISTENT_DIRSTACK
1527 function grml_dirstack_filter () {
1528 local -a exclude
1529 local filter entry
1530 if zstyle -s ':grml:chpwd:dirstack' filter filter; then
1531 $filter $1 && return 0
1532 fi
1533 if zstyle -a ':grml:chpwd:dirstack' exclude exclude; then
1534 for entry in "${exclude[@]}"; do
1535 [[ $1 == ${~entry} ]] && return 0
1536 done
1537 fi
1538 return 1
1539 }
1540
1541 function chpwd () {
1542 (( ZSH_SUBSHELL )) && return
1543 [[ -z $DIRSTACKSIZE ]] && return
1544 (( $DIRSTACKSIZE <= 0 )) && return
1545 [[ -z $DIRSTACKFILE ]] && return
1546 grml_dirstack_filter $PWD && return
1547 GRML_PERSISTENT_DIRSTACK=(
1548 $PWD "${(@)GRML_PERSISTENT_DIRSTACK[1,$DIRSTACKSIZE]}"
1549 )
1550 builtin print -l ${GRML_PERSISTENT_DIRSTACK} >! ${DIRSTACKFILE}
1551 }
1552
1553 if [[ -f ${DIRSTACKFILE} ]]; then
1554 # Enabling NULL_GLOB via (N) weeds out any non-existing
1555 # directories from the saved dir-stack file.
1556 dirstack=( ${(f)"$(< $DIRSTACKFILE)"}(N) )
1557 # "cd -" won't work after login by just setting $OLDPWD, so
1558 [[ -d $dirstack[1] ]] && cd -q $dirstack[1] && cd -q $OLDPWD
1559 fi
1560
1561 if zstyle -t ':grml:chpwd:dirstack' filter-on-load; then
1562 for i in "${dirstack[@]}"; do
1563 if ! grml_dirstack_filter "$i"; then
1564 GRML_PERSISTENT_DIRSTACK=(
1565 "${GRML_PERSISTENT_DIRSTACK[@]}"
1566 $i
1567 )
1568 fi
1569 done
1570 else
1571 GRML_PERSISTENT_DIRSTACK=( "${dirstack[@]}" )
1572 fi
1573fi
1574
1575# directory based profiles
1576
1577# chpwd_profiles(): Directory Profiles, Quickstart:
1578#
1579# In .zshrc.local:
1580#
1581# zstyle ':chpwd:profiles:/usr/src/grml(|/|/*)' profile grml
1582# zstyle ':chpwd:profiles:/usr/src/debian(|/|/*)' profile debian
1583# chpwd_profiles
1584#
1585# For details see the `grmlzshrc.5' manual page.
1586function chpwd_profiles () {
1587 local profile context
1588 local -i reexecute
1589
1590 context=":chpwd:profiles:$PWD"
1591 zstyle -s "$context" profile profile || profile='default'
1592 zstyle -T "$context" re-execute && reexecute=1 || reexecute=0
1593
1594 if (( ${+parameters[CHPWD_PROFILE]} == 0 )); then
1595 typeset -g CHPWD_PROFILE
1596 local CHPWD_PROFILES_INIT=1
1597 (( ${+functions[chpwd_profiles_init]} )) && chpwd_profiles_init
1598 elif [[ $profile != $CHPWD_PROFILE ]]; then
1599 (( ${+functions[chpwd_leave_profile_$CHPWD_PROFILE]} )) \
1600 && chpwd_leave_profile_${CHPWD_PROFILE}
1601 fi
1602 if (( reexecute )) || [[ $profile != $CHPWD_PROFILE ]]; then
1603 (( ${+functions[chpwd_profile_$profile]} )) && chpwd_profile_${profile}
1604 fi
1605
1606 CHPWD_PROFILE="${profile}"
1607 return 0
1608}
1609
1610chpwd_functions=( ${chpwd_functions} chpwd_profiles )
1611
1612# Prompt setup for grml:
1613
1614# set colors for use in prompts.
1615BLUE="%F{blue}"
1616RED="%F{red}"
1617GREEN="%F{green}"
1618CYAN="%F{cyan}"
1619MAGENTA="%F{magenta}"
1620YELLOW="%F{yellow}"
1621WHITE="%F{white}"
1622NO_COLOR="%f"
1623
1624# First, the easy ones: PS2..4:
1625
1626# secondary prompt, printed when the shell needs more information to complete a
1627# command.
1628PS2='\`%_> '
1629# selection prompt used within a select loop.
1630PS3='?# '
1631# the execution trace prompt (setopt xtrace). default: '+%N:%i>'
1632PS4='+%N:%i:%_> '
1633
1634# Some additional features to use with our prompt:
1635#
1636# - battery status
1637# - debian_chroot
1638# - vcs_info setup and version specific fixes
1639
1640# display battery status on right side of prompt using 'GRML_DISPLAY_BATTERY=1' in .zshrc.pre
1641
1642function battery () {
1643if [[ $GRML_DISPLAY_BATTERY -gt 0 ]] ; then
1644 if islinux ; then
1645 batterylinux
1646 elif isopenbsd ; then
1647 batteryopenbsd
1648 elif isfreebsd ; then
1649 batteryfreebsd
1650 elif isdarwin ; then
1651 batterydarwin
1652 else
1653 #not yet supported
1654 GRML_DISPLAY_BATTERY=0
1655 fi
1656fi
1657}
1658
1659function batterylinux () {
1660GRML_BATTERY_LEVEL=''
1661local batteries bat capacity
1662batteries=( /sys/class/power_supply/BAT*(N) )
1663if (( $#batteries > 0 )) ; then
1664 for bat in $batteries ; do
1665 if [[ -e $bat/capacity ]]; then
1666 capacity=$(< $bat/capacity)
1667 else
1668 typeset -F energy_full=$(< $bat/energy_full)
1669 typeset -F energy_now=$(< $bat/energy_now)
1670 typeset -i capacity=$(( 100 * $energy_now / $energy_full))
1671 fi
1672 case $(< $bat/status) in
1673 Charging)
1674 GRML_BATTERY_LEVEL+=" ^"
1675 ;;
1676 Discharging)
1677 if (( capacity < 20 )) ; then
1678 GRML_BATTERY_LEVEL+=" !v"
1679 else
1680 GRML_BATTERY_LEVEL+=" v"
1681 fi
1682 ;;
1683 *) # Full, Unknown
1684 GRML_BATTERY_LEVEL+=" ="
1685 ;;
1686 esac
1687 GRML_BATTERY_LEVEL+="${capacity}%%"
1688 done
1689fi
1690}
1691
1692function batteryopenbsd () {
1693GRML_BATTERY_LEVEL=''
1694local bat batfull batwarn batnow num
1695for num in 0 1 ; do
1696 bat=$(sysctl -n hw.sensors.acpibat${num} 2>/dev/null)
1697 if [[ -n $bat ]]; then
1698 batfull=${"$(sysctl -n hw.sensors.acpibat${num}.amphour0)"%% *}
1699 batwarn=${"$(sysctl -n hw.sensors.acpibat${num}.amphour1)"%% *}
1700 batnow=${"$(sysctl -n hw.sensors.acpibat${num}.amphour3)"%% *}
1701 case "$(sysctl -n hw.sensors.acpibat${num}.raw0)" in
1702 *" discharging"*)
1703 if (( batnow < batwarn )) ; then
1704 GRML_BATTERY_LEVEL+=" !v"
1705 else
1706 GRML_BATTERY_LEVEL+=" v"
1707 fi
1708 ;;
1709 *" charging"*)
1710 GRML_BATTERY_LEVEL+=" ^"
1711 ;;
1712 *)
1713 GRML_BATTERY_LEVEL+=" ="
1714 ;;
1715 esac
1716 GRML_BATTERY_LEVEL+="${$(( 100 * batnow / batfull ))%%.*}%%"
1717 fi
1718done
1719}
1720
1721function batteryfreebsd () {
1722GRML_BATTERY_LEVEL=''
1723local num
1724local -A table
1725for num in 0 1 ; do
1726 table=( ${=${${${${${(M)${(f)"$(acpiconf -i $num 2>&1)"}:#(State|Remaining capacity):*}%%( ##|%)}//:[ $'\t']##/@}// /-}//@/ }} )
1727 if [[ -n $table ]] && [[ $table[State] != "not-present" ]] ; then
1728 case $table[State] in
1729 *discharging*)
1730 if (( $table[Remaining-capacity] < 20 )) ; then
1731 GRML_BATTERY_LEVEL+=" !v"
1732 else
1733 GRML_BATTERY_LEVEL+=" v"
1734 fi
1735 ;;
1736 *charging*)
1737 GRML_BATTERY_LEVEL+=" ^"
1738 ;;
1739 *)
1740 GRML_BATTERY_LEVEL+=" ="
1741 ;;
1742 esac
1743 GRML_BATTERY_LEVEL+="$table[Remaining-capacity]%%"
1744 fi
1745done
1746}
1747
1748function batterydarwin () {
1749GRML_BATTERY_LEVEL=''
1750local -a table
1751table=( ${$(pmset -g ps)[(w)8,9]%%(\%|);} )
1752if [[ -n $table[2] ]] ; then
1753 case $table[2] in
1754 charging)
1755 GRML_BATTERY_LEVEL+=" ^"
1756 ;;
1757 discharging)
1758 if (( $table[1] < 20 )) ; then
1759 GRML_BATTERY_LEVEL+=" !v"
1760 else
1761 GRML_BATTERY_LEVEL+=" v"
1762 fi
1763 ;;
1764 *)
1765 GRML_BATTERY_LEVEL+=" ="
1766 ;;
1767 esac
1768 GRML_BATTERY_LEVEL+="$table[1]%%"
1769fi
1770}
1771
1772# set variable debian_chroot if running in a chroot with /etc/debian_chroot
1773if [[ -z "$debian_chroot" ]] && [[ -r /etc/debian_chroot ]] ; then
1774 debian_chroot=$(</etc/debian_chroot)
1775fi
1776
1777# gather version control information for inclusion in a prompt
1778
1779if zrcautoload vcs_info; then
1780 zstyle ':vcs_info:*' max-exports 2
1781
1782 if [[ -o restricted ]]; then
1783 zstyle ':vcs_info:*' enable NONE
1784 fi
1785fi
1786
1787typeset -A grml_vcs_coloured_formats
1788typeset -A grml_vcs_plain_formats
1789
1790grml_vcs_plain_formats=(
1791 format "(%s%)-[%b] " "zsh: %r"
1792 actionformat "(%s%)-[%b|%a] " "zsh: %r"
1793 rev-branchformat "%b:%r"
1794)
1795
1796grml_vcs_coloured_formats=(
1797 format "${MAGENTA}(${NO_COLOR}%s${MAGENTA})${YELLOW}-${MAGENTA}[${GREEN}%b${MAGENTA}]${NO_COLOR} "
1798 actionformat "${MAGENTA}(${NO_COLOR}%s${MAGENTA})${YELLOW}-${MAGENTA}[${GREEN}%b${YELLOW}|${RED}%a${MAGENTA}]${NO_COLOR} "
1799 rev-branchformat "%b${RED}:${YELLOW}%r"
1800)
1801
1802typeset GRML_VCS_COLOUR_MODE=xxx
1803
1804function grml_vcs_info_toggle_colour () {
1805 emulate -L zsh
1806 if [[ $GRML_VCS_COLOUR_MODE == plain ]]; then
1807 grml_vcs_info_set_formats coloured
1808 else
1809 grml_vcs_info_set_formats plain
1810 fi
1811 return 0
1812}
1813
1814function grml_vcs_info_set_formats () {
1815 emulate -L zsh
1816 #setopt localoptions xtrace
1817 local mode=$1 AF F BF
1818 if [[ $mode == coloured ]]; then
1819 AF=${grml_vcs_coloured_formats[actionformat]}
1820 F=${grml_vcs_coloured_formats[format]}
1821 BF=${grml_vcs_coloured_formats[rev-branchformat]}
1822 GRML_VCS_COLOUR_MODE=coloured
1823 else
1824 AF=${grml_vcs_plain_formats[actionformat]}
1825 F=${grml_vcs_plain_formats[format]}
1826 BF=${grml_vcs_plain_formats[rev-branchformat]}
1827 GRML_VCS_COLOUR_MODE=plain
1828 fi
1829
1830 zstyle ':vcs_info:*' actionformats "$AF" "zsh: %r"
1831 zstyle ':vcs_info:*' formats "$F" "zsh: %r"
1832 zstyle ':vcs_info:(sv[nk]|bzr):*' branchformat "$BF"
1833 return 0
1834}
1835
1836# Change vcs_info formats for the grml prompt. The 2nd format sets up
1837# $vcs_info_msg_1_ to contain "zsh: repo-name" used to set our screen title.
1838if [[ "$TERM" == dumb ]] ; then
1839 grml_vcs_info_set_formats plain
1840else
1841 grml_vcs_info_set_formats coloured
1842fi
1843
1844# Now for the fun part: The grml prompt themes in `promptsys' mode of operation
1845
1846# This actually defines three prompts:
1847#
1848# - grml
1849# - grml-large
1850# - grml-chroot
1851#
1852# They all share the same code and only differ with respect to which items they
1853# contain. The main source of documentation is the `prompt_grml_help' function
1854# below, which gets called when the user does this: prompt -h grml
1855
1856function prompt_grml_help () {
1857 <<__EOF0__
1858 prompt grml
1859
1860 This is the prompt as used by the grml-live system <http://grml.org>. It is
1861 a rather simple one-line prompt, that by default looks something like this:
1862
1863 <user>@<host> <current-working-directory>[ <vcs_info-data>]%
1864
1865 The prompt itself integrates with zsh's prompt themes system (as you are
1866 witnessing right now) and is configurable to a certain degree. In
1867 particular, these aspects are customisable:
1868
1869 - The items used in the prompt (e.g. you can remove \`user' from
1870 the list of activated items, which will cause the user name to
1871 be omitted from the prompt string).
1872
1873 - The attributes used with the items are customisable via strings
1874 used before and after the actual item.
1875
1876 The available items are: at, battery, change-root, date, grml-chroot,
1877 history, host, jobs, newline, path, percent, rc, rc-always, sad-smiley,
1878 shell-level, time, user, vcs
1879
1880 The actual configuration is done via zsh's \`zstyle' mechanism. The
1881 context, that is used while looking up styles is:
1882
1883 ':prompt:grml:<left-or-right>:<subcontext>'
1884
1885 Here <left-or-right> is either \`left' or \`right', signifying whether the
1886 style should affect the left or the right prompt. <subcontext> is either
1887 \`setup' or 'items:<item>', where \`<item>' is one of the available items.
1888
1889 The styles:
1890
1891 - use-rprompt (boolean): If \`true' (the default), print a sad smiley
1892 in $RPROMPT if the last command a returned non-successful error code.
1893 (This in only valid if <left-or-right> is "right"; ignored otherwise)
1894
1895 - items (list): The list of items used in the prompt. If \`vcs' is
1896 present in the list, the theme's code invokes \`vcs_info'
1897 accordingly. Default (left): rc change-root user at host path vcs
1898 percent; Default (right): sad-smiley
1899
1900 - strip-sensitive-characters (boolean): If the \`prompt_subst' option
1901 is active in zsh, the shell performs lots of expansions on prompt
1902 variable strings, including command substitution. So if you don't
1903 control where some of your prompt strings is coming from, this is
1904 an exploitable weakness. Grml's zsh setup does not set this option
1905 and it is off in the shell in zsh-mode by default. If it *is* turned
1906 on however, this style becomes active, and there are two flavours of
1907 it: On per default is a global variant in the '*:setup' context. This
1908 strips characters after the whole prompt string was constructed. There
1909 is a second variant in the '*:items:<item>', that is off by default.
1910 It allows fine grained control over which items' data is stripped.
1911 The characters that are stripped are: \$ and \`.
1912
1913 Available styles in 'items:<item>' are: pre, post. These are strings that
1914 are inserted before (pre) and after (post) the item in question. Thus, the
1915 following would cause the user name to be printed in red instead of the
1916 default blue:
1917
1918 zstyle ':prompt:grml:*:items:user' pre '%F{red}'
1919
1920 Note, that the \`post' style may remain at its default value, because its
1921 default value is '%f', which turns the foreground text attribute off (which
1922 is exactly, what is still required with the new \`pre' value).
1923__EOF0__
1924}
1925
1926function prompt_grml-chroot_help () {
1927 <<__EOF0__
1928 prompt grml-chroot
1929
1930 This is a variation of the grml prompt, see: prompt -h grml
1931
1932 The main difference is the default value of the \`items' style. The rest
1933 behaves exactly the same. Here are the defaults for \`grml-chroot':
1934
1935 - left: grml-chroot user at host path percent
1936 - right: (empty list)
1937__EOF0__
1938}
1939
1940function prompt_grml-large_help () {
1941 <<__EOF0__
1942 prompt grml-large
1943
1944 This is a variation of the grml prompt, see: prompt -h grml
1945
1946 The main difference is the default value of the \`items' style. In
1947 particular, this theme uses _two_ lines instead of one with the plain
1948 \`grml' theme. The rest behaves exactly the same. Here are the defaults
1949 for \`grml-large':
1950
1951 - left: rc jobs history shell-level change-root time date newline user
1952 at host path vcs percent
1953 - right: sad-smiley
1954__EOF0__
1955}
1956
1957function grml_prompt_setup () {
1958 emulate -L zsh
1959 autoload -Uz vcs_info
1960 add-zsh-hook precmd prompt_$1_precmd
1961}
1962
1963function prompt_grml_setup () {
1964 grml_prompt_setup grml
1965}
1966
1967function prompt_grml-chroot_setup () {
1968 grml_prompt_setup grml-chroot
1969}
1970
1971function prompt_grml-large_setup () {
1972 grml_prompt_setup grml-large
1973}
1974
1975# These maps define default tokens and pre-/post-decoration for items to be
1976# used within the themes. All defaults may be customised in a context sensitive
1977# matter by using zsh's `zstyle' mechanism.
1978typeset -gA grml_prompt_pre_default \
1979 grml_prompt_post_default \
1980 grml_prompt_token_default \
1981 grml_prompt_token_function
1982
1983grml_prompt_pre_default=(
1984 at ''
1985 battery ' '
1986 change-root ''
1987 date '%F{blue}'
1988 grml-chroot '%F{red}'
1989 history '%F{green}'
1990 host ''
1991 jobs '%F{cyan}'
1992 newline ''
1993 path '%B'
1994 percent ''
1995 rc '%B%F{red}'
1996 rc-always ''
1997 sad-smiley ''
1998 shell-level '%F{red}'
1999 time '%F{blue}'
2000 user '%B%F{blue}'
2001 vcs ''
2002)
2003
2004grml_prompt_post_default=(
2005 at ''
2006 battery ''
2007 change-root ''
2008 date '%f'
2009 grml-chroot '%f '
2010 history '%f'
2011 host ''
2012 jobs '%f'
2013 newline ''
2014 path '%b'
2015 percent ''
2016 rc '%f%b'
2017 rc-always ''
2018 sad-smiley ''
2019 shell-level '%f'
2020 time '%f'
2021 user '%f%b'
2022 vcs ''
2023)
2024
2025grml_prompt_token_default=(
2026 at '@'
2027 battery 'GRML_BATTERY_LEVEL'
2028 change-root 'debian_chroot'
2029 date '%D{%Y-%m-%d}'
2030 grml-chroot 'GRML_CHROOT'
2031 history '{history#%!} '
2032 host '%m '
2033 jobs '[%j running job(s)] '
2034 newline $'\n'
2035 path '%40<..<%~%<< '
2036 percent '%# '
2037 rc '%(?..%? )'
2038 rc-always '%?'
2039 sad-smiley '%(?..:()'
2040 shell-level '%(3L.+ .)'
2041 time '%D{%H:%M:%S} '
2042 user '%n'
2043 vcs '0'
2044)
2045
2046function grml_theme_has_token () {
2047 if (( ARGC != 1 )); then
2048 printf 'usage: grml_theme_has_token <name>\n'
2049 return 1
2050 fi
2051 (( ${+grml_prompt_token_default[$1]} ))
2052}
2053
2054function GRML_theme_add_token_usage () {
2055 <<__EOF0__
2056 Usage: grml_theme_add_token <name> [-f|-i] <token/function> [<pre> <post>]
2057
2058 <name> is the name for the newly added token. If the \`-f' or \`-i' options
2059 are used, <token/function> is the name of the function (see below for
2060 details). Otherwise it is the literal token string to be used. <pre> and
2061 <post> are optional.
2062
2063 Options:
2064
2065 -f <function> Use a function named \`<function>' each time the token
2066 is to be expanded.
2067
2068 -i <function> Use a function named \`<function>' to initialise the
2069 value of the token _once_ at runtime.
2070
2071 The functions are called with one argument: the token's new name. The
2072 return value is expected in the \$REPLY parameter. The use of these
2073 options is mutually exclusive.
2074
2075 There is a utility function \`grml_theme_has_token', which you can use
2076 to test if a token exists before trying to add it. This can be a guard
2077 for situations in which a \`grml_theme_add_token' call may happen more
2078 than once.
2079
2080 Example:
2081
2082 To add a new token \`day' that expands to the current weekday in the
2083 current locale in green foreground colour, use this:
2084
2085 grml_theme_add_token day '%D{%A}' '%F{green}' '%f'
2086
2087 Another example would be support for \$VIRTUAL_ENV:
2088
2089 function virtual_env_prompt () {
2090 REPLY=\${VIRTUAL_ENV+\${VIRTUAL_ENV:t} }
2091 }
2092 grml_theme_add_token virtual-env -f virtual_env_prompt
2093
2094 After that, you will be able to use a changed \`items' style to
2095 assemble your prompt.
2096__EOF0__
2097}
2098
2099function grml_theme_add_token () {
2100 emulate -L zsh
2101 local name token pre post
2102 local -i init funcall
2103
2104 if (( ARGC == 0 )); then
2105 GRML_theme_add_token_usage
2106 return 0
2107 fi
2108
2109 init=0
2110 funcall=0
2111 pre=''
2112 post=''
2113 name=$1
2114 shift
2115 if [[ $1 == '-f' ]]; then
2116 funcall=1
2117 shift
2118 elif [[ $1 == '-i' ]]; then
2119 init=1
2120 shift
2121 fi
2122
2123 if (( ARGC == 0 )); then
2124 printf '
2125grml_theme_add_token: No token-string/function-name provided!\n\n'
2126 GRML_theme_add_token_usage
2127 return 1
2128 fi
2129 token=$1
2130 shift
2131 if (( ARGC != 0 && ARGC != 2 )); then
2132 printf '
2133grml_theme_add_token: <pre> and <post> need to by specified _both_!\n\n'
2134 GRML_theme_add_token_usage
2135 return 1
2136 fi
2137 if (( ARGC )); then
2138 pre=$1
2139 post=$2
2140 shift 2
2141 fi
2142
2143 if grml_theme_has_token $name; then
2144 printf '
2145grml_theme_add_token: Token `%s'\'' exists! Giving up!\n\n' $name
2146 GRML_theme_add_token_usage
2147 return 2
2148 fi
2149 if (( init )); then
2150 REPLY=''
2151 $token $name
2152 token=$REPLY
2153 fi
2154 grml_prompt_pre_default[$name]=$pre
2155 grml_prompt_post_default[$name]=$post
2156 if (( funcall )); then
2157 grml_prompt_token_function[$name]=$token
2158 grml_prompt_token_default[$name]=23
2159 else
2160 grml_prompt_token_default[$name]=$token
2161 fi
2162}
2163
2164function grml_wrap_reply () {
2165 emulate -L zsh
2166 local target="$1"
2167 local new="$2"
2168 local left="$3"
2169 local right="$4"
2170
2171 if (( ${+parameters[$new]} )); then
2172 REPLY="${left}${(P)new}${right}"
2173 else
2174 REPLY=''
2175 fi
2176}
2177
2178function grml_prompt_addto () {
2179 emulate -L zsh
2180 local target="$1"
2181 local lr it apre apost new v REPLY
2182 local -a items
2183 shift
2184
2185 [[ $target == PS1 ]] && lr=left || lr=right
2186 zstyle -a ":prompt:${grmltheme}:${lr}:setup" items items || items=( "$@" )
2187 typeset -g "${target}="
2188 for it in "${items[@]}"; do
2189 zstyle -s ":prompt:${grmltheme}:${lr}:items:$it" pre apre \
2190 || apre=${grml_prompt_pre_default[$it]}
2191 zstyle -s ":prompt:${grmltheme}:${lr}:items:$it" post apost \
2192 || apost=${grml_prompt_post_default[$it]}
2193 zstyle -s ":prompt:${grmltheme}:${lr}:items:$it" token new \
2194 || new=${grml_prompt_token_default[$it]}
2195 if (( ${+grml_prompt_token_function[$it]} )); then
2196 REPLY=''
2197 ${grml_prompt_token_function[$it]} $it
2198 else
2199 case $it in
2200 battery)
2201 grml_wrap_reply $target $new '' ''
2202 ;;
2203 change-root)
2204 grml_wrap_reply $target $new '(' ')'
2205 ;;
2206 grml-chroot)
2207 if [[ -n ${(P)new} ]]; then
2208 REPLY="$CHROOT"
2209 else
2210 REPLY=''
2211 fi
2212 ;;
2213 vcs)
2214 v="vcs_info_msg_${new}_"
2215 if (( ! vcscalled )); then
2216 vcs_info
2217 vcscalled=1
2218 fi
2219 if (( ${+parameters[$v]} )) && [[ -n "${(P)v}" ]]; then
2220 REPLY="${(P)v}"
2221 else
2222 REPLY=''
2223 fi
2224 ;;
2225 *) REPLY="$new" ;;
2226 esac
2227 fi
2228 # Strip volatile characters per item. This is off by default. See the
2229 # global stripping code a few lines below for details.
2230 if [[ -o prompt_subst ]] && zstyle -t ":prompt:${grmltheme}:${lr}:items:$it" \
2231 strip-sensitive-characters
2232 then
2233 REPLY="${REPLY//[$\`]/}"
2234 fi
2235 typeset -g "${target}=${(P)target}${apre}${REPLY}${apost}"
2236 done
2237
2238 # Per default, strip volatile characters (in the prompt_subst case)
2239 # globally. If the option is off, the style has no effect. For more
2240 # control, this can be turned off and stripping can be configured on a
2241 # per-item basis (see above).
2242 if [[ -o prompt_subst ]] && zstyle -T ":prompt:${grmltheme}:${lr}:setup" \
2243 strip-sensitive-characters
2244 then
2245 typeset -g "${target}=${${(P)target}//[$\`]/}"
2246 fi
2247}
2248
2249function prompt_grml_precmd () {
2250 emulate -L zsh
2251 local grmltheme=grml
2252 local -a left_items right_items
2253 left_items=(rc change-root user at host path vcs percent)
2254 right_items=(sad-smiley)
2255
2256 prompt_grml_precmd_worker
2257}
2258
2259function prompt_grml-chroot_precmd () {
2260 emulate -L zsh
2261 local grmltheme=grml-chroot
2262 local -a left_items right_items
2263 left_items=(grml-chroot user at host path percent)
2264 right_items=()
2265
2266 prompt_grml_precmd_worker
2267}
2268
2269function prompt_grml-large_precmd () {
2270 emulate -L zsh
2271 local grmltheme=grml-large
2272 local -a left_items right_items
2273 left_items=(rc jobs history shell-level change-root time date newline
2274 user at host path vcs percent)
2275 right_items=(sad-smiley)
2276
2277 prompt_grml_precmd_worker
2278}
2279
2280function prompt_grml_precmd_worker () {
2281 emulate -L zsh
2282 local -i vcscalled=0
2283
2284 grml_prompt_addto PS1 "${left_items[@]}"
2285 if zstyle -T ":prompt:${grmltheme}:right:setup" use-rprompt; then
2286 grml_prompt_addto RPS1 "${right_items[@]}"
2287 fi
2288}
2289
2290function grml_prompt_fallback () {
2291 setopt prompt_subst
2292 local p0 p1
2293
2294 p0="${RED}%(?..%? )${WHITE}${debian_chroot:+($debian_chroot)}"
2295 p1="${BLUE}%n${NO_COLOR}@%m %40<...<%B%~%b%<< "'${vcs_info_msg_0_}'"%# "
2296 if (( EUID == 0 )); then
2297 PROMPT="${BLUE}${p0}${RED}${p1}"
2298 else
2299 PROMPT="${RED}${p0}${BLUE}${p1}"
2300 fi
2301}
2302
2303if zrcautoload promptinit && promptinit 2>/dev/null ; then
2304 grml_status_feature promptinit 0
2305 # Since we define the required functions in here and not in files in
2306 # $fpath, we need to stick the theme's name into `$prompt_themes'
2307 # ourselves, since promptinit does not pick them up otherwise.
2308 prompt_themes+=( grml grml-chroot grml-large )
2309 # Also, keep the array sorted...
2310 prompt_themes=( "${(@on)prompt_themes}" )
2311else
2312 grml_status_feature promptinit 1
2313 grml_prompt_fallback
2314 function precmd () { (( ${+functions[vcs_info]} )) && vcs_info; }
2315fi
2316
2317if [[ $GRML_DISPLAY_BATTERY -gt 0 ]]; then
2318 zstyle ':prompt:grml:right:setup' items sad-smiley battery
2319 add-zsh-hook precmd battery
2320fi
2321if [[ "$TERM" == dumb ]] ; then
2322 zstyle ":prompt:grml(|-large|-chroot):*:items:grml-chroot" pre ''
2323 zstyle ":prompt:grml(|-large|-chroot):*:items:grml-chroot" post ' '
2324 for i in rc user path jobs history date time shell-level; do
2325 zstyle ":prompt:grml(|-large|-chroot):*:items:$i" pre ''
2326 zstyle ":prompt:grml(|-large|-chroot):*:items:$i" post ''
2327 done
2328 unset i
2329 zstyle ':prompt:grml(|-large|-chroot):right:setup' use-rprompt false
2330elif (( EUID == 0 )); then
2331 zstyle ':prompt:grml(|-large|-chroot):*:items:user' pre '%B%F{red}'
2332fi
2333
2334# Finally enable one of the prompts.
2335if [[ -n $GRML_CHROOT ]]; then
2336 prompt grml-chroot
2337elif [[ $GRMLPROMPT -gt 0 ]]; then
2338 prompt grml-large
2339else
2340 prompt grml
2341fi
2342
2343# make sure to use right prompt only when not running a command
2344setopt transient_rprompt
2345
2346# Terminal-title wizardry
2347
2348function ESC_print () {
2349 info_print $'\ek' $'\e\\' "$@"
2350}
2351function set_title () {
2352 info_print $'\e]0;' $'\a' "$@"
2353}
2354
2355function info_print () {
2356 local esc_begin esc_end
2357 esc_begin="$1"
2358 esc_end="$2"
2359 shift 2
2360 printf '%s' ${esc_begin}
2361 printf '%s' "$*"
2362 printf '%s' "${esc_end}"
2363}
2364
2365function grml_reset_screen_title () {
2366 # adjust title of xterm
2367 # see http://www.faqs.org/docs/Linux-mini/Xterm-Title.html
2368 [[ ${NOTITLE:-} -gt 0 ]] && return 0
2369 case $TERM in
2370 (xterm*|rxvt*|alacritty|foot)
2371 set_title ${(%):-"%n@%m: %~"}
2372 ;;
2373 esac
2374}
2375
2376function grml_vcs_to_screen_title () {
2377 if [[ $TERM == screen* ]] ; then
2378 if [[ -n ${vcs_info_msg_1_} ]] ; then
2379 ESC_print ${vcs_info_msg_1_}
2380 else
2381 ESC_print "zsh"
2382 fi
2383 fi
2384}
2385
2386function grml_cmd_to_screen_title () {
2387 # get the name of the currently running program to set screen window title
2388 # if running in a screen.
2389 if [[ "$TERM" == screen* ]] ; then
2390 local CMD="${1[(wr)^(*=*|sudo|ssh|-*)]}"
2391 ESC_print ${CMD}
2392 fi
2393}
2394
2395function grml_control_xterm_title () {
2396 case $TERM in
2397 (xterm*|rxvt*|alacritty|foot)
2398 set_title "${(%):-"%n@%m:"}" "$2"
2399 ;;
2400 esac
2401}
2402
2403if [[ $NOPRECMD -eq 0 ]]; then
2404 add-zsh-hook precmd grml_reset_screen_title
2405 add-zsh-hook precmd grml_vcs_to_screen_title
2406 add-zsh-hook preexec grml_cmd_to_screen_title
2407 if [[ $NOTITLE -eq 0 ]]; then
2408 add-zsh-hook preexec grml_control_xterm_title
2409 fi
2410fi
2411
2412# 'hash' some often used directories
2413#d# start
2414hash -d deb=/var/cache/apt/archives
2415hash -d doc=/usr/share/doc
2416hash -d linux=/lib/modules/$(command uname -r)/build/
2417hash -d log=/var/log
2418hash -d slog=/var/log/syslog
2419hash -d src=/usr/src
2420hash -d www=/var/www
2421#d# end
2422
2423# some aliases
2424if check_com -c screen ; then
2425 if [[ $UID -eq 0 ]] ; then
2426 if [[ -r /etc/grml/screenrc ]]; then
2427 alias screen='screen -c /etc/grml/screenrc'
2428 fi
2429 elif [[ ! -r $HOME/.screenrc ]] ; then
2430 if [[ -r /etc/grml/screenrc_grml ]]; then
2431 alias screen='screen -c /etc/grml/screenrc_grml'
2432 else
2433 if [[ -r /etc/grml/screenrc ]]; then
2434 alias screen='screen -c /etc/grml/screenrc'
2435 fi
2436 fi
2437 fi
2438fi
2439
2440# do we have GNU ls with color-support?
2441if [[ "$TERM" != dumb ]]; then
2442 #a1# List files with colors (\kbd{ls \ldots})
2443 alias ls="command ls ${ls_options:+${ls_options[*]}}"
2444 #a1# List all files, with colors (\kbd{ls -la \ldots})
2445 alias la="command ls -la ${ls_options:+${ls_options[*]}}"
2446 #a1# List files with long colored list, without dotfiles (\kbd{ls -l \ldots})
2447 alias ll="command ls -l ${ls_options:+${ls_options[*]}}"
2448 #a1# List files with long colored list, human readable sizes (\kbd{ls -hAl \ldots})
2449 alias lh="command ls -hAl ${ls_options:+${ls_options[*]}}"
2450 #a1# List files with long colored list, append qualifier to filenames (\kbd{ls -l \ldots})\\&\quad(\kbd{/} for directories, \kbd{@} for symlinks ...)
2451 alias l="command ls -l ${ls_options:+${ls_options[*]}}"
2452else
2453 alias la='command ls -la'
2454 alias ll='command ls -l'
2455 alias lh='command ls -hAl'
2456 alias l='command ls -l'
2457fi
2458
2459# use ip from iproute2 with color support
2460if ip -color=auto addr show dev lo >/dev/null 2>&1; then
2461 alias ip='command ip -color=auto'
2462fi
2463
2464if [[ -r /proc/mdstat ]]; then
2465 alias mdstat='cat /proc/mdstat'
2466fi
2467
2468alias ...='cd ../../'
2469
2470# generate alias named "$KERNELVERSION-reboot" so you can use boot with kexec:
2471if [[ -x /sbin/kexec ]] && [[ -r /proc/cmdline ]] ; then
2472 alias "$(uname -r)-reboot"="kexec -l --initrd=/boot/initrd.img-"$(uname -r)" --command-line=\"$(cat /proc/cmdline)\" /boot/vmlinuz-"$(uname -r)""
2473fi
2474
2475#f1# Hints for the use of zsh on grml
2476function zsh-help () {
2477 print "$bg[white]$fg[black]
2478zsh-help - hints for use of zsh on grml
2479=======================================$reset_color"
2480
2481 print '
2482Main configuration of zsh happens in /etc/zsh/zshrc.
2483That file is part of the package grml-etc-core, if you want to
2484use them on a non-grml-system just get the tar.gz from
2485http://deb.grml.org/ or (preferably) get it from the git repository:
2486
2487 http://git.grml.org/f/grml-etc-core/etc/zsh/zshrc
2488
2489This version of grml'\''s zsh setup does not use skel/.zshrc anymore.
2490The file is still there, but it is empty for backwards compatibility.
2491
2492For your own changes use these two files:
2493 $HOME/.zshrc.pre
2494 $HOME/.zshrc.local
2495
2496The former is sourced very early in our zshrc, the latter is sourced
2497very lately.
2498
2499System wide configuration without touching configuration files of grml
2500can take place in /etc/zsh/zshrc.local.
2501
2502For information regarding zsh start at http://grml.org/zsh/
2503
2504Take a look at grml'\''s zsh refcard:
2505% xpdf =(zcat /usr/share/doc/grml-docs/zsh/grml-zsh-refcard.pdf.gz)
2506
2507Check out the main zsh refcard:
2508% '$BROWSER' http://www.bash2zsh.com/zsh_refcard/refcard.pdf
2509
2510And of course visit the zsh-lovers:
2511% man zsh-lovers
2512
2513You can adjust some options through environment variables when
2514invoking zsh without having to edit configuration files.
2515Basically meant for bash users who are not used to the power of
2516the zsh yet. :)
2517
2518 "NOCOR=1 zsh" => deactivate automatic correction
2519 "NOMENU=1 zsh" => do not use auto menu completion
2520 (note: use ctrl-d for completion instead!)
2521 "NOPRECMD=1 zsh" => disable the precmd + preexec commands (set GNU screen title)
2522 "NOTITLE=1 zsh" => disable setting the title of xterms without disabling
2523 preexec() and precmd() completely
2524 "GRML_DISPLAY_BATTERY=1 zsh"
2525 => activate battery status on right side of prompt (WIP)
2526 "COMMAND_NOT_FOUND=1 zsh"
2527 => Enable a handler if an external command was not found
2528 The command called in the handler can be altered by setting
2529 the GRML_ZSH_CNF_HANDLER variable, the default is:
2530 "/usr/share/command-not-found/command-not-found"
2531
2532A value greater than 0 is enables a feature; a value equal to zero
2533disables it. If you like one or the other of these settings, you can
2534add them to ~/.zshrc.pre to ensure they are set when sourcing grml'\''s
2535zshrc.'
2536
2537 print "
2538$bg[white]$fg[black]
2539Please report wishes + bugs to the grml-team: http://grml.org/bugs/
2540Enjoy your grml system with the zsh!$reset_color"
2541}
2542
2543# debian stuff
2544if [[ -r /etc/debian_version ]] ; then
2545 if [[ -z "$GRML_NO_APT_ALIASES" ]]; then
2546 #a3# Execute \kbd{apt-cache policy}
2547 alias acp='apt-cache policy'
2548 if check_com -c apt ; then
2549 #a3# Execute \kbd{apt search}
2550 alias acs='apt search'
2551 #a3# Execute \kbd{apt show}
2552 alias acsh='apt show'
2553 #a3# Execute \kbd{apt dist-upgrade}
2554 salias adg="apt dist-upgrade"
2555 #a3# Execute \kbd{apt upgrade}
2556 salias ag="apt upgrade"
2557 #a3# Execute \kbd{apt install}
2558 salias agi="apt install"
2559 #a3# Execute \kbd{apt update}
2560 salias au="apt update"
2561 else
2562 alias acs='apt-cache search'
2563 alias acsh='apt-cache show'
2564 salias adg="apt-get dist-upgrade"
2565 salias ag="apt-get upgrade"
2566 salias agi="apt-get install"
2567 salias au="apt-get update"
2568 fi
2569 if check_com -c aptitude ; then
2570 #a3# Execute \kbd{aptitude install}
2571 salias ati="aptitude install"
2572 #a3# Execute \kbd{aptitude update ; aptitude safe-upgrade}
2573 salias -a up="aptitude update ; aptitude safe-upgrade"
2574 fi
2575 if check_com -c dpkg-buildpackage ; then
2576 #a3# Execute \kbd{dpkg-buildpackage}
2577 alias dbp='dpkg-buildpackage'
2578 fi
2579 if check_com -c grep-excuses ; then
2580 #a3# Execute \kbd{grep-excuses}
2581 alias ge='grep-excuses'
2582 fi
2583 if check_com -c apt-file ; then
2584 alias afs='apt-file search'
2585 alias afl='apt-file list'
2586 fi
2587 fi
2588
2589 # get a root shell as normal user in live-cd mode:
2590 if isgrmlcd && [[ $UID -ne 0 ]] ; then
2591 alias su="sudo su"
2592 fi
2593
2594fi
2595
2596# use /var/log/syslog iff present, fallback to journalctl otherwise
2597if [ -e /var/log/syslog ] ; then
2598 #a1# Take a look at the syslog: \kbd{\$PAGER /var/log/syslog || journalctl}
2599 salias llog="$PAGER /var/log/syslog" # take a look at the syslog
2600 #a1# Take a look at the syslog: \kbd{tail -f /var/log/syslog || journalctl}
2601 salias tlog="tail --follow=name /var/log/syslog" # follow the syslog
2602elif check_com -c journalctl ; then
2603 salias llog="journalctl"
2604 salias tlog="journalctl -f"
2605fi
2606
2607# sort installed Debian-packages by size
2608if check_com -c dpkg-query ; then
2609 #a3# List installed Debian-packages sorted by size
2610 alias debs-by-size="dpkg-query -Wf 'x \${Installed-Size} \${Package} \${Status}\n' | sed -ne '/^x /d' -e '/^x \(.*\) install ok installed$/s//\1/p' | sort -nr"
2611fi
2612
2613if isgrmlcd; then
2614 # No core dumps: important for a live-cd-system
2615 limit -s core 0
2616fi
2617
2618# grmlstuff
2619function grmlstuff () {
2620 if [ -r /etc/grml_version ]; then
2621 #a1# Output version of running grml
2622 alias grml-version='cat /etc/grml_version'
2623 fi
2624
2625 if check_com -c grml-debootstrap ; then
2626 function debian2hd () {
2627 echo "Installing debian to harddisk is possible by using grml-debootstrap."
2628 return 1
2629 }
2630 fi
2631
2632 if check_com -c tmate && check_com -c qrencode ; then
2633 function grml-remote-support() {
2634 tmate -L grml-remote-support new -s grml-remote-support -d
2635 tmate -L grml-remote-support wait tmate-ready
2636 tmate -L grml-remote-support display -p '#{tmate_ssh}' | qrencode -t ANSI
2637 echo "tmate session: $(tmate -L grml-remote-support display -p '#{tmate_ssh}')"
2638 echo
2639 echo "Scan this QR code and send it to your support team."
2640 }
2641 fi
2642}
2643
2644# now run the functions
2645isgrml && grmlstuff
2646grmlcomp
2647
2648# keephack
2649xsource "/etc/zsh/keephack"
2650
2651# wonderful idea of using "e" glob qualifier by Peter Stephenson
2652# You use it as follows:
2653# $ NTREF=/reference/file
2654# $ ls -l *(e:nt:)
2655# This lists all the files in the current directory newer than the reference file.
2656# You can also specify the reference file inline; note quotes:
2657# $ ls -l *(e:'nt ~/.zshenv':)
2658function nt () {
2659 if [[ -n $1 ]] ; then
2660 local NTREF=${~1}
2661 fi
2662 [[ $REPLY -nt $NTREF ]]
2663}
2664
2665# shell functions
2666
2667#f1# Reload an autoloadable function
2668function freload () { while (( $# )); do; unfunction $1; autoload -U $1; shift; done }
2669compdef _functions freload
2670
2671#
2672# Usage:
2673#
2674# e.g.: a -> b -> c -> d ....
2675#
2676# sll a
2677#
2678#
2679# if parameter is given with leading '=', lookup $PATH for parameter and resolve that
2680#
2681# sll =java
2682#
2683# Note: limit for recursive symlinks on linux:
2684# http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/fs/namei.c?id=refs/heads/master#l808
2685# This limits recursive symlink follows to 8,
2686# while limiting consecutive symlinks to 40.
2687#
2688# When resolving and displaying information about symlinks, no check is made
2689# that the displayed information does make any sense on your OS.
2690# We leave that decission to the user.
2691#
2692# The zstat module is used to detect symlink loops.
2693# When a symlink loop is detected, a warning ist printed and further processing is stopped.
2694#
2695# Module zstat is loaded by default in grml zshrc, no extra action needed for that.
2696#
2697# Known bugs:
2698# If you happen to come across a symlink that points to a destination on another partition
2699# with the same inode number, that will be marked as symlink loop though it is not.
2700# Two hints for this situation:
2701# I) Play lottery the same day, as you seem to be rather lucky right now.
2702# II) Send patches.
2703#
2704# return status:
2705# 0 upon success
2706# 1 file/dir not accesible
2707# 2 symlink loop detected
2708#
2709#f1# List symlinks in detail (more detailed version of 'readlink -f', 'whence -s' and 'namei -l')
2710function sll () {
2711 if [[ -z ${1} ]] ; then
2712 printf 'Usage: %s <symlink(s)>\n' "${0}"
2713 return 1
2714 fi
2715
2716 local file jumpd curdir
2717 local -i 10 RTN LINODE i
2718 local -a SEENINODES
2719 curdir="${PWD}"
2720 RTN=0
2721
2722 for file in "${@}" ; do
2723 SEENINODES=()
2724 ls -l "${file:a}" || RTN=1
2725
2726 while [[ -h "$file" ]] ; do
2727 LINODE=$(zstat -L +inode "${file}")
2728 for i in ${SEENINODES} ; do
2729 if (( ${i} == ${LINODE} )) ; then
2730 builtin cd -q "${curdir}"
2731 print 'link loop detected, aborting!'
2732 return 2
2733 fi
2734 done
2735 SEENINODES+=${LINODE}
2736
2737 jumpd="${file:h}"
2738 file="${file:t}"
2739
2740 if [[ -d ${jumpd} ]] ; then
2741 builtin cd -q "${jumpd}" || RTN=1
2742 fi
2743 file=$(readlink "$file")
2744
2745 jumpd="${file:h}"
2746 file="${file:t}"
2747
2748 if [[ -d ${jumpd} ]] ; then
2749 builtin cd -q "${jumpd}" || RTN=1
2750 fi
2751
2752 ls -l "${PWD}/${file}" || RTN=1
2753 done
2754 shift 1
2755 if (( ${#} >= 1 )) ; then
2756 print ""
2757 fi
2758 builtin cd -q "${curdir}"
2759 done
2760 return ${RTN}
2761}
2762
2763if check_com -c $PAGER ; then
2764 #f3# View Debian's changelog of given package(s)
2765 function dchange () {
2766 emulate -L zsh
2767 [[ -z "$1" ]] && printf 'Usage: %s <package_name(s)>\n' "$0" && return 1
2768
2769 local package
2770
2771 # `less` as $PAGER without e.g. `|lesspipe %s` inside $LESSOPEN can't properly
2772 # read *.gz files, try to detect this to use vi instead iff available
2773 local viewer
2774
2775 if [[ ${$(typeset -p PAGER)[2]} = -a ]] ; then
2776 viewer=($PAGER) # support PAGER=(less -Mr) but leave array untouched
2777 else
2778 viewer=(${=PAGER}) # support PAGER='less -Mr'
2779 fi
2780
2781 if [[ ${viewer[1]:t} = less ]] && [[ -z "${LESSOPEN}" ]] && check_com vi ; then
2782 viewer='vi'
2783 fi
2784
2785 for package in "$@" ; do
2786 if [[ -r /usr/share/doc/${package}/changelog.Debian.gz ]] ; then
2787 $viewer /usr/share/doc/${package}/changelog.Debian.gz
2788 elif [[ -r /usr/share/doc/${package}/changelog.gz ]] ; then
2789 $viewer /usr/share/doc/${package}/changelog.gz
2790 elif [[ -r /usr/share/doc/${package}/changelog ]] ; then
2791 $viewer /usr/share/doc/${package}/changelog
2792 else
2793 if check_com -c aptitude ; then
2794 echo "No changelog for package $package found, using aptitude to retrieve it."
2795 aptitude changelog "$package"
2796 elif check_com -c apt-get ; then
2797 echo "No changelog for package $package found, using apt-get to retrieve it."
2798 apt-get changelog "$package"
2799 else
2800 echo "No changelog for package $package found, sorry."
2801 fi
2802 fi
2803 done
2804 }
2805 function _dchange () { _files -W /usr/share/doc -/ }
2806 compdef _dchange dchange
2807
2808 #f3# View Debian's NEWS of a given package
2809 function dnews () {
2810 emulate -L zsh
2811 if [[ -r /usr/share/doc/$1/NEWS.Debian.gz ]] ; then
2812 $PAGER /usr/share/doc/$1/NEWS.Debian.gz
2813 else
2814 if [[ -r /usr/share/doc/$1/NEWS.gz ]] ; then
2815 $PAGER /usr/share/doc/$1/NEWS.gz
2816 else
2817 echo "No NEWS file for package $1 found, sorry."
2818 return 1
2819 fi
2820 fi
2821 }
2822 function _dnews () { _files -W /usr/share/doc -/ }
2823 compdef _dnews dnews
2824
2825 #f3# View Debian's copyright of a given package
2826 function dcopyright () {
2827 emulate -L zsh
2828 if [[ -r /usr/share/doc/$1/copyright ]] ; then
2829 $PAGER /usr/share/doc/$1/copyright
2830 else
2831 echo "No copyright file for package $1 found, sorry."
2832 return 1
2833 fi
2834 }
2835 function _dcopyright () { _files -W /usr/share/doc -/ }
2836 compdef _dcopyright dcopyright
2837
2838 #f3# View upstream's changelog of a given package
2839 function uchange () {
2840 emulate -L zsh
2841 if [[ -r /usr/share/doc/$1/changelog.gz ]] ; then
2842 $PAGER /usr/share/doc/$1/changelog.gz
2843 else
2844 echo "No changelog for package $1 found, sorry."
2845 return 1
2846 fi
2847 }
2848 function _uchange () { _files -W /usr/share/doc -/ }
2849 compdef _uchange uchange
2850fi
2851
2852# zsh profiling
2853function profile () {
2854 ZSH_PROFILE_RC=1 zsh "$@"
2855}
2856
2857#f1# Edit an alias via zle
2858function edalias () {
2859 [[ -z "$1" ]] && { echo "Usage: edalias <alias_to_edit>" ; return 1 } || vared aliases'[$1]' ;
2860}
2861compdef _aliases edalias
2862
2863#f1# Edit a function via zle
2864function edfunc () {
2865 [[ -z "$1" ]] && { echo "Usage: edfunc <function_to_edit>" ; return 1 } || zed -f "$1" ;
2866}
2867compdef _functions edfunc
2868
2869# use it e.g. via 'Restart apache2'
2870#m# f6 Start() \kbd{service \em{process}}\quad\kbd{start}
2871#m# f6 Restart() \kbd{service \em{process}}\quad\kbd{restart}
2872#m# f6 Stop() \kbd{service \em{process}}\quad\kbd{stop}
2873#m# f6 Reload() \kbd{service \em{process}}\quad\kbd{reload}
2874#m# f6 Force-Reload() \kbd{service \em{process}}\quad\kbd{force-reload}
2875#m# f6 Status() \kbd{service \em{process}}\quad\kbd{status}
2876if [[ -d /etc/init.d ]] ; then
2877 function __start_stop () {
2878 local action_="${1:l}" # e.g Start/Stop/Restart
2879 local service_="$2"
2880 local param_="$3"
2881
2882 if check_com -c service ; then
2883 $SUDO service "$service_" "${action_}" "$param_"
2884 else
2885 $SUDO "/etc/init.d/$service_" "${action_}" "$param_"
2886 fi
2887 }
2888
2889 function _grmlinitd () {
2890 local -a scripts
2891 scripts=( /etc/init.d/*(x:t) )
2892 _describe "service startup script" scripts
2893 }
2894
2895 for i in Start Restart Stop Force-Reload Reload Status ; do
2896 eval "function $i () { __start_stop $i \"\$1\" \"\$2\" ; }"
2897 compdef _grmlinitd $i
2898 done
2899 builtin unset -v i
2900fi
2901
2902#f1# Provides useful information on globbing
2903function H-Glob () {
2904 echo -e "
2905 / directories
2906 . plain files
2907 @ symbolic links
2908 = sockets
2909 p named pipes (FIFOs)
2910 * executable plain files (0100)
2911 % device files (character or block special)
2912 %b block special files
2913 %c character special files
2914 r owner-readable files (0400)
2915 w owner-writable files (0200)
2916 x owner-executable files (0100)
2917 A group-readable files (0040)
2918 I group-writable files (0020)
2919 E group-executable files (0010)
2920 R world-readable files (0004)
2921 W world-writable files (0002)
2922 X world-executable files (0001)
2923 s setuid files (04000)
2924 S setgid files (02000)
2925 t files with the sticky bit (01000)
2926
2927 print *(m-1) # Files modified up to a day ago
2928 print *(a1) # Files accessed a day ago
2929 print *(@) # Just symlinks
2930 print *(Lk+50) # Files bigger than 50 kilobytes
2931 print *(Lk-50) # Files smaller than 50 kilobytes
2932 print **/*.c # All *.c files recursively starting in \$PWD
2933 print **/*.c~file.c # Same as above, but excluding 'file.c'
2934 print (foo|bar).* # Files starting with 'foo' or 'bar'
2935 print *~*.* # All Files that do not contain a dot
2936 chmod 644 *(.^x) # make all plain non-executable files publically readable
2937 print -l *(.c|.h) # Lists *.c and *.h
2938 print **/*(g:users:) # Recursively match all files that are owned by group 'users'
2939 echo /proc/*/cwd(:h:t:s/self//) # Analogous to >ps ax | awk '{print \$1}'<"
2940}
2941alias help-zshglob=H-Glob
2942
2943# grep for running process, like: 'any vim'
2944function any () {
2945 emulate -L zsh
2946 unsetopt KSH_ARRAYS
2947 if [[ -z "$1" ]] ; then
2948 echo "any - grep for process(es) by keyword" >&2
2949 echo "Usage: any <keyword>" >&2 ; return 1
2950 else
2951 ps xauwww | grep -i "${grep_options[@]}" "[${1[1]}]${1[2,-1]}"
2952 fi
2953}
2954
2955
2956# After resuming from suspend, system is paging heavily, leading to very bad interactivity.
2957# taken from $LINUX-KERNELSOURCE/Documentation/power/swsusp.txt
2958[[ -r /proc/1/maps ]] && \
2959function deswap () {
2960 print 'Reading /proc/[0-9]*/maps and sending output to /dev/null, this might take a while.'
2961 cat $(sed -ne 's:.* /:/:p' /proc/[0-9]*/maps | sort -u | grep -v '^/dev/') > /dev/null
2962 print 'Finished, running "swapoff -a; swapon -a" may also be useful.'
2963}
2964
2965# a wrapper for vim, that deals with title setting
2966# VIM_OPTIONS
2967# set this array to a set of options to vim you always want
2968# to have set when calling vim (in .zshrc.local), like:
2969# VIM_OPTIONS=( -p )
2970# This will cause vim to send every file given on the
2971# commandline to be send to it's own tab (needs vim7).
2972if check_com vim; then
2973 function vim () {
2974 VIM_PLEASE_SET_TITLE='yes' command vim ${VIM_OPTIONS} "$@"
2975 }
2976fi
2977
2978ssl_hashes=( sha512 sha256 sha1 md5 )
2979
2980for sh in ${ssl_hashes}; do
2981 eval 'ssl-cert-'${sh}'() {
2982 emulate -L zsh
2983 if [[ -z $1 ]] ; then
2984 printf '\''usage: %s <file>\n'\'' "ssh-cert-'${sh}'"
2985 return 1
2986 fi
2987 openssl x509 -noout -fingerprint -'${sh}' -in $1
2988 }'
2989done; unset sh
2990
2991function ssl-cert-fingerprints () {
2992 emulate -L zsh
2993 local i
2994 if [[ -z $1 ]] ; then
2995 printf 'usage: ssl-cert-fingerprints <file>\n'
2996 return 1
2997 fi
2998 for i in ${ssl_hashes}
2999 do ssl-cert-$i $1;
3000 done
3001}
3002
3003function ssl-cert-info () {
3004 emulate -L zsh
3005 if [[ -z $1 ]] ; then
3006 printf 'usage: ssl-cert-info <file>\n'
3007 return 1
3008 fi
3009 openssl x509 -noout -text -in $1
3010 ssl-cert-fingerprints $1
3011}
3012
3013# make sure our environment is clean regarding colors
3014builtin unset -v BLUE RED GREEN CYAN YELLOW MAGENTA WHITE NO_COLOR
3015
3016# "persistent history"
3017# just write important commands you always need to $GRML_IMPORTANT_COMMANDS
3018# defaults for backward compatibility to ~/.important_commands
3019if [[ -r ~/.important_commands ]] ; then
3020 GRML_IMPORTANT_COMMANDS=~/.important_commands
3021else
3022 GRML_IMPORTANT_COMMANDS=${GRML_IMPORTANT_COMMANDS:-${ZDOTDIR:-${HOME}}/.important_commands}
3023fi
3024[[ -r ${GRML_IMPORTANT_COMMANDS} ]] && builtin fc -R ${GRML_IMPORTANT_COMMANDS}
3025
3026# load the lookup subsystem if it's available on the system
3027zrcautoload lookupinit && lookupinit
3028
3029# variables
3030
3031# set terminal property (used e.g. by msgid-chooser)
3032case "${COLORTERM}" in
3033 truecolor)
3034 # do not overwrite
3035 ;;
3036 *)
3037 export COLORTERM="yes"
3038 ;;
3039esac
3040
3041# aliases
3042
3043# general
3044#a2# Execute \kbd{du -sch}
3045[[ -n "$GRML_NO_SMALL_ALIASES" ]] || alias da='du -sch'
3046
3047# listing stuff
3048#a2# Execute \kbd{ls -lSrah}
3049alias dir="command ls -lSrah"
3050#a2# Only show dot-directories
3051alias lad='command ls -d .*(/)'
3052#a2# Only show dot-files
3053alias lsa='command ls -a .*(.)'
3054#a2# Only files with setgid/setuid/sticky flag
3055alias lss='command ls -l *(s,S,t)'
3056#a2# Only show symlinks
3057alias lsl='command ls -l *(@)'
3058#a2# Display only executables
3059alias lsx='command ls -l *(*)'
3060#a2# Display world-{readable,writable,executable} files
3061alias lsw='command ls -ld *(R,W,X.^ND/)'
3062#a2# Display the ten biggest files
3063alias lsbig="command ls -flh *(.OL[1,10])"
3064#a2# Only show directories
3065alias lsd='command ls -d *(/)'
3066#a2# Only show empty directories
3067alias lse='command ls -d *(/^F)'
3068#a2# Display the ten newest files
3069alias lsnew="command ls -rtlh *(D.om[1,10])"
3070#a2# Display the ten oldest files
3071alias lsold="command ls -rtlh *(D.Om[1,10])"
3072#a2# Display the ten smallest files
3073alias lssmall="command ls -Srl *(.oL[1,10])"
3074#a2# Display the ten newest directories and ten newest .directories
3075alias lsnewdir="command ls -rthdl *(/om[1,10]) .*(D/om[1,10])"
3076#a2# Display the ten oldest directories and ten oldest .directories
3077alias lsolddir="command ls -rthdl *(/Om[1,10]) .*(D/Om[1,10])"
3078
3079# some useful aliases
3080#a2# Remove current empty directory. Execute \kbd{cd ..; rmdir \$OLDCWD}
3081alias rmcdir='cd ..; rmdir $OLDPWD || cd $OLDPWD'
3082
3083#a2# ssh with StrictHostKeyChecking=no \\&\quad and UserKnownHostsFile unset
3084alias insecssh='ssh -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null"'
3085#a2# scp with StrictHostKeyChecking=no \\&\quad and UserKnownHostsFile unset
3086alias insecscp='scp -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null"'
3087
3088#a2# lsblk (list block devices) with the most useful columns
3089alias llblk="lsblk -o +LABEL,PARTLABEL,UUID,FSTYPE,SERIAL"
3090
3091# useful functions
3092
3093#f5# Backup \kbd{file_or_folder {\rm to} file_or_folder\_timestamp}
3094function bk () {
3095 emulate -L zsh
3096 local current_date=$(date -u "+%Y%m%dT%H%M%SZ")
3097 local clean keep move verbose result all to_bk
3098 setopt extended_glob
3099 keep=1
3100 while getopts ":hacmrv" opt; do
3101 case $opt in
3102 a) (( all++ ));;
3103 c) unset move clean && (( ++keep ));;
3104 m) unset keep clean && (( ++move ));;
3105 r) unset move keep && (( ++clean ));;
3106 v) verbose="-v";;
3107 h) <<__EOF0__
3108bk [-hcmv] FILE [FILE ...]
3109bk -r [-av] [FILE [FILE ...]]
3110Backup a file or folder in place and append the timestamp
3111Remove backups of a file or folder, or all backups in the current directory
3112
3113Usage:
3114-h Display this help text
3115-c Keep the file/folder as is, create a copy backup using cp(1) (default)
3116-m Move the file/folder, using mv(1)
3117-r Remove backups of the specified file or directory, using rm(1). If none
3118 is provided, remove all backups in the current directory.
3119-a Remove all (even hidden) backups.
3120-v Verbose
3121
3122The -c, -r and -m options are mutually exclusive. If specified at the same time,
3123the last one is used.
3124
3125The return code is the sum of all cp/mv/rm return codes.
3126__EOF0__
3127return 0;;
3128 \?) bk -h >&2; return 1;;
3129 esac
3130 done
3131 shift "$((OPTIND-1))"
3132 if (( keep > 0 )); then
3133 if islinux || isfreebsd; then
3134 for to_bk in "$@"; do
3135 cp $verbose -a "${to_bk%/}" "${to_bk%/}_$current_date"
3136 (( result += $? ))
3137 done
3138 else
3139 for to_bk in "$@"; do
3140 cp $verbose -pR "${to_bk%/}" "${to_bk%/}_$current_date"
3141 (( result += $? ))
3142 done
3143 fi
3144 elif (( move > 0 )); then
3145 while (( $# > 0 )); do
3146 mv $verbose "${1%/}" "${1%/}_$current_date"
3147 (( result += $? ))
3148 shift
3149 done
3150 elif (( clean > 0 )); then
3151 if (( $# > 0 )); then
3152 for to_bk in "$@"; do
3153 rm $verbose -rf "${to_bk%/}"_[0-9](#c8)T([0-1][0-9]|2[0-3])([0-5][0-9])(#c2)Z
3154 (( result += $? ))
3155 done
3156 else
3157 if (( all > 0 )); then
3158 rm $verbose -rf *_[0-9](#c8)T([0-1][0-9]|2[0-3])([0-5][0-9])(#c2)Z(D)
3159 else
3160 rm $verbose -rf *_[0-9](#c8)T([0-1][0-9]|2[0-3])([0-5][0-9])(#c2)Z
3161 fi
3162 (( result += $? ))
3163 fi
3164 fi
3165 return $result
3166}
3167
3168#f5# cd to directory and list files
3169function cl () {
3170 emulate -L zsh
3171 cd $1 && ls -a
3172}
3173
3174# smart cd function, allows switching to /etc when running 'cd /etc/fstab'
3175function cd () {
3176 if (( ${#argv} == 1 )) && [[ -f ${1} ]]; then
3177 [[ ! -e ${1:h} ]] && return 1
3178 print "Correcting ${1} to ${1:h}"
3179 builtin cd ${1:h}
3180 else
3181 builtin cd "$@"
3182 fi
3183}
3184
3185#f5# Create Directory and \kbd{cd} to it
3186function mkcd () {
3187 if (( ARGC != 1 )); then
3188 printf 'usage: mkcd <new-directory>\n'
3189 return 1;
3190 fi
3191 if [[ ! -d "$1" ]]; then
3192 command mkdir -p "$1"
3193 else
3194 printf '`%s'\'' already exists: cd-ing.\n' "$1"
3195 fi
3196 builtin cd "$1"
3197}
3198
3199#f5# Create temporary directory and \kbd{cd} to it
3200function cdt () {
3201 local -a cdttemplate
3202 if [ "$#" -eq 1 ]; then
3203 if isfreebsd; then
3204 # mktemp(1) on FreeBSD doesn't behave the same, cf.
3205 # https://man.freebsd.org/cgi/man.cgi?query=mktemp#OPTIONS
3206 cdttemplate=(-t "$1")
3207 else
3208 cdttemplate=(-t "$1".XXXXXXX)
3209 fi
3210 fi
3211 builtin cd "$(mktemp -d ${cdttemplate[@]})"
3212 builtin pwd
3213}
3214
3215#f5# List files which have been accessed within the last {\it n} days, {\it n} defaults to 1
3216function accessed () {
3217 emulate -L zsh
3218 print -l -- *(a-${1:-1})
3219}
3220
3221#f5# List files which have been changed within the last {\it n} days, {\it n} defaults to 1
3222function changed () {
3223 emulate -L zsh
3224 print -l -- *(c-${1:-1})
3225}
3226
3227#f5# List files which have been modified within the last {\it n} days, {\it n} defaults to 1
3228function modified () {
3229 emulate -L zsh
3230 print -l -- *(m-${1:-1})
3231}
3232# modified() was named new() in earlier versions, add an alias for backwards compatibility
3233check_com new || alias new=modified
3234
3235# use colors when GNU grep with color-support
3236if (( $#grep_options > 0 )); then
3237 o=${grep_options:+"${grep_options[*]}"}
3238 #a2# Execute \kbd{grep -{}-color=auto}
3239 alias grep='grep '$o
3240 alias egrep='egrep '$o
3241 unset o
3242fi
3243
3244# Translate DE<=>EN
3245# 'translate' looks up a word in a file with language-to-language
3246# translations (field separator should be " : "). A typical wordlist looks
3247# like the following:
3248# | english-word : german-translation
3249# It's also only possible to translate english to german but not reciprocal.
3250# Use the following oneliner to reverse the sort order:
3251# $ awk -F ':' '{ print $2" : "$1" "$3 }' \
3252# /usr/local/lib/words/en-de.ISO-8859-1.vok > ~/.translate/de-en.ISO-8859-1.vok
3253#f5# Translates a word
3254if ! check_com -c trans; then
3255 function trans () {
3256 emulate -L zsh
3257 case "$1" in
3258 -[dD]*)
3259 translate -l de-en $2
3260 ;;
3261 -[eE]*)
3262 translate -l en-de $2
3263 ;;
3264 *)
3265 echo "Usage: $0 { -D | -E }"
3266 echo " -D == German to English"
3267 echo " -E == English to German"
3268 esac
3269 }
3270fi
3271
3272# Usage: simple-extract <file>
3273# Using option -d deletes the original archive file.
3274#f5# Smart archive extractor
3275function simple-extract () {
3276 emulate -L zsh
3277 setopt extended_glob noclobber
3278 local ARCHIVE DELETE_ORIGINAL DECOMP_CMD USES_STDIN USES_STDOUT GZTARGET WGET_CMD
3279 local RC=0
3280 zparseopts -D -E "d=DELETE_ORIGINAL"
3281 for ARCHIVE in "${@}"; do
3282 case $ARCHIVE in
3283 *(tar.bz2|tbz2|tbz))
3284 DECOMP_CMD="tar -xvjf -"
3285 USES_STDIN=true
3286 USES_STDOUT=false
3287 ;;
3288 *(tar.gz|tgz))
3289 DECOMP_CMD="tar -xvzf -"
3290 USES_STDIN=true
3291 USES_STDOUT=false
3292 ;;
3293 *(tar.xz|txz|tar.lzma))
3294 DECOMP_CMD="tar -xvJf -"
3295 USES_STDIN=true
3296 USES_STDOUT=false
3297 ;;
3298 *tar.zst)
3299 DECOMP_CMD="tar --zstd -xvf -"
3300 USES_STDIN=true
3301 USES_STDOUT=false
3302 ;;
3303 *tar.lrz)
3304 DECOMP_CMD="lrzuntar"
3305 USES_STDIN=false
3306 USES_STDOUT=false
3307 ;;
3308 *tar)
3309 DECOMP_CMD="tar -xvf -"
3310 USES_STDIN=true
3311 USES_STDOUT=false
3312 ;;
3313 *rar)
3314 DECOMP_CMD="unrar x"
3315 USES_STDIN=false
3316 USES_STDOUT=false
3317 ;;
3318 *lzh)
3319 DECOMP_CMD="lha x"
3320 USES_STDIN=false
3321 USES_STDOUT=false
3322 ;;
3323 *7z)
3324 DECOMP_CMD="7z x"
3325 USES_STDIN=false
3326 USES_STDOUT=false
3327 ;;
3328 *(zip|jar))
3329 DECOMP_CMD="unzip"
3330 USES_STDIN=false
3331 USES_STDOUT=false
3332 ;;
3333 *deb)
3334 DECOMP_CMD="ar -x"
3335 USES_STDIN=false
3336 USES_STDOUT=false
3337 ;;
3338 *bz2)
3339 DECOMP_CMD="bzip2 -d -c -"
3340 USES_STDIN=true
3341 USES_STDOUT=true
3342 ;;
3343 *(gz|Z))
3344 DECOMP_CMD="gzip -d -c -"
3345 USES_STDIN=true
3346 USES_STDOUT=true
3347 ;;
3348 *(xz|lzma))
3349 DECOMP_CMD="xz -d -c -"
3350 USES_STDIN=true
3351 USES_STDOUT=true
3352 ;;
3353 *zst)
3354 DECOMP_CMD="zstd -d -c -"
3355 USES_STDIN=true
3356 USES_STDOUT=true
3357 ;;
3358 *lrz)
3359 DECOMP_CMD="lrunzip -"
3360 USES_STDIN=true
3361 USES_STDOUT=true
3362 ;;
3363 *)
3364 print "ERROR: '$ARCHIVE' has unrecognized archive type." >&2
3365 RC=$((RC+1))
3366 continue
3367 ;;
3368 esac
3369
3370 if ! check_com ${DECOMP_CMD[(w)1]}; then
3371 echo "ERROR: ${DECOMP_CMD[(w)1]} not installed." >&2
3372 RC=$((RC+2))
3373 continue
3374 fi
3375
3376 GZTARGET="${ARCHIVE:t:r}"
3377 if [[ -f $ARCHIVE ]] ; then
3378
3379 print "Extracting '$ARCHIVE' ..."
3380 if $USES_STDIN; then
3381 if $USES_STDOUT; then
3382 ${=DECOMP_CMD} < "$ARCHIVE" > $GZTARGET
3383 else
3384 ${=DECOMP_CMD} < "$ARCHIVE"
3385 fi
3386 else
3387 if $USES_STDOUT; then
3388 ${=DECOMP_CMD} "$ARCHIVE" > $GZTARGET
3389 else
3390 ${=DECOMP_CMD} "$ARCHIVE"
3391 fi
3392 fi
3393 [[ $? -eq 0 && -n "$DELETE_ORIGINAL" ]] && rm -f "$ARCHIVE"
3394
3395 elif [[ "$ARCHIVE" == (#s)(https|http|ftp)://* ]] ; then
3396 if check_com curl; then
3397 WGET_CMD="curl -L -s -o -"
3398 elif check_com wget; then
3399 WGET_CMD="wget -q -O -"
3400 elif check_com fetch; then
3401 WGET_CMD="fetch -q -o -"
3402 else
3403 print "ERROR: neither wget, curl nor fetch is installed" >&2
3404 RC=$((RC+4))
3405 continue
3406 fi
3407 print "Downloading and Extracting '$ARCHIVE' ..."
3408 if $USES_STDIN; then
3409 if $USES_STDOUT; then
3410 ${=WGET_CMD} "$ARCHIVE" | ${=DECOMP_CMD} > $GZTARGET
3411 RC=$((RC+$?))
3412 else
3413 ${=WGET_CMD} "$ARCHIVE" | ${=DECOMP_CMD}
3414 RC=$((RC+$?))
3415 fi
3416 else
3417 if $USES_STDOUT; then
3418 ${=DECOMP_CMD} =(${=WGET_CMD} "$ARCHIVE") > $GZTARGET
3419 else
3420 ${=DECOMP_CMD} =(${=WGET_CMD} "$ARCHIVE")
3421 fi
3422 fi
3423
3424 else
3425 print "ERROR: '$ARCHIVE' is neither a valid file nor a supported URI." >&2
3426 RC=$((RC+8))
3427 fi
3428 done
3429 return $RC
3430}
3431
3432function __archive_or_uri () {
3433 _alternative \
3434 'files:Archives:_files -g "*.(#l)(tar.bz2|tbz2|tbz|tar.gz|tgz|tar.xz|txz|tar.lzma|tar|rar|lzh|7z|zip|jar|deb|bz2|gz|Z|xz|lzma)"' \
3435 '_urls:Remote Archives:_urls'
3436}
3437
3438function _simple_extract () {
3439 _arguments \
3440 '-d[delete original archivefile after extraction]' \
3441 '*:Archive Or Uri:__archive_or_uri'
3442}
3443compdef _simple_extract simple-extract
3444[[ -n "$GRML_NO_SMALL_ALIASES" ]] || alias se=simple-extract
3445
3446#f5# Change the xterm title from within GNU-screen
3447function xtrename () {
3448 emulate -L zsh
3449 if [[ $1 != "-f" ]] ; then
3450 if [[ -z ${DISPLAY} ]] ; then
3451 printf 'xtrename only makes sense in X11.\n'
3452 return 1
3453 fi
3454 else
3455 shift
3456 fi
3457 if [[ -z $1 ]] ; then
3458 printf 'usage: xtrename [-f] "title for xterm"\n'
3459 printf ' renames the title of xterm from _within_ screen.\n'
3460 printf ' also works without screen.\n'
3461 printf ' will not work if DISPLAY is unset, use -f to override.\n'
3462 return 0
3463 fi
3464 print -n "\eP\e]0;${1}\C-G\e\\"
3465 return 0
3466}
3467
3468#f2# Find history events by search pattern and list them by date.
3469function whatwhen () {
3470 emulate -L zsh
3471 local usage help ident format_l format_s first_char remain first last
3472 usage='USAGE: whatwhen [options] <searchstring> <search range>'
3473 help='Use `whatwhen -h'\'' for further explanations.'
3474 ident=${(l,${#${:-Usage: }},, ,)}
3475 format_l="${ident}%s\t\t\t%s\n"
3476 format_s="${format_l//(\\t)##/\\t}"
3477 # Make the first char of the word to search for case
3478 # insensitive; e.g. [aA]
3479 first_char=[${(L)1[1]}${(U)1[1]}]
3480 remain=${1[2,-1]}
3481 # Default search range is `-100'.
3482 first=${2:-\-100}
3483 # Optional, just used for `<first> <last>' given.
3484 last=$3
3485 case $1 in
3486 ("")
3487 printf '%s\n\n' 'ERROR: No search string specified. Aborting.'
3488 printf '%s\n%s\n\n' ${usage} ${help} && return 1
3489 ;;
3490 (-h)
3491 printf '%s\n\n' ${usage}
3492 print 'OPTIONS:'
3493 printf $format_l '-h' 'show help text'
3494 print '\f'
3495 print 'SEARCH RANGE:'
3496 printf $format_l "'0'" 'the whole history,'
3497 printf $format_l '-<n>' 'offset to the current history number; (default: -100)'
3498 printf $format_s '<[-]first> [<last>]' 'just searching within a give range'
3499 printf '\n%s\n' 'EXAMPLES:'
3500 printf ${format_l/(\\t)/} 'whatwhen grml' '# Range is set to -100 by default.'
3501 printf $format_l 'whatwhen zsh -250'
3502 printf $format_l 'whatwhen foo 1 99'
3503 ;;
3504 (\?)
3505 printf '%s\n%s\n\n' ${usage} ${help} && return 1
3506 ;;
3507 (*)
3508 # -l list results on stout rather than invoking $EDITOR.
3509 # -i Print dates as in YYYY-MM-DD.
3510 # -m Search for a - quoted - pattern within the history.
3511 fc -li -m "*${first_char}${remain}*" $first $last
3512 ;;
3513 esac
3514}
3515
3516# mercurial related stuff
3517if check_com -c hg ; then
3518 # gnu like diff for mercurial
3519 # http://www.selenic.com/mercurial/wiki/index.cgi/TipsAndTricks
3520 #f5# GNU like diff for mercurial
3521 function hgdi () {
3522 emulate -L zsh
3523 local i
3524 for i in $(hg status -marn "$@") ; diff -ubwd <(hg cat "$i") "$i"
3525 }
3526
3527 # execute commands on the versioned patch-queue from the current repos
3528 [[ -n "$GRML_NO_SMALL_ALIASES" ]] || alias mq='hg -R $(readlink -f $(hg root)/.hg/patches)'
3529
3530 # diffstat for specific version of a mercurial repository
3531 # hgstat => display diffstat between last revision and tip
3532 # hgstat 1234 => display diffstat between revision 1234 and tip
3533 #f5# Diffstat for specific version of a mercurial repos
3534 function hgstat () {
3535 emulate -L zsh
3536 [[ -n "$1" ]] && hg diff -r $1 -r tip | diffstat || hg export tip | diffstat
3537 }
3538
3539fi # end of check whether we have the 'hg'-executable
3540
3541# disable bracketed paste mode for dumb terminals
3542[[ "$TERM" == dumb ]] && unset zle_bracketed_paste
3543
3544# grml-small cleanups and workarounds
3545
3546# The following is used to remove zsh-config-items that do not work
3547# in grml-small by default.
3548# If you do not want these adjustments (for whatever reason), set
3549# $GRMLSMALL_SPECIFIC to 0 in your .zshrc.pre file (which this configuration
3550# sources if it is there).
3551
3552if (( GRMLSMALL_SPECIFIC > 0 )) && isgrmlsmall ; then
3553
3554 # Clean up
3555
3556 unset "abk[V]"
3557 unalias 'V' &> /dev/null
3558 unfunction vman &> /dev/null
3559 unfunction viless &> /dev/null
3560 unfunction 2html &> /dev/null
3561
3562 # manpages are not in grmlsmall
3563 unfunction manzsh &> /dev/null
3564 unfunction man2 &> /dev/null
3565
3566 # Workarounds
3567
3568 # See https://github.com/grml/grml/issues/56
3569 if ! [[ -x ${commands[dig]} ]]; then
3570 function dig_after_all () {
3571 unfunction dig
3572 unfunction _dig
3573 autoload -Uz _dig
3574 unfunction dig_after_all
3575 }
3576 function dig () {
3577 if [[ -x ${commands[dig]} ]]; then
3578 dig_after_all
3579 command dig "$@"
3580 return "$!"
3581 fi
3582 printf 'This installation does not include `dig'\'' for size reasons.\n'
3583 printf 'Try `drill'\'' as a light weight alternative.\n'
3584 return 0
3585 }
3586 function _dig () {
3587 if [[ -x ${commands[dig]} ]]; then
3588 dig_after_all
3589 zle -M 'Found `dig'\'' installed. '
3590 else
3591 zle -M 'Try `drill'\'' instead of `dig'\''.'
3592 fi
3593 }
3594 compdef _dig dig
3595 fi
3596fi
3597
3598zrclocal
3599
3600unfunction grml_status_feature
3601
3602## genrefcard.pl settings
3603
3604### doc strings for external functions from files
3605#m# f5 grml-wallpaper() Sets a wallpaper (try completion for possible values)
3606
3607### example: split functions-search 8,16,24,32
3608#@# split functions-search 8
3609
3610## END OF FILE #################################################################
3611# vim:filetype=zsh foldmethod=marker autoindent expandtab shiftwidth=4
3612# Local variables:
3613# mode: sh
3614# End:
3615
3616# History configuration
3617HISTFILE=~/.histfile
3618HISTSIZE=3000
3619SAVEHIST=5000
3620
3621# ZSH plugins (Solus)
3622source /usr/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
3623source /usr/share/zsh-autosuggestions/zsh-autosuggestions.zsh
3624
3625# Make Flatpaks accessible via the shell
3626export PATH="$PATH:/var/lib/flatpak/exports/bin"
3627
3628# Reset prompt to default
3629prompt default
3630PROMPT='%# '
3631
3632# Load Headline ZSH theme
3633source ~/.config/headline.zsh-theme
3634
3635fastfetch
3636# NOTE: Package cowsay for Solus
3637#fortune | cowsay -f tux
3638