Update docs for transient prompt

See #11153
This commit is contained in:
kerty
2025-03-24 17:58:25 +03:00
committed by Johannes Altmanninger
parent ca1d7ef863
commit 231ab22ce4
2 changed files with 61 additions and 26 deletions

View File

@@ -5,7 +5,7 @@
use crate::input_common::{update_wait_on_escape_ms, update_wait_on_sequence_key_ms};
use crate::reader::{
reader_change_cursor_end_mode, reader_change_cursor_selection_mode, reader_change_history,
reader_schedule_prompt_repaint, reader_set_autosuggestion_enabled,
reader_schedule_prompt_repaint, reader_set_autosuggestion_enabled, reader_set_transient_prompt,
};
use crate::screen::{
screen_set_midnight_commander_hack, IS_DUMB, LAYOUT_CACHE_SHARED, ONLY_GRAYSCALE,
@@ -73,6 +73,7 @@
L!("fish_autosuggestion_enabled"),
handle_autosuggestion_change,
);
table.add_anon(L!("fish_transient_prompt"), handle_transient_prompt_change);
table.add_anon(
L!("fish_use_posix_spawn"),
handle_fish_use_posix_spawn_change,
@@ -284,6 +285,10 @@ fn handle_autosuggestion_change(vars: &EnvStack) {
reader_set_autosuggestion_enabled(vars);
}
fn handle_transient_prompt_change(vars: &EnvStack) {
reader_set_transient_prompt(vars);
}
fn handle_function_path_change(_: &EnvStack) {
function::invalidate_path();
}

View File

@@ -320,6 +320,9 @@ pub struct ReaderConfig {
/// Whether to allow autosuggestions.
pub autosuggest_ok: bool,
/// Whether to reexecute prompt function before final rendering.
pub transient_prompt: bool,
/// Whether to expand abbreviations.
pub expand_abbrev_ok: bool,
@@ -666,12 +669,13 @@ fn read_i(parser: &Parser) {
assert_is_main_thread();
parser.assert_can_execute();
let mut conf = ReaderConfig::default();
conf.event = L!("fish_prompt");
conf.complete_ok = true;
conf.highlight_ok = true;
conf.syntax_check_ok = true;
conf.autosuggest_ok = check_autosuggestion_enabled(parser.vars());
conf.expand_abbrev_ok = true;
conf.event = L!("fish_prompt");
conf.autosuggest_ok = check_bool_var(parser.vars(), L!("fish_autosuggestion_enabled"), true);
conf.transient_prompt = check_bool_var(parser.vars(), L!("fish_transient_prompt"), false);
if parser.is_breakpoint() && function::exists(DEBUG_PROMPT_FUNCTION_NAME, parser) {
conf.left_prompt_cmd = DEBUG_PROMPT_FUNCTION_NAME.to_owned();
@@ -933,25 +937,32 @@ pub fn reader_change_cursor_end_mode(end_mode: CursorEndMode) {
}
}
fn check_autosuggestion_enabled(vars: &dyn Environment) -> bool {
vars.get(L!("fish_autosuggestion_enabled"))
fn check_bool_var(vars: &dyn Environment, name: &wstr, default: bool) -> bool {
vars.get(name)
.map(|v| v.as_string())
.map(|v| v != L!("0"))
.unwrap_or(true)
.unwrap_or(default)
}
/// Enable or disable autosuggestions based on the associated variable.
pub fn reader_set_autosuggestion_enabled(vars: &dyn Environment) {
// We don't need to _change_ if we're not initialized yet.
let Some(data) = current_data() else {
return;
};
let enable = check_autosuggestion_enabled(vars);
if data.conf.autosuggest_ok != enable {
data.conf.autosuggest_ok = enable;
data.force_exec_prompt_and_repaint = true;
data.input_data
.queue_char(CharEvent::from_readline(ReadlineCmd::Repaint));
if let Some(data) = current_data() {
let enable = check_bool_var(vars, L!("fish_autosuggestion_enabled"), true);
if data.conf.autosuggest_ok != enable {
data.conf.autosuggest_ok = enable;
data.force_exec_prompt_and_repaint = true;
data.input_data
.queue_char(CharEvent::from_readline(ReadlineCmd::Repaint));
}
}
}
/// Enable or disable transient prompt based on the associated variable.
pub fn reader_set_transient_prompt(vars: &dyn Environment) {
// We don't need to _change_ if we're not initialized yet.
if let Some(data) = current_data() {
data.conf.transient_prompt = check_bool_var(vars, L!("fish_transient_prompt"), false);
}
}
@@ -2220,7 +2231,7 @@ fn readline(&mut self, nchars: Option<NonZeroUsize>) -> Option<WString> {
if !self.conf.event.is_empty() {
event::fire_generic(self.parser, self.conf.event.to_owned(), vec![]);
}
self.exec_prompt(true);
self.exec_prompt(true, false);
// Start out as initially dirty.
self.force_exec_prompt_and_repaint = true;
@@ -2231,6 +2242,10 @@ fn readline(&mut self, nchars: Option<NonZeroUsize>) -> Option<WString> {
}
}
if self.conf.transient_prompt {
self.exec_prompt(true, true);
}
// Redraw the command line. This is what ensures the autosuggestion is hidden, etc. after the
// user presses enter.
if self.is_repaint_needed(None)
@@ -2736,7 +2751,7 @@ fn handle_readline_command(&mut self, c: ReadlineCmd) {
// This can happen e.g. if a variable triggers a repaint,
// and the variable is set inside the prompt (#7324).
// builtin commandline will refuse to enqueue these.
self.exec_prompt(false);
self.exec_prompt(false, false);
if !self.mode_prompt_buff.is_empty() {
if self.is_repaint_needed(None) {
self.screen.reset_line(/*repaint_prompt=*/ true);
@@ -2747,7 +2762,7 @@ fn handle_readline_command(&mut self, c: ReadlineCmd) {
}
// Else we repaint as normal.
}
self.exec_prompt(true);
self.exec_prompt(true, false);
self.screen.reset_line(/*repaint_prompt=*/ true);
self.layout_and_repaint(L!("readline"));
self.force_exec_prompt_and_repaint = false;
@@ -3853,7 +3868,7 @@ fn clear_screen_and_repaint(&mut self) {
self.screen.reset_line(/*repaint_prompt=*/ true);
self.layout_and_repaint(L!("readline"));
self.exec_prompt(true);
self.exec_prompt(true, false);
self.screen.reset_line(/*repaint_prompt=*/ true);
self.layout_and_repaint(L!("readline"));
self.force_exec_prompt_and_repaint = false;
@@ -4523,14 +4538,23 @@ pub fn reader_write_title(
}
impl<'a> Reader<'a> {
fn exec_prompt_cmd(&self, prompt_cmd: &wstr) -> Vec<WString> {
fn exec_prompt_cmd(&self, prompt_cmd: &wstr, final_prompt: bool) -> Vec<WString> {
let mut output = vec![];
let _ = exec_subshell(prompt_cmd, self.parser, Some(&mut output), false);
if final_prompt && function::exists(prompt_cmd, self.parser) {
let _ = exec_subshell(
&(prompt_cmd.to_owned() + L!(" --final-rendering")),
self.parser,
Some(&mut output),
false,
);
} else {
let _ = exec_subshell(prompt_cmd, self.parser, Some(&mut output), false);
};
output
}
/// Execute prompt commands based on the provided arguments. The output is inserted into prompt_buff.
fn exec_prompt(&mut self, full_prompt: bool) {
fn exec_prompt(&mut self, full_prompt: bool, final_prompt: bool) {
// Suppress fish_trace while in the prompt.
let _suppress_trace = self.parser.push_scope(|s| s.suppress_fish_trace = true);
@@ -4545,7 +4569,7 @@ fn exec_prompt(&mut self, full_prompt: bool) {
if function::exists(MODE_PROMPT_FUNCTION_NAME, self.parser) {
// We do not support multiline mode indicators, so just concatenate all of them.
self.mode_prompt_buff =
WString::from_iter(self.exec_prompt_cmd(MODE_PROMPT_FUNCTION_NAME));
WString::from_iter(self.exec_prompt_cmd(MODE_PROMPT_FUNCTION_NAME, final_prompt));
}
if full_prompt {
@@ -4564,7 +4588,12 @@ fn exec_prompt(&mut self, full_prompt: bool) {
DEFAULT_PROMPT
};
self.left_prompt_buff = join_strings(&self.exec_prompt_cmd(prompt_cmd), '\n');
self.left_prompt_buff =
join_strings(&self.exec_prompt_cmd(prompt_cmd, final_prompt), '\n');
if final_prompt {
self.screen.reset_line(true)
}
}
// Don't execute the right prompt if it is undefined fish_right_prompt
@@ -4573,8 +4602,9 @@ fn exec_prompt(&mut self, full_prompt: bool) {
|| function::exists(&self.conf.right_prompt_cmd, self.parser))
{
// Right prompt does not support multiple lines, so just concatenate all of them.
self.right_prompt_buff =
WString::from_iter(self.exec_prompt_cmd(&self.conf.right_prompt_cmd));
self.right_prompt_buff = WString::from_iter(
self.exec_prompt_cmd(&self.conf.right_prompt_cmd, final_prompt),
);
}
}