Parent directory

dirhistory.plugin.zsh

7112 bytes
  1##
  2#   Navigate directory history using ALT-LEFT and ALT-RIGHT. ALT-LEFT moves back to directories
  3#   that the user has changed to in the past, and ALT-RIGHT undoes ALT-LEFT.
  4#
  5#   Navigate directory hierarchy using ALT-UP and ALT-DOWN.
  6#   ALT-UP moves to higher hierarchy (cd ..)
  7#   ALT-DOWN moves into the first directory found in alphabetical order
  8#
  9
 10dirhistory_past=($PWD)
 11dirhistory_future=()
 12export dirhistory_past
 13export dirhistory_future
 14export DIRHISTORY_SIZE=30
 15
 16alias cde='dirhistory_cd'
 17
 18# Pop the last element of dirhistory_past.
 19# Pass the name of the variable to return the result in.
 20# Returns the element if the array was not empty,
 21# otherwise returns empty string.
 22function pop_past() {
 23  setopt localoptions no_ksh_arrays
 24  if [[ $#dirhistory_past -gt 0 ]]; then
 25    typeset -g $1="${dirhistory_past[$#dirhistory_past]}"
 26    dirhistory_past[$#dirhistory_past]=()
 27  fi
 28}
 29
 30function pop_future() {
 31  setopt localoptions no_ksh_arrays
 32  if [[ $#dirhistory_future -gt 0 ]]; then
 33    typeset -g $1="${dirhistory_future[$#dirhistory_future]}"
 34    dirhistory_future[$#dirhistory_future]=()
 35  fi
 36}
 37
 38# Push a new element onto the end of dirhistory_past. If the size of the array
 39# is >= DIRHISTORY_SIZE, the array is shifted
 40function push_past() {
 41  setopt localoptions no_ksh_arrays
 42  if [[ $#dirhistory_past -ge $DIRHISTORY_SIZE ]]; then
 43    shift dirhistory_past
 44  fi
 45  if [[ $#dirhistory_past -eq 0 || $dirhistory_past[$#dirhistory_past] != "$1" ]]; then
 46    dirhistory_past+=($1)
 47  fi
 48}
 49
 50function push_future() {
 51  setopt localoptions no_ksh_arrays
 52  if [[ $#dirhistory_future -ge $DIRHISTORY_SIZE ]]; then
 53    shift dirhistory_future
 54  fi
 55  if [[ $#dirhistory_future -eq 0 || $dirhistory_futuret[$#dirhistory_future] != "$1" ]]; then
 56    dirhistory_future+=($1)
 57  fi
 58}
 59
 60# Called by zsh when directory changes
 61autoload -U add-zsh-hook
 62add-zsh-hook chpwd chpwd_dirhistory
 63function chpwd_dirhistory() {
 64  push_past $PWD
 65  # If DIRHISTORY_CD is not set...
 66  if [[ -z "${DIRHISTORY_CD+x}" ]]; then
 67    # ... clear future.
 68    dirhistory_future=()
 69  fi
 70}
 71
 72function dirhistory_cd(){
 73  DIRHISTORY_CD="1"
 74  cd $1
 75  unset DIRHISTORY_CD
 76}
 77
 78# Move backward in directory history
 79function dirhistory_back() {
 80  local cw=""
 81  local d=""
 82  # Last element in dirhistory_past is the cwd.
 83
 84  pop_past cw
 85  if [[ "" == "$cw" ]]; then
 86    # Someone overwrote our variable. Recover it.
 87    dirhistory_past=($PWD)
 88    return
 89  fi
 90
 91  pop_past d
 92  if [[ "" != "$d" ]]; then
 93    dirhistory_cd $d
 94    push_future $cw
 95  else
 96    push_past $cw
 97  fi
 98}
 99
100
101# Move forward in directory history
102function dirhistory_forward() {
103  local d=""
104
105  pop_future d
106  if [[ "" != "$d" ]]; then
107    dirhistory_cd $d
108    push_past $d
109  fi
110}
111
112
113# Bind keys to history navigation
114function dirhistory_zle_dirhistory_back() {
115  # Erase current line in buffer
116  zle .kill-buffer
117  dirhistory_back
118  zle .accept-line
119}
120
121function dirhistory_zle_dirhistory_future() {
122  # Erase current line in buffer
123  zle .kill-buffer
124  dirhistory_forward
125  zle .accept-line
126}
127
128zle -N dirhistory_zle_dirhistory_back
129zle -N dirhistory_zle_dirhistory_future
130
131for keymap in emacs vicmd viins; do
132  # dirhistory_back
133  bindkey -M $keymap "\e[3D" dirhistory_zle_dirhistory_back    # xterm in normal mode
134  bindkey -M $keymap "\e[1;3D" dirhistory_zle_dirhistory_back  # xterm in normal mode
135  bindkey -M $keymap "\e\e[D" dirhistory_zle_dirhistory_back   # Putty
136  bindkey -M $keymap "\eO3D" dirhistory_zle_dirhistory_back    # GNU screen
137
138  case "$TERM_PROGRAM" in
139  Apple_Terminal) bindkey -M $keymap "^[b" dirhistory_zle_dirhistory_back ;; # Terminal.app
140  ghostty) bindkey -M $keymap "^[b" dirhistory_zle_dirhistory_back ;;        # ghostty
141  iTerm.app)
142    bindkey -M $keymap "^[^[[D" dirhistory_zle_dirhistory_back
143    bindkey -M $keymap "^[b" dirhistory_zle_dirhistory_back
144    ;;
145  esac
146
147  if (( ${+terminfo[kcub1]} )); then
148    bindkey -M $keymap "^[${terminfo[kcub1]}" dirhistory_zle_dirhistory_back  # urxvt
149  fi
150
151  # dirhistory_future
152  bindkey -M $keymap "\e[3C" dirhistory_zle_dirhistory_future    # xterm in normal mode
153  bindkey -M $keymap "\e[1;3C" dirhistory_zle_dirhistory_future  # xterm in normal mode
154  bindkey -M $keymap "\e\e[C" dirhistory_zle_dirhistory_future   # Putty
155  bindkey -M $keymap "\eO3C" dirhistory_zle_dirhistory_future    # GNU screen
156
157  case "$TERM_PROGRAM" in
158  Apple_Terminal) bindkey -M $keymap "^[f" dirhistory_zle_dirhistory_future ;; # Terminal.app
159  ghostty) bindkey -M $keymap "^[f" dirhistory_zle_dirhistory_future ;;        # ghostty
160  iTerm.app)
161    bindkey -M $keymap "^[^[[C" dirhistory_zle_dirhistory_future
162    bindkey -M $keymap "^[f" dirhistory_zle_dirhistory_future
163    ;;
164  esac
165
166  if (( ${+terminfo[kcuf1]} )); then
167    bindkey -M $keymap "^[${terminfo[kcuf1]}" dirhistory_zle_dirhistory_future # urxvt
168  fi
169done
170
171#
172# HIERARCHY Implemented in this section, in case someone wants to split it to another plugin if it clashes bindings
173#
174
175# Move up in hierarchy
176function dirhistory_up() {
177  cd .. || return 1
178}
179
180# Move down in hierarchy
181function dirhistory_down() {
182  cd "$(find . -mindepth 1 -maxdepth 1 -type d | sort -n | head -n 1)" || return 1
183}
184
185
186# Bind keys to hierarchy navigation
187function dirhistory_zle_dirhistory_up() {
188  zle .kill-buffer   # Erase current line in buffer
189  dirhistory_up
190  zle .accept-line
191}
192
193function dirhistory_zle_dirhistory_down() {
194  zle .kill-buffer   # Erase current line in buffer
195  dirhistory_down
196  zle .accept-line
197}
198
199zle -N dirhistory_zle_dirhistory_up
200zle -N dirhistory_zle_dirhistory_down
201
202for keymap in emacs vicmd viins; do
203  # dirhistory_up
204  bindkey -M $keymap "\e[3A" dirhistory_zle_dirhistory_up    # xterm in normal mode
205  bindkey -M $keymap "\e[1;3A" dirhistory_zle_dirhistory_up  # xterm in normal mode
206  bindkey -M $keymap "\e\e[A" dirhistory_zle_dirhistory_up   # Putty
207  bindkey -M $keymap "\eO3A" dirhistory_zle_dirhistory_up    # GNU screen
208
209  case "$TERM_PROGRAM" in
210  Apple_Terminal) bindkey -M $keymap "^[[A" dirhistory_zle_dirhistory_up ;;  # Terminal.app
211  iTerm.app) bindkey -M $keymap "^[^[[A" dirhistory_zle_dirhistory_up ;;     # iTerm2
212  ghostty) bindkey -M $keymap "^[[1;3A" dirhistory_zle_dirhistory_up ;;      # ghostty
213  esac
214
215  if (( ${+terminfo[kcuu1]} )); then
216    bindkey -M $keymap "^[${terminfo[kcuu1]}" dirhistory_zle_dirhistory_up # urxvt
217  fi
218
219  # dirhistory_down
220  bindkey -M $keymap "\e[3B" dirhistory_zle_dirhistory_down    # xterm in normal mode
221  bindkey -M $keymap "\e[1;3B" dirhistory_zle_dirhistory_down  # xterm in normal mode
222  bindkey -M $keymap "\e\e[B" dirhistory_zle_dirhistory_down   # Putty
223  bindkey -M $keymap "\eO3B" dirhistory_zle_dirhistory_down    # GNU screen
224
225  case "$TERM_PROGRAM" in
226  Apple_Terminal) bindkey -M $keymap "^[[B" dirhistory_zle_dirhistory_down ;;  # Terminal.app
227  iTerm.app) bindkey -M $keymap "^[^[[B" dirhistory_zle_dirhistory_down ;;     # iTerm2
228  ghostty) bindkey -M $keymap "^[[1;3B" dirhistory_zle_dirhistory_down ;;      # ghostty
229  esac
230
231  if (( ${+terminfo[kcud1]} )); then
232    bindkey -M $keymap "^[${terminfo[kcud1]}" dirhistory_zle_dirhistory_down # urxvt
233  fi
234done
235
236unset keymap