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

View File

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

View File

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

View File

@ -213,10 +213,11 @@ pub fn nu_repl() {
// Check for pre_execution hook
let config = engine_state.get_config();
*engine_state
.repl_buffer_state
engine_state
.repl_state
.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 Err(err) = eval_hook(&mut engine_state, &mut stack, None, vec![], &hook) {