From 25d930b7800ca844df3f625e70b66e96fc429c67 Mon Sep 17 00:00:00 2001 From: Arnaud Ritti <77437157+arnaud-ritti@users.noreply.github.com> Date: Sat, 7 Nov 2026 14:24:50 +0100 Subject: [PATCH] feat(plugins): let a code action create, rename and delete files (#1778) A new optional file-actions export (worlds plugin-file-actions / file-actions-provider, API 1.3) lists quick fixes whose operations (create with text, rename, delete) and text edits are applied as one workspace edit, so a failure changes nothing and one undo reverses it; paths stay inside the project root, and `open` shows a file once the action is applied. Like providers' code actions, an action can carry only `data` and get its operations from `resolve` when picked. Co-authored-by: arnaud-ritti <77437157+arnaud-ritti@users.noreply.github.com> --- crates/ide-host/src/ops/lsp.rs | 207 ++++++++++++++++-- crates/ide-host/src/plugins/providers.rs | 8 +- crates/ide-host/tests/plugins.rs | 24 ++ crates/ide-plugin/src/lib.rs | 2 +- crates/ide-plugin/src/runtime.rs | 128 ++++++++++- crates/ide-plugin/src/sandbox.rs | 73 ++++++ crates/ide-plugin/src/types.rs | 13 ++ crates/ide-plugin/src/wit_host.rs | 8 + .../tests/fixtures/commit/dist/plugin.wasm | Bin 100250 -> 100258 bytes .../fixtures/commit/dist/plugin.wasm.sources | 2 +- .../tests/fixtures/hello/dist/plugin.wasm | Bin 143243 -> 143251 bytes .../fixtures/hello/dist/plugin.wasm.sources | 2 +- .../tests/fixtures/hover/dist/plugin.wasm | Bin 89596 -> 89604 bytes .../fixtures/hover/dist/plugin.wasm.sources | 2 +- .../tests/fixtures/indexer/dist/plugin.wasm | Bin 83023 -> 83031 bytes .../fixtures/indexer/dist/plugin.wasm.sources | 2 +- .../fixtures/inlay-hints/dist/plugin.wasm | Bin 91543 -> 91543 bytes .../inlay-hints/dist/plugin.wasm.sources | 2 +- .../tests/fixtures/jobs/dist/plugin.wasm | Bin 145208 -> 145216 bytes .../fixtures/jobs/dist/plugin.wasm.sources | 2 +- .../tests/fixtures/misbehave/dist/plugin.wasm | Bin 97260 -> 109143 bytes .../misbehave/dist/plugin.wasm.sources | 2 +- .../tests/fixtures/misbehave/src/lib.rs | 61 ++++++ .../fixtures/semantic-tokens/dist/plugin.wasm | Bin 91827 -> 91827 bytes .../semantic-tokens/dist/plugin.wasm.sources | 2 +- .../tests/fixtures/storage/dist/plugin.wasm | Bin 73958 -> 73966 bytes .../fixtures/storage/dist/plugin.wasm.sources | 2 +- .../tests/fixtures/tables/dist/plugin.wasm | Bin 115780 -> 115788 bytes .../fixtures/tables/dist/plugin.wasm.sources | 2 +- plugins/README.md | 11 +- .../official/ai-completion/dist/plugin.wasm | Bin 173102 -> 173102 bytes .../ai-completion/dist/plugin.wasm.sources | 2 +- plugins/official/checkstyle/dist/plugin.wasm | Bin 169550 -> 169558 bytes .../checkstyle/dist/plugin.wasm.sources | 2 +- plugins/official/csv-editor/dist/plugin.wasm | Bin 133413 -> 133421 bytes .../csv-editor/dist/plugin.wasm.sources | 2 +- plugins/official/git-toolbox/dist/plugin.wasm | Bin 110087 -> 110095 bytes .../git-toolbox/dist/plugin.wasm.sources | 2 +- plugins/official/graphviz/dist/plugin.wasm | Bin 129121 -> 129129 bytes .../graphviz/dist/plugin.wasm.sources | 2 +- .../official/key-promoter/dist/plugin.wasm | Bin 100203 -> 100211 bytes .../key-promoter/dist/plugin.wasm.sources | 2 +- .../official/license-header/dist/plugin.wasm | Bin 152621 -> 152629 bytes .../license-header/dist/plugin.wasm.sources | 2 +- plugins/official/mybatis/dist/plugin.wasm | Bin 168362 -> 168370 bytes .../official/mybatis/dist/plugin.wasm.sources | 2 +- .../official/regex-tester/dist/plugin.wasm | Bin 931746 -> 931754 bytes .../regex-tester/dist/plugin.wasm.sources | 2 +- plugins/official/solidity/dist/plugin.wasm | Bin 108045 -> 108045 bytes .../solidity/dist/plugin.wasm.sources | 2 +- .../official/string-tools/dist/plugin.wasm | Bin 165803 -> 165811 bytes .../string-tools/dist/plugin.wasm.sources | 2 +- sdk/rust/openidea-plugin/src/file_actions.rs | 59 +++++ sdk/rust/openidea-plugin/src/lib.rs | 132 +++++++++++ sdk/rust/openidea-plugin/wit/file-actions.wit | 79 +++++++ sdk/rust/openidea-plugin/wit/plugin.wit | 11 + wit/file-actions.wit | 79 +++++++ wit/plugin.wit | 11 + 58 files changed, 896 insertions(+), 52 deletions(-) create mode 100644 sdk/rust/openidea-plugin/src/file_actions.rs create mode 100644 sdk/rust/openidea-plugin/wit/file-actions.wit create mode 100644 wit/file-actions.wit diff --git a/crates/ide-host/src/ops/lsp.rs b/crates/ide-host/src/ops/lsp.rs index c4a14fa8c..6dc3dbc5b 100644 --- a/crates/ide-host/src/ops/lsp.rs +++ b/crates/ide-host/src/ops/lsp.rs @@ -7,6 +7,7 @@ use ide_core::error::ErrorKind; use ide_core::{DocId, IdeResult, Location, Pos, Range, RequestId, ServerId, TextEdit, WorkspaceEdit}; use ide_lsp::types::*; use ide_plugin::ProviderDocument; +use std::path::Path; async fn prepare_actions( project: std::sync::Arc, @@ -85,7 +86,12 @@ const PLUGIN_SERVER: ServerId = ServerId(0); #[derive(serde::Serialize, serde::Deserialize)] struct PluginActionRef { plugin: String, - data: String, + data: Option, + /// Opened once the action is applied. + open: Option, + /// Listed by the plugin's `file-actions` export, which resolves it. + #[serde(default, skip_serializing_if = "std::ops::Not::not")] + file: bool, } /// A plugin's `completion-item.kind` (wit/providers.wit lists them). @@ -443,7 +449,7 @@ pub async fn lsp_code_actions( }; let plugin_actions: Vec = plugin_actions .into_iter() - .map(|(plugin, a)| plugin_code_action(&plugin, a)) + .map(|(plugin, a)| plugin_code_action(&plugin, &project.root, a)) .filter(|a| { only.is_empty() || a.kind.as_ref().is_some_and(|k| only.iter().any(|o| k == o || k.starts_with(&format!("{o}.")))) @@ -459,23 +465,26 @@ pub async fn lsp_code_actions( prepare_actions(project, doc, version, actions).await } -fn plugin_code_action(plugin: &str, a: ide_plugin::CodeAction) -> CodeAction { - // With `data` and no edits, the plugin computes them when the action is picked. - let lazy = a.edits.is_empty() && a.data.is_some(); - let files: Vec<_> = a - .edits - .into_iter() - .map(|(path, edits)| ide_core::FileEdit::Edit { path: path.into(), edits, version: None }) - .collect(); - let data = a - .data - .filter(|_| lazy) - .and_then(|data| serde_json::to_value(PluginActionRef { plugin: plugin.to_owned(), data }).ok()); +fn plugin_code_action(plugin: &str, root: &Path, a: ide_plugin::CodeAction) -> CodeAction { + // With `data` and nothing to apply, the plugin computes the edits when the action is picked. + let lazy = a.edits.is_empty() && a.operations.is_empty() && a.data.is_some(); + let (files, open, disabled_reason) = match plugin_file_edits(root, &a) { + Ok((files, open)) => (files, open, None), + Err(reason) => (Vec::new(), None, Some(reason)), + }; + let data = (lazy || open.is_some()) + .then(|| PluginActionRef { + plugin: plugin.to_owned(), + data: a.data.filter(|_| lazy), + open: open.map(Into::into), + file: a.file_action, + }) + .and_then(|r| serde_json::to_value(r).ok()); CodeAction { title: a.title, kind: a.kind, is_preferred: a.preferred, - disabled_reason: None, + disabled_reason, edit: (!lazy).then(|| WorkspaceEdit { files, preconditions: Vec::new() }), command: None, data, @@ -483,6 +492,53 @@ fn plugin_code_action(plugin: &str, a: ide_plugin::CodeAction) -> CodeAction { } } +/// The action's file operations, then its text edits, as one workspace edit's files, and the +/// file to open. An action with file operations or an `open` target stays inside the project +/// root as a whole: a path outside it disables the action. +fn plugin_file_edits( + root: &Path, + a: &ide_plugin::CodeAction, +) -> Result<(Vec, Option), String> { + use ide_core::FileEdit; + use ide_plugin::FileOperation; + let confine = !a.operations.is_empty() || a.open.is_some(); + let confined = |path: &Path| ide_plugin::resolve_new_in_root(root, &path.to_string_lossy()); + let mut files = Vec::new(); + let mut created_with_text = Vec::new(); + for operation in &a.operations { + match operation { + FileOperation::Create { path, text, overwrite } => { + let path = confined(path)?; + files.push(FileEdit::Create { path: path.clone().into(), overwrite: *overwrite }); + if !text.is_empty() { + let start = Range::point(Pos::new(0, 0)); + files.push(FileEdit::Edit { + path: path.clone().into(), + edits: vec![TextEdit { range: start, new_text: text.clone() }], + version: None, + }); + created_with_text.push(path); + } + } + FileOperation::Rename { from, to } => { + files.push(FileEdit::Rename { from: confined(from)?.into(), to: confined(to)?.into() }); + } + FileOperation::Delete { path } => { + files.push(FileEdit::Delete { path: confined(path)?.into(), recursive: false }); + } + } + } + for (path, edits) in &a.edits { + let path = if confine { confined(path)? } else { path.clone() }; + if created_with_text.contains(&path) { + return Err("put the text of a created file in its `create`, not in an edit".into()); + } + files.push(FileEdit::Edit { path: path.into(), edits: edits.clone(), version: None }); + } + let open = a.open.as_deref().map(confined).transpose()?; + Ok((files, open)) +} + /// A code action resolved by whoever offered it: its language server, or /// the plugin its `data` names. async fn resolve_action(host: &Host, window: &str, doc: DocId, action: CodeAction) -> IdeResult { @@ -499,11 +555,15 @@ async fn resolve_action(host: &Host, window: &str, doc: DocId, action: CodeActio kind: action.kind.clone(), preferred: action.is_preferred, edits: Vec::new(), - data: Some(r.data), + operations: Vec::new(), + open: None, + data: r.data, + file_action: r.file, }; let plugin = r.plugin.clone(); let resolved = blocking(move || plugins.resolve_code_action(&plugin, &d, pending)).await?; - Ok(plugin_code_action(&r.plugin, ide_plugin::CodeAction { data: None, ..resolved })) + let root = host.project(window)?.root.clone(); + Ok(plugin_code_action(&r.plugin, &root, ide_plugin::CodeAction { data: None, ..resolved })) } /// Cancellable code actions with the kinds the servers advertise (Refactor This, refactoring availability). @@ -554,11 +614,15 @@ pub async fn lsp_apply_code_action(host: &Host, window: &str, doc: DocId, action } else { action }; + if let Some(reason) = &action.disabled_reason { + return Err(ide_core::IdeError::invalid(reason.clone())); + } if let Some(edit) = &action.edit { let documents = project.documents.clone(); let edit = edit.clone(); blocking(move || apply_edit(&documents, &edit)).await?; } + open_plugin_action_target(&action, window); if let Some(command) = action.command && !(action.edit.is_some() && is_client_follow_up(&project, doc, None, &command).await) { @@ -567,6 +631,24 @@ pub async fn lsp_apply_code_action(host: &Host, window: &str, doc: DocId, action Ok(()) } +/// The plugin and the file its action asks to show once applied. +fn plugin_action_open(action: &CodeAction) -> Option<(String, ide_core::IpcPath)> { + if action.server != PLUGIN_SERVER { + return None; + } + let r = action.data.clone().and_then(|d| serde_json::from_value::(d).ok())?; + Some((r.plugin, r.open?)) +} + +/// Opens the file a plugin's action asked to show, now that the action is applied. +fn open_plugin_action_target(action: &CodeAction, window: &str) { + let (Some((plugin, path)), Some(plugins)) = (plugin_action_open(action), crate::plugins::editor_plugin_host()) + else { + return; + }; + plugins.open_file(&plugin, window, path); +} + /// A command after a code action's edit that no server provides: what other editors' /// extensions do once the edit is applied (vtsls' `_typescript.didOrganizeImports`). The edit /// is the action; there is nothing to run. @@ -846,6 +928,8 @@ pub async fn lsp_execute_code_action( return Err(ide_core::IdeError::cancelled()); } let edited = action.edit.is_some(); + // A plugin's action may name a file to show once applied; the caller opens it. + let open = plugin_action_open(&action).map(|(_, path)| path); if let Some(edit) = action.edit { let documents = project.documents.clone(); tokio::task::spawn_blocking(move || apply_edit(&documents, &edit)) @@ -861,7 +945,7 @@ pub async fn lsp_execute_code_action( .execute_action_command(doc, action.server, command, answers, cancel) .await .map(|paths| paths.into_iter().map(ide_core::IpcPath::from).collect()), - None => Ok(Vec::new()), + None => Ok(open.into_iter().collect()), } } .await; @@ -1025,15 +1109,19 @@ mod tests { kind: None, preferred: false, edits, + operations: Vec::new(), + open: None, data: data.map(str::to_owned), + file_action: false, }; - let lazy = plugin_code_action("acme.x", action(Vec::new(), Some("ref"))); + let root = Path::new("/p"); + let lazy = plugin_code_action("acme.x", root, action(Vec::new(), Some("ref"))); assert!(lazy.edit.is_none()); let r: PluginActionRef = serde_json::from_value(lazy.data.unwrap()).unwrap(); - assert_eq!((r.plugin.as_str(), r.data.as_str()), ("acme.x", "ref")); + assert_eq!((r.plugin.as_str(), r.data.as_deref()), ("acme.x", Some("ref"))); // With edits, `data` is the plugin's business: applied as is. let edit = TextEdit { range: Range::default(), new_text: "x".into() }; - let eager = plugin_code_action("acme.x", action(vec![("/a".into(), vec![edit])], Some("ref"))); + let eager = plugin_code_action("acme.x", root, action(vec![("/a".into(), vec![edit])], Some("ref"))); assert!(eager.edit.is_some() && eager.data.is_none()); } @@ -1110,6 +1198,83 @@ mod tests { assert!(without_generated_helpers(Vec::new()).is_empty()); } + #[test] + fn a_plugin_action_maps_its_file_operations_before_its_edits_and_stays_in_the_project() { + use ide_core::FileEdit; + use ide_plugin::FileOperation; + let tmp = tempfile::tempdir().unwrap(); + let root = tmp.path().join("proj"); + std::fs::create_dir_all(&root).unwrap(); + let root = root.canonicalize().unwrap(); + let action = |operations: Vec| ide_plugin::CodeAction { + title: "Create view".into(), + kind: Some("quickfix".into()), + preferred: false, + edits: vec![(root.join("a.txt"), vec![TextEdit { range: Range::default(), new_text: "x".into() }])], + operations, + open: Some(root.join("views/home.html")), + data: None, + file_action: true, + }; + + let created = plugin_code_action( + "acme.x", + &root, + action(vec![ + FileOperation::Create { path: "views/home.html".into(), text: "

".into(), overwrite: false }, + FileOperation::Rename { from: root.join("old.txt"), to: root.join("new.txt") }, + FileOperation::Delete { path: root.join("gone.txt") }, + ]), + ); + assert_eq!(created.disabled_reason, None); + let files = created.edit.unwrap().files; + let home = root.join("views/home.html"); + assert!(matches!(&files[0], FileEdit::Create { path, overwrite: false } if **path == home)); + assert!( + matches!(&files[1], FileEdit::Edit { path, edits, .. } if **path == home && edits[0].new_text == "

") + ); + assert!(matches!(&files[2], FileEdit::Rename { to, .. } if **to == root.join("new.txt"))); + assert!(matches!(&files[3], FileEdit::Delete { recursive: false, .. })); + assert!(matches!(&files[4], FileEdit::Edit { path, .. } if **path == root.join("a.txt"))); + let r: PluginActionRef = serde_json::from_value(created.data.unwrap()).unwrap(); + assert_eq!(r.data, None); + assert!(r.file, "resolved by the file-actions export"); + let opened = r.open.unwrap().to_path_buf(); + assert!(opened.components().eq(dunce::simplified(&home).components()), "{opened:?}"); + + let outside = tmp.path().join("evil.txt"); + let mut open_outside = action(Vec::new()); + open_outside.open = Some(outside.clone()); + assert!(plugin_code_action("acme.x", &root, open_outside).disabled_reason.is_some()); + let mut edit_outside = action(vec![FileOperation::Delete { path: root.join("gone.txt") }]); + edit_outside.edits.push((outside, Vec::new())); + assert!(plugin_code_action("acme.x", &root, edit_outside).disabled_reason.is_some()); + let mut edit_created = + action(vec![FileOperation::Create { path: root.join("n.txt"), text: "x".into(), overwrite: false }]); + edit_created.edits = vec![(root.join("n.txt"), Vec::new())]; + assert!(plugin_code_action("acme.x", &root, edit_created).disabled_reason.is_some()); + + for outside in [tmp.path().join("evil.txt"), "../evil.txt".into()] { + for operation in [ + FileOperation::Create { path: outside.clone(), text: String::new(), overwrite: false }, + FileOperation::Rename { from: root.join("old.txt"), to: outside.clone() }, + FileOperation::Delete { path: outside.clone() }, + ] { + let rejected = plugin_code_action("acme.x", &root, action(vec![operation])); + assert!(rejected.disabled_reason.is_some_and(|r| r.contains("outside the project root"))); + assert!(rejected.edit.unwrap().files.is_empty()); + } + } + + // `data` and nothing to apply: the file-actions export computes it when picked. + let mut lazy = action(Vec::new()); + (lazy.edits, lazy.open, lazy.data) = (Vec::new(), None, Some("ref".into())); + let lazy = plugin_code_action("acme.x", &root, lazy); + assert!(lazy.edit.is_none()); + let r: PluginActionRef = serde_json::from_value(lazy.data.unwrap()).unwrap(); + assert_eq!((r.data.as_deref(), r.file), (Some("ref"), true)); + } + #[test] fn every_completion_kind_the_plugin_api_documents_is_understood() { let wit = include_str!("../../../../wit/providers.wit"); diff --git a/crates/ide-host/src/plugins/providers.rs b/crates/ide-host/src/plugins/providers.rs index 2703ca127..3a6697da5 100644 --- a/crates/ide-host/src/plugins/providers.rs +++ b/crates/ide-host/src/plugins/providers.rs @@ -169,7 +169,7 @@ pub(super) fn secret(_pkg: &Package, decl: toml::Value) -> Result Vec { let d = Arc::new(doc.clone()); self.edit_calls(ProviderKind::Definition, &doc.language, move |rt, timeout| { diff --git a/crates/ide-host/tests/plugins.rs b/crates/ide-host/tests/plugins.rs index c4807d701..74ed0de20 100644 --- a/crates/ide-host/tests/plugins.rs +++ b/crates/ide-host/tests/plugins.rs @@ -2951,6 +2951,30 @@ fn completion_quick_fixes_problems_and_event_kinds_of_api_1() { let foreign = ide_plugin::CodeAction { data: Some("other".into()), ..action }; assert!(f.host.resolve_code_action(&plugin, &doc("lazy"), foreign).is_err()); + // File operations come from the `file-actions` export, next to the providers' own. + let mut actions = f.host.provide_code_actions(&doc("files"), ide_core::Range::default()).into_iter(); + let (_, action) = actions.next().expect("offered"); + let (plugin, later) = actions.next().expect("a lazy one too"); + let dir = f.project.clone(); + assert_eq!(action.title, "Reorganise"); + assert_eq!( + action.operations, + vec![ + ide_plugin::FileOperation::Create { path: dir.join("created.txt"), text: "hello".into(), overwrite: false }, + ide_plugin::FileOperation::Rename { from: dir.join("old.txt"), to: dir.join("renamed.txt") }, + ide_plugin::FileOperation::Delete { path: dir.join("gone.txt") }, + ] + ); + assert_eq!(action.open, Some(dir.join("created.txt"))); + // Listed with `data` only: `resolve` on the same export computes its operations. + assert!(later.file_action && later.operations.is_empty() && later.data.is_some()); + let resolved = f.host.resolve_code_action(&plugin, &doc("files"), later).unwrap(); + assert_eq!( + resolved.operations, + vec![ide_plugin::FileOperation::Create { path: dir.join("later.txt"), text: "later".into(), overwrite: false }] + ); + assert!(f.host.provide_code_actions(&doc("rich"), ide_core::Range::default()).is_empty()); + // A kind this IDE doesn't know is refused, not a trap. let err = f.host.run_command("misbehave", "subscribe", Some("file-deleted"), f.inv()).unwrap_err(); assert!(err.message.contains("no event kind"), "{}", err.message); diff --git a/crates/ide-plugin/src/lib.rs b/crates/ide-plugin/src/lib.rs index 1725a06fc..1b417b2b0 100644 --- a/crates/ide-plugin/src/lib.rs +++ b/crates/ide-plugin/src/lib.rs @@ -20,6 +20,6 @@ pub use runtime::{ API_VERSION, CANCELLED, CallCancel, CallError, GuestError, HostApi, PluginEngine, Runtime, RuntimeSetup, check_api, component_api, host_api, }; -pub use sandbox::{MAX_READ_BYTES, inside_root, read_text, resolve_in_root}; +pub use sandbox::{MAX_READ_BYTES, inside_root, read_text, resolve_in_root, resolve_new_in_root}; pub use types::*; pub use wasmtime::component::Component; diff --git a/crates/ide-plugin/src/runtime.rs b/crates/ide-plugin/src/runtime.rs index aabc1d6ee..d27449533 100644 --- a/crates/ide-plugin/src/runtime.rs +++ b/crates/ide-plugin/src/runtime.rs @@ -4,8 +4,8 @@ //! themselves are in `wit_host`. use crate::types::{ - CodeAction, CommitDraft, CommitProblem, CompletionItem, InlineSuggestion, LineMarker, Location, PluginHover, - PluginInlayHint, ProviderDocument, SemanticToken, + CodeAction, CommitDraft, CommitProblem, CompletionItem, FileOperation, InlineSuggestion, LineMarker, Location, + PluginHover, PluginInlayHint, ProviderDocument, SemanticToken, }; use crate::types::{ EventKind, HostError, HttpRequest, HttpResponse, Invocation, Limits, NotificationLevel, ProcessOutput, Prompt, @@ -16,8 +16,8 @@ use crate::types::{ ViewEvent, ViewField, ViewListItem, ViewTable, ViewTreeItem, Viewport, }; use crate::wit_host::{ - bindings, commit_checks_bindings, details_bindings, hover_bindings, indexing_bindings, inlay_bindings, - providers_bindings, semantic_bindings, syntax_bindings, views_bindings, + bindings, commit_checks_bindings, details_bindings, file_actions_bindings, hover_bindings, indexing_bindings, + inlay_bindings, providers_bindings, semantic_bindings, syntax_bindings, views_bindings, }; use ide_core::CancellationToken; use ide_core::ipc_path::to_ipc; @@ -37,6 +37,7 @@ use bindings::openidea::plugin::types as wit_types; use commit_checks_bindings::exports::openidea::plugin::commit_checker as wit_cc; use details_bindings::exports::openidea::plugin::detail_provider as wit_detail; use details_bindings::openidea::plugin::detail_types as wit_dt; +use file_actions_bindings::exports::openidea::plugin::file_actions as wit_fa; use hover_bindings::exports::openidea::plugin::hover_provider as wit_hover; use indexing_bindings::exports::openidea::plugin::document_indexer as wit_index; use inlay_bindings::exports::openidea::plugin::inlay_hints_provider as wit_inlay; @@ -543,6 +544,7 @@ struct Exports { syntax: Option, providers: Option, indexer: Option, + file_actions: Option, views: Option, semantic: Option, details: Option, @@ -626,6 +628,7 @@ impl Runtime { let plugin_indices = bindings::PluginIndices::new(&pre).map_err(api_hint)?; let syntax_indices = wit_syntax::GuestIndices::new(&pre).ok(); let index_indices = wit_index::GuestIndices::new(&pre).ok(); + let file_action_indices = wit_fa::GuestIndices::new(&pre).ok(); let provider_indices = wit_prov::GuestIndices::new(&pre).ok(); let view_indices = wit_view::GuestIndices::new(&pre).ok(); let semantic_indices = wit_sem::GuestIndices::new(&pre).ok(); @@ -647,6 +650,10 @@ impl Runtime { Some(i) => Some(i.load(&mut store, &instance).map_err(api_hint)?), None => None, }; + let file_actions = match file_action_indices { + Some(i) => Some(i.load(&mut store, &instance).map_err(api_hint)?), + None => None, + }; let views = match view_indices { Some(indices) => Some(indices.load(&mut store, &instance).map_err(api_hint)?), None => None, @@ -684,6 +691,7 @@ impl Runtime { hover, commit_checks, inlay, + file_actions, }, limits: setup.limits, version: setup.version, @@ -866,9 +874,23 @@ impl Runtime { selection: ide_core::Range, timeout: Duration, ) -> Result, CallError> { - let d = doc_to_wit(doc); - let actions = self.provider_call(timeout, |p, s| p.call_code_actions(s, &d, range_to_wit(selection)))?; - Ok(actions.into_iter().take(MAX_PROVIDER_ITEMS).map(code_action_from_wit).collect()) + let mut out = Vec::new(); + if self.exports.providers.is_some() { + let d = doc_to_wit(doc); + let actions = self.provider_call(timeout, |p, s| p.call_code_actions(s, &d, range_to_wit(selection)))?; + out.extend(actions.into_iter().take(MAX_PROVIDER_ITEMS).map(code_action_from_wit)); + } + if self.exports.file_actions.is_some() { + let d = file_action_doc(doc); + let actions = self.call(Invocation::default(), timeout, |e, store| { + e.file_actions.as_ref().expect("checked").call_code_actions(store, &d, range_to_wit(selection)) + })?; + out.extend(actions.into_iter().take(MAX_PROVIDER_ITEMS).map(file_action_from_wit)); + } + if out.is_empty() && self.exports.providers.is_none() { + return Err(CallError::missing_export("providers")); + } + Ok(out) } /// The edits of an action `provide_code_actions` returned with `data`. @@ -878,6 +900,17 @@ impl Runtime { action: &CodeAction, timeout: Duration, ) -> Result { + if action.file_action { + if self.exports.file_actions.is_none() { + return Err(CallError::missing_export("file-actions")); + } + let d = file_action_doc(doc); + let a = file_action_to_wit(action); + let resolved = self.call(Invocation::default(), timeout, |e, store| { + e.file_actions.as_ref().expect("checked").call_resolve(store, &d, &a) + })?; + return resolved.map(file_action_from_wit).map_err(|e| CallError::Guest(e.into())); + } let d = doc_to_wit(doc); let a = code_action_to_wit(action); let resolved = self.provider_call(timeout, |p, s| p.call_resolve_code_action(s, &d, &a))?; @@ -1281,7 +1314,10 @@ fn code_action_from_wit(a: wit_prov::CodeAction) -> CodeAction { .into_iter() .map(|f| (std::path::PathBuf::from(f.path), f.edits.into_iter().map(edit_from_wit).collect())) .collect(), + operations: Vec::new(), + open: None, data: a.data.map(|d| clip(d, 64 << 10)), + file_action: false, } } @@ -1305,6 +1341,82 @@ fn code_action_to_wit(a: &CodeAction) -> wit_prov::CodeAction { } } +const MAX_FILE_OPERATIONS: usize = 1000; + +fn file_action_doc(doc: &ProviderDocument) -> wit_fa::Document { + wit_fa::Document { + path: to_ipc(&doc.path), + language: doc.language.clone(), + version: doc.version, + text: doc.text.clone(), + } +} + +fn file_action_from_wit(a: wit_fa::FileAction) -> CodeAction { + CodeAction { + title: clip(a.title, MAX_TITLE), + kind: a.kind.map(|k| clip(k, 64)), + preferred: a.preferred, + edits: a + .edits + .into_iter() + .map(|f| (std::path::PathBuf::from(f.path), f.edits.into_iter().map(edit_from_wit).collect())) + .collect(), + operations: a.operations.into_iter().take(MAX_FILE_OPERATIONS).map(operation_from_wit).collect(), + open: a.open.map(std::path::PathBuf::from), + data: a.data.map(|d| clip(d, 64 << 10)), + file_action: true, + } +} + +fn file_action_to_wit(a: &CodeAction) -> wit_fa::FileAction { + wit_fa::FileAction { + title: a.title.clone(), + kind: a.kind.clone(), + preferred: a.preferred, + operations: a + .operations + .iter() + .map(|op| match op { + FileOperation::Create { path, text, overwrite } => wit_fa::FileOperation::Create(wit_fa::CreateFile { + path: to_ipc(path), + text: text.clone(), + overwrite: *overwrite, + }), + FileOperation::Rename { from, to } => { + wit_fa::FileOperation::Rename(wit_fa::RenameFile { path: to_ipc(from), new_path: to_ipc(to) }) + } + FileOperation::Delete { path } => { + wit_fa::FileOperation::Delete(wit_fa::DeleteFile { path: to_ipc(path) }) + } + }) + .collect(), + edits: a + .edits + .iter() + .map(|(path, edits)| wit_fa::FileEdit { + path: to_ipc(path), + edits: edits + .iter() + .map(|e| wit_types::TextEdit { range: range_to_wit(e.range), text: e.new_text.clone() }) + .collect(), + }) + .collect(), + open: a.open.as_deref().map(to_ipc), + data: a.data.clone(), + } +} + +fn operation_from_wit(op: wit_fa::FileOperation) -> FileOperation { + match op { + wit_fa::FileOperation::Create(c) => { + FileOperation::Create { path: c.path.into(), text: c.text, overwrite: c.overwrite } + } + wit_fa::FileOperation::Rename(r) => FileOperation::Rename { from: r.path.into(), to: r.new_path.into() }, + wit_fa::FileOperation::Delete(d) => FileOperation::Delete { path: d.path.into() }, + } +} + fn opt_clip(s: Option, max: usize) -> Option { s.map(|s| clip(s, max)) } @@ -1523,6 +1635,8 @@ mod tests { kind: None, preferred: false, edits: vec![(path.into(), Vec::new())], + operations: Vec::new(), + open: None, data: None, }; assert_eq!(code_action_to_wit(&action).edits[0].path, expected); diff --git a/crates/ide-plugin/src/sandbox.rs b/crates/ide-plugin/src/sandbox.rs index 1756b1f9a..7d966ff16 100644 --- a/crates/ide-plugin/src/sandbox.rs +++ b/crates/ide-plugin/src/sandbox.rs @@ -68,6 +68,49 @@ pub fn inside_root(root: &Path, path: &str) -> Result { Ok(resolve_real(&joined).starts_with(&root)) } +/// Like [`resolve_in_root`] for a path that may not exist yet (a file about to +/// be created) or that names a symlink itself (to delete or rename it): the +/// directory part is resolved through symlinks, the final name is kept as is, +/// and the result must stay inside `root`. +pub fn resolve_new_in_root(root: &Path, path: &str) -> Result { + let outside = || format!("{path}: access outside the project root is not allowed"); + if path.is_empty() { + return Err("empty path".into()); + } + let root = root.canonicalize().map_err(|e| format!("project root unavailable: {e}"))?; + let requested = Path::new(path); + let joined = if requested.is_absolute() { requested.to_path_buf() } else { root.join(requested) }; + let mut lexical = PathBuf::new(); + for part in joined.components() { + match part { + std::path::Component::ParentDir => { + lexical.pop(); + } + std::path::Component::CurDir => {} + part => lexical.push(part), + } + } + let (Some(name), Some(parent)) = (lexical.file_name(), lexical.parent()) else { + return Err(outside()); + }; + let mut missing = Vec::new(); + let mut existing = parent; + while !existing.exists() { + let (Some(dir), Some(above)) = (existing.file_name(), existing.parent()) else { + return Err(outside()); + }; + missing.push(dir); + existing = above; + } + let mut real = existing.canonicalize().map_err(|e| format!("{path}: {e}"))?; + real.extend(missing.into_iter().rev()); + real.push(name); + if !real.starts_with(&root) { + return Err(outside()); + } + Ok(real) +} + /// Reads a UTF-8 file that `resolve_in_root` already approved. pub fn read_text(real: &Path) -> Result { let meta = std::fs::metadata(real).map_err(|e| e.to_string())?; @@ -130,6 +173,36 @@ mod tests { assert!(inside_root(&root, "").is_err()); } + #[test] + fn new_paths_are_confined_to_root() { + let tmp = tempfile::tempdir().unwrap(); + let root = tmp.path().join("proj"); + std::fs::create_dir_all(root.join("src")).unwrap(); + let root_real = root.canonicalize().unwrap(); + + assert_eq!(resolve_new_in_root(&root, "src/new/a.txt").unwrap(), root_real.join("src/new/a.txt")); + assert_eq!(resolve_new_in_root(&root, "src/../b.txt").unwrap(), root_real.join("b.txt")); + assert!(resolve_new_in_root(&root, "../x.txt").unwrap_err().contains("outside")); + assert!(resolve_new_in_root(&root, "src/../../x.txt").unwrap_err().contains("outside")); + assert!(resolve_new_in_root(&root, "/etc/new.txt").is_err()); + assert!(resolve_new_in_root(&root, "").is_err()); + } + + #[cfg(unix)] + #[test] + fn a_symlink_is_named_not_followed() { + let tmp = tempfile::tempdir().unwrap(); + let root = tmp.path().join("proj"); + std::fs::create_dir_all(&root).unwrap(); + std::fs::write(root.join("target.txt"), "t").unwrap(); + std::os::unix::fs::symlink(root.join("target.txt"), root.join("link.txt")).unwrap(); + std::os::unix::fs::symlink(tmp.path(), root.join("out")).unwrap(); + let root_real = root.canonicalize().unwrap(); + + assert_eq!(resolve_new_in_root(&root, "link.txt").unwrap(), root_real.join("link.txt")); + assert!(resolve_new_in_root(&root, "out/x.txt").unwrap_err().contains("outside")); + } + #[cfg(unix)] #[test] fn symlinks_cannot_escape() { diff --git a/crates/ide-plugin/src/types.rs b/crates/ide-plugin/src/types.rs index 6287b8e88..d071a247f 100644 --- a/crates/ide-plugin/src/types.rs +++ b/crates/ide-plugin/src/types.rs @@ -442,8 +442,21 @@ pub struct CodeAction { pub kind: Option, pub preferred: bool, pub edits: Vec<(PathBuf, Vec)>, + /// Applied before `edits`, in one workspace edit with them. + pub operations: Vec, + /// Opened once the action is applied. + pub open: Option, /// The plugin's reference: the edits come from `resolve_code_action`. pub data: Option, + /// Listed by the `file-actions` export, which also resolves it. + pub file_action: bool, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum FileOperation { + Create { path: PathBuf, text: String, overwrite: bool }, + Rename { from: PathBuf, to: PathBuf }, + Delete { path: PathBuf }, } #[derive(Clone, Debug, PartialEq, Eq)] diff --git a/crates/ide-plugin/src/wit_host.rs b/crates/ide-plugin/src/wit_host.rs index 44eaef7a1..368510666 100644 --- a/crates/ide-plugin/src/wit_host.rs +++ b/crates/ide-plugin/src/wit_host.rs @@ -986,3 +986,11 @@ pub(crate) mod inlay_bindings { with: { "openidea:plugin/types": super::bindings::openidea::plugin::types }, }); } + +/// The optional `file-actions` export. +pub(crate) mod file_actions_bindings { + wasmtime::component::bindgen!({ + world: "file-actions-provider", path: "../../wit", + with: { "openidea:plugin/types": super::bindings::openidea::plugin::types }, + }); +} diff --git a/crates/ide-plugin/tests/fixtures/commit/dist/plugin.wasm b/crates/ide-plugin/tests/fixtures/commit/dist/plugin.wasm index 8f307470c3cb96fa68b35e977aae69634f3f8ca0..1e0a4b5d60fa063aaf85a3c66ac93c7b0d002b71 100644 GIT binary patch delta 2469 zcmZvdeN;?&7{~8(XG||sWTl--+np(^)=Mg43Ee$QmTfD-Vpkly>U7%WY~GHH zvdIS0lBmL)XNdt3?7tjO2We=hT#~#mv|@nLN)m!Y0U6m15NKlFeAfB zc!nxizQ3MD{clMxQJ=HvQ&SmJ1l8tD32m=*YbapWqc+Jf_(3g=G{cb*tA8LUQWU_d zn@Pa-Dm23L?K$sIk<+QMkWYs03a|N=ml?wo9PgT8=Eei$r!=n zneWI{l4pnfaU*>*zc$?$;`M~Axp=Im4Hg=+w&58IQHSHP8*=&ANYDsFvS$IFz>=I~ zI4E@Iq)Bkh5^^IzC+KsB0^Zy_7K|J6{_!dO1wUt7yHgwiu?fd&d&FSYGGCWAsMs~`@+S@6@?3+MJO%Y zCL7vj%H_iq4jx>!es4H1XMaD#4_56h?|mIqW)-axn_Zye<5MKQ>N zqA=w1qBI9{4AlURN)B9HfXjbf3_=bs9*Ck^1Xo==zO3vAE(r`yhp}g72*#xmpmfB^!k<6^{b++}`KzD`F% zcO3_qv|e9^oN(hl(zDGRBnz(}ws|1!+G!oZ?Q|-N+9x56?N`BgwDczZpp@O(^zJl~ z9lj_{>c0>!#6tda}efoCAEZ2g%tG{6D;c z+5IM}tA{o}^d4<~?>%}5Rrg{Bz&XM1;Ud7F>W_~`*>^OWKIT&Xk)V6jE5X&Xz28Bu z;Q4o`3%twoL2i0pGIFquuWbjnuACL7y#~+?26&Bs7CjJ8l%DNQS&H zmkJ!~be;y0%geL|Ke*!sof)U*LYOj|Wf(7pVd`w0m?*Sic(3etAD-bF1wzKsD3E3t hq9D}{eGF=tRoaE~U6dV9%>T38>=yt4 delta 2460 zcmZvdc~BE)6u|dwLO=o)tJnZiHUSmtEs9q0*iIFzwSc0w+IozwFbu6u@fs0{2a44i z^czJvgnAJb6uZ`dM2r|gF-SyIP;?NmI^#~IBOPhI`o3fnapa%h+wXhtd)N1N_kd23 zsZ$g+cVl1e7h1brR-~M+H8IK*hBr&HPLg^_wo6h$jb2KNyc_mI?sQY>#9nFp;Xb?C zlWO)#XHHAXY)O7Vm1egZyJ?dU+QW4ow34w2e#kiq-#{Zdl`s!pZx7m&=!LqD~g*K9$xBx_QFHr;fUCS3kI{AM2NMz>nHGT9qOj;&BM8>G)vWcAh zvy^C0HgLUGt7Uk-Fm#0nKmi%IG77SZHOoiHUpWjwOBz-+Ly=%yJ%a@!>7JAXr^vRX z2=?VwQkSH`#q*>+7;negsgOn*)`oXavjyQ{48w2?|Cj_Nhk%KEl{~obV+#%MMKB`6 z$#{lZuzY8G7VUpaevNhIt^3@T#yCNfk}0F*m2HRsjC#;@6ZB}hNF04pFS{&pN@2%lbOlE9N2yCmReg-j&!;=Ph`yOY@4tP;`u=OCo zWsxIN%_vF@7F{Yka6VAuE_T_!U8f6H(0P{Z3NgP#N;GkHRQtnXebbR=1v8?f%$ox zAYEw5)5&m=cqj^r1@j?qs=0GG92@e{krh3Sw!7}sKi)`kk3{&JZ2KBnFe}&KRR^eBH@593^9tT7asWsC@r9LPB) zjP1qAIYk)j=JA12N=77bt`~?x?{oO}i6pQr2D!Sd0y*J)Jo4E2T$Q5^H%vqJg(GQR zB#TT5XmZWe5BZPj6C`(G_yA{tlboiGEjP8?1EkoUiau~*fsZ3du}mY!gU)t|#J7An zdY)d+A%7~5!U;HEKDoEUzDTB)cQW?7xET!&TwIIB0p^8Bt(hiv-0bH(qS7edrY4d` z^QWN>Z(g?GoGT}f^mHW3+m)Pa80+Q8UBQcF%B2uLM`769AYQvpt&lmcStQ#pxrU6Y>Wz%8+JbyqH3S)OwE_9>Rcb%bl8iiN8HB92+(VwJrZ#_8*C9)< z(Sdn-Z6b1LO`J0~)!R2mBn360PDQWIif1)HLdiqYl-x?tP2={T{77`94M#3h!%ajf0zL8eT1Z$eO03_!RVDyqh#i z40+QMj9bC2w9sUy`*(`un`x1&o8K0BqL~)y)k2HxXrbPNTeGA$oCAEZyDQm=_hI5b1N<0`ynlU*F$;M!Cz_d2WX*COXz1(Vn&!`)MDKSH(; z@OMOSXg9>VLaRHcIJxwV z$I!C)Bz_XD9mRNt`1`vCXiv6YF95N24xVg)t%P;GJIk{$gsvhnhUC! Z1jC|P&>tY(uyr;hvfyEO^)(zG{6C5Q=K=r# diff --git a/crates/ide-plugin/tests/fixtures/commit/dist/plugin.wasm.sources b/crates/ide-plugin/tests/fixtures/commit/dist/plugin.wasm.sources index a1ba8694c..afeba1992 100644 --- a/crates/ide-plugin/tests/fixtures/commit/dist/plugin.wasm.sources +++ b/crates/ide-plugin/tests/fixtures/commit/dist/plugin.wasm.sources @@ -1 +1 @@ -6c6c9e25269f0c7d11aae8fd6c7ff66f457c8883b4f9ff19ae75f96c445ca3ff +5752ebfddd9d2f2aef2ed7dfea7f39b3439f28b7f9bd09e2f32e40a65fc65f07 diff --git a/crates/ide-plugin/tests/fixtures/hello/dist/plugin.wasm b/crates/ide-plugin/tests/fixtures/hello/dist/plugin.wasm index ba88bd79d4688036d361478214cbce2b11db4507..015e757dca13e4976c1e46c9745c9a193fa7131d 100644 GIT binary patch delta 2732 zcmZ`*eNa@_6@S0C%d+eOyD5b5S>G-Q8b1&X6#3A72uma=q5{#NfH4y#q)9*0POLFl zO(c=TZC^82V@Y&MD_RjQ%Ic|rc^SP*+dcs7JXq4keLwnYyf z4H+Hd!A6 z{0($_Cx(kG8Ry3a+J)9df)FQU?rm>x7aW59xQ>z_pI6GpJUFI&FqV%oZ_Kz)6#bVJ z`)88!uZc8tDz?u881R}uKOes96( z1c%Y!l8j}~*T#v#aM*<(cs!#b275Mu#$dt31f5)Z6rBwgElf7pM0C1Mftk2lw<} z)-$=o%E|rgcR;RXkh`g>pG^Yyab?ELdjgzoH*Og6va0 z7IXl8YDz5HXDfFq4y{z~-gqcD#!klLJ7i_pkeWUaRP@*TNKwHmnWShbI@H|(w!wz) zBEWn$A{$_Nc5FpI^Vo4?7Wq8)pmTP2soMHA1PrMipK!hgdGhD_KXMGUF1D50cv#(? zgd7?~R+j61)@=D`C9^$Qc)=ShLuaVR*}Rsb^B=IRA)Nc zNCS2#1GVt0S29oqbg+eUupdL}nK{^Cq;yePSchY3eHQN3g>0Kk4fvRyoQr1?y7^Sj z_?+Z!mY0o6;__@Z(g%%$7LXRrW!!;8P#`t19 zLQs*51|r{;i+v^%)lq;1^sD&==n@xcoX9*e*(t^eqAS#n-p_T_=81yS5T076QSN28 z3n{38Qpny_ z*i9RzSD~4pshm@Kxg2SceaTMK9a0+mZ8?@N3+J>ujkHFeld&c)%ux<5O3?+PJxtpq zYb>V%^QmBM1yZQe6BRfX?wwJxQt$3_qn;MN>E>aF-N;Lfl&OiRqOoB&PcZ35DTU`( z;?+BOER^TZmFT5~-4Aj>PCtn6la;d?g#^v3ae*MW3P}X+DjXoVP=#EA=_>q#VCW&f z&svS=$a<+7iwM+e3=_PzhDV;G;UnwywS0Citc8m#TMc$Z2q#z0AbhX}%OWd@Ggtmv zgKyK;igkF8z+TI9!u799&fG312lVA*CRupJ(|2sg1H;{j=GIFM^;)L zpX|+b+`0H+WUxamh+@5UI1s6S7qiNG{+;ZphZJddqSG{!;@kCTq1;IgxK1$L5YBy+ ztoNt{!Pvu`Y1$?}NryL~h@2m6!XKfX=-Ny#2o2&R*fTqYC5_Z>jcsm3K_uWVjk+6g zhyotif<}TLZQ)WiZq<3Hom=T8Aa7hVr*&f+(%GhFoFtc_1uM*VhAm)J*=JuVYXoEb4+5g8^ncK{xy$YdC?0bS)R2LYCTd0`$7~vS0S# z2tmb3d`J=Lr|1pvs}vDs65Fq-EBiqBwRzbV}@O$emIIR!QQ`yvoYisXkA#M WzIq)`0p05K7@|db@J$nVq5OYXQOGI) delta 2728 zcmZ`*eNzx5X6D2ezXM+`zx5YXmrux*SKF<6+C;rhN#I6wbgs?xfJ`l1^YVfI$ z;T{fdidUVZe(79FLaK5;=o}WU z=M?m1&)3HB!E$1o_pyJ+0#~Gs-z~u@_IfH(yhGpR1AS7`wQtbw9lN%ahfk^=`89S+ zzL83_N!HO!({3%Lxe1V(l|-p_^jRp<$D>v7OG#rT7Qc2b5k;JO5}(vOHl5aYjLn*Q z?X1ehy7M>cA$20BM)2aqc%I@KyDIiqHB zg_RRM>^&gQ z26W3Qv2agT?qD2RsN5a#kg$gxh{rF<%CI0cy*H@nJ6lOn&MX*&Xdyb(-CnlLf~OE* zJ`0fzuzV|4qldLyadi^;+Hb?o$=#)L%k3D|rMkb-`0B)wzo`F+G1R))7HVU=yeSDe zG>EJ&1vYjp8TsgBBgt45bRCZA)V4Z!z0~}90uxeE$R8b)PG4VuQ!-86R^X^?Pe&_h zz;v5Va( zr2GoYnu|vWcFx5jf|GNxD>j(N9wn$@PZv=^g?&;42Z6pA1q4OKq!n!{#uS1>#h6EM zxfm-6TqT%8u(1S{Q$m^a0_Wfp1-)Q!@W$A9bBLM3&Xyn%iu^+f=sHjsKM%_Z8s^~x zf}hQ&;ZxX4^YKP<_-ICArCS(2ho~^8le(v{zdDgkFyN$bPhmHlm^~wM?utlw*k!co zV-aF8QHw1i*3kBIBJLy@6R8gh%PoUIu&9g%po_g;23Jy;jYntGM|4)$^)kFjAzKz; z6Kxn@fF^=9e z!g4AwoeI`gAcZPDT7k}R@AQJ1dUvM_^|bJFmln3ih5W=wnVN_y3LA832}WEfrSO7E z{QhPh6Xp4|5{GDE(|wvChwsC$$jVuWLV~7+I8KmPg(L!36}A%`uRe?$a<+7GYRBs3=+J&NQ*qS2m@rjx>%c?4AI z)!<3mTCoHl5m;-r?9N)eOV)pDH6C{_)p-1EDej@!JHHee>g>_vWfDwXuI;E>j$>q{ z)oGKxvQBf(dH@-0S2Lp6p*n1j)W3yUWxe*DY_5k8X?LRCFp*+UJ(?+ZQUfj#j5maH zzed(aRD!_&fW|a!g*HihR-lNSpRK@$Q1*AMq!)w+@j+~!oWk9W)NX~XY=k2caEnG= zjo3v2_pCxA!R}R>RE?`u9`erB^b(Lau1TYHbuH4_iY6Q&m#!J}jG;;7SaTgx*vLb$ z&`R{WpfJxx>fNG=uvXKgVeS9dGeHv+SoE-p3mDBbTn_!h^_?yZ3`$_b&EU zH(nvAIDjuGBK;t}0e+bxq73}#1$n-Q)SzDi&m6&B^dm>!=S88O!cWRrlHk6e@q)lx zd(@}ZY(6iS_TuCWw6WwNbl4m`$7OOH_jQbwTTYlowrzr)Eq^hDAHhDqh~6k#<8tLc VUBctQUfD2=Xr3PX_{(^q{C|=Szz6^U diff --git a/crates/ide-plugin/tests/fixtures/hello/dist/plugin.wasm.sources b/crates/ide-plugin/tests/fixtures/hello/dist/plugin.wasm.sources index a92345f28..1c16ed578 100644 --- a/crates/ide-plugin/tests/fixtures/hello/dist/plugin.wasm.sources +++ b/crates/ide-plugin/tests/fixtures/hello/dist/plugin.wasm.sources @@ -1 +1 @@ -21fefee002afa17326ad22d9ff7e099500d07ab595035be3c6001ac15f4a08b0 +5f0ec195975e34065350eddabc252b830d2d7e8c87842be2d6310bff5a22eb67 diff --git a/crates/ide-plugin/tests/fixtures/hover/dist/plugin.wasm b/crates/ide-plugin/tests/fixtures/hover/dist/plugin.wasm index efcad8abe2bcce9a9c811b181b93b72c5f57fe2a..f5c370a19a90f8de3812f927f89c0b44eb413c23 100644 GIT binary patch delta 2499 zcmZve2}~4M7=Y)WT^3|PX+Q!hvb$InEyy8wR4wCy)T7{ukSdB&EQbwZ#Zu4}Rwatn z@X%f55JbfTboC7d6%e9TS`|>J&{hpGq-uJgDT&yq?f-UXS8T~9-#h-}{l}Y`eRbJJ zS8HP|wS$NBsNE#Rw%_kGaLR3*kbBoW7D{86v|lT&6-?=xv;ekvA}#FMf@kQGb{Y+4 zUk+@uRdV!75_U_YBNM)|Yc{JI>FOcZ{h*zW37N%1H%Xj133_SS%<%v^+A=EzAfF0z ze&jtW?lx$-1Rsub?ybNtr(lULn<_ zWqt=3Y59WlJk*e=@EABoE{1DR<$m~D=p-Q#LCDP!>F|s^j~E8esKX)$K(YJc2xujZ z(e5;Ru|J?~)sjchM-59C^UzCvTmCh?B=M1RK_urQz3g6^0#vRherZEVPh>i7C#;x< z4ysm68`5eL3NV#p@f!1@yrGYbi}HQHJ92=M9+p+ z+8Es-!*mX<3Ih=7qZokq3^$pRP)lV51MOYy2GBqpW1FCX-is|AK!@b4TaS4^UpEc& z_Ki#Os`+n)H6WPxRHm>%5NTap8SvWMBsM<4zRMK43WR60I6eoUlaBdZJJ3Nj2?=YZ^#{RcRJnjMIV-lq@=oG1$L*7;h~AF-K-{UU;1NDY&NentK?< z_H_C*Efkwg{k}@VoJdjnBIu$$>GJ?PFf~I5P4r4eq71Lrcx?o)ZKIi57r<5C_G!Gf zg|u$p4AL?W*-_G6;t`-U?gszI2eq4a4-nztY3tT(|aO! z=w~3W>7$XJhCq9>DK>WyF`jlM8x3PoP+;(IwZtXY*w1kUDJ+pT8}Qi^$uEbNBK;0u zN4_|mfQ&6T;%2e2!%$=&TLKqE;$E19Dmx2DBP$EXAv+5LT&zjXv8v{hkwvax$uqhr z#@*txMy8RYp0z?Exmy%~j%(S|GKDg|gw_feh>&dbT++KE!l_=*}8i;wvC*yR=@n&n695iy3Y~kBOi06r2s8W7n z0`1LTHNOsDu%J2LfjAhP^)2=dA4^)8n9-RAalz3xn) zRp8QJaOTWLv>RFR1M+DF^Xgt%i@aCKP9AiYoxJPpM0}Ojp7mfi@8@$~$T#Phs;}`o zWUq0Com3$p4=KCAwxS2op3k)&`A#gV3+&N|yuj|wqIwtP-V1AxJr^D$J1FyPD;9W4 zKDl7tZU|lu{4o3j^ZVu0CyLHmoPXQcS*}C@#|$4X;b|O5>R^zXZLH_qdmNi z?RH&Z1+XE>bz7{y-zmb&I#vX~`nN^+tezF2sh$~KDtRJ@<*z+^5 zk@aI+W4sM?)5q7N0YA4hn?A75ZDlVld=Kx zAN4l)rAhtk6w;%&68}%!?2VTV)7@d#)(?(@N-jN!?PNip8~*n&b1TlO=mJ%EPs4$BEG6 F{V%E(%Jl#M delta 2490 zcmZuy2~1Q+7=Hg-c0m@D1|*;$yNgxPiX4hZ(egZidK5enQZJN35p56)N>Nu_k0@5c zpu5T;2ny=s(1C&q2(eXKDI!>*EjGrOim5G{l1Ll0{b%>>iYN6J_{kh+&w1|EYPFo2b2!096(zq57bG?!1VmC1;c4^2n4oe!@ktp;dLvR%9KU)Y zG?VJpfg_rYN&#kZEZ@?sNH2I!CPsR{YiMC*Is9R)L?&>|fENav^Fk@v75N%#NsF2f zEwm}BQ-uNe{YVo@Omaa64kwN0p^7x;^rN58((un^1)Hq+cFK%eJyZd}mEz^y~>o7rgQo#?j zk{gGk*x+$w6%I7zNV;NVW(PX~6L=R53_1nFv-0@KqD95qb9|6Qv98nPz-eS=2aT1W zBVE~J@!-D7jzx?)z66mTKW1l&p^>YY$wwz5P<-x00OEra(-0l?OA%xA9*Fz(a}dAQ zMFIWH@X?E-s{(h_N_0q>qjem=PZ(dX1n#FwYy z5u z6#;yeOvwkCK69;>#wgz8Cz9-fndsbF;3n;)vJT)KlqMgILJ+eGy+&IK3*g5J+TCh} z%-mOz%r7i3_sdG9#C|<5T!jHc&Uj&diD!Jh%>_GzSy++MH1340QpT&LpR6E~wllNQ zeR$EAZ=%{_)Y2jm#Vd;$MTd%0K+HNj1E(|3wpzMmr?FDWmb}@7c$_6@R65neAmy_8|u@~vD{m)X^bxXjMY(gr8Qqn9@z_FjI1*hyJr>#7_NDJB=d z+l;`&fe*t!uxLTf|TO8yG4t0^_Rht6bJtrwd5 z*9KVBZ*jA$_86+|uY8Oce}yqL?J6cmW3Fl$6Te<#nKn1L5x=_gIP0!sS9^3llRmu8 z2#}L4^*b!F-y-3!dPagz!y6JlX<#HYH!u<^ubYD8;5@C-9r08n>&N$v?EWllV*S|D z6f4JH?~|KRfY0sR=J#xMZS1FoKcQ^8qq#taQrDI(_#_@|32}yEdgsw&TO6u>Z;<0l zll13#MEAZjct&sc#mYtv7`-hIj-AR%x`-`galZ?`_a@wp^A@V_kKrMMzWTe34Xv;G zZ9vrDQoudPt;w~9{W8a5Q!=399WvP)rc^$unW}_2o=~b!@`lOk0G{JKIgYz!?ZBr{9w4Zu&=-<;sH+({6?(n?1&U diff --git a/crates/ide-plugin/tests/fixtures/hover/dist/plugin.wasm.sources b/crates/ide-plugin/tests/fixtures/hover/dist/plugin.wasm.sources index a31a00868..75d41c99a 100644 --- a/crates/ide-plugin/tests/fixtures/hover/dist/plugin.wasm.sources +++ b/crates/ide-plugin/tests/fixtures/hover/dist/plugin.wasm.sources @@ -1 +1 @@ -d7aa5bd1a9fefa6e6c35534dfd507d0f4aa872bb128ab6a01c35fb8abdc474b2 +9551f337f0949c7249b022b8663333a66ae3534a7e0e112b37ed93d431960a54 diff --git a/crates/ide-plugin/tests/fixtures/indexer/dist/plugin.wasm b/crates/ide-plugin/tests/fixtures/indexer/dist/plugin.wasm index ed7a7ecb6ac5f1160d3173ec14f8590edde6c930..596b975d16dd0d534c7d876eb72d42e5b73d523f 100644 GIT binary patch delta 2366 zcmZvddrVVT7{Kp$TS{$FyHQAe5ZmIWxak56oJ<$43QQNKs1YALd`u}Qn-k|06g!8A z(MjRV0g4d>l}CZ%5n2!x5fKywlP+kS3)wVkG93&4fm^2gPG58zY4SVwobUa8=l1sI zc=YFZm`bJ4NKZ>cB>Rrkw{r4*oM3dUEsj<1SbuV?5~lRfvB^1aHuM)`Hux9Yi+nH)Ek^Z!P#*K-<9@dI1coX}0Y zV^@QTq{fDTiI&CI@SrD0*J#N0HItwipN6529$Z_`!(B2bArab1QG%A&*OE&K8(^5I z6GMS>Hv9sGbl1jZJbX`XZOVWm z616!BtR#1{zqIH)OHsa#D6)M>@8)zoUYxWT9UM!VJATlXzW`wz%eapWBn3brk?Cf= z)oNsBibGfxrxpnu)8GYneIE7Wb+1rAE_opg($eI95mvN2^D8Q~(3y*|ts?pp9Raj-o?!X*#U@PTE|oeB6$${&)Y|WGx8xGqo)(5Ulj%jxvA} zBJ2#7>1$X}H3$Zpxibe~n0oHgj~1tJcM8T4r4x8a3ewZy1(9b=^vkjrZrqQBb8@vr z?Wy*(&sNAXlKB~F&`KIJbjT@t5}=c0?)m-yb&|}zM@BuJM^|MIW1C3Keie2gW&boD zo{$9xG=yda;!qxC#oP9E_&juAIe)j3#3wJXje8#L%8tZwQ$@~JtcvVC6oa>c_8nRT zID?6Yv)~Cmb$E*i@0L7wDU{H-Tpz&AcEeokOr7B??{eE!aJ#KSIhmao1r=mp-X!FS zybqE6HhSl4@Hr%3H>#B>KM1A2=1+wRDkVh{C?}_j)*@dO#X>nkISCqRQs# zw~^mf&p=wLgOsi!BV4LR@~YYwoOOm76DK%*T0~kg>bW{(CFhMn=;)DAjg-_ZMXT7F zNLSt_kw)yMOlz`HA*^-}Dw}K9AysuVf*jRLLir0KIUjESIcs$dMlzD0mF%dSgT}RW zlO2)No}s)#Znx1&1S=V+3z+1pER>%r=rc7Ek#n$CGSyV#9GF-w$AR^kR-(sg^#Pb* zOnu-iXT^#ouC_Sxw1vW1$x}3r|5%J?s-K7E&+Ctlc$J~oobyIJ4xy|^I{GzofPR3S zaN)LVPF`BES`9gnvIzY4G66StB|uLU{7ipgM$iVR(gN7I=0 zFyxW;F0huZybd_k*pAFm6CqDK0#McaMyN~tuhzuh$VKt98*#|RovcAVU6>q==+d)B zblhZ_R`g6JZ{DiJrh~bg-Md`A-Frapb+aZYdPbTM*~6Mp(ZiZx zxNUcG0-xi0{gCOsY#cSc>;;<9$HtM^m*l}`nP}&as{uc@+WvQCMw9J(BNkfds{TO{ zo-Vqd3NNVn{@-5EO&gv(l;LuG=%SZ*w_O#~yrPPIU*vMqpaWhBhJr0h@Y5vn9Out* zoW?`Jt-v)J_ZqkTl7dPlkb*uXhzsWWK+YJHaj3(Eo4b5q8i3CHhc65Pd}e;6f|Pgu E0ljjjCIA2c delta 2362 zcmZvddrVVT7{Kp$3#Ds8yYUD~uBB4wH~$VN2j52@aDIRoEExa~b;@SQsJeBBP*_6h_L}={nLC zc>pGfB+45Z5|so>@*rw4D7lwWw!qF*kw2ri!%I>Uw}?Bq-viM4(t%$ghdX(2Ckt6* z@K7@3lAxF%(2?vIS3zzgjZ+j&#OaP?I3@{?x5jRT334gcZ{dVK2|4&OH0*vd9_tP{ zM5tKverqi?6JNm87zt0#Pz_dYsn4Q*gkl!c36I+hFS(MqF&<`gD&aE#9oPFMz`N=i z>Lk!qA-S3x{mL2OA$fJQA0BcoUzg0ILllV$%=|&3A7;Mb_z~BU|5jQCa>JQK9~Q`U z+|}cy00l&T!b>=d$z!Q?6l!!GIB`xKJ}vxT8h#D!e`p6{sE z-?ox zY+Hj5nYDzftSJx0D~#$!9B1W`%m@3h78=ttUEqRx3gB z>vo`3XkDN=ZZ%J8WueT~rK5sx{b^Lz)JG$oRjWLW+4FtaCZ34(H~dVwnj6EPi%&<6 ztJa}$y=tlPCW(y?D;61SWPG`fjH}$2m^1TX-Q=k$Qa;brSRHXw7n>SpB@to6M${qb zaYchW1{mDnvBs3Kc)PhQ#yIs?VXs8-Qsavj?^8FdNAuSWKhAj-qE}^OEgpMwv_=Z< zTjV(R335@>eRH2|WmXd2wz*r#+olXu$!PuvscC+M%x$3#v@K_l8#SwuM>S88U$j!4 zl-5z?t~M`ZMw>sfzfIv_O29eD!u95MFSEeGQjpnx4DDvy?;!^|sMj|goye9>dh?4; zdUI^o$M_yC>T;p8*M8F#`O8hJy5QCw>T=e<{!8C^0ytY9Hd2Ywaa!siw#mE86;U28=qJDthY z?Fcjt*7_o|v;&|k4Y>o@)zH3_c>^IY`rJ{~{;rQ%{IAkP+|5SutGnUIt^Kq>jsqAR z7ch`Y3(^uPVrAU*BAPxH4X+jJ+*zAbA&9_eTi#6xpM2ppnC zs2rk2$hmKDas{8mhh30K!?YcB!}JfdYJ|2UY9!X0ol$Z9Kko(n*viH}6qc#!YYSgP zP28TbNgkeVd7OaXL(SvAZ9&U5Py8;#XAt-aQu3KCXaO}{T9QD(COSO-w%A9es2 zsSnFAt_;ISt;Ni4T-|Ulwb(DuuW|sA@9zjoYZNhlng@=s0w7xR#tEhX!Zoj)A^wAZ E015`9%K!iX diff --git a/crates/ide-plugin/tests/fixtures/indexer/dist/plugin.wasm.sources b/crates/ide-plugin/tests/fixtures/indexer/dist/plugin.wasm.sources index 9bf5f1550..d4079b4f3 100644 --- a/crates/ide-plugin/tests/fixtures/indexer/dist/plugin.wasm.sources +++ b/crates/ide-plugin/tests/fixtures/indexer/dist/plugin.wasm.sources @@ -1 +1 @@ -44145d1953b8b1c5a5bd57a15f88d4b6e86c1d7f456a2cb24758d19aca9e152e +600ef2642cfb359fea47e10a6a056e3e34f230681152aaff5077127da4325f10 diff --git a/crates/ide-plugin/tests/fixtures/inlay-hints/dist/plugin.wasm b/crates/ide-plugin/tests/fixtures/inlay-hints/dist/plugin.wasm index 6be609a4e1f4ebb4143446679f31bfe86398f1e0..32a057954a578dd42975f0723c4efa1553083054 100644 GIT binary patch delta 162 zcmbP!nsxeV)(!7H87FN1;91DXxL|XV_abJ-Ih$GiyEz%(Or97Kz<6i#qX?U{GdYVA#Pfzz_nYRe*d&B);18TvNvX(+kWPS8xJ_8GzCZ8rx;f8LRXF DDibw; diff --git a/crates/ide-plugin/tests/fixtures/inlay-hints/dist/plugin.wasm.sources b/crates/ide-plugin/tests/fixtures/inlay-hints/dist/plugin.wasm.sources index 0b0a14901..fc837c71a 100644 --- a/crates/ide-plugin/tests/fixtures/inlay-hints/dist/plugin.wasm.sources +++ b/crates/ide-plugin/tests/fixtures/inlay-hints/dist/plugin.wasm.sources @@ -1 +1 @@ -c324bb5591738282f63e90918be93cd7ac2a15f3c75fa105b60ead52a0504334 +c766b42405732d8d0dfec0955c6592e937928c96f2aedcbf317cddb55fccbdcb diff --git a/crates/ide-plugin/tests/fixtures/jobs/dist/plugin.wasm b/crates/ide-plugin/tests/fixtures/jobs/dist/plugin.wasm index 68beedeeeb18a53fc439e4a031c7af1d47f0f53e..f6d907d3d1d8d3b65fba58fec36598a328c24fe2 100644 GIT binary patch delta 2598 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 Vec { + use exports::openidea::plugin::file_actions::{CreateFile, DeleteFile, FileAction, FileOperation, RenameFile}; + if doc.text != "files" { + return Vec::new(); + } + let dir = doc.path.rsplit_once('/').map_or("", |(dir, _)| dir).to_owned(); + vec![ + FileAction { + title: "Reorganise".into(), + kind: Some("quickfix".into()), + preferred: false, + operations: vec![ + FileOperation::Create(CreateFile { + path: format!("{dir}/created.txt"), + text: "hello".into(), + overwrite: false, + }), + FileOperation::Rename(RenameFile { + path: format!("{dir}/old.txt"), + new_path: format!("{dir}/renamed.txt"), + }), + FileOperation::Delete(DeleteFile { path: format!("{dir}/gone.txt") }), + ], + edits: Vec::new(), + open: Some(format!("{dir}/created.txt")), + data: None, + }, + FileAction { + title: "Create later".into(), + kind: Some("quickfix".into()), + preferred: false, + operations: Vec::new(), + edits: Vec::new(), + open: None, + data: Some(dir), + }, + ] + } + + fn resolve( + _doc: exports::openidea::plugin::file_actions::Document, + action: exports::openidea::plugin::file_actions::FileAction, + ) -> Result { + use exports::openidea::plugin::file_actions::{CreateFile, FileOperation}; + let dir = action.data.clone().ok_or_else(|| types::Error::Invalid("no data".into()))?; + let operations = vec![FileOperation::Create(CreateFile { + path: format!("{dir}/later.txt"), + text: "later".into(), + overwrite: false, + })]; + Ok(exports::openidea::plugin::file_actions::FileAction { operations, data: None, ..action }) + } +} + export!(Misbehave); diff --git a/crates/ide-plugin/tests/fixtures/semantic-tokens/dist/plugin.wasm b/crates/ide-plugin/tests/fixtures/semantic-tokens/dist/plugin.wasm index e85457d1d9690c0ed180647a481114a71ca9ddc3..006add95d46fe831056a82f598bf9250d2ef9d64 100644 GIT binary patch delta 162 zcmdmdmUZ)4)(yuz8EF>-L*RTTR7`|*@Y{4j?2LROZ BIHdpp delta 166 zcmdmdmUZ)4)(yuz8LwEFy5S8xKw8G!N(AGR;HU=+{; E0D%lQ`Tzg` diff --git a/crates/ide-plugin/tests/fixtures/semantic-tokens/dist/plugin.wasm.sources b/crates/ide-plugin/tests/fixtures/semantic-tokens/dist/plugin.wasm.sources index 58b7a457b..fecbd15f9 100644 --- a/crates/ide-plugin/tests/fixtures/semantic-tokens/dist/plugin.wasm.sources +++ b/crates/ide-plugin/tests/fixtures/semantic-tokens/dist/plugin.wasm.sources @@ -1 +1 @@ -aa2d8d38e49d10c03f6c639ce45b2a26b772c9f106a70547e94a9d46d8eef662 +8c7e44efd87d5463fc2333adffe051c9937e80e06869c2f5ffe8b49daa49ec0d diff --git a/crates/ide-plugin/tests/fixtures/storage/dist/plugin.wasm b/crates/ide-plugin/tests/fixtures/storage/dist/plugin.wasm index 36c158c773443f07f54fc215bbfeccd91b4070cd..b732a322d2e749553cf9473a1a9dda0568782ba9 100644 GIT binary patch delta 2460 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 HHje!t{t3=A diff --git a/crates/ide-plugin/tests/fixtures/tables/dist/plugin.wasm.sources b/crates/ide-plugin/tests/fixtures/tables/dist/plugin.wasm.sources index 603bbcedb..87140907b 100644 --- a/crates/ide-plugin/tests/fixtures/tables/dist/plugin.wasm.sources +++ b/crates/ide-plugin/tests/fixtures/tables/dist/plugin.wasm.sources @@ -1 +1 @@ -d7840fe3f2f2b21a2cfbdb7c874ebc3214d1a81e324853dd47b04d914434f050 +5d510fc9bdfe868bd392a8a0a46739f23db3db38bd9adb43d6b3c05d0c125c1d diff --git a/plugins/README.md b/plugins/README.md index 6a1b306f3..9bada5b16 100644 --- a/plugins/README.md +++ b/plugins/README.md @@ -480,7 +480,16 @@ can be a `snippet` (`$1`, `${1:name}`, `$0`), match on `filter_text` instead of its label, and bring `additional_edits` elsewhere in the document (an import). A code action can leave `edits` empty and set `data`: its edits are then computed by `resolve_code_action` when the user picks it, under the -command budget instead of the 50 ms. Problems (`publish_diagnostics`) can name +command budget instead of the 50 ms. A quick fix that creates, renames or +deletes files implements `file_actions::FileActions` too +(`register_plugin!(T, providers, file_actions)`; the `code-actions` kind +covers both): a `FileAction` carries `operations` (`FileOperation::Create { +path, text, overwrite }`, `Rename`, `Delete`) and `edits`, applied as one +workspace edit, so a failure changes nothing and one undo reverses it. A path +outside the project root disables the action; `open` shows a file once the +action is applied. Like a code action, it can leave `operations` and `edits` +empty and set `data`: `resolve_file_action` computes them when the user picks +it. File actions are new in API 1.3. Problems (`publish_diagnostics`) can name the tool that found them (`source`) and be `unnecessary` (faded) or `deprecated` (struck through). Editor providers run under the edit-path budget: 50 ms, after which the diff --git a/plugins/official/ai-completion/dist/plugin.wasm b/plugins/official/ai-completion/dist/plugin.wasm index c9697cd9883e9c355787c4cf9c3f84a7aec21165..edb14100e43db83ef4e7d377a66201a26f61f57a 100644 GIT binary patch delta 187 zcmZ2?f@|Fgu7)j)Dte3^+g0@#otYSCOwTl6G-q6~eW3y4OA*E;+q+#E*Kjg^nQr0F z7{K^s`h##r$?c2$8Go=d_Dr80&gjDUWIIsoju7LX?R&ErPjE7wnJ|4$IHNN}t?hP> zQbspM#xvXf%NX}DGJe_4SHbAT$k?+zvXXJqBgJ?o1_osY28KUe0t_KQ+84-IMB@8z a=ZRrrXP(X<&$NdXD95m6`;~a6C>H?z`a0|Y delta 191 zcmZ2?f@|Fgu7)j)Dte49+g0@#otYS?OwTl6G-q70eW3y4OA*Ee+q+#E*Kjg^m~P?E z7{K^o`h##r$?c2$8Go=dc1)ig&gjDUU^`Ikju7LH?R&ErPjE7wm@s`#IHNN}t?hP> zQbspM#uMB9%NX}DGJe?3SHbAT$k?$xvXXJqBSkYN1_osY28KUe0t_KQS_Q~gMB=M$ d=ZRrrXPzz|&$NRRD9!+sXV|d)N<34P3jnOSIz0dY diff --git a/plugins/official/ai-completion/dist/plugin.wasm.sources b/plugins/official/ai-completion/dist/plugin.wasm.sources index 0267b45f3..07b79acd0 100644 --- a/plugins/official/ai-completion/dist/plugin.wasm.sources +++ b/plugins/official/ai-completion/dist/plugin.wasm.sources @@ -1 +1 @@ -43d43f7a317c6fb8d5cca1b2a07f0e8dae05be6f5fcfc002527a409c519deb4f +df2aad3aa261a7cc4059c92666d221d1599306d47049b7b97a7bba263c6f51e5 diff --git a/plugins/official/checkstyle/dist/plugin.wasm b/plugins/official/checkstyle/dist/plugin.wasm index 5d0d07fff45dc147d17e6bbaf7268a3c0fdbdeeb..dced97eff27ce27fd2b67baf1e8f08542ad3d550 100644 GIT binary patch delta 2788 zcma)8dr(x@9lqbW7Xl0FW<;_+D0dgrU=q_P24A4uA`hQPG-_fKN{GTRMs3s9G*(?$ zkc|>hM2;fpqN_pNO-PgJ(J4*Al9seLmYLcHQ=Fu>(>QIW(uo;}VWhu%_u<<3NB-Gw zfA8lx=U(zz{^GNAW{t=2+uHaAmOVEsdZf5LlIE=p;5$LQ9^}Uv!plLX)gT6g1PsFI z3YaAr1T%g{g5uUQ-KOJ2gV`SR))-VD4JthlWk|iQF`F2(A!-WV;ZbS0ozz>|crG&FHNeh4pNkJMApS59 zZ!z@qT?t=Zx7Dz@xeSCTjX28Q&<>0Xg`@ZU?T&!2AY)O?h$Hq(+IG_c1s+lJ=UHq*Or+{`|y#{F(_oxwFg?2<- zTmv`Ap;+-0_S`Gr;5w8W0rS_R0iW@|uE$Fl0W#qH@;pcFWQJqKK2X>zAh6adqSBq5Xer}F0>nIYO&Pl_;PCcb@4_K9%8f}HP6#F z4Hwh2NBE5A@oa$gCQ)-su!emy!rO9@jS)d>;i8QYYd2wwQ6|5*nbyTECYI9JX;ROX zp$bFd?`5c$X-i+)Lee9mcMB$g$d6v6-EHR&Y{ic!wwTKpvHMyJKd}{gNgh++kW-oB zpw&oaF?r#!dbqre=H%gv1F&-&>_oM0L)kqY+O}gh$(L`(ba=$}?Km0@AGhqlMuN>d zupU0~?hd%3Cv}=pQ<=?yaI{XbZZ}%lOg$`P<0O_9JTl%I<20o*$sva<9E#@UY6S(; zc}@jN3H%jUN$^z#>f-}`98s#F)>KK+b^f19q!T>oqGPJ_jV=@t_+3aQ_`rol1o2gP zhM=?xX#~frke3|vq^MFlOHdUxI-SMDkB3`tUK*-H(|NI*2CVZ-ZhV{I3pXAnP+!IDN5XaIgw;c=7`qaWU>1?R zIQc4yCWk_ummLb3hWn`VDf?(jI$yaDD#6x$v@>4*>wU;g4B2$bb|u1K>VE7cm6QAN zGcri7#rFxEwPudzYB4ozXLCf~$x`QowV0n4@@X~GQ14Tff^ngwwSZ8)FP&LKbwq1A z&wmXwriQAdo=?}DyY10(Xccr``x-o<`6_B0&39fM)=^gVb#&)>`Gq>nN(e_T2zO5B zx9c#O^lbIWBv@CEx;uU>*=jNiJV@f5XA#9eXhlsp{#}`s9XHR?iR0!Tbssm*0RQuG z6cfxnflmpNJt1$$i264wKpd>0yPty7HbE^`!9BX?&01=cmo)>^fuQA^d0HG#c<&yP1~t9H#MC+Hsax)6Zg2 zOmH0~K6VbN#7y-Cy09x8>aGT89cBYw?ucx_8y#i?$hXmek#lAwa&#RQ>V?rFu zqW5bI%Oh6vn$PUZB){302ERG8-}#Y{Kpz2vJ(z}C@nsJ^Ty%>j{Dv+mbn$Jyc+_%v z%zO_O?H}TFFJcwqzuAWu>9tOJA9;y#m9s~bevE4t^WTbpp(~0!#tu>8E&S~v_^CC; z|3#_1Y0zn0vexP zkr;Z8pOx8VjEdO`8!&2&i)M{7ZgNj78#BPd=;{_9TG&tJiByvL37|5o%g8A%ZdjCz zXCKd}kBaPk=C>CyNlK9<=_89(T1&W+XnO=*Ansqv4uNMaV+!{!W1d(NN~9$9iKWZg VL!f8%2P@bq`T!G?3fTO-{{dsf$9Mn$ delta 2779 zcma)8dr(x@9lqbW7XrJen-R(Spxj+Zf^AHr7<_?pi#*~BiAGIqVhK?g#;DV@HHlRh z76g?5LF6DVx+oe%HX%)>N2fGJd()cMSY}EaO>tsvrg7R#p%XI_%}9Uu?%j25{3HMD zx4-xEoOA!$ZM)EI>&Y66p?9>gb8S06FFzyMcS@SCB8c4C5ueROfWgD}&q4-#2Dtbav+xo6#UE$m zZH9Av`#h|J&M(h{8=mG26yq9yA%m>1@zxByI>qBP!cCPWmm+7W$`5uHj$y&LnnygA zi8!E=XU@lRT<878m?++ukLkcgerW-&qDJ&);Yo%jJ}w*Eu$%AAMji(EpRh3uI(ZWlO58Nrn#7A}ttM zwCCV973rwqY zZPSe+n)WcC`aGTuvfd(URxwtv!4ck`i)>sMv=&}qP^?^!jYgUL>;_twN-@5K#!i!Z zt`wEHCjL>1dYQM?kbe9k?XI6cun9jM-()Uh#O`ZN{O~5^CAOFXx17op zH?2l0i^&U*wS~)@X-+MCK@hfWhKs1S%_zO6L+2LEAo=1gNI{F(vIPgC(ZOw7v6f)N zR;)&ccyBAb(Gxn&sHx29MmSohShWLfY?>aHu`v?MvW|?e+Bi+AOmfR13%8>AxLQuZ zbe>a=5`sWEmJ-}5M}1t-k2^{=)S4?Oy3YSofpmfgy>v`s(qbqp`H4^+n$C-AXuvwZP=kjEzO2D_3Dn(~@x5@}Ibrn>E5@b7!O9}C z7e{tu-NaC+Q?gqj({LYkK4}k4N#{%VKqc6;hjzxtf3pX<2_c&v*`-7nOx}xKq;h00 zeoh8SwfGT%r`F8zWGyC#?VRrDJ6Y;{uoiRDLOva48tQ$jQZOczv=$Vq_oXvOsE%k& z=lQQ;>f}(B)bkY0v%?iFhgL!7wXeY+ny;eTX}+`Tu!^#(ucJH9$4}Q`dVDx?LAY}| zzg>rkr01+hCc&zD)ZOu8BR|9S=q5p1gW04025coN|8>kJD1RLn2$nY@fuN)j)dWM0 z_&!0>K3pRBYM*KMNE5ab)zyS)1Q(ldnc$cEP0fGq#{f~kYBu+4s2N#AJ;qTQPS|

vXyubBTGq9Unk{wH@W(!&aOb>;mI)RV$f$M8dfUmP==v;DY{hX@>p$7sN#on~5&lbFI^?ZgRUrJTV0 z7;7CRK6(_BPY#BRQ>W1O93 z(fc)u#SyD{wcG5=gn-$X#(+7q-v{;$r^!$r4f{BP-!qOX{ybi^vef9o7xq}Mv}1LP&hUyt^Ql235eX8v39FZ4!{$Jk*iyotXvi~zN! z=)WkD*AIA%OV&|U>G4RCU5!%}>yGOP3hFHZ-Kmz~-ES#~a3!XFiS-PhihVcGZ{Q0z zF%m=1@v|};phs_p!Y&#$+M`*MjL*40mW>);Wcuy+lNH) zSoX;r`l!gxX8~6_lcZ!xl0LRMq?LpzM7tvBhs6C)uzld2i!ujwmG P*iriK5{U(DPTv0j@94tk diff --git a/plugins/official/checkstyle/dist/plugin.wasm.sources b/plugins/official/checkstyle/dist/plugin.wasm.sources index b486e9c11..ab7fc8de2 100644 --- a/plugins/official/checkstyle/dist/plugin.wasm.sources +++ b/plugins/official/checkstyle/dist/plugin.wasm.sources @@ -1 +1 @@ -881d4ad1ac25784507c836c220fc09bdcdf45193f13538e928b8b3619b548552 +ef4128ec97e203c3dd0c49f3bcdbfaa5eb2be59123dc4628fc31d52dc61b3186 diff --git a/plugins/official/csv-editor/dist/plugin.wasm b/plugins/official/csv-editor/dist/plugin.wasm index 4f93512a0bba269f150caa43e59cba0f7a8ef8c6..e2211c9ed9e5dacdcf1363d098983a74c954b5d1 100644 GIT binary patch delta 2857 zcmah~Yfuzd7VfXRfstWgG{6FbNzXtO4R0Al1f^A8Dgljxk0elKOpJNdx@KRRl}Slb zBpDyEv)hD4Gn-;lS_=uuSk)w^Qlv_&FhOG?ZU&2F&1ywVOh7jp)*4{%neG{3*WLXy z-<M=*)?4nR2iAx$+S$Msf+~bYD z5(SoH`?dz7>RT~L^gjP>4sb!yzWY0Ry{%VQ^Jr7P|6wOiDvuABV^Dc#I3@CAprpA0 zP)2%VmFvU5<(meSr$#E_QM8dFt0%zADCB4%t^q~3md2>`YniipKPNTTD{Qr#B*+|v z@bcsYo)TQw##q9x>&tXm#qa*3Rbb2g_(Z3KaO7_^3sm%ecleWMCS@%f+agdt^ygg%YfQ@t0#JtGn zv(#3C+~W02G=mk><^qj(=%v2TV=Lp;Spp8=s`{RQ?eMD^B9fBb`WW`^W@F&YQn(Z$ zMHrjnRyT=w2ED3J#1;l}7#_wM)f0x{|6H@`35Wa6?qY361V)7wv?HSNknVb$S#dFVfWPpm(s+F-Mm2UocC*8wZ>9g(FL zgq+%qY?whc_*}NV4C``ng7EHnc%1OXc{r39%r-H>LS=B3GNViK@C1c*=HXt#{yfYf zoXA7YeWA&ehEjqqlUcM=J{VXV} zOR$Tf?O-vt^6@;2am~lGlrlaa^@Q~Wy0(`JkQB;IaD?Ah$AXR(pdc?;*y<1&$!?@r zZ3(JntET;yBJz1_Z~@^oirEX0#=6!lKq7T}VgX(cZnG$v**3=)qL!Ga3j={_A#&nE zovK44Vi8{!B7q`*Dnt>Xb0PNJt`*5@onD9zVxBG1$Mbd(ens}|V$3IOD8?zmtVM_; zEL(&Z2v09UCgJ!Z_y~QA^?Y-QKC2f?kWPNB1cQXXm-YA)GR~6SxRn1oag6M-Qe9PcnXc-sGR$Ls?P3{{ z1E&=ga8TgA6?)>@3LGcfR;k~R4VAh-b0w11H!I-|37M*~e7Sz(b}h#}p(7FN2%n<% z=yEhr@%R<^hH!jEsCX;cAG0QeLo0RFwkqr-yQK;X2+vlbm+;{Im|zFwU^RCA7dhEA zNTbLNHE@PPrjD+?274(aZxuEYzOqUm;e)FKqBQqv_5u-MS);2Qu7yoqw+2VZDXc}Y z$vD8A+E9r^^=2Jni2B7^ycX&?bxKmLKBch8Yv3}9@^S4@ z14abq-}eZfVqs&CpgbP^TIo()iexzV1$-FB-rg%O;|K%AjZU;_@*X@UZ0`7is#t?> zaFiq(Ur2wTytT!6oZ08vAl!P!|0O1s(k!oFGmj6n?F!BiF8c#UP3%Avzm9(NsWUw6 zjq+=y9<+;h_3P_`#9Q6e+-&}f=5NQ2S?E%K{RxWg^*qO=a2&UInw49_u!`CCNp`h* p?h{;8Yx*Fn-F-Mbjd2`{;VQJvr!X7%xwhvtw)42E;WMNb{0q_h|4{${ delta 2848 zcmah~Yfuzd7VfXRfstWgG(dpCq-P+ChPMnNg3`)Ed_;5=eC$T5j0rI@RmSW~voa}3 z$|U0>wn-a;W|C!7S|thDv8qW-rLYRC%m!Ven2agiC6S7l7w8hhT0Hii>7EvL-Q7R) z%{kw>=X~efd;7K=u>9$OrFE|jKlu0A?3VhbKs#rx=j3h!dkqXD=YGRzxTFU~lGAG# ztp-Mu^Qd989ML1~O<^Taj`|fMB`y0Ps$>X5%!;d>~N_o7$0^Q2{{V9>Bf+?-F zfHH6Kws@_xT>Y&TdkZ6;8Ems;wFJT^04ohIM_desjEY-8!AiIFeTJB^# zNu8^{DX2n&c4G<_15IjCEE>?Kor=Xiftf237<)#0I{|UTwk4tnKJ}+W{Q92Gf1kSC zss14e6;r!{giA={MHf3DX}qPv+~F?ut0c@tmpauEgtZPhnYF`#y1OR4C4^SEM7diXO-Cv}d`V5sz@voT3@j!5G6Q>~^i-}ei6WoLL=7=#GvOu_vyewv zn1w1rZx-$&Jf4MO!tb)Mmase0uiS_y{HGf^gz5RXpKw_|mZMueoR9K*L$X>0 zr)X{mi@BYT=UI$rHlC#=qqDJra6^Hv?WF=FnQIeV;dj)rppykC$O|R5yF^B^8!0Zg zh19aHX}_h2eBK^vAe=@qeGbxC)v7s2q-syh!JDCN79}g&=J-NX6Z2GIFi%NS5o|TpTCn*&=;B?-k)UWKS=~Y{J@NoF&Yfhd9FW zd3b^F+&p9wj?P1XFfd;&rkLTshgWu^Fp&|aojDJjEAvPa5vRoUgbs&~sVi}|&ym zRxE;x0v}kUFI>F{9b`Ky^&7ITQuk*rMY8%%CA_APi5e>w>o;!aV%%>YiC9jb#6Y6(Q_fs;hP^!w#|!EyEnb3(IhZ@bE(zV+Z8$a_sysaFINUdY2KCW1tP+>N>|xm4TrjB6^@ZpSdC(f zaez6swi1czts2A-_4I1IZq}SQC8=7UQcd;$n9`nVeM+p}H=z>z#1au}&?p(z!9Gth zR=$KipJP}u{_vk#qmOZLjXuV$YxT{4XDuELV^5521J(ft)w)`wM;`w?co{|cBkf2n z1_b8c_XxJIu#rbl5syx-YzKNH8P0qGABVBG_xj5?#z66+1qU^G4;~XXHGe@_?4dU} zN)nAPi9i>U}}t?OrNwwf<2XZpQX$II8~kQxrS%d5%lrIBxzVJGY8qDzlyA>}l%7 jPjOZKs1rxS7{!%pTh3xSP^Z0m4%>M2YLh-gYQet%us$|f diff --git a/plugins/official/csv-editor/dist/plugin.wasm.sources b/plugins/official/csv-editor/dist/plugin.wasm.sources index 3093f1ac3..1e822e99b 100644 --- a/plugins/official/csv-editor/dist/plugin.wasm.sources +++ b/plugins/official/csv-editor/dist/plugin.wasm.sources @@ -1 +1 @@ -b029de3ddd2add1812b3071d407c59a97463a701b63c22232450b19a9f1d6557 +14dc3f5a5356ed82a84e7802c822545cba412d3e4a3b614aab6f4f7d3686584c diff --git a/plugins/official/git-toolbox/dist/plugin.wasm b/plugins/official/git-toolbox/dist/plugin.wasm index b238f5dd66adb45ea7bc28c3447365412bd815ef..52d7b9fe43e9c0287a0a1ffea492d5c1480c104b 100644 GIT binary patch delta 2571 zcmZuy3s6*57{34A6&8?0TNE5OFBda3-z18HdQ$-{71PnlN=+?+(KH|V3|GJ>5Ddp$ z70mU~v<;Yx*KyIzSsX2rhZqYB@^BFlR1#7Y(oOr%?%f3)W@o;0{>S+r-}%qpJyk9# zRWAAxPpA=1o+sSgOf^QvV+SMDlO6rI9eI+JaNDl!LrqDNpqEw|Rq7<6?x@|fA5~tx zWf!ul?CVv@DN9;?Y~haEjj7U_Cmm|7Gm3Bdz%oc8+}58|Z8b(U6EmD)JQ@F;YPFj2 zW4v^9(Nsl#yUR=K;n`PCv$>6xf&`Ng2 z@t`BRxaFWFJ>$nBz8}98a>#G-{UJvzkM9W>q9Gv?ib-;^uQ+GdXh7@E-FLt!uGsSt z3r1qtw+(Vh;Qnw{Z6@3I^C%qKe-Lv9CC-FHWM^VXuS2(K(E?0hXqg?PAaMv>B~KGa zyxnZ37Oykd3d6|+hI+6s~c3)s!tG#&KTmC+z! z4n_nW8FFBxyV0h_d=|3oz)(0xk`M5m%3^Ziz%H!#?mA~57WtXerL9pvMTVEhp#s29h0rJS@j6io?Ijx!lAxC_k zu@^uqCj6l8E|0f12J@)31g}d`K%O|@>^wQ1 zUVA==m#Y$F~#$X_gi9^gWMdB&9(lFddmMRgyDBX>k z=F;uBk1kt^c)e_>${vk#31ZL5JlHArpQAa_+e}XmHU}dvH4l(D;9P@PFAuvD?;==9 znt2F@zGU`Aw=%QV!ML3B5KJVld;zK}%BhR2V)O_{{a$mNO-e=B!s5H~i1CyDfid>7 zicmbRt@y4psyjxVa4QSdjkjpW{VO*ird5td%&#nRvfh)IbFx{TSx9!(9&`z=9*G!T zU4b~Yh6ebi=3B(Jn&F82?P{>5S*Xh>iwUtuEuDkl+9`-zYonBo`h7azgOxn34Rjim zT@9gk*5Nt*o$H9(>S)x=x=V;r^)zvMJx%P}@E%yj*$pZ>NUQGpBc|S^uEx995O+6D zQb-H|S$jVKRfq4ZNS~%8XUbP! zgPi79`03S>g63l_pCVdYC`*5|Vnt$mtD3U0`4KH|(USq>>Z6}=_tj(iKuK5okZy3oc4qTdZTarGJ*!xanx4+$?(1=%AcM%6&=U<6gFmDw6Uv z7I$y7s}P5^Q%aV!Q%b7Z=_U5=SlI)=om>7}1o-_ny%^?RUTOOl$%Q7-{bj2RjGE^x ztcFxWv<$-gLWd#S7wX+{Jva!aDNtWI42oG?vqpl-4fLAp;~^YR^$7+v7$yh9V1NwG zmlNPHWE`9bWh!G8&EVBQzfAa{Kb22K!Ih(eMS}+h8Ty4lZ4YQQ{42mXVAa){F;n3Z z7!55`VZ0op1w=q3bZE9jfEp?d&msV)tX0$SHH7*tVHw7sVVG!z7c(E%St$E;k>_Zp lu7eUypY?Fc4b=>q8Li>h^{@s&X?S-dxU#?*0ylvv=zqhQBzyn> delta 2567 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 U0a#JKbroP5=M^ delta 2354 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 O$lGOfiz(5vvgm(|+rkk5 delta 2826 zcmZuzeNa@_6@S0CyRfhjmP#C8A--Jl{SY(!^L}&A zJ>Tctd)~>enAf{ve2Wus=6Geo4{h%A{|rdB?ULFy6vUs0(4;fX`llx(vGYVw;zUTo zsvn*T5zvXj5D}*n24~=Bj--_H9|aY)D?z*&61%i7+mRMC5IXHRUh1%aoPJ~|;E~p4 zOH#a)@q)+Wk(`qKn2w619(i>;yf{L3U^=deIY5t$>y%(dfxP;HPFQYS2d?Sy{i2l48(|YqTc@sch|74B~*BBw{fiL*yQV6ydZX zhn-Ma9IoQJ$d5;<%!)53;Cb92iybBK(mXpdm};_PKQyu?;t5?N5d{f7MlLF5NqY2M z^y@@S#ChsT#FYDQUDWfmzxJY@nn{&(8Ce~vA+v_#2e^&hlsX2FVMuUHH70b4(_^s> zoa7_P=t83Zf^KO}xL&HCzD>c@*gk{Jey>wrDkk9_a;L&|hdoF?NySU>ibMx6iWQNO zhGcNj3ewR7zp&hgL!*e17>7D8w4$JZ^R8AN#V z2{Pw#C4C5H$%TdJeqjFR+ zbe1ER;bJ*T#)T}I6)9g%Qp`$JzHE)V#};v{nhKON_$%-(!}diy zb{c)Q2nUnHsaZKH)7)?#sz!$vb2l}*rxKYA(<}MbX|%i&(S^j#I^j1BAfOiuF%g(XX{lSQsB zK?^Immtr|XV5t$~zn8)h(Mxtk-HB48v}!z*8@6dT!r+@_ekwj3v>H5AqVr{YIFBe* zqxNb{bcD0ynvYjK+niCR@F-~1TaAuzf6a=G`@3}+Dmbch%lMsaqi>cWCn@6jsYvBC zDsm%*Ya9z)Yw!}_7MIK|Ymbw(U}*BNmnJdHe_&&Qrdx;~#P z>v`>Hw6osO_YO#j>K4d$K=NT=)1!9wv3*cI`AS7coc#$CGHpwH3%M*RxV zy^UDGu%!{7GPpN{jU8ZWaud7PXl|1cT1%5LP2V(O7BllU;?K}JZ*SyhKaVteYb$=k ztX0pU$QqhPiDtJTiEkRr=)XR^jy`et4b+-a2M2XC z_VCh+Q_P|F%twVMc|ipXNDTzVJ_zl`5n`h8Bv$iZl=z!KpN>c0!myQpYYv{~3HQ*Z zcX+UTG^?BcbprHaHy&W$zw71~4zE%FyZ9x;hBN3-4_q-K`K#`Ne`s!=(@8a2(TPD~ zjqzev53X3)#oG5V1H4-fox>!V3)A}nW}4ZKr62Rhv>Tx+P-J_zZp&u7DC+t#Yci*P z7;?5VUzVf{Ns{(j?NT}8c&42r=uEl+`84@ux!uA?(g`uwBsYTnziF1Y$mkF`(Xx5o F{{a&BygmQ` diff --git a/plugins/official/license-header/dist/plugin.wasm.sources b/plugins/official/license-header/dist/plugin.wasm.sources index 9d2cd989e..12094f2f7 100644 --- a/plugins/official/license-header/dist/plugin.wasm.sources +++ b/plugins/official/license-header/dist/plugin.wasm.sources @@ -1 +1 @@ -444dc979be1b8194631303c3ad6399b876ee9229d1a8554681406fd39164f604 +522aa68db4454f9c5511a90c74c6c26a8b95922e6725d9e411ddde7db998fa71 diff --git a/plugins/official/mybatis/dist/plugin.wasm b/plugins/official/mybatis/dist/plugin.wasm index 52c6fdb6a673ed870e311366c3412f7b3b1ffca4..66fc3eebd0b1f255560e555baf6c38d16022769c 100644 GIT binary patch delta 2972 zcmZuz3s6+o8NT1y<+Z@D1$=-oUe?qa6BM*X6Q36&L>Lf_!k9qtQHo(`qZq{|3Om6> z(s4wDcz6l|DiTDDm;(+N+HNwKaWZ7eL~ZS8Q(Dnp12$?`%B218-3OR3%<%31ex7q~ zOQY%IMpOGQP59S^EYn5r_2o}`CEr3xu{m+Ti3W{X>?9sK(OYAVIf?pFhozs!^mqTO zD9a5Bn?3Z{A?$D})i}|t=?yhGgyltTL82`PiJ@o`qmfv}(7~5SVG(R%PZW0hU_huZ zU?(srUSEQfhVa2By;dnFQj+|oS?^k{Rw+U<*J>zB${?3lU=wchw^!g7Xcp}&(8tiu ze;bRXxT-+}zZQ#Y%sMRESD~F@gl~yMCVKhr<6wcE55{2|j_{Y`$^Hm0h{xMu&7)et zXAM$>(XdiB#ul#gXO759vj~0}exL{uYmkC^k+%j3Kr!!0z&B_Y^@&)|$j^64cn9bC zo5_erKNrcEMbuxCaSSTYTT3Qnu@*}MiuF(mUX-+IhPZbMo<%udkb-&W=37!Qd-QQR4=+*tE9*?|%6 zk&1|Mem##$Me!u&S5n8#LFO#YVLmTy+#E{1*pvo4v>v~*i3&!)sD2f|j~$A$uVFf< z>z}8i4|Y+KffJLcaU~PmX;LkjG{s_mClk4|Mt-;j7AOv$ENR_?qKZA6(Fj!V(5+Z# zvOmzPhEgojwxSpq5x2L&I$5}#S;(PqH?vSitF+@+*cCpa_ssmL$ZC}&U)ftW$Oh*Q zSRWkAMhLS$;4`wZ3!S_qo3icX_H4XPrKN4h@Q*9!X>Z`rM>Z(e#j4-nXN(F9+e!O;Xa}Nc;+JKxK1>0TY5S@56})^u zb_aFqOFH2ID&0J+0P*3yy1-(X!;BV5Ch(4T?_Mvr7GMdTvu+323lKq6Xd$*w>hQxt zEFgJbA)Z06xL=5WdZLC8ypPuiq7EVrHKO<+iae+E>rv;h=@z)7^$YnhYFVV}mN9>c zt#nSz_Py57IZUz`Tox9iV&nIYP%xDTlp>oTzZ6LXpOvD-&*8`7A!}-zk5Y7%cOFFy z!SGSKDOCQ`GU_H7m0>0UFT-+zugmZ%L3BA55@eOrVNm(ma)eKHC1$jkR{O)5mnv?T zYqyEY?|+C51hL2PIe`zSeN_2d9Cg!OhTfEnVT~(&Mdi;`&{$PoQGwY6pH^Tl!MzGB z2zHmd+O2NmQI(hqcgeYx$P970?lf48r0Q;$$_FcH7%HDu1({%R6|IJie^5pHr1JhM z1QYzD3hxs$w;KD1x?7FS1PL{m8}4u`d&aO1gD+d@_;XdvOKWuVQ#E*j3~tvT%-I{+ zD~6eU9eNf|Mdg9DbQjwA(prR&W@;_!U1KrIzKV^r<47gJrsKL=(Q!o2b5&$s>#p3H zjqY6bl6`X`oUaH)_~tm4kq5aBhsRx;$n~WcwGXyXiqPoVDijnbkM4(e02w6+zL-MucQMdq%iX$(h2rm z)O#5JiI$$o|AZb7;@X9t?Vm3pjK9>0GsOC~Q$PKYUAiQr3sr9SPj$xk5@HrPDzr$7 zRwLC%5UiK#`o?e#{0BYTdr9vZ#l7R22-7AK!jrlXKv_`Sa30W&0{VTpn}(|L)^5F9 zx4QLirT6FqFYQ6L2gbycKhR}`Lwth`&zqVa>5q?5=@7rO!N*Aa@;>|;R|UI*c)B@6 z!YvG%2Er$jtmud-;8Rxk#VJVi#h7*Cnvph)gC)vm{AcVlqn`2$P78m_V-; r8Hwxy_MCg( z=iGbtgCUBm+y`fAKk7g0Ix)C|y= zfu66@@|=)}c|(t#hpjH53KyC+x#6?U!{WmB5YZljIjcpj@Z>`49$e?XC z`WTw|uj8=-y&6RETk*KX#vTgWTG$wd`K|u(E?9!*GX~khOJm+DspISvfs>aZ^Z)k z?FjcuL(~MnlEXbSZkX%p%ob(Zc_Uzk3j4y96TOUD?r8o#`a5=Nh>c?G}^4T`o` zF%wkvkGG=_4pFiLXQmM2N(S~)r&=QC{CU%Y1M1a(YLz5^*;h8m z2GRZKucLTs_DT_(jWI)b&%gD6 z4a%)1?T6wgGbJEfHYojK?XU0?Mu|o2r+F^khgjClIC(gjpHctk!DBRlm2i(x)9S|pjkH_R$vK1W(8damA6$Oa=JS(qs6o?5U#jX zF;t@HB^D6e zuf*a|PrBOmxr&-xMj&&IP*&64^oiQ(~)z#0};(1aSszrpW zHnL9~Gy6N`EZ&OBgX`!mwDT2p2qVd~IyAW3VwC+AJ7=enMhDwY>tcnc5xdZxk$Iyh zb5}IFaoI=q&yI3!5%TcGX{;m*ay?E=m^P8=YxQWQgRBO<4Al+DBP#d|mJuYM!Ka?C z1Xzr+VZ($o9@~iHB-GW2MFjU6ahu>zO}d@OO*l%_n`aSC(0CSqC$OH=C2i+0K-9bE z^~vcvk2OS%pU2)%cTO`W?v~0AUBD90N$BL0?hD8z)tF{{Lh#>a-TJc^VJB+%q8`Vr z7Cnxt7W@>d__PI)+6X@Q9W5!9n_G2_HLduFDDO6`@^zIE+;Iu>i5X@?BtO}PVowB5 z#kROzzbCJ^L-ve)sKtA7koE1@MTT$*cM0xY(p{3-n%OR2QXKOQqT!*X^*)mK zdbRG@^=fVJ)*D{djVv#WiYI@h$BK5wmR>w(s(qv{AEVMLe%lK_Bk?Qx@JsXxb_0p@ za)_imP)&r3?&G=_2Kd7f%6))WI?zT-CgE#j8R(^MAEgCP_gaHd9l}R-(`M^2tG-GD zWTX2r5W$a-$#7O2{tx;!TtAL6U)oLa1~z~WF~i6T4P>pxhb5A=FMZf^8_b(CKXR!DsxXJ62SY1>clcYJ4BrP|Yr7eVWiH@2? n&l5Y6*%ih^Q`qNTbSCA9M=9(LU{GYHvI7iT#O=-O_NxB_UPe1$ diff --git a/plugins/official/mybatis/dist/plugin.wasm.sources b/plugins/official/mybatis/dist/plugin.wasm.sources index 9ea91bfca..a97db01e5 100644 --- a/plugins/official/mybatis/dist/plugin.wasm.sources +++ b/plugins/official/mybatis/dist/plugin.wasm.sources @@ -1 +1 @@ -6f9412fce5e1a3d7453b0a1089d50544d49a3b1e8f022a5a1221ea597d2fd7dd +2f23364367583f9101cea4fc8f4ff190038a8b04c0f3b07a0f145c917807c237 diff --git a/plugins/official/regex-tester/dist/plugin.wasm b/plugins/official/regex-tester/dist/plugin.wasm index 6c56e4a059b48fe97f8914be77c5387c87db10cd..beb27e62f571c804f6718879683c2d76d0df48ce 100644 GIT binary patch delta 2936 zcmZ`*4Nz3q6@K^agYOEvl{9EDpgb0AJH2(Cw$J-Sfx-)maIrp4< z&Ueo_d+ytHGj8wAxC7@M?9+o692t&5?&5kWc(vr(Y~dFcHd&|`%Jfay;jhTyX0ognJ#F%p-QM z!*AIEf%O^S+QqF*3}ZP$%|f52Ok^^dl!ZrRa|?A0mxW60^3$-P3WRw20VzuoIhzP2?{8IpPcRdLacG6-NqIxoT5w)=itl zzFl~pHHl-pu$(G1aW@tc?)^vo4$d6F}{S=A7JBoLsgR4PoAjLhSVEZ)0mYck8uVGkMw7LRT_sq{D)hkzQDOA>rGMgI)B**Eu$Z;$ zp*qT#?DmN2QY6!%s87(xl;aL#oV?Z}RvgCiXPeB1>sCHjlX!3#N&Q<)h12$etT-i= zfG7DX>}nD7$}o;7=XF6t8P%~x+%Lnz9v!YI#|Y9Flw%-k(NC1)?}02`EI5MS5F9yz zSu9--{|o`3J4GGGv&4S%acq-^Y6p$9z95G=WrrlkTa|1*)U_))Z9Ym)#nmbvpCJF5 z7+8e`1X>lQ5}c_*mc7f5Ge9-WR-B}OnmBP1u>^{j{^*(*>!r-nAul2cJYGyBxa!3m zg2ZZ!BzUJ9Ns*Q(MU`UZP*qU_V`XmtL9oS46D`#Ur3rPn+L#KOkZUl5U{($OO)#LA z%BhJBwb&l!yBa4}wx9d%;nGBW9o1SBMRgcNP+Nx|6FjcNh?o5LPVk%iws@3cXBLa@ zxmZ(AvrQA{>hT=Gy?UyHCWf4XN-*^lO{`Y&;VC5c^|3i%i&Fe~*2Mi&SWhNv8nBWM zJZiu^f|S!HrT0%G+hCdy9Zm61N5Ax?#KDpV!e;p6D)QmTlRLwvLYU78qt zhUQ(Xn0|(aw!!46;T6g8M?_go`>MT(`3rdduSVnY34lKolHM02C*pra8J$b57Y zGN1SfB0nda;337zW-}rCoADQt27iS(f_Yz|ieUIz^d(3MB%!xkH_S-6{U#D&8R9eXpU7 z;L$ao@2w<#P9X>`T{oGA-!MBV=LW{oX3Y&8V_N>UoAfeKBer8z&lFz1MdjASoLh+X z8$6Yxk8UB03`Tu}xdeav#!S`R+XfF^yG^eL?K1sW98d4w zV>YE*AAfq!OxvA%X4>AmZx;CD`*=Gr=#s~JDLcg=#;4E-UB-C2OrHtg+4zv414X7< zaaHIs3LmA={_i<=(Ib)^#3RIKoWDk&E6!eg2&0)ydkg!}*e#9ZNiu6cqhar{fpSbvZ`V!M4CvmTV?TLJZgJML_;9iA7-2G#A2D5(goBK$A injI>=YACFqp`R^^?m6;_%gpn8>N)H%%F)2vZx z$85154Q7ekVLZuI{;(bDd17bLDKL-ps1U|-QlNz#R5ra2l|1QX;!a2+dzp17m`M>k zyc2#)Yz%fm6hh1{csHcBs@ck|f5pIs35Hlv`0)f=Qd*B}K0E|_kWFYI{5hmfyIz1T9gD;Hi&Qj- z2K}ZEcB~Ly!b)8zge_R1`G;X0Lh)gElg~fG`j$Wt3oU}?|4k9|Jp$LQ0j~a@dHOU_Ojqu)->kNwqThIMk{=-u)^3gVZwH zN!WnjOrQcagm)cf4b_lH>`K@v7^BJ2r(rJt_$b?Y8n(RX&>C)7`6LH>d>RraI5mUW z@G>u$IT3*-cq%M8+3FgYi2ahz)zKrt7(0i4>I#6j*rzV*>=*c<;(^TC9@#4 zv8R{Nzsx4p!&-#&dUyljYCU8b-G0nIqPlJCWeg~@OP9fdAlUIkm)RUUW)=_GArzt1 z4)YQ2+F=Dkd;`oxc((x(LUm7q$XWP6Q4oDCJT-pLUuPz>js^%Mvht`woeDDJ8(}HJ z@<#X>v|O%Q?LXo4RiJZ*v*uX^tt=iTm6 z(J;YCbQZ&Nk(ng*i;z81aF>YHrN8Y za7&64w&8&xC#*(Dx}s6~;0gqL&jp!%pOKPT%@ufkrpIT1SwNczqL66vaFpCe5iERw zhqkXIv&mO+-nFqMS8;gDY{OMJ=&79``eW_JwZbpau&GtsmfH%Ef!;8Q-mJ*1y;XD2 z-wH9fJ*o{dpZW1aKbPB}6b;+jwS<(n!(ULE{3S#qto{<}5vE^*u?X?ka0tn){u)e2 z7`g^m5S$&_IsfaBjMDDwFcm?$4($m0ZfHBt-2ewlc{jD*slN%aD2=`a>%4@6o_$a< z`|uXb^jZRkTfVpjoAGGeSMV7^K&R$CwiC{v^rTbc@miP0<5(BW!rr^t1ryZXBe(ID zk=YM!YbTc7hI1$d-_bgI#T`vK?H&&GtZ%`GmEM6=Z~W(&CEV4%lkImw^p-o&>^q#| ziM#L?`X1W@T?j)x9^d;>`V2!Lbl=mM2H)2@Dfd3iL1p88xIpCMf(Q6AVI%g!_K_*P z)`#Vm*@`}}csD$kqoO{@!VR;&hLs3^`&vuY%7-csCH*139;h`v(r7*ChY>Yd23x9;H6+3$kUXn_HDVv@b_p38~YujOQU|NqZPM!%L54AWuU|*0{!;d`2tpU(2;EF*8jrsT z-x=r>KUAR2_KO}KN`a7C|yNr74s-Mh2Ts^-MTS2cB?~a0#CY6 zn&}q?(w$?baY|4GT{a3$o2Jtz>e$|Bq3tAFSvZ?6^dSe?zIn6+;YTsF3?G?$F?6lr zrH*52?0^#e6*h{3J|8RCCW!{&8>PcRRjN=nUANoNyMQ5^LqCFFC(l0;io^Y?#8ClZp88o7qz8imUbm%kFZ#wb|v$HMZJ z@qU%sWDi zGdBCIIl;-e0wM-fWV?C#HaAAb6`SvE-^a*!Ve{ObUW|+{How@Fy+zTCiGe|xfq{XS qU4S73NUH$(ib#C5?Irn)%UP$(moj#60>v4C@(cpo*OW3Q8UO$WZ8BZ} diff --git a/plugins/official/solidity/dist/plugin.wasm.sources b/plugins/official/solidity/dist/plugin.wasm.sources index a042f606c..4f4a414a0 100644 --- a/plugins/official/solidity/dist/plugin.wasm.sources +++ b/plugins/official/solidity/dist/plugin.wasm.sources @@ -1 +1 @@ -ccd7eab004cd2f767f6be21ce272f647e20695ceff8694293beff8ce8a06c646 +9a19f399c1aa5fbc4d80aa7d11c5b73d968d0664bbc12dea8488d5fcab846075 diff --git a/plugins/official/string-tools/dist/plugin.wasm b/plugins/official/string-tools/dist/plugin.wasm index 619f9374de4f0e536f4f63c66d9a9c0cea4a2cd1..15934b2328595c09b5cc2a0c213ff8a7f7dd19ed 100644 GIT binary patch delta 2733 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 diff --git a/plugins/official/string-tools/dist/plugin.wasm.sources b/plugins/official/string-tools/dist/plugin.wasm.sources index 624214523..2b16319be 100644 --- a/plugins/official/string-tools/dist/plugin.wasm.sources +++ b/plugins/official/string-tools/dist/plugin.wasm.sources @@ -1 +1 @@ -8ae2a72ec23163926bac3914f4b27a429598982cd12f42f985df10e920942fdb +73b65742330387b7dbf498c6ec275ab41a55475243d771c1274de70b939c327f diff --git a/sdk/rust/openidea-plugin/src/file_actions.rs b/sdk/rust/openidea-plugin/src/file_actions.rs new file mode 100644 index 000000000..b0d911df7 --- /dev/null +++ b/sdk/rust/openidea-plugin/src/file_actions.rs @@ -0,0 +1,59 @@ +//! Quick fixes that create, rename or delete files: implement +//! [`FileActions`] and register with `register_plugin!(T, file_actions)` (with +//! any other exports, e.g. `register_plugin!(T, providers, file_actions)`). +//! Declare the `code-actions` kind in `[[contributes.providers]]`; the actions +//! are listed with those of [`crate::providers::Providers::code_actions`] and +//! have the same budget. + +use crate::providers::Document; +use crate::types::{Range, TextEdit}; + +/// A file change a [`FileAction`] makes. Paths are absolute or relative to the +/// project root, and stay inside it. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum FileOperation { + /// Fails when the file exists, unless `overwrite`. + Create { + path: String, + text: String, + overwrite: bool, + }, + Rename { + from: String, + to: String, + }, + /// Deletes the file; undoing the action restores it. + Delete { + path: String, + }, +} + +/// Applied as one workspace edit: `operations` in order, then `edits`. If any +/// step fails nothing changes, and one undo reverses all of it. +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct FileAction { + pub title: String, + /// `quickfix`, `refactor`, … + pub kind: Option, + pub preferred: bool, + pub operations: Vec, + /// (path, edits) per file; may target files the operations create. + pub edits: Vec<(String, Vec)>, + /// Opened once the action is applied. + pub open: Option, + /// The plugin's own reference: with it and no `operations` or `edits`, + /// they come from [`FileActions::resolve_file_action`] when the user picks + /// the action. + pub data: Option, +} + +pub trait FileActions { + fn file_actions(&mut self, doc: &Document, selection: Range) -> Vec; + + /// The operations and edits of an action [`FileActions::file_actions`] + /// returned with `data`, when the user picks it (the command budget + /// applies, not 50 ms). + fn resolve_file_action(&mut self, _doc: &Document, action: FileAction) -> Result { + Ok(action) + } +} diff --git a/sdk/rust/openidea-plugin/src/lib.rs b/sdk/rust/openidea-plugin/src/lib.rs index 3af96e16c..853d85ad0 100644 --- a/sdk/rust/openidea-plugin/src/lib.rs +++ b/sdk/rust/openidea-plugin/src/lib.rs @@ -41,6 +41,7 @@ pub mod commit; pub mod details; +pub mod file_actions; pub mod host; pub mod hover; pub mod indexing; @@ -197,6 +198,17 @@ pub mod inlay_bindings { }); } +#[cfg(target_arch = "wasm32")] +#[doc(hidden)] +pub mod file_actions_bindings { + wit_bindgen::generate!({ + world: "file-actions-provider", path: "wit", pub_export_macro: true, + export_macro_name: "__export_file_actions_world", + default_bindings_module: "openidea_plugin::file_actions_bindings", + with: { "openidea:plugin/types@1.3.0": crate::bindings::openidea::plugin::types }, + }); +} + /// The plugin API version this SDK targets. pub const API_VERSION: &str = "1.3"; @@ -254,6 +266,9 @@ macro_rules! __optional_exports { (semantic_tokens, $plugin:ty, $component:ident) => { $crate::__semantic_tokens_exports!($plugin, $component); }; + (file_actions, $plugin:ty, $component:ident) => { + $crate::__file_actions_exports!($plugin, $component); + }; (details, $plugin:ty, $component:ident) => { $crate::__details_exports!($plugin, $component); }; @@ -383,6 +398,32 @@ macro_rules! __views_exports { }; } +#[doc(hidden)] +#[macro_export] +macro_rules! __file_actions_exports { + ($plugin:ty, $component:ident) => { + impl $crate::file_actions_bindings::exports::openidea::plugin::file_actions::Guest for $component { + fn code_actions( + doc: $crate::file_actions_bindings::exports::openidea::plugin::file_actions::Document, + selection: $crate::bindings::openidea::plugin::types::Range, + ) -> ::std::vec::Vec<$crate::file_actions_bindings::exports::openidea::plugin::file_actions::FileAction> { + $crate::__rt::file_actions::<$plugin>(doc, selection) + } + + fn resolve( + doc: $crate::file_actions_bindings::exports::openidea::plugin::file_actions::Document, + action: $crate::file_actions_bindings::exports::openidea::plugin::file_actions::FileAction, + ) -> ::core::result::Result< + $crate::file_actions_bindings::exports::openidea::plugin::file_actions::FileAction, + $crate::bindings::openidea::plugin::types::Error, + > { + $crate::__rt::resolve_file_action::<$plugin>(doc, action) + } + } + $crate::file_actions_bindings::__export_file_actions_world!($component with_types_in $crate::file_actions_bindings); + }; +} + #[doc(hidden)] #[macro_export] macro_rules! __indexing_exports { @@ -772,6 +813,97 @@ pub mod __rt { .collect() } + pub fn file_actions( + d: crate::file_actions_bindings::exports::openidea::plugin::file_actions::Document, + sel: b::types::Range, + ) -> Vec { + let doc = file_doc(d); + let actions = with::(|x| x.file_actions(&doc, crate::host::__range_from(sel))); + actions.into_iter().map(file_action_out).collect() + } + + pub fn resolve_file_action( + d: crate::file_actions_bindings::exports::openidea::plugin::file_actions::Document, + action: crate::file_actions_bindings::exports::openidea::plugin::file_actions::FileAction, + ) -> Result + { + let doc = file_doc(d); + with::(|x| x.resolve_file_action(&doc, file_action_in(action))).map(file_action_out).map_err(error_out) + } + + fn file_doc(d: crate::file_actions_bindings::exports::openidea::plugin::file_actions::Document) -> p::Document { + p::Document { path: d.path, language: d.language, version: d.version, text: d.text } + } + + fn file_action_out( + a: crate::file_actions::FileAction, + ) -> crate::file_actions_bindings::exports::openidea::plugin::file_actions::FileAction { + use crate::file_actions as f; + use crate::file_actions_bindings::exports::openidea::plugin::file_actions as w; + w::FileAction { + title: a.title, + kind: a.kind, + preferred: a.preferred, + operations: a + .operations + .into_iter() + .map(|op| match op { + f::FileOperation::Create { path, text, overwrite } => { + w::FileOperation::Create(w::CreateFile { path, text, overwrite }) + } + f::FileOperation::Rename { from, to } => { + w::FileOperation::Rename(w::RenameFile { path: from, new_path: to }) + } + f::FileOperation::Delete { path } => w::FileOperation::Delete(w::DeleteFile { path }), + }) + .collect(), + edits: a + .edits + .into_iter() + .map(|(path, edits)| w::FileEdit { path, edits: edits.into_iter().map(edit_out).collect() }) + .collect(), + open: a.open, + data: a.data, + } + } + + fn file_action_in( + a: crate::file_actions_bindings::exports::openidea::plugin::file_actions::FileAction, + ) -> crate::file_actions::FileAction { + use crate::file_actions as f; + use crate::file_actions_bindings::exports::openidea::plugin::file_actions as w; + f::FileAction { + title: a.title, + kind: a.kind, + preferred: a.preferred, + operations: a + .operations + .into_iter() + .map(|op| match op { + w::FileOperation::Create(c) => { + f::FileOperation::Create { path: c.path, text: c.text, overwrite: c.overwrite } + } + w::FileOperation::Rename(r) => f::FileOperation::Rename { from: r.path, to: r.new_path }, + w::FileOperation::Delete(d) => f::FileOperation::Delete { path: d.path }, + }) + .collect(), + edits: a + .edits + .into_iter() + .map(|f| { + let edits = f + .edits + .into_iter() + .map(|e| crate::TextEdit { range: crate::host::__range_from(e.range), text: e.text }) + .collect(); + (f.path, edits) + }) + .collect(), + open: a.open, + data: a.data, + } + } + // ---- views ---- use crate::views as v; diff --git a/sdk/rust/openidea-plugin/wit/file-actions.wit b/sdk/rust/openidea-plugin/wit/file-actions.wit new file mode 100644 index 000000000..2d08b9b06 --- /dev/null +++ b/sdk/rust/openidea-plugin/wit/file-actions.wit @@ -0,0 +1,79 @@ +package openidea:plugin@1.3.0; + +/// Optional export (world `plugin-file-actions`): quick fixes and +/// refactorings that create, rename or delete files, next to the text edits +/// `providers.code-actions` offers. Declare the `code-actions` provider kind in +/// `[[contributes.providers]]`; the host calls `code-actions` here with the same +/// budget and lists the results with the others. +interface file-actions { + use types.{error, range, text-edit}; + + /// The document the actions are for (the editor's text while it is open). + record document { + /// Absolute path. + path: string, + language: string, + version: u64, + text: string, + } + + /// Text edits to one file. + record file-edit { + path: string, + edits: list, + } + + /// A file change, applied before the action's text edits. + variant file-operation { + /// Fails when the file exists, unless `overwrite`. + create(create-file), + rename(rename-file), + /// Deletes the file; undoing the action restores it. + delete(delete-file), + } + + /// A new file with its text; missing parent directories are created. + record create-file { + path: string, + text: string, + overwrite: bool, + } + + /// Moves `path` to `new-path`. + record rename-file { + path: string, + new-path: string, + } + + /// The file to delete. + record delete-file { + path: string, + } + + /// A code action that changes files. Paths are absolute or relative to the + /// project root, and stay inside it: a path outside disables the action. + record file-action { + title: string, + /// `quickfix`, `refactor`, … + kind: option, + preferred: bool, + /// Applied first, in order, as one workspace edit with `edits`: if + /// any operation or edit fails, nothing is applied, and one undo + /// reverses all of it. + operations: list, + /// Applied after the operations; may target files they create. + edits: list, + /// Opened once the action is applied. + open: option, + /// The plugin's own reference: with it and no `operations` or `edits`, + /// they are computed by `resolve` once the user picks the action. + data: option, + } + + /// Actions for `selection`, under the edit-path budget. + code-actions: func(doc: document, selection: range) -> list; + /// The operations and edits of an action listed with `data` and nothing + /// to apply, once the user picks it (the command budget applies, not the + /// editor's 50 ms). + resolve: func(doc: document, action: file-action) -> result; +} diff --git a/sdk/rust/openidea-plugin/wit/plugin.wit b/sdk/rust/openidea-plugin/wit/plugin.wit index 19c6dc9e1..ad07bbacc 100644 --- a/sdk/rust/openidea-plugin/wit/plugin.wit +++ b/sdk/rust/openidea-plugin/wit/plugin.wit @@ -86,6 +86,12 @@ world plugin-commit-checks { export commit-checker; } +/// A plugin with file-changing code actions (`file-actions`, next to `[[contributes.providers]]`). +world plugin-file-actions { + include plugin; + export file-actions; +} + /// Only the `syntax-provider` export: guests generate it next to `plugin` /// (the component tools merge both into one component). world syntax { @@ -129,3 +135,8 @@ world details { world commit-checks { export commit-checker; } + +/// Only the `file-actions` export, generated next to `plugin` like `syntax`. +world file-actions-provider { + export file-actions; +} diff --git a/wit/file-actions.wit b/wit/file-actions.wit new file mode 100644 index 000000000..2d08b9b06 --- /dev/null +++ b/wit/file-actions.wit @@ -0,0 +1,79 @@ +package openidea:plugin@1.3.0; + +/// Optional export (world `plugin-file-actions`): quick fixes and +/// refactorings that create, rename or delete files, next to the text edits +/// `providers.code-actions` offers. Declare the `code-actions` provider kind in +/// `[[contributes.providers]]`; the host calls `code-actions` here with the same +/// budget and lists the results with the others. +interface file-actions { + use types.{error, range, text-edit}; + + /// The document the actions are for (the editor's text while it is open). + record document { + /// Absolute path. + path: string, + language: string, + version: u64, + text: string, + } + + /// Text edits to one file. + record file-edit { + path: string, + edits: list, + } + + /// A file change, applied before the action's text edits. + variant file-operation { + /// Fails when the file exists, unless `overwrite`. + create(create-file), + rename(rename-file), + /// Deletes the file; undoing the action restores it. + delete(delete-file), + } + + /// A new file with its text; missing parent directories are created. + record create-file { + path: string, + text: string, + overwrite: bool, + } + + /// Moves `path` to `new-path`. + record rename-file { + path: string, + new-path: string, + } + + /// The file to delete. + record delete-file { + path: string, + } + + /// A code action that changes files. Paths are absolute or relative to the + /// project root, and stay inside it: a path outside disables the action. + record file-action { + title: string, + /// `quickfix`, `refactor`, … + kind: option, + preferred: bool, + /// Applied first, in order, as one workspace edit with `edits`: if + /// any operation or edit fails, nothing is applied, and one undo + /// reverses all of it. + operations: list, + /// Applied after the operations; may target files they create. + edits: list, + /// Opened once the action is applied. + open: option, + /// The plugin's own reference: with it and no `operations` or `edits`, + /// they are computed by `resolve` once the user picks the action. + data: option, + } + + /// Actions for `selection`, under the edit-path budget. + code-actions: func(doc: document, selection: range) -> list; + /// The operations and edits of an action listed with `data` and nothing + /// to apply, once the user picks it (the command budget applies, not the + /// editor's 50 ms). + resolve: func(doc: document, action: file-action) -> result; +} diff --git a/wit/plugin.wit b/wit/plugin.wit index 19c6dc9e1..ad07bbacc 100644 --- a/wit/plugin.wit +++ b/wit/plugin.wit @@ -86,6 +86,12 @@ world plugin-commit-checks { export commit-checker; } +/// A plugin with file-changing code actions (`file-actions`, next to `[[contributes.providers]]`). +world plugin-file-actions { + include plugin; + export file-actions; +} + /// Only the `syntax-provider` export: guests generate it next to `plugin` /// (the component tools merge both into one component). world syntax { @@ -129,3 +135,8 @@ world details { world commit-checks { export commit-checker; } + +/// Only the `file-actions` export, generated next to `plugin` like `syntax`. +world file-actions-provider { + export file-actions; +}