Repository: typst/typst
File: crates/typst-ide/src/complete.rs (Rust)

Code before:

/// Resolve a callee expression to a global function.
fn resolve_global_callee<'a>(
    ctx: &CompletionContext<'a>,
    callee: ast::Expr<'a>,
) -> Option<&'a Func> {
    let globals = globals(ctx.world, ctx.leaf);
    let value = match callee {
        ast::Expr::Ident(ident) => globals.get(&ident)?.read(),
        ast::Expr::FieldAccess(access) => match access.target() {
            ast::Expr::Ident(target) => {
                globals.get(&target)?.read().scope()?.get(&access.field())?.read()
            }
            _ => return None,
        },
        _ => return None,
    };

    match value {
        Value::Func(func) => Some(func),
        _ => None,
    }
}

/// Complete in code mode.
fn complete_code(ctx: &mut CompletionContext) -> bool {
    if matches!(
        ctx.leaf.parent_kind(),
        None | Some(SyntaxKind::Markup)
            | Some(SyntaxKind::Math)
            | Some(SyntaxKind::MathFrac)
            | Some(SyntaxKind::MathAttach)
            | Some(SyntaxKind::MathRoot)
    ) {
        return false;
    }

    // An existing identifier (which is not the key of a named pair): "{ pa| }".
    if ctx.leaf.kind() == SyntaxKind::Ident
        && (ctx.leaf.index() > 0 || ctx.leaf.parent_kind() != Some(SyntaxKind::Named))
    {
        ctx.from = ctx.leaf.offset();
        code_completions(ctx, false);
        return true;
    }

    // A potential label (only at the start of an argument list): "(<|".
    if ctx.before.ends_with("(<") {
        ctx.from = ctx.cursor;
        ctx.label_completions();
        return true;

Review comment (suggestion):
An attempt at being a bit more descriptive:

```suggestion
    // An existing identifier: "{ pa| }".
    // Ignores named pair keys as they are not variables (as in "func(pa|: 23)").
    if ctx.leaf.kind() == SyntaxKind::Ident
        && (ctx.leaf.index() > 0 || ctx.leaf.parent_kind() != Some(SyntaxKind::Named))
    {
```

Code after:
    };

    match value {
        Value::Func(func) => Some(func),
        _ => None,
    }
}

/// Complete in code mode.
fn complete_code(ctx: &mut CompletionContext) -> bool {
    if matches!(
        ctx.leaf.parent_kind(),
        None | Some(SyntaxKind::Markup)
            | Some(SyntaxKind::Math)
            | Some(SyntaxKind::MathFrac)
            | Some(SyntaxKind::MathAttach)
            | Some(SyntaxKind::MathRoot)
    ) {
        return false;
    }

    // An existing identifier: "{ pa| }".
    // Ignores named pair keys as they are not variables (as in "(pa|: 23)").
    if ctx.leaf.kind() == SyntaxKind::Ident
        && (ctx.leaf.index() > 0 || ctx.leaf.parent_kind() != Some(SyntaxKind::Named))
    {
        ctx.from = ctx.leaf.offset();
        code_completions(ctx, false);
        return true;
    }

    // A potential label (only at the start of an argument list): "(<|".
    if ctx.before.ends_with("(<") {
        ctx.from = ctx.cursor;
        ctx.label_completions();
        return true;
    }

    // Anywhere: "{ | }", "(|)", "(1,|)", "(a:|)".
    // But not within or after an expression, and also not part of a dictionary
    // key (as in "(pa: |,)")
    if ctx.explicit
        && ctx.leaf.parent_kind() != Some(SyntaxKind::Dict)
        && (ctx.leaf.kind().is_trivia()
            || matches!(
                ctx.leaf.kind(),
                SyntaxKind::LeftParen
                    | SyntaxKind::LeftBrace
                    | SyntaxKind::Comma
                    | SyntaxKind::Colon
            ))