mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-26 21:03:12 +00:00
fish_clipboard_paste: don't bypass pager search field.
To do so add an ad-hoc "commandline --search-field" to operate on pager search field. This is primarily motivated because a following commit reuses the fish_clipboard_paste logic for bracketed paste. This avoids a regression.
This commit is contained in:
parent
d0cdb142de
commit
22717339b4
5 changed files with 95 additions and 19 deletions
|
@ -70,6 +70,9 @@ The following options change what part of the commandline is printed or updated:
|
|||
**-t** or **--current-token**
|
||||
Selects the current token
|
||||
|
||||
**--search-field**
|
||||
Use the pager search field instead of the command line. Returns false is the search field is not shown.
|
||||
|
||||
The following options change the way ``commandline`` prints the current commandline buffer:
|
||||
|
||||
**-c** or **--cut-at-cursor**
|
||||
|
|
|
@ -22,6 +22,7 @@ complete -c commandline -s L -l line -d "Print the line that the cursor is on"
|
|||
complete -c commandline -s S -l search-mode -d "Return true if performing a history search"
|
||||
complete -c commandline -s P -l paging-mode -d "Return true if showing pager content"
|
||||
complete -c commandline -l paging-full-mode -d "Return true if pager is showing all content"
|
||||
complete -c commandline -l search-field -d "Operate on the pager search field"
|
||||
complete -c commandline -l is-valid -d "Return true if the command line is syntactically valid and complete"
|
||||
|
||||
complete -c commandline -n '__fish_contains_opt -s f function' -a '(bind --function-names)' -d 'Function name' -x
|
||||
|
|
|
@ -26,6 +26,11 @@ function fish_clipboard_paste
|
|||
# Also split on \r, otherwise it looks confusing
|
||||
set data (string split \r -- $data | string split \n)
|
||||
|
||||
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.
|
||||
|
|
|
@ -11,7 +11,9 @@ use crate::parse_util::{
|
|||
parse_util_token_extent,
|
||||
};
|
||||
use crate::proc::is_interactive_session;
|
||||
use crate::reader::{commandline_get_state, commandline_set_buffer, reader_queue_ch};
|
||||
use crate::reader::{
|
||||
commandline_get_state, commandline_set_buffer, commandline_set_search_field, reader_queue_ch,
|
||||
};
|
||||
use crate::tokenizer::TOK_ACCEPT_UNFINISHED;
|
||||
use crate::tokenizer::{TokenType, Tokenizer};
|
||||
use crate::wchar::prelude::*;
|
||||
|
@ -57,6 +59,7 @@ fn replace_part(
|
|||
insert_mode: AppendMode,
|
||||
buff: &wstr,
|
||||
cursor_pos: usize,
|
||||
search_field_mode: bool,
|
||||
) {
|
||||
let mut out_pos = cursor_pos;
|
||||
let mut out = buff[..range.start].to_owned();
|
||||
|
@ -81,7 +84,11 @@ fn replace_part(
|
|||
}
|
||||
|
||||
out.push_utfstr(&buff[range.end..]);
|
||||
commandline_set_buffer(out, Some(out_pos));
|
||||
if search_field_mode {
|
||||
commandline_set_search_field(out, Some(out_pos));
|
||||
} else {
|
||||
commandline_set_buffer(out, Some(out_pos));
|
||||
}
|
||||
}
|
||||
|
||||
/// Output the specified selection.
|
||||
|
@ -191,6 +198,7 @@ pub fn commandline(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr])
|
|||
let mut search_mode = false;
|
||||
let mut paging_mode = false;
|
||||
let mut paging_full_mode = false;
|
||||
let mut search_field_mode = false;
|
||||
let mut is_valid = false;
|
||||
|
||||
let mut range = 0..0;
|
||||
|
@ -224,6 +232,7 @@ pub fn commandline(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr])
|
|||
wopt(L!("search-mode"), woption_argument_t::no_argument, 'S'),
|
||||
wopt(L!("paging-mode"), woption_argument_t::no_argument, 'P'),
|
||||
wopt(L!("paging-full-mode"), woption_argument_t::no_argument, 'F'),
|
||||
wopt(L!("search-field"), woption_argument_t::no_argument, '\x03'),
|
||||
wopt(L!("is-valid"), woption_argument_t::no_argument, '\x01'),
|
||||
];
|
||||
|
||||
|
@ -269,6 +278,7 @@ pub fn commandline(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr])
|
|||
's' => selection_mode = true,
|
||||
'P' => paging_mode = true,
|
||||
'F' => paging_full_mode = true,
|
||||
'\x03' => search_field_mode = true,
|
||||
'\x01' => is_valid = true,
|
||||
'h' => {
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
|
@ -361,10 +371,10 @@ pub fn commandline(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr])
|
|||
return STATUS_INVALID_ARGS;
|
||||
}
|
||||
|
||||
if (buffer_part.is_some() || token_mode.is_some() || cut_at_cursor)
|
||||
if (buffer_part.is_some() || token_mode.is_some() || cut_at_cursor || search_field_mode)
|
||||
&& (cursor_mode || line_mode || search_mode || paging_mode || paging_full_mode)
|
||||
// Special case - we allow to get/set cursor position relative to the process/job/token.
|
||||
&& (buffer_part.is_none() || !cursor_mode)
|
||||
&& ((buffer_part.is_none() && !search_field_mode) || !cursor_mode)
|
||||
{
|
||||
streams.err.append(wgettext_fmt!(BUILTIN_ERR_COMBO, cmd));
|
||||
builtin_print_error_trailer(parser, streams.err, cmd);
|
||||
|
@ -381,6 +391,12 @@ pub fn commandline(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr])
|
|||
return STATUS_INVALID_ARGS;
|
||||
}
|
||||
|
||||
if search_field_mode && buffer_part.is_some() {
|
||||
streams.err.append(wgettext_fmt!(BUILTIN_ERR_COMBO, cmd,));
|
||||
builtin_print_error_trailer(parser, streams.err, cmd);
|
||||
return STATUS_INVALID_ARGS;
|
||||
}
|
||||
|
||||
if append_mode.is_some() && positional_args == 0 {
|
||||
// No tokens in insert mode just means we do nothing.
|
||||
return STATUS_CMD_ERROR;
|
||||
|
@ -447,7 +463,15 @@ pub fn commandline(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr])
|
|||
let current_buffer;
|
||||
let current_cursor_pos;
|
||||
let transient;
|
||||
if let Some(override_buffer) = &override_buffer {
|
||||
|
||||
if search_field_mode {
|
||||
let Some((search_field_text, cursor_pos)) = commandline_get_state().search_field else {
|
||||
return STATUS_CMD_ERROR;
|
||||
};
|
||||
transient = search_field_text;
|
||||
current_buffer = &transient;
|
||||
current_cursor_pos = cursor_pos;
|
||||
} else if let Some(override_buffer) = &override_buffer {
|
||||
current_buffer = override_buffer;
|
||||
current_cursor_pos = current_buffer.len();
|
||||
} else if !ld.transient_commandlines.is_empty() && !cursor_mode {
|
||||
|
@ -487,18 +511,22 @@ pub fn commandline(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr])
|
|||
};
|
||||
}
|
||||
|
||||
match buffer_part {
|
||||
TextScope::String => {
|
||||
range = 0..current_buffer.len();
|
||||
}
|
||||
TextScope::Job => {
|
||||
range = parse_util_job_extent(current_buffer, current_cursor_pos, None);
|
||||
}
|
||||
TextScope::Process => {
|
||||
range = parse_util_process_extent(current_buffer, current_cursor_pos, None);
|
||||
}
|
||||
TextScope::Token => {
|
||||
parse_util_token_extent(current_buffer, current_cursor_pos, &mut range, None);
|
||||
if search_field_mode {
|
||||
range = 0..current_buffer.len();
|
||||
} else {
|
||||
match buffer_part {
|
||||
TextScope::String => {
|
||||
range = 0..current_buffer.len();
|
||||
}
|
||||
TextScope::Job => {
|
||||
range = parse_util_job_extent(current_buffer, current_cursor_pos, None);
|
||||
}
|
||||
TextScope::Process => {
|
||||
range = parse_util_process_extent(current_buffer, current_cursor_pos, None);
|
||||
}
|
||||
TextScope::Token => {
|
||||
parse_util_token_extent(current_buffer, current_cursor_pos, &mut range, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -546,10 +574,18 @@ pub fn commandline(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr])
|
|||
append_mode,
|
||||
current_buffer,
|
||||
current_cursor_pos,
|
||||
search_field_mode,
|
||||
);
|
||||
} else {
|
||||
let sb = join_strings(&w.argv[w.woptind..], '\n');
|
||||
replace_part(range, &sb, append_mode, current_buffer, current_cursor_pos);
|
||||
replace_part(
|
||||
range,
|
||||
&sb,
|
||||
append_mode,
|
||||
current_buffer,
|
||||
current_cursor_pos,
|
||||
search_field_mode,
|
||||
);
|
||||
}
|
||||
|
||||
STATUS_CMD_OK
|
||||
|
|
|
@ -21,6 +21,7 @@ use nix::fcntl::OFlag;
|
|||
use nix::sys::stat::Mode;
|
||||
use once_cell::sync::Lazy;
|
||||
use std::cell::UnsafeCell;
|
||||
use std::cmp;
|
||||
use std::io::BufReader;
|
||||
use std::num::NonZeroUsize;
|
||||
use std::ops::Range;
|
||||
|
@ -305,6 +306,8 @@ pub struct CommandlineState {
|
|||
pub pager_mode: bool,
|
||||
/// pager already shows everything if possible
|
||||
pub pager_fully_disclosed: bool,
|
||||
/// The search field, if shown.
|
||||
pub search_field: Option<(WString, usize)>,
|
||||
/// pager is visible and search is active
|
||||
pub search_mode: bool,
|
||||
/// if false, the reader has not yet been entered
|
||||
|
@ -320,6 +323,7 @@ impl CommandlineState {
|
|||
history: None,
|
||||
pager_mode: false,
|
||||
pager_fully_disclosed: false,
|
||||
search_field: None,
|
||||
search_mode: false,
|
||||
initialized: false,
|
||||
}
|
||||
|
@ -937,10 +941,17 @@ pub fn commandline_get_state() -> CommandlineState {
|
|||
/// will pick it up when it is done executing.
|
||||
pub fn commandline_set_buffer(text: WString, cursor_pos: Option<usize>) {
|
||||
let mut state = commandline_state_snapshot();
|
||||
state.cursor_pos = std::cmp::min(cursor_pos.unwrap_or(usize::MAX), text.len());
|
||||
state.cursor_pos = cmp::min(cursor_pos.unwrap_or(usize::MAX), text.len());
|
||||
state.text = text;
|
||||
}
|
||||
|
||||
pub fn commandline_set_search_field(text: WString, cursor_pos: Option<usize>) {
|
||||
let mut state = commandline_state_snapshot();
|
||||
assert!(state.search_field.is_some());
|
||||
let new_pos = cmp::min(cursor_pos.unwrap_or(usize::MAX), text.len());
|
||||
state.search_field = Some((text, new_pos));
|
||||
}
|
||||
|
||||
/// Return the current interactive reads loop count. Useful for determining how many commands have
|
||||
/// been executed between invocations of code.
|
||||
pub fn reader_run_count() -> u64 {
|
||||
|
@ -1163,6 +1174,12 @@ impl ReaderData {
|
|||
snapshot.selection = self.get_selection();
|
||||
snapshot.pager_mode = !self.pager.is_empty();
|
||||
snapshot.pager_fully_disclosed = self.current_page_rendering.remaining_to_disclose == 0;
|
||||
snapshot.search_field = self.pager.search_field_shown.then(|| {
|
||||
(
|
||||
self.pager.search_field_line.text().to_owned(),
|
||||
self.pager.search_field_line.position(),
|
||||
)
|
||||
});
|
||||
snapshot.search_mode = self.history_search.active();
|
||||
snapshot.initialized = true;
|
||||
}
|
||||
|
@ -1179,6 +1196,20 @@ impl ReaderData {
|
|||
self.clear_pager();
|
||||
self.set_buffer_maintaining_pager(&state.text, state.cursor_pos, false);
|
||||
self.reset_loop_state = true;
|
||||
} else if let Some((new_search_field, new_cursor_pos)) = state.search_field {
|
||||
if !self.pager.search_field_shown {
|
||||
return; // Not yet supported.
|
||||
}
|
||||
if new_search_field == self.pager.search_field_line.text()
|
||||
&& new_cursor_pos == self.pager.search_field_line.position()
|
||||
{
|
||||
return;
|
||||
}
|
||||
self.push_edit(
|
||||
EditableLineTag::SearchField,
|
||||
Edit::new(0..self.pager.search_field_line.len(), new_search_field),
|
||||
);
|
||||
self.pager.search_field_line.set_position(new_cursor_pos);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue