Add editor::InsertSnippet action (#44428)
Closes #20036 This introduces new action `editor: insert snippet`. It supports three modes: ``` ["editor::InsertSnippet", {"name": "snippet_name"}] ["editor::InsertSnippet", {"language": "language_name", "name": "snippet_name"}] ["editor::InsertSnippet", {"snippet": "snippet with $1 tab stops"}] ``` ## Example usage ### `keymap.json` ```json { "context": "Editor", "bindings": { // named global snippet "cmd-k cmd-r": ["editor::InsertSnippet", {"name": "all rights reserved"}], // named language-specific snippet "cmd-k cmd-p": ["editor::InsertSnippet", {"language": "rust", "name": "debug-print a value"}], // inline snippet "cmd-k cmd-e": ["editor::InsertSnippet", {"snippet": "println!(\"This snippet has multiple lines.\")\nprintln!(\"It belongs to $1 and is very $2.\")"}], }, }, ``` ### `~/.config/zed/snippets/rust.json` ```json { "debug-print a value": { "body": "println!(\"$1 = {:?}\", $1)", }, } ``` ### `~/.config/zed/snippets/snippets.json` ```json { "all rights reserved": { "body": "Copyright © ${1:2025} ${2:your name}. All rights reserved.", }, } ``` ## Future extensions - Support multiline inline snippets using an array of strings using something similar to `ListOrDirect` in `snippet_provider::format::VsCodeSnippet` - When called with no arguments, open a modal to select a snippet to insert ## Release notes Release Notes: - Added `editor::InsertSnippet` action
This commit is contained in:
@@ -26895,6 +26895,82 @@ async fn test_add_selection_skip_soft_wrap_option(cx: &mut TestAppContext) {
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_insert_snippet(cx: &mut TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
let mut cx = EditorTestContext::new(cx).await;
|
||||
|
||||
cx.update_editor(|editor, _, cx| {
|
||||
editor.project().unwrap().update(cx, |project, cx| {
|
||||
project.snippets().update(cx, |snippets, _cx| {
|
||||
let snippet = project::snippet_provider::Snippet {
|
||||
prefix: vec![], // no prefix needed!
|
||||
body: "an Unspecified".to_string(),
|
||||
description: Some("shhhh it's a secret".to_string()),
|
||||
name: "super secret snippet".to_string(),
|
||||
};
|
||||
snippets.add_snippet_for_test(
|
||||
None,
|
||||
PathBuf::from("test_snippets.json"),
|
||||
vec![Arc::new(snippet)],
|
||||
);
|
||||
|
||||
let snippet = project::snippet_provider::Snippet {
|
||||
prefix: vec![], // no prefix needed!
|
||||
body: " Location".to_string(),
|
||||
description: Some("the word 'location'".to_string()),
|
||||
name: "location word".to_string(),
|
||||
};
|
||||
snippets.add_snippet_for_test(
|
||||
Some("Markdown".to_string()),
|
||||
PathBuf::from("test_snippets.json"),
|
||||
vec![Arc::new(snippet)],
|
||||
);
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
cx.set_state(indoc!(r#"First cursor at ˇ and second cursor at ˇ"#));
|
||||
|
||||
cx.update_editor(|editor, window, cx| {
|
||||
editor.insert_snippet_at_selections(
|
||||
&InsertSnippet {
|
||||
language: None,
|
||||
name: Some("super secret snippet".to_string()),
|
||||
snippet: None,
|
||||
},
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
|
||||
// Language is specified in the action,
|
||||
// so the buffer language does not need to match
|
||||
editor.insert_snippet_at_selections(
|
||||
&InsertSnippet {
|
||||
language: Some("Markdown".to_string()),
|
||||
name: Some("location word".to_string()),
|
||||
snippet: None,
|
||||
},
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
|
||||
editor.insert_snippet_at_selections(
|
||||
&InsertSnippet {
|
||||
language: None,
|
||||
name: None,
|
||||
snippet: Some("$0 after".to_string()),
|
||||
},
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
|
||||
cx.assert_editor_state(
|
||||
r#"First cursor at an Unspecified Locationˇ after and second cursor at an Unspecified Locationˇ after"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test(iterations = 10)]
|
||||
async fn test_document_colors(cx: &mut TestAppContext) {
|
||||
let expected_color = Rgba {
|
||||
|
||||
Reference in New Issue
Block a user