1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
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
336
337
338
339
340
341
342
343
| | #!/bin/zsh -fi
# A zsh sticky-note ("post-it") application. Load this file as a function:
# autoload -Uz sticky-note
#
# It may then be bound as a widget:
# zle -N sticky-note
# And/or run as a command:
# sticky-note
# sticky-note -b
# sticky-note -l ...
# The -b option is like "zed -b": it installs keymaps/bindings only.
# Use the -l option to list previous sticky notes. Most options of the
# "fc -l" command are supported, for selecting which notes to display.
# If "sticky-note -l" is run from inside a widget, the cursor is moved
# to the top left of the terminal before display and returned to its
# original position after display. The -l option is implicitly added
# when sticky-note is called from zle-line-init, to avoid inadvertently
# trapping the user inside the note editor.
#
# Otherwise, invoke the line editor with the previous notes available
# as an editor history. Two quick taps on the return/enter key finish
# the note, or you can use ^X^W as usual (ZZ in vicmd mode).
# The application is configured by several zstyles, all using the context
# ":sticky-note". The complete list of styles is and their types is:
# notefile string (filename)
# maxnotes number
# history-opts array
# vared-options array
# theme associative array
# display associative array
# list-display boolean (string true|yes|on|1 or not set for false)
# The first two styles are "notefile" and "maxnotes" to name the file in
# which notes are stored and the maximum number of notes to retain:
# zstyle :sticky-note notefile ~/.zsticky
# zstyle :sticky-note maxnotes 1000
# For backwards compatibility with an earlier version, the notefile may
# also be named by the STICKYFILE variable (defaults to $HOME/.zsticky).
# The number of notes stored may be given by STICKYSIZE (1000).
# The "history-opts" style gives a list of setopt names, passed to
# "setopt localoptions ...". Note that this means you must use the "no"
# prefix to disable an option. The extendedhistory option is always used
# regardless of the setting of this style, to record note timestamps.
# Otherwise, the default is equivalent to
# zstyle :sticky-note history-opts \
# noappendhistory nobanghist histignoredups
# Values that do not contain the substring "hist" are ignored, along with:
# histlexwords histnofunctions histnostore incappendhistory sharehistory
# Useful values include:
# histexpiredupsfirst histfindnodups histignorealldups histsavenodups
# Other setopts not related to history are reset via "emulate -R zsh".
# The "vared-options" style lists options passed to vared when a note
# is edited. The vared options -A, -a, -c, -M, and -m are ignored. The
# useful options are -i, -f, -e, -p, -r, and in unusual cases -t. The
# options -p and -r should use the same syntax as the "prompt" value of
# the "theme" style, described below, and the -r option should. As a
# special case, to make the note history unavailable when editing,
# include +h in the vared-options style. Example:
# zstyle :sticky-note vared-options +h -e -r %T
# The "theme" style may be set to control the appearance of the notes.
# The style is an associative array; the current set of values (defaults
# in parens) are:
# bg => name or ANSI escape for background color (yellow)
# fg => name or ANSI escape for foreground color (black)
# color => ANSI escape for color scheme ($theme[bg]$theme[fg])
# reset => ANSI escape to restore "normal" colors
# prompt => Passed to vared. May refer to %{${theme[bg]}%} et al.
# Values given as names are looked up in the $bg and $fg arrays from the
# "colors" function. If a "color" field is set, the "bg" and "fg" fields
# are not used unless referenced in "prompt". The prompt value should
# be single-quoted and must use appropriate %{...%} wrappers around
# zero-width outputs such as color changes. Example:
# zstyle :sticky-note theme \
# bg red \
# fg $fg_bold[yellow] \
# prompt '%{$theme[bg]$fg_bold[white]%}POST-IT:%{$theme[reset]%}'
# NOTE: You must define either color or both fg and bg, but the values
# $theme[color] and $theme[reset] are always generated if omitted.
# The "display" style is an associative array mapping custom display
# attribute names to the ANSI codes to enable them. The style must use
# "%s" at the position where the note should appear, and must end with
# ANSI codes to discontinue the style. An empty value turns off the
# display formatting. For example:
# zstyle :sticky-note display \
# none "" \
# blink "$(echoti blink)%s$(echoti sgr0)" \
# reverse $'\e[07m%s\e[00m'
# If you use this style, a file named $STICKYFILE.display is created
# to preserve the display attributes of the notes in $STICKYFILE.
# NOTE: Changing the display zstyle does not change the display of
# previously created notes. There is no default display style.
# To set the display for a note, type ctrl-x question-mark (^X?) to
# run the widget "_sticky-display". When a "display" style is set, this
# replaces the _complete_help binding from the default keymap. The
# keymap named "sticky" may be modified to customize this, after running
# "sticky-note -b" to initialize.
# By default the display style is only applied when "posting" notes to
# the top of the screen via the ZLE widget, but can be applied to the
# output of "sticky-note -l" by setting the "list-display" style:
# zstyle :sticky-note list-display true
# I encourage all you creative people to contribute enhancements ...
emulate -LR zsh
typeset -gA .zsticky.display
# Set up keybindings (adapted from "zed")
if ! bindkey -M sticky >& /dev/null
then
bindkey -N sticky main
bindkey -M sticky ^X^W accept-line
bindkey -M sticky ^M^M accept-line # Two quick RETs ends note
bindkey -M sticky ^M self-insert-unmeta
fi
if ! bindkey -M sticky-vicmd >& /dev/null
then
bindkey -N sticky-vicmd vicmd
bindkey -M sticky-vicmd ZZ accept-line
fi
if ! functions _sticky-display >& /dev/null &&
zstyle -m :sticky-note display '*'
then
function _sticky-display {
if [[ -z $compstate[vared] ]]
then
local save_buffer=$BUFFER save_cursor=$CURSOR
BUFFER=
zle -U $'\t'
zle recursive-edit -K sticky-display
.zsticky.display[last]=$BUFFER
PREDISPLAY="[ $BUFFER ] "
BUFFER=$save_buffer CURSOR=$save_cursor
zle reset-prompt
else
zstyle -a :sticky-note display sticky_displays
compadd -x "Press TAB to choose display mode, ENTER to set:" \
-V nosort ${.zsticky.display[last]} \
${${(ok)sticky_displays}:#${.zsticky.display[last]}}
compstate[insert]=menu
fi
}
zle -N _sticky-display
bindkey -M sticky '^X?' _sticky-display
zle -C sticky-display-choices menu-complete _sticky-display
bindkey -N sticky-display
bindkey -M sticky-display $'\t' sticky-display-choices
bindkey -M sticky-display ^M accept-line
fi
[[ "$1" == -b ]] && return 0
setopt noflowcontrol nobanghist extendedhistory histignoredups
setopt noappendhistory nosharehistory noincappendhistory
unsetopt histlexwords histnofunctions histnostore
zmodload -i zsh/datetime
local STICKYFILE=${STICKYFILE:-$HOME/.zsticky}
local STICKYSIZE=${STICKYSIZE:-1000}
local PREDISPLAY sticky stickyfile stickysize
local -A sticky_displays vared_options
zstyle -s :sticky-note notefile stickyfile || stickyfile=$STICKYFILE
zstyle -s :sticky-note maxnotes stickysize || stickysize=$STICKYSIZE
# Populate custom history setopts
() {
local -a h0
if zstyle -a :sticky-note history-opts h0
then
h0=( ${(M)h0:#*hist*} )
h0=( ${h0:#*(extended|lexwords|nofunctions|nostore|incappend|share)*} )
setopt $h0
fi
}
# Populate options to vared
() {
local -a v0
if zstyle -a :sticky-note vared-options v0
then
v0[${v0[(i)-a]}]=()
v0[${v0[(i)-A]}]=()
v0[${v0[(i)-c]}]=()
if (( ${v0[(I)+h]} ))
then
v0[${v0[(i)-h]}]=()
v0[${v0[(i)+h]}]=()
else
v0+=(-h '')
fi
if (( ${v0[(I)-g]} ))
then
v0[${v0[(i)-g]}]=(-g '')
fi
if (( ${v0[(I)-e]} ))
then
v0[${v0[(i)-e]}]=(-e '')
fi
vared_options=( "$v0[@]" )
else
vared_options=(-h '')
fi
}
: ${vared_options[-i]:=undefined-key}
: ${vared_options[-f]:=undefined-key}
: ${vared_options[-M]::=sticky}
: ${vared_options[-m]::=sticky-vicmd}
# Look up color theme
local -A theme
(($+bg && $+fg)) || { autoload -Uz colors; colors }
zstyle -m :sticky-note theme '*' || {
zstyle :sticky-note theme bg yellow fg black
}
zstyle -a :sticky-note theme theme
(( ${+bg[$theme[bg]]} )) && theme[bg]=$bg[$theme[bg]]
(( ${+fg[$theme[fg]]} )) && theme[fg]=$fg[$theme[fg]]
(( ${+theme[color]} )) || theme[color]=$theme[bg]$theme[fg]
(( ${+theme[reset]} )) || theme[reset]=$reset_color
(( ${+theme[prompt]} )) || theme[prompt]=$vared_options[-p]
theme[prompt]="${(e)theme[prompt]}%{${theme[color]}%}"
vared_options[-p]=$theme[prompt]
# Load per-note display settings
if [[ -z ${.zsticky.display} && -r $stickyfile.display ]]
then
source $stickyfile.display
# Clean up notes expired from the STICKYFILE.
() {
local -a display_keys=(last) d0
while IFS=': ' read -A d0
do
display_keys+=( $d0[2] )
done < $stickyfile
d0=( ${(k).zsticky.display} )
set -- ${d0:|display_keys}
while [[ -n $1 ]]
do
unset ".zsticky.display[$1]"
shift
done
typeset -p 1 .zsticky.display >| $stickyfile.display
}
fi
# If invoked as a widget, behave a bit like run-help
if zle
then
zmodload -i zsh/parameter
if [[ $* == -*l* || $functrace == *zle-line-init:* ]]
then
local num stamp ceol=${ echoti el }
fc -ap $stickyfile $stickysize $stickysize
echoti cup $LINES 1
zle reset-prompt
echoti sc
echoti home
print -nr "$theme[color]"
fc -t %s -l "${@:--1}" |
while read -r num stamp sticky
do
if [[ -n ${.zsticky.display[$stamp]} ]]
then
printf -v sticky "${.zsticky.display[$stamp]}$theme[color]" $sticky
fi
printf %s\\n "$num "${sticky//$'\\n'/$ceol$'\n'}$ceol
done
print -nr "$theme[reset]"
echoti rc
elif [[ $CONTEXT = (cont|select|vared) ]]
then
zle -M "No stickies during ${${(z)PREBUFFER}[1]:-$CONTEXT}, sorry"
zle .beep
zle -R
else
zle .push-line
BUFFER=sticky-note
zle .accept-line
fi
return 0
fi
# Invoked as a command, behave like zed, but write a history file
fc -ap $stickyfile $stickysize $stickysize
# With a -l option, list the existing sticky notes
if [[ "$*" == -*l* ]]
then
local num stamp display
print -nr "$theme[color]"
# Use read/print loop to interpolate "\n" in history lines
fc -t %s "$@" |
while read -r num stamp sticky
do
if zstyle -t :sticky-note list-display &&
[[ -n ${.zsticky.display[$stamp]} ]]
then
printf -v sticky "${.zsticky.display[$stamp]}$theme[color]" $sticky
fi
print -- "${| strftime -s REPLY -n '%x %H:%M' $stamp } $sticky"
done
print -nr "$theme[reset]"
return 0
fi
# Edit a new sticky note and add it to the stickyfile
while {
vared ${(kv)vared_options} sticky
} always {
# Assure we reach "return 0" to complete fc -ap
TRY_BLOCK_INTERRUPT=0
} do
{
if [[ -n "$sticky" ]]
then
print -s -- "$sticky"
fc -W && SAVEHIST=0
# File is updated but internal "fc -l" is not yet. Get the timestamp.
stamp=${${${| local line;
while read line; do REPLY=$line; done <$stickyfile }#: }%%:*}
if [[ -n $stamp && -n ${.zsticky.display[last]} && -n $sticky_displays ]]
then
.zsticky.display[$stamp]=${sticky_displays[${.zsticky.display[last]}]}
typeset -p 1 .zsticky.display >| $stickyfile.display
fi
fi
} always {
unset sticky_displays
(( TRY_BLOCK_ERROR = 0 ))
} && break
echo -n -e '\a'
done
return 0
|