From 70f7db14d4141c4680fda82a5519fbcd4080bd1f Mon Sep 17 00:00:00 2001 From: Yash Thakur <45539777+ysthakur@users.noreply.github.com> Date: Mon, 18 Dec 2023 10:33:04 -0500 Subject: [PATCH] Only run $env.PROMPT_COMMAND once per prompt (copy of #10986) (#11366) # Description This PR is basically a copy of #10986 by @CAD97, which made `$env.PROMPT_COMMAND` only run once per prompt, but @fdncred found an issue where hitting Enter would make the transient prompt appear and be immediately overwritten by the regular prompt, so it was [reverted](https://github.com/nushell/nushell/pull/11340). https://github.com/nushell/nushell/pull/10788 was also made to do the same thing as #10986 but that ended up having the same issue. For some reason, this branch doesn't have that problem, although I haven't figured out why yet. @CAD97, if you have any inputs or want to make your own PR, let me know. # User-Facing Changes When hitting enter, the prompt shouldn't blink in place anymore. # Tests + Formatting # After Submitting --- crates/nu-cli/src/prompt_update.rs | 176 ++++++++--------------------- crates/nu-cli/src/repl.rs | 25 ++-- 2 files changed, 54 insertions(+), 147 deletions(-) diff --git a/crates/nu-cli/src/prompt_update.rs b/crates/nu-cli/src/prompt_update.rs index bacb1167a24f..8b3f28b71787 100644 --- a/crates/nu-cli/src/prompt_update.rs +++ b/crates/nu-cli/src/prompt_update.rs @@ -7,8 +7,6 @@ use nu_protocol::{ Config, PipelineData, Value, }; use reedline::Prompt; -use std::borrow::Cow; -use std::sync::{Arc, RwLock}; // Name of environment variable where the prompt could be stored pub(crate) const PROMPT_COMMAND: &str = "PROMPT_COMMAND"; @@ -102,7 +100,7 @@ pub(crate) fn update_prompt( config: &Config, engine_state: &EngineState, stack: &Stack, - nu_prompt: Arc>, + nu_prompt: &mut NushellPrompt, ) { let mut stack = stack.clone(); @@ -138,145 +136,63 @@ pub(crate) fn update_prompt( get_prompt_string(PROMPT_INDICATOR_VI_NORMAL, config, engine_state, &mut stack); // apply the other indicators - nu_prompt - .write() - .expect("Could not lock on nu_prompt to update") - .update_all_prompt_strings( - left_prompt_string, - right_prompt_string, - prompt_indicator_string, - prompt_multiline_string, - (prompt_vi_insert_string, prompt_vi_normal_string), - config.render_right_prompt_on_last_line, - ); - + nu_prompt.update_all_prompt_strings( + left_prompt_string, + right_prompt_string, + prompt_indicator_string, + prompt_multiline_string, + (prompt_vi_insert_string, prompt_vi_normal_string), + config.render_right_prompt_on_last_line, + ); trace!("update_prompt {}:{}:{}", file!(), line!(), column!()); } -struct TransientPrompt { - prompt_lock: Arc>, - engine_state: Arc, - stack: Stack, -} +/// Construct the transient prompt based on the normal nu_prompt +pub(crate) fn make_transient_prompt( + config: &Config, + engine_state: &EngineState, + stack: &mut Stack, + nu_prompt: &NushellPrompt, +) -> Box { + let mut nu_prompt = nu_prompt.clone(); -impl TransientPrompt { - fn new_prompt(&self, shell_integration: bool) -> NushellPrompt { - if let Ok(prompt) = self.prompt_lock.read() { - prompt.clone() - } else { - NushellPrompt::new(shell_integration) - } + if let Some(s) = get_prompt_string(TRANSIENT_PROMPT_COMMAND, config, engine_state, stack) { + nu_prompt.update_prompt_left(Some(s)) } -} -impl Prompt for TransientPrompt { - fn render_prompt_left(&self) -> Cow { - let config = self.engine_state.get_config(); - let mut nu_prompt = self.new_prompt(config.shell_integration); - let mut stack = self.stack.clone(); - if let Some(s) = get_prompt_string( - TRANSIENT_PROMPT_COMMAND, - config, - &self.engine_state, - &mut stack, - ) { - nu_prompt.update_prompt_left(Some(s)) - } - let left_prompt = nu_prompt.render_prompt_left(); - if config.shell_integration { - format!("{PRE_PROMPT_MARKER}{left_prompt}{POST_PROMPT_MARKER}").into() - } else { - left_prompt.to_string().into() - } + if let Some(s) = get_prompt_string(TRANSIENT_PROMPT_COMMAND_RIGHT, config, engine_state, stack) + { + nu_prompt.update_prompt_right(Some(s), config.render_right_prompt_on_last_line) } - fn render_prompt_right(&self) -> Cow { - let config = self.engine_state.get_config(); - let mut nu_prompt = self.new_prompt(config.shell_integration); - let mut stack = self.stack.clone(); - if let Some(s) = get_prompt_string( - TRANSIENT_PROMPT_COMMAND_RIGHT, - config, - &self.engine_state, - &mut stack, - ) { - nu_prompt.update_prompt_right(Some(s), config.render_right_prompt_on_last_line) - } - nu_prompt.render_prompt_right().to_string().into() + if let Some(s) = get_prompt_string(TRANSIENT_PROMPT_INDICATOR, config, engine_state, stack) { + nu_prompt.update_prompt_indicator(Some(s)) } - - fn render_prompt_indicator(&self, prompt_mode: reedline::PromptEditMode) -> Cow { - let config = self.engine_state.get_config(); - let mut nu_prompt = self.new_prompt(config.shell_integration); - let mut stack = self.stack.clone(); - if let Some(s) = get_prompt_string( - TRANSIENT_PROMPT_INDICATOR, - config, - &self.engine_state, - &mut stack, - ) { - nu_prompt.update_prompt_indicator(Some(s)) - } - if let Some(s) = get_prompt_string( - TRANSIENT_PROMPT_INDICATOR_VI_INSERT, - config, - &self.engine_state, - &mut stack, - ) { - nu_prompt.update_prompt_vi_insert(Some(s)) - } - if let Some(s) = get_prompt_string( - TRANSIENT_PROMPT_INDICATOR_VI_NORMAL, - config, - &self.engine_state, - &mut stack, - ) { - nu_prompt.update_prompt_vi_normal(Some(s)) - } - nu_prompt - .render_prompt_indicator(prompt_mode) - .to_string() - .into() + if let Some(s) = get_prompt_string( + TRANSIENT_PROMPT_INDICATOR_VI_INSERT, + config, + engine_state, + stack, + ) { + nu_prompt.update_prompt_vi_insert(Some(s)) } - - fn render_prompt_multiline_indicator(&self) -> Cow { - let config = self.engine_state.get_config(); - let mut nu_prompt = self.new_prompt(config.shell_integration); - let mut stack = self.stack.clone(); - if let Some(s) = get_prompt_string( - TRANSIENT_PROMPT_MULTILINE_INDICATOR, - config, - &self.engine_state, - &mut stack, - ) { - nu_prompt.update_prompt_multiline(Some(s)) - } - nu_prompt - .render_prompt_multiline_indicator() - .to_string() - .into() + if let Some(s) = get_prompt_string( + TRANSIENT_PROMPT_INDICATOR_VI_NORMAL, + config, + engine_state, + stack, + ) { + nu_prompt.update_prompt_vi_normal(Some(s)) } - fn render_prompt_history_search_indicator( - &self, - history_search: reedline::PromptHistorySearch, - ) -> Cow { - NushellPrompt::new(self.engine_state.get_config().shell_integration) - .render_prompt_history_search_indicator(history_search) - .to_string() - .into() + if let Some(s) = get_prompt_string( + TRANSIENT_PROMPT_MULTILINE_INDICATOR, + config, + engine_state, + stack, + ) { + nu_prompt.update_prompt_multiline(Some(s)) } -} -/// Construct the transient prompt -pub(crate) fn transient_prompt( - prompt_lock: Arc>, - engine_state: Arc, - stack: &Stack, -) -> Box { - Box::new(TransientPrompt { - prompt_lock, - engine_state, - stack: stack.clone(), - }) + Box::new(nu_prompt) } diff --git a/crates/nu-cli/src/repl.rs b/crates/nu-cli/src/repl.rs index ac2dc87781a5..bf53a994022c 100644 --- a/crates/nu-cli/src/repl.rs +++ b/crates/nu-cli/src/repl.rs @@ -29,7 +29,7 @@ use std::{ env::temp_dir, io::{self, IsTerminal, Write}, path::Path, - sync::{atomic::Ordering, Arc, RwLock}, + sync::atomic::Ordering, time::Instant, }; use sysinfo::SystemExt; @@ -69,7 +69,7 @@ pub fn evaluate_repl( let mut entry_num = 0; - let nu_prompt = Arc::new(RwLock::new(NushellPrompt::new(config.shell_integration))); + let mut nu_prompt = NushellPrompt::new(config.shell_integration); let start_time = std::time::Instant::now(); // Translate environment variables from Strings to Values @@ -268,12 +268,7 @@ pub fn evaluate_repl( .with_quick_completions(config.quick_completions) .with_partial_completions(config.partial_completions) .with_ansi_colors(config.use_ansi_coloring) - .with_cursor_config(cursor_config) - .with_transient_prompt(prompt_update::transient_prompt( - Arc::clone(&nu_prompt), - engine_reference.clone(), - stack, - )); + .with_cursor_config(cursor_config); perf( "reedline builder", start_time, @@ -426,7 +421,9 @@ pub fn evaluate_repl( start_time = std::time::Instant::now(); let config = &engine_state.get_config().clone(); - prompt_update::update_prompt(config, engine_state, stack, Arc::clone(&nu_prompt)); + prompt_update::update_prompt(config, engine_state, stack, &mut nu_prompt); + let transient_prompt = + prompt_update::make_transient_prompt(config, engine_state, stack, &nu_prompt); perf( "update_prompt", start_time, @@ -439,14 +436,8 @@ pub fn evaluate_repl( entry_num += 1; start_time = std::time::Instant::now(); - let input = { - line_editor.read_line( - &nu_prompt - .read() - .expect("Could not lock on prompt to pass to read_line") - .to_owned(), - ) - }; + line_editor = line_editor.with_transient_prompt(transient_prompt); + let input = line_editor.read_line(&nu_prompt); let shell_integration = config.shell_integration; match input {