Parent directory

per-directory-history.zsh

6984 bytes
  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 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#-------------------------------------------------------------------------------
 56# configuration, the base under which the directory histories are stored
 57#-------------------------------------------------------------------------------
 58
 59[[ -z $HISTORY_BASE ]] && HISTORY_BASE="$HOME/.directory_history"
 60[[ -z $HISTORY_START_WITH_GLOBAL ]] && HISTORY_START_WITH_GLOBAL=false
 61[[ -z $PER_DIRECTORY_HISTORY_TOGGLE ]] && PER_DIRECTORY_HISTORY_TOGGLE='^G'
 62[[ -z $PER_DIRECTORY_HISTORY_PRINT_MODE_CHANGE ]] && PER_DIRECTORY_HISTORY_PRINT_MODE_CHANGE=true
 63
 64#-------------------------------------------------------------------------------
 65# toggle global/directory history used for searching - ctrl-G by default
 66#-------------------------------------------------------------------------------
 67
 68function per-directory-history-toggle-history() {
 69  if [[ $_per_directory_history_is_global == true ]]; then
 70    _per-directory-history-set-directory-history
 71    _per_directory_history_is_global=false
 72    if [[ $PER_DIRECTORY_HISTORY_PRINT_MODE_CHANGE == true ]]; then
 73      zle -M "using local history"
 74    fi
 75  else
 76    _per-directory-history-set-global-history
 77    _per_directory_history_is_global=true
 78    if [[ $PER_DIRECTORY_HISTORY_PRINT_MODE_CHANGE == true ]]; then
 79      zle -M "using global history"
 80    fi
 81  fi
 82}
 83
 84autoload per-directory-history-toggle-history
 85zle -N per-directory-history-toggle-history
 86bindkey $PER_DIRECTORY_HISTORY_TOGGLE per-directory-history-toggle-history
 87bindkey -M vicmd $PER_DIRECTORY_HISTORY_TOGGLE per-directory-history-toggle-history
 88
 89#-------------------------------------------------------------------------------
 90# implementation details
 91#-------------------------------------------------------------------------------
 92
 93_per_directory_history_directory="$HISTORY_BASE${PWD:A}/history"
 94_per_directory_history_global="$HISTFILE"
 95
 96function _per-directory-history-change-directory() {
 97  _per_directory_history_directory="$HISTORY_BASE${PWD:A}/history"
 98  mkdir -p ${_per_directory_history_directory:h}
 99  if [[ $_per_directory_history_is_global == false ]]; then
100    #save to the global history
101    fc -AI "$_per_directory_history_global"
102    #save history to previous file
103    local prev="$HISTORY_BASE${OLDPWD:A}/history"
104    mkdir -p ${prev:h}
105    fc -AI $prev
106
107    #discard previous directory's history
108    local original_histsize=$HISTSIZE
109    HISTSIZE=0
110    HISTSIZE=$original_histsize
111
112    #read history in new file
113    if [[ -e $_per_directory_history_directory ]]; then
114      fc -R $_per_directory_history_directory
115    fi
116  fi
117}
118
119function _per-directory-history-addhistory() {
120  # respect hist_ignore_space
121  if [[ -o hist_ignore_space ]] && [[ "$1" == \ * ]]; then
122      true
123  else
124      print -Sr -- "${1%%$'\n'}"
125      # instantly write history if set options require it.
126      if [[ -o share_history ]] || \
127         [[ -o inc_append_history ]] || \
128         [[ -o inc_append_history_time ]]; then
129          fc -AI "$_per_directory_history_global"
130          fc -AI $_per_directory_history_directory
131      fi
132  fi
133}
134
135function _per-directory-history-precmd() {
136  if [[ $_per_directory_history_initialized == false ]]; then
137    _per_directory_history_initialized=true
138
139    if [[ $HISTORY_START_WITH_GLOBAL == true ]]; then
140      _per-directory-history-set-global-history
141      _per_directory_history_is_global=true
142    else
143      _per-directory-history-set-directory-history
144      _per_directory_history_is_global=false
145    fi
146  fi
147}
148
149function _per-directory-history-set-directory-history() {
150  fc -AI "$_per_directory_history_global"
151  local original_histsize=$HISTSIZE
152  HISTSIZE=0
153  HISTSIZE=$original_histsize
154  if [[ -e "$_per_directory_history_directory" ]]; then
155    fc -R "$_per_directory_history_directory"
156    fc -p "$_per_directory_history_directory"
157  fi
158}
159
160function _per-directory-history-set-global-history() {
161  fc -AI $_per_directory_history_directory
162  local original_histsize=$HISTSIZE
163  HISTSIZE=0
164  HISTSIZE=$original_histsize
165  if [[ -e "$_per_directory_history_global" ]]; then
166    fc -R "$_per_directory_history_global"
167    fc -p "$_per_directory_history_global"
168  fi
169}
170
171mkdir -p ${_per_directory_history_directory:h}
172
173#add functions to the exec list for chpwd and zshaddhistory
174autoload -U add-zsh-hook
175add-zsh-hook chpwd _per-directory-history-change-directory
176add-zsh-hook zshaddhistory _per-directory-history-addhistory
177add-zsh-hook precmd _per-directory-history-precmd
178
179# set initialized flag to false
180_per_directory_history_initialized=false