From: Bart Schaefer <schaefer@brasslantern.com>
To: Zsh Hackers List <zsh-workers@zsh.org>
Cc: vapnik spaknik <vapniks@yahoo.com>
Subject: Re: Suggested improvement for sticky-note
Date: Sat, 18 Nov 2023 21:25:19 -0800 [thread overview]
Message-ID: <CAH+w=7bbeg=XEQyNiaC_UwW=z1a8F0ERm-Mtzo_npbAhUKgnfg@mail.gmail.com> (raw)
In-Reply-To: <CAH+w=7ZRvCU1Uog_38D=CH7xTGYy1Lnuq4ORR0Oz77psZZAmag@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 899 bytes --]
On Sun, Nov 12, 2023 at 1:10 PM Bart Schaefer <schaefer@brasslantern.com> wrote:
>
> I'm sure there are undiscovered bugs with this, so mess around if interested.
>
> > That also caused me to notice that interrupting
> > sticky-note with a keyboard interrupt (^C) can cause old notes to
> > disappear, so that should be fixed.
I solved this. It turns out that "fc -ap" removes events from the
history file if the enclosing function exits on interrupt. This is
probably a bug of some sort, but easily worked around by addition of
an "always" block that clears the interrupt state.
> Also yet to be fixed is expiring
> lines from the display file when the corresponding lines expire from
> the history.
Fixed this too.
The attached revision also adds a "history-opts" style for changing
the localoptions used e.g. when navigating past notes and rewriting
the stickyfile.
[-- Attachment #2: sticky-note --]
[-- Type: application/octet-stream, Size: 11851 bytes --]
#!/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
prev parent reply other threads:[~2023-11-19 5:25 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <1185563186.165566.1619896723304.ref@mail.yahoo.com>
2021-05-01 19:18 ` vapnik spaknik
2021-05-02 23:57 ` Bart Schaefer
2021-05-04 2:06 ` vapnik spaknik
2021-05-09 20:50 ` Bart Schaefer
2021-05-11 10:18 ` Mikael Magnusson
2021-05-14 23:40 ` Termcap and boldface (was sticky-note) Bart Schaefer
2021-05-11 12:37 ` Suggested improvement for sticky-note vapnik spaknik
2023-11-12 21:10 ` Bart Schaefer
2023-11-19 5:25 ` Bart Schaefer [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAH+w=7bbeg=XEQyNiaC_UwW=z1a8F0ERm-Mtzo_npbAhUKgnfg@mail.gmail.com' \
--to=schaefer@brasslantern.com \
--cc=vapniks@yahoo.com \
--cc=zsh-workers@zsh.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.vuxu.org/mirror/zsh/
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).