Add code navigation for multiple languages in Vi/Vim/Neovim.
Leverages tree-sitter to fulfill the goal of supporting multiple programming languages with minimal effort without sacrificing maintainability or performance.
To get a brief overview of what treetags does and how it compares to Universal ctags see here.
Support for these languages is available out of the box in treetags
Refer to Universal ctags documentation for more about extension fields.
Treetags functionality can be extended via WASM plugins. WASM plugins are functionally equivalent to native tag generators, except they are not installed by default and they can be updated independently of treetags releases.
Treetags has support for these languages via user installable WASM plugins.
Use --suggest-plugins CLI arg to find plugin that may be of interest to you
treetags --suggest-plugins
Plugins available for file types in your tree:
PLUGIN HANDLES TYPE INSTALL WITH
kotlin *.kt adds support treetags plugin install kotlin
No plugin available for unsupported types: *.0, *.1, *.2, *.a, *.bin, *.cache, *.d, *.db, *.db-shm, *.db-wal, *.dylib, *.echo, *.gleam, *.history, *.idx, *.isle, *.json, *.ll, *.lock, *.md, *.o, *.pack, *.plist, *.qc, *.rev, *.rlib, *.rmeta, *.scm, *.timestamp, *.tmp, *.toml, *.txt, *.wasm, *.wit, *.yml
List of all plugin management commands
treetags plugin available # List all known compatible plugins
treetags plugin installed # List all installed plugins
treetags plugin install <NAME> # Fetch and install <NAME> plugin
treetags plugin uninstall <NAME> # Un-install <NAME> plugin
treetags plugin update # Update all installed plugins
treetags plugin help # Print `treetags plugin` usage help
See here for more information on plugin implementation details.
Users need to provide two things for treetags to be able to generate tags for languages that do not have a builtin grammar supplied.
[[user_grammars]] toml array of the treetags config fileAn example config for Kotlin language located at the defualt location of ~/.config/treetags/config.toml
is shown below:
[[user_grammars]]
language_name = "kotlin"
grammar_lib_path = "/home/naman/.local/share/nvim/lazy/nvim-treesitter/parser/kotlin.so"
query_file_path = "/home/naman/.config/treetags/queries/kotlin.scm"
extensions = ["kt", "kts"]
Some languages have tags query and extensions built-in into treetags. Users only
need to provide the tree-sitter grammar in that case for treetags to be able to
generate tags for that language. Leave the query_file_path empty for these
languages to use the tags queries provided with treetags.
There are three prerequisites to build treetags
Install Rust and C developmet toolchains on your system
Add wasm32-wasip2 target for rustc
rustup target add wasm32-wasip2
binCC environment varaible.export WASI_SDK_PATH=/home/username/play/wasi-sdk-30.0-arm64-linux
export binCC="${WASI_SDK_PATH}/bin/clang --sysroot=${WASI_SDK_PATH}/share/wasi-sysroot"
Building treetags once development setup is complete:
cargo build --release
cp target/release/treetags /somewhere/in/the/PATH/
While it is fine to manually invoke treetags to generate tags file for a project,
the recommended way is to use the gutentags
plugin to manage the tags file. There is a nice write-up on setting up gutentags
here,
which can be useful for setting things up.
You will have to configure gutentags to use treetags as the tags generator at
a minimum in your vim/nvim configuration file.
let g:gutentags_ctags_executable = 'treetags'
Or, if you are using lua for configuration
vim.g.gutentags_ctags_executable = 'treetags'
Users can generate completions like:
# refer to your shell documentation for determining the correct path for autcomplete files
treetags completions bash > ~/.local/share/bash-completion/completions/treetags
treetags completions zsh > ~/.local/share/zsh/site-functions/_treetags
treetags completions fish > ~/.config/fish/completions/treetags.fish
Integration tests are built from test cases on demand
cargo build # Generates test files
cargo test # Runs all tests including generated ones
Use the --help option to see supported command line arguments.
$ target/release/treetags --help
Generate vi compatible tags for multiple languages
Usage: treetags [OPTIONS] [FILE_NAMES]...
Arguments:
[FILE_NAMES]... List of file names to be processed when `--append` option is passed
Options:
... # Options omitted for brevity
For each input file, treetags picks a language in this order:
--language-force=<lang> — if given, every file is parsed as <lang>
(accepts a language name or alias; auto disables it).Rakefile,
Gemfile, .bashrc, or *.gemspec. This matches files that have no
distinguishing extension..rs, .py, .rb. Some extensions map to more
than one language: .h may be C or C++, and treetags disambiguates by
scanning the file for C++ signals (class, namespace, ::, …), defaulting
to C when there are none.#! shebang line — when the name gives no match, the interpreter
(python3, bash, ruby, …) selects the language. To keep things cheap,
this runs only for files with the executable bit set, unless you pass
--guess-language-eagerly / -G, which enables it for every file. (On
platforms without an executable bit, shebang detection requires -G.)-G, treetags reads Vim
modelines (vim: set ft=python:) and Emacs modelines (-*- mode: python -*-
and trailing Local Variables: blocks) from the file's head and tail.Run treetags --print-language <files...> to see which language each file
resolves to (or NONE) without generating tags.
You can override which extensions and filename patterns map to a language (syntax mirrors Universal Ctags):
--map-<LANG>=[+|-]<item> — add (+, the default) or remove (-) a single
matcher. <item> is one of:
.ext — a file extension (e.g. --map-c=.qc)(pattern) — an fnmatch glob on the basename (e.g. --map-ruby=(Jarfile))%regex% — a regular expression matched against the whole relative path
(directory components included), so it can express things a basename glob
can't (e.g. --map-c++=%include/.*\.h% treats headers under include/ as
C++). Append i or {icase} for case-insensitivity (%…%i), and escape a
literal % as \%.Repeatable. Regexes take precedence over patterns, which take precedence over
extensions. Examples: --map-c=.qc, --map-c=-.h, --map-ruby=(Jarfile).
--langmap=<LANG>:<spec>[,<LANG>:<spec>...] — bulk form. <spec> is a run of
.ext and (pattern) tokens (e.g. .c.h or (Makefile).mak). A leading +
on the spec appends; otherwise it replaces the language's mappings.
(Regexes are only available via --map-<LANG>, matching ctags.)
--list-maps[=<LANG>] — print the effective extensions and patterns for every
language (or just <LANG>) and exit.
Treetags creates a tags file that vim can use for allowing the user to easily navigate their source code files.
We can quote vim help files to get an idea of what a tag and a tags file are:
What is a tag? It is a location where an identifier is defined. An example is a function definition in a C or C++ program. A list of tags is kept in a tags file. This can be used by Vim to directly jump from any place to the tag, the place where an identifier is defined.
To get a full overview of tags related functionality backed into vim/neovim one
can use :help tagsrch in vim or refer to the online docs
This is similar to what Universal ctags and other verions of ctags do. The ctags versions are much more mature and battle tested than treetags. Universal ctags in particular also has support for many more languages and is actively maintained.
Treetags differs from these in two ways technically. First is that it uses tree-sitter for parsing code. Second is that treetags is multithreaded and can parse multiple files simultaneously. Another important difference is that treetags is primarily maintained by a single person.
Refer to this issue to see how tags compare to LSP.
Rust
82.4%
C++
4.3%
Kotlin
3.9%
Gleam
3.0%
C
2.7%
Shell
1.0%
Add code navigation for multiple languages in Vi/Vim/Neovim.
Leverages tree-sitter to fulfill the goal of supporting multiple programming languages with minimal effort without sacrificing maintainability or performance.
To get a brief overview of what treetags does and how it compares to Universal ctags see here.
Support for these languages is available out of the box in treetags
Refer to Universal ctags documentation for more about extension fields.
Treetags functionality can be extended via WASM plugins. WASM plugins are functionally equivalent to native tag generators, except they are not installed by default and they can be updated independently of treetags releases.
Treetags has support for these languages via user installable WASM plugins.
Use --suggest-plugins CLI arg to find plugin that may be of interest to you
treetags --suggest-plugins
Plugins available for file types in your tree:
PLUGIN HANDLES TYPE INSTALL WITH
kotlin *.kt adds support treetags plugin install kotlin
No plugin available for unsupported types: *.0, *.1, *.2, *.a, *.bin, *.cache, *.d, *.db, *.db-shm, *.db-wal, *.dylib, *.echo, *.gleam, *.history, *.idx, *.isle, *.json, *.ll, *.lock, *.md, *.o, *.pack, *.plist, *.qc, *.rev, *.rlib, *.rmeta, *.scm, *.timestamp, *.tmp, *.toml, *.txt, *.wasm, *.wit, *.yml
List of all plugin management commands
treetags plugin available # List all known compatible plugins
treetags plugin installed # List all installed plugins
treetags plugin install <NAME> # Fetch and install <NAME> plugin
treetags plugin uninstall <NAME> # Un-install <NAME> plugin
treetags plugin update # Update all installed plugins
treetags plugin help # Print `treetags plugin` usage help
See here for more information on plugin implementation details.
Users need to provide two things for treetags to be able to generate tags for languages that do not have a builtin grammar supplied.
[[user_grammars]] toml array of the treetags config fileAn example config for Kotlin language located at the defualt location of ~/.config/treetags/config.toml
is shown below:
[[user_grammars]]
language_name = "kotlin"
grammar_lib_path = "/home/naman/.local/share/nvim/lazy/nvim-treesitter/parser/kotlin.so"
query_file_path = "/home/naman/.config/treetags/queries/kotlin.scm"
extensions = ["kt", "kts"]
Some languages have tags query and extensions built-in into treetags. Users only
need to provide the tree-sitter grammar in that case for treetags to be able to
generate tags for that language. Leave the query_file_path empty for these
languages to use the tags queries provided with treetags.
There are three prerequisites to build treetags
Install Rust and C developmet toolchains on your system
Add wasm32-wasip2 target for rustc
rustup target add wasm32-wasip2
binCC environment varaible.export WASI_SDK_PATH=/home/username/play/wasi-sdk-30.0-arm64-linux
export binCC="${WASI_SDK_PATH}/bin/clang --sysroot=${WASI_SDK_PATH}/share/wasi-sysroot"
Building treetags once development setup is complete:
cargo build --release
cp target/release/treetags /somewhere/in/the/PATH/
While it is fine to manually invoke treetags to generate tags file for a project,
the recommended way is to use the gutentags
plugin to manage the tags file. There is a nice write-up on setting up gutentags
here,
which can be useful for setting things up.
You will have to configure gutentags to use treetags as the tags generator at
a minimum in your vim/nvim configuration file.
let g:gutentags_ctags_executable = 'treetags'
Or, if you are using lua for configuration
vim.g.gutentags_ctags_executable = 'treetags'
Users can generate completions like:
# refer to your shell documentation for determining the correct path for autcomplete files
treetags completions bash > ~/.local/share/bash-completion/completions/treetags
treetags completions zsh > ~/.local/share/zsh/site-functions/_treetags
treetags completions fish > ~/.config/fish/completions/treetags.fish
Integration tests are built from test cases on demand
cargo build # Generates test files
cargo test # Runs all tests including generated ones
Use the --help option to see supported command line arguments.
$ target/release/treetags --help
Generate vi compatible tags for multiple languages
Usage: treetags [OPTIONS] [FILE_NAMES]...
Arguments:
[FILE_NAMES]... List of file names to be processed when `--append` option is passed
Options:
... # Options omitted for brevity
For each input file, treetags picks a language in this order:
--language-force=<lang> — if given, every file is parsed as <lang>
(accepts a language name or alias; auto disables it).Rakefile,
Gemfile, .bashrc, or *.gemspec. This matches files that have no
distinguishing extension..rs, .py, .rb. Some extensions map to more
than one language: .h may be C or C++, and treetags disambiguates by
scanning the file for C++ signals (class, namespace, ::, …), defaulting
to C when there are none.#! shebang line — when the name gives no match, the interpreter
(python3, bash, ruby, …) selects the language. To keep things cheap,
this runs only for files with the executable bit set, unless you pass
--guess-language-eagerly / -G, which enables it for every file. (On
platforms without an executable bit, shebang detection requires -G.)-G, treetags reads Vim
modelines (vim: set ft=python:) and Emacs modelines (-*- mode: python -*-
and trailing Local Variables: blocks) from the file's head and tail.Run treetags --print-language <files...> to see which language each file
resolves to (or NONE) without generating tags.
You can override which extensions and filename patterns map to a language (syntax mirrors Universal Ctags):
--map-<LANG>=[+|-]<item> — add (+, the default) or remove (-) a single
matcher. <item> is one of:
.ext — a file extension (e.g. --map-c=.qc)(pattern) — an fnmatch glob on the basename (e.g. --map-ruby=(Jarfile))%regex% — a regular expression matched against the whole relative path
(directory components included), so it can express things a basename glob
can't (e.g. --map-c++=%include/.*\.h% treats headers under include/ as
C++). Append i or {icase} for case-insensitivity (%…%i), and escape a
literal % as \%.Repeatable. Regexes take precedence over patterns, which take precedence over
extensions. Examples: --map-c=.qc, --map-c=-.h, --map-ruby=(Jarfile).
--langmap=<LANG>:<spec>[,<LANG>:<spec>...] — bulk form. <spec> is a run of
.ext and (pattern) tokens (e.g. .c.h or (Makefile).mak). A leading +
on the spec appends; otherwise it replaces the language's mappings.
(Regexes are only available via --map-<LANG>, matching ctags.)
--list-maps[=<LANG>] — print the effective extensions and patterns for every
language (or just <LANG>) and exit.
Treetags creates a tags file that vim can use for allowing the user to easily navigate their source code files.
We can quote vim help files to get an idea of what a tag and a tags file are:
What is a tag? It is a location where an identifier is defined. An example is a function definition in a C or C++ program. A list of tags is kept in a tags file. This can be used by Vim to directly jump from any place to the tag, the place where an identifier is defined.
To get a full overview of tags related functionality backed into vim/neovim one
can use :help tagsrch in vim or refer to the online docs
This is similar to what Universal ctags and other verions of ctags do. The ctags versions are much more mature and battle tested than treetags. Universal ctags in particular also has support for many more languages and is actively maintained.
Treetags differs from these in two ways technically. First is that it uses tree-sitter for parsing code. Second is that treetags is multithreaded and can parse multiple files simultaneously. Another important difference is that treetags is primarily maintained by a single person.
Refer to this issue to see how tags compare to LSP.
Rust
82.4%
C++
4.3%
Kotlin
3.9%
Gleam
3.0%
C
2.7%
Shell
1.0%