mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-27 05:13:10 +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**
|
**-t** or **--current-token**
|
||||||
Selects the 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:
|
The following options change the way ``commandline`` prints the current commandline buffer:
|
||||||
|
|
||||||
**-c** or **--cut-at-cursor**
|
**-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 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 -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 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 -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
|
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
|
# Also split on \r, otherwise it looks confusing
|
||||||
set data (string split \r -- $data | string split \n)
|
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,
|
# If the current token has an unmatched single-quote,
|
||||||
# escape all single-quotes (and backslashes) in the paste,
|
# escape all single-quotes (and backslashes) in the paste,
|
||||||
# in order to turn it into a single literal token.
|
# in order to turn it into a single literal token.
|
||||||
|
|
|
@ -11,7 +11,9 @@ use crate::parse_util::{
|
||||||
parse_util_token_extent,
|
parse_util_token_extent,
|
||||||
};
|
};
|
||||||
use crate::proc::is_interactive_session;
|
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::TOK_ACCEPT_UNFINISHED;
|
||||||
use crate::tokenizer::{TokenType, Tokenizer};
|
use crate::tokenizer::{TokenType, Tokenizer};
|
||||||
use crate::wchar::prelude::*;
|
use crate::wchar::prelude::*;
|
||||||
|
@ -57,6 +59,7 @@ fn replace_part(
|
||||||
insert_mode: AppendMode,
|
insert_mode: AppendMode,
|
||||||
buff: &wstr,
|
buff: &wstr,
|
||||||
cursor_pos: usize,
|
cursor_pos: usize,
|
||||||
|
search_field_mode: bool,
|
||||||
) {
|
) {
|
||||||
let mut out_pos = cursor_pos;
|
let mut out_pos = cursor_pos;
|
||||||
let mut out = buff[..range.start].to_owned();
|
let mut out = buff[..range.start].to_owned();
|
||||||
|
@ -81,7 +84,11 @@ fn replace_part(
|
||||||
}
|
}
|
||||||
|
|
||||||
out.push_utfstr(&buff[range.end..]);
|
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.
|
/// 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 search_mode = false;
|
||||||
let mut paging_mode = false;
|
let mut paging_mode = false;
|
||||||
let mut paging_full_mode = false;
|
let mut paging_full_mode = false;
|
||||||
|
let mut search_field_mode = false;
|
||||||
let mut is_valid = false;
|
let mut is_valid = false;
|
||||||
|
|
||||||
let mut range = 0..0;
|
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!("search-mode"), woption_argument_t::no_argument, 'S'),
|
||||||
wopt(L!("paging-mode"), woption_argument_t::no_argument, 'P'),
|
wopt(L!("paging-mode"), woption_argument_t::no_argument, 'P'),
|
||||||
wopt(L!("paging-full-mode"), woption_argument_t::no_argument, 'F'),
|
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'),
|
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,
|
's' => selection_mode = true,
|
||||||
'P' => paging_mode = true,
|
'P' => paging_mode = true,
|
||||||
'F' => paging_full_mode = true,
|
'F' => paging_full_mode = true,
|
||||||
|
'\x03' => search_field_mode = true,
|
||||||
'\x01' => is_valid = true,
|
'\x01' => is_valid = true,
|
||||||
'h' => {
|
'h' => {
|
||||||
builtin_print_help(parser, streams, cmd);
|
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;
|
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)
|
&& (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.
|
// 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));
|
streams.err.append(wgettext_fmt!(BUILTIN_ERR_COMBO, cmd));
|
||||||
builtin_print_error_trailer(parser, streams.err, 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;
|
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 {
|
if append_mode.is_some() && positional_args == 0 {
|
||||||
// No tokens in insert mode just means we do nothing.
|
// No tokens in insert mode just means we do nothing.
|
||||||
return STATUS_CMD_ERROR;
|
return STATUS_CMD_ERROR;
|
||||||
|
@ -447,7 +463,15 @@ pub fn commandline(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr])
|
||||||
let current_buffer;
|
let current_buffer;
|
||||||
let current_cursor_pos;
|
let current_cursor_pos;
|
||||||
let transient;
|
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_buffer = override_buffer;
|
||||||
current_cursor_pos = current_buffer.len();
|
current_cursor_pos = current_buffer.len();
|
||||||
} else if !ld.transient_commandlines.is_empty() && !cursor_mode {
|
} 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 {
|
if search_field_mode {
|
||||||
TextScope::String => {
|
range = 0..current_buffer.len();
|
||||||
range = 0..current_buffer.len();
|
} else {
|
||||||
}
|
match buffer_part {
|
||||||
TextScope::Job => {
|
TextScope::String => {
|
||||||
range = parse_util_job_extent(current_buffer, current_cursor_pos, None);
|
range = 0..current_buffer.len();
|
||||||
}
|
}
|
||||||
TextScope::Process => {
|
TextScope::Job => {
|
||||||
range = parse_util_process_extent(current_buffer, current_cursor_pos, None);
|
range = parse_util_job_extent(current_buffer, current_cursor_pos, None);
|
||||||
}
|
}
|
||||||
TextScope::Token => {
|
TextScope::Process => {
|
||||||
parse_util_token_extent(current_buffer, current_cursor_pos, &mut range, None);
|
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,
|
append_mode,
|
||||||
current_buffer,
|
current_buffer,
|
||||||
current_cursor_pos,
|
current_cursor_pos,
|
||||||
|
search_field_mode,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
let sb = join_strings(&w.argv[w.woptind..], '\n');
|
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
|
STATUS_CMD_OK
|
||||||
|
|
|
@ -21,6 +21,7 @@ use nix::fcntl::OFlag;
|
||||||
use nix::sys::stat::Mode;
|
use nix::sys::stat::Mode;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use std::cell::UnsafeCell;
|
use std::cell::UnsafeCell;
|
||||||
|
use std::cmp;
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
@ -305,6 +306,8 @@ pub struct CommandlineState {
|
||||||
pub pager_mode: bool,
|
pub pager_mode: bool,
|
||||||
/// pager already shows everything if possible
|
/// pager already shows everything if possible
|
||||||
pub pager_fully_disclosed: bool,
|
pub pager_fully_disclosed: bool,
|
||||||
|
/// The search field, if shown.
|
||||||
|
pub search_field: Option<(WString, usize)>,
|
||||||
/// pager is visible and search is active
|
/// pager is visible and search is active
|
||||||
pub search_mode: bool,
|
pub search_mode: bool,
|
||||||
/// if false, the reader has not yet been entered
|
/// if false, the reader has not yet been entered
|
||||||
|
@ -320,6 +323,7 @@ impl CommandlineState {
|
||||||
history: None,
|
history: None,
|
||||||
pager_mode: false,
|
pager_mode: false,
|
||||||
pager_fully_disclosed: false,
|
pager_fully_disclosed: false,
|
||||||
|
search_field: None,
|
||||||
search_mode: false,
|
search_mode: false,
|
||||||
initialized: false,
|
initialized: false,
|
||||||
}
|
}
|
||||||
|
@ -937,10 +941,17 @@ pub fn commandline_get_state() -> CommandlineState {
|
||||||
/// will pick it up when it is done executing.
|
/// will pick it up when it is done executing.
|
||||||
pub fn commandline_set_buffer(text: WString, cursor_pos: Option<usize>) {
|
pub fn commandline_set_buffer(text: WString, cursor_pos: Option<usize>) {
|
||||||
let mut state = commandline_state_snapshot();
|
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;
|
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
|
/// Return the current interactive reads loop count. Useful for determining how many commands have
|
||||||
/// been executed between invocations of code.
|
/// been executed between invocations of code.
|
||||||
pub fn reader_run_count() -> u64 {
|
pub fn reader_run_count() -> u64 {
|
||||||
|
@ -1163,6 +1174,12 @@ impl ReaderData {
|
||||||
snapshot.selection = self.get_selection();
|
snapshot.selection = self.get_selection();
|
||||||
snapshot.pager_mode = !self.pager.is_empty();
|
snapshot.pager_mode = !self.pager.is_empty();
|
||||||
snapshot.pager_fully_disclosed = self.current_page_rendering.remaining_to_disclose == 0;
|
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.search_mode = self.history_search.active();
|
||||||
snapshot.initialized = true;
|
snapshot.initialized = true;
|
||||||
}
|
}
|
||||||
|
@ -1179,6 +1196,20 @@ impl ReaderData {
|
||||||
self.clear_pager();
|
self.clear_pager();
|
||||||
self.set_buffer_maintaining_pager(&state.text, state.cursor_pos, false);
|
self.set_buffer_maintaining_pager(&state.text, state.cursor_pos, false);
|
||||||
self.reset_loop_state = true;
|
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