mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-08-03 17:58:17 +00:00
feat: complete bracket if the function accepts an only content arg (#848)
* feat: complete bracket if the function will accept an only content argument * test: update snapshot
This commit is contained in:
parent
ccd3cea08c
commit
a1a15a6795
31 changed files with 315 additions and 47 deletions
|
@ -81,19 +81,7 @@ fn check_signature<'a>(
|
|||
.iter()
|
||||
.map(|args| args.positional_params().len())
|
||||
.sum::<usize>();
|
||||
let pos_idx = bound_pos + positional;
|
||||
let nth = sig_ins.pos(pos_idx).cloned();
|
||||
let nth = nth.or_else(|| {
|
||||
let rest_idx = || pos_idx.saturating_sub(sig_ins.positional_params().len());
|
||||
|
||||
let rest_ty = sig_ins.rest_param()?;
|
||||
match rest_ty {
|
||||
Ty::Array(ty) => Some(ty.as_ref().clone()),
|
||||
Ty::Tuple(tys) => tys.get(rest_idx()).cloned(),
|
||||
_ => None,
|
||||
}
|
||||
});
|
||||
if let Some(nth) = nth {
|
||||
if let Some(nth) = sig_ins.pos_or_rest(bound_pos + positional) {
|
||||
receiver.insert(nth, !pol);
|
||||
}
|
||||
|
||||
|
|
|
@ -243,6 +243,10 @@ impl StatefulRequest for CompletionRequest {
|
|||
}),
|
||||
text_edit: Some(text_edit),
|
||||
insert_text_format: Some(InsertTextFormat::SNIPPET),
|
||||
commit_characters: typst_completion
|
||||
.commit_char
|
||||
.as_ref()
|
||||
.map(|v| vec![v.to_string()]),
|
||||
command: typst_completion.command.as_ref().map(|c| Command {
|
||||
command: c.to_string(),
|
||||
..Default::default()
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
/// contains: strong, strong[]
|
||||
|
||||
#(/* range after 1..2 */st);
|
|
@ -0,0 +1,3 @@
|
|||
/// contains: delta
|
||||
|
||||
#strong(/* range after 1..2 */[];
|
|
@ -0,0 +1,3 @@
|
|||
/// contains: delta
|
||||
|
||||
#strong(/* range after 1..2 */[]);
|
|
@ -0,0 +1,33 @@
|
|||
---
|
||||
source: crates/tinymist-query/src/completion.rs
|
||||
description: Completion on t (57..58)
|
||||
expression: "JsonRepr::new_pure(results)"
|
||||
input_file: crates/tinymist-query/src/fixtures/completion/bracket_strong.typ
|
||||
---
|
||||
[
|
||||
{
|
||||
"isIncomplete": false,
|
||||
"items": [
|
||||
{
|
||||
"kind": 3,
|
||||
"label": "strong",
|
||||
"labelDetails": {
|
||||
"description": "(content, delta: int) => strong"
|
||||
},
|
||||
"textEdit": {
|
||||
"newText": "strong[${1:}]",
|
||||
"range": {
|
||||
"end": {
|
||||
"character": 26,
|
||||
"line": 2
|
||||
},
|
||||
"start": {
|
||||
"character": 24,
|
||||
"line": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,34 @@
|
|||
---
|
||||
source: crates/tinymist-query/src/completion.rs
|
||||
description: "Completion on ] (52..53)"
|
||||
expression: "JsonRepr::new_pure(results)"
|
||||
input_file: crates/tinymist-query/src/fixtures/completion/bracket_strong_delta.typ
|
||||
---
|
||||
[
|
||||
{
|
||||
"isIncomplete": false,
|
||||
"items": [
|
||||
{
|
||||
"kind": 5,
|
||||
"label": "delta",
|
||||
"labelDetails": {
|
||||
"description": "int"
|
||||
},
|
||||
"sortText": "001",
|
||||
"textEdit": {
|
||||
"newText": "delta: ${1:})",
|
||||
"range": {
|
||||
"end": {
|
||||
"character": 31,
|
||||
"line": 2
|
||||
},
|
||||
"start": {
|
||||
"character": 31,
|
||||
"line": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,34 @@
|
|||
---
|
||||
source: crates/tinymist-query/src/completion.rs
|
||||
description: "Completion on ] (52..53)"
|
||||
expression: "JsonRepr::new_pure(results)"
|
||||
input_file: crates/tinymist-query/src/fixtures/completion/bracket_strong_delta2.typ
|
||||
---
|
||||
[
|
||||
{
|
||||
"isIncomplete": false,
|
||||
"items": [
|
||||
{
|
||||
"kind": 5,
|
||||
"label": "delta",
|
||||
"labelDetails": {
|
||||
"description": "int"
|
||||
},
|
||||
"sortText": "001",
|
||||
"textEdit": {
|
||||
"newText": "delta: ${1:}",
|
||||
"range": {
|
||||
"end": {
|
||||
"character": 31,
|
||||
"line": 2
|
||||
},
|
||||
"start": {
|
||||
"character": 31,
|
||||
"line": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -15,7 +15,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/colon_markup.typ
|
|||
"description": "(content, b: content | none, bl: content | none, br: content | none, t: content | none, tl: content | none, tr: content | none) => attach"
|
||||
},
|
||||
"textEdit": {
|
||||
"newText": "attach(${1:})",
|
||||
"newText": "attach[${1:}]",
|
||||
"range": {
|
||||
"end": {
|
||||
"character": 2,
|
||||
|
|
|
@ -15,7 +15,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/colon_math.typ
|
|||
"description": "(content, b: content | none, bl: content | none, br: content | none, t: content | none, tl: content | none, tr: content | none) => attach"
|
||||
},
|
||||
"textEdit": {
|
||||
"newText": "attach(${1:})",
|
||||
"newText": "attach[${1:}]",
|
||||
"range": {
|
||||
"end": {
|
||||
"character": 2,
|
||||
|
|
|
@ -11,6 +11,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/element_where.typ
|
|||
{
|
||||
"kind": 5,
|
||||
"label": "caption",
|
||||
"labelDetails": {
|
||||
"description": "content | none"
|
||||
},
|
||||
"sortText": "000",
|
||||
"textEdit": {
|
||||
"newText": "caption: ${1:}",
|
||||
|
|
|
@ -11,6 +11,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/func_args.typ
|
|||
{
|
||||
"kind": 5,
|
||||
"label": "authors",
|
||||
"labelDetails": {
|
||||
"description": "array | str"
|
||||
},
|
||||
"sortText": "000",
|
||||
"textEdit": {
|
||||
"newText": "authors: ${1:}",
|
||||
|
@ -29,6 +32,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/func_args.typ
|
|||
{
|
||||
"kind": 5,
|
||||
"label": "class",
|
||||
"labelDetails": {
|
||||
"description": "\"article\" | \"letter\" | str"
|
||||
},
|
||||
"sortText": "001",
|
||||
"textEdit": {
|
||||
"newText": "class: ${1:}",
|
||||
|
@ -47,6 +53,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/func_args.typ
|
|||
{
|
||||
"kind": 5,
|
||||
"label": "font",
|
||||
"labelDetails": {
|
||||
"description": "array | none | text.font"
|
||||
},
|
||||
"sortText": "002",
|
||||
"textEdit": {
|
||||
"newText": "font: ${1:}",
|
||||
|
@ -68,7 +77,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/func_args.typ
|
|||
"labelDetails": {
|
||||
"description": "type"
|
||||
},
|
||||
"sortText": "052",
|
||||
"sortText": "053",
|
||||
"textEdit": {
|
||||
"newText": "content",
|
||||
"range": {
|
||||
|
|
|
@ -11,6 +11,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/func_args2.typ
|
|||
{
|
||||
"kind": 5,
|
||||
"label": "class",
|
||||
"labelDetails": {
|
||||
"description": "\"article\" | \"letter\" | str"
|
||||
},
|
||||
"sortText": "000",
|
||||
"textEdit": {
|
||||
"newText": " class: ${1:}",
|
||||
|
@ -29,6 +32,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/func_args2.typ
|
|||
{
|
||||
"kind": 5,
|
||||
"label": "font",
|
||||
"labelDetails": {
|
||||
"description": "array | none | text.font"
|
||||
},
|
||||
"sortText": "001",
|
||||
"textEdit": {
|
||||
"newText": " font: ${1:}",
|
||||
|
|
|
@ -11,6 +11,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/func_args_after.typ
|
|||
{
|
||||
"kind": 5,
|
||||
"label": "class",
|
||||
"labelDetails": {
|
||||
"description": "\"article\" | \"letter\" | str"
|
||||
},
|
||||
"sortText": "000",
|
||||
"textEdit": {
|
||||
"newText": "class: ${1:}, ",
|
||||
|
|
|
@ -11,6 +11,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/func_builtin_args.typ
|
|||
{
|
||||
"kind": 5,
|
||||
"label": "columns",
|
||||
"labelDetails": {
|
||||
"description": "array | auto | length | type"
|
||||
},
|
||||
"sortText": "002",
|
||||
"textEdit": {
|
||||
"newText": "columns: ${1:}",
|
||||
|
@ -32,7 +35,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/func_builtin_args.typ
|
|||
"labelDetails": {
|
||||
"description": "(int, content, gutter: relative) => columns"
|
||||
},
|
||||
"sortText": "056",
|
||||
"sortText": "057",
|
||||
"textEdit": {
|
||||
"newText": "columns(${1:})",
|
||||
"range": {
|
||||
|
|
|
@ -11,6 +11,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/func_with_args.typ
|
|||
{
|
||||
"kind": 5,
|
||||
"label": "authors",
|
||||
"labelDetails": {
|
||||
"description": "array | str"
|
||||
},
|
||||
"sortText": "000",
|
||||
"textEdit": {
|
||||
"newText": "authors: ${1:}",
|
||||
|
@ -29,6 +32,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/func_with_args.typ
|
|||
{
|
||||
"kind": 5,
|
||||
"label": "class",
|
||||
"labelDetails": {
|
||||
"description": "\"article\" | \"letter\" | str"
|
||||
},
|
||||
"sortText": "001",
|
||||
"textEdit": {
|
||||
"newText": "class: ${1:}",
|
||||
|
@ -47,6 +53,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/func_with_args.typ
|
|||
{
|
||||
"kind": 5,
|
||||
"label": "font",
|
||||
"labelDetails": {
|
||||
"description": "array | none | text.font"
|
||||
},
|
||||
"sortText": "002",
|
||||
"textEdit": {
|
||||
"newText": "font: ${1:}",
|
||||
|
@ -68,7 +77,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/func_with_args.typ
|
|||
"labelDetails": {
|
||||
"description": "type"
|
||||
},
|
||||
"sortText": "052",
|
||||
"sortText": "053",
|
||||
"textEdit": {
|
||||
"newText": "content",
|
||||
"range": {
|
||||
|
|
|
@ -11,6 +11,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/half_completion.typ
|
|||
{
|
||||
"kind": 5,
|
||||
"label": "font",
|
||||
"labelDetails": {
|
||||
"description": "array | text.font"
|
||||
},
|
||||
"sortText": "011",
|
||||
"textEdit": {
|
||||
"newText": "font: ${1:}, ",
|
||||
|
@ -34,6 +37,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/half_completion.typ
|
|||
{
|
||||
"kind": 5,
|
||||
"label": "font",
|
||||
"labelDetails": {
|
||||
"description": "array | text.font"
|
||||
},
|
||||
"sortText": "011",
|
||||
"textEdit": {
|
||||
"newText": "font: ${1:}",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: crates/tinymist-query/src/completion.rs
|
||||
description: Completion on n (31..32)
|
||||
description: Completion on n (32..33)
|
||||
expression: "JsonRepr::new_pure(results)"
|
||||
input_file: crates/tinymist-query/src/fixtures/completion/keyword_ident.typ
|
||||
---
|
||||
|
@ -11,6 +11,9 @@ input_file: crates/tinymist-query/src/fixtures/completion/keyword_ident.typ
|
|||
{
|
||||
"kind": 5,
|
||||
"label": "inset",
|
||||
"labelDetails": {
|
||||
"description": "inset"
|
||||
},
|
||||
"sortText": "007",
|
||||
"textEdit": {
|
||||
"newText": "inset: ${1:}",
|
||||
|
|
|
@ -14,7 +14,7 @@ input_file: crates/tinymist-query/src/fixtures/pkgs/touying-core-slides.typ
|
|||
"labelDetails": {
|
||||
"description": "() => any"
|
||||
},
|
||||
"sortText": "050",
|
||||
"sortText": "051",
|
||||
"textEdit": {
|
||||
"newText": "config-xxx()${1:}",
|
||||
"range": {
|
||||
|
|
|
@ -11,6 +11,9 @@ input_file: crates/tinymist-query/src/fixtures/pkgs/touying-core-slides.typ
|
|||
{
|
||||
"kind": 5,
|
||||
"label": "config",
|
||||
"labelDetails": {
|
||||
"description": "dictionary"
|
||||
},
|
||||
"sortText": "003",
|
||||
"textEdit": {
|
||||
"newText": "config: ${1:}",
|
||||
|
@ -29,6 +32,9 @@ input_file: crates/tinymist-query/src/fixtures/pkgs/touying-core-slides.typ
|
|||
{
|
||||
"kind": 5,
|
||||
"label": "repeat",
|
||||
"labelDetails": {
|
||||
"description": "auto"
|
||||
},
|
||||
"sortText": "004",
|
||||
"textEdit": {
|
||||
"newText": "repeat: ${1:}",
|
||||
|
@ -50,9 +56,9 @@ input_file: crates/tinymist-query/src/fixtures/pkgs/touying-core-slides.typ
|
|||
"labelDetails": {
|
||||
"description": "(content, gap: length, justify: bool) => repeat"
|
||||
},
|
||||
"sortText": "245",
|
||||
"sortText": "250",
|
||||
"textEdit": {
|
||||
"newText": "repeat(${1:})",
|
||||
"newText": "repeat[${1:}]",
|
||||
"range": {
|
||||
"end": {
|
||||
"character": 7,
|
||||
|
|
|
@ -11,6 +11,9 @@ input_file: crates/tinymist-query/src/fixtures/pkgs/touying-utils-cover-with-rec
|
|||
{
|
||||
"kind": 5,
|
||||
"label": "fill",
|
||||
"labelDetails": {
|
||||
"description": "auto | color | int | ratio | type"
|
||||
},
|
||||
"sortText": "001",
|
||||
"textEdit": {
|
||||
"newText": "fill: ${1:}",
|
||||
|
@ -32,7 +35,7 @@ input_file: crates/tinymist-query/src/fixtures/pkgs/touying-utils-cover-with-rec
|
|||
"labelDetails": {
|
||||
"description": "type"
|
||||
},
|
||||
"sortText": "289",
|
||||
"sortText": "296",
|
||||
"textEdit": {
|
||||
"newText": "stroke(${1:})",
|
||||
"range": {
|
||||
|
|
|
@ -32,7 +32,7 @@ input_file: crates/tinymist-query/src/fixtures/pkgs/touying-utils-current-headin
|
|||
"labelDetails": {
|
||||
"description": "type"
|
||||
},
|
||||
"sortText": "131",
|
||||
"sortText": "134",
|
||||
"textEdit": {
|
||||
"newText": "int(${1:})",
|
||||
"range": {
|
||||
|
|
|
@ -11,6 +11,9 @@ input_file: crates/tinymist-query/src/fixtures/pkgs/touying-utils-current-headin
|
|||
{
|
||||
"kind": 5,
|
||||
"label": "depth",
|
||||
"labelDetails": {
|
||||
"description": "9999"
|
||||
},
|
||||
"sortText": "000",
|
||||
"textEdit": {
|
||||
"newText": "depth: ${1:}",
|
||||
|
@ -29,6 +32,9 @@ input_file: crates/tinymist-query/src/fixtures/pkgs/touying-utils-current-headin
|
|||
{
|
||||
"kind": 5,
|
||||
"label": "hierachical",
|
||||
"labelDetails": {
|
||||
"description": "true"
|
||||
},
|
||||
"sortText": "001",
|
||||
"textEdit": {
|
||||
"newText": "hierachical: ${1:}",
|
||||
|
@ -47,6 +53,9 @@ input_file: crates/tinymist-query/src/fixtures/pkgs/touying-utils-current-headin
|
|||
{
|
||||
"kind": 5,
|
||||
"label": "level",
|
||||
"labelDetails": {
|
||||
"description": "auto | int"
|
||||
},
|
||||
"sortText": "002",
|
||||
"textEdit": {
|
||||
"newText": "level: ${1:}",
|
||||
|
|
|
@ -68,7 +68,7 @@ input_file: crates/tinymist-query/src/fixtures/pkgs/touying-utils-markup-text.ty
|
|||
"labelDetails": {
|
||||
"description": "type"
|
||||
},
|
||||
"sortText": "281",
|
||||
"sortText": "288",
|
||||
"textEdit": {
|
||||
"newText": "str(${1:})",
|
||||
"range": {
|
||||
|
|
|
@ -11,6 +11,9 @@ input_file: crates/tinymist-query/src/fixtures/pkgs/touying-utils-reconstruct.ty
|
|||
{
|
||||
"kind": 5,
|
||||
"label": "body-name",
|
||||
"labelDetails": {
|
||||
"description": "\"body\""
|
||||
},
|
||||
"sortText": "000",
|
||||
"textEdit": {
|
||||
"newText": "body-name: ${1:}",
|
||||
|
@ -29,6 +32,9 @@ input_file: crates/tinymist-query/src/fixtures/pkgs/touying-utils-reconstruct.ty
|
|||
{
|
||||
"kind": 5,
|
||||
"label": "labeled",
|
||||
"labelDetails": {
|
||||
"description": "true"
|
||||
},
|
||||
"sortText": "001",
|
||||
"textEdit": {
|
||||
"newText": "labeled: ${1:}",
|
||||
|
@ -47,6 +53,9 @@ input_file: crates/tinymist-query/src/fixtures/pkgs/touying-utils-reconstruct.ty
|
|||
{
|
||||
"kind": 5,
|
||||
"label": "named",
|
||||
"labelDetails": {
|
||||
"description": "false"
|
||||
},
|
||||
"sortText": "002",
|
||||
"textEdit": {
|
||||
"newText": "named: ${1:}",
|
||||
|
|
|
@ -21,6 +21,25 @@ pub trait BoundChecker: Sized + TyCtx {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(BindTyCtx)]
|
||||
#[bind(0)]
|
||||
pub struct BoundPred<'a, T: TyCtx, F>(pub &'a T, pub F);
|
||||
|
||||
impl<'a, T: TyCtx, F> BoundPred<'a, T, F> {
|
||||
pub fn new(t: &'a T, f: F) -> Self {
|
||||
Self(t, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: TyCtx, F> BoundChecker for BoundPred<'a, T, F>
|
||||
where
|
||||
F: FnMut(&Ty, bool),
|
||||
{
|
||||
fn collect(&mut self, ty: &Ty, pol: bool) {
|
||||
self.1(ty, pol);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum DocSource {
|
||||
Var(Interned<TypeVar>),
|
||||
|
|
|
@ -15,11 +15,11 @@ use reflexo_typst::TypstFileId;
|
|||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use typst::{
|
||||
foundations::{ParamInfo, Value},
|
||||
foundations::{Content, ParamInfo, Type, Value},
|
||||
syntax::{ast, Span, SyntaxKind, SyntaxNode},
|
||||
};
|
||||
|
||||
use super::PackageId;
|
||||
use super::{BoundPred, PackageId};
|
||||
use crate::{
|
||||
adt::{interner::impl_internable, snapshot_map},
|
||||
analysis::BuiltinTy,
|
||||
|
@ -221,6 +221,24 @@ impl Ty {
|
|||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_content<T: TyCtx>(&self, ctx: &T) -> bool {
|
||||
let mut res = false;
|
||||
self.bounds(
|
||||
false,
|
||||
&mut BoundPred::new(ctx, |ty: &Ty, _pol| {
|
||||
res = res || {
|
||||
match ty {
|
||||
Ty::Value(v) => matches!(v.val, Value::Content(..)),
|
||||
Ty::Builtin(BuiltinTy::Content | BuiltinTy::Element(..)) => true,
|
||||
Ty::Builtin(BuiltinTy::Type(v)) => *v == Type::of::<Content>(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}),
|
||||
);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
/// A function parameter type
|
||||
|
@ -847,6 +865,21 @@ impl SigTy {
|
|||
.and_then(|_| self.inputs.get(idx))
|
||||
}
|
||||
|
||||
/// Get the parameter or the rest parameter at the given index
|
||||
pub fn pos_or_rest(&self, idx: usize) -> Option<Ty> {
|
||||
let nth = self.pos(idx).cloned();
|
||||
nth.or_else(|| {
|
||||
let rest_idx = || idx.saturating_sub(self.positional_params().len());
|
||||
|
||||
let rest_ty = self.rest_param()?;
|
||||
match rest_ty {
|
||||
Ty::Array(ty) => Some(ty.as_ref().clone()),
|
||||
Ty::Tuple(tys) => tys.get(rest_idx()).cloned(),
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Get the named parameters of the function
|
||||
pub fn named_params(&self) -> impl ExactSizeIterator<Item = (&StrRef, &Ty)> {
|
||||
let named_names = self.names.names.iter();
|
||||
|
|
|
@ -32,6 +32,16 @@ pub trait TyCtx {
|
|||
fn global_bounds(&self, _var: &Interned<TypeVar>, _pol: bool) -> Option<TypeBounds>;
|
||||
}
|
||||
|
||||
impl TyCtx for () {
|
||||
fn local_bind_of(&self, _var: &Interned<TypeVar>) -> Option<Ty> {
|
||||
None
|
||||
}
|
||||
|
||||
fn global_bounds(&self, _var: &Interned<TypeVar>, _pol: bool) -> Option<TypeBounds> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// A mutable type context.
|
||||
pub trait TyCtxMut: TyCtx {
|
||||
/// The type of a snapshot of the scope.
|
||||
|
|
|
@ -64,6 +64,8 @@ pub struct Completion {
|
|||
pub sort_text: Option<EcoString>,
|
||||
/// The composed text used for filtering.
|
||||
pub filter_text: Option<EcoString>,
|
||||
/// The character that should be committed when selecting this completion.
|
||||
pub commit_char: Option<char>,
|
||||
/// The completed version of the input, possibly described with snippet
|
||||
/// syntax like `${lhs} + ${rhs}`.
|
||||
///
|
||||
|
|
|
@ -13,7 +13,7 @@ use typst::visualize::Color;
|
|||
|
||||
use super::{Completion, CompletionContext, CompletionKind};
|
||||
use crate::adt::interner::Interned;
|
||||
use crate::analysis::{BuiltinTy, PathPreference, Ty};
|
||||
use crate::analysis::{func_signature, BuiltinTy, PathPreference, Ty};
|
||||
use crate::syntax::{descending_decls, is_ident_like, CheckTarget, DescentDecl};
|
||||
use crate::ty::{Iface, IfaceChecker, InsTy, SigTy, TyCtx, TypeBounds, TypeScheme, TypeVar};
|
||||
use crate::upstream::complete::complete_code;
|
||||
|
@ -174,8 +174,13 @@ impl<'a> CompletionContext<'a> {
|
|||
..base
|
||||
});
|
||||
} else {
|
||||
let apply = if fn_feat.prefer_content_bracket {
|
||||
eco_format!("{name}[${{}}]")
|
||||
} else {
|
||||
eco_format!("{name}(${{}})")
|
||||
};
|
||||
self.completions.push(Completion {
|
||||
apply: Some(eco_format!("{}(${{}})", name)),
|
||||
apply: Some(apply),
|
||||
label: name,
|
||||
..base
|
||||
});
|
||||
|
@ -392,6 +397,7 @@ impl CompletionKindChecker {
|
|||
#[derive(Default, Debug)]
|
||||
struct FnCompletionFeat {
|
||||
zero_args: bool,
|
||||
prefer_content_bracket: bool,
|
||||
is_element: bool,
|
||||
}
|
||||
|
||||
|
@ -408,15 +414,12 @@ impl FnCompletionFeat {
|
|||
match ty {
|
||||
Ty::Value(val) => match &val.val {
|
||||
Value::Type(..) => {}
|
||||
Value::Func(sig) => {
|
||||
if sig.element().is_some() {
|
||||
Value::Func(func) => {
|
||||
if func.element().is_some() {
|
||||
self.is_element = true;
|
||||
}
|
||||
let ps = sig.params().into_iter().flatten();
|
||||
let pos_size = ps.filter(|s| s.positional).count();
|
||||
if pos_size <= pos {
|
||||
self.zero_args = true;
|
||||
}
|
||||
let sig = func_signature(func.clone()).type_sig();
|
||||
self.check_sig(&sig, pos);
|
||||
}
|
||||
_ => panic!("FnCompletionFeat check_one {val:?}"),
|
||||
},
|
||||
|
@ -424,18 +427,25 @@ impl FnCompletionFeat {
|
|||
Ty::With(w) => {
|
||||
self.check_one(&w.sig, pos + w.with.positional_params().len());
|
||||
}
|
||||
Ty::Builtin(BuiltinTy::Element(..)) => {
|
||||
Ty::Builtin(BuiltinTy::Element(func)) => {
|
||||
self.is_element = true;
|
||||
let sig = (*func).into();
|
||||
let sig = func_signature(sig).type_sig();
|
||||
self.check_sig(&sig, pos);
|
||||
}
|
||||
Ty::Builtin(BuiltinTy::TypeType(..)) => {}
|
||||
_ => panic!("FnCompletionFeat check_one {ty:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn check_sig(&mut self, sig: &SigTy, pos: usize) {
|
||||
if pos >= sig.positional_params().len() {
|
||||
self.zero_args = true;
|
||||
}
|
||||
// todo: sig is element
|
||||
fn check_sig(&mut self, sig: &SigTy, idx: usize) {
|
||||
let pos_size = sig.positional_params().len();
|
||||
let prefer_content_bracket =
|
||||
sig.rest_param().is_none() && sig.pos(idx).map_or(false, |ty| ty.is_content(&()));
|
||||
self.prefer_content_bracket = self.prefer_content_bracket || prefer_content_bracket;
|
||||
let name_size = sig.named_params().len();
|
||||
self.zero_args = pos_size <= idx && name_size == 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -462,8 +472,7 @@ fn sort_and_explicit_code_completion(ctx: &mut CompletionContext) {
|
|||
// ctx.strict_scope_completions(false, |value| value.ty() == ty);
|
||||
|
||||
log::debug!(
|
||||
"sort_and_explicit_code_completion: {:#?} {:#?}",
|
||||
completions,
|
||||
"sort_and_explicit_code_completion: {completions:#?} {:#?}",
|
||||
ctx.completions
|
||||
);
|
||||
|
||||
|
@ -617,6 +626,7 @@ fn type_completion(
|
|||
Ty::Param(p) => {
|
||||
// todo: variadic
|
||||
|
||||
let docs = docs.or_else(|| p.docs.as_deref());
|
||||
if p.attrs.positional {
|
||||
type_completion(ctx, &p.ty, docs);
|
||||
}
|
||||
|
@ -637,12 +647,11 @@ fn type_completion(
|
|||
return Some(());
|
||||
}
|
||||
|
||||
// todo: label details
|
||||
let docs = docs.or_else(|| p.docs.as_deref());
|
||||
ctx.completions.push(Completion {
|
||||
kind: CompletionKind::Field,
|
||||
label: f.into(),
|
||||
apply: Some(eco_format!("{}: ${{}}", f)),
|
||||
label_detail: p.ty.describe(),
|
||||
detail: docs.map(Into::into),
|
||||
command: ctx
|
||||
.trigger_named_completion
|
||||
|
@ -871,6 +880,7 @@ pub(crate) fn complete_type(ctx: &mut CompletionContext) -> Option<()> {
|
|||
|
||||
let check_target = get_check_target(ctx.leaf.clone());
|
||||
log::debug!("complete_type: pos {:?} -> {check_target:#?}", ctx.leaf);
|
||||
let mut args_node = None;
|
||||
|
||||
match check_target {
|
||||
Some(CheckTarget::Element { container, .. }) => {
|
||||
|
@ -889,6 +899,13 @@ pub(crate) fn complete_type(ctx: &mut CompletionContext) -> Option<()> {
|
|||
ctx.seen_field(named.name().into());
|
||||
}
|
||||
}
|
||||
args_node = Some(args.to_untyped().clone());
|
||||
}
|
||||
Some(CheckTarget::Normal(e))
|
||||
if (matches!(e.kind(), SyntaxKind::ContentBlock)
|
||||
&& matches!(ctx.leaf.kind(), SyntaxKind::LeftBracket)) =>
|
||||
{
|
||||
args_node = e.parent().map(|s| s.get().clone());
|
||||
}
|
||||
Some(CheckTarget::Normal(e))
|
||||
if matches!(
|
||||
|
@ -920,6 +937,22 @@ pub(crate) fn complete_type(ctx: &mut CompletionContext) -> Option<()> {
|
|||
}
|
||||
|
||||
sort_and_explicit_code_completion(ctx);
|
||||
|
||||
if let Some(c) = args_node {
|
||||
log::debug!("content block compl: args {c:?}");
|
||||
let is_unclosed = matches!(c.kind(), SyntaxKind::Args)
|
||||
&& c.children().fold(0i32, |acc, node| match node.kind() {
|
||||
SyntaxKind::LeftParen => acc + 1,
|
||||
SyntaxKind::RightParen => acc - 1,
|
||||
SyntaxKind::Error if node.text() == "(" => acc + 1,
|
||||
SyntaxKind::Error if node.text() == ")" => acc - 1,
|
||||
_ => acc,
|
||||
}) > 0;
|
||||
if is_unclosed {
|
||||
ctx.enrich("", ")");
|
||||
}
|
||||
}
|
||||
|
||||
Some(())
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue