Blame view

repos/robbyrussell/oh-my-zsh/plugins/zsh-navigation-tools/n-history 12.2 KB
7378b55de   mj   Squashed 'repos/r...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  # Copy this file into /usr/share/zsh/site-functions/
  # and add 'autoload n-history` to .zshrc
  #
  # This function allows to browse Z shell's history and use the
  # entries
  #
  # Uses n-list
  
  emulate -L zsh
  
  setopt extendedglob
  zmodload zsh/curses
  zmodload zsh/parameter
  
  local IFS="
  "
d9bebbb3c   mj   Squashed 'repos/r...
17
18
19
20
21
22
23
24
25
26
27
28
29
  # Variables to save list's state when switching views
  # The views are: history and "most frequent history words"
  local one_NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN
  local one_NLIST_CURRENT_IDX
  local one_NLIST_IS_SEARCH_MODE
  local one_NLIST_SEARCH_BUFFER
  local one_NLIST_TEXT_OFFSET
  local one_NLIST_IS_UNIQ_MODE
  local one_NLIST_IS_F_MODE
  local one_NLIST_GREP_STRING
  local one_NLIST_NONSELECTABLE_ELEMENTS
  local one_NLIST_REMEMBER_STATE
  local one_NLIST_ENABLED_EVENTS
7378b55de   mj   Squashed 'repos/r...
30

d9bebbb3c   mj   Squashed 'repos/r...
31
32
33
34
35
36
37
38
39
40
41
  local two_NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN
  local two_NLIST_CURRENT_IDX
  local two_NLIST_IS_SEARCH_MODE
  local two_NLIST_SEARCH_BUFFER
  local two_NLIST_TEXT_OFFSET
  local two_NLIST_IS_UNIQ_MODE
  local two_NLIST_IS_F_MODE
  local two_NLIST_GREP_STRING
  local two_NLIST_NONSELECTABLE_ELEMENTS
  local two_NLIST_REMEMBER_STATE
  local two_NLIST_ENABLED_EVENTS
7378b55de   mj   Squashed 'repos/r...
42

d9bebbb3c   mj   Squashed 'repos/r...
43
44
45
46
47
48
49
50
51
52
53
  local three_NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN
  local three_NLIST_CURRENT_IDX
  local three_NLIST_IS_SEARCH_MODE
  local three_NLIST_SEARCH_BUFFER
  local three_NLIST_TEXT_OFFSET
  local three_NLIST_IS_UNIQ_MODE
  local three_NLIST_IS_F_MODE
  local three_NLIST_GREP_STRING
  local three_NLIST_NONSELECTABLE_ELEMENTS
  local three_NLIST_REMEMBER_STATE
  local three_NLIST_ENABLED_EVENTS
7378b55de   mj   Squashed 'repos/r...
54

d9bebbb3c   mj   Squashed 'repos/r...
55
56
  # history view
  integer active_view=0
7378b55de   mj   Squashed 'repos/r...
57

d9bebbb3c   mj   Squashed 'repos/r...
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
  # Lists are "0", "1", "2" - 1st, 2nd, 3rd
  # Switching is done in cyclic manner
  # i.e. 0 -> 1, 1 -> 2, 2 -> 0
  _nhistory_switch_lists_states() {
      # First argument is current, newly selected list, i.e. $active_view
      # This implies that we are switching from previous view
     
      if [ "$1" = "0" ]; then
          # Switched to 1st list, save 3rd list's state
          three_NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN=$NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN
          three_NLIST_CURRENT_IDX=$NLIST_CURRENT_IDX
          three_NLIST_IS_SEARCH_MODE=$NLIST_IS_SEARCH_MODE
          three_NLIST_SEARCH_BUFFER=$NLIST_SEARCH_BUFFER
          three_NLIST_TEXT_OFFSET=$NLIST_TEXT_OFFSET
          three_NLIST_IS_UNIQ_MODE=$NLIST_IS_UNIQ_MODE
          three_NLIST_IS_F_MODE=$NLIST_IS_F_MODE
          three_NLIST_GREP_STRING=$NLIST_GREP_STRING
          three_NLIST_NONSELECTABLE_ELEMENTS=( ${NLIST_NONSELECTABLE_ELEMENTS[@]} )
          three_NLIST_REMEMBER_STATE=$NLIST_REMEMBER_STATE
          three_NLIST_ENABLED_EVENTS=( ${NLIST_ENABLED_EVENTS[@]} )
7378b55de   mj   Squashed 'repos/r...
78

d9bebbb3c   mj   Squashed 'repos/r...
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
          # ..and restore 1st list's state
          NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN=$one_NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN
          NLIST_CURRENT_IDX=$one_NLIST_CURRENT_IDX
          NLIST_IS_SEARCH_MODE=$one_NLIST_IS_SEARCH_MODE
          NLIST_SEARCH_BUFFER=$one_NLIST_SEARCH_BUFFER
          NLIST_TEXT_OFFSET=$one_NLIST_TEXT_OFFSET
          NLIST_IS_UNIQ_MODE=$one_NLIST_IS_UNIQ_MODE
          NLIST_IS_F_MODE=$one_NLIST_IS_F_MODE
          NLIST_GREP_STRING=$one_NLIST_GREP_STRING
          NLIST_NONSELECTABLE_ELEMENTS=( ${one_NLIST_NONSELECTABLE_ELEMENTS[@]} )
          NLIST_REMEMBER_STATE=$one_NLIST_REMEMBER_STATE
          NLIST_ENABLED_EVENTS=( ${one_NLIST_ENABLED_EVENTS[@]} )
      elif [ "$1" = "1" ]; then
          # Switched to 2nd list, save 1st list's state
          one_NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN=$NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN
          one_NLIST_CURRENT_IDX=$NLIST_CURRENT_IDX
          one_NLIST_IS_SEARCH_MODE=$NLIST_IS_SEARCH_MODE
          one_NLIST_SEARCH_BUFFER=$NLIST_SEARCH_BUFFER
          one_NLIST_TEXT_OFFSET=$NLIST_TEXT_OFFSET
          one_NLIST_IS_UNIQ_MODE=$NLIST_IS_UNIQ_MODE
          one_NLIST_IS_F_MODE=$NLIST_IS_F_MODE
          one_NLIST_GREP_STRING=$NLIST_GREP_STRING
          one_NLIST_NONSELECTABLE_ELEMENTS=( ${NLIST_NONSELECTABLE_ELEMENTS[@]} )
          one_NLIST_REMEMBER_STATE=$NLIST_REMEMBER_STATE
          one_NLIST_ENABLED_EVENTS=( ${NLIST_ENABLED_EVENTS[@]} )
  
          # ..and restore 2nd list's state
          NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN=$two_NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN
          NLIST_CURRENT_IDX=$two_NLIST_CURRENT_IDX
          NLIST_IS_SEARCH_MODE=$two_NLIST_IS_SEARCH_MODE
          NLIST_SEARCH_BUFFER=$two_NLIST_SEARCH_BUFFER
          NLIST_TEXT_OFFSET=$two_NLIST_TEXT_OFFSET
          NLIST_IS_UNIQ_MODE=$two_NLIST_IS_UNIQ_MODE
          NLIST_IS_F_MODE=$two_NLIST_IS_F_MODE
          NLIST_GREP_STRING=$two_NLIST_GREP_STRING
          NLIST_NONSELECTABLE_ELEMENTS=( ${two_NLIST_NONSELECTABLE_ELEMENTS[@]} )
          NLIST_REMEMBER_STATE=$two_NLIST_REMEMBER_STATE
          NLIST_ENABLED_EVENTS=( ${two_NLIST_ENABLED_EVENTS[@]} )
      elif [ "$1" = "2" ]; then
          # Switched to 3rd list, save 2nd list's state
          two_NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN=$NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN
          two_NLIST_CURRENT_IDX=$NLIST_CURRENT_IDX
          two_NLIST_IS_SEARCH_MODE=$NLIST_IS_SEARCH_MODE
          two_NLIST_SEARCH_BUFFER=$NLIST_SEARCH_BUFFER
          two_NLIST_TEXT_OFFSET=$NLIST_TEXT_OFFSET
          two_NLIST_IS_UNIQ_MODE=$NLIST_IS_UNIQ_MODE
          two_NLIST_IS_F_MODE=$NLIST_IS_F_MODE
          two_NLIST_GREP_STRING=$NLIST_GREP_STRING
          two_NLIST_NONSELECTABLE_ELEMENTS=( ${NLIST_NONSELECTABLE_ELEMENTS[@]} )
          two_NLIST_REMEMBER_STATE=$NLIST_REMEMBER_STATE
          two_NLIST_ENABLED_EVENTS=( ${NLIST_ENABLED_EVENTS[@]} )
  
          # ..and restore 3rd list's state
          NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN=$three_NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN
          NLIST_CURRENT_IDX=$three_NLIST_CURRENT_IDX
          NLIST_IS_SEARCH_MODE=$three_NLIST_IS_SEARCH_MODE
          NLIST_SEARCH_BUFFER=$three_NLIST_SEARCH_BUFFER
          NLIST_TEXT_OFFSET=$three_NLIST_TEXT_OFFSET
          NLIST_IS_UNIQ_MODE=$three_NLIST_IS_UNIQ_MODE
          NLIST_IS_F_MODE=$three_NLIST_IS_F_MODE
          NLIST_GREP_STRING=$three_NLIST_GREP_STRING
          NLIST_NONSELECTABLE_ELEMENTS=( ${three_NLIST_NONSELECTABLE_ELEMENTS[@]} )
          NLIST_REMEMBER_STATE=$three_NLIST_REMEMBER_STATE
          NLIST_ENABLED_EVENTS=( ${three_NLIST_ENABLED_EVENTS[@]} )
      fi
  }
  
  local most_frequent_db="$HOME/.config/znt/mostfrequent.db"
  _nhistory_generate_most_frequent() {
      local title=$'\x1b[00;31m'"Most frequent history words:"$'\x1b[00;00m\0'
  
      typeset -A uniq
      for k in "${historywords[@]}"; do
          uniq[$k]=$(( ${uniq[$k]:-0} + 1 ))
      done
      vk=()
      for k v in ${(kv)uniq}; do
          vk+="$v"$'\t'"$k"
      done
  
      print -rl -- "$title" "${(On)vk[@]}" > "$most_frequent_db"
  }
  
  # Load configuration
  unset NLIST_COLORING_PATTERN
  [ -f ~/.config/znt/n-list.conf ] && builtin source ~/.config/znt/n-list.conf
  [ -f ~/.config/znt/n-history.conf ] && builtin source ~/.config/znt/n-history.conf
  
  local list
  local selected
  local private_history_db="$HOME/.config/znt/privhist.db"
7378b55de   mj   Squashed 'repos/r...
170
171
  
  local NLIST_GREP_STRING="$1"
d9bebbb3c   mj   Squashed 'repos/r...
172
173
174
175
176
177
178
179
180
181
182
183
  # 2 is: init once, then remember
  local NLIST_REMEMBER_STATE=2
  two_NLIST_REMEMBER_STATE=2
  three_NLIST_REMEMBER_STATE=2
  
  # Only Private history has EDIT
  local -a NLIST_ENABLED_EVENTS
  NLIST_ENABLED_EVENTS=( "F1" "HELP" )
  two_NLIST_ENABLED_EVENTS=( "F1" "EDIT" "HELP" )
  three_NLIST_ENABLED_EVENTS=( "F1" "HELP" )
  
  # All view should attempt to replace new lines with 
7378b55de   mj   Squashed 'repos/r...
184
  local NLIST_REPLACE_NEWLINES="1"
d9bebbb3c   mj   Squashed 'repos/r...
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
  two_NLIST_REPLACE_NEWLINES="1"
  three_NLIST_REPLACE_NEWLINES="1"
  
  # Only second and third view has non-selectable first entry
  local -a NLIST_NONSELECTABLE_ELEMENTS
  NLIST_NONSELECTABLE_ELEMENTS=( )
  two_NLIST_NONSELECTABLE_ELEMENTS=( 1 )
  three_NLIST_NONSELECTABLE_ELEMENTS=( 1 )
  
  while (( 1 )); do
  
      #
      # View 1 - history
      #
      if [ "$active_view" = "0" ]; then
          list=( "$history[@]" )
          list=( "${(@M)list:#(#i)*$NLIST_GREP_STRING*}" )
  
          if [ "$#list" -eq 0 ]; then
              echo "No matching history entries"
              return 1
          fi
  
          n-list "${list[@]}"
  
          # Selection or quit?
          if [[ "$REPLY" = -(#c0,1)[0-9]## && ("$REPLY" -lt 0 || "$REPLY" -gt 0) ]]; then
              break
          fi
  
          # View change?
          if [ "$REPLY" = "F1" ]; then
              # Target view: 2
              active_view=1
              _nhistory_switch_lists_states "1"
          elif [ "$REPLY" = "HELP" ]; then
              n-help
          fi
  
      #
      # View 3 - most frequent words in history
      #
      elif [ "$active_view" = "2" ]; then
          local -a dbfile
          dbfile=( $most_frequent_db(Nm+1) )
  
          # Compute most frequent history words
          if [[ "${#NHISTORY_WORDS}" -eq "0" || "${#dbfile}" -ne "0" ]]; then
              # Read the list if it's there
              local -a list
              list=()
              [ -s "$most_frequent_db" ] && list=( ${(f)"$(<$most_frequent_db)"} )
  
              # Will wait for the data?
              local message=0
              if [[ "${#list}" -eq 0 ]]; then
                  message=1
                  _nlist_alternate_screen 1
                  zcurses init
                  zcurses delwin info 2>/dev/null
                  zcurses addwin info "$term_height" "$term_width" 0 0
                  zcurses bg info white/black
                  zcurses string info "Computing most frequent history words..."$'
  '
                  zcurses string info "(This is done once per day, from now on transparently)"$'
  '
                  zcurses refresh info
                  sleep 3
              fi
  
              # Start periodic list regeneration?
              if [[ "${#list}" -eq 0 || "${#dbfile}" -ne "0" ]]; then
                  # Mark the file with current time, to prevent double
                  # regeneration (on quick double change of view)
                  print >> "$most_frequent_db"
                  (_nhistory_generate_most_frequent &) &> /dev/null
              fi
  
              # Ensure we got the list, wait for it if needed
              while [[ "${#list}" -eq 0 ]]; do
                  zcurses string info "."
                  zcurses refresh info
                  LANG=C sleep 0.5
                  [ -s "$most_frequent_db" ] && list=( ${(f)"$(<$most_frequent_db)"} )
              done
  
              NHISTORY_WORDS=( "${list[@]}" )
  
              if [ "$message" -eq "1" ]; then
                  zcurses delwin info 2>/dev/null
                  zcurses refresh
                  zcurses end
                  _nlist_alternate_screen 0
              fi
          else
              # Reuse most frequent history words
              local -a list
              list=( "${NHISTORY_WORDS[@]}" )
          fi
  
          n-list "${list[@]}"
  
          if [ "$REPLY" = "F1" ]; then
              # Target view: 1
              active_view=0
              _nhistory_switch_lists_states "0"
          elif [[ "$REPLY" = -(#c0,1)[0-9]## && "$REPLY" -lt 0 ]]; then
              break
          elif [[ "$REPLY" = -(#c0,1)[0-9]## && "$REPLY" -gt 0 ]]; then
              local word="${reply[REPLY]#(#s) #[0-9]##$'\t'}"
              one_NLIST_SEARCH_BUFFER="$word"
              one_NLIST_SEARCH_BUFFER="${one_NLIST_SEARCH_BUFFER## ##}"
  
              # Target view: 1
              active_view=0
              _nhistory_switch_lists_states "0"
          elif [ "$REPLY" = "HELP" ]; then
              n-help
          fi
  
      #
      # View 2 - private history
      #
      elif [ "$active_view" = "1" ]; then
          if [ -s "$private_history_db" ]; then
              local title=$'\x1b[00;32m'"Private history:"$'\x1b[00;00m\0'
              () { fc -ap -R "$private_history_db"; list=( "$title" ${history[@]} ) }
          else
              list=( "Private history - history entries selected via this tool will be put here" )
          fi
  
          n-list "${list[@]}"
  
          # Selection or quit?
          if [[ "$REPLY" = -(#c0,1)[0-9]## && ("$REPLY" -lt 0 || "$REPLY" -gt 0) ]]; then
              break
          fi
  
          # View change?
          if [ "$REPLY" = "F1" ]; then
              # Target view: 3
              active_view=2
              _nhistory_switch_lists_states "2"
          # Edit of the history?
          elif [ "$REPLY" = "EDIT" ]; then
              "${EDITOR:-vim}" "$private_history_db"
          elif [ "$REPLY" = "HELP" ]; then
              n-help
          fi
      fi
  done
7378b55de   mj   Squashed 'repos/r...
336
337
338
339
340
  
  if [ "$REPLY" -gt 0 ]; then
      selected="$reply[REPLY]"
      # ZLE?
      if [ "${(t)CURSOR}" = "integer-local-special" ]; then
d9bebbb3c   mj   Squashed 'repos/r...
341
342
343
344
345
346
347
348
349
          zle .redisplay
          zle .kill-buffer
          LBUFFER+="$selected"
  
          # Append to private history
          local newline=$'
  '
          selected="${selected//$newline/\\$newline}"
          [ "$active_view" = "0" ] && print -r -- "$selected" >> "$private_history_db"
7378b55de   mj   Squashed 'repos/r...
350
      else
d9bebbb3c   mj   Squashed 'repos/r...
351
          print -zr -- "$selected"
7378b55de   mj   Squashed 'repos/r...
352
353
354
355
356
357
      fi
  else
      [ "${(t)CURSOR}" = "integer-local-special" ] && zle redisplay
  fi
  
  # vim: set filetype=zsh: