mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-13 21:44:16 +00:00
Update commandline state snapshot lazily
I think commit 8386088b3
(Update commandline state changes eagerly as well,
2024-04-11) broke the alt-s binding.
This is because we update the commandline state snapshot (which is consumed
by builtin commandline and others) only at key points. This seems like a
dubious optimization. With the new streamlined bind execution semantics,
this doesn't really work anymore; any shell command can run any number of
commands like "commandline -i foo" which should synchronize.
Do the simple thing of calculating the snapshot whenever needed.
This commit is contained in:
parent
edb5cb7226
commit
4f536d6a9b
6 changed files with 42 additions and 27 deletions
|
@ -181,7 +181,7 @@ fn write_part(
|
|||
|
||||
/// The commandline builtin. It is used for specifying a new value for the commandline.
|
||||
pub fn commandline(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> Option<c_int> {
|
||||
let rstate = commandline_get_state();
|
||||
let rstate = commandline_get_state(true);
|
||||
|
||||
let mut buffer_part = None;
|
||||
let mut cut_at_cursor = false;
|
||||
|
|
|
@ -485,7 +485,7 @@ pub fn complete(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) ->
|
|||
let do_complete_param = match do_complete_param {
|
||||
None => {
|
||||
// No argument given, try to use the current commandline.
|
||||
let commandline_state = commandline_get_state();
|
||||
let commandline_state = commandline_get_state(true);
|
||||
if !commandline_state.initialized {
|
||||
// This corresponds to using 'complete -C' in non-interactive mode.
|
||||
// See #2361 .
|
||||
|
|
|
@ -243,7 +243,7 @@ pub fn history(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) ->
|
|||
|
||||
// Use the default history if we have none (which happens if invoked non-interactively, e.g.
|
||||
// from webconfig.py.
|
||||
let history = commandline_get_state()
|
||||
let history = commandline_get_state(true)
|
||||
.history
|
||||
.unwrap_or_else(|| History::with_name(&history_session_id(parser.vars())));
|
||||
|
||||
|
|
2
src/env/environment_impl.rs
vendored
2
src/env/environment_impl.rs
vendored
|
@ -353,7 +353,7 @@ impl EnvScopedImpl {
|
|||
if !is_main_thread() {
|
||||
return None;
|
||||
}
|
||||
let history = commandline_get_state().history.unwrap_or_else(|| {
|
||||
let history = commandline_get_state(true).history.unwrap_or_else(|| {
|
||||
let fish_history_var = self.getf(L!("fish_history"), EnvMode::default());
|
||||
let session_id = history_session_id_from_var(fish_history_var);
|
||||
History::with_name(&session_id)
|
||||
|
|
|
@ -156,8 +156,8 @@ static INTERRUPTED: AtomicI32 = AtomicI32::new(0);
|
|||
/// This is set from a signal handler.
|
||||
static SIGHUP_RECEIVED: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
|
||||
|
||||
/// A singleton snapshot of the reader state. This is updated when the reader changes. This is
|
||||
/// factored out for thread-safety reasons: it may be fetched on a background thread.
|
||||
/// A singleton snapshot of the reader state. This is factored out for thread-safety reasons:
|
||||
/// it may be fetched on a background thread.
|
||||
fn commandline_state_snapshot() -> MutexGuard<'static, CommandlineState> {
|
||||
static STATE: Mutex<CommandlineState> = Mutex::new(CommandlineState::new());
|
||||
STATE.lock().unwrap()
|
||||
|
@ -233,7 +233,6 @@ fn reader_push_ret(
|
|||
if reader_data_stack().len() == 1 {
|
||||
reader_interactive_init(parser);
|
||||
}
|
||||
data.update_commandline_state();
|
||||
data
|
||||
}
|
||||
|
||||
|
@ -252,7 +251,6 @@ pub fn reader_pop() {
|
|||
new_reader
|
||||
.screen
|
||||
.reset_abandoning_line(usize::try_from(termsize_last().width).unwrap());
|
||||
new_reader.update_commandline_state();
|
||||
} else {
|
||||
reader_interactive_destroy();
|
||||
*commandline_state_snapshot() = CommandlineState::new();
|
||||
|
@ -907,7 +905,6 @@ pub fn reader_execute_readline_cmd(ch: CharEvent) {
|
|||
}
|
||||
data.save_screen_state();
|
||||
data.handle_char_event(Some(ch));
|
||||
data.update_commandline_state();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -940,7 +937,10 @@ pub fn reader_readline(nchars: usize) -> Option<WString> {
|
|||
}
|
||||
|
||||
/// Get the command line state. This may be fetched on a background thread.
|
||||
pub fn commandline_get_state() -> CommandlineState {
|
||||
pub fn commandline_get_state(sync: bool) -> CommandlineState {
|
||||
if sync {
|
||||
current_data().map(|data| data.update_commandline_state());
|
||||
}
|
||||
commandline_state_snapshot().clone()
|
||||
}
|
||||
|
||||
|
@ -1182,27 +1182,34 @@ impl ReaderData {
|
|||
self.pager_selection_changed();
|
||||
}
|
||||
}
|
||||
// Ensure that the commandline builtin sees our new state.
|
||||
self.update_commandline_state();
|
||||
}
|
||||
|
||||
/// Reflect our current data in the command line state snapshot.
|
||||
/// This is called before we run any fish script, so that the commandline builtin can see our
|
||||
/// state.
|
||||
fn update_commandline_state(&self) {
|
||||
let mut snapshot = commandline_state_snapshot();
|
||||
snapshot.text = self.command_line.text().to_owned();
|
||||
if snapshot.text != self.command_line.text() {
|
||||
snapshot.text = self.command_line.text().to_owned();
|
||||
}
|
||||
snapshot.cursor_pos = self.command_line.position();
|
||||
snapshot.history = Some(self.history.clone());
|
||||
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(),
|
||||
)
|
||||
});
|
||||
if snapshot
|
||||
.search_field
|
||||
.as_ref()
|
||||
.is_none_or(|(text, position)| {
|
||||
text != self.pager.search_field_line.text()
|
||||
|| *position != self.pager.search_field_line.position()
|
||||
})
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -1211,7 +1218,7 @@ impl ReaderData {
|
|||
/// incorporating changes from the commandline builtin.
|
||||
fn apply_commandline_state_changes(&mut self) {
|
||||
// Only the text and cursor position may be changed.
|
||||
let state = commandline_get_state();
|
||||
let state = commandline_get_state(false);
|
||||
if state.text != self.command_line.text()
|
||||
|| state.cursor_pos != self.command_line.position()
|
||||
{
|
||||
|
@ -1904,7 +1911,6 @@ impl ReaderData {
|
|||
|
||||
/// Run a sequence of commands from an input binding.
|
||||
fn run_input_command_scripts(&mut self, cmd: &wstr) {
|
||||
self.update_commandline_state();
|
||||
self.eval_bind_cmd(cmd);
|
||||
|
||||
// Restore tty to shell modes.
|
||||
|
@ -4554,7 +4560,6 @@ impl ReaderData {
|
|||
let (elt, el) = self.active_edit_line();
|
||||
if self.conf.expand_abbrev_ok && elt == EditableLineTag::Commandline {
|
||||
// Try expanding abbreviations.
|
||||
self.update_commandline_state();
|
||||
let cursor_pos = el.position().saturating_sub(cursor_backtrack);
|
||||
if let Some(replacement) =
|
||||
reader_expand_abbreviation_at_cursor(el.text(), cursor_pos, self.parser())
|
||||
|
@ -5284,9 +5289,6 @@ impl ReaderData {
|
|||
// up to the end of the token we're completing.
|
||||
let cmdsub = &el.text()[cmdsub_range.start..token_range.end];
|
||||
|
||||
// Ensure that `commandline` inside the completions gets the current state.
|
||||
self.update_commandline_state();
|
||||
|
||||
let (comp, _needs_load) = complete(
|
||||
cmdsub,
|
||||
CompletionRequestOptions::normal(),
|
||||
|
|
13
tests/checks/tmux-bind2.fish
Normal file
13
tests/checks/tmux-bind2.fish
Normal file
|
@ -0,0 +1,13 @@
|
|||
#RUN: %fish %s
|
||||
#REQUIRES: command -v tmux
|
||||
|
||||
isolated-tmux-start
|
||||
|
||||
isolated-tmux send-keys "function prepend; commandline --cursor 0; commandline -i echo; end" Enter
|
||||
isolated-tmux send-keys "bind c-g prepend" Enter
|
||||
isolated-tmux send-keys C-l
|
||||
isolated-tmux send-keys 'printf'
|
||||
isolated-tmux send-keys C-g Space
|
||||
tmux-sleep
|
||||
isolated-tmux capture-pane -p
|
||||
# CHECK: prompt 2> echo printf
|
Loading…
Reference in a new issue