mirror of
https://github.com/alexpasmantier/television.git
synced 2025-07-29 06:11:37 +00:00
feat: introduction of a new binding system to better handle key/events/actions
the system is backwards compatible with the existing TOML keybinding implementation allowing for slow migration to use the new features
This commit is contained in:
parent
1d6b996c83
commit
71b361161c
110
.config/bindings.tvb
Normal file
110
.config/bindings.tvb
Normal file
@ -0,0 +1,110 @@
|
||||
// Television Binding System Reference
|
||||
// =====================================
|
||||
//
|
||||
// SYNTAX:
|
||||
// key => action; // Basic key binding
|
||||
// key => { action1; action2; }; // Action block (multiple actions, executed sequentially)
|
||||
// @event => action; // Event binding
|
||||
// channel "name" { key => action; } // Channel-specific binding, overrides global
|
||||
//
|
||||
// KEY CODES:
|
||||
// Basic: up, down, left, right, enter, esc, tab, space, backspace, delete, home, end, pageup, pagedown
|
||||
// Function: f1, f2, f3, ..., f12
|
||||
// Modified: ctrl-a, ctrl-c, alt-enter, etc.
|
||||
// Mouse: mouse-scroll-up, mouse-scroll-down
|
||||
// Special: backtab (Shift+Tab)
|
||||
// Characters: a-z, 0-9, symbols (!@#$%^&*()_+-=[]{}|;':"<>,.?/~`)
|
||||
//
|
||||
// EVENTS:
|
||||
// @start - Application startup
|
||||
// @load - Channel data loaded
|
||||
// @result - Search filtering complete
|
||||
// @one - Exactly one search match
|
||||
// @zero - No search matches
|
||||
// @selection-change - Multi-selection changed
|
||||
//
|
||||
// ACTIONS:
|
||||
// Navigation: select_next_entry, select_prev_entry, select_next_page, select_prev_page
|
||||
// History: select_next_history, select_prev_history
|
||||
// Selection: confirm_selection, select_and_exit, toggle_selection_down, toggle_selection_up
|
||||
// Input: go_to_input_start, go_to_input_end, go_to_next_char, go_to_prev_char
|
||||
// Edit: delete_line, delete_next_char, delete_prev_char, delete_prev_word
|
||||
// Preview: scroll_preview_up, scroll_preview_down, scroll_preview_half_page_up, scroll_preview_half_page_down
|
||||
// Control: quit, suspend, resume, reload_source
|
||||
// Toggle: toggle_preview, toggle_help, toggle_status_bar, toggle_remote_control
|
||||
// Data: copy_entry_to_clipboard, cycle_sources
|
||||
// Special: nil (no-op)
|
||||
//
|
||||
// For more information, see: https://alexpasmantier.github.io/television/docs/Users/04-keybindings.html
|
||||
|
||||
bindings {
|
||||
// === APPLICATION CONTROL ===
|
||||
// Quit the application
|
||||
esc => quit;
|
||||
ctrl-c => quit;
|
||||
|
||||
// === NAVIGATION AND SELECTION ===
|
||||
// Scrolling through entries
|
||||
down => select_next_entry;
|
||||
ctrl-n => select_next_entry;
|
||||
ctrl-j => select_next_entry;
|
||||
|
||||
up => select_prev_entry;
|
||||
ctrl-p => select_prev_entry;
|
||||
ctrl-k => select_prev_entry;
|
||||
|
||||
// Page navigation (uncomment to enable)
|
||||
// pagedown => select_next_page;
|
||||
// pageup => select_prev_page;
|
||||
|
||||
// === HISTORY NAVIGATION ===
|
||||
// Navigate through search query history
|
||||
ctrl-up => select_prev_history;
|
||||
ctrl-down => select_next_history;
|
||||
|
||||
// === MULTI-SELECTION ===
|
||||
// Add entry to selection and move to the next entry
|
||||
tab => toggle_selection_down;
|
||||
// Add entry to selection and move to the previous entry
|
||||
backtab => toggle_selection_up;
|
||||
// Confirm selection
|
||||
enter => confirm_selection;
|
||||
|
||||
// === PREVIEW PANEL CONTROL ===
|
||||
// Scrolling the preview pane
|
||||
pagedown => scroll_preview_half_page_down;
|
||||
mouse-scroll-down => scroll_preview_half_page_down;
|
||||
|
||||
pageup => scroll_preview_half_page_up;
|
||||
mouse-scroll-up => scroll_preview_half_page_up;
|
||||
|
||||
// === DATA OPERATIONS ===
|
||||
// Copy the selected entry to the clipboard
|
||||
ctrl-y => copy_entry_to_clipboard;
|
||||
// Reload the current source
|
||||
ctrl-r => reload_source;
|
||||
// Cycle through the available sources for the current channel
|
||||
ctrl-s => cycle_sources;
|
||||
|
||||
// === UI FEATURES ===
|
||||
// Toggle features
|
||||
ctrl-t => toggle_remote_control;
|
||||
ctrl-o => toggle_preview;
|
||||
ctrl-h => toggle_help;
|
||||
f12 => toggle_status_bar;
|
||||
|
||||
// === INPUT FIELD CONTROLS ===
|
||||
// Text editing
|
||||
backspace => delete_prev_char;
|
||||
ctrl-w => delete_prev_word;
|
||||
ctrl-u => delete_line;
|
||||
delete => delete_next_char;
|
||||
|
||||
// Cursor movement
|
||||
left => go_to_prev_char;
|
||||
right => go_to_next_char;
|
||||
home => go_to_input_start;
|
||||
ctrl-a => go_to_input_start;
|
||||
end => go_to_input_end;
|
||||
ctrl-e => go_to_input_end;
|
||||
}
|
@ -125,69 +125,22 @@ sort_alphabetically = true
|
||||
# Keybindings
|
||||
# ----------------------------------------------------------------------------
|
||||
#
|
||||
# HARDCODED KEYBINDINGS (cannot be changed via config):
|
||||
# Input field actions (always active):
|
||||
# Backspace - Delete previous character
|
||||
# Ctrl+w - Delete previous word
|
||||
# Ctrl+u - Delete entire line
|
||||
# Delete - Delete next character
|
||||
# Left/Right - Move cursor left/right
|
||||
# Home / Ctrl+a - Go to input start
|
||||
# End / Ctrl+e - Go to input end
|
||||
# NEW BINDING SYSTEM:
|
||||
# -------------------------
|
||||
# Television now uses a new binding system defined in:
|
||||
# ~/.config/television/bindings.tvb, or similar depending on the OS
|
||||
#
|
||||
# CONFIGURABLE KEYBINDINGS (can be customized below):
|
||||
# --------------------------------------------------
|
||||
# For full documentation, see:
|
||||
# https://alexpasmantier.github.io/television/docs/Users/04-keybindings.html
|
||||
#
|
||||
# LEGACY TOML KEYBINDINGS (deprecated but still supported):
|
||||
# ---------------------------------------------------------
|
||||
# The following \[keybindings] section is the legacy format.
|
||||
# It is recommended to migrate to the modern bindings.tvb format.
|
||||
[keybindings]
|
||||
# Application control
|
||||
# ------------------
|
||||
# Quit the application
|
||||
# Legacy TOML format - consider migrating to bindings.tvb
|
||||
quit = ["esc", "ctrl-c"]
|
||||
|
||||
# Navigation and selection
|
||||
# -----------------------
|
||||
# Scrolling through entries
|
||||
select_next_entry = ["down", "ctrl-n", "ctrl-j"]
|
||||
select_prev_entry = ["up", "ctrl-p", "ctrl-k"]
|
||||
#select_next_page = "pagedown"
|
||||
#select_prev_page = "pageup"
|
||||
|
||||
# History navigation
|
||||
# -----------------
|
||||
# Navigate through search query history
|
||||
select_prev_history = "ctrl-up"
|
||||
select_next_history = "ctrl-down"
|
||||
|
||||
# Multi-selection
|
||||
# --------------
|
||||
# Add entry to selection and move to the next entry
|
||||
toggle_selection_down = "tab"
|
||||
# Add entry to selection and move to the previous entry
|
||||
toggle_selection_up = "backtab"
|
||||
# Confirm selection
|
||||
confirm_selection = "enter"
|
||||
|
||||
# Preview panel control
|
||||
# --------------------
|
||||
# Scrolling the preview pane
|
||||
scroll_preview_half_page_down = ["pagedown", "mousescrolldown"]
|
||||
scroll_preview_half_page_up = ["pageup", "mousescrollup"]
|
||||
|
||||
# Data operations
|
||||
# --------------
|
||||
# Copy the selected entry to the clipboard
|
||||
copy_entry_to_clipboard = "ctrl-y"
|
||||
# Reload the current source
|
||||
reload_source = "ctrl-r"
|
||||
# Cycle through the available sources for the current channel
|
||||
cycle_sources = "ctrl-s"
|
||||
|
||||
# UI Features
|
||||
# ----------
|
||||
toggle_remote_control = "ctrl-t"
|
||||
toggle_preview = "ctrl-o"
|
||||
toggle_help = "ctrl-h"
|
||||
toggle_status_bar = "f12"
|
||||
|
||||
# Shell integration
|
||||
# ----------------------------------------------------------------------------
|
||||
#
|
||||
|
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -2000,6 +2000,8 @@ dependencies = [
|
||||
"lazy-regex",
|
||||
"nucleo",
|
||||
"parking_lot",
|
||||
"pest",
|
||||
"pest_derive",
|
||||
"portable-pty",
|
||||
"ratatui",
|
||||
"rustc-hash",
|
||||
|
@ -51,6 +51,8 @@ serde_json = "1.0.140"
|
||||
colored = "3.0.0"
|
||||
serde_with = "3.13.0"
|
||||
which = "8.0.0"
|
||||
pest = "2.8"
|
||||
pest_derive = "2.8"
|
||||
|
||||
|
||||
# target specific dependencies
|
||||
@ -74,7 +76,7 @@ vt100 = "0.15"
|
||||
|
||||
[build-dependencies]
|
||||
clap = { version = "4.5", features = ["derive", "cargo"] }
|
||||
clap_mangen = "0.2.26"
|
||||
clap_mangen = "0.2"
|
||||
|
||||
|
||||
[[bin]]
|
||||
|
@ -1,5 +1,12 @@
|
||||
# Keybindings
|
||||
|
||||
Television supports two keybinding configuration formats:
|
||||
|
||||
1. **Binding syntax** - The modern, recommended format (key => action;)
|
||||
2. **TOML format** - The legacy format (action = ["key1", "key2"])
|
||||
|
||||
Both formats are fully supported and can be used together. The binding syntax is recommended for new configurations due to its enhanced features like action blocks, event bindings, and channel-specific overrides.
|
||||
|
||||
## Default Keybindings
|
||||
|
||||
Default keybindings are as follows:
|
||||
@ -7,35 +14,308 @@ Default keybindings are as follows:
|
||||
| Key | Description |
|
||||
| :---------------------------------------------------------------------------------------------------------------------------: | -------------------------------------------------- |
|
||||
| <kbd>↑</kbd> / <kbd>↓</kbd> or <kbd>Ctrl</kbd> + <kbd>p</kbd> / <kbd>n</kbd> or <kbd>Ctrl</kbd> + <kbd>k</kbd> / <kbd>j</kbd> | Navigate through the list of entries |
|
||||
| <kbd>Ctrl</kbd> + <kbd>u</kbd> / <kbd>d</kbd> | Scroll the preview pane up / down |
|
||||
| <kbd>PageUp</kbd> / <kbd>PageDown</kbd> or <kbd>Mouse Wheel ↑</kbd> / <kbd>Mouse Wheel ↓</kbd> | Scroll the preview pane up / down |
|
||||
| <kbd>Enter</kbd> | Select the current entry |
|
||||
| <kbd>Tab</kbd> / <kbd>BackTab</kbd> | Toggle selection and move to next / previous entry |
|
||||
| <kbd>Ctrl</kbd> + <kbd>y</kbd> | Copy the selected entry to the clipboard |
|
||||
| <kbd>Ctrl</kbd> + <kbd>r</kbd> | Toggle remote control mode |
|
||||
| <kbd>Ctrl</kbd> + <kbd>s</kbd> | Toggle send to channel mode |
|
||||
| <kbd>Ctrl</kbd> + <kbd>g</kbd> | Toggle the help panel |
|
||||
| <kbd>Ctrl</kbd> + <kbd>t</kbd> | Toggle remote control mode |
|
||||
| <kbd>Ctrl</kbd> + <kbd>h</kbd> | Toggle the help panel |
|
||||
| <kbd>Ctrl</kbd> + <kbd>o</kbd> | Toggle the preview panel |
|
||||
| <kbd>Esc</kbd> | Quit the application |
|
||||
|
||||
These keybindings are all configurable via tv's configuration file (see [Configuration](./configuration)).
|
||||
|
||||
# Keybindings Guide
|
||||
## Configuration Formats
|
||||
|
||||
Following this are some configuration presets you can use for your bindings. Most of these will probably match an existing program.
|
||||
### TOML Format
|
||||
|
||||
The traditional TOML format maps actions to lists of keys:
|
||||
|
||||
```toml
|
||||
[keybindings]
|
||||
quit = ["esc", "ctrl-c"]
|
||||
select_next_entry = ["down", "ctrl-n", "ctrl-j"]
|
||||
select_prev_entry = ["up", "ctrl-p", "ctrl-k"]
|
||||
toggle_selection_down = "tab"
|
||||
toggle_selection_up = "backtab"
|
||||
confirm_selection = "enter"
|
||||
toggle_remote_control = "ctrl-t"
|
||||
toggle_preview = "ctrl-o"
|
||||
toggle_help = "ctrl-h"
|
||||
toggle_status_bar = "f12"
|
||||
```
|
||||
|
||||
### Binding Syntax
|
||||
|
||||
The new binding syntax is an alternative way that uses that follows a key/event to action mapping:
|
||||
|
||||
```javascript
|
||||
bindings {
|
||||
// === APPLICATION CONTROL ===
|
||||
esc => quit;
|
||||
ctrl-c => quit;
|
||||
|
||||
// === NAVIGATION AND SELECTION ===
|
||||
down => select_next_entry;
|
||||
ctrl-n => select_next_entry;
|
||||
ctrl-j => select_next_entry;
|
||||
|
||||
up => select_prev_entry;
|
||||
ctrl-p => select_prev_entry;
|
||||
ctrl-k => select_prev_entry;
|
||||
|
||||
// === SELECTION ===
|
||||
tab => toggle_selection_down;
|
||||
backtab => toggle_selection_up;
|
||||
enter => confirm_selection;
|
||||
|
||||
// === UI FEATURES ===
|
||||
ctrl-t => toggle_remote_control;
|
||||
ctrl-o => toggle_preview;
|
||||
ctrl-h => toggle_help;
|
||||
f12 => toggle_status_bar;
|
||||
}
|
||||
```
|
||||
|
||||
#### Comments
|
||||
|
||||
Full comment support with both single-line and multi-line comments:
|
||||
|
||||
```javascript
|
||||
bindings {
|
||||
// Single-line comments
|
||||
ctrl-o => toggle_preview; // inline comments are allowed too
|
||||
|
||||
/* Multi-line comments
|
||||
are also supported */
|
||||
enter => confirm_selection;
|
||||
}
|
||||
```
|
||||
|
||||
#### Action Blocks
|
||||
|
||||
Execute multiple actions in sequence with a single key press:
|
||||
|
||||
```javascript
|
||||
bindings {
|
||||
// Move to next entry and select the next two items
|
||||
f5 => {
|
||||
select_next_entry;
|
||||
toggle_selection_down;
|
||||
toggle_selection_down;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
> **Note**: Action blocks execute each action in order, one after another. This guarantees consistent behavior and prevents actions from interfering with each other.
|
||||
|
||||
#### Event Bindings
|
||||
|
||||
Respond to application events automatically:
|
||||
|
||||
```javascript
|
||||
bindings {
|
||||
// Triggered when input stream is complete
|
||||
@load => reload_source;
|
||||
|
||||
// Triggered when filtering is complete
|
||||
@result => toggle_status_bar;
|
||||
|
||||
// Triggered when multi-selection changes
|
||||
@selection-change => copy_entry_to_clipboard;
|
||||
|
||||
// Triggered when there's only one match
|
||||
@one => select_and_exit;
|
||||
|
||||
// Triggered when there's no match
|
||||
@zero => quit;
|
||||
}
|
||||
```
|
||||
|
||||
## Key Specifications
|
||||
|
||||
### Basic Keys
|
||||
|
||||
- **Movement**: `up`, `down`, `left`, `right`
|
||||
- **Text**: `enter`, `esc`, `tab`, `space`, `backspace`, `delete`
|
||||
- **Navigation**: `home`, `end`, `pageup`, `pagedown`, `insert`
|
||||
- **Function**: `f1` through `f12`
|
||||
|
||||
### Character Keys
|
||||
|
||||
- **Letters**: `a` through `z`
|
||||
- **Numbers**: `0` through `9`
|
||||
- **Symbols**
|
||||
|
||||
### Modified Keys
|
||||
|
||||
- **Ctrl**: `ctrl-a`, `ctrl-space`, `ctrl-enter`, etc.
|
||||
- **Alt**: `alt-a`, `alt-space`, `alt-enter`, etc.
|
||||
|
||||
### Special Keys
|
||||
|
||||
- `backtab` (Shift+Tab)
|
||||
- `mouse-scroll-up`, `mouse-scroll-down`
|
||||
|
||||
## Available Actions
|
||||
|
||||
### Navigation
|
||||
|
||||
- `select_next_entry` - Move to next entry
|
||||
- `select_prev_entry` - Move to previous entry
|
||||
- `select_next_page` - Move to next page
|
||||
- `select_prev_page` - Move to previous page
|
||||
- `select_next_history` - Navigate forward in search history
|
||||
- `select_prev_history` - Navigate backward in search history
|
||||
|
||||
### Selection
|
||||
|
||||
- `confirm_selection` - Confirm current selection
|
||||
- `select_and_exit` - Select the entry currently under cursor and exit
|
||||
- `toggle_selection_down` - Toggle selection and move down
|
||||
- `toggle_selection_up` - Toggle selection and move up
|
||||
|
||||
### Input Navigation
|
||||
|
||||
- `go_to_input_start` - Move cursor to start of input
|
||||
- `go_to_input_end` - Move cursor to end of input
|
||||
- `go_to_next_char` - Move cursor to next character
|
||||
- `go_to_prev_char` - Move cursor to previous character
|
||||
|
||||
### Input Editing
|
||||
|
||||
- `delete_line` - Delete the current line from input buffer
|
||||
- `delete_next_char` - Delete character after cursor
|
||||
- `delete_prev_char` - Delete character before cursor
|
||||
- `delete_prev_word` - Delete previous word from input buffer
|
||||
|
||||
### Preview Control
|
||||
|
||||
- `scroll_preview_up` - Scroll preview pane up
|
||||
- `scroll_preview_down` - Scroll preview pane down
|
||||
- `scroll_preview_half_page_up` - Scroll preview half page up
|
||||
- `scroll_preview_half_page_down` - Scroll preview half page down
|
||||
|
||||
### Application Control
|
||||
|
||||
- `quit` - Exit the application
|
||||
- `suspend` - Suspend the application
|
||||
- `resume` - Resume the application
|
||||
- `reload_source` - Reload the current data source
|
||||
|
||||
### Feature Toggles
|
||||
|
||||
- `toggle_preview` - Toggle the preview pane
|
||||
- `toggle_help` - Toggle the help panel
|
||||
- `toggle_status_bar` - Toggle the status bar
|
||||
- `toggle_remote_control` - Toggle remote control mode
|
||||
|
||||
### Data Operations
|
||||
|
||||
- `copy_entry_to_clipboard` - Copy selected entry to clipboard
|
||||
- `cycle_sources` - Cycle through available data sources
|
||||
|
||||
### Special Actions
|
||||
|
||||
- `nil` - No operation/unbind action
|
||||
|
||||
## Event System
|
||||
|
||||
Events allow you to automatically trigger actions when certain application events occur.
|
||||
|
||||
### Available Events
|
||||
|
||||
- `@start` - Triggered once when Television starts up
|
||||
- `@load` - Triggered when a channel finishes loading data
|
||||
- `@result` - Triggered when search filtering completes
|
||||
- `@one` - Triggered when search has exactly one match
|
||||
- `@zero` - Triggered when search has no matches
|
||||
- `@selection-change` - Triggered when multi-selection changes
|
||||
|
||||
## Migration Guide
|
||||
|
||||
### From TOML to New Syntax
|
||||
|
||||
**TOML format:**
|
||||
|
||||
```toml
|
||||
[keybindings]
|
||||
quit = ["esc", "ctrl-c"]
|
||||
select_next_entry = ["down", "ctrl-j"]
|
||||
toggle_preview = "ctrl-o"
|
||||
```
|
||||
|
||||
**New syntax equivalent:**
|
||||
|
||||
```javascript
|
||||
bindings {
|
||||
esc => quit;
|
||||
ctrl-c => quit;
|
||||
down => select_next_entry;
|
||||
ctrl-j => select_next_entry;
|
||||
ctrl-o => toggle_preview;
|
||||
}
|
||||
```
|
||||
|
||||
### Using Both Formats
|
||||
|
||||
You can use both formats together by creating a `bindings.tvb` file alongside your existing `config.toml`:
|
||||
|
||||
**Create**: `~/.config/television/bindings.tvb`
|
||||
|
||||
```javascript
|
||||
bindings {
|
||||
up => select_next_entry;
|
||||
down => select_prev_entry;
|
||||
ctrl-c => quit;
|
||||
enter => confirm_selection;
|
||||
}
|
||||
```
|
||||
|
||||
**Keep your existing**: `~/.config/television/config.toml`
|
||||
|
||||
```toml
|
||||
[ui]
|
||||
theme = "default"
|
||||
|
||||
[keybindings]
|
||||
copy_entry_to_clipboard = "ctrl-y"
|
||||
```
|
||||
|
||||
Television automatically loads and merges both formats. The binding syntax takes precedence over TOML for conflicting bindings.
|
||||
|
||||
## Channel-Specific Bindings
|
||||
|
||||
The binding syntax supports channel-specific overrides that only apply when using specific channels:
|
||||
|
||||
```javascript
|
||||
bindings {
|
||||
// Global bindings
|
||||
ctrl-c => quit;
|
||||
|
||||
// Only active when using the "files" channel
|
||||
channel "files" {
|
||||
f8 => toggle_preview;
|
||||
f7 => copy_entry_to_clipboard;
|
||||
}
|
||||
|
||||
// Pattern-based channel binding
|
||||
for_channels("dirs") {
|
||||
f1 => toggle_help;
|
||||
f5 => reload_source;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Example configuration used as reference
|
||||
|
||||
For a complete, up-to-date reference of all available keys, events, and actions, see the default configuration file:
|
||||
|
||||
- **In repository**: `.config/bindings.tvb`
|
||||
- **Documentation header**: Contains comprehensive syntax guide and all available options
|
||||
|
||||
This file serves as the authoritative reference and is kept in sync with the latest features.
|
||||
|
||||
:::note
|
||||
**This list is maintained by the community, so feel free to contribute your own ideas too! 😊**
|
||||
:::
|
||||
|
||||
## Emacs
|
||||
|
||||
```toml
|
||||
# Television already has some pretty Emacsy keybinds.
|
||||
# This just makes them "Emacsier".
|
||||
[keybindings]
|
||||
scroll_preview_half_page_down = "alt-v"
|
||||
scroll_preview_half_page_up = "ctrl-v"
|
||||
toggle_remote_control = "alt-x" # Like execute-extended-command
|
||||
toggle_help = "ctrl-h"
|
||||
|
||||
```
|
||||
|
150
docs/02-Developers/03-binding-system.md
Normal file
150
docs/02-Developers/03-binding-system.md
Normal file
@ -0,0 +1,150 @@
|
||||
# Binding System Architecture
|
||||
|
||||
## Overview
|
||||
|
||||
The Television binding system maps keys and events to actions using a dual-format parser (Television syntax + TOML) built on Pest. The system supports channel-specific bindings, action blocks, event bindings, and multi-source configuration loading.
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Configuration Input] --> B{Parser Selection}
|
||||
|
||||
B -->|Binding System| C1
|
||||
B -->|TOML| D1
|
||||
|
||||
subgraph primary[" "]
|
||||
C1[parse_bindings]
|
||||
C2[Pest Grammar Processing]
|
||||
C3[Television AST Generation]
|
||||
C1 --> C2 --> C3
|
||||
end
|
||||
|
||||
subgraph secondary[" "]
|
||||
D1[parse_toml_bindings]
|
||||
D2[TOML Grammar Processing]
|
||||
D3[TOML to AST Conversion]
|
||||
D1 --> D2 --> D3
|
||||
end
|
||||
|
||||
C3 --> E[Unified AST]
|
||||
D3 --> E
|
||||
|
||||
E --> F[Converter Layer]
|
||||
F --> G[Television Bindings]
|
||||
G --> H[Runtime Execution]
|
||||
|
||||
B -->|Both Fail| I[Parse Error]
|
||||
```
|
||||
|
||||
## Grammar Definition
|
||||
|
||||
### Core Grammar Structure
|
||||
|
||||
```pest
|
||||
// Dual format support
|
||||
file = { SOI ~ (bindings | toml_bindings)? ~ EOI }
|
||||
|
||||
// Television syntax
|
||||
bindings = { "bindings" ~ "{" ~ binding* ~ "}" }
|
||||
binding = {
|
||||
key_binding | event_binding | channel_binding |
|
||||
for_channels_binding | comment
|
||||
}
|
||||
|
||||
// Binding types
|
||||
key_binding = { key_sequence ~ "=>" ~ action_target ~ ";" }
|
||||
event_binding = { "@" ~ event_name ~ "=>" ~ action_target ~ ";" }
|
||||
channel_binding = { "channel" ~ string_literal ~ "{" ~ binding* ~ "}" }
|
||||
for_channels_binding = { "for_channels" ~ "(" ~ string_literal ~ ")" ~ "{" ~ binding* ~ "}" }
|
||||
|
||||
// Action targets
|
||||
action_target = { action_block | action_array | action_name }
|
||||
action_block = { "{" ~ action_name ~ (";" ~ action_name)* ~ "}" }
|
||||
action_array = { "[" ~ action_name ~ ("," ~ action_name)* ~ "]" }
|
||||
|
||||
// TOML format support
|
||||
toml_bindings = { toml_section+ }
|
||||
toml_section = { "[" ~ section_name ~ "]" ~ toml_entry* }
|
||||
```
|
||||
|
||||
### Key Grammar Components
|
||||
|
||||
```pest
|
||||
// Key specifications
|
||||
key_sequence = { (modifier ~ "-")* ~ key_name }
|
||||
modifier = { "ctrl" | "alt" | "shift" }
|
||||
key_name = { named_key | function_key | character_key | mouse_event }
|
||||
|
||||
// Named keys
|
||||
named_key = {
|
||||
"enter" | "esc" | "tab" | "space" | "backspace" | "delete" |
|
||||
"home" | "end" | "pageup" | "pagedown" | "insert" |
|
||||
"up" | "down" | "left" | "right" | "backtab"
|
||||
}
|
||||
|
||||
// Function keys and mouse events
|
||||
function_key = { "f" ~ number }
|
||||
mouse_event = { "mouse-scroll-up" | "mouse-scroll-down" }
|
||||
|
||||
// Event specifications
|
||||
event_name = {
|
||||
"start" | "load" | "result" | "one" | "zero" |
|
||||
"selection-change" | "resize"
|
||||
}
|
||||
```
|
||||
|
||||
## Hierarchical Configuration Merging
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
A["Embedded Defaults"] --> B["User Config"]
|
||||
B --> C["Channel Configs"]
|
||||
|
||||
subgraph ABS["Multi-Source Loading"]
|
||||
D1["Explicit Files<br/>--bindings-file FILENAME"]
|
||||
D2["Custom Directory<br/>--bindings-dir DIRNAME"]
|
||||
D3["Default Directory<br/>$CONFIG/bindings.tvb<br/>$CONFIG/keybindings.toml"]
|
||||
end
|
||||
|
||||
C --> D1
|
||||
C --> D2
|
||||
C --> D3
|
||||
|
||||
E["Merge Bindings"] --> F["Final Configuration"]
|
||||
|
||||
D1 --> E
|
||||
D2 --> E
|
||||
D3 --> E
|
||||
```
|
||||
|
||||
## Action Block State Management
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> Received: ActionBlock arrives
|
||||
Received --> HashCheck: Calculate hash
|
||||
HashCheck --> Processed: Hash not found
|
||||
HashCheck --> Skipped: Hash exists
|
||||
Processed --> Queued: Mark hash, queue actions
|
||||
Queued --> [*]: Actions sent to channel
|
||||
Skipped --> [*]: Duplicate prevention
|
||||
note right of HashCheck
|
||||
Hash-based deduplication
|
||||
end note
|
||||
note left of Queued
|
||||
Individual actions sent
|
||||
via action_tx channel
|
||||
end note
|
||||
note left of Processed
|
||||
Action blocks processed
|
||||
sequentially to maintain
|
||||
execution order
|
||||
end note
|
||||
```
|
||||
|
||||
## Grammar Extensions (not Implemented)
|
||||
|
||||
- 🔄 Parameterized action execution
|
||||
- 🔄 Advanced pattern matching for channels
|
||||
- 🔄 Conditional binding logic
|
||||
- 🔄 Runtime binding modification
|
||||
- 🔄 LSP support using AST span information
|
185
television/bindings_parser/grammar.pest
Normal file
185
television/bindings_parser/grammar.pest
Normal file
@ -0,0 +1,185 @@
|
||||
// Core Rules
|
||||
WHITESPACE = _{ " " | "\t" | "\r" | "\n" }
|
||||
NEWLINE = _{ "\n" | "\r\n" }
|
||||
|
||||
// Comments
|
||||
COMMENT = _{ line_comment | block_comment | toml_comment }
|
||||
line_comment = _{ "//" ~ (!"\n" ~ ANY)* }
|
||||
block_comment = _{ "/*" ~ (!"*/" ~ ANY)* ~ "*/" }
|
||||
toml_comment = _{ "#" ~ (!"\n" ~ ANY)* }
|
||||
|
||||
// Basic atomic tokens
|
||||
identifier = @{ ASCII_ALPHA ~ (ASCII_ALPHANUMERIC | "_")* }
|
||||
string_literal = @{ "\"" ~ (!"\"" ~ ANY)* ~ "\"" }
|
||||
number = @{ ASCII_DIGIT+ }
|
||||
key_string = @{ (!"\"" ~ (ASCII_ALPHANUMERIC | "-" | " " | "_" | "[" | "]" | ";" | ":" | "'" | "`" | "~" | "!" | "@" | "#" | "$" | "%" | "^" | "&" | "*" | "(" | ")" | "+" | "=" | "{" | "}" | "|" | "\\" | "<" | ">" | "," | "." | "?" | "/"))+ }
|
||||
|
||||
// Entry points - Main grammar rules
|
||||
bindings = { SOI ~ "bindings" ~ "{" ~ binding* ~ "}" ~ EOI }
|
||||
standalone_key = { SOI ~ key ~ EOI }
|
||||
|
||||
// TOML compatibility
|
||||
toml_bindings = { SOI ~ (toml_binding | toml_section | toml_comment | NEWLINE)* ~ EOI }
|
||||
toml_section = { "[" ~ "keybindings" ~ "]" ~ NEWLINE? ~ (toml_binding | toml_comment | NEWLINE)* }
|
||||
toml_binding = { action_name ~ "=" ~ (toml_key_array | toml_string_key) ~ NEWLINE? }
|
||||
toml_key_array = { "[" ~ toml_string_key ~ ("," ~ toml_string_key)* ~ ","? ~ "]" }
|
||||
toml_string_key = { "\"" ~ key_string ~ "\"" }
|
||||
|
||||
// Binding types
|
||||
binding = { key_binding | event_binding | channel_binding | for_channels_binding }
|
||||
|
||||
key_binding = { key_sequence ~ "=>" ~ action_target ~ ";" }
|
||||
event_binding = { "@" ~ event_name ~ "=>" ~ action_target ~ ";" }
|
||||
channel_binding = { "channel" ~ channel_specifier ~ "{" ~ binding_list ~ "}" }
|
||||
for_channels_binding = { "for_channels" ~ "(" ~ channel_pattern_list ~ ")" ~ "{" ~ binding_list ~ "}" }
|
||||
|
||||
// Channel-specific
|
||||
channel_specifier = { string_literal }
|
||||
channel_pattern_list = { channel_pattern ~ ("," ~ channel_pattern)* }
|
||||
channel_pattern = { string_literal }
|
||||
binding_list = { (key_binding | event_binding)* }
|
||||
|
||||
// Key specifications
|
||||
key_sequence = { key ~ ("+" ~ key)* }
|
||||
key = { modifier_key | named_key | character_key }
|
||||
|
||||
// Modifier keys
|
||||
modifier_key = {
|
||||
("ctrl-" ~ (named_key | character_key))
|
||||
| ("alt-" ~ (named_key | character_key))
|
||||
}
|
||||
|
||||
// Named keys
|
||||
named_key = {
|
||||
// Most common keys first
|
||||
"enter"
|
||||
| "esc"
|
||||
| "tab"
|
||||
| "space"
|
||||
| "backspace"
|
||||
| "delete"
|
||||
| // Arrow keys
|
||||
"up"
|
||||
| "down"
|
||||
| "left"
|
||||
| "right"
|
||||
| // Navigation keys
|
||||
"home"
|
||||
| "end"
|
||||
| "pageup"
|
||||
| "pagedown"
|
||||
| "insert"
|
||||
| "backtab"
|
||||
| // Function keys (pattern)
|
||||
("f" ~ number)
|
||||
| // Mouse events
|
||||
"mouse-scroll-up"
|
||||
| "mouse-scroll-down"
|
||||
}
|
||||
|
||||
// Character keys
|
||||
character_key = { ASCII_ALPHA | ASCII_DIGIT | symbol }
|
||||
|
||||
// Symbol definition
|
||||
symbol = {
|
||||
"!"
|
||||
| "$"
|
||||
| "%"
|
||||
| "^"
|
||||
| "&"
|
||||
| "*"
|
||||
| "("
|
||||
| ")"
|
||||
| "_"
|
||||
| "+"
|
||||
| "-"
|
||||
| "="
|
||||
| "["
|
||||
| "]"
|
||||
| "{"
|
||||
| "}"
|
||||
| "|"
|
||||
| "\\"
|
||||
| ";"
|
||||
| ":"
|
||||
| "'"
|
||||
| "\""
|
||||
| "<"
|
||||
| ">"
|
||||
| ","
|
||||
| "."
|
||||
| "?"
|
||||
| "/"
|
||||
| "~"
|
||||
| "`"
|
||||
}
|
||||
|
||||
// Event names - Ordered by usage frequency
|
||||
event_name = {
|
||||
"start"
|
||||
| "load"
|
||||
| "result"
|
||||
| "selection-change"
|
||||
| "resize"
|
||||
| "one"
|
||||
| "zero"
|
||||
}
|
||||
|
||||
// Action specifications - Ordered by complexity
|
||||
action_target = { single_action | action_block | action_array }
|
||||
|
||||
single_action = { action_name ~ action_params? }
|
||||
action_block = { "{" ~ action_statement* ~ "}" }
|
||||
action_array = { "[" ~ action_list ~ "]" }
|
||||
action_statement = { action_name ~ action_params? ~ ";"? }
|
||||
action_list = { action_name ~ ("," ~ action_name)* ~ ","? }
|
||||
action_params = { "(" ~ string_literal ~ ")" }
|
||||
|
||||
// Action names
|
||||
action_name = {
|
||||
// High frequency actions first
|
||||
"quit"
|
||||
| "nil"
|
||||
| "confirm_selection"
|
||||
| "select_and_exit"
|
||||
| // Navigation actions - grouped by prefix
|
||||
"select_next_entry"
|
||||
| "select_next_history"
|
||||
| "select_next_page"
|
||||
| "select_prev_entry"
|
||||
| "select_prev_history"
|
||||
| "select_prev_page"
|
||||
| // Toggle actions - grouped by prefix
|
||||
"toggle_help"
|
||||
| "toggle_preview"
|
||||
| "toggle_remote_control"
|
||||
| "toggle_selection_down"
|
||||
| "toggle_selection_up"
|
||||
| "toggle_status_bar"
|
||||
| // Scroll actions - grouped by prefix
|
||||
"scroll_preview_down"
|
||||
| "scroll_preview_half_page_down"
|
||||
| "scroll_preview_half_page_up"
|
||||
| "scroll_preview_up"
|
||||
| // Input actions
|
||||
"delete_line"
|
||||
| "delete_next_char"
|
||||
| "delete_prev_char"
|
||||
| "delete_prev_word"
|
||||
| "go_to_input_end"
|
||||
| "go_to_input_start"
|
||||
| "go_to_next_char"
|
||||
| "go_to_prev_char"
|
||||
| // System actions
|
||||
"resume"
|
||||
| "suspend"
|
||||
| // Channel actions
|
||||
"copy_entry_to_clipboard"
|
||||
| "cycle_sources"
|
||||
| "reload_source"
|
||||
| // Parameterized actions
|
||||
"execute"
|
||||
| "switch_to_channel"
|
||||
| // Generic extensibility
|
||||
identifier
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user