Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

231 changes: 221 additions & 10 deletions rust/contracts/rust-core-api.md

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions rust/crates/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ lithe-diagnostics = { path = "../diagnostics" }
lithe-diff = { path = "../diff" }
lithe-document-uri = { path = "../document-uri" }
lithe-editor = { path = "../editor" }
lithe-editor-layout = { path = "../editor-layout" }
lithe-execution = { path = "../execution" }
lithe-git = { path = "../git" }
lithe-git-host = { path = "../git-host" }
Expand All @@ -36,6 +37,7 @@ lithe-plugin-function-relay = { path = "../plugin-function-relay" }
lithe-plugin-keymap-import = { path = "../plugin-keymap-import" }
lithe-plugin-language-servers = { path = "../plugin-language-servers" }
lithe-plugin-manifest = { path = "../plugin-manifest" }
lithe-plugin-lifecycle = { path = "../plugin-lifecycle" }
lithe-plugin-marketplace = { path = "../plugin-marketplace" }
lithe-plugin-model = { path = "../plugin-model" }
lithe-plugin-native-ui = { path = "../plugin-native-ui" }
Expand All @@ -45,7 +47,9 @@ lithe-plugin-web-content = { path = "../plugin-web-content" }
lithe-process = { path = "../process" }
lithe-project = { path = "../project" }
lithe-project-generators = { path = "../project-generators" }
lithe-project-tree = { path = "../project-tree" }
lithe-protocol = { path = "../protocol" }
lithe-row-selection = { path = "../row-selection" }
lithe-request-context = { path = "../request-context" }
lithe-terminal = { path = "../terminal" }
lithe-text = { path = "../text" }
Expand Down
36 changes: 36 additions & 0 deletions rust/crates/core/src/protocol/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,9 @@ pub enum PluginsCommand {
DeclarativeSettingsActionPlan,
/// Selects numeric installed versions and reports malformed native facts.
InstalledSelect,
/// Reports installed plugins' enablement and plans a lifecycle action
/// (`plugins.installed.lifecycle`).
InstalledLifecycle,
/// Validates an atomic plugin settings edit and preserves unrelated values.
DeclarativeEditSettings,
/// Expands a language server's `workspaceConfiguration` (`plugins.declarative.workspaceConfiguration`).
Expand Down Expand Up @@ -460,6 +463,12 @@ pub enum WorkspaceCommand {
ReleaseIndexing,
/// Lists the visible children of project directories (`workspace.listDirectories`).
ListDirectories,
/// Says which loaded project tree nodes show as rows and keeps the selection on one
/// (`workspace.projectTree.rows`).
ProjectTreeRows,
/// Applies one click to the multi-selection of rows of workspace paths
/// (`workspace.rowSelection.reduce`).
RowSelectionReduce,
/// Orders natively enumerated directory siblings (`workspace.orderEntries`).
OrderEntries,
/// Ranks host-supplied candidate names with the shared matcher (`workspace.rankNames`).
Expand Down Expand Up @@ -533,6 +542,13 @@ pub enum EditorCommand {
/// (`editor.workbenchState.reduce`). The rule lives in `lithe-core-rules` so the Windows frontend
/// can run it synchronously inside store updates.
WorkbenchStateReduce,
/// Applies one transition to the editor groups and the tree that divides the editor area
/// among them: a workbench state action, opening a tab, dropping a dragged one or removing
/// empty groups (`editor.groupLayout.reduce`).
GroupLayoutReduce,
/// Says which places of each editor group accept a dragged tab
/// (`editor.groupLayout.dropTargets`).
GroupLayoutDropTargets,
/// Applies a deterministic line-level editing transform
/// (`editor.lineEdit`).
LineEdit,
Expand Down Expand Up @@ -803,6 +819,11 @@ pub enum GitCommand {
RebasePlanPreview,
/// Groups one kind of loaded references into an ordered tree (`git.referenceTree`).
ReferenceTree,
/// Groups changed files by folder in natural order (`git.changedFileGroups`).
ChangedFileGroups,
/// Derives the worktree creation dialog's choices, branch, destination and readiness
/// (`git.worktreeCreationPreview`).
WorktreeCreationPreview,
/// Resolves the destination and commits for a branch push (`git.pushPreview`).
PushPreview,
/// Resolves metadata for one commit (`git.commit`).
Expand Down Expand Up @@ -982,6 +1003,9 @@ impl CoreCommand {
Some(Self::Plugins(PluginsCommand::DeclarativeSettingsActionPlan))
}
"plugins.installed.select" => Some(Self::Plugins(PluginsCommand::InstalledSelect)),
"plugins.installed.lifecycle" => {
Some(Self::Plugins(PluginsCommand::InstalledLifecycle))
}
"plugins.declarative.editSettings" => {
Some(Self::Plugins(PluginsCommand::DeclarativeEditSettings))
}
Expand Down Expand Up @@ -1094,6 +1118,12 @@ impl CoreCommand {
"workspace.refreshIndexing" => Some(Self::Workspace(WorkspaceCommand::RefreshIndexing)),
"workspace.filterChanges" => Some(Self::Workspace(WorkspaceCommand::FilterChanges)),
"workspace.listDirectories" => Some(Self::Workspace(WorkspaceCommand::ListDirectories)),
"workspace.projectTree.rows" => {
Some(Self::Workspace(WorkspaceCommand::ProjectTreeRows))
}
"workspace.rowSelection.reduce" => {
Some(Self::Workspace(WorkspaceCommand::RowSelectionReduce))
}
"workspace.orderEntries" => Some(Self::Workspace(WorkspaceCommand::OrderEntries)),
"workspace.rankNames" => Some(Self::Workspace(WorkspaceCommand::RankNames)),
"workspace.planDuplicate" => Some(Self::Workspace(WorkspaceCommand::PlanDuplicate)),
Expand Down Expand Up @@ -1157,6 +1187,10 @@ impl CoreCommand {
"editor.workbenchState.reduce" => {
Some(Self::Editor(EditorCommand::WorkbenchStateReduce))
}
"editor.groupLayout.reduce" => Some(Self::Editor(EditorCommand::GroupLayoutReduce)),
"editor.groupLayout.dropTargets" => {
Some(Self::Editor(EditorCommand::GroupLayoutDropTargets))
}
"workspace.classifyVisibility" => {
Some(Self::Workspace(WorkspaceCommand::ClassifyVisibility))
}
Expand Down Expand Up @@ -1367,6 +1401,8 @@ impl CoreCommand {
"git.normalizeChangeTargets" => Some(Self::Git(GitCommand::NormalizeChangeTargets)),
"git.rebasePlanPreview" => Some(Self::Git(GitCommand::RebasePlanPreview)),
"git.referenceTree" => Some(Self::Git(GitCommand::ReferenceTree)),
"git.changedFileGroups" => Some(Self::Git(GitCommand::ChangedFileGroups)),
"git.worktreeCreationPreview" => Some(Self::Git(GitCommand::WorktreeCreationPreview)),
"git.pushPreview" => Some(Self::Git(GitCommand::PushPreview)),
"git.commit" => Some(Self::Git(GitCommand::Commit)),
"git.commitFiles" => Some(Self::Git(GitCommand::CommitFiles)),
Expand Down
8 changes: 7 additions & 1 deletion rust/crates/core/src/runtime/dispatcher/editor.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! `editor.*` commands: workbench state, text edits, find, navigation and preferences.
//! `editor.*` commands: workbench state, group layout, text edits, find, navigation and preferences.

use super::{plugin_response, rules_response};
use crate::protocol::{CoreError, CoreResponse, EditorCommand, ErrorCode};
Expand All @@ -15,6 +15,12 @@ pub(super) fn dispatch(
EditorCommand::WorkbenchStateReduce => {
rules_response(id, "editor.workbenchState.reduce", payload)
}
EditorCommand::GroupLayoutReduce => {
plugin_response(id, payload, lithe_editor_layout::reduce_command)
}
EditorCommand::GroupLayoutDropTargets => {
plugin_response(id, payload, lithe_editor_layout::drop_targets_command)
}
EditorCommand::Find => match lithe_editor::find::command(payload, document) {
Ok(data) => CoreResponse::success(id, data),
Err(error) => CoreResponse::failure(id, error),
Expand Down
6 changes: 6 additions & 0 deletions rust/crates/core/src/runtime/dispatcher/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,12 @@ pub(super) fn dispatch(command: GitCommand, id: Option<String>, payload: Value)
GitCommand::ReferenceTree => {
plugin_response(id, payload, lithe_git::reference_tree_command)
}
GitCommand::ChangedFileGroups => {
plugin_response(id, payload, lithe_git::changed_file_groups_command)
}
GitCommand::WorktreeCreationPreview => {
plugin_response(id, payload, lithe_git::worktree_creation_preview_command)
}
GitCommand::PrepareCommitSelection => {
plugin_response(id, payload, lithe_git::prepare_commit_selection_command)
}
Expand Down
3 changes: 3 additions & 0 deletions rust/crates/core/src/runtime/dispatcher/plugins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ pub(super) fn dispatch(
PluginsCommand::InstalledSelect => {
plugin_response(id, payload, lithe_plugin_model::installed::select_command)
}
PluginsCommand::InstalledLifecycle => {
plugin_response(id, payload, lithe_plugin_lifecycle::command)
}
PluginsCommand::SettingsCatalog => {
plugin_response(id, payload, lithe_plugin_manifest::settings_catalog_command)
}
Expand Down
9 changes: 8 additions & 1 deletion rust/crates/core/src/runtime/dispatcher/workspace.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//! `workspace.*` commands: snapshots, indexing, directory actions, repositories and search.
//! `workspace.*` commands: snapshots, indexing, project tree rows, row selection, directory
//! actions, repositories and search.

use super::{plugin_response, rules_response};
use crate::project::{
Expand Down Expand Up @@ -93,6 +94,12 @@ pub(super) fn dispatch(
),
}
}
WorkspaceCommand::ProjectTreeRows => {
plugin_response(id, payload, lithe_project_tree::command)
}
WorkspaceCommand::RowSelectionReduce => {
plugin_response(id, payload, lithe_row_selection::command)
}
WorkspaceCommand::ListDirectories => {
match serde_json::from_value::<DirectoryListingRequest>(payload)
.map_err(|error| {
Expand Down
31 changes: 31 additions & 0 deletions rust/crates/core/src/tests/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1846,6 +1846,37 @@ fn git_worktrees_lists_primary_linked_and_locked_metadata() {
assert_eq!(worktrees[1]["branch"], "refs/heads/feature/linked");
assert_eq!(worktrees[1]["isLocked"], true);
assert_eq!(worktrees[1]["lockReason"], "Codex task");
assert_eq!(worktrees[0]["status"], "current");
assert_eq!(worktrees[0]["changes"], Value::Null);
assert_eq!(
worktrees[0]["actions"]["remove"]["reason"],
"git_worktree_primary"
);
assert_eq!(worktrees[1]["status"], "locked");
assert_eq!(
worktrees[1]["actions"]["remove"]["reason"],
"git_worktree_locked"
);
assert_eq!(worktrees[1]["actions"]["lock"]["allowed"], true);

fs::write(root.join("draft.txt"), "draft\n").expect("untracked file should be written");
let counted: Value = serde_json::from_str(&execute_json(
&serde_json::to_string(&serde_json::json!({
"id": "git-worktrees-count",
"command": "git.worktrees",
"payload": { "root": root, "countChanges": true }
}))
.expect("worktrees request should encode"),
))
.expect("worktrees response should be JSON");
assert_eq!(counted["ok"], true, "{counted:?}");
let counted = counted["data"]["worktrees"]
.as_array()
.expect("worktrees should be an array");
assert_eq!(counted[0]["changes"], 1, "{counted:?}");
assert_eq!(counted[0]["status"], "modified");
assert_eq!(counted[1]["changes"], 0, "{counted:?}");
assert_eq!(counted[1]["status"], "locked");
}

#[test]
Expand Down
34 changes: 34 additions & 0 deletions rust/crates/core/src/tests/git_changed_file_groups.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//! `git.changedFileGroups` against the shared fixture.

use serde_json::{json, Value};

fn call(payload: Value) -> Value {
serde_json::from_str(&crate::execute_json(
&json!({"id":"groups", "command":"git.changedFileGroups", "payload":payload}).to_string(),
))
.unwrap()
}

#[test]
fn shared_fixture_paths_have_one_grouping_and_order() {
let fixture: Value = serde_json::from_str(include_str!(
"../../../../fixtures/git/changed-file-groups-v1.json"
))
.unwrap();
for case in fixture["cases"].as_array().unwrap() {
let response = call(case["request"].clone());
assert_eq!(response["ok"], true, "{}: {response}", case["name"]);
assert_eq!(
response["data"]["folders"], case["folders"],
"{}",
case["name"]
);
}
}

#[test]
fn rejects_unknown_fields() {
let response = call(json!({"paths":["a"],"status":["M"]}));
assert_eq!(response["ok"], false);
assert_eq!(response["error"]["code"], "invalid_request");
}
Loading
Loading