hyprlang-rs
A Rust reimplementation of Hyprlang, the configuration language used by Hyprland.
Hyprlang is a powerful configuration language featuring variables, nested categories, expressions, custom handlers, and more. This library provides a complete parser and configuration manager with a clean, idiomatic Rust API.
Features
- 🎯 Complete Hyprlang Implementation - Full compatibility with the original C++ version
- 🚀 Fast PEG Parser - Built with pest for efficient parsing
- 🔧 Type-Safe API - Strongly-typed configuration values (Int, Float, String, Vec2, Color)
- 📦 Variable System - Support for user-defined and environment variables with cycle detection
- 🧮 Expression Evaluation - Arithmetic expressions with
{{expr}}syntax - 🎨 Color Support - Multiple color formats:
rgba(),rgb(), and hex colors - 📐 Vec2 Coordinates - Built-in support for 2D coordinate pairs
- 🔌 Handler System - Extensible keyword handlers for custom syntax
- 🏷️ Special Categories - Keyed, static, and anonymous category types
- 📄 Source Directives - Include external configuration files
- 💬 Conditional Directives -
# hyprlang if/endif/noerrorsupport - ✅ Fully Tested - 44 tests covering all features
Installation
Add this to your Cargo.toml:
[]
= "0.1.0"
Optional Features
hyprland Feature
Enable the hyprland feature to get a high-level Hyprland struct with pre-configured handlers and typed access to Hyprland configuration options:
[]
= { = "0.1.0", = ["hyprland"] }
This feature provides:
- Automatic registration of all Hyprland handlers (bind, monitor, env, etc.)
- Typed accessor methods for common Hyprland config values
- Convenient methods to access all binds, windowrules, animations, etc.
Quick Start
use Config;
Hyprland API (Optional Feature)
The hyprland feature provides a high-level, type-safe API specifically designed for working with Hyprland configurations. Instead of manually registering handlers and using string-based key access, you get a convenient Hyprland struct with pre-configured handlers and typed accessor methods.
Why Use the Hyprland Feature?
Without the Hyprland feature (using low-level Config API):
use Config;
let mut config = new;
// Manually register all handlers
config.register_handler_fn;
config.register_handler_fn;
config.register_handler_fn;
// ... register 20+ more handlers
config.register_category_handler_fn;
config.register_category_handler_fn;
// Access values with string keys and manual type conversion
let border_size = config.get_int?;
let gaps_in = config.get_string?; // Could be int or string
let binds = config.get_handler_calls.unwrap_or;
With the Hyprland feature (using high-level Hyprland API):
use Hyprland;
let mut hypr = new; // All handlers pre-registered!
// Typed accessor methods
let border_size = hypr.general_border_size?; // Returns i64
let gaps_in = hypr.general_gaps_in?; // Returns String (CSS-style)
let active_border = hypr.general_active_border_color?; // Returns Color
// Convenient array access
let binds = hypr.all_binds; // Returns Vec<&String>
Complete Example
use Hyprland;
use Path;
Available Methods
General Settings
hypr.general_border_size .general_gaps_in // CSS-style: "5" or "5 10 15 20"
hypr.general_gaps_out // CSS-style: "20" or "5 10 15 20"
hypr.general_layout // "dwindle" or "master"
hypr.general_allow_tearing .general_active_border_color .general_inactive_border_color
Decoration Settings
hypr.decoration_rounding .decoration_active_opacity .decoration_inactive_opacity .decoration_blur_enabled .decoration_blur_size .decoration_blur_passes
Animation Settings
hypr.animations_enabled .all_animations // All animation definitions
hypr.all_beziers // All bezier curve definitions
Input Settings
hypr.input_kb_layout .input_follow_mouse .input_sensitivity .input_touchpad_natural_scroll
Layout Settings
hypr.dwindle_pseudotile .dwindle_preserve_split .master_new_status
Misc Settings
hypr.misc_disable_hyprland_logo .misc_force_default_wallpaper
Handler Calls (Arrays)
hypr.all_binds // All bind definitions
hypr.all_bindm // All mouse bindings
hypr.all_bindel // All bindel definitions
hypr.all_bindl // All bindl definitions
hypr.all_windowrules // All windowrule definitions
hypr.all_windowrulesv2 // All windowrulev2 definitions
hypr.all_layerrules // All layerrule definitions
hypr.all_workspaces // All workspace definitions
hypr.all_monitors // All monitor definitions
hypr.all_env // All env definitions
hypr.all_exec // All exec definitions
hypr.all_exec_once // All exec-once definitions
Variables
hypr.variables // All variables
hypr.get_variable // Get specific variable
Direct Config Access
If you need access to the underlying low-level Config API:
let config: &Config = hypr.config; // Immutable access
let config: &mut Config = hypr.config_mut; // Mutable access
// Use all Config methods
let custom_value = config.get?;
config.register_handler_fn;
What Handlers Are Pre-Registered?
The Hyprland struct automatically registers these handlers:
Root-level handlers:
monitor- Monitor configurationenv- Environment variablesbind,bindm,bindel,bindl,bindr,binde,bindn- Keybindingswindowrule,windowrulev2- Window ruleslayerrule- Layer rulesworkspace- Workspace configurationexec,exec-once- Commandssource- File inclusionblurls- Blur layer surfaceplugin- Plugin loading
Category-specific handlers:
animations:animation- Animation definitionsanimations:bezier- Bezier curve definitions
Special categories:
device[name]- Per-device input configurationmonitor[name]- Per-monitor configuration (keyed category)
When to Use Each API
Use the Hyprland API when:
- ✅ You're working specifically with Hyprland configurations
- ✅ You want typed, convenient access to common config values
- ✅ You want all Hyprland handlers pre-registered automatically
- ✅ You're building tools for Hyprland users (config editors, validators, etc.)
Use the low-level Config API when:
- ✅ You're implementing a different config language
- ✅ You need full control over handler registration
- ✅ You're working with a custom config format
- ✅ You want minimal dependencies (no Hyprland-specific code)
Usage Examples
Basic Values
use Config;
let mut config = new;
config.parse?;
assert_eq!;
assert_eq!;
assert_eq!;
Variables
use Config;
let mut config = new;
config.parse?;
// Access variables directly
let vars = config.variables;
assert_eq!;
// Or access expanded values
assert_eq!;
Colors
use Config;
let mut config = new;
config.parse?;
let color = config.get_color?;
println!;
Vec2 (2D Coordinates)
use Config;
let mut config = new;
config.parse?;
let pos = config.get_vec2?;
assert_eq!;
assert_eq!;
Expressions
use Config;
let mut config = new;
config.parse?;
assert_eq!;
assert_eq!;
assert_eq!;
Nested Categories
use Config;
let mut config = new;
config.parse?;
// Access with colon-separated paths
assert_eq!;
assert_eq!;
assert_eq!;
Custom Handlers
use Config;
let mut config = new;
// Register a handler for custom keywords
config.register_handler_fn;
config.parse?;
// Access handler calls as arrays
let binds = config.get_handler_calls.unwrap;
assert_eq!;
Category-Specific Handlers
use Config;
let mut config = new;
// Register handlers that only work in specific categories
config.register_category_handler_fn;
config.parse?;
// Handler calls are namespaced by category
let anims = config.get_handler_calls.unwrap;
assert_eq!;
Special Categories
use ;
let mut config = new;
// Register a special category
config.register_special_category;
config.parse?;
// Access keyed category instances
let mouse = config.get_special_category?;
println!;
Source Directive
use ;
use PathBuf;
let mut options = default;
options.base_dir = Some;
let mut config = with_options;
// This will include another config file
config.parse?;
Parse from File
use Config;
use Path;
let mut config = new;
config.parse_file?;
// Access all keys
for key in config.keys
Hyprland Feature (Optional)
When the hyprland feature is enabled, you can use the high-level Hyprland struct:
use Hyprland;
use Path;
// Create a new Hyprland config (automatically registers all handlers)
let mut hypr = new;
// Parse your Hyprland config
hypr.parse_file?;
// Access config with typed methods
let border_size = hypr.general_border_size?;
let gaps_in = hypr.general_gaps_in?;
let active_border = hypr.general_active_border_color?;
// Get all binds as an array
let binds = hypr.all_binds;
for bind in binds
// Get all animations
let animations = hypr.all_animations;
println!;
// Get all window rules
let rules = hypr.all_windowrules;
for rule in rules
// Access variables
let terminal = hypr.get_variable;
The Hyprland struct provides convenient typed access to:
- General settings: border_size, gaps, colors, layout, etc.
- Decoration: rounding, opacity, blur settings
- Animations: enabled status, all animations, all beziers
- Input: keyboard layout, mouse settings, touchpad
- Layout: dwindle and master layout settings
- Handlers: all binds, windowrules, monitors, env vars, exec-once, etc.
- Variables: all user-defined variables
Configuration Options
use ;
use PathBuf;
let mut options = default;
// Collect all errors instead of stopping at the first one
options.throw_all_errors = false;
// Allow parsing after initial parse
options.allow_dynamic_parsing = true;
// Base directory for resolving source directives
options.base_dir = Some;
let config = with_options;
API Overview
Main Types
Config- Main configuration managerConfigValue- Enum representing all value typesInt(i64)- Integer valueFloat(f64)- Float valueString(String)- String valueVec2(Vec2)- 2D coordinateColor(Color)- RGBA colorCustom { type_name, value }- Custom value type
Color- RGBA color (r, g, b, a)Vec2- 2D coordinate (x, y)
Key Methods
// Parsing
config.parse .parse_file // Getting values
config.get .get_int .get_float .get_string .get_vec2 .get_color // Setting values
config.set
Examples
The repository includes several examples demonstrating different features:
examples/pretty_print.rs
A comprehensive example showing a complete configuration with all features:
examples/parse_hyprland.rs
Parse and pretty-print a real Hyprland configuration file:
This example demonstrates:
- Parsing complex real-world configs
- Variable handling
- Nested categories
- Handler calls (binds, windowrules, etc.)
- Beautiful formatted output
examples/hyprland_api.rs
Demonstrate the high-level Hyprland API (requires hyprland feature):
This example demonstrates:
- Using the
Hyprlandstruct for typed config access - Accessing general, decoration, animation, and input settings
- Getting all binds, windowrules, and other handler calls
- Working with variables
- Comprehensive display of all Hyprland configuration options
Testing
Run the full test suite:
The project includes:
- 29 unit tests covering core functionality
- 12 integration tests for Hyprland-specific scenarios
- 3 documentation tests
All tests from the original Hyprlang C++ implementation have been ported and pass successfully.
Grammar
The parser is implemented using pest with a PEG grammar. The grammar file is located at src/hyprlang.pest.
Key syntax features:
- Comments:
#for single-line,##for documentation - Variables:
$VAR = value - Expressions:
{{expr}} - Categories:
category { ... } - Special categories:
category[key] { ... } - Assignments:
key = value - Handlers:
keyword = value - Directives:
source = path,# hyprlang if/endif/noerror
License
This project is a reimplementation of Hyprlang in Rust, based on the original C++ implementation by the Hyprland team.
Contributing
Contributions are welcome! Please ensure all tests pass before submitting a PR: