From 3f67c5220d3834817e84c454c29a8f92f2688c1d Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Thu, 18 Dec 2025 20:59:05 -0600 Subject: [PATCH] Remove `zed` dependency from `docs_preprocessor` (#45130) Closes #ISSUE Uses the existing `--dump-all-actions` arg on the Zed binary to generate an asset of all of our actions so that the `docs_preprocessor` can injest it, rather than depending on the Zed crate itself to collect all action names Release Notes: - N/A *or* Added/Fixed/Improved ... --------- Co-authored-by: Zed Zippy <234243425+zed-zippy[bot]@users.noreply.github.com> --- .github/workflows/run_tests.yml | 3 + .gitignore | 1 + Cargo.lock | 3 - crates/docs_preprocessor/Cargo.toml | 5 +- crates/docs_preprocessor/src/main.rs | 88 +++++++++++-------- crates/title_bar/src/application_menu.rs | 20 ++--- crates/zed/Cargo.toml | 4 - crates/zed/src/main.rs | 13 +-- crates/zed/src/zed-main.rs | 8 -- crates/zed/src/zed.rs | 1 - script/generate-action-metadata | 10 +++ .../xtask/src/tasks/workflows/run_tests.rs | 1 + 12 files changed, 83 insertions(+), 74 deletions(-) delete mode 100644 crates/zed/src/zed-main.rs create mode 100755 script/generate-action-metadata diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index 256bb2916a56485c06c2ebc4de8724151d622c4f..47a84574e7c33fb8a40a90c67cd4f7dadb356978 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -353,6 +353,9 @@ jobs: - name: steps::download_wasi_sdk run: ./script/download-wasi-sdk shell: bash -euxo pipefail {0} + - name: ./script/generate-action-metadata + run: ./script/generate-action-metadata + shell: bash -euxo pipefail {0} - name: run_tests::check_docs::install_mdbook uses: peaceiris/actions-mdbook@ee69d230fe19748b7abf22df32acaa93833fad08 with: diff --git a/.gitignore b/.gitignore index 54faaf1374299ee8f97925a95a93b375c349d707..c71417c32bff76af9d4c9c67661556e1625c9d15 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,7 @@ DerivedData/ Packages xcuserdata/ +crates/docs_preprocessor/actions.json # Don't commit any secrets to the repo. .env diff --git a/Cargo.lock b/Cargo.lock index 1bb39f2bdf8c5745b3e5c0e5ad1200be34ec6ab0..3f7077e721e934cd6cb05af0cdaefef75602b429 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5021,8 +5021,6 @@ name = "docs_preprocessor" version = "0.1.0" dependencies = [ "anyhow", - "command_palette", - "gpui", "mdbook", "regex", "serde", @@ -5031,7 +5029,6 @@ dependencies = [ "task", "theme", "util", - "zed", "zlog", ] diff --git a/crates/docs_preprocessor/Cargo.toml b/crates/docs_preprocessor/Cargo.toml index e71f9ae3f3f6fcff790db27fb1e377f0d1c20e40..07da23899956822f7577118ae85b6338b4cefae7 100644 --- a/crates/docs_preprocessor/Cargo.toml +++ b/crates/docs_preprocessor/Cargo.toml @@ -7,8 +7,6 @@ license = "GPL-3.0-or-later" [dependencies] anyhow.workspace = true -command_palette.workspace = true -gpui.workspace = true # We are specifically pinning this version of mdbook, as later versions introduce issues with double-nested subdirectories. # Ask @maxdeviant about this before bumping. mdbook = "= 0.4.40" @@ -17,7 +15,6 @@ serde.workspace = true serde_json.workspace = true settings.workspace = true util.workspace = true -zed.workspace = true zlog.workspace = true task.workspace = true theme.workspace = true @@ -27,4 +24,4 @@ workspace = true [[bin]] name = "docs_preprocessor" -path = "src/main.rs" +path = "src/main.rs" \ No newline at end of file diff --git a/crates/docs_preprocessor/src/main.rs b/crates/docs_preprocessor/src/main.rs index b614a8251139413f4b316937db1d4e3c0d551df6..d90dcc10db9fbd8d27a968094ea8d733a79b7e80 100644 --- a/crates/docs_preprocessor/src/main.rs +++ b/crates/docs_preprocessor/src/main.rs @@ -22,16 +22,13 @@ static KEYMAP_WINDOWS: LazyLock = LazyLock::new(|| { load_keymap("keymaps/default-windows.json").expect("Failed to load Windows keymap") }); -static ALL_ACTIONS: LazyLock> = LazyLock::new(dump_all_gpui_actions); +static ALL_ACTIONS: LazyLock> = LazyLock::new(load_all_actions); const FRONT_MATTER_COMMENT: &str = ""; fn main() -> Result<()> { zlog::init(); zlog::init_output_stderr(); - // call a zed:: function so everything in `zed` crate is linked and - // all actions in the actual app are registered - zed::stdout_is_a_pty(); let args = std::env::args().skip(1).collect::>(); match args.get(0).map(String::as_str) { @@ -72,8 +69,8 @@ enum PreprocessorError { impl PreprocessorError { fn new_for_not_found_action(action_name: String) -> Self { for action in &*ALL_ACTIONS { - for alias in action.deprecated_aliases { - if alias == &action_name { + for alias in &action.deprecated_aliases { + if alias == action_name.as_str() { return PreprocessorError::DeprecatedActionUsed { used: action_name, should_be: action.name.to_string(), @@ -214,7 +211,7 @@ fn template_and_validate_keybindings(book: &mut Book, errors: &mut HashSet{}", name); }; format!("{}", &action.human_name) }) @@ -257,11 +256,19 @@ fn template_and_validate_actions(book: &mut Book, errors: &mut HashSet Option<&ActionDef> { ALL_ACTIONS - .binary_search_by(|action| action.name.cmp(name)) + .binary_search_by(|action| action.name.as_str().cmp(name)) .ok() .map(|index| &ALL_ACTIONS[index]) } +fn actions_available() -> bool { + !ALL_ACTIONS.is_empty() +} + +fn is_missing_action(name: &str) -> bool { + actions_available() && find_action_by_name(name).is_none() +} + fn find_binding(os: &str, action: &str) -> Option { let keymap = match os { "macos" => &KEYMAP_MACOS, @@ -384,18 +391,13 @@ fn template_and_validate_json_snippets(book: &mut Book, errors: &mut HashSet
, _>>()
-                            .context("Failed to parse keystroke")?;
+                    for (_keystrokes, action) in section.bindings() {
                         if let Some((action_name, _)) = settings::KeymapFile::parse_action(action)
                             .map_err(|err| anyhow::format_err!(err))
                             .context("Failed to parse action")?
                         {
                             anyhow::ensure!(
-                                find_action_by_name(action_name).is_some(),
+                                !is_missing_action(action_name),
                                 "Action not found: {}",
                                 action_name
                             );
@@ -491,27 +493,35 @@ where
     });
 }
 
-#[derive(Debug, serde::Serialize)]
+#[derive(Debug, serde::Serialize, serde::Deserialize)]
 struct ActionDef {
-    name: &'static str,
+    name: String,
     human_name: String,
-    deprecated_aliases: &'static [&'static str],
-    docs: Option<&'static str>,
+    deprecated_aliases: Vec,
+    #[serde(rename = "documentation")]
+    docs: Option,
 }
 
-fn dump_all_gpui_actions() -> Vec {
-    let mut actions = gpui::generate_list_of_all_registered_actions()
-        .map(|action| ActionDef {
-            name: action.name,
-            human_name: command_palette::humanize_action_name(action.name),
-            deprecated_aliases: action.deprecated_aliases,
-            docs: action.documentation,
-        })
-        .collect::>();
-
-    actions.sort_by_key(|a| a.name);
-
-    actions
+fn load_all_actions() -> Vec {
+    let asset_path = concat!(env!("CARGO_MANIFEST_DIR"), "/actions.json");
+    match std::fs::read_to_string(asset_path) {
+        Ok(content) => {
+            let mut actions: Vec =
+                serde_json::from_str(&content).expect("Failed to parse actions.json");
+            actions.sort_by(|a, b| a.name.cmp(&b.name));
+            actions
+        }
+        Err(err) => {
+            if std::env::var("CI").is_ok() {
+                panic!("actions.json not found at {}: {}", asset_path, err);
+            }
+            eprintln!(
+                "Warning: actions.json not found, action validation will be skipped: {}",
+                err
+            );
+            Vec::new()
+        }
+    }
 }
 
 fn handle_postprocessing() -> Result<()> {
@@ -647,7 +657,7 @@ fn generate_big_table_of_actions() -> String {
     let mut output = String::new();
 
     let mut actions_sorted = actions.iter().collect::>();
-    actions_sorted.sort_by_key(|a| a.name);
+    actions_sorted.sort_by_key(|a| a.name.as_str());
 
     // Start the definition list with custom styling for better spacing
     output.push_str("
\n"); @@ -664,7 +674,7 @@ fn generate_big_table_of_actions() -> String { output.push_str("
\n"); // Add the description, escaping HTML if needed - if let Some(description) = action.docs { + if let Some(description) = action.docs.as_ref() { output.push_str( &description .replace("&", "&") @@ -674,7 +684,7 @@ fn generate_big_table_of_actions() -> String { output.push_str("
\n"); } output.push_str("Keymap Name: "); - output.push_str(action.name); + output.push_str(&action.name); output.push_str("
\n"); if !action.deprecated_aliases.is_empty() { output.push_str("Deprecated Alias(es): "); diff --git a/crates/title_bar/src/application_menu.rs b/crates/title_bar/src/application_menu.rs index 817b73c45ecd2df4a76e9a67f425b2b459c0c026..579e4dadbd590981a4aee15019bbe73e2bb28d5c 100644 --- a/crates/title_bar/src/application_menu.rs +++ b/crates/title_bar/src/application_menu.rs @@ -1,12 +1,7 @@ -use gpui::{Entity, OwnedMenu, OwnedMenuItem}; +use gpui::{Action, Entity, OwnedMenu, OwnedMenuItem, actions}; use settings::Settings; -#[cfg(not(target_os = "macos"))] -use gpui::{Action, actions}; - -#[cfg(not(target_os = "macos"))] use schemars::JsonSchema; -#[cfg(not(target_os = "macos"))] use serde::Deserialize; use smallvec::SmallVec; @@ -14,18 +9,23 @@ use ui::{ContextMenu, PopoverMenu, PopoverMenuHandle, Tooltip, prelude::*}; use crate::title_bar_settings::TitleBarSettings; -#[cfg(not(target_os = "macos"))] actions!( app_menu, [ - /// Navigates to the menu item on the right. + /// Activates the menu on the right in the client-side application menu. + /// + /// Does not apply to platform menu bars (e.g. on macOS). ActivateMenuRight, - /// Navigates to the menu item on the left. + /// Activates the menu on the left in the client-side application menu. + /// + /// Does not apply to platform menu bars (e.g. on macOS). ActivateMenuLeft ] ); -#[cfg(not(target_os = "macos"))] +/// Opens the named menu in the client-side application menu. +/// +/// Does not apply to platform menu bars (e.g. on macOS). #[derive(Clone, Deserialize, JsonSchema, PartialEq, Default, Action)] #[action(namespace = app_menu)] pub struct OpenApplicationMenu(String); diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index fd160759f4440e2736d57cea62abb6bdb138ae72..80eca20e00309bb8d22552287a1c39cb9891307d 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -15,10 +15,6 @@ tracy = ["ztracing/tracy"] [[bin]] name = "zed" -path = "src/zed-main.rs" - -[lib] -name = "zed" path = "src/main.rs" [dependencies] diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 7008e491c5e2ade35fa96cafbd9d8969c008fa96..312d16f0cd674a6dda81176863a859f3b763c2c0 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -1,3 +1,6 @@ +// Disable command line from opening on release mode +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + mod reliability; mod zed; @@ -163,9 +166,9 @@ fn fail_to_open_window(e: anyhow::Error, _cx: &mut App) { .detach(); } } -pub static STARTUP_TIME: OnceLock = OnceLock::new(); +static STARTUP_TIME: OnceLock = OnceLock::new(); -pub fn main() { +fn main() { STARTUP_TIME.get_or_init(|| Instant::now()); #[cfg(unix)] @@ -1301,7 +1304,7 @@ fn init_paths() -> HashMap> { }) } -pub fn stdout_is_a_pty() -> bool { +fn stdout_is_a_pty() -> bool { std::env::var(FORCE_CLI_MODE_ENV_VAR_NAME).ok().is_none() && io::stdout().is_terminal() } @@ -1547,14 +1550,14 @@ fn dump_all_gpui_actions() { struct ActionDef { name: &'static str, human_name: String, - aliases: &'static [&'static str], + deprecated_aliases: &'static [&'static str], documentation: Option<&'static str>, } let mut actions = gpui::generate_list_of_all_registered_actions() .map(|action| ActionDef { name: action.name, human_name: command_palette::humanize_action_name(action.name), - aliases: action.deprecated_aliases, + deprecated_aliases: action.deprecated_aliases, documentation: action.documentation, }) .collect::>(); diff --git a/crates/zed/src/zed-main.rs b/crates/zed/src/zed-main.rs deleted file mode 100644 index 6c49c197dda01e97828c3662aa09ecf57804dfbc..0000000000000000000000000000000000000000 --- a/crates/zed/src/zed-main.rs +++ /dev/null @@ -1,8 +0,0 @@ -// Disable command line from opening on release mode -#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] - -pub fn main() { - // separated out so that the file containing the main function can be imported by other crates, - // while having all gpui resources that are registered in main (primarily actions) initialized - zed::main(); -} diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index d088df00839814e32a9c246a3486ac5ad5ca4b9e..3441cb88d96b06dfdbb65a58553d2c58f435d157 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -4780,7 +4780,6 @@ mod tests { "activity_indicator", "agent", "agents", - #[cfg(not(target_os = "macos"))] "app_menu", "assistant", "assistant2", diff --git a/script/generate-action-metadata b/script/generate-action-metadata new file mode 100755 index 0000000000000000000000000000000000000000..146b1f0d78ef92c47322a70dccf0e9e1f3f530d3 --- /dev/null +++ b/script/generate-action-metadata @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +set -euo pipefail + +cd "$(dirname "$0")/.." + +echo "Generating action metadata..." +cargo run -p zed -- --dump-all-actions > crates/docs_preprocessor/actions.json + +echo "Generated crates/docs_preprocessor/actions.json with $(grep -c '"name":' crates/docs_preprocessor/actions.json) actions" diff --git a/tooling/xtask/src/tasks/workflows/run_tests.rs b/tooling/xtask/src/tasks/workflows/run_tests.rs index f726f48740eb7819fbbd3fed369e5e4e89c526c9..aceb575b647e7ea0b2d8a74da9fbc153767d149d 100644 --- a/tooling/xtask/src/tasks/workflows/run_tests.rs +++ b/tooling/xtask/src/tasks/workflows/run_tests.rs @@ -448,6 +448,7 @@ fn check_docs() -> NamedJob { lychee_link_check("./docs/src/**/*"), // check markdown links ) .map(steps::install_linux_dependencies) + .add_step(steps::script("./script/generate-action-metadata")) .add_step(install_mdbook()) .add_step(build_docs()) .add_step(