Improve mouse support
Some checks failed
make test / ubuntu (push) Has been cancelled
make test / ubuntu-32bit-static-pcre2 (push) Has been cancelled
make test / ubuntu-asan (push) Has been cancelled
make test / macos (push) Has been cancelled
Rust checks / rustfmt (push) Has been cancelled
Rust checks / clippy (push) Has been cancelled
Lock threads / lock (push) Has been cancelled

This commit is contained in:
kerty 2025-01-14 09:48:59 +03:00 committed by Johannes Altmanninger
parent a0e687965e
commit f139d8ebed
4 changed files with 67 additions and 36 deletions

View File

@ -18,6 +18,7 @@ Interactive improvements
when typing a command and :kbd:`enter` while the previous one is still running, the new one will no longer execute immediately. Similarly, keys that are bound to shell commands will be ignored.
This mitigates a security issue where a command like ``cat malicious-file.txt`` could write terminal escape codes prompting the terminal to write arbitrary text to fish's standard input.
Such a malicious file can still potentially insert arbitrary text into the command line but can no longer execute it directly (:issue:`10987`).
- Left mouse click now can select pager items.
New or improved bindings
^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -13,7 +13,7 @@ use crate::future::IsSomeAnd;
use crate::highlight::{highlight_shell, HighlightRole, HighlightSpec};
use crate::libc::MB_CUR_MAX;
use crate::operation_context::OperationContext;
use crate::screen::{wcswidth_rendered, wcwidth_rendered, Line, ScreenData};
use crate::screen::{wcswidth_rendered, wcwidth_rendered, CharOffset, Line, ScreenData};
use crate::termsize::Termsize;
use crate::wchar::prelude::*;
use crate::wcstringutil::string_fuzzy_match_string;
@ -253,9 +253,7 @@ impl Pager {
assert!(stop_row <= row_count);
assert!(stop_row - start_row <= term_height);
// This always printed at the end of the command line.
let offset_in_cmdline = usize::MAX;
self.completion_print(
offset_in_cmdline,
cols,
&width_by_column,
start_row,
@ -300,7 +298,7 @@ impl Pager {
HighlightRole::pager_progress,
);
print_max(
offset_in_cmdline,
CharOffset::None,
&progress_text,
spec,
term_width,
@ -329,7 +327,7 @@ impl Pager {
let mut search_field_remaining = term_width - 1;
search_field_remaining -= print_max(
offset_in_cmdline,
CharOffset::None,
wgettext!(SEARCH_FIELD_PROMPT),
HighlightSpec::new(),
search_field_remaining,
@ -337,7 +335,7 @@ impl Pager {
search_field,
);
search_field_remaining -= print_max(
offset_in_cmdline,
CharOffset::None,
&search_field_text,
underline,
search_field_remaining,
@ -407,7 +405,6 @@ impl Pager {
/// \param lst The list of completions to print
fn completion_print(
&self,
offset_in_cmdline: usize,
cols: usize,
width_by_column: &[usize; PAGER_MAX_COLS],
row_start: usize,
@ -437,7 +434,7 @@ impl Pager {
// Print this completion on its own "line".
let mut line = self.completion_print_item(
offset_in_cmdline,
CharOffset::Pager(idx),
prefix,
el,
col_width,
@ -447,7 +444,7 @@ impl Pager {
// If there's more to come, append two spaces.
if col + 1 < cols {
line.append_str(PAGER_SPACER_STRING, HighlightSpec::new(), offset_in_cmdline);
line.append_str(PAGER_SPACER_STRING, HighlightSpec::new(), CharOffset::None);
}
// Append this to the real line.
@ -462,7 +459,7 @@ impl Pager {
/// Print the specified item using at the specified amount of space.
fn completion_print_item(
&self,
offset_in_cmdline: usize,
offset_in_cmdline: CharOffset,
prefix: &wstr,
c: &PagerComp,
width: usize,
@ -1100,7 +1097,7 @@ fn divide_round_up(numer: usize, denom: usize) -> usize {
/// \param has_more if this flag is true, this is not the entire string, and the string should be
/// ellipsized even if the string fits but takes up the whole space.
fn print_max_impl(
offset_in_cmdline: usize,
offset_in_cmdline: CharOffset,
s: &wstr,
color: impl Fn(usize) -> HighlightSpec,
max: usize,
@ -1136,7 +1133,7 @@ fn print_max_impl(
}
fn print_max(
offset_in_cmdline: usize,
offset_in_cmdline: CharOffset,
s: &wstr,
color: HighlightSpec,
max: usize,

View File

@ -120,7 +120,7 @@ use crate::proc::{
print_exit_warning_for_jobs, proc_update_jiffies,
};
use crate::reader_history_search::{smartcase_flags, ReaderHistorySearch, SearchMode};
use crate::screen::{screen_clear, screen_force_clear_to_end, Screen};
use crate::screen::{screen_clear, screen_force_clear_to_end, CharOffset, Screen};
use crate::signal::{
signal_check_cancel, signal_clear_cancel, signal_reset_handlers, signal_set_handlers,
signal_set_handlers_once,
@ -1403,11 +1403,20 @@ impl ReaderData {
"; received left mouse click at",
click_position
);
let new_pos = self
match self
.screen
.offset_in_cmdline_given_cursor(click_position, cursor);
let (elt, _el) = self.active_edit_line();
self.update_buff_pos(elt, Some(new_pos));
.offset_in_cmdline_given_cursor(click_position, cursor)
{
CharOffset::Cmd(new_pos) | CharOffset::Pointer(new_pos) => {
let (elt, _el) = self.active_edit_line();
self.update_buff_pos(elt, Some(new_pos));
}
CharOffset::Pager(idx) if self.pager.selected_completion_idx != Some(idx) => {
self.pager.selected_completion_idx = Some(idx);
self.pager_selection_changed();
}
_ => {}
}
}
}

View File

@ -42,12 +42,21 @@ use crate::wchar::prelude::*;
use crate::wcstringutil::string_prefixes_string;
use crate::wutil::fstat;
#[derive(Copy, Clone, Default)]
pub enum CharOffset {
#[default]
None,
Cmd(usize),
Pointer(usize),
Pager(usize),
}
#[derive(Clone, Default)]
pub struct HighlightedChar {
highlight: HighlightSpec,
character: char,
// Logical offset within the command line.
offset_in_cmdline: usize,
offset_in_cmdline: CharOffset,
}
/// A class representing a single line of a screen.
@ -70,7 +79,12 @@ impl Line {
}
/// Append a single character `txt` to the line with color `c`.
pub fn append(&mut self, character: char, highlight: HighlightSpec, offset_in_cmdline: usize) {
pub fn append(
&mut self,
character: char,
highlight: HighlightSpec,
offset_in_cmdline: CharOffset,
) {
self.text.push(HighlightedChar {
highlight,
character: rendered_character(character),
@ -79,7 +93,12 @@ impl Line {
}
/// Append a nul-terminated string `txt` to the line, giving each character `color`.
pub fn append_str(&mut self, txt: &wstr, highlight: HighlightSpec, offset_in_cmdline: usize) {
pub fn append_str(
&mut self,
txt: &wstr,
highlight: HighlightSpec,
offset_in_cmdline: CharOffset,
) {
for c in txt.chars() {
self.append(c, highlight, offset_in_cmdline);
}
@ -101,7 +120,7 @@ impl Line {
}
/// Return the logical offset corresponding to this cell
pub fn offset_in_cmdline_at(&self, idx: usize) -> usize {
pub fn offset_in_cmdline_at(&self, idx: usize) -> CharOffset {
self.text[idx].offset_in_cmdline
}
@ -338,9 +357,14 @@ impl Screen {
self.desired.cursor.y = 0;
// Append spaces for the left prompt.
let prompt_offset = if pager.search_field_shown {
CharOffset::None
} else {
CharOffset::Pointer(0)
};
for _ in 0..layout.left_prompt_space {
let _ = self.desired_append_char(
/*offset_in_cmdline=*/ 0,
prompt_offset,
usize::MAX,
' ',
HighlightSpec::new(),
@ -386,11 +410,14 @@ impl Screen {
break scrolled_cursor.unwrap();
}
if !self.desired_append_char(
/*offset_in_cmdline=*/
if i <= explicit_before_suggestion.len() + layout.autosuggestion.len() {
i.min(explicit_before_suggestion.len())
if pager.search_field_shown {
CharOffset::None
} else if i < explicit_before_suggestion.len() {
CharOffset::Cmd(i)
} else if i < explicit_before_suggestion.len() + layout.autosuggestion.len() {
CharOffset::Pointer(explicit_before_suggestion.len())
} else {
i - layout.autosuggestion.len()
CharOffset::Cmd(i - layout.autosuggestion.len())
},
if is_final_rendering {
usize::MAX
@ -553,7 +580,7 @@ impl Screen {
&mut self,
viewport_position: ViewportPosition,
viewport_cursor: ViewportPosition,
) -> usize {
) -> CharOffset {
let viewport_prompt_y = self.command_line_y_given_cursor_y(viewport_cursor.y);
let y = viewport_position
.y
@ -574,14 +601,11 @@ impl Screen {
let x = viewport_position.x - viewport_prompt_x;
let line = self.actual.line(y);
let x = x.max(line.indentation);
if x >= line.len() {
if self.actual.line_count() == 1 {
0
} else {
line.text.last().unwrap().offset_in_cmdline + 1
}
} else {
line.offset_in_cmdline_at(x)
let char = line.text.get(x).or(line.text.last()).unwrap();
match char.offset_in_cmdline {
CharOffset::Cmd(value) if x >= line.len() => CharOffset::Cmd(value + 1),
CharOffset::Pager(_) if x >= line.len() => CharOffset::None,
offset => offset,
}
}
@ -706,7 +730,7 @@ impl Screen {
/// automatically handles linebreaks and lines longer than the screen width.
fn desired_append_char(
&mut self,
offset_in_cmdline: usize,
offset_in_cmdline: CharOffset,
max_y: usize,
b: char,
c: HighlightSpec,