mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-07-24 05:05:00 +00:00
dev: {re,}move conversions of completion structs (#264)
* dev: {re,}move conversions * dev: update dependencies
This commit is contained in:
parent
94a0a1b23a
commit
869960a89c
5 changed files with 73 additions and 128 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -3879,7 +3879,6 @@ dependencies = [
|
||||||
"indexmap 2.2.6",
|
"indexmap 2.2.6",
|
||||||
"insta",
|
"insta",
|
||||||
"itertools 0.12.1",
|
"itertools 0.12.1",
|
||||||
"lazy_static",
|
|
||||||
"log",
|
"log",
|
||||||
"lsp-types",
|
"lsp-types",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
|
|
@ -19,7 +19,6 @@ yaml-rust2.workspace = true
|
||||||
biblatex.workspace = true
|
biblatex.workspace = true
|
||||||
serde_yaml.workspace = true
|
serde_yaml.workspace = true
|
||||||
itertools.workspace = true
|
itertools.workspace = true
|
||||||
lazy_static.workspace = true
|
|
||||||
strum.workspace = true
|
strum.workspace = true
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
use lsp_types::CompletionList;
|
use lsp_types::{
|
||||||
|
Command, CompletionItemLabelDetails, CompletionList, CompletionTextEdit, InsertTextFormat,
|
||||||
|
TextEdit,
|
||||||
|
};
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
use regex::{Captures, Regex};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
analysis::{FlowBuiltinType, FlowType},
|
analysis::{FlowBuiltinType, FlowType},
|
||||||
|
@ -8,7 +13,9 @@ use crate::{
|
||||||
StatefulRequest,
|
StatefulRequest,
|
||||||
};
|
};
|
||||||
|
|
||||||
use self::typst_to_lsp::completion;
|
pub(crate) type LspCompletion = lsp_types::CompletionItem;
|
||||||
|
pub(crate) type LspCompletionKind = lsp_types::CompletionItemKind;
|
||||||
|
pub(crate) type TypstCompletionKind = crate::upstream::CompletionKind;
|
||||||
|
|
||||||
/// The [`textDocument/completion`] request is sent from the client to the
|
/// The [`textDocument/completion`] request is sent from the client to the
|
||||||
/// server to compute completion items at a given cursor position.
|
/// server to compute completion items at a given cursor position.
|
||||||
|
@ -201,12 +208,36 @@ impl StatefulRequest for CompletionRequest {
|
||||||
replace_range = LspRange::new(lsp_start_position, self.position);
|
replace_range = LspRange::new(lsp_start_position, self.position);
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(
|
let completions = completions.iter().map(|typst_completion| {
|
||||||
completions
|
let typst_snippet = typst_completion
|
||||||
.iter()
|
.apply
|
||||||
.map(|typst_completion| completion(typst_completion, replace_range))
|
.as_ref()
|
||||||
.collect_vec(),
|
.unwrap_or(&typst_completion.label);
|
||||||
)
|
let lsp_snippet = to_lsp_snippet(typst_snippet);
|
||||||
|
let text_edit = CompletionTextEdit::Edit(TextEdit::new(replace_range, lsp_snippet));
|
||||||
|
|
||||||
|
LspCompletion {
|
||||||
|
label: typst_completion.label.to_string(),
|
||||||
|
kind: Some(completion_kind(typst_completion.kind.clone())),
|
||||||
|
detail: typst_completion.detail.as_ref().map(String::from),
|
||||||
|
sort_text: typst_completion.sort_text.as_ref().map(String::from),
|
||||||
|
label_details: typst_completion.label_detail.as_ref().map(|e| {
|
||||||
|
CompletionItemLabelDetails {
|
||||||
|
detail: None,
|
||||||
|
description: Some(e.to_string()),
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
text_edit: Some(text_edit),
|
||||||
|
insert_text_format: Some(InsertTextFormat::SNIPPET),
|
||||||
|
command: typst_completion.command.as_ref().map(|c| Command {
|
||||||
|
command: c.to_string(),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Some(completions.collect_vec())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
if let Some(items_rest) = completion_items_rest.as_mut() {
|
if let Some(items_rest) = completion_items_rest.as_mut() {
|
||||||
|
@ -223,15 +254,41 @@ impl StatefulRequest for CompletionRequest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn completion_kind(typst_completion_kind: TypstCompletionKind) -> LspCompletionKind {
|
||||||
|
match typst_completion_kind {
|
||||||
|
TypstCompletionKind::Syntax => LspCompletionKind::SNIPPET,
|
||||||
|
TypstCompletionKind::Func => LspCompletionKind::FUNCTION,
|
||||||
|
TypstCompletionKind::Param => LspCompletionKind::VARIABLE,
|
||||||
|
TypstCompletionKind::Field => LspCompletionKind::FIELD,
|
||||||
|
TypstCompletionKind::Variable => LspCompletionKind::VARIABLE,
|
||||||
|
TypstCompletionKind::Constant => LspCompletionKind::CONSTANT,
|
||||||
|
TypstCompletionKind::Symbol(_) => LspCompletionKind::FIELD,
|
||||||
|
TypstCompletionKind::Type => LspCompletionKind::CLASS,
|
||||||
|
TypstCompletionKind::Module => LspCompletionKind::MODULE,
|
||||||
|
TypstCompletionKind::File => LspCompletionKind::FILE,
|
||||||
|
TypstCompletionKind::Folder => LspCompletionKind::FOLDER,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static TYPST_SNIPPET_PLACEHOLDER_RE: Lazy<Regex> =
|
||||||
|
Lazy::new(|| Regex::new(r"\$\{(.*?)\}").unwrap());
|
||||||
|
|
||||||
|
/// Adds numbering to placeholders in snippets
|
||||||
|
fn to_lsp_snippet(typst_snippet: &EcoString) -> String {
|
||||||
|
let mut counter = 1;
|
||||||
|
let result =
|
||||||
|
TYPST_SNIPPET_PLACEHOLDER_RE.replace_all(typst_snippet.as_str(), |cap: &Captures| {
|
||||||
|
let substitution = format!("${{{}:{}}}", counter, &cap[1]);
|
||||||
|
counter += 1;
|
||||||
|
substitution
|
||||||
|
});
|
||||||
|
|
||||||
|
result.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
fn is_arg_like_context(mut matching: &LinkedNode) -> bool {
|
fn is_arg_like_context(mut matching: &LinkedNode) -> bool {
|
||||||
while let Some(parent) = matching.parent() {
|
while let Some(parent) = matching.parent() {
|
||||||
use SyntaxKind::*;
|
use SyntaxKind::*;
|
||||||
// if parent.kind() == SyntaxKind::Markup | SyntaxKind::Markup |
|
|
||||||
// SyntaxKind::Markup { return true;
|
|
||||||
// }
|
|
||||||
// if parent.kind() == SyntaxKind::Args {
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// todo: contextual
|
// todo: contextual
|
||||||
match parent.kind() {
|
match parent.kind() {
|
||||||
|
|
|
@ -63,11 +63,6 @@ impl From<PositionEncoding> for lsp_types::PositionEncodingKind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type LspCompletion = lsp_types::CompletionItem;
|
|
||||||
pub type LspCompletionKind = lsp_types::CompletionItemKind;
|
|
||||||
pub type TypstCompletion = crate::upstream::Completion;
|
|
||||||
pub type TypstCompletionKind = crate::upstream::CompletionKind;
|
|
||||||
|
|
||||||
const UNTITLED_ROOT: &str = "/untitled";
|
const UNTITLED_ROOT: &str = "/untitled";
|
||||||
static EMPTY_URL: Lazy<Url> = Lazy::new(|| Url::parse("file://").unwrap());
|
static EMPTY_URL: Lazy<Url> = Lazy::new(|| Url::parse("file://").unwrap());
|
||||||
|
|
||||||
|
@ -208,15 +203,7 @@ pub mod lsp_to_typst {
|
||||||
|
|
||||||
pub mod typst_to_lsp {
|
pub mod typst_to_lsp {
|
||||||
|
|
||||||
use itertools::Itertools;
|
use lsp_types::{LanguageString, MarkedString};
|
||||||
use lazy_static::lazy_static;
|
|
||||||
use lsp_types::{
|
|
||||||
Command, CompletionItemLabelDetails, CompletionTextEdit, Documentation, InsertTextFormat,
|
|
||||||
LanguageString, MarkedString, MarkupContent, MarkupKind, TextEdit,
|
|
||||||
};
|
|
||||||
use regex::{Captures, Regex};
|
|
||||||
use typst::diag::EcoString;
|
|
||||||
use typst::foundations::{CastInfo, Repr};
|
|
||||||
use typst::syntax::Source;
|
use typst::syntax::Source;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -267,68 +254,6 @@ pub mod typst_to_lsp {
|
||||||
LspRange::new(lsp_start, lsp_end)
|
LspRange::new(lsp_start, lsp_end)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn completion_kind(typst_completion_kind: TypstCompletionKind) -> LspCompletionKind {
|
|
||||||
match typst_completion_kind {
|
|
||||||
TypstCompletionKind::Syntax => LspCompletionKind::SNIPPET,
|
|
||||||
TypstCompletionKind::Func => LspCompletionKind::FUNCTION,
|
|
||||||
TypstCompletionKind::Param => LspCompletionKind::VARIABLE,
|
|
||||||
TypstCompletionKind::Field => LspCompletionKind::FIELD,
|
|
||||||
TypstCompletionKind::Variable => LspCompletionKind::VARIABLE,
|
|
||||||
TypstCompletionKind::Constant => LspCompletionKind::CONSTANT,
|
|
||||||
TypstCompletionKind::Symbol(_) => LspCompletionKind::FIELD,
|
|
||||||
TypstCompletionKind::Type => LspCompletionKind::CLASS,
|
|
||||||
TypstCompletionKind::Module => LspCompletionKind::MODULE,
|
|
||||||
TypstCompletionKind::File => LspCompletionKind::FILE,
|
|
||||||
TypstCompletionKind::Folder => LspCompletionKind::FOLDER,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
static ref TYPST_SNIPPET_PLACEHOLDER_RE: Regex = Regex::new(r"\$\{(.*?)\}").unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds numbering to placeholders in snippets
|
|
||||||
fn snippet(typst_snippet: &EcoString) -> String {
|
|
||||||
let mut counter = 1;
|
|
||||||
let result =
|
|
||||||
TYPST_SNIPPET_PLACEHOLDER_RE.replace_all(typst_snippet.as_str(), |cap: &Captures| {
|
|
||||||
let substitution = format!("${{{}:{}}}", counter, &cap[1]);
|
|
||||||
counter += 1;
|
|
||||||
substitution
|
|
||||||
});
|
|
||||||
|
|
||||||
result.to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn completion(typst_completion: &TypstCompletion, lsp_replace: LspRange) -> LspCompletion {
|
|
||||||
let typst_snippet = typst_completion
|
|
||||||
.apply
|
|
||||||
.as_ref()
|
|
||||||
.unwrap_or(&typst_completion.label);
|
|
||||||
let lsp_snippet = snippet(typst_snippet);
|
|
||||||
let text_edit = CompletionTextEdit::Edit(TextEdit::new(lsp_replace, lsp_snippet));
|
|
||||||
|
|
||||||
LspCompletion {
|
|
||||||
label: typst_completion.label.to_string(),
|
|
||||||
kind: Some(completion_kind(typst_completion.kind.clone())),
|
|
||||||
detail: typst_completion.detail.as_ref().map(String::from),
|
|
||||||
sort_text: typst_completion.sort_text.as_ref().map(String::from),
|
|
||||||
label_details: typst_completion.label_detail.as_ref().map(|e| {
|
|
||||||
CompletionItemLabelDetails {
|
|
||||||
detail: None,
|
|
||||||
description: Some(e.to_string()),
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
text_edit: Some(text_edit),
|
|
||||||
insert_text_format: Some(InsertTextFormat::SNIPPET),
|
|
||||||
command: typst_completion.command.as_ref().map(|c| Command {
|
|
||||||
command: c.to_string(),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn tooltip(typst_tooltip: &TypstTooltip) -> LspHoverContents {
|
pub fn tooltip(typst_tooltip: &TypstTooltip) -> LspHoverContents {
|
||||||
let lsp_marked_string = match typst_tooltip {
|
let lsp_marked_string = match typst_tooltip {
|
||||||
TypstTooltip::Text(text) => MarkedString::String(text.to_string()),
|
TypstTooltip::Text(text) => MarkedString::String(text.to_string()),
|
||||||
|
@ -339,41 +264,6 @@ pub mod typst_to_lsp {
|
||||||
};
|
};
|
||||||
LspHoverContents::Scalar(lsp_marked_string)
|
LspHoverContents::Scalar(lsp_marked_string)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn param_info(typst_param_info: &TypstParamInfo) -> LspParamInfo {
|
|
||||||
LspParamInfo {
|
|
||||||
label: lsp_types::ParameterLabel::Simple(typst_param_info.name.to_owned()),
|
|
||||||
documentation: param_info_to_docs(typst_param_info),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn param_info_to_label(typst_param_info: &TypstParamInfo) -> String {
|
|
||||||
format!(
|
|
||||||
"{}: {}",
|
|
||||||
typst_param_info.name,
|
|
||||||
cast_info_to_label(&typst_param_info.input)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn param_info_to_docs(typst_param_info: &TypstParamInfo) -> Option<Documentation> {
|
|
||||||
if !typst_param_info.docs.is_empty() {
|
|
||||||
Some(Documentation::MarkupContent(MarkupContent {
|
|
||||||
value: typst_param_info.docs.to_owned(),
|
|
||||||
kind: MarkupKind::Markdown,
|
|
||||||
}))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cast_info_to_label(cast_info: &CastInfo) -> String {
|
|
||||||
match cast_info {
|
|
||||||
CastInfo::Any => "any".to_owned(),
|
|
||||||
CastInfo::Value(value, _) => value.repr().to_string(),
|
|
||||||
CastInfo::Type(ty) => ty.to_string(),
|
|
||||||
CastInfo::Union(options) => options.iter().map(cast_info_to_label).join(" "),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -21,7 +21,7 @@ use crate::syntax::param_index_at_leaf;
|
||||||
use crate::upstream::complete::complete_code;
|
use crate::upstream::complete::complete_code;
|
||||||
use crate::upstream::plain_docs_sentence;
|
use crate::upstream::plain_docs_sentence;
|
||||||
|
|
||||||
use crate::{prelude::*, typst_to_lsp::completion_kind, LspCompletion};
|
use crate::{completion_kind, prelude::*, LspCompletion};
|
||||||
|
|
||||||
impl<'a, 'w> CompletionContext<'a, 'w> {
|
impl<'a, 'w> CompletionContext<'a, 'w> {
|
||||||
pub fn world(&self) -> &'w dyn typst::World {
|
pub fn world(&self) -> &'w dyn typst::World {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue