fix(shell_integration): set window title on startup (#12569)

Should close #10833 — though I'd imagine that should have already been
closed.

# Description

Very minor tweak, but it was quite noticeable when using Zellij which
relies on OSC 2 to set pane titles. Before the change:

![image](https://github.com/nushell/nushell/assets/6251883/b944bbce-2040-4886-9955-3c5b57d368e9)

Note that the default `Pane #1` is still showing for the untouched
shell, but running a command like `htop` or `ls` correctly sets the
title during / afterwards.

After this PR:

![image](https://github.com/nushell/nushell/assets/6251883/dd513cfe-923c-450f-b0f2-c66938b0d6f0)

There are now no-longer any unset titles — even if the shell hasn't been
touched.

**As an aside:** I feel quite strongly that (at least OSC 2) shell
integration should be enabled by default, as it is for every other Linux
shell I've used, but I'm not sure which issues that caused that the
default config refers to? Which terminals are broken by shell
integration, and could some of the shell integrations be turned on by
default after splitting things into sub-options as suggested in #11301 ?

# User-Facing Changes

You'll just have shell integrations working from right after the shell
has been launched, instead of needing to run something first.

# Tests + Formatting

Not quite sure how to test this one? Are there any other tests that
currently exist for shell integration? I couldn't quite track them
down...

# After Submitting

Let me know if you think this needs any user-facing docs changes!
This commit is contained in:
Brooks Rady 2024-04-18 18:30:37 -07:00 committed by GitHub
parent 7fe2e60af7
commit 351bff8233
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -74,7 +74,8 @@ pub fn evaluate_repl(
let mut entry_num = 0;
let nu_prompt = NushellPrompt::new(config.shell_integration);
let shell_integration = config.shell_integration;
let nu_prompt = NushellPrompt::new(shell_integration);
let start_time = std::time::Instant::now();
// Translate environment variables from Strings to Values
@ -114,6 +115,11 @@ pub fn evaluate_repl(
engine_state.merge_env(&mut unique_stack, cwd)?;
}
let hostname = System::host_name();
if shell_integration {
shell_integration_osc_7_633_2(hostname.as_deref(), engine_state, &mut unique_stack);
}
engine_state.set_startup_time(entire_start_time.elapsed().as_nanos() as i64);
// Regenerate the $nu constant to contain the startup time and any other potential updates
@ -147,7 +153,7 @@ pub fn evaluate_repl(
let temp_file_cloned = temp_file.clone();
let mut nu_prompt_cloned = nu_prompt.clone();
let iteration_panic_state = catch_unwind(AssertUnwindSafe(move || {
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,
@ -156,6 +162,7 @@ pub fn evaluate_repl(
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
@ -232,6 +239,7 @@ struct LoopContext<'a> {
temp_file: &'a Path,
use_color: bool,
entry_num: &'a mut usize,
hostname: Option<&'a str>,
}
/// Perform one iteration of the REPL loop
@ -250,6 +258,7 @@ fn loop_iteration(ctx: LoopContext) -> (bool, Stack, Reedline) {
temp_file,
use_color,
entry_num,
hostname,
} = ctx;
let cwd = get_guaranteed_cwd(engine_state, &stack);
@ -520,14 +529,13 @@ fn loop_iteration(ctx: LoopContext) -> (bool, Stack, Reedline) {
let line_editor_input_time = std::time::Instant::now();
match input {
Ok(Signal::Success(s)) => {
let hostname = System::host_name();
let history_supports_meta = matches!(
engine_state.history_config().map(|h| h.file_format),
Some(HistoryFileFormat::Sqlite)
);
if history_supports_meta {
prepare_history_metadata(&s, &hostname, engine_state, &mut line_editor);
prepare_history_metadata(&s, hostname, engine_state, &mut line_editor);
}
// For pre_exec_hook
@ -658,7 +666,7 @@ fn loop_iteration(ctx: LoopContext) -> (bool, Stack, Reedline) {
if shell_integration {
start_time = Instant::now();
do_shell_integration_finalize_command(hostname, engine_state, &mut stack);
shell_integration_osc_7_633_2(hostname, engine_state, &mut stack);
perf(
"shell_integration_finalize ansi escape sequences",
@ -759,7 +767,7 @@ fn loop_iteration(ctx: LoopContext) -> (bool, Stack, Reedline) {
///
fn prepare_history_metadata(
s: &str,
hostname: &Option<String>,
hostname: Option<&str>,
engine_state: &EngineState,
line_editor: &mut Reedline,
) {
@ -767,7 +775,7 @@ fn prepare_history_metadata(
let result = line_editor
.update_last_command_context(&|mut c| {
c.start_timestamp = Some(chrono::Utc::now());
c.hostname.clone_from(hostname);
c.hostname = hostname.map(str::to_string);
c.cwd = Some(StateWorkingSet::new(engine_state).get_cwd());
c
@ -1014,10 +1022,11 @@ fn do_run_cmd(
///
/// Output some things and set environment variables so shells with the right integration
/// can have more information about what is going on (after we have run a command)
/// can have more information about what is going on (both on startup and after we have
/// run a command)
///
fn do_shell_integration_finalize_command(
hostname: Option<String>,
fn shell_integration_osc_7_633_2(
hostname: Option<&str>,
engine_state: &EngineState,
stack: &mut Stack,
) {
@ -1037,7 +1046,7 @@ fn do_shell_integration_finalize_command(
run_ansi_sequence(&format!(
"\x1b]7;file://{}{}{}\x1b\\",
percent_encoding::utf8_percent_encode(
&hostname.unwrap_or_else(|| "localhost".to_string()),
hostname.unwrap_or("localhost"),
percent_encoding::CONTROLS
),
if path.starts_with('/') { "" } else { "/" },