Compare commits
6 Commits
diff_down
...
actions_js
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
73f7061b1d | ||
|
|
332660d888 | ||
|
|
a85915486b | ||
|
|
1b73741d6d | ||
|
|
b595445e6a | ||
|
|
33e4300647 |
19
Cargo.lock
generated
19
Cargo.lock
generated
@@ -2,6 +2,20 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "actions"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"command_palette",
|
||||
"gpui",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"util",
|
||||
"workspace-hack",
|
||||
"zed",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "activity_indicator"
|
||||
version = "0.1.0"
|
||||
@@ -4596,18 +4610,17 @@ dependencies = [
|
||||
name = "docs_preprocessor"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"actions",
|
||||
"anyhow",
|
||||
"clap",
|
||||
"command_palette",
|
||||
"gpui",
|
||||
"mdbook",
|
||||
"regex",
|
||||
"rust-embed",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"settings",
|
||||
"util",
|
||||
"workspace-hack",
|
||||
"zed",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
members = [
|
||||
"crates/actions",
|
||||
"crates/activity_indicator",
|
||||
"crates/agent",
|
||||
"crates/agent_settings",
|
||||
@@ -200,7 +201,7 @@ members = [
|
||||
"tooling/workspace-hack",
|
||||
"tooling/xtask",
|
||||
]
|
||||
default-members = ["crates/zed"]
|
||||
default-members = ["crates/zed", "crates/actions"]
|
||||
|
||||
[workspace.package]
|
||||
publish = false
|
||||
@@ -212,6 +213,7 @@ edition = "2024"
|
||||
# Workspace member crates
|
||||
#
|
||||
|
||||
actions = { path = "crates/actions" }
|
||||
activity_indicator = { path = "crates/activity_indicator" }
|
||||
agent = { path = "crates/agent" }
|
||||
agent_settings = { path = "crates/agent_settings" }
|
||||
|
||||
3774
assets/actions/actions.json
Normal file
3774
assets/actions/actions.json
Normal file
File diff suppressed because it is too large
Load Diff
28
crates/actions/Cargo.toml
Normal file
28
crates/actions/Cargo.toml
Normal file
@@ -0,0 +1,28 @@
|
||||
[package]
|
||||
name = "actions"
|
||||
version = "0.1.0"
|
||||
edition.workspace = true
|
||||
publish.workspace = true
|
||||
license = "GPL-3.0-or-later"
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
command_palette.workspace = true
|
||||
gpui.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
util.workspace = true
|
||||
workspace-hack.workspace = true
|
||||
zed.workspace = true
|
||||
|
||||
[build-dependencies]
|
||||
anyhow.workspace = true
|
||||
command_palette.workspace = true
|
||||
gpui.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
util.workspace = true
|
||||
zed.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
59
crates/actions/build.rs
Normal file
59
crates/actions/build.rs
Normal file
@@ -0,0 +1,59 @@
|
||||
use anyhow::Result;
|
||||
use serde::Serialize;
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct ActionDef {
|
||||
name: String,
|
||||
human_name: String,
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
deprecated_aliases: Vec<String>,
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
// 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 actions = dump_all_gpui_actions();
|
||||
|
||||
let out_dir = env::var("CARGO_MANIFEST_DIR")?;
|
||||
let assets_path = Path::new(&out_dir)
|
||||
.parent()
|
||||
.unwrap()
|
||||
.parent()
|
||||
.unwrap()
|
||||
.join("assets/actions");
|
||||
|
||||
// Create the actions directory if it doesn't exist
|
||||
fs::create_dir_all(&assets_path)?;
|
||||
|
||||
let json_path = assets_path.join("actions.json");
|
||||
let json_content = serde_json::to_string_pretty(&actions)?;
|
||||
fs::write(&json_path, json_content)?;
|
||||
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
println!("cargo:rerun-if-changed=../../assets/actions/actions.json");
|
||||
|
||||
// This sucks. We regenerate actions.json on every cargo invocation
|
||||
println!("cargo:rerun-if-changed=*");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn dump_all_gpui_actions() -> Vec<ActionDef> {
|
||||
let mut actions = gpui::generate_list_of_all_registered_actions()
|
||||
.into_iter()
|
||||
.map(|action| ActionDef {
|
||||
name: action.name.to_string(),
|
||||
human_name: command_palette::humanize_action_name(action.name),
|
||||
deprecated_aliases: action.aliases.iter().map(|s| s.to_string()).collect(),
|
||||
})
|
||||
.collect::<Vec<ActionDef>>();
|
||||
|
||||
actions.sort_by_key(|a| a.name.clone());
|
||||
|
||||
actions
|
||||
}
|
||||
18
crates/actions/src/lib.rs
Normal file
18
crates/actions/src/lib.rs
Normal file
@@ -0,0 +1,18 @@
|
||||
//! Actions crate that generates actions.json at build time.
|
||||
//!
|
||||
//! This crate uses build.rs to automatically regenerate the actions.json file
|
||||
//! whenever the crate is built, eliminating the need for manual updates.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Represents an action definition that can be serialized to/from JSON.
|
||||
/// This struct is shared between the build script that generates actions.json
|
||||
/// and other crates that need to read action definitions.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ActionDef {
|
||||
pub name: String,
|
||||
pub human_name: String,
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
pub deprecated_aliases: Vec<String>,
|
||||
}
|
||||
@@ -6,6 +6,7 @@ publish.workspace = true
|
||||
license = "GPL-3.0-or-later"
|
||||
|
||||
[dependencies]
|
||||
actions.workspace = true
|
||||
anyhow.workspace = true
|
||||
clap.workspace = true
|
||||
mdbook = "0.4.40"
|
||||
@@ -13,11 +14,9 @@ serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
settings.workspace = true
|
||||
regex.workspace = true
|
||||
rust-embed.workspace = true
|
||||
util.workspace = true
|
||||
workspace-hack.workspace = true
|
||||
zed.workspace = true
|
||||
gpui.workspace = true
|
||||
command_palette.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
use actions::ActionDef;
|
||||
use anyhow::Result;
|
||||
use clap::{Arg, ArgMatches, Command};
|
||||
use mdbook::BookItem;
|
||||
use mdbook::book::{Book, Chapter};
|
||||
use mdbook::preprocess::CmdPreprocessor;
|
||||
use regex::Regex;
|
||||
use rust_embed::RustEmbed;
|
||||
use settings::KeymapFile;
|
||||
use std::collections::HashSet;
|
||||
use std::io::{self, Read};
|
||||
use std::process;
|
||||
use std::sync::LazyLock;
|
||||
|
||||
#[derive(RustEmbed)]
|
||||
#[folder = "../../assets"]
|
||||
#[include = "actions/*"]
|
||||
struct Assets;
|
||||
|
||||
static KEYMAP_MACOS: LazyLock<KeymapFile> = LazyLock::new(|| {
|
||||
load_keymap("keymaps/default-macos.json").expect("Failed to load MacOS keymap")
|
||||
});
|
||||
@@ -18,7 +25,7 @@ static KEYMAP_LINUX: LazyLock<KeymapFile> = LazyLock::new(|| {
|
||||
load_keymap("keymaps/default-linux.json").expect("Failed to load Linux keymap")
|
||||
});
|
||||
|
||||
static ALL_ACTIONS: LazyLock<Vec<ActionDef>> = LazyLock::new(dump_all_gpui_actions);
|
||||
static ALL_ACTIONS: LazyLock<Vec<ActionDef>> = LazyLock::new(load_all_actions);
|
||||
|
||||
pub fn make_app() -> Command {
|
||||
Command::new("zed-docs-preprocessor")
|
||||
@@ -32,9 +39,6 @@ pub fn make_app() -> Command {
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let matches = make_app().get_matches();
|
||||
// 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();
|
||||
|
||||
if let Some(sub_args) = matches.subcommand_matches("supports") {
|
||||
handle_supports(sub_args);
|
||||
@@ -54,7 +58,7 @@ enum Error {
|
||||
impl Error {
|
||||
fn new_for_not_found_action(action_name: String) -> Self {
|
||||
for action in &*ALL_ACTIONS {
|
||||
for alias in action.deprecated_aliases {
|
||||
for alias in &action.deprecated_aliases {
|
||||
if alias == &action_name {
|
||||
return Error::DeprecatedActionUsed {
|
||||
used: action_name.clone(),
|
||||
@@ -163,7 +167,7 @@ fn template_and_validate_actions(book: &mut Book, errors: &mut HashSet<Error>) {
|
||||
|
||||
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])
|
||||
}
|
||||
@@ -234,24 +238,80 @@ where
|
||||
});
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Serialize)]
|
||||
struct ActionDef {
|
||||
name: &'static str,
|
||||
human_name: String,
|
||||
deprecated_aliases: &'static [&'static str],
|
||||
fn load_all_actions() -> Vec<ActionDef> {
|
||||
let content = util::asset_str::<Assets>("actions/actions.json");
|
||||
let mut actions: Vec<ActionDef> =
|
||||
serde_json::from_str(content.as_ref()).expect("Failed to parse actions.json");
|
||||
|
||||
actions.sort_by(|a, b| a.name.cmp(&b.name));
|
||||
actions
|
||||
}
|
||||
|
||||
fn dump_all_gpui_actions() -> Vec<ActionDef> {
|
||||
let mut actions = gpui::generate_list_of_all_registered_actions()
|
||||
.into_iter()
|
||||
.map(|action| ActionDef {
|
||||
name: action.name,
|
||||
human_name: command_palette::humanize_action_name(action.name),
|
||||
deprecated_aliases: action.aliases,
|
||||
})
|
||||
.collect::<Vec<ActionDef>>();
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
actions.sort_by_key(|a| a.name);
|
||||
#[test]
|
||||
fn test_load_actions() {
|
||||
let actions = load_all_actions();
|
||||
assert!(!actions.is_empty(), "Actions should not be empty");
|
||||
|
||||
return actions;
|
||||
// Check that actions are sorted
|
||||
for i in 1..actions.len() {
|
||||
assert!(
|
||||
actions[i - 1].name <= actions[i].name,
|
||||
"Actions should be sorted by name"
|
||||
);
|
||||
}
|
||||
|
||||
// Check that we can find a common action
|
||||
assert!(
|
||||
find_action_by_name("editor::Cut").is_some(),
|
||||
"Should be able to find editor::Cut action"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_find_action_by_name() {
|
||||
// Test finding an action that exists
|
||||
let action = find_action_by_name("editor::Cut");
|
||||
assert!(action.is_some());
|
||||
assert_eq!(action.unwrap().name, "editor::Cut");
|
||||
|
||||
// Test finding an action that doesn't exist
|
||||
let action = find_action_by_name("nonexistent::Action");
|
||||
assert!(action.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_name_for_action() {
|
||||
// Test simple action name
|
||||
assert_eq!(name_for_action("editor::Cut".to_string()), "editor::Cut");
|
||||
|
||||
// Test action with parameters
|
||||
assert_eq!(
|
||||
name_for_action(
|
||||
"\"editor::ToggleComments\", {\"advance_downwards\":false}".to_string()
|
||||
),
|
||||
"editor::ToggleComments"
|
||||
);
|
||||
|
||||
// Test action with quotes
|
||||
assert_eq!(
|
||||
name_for_action("\"workspace::NewFile\"".to_string()),
|
||||
"workspace::NewFile"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_error_creation() {
|
||||
// Test creating error for non-existent action
|
||||
let error = Error::new_for_not_found_action("nonexistent::Action".to_string());
|
||||
match error {
|
||||
Error::ActionNotFound { action_name } => {
|
||||
assert_eq!(action_name, "nonexistent::Action");
|
||||
}
|
||||
_ => panic!("Expected ActionNotFound error"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,6 +158,9 @@ windows.workspace = true
|
||||
[target.'cfg(target_os = "windows")'.build-dependencies]
|
||||
winresource = "0.1"
|
||||
|
||||
[build-dependencies]
|
||||
zed_actions.workspace = true
|
||||
|
||||
[target.'cfg(any(target_os = "linux", target_os = "freebsd"))'.dependencies]
|
||||
ashpd.workspace = true
|
||||
|
||||
|
||||
Reference in New Issue
Block a user