diff --git a/share/completions/set.fish b/share/completions/set.fish index cccf262ca418..9fa132be0937 100644 --- a/share/completions/set.fish +++ b/share/completions/set.fish @@ -54,7 +54,6 @@ function __fish_complete_special_vars FISH_DEBUG_OUTPUT "debug output path" \ umask "current file creation mask" \ fish_handle_reflow "if fish should repaint prompt when the term resizes" \ - fish_trace "print cmds as they execute, like set -x" \ fish_emoji_width "cols wide fish assumes emoji render as" \ fish_key_bindings "name of function that sets binds" \ fish_autosuggestion_enabled "turns autosuggestions on or off" \ @@ -62,7 +61,7 @@ function __fish_complete_special_vars fish_escape_delay_ms "How long fish waits to distinguish escape and alt" \ fish_greeting "The message to display at start (also a function)" \ fish_history "The session id to store history under" \ - fish_trace "Enables execution tracing (if set to non-empty value)" \ + fish_trace "Enables execution tracing, usually '1', or bind/event/prompt/title/all" \ fish_user_paths "A list of dirs to prepend to PATH" end diff --git a/src/env_dispatch.rs b/src/env_dispatch.rs index 6a63b9bfe6b5..7f01ab3eacf2 100644 --- a/src/env_dispatch.rs +++ b/src/env_dispatch.rs @@ -352,7 +352,7 @@ fn handle_read_limit_change(vars: &EnvStack) { } fn handle_fish_trace(vars: &EnvStack) { - let enabled = vars.get_unless_empty(L!("fish_trace")).is_some(); + let enabled = vars.get_unless_empty(L!("fish_trace")); crate::trace::trace_set_enabled(enabled); } diff --git a/src/event.rs b/src/event.rs index b698f856323a..f7d579118626 100644 --- a/src/event.rs +++ b/src/event.rs @@ -15,6 +15,7 @@ use crate::job_group::MaybeJobId; use crate::parser::{Block, Parser}; use crate::signal::{signal_check_cancel, signal_handle, Signal}; use crate::termsize; +use crate::trace::{should_suppress_trace, TraceCategory}; use crate::wchar::prelude::*; pub enum event_type_t { @@ -466,15 +467,17 @@ fn fire_internal(parser: &Parser, event: &Event) { |new_value| std::mem::replace(&mut parser.libdata_mut().pods.is_event, new_value), is_event + 1, ); - let _suppress_trace = scoped_push_replacer( - |new_value| { - std::mem::replace( - &mut parser.libdata_mut().pods.suppress_fish_trace, - new_value, - ) - }, - true, - ); + let _suppress_trace = should_suppress_trace(TraceCategory::Event).then(|| { + scoped_push_replacer( + |new_value| { + std::mem::replace( + &mut parser.libdata_mut().pods.suppress_fish_trace, + new_value, + ) + }, + true, + ) + }); // Capture the event handlers that match this event. let fire: Vec<_> = EVENT_HANDLERS diff --git a/src/parser.rs b/src/parser.rs index 9e1aefd96f8c..1779f560dd61 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1286,8 +1286,8 @@ pub struct library_data_pod_t { /// Whether we are currently interactive. pub is_interactive: bool, - /// Whether to suppress fish_trace output. This occurs in the prompt, event handlers, and key - /// bindings. + /// Whether to suppress fish_trace output. This may occur in prompt, title, event handlers, + /// and key bindings. pub suppress_fish_trace: bool, /// Whether we should break or continue the current loop. diff --git a/src/reader.rs b/src/reader.rs index 44e1b1cc3ffe..a124095dd74e 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -110,6 +110,7 @@ use crate::tokenizer::{ tok_command, MoveWordStateMachine, MoveWordStyle, TokenType, Tokenizer, TOK_ACCEPT_UNFINISHED, TOK_SHOW_COMMENTS, }; +use crate::trace::{should_suppress_trace, TraceCategory}; use crate::wchar::prelude::*; use crate::wcstringutil::{ count_preceding_backslashes, join_strings, string_prefixes_string, @@ -1751,10 +1752,14 @@ impl ReaderData { let mut zelf = scoped_push_replacer_ctx( self, |zelf, new_value| { - std::mem::replace( - &mut zelf.parser().libdata_mut().pods.suppress_fish_trace, - new_value, - ) + if should_suppress_trace(TraceCategory::Bind) { + std::mem::replace( + &mut zelf.parser().libdata_mut().pods.suppress_fish_trace, + new_value, + ) + } else { + false // Don't care + } }, true, ); @@ -3644,15 +3649,17 @@ pub fn reader_write_title( |new_value| std::mem::replace(&mut parser.libdata_mut().pods.is_interactive, new_value), false, ); - let _in_title = scoped_push_replacer( - |new_value| { - std::mem::replace( - &mut parser.libdata_mut().pods.suppress_fish_trace, - new_value, - ) - }, - true, - ); + let _in_title = should_suppress_trace(TraceCategory::Title).then(|| { + scoped_push_replacer( + |new_value| { + std::mem::replace( + &mut parser.libdata_mut().pods.suppress_fish_trace, + new_value, + ) + }, + true, + ) + }); let mut fish_title_command = DEFAULT_TITLE.to_owned(); if function::exists(L!("fish_title"), parser) { @@ -3721,10 +3728,14 @@ impl ReaderData { let mut zelf = scoped_push_replacer_ctx( self, |zelf, new_value| { - std::mem::replace( - &mut zelf.parser().libdata_mut().pods.suppress_fish_trace, - new_value, - ) + if should_suppress_trace(TraceCategory::Prompt) { + std::mem::replace( + &mut zelf.parser().libdata_mut().pods.suppress_fish_trace, + new_value, + ) + } else { + false // Don't care + } }, true, ); diff --git a/src/trace.rs b/src/trace.rs index 1d1fcefc63be..1187cee3b2c8 100644 --- a/src/trace.rs +++ b/src/trace.rs @@ -1,20 +1,51 @@ +use std::sync::Mutex; + +use crate::env::EnvVar; use crate::flog::log_extra_to_flog_file; +#[allow(unused_imports)] +use crate::future::IsSomeAnd; use crate::parser::Parser; -use crate::{common::escape, global_safety::RelaxedAtomicBool, wchar::prelude::*}; +use crate::{common::escape, wchar::prelude::*}; + +static TRACE_VAR: Mutex> = Mutex::new(None); + +pub fn trace_set_enabled(trace_var: Option) { + *TRACE_VAR.lock().unwrap() = trace_var; +} + +pub(crate) enum TraceCategory { + Bind, + Event, + Prompt, + Title, +} + +pub(crate) fn should_suppress_trace(category: TraceCategory) -> bool { + let trace_var = TRACE_VAR.lock().unwrap(); + let Some(enabled_categories) = trace_var.as_ref() else { + return false; // not tracing, no need to suppress anything + }; + let enabled_categories = enabled_categories.as_list(); -static DO_TRACE: RelaxedAtomicBool = RelaxedAtomicBool::new(false); + let category = match category { + TraceCategory::Bind => "bind", + TraceCategory::Event => "event", + TraceCategory::Prompt => "prompt", + TraceCategory::Title => "title", + }; -pub fn trace_set_enabled(do_enable: bool) { - DO_TRACE.store(do_enable); + !enabled_categories + .iter() + .any(|s| s == "all" || s == category) } /// return whether tracing is enabled. -pub fn trace_enabled(parser: &Parser) -> bool { +fn trace_enabled(parser: &Parser) -> bool { let ld = &parser.libdata().pods; if ld.suppress_fish_trace { return false; } - DO_TRACE.load() + TRACE_VAR.lock().unwrap().is_some() } /// Trace an "argv": a list of arguments where the first is the command.