syntect-tmlanguage 0.1.0

Load real TextMate .tmLanguage.json grammars into syntect's own SyntaxDefinition data model
Documentation
//! Integration test: translate a real, non-trivial third-party grammar
//! (Zig — chosen only as a real "not natively supported" example, see
//! `TODO.canvas.md`) and drive it through `syntect`'s *own* `ParseState`,
//! not just this crate's translator in isolation. Exercises nested
//! `begin`/`end` contexts, `captures`, and `include`.

use std::collections::BTreeSet;
use std::fs;

use syntect::parsing::{Scope, ScopeStack, SyntaxSetBuilder};

#[test]
fn translated_zig_grammar_parses_via_syntects_own_parser() {
    let grammar_json = fs::read_to_string("tests/fixtures/zig.tmLanguage.json").unwrap();
    let source = fs::read_to_string("tests/fixtures/sample.zig").unwrap();

    let definition = syntect_tmlanguage::load(&grammar_json).expect("translation failed");
    assert_eq!(definition.scope, Scope::new("source.zig").unwrap());

    let mut builder = SyntaxSetBuilder::new();
    builder.add(definition);
    let syntax_set = builder.build();

    let syntax = syntax_set
        .find_syntax_by_scope(Scope::new("source.zig").unwrap())
        .expect("translated syntax should be registered under its scope");

    let mut parse_state = syntect::parsing::ParseState::new(syntax);
    let mut scope_stack = ScopeStack::new();
    let mut seen_scopes: BTreeSet<String> = BTreeSet::new();

    for line in source.lines() {
        let ops = parse_state
            .parse_line(line, &syntax_set)
            .expect("syntect failed to parse a line produced by the translated grammar");
        for (_, op) in ops {
            scope_stack.apply(&op).expect("invalid scope stack op");
            for scope in scope_stack.as_slice() {
                seen_scopes.insert(scope.build_string());
            }
        }
    }

    // Same real-world exercise as the hands-on `syntaxmate`/`shiki` stress
    // test in TODO.canvas.md — nested begin/end (comments, strings),
    // captures (function names, keywords), and includes should all fire.
    for expected in [
        "source.zig",
        "comment.line.double-slash.zig",
        "string.quoted.double.zig",
        "entity.name.function.zig",
        "keyword.control.trycatch.zig",
    ] {
        assert!(
            seen_scopes.contains(expected),
            "expected scope {expected:?} to appear; got {seen_scopes:#?}"
        );
    }
}