Repository: nushell/nushell
File: crates/nu-cli/src/repl.rs (Rust)

Code before:
        let iteration_panic_state = catch_unwind(AssertUnwindSafe(|| {
            let (continue_loop, current_stack, line_editor) = loop_iteration(LoopContext {
                engine_state: &mut current_engine_state,
                stack: current_stack,
                line_editor,
                nu_prompt: &mut nu_prompt_cloned,
                temp_file: &temp_file_cloned,
                use_color,
                entry_num: &mut entry_num,
                hostname: hostname.as_deref(),
            });

            // pass the most recent version of the line_editor back
            (
                continue_loop,
                current_engine_state,
                current_stack,
                line_editor,
            )
        }));
        match iteration_panic_state {
            Ok((continue_loop, es, s, le)) => {
                // We apply the changes from the updated stack back onto our previous stack
                let mut merged_stack = Stack::with_changes_from_child(previous_stack_arc, s);
                // Clean up unused variables from stack to prevent memory leaks from variable shadowing
                es.cleanup_stack_variables(&mut merged_stack);
                previous_stack_arc = Arc::new(merged_stack);
                // setup state for the next iteration of the repl loop
                previous_engine_state = es;
                line_editor = le;
                if !continue_loop {
                    break;
                }
            }
            Err(_) => {
                // line_editor is lost in the error case so reconstruct a new one
                line_editor = get_line_editor(engine_state, use_color)?;
            }
        }
    }

    Ok(())
}

fn escape_special_vscode_bytes(input: &str) -> Result<String, ShellError> {
    let bytes = input
        .chars()
        .flat_map(|c| {
            let mut buf = [0; 4]; // Buffer to hold UTF-8 bytes of the character
            let c_bytes = c.encode_utf8(&mut buf); // Get UTF-8 bytes for the character


Review comment (suggestion):
Does it get executed for each loop in the REPL, even if it has nothing to do with variable shadowing at all?

I guess the extra overhead is marginal comparing to other heavy stuff like prompt painting, yet I still prefer a lighter solution, if possible.

Code after:
        let mut nu_prompt_cloned = nu_prompt.clone();

        let iteration_panic_state = catch_unwind(AssertUnwindSafe(|| {
            let (continue_loop, current_stack, line_editor) = loop_iteration(LoopContext {
                engine_state: &mut current_engine_state,
                stack: current_stack,
                line_editor,
                nu_prompt: &mut nu_prompt_cloned,
                temp_file: &temp_file_cloned,
                use_color,
                entry_num: &mut entry_num,
                hostname: hostname.as_deref(),
            });

            // pass the most recent version of the line_editor back
            (
                continue_loop,
                current_engine_state,
                current_stack,
                line_editor,
            )
        }));
        match iteration_panic_state {
            Ok((continue_loop, mut es, s, le)) => {
                // We apply the changes from the updated stack back onto our previous stack
                let mut merged_stack = Stack::with_changes_from_child(previous_stack_arc, s);

                // Check if new variables were created (indicating potential variable shadowing)
                let prev_total_vars = previous_engine_state.num_vars();
                let curr_total_vars = es.num_vars();
                let new_variables_created = curr_total_vars > prev_total_vars;

                if new_variables_created {
                    // New variables created, clean up stack to prevent memory leaks
                    es.cleanup_stack_variables(&mut merged_stack);
                }

                previous_stack_arc = Arc::new(merged_stack);
                // setup state for the next iteration of the repl loop
                previous_engine_state = es;
                line_editor = le;
                if !continue_loop {
                    break;
                }
            }
            Err(_) => {
                // line_editor is lost in the error case so reconstruct a new one
                line_editor = get_line_editor(engine_state, use_color)?;
            }
        }
    }