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>
This commit is contained in:
3
.github/workflows/run_tests.yml
vendored
3
.github/workflows/run_tests.yml
vendored
@@ -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:
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -36,6 +36,7 @@
|
||||
DerivedData/
|
||||
Packages
|
||||
xcuserdata/
|
||||
crates/docs_preprocessor/actions.json
|
||||
|
||||
# Don't commit any secrets to the repo.
|
||||
.env
|
||||
|
||||
3
Cargo.lock
generated
3
Cargo.lock
generated
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
if actions_available() {
|
||||
errors.insert(PreprocessorError::new_for_not_found_action(
|
||||
name.to_string(),
|
||||
));
|
||||
return String::new();
|
||||
}
|
||||
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);
|
||||
|
||||
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",
|
||||
|
||||
10
script/generate-action-metadata
Executable file
10
script/generate-action-metadata
Executable file
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user