refactor: merge repl_buffer_state, repl_cursor_pos into one mutex (#9031)

# Description
Merge `repl_buffer_state`, `repl_cursor_pos` into one mutex.

# User-Facing Changes

# Tests + Formatting

# After Submitting
This commit is contained in:
Steven Xu 2023-06-11 08:38:11 +10:00 committed by GitHub
parent 374df9d69f
commit be53ecbbaa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 44 additions and 68 deletions

View File

@ -61,27 +61,20 @@ impl Command for Commandline {
_input: PipelineData, _input: PipelineData,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
if let Some(cmd) = call.opt::<Value>(engine_state, stack, 0)? { if let Some(cmd) = call.opt::<Value>(engine_state, stack, 0)? {
let mut buffer = engine_state let mut repl = engine_state.repl_state.lock().expect("repl state mutex");
.repl_buffer_state
.lock()
.expect("repl buffer state mutex");
let mut cursor_pos = engine_state
.repl_cursor_pos
.lock()
.expect("repl cursor pos mutex");
if call.has_flag("cursor") { if call.has_flag("cursor") {
let cmd_str = cmd.as_string()?; let cmd_str = cmd.as_string()?;
match cmd_str.parse::<i64>() { match cmd_str.parse::<i64>() {
Ok(n) => { Ok(n) => {
*cursor_pos = if n <= 0 { repl.cursor_pos = if n <= 0 {
0usize 0usize
} else { } else {
buffer repl.buffer
.grapheme_indices(true) .grapheme_indices(true)
.map(|(i, _c)| i) .map(|(i, _c)| i)
.nth(n as usize) .nth(n as usize)
.unwrap_or(buffer.len()) .unwrap_or(repl.buffer.len())
} }
} }
Err(_) => { Err(_) => {
@ -96,30 +89,25 @@ impl Command for Commandline {
} }
} }
} else if call.has_flag("append") { } else if call.has_flag("append") {
buffer.push_str(&cmd.as_string()?); repl.buffer.push_str(&cmd.as_string()?);
} else if call.has_flag("insert") { } else if call.has_flag("insert") {
let cmd_str = cmd.as_string()?; let cmd_str = cmd.as_string()?;
buffer.insert_str(*cursor_pos, &cmd_str); let cursor_pos = repl.cursor_pos;
*cursor_pos += cmd_str.len(); repl.buffer.insert_str(cursor_pos, &cmd_str);
repl.cursor_pos += cmd_str.len();
} else { } else {
*buffer = cmd.as_string()?; repl.buffer = cmd.as_string()?;
*cursor_pos = buffer.len(); repl.cursor_pos = repl.buffer.len();
} }
Ok(Value::Nothing { span: call.head }.into_pipeline_data()) Ok(Value::Nothing { span: call.head }.into_pipeline_data())
} else { } else {
let buffer = engine_state let repl = engine_state.repl_state.lock().expect("repl state mutex");
.repl_buffer_state
.lock()
.expect("repl buffer state mutex");
if call.has_flag("cursor") { if call.has_flag("cursor") {
let cursor_pos = engine_state let char_pos = repl
.repl_cursor_pos .buffer
.lock()
.expect("repl cursor pos mutex");
let char_pos = buffer
.grapheme_indices(true) .grapheme_indices(true)
.chain(std::iter::once((buffer.len(), ""))) .chain(std::iter::once((repl.buffer.len(), "")))
.position(|(i, _c)| i == *cursor_pos) .position(|(i, _c)| i == repl.cursor_pos)
.expect("Cursor position isn't on a grapheme boundary"); .expect("Cursor position isn't on a grapheme boundary");
Ok(Value::String { Ok(Value::String {
val: char_pos.to_string(), val: char_pos.to_string(),
@ -128,7 +116,7 @@ impl Command for Commandline {
.into_pipeline_data()) .into_pipeline_data())
} else { } else {
Ok(Value::String { Ok(Value::String {
val: buffer.to_string(), val: repl.buffer.to_string(),
span: call.head, span: call.head,
} }
.into_pipeline_data()) .into_pipeline_data())

View File

@ -475,30 +475,19 @@ pub fn evaluate_repl(
// hook // hook
if let Some(hook) = config.hooks.pre_execution.clone() { if let Some(hook) = config.hooks.pre_execution.clone() {
// Set the REPL buffer to the current command for the "pre_execution" hook // Set the REPL buffer to the current command for the "pre_execution" hook
let mut repl_buffer = engine_state let mut repl = engine_state.repl_state.lock().expect("repl state mutex");
.repl_buffer_state repl.buffer = s.to_string();
.lock() drop(repl);
.expect("repl buffer state mutex");
*repl_buffer = s.to_string();
drop(repl_buffer);
if let Err(err) = eval_hook(engine_state, stack, None, vec![], &hook) { if let Err(err) = eval_hook(engine_state, stack, None, vec![], &hook) {
report_error_new(engine_state, &err); report_error_new(engine_state, &err);
} }
} }
let mut repl_cursor = engine_state let mut repl = engine_state.repl_state.lock().expect("repl state mutex");
.repl_cursor_pos repl.cursor_pos = line_editor.current_insertion_point();
.lock() repl.buffer = line_editor.current_buffer_contents().to_string();
.expect("repl cursor pos mutex"); drop(repl);
*repl_cursor = line_editor.current_insertion_point();
drop(repl_cursor);
let mut repl_buffer = engine_state
.repl_buffer_state
.lock()
.expect("repl buffer state mutex");
*repl_buffer = line_editor.current_buffer_contents().to_string();
drop(repl_buffer);
if shell_integration { if shell_integration {
run_ansi_sequence(PRE_EXECUTE_MARKER)?; run_ansi_sequence(PRE_EXECUTE_MARKER)?;
@ -685,23 +674,15 @@ pub fn evaluate_repl(
run_ansi_sequence(RESET_APPLICATION_MODE)?; run_ansi_sequence(RESET_APPLICATION_MODE)?;
} }
let mut repl_buffer = engine_state let mut repl = engine_state.repl_state.lock().expect("repl state mutex");
.repl_buffer_state
.lock()
.expect("repl buffer state mutex");
let mut repl_cursor_pos = engine_state
.repl_cursor_pos
.lock()
.expect("repl cursor pos mutex");
line_editor.run_edit_commands(&[ line_editor.run_edit_commands(&[
EditCommand::Clear, EditCommand::Clear,
EditCommand::InsertString(repl_buffer.to_string()), EditCommand::InsertString(repl.buffer.to_string()),
EditCommand::MoveToPosition(*repl_cursor_pos), EditCommand::MoveToPosition(repl.cursor_pos),
]); ]);
*repl_buffer = "".to_string(); repl.buffer = "".to_string();
drop(repl_buffer); repl.cursor_pos = 0;
*repl_cursor_pos = 0; drop(repl);
drop(repl_cursor_pos);
} }
Ok(Signal::CtrlC) => { Ok(Signal::CtrlC) => {
// `Reedline` clears the line content. New prompt is shown // `Reedline` clears the line content. New prompt is shown

View File

@ -60,6 +60,12 @@ pub enum VirtualPath {
Dir(Vec<VirtualPathId>), Dir(Vec<VirtualPathId>),
} }
pub struct ReplState {
pub buffer: String,
// A byte position, as `EditCommand::MoveToPosition` is also a byte position
pub cursor_pos: usize,
}
/// The core global engine state. This includes all global definitions as well as any global state that /// The core global engine state. This includes all global definitions as well as any global state that
/// will persist for the whole session. /// will persist for the whole session.
/// ///
@ -118,10 +124,8 @@ pub struct EngineState {
pub previous_env_vars: HashMap<String, Value>, pub previous_env_vars: HashMap<String, Value>,
pub config: Config, pub config: Config,
pub pipeline_externals_state: Arc<(AtomicU32, AtomicU32)>, pub pipeline_externals_state: Arc<(AtomicU32, AtomicU32)>,
pub repl_buffer_state: Arc<Mutex<String>>, pub repl_state: Arc<Mutex<ReplState>>,
pub table_decl_id: Option<usize>, pub table_decl_id: Option<usize>,
// A byte position, as `EditCommand::MoveToPosition` is also a byte position
pub repl_cursor_pos: Arc<Mutex<usize>>,
#[cfg(feature = "plugin")] #[cfg(feature = "plugin")]
pub plugin_signatures: Option<PathBuf>, pub plugin_signatures: Option<PathBuf>,
#[cfg(not(windows))] #[cfg(not(windows))]
@ -174,8 +178,10 @@ impl EngineState {
previous_env_vars: HashMap::new(), previous_env_vars: HashMap::new(),
config: Config::default(), config: Config::default(),
pipeline_externals_state: Arc::new((AtomicU32::new(0), AtomicU32::new(0))), pipeline_externals_state: Arc::new((AtomicU32::new(0), AtomicU32::new(0))),
repl_buffer_state: Arc::new(Mutex::new("".to_string())), repl_state: Arc::new(Mutex::new(ReplState {
repl_cursor_pos: Arc::new(Mutex::new(0)), buffer: "".to_string(),
cursor_pos: 0,
})),
table_decl_id: None, table_decl_id: None,
#[cfg(feature = "plugin")] #[cfg(feature = "plugin")]
plugin_signatures: None, plugin_signatures: None,

View File

@ -213,10 +213,11 @@ pub fn nu_repl() {
// Check for pre_execution hook // Check for pre_execution hook
let config = engine_state.get_config(); let config = engine_state.get_config();
*engine_state engine_state
.repl_buffer_state .repl_state
.lock() .lock()
.expect("repl buffer state mutex") = line.to_string(); .expect("repl state mutex")
.buffer = line.to_string();
if let Some(hook) = config.hooks.pre_execution.clone() { if let Some(hook) = config.hooks.pre_execution.clone() {
if let Err(err) = eval_hook(&mut engine_state, &mut stack, None, vec![], &hook) { if let Err(err) = eval_hook(&mut engine_state, &mut stack, None, vec![], &hook) {