{"id":15282577,"url":"https://github.com/rubixdev/syntastica","last_synced_at":"2025-07-08T17:38:54.626Z","repository":{"id":167332100,"uuid":"628711216","full_name":"RubixDev/syntastica","owner":"RubixDev","description":"Modern and easy syntax highlighting using tree-sitter","archived":false,"fork":false,"pushed_at":"2025-03-31T13:34:48.000Z","size":106490,"stargazers_count":19,"open_issues_count":2,"forks_count":5,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-04-12T23:05:41.974Z","etag":null,"topics":["crates","rust","syntax-highlighting","tree-sitter"],"latest_commit_sha":null,"homepage":"https://rubixdev.github.io/syntastica/","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RubixDev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"ko_fi":"rubixdev"}},"created_at":"2023-04-16T19:31:47.000Z","updated_at":"2025-03-31T13:18:32.000Z","dependencies_parsed_at":"2024-09-30T14:27:15.386Z","dependency_job_id":"0c90a799-fa6f-4b50-9f0d-c7782422d56f","html_url":"https://github.com/RubixDev/syntastica","commit_stats":null,"previous_names":["rubixdev/syntastica"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RubixDev%2Fsyntastica","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RubixDev%2Fsyntastica/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RubixDev%2Fsyntastica/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RubixDev%2Fsyntastica/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RubixDev","download_url":"https://codeload.github.com/RubixDev/syntastica/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248643008,"owners_count":21138354,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["crates","rust","syntax-highlighting","tree-sitter"],"created_at":"2024-09-30T14:27:04.446Z","updated_at":"2025-04-12T23:05:55.454Z","avatar_url":"https://github.com/RubixDev.png","language":"Rust","readme":"# `syntastica`\n\nModern and easy syntax highlighting using tree-sitter\n\n\u003e **Note**\n\u003e\n\u003e If viewing this file on [GitHub](https://github.com/RubixDev/syntastica) or\n\u003e [crates.io](https://crates.io/crates/syntastica), some links might not be\n\u003e working. Go to the\n\u003e [custom docs page](https://rubixdev.github.io/syntastica/syntastica/) or the\n\u003e [docs.rs page](https://docs.rs/syntastica/) instead, which additionally\n\u003e include the [Features](#features) section.\n\n## Overview\n\nTo use `syntastica`, you probably want to depend on three crates:\n\n1. The main `syntastica` crate for all the logic.\n2. A parser collection to provide language support (see\n   [parser collections](#parser-collections))\n3. The theme collection for some default themes (see\n   [theme collection](#theme-collection))\n\nSo for example:\n\n```toml\nsyntastica = \"\u003cversion\u003e\"\nsyntastica-parsers = { version = \"\u003cversion\u003e\", features = [\"some\"] }\nsyntastica-themes = \"\u003cversion\u003e\"\n```\n\n### Use cases\n\n`syntastica` has three main ways of highlighting code, for three different use\ncases:\n\n1. Highlight _one_ input _exactly once_: see [`highlight`] and\n   [this example](#example-highlight-once)\n2. Highlight _one_ input _multiple times_ (e.g. with different themes or\n   renderers): see [`Processor::process_once`], [`render`], and\n   [this example](#example-highlight-the-same-input-multiple-times)\n3. Highlight _multiple_ different inputs _any_ number of times: see\n   [`Processor`], [`render`], and\n   [this example](#example-highlight-multiple-different-inputs)\n\n### Using `syntastica` as a Git Dependency\n\nUsing [`syntastica-queries`](#syntastica-queries), and in turn any crate in this\nworkspace which depends on [`syntastica-queries`](#syntastica-queries), as a git\ndependency with cargo is not immediately possible, because the auto-generated\nquery files are not checked in. For that purpose, the `git-deploy` is updated\nwith the latest state of the main branch after every push. That means you can\ndepend on for example [`syntastica-parsers-git`](#syntastica-parsers-git) like\nthis:\n\n```toml\nsyntastica-parsers-git = { git = \"https://github.com/RubixDev/syntastica\", branch = \"git-deploy\" }\n```\n\n## Subprojects\n\nBesides the main `syntastica` crate, many other crates for different purposes\nwere developed and are included in the repository. This section aims to provide\na good overview.\n\n### Parser collections\n\nThe main `syntastica` crate provides no tree-sitter parsers and queries by\nitself. However, the project does provide four different parser collections with\ndifferent advantages and drawbacks each. Three of them depend on\n[`syntastica-queries`](#syntastica-queries) for the tree-sitter queries. Choose\none, and add it as a dependency next to `syntastica` itself.\n\nThe odd one out here is\n[`syntastica-parsers-dynamic`](https://crates.io/crates/syntastica-parsers-dynamic),\nwhich unlike the others doesn't actually include any parsers but instead\nprovides an interface to load them during runtime.\n\nThe other three parser collections all provide the same public API and have\nfeatures for all supported languages, as well as the three feature groups\n`some`, `most`, and `all`. Take a look at the respective crate documentation for\nmore information.\n\nIf you want to additionally use languages that are not in any of these parser\ncollections or combine multiple sets, have a look at the\n[`Union`](language_set::Union) type or the\n[custom languages example](https://github.com/RubixDev/syntastica/blob/main/examples/custom_languages.rs).\n\n- [`syntastica-parsers`](https://crates.io/crates/syntastica-parsers) is\n  probably the easiest to start with. It uses parsers from\n  [crates.io](https://crates.io). This has the main benefit of being well\n  integrated in the cargo ecosystem. However, many tree-sitter parsers do not\n  get published to crates.io, and those that are, are usually very outdated.\n  Thus, this collection is relatively limited.\n- \u003ca name=\"syntastica-parsers-git\" href=\"https://crates.io/crates/syntastica-parsers-git\"\u003e\u003ccode\u003esyntastica-parsers-git\u003c/code\u003e\u003c/a\u003e\n  is probably the best choice overall. It contains all supported languages and\n  is the only choice when targeting WebAssembly. It pulls pinned revisions of\n  parser git repositories in the build script and links to the C and C++ parser\n  sources. As such, it does not depend on the upstream parsers to have\n  up-to-date Rust bindings. However, this way of fetching the parsers requires\n  the `git` command to be accessible and internet access during compilation,\n  which may not be desirable. Additionally, compilation can take very long\n  unless you manually specify a cache directory that can be reused between\n  builds. See the crate's docs for more information on that.\n- [`syntastica-parsers-gitdep`](https://github.com/RubixDev/syntastica/tree/main/syntastica-parsers-gitdep)\n  is a mix of both of the above. It uses cargo git dependencies to fetch the\n  parser repositories and depends on a remote Rust binding (which is why not\n  _all_ parsers are included). The main disadvantages are that this collection\n  cannot be published to crates.io, because it depends on crates that are not on\n  crates.io (namely the parsers). This means, to use it you must also depend on\n  it using a git dependency, which in turn forbids your crate to be published on\n  crates.io. Unlike [`syntastica-parsers-git`](#syntastica-parsers-git) however,\n  the parsers only need to be fetched once by cargo, and subsequent builds will\n  be much faster.\n- [`syntastica-parsers-dynamic`](https://crates.io/crates/syntastica-parsers-dynamic)\n  doesn't include any parsers by itself but instead provides a\n  [`LanguageSet`](language_set::LanguageSet) implementation that can find and\n  load parsers at runtime. This allows for behavior similar to what the\n  tree-sitter CLI does, and opens up more possibilities for end-users, but also\n  places more responsibilities on them, as the appropriate queries also need to\n  be provided manually.\n\n### Theme collection\n\nTo [render highlighted code](render) to end users, a\n[theme](theme::ResolvedTheme) is needed, which specifies the colors to use for\nwhich [theme key](theme::THEME_KEYS). The `syntastica` project comes with a\nseparate crate containing a few default themes:\n[`syntastica-themes`](https://crates.io/crates/syntastica-themes).\n\nIf you wish to create your own theme, have a look at the\n[custom theme example](#example-custom-theme) and the documentation for the\n[`theme!`] macro.\n\n### Crates for internal use\n\nThe `syntastica` repository/workspace also includes some crates which are not\nmeant for outside use, but are instead used internally. These are listed below.\n\n\u003e Note: **There are no guarantees about the public API of these crates!** If,\n\u003e for any reason, you have to depend on one of them, then pin the _exact_\n\u003e version using `\u003ccrate\u003e = \"=\u003cversion\u003e\"`.\n\n- [`syntastica-core`](https://crates.io/crates/syntastica-core) defines types,\n  traits, constants, etc. which are used in multiple of the other crates. The\n  main `syntastica` crate re-exports all those items transparently, so that\n  external projects only need a dependency on that. The items are defined in\n  `syntastica-core` however, to avoid cyclic (dev-)dependencies inside this\n  workspace.\n- [`syntastica-macros`](https://crates.io/crates/syntastica-macros) defines\n  procedural macros for use **exclusively** inside this workspace. This crate\n  allows the list of languages/parsers to be in _one_ combined `languages.toml`\n  file, and the different macros are used in the different places where this\n  list needs to be referenced.\n- [`syntastica-highlight`](https://crates.io/crates/syntastica-highlight) is a\n  fork of\n  [`tree-sitter-highlight`](https://crates.io/crates/tree-sitter-highlight),\n  which is adjusted and trimmed down for the use in `syntastica`. It contains\n  the main highlighting logic.\n- \u003ca name=\"syntastica-queries\" href=\"https://crates.io/crates/syntastica-queries\"\u003e\u003ccode\u003esyntastica-queries\u003c/code\u003e\u003c/a\u003e\n  is a collection of tree-sitter queries for all supported languages. It is\n  marked as \"for internal use\", because all three\n  [parser collections](#parser-collections) depend on this crate and expose the\n  queries through their implementation of\n  [`LanguageSet`](language_set::LanguageSet). Unlike the previous crates in this\n  list however, you may actually want to depend on this crate yourself, if you\n  _only_ need the queries.\n\n### General side-products\n\nThis list includes crates which were developed for `syntastica` but have no\ndirect association with the main project and can be used completely separately.\n\n- [`rsexpr`](https://crates.io/crates/rsexpr) is a generic S-expression parser\n  with added support for square-brackets, strings, and comments. Additionally,\n  the parsed S-expressions can be pretty-printed to provide a uniform\n  formatting. See\n  [`dprint-plugin-sexpr`](https://github.com/RubixDev/dprint-plugin-sexpr) for\n  more information on using this as a formatter. In `syntastica` this crate is\n  used for parsing (and formatting) the tree-sitter queries in the\n  [`queries`](https://github.com/RubixDev/syntastica/tree/main/queries)\n  directory. These are processed by `cargo xtask codegen queries` and result in\n  the queries inside the\n  [`generated_queries`](https://github.com/RubixDev/syntastica/tree/main/syntastica-queries/generated_queries)\n  directory, which are the ones that are bundled with\n  [`syntastica-queries`](#syntastica-queries).\n- [`lua-pattern`](https://crates.io/crates/lua-pattern) is a parser for Lua\n  patterns. These are similar to regular expressions, but generally more\n  limited. The crate also provides a best-effort conversion to regular\n  expression strings. In `syntastica` this is used, as many of the source\n  queries are forked from\n  [nvim-treesitter](https://github.com/nvim-treesitter/nvim-treesitter) which\n  makes heavy use of `#lua-match?` predicates for matching with Lua patterns.\n  The official tree-sitter Rust bindings do not support Lua pattern matching\n  however (obviously), which is why during the processing of the queries (with\n  `cargo xtask codegen queries`), all Lua patterns are replaced with regular\n  expressions using this crate.\n- [`syntastica-query-preprocessor`](https://crates.io/crates/syntastica-query-preprocessor)\n  is a pre-processor for tree-sitter queries which allows usage of\n  `; inherits \u003clang\u003e` comments, conditional skipping of nodes with comments,\n  usage of additional predicates like `lua-match?`, `contains?` and `any-of?`,\n  Neovim's old injections syntax, and order reversing for priority flipping. The\n  crate can be used to use queries designed for Neovim with the official\n  [tree-sitter Rust bindings](https://crates.io/crates/tree-sitter) with minimal\n  manual changes. Despite having `syntastica` in the name, the crate can be used\n  externally and does not depend on any of the other `syntastica-` crates. In\n  `syntastica` it is used in the\n  [`codegen queries` xtask](https://github.com/RubixDev/syntastica/blob/main/xtask/src/codegen/queries.rs),\n  because many of the queries are forked from\n  [nvim-treesitter](https://github.com/nvim-treesitter/nvim-treesitter), and to\n  adjust the queries for older parser versions from\n  [crates.io](https://crates.io).\n\n## WebAssembly support\n\n`syntastica` can be used with WebAssembly, although the current support is a bit\nlacking. There are currently two primary ways to use `syntastica` in a\nWebAssembly context.\n\n### 1. Using the `tree-sitter-c2rust` runtime\n\nIn order to make `syntastica` compile to `wasm32-unknown-unknown` targets,\nfeature flags can be used to use the\n[c2rust transpilation of tree-sitter](https://crates.io/crates/tree-sitter-c2rust)\ninstead of the\n[official C implementation](https://crates.io/crates/tree-sitter). This is only\nsupported by the `syntastica-parsers-git` parser collection as only that\ncollection has enough control over the parser build process to allow for Wasm\nsupport.\n\nTo use this approach, simply set `default-features = false` and enable the\n`runtime-c2rust` feature for _all_ `syntastica` dependencies. There are two\nexample projects using this approach:\n\n- [Basic usage with wasm-bindgen and wasm-pack](https://github.com/RubixDev/syntastica/tree/main/examples/wasm/wasm-pack)\n- [Usage in a Dioxus application](https://github.com/RubixDev/syntastica/tree/main/examples/wasm/dioxus)\n\nNote that for extra safety, you should compile this with nightly Rust and the\n`-Zwasm_c_abi=spec` option set, as otherwise the `wasm32-unknown-unknown` target\ndoesn't yet conform with the C ABI. In my personal testing I haven't had any\nissues on stable Rust either though.\n\n### 2. Using Emscripten / the `syntastica-js` package\n\n`syntastica` can also be compiled to `wasm32-unknown-emscripten` which has much\nbetter support for C and C++ interop. But annoyingly, basically the entire Rust\nWasm ecosystem is built around the `wasm32-unknown-unknown` target (e.g.,\n`wasm-pack` and `wasm-bindgen` can only be used with `wasm32-unknown-unknown`),\nwhich makes it very cumbersome to use Emscripten for Rust. In the attempt to\nmake using `syntastica` on the web a bit easier, the\n[`syntastica-js` crate](https://github.com/RubixDev/syntastica/tree/main/syntastica-js)\nand accompanying\n[`@syntastica/core` NPM package](https://www.npmjs.com/package/@syntastica/core)\nprovide a JavaScript/TypeScript wrapper around an Emscripten build of\n`syntastica`.\n\nThere are two example projects using `syntastica-js`:\n\n- [Usage from TypeScript in the browser with Vite and Svelte](https://github.com/RubixDev/syntastica/tree/main/examples/wasm/vite)\n- [Usage from JavaScript in NodeJS for console applications](https://github.com/RubixDev/syntastica/tree/main/examples/wasm/node)\n\n## Examples\n\nThis section contains some basic usage examples. More specific examples can be\nfound in the documentation of some items such as the [`Processor`] type or the\n[`render`] function. Additionally, the\n[`examples`](https://github.com/RubixDev/syntastica/tree/main/examples)\ndirectory contains a few complete examples.\n\nThis is the list of examples found here:\n\n- [Highlight once](#example-highlight-once)\n- [Highlight the same input multiple times](#example-highlight-the-same-input-multiple-times)\n- [Highlight multiple different inputs](#example-highlight-multiple-different-inputs)\n- [Detect the language based on a file type](#example-detect-language-from-file-type)\n- [Specify a custom theme](#example-custom-theme)\n\n### Example: highlight once\n\nThis example shows the easiest and quickest way to use `syntastica`. See the\nsection about [use cases](#use-cases) for when it is appropriate to use\n`syntastica` this way.\n\n```rust\nuse syntastica::renderer::TerminalRenderer;\nuse syntastica_parsers::{Lang, LanguageSetImpl};\n\nlet output = syntastica::highlight(\n    // the code to highlight\n    r#\"fn main() { println!(\"42\"); }\"#,\n    // the input's language\n    Lang::Rust,\n    // use `syntastica-parsers` language set\n    \u0026LanguageSetImpl::new(),\n    // use the TerminalRenderer with no background color\n    \u0026mut TerminalRenderer::new(None),\n    // use the gruvbox dark theme from `syntastica-themes`\n    syntastica_themes::gruvbox::dark(),\n)\n.unwrap_or_else(|err| panic!(\"highlighting failed: {err}\"));\n\nprintln!(\"{output}\");\n```\n\n### Example: highlight the same input multiple times\n\nThis example shows how to render the same input with two different themes using\ntwo different renderers.\n\n```rust\nuse syntastica::{Processor, style::Color, renderer::*};\nuse syntastica_parsers::{Lang, LanguageSetImpl};\n\n// process the input once, but store the raw highlight information\nlet highlights = Processor::process_once(\n    // the code to highlight\n    r#\"fn main() { println!(\"42\"); }\"#,\n    // the input's language\n    Lang::Rust,\n    // use `syntastica-parsers` language set\n    \u0026LanguageSetImpl::new(),\n)\n.unwrap_or_else(|err| panic!(\"highlighting failed: {err}\"));\n\n// render the highlights to the terminal using the\n// gruvbox dark theme on a dark gray background\nprintln!(\"{}\", syntastica::render(\n    \u0026highlights,\n    \u0026mut TerminalRenderer::new(Some(Color::new(40, 40, 40))),\n    syntastica_themes::gruvbox::dark(),\n));\n\n// render the same input to HTML using the onelight theme\nlet html = syntastica::render(\n    \u0026highlights,\n    \u0026mut HtmlRenderer::new(),\n    syntastica_themes::one::light(),\n);\n// you could for example write that to a file called `index.html`:\n// std::fs::write(\"index.html\", html).unwrap();\n```\n\n### Example: highlight multiple different inputs\n\nThis example shows how a [`Processor`] can be reused if multiple different\ninputs should be highlighted.\n\n```rust\nuse syntastica::{Processor, style::Color, renderer::*};\nuse syntastica_parsers::{Lang, LanguageSetImpl};\n\n// create a language set and a `Processor`\nlet language_set = LanguageSetImpl::new();\nlet mut processor = Processor::new(\u0026language_set);\n// Note: `language_set` has to be stored in a variable, because the processor\n// is bound to the lifetime of the reference passed to `new`\n\n// process some input\nlet highlights_rust = processor.process(\n    // the code to highlight\n    r#\"fn main() { println!(\"42\"); }\"#,\n    // the input's language\n    Lang::Rust,\n)\n.unwrap_or_else(|err| panic!(\"highlighting failed: {err}\"));\n\n// process some other input in another language\nlet highlights_js = processor.process(r\"console.log('42')\", Lang::Javascript)\n    .unwrap_or_else(|err| panic!(\"highlighting failed: {err}\"));\n\n// render the rust code to the terminal using the\n// gruvbox dark theme on a dark gray background\nprintln!(\"{}\", syntastica::render(\n    \u0026highlights_rust,\n    \u0026mut TerminalRenderer::new(Some(Color::new(40, 40, 40))),\n    syntastica_themes::gruvbox::dark(),\n));\n\n// render the same rust code to HTML using the onelight theme\nlet html = syntastica::render(\n    \u0026highlights_rust,\n    \u0026mut HtmlRenderer::new(),\n    syntastica_themes::one::light(),\n);\n// you could for example write that to a file called `index.html`:\n// std::fs::write(\"index.html\", html).unwrap();\n\n// now render the javascript code to the terminal using the\n// onedark theme and no background color\nprintln!(\"{}\", syntastica::render(\n    \u0026highlights_js,\n    \u0026mut TerminalRenderer::new(None),\n    syntastica_themes::one::dark(),\n));\n```\n\n### Example: detect language from file type\n\nThis is an alteration of the [first example](#example-highlight-once) showing\nhow to detect the language to use based on a file type. See that first example\nfor explanations of the rest of the code.\n\n`syntastica` uses [`tft`](https://crates.io/crates/tft) for file types which\nprovides automatic detection.\n\n```rust\nuse syntastica::{renderer::TerminalRenderer, language_set::{LanguageSet, SupportedLanguage}};\nuse syntastica_parsers::{Lang, LanguageSetImpl};\n\n// detect the file type given a file's path and content.\n// this requires a dependency on `tft`\nlet ft = tft::detect(\"main.rs\", \"\");\n\nlet language_set = LanguageSetImpl::new();\nlet output = syntastica::highlight(\n    r#\"fn main() { println!(\"42\"); }\"#,\n    // the `SupportedLanguage` trait provides a `for_file_type` function\n    // which returns an `Option\u003cLang\u003e`\n    // make sure to have the trait in scope\n    Lang::for_file_type(ft, \u0026()).unwrap(),\n    \u0026language_set,\n    \u0026mut TerminalRenderer::new(None),\n    syntastica_themes::gruvbox::dark(),\n)\n.unwrap_or_else(|err| panic!(\"highlighting failed: {err}\"));\n\nprintln!(\"{output}\");\n```\n\n### Example: custom theme\n\nThis is an alteration of the [first example](#example-highlight-once) showing\nhow to create a simple custom theme. See that first example for explanations of\nthe rest of the code, and see the documentation of the [`theme!`] macro for more\ninformation.\n\n```rust\nuse syntastica::{renderer::TerminalRenderer, theme};\nuse syntastica_parsers::{Lang, LanguageSetImpl};\n\nlet theme = theme! {\n    // specify colors using hex literals\n    \"purple\": \"#c678dd\",\n    \"blue\": \"#61afef\",\n    \"green\": \"#98c379\",\n\n    // link to other keys using a `$` sign\n    \"keyword\": \"$purple\",\n    \"function\": \"$blue\",\n\n    // specify more styling options in curly braces\n    // (note that currently this order is required by the macro)\n    \"string\": {\n        color: None,\n        bg: None,\n        underline: false,\n        strikethrough: false,\n        italic: true,\n        bold: false,\n        link: \"green\",\n    },\n};\n\nlet output = syntastica::highlight(\n    r#\"fn main() { println!(\"42\"); }\"#,\n    Lang::Rust,\n    \u0026LanguageSetImpl::new(),\n    \u0026mut TerminalRenderer::new(None),\n    theme,\n)\n.unwrap_or_else(|err| panic!(\"highlighting failed: {err}\"));\n\nprintln!(\"{output}\");\n```\n\n## Versioning\n\nAll crates in this workspace whose names start with `syntastica` share the same\nversion. The typical semantic versioning rules are used across the public APIs\nof _all_ of these, except for\n[the ones listed as internal](#crates-for-internal-use). The\n[other crates in this workspace](#general-side-products) have their own separate\nversions.\n\nVersions are specified as `MAJOR.MINOR.PATCH`. As long as the `MAJOR` version\nspecifier is still at `0`, changes to the `MINOR` version may also be breaking\nchanges. The `PATCH` part is only incremented if the public API stays fully\ncompatible, with one exception: Changes to the bundled parsers and queries in\nthe parser collections do **not** count as breaking changes. This implies that\nif a parser stops being compatible with one of the collections, it is not\nconsidered a breaking change to remove that parser.\n\n## Inspiration\n\nThe entire idea of this project started out as a way to use tree-sitter code\nhighlighting in a LaTeX project. While working with\n[@MikMuellerDev](https://github.com/MikMuellerDev) on\n[our paper](https://github.com/rush-rs/paper) on [rush](https://rush-lang.de/) I\ncreated a CLI app called [`lirstings`](https://github.com/rush-rs/lirstings).\nThe initial sketch simply called out to the `tree-sitter-cli` and converted the\noutput HTML to LaTeX code. However, not long after that I already implemented\nsome of the logic myself and made a\n[first public commit](https://github.com/rush-rs/lirstings/commit/d2fc87213e8e2d629033f2eba99b2d019883fd43).\nThis version of `lirstings` (called `ts2tex` at the time) already laid out some\ngroundwork like\n[query pre-processing](https://rubixdev.github.io/syntastica/syntastica_query_preprocessor/)\nand [theming](https://rubixdev.github.io/syntastica/syntastica/theme/) that is\nstill present in `syntastica` today. Towards the end of our project we wanted to\nuse the same highlighting on our [rush playground](https://play.rush-lang.de/),\nwhich would require `lirstings` to become more general and support WebAssembly.\nWork on that started in the\n[generalize branch](https://github.com/rush-rs/lirstings/tree/generalize) just\nenough to suffice for our needs at the time.\n\nAfter the entire rush project was done and after taking a break for a while, I\nstarted `syntastica` with the intent to be a library from the ground up, and a\npossible replacement for [`syntect`](https://crates.io/crates/syntect). The main\ndifference from `lirstings` at the start was the parser collection(s), providing\na rigid set of parsers and queries for users. Over time `syntastica` then grew\nto the big project it is today.\n","funding_links":["https://ko-fi.com/rubixdev"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frubixdev%2Fsyntastica","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frubixdev%2Fsyntastica","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frubixdev%2Fsyntastica/lists"}