# 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