From d0e47cf58a8bb90cfcf4ecbdef447f3cfe823874 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Thu, 30 Apr 2026 18:54:24 +0800 Subject: [PATCH] Move current_filename out of LibraryData The ScopedRefCell wrapping from library_data is used for two things 1. to allow mutating library_data from a &Parser (for this, a RefCell would be enough) 2. to replace "current_filename" for a scope A following commit wants to pass parser as "&mut Parser", which voids reason 1. It will also remove the ScopedRefCell wrapping from LibraryData because reason 2 alone is not strong enough. Move "current_filename" outside of that, next to "current_node" which is already a ScopedRefCell. In future we could maybe consolidate them into one field, like (or even merging with) ScopedData. --- src/bin/fish.rs | 6 ++---- src/builtins/function.rs | 2 +- src/builtins/source.rs | 4 ++-- src/exec.rs | 2 +- src/parser.rs | 13 ++++++------- 5 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/bin/fish.rs b/src/bin/fish.rs index 78d74e42f..54e83ea0a 100644 --- a/src/bin/fish.rs +++ b/src/bin/fish.rs @@ -588,10 +588,8 @@ fn throwing_main() -> i32 { list.iter().map(|s| s.to_owned()).collect(), ); let _filename_push = parser - .library_data - .scoped_set(Some(Arc::new(filename.to_owned())), |s| { - &mut s.current_filename - }); + .current_filename + .scoped_replace(Some(Arc::new(filename.to_owned()))); res = reader_read(parser, f.as_raw_fd(), &IoChain::new()); if res.is_err() { flog!( diff --git a/src/builtins/function.rs b/src/builtins/function.rs index d64f7a240..3f66a28f7 100644 --- a/src/builtins/function.rs +++ b/src/builtins/function.rs @@ -317,7 +317,7 @@ pub fn function( } // Extract the current filename. - let definition_file = parser.libdata().current_filename.clone(); + let definition_file = parser.current_filename.borrow().clone(); // Ensure inherit_vars is unique and then populate it. opts.inherit_vars.sort_unstable(); diff --git a/src/builtins/source.rs b/src/builtins/source.rs index b8a85857e..23428997b 100644 --- a/src/builtins/source.rs +++ b/src/builtins/source.rs @@ -72,8 +72,8 @@ pub fn source(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> B let sb = parser.push_block(Block::source_block(func_filename.clone())); let _filename_push = parser - .library_data - .scoped_set(Some(func_filename.clone()), |s| &mut s.current_filename); + .current_filename + .scoped_replace(Some(func_filename.clone())); // Construct argv for the sourced file from our remaining args. // This is slightly subtle. If this is a bare `source` with no args then `argv + optind` already diff --git a/src/exec.rs b/src/exec.rs index 45692d259..c32fe4f5d 100644 --- a/src/exec.rs +++ b/src/exec.rs @@ -901,7 +901,7 @@ fn exec_external_command( #[cfg(have_posix_spawn)] // Prefer to use posix_spawn, since it's faster on some systems like OS X. if can_use_posix_spawn_for_job(j, &dup2s) { - let file = &parser.libdata().current_filename; + let file = parser.current_filename.borrow(); let count = FORK_COUNT.fetch_add(1, Ordering::Relaxed) + 1; // spawn counts as a fork+exec let pid = PosixSpawner::new(j, pgroup_policy, &dup2s).and_then(|mut spawner| { diff --git a/src/parser.rs b/src/parser.rs index e87e2024f..a5709d977 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -269,9 +269,6 @@ fn default() -> Self { /// Miscellaneous data used to avoid recursion and others. #[derive(Default)] pub struct LibraryData { - /// The current filename we are evaluating, either from builtin source or on the command line. - pub current_filename: Option, - /// A fake value to be returned by builtin_commandline. This is used by the completion /// machinery when wrapping: e.g. if `tig` wraps `git` then git completions need to see git on /// the command line. @@ -383,6 +380,9 @@ pub enum CancelBehavior { pub struct Parser { pub interactive_initialized: RelaxedAtomicBool, + /// The current filename we are evaluating, either from builtin source or on the command line. + pub current_filename: ScopedRefCell>, + /// The currently executing Node. current_node: ScopedRefCell>>, @@ -445,6 +445,7 @@ pub fn new(variables: EnvStack, cancel_behavior: CancelBehavior) -> Parser { let result = Self { interactive_initialized: RelaxedAtomicBool::new(false), current_node: ScopedRefCell::new(None), + current_filename: ScopedRefCell::new(None), job_list: RefCell::default(), wait_handles: RefCell::default(), block_list: RefCell::default(), @@ -604,9 +605,7 @@ pub fn eval_file_wstr( ) -> Result { let _interactive_push = self.push_scope(|s| s.is_interactive = false); let sb = self.push_block(Block::source_block(filename.clone())); - let _filename_push = self - .library_data - .scoped_set(Some(filename), |s| &mut s.current_filename); + let _filename_push = self.current_filename.scoped_replace(Some(filename)); let ret = self.eval_wstr(src, io, job_group, BlockType::Top); @@ -1200,7 +1199,7 @@ pub fn current_filename(&self) -> Option { Some(BlockData::Source { file, .. }) => Some(file.clone()), _ => None, }) - .or_else(|| self.libdata().current_filename.clone()) + .or_else(|| self.current_filename.borrow().clone()) } /// Return if we are interactive, which means we are executing a command that the user typed in