Add auto-completion support for snippet files (#23698)

Release Notes:

- Added auto-completion support for snippet files.


![image](https://github.com/user-attachments/assets/ad165fc7-a6e7-426c-8892-f7004515dfc7)
This commit is contained in:
loczek 2025-01-27 12:32:22 +01:00 committed by GitHub
parent 6e9ea47849
commit 6293b20fd0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 64 additions and 5 deletions

2
Cargo.lock generated
View file

@ -6956,6 +6956,7 @@ dependencies = [
"serde_json",
"settings",
"smol",
"snippet_provider",
"task",
"text",
"theme",
@ -12059,6 +12060,7 @@ dependencies = [
"gpui",
"parking_lot",
"paths",
"schemars",
"serde",
"serde_json",
"snippet",

View file

@ -60,6 +60,7 @@ serde.workspace = true
serde_json.workspace = true
settings.workspace = true
smol.workspace = true
snippet_provider.workspace = true
task.workspace = true
toml.workspace = true
tree-sitter = { workspace = true, optional = true }

View file

@ -85,6 +85,7 @@ impl JsonLspAdapter {
cx,
);
let tasks_schema = task::TaskTemplates::generate_json_schema();
let snippets_schema = snippet_provider::format::VSSnippetsFile::generate_json_schema();
let tsconfig_schema = serde_json::Value::from_str(TSCONFIG_SCHEMA).unwrap();
let package_json_schema = serde_json::Value::from_str(PACKAGE_JSON_SCHEMA).unwrap();
@ -125,8 +126,17 @@ impl JsonLspAdapter {
paths::local_tasks_file_relative_path()
],
"schema": tasks_schema,
},
{
"fileMatch": [
schema_file_match(
paths::snippets_dir()
.join("*.json")
.as_path()
)
],
"schema": snippets_schema,
}
]
}
})

View file

@ -189,6 +189,12 @@ pub fn themes_dir() -> &'static PathBuf {
THEMES_DIR.get_or_init(|| config_dir().join("themes"))
}
/// Returns the path to the snippets directory.
pub fn snippets_dir() -> &'static PathBuf {
static SNIPPETS_DIR: OnceLock<PathBuf> = OnceLock::new();
SNIPPETS_DIR.get_or_init(|| config_dir().join("snippets"))
}
/// Returns the path to the contexts directory.
///
/// This is where the saved contexts from the Assistant are stored.

View file

@ -21,3 +21,4 @@ serde.workspace = true
serde_json.workspace = true
snippet.workspace = true
util.workspace = true
schemars.workspace = true

View file

@ -1,13 +1,47 @@
use collections::HashMap;
use schemars::{
gen::SchemaSettings,
schema::{ObjectValidation, Schema, SchemaObject},
JsonSchema,
};
use serde::Deserialize;
use serde_json::Value;
#[derive(Deserialize)]
pub(crate) struct VSSnippetsFile {
pub struct VSSnippetsFile {
#[serde(flatten)]
pub(crate) snippets: HashMap<String, VSCodeSnippet>,
}
#[derive(Deserialize)]
impl VSSnippetsFile {
pub fn generate_json_schema() -> Value {
let schema = SchemaSettings::draft07()
.with(|settings| settings.option_add_null_type = false)
.into_generator()
.into_root_schema_for::<Self>();
serde_json::to_value(schema).unwrap()
}
}
impl JsonSchema for VSSnippetsFile {
fn schema_name() -> String {
"VSSnippetsFile".into()
}
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> Schema {
SchemaObject {
object: Some(Box::new(ObjectValidation {
additional_properties: Some(Box::new(gen.subschema_for::<VSCodeSnippet>())),
..Default::default()
})),
..Default::default()
}
.into()
}
}
#[derive(Deserialize, JsonSchema)]
#[serde(untagged)]
pub(crate) enum ListOrDirect {
Single(String),
@ -36,9 +70,14 @@ impl std::fmt::Display for ListOrDirect {
}
}
#[derive(Deserialize)]
#[derive(Deserialize, JsonSchema)]
pub(crate) struct VSCodeSnippet {
/// The snippet prefix used to decide whether a completion menu should be shown.
pub(crate) prefix: Option<ListOrDirect>,
/// The snippet content. Use `$1` and `${1:defaultText}` to define cursor positions and `$0` for final cursor position.
pub(crate) body: ListOrDirect,
/// The snippet description displayed inside the completion menu.
pub(crate) description: Option<ListOrDirect>,
}

View file

@ -1,5 +1,5 @@
mod extension_snippet;
mod format;
pub mod format;
mod registry;
use std::{