per-directory-history.zsh 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. #!/usr/bin/env zsh
  2. #
  3. # This is a implementation of per directory history for zsh, some
  4. # implementations of which exist in bash[1,2]. It also implements
  5. # a per-directory-history-toggle-history function to change from using the
  6. # directory history to using the global history. In both cases the history is
  7. # always saved to both the global history and the directory history, so the
  8. # toggle state will not effect the saved histories. Being able to switch
  9. # between global and directory histories on the fly is a novel feature as far
  10. # as I am aware.
  11. #
  12. #-------------------------------------------------------------------------------
  13. # Configuration
  14. #-------------------------------------------------------------------------------
  15. #
  16. # HISTORY_BASE a global variable that defines the base directory in which the
  17. # directory histories are stored
  18. #
  19. #-------------------------------------------------------------------------------
  20. # History
  21. #-------------------------------------------------------------------------------
  22. #
  23. # The idea/inspiration for a per directory history is from Stewart MacArthur[1]
  24. # and Dieter[2], the implementation idea is from Bart Schaefer on the the zsh
  25. # mailing list[3]. The implementation is by Jim Hester in September 2012.
  26. #
  27. # [1]: http://www.compbiome.com/2010/07/bash-per-directory-bash-history.html
  28. # [2]: http://dieter.plaetinck.be/per_directory_bash
  29. # [3]: http://www.zsh.org/mla/users/1997/msg00226.html
  30. #
  31. ################################################################################
  32. #
  33. # Copyright (c) 2014 Jim Hester
  34. #
  35. # This software is provided 'as-is', without any express or implied warranty.
  36. # In no event will the authors be held liable for any damages arising from the
  37. # use of this software.
  38. #
  39. # Permission is granted to anyone to use this software for any purpose,
  40. # including commercial applications, and to alter it and redistribute it
  41. # freely, subject to the following restrictions:
  42. #
  43. # 1. The origin of this software must not be misrepresented; you must not claim
  44. # that you wrote the original software. If you use this software in a product,
  45. # an acknowledgment in the product documentation would be appreciated but is
  46. # not required.
  47. #
  48. # 2. Altered source versions must be plainly marked as such, and must not be
  49. # misrepresented as being the original software.
  50. #
  51. # 3. This notice may not be removed or altered from any source distribution..
  52. #
  53. ################################################################################
  54. #-------------------------------------------------------------------------------
  55. # configuration, the base under which the directory histories are stored
  56. #-------------------------------------------------------------------------------
  57. [[ -z $HISTORY_BASE ]] && HISTORY_BASE="$HOME/.directory_history"
  58. [[ -z $HISTORY_START_WITH_GLOBAL ]] && HISTORY_START_WITH_GLOBAL=false
  59. [[ -z $PER_DIRECTORY_HISTORY_TOGGLE ]] && PER_DIRECTORY_HISTORY_TOGGLE='^G'
  60. [[ -z $PER_DIRECTORY_HISTORY_PRINT_MODE_CHANGE ]] && PER_DIRECTORY_HISTORY_PRINT_MODE_CHANGE=true
  61. #-------------------------------------------------------------------------------
  62. # toggle global/directory history used for searching - ctrl-G by default
  63. #-------------------------------------------------------------------------------
  64. function per-directory-history-toggle-history() {
  65. if [[ $_per_directory_history_is_global == true ]]; then
  66. _per-directory-history-set-directory-history
  67. _per_directory_history_is_global=false
  68. if [[ $PER_DIRECTORY_HISTORY_PRINT_MODE_CHANGE == true ]]; then
  69. zle -M "using local history"
  70. fi
  71. else
  72. _per-directory-history-set-global-history
  73. _per_directory_history_is_global=true
  74. if [[ $PER_DIRECTORY_HISTORY_PRINT_MODE_CHANGE == true ]]; then
  75. zle -M "using global history"
  76. fi
  77. fi
  78. }
  79. autoload per-directory-history-toggle-history
  80. zle -N per-directory-history-toggle-history
  81. bindkey $PER_DIRECTORY_HISTORY_TOGGLE per-directory-history-toggle-history
  82. bindkey -M vicmd $PER_DIRECTORY_HISTORY_TOGGLE per-directory-history-toggle-history
  83. #-------------------------------------------------------------------------------
  84. # implementation details
  85. #-------------------------------------------------------------------------------
  86. _per_directory_history_directory="$HISTORY_BASE${PWD:A}/history"
  87. function _per-directory-history-change-directory() {
  88. _per_directory_history_directory="$HISTORY_BASE${PWD:A}/history"
  89. mkdir -p ${_per_directory_history_directory:h}
  90. if [[ $_per_directory_history_is_global == false ]]; then
  91. #save to the global history
  92. fc -AI $HISTFILE
  93. #save history to previous file
  94. local prev="$HISTORY_BASE${OLDPWD:A}/history"
  95. mkdir -p ${prev:h}
  96. fc -AI $prev
  97. #discard previous directory's history
  98. local original_histsize=$HISTSIZE
  99. HISTSIZE=0
  100. HISTSIZE=$original_histsize
  101. #read history in new file
  102. if [[ -e $_per_directory_history_directory ]]; then
  103. fc -R $_per_directory_history_directory
  104. fi
  105. fi
  106. }
  107. function _per-directory-history-addhistory() {
  108. # respect hist_ignore_space
  109. if [[ -o hist_ignore_space ]] && [[ "$1" == \ * ]]; then
  110. true
  111. else
  112. print -Sr -- "${1%%$'\n'}"
  113. # instantly write history if set options require it.
  114. if [[ -o share_history ]] || \
  115. [[ -o inc_append_history ]] || \
  116. [[ -o inc_append_history_time ]]; then
  117. fc -AI $HISTFILE
  118. fc -AI $_per_directory_history_directory
  119. fi
  120. fc -p $_per_directory_history_directory
  121. fi
  122. }
  123. function _per-directory-history-precmd() {
  124. if [[ $_per_directory_history_initialized == false ]]; then
  125. _per_directory_history_initialized=true
  126. if [[ $HISTORY_START_WITH_GLOBAL == true ]]; then
  127. _per-directory-history-set-global-history
  128. _per_directory_history_is_global=true
  129. else
  130. _per-directory-history-set-directory-history
  131. _per_directory_history_is_global=false
  132. fi
  133. fi
  134. }
  135. function _per-directory-history-set-directory-history() {
  136. fc -AI $HISTFILE
  137. local original_histsize=$HISTSIZE
  138. HISTSIZE=0
  139. HISTSIZE=$original_histsize
  140. if [[ -e "$_per_directory_history_directory" ]]; then
  141. fc -R "$_per_directory_history_directory"
  142. fi
  143. }
  144. function _per-directory-history-set-global-history() {
  145. fc -AI $_per_directory_history_directory
  146. local original_histsize=$HISTSIZE
  147. HISTSIZE=0
  148. HISTSIZE=$original_histsize
  149. if [[ -e "$HISTFILE" ]]; then
  150. fc -R "$HISTFILE"
  151. fi
  152. }
  153. mkdir -p ${_per_directory_history_directory:h}
  154. #add functions to the exec list for chpwd and zshaddhistory
  155. autoload -U add-zsh-hook
  156. add-zsh-hook chpwd _per-directory-history-change-directory
  157. add-zsh-hook zshaddhistory _per-directory-history-addhistory
  158. add-zsh-hook precmd _per-directory-history-precmd
  159. # set initialized flag to false
  160. _per_directory_history_initialized=false