Detailed changes
@@ -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:
@@ -36,6 +36,7 @@
DerivedData/
Packages
xcuserdata/
+crates/docs_preprocessor/actions.json
# Don't commit any secrets to the repo.
.env
@@ -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",
]
@@ -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"
@@ -22,16 +22,13 @@ static KEYMAP_WINDOWS: LazyLock<KeymapFile> = LazyLock::new(|| {
load_keymap("keymaps/default-windows.json").expect("Failed to load Windows keymap")
});
-static ALL_ACTIONS: LazyLock<Vec<ActionDef>> = LazyLock::new(dump_all_gpui_actions);
+static ALL_ACTIONS: LazyLock<Vec<ActionDef>> = LazyLock::new(load_all_actions);
const FRONT_MATTER_COMMENT: &str = "<!-- ZED_META {} -->";
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::<Vec<_>>();
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<Prepr
chapter.content = regex
.replace_all(&chapter.content, |caps: ®ex::Captures| {
let action = caps[1].trim();
- if find_action_by_name(action).is_none() {
+ if is_missing_action(action) {
errors.insert(PreprocessorError::new_for_not_found_action(
action.to_string(),
));
@@ -244,10 +241,12 @@ fn template_and_validate_actions(book: &mut Book, errors: &mut HashSet<Preproces
.replace_all(&chapter.content, |caps: ®ex::Captures| {
let name = caps[1].trim();
let Some(action) = find_action_by_name(name) else {
- errors.insert(PreprocessorError::new_for_not_found_action(
- name.to_string(),
- ));
- return String::new();
+ if actions_available() {
+ errors.insert(PreprocessorError::new_for_not_found_action(
+ name.to_string(),
+ ));
+ }
+ return format!("<code class=\"hljs\">{}</code>", name);
};
format!("<code class=\"hljs\">{}</code>", &action.human_name)
})
@@ -257,11 +256,19 @@ fn template_and_validate_actions(book: &mut Book, errors: &mut HashSet<Preproces
fn find_action_by_name(name: &str) -> 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<String> {
let keymap = match os {
"macos" => &KEYMAP_MACOS,
@@ -384,18 +391,13 @@ fn template_and_validate_json_snippets(book: &mut Book, errors: &mut HashSet<Pre
let keymap = settings::KeymapFile::parse(&snippet_json_fixed)
.context("Failed to parse keymap JSON")?;
for section in keymap.sections() {
- for (keystrokes, action) in section.bindings() {
- keystrokes
- .split_whitespace()
- .map(|source| gpui::Keystroke::parse(source))
- .collect::<std::result::Result<Vec<_>, _>>()
- .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<String>,
+ #[serde(rename = "documentation")]
+ docs: Option<String>,
}
-fn dump_all_gpui_actions() -> Vec<ActionDef> {
- 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::<Vec<ActionDef>>();
-
- actions.sort_by_key(|a| a.name);
-
- actions
+fn load_all_actions() -> Vec<ActionDef> {
+ let asset_path = concat!(env!("CARGO_MANIFEST_DIR"), "/actions.json");
+ match std::fs::read_to_string(asset_path) {
+ Ok(content) => {
+ let mut actions: Vec<ActionDef> =
+ 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::<Vec<_>>();
- 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("<dl style=\"line-height: 1.8;\">\n");
@@ -664,7 +674,7 @@ fn generate_big_table_of_actions() -> String {
output.push_str("<dd style=\"margin-left: 2em; margin-bottom: 1em;\">\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("<br>\n");
}
output.push_str("Keymap Name: <code>");
- output.push_str(action.name);
+ output.push_str(&action.name);
output.push_str("</code><br>\n");
if !action.deprecated_aliases.is_empty() {
output.push_str("Deprecated Alias(es): ");
@@ -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);
@@ -15,10 +15,6 @@ tracy = ["ztracing/tracy"]
[[bin]]
name = "zed"
-path = "src/zed-main.rs"
-
-[lib]
-name = "zed"
path = "src/main.rs"
[dependencies]
@@ -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<Instant> = OnceLock::new();
+static STARTUP_TIME: OnceLock<Instant> = OnceLock::new();
-pub fn main() {
+fn main() {
STARTUP_TIME.get_or_init(|| Instant::now());
#[cfg(unix)]
@@ -1301,7 +1304,7 @@ fn init_paths() -> HashMap<io::ErrorKind, Vec<&'static Path>> {
})
}
-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::<Vec<ActionDef>>();
@@ -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();
-}
@@ -4780,7 +4780,6 @@ mod tests {
"activity_indicator",
"agent",
"agents",
- #[cfg(not(target_os = "macos"))]
"app_menu",
"assistant",
"assistant2",
@@ -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"
@@ -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(