mirror of
https://github.com/fish-shell/fish-shell.git
synced 2025-02-09 03:32:59 +08:00
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
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:
parent
a0e687965e
commit
f139d8ebed
|
@ -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.
|
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.
|
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`).
|
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
|
New or improved bindings
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
21
src/pager.rs
21
src/pager.rs
|
@ -13,7 +13,7 @@ use crate::future::IsSomeAnd;
|
||||||
use crate::highlight::{highlight_shell, HighlightRole, HighlightSpec};
|
use crate::highlight::{highlight_shell, HighlightRole, HighlightSpec};
|
||||||
use crate::libc::MB_CUR_MAX;
|
use crate::libc::MB_CUR_MAX;
|
||||||
use crate::operation_context::OperationContext;
|
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::termsize::Termsize;
|
||||||
use crate::wchar::prelude::*;
|
use crate::wchar::prelude::*;
|
||||||
use crate::wcstringutil::string_fuzzy_match_string;
|
use crate::wcstringutil::string_fuzzy_match_string;
|
||||||
|
@ -253,9 +253,7 @@ impl Pager {
|
||||||
assert!(stop_row <= row_count);
|
assert!(stop_row <= row_count);
|
||||||
assert!(stop_row - start_row <= term_height);
|
assert!(stop_row - start_row <= term_height);
|
||||||
// This always printed at the end of the command line.
|
// This always printed at the end of the command line.
|
||||||
let offset_in_cmdline = usize::MAX;
|
|
||||||
self.completion_print(
|
self.completion_print(
|
||||||
offset_in_cmdline,
|
|
||||||
cols,
|
cols,
|
||||||
&width_by_column,
|
&width_by_column,
|
||||||
start_row,
|
start_row,
|
||||||
|
@ -300,7 +298,7 @@ impl Pager {
|
||||||
HighlightRole::pager_progress,
|
HighlightRole::pager_progress,
|
||||||
);
|
);
|
||||||
print_max(
|
print_max(
|
||||||
offset_in_cmdline,
|
CharOffset::None,
|
||||||
&progress_text,
|
&progress_text,
|
||||||
spec,
|
spec,
|
||||||
term_width,
|
term_width,
|
||||||
|
@ -329,7 +327,7 @@ impl Pager {
|
||||||
|
|
||||||
let mut search_field_remaining = term_width - 1;
|
let mut search_field_remaining = term_width - 1;
|
||||||
search_field_remaining -= print_max(
|
search_field_remaining -= print_max(
|
||||||
offset_in_cmdline,
|
CharOffset::None,
|
||||||
wgettext!(SEARCH_FIELD_PROMPT),
|
wgettext!(SEARCH_FIELD_PROMPT),
|
||||||
HighlightSpec::new(),
|
HighlightSpec::new(),
|
||||||
search_field_remaining,
|
search_field_remaining,
|
||||||
|
@ -337,7 +335,7 @@ impl Pager {
|
||||||
search_field,
|
search_field,
|
||||||
);
|
);
|
||||||
search_field_remaining -= print_max(
|
search_field_remaining -= print_max(
|
||||||
offset_in_cmdline,
|
CharOffset::None,
|
||||||
&search_field_text,
|
&search_field_text,
|
||||||
underline,
|
underline,
|
||||||
search_field_remaining,
|
search_field_remaining,
|
||||||
|
@ -407,7 +405,6 @@ impl Pager {
|
||||||
/// \param lst The list of completions to print
|
/// \param lst The list of completions to print
|
||||||
fn completion_print(
|
fn completion_print(
|
||||||
&self,
|
&self,
|
||||||
offset_in_cmdline: usize,
|
|
||||||
cols: usize,
|
cols: usize,
|
||||||
width_by_column: &[usize; PAGER_MAX_COLS],
|
width_by_column: &[usize; PAGER_MAX_COLS],
|
||||||
row_start: usize,
|
row_start: usize,
|
||||||
|
@ -437,7 +434,7 @@ impl Pager {
|
||||||
|
|
||||||
// Print this completion on its own "line".
|
// Print this completion on its own "line".
|
||||||
let mut line = self.completion_print_item(
|
let mut line = self.completion_print_item(
|
||||||
offset_in_cmdline,
|
CharOffset::Pager(idx),
|
||||||
prefix,
|
prefix,
|
||||||
el,
|
el,
|
||||||
col_width,
|
col_width,
|
||||||
|
@ -447,7 +444,7 @@ impl Pager {
|
||||||
|
|
||||||
// If there's more to come, append two spaces.
|
// If there's more to come, append two spaces.
|
||||||
if col + 1 < cols {
|
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.
|
// Append this to the real line.
|
||||||
|
@ -462,7 +459,7 @@ impl Pager {
|
||||||
/// Print the specified item using at the specified amount of space.
|
/// Print the specified item using at the specified amount of space.
|
||||||
fn completion_print_item(
|
fn completion_print_item(
|
||||||
&self,
|
&self,
|
||||||
offset_in_cmdline: usize,
|
offset_in_cmdline: CharOffset,
|
||||||
prefix: &wstr,
|
prefix: &wstr,
|
||||||
c: &PagerComp,
|
c: &PagerComp,
|
||||||
width: usize,
|
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
|
/// \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.
|
/// ellipsized even if the string fits but takes up the whole space.
|
||||||
fn print_max_impl(
|
fn print_max_impl(
|
||||||
offset_in_cmdline: usize,
|
offset_in_cmdline: CharOffset,
|
||||||
s: &wstr,
|
s: &wstr,
|
||||||
color: impl Fn(usize) -> HighlightSpec,
|
color: impl Fn(usize) -> HighlightSpec,
|
||||||
max: usize,
|
max: usize,
|
||||||
|
@ -1136,7 +1133,7 @@ fn print_max_impl(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_max(
|
fn print_max(
|
||||||
offset_in_cmdline: usize,
|
offset_in_cmdline: CharOffset,
|
||||||
s: &wstr,
|
s: &wstr,
|
||||||
color: HighlightSpec,
|
color: HighlightSpec,
|
||||||
max: usize,
|
max: usize,
|
||||||
|
|
|
@ -120,7 +120,7 @@ use crate::proc::{
|
||||||
print_exit_warning_for_jobs, proc_update_jiffies,
|
print_exit_warning_for_jobs, proc_update_jiffies,
|
||||||
};
|
};
|
||||||
use crate::reader_history_search::{smartcase_flags, ReaderHistorySearch, SearchMode};
|
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::{
|
use crate::signal::{
|
||||||
signal_check_cancel, signal_clear_cancel, signal_reset_handlers, signal_set_handlers,
|
signal_check_cancel, signal_clear_cancel, signal_reset_handlers, signal_set_handlers,
|
||||||
signal_set_handlers_once,
|
signal_set_handlers_once,
|
||||||
|
@ -1403,12 +1403,21 @@ impl ReaderData {
|
||||||
"; received left mouse click at",
|
"; received left mouse click at",
|
||||||
click_position
|
click_position
|
||||||
);
|
);
|
||||||
let new_pos = self
|
match self
|
||||||
.screen
|
.screen
|
||||||
.offset_in_cmdline_given_cursor(click_position, cursor);
|
.offset_in_cmdline_given_cursor(click_position, cursor)
|
||||||
|
{
|
||||||
|
CharOffset::Cmd(new_pos) | CharOffset::Pointer(new_pos) => {
|
||||||
let (elt, _el) = self.active_edit_line();
|
let (elt, _el) = self.active_edit_line();
|
||||||
self.update_buff_pos(elt, Some(new_pos));
|
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();
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a command line and an autosuggestion, return the string that gets shown to the user.
|
/// Given a command line and an autosuggestion, return the string that gets shown to the user.
|
||||||
|
|
|
@ -42,12 +42,21 @@ use crate::wchar::prelude::*;
|
||||||
use crate::wcstringutil::string_prefixes_string;
|
use crate::wcstringutil::string_prefixes_string;
|
||||||
use crate::wutil::fstat;
|
use crate::wutil::fstat;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Default)]
|
||||||
|
pub enum CharOffset {
|
||||||
|
#[default]
|
||||||
|
None,
|
||||||
|
Cmd(usize),
|
||||||
|
Pointer(usize),
|
||||||
|
Pager(usize),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct HighlightedChar {
|
pub struct HighlightedChar {
|
||||||
highlight: HighlightSpec,
|
highlight: HighlightSpec,
|
||||||
character: char,
|
character: char,
|
||||||
// Logical offset within the command line.
|
// Logical offset within the command line.
|
||||||
offset_in_cmdline: usize,
|
offset_in_cmdline: CharOffset,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A class representing a single line of a screen.
|
/// 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`.
|
/// 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 {
|
self.text.push(HighlightedChar {
|
||||||
highlight,
|
highlight,
|
||||||
character: rendered_character(character),
|
character: rendered_character(character),
|
||||||
|
@ -79,7 +93,12 @@ impl Line {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Append a nul-terminated string `txt` to the line, giving each character `color`.
|
/// 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() {
|
for c in txt.chars() {
|
||||||
self.append(c, highlight, offset_in_cmdline);
|
self.append(c, highlight, offset_in_cmdline);
|
||||||
}
|
}
|
||||||
|
@ -101,7 +120,7 @@ impl Line {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the logical offset corresponding to this cell
|
/// 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
|
self.text[idx].offset_in_cmdline
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,9 +357,14 @@ impl Screen {
|
||||||
self.desired.cursor.y = 0;
|
self.desired.cursor.y = 0;
|
||||||
|
|
||||||
// Append spaces for the left prompt.
|
// 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 {
|
for _ in 0..layout.left_prompt_space {
|
||||||
let _ = self.desired_append_char(
|
let _ = self.desired_append_char(
|
||||||
/*offset_in_cmdline=*/ 0,
|
prompt_offset,
|
||||||
usize::MAX,
|
usize::MAX,
|
||||||
' ',
|
' ',
|
||||||
HighlightSpec::new(),
|
HighlightSpec::new(),
|
||||||
|
@ -386,11 +410,14 @@ impl Screen {
|
||||||
break scrolled_cursor.unwrap();
|
break scrolled_cursor.unwrap();
|
||||||
}
|
}
|
||||||
if !self.desired_append_char(
|
if !self.desired_append_char(
|
||||||
/*offset_in_cmdline=*/
|
if pager.search_field_shown {
|
||||||
if i <= explicit_before_suggestion.len() + layout.autosuggestion.len() {
|
CharOffset::None
|
||||||
i.min(explicit_before_suggestion.len())
|
} 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 {
|
} else {
|
||||||
i - layout.autosuggestion.len()
|
CharOffset::Cmd(i - layout.autosuggestion.len())
|
||||||
},
|
},
|
||||||
if is_final_rendering {
|
if is_final_rendering {
|
||||||
usize::MAX
|
usize::MAX
|
||||||
|
@ -553,7 +580,7 @@ impl Screen {
|
||||||
&mut self,
|
&mut self,
|
||||||
viewport_position: ViewportPosition,
|
viewport_position: ViewportPosition,
|
||||||
viewport_cursor: ViewportPosition,
|
viewport_cursor: ViewportPosition,
|
||||||
) -> usize {
|
) -> CharOffset {
|
||||||
let viewport_prompt_y = self.command_line_y_given_cursor_y(viewport_cursor.y);
|
let viewport_prompt_y = self.command_line_y_given_cursor_y(viewport_cursor.y);
|
||||||
let y = viewport_position
|
let y = viewport_position
|
||||||
.y
|
.y
|
||||||
|
@ -574,14 +601,11 @@ impl Screen {
|
||||||
let x = viewport_position.x - viewport_prompt_x;
|
let x = viewport_position.x - viewport_prompt_x;
|
||||||
let line = self.actual.line(y);
|
let line = self.actual.line(y);
|
||||||
let x = x.max(line.indentation);
|
let x = x.max(line.indentation);
|
||||||
if x >= line.len() {
|
let char = line.text.get(x).or(line.text.last()).unwrap();
|
||||||
if self.actual.line_count() == 1 {
|
match char.offset_in_cmdline {
|
||||||
0
|
CharOffset::Cmd(value) if x >= line.len() => CharOffset::Cmd(value + 1),
|
||||||
} else {
|
CharOffset::Pager(_) if x >= line.len() => CharOffset::None,
|
||||||
line.text.last().unwrap().offset_in_cmdline + 1
|
offset => offset,
|
||||||
}
|
|
||||||
} else {
|
|
||||||
line.offset_in_cmdline_at(x)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -706,7 +730,7 @@ impl Screen {
|
||||||
/// automatically handles linebreaks and lines longer than the screen width.
|
/// automatically handles linebreaks and lines longer than the screen width.
|
||||||
fn desired_append_char(
|
fn desired_append_char(
|
||||||
&mut self,
|
&mut self,
|
||||||
offset_in_cmdline: usize,
|
offset_in_cmdline: CharOffset,
|
||||||
max_y: usize,
|
max_y: usize,
|
||||||
b: char,
|
b: char,
|
||||||
c: HighlightSpec,
|
c: HighlightSpec,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user