# tree-sitter-rstml [![GitHub License](https://img.shields.io/github/license/rayliwell/tree-sitter-rstml?color=purple)](https://github.com/rayliwell/tree-sitter-rstml/blob/main/LICENSE) [![GitHub last commit (branch)](https://img.shields.io/github/last-commit/rayliwell/tree-sitter-rstml/main)](https://github.com/rayliwell/tree-sitter-rstml/commits/main/) [![GitHub Tag](https://img.shields.io/github/v/tag/rayliwell/tree-sitter-rstml?label=version)](https://github.com/rayliwell/tree-sitter-rstml/tags) [![NPM Version](https://img.shields.io/npm/v/tree-sitter-rstml?style=flat&logo=npm&color=blue)](https://www.npmjs.com/package/tree-sitter-rstml) [![Crates.io Version](https://img.shields.io/crates/v/tree-sitter-rstml?logo=rust&color=blue)](https://crates.io/crates/tree-sitter-rstml) [![docs.rs](https://img.shields.io/docsrs/tree-sitter-rust)](https://docs.rs/tree-sitter-rstml/latest/tree_sitter_rstml/) Rust + html grammar for the [tree-sitter](https://github.com/tree-sitter/tree-sitter) parser library. Rust web frameworks, like [Leptos](https://github.com/leptos-rs/leptos), rely on JSX-style templates embedded inside Rust code using the [rstml](https://github.com/rs-tml/rstml) library. This project enables the parsing of those templates for various purposes, such as syntax highlighting in text editors. ## Usage Since rstml isn't a supposed to be a standalone language, there are two grammars defined for convenience:
rstml rust_with_rstml
Language This grammar only parses the rstml template without requiring it to be wrapped in a view! macro invocation. This grammar parses an entire rust source file as normal but will parse any view! macro invocations as a rstml template.
Intended use This is intended to be injected into the tree-sitter-rust grammar. This approach provides the most flexibility by allowing the user to configure what should be interpreted as an rstml macro. In cases where tree-sitter injection is unsupported, this grammar is the best option. The macro invocation behaviour cannot be configured by the user.
Example valid code
<div>Hello, world</div>
view! {
    <div>Hello, world</div>
}
Parser location rstml/src rust_with_rstml/src
Rust binding usage
Show code
let code = "<div>Hello, world</div>";
let mut parser = tree_sitter::Parser::new();
parser.set_language(tree_sitter_rstml::language_rstml()).expect("Error loading rstml grammar");
let tree = parser.parse(code, None).unwrap();
Show code
let code = r#"
    view! {
        <div>hello, world</div>
    }
"#;
let mut parser = tree_sitter::Parser::new();
parser.set_language(tree_sitter_rstml::language_rust_with_rstml()).expect("Error loading rust_with_rstml grammar");
let tree = parser.parse(code, None).unwrap();
JavaScript binding usage
Show code
const Parser = require('tree-sitter')
const code = '<div>Hello, world</div>'
const parser = new Parser()
parser.setLanguage(require('tree-sitter-rstml').rstml)
const tree = parser.parse(code)
Show code
const Parser = require('tree-sitter')
const code = `
    view! {
        <div>Hello, world</div>
    }
`
const parser = new Parser()
parser.setLanguage(require('tree-sitter-rstml').rust_with_rstml)
const tree = parser.parse(code)
## Editor support ### Neovim Neovim's [tree-sitter integration](https://neovim.io/doc/user/treesitter.html) supports syntax highlighting, indentation, and code folding. | Without `rstml` highlighting | With `rstml` highlighting | |---------------------------------------------------|-------------------------------------------------| | ![before](/assets/neovim_before_highlighting.png) | ![after](/assets/neovim_after_highlighting.png) | To use the Neovim support with [nvim-treesitter](https://github.com/nvim-treesitter/nvim-treesitter), you should: - Ensure `"nvim-treesitter/nvim-treesitter"` is installed and configured correctly. - Install the `"rayliwell/tree-sitter-rstml"` plugin in your preferred package manager. - Ensure `require("tree-sitter-rstml").setup()` is ran after every time `nvim-treesitter` is loaded. Here's an example config using [lazy.nvim](https://github.com/folke/lazy.nvim): ```lua require("lazy").setup({ { "nvim-treesitter/nvim-treesitter", build = ":TSUpdate", config = function () local configs = require("nvim-treesitter.configs") configs.setup({ ensure_installed = { "c", "lua", "vim", "vimdoc", "query", "rust" }, sync_install = false, highlight = { enable = true }, indent = { enable = true }, }) end }, { "rayliwell/tree-sitter-rstml", dependencies = { "nvim-treesitter" }, build = ":TSUpdate", config = function () require("tree-sitter-rstml").setup() end }, -- Experimental automatic tag closing and renaming (optional) { "rayliwell/nvim-ts-autotag", config = function() require("nvim-ts-autotag").setup() end, }, }) ``` > [!NOTE] > Neovim support is intended to work on the latest Neovim release and version of `nvim-treesitter`. If you are using a Neovim distribution, like LunarVim, support is not guarenteed. ### NixVim (Advanced) To use the [NixVim](https://github.com/nix-community/nixvim) integration with flakes, you should: - Add `github:rayliwell/tree-sitter-rstml` as a flake input. - Import `inputs.tree-sitter-rstml.nixvimModule` inside of your NixVim configuration. For example: ```nix { description = "NixVim configuration with tree-sitter-rstml."; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; nixvim.url = "github:nix-community/nixvim"; tree-sitter-rstml.url = "github:rayliwell/tree-sitter-rstml/flake"; }; outputs = { system, nixpkgs, nixvim, tree-sitter-rstml, ... }: let forAllSystems = function: nixpkgs.lib.genAttrs [ "aarch64-darwin" "aarch64-linux" "x86_64-darwin" "x86_64-linux" ] (system: function nixpkgs.legacyPackages.${system}); in { packages = forAllSystems (pkgs: { default = nixvim.legacyPackages.${system}.makeNixvimWithModule { inherit pkgs; module = { imports = [ tree-sitter-rstml.nixvimModule ]; }; }; }); }; } ``` ### Emacs Emacs' (29.1+) [tree-sitter integration](https://www.masteringemacs.org/article/how-to-get-started-tree-sitter) supports syntax highlighting and indentation. | **Before (`rust-ts-mode`)** | **After (`rstml-ts-mode`)** | |--------------------------------------------------|------------------------------------------------| | ![before](/assets/emacs_before_highlighting.png) | ![after](/assets/emacs_after_highlighting.png) | Emacs support is provided by the `rstml-ts-mode` package. **You can read more on the project's [GitHub](https://github.com/rayliwell/rstml-ts-mode).** ## Acknowledgements This project extends and heavily relies upon the [tree-sitter-rust](https://github.com/tree-sitter/tree-sitter-rust) grammar. It would not be possible without its [contributors](https://github.com/tree-sitter/tree-sitter-rust/graphs/contributors), as well as those who have [contributed](https://github.com/tree-sitter/tree-sitter/graphs/contributors) to the wider tree-sitter ecosystem. Additionally, this project is based on the work of the [rstml](https://github.com/rs-tml/rstml) library. Originating as a fork of [syn-rsx](https://github.com/stoically/syn-rsx), whose creator, unfortunately, has [passed away](https://github.com/stoically/temporary-containers/issues/618). ## License Licensed under the [MIT License](https://mit-license.org/). Copyright © 2024 Ryan Halliwell