Seq macro

#seq is used to define a sequence of nodes and it only works with structs.

Fields can be named however you want, auto_lsp relies on query names to build the AST.

A field can either be:

  • Another struct (a nested sequence of nodes).
  • An enum (a choice between multiple sequences of nodes).
  • A Vec of structs or enums built with the same macros.
  • An Option of a struct or enum.

A Vec can contain 0 or any number of elements. Since tree sitter already defines repeat and repeat1, a repeat1 would return an error from the tree-sitter lexer if the Vec is empty.

use auto_lsp::core::ast::*;
use auto_lsp::{seq, choice};

#[seq(query = "document")]
struct Document {
    // A simple field
    name: Identifier,
    // A vec of structs
    functions: Vec<Function>,
    // A vec of enums
    elements: Vec<Element>,
    // An optional field
    return_type: Option<Type>,
}

#[seq(query = "function")]
struct Function {}

#[choice]
enum Element {
     Statement(Statement),
     Expression(Expression),
}

#[seq(query = "statement")]
struct Statement {}

#[seq(query = "expression")]
struct Expression {}

#[seq(query = "type")]
struct Identifier {}

#[seq(query = "type")]
struct Type {}

Seq Attributes

  • query: The name of the query used to capture the node.

All other attributes are optional. By default #seq will generate an empty version of each trait.

(Since rust does not have stable specialization)

When an attribute is provided, the corresponding trait must be implemented manually.

To activate an attribute, just add it to any #seq macro parameters:

use auto_lsp::seq;
use auto_lsp::core::ast::{BuildDocumentSymbols, BuildCodeActions};
use auto_lsp::core::document_symbols_builder::DocumentSymbolsBuilder;

// Here, we tell auto_lsp that document_symbols and code_actions
// will be implemented manually.

// If an attribute is declared but no implementation is provided,
// your code won't compile.
#[seq(query = "function",
        document_symbols,
        code_actions,
    )]
struct Function {}

impl BuildDocumentSymbols for Function {
    fn build_document_symbols(&self, doc: &Document, builder: &mut DocumentSymbolsBuilder {
        /* ... */
    }
}

impl BuildCodeActions for Function {
    fn build_code_actions(&self, doc: &Document, acc: &mut Vec<lsp_types::CodeAction>) {
        /* ... */
    }
}

LSP traits

Special traits

  • comment: mark this node as a node that can potentially contain a comment. If the comments query is provided in the parser configuration, comments found above the node will be attached to it.

  • check: Check trait.

The Check trait is a special trait used to validate a symbol. When implemented, auto_lsp will execute the check method to verify the symbol's validity.

Note

check returns a CheckStatus to indicate whether the validation was successful. To add diagnostics, push them into the provided diagnostics vector.

use auto_lsp::seq;
use auto_lsp::core::ast::{Check, CheckStatus};

#[seq(query = "document", check)]
struct Document {}

impl Check for Document {
    fn check(
        &self,
        doc: &Document,
        diagnostics: &mut Vec<lsp_types::Diagnostic>,
    ) -> CheckStatus {
        let source = doc.texter.text.as_bytes();
        let document_text = self.read().get_text(source);

        if document_text.starts_with("Hello, World") {
            return CheckStatus::Ok
        } else {
            diagnostics.push(lsp_types::Diagnostic {
                range: self.get_lsp_range(document),
                severity: Some(lsp_types::DiagnosticSeverity::Error),
                message: "Document must start with 'Hello, World'".to_string(),
                ..Default::default()
            });
            return CheckStatus::Fail;
        }
    }
}