Files
fish-shell/share/functions/__fish_paste.fish
Johannes Altmanninger f415413bfb Strip "$ " prefixes on paste
Code blocks are often written like

	$ echo hello world
	hello world

The "$ " is widely understood to introduce a shell command.  It's often
easier to copy the whole line than copying everything after "$ ".

This gets more pronounced when there are multiple commands without interleaved
output (either due to omission or the rule of silence). Copying the whole
code block is the most natural first step.

You could argue that this is a presentation issue - the dollar prefix
should be rendered but not copied to clipboard. But in my experience there
are many cases where there is no HTML or Javascript that would allow the
copy-to-clipboard functionality to strip the prefixes.

The "$ " prefix is almost never useful when pasting; strip it automatically.

Privileged commands use "# " as prefix which overlaps with comments, so do
not strip that until we can disambiguate (another potential reason not to
do that would be safety but it's unclear if that really matters).

Add the new logic to the commandline builtin, because we don't know about the
AST in fish script. (Technically, the tokenizer already knows whether a "$
" is in command position and at the beginning of a line, but we don't
have that either (yet).)

Maybe we should move the rest of __fish_paste over as well. I'm not sure what
difference that would make; for one, pasting could no longer be cancelled
by ctrl-c (in theory), which seems like a good direction?
2025-03-01 07:55:53 +01:00

49 lines
1.8 KiB
Fish

function __fish_paste
# Also split on \r, otherwise it looks confusing
set -l data (string split \r -- $argv[1] | string split \n)
set data (string replace -ra [[:cntrl:]] '' -- $data)
if commandline --search-field >/dev/null
commandline --search-field -i -- $data
return
end
# If the current token has an unmatched single-quote,
# escape all single-quotes (and backslashes) in the paste,
# in order to turn it into a single literal token.
#
# This eases pasting non-code (e.g. markdown or git commitishes).
set -l quote_state (__fish_tokenizer_state -- (commandline -ct | string collect))
if contains -- $quote_state single single-escaped
if status test-feature regex-easyesc
set data (string replace -ra "(['\\\])" '\\\\$1' -- $data)
else
set data (string replace -ra "(['\\\])" '\\\\\\\$1' -- $data)
end
else if not contains -- $quote_state double double-escaped
and set -q data[2]
# Leading whitespace in subsequent lines is unneded, since fish
# already indents. Also gets rid of tabs (issue #5274).
set -l tmp
for line in $data
switch $quote_state
case normal
set -a tmp (string trim -l -- $line)
case single single-escaped double double-escaped escaped
set -a tmp $line
end
set quote_state (__fish_tokenizer_state -i $quote_state -- $line)
end
set data $data[1] $tmp[2..]
end
if not string length -q -- (commandline -c)
# If we're at the beginning of the first line, trim whitespace from the start,
# so we don't trigger ignoring history.
set data[1] (string trim -l -- $data[1])
end
if test -n "$data"
commandline --insert-smart -- $data
end
end