annotate .shell.d/99.safe-paste.zsh @ 531:ec44059d05b0

zsh: update safe-paste logic
author Augie Fackler <raf@durin42.com>
date Wed, 25 Mar 2026 21:44:37 -0400
parents bef29d49d19f
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
531
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
1 # A good summary of the zsh 5.1 Bracketed Paste Mode changes is at:
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
2 # https://archive.zhimingwang.org/blog/2015-09-21-zsh-51-and-bracketed-paste.html
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
3
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
4 # zsh 5.1 (September 2015) introduced built-in support for Bracketed Paste Mode
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
5 # https://github.com/zsh-users/zsh/blob/68405f31a043bdd5bf338eb06688ed3e1f740937/README#L38-L45
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
6 #
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
7 # zsh 5.1 breaks url-quote-magic and other widgets replacing self-insert
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
8 # zsh-users' bracketed-paste-magic resolves these issues:
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
9 # https://github.com/zsh-users/zsh/blob/f702e17b14d75aa21bff014168fa9048124db286/Functions/Zle/bracketed-paste-magic#L9-L12
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
10
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
11 # Load bracketed-paste-magic if zsh version is >= 5.1
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
12 autoload -Uz is-at-least
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
13 if is-at-least 5.1; then
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
14 set zle_bracketed_paste # Explicitly restore this zsh default
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
15 autoload -Uz bracketed-paste-magic
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
16 zle -N bracketed-paste bracketed-paste-magic
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
17 return ### The rest of this file is NOT executed on zsh version >= 5.1 ###
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
18 fi
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
19
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
20 ######################################################################
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
21 # The rest of this file is ONLY executed if zsh version < 5.1
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
22 ######################################################################
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
23
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
24 # Code from Mikael Magnusson: https://www.zsh.org/mla/users/2011/msg00367.html
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
25 #
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
26 # Requires xterm, urxvt, iTerm2 or any other terminal that supports
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
27 # Bracketed Paste Mode as documented:
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
28 # https://www.xfree86.org/current/ctlseqs.html#Bracketed%20Paste%20Mode
351
bef29d49d19f safe-paste: adds support for bracketed paste mode to zsh
Augie Fackler <raf@durin42.com>
parents:
diff changeset
29 #
531
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
30 # For tmux, use: bind ] paste-buffer -p
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
31 #
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
32 # Additional technical details: https://cirw.in/blog/bracketed-paste
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
33
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
34 # Create a new keymap to use while pasting
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
35 bindkey -N bracketed-paste
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
36 # Make everything in this new keymap enqueue characters for pasting
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
37 bindkey -RM bracketed-paste '\x00-\xFF' bracketed-paste-enqueue
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
38 # These are the codes sent around the pasted text in bracketed paste mode
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
39 bindkey -M main '^[[200~' _bracketed_paste_begin
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
40 bindkey -M bracketed-paste '^[[201~' _bracketed_paste_end
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
41 # Insert newlines rather than carriage returns when pasting newlines
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
42 bindkey -M bracketed-paste -s '^M' '^J'
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
43
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
44 zle -N _bracketed_paste_begin
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
45 zle -N _bracketed_paste_end
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
46 zle -N bracketed-paste-enqueue _bracketed_paste_enqueue
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
47
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
48 # Attempt to not clobber zle_line_{init,finish}
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
49 # Use https://github.com/willghatch/zsh-hooks if available
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
50 if typeset -f hooks-add-hook > /dev/null; then
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
51 hooks-add-hook zle_line_init_hook _bracketed_paste_zle_init
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
52 hooks-add-hook zle_line_finish_hook _bracketed_paste_zle_finish
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
53 else
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
54 zle -N zle-line-init _bracketed_paste_zle_init
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
55 zle -N zle-line-finish _bracketed_paste_zle_finish
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
56 fi
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
57
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
58 # Switch the active keymap to paste mode
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
59 _bracketed_paste_begin() {
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
60 # Save the bindkey command to restore the active ("main") keymap
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
61 # Tokenise the restorative bindkey command into an array
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
62 _bracketed_paste_restore_keymap=( ${(z)"$(bindkey -lL main)"} )
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
63 bindkey -A bracketed-paste main
351
bef29d49d19f safe-paste: adds support for bracketed paste mode to zsh
Augie Fackler <raf@durin42.com>
parents:
diff changeset
64 }
bef29d49d19f safe-paste: adds support for bracketed paste mode to zsh
Augie Fackler <raf@durin42.com>
parents:
diff changeset
65
531
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
66 # Go back to our normal keymap, and insert all the pasted text in the
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
67 # command line. This has the nice effect of making the whole paste be
351
bef29d49d19f safe-paste: adds support for bracketed paste mode to zsh
Augie Fackler <raf@durin42.com>
parents:
diff changeset
68 # a single undo/redo event.
531
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
69 _bracketed_paste_end() {
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
70 # Only execute the restore command if it starts with 'bindkey'
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
71 # Allow for option KSH_ARRAYS being set (indexing starts at 0)
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
72 if [ ${_bracketed_paste_restore_keymap[@]:0:1} = 'bindkey' ]; then
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
73 $_bracketed_paste_restore_keymap
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
74 fi
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
75 LBUFFER+=$_bracketed_paste_content
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
76 unset _bracketed_paste_content _bracketed_paste_restore_keymap
351
bef29d49d19f safe-paste: adds support for bracketed paste mode to zsh
Augie Fackler <raf@durin42.com>
parents:
diff changeset
77 }
bef29d49d19f safe-paste: adds support for bracketed paste mode to zsh
Augie Fackler <raf@durin42.com>
parents:
diff changeset
78
531
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
79 # Append a pasted character to the content which is later inserted as a whole
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
80 _bracketed_paste_enqueue() {
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
81 _bracketed_paste_content+=$KEYS
351
bef29d49d19f safe-paste: adds support for bracketed paste mode to zsh
Augie Fackler <raf@durin42.com>
parents:
diff changeset
82 }
bef29d49d19f safe-paste: adds support for bracketed paste mode to zsh
Augie Fackler <raf@durin42.com>
parents:
diff changeset
83
531
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
84 # Run at zle-line-init
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
85 _bracketed_paste_zle_init() {
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
86 _bracketed_paste_content=''
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
87 # Tell terminal to send escape codes around pastes
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
88 if [[ $TERM =~ '^(rxvt-unicode|xterm(-256color)?|screen(-256color)?)$' ]]; then
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
89 printf '\e[?2004h'
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
90 fi
351
bef29d49d19f safe-paste: adds support for bracketed paste mode to zsh
Augie Fackler <raf@durin42.com>
parents:
diff changeset
91 }
bef29d49d19f safe-paste: adds support for bracketed paste mode to zsh
Augie Fackler <raf@durin42.com>
parents:
diff changeset
92
531
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
93 # Run at zle-line-finish
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
94 _bracketed_paste_zle_finish() {
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
95 # Turn off bracketed paste when we leave ZLE, so pasting in other programs
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
96 # doesn't get the ^[[200~ codes around the pasted text
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
97 if [[ $TERM =~ '^(rxvt-unicode|xterm(-256color)?|screen(-256color)?)$' ]]; then
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
98 printf '\e[?2004l'
ec44059d05b0 zsh: update safe-paste logic
Augie Fackler <raf@durin42.com>
parents: 351
diff changeset
99 fi
351
bef29d49d19f safe-paste: adds support for bracketed paste mode to zsh
Augie Fackler <raf@durin42.com>
parents:
diff changeset
100 }
bef29d49d19f safe-paste: adds support for bracketed paste mode to zsh
Augie Fackler <raf@durin42.com>
parents:
diff changeset
101