Technical Documentation: cordx56/rustowl
โน๏ธ Provenance: Multi-Tier Ingestion ยท CodeWiki Reference
Overview (`README.md`)
RustOwl visualizes ownership movement and lifetimes of variables.
When you save Rust source code, it is analyzed, and the ownership and lifetimes of variables are visualized when you hover over a variable or function call.
RustOwl visualizes those by using underlines:
- ๐ฉ green: variable's lifetime
- definitely live: the variable is provably initialized on every path reaching this point
- maybe live (wavy): the variable is initialized on some paths but may have been moved, dropped, or be uninitialized on others
- ๐ฆ blue: immutable borrowing
- ๐ช purple: mutable borrowing
- ๐ง orange: value moved / function call
- ๐ฅ red: lifetime error
- Diff of lifetime between actual and expected, or
- Invalid overlapped lifetime of mutable and shared (immutable) references
Detailed usage is described here.
Currently, we offer VSCode extension, Neovim plugin and Emacs package.
For these editors, move the text cursor over the variable or function call you want to inspect and wait for 2 seconds to visualize the information.
We implemented LSP server with an extended protocol.
So, RustOwl can be used easily from other editor.
Table Of Contents
Support
If you're looking for support, please consider checking all issues, existing discussions, and starting a discussion first!
Also, you can reach out to us on the Discord server provided above.
Quick Start
Here we describe how to start using RustOwl.
Prerequisite
cargoinstalled- You can install
cargousingrustupfrom this link.
- You can install
- Visual Studio Code (VS Code) installed
We tested this guide on macOS Sequoia 15.3.2 on arm64 architecture with VS Code 1.99.3 and cargo 1.90.0.
VS Code
You can install VS Code extension from this link.
RustOwl will be installed automatically when the extension is activated.
For more detailed configuration options, see the VS Code Configuration Guide.
Vscodium
You can install Vscodium extension from this link.
RustOwl will be installed automatically when the extension is activated.
After installation, the extension will automatically run RustOwl when you save any Rust program in cargo workspace.
The initial analysis may take some time, but from the second run onward, compile caching is used to reduce the analysis time.
Same as VS Code, see the VS Code Configuration Guide for more detailed configuration options.
Other editor support
We support Neovim and Emacs.
You have to install RustOwl before using RustOwl with other editors.
You can also create your own LSP client.
If you would like to implement a client, please refer to the The RustOwl LSP specification.
Neovim
Minimal setup with lazy.nvim:
{
'cordx56/rustowl',
version = '*', -- Latest stable version
build = 'cargo install rustowl',
lazy = false, -- This plugin is already lazy
opts = {},
}For comprehensive configuration options including custom highlight colors, see the Neovim Configuration Guide.
Emacs
Elpaca example:
(elpaca
(rustowl
:host github
:repo "cordx56/rustowl"))Then use-package:
(use-package rustowl
:after lsp-mode)You have to install RustOwl LSP server manually.
For more detailed configuration options, see the Emacs Configuration Guide.
RustRover / IntelliJ IDEs
There is a third-party repository that supports IntelliJ IDEs.
You have to install RustOwl LSP server manually.
Sublime Text
There is a third-party repository that supports Sublime Text.
Installation
Please see Installation for detailed installation instructions.
Usage
Please see Usage for detailed usage instructions.
Note
We support the 5 latest versions of Rust (best effort).
In this tool, due to the limitations of VS Code's decoration specifications, characters with descenders, such as g or parentheses, may occasionally not display underlines properly.
Additionally, we observed that the println! macro sometimes produces extra output, though this does not affect usability in any significant way.
Overview (`scripts/README.md`)
RustOwl Scripts
This directory contains utility scripts for local development and testing that complement the CI workflows.
Quick Start
# Run development checks
./scripts/dev-checks.sh
# Check binary size changes
./scripts/size-check.sh
# Run security and memory safety tests
./scripts/security.sh
# Run performance benchmarks
./scripts/bench.sh
# Run Neovim Tests
./scripts/run_nvim_tests.shScript Overview
`dev-checks.sh`
Runs comprehensive development checks including formatting, linting, and tests.
Features:
- Code formatting checks (
cargo fmt) - Linting with Clippy
- Unit tests
- Integration tests
- Documentation tests
`size-check.sh`
Analyzes binary size changes to detect bloat and track optimization efforts.
Features:
- Binary size comparison
- Dependency analysis
- Size regression detection
๐ก๏ธ `security.sh`
Comprehensive security and memory safety testing framework.
Features:
- Multi-tool testing (Miri, Valgrind, ThreadSanitizer, cargo-deny, cargo-shear, Instruments)
- Cross-platform support (Linux, macOS, ARM64)
- Graceful degradation when tools unavailable
- Configurable test categories
- Color-coded output with progress indicators
Usage:
# Run all applicable tests for the current platform
./scripts/security.sh
# Run specific test categories
./scripts/security.sh --no-miri
./scripts/security.sh --no-valgrind
./scripts/security.sh --no-audit
# ThreadSanitizer is opt-in: it instruments every build, so it is slow
./scripts/security.sh --thread-sanitizer
# Check available tools and configuration
./scripts/security.sh --checkPlatform notes:
- On Linux, Instruments is disabled and Valgrind covers memory errors.
- On macOS, Valgrind is disabled and a Time Profiler trace is captured with
xcrun xctraceinstead. The trace is written asinstruments_output_<timestamp>.trace, which CI uploads as an artifact when
the run fails. - ThreadSanitizer requires a nightly toolchain and is opt-in on any platform
via--thread-sanitizer. CI exercises it in a dedicated Linux job. It needsrust-src, because-Zsanitizerchanges the
crate ABI and therefore requires-Zbuild-stdto rebuildcoreandcompiler_builtinswith the same flag โ without it rustc fails with
"mixing-Zsanitizerwill cause an ABI mismatch". - Findings matching
.tsan-suppressionsare
suppressed. They are not real races: any program building a multi-threaded
tokio runtime reproduces them when the synchronisation sits insideOnceLock/Mutexor is driven through epoll, and tokio's own suite is clean
under-Zbuild-std. The file records the evidence and what would make each
entry safe to remove. - The instrumented build and the instrumented run are two separate steps. An
aborted run produces zero ThreadSanitizer warnings and would otherwise be
indistinguishable from a clean one, so a failed build fails the suite rather
than reporting "no races detected". - The run is bounded at 300s, because a TSan run does not always converge โ
tokio'stest_tuninginrt_threaded.rshas to be killed after ~27 minutes
under the sanitizer. cargo-shearruns on both Linux and macOS.- In CI, missing tools are installed automatically unless you pass
--no-auto-install, which is honoured even though CI detection would
otherwise enable installation.
Dependency policy: `cargo-deny`
cargo-deny checks the
dependency graph for known advisories, disallowed licences, banned crates and
unexpected sources. Its rules live in deny.toml at the repo
root; cargo deny check must pass locally before pushing.
cargo deny check # all four checks
cargo deny check advisories # just the vulnerability checkCI runs this in a separate job viaEmbarkStudios/cargo-deny-action,
so security.sh is invoked there with --no-audit to avoid resolving the full
graph three times across the OS matrix.
Notes on the current configuration:
multiple-versionsis a warning: duplicate versions are normal in a real
graph and unifying them is rarely worth the churn.- MPL-2.0 is not in the blanket allow list.
rustowlis MPL-2.0, and it is
permitted by name, so adding another MPL-2.0 dependency has to be a deliberate
edit rather than an accident. - Other per-crate exceptions exist for
r-efi(LGPL-2.1-or-later),webpki-root-certs(CDLA-Permissive-2.0) andlibbz2-rs-sys
(bzip2-1.0.6), each with a comment explaining why.
Unused dependencies: `cargo-shear`
cargo-shear replaces cargo-machete.security.sh runs it with --check-test-targets, so a dependency used only
from a test target is not reported as unused.
cargo shear --check-test-targets๐ `bench.sh`
Local performance benchmarking with regression detection.
Features:
- Criterion benchmark integration
- Baseline creation and comparison
- Automatic test package detection
- Configurable regression thresholds
- HTML report generation
- Local development focus
Usage:
# Standard benchmark run
./scripts/bench.sh
# Create and compare baselines
./scripts/bench.sh --save my-baseline
./scripts/bench.sh --load my-baseline --threshold 3%
# Development workflow
./scripts/bench.sh --clean --open --test-package ./examplesNote: Benchmarks are designed for local development only. CI environments introduce too much variability for reliable performance measurement.
`run_nvim_tests.sh`
Run tests defined in nvim-tests directory.
Usage
./scripts/run_nvim_tests.shIn uses [mini.test](https://github.com/echasnovski/mini.test) plugin to test.
Prerequisites
Common Requirements
- Rust toolchain (automatically managed via
rust-toolchain.toml) - Basic build tools
- Neovim (Only For The Tests And If You Are Changing Neovim Specific Things)
Platform-Specific Tools
Linux
sudo apt-get update
sudo apt-get install -y valgrind gnuplot build-essentialmacOS
brew install gnuplot
# Optional: brew install valgrind (limited support)Integration with CI
These scripts are designed to complement CI workflows where applicable:
security.shโ.github/workflows/security.yml: Same security analysis tools
Note: Benchmarking (bench.sh) is intentionally local-only due to CI environment variability.
GitHub Actions Integration
The scripts integrate with workflows where appropriate:
Security Workflows
security.yml: Runs comprehensive security testing across platforms
Development Scripts
bench.sh: Local-only performance testing (not suitable for CI)dev-checks.sh: Can be used in CI for code quality checks
Development Workflow
Before Committing
# Run all development checks
./scripts/dev-checks.sh
# Run security tests
./scripts/security.sh
# Check performance impact (local only)
./scripts/bench.sh
# Check binary size impact
./scripts/size-check.sh
# If you changed any neovim specific things (like lua files)
./scripts/run_nvim_tests.shSetting Up New Environment
For setting up a development environment, ensure you have the platform-specific tools listed in the Prerequisites section above.
Troubleshooting
Script Permissions
chmod +x scripts/*.shMissing Tools
Run the setup script or check platform-specific installation commands above.
CI Failures
- Check workflow logs for specific error messages
- Verify
rust-toolchain.tomlcompatibility - Ensure scripts have execution permissions
- Test locally with the same script used in CI
Script Architecture
All scripts follow common patterns:
- Color-coded output with emoji indicators
- Progressive enhancement based on available tools
- Comprehensive help text with examples
- Error handling with remediation suggestions
- Cross-platform compatibility with platform-specific optimizations
Shared code
lib/common.sh holds everything the in-repo scripts have in common: the colour
constants and log_* helpers, the NixOS nix-ld path setup, have_cmd /require_cmd, print_host_tuple, the rustc version gate, and the integer
percentage helpers. Scripts source it as lib/common.sh relative to their own
directory:
SCRIPT_DIR="$(CDPATH='' cd -- "$(dirname "$0")" && pwd)"
. "$SCRIPT_DIR/lib/common.sh"The library is POSIX sh โ no [[ ]], no arrays, no echo -e โ becausetoolchain sources it and runs under dash and busybox-ash in CI. It also has no
side effects at source time.
installer is the one exception. It is piped into sh from a URL and so has
to stay self-contained; it keeps its own copy of print_host_tuple.
Overview (`vscode/README.md`)
RustOwl VSCode
This is RustOwl extension for VSCode. It will download the binaries and will do toolchain setup automatically.
Configuring RustOwl
For detail, refer to the vscode configuration guide.
Overview (`crates/rustowl/perf-tests/dummy-package/README.md`)
RustOwl Performance Test Dummy Package
This is a dummy Rust package specifically designed for performance testing with RustOwl. The package contains various Rust patterns and constructs that RustOwl can analyze, including:
Features Tested
Ownership and Borrowing Issues
- Methods returning references to internal data
- Potential lifetime issues
- Clone operations that might be unnecessary
Error Handling Patterns
- Use of
unwrap()that might panic - Proper error handling with
ResultandContext - Missing error propagation
Resource Management
- File handling and potential resource leaks
- Thread safety and potential deadlocks
- Memory allocation patterns
Async/Concurrency Patterns
- Async operations with tokio
- Thread-based parallel processing
- Shared state with
Arc<Mutex<T>>
Performance Patterns
- Memory-intensive operations
- CPU-intensive computations
- I/O operations
Usage
The dummy package can be built and run to provide realistic workload for RustOwl analysis:
cargo build --release
cargo run -- --helpOperations
The dummy application supports several operations:
data- Run data structure operations with potential ownership issuesnetwork- Run network operations (may fail without internet)files- Run file I/O operationscompute- Run CPU-intensive computationsall- Run all operations
Performance Testing
This package is used by the RustOwl performance testing script (perf-tests.sh) to provide a consistent, realistic codebase for performance analysis.
The code intentionally contains patterns that RustOwl can analyze and potentially flag, making it an ideal test case for measuring RustOwl's analysis performance on real-world-like Rust code.
Testing Modes
The performance testing script supports different analysis modes:
- Default Mode: Fast analysis with current target and default features
- Comprehensive Mode: Thorough analysis with
--all-targets --all-features
The package includes multiple targets (main binary, examples, tests) and conditional features to enable comprehensive testing of RustOwl's analysis capabilities across different code paths and compilation scenarios.
CODE OF CONDUCT (`docs/CODE_OF_CONDUCT.md`)
Contributor Covenant Code of Conduct
Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience - Focusing on what is best not just for us as individuals, but for the overall
community
Examples of unacceptable behavior include:
- The use of sexualized language or imagery, and sexual attention or advances of
any kind - Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or email address,
without their explicit permission - Other conduct which could reasonably be considered inappropriate in a
professional setting
Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official email address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
[email protected].
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
1. Correction
Community Impact: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
Consequence: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
2. Warning
Community Impact: A violation through a single incident or series of
actions.
Consequence: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or permanent
ban.
3. Temporary Ban
Community Impact: A serious violation of community standards, including
sustained inappropriate behavior.
Consequence: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
4. Permanent Ban
Community Impact: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
Consequence: A permanent ban from any sort of public interaction within the
community.
Attribution
This Code of Conduct is adapted from the Contributor Covenant,
version 2.1, available at
https://www.contributor-covenant.org/version/2/1/code_of_conduct.html.
Community Impact Guidelines were inspired by
Mozilla's code of conduct enforcement ladder.
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.
CONTRIBUTING (`docs/CONTRIBUTING.md`)
Contribution guide
This document is under construction.
Thank you for considering to contribute RustOwl!
In this document we describe how to contribute our project, as follows:
- How to setup development environment
- Checklist before submitting PR
Table of Contents
Set up your environment
Prerequisites
Common Requirements
- Rust toolchain (automatically managed via
rust-toolchain.toml) - Basic build tools
Platform-Specific Tools
Linux
sudo apt-get update
sudo apt-get install -y valgrind bc gnuplot build-essential # For Rustowl Itself
sudo apt-get install -y neovim # Optional: Install Neovim for neovim plugin development
sudo apt-get install -y emacs # Optional: Install Emacs for emacs plugin development
# Install Visual Studio Code as in their documentationmacOS
brew install gnuplot
# Optional: brew install valgrind (limited support)
brew install neovim # Optional: Install Neovim for neovim plugin development
brew install emacs # Optional: Install Emacs for emacs plugin development
# Install Visual Studio Code as in their documentationRust code
In the Rust code, we utilize nightly compiler features, which require some tweaks.
Before starting this section, you might be required to install rustup since our project requires nightly compiler.
Our project uses rust-toolchain.toml to automatically manage the correct Rust version.
Build and test using the nightly environment
For building, testing, or installing, you can do the same as any common Rust project using the cargo command.
Build with stable Rust compiler
To distribute release binary, we use stable Rust compiler to ship RustOwl with stable Rust compiler for users.
The executable binary named rustowlc, which is one of the components of RustOwl, behaves like a Rust compiler.
So we would like to compile rustowlc, which uses nightly features, with the stable Rust compiler.
[!NOTE]
Using this method is strongly discouraged officially. See Unstable Book.
To compile rustowlc with stable compiler, you should set environment variable as RUSTC_BOOTSTRAP=1.
Our script automates most of the work, so to build with the toolchain specified in channel file:
./scripts/build/toolchain cargo build --releaseTo do it manually:
# 1.89.0 can be any version
RUSTC_BOOTSTRAP=1 rustup +1.89.0 run cargo build --releaseAs new Rust versions release, their APIs change. Thus, RustOwl code also changes. You might see errors if the version is newer. We strive to make the code in the main branch compatible with the latest Rust version, which is specified in the channel file.
Note that by using normal cargo command RustOwl will be built with nightly compiler since there is a rust-toolchain.toml which specifies nightly compiler for development environment.
VS Code extension
For VS Code extension, we use pnpm to setup environment.
To get started, you have to install dependencies by running following command inside vscode directory:
pnpm installNeovim Plugin
You need to install stylua and selene for code formatting and linting.
Now write your code, see lua, ftplugin, nvim-tests.
Please write a test using mini.test before submitting a pr, you can run tests using run_nvim_tests.sh.
Emacs Plugin
You need to install eask for code formatting, linting, testing and whatnot.
Now write your code, see rustowl.el and emacs-tests.
Please write a test using ERT before submitting a pr, you can run tests using eask script run test. (needs eask)
Before submitting PR
Before submitting PR, you have to check below:
Development Checks
Use the helper scripts in ./scripts to run development checks and fixes. Examples:
# Run all development checks
./scripts/dev-checks.sh
# Run checks and automatically fix issues where possible
./scripts/dev-checks.sh --fixRefer to individual scripts for details (security, benchmarking, size checks). For CI-consistent runs, prefer the scripts above instead of invoking tools manually.
Security and Memory Safety Testing
Use ./scripts/security.sh to run the available security and UB detection tools. See the script for options to skip Miri/Valgrind/audit steps.
Performance Testing
Use ./scripts/bench.sh to run performance benchmarks. Create and compare baselines using the script's flags.
Binary Size Monitoring
Use ./scripts/size-check.sh to analyze and compare binary sizes. Save/Load baselines via the script flags.
Manual Checks
If the automated scripts are not available, ensure:
Rust code correctness and formatting
- Correctly formatted by
cargo fmt - Linted using Clippy by
cargo clippy - All tests pass with
cargo test
VS Code extension Style
- Correctly formatted by
pnpm fmt - Linting passes with
pnpm lint - Type checking passes with
pnpm check-types
Neovim Plugin Checks
- Correctly formatted by
stylua - Linting passes with
selene - Tests passing with
mini.test
Development Workflow
Recommended Development Process
Before making changes:
bash# Create performance baseline ./scripts/bench.sh --save before-changesDuring development:
bash# Run quick checks frequently ./scripts/dev-checks.sh --fixBefore committing:
bash# For Rust Code ./scripts/dev-checks.sh ./scripts/security.sh ./scripts/bench.sh --load before-changes ./scripts/size-check.sh # For Neovim ./scripts/run_nvim_tests.sh stylua . selene . # For Emacs eask script run test eask script run format eask lint <linter>
Troubleshooting
Script Permissions
chmod +x scripts/*.shMissing Tools
Install the required tools manually using the platform-specific commands in the Prerequisites section above.
CI Failures
- Check workflow logs for specific error messages
- Verify
rust-toolchain.tomlcompatibility - Ensure scripts have execution permissions
- Test locally with the same script used in CI
For more detailed information about the scripts, see scripts/README.md.
SECURITY (`docs/SECURITY.md`)
Security Reporting
If you wish to report a security vulnerability but not in a public issue -- thank you! -- we ask that you follow the following process.
Please report security vulnerabilities by filling out the following template:
- PUBLIC: Please let us know if this vulnerability has been made or discussed publicly already, and if so, please let us know where.
- DESCRIPTION: Please provide precise description of the security vulnerability you have found with as much information as you are able and willing to provide.
Please send the above info, along with any other information you feel is pertinent to: [email protected].
In addition, you may request that the project provide you a patched release in advance of the release announcement, however, we can not guarantee that such information will be provided to you in advance of the public release and announcement.
However, I will email you at the same time the public announcement is made.
We will let you know within a few weeks whether or not your report has been accepted or rejected.
We ask that you please keep the report confidential until we have made a public announcement.
Build (`docs/build.md`)
Build guide
Here we describe how to build each of our repository.
RustOwl
You can choose one of two ways to build RustOwl.
You can add runtime directory paths to the search paths by specifying the RUSTOWL_RUNTIME_DIRS or RUSTOWL_SYSROOTS environment variables.
The default runtime directory is $HOME/.rustowl.
On a freshly installed Ubuntu system, you need to run apt install build-essential to ensure all required build tools are available for linking.
Build RustOwl using stable toolchain
There are scripts to build the stable version of RustOwl.scripts/toolchain sets up the RustOwl toolchain and executes command using that toolchain.
./scripts/toolchain cargo install --path . --lockedBuild RustOwl using custom toolchain
You can build RustOwl using a custom toolchain. This method is recommended for contributors to RustOwl.
The prerequisites are as follows:
rustupinstalled- You can install
rustupfrom this link. - You need to set up the
PATHenvironment variable. Follow the instructions provided by therustupinstaller to do this.
- You can install
gccorclanginstalled.- On Windows, you can install the Visual Studio toolchain instead.
Building RustOwl requires a nightly build of rustc. It will be installed automatically by rustup if needed.
Other dependencies are specified in the configuration files and will be installed automatically.
cargo install --path . --lockedVSCode extension
Prerequisite
- VS Code installed
- You can install VS Code from this link.
- Node.js installed
pnpminstalled- After installing Node.js, You can install
pnpmby runningnpm install pnpm.
- After installing Node.js, You can install
VS Code extension has been tested on macOS Sequoia 15.3.2 on arm64 architecture with Visual Studio Code 1.99.3, Node.js v20.16.0, and pnpm 1.22.22.
Other dependencies are locked in the configuration files and will be installed automatically.
Build & Run
First, install the dependencies:
cd vscode
pnpm install --frozen-lockfileThen, open the vscode directory in VS Code.
A notification to install the recommended VS Code extension will appear in the bottom right corner of VS Code.
Click the install button, wait for the installation to finish, and then restart VS Code.
Open the vscode directory again, and press the F5 key in the VS Code window.
A new VS Code window with the extension enabled will appear.
Open the cargo workspace directory in the new VS Code window.
When you save Rust files, decorations indicating the movement of ownership and lifetimes will appear in the editor.
Emacs Configuration (`docs/emacs-configuration.md`)
RustOwl Configuration (Emacs)
Table Of Contents
Quick Start
- Install RustOwl (see docs/installation.md) and install the Emacs package via
elpacaoruse-package. - Open a Rust Cargo workspace in Emacs.
- Place the cursor on a variable and wait ~2 seconds (default) to see overlays with lifetime and borrow info.
This document describes how to use RustOwl from Emacs. It mirrors the detail level of docs/neovim-configuration.md and is derived from rustowl.el.
Basic Setup
Install the rustowl executable (see docs/installation.md). Install the Emacs package via elpaca or use-package.
Elpaca example:
(elpaca
(rustowl
:host github
:repo "cordx56/rustowl"))Use-package example:
(use-package rustowl
:after lsp-mode)What the package does
- Registers an LSP client for
rust-mode,rust-ts-mode, andrustic-modeusingrustowlas the executable. - Sends
rustowl/analyzeon save (seerustowl-enable-analyze-on-save). - Sends
rustowl/cursorwhen the cursor has been idle forrustowl-cursor-timeoutseconds (default 2.0 seconds) and applies underlines via overlays.
Defaults and variables
rustowl-cursor-timeout(float) โ default: 2.0 seconds. Idle time before the cursor request is sent.rustowl-cursor-timerโ internal timer variable managed by the package.
How highlighting works
- The package sends
rustowl/cursorwith position and document URI. The server responds with decorations (type, range, hover text, overlapped). - For each non-overlapped decoration, the package maps types to underline colors:
definitely_liveโ#00cc00(green, straight)maybe_initializedโ#00cc00(green, wavy)imm_borrowโ#0000cc(blue)mut_borrowโ#cc00cc(purple)move/callโ#cccc00(yellow)outlive/shared_mutโ#cc0000(red, wavy)
- Underlines are implemented via overlays with face
(:underline (:color <color> :style wave)).
Enabling / Disabling
rustowl-enable-cursorโ enable cursor-based highlighting for current buffer (adds post-command-hook).rustowl-disable-cursorโ disable cursor-based highlighting (removes hook, cancels timer and clears overlays).- Cursor highlighting is automatically enabled for Rust buffers via
rust-mode-hook,rust-ts-mode-hook, andrustic-mode-hook. - Obsolete aliases
enable-rustowl-cursor/disable-rustowl-cursorremain for backward compatibility.
Examples
To disable analyze-on-save globally, remove the hooks or call:
(remove-hook 'rust-mode-hook #'rustowl-enable-cursor)To customize the timeout in your config:
(setq rustowl-cursor-timeout 1.0) ; 1 secondTroubleshooting
- If overlays don't appear, ensure
lsp-modeis active andrustowlserver is reachable. - Use
M-x rustowl-clear-overlaysto clear overlays if they persist.
See docs/lsp-spec.md for the LSP request/response shapes.
Installation (`docs/installation.md`)
Installation
Table Of Contents
Quick Start
- Install using our script (recommended):
curl -L https://raw.githubusercontent.com/cordx56/rustowl/refs/heads/main/scripts/installer | shcargo-binstall
Install the prebuilt binary using cargo-binstall:
cargo binstall rustowlThis automatically downloads and unpacks a Rust toolchain if required.
Windows (winget)
Install with:
winget install rustowlArch Linux (AUR)
We provide AUR packages that either install prebuilt binaries or build from source.
Prebuilt binaries (recommended):
yay -S rustowl-binBuild from AUR (cargo build):
yay -S rustowlGit (build from latest source):
yay -S rustowl-gitReplace yay with your AUR helper of choice.
Nix flake
There is a third-party Nix flake repository in the Nix community.
GitHub Releases
Download the rustowl executable from the release page:
https://github.com/cordx56/rustowl/releases/latest
Place the executable into a directory on your PATH.
Docker
Run the prebuilt image from GitHub Container Registry:
docker pull ghcr.io/cordx56/rustowl:latestRun it against a project directory:
docker run --rm -v /path/to/project:/app ghcr.io/cordx56/rustowl:latestUse an alias to act like a local CLI:
alias rustowl='docker run --rm -v $(pwd):/app ghcr.io/cordx56/rustowl:latest'Build manually
See docs/build.md for detailed build instructions and how to build editor extensions.
Lsp Spec (`docs/lsp-spec.md`)
The RustOwl LSP specification
Table of Contents
rustowl, is an LSP server which provides RustOwl information.
To display various types of decorations, RustOwl supports some custom methods from the client.
Here, we describe the specifications of those custom methods.
Types
Here, we describe the types we will use in this document.
`OprType`
"lifetime" | "definitely_live" | "maybe_initialized"
| "imm_borrow" | "mut_borrow" | "move" | "call"
| "outlive" | "shared_mut"definitely_live and maybe_initialized are derived from a CFG-based liveness analysis:
definitely_livecovers ranges where the local is provably initialized on every path that reaches the location (state is exactly{Initialized}).maybe_initializedcovers ranges where the local is initialized on at least one path but may also have been moved, dropped, or be uninitialized on others (state containsInitializedtogether with other variants). Useful for spotting conditional drops and other resource-management ambiguity.
lifetime is retained for backward compatibility; clients should treat definitely_live as the replacement for the previous "actual lifetime" decoration.
`Decoration`
{
"type": OprType,
"range": Range,
"hover_text": Option<String>,
"overlapped": bool
}
overlapped field indicates that the decoration is overlapped and should be hidden.
Methods
We describe the custom methods used in RustOwl.
`rustowl/cursor`
Request payload
{
"position": Position,
"document": {
"uri": DocumentUri
}
}
Response payload
{
"is_analyzed": bool,
"decorations": [Decoration]
}
Neovim Configuration (`docs/neovim-configuration.md`)
RustOwl Configuration (Neovim)
Quick Start
- Install RustOwl (see docs/installation.md) and the Neovim plugin via your plugin manager.
- Add the minimal setup to your lazy.nvim config and open a Rust Cargo workspace.
- Hover the cursor over a variable and wait ~500ms to see visualizations.
This document describes all available configuration options for the RustOwl Neovim plugin.
Table of Contents
- RustOwl Configuration (Neovim)
Basic Setup
The minimal configuration for RustOwl using lazy.nvim:
{
'cordx56/rustowl',
version = '*', -- Latest stable version
build = 'cargo install rustowl',
lazy = false, -- This plugin is already lazy
opts = {},
}Configuration Options
All configuration options are optional and have sensible defaults:
`auto_attach` (boolean)
- Default:
true - Description: Automatically attach the RustOwl LSP client when opening a Rust file.
`auto_enable` (boolean)
- Default:
false - Description: Enable RustOwl highlighting immediately when the LSP client attaches. When
false, you need to manually enable highlighting using:Rustowl enableorrequire('rustowl').enable().
`idle_time` (number)
- Default:
500 - Description: Time in milliseconds to hover with the cursor before triggering RustOwl analysis and highlighting.
`highlight_style` (table)
- Description: The style of underline for different highlight types.
'undercurl'or'underline'.
`colors` (table)
- Description: Custom colors for different highlight types. Each color should be a hex color string (e.g.,
'#ff0000').
Available Color Options:
lifetime: Color for variable lifetime highlights (default:'#00cc00'- green)imm_borrow: Color for immutable borrow highlights (default:'#0000cc'- blue)mut_borrow: Color for mutable borrow highlights (default:'#cc00cc'- purple)move: Color for value move highlights (default:'#cccc00'- yellow)call: Color for function call highlights (default:'#cccc00'- yellow)outlive: Color for lifetime error highlights (default:'#cc0000'- red)
`client` (table)
- Description: LSP client configuration that gets passed to
vim.lsp.start. This follows the same structure as Neovim's LSP client configuration.
Customizing Highlight Colors
Default Highlight Style
Default highlight style is straight underline except for maybe live and errors.
Default Colors
The default color scheme uses the following colors that correspond to the visual legend:
- ๐ฉ Green (
#00cc00): Variable's lifetime - ๐ฆ Blue (
#0000cc): Immutable borrowing - ๐ช Purple (
#cc00cc): Mutable borrowing - ๐ง Yellow (
#cccc00): Value moved / function call - ๐ฅ Red (
#cc0000): Lifetime errors
Custom Colors
To customize colors, specify them in the colors table:
opts = {
colors = {
lifetime = '#32cd32', -- Lime green
imm_borrow = '#4169e1', -- Royal blue
mut_borrow = '#ff69b4', -- Hot pink
move = '#ffa500', -- Orange
call = '#ffd700', -- Gold
outlive = '#dc143c', -- Crimson
},
}Color Format
Colors must be specified as hex color strings:
- โ
Valid:
'#ff0000','#00ff00','#0000ff' - โ Invalid:
'red','rgb(255,0,0)','#f00'
Partial Color Customization
You can customize only specific colors while keeping the defaults for others:
opts = {
colors = {
lifetime = '#90ee90', -- Light green for better visibility
outlive = '#ff4500', -- Orange red for errors
-- Other colors will use defaults
},
}Examples
Example 1: Minimal Configuration
{
'cordx56/rustowl',
version = '*',
build = 'cargo install rustowl',
lazy = false,
opts = {},
}Example 2: Auto-enable with Custom Colors
{
'cordx56/rustowl',
version = '*',
build = 'cargo install rustowl',
lazy = false,
opts = {
auto_enable = true,
colors = {
lifetime = '#90ee90', -- Light green
imm_borrow = '#87ceeb', -- Sky blue
mut_borrow = '#dda0dd', -- Plum
move = '#f0e68c', -- Khaki
call = '#ffd700', -- Gold
outlive = '#ff6347', -- Tomato
},
},
}Example 3: Custom Key Binding and Styling
{
'cordx56/rustowl',
version = '*',
build = 'cargo install rustowl',
lazy = false,
opts = {
auto_enable = false,
idle_time = 300,
highlight_style = {
definitely_live = 'underline',
maybe_initialized = 'undercurl',
},
colors = {
outlive = '#ff0000', -- Bright red for errors
},
client = {
on_attach = function(_, buffer)
vim.keymap.set('n', '<leader>ro', function()
require('rustowl').toggle(buffer)
end, { buffer = buffer, desc = 'Toggle RustOwl' })
vim.keymap.set('n', '<leader>re', function()
require('rustowl').enable(buffer)
end, { buffer = buffer, desc = 'Enable RustOwl' })
vim.keymap.set('n', '<leader>rd', function()
require('rustowl').disable(buffer)
end, { buffer = buffer, desc = 'Disable RustOwl' })
end
},
},
}Example 4: Dark Theme Optimized Colors
{
'cordx56/rustowl',
version = '*',
build = 'cargo install rustowl',
lazy = false,
opts = {
colors = {
lifetime = '#50fa7b', -- Dracula green
imm_borrow = '#8be9fd', -- Dracula cyan
mut_borrow = '#ff79c6', -- Dracula pink
move = '#f1fa8c', -- Dracula yellow
call = '#ffb86c', -- Dracula orange
outlive = '#ff5555', -- Dracula red
},
},
}Example 5: For init.vim Users
If you're using init.vim instead of init.lua, you can configure RustOwl using Vim script:
lua << EOF
require('lazy').setup({
{
'cordx56/rustowl',
version = '*',
build = 'cargo install rustowl',
lazy = false,
opts = {
colors = {
lifetime = '#00ff00',
imm_borrow = '#0080ff',
mut_borrow = '#ff00ff',
move = '#ffff00',
call = '#ffa500',
outlive = '#ff0000',
},
},
},
})
EOFUsage Commands
When opening a Rust file, the following commands become available:
:Rustowl start_client- Start the RustOwl LSP client:Rustowl stop_client- Stop the RustOwl LSP client:Rustowl restart_client- Restart the RustOwl LSP client:Rustowl enable- Enable RustOwl highlighting:Rustowl disable- Disable RustOwl highlighting:Rustowl toggle- Toggle RustOwl highlighting
You can also use the Lua API:
require('rustowl').enable() -- Enable highlighting
require('rustowl').disable() -- Disable highlighting
require('rustowl').toggle() -- Toggle highlighting
require('rustowl').is_enabled() -- Check if enabledUsage (`docs/usage.md`)
RustOwl usage
Table of Contents
Quick Start
- Install RustOwl (docs/installation.md) and the editor extension for your editor.
- Open a Rust Cargo workspace and save a Rust file to trigger analysis.
- Place the cursor on a variable or function call and wait a short idle time to see visualizations.
Here, I describe how to use RustOwl in your workflow.
Getting started
First, please install the RustOwl LSP server and extension for your editor.
Installation guide is on installation file.
Then, please open a Rust source code file (.rs) in the editor.
RustOwl only works with a Cargo workspace, so you need to open the source code that is part of a Cargo workspace.
I recommend you try RustOwl with a small, simple workspace first.
RustOwl's analysis may take a long time for a large workspace.
VS Code extension will automatically start analyzing the workspace.
For other editors, you may need to enable RustOwl manually, but you can enable automatic loading in your configuration file.
The progress of analysis will be shown in your editor.
After the analysis started, RustOwl waits for your request.
Please place the text cursor on a variable or function call you would like to inspect.
RustOwl works for the analyzed portion, even if the entire analysis has not finished.
If your program has some fatal errors (e.g., syntax errors or unrecoverable type errors), RustOwl cannot work for the part where the analysis failed.
Wait for a few seconds, and then the ownership-related operations and lifetimes of the variable to which the unwrap() method call assigns a value will appear.
Basic usage
Basically, RustOwl can be used to resolve ownership and lifetime errors.
What RustOwl visualizes is:
- Lifetime of variables, split into two precisions:
- Definitely live range: the variable is provably initialized on every path that reaches the location.
- Maybe live range: the variable is initialized on at least one path but may have been moved, dropped, or be uninitialized on others.
- Shared (immutable) borrowing of variables
- Mutable borrowing of variables
- Value movement
- Function call
- Ownership and lifetime errors
You can see which color is assigned to them on the top page of this repository.
RustOwl can be used to see where a variable lives, where it dies, and where it is borrowed or moved.
For VS Code, you can see the message that explains the meaning of the underline by hovering your mouse cursor over it.
This is the basic usage of RustOwl!
Now you have a master's degree in RustOwl.
Advanced usage
The lifetime that RustOwl visualizes is the range of these variables:
- Where the variable lives
- For the meaning of NLL
- Until the variable is dropped or moved
- For the meaning of RAII
Based on this, we can use RustOwl as listed below:
- To resolve dead lock that is caused by some data structures like
Mutex- Because these locks are freed where the lock object is dropped
- To manage resources
- Like memories, files, and anything which is managed by RAII respective
Definitely live vs. maybe live
The lifetime visualization is split by a CFG-based liveness analysis into two precisions, which is useful when ownership depends on control flow.
fn f(cond: bool) {
let v: Vec<_> = (0..100).collect();
if cond {
drop(v); // v is dropped only on the `cond == true` branch
}
// After the `if`, v is "maybe live": still owned on the `false`
// branch, but already dropped on the `true` branch.
}- A definitely live range marks code where the variable is owned on every path. Dropping or freeing a resource here is safe.
- A maybe live range marks code where the variable is owned on some paths only. Reading from or moving the variable here would not compile, and it is a hint that resource cleanup is happening conditionally.
When auditing resource management (file handles, locks, allocations), the boundary between the two ranges is typically the location to inspect.
Did you get a Ph.D. in lifetimes?
So let's try managing resources with RustOwl.
You will get a Ph.D. in RustOwl and computer resource management.
Vscode Configuration (`docs/vscode-configuration.md`)
RustOwl Configuration (VS Code)
Table Of Contents
This document describes configuration options for the RustOwl VS Code extension.
Quick Start
Install the extension from the Marketplace or Open VSX. The extension will download and run the rustowl binary automatically when activated.
- Install the extension in VS Code.
- Open a Rust Cargo workspace.
- Save a Rust file and hover over a variable after a short idle time to see decorations.
Configuration
The VS Code extension exposes configurable settings and commands. Here are the concrete settings and behavior derived from code.
Settings (configuration keys)
rustowl.underlineThickness(string) โ The stroke thickness of the underline line. Allowed values: "1", "2", "3", "4".rustowl.lifetimeColor(string) โ The color of the lifetime (definitely live).rustowl.maybeInitColor(string) โ The color of the lifetime (maybe initialized).rustowl.moveCallColor(string) โ The color of the move/call.rustowl.immutableBorrowColor(string) โ The color of the immutable borrow.rustowl.mutableBorrowColor(string) โ The color of the mutable borrow.rustowl.outliveColor(string) โ The color of the outlive.rustowl.displayDelay(number) โ Delay in displaying underlines (ms).rustowl.highlightBackground(boolean) โ Highlight text background instead of underline.rustowl.defaultEnabled(boolean) โ Enabled by default.
Commands
rustowl.hoverโ manually request hover/decorations for current selection.rustowl.toggleโ toggle decorations on/off (status bar changes accordingly).
Behavior
- The extension bootstraps the
rustowlbinary usingbootstrap.tsand starts an LSP client pointing at the executable. - On save of Rust files the extension sends
rustowl/analyzeto the server (if enabled). - On cursor selection changes, after
displayDelayms the extension sendsrustowl/cursorand applies decorations returned by server. - Decorations ignore overlapped ranges and map LSP response types to decorations (lifetime, imm_borrow, mut_borrow, move/call, outlive/shared_mut).
Examples
Add settings to .vscode/settings.json:
{
"rustowl.displayDelay": 2000,
"rustowl.defaultEnabled": true,
"rustowl.lifetimeColor": "#00cc00",
"rustowl.maybeInitColor": "#00cc00",
"rustowl.immutableBorrowColor": "#0000cc",
"rustowl.mutableBorrowColor": "#cc00cc",
"rustowl.moveCallColor": "#cccc00",
"rustowl.outliveColor": "#cc0000",
"rustowl.highlightBackground": false,
"rustowl.underlineThickness": 2
}Troubleshooting
- Check Output -> RustOwl for logs. If the server failed to start, the extension shows an error message.
- Ensure the
rustowlexecutable is in PATH or let the extension download it (bootstrap).
--- METRICS ---
- Files Extracted: 14
- Estimated Token Budget: ~15000 tokens
- Canonical Reference: https://codewiki.google/github.com/cordx56/rustowl