diff --git a/CMakeLists.txt b/CMakeLists.txt index 862bd6117..281455fed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,8 +123,7 @@ set(FISH_SRCS src/pager.cpp src/parse_execution.cpp src/parse_tree.cpp src/parse_util.cpp src/parser.cpp src/parser_keywords.cpp src/path.cpp src/postfork.cpp src/proc.cpp src/re.cpp src/reader.cpp src/screen.cpp - src/signals.cpp src/tinyexpr.cpp - src/trace.cpp src/utf8.cpp + src/signals.cpp src/tinyexpr.cpp src/utf8.cpp src/wcstringutil.cpp src/wgetopt.cpp src/wildcard.cpp src/wutil.cpp src/fds.cpp src/rustffi.cpp ) diff --git a/fish-rust/build.rs b/fish-rust/build.rs index c1553ed75..5ffbbabd1 100644 --- a/fish-rust/build.rs +++ b/fish-rust/build.rs @@ -39,6 +39,7 @@ fn main() -> miette::Result<()> { "src/timer.rs", "src/tokenizer.rs", "src/topic_monitor.rs", + "src/trace.rs", "src/util.rs", "src/wait_handle.rs", "src/builtins/shared.rs", diff --git a/fish-rust/src/ffi.rs b/fish-rust/src/ffi.rs index 997227f1f..deebfe238 100644 --- a/fish-rust/src/ffi.rs +++ b/fish-rust/src/ffi.rs @@ -56,6 +56,7 @@ include_cpp! { generate!("valid_var_name_char") generate!("get_flog_file_fd") + generate!("log_extra_to_flog_file") generate!("parse_util_unescape_wildcards") diff --git a/fish-rust/src/lib.rs b/fish-rust/src/lib.rs index e6e8f0947..e0af59d0d 100644 --- a/fish-rust/src/lib.rs +++ b/fish-rust/src/lib.rs @@ -28,6 +28,7 @@ mod ffi_init; mod ffi_tests; mod flog; mod future_feature_flags; +mod global_safety; mod job_group; mod locale; mod nix; @@ -42,6 +43,7 @@ mod threads; mod timer; mod tokenizer; mod topic_monitor; +mod trace; mod util; mod wait_handle; mod wchar; diff --git a/fish-rust/src/trace.rs b/fish-rust/src/trace.rs new file mode 100644 index 000000000..0f554b5f0 --- /dev/null +++ b/fish-rust/src/trace.rs @@ -0,0 +1,74 @@ +use crate::{ + common::{escape_string, EscapeStringStyle}, + ffi::{self, parser_t, wcharz_t}, + global_safety::RelaxedAtomicBool, + wchar::{self, wstr, L}, + wchar_ffi::WCharToFFI, +}; + +#[cxx::bridge] +mod trace_ffi { + extern "C++" { + include!("wutil.h"); + include!("parser.h"); + type wcharz_t = super::wcharz_t; + type parser_t = super::parser_t; + } + + extern "Rust" { + fn trace_set_enabled(do_enable: bool); + fn trace_enabled(parser: &parser_t) -> bool; + #[cxx_name = "trace_argv"] + fn trace_argv_ffi(parser: &parser_t, command: wcharz_t, args: &Vec); + } +} + +static DO_TRACE: RelaxedAtomicBool = RelaxedAtomicBool::new(false); + +pub fn trace_set_enabled(do_enable: bool) { + DO_TRACE.store(do_enable); +} + +/// return whether tracing is enabled. +pub fn trace_enabled(parser: &parser_t) -> bool { + let ld = parser.ffi_libdata_pod_const(); + if ld.suppress_fish_trace { + return false; + } + DO_TRACE.load() +} + +/// Trace an "argv": a list of arguments where the first is the command. +// Allow the `&Vec` parameter as this function only exists temporarily for the FFI +#[allow(clippy::ptr_arg)] +fn trace_argv_ffi(parser: &parser_t, command: wcharz_t, args: &Vec) { + let command: wchar::WString = command.into(); + let args: Vec = args.iter().map(Into::into).collect(); + let args_ref: Vec<&wstr> = args.iter().map(wchar::WString::as_utfstr).collect(); + trace_argv(parser, command.as_utfstr(), &args_ref); +} + +pub fn trace_argv(parser: &parser_t, command: &wstr, args: &[&wstr]) { + // Format into a string to prevent interleaving with flog in other threads. + // Add the + prefix. + let mut trace_text = L!("-").repeat(parser.blocks_size() - 1); + trace_text.push('>'); + + if !command.is_empty() { + trace_text.push(' '); + trace_text.push_utfstr(command); + } + for arg in args { + trace_text.push(' '); + trace_text.push_utfstr(&escape_string(arg, EscapeStringStyle::default())); + } + trace_text.push('\n'); + ffi::log_extra_to_flog_file(&trace_text.to_ffi()); +} + +/// Convenience helper to trace a single string if tracing is enabled. +pub fn trace_if_enabled(parser: &parser_t, command: &wstr, args: &[&wstr]) { + if trace_enabled(parser) { + trace_argv(parser, command, args); + } +} diff --git a/src/builtin.cpp b/src/builtin.cpp index ed9d86566..3bf424c8e 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -59,6 +59,7 @@ #include "cxx.h" #include "cxxgen.h" #include "fallback.h" // IWYU pragma: keep +#include "ffi.h" #include "flog.h" #include "io.h" #include "null_terminated_array.h" @@ -565,13 +566,8 @@ static maybe_t try_get_rust_builtin(const wcstring &cmd) { static maybe_t builtin_run_rust(parser_t &parser, io_streams_t &streams, const wcstring_list_t &argv, RustBuiltin builtin) { - ::rust::Vec rust_argv; - for (const wcstring &arg : argv) { - rust_argv.emplace_back(arg.c_str()); - } - int status_code; - bool update_status = rust_run_builtin(parser, streams, rust_argv, builtin, status_code); + bool update_status = rust_run_builtin(parser, streams, to_rust_string_vec(argv), builtin, status_code); if (update_status) { return status_code; } else { diff --git a/src/env_dispatch.cpp b/src/env_dispatch.cpp index c7659d2b5..1b8efe5c3 100644 --- a/src/env_dispatch.cpp +++ b/src/env_dispatch.cpp @@ -47,7 +47,7 @@ #include "reader.h" #include "screen.h" #include "termsize.h" -#include "trace.h" +#include "trace.rs.h" #include "wcstringutil.h" #include "wutil.h" diff --git a/src/exec.cpp b/src/exec.cpp index 57a666fea..de025deb3 100644 --- a/src/exec.cpp +++ b/src/exec.cpp @@ -7,6 +7,7 @@ #include #include #include +#include "trace.rs.h" #ifdef HAVE_SIGINFO_H #include #endif @@ -33,6 +34,7 @@ #include "exec.h" #include "fallback.h" // IWYU pragma: keep #include "fds.h" +#include "ffi.h" #include "flog.h" #include "function.h" #include "global_safety.h" @@ -48,7 +50,7 @@ #include "reader.h" #include "redirection.h" #include "timer.rs.h" -#include "trace.h" +#include "trace.rs.h" #include "wcstringutil.h" #include "wutil.h" // IWYU pragma: keep @@ -827,9 +829,7 @@ static launch_result_t exec_process_in_job(parser_t &parser, process_t *p, // Maybe trace this process. // TODO: 'and' and 'or' will not show. - if (trace_enabled(parser)) { - trace_argv(parser, nullptr, p->argv()); - } + trace_if_enabled(parser, L"", p->argv()); // The IO chain for this process. io_chain_t process_net_io_chain = block_io; diff --git a/src/ffi.h b/src/ffi.h index 711ece232..9dea99f97 100644 --- a/src/ffi.h +++ b/src/ffi.h @@ -2,6 +2,7 @@ #include #include "cxx.h" +#include "trace.rs.h" #if INCLUDE_RUST_HEADERS // For some unknown reason, the definition of rust::Box is in this particular header: #include "parse_constants.rs.h" @@ -13,3 +14,19 @@ inline std::shared_ptr box_to_shared_ptr(rust::Box &&value) { std::shared_ptr shared(ptr, [](T *ptr) { rust::Box::from_raw(ptr); }); return shared; } + +inline static rust::Vec to_rust_string_vec(const wcstring_list_t &strings) { + rust::Vec rust_strings; + rust_strings.reserve(strings.size()); + for (const wcstring &string : strings) { + rust_strings.emplace_back(string.c_str()); + } + return rust_strings; +} + +inline static void trace_if_enabled(const parser_t &parser, wcharz_t command, + const wcstring_list_t &args = {}) { + if (trace_enabled(parser)) { + trace_argv(parser, command, to_rust_string_vec(args)); + } +} diff --git a/src/parse_execution.cpp b/src/parse_execution.cpp index e67d2031e..a8ed65c4f 100644 --- a/src/parse_execution.cpp +++ b/src/parse_execution.cpp @@ -42,7 +42,7 @@ #include "reader.h" #include "timer.rs.h" #include "tokenizer.h" -#include "trace.h" +#include "trace.rs.h" #include "wildcard.h" #include "wutil.h" @@ -390,6 +390,7 @@ end_execution_reason_t parse_execution_context_t::run_function_statement( if (result != end_execution_reason_t::ok) { return result; } + trace_if_enabled(*parser, L"function", arguments); null_output_stream_t outs; string_output_stream_t errs; @@ -537,7 +538,8 @@ end_execution_reason_t parse_execution_context_t::run_switch_statement( } end_execution_reason_t result = end_execution_reason_t::ok; - if (trace_enabled(*parser)) trace_argv(*parser, L"switch", {switch_value_expanded}); + + trace_if_enabled(*parser, L"switch", {switch_value_expanded}); block_t *sb = parser->push_block(block_t::switch_block()); // Expand case statements. diff --git a/src/parser.cpp b/src/parser.cpp index 89a18fdf2..d5d2e5ed0 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -514,6 +514,7 @@ job_t *parser_t::job_get_from_pid(int64_t pid, size_t &job_pos) const { library_data_pod_t *parser_t::ffi_libdata_pod() { return &library_data; } job_t *parser_t::ffi_job_get_from_pid(int pid) const { return job_get_from_pid(pid); } +const library_data_pod_t &parser_t::ffi_libdata_pod_const() const { return library_data; } profile_item_t *parser_t::create_profile_item() { if (g_profiling_active) { diff --git a/src/parser.h b/src/parser.h index 661e3c54f..4a78b1d03 100644 --- a/src/parser.h +++ b/src/parser.h @@ -383,6 +383,8 @@ class parser_t : public std::enable_shared_from_this { /// Return the list of blocks. The first block is at the top. const std::deque &blocks() const { return block_list; } + size_t blocks_size() const { return block_list.size(); } + /// Get the list of jobs. job_list_t &jobs() { return job_list; } const job_list_t &jobs() const { return job_list; } @@ -500,6 +502,7 @@ class parser_t : public std::enable_shared_from_this { RustFFIJobList ffi_jobs() const; library_data_pod_t *ffi_libdata_pod(); job_t *ffi_job_get_from_pid(int pid) const; + const library_data_pod_t &ffi_libdata_pod_const() const; /// autocxx junk. bool ffi_has_funtion_block() const; diff --git a/src/trace.cpp b/src/trace.cpp deleted file mode 100644 index 8fa2cfe63..000000000 --- a/src/trace.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include "config.h" // IWYU pragma: keep - -#include "trace.h" - -#include -#include - -#include "common.h" -#include "flog.h" -#include "parser.h" - -static bool do_trace = false; - -void trace_set_enabled(bool do_enable) { do_trace = do_enable; } - -bool trace_enabled(const parser_t &parser) { - const auto &ld = parser.libdata(); - if (ld.suppress_fish_trace) return false; - return do_trace; -} - -/// Trace an "argv": a list of arguments where the first is the command. -void trace_argv(const parser_t &parser, const wchar_t *command, const wcstring_list_t &argv) { - // Format into a string to prevent interleaving with flog in other threads. - // Add the + prefix. - wcstring trace_text(parser.blocks().size() - 1, L'-'); - trace_text.push_back(L'>'); - - if (command && command[0]) { - trace_text.push_back(L' '); - trace_text.append(command); - } - for (const wcstring &arg : argv) { - trace_text.push_back(L' '); - trace_text.append(escape_string(arg)); - } - trace_text.push_back(L'\n'); - log_extra_to_flog_file(trace_text); -} - -void trace_if_enabled(const parser_t &parser, const wchar_t *command, const wcstring_list_t &argv) { - if (trace_enabled(parser)) trace_argv(parser, command, argv); -} diff --git a/src/trace.h b/src/trace.h deleted file mode 100644 index e891fdbb3..000000000 --- a/src/trace.h +++ /dev/null @@ -1,25 +0,0 @@ -/// Support for fish_trace. -#ifndef FISH_TRACE_H -#define FISH_TRACE_H - -#include "config.h" // IWYU pragma: keep - -#include "common.h" - -class parser_t; - -/// Trace an "argv": a list of arguments. Each argument is escaped. -/// If \p command is not null, it is traced first (and not escaped) -void trace_argv(const parser_t &parser, const wchar_t *command, const wcstring_list_t &argv); - -/// \return whether tracing is enabled. -bool trace_enabled(const parser_t &parser); - -/// Enable or disable tracing. -void trace_set_enabled(bool do_enable); - -/// Convenience helper to trace a single string if tracing is enabled. -void trace_if_enabled(const parser_t &parser, const wchar_t *command, - const wcstring_list_t &argv = {}); - -#endif