version bumped to 0.5.1
This commit is contained in:
89
README.md
89
README.md
@@ -1,6 +1,6 @@
|
||||
# mould
|
||||
|
||||
mould is a modern Terminal User Interface (TUI) tool designed for interactively generating and editing configuration files from templates. Whether you are setting up a `.env` file from an example, creating a `docker-compose.override.yml`, or editing nested `JSON`, `YAML`, `TOML`, `XML`, `INI`, or `Properties` configurations, mould provides a fast, Vim-inspired workflow to get your environment ready.
|
||||
`mould` is a modern Terminal User Interface (TUI) tool designed for interactively generating and editing configuration files from templates. Whether you are setting up a `.env` file from an example, creating a `docker-compose.override.yml`, or editing nested `JSON`, `YAML`, `TOML`, `XML`, `INI`, or `Properties` configurations, `mould` provides a fast, Vim-inspired workflow to get your environment ready.
|
||||
|
||||
## Features
|
||||
|
||||
@@ -9,7 +9,7 @@ mould is a modern Terminal User Interface (TUI) tool designed for interactively
|
||||
- **Smart Template Discovery**: Rule-based resolver automatically discovers relationships (e.g., `.env.example` vs `.env`, `config.template.properties` vs `config.properties`) and highlights missing keys.
|
||||
- **Strict Type Preservation**: Intelligently preserves data types (integers, booleans, strings) during edit-save cycles, ensuring your configuration stays valid.
|
||||
- **Add Missing Keys**: Instantly pull missing keys and their default values from your template into your active configuration with a single keystroke.
|
||||
- **Advanced Undo/Redo Engine**: Features a tree-based undo/redo history that ensures you never lose changes during complex branching edits.
|
||||
- **Advanced Undo/Redo Engine**: Features a tree-based undo/redo history that ensures you never lose changes during complex branching edits. It properly tracks all modifications, including nested renames and item additions/deletions.
|
||||
- **Vim-inspired Workflow**: Navigate with `j`/`k`, `gg`/`G`, edit with `i`, search with `/`, and save with `:w`.
|
||||
- **Modern UI**: A polished, rounded interface featuring a semantic Catppuccin Mocha palette with support for terminal transparency.
|
||||
- **Highly Configurable**: Customize keybindings and semantic themes via a simple TOML user configuration.
|
||||
@@ -74,15 +74,16 @@ Open any configuration file in Neovim and run `:Mould`. It will launch a floatin
|
||||
- `k` / `Up`: Move selection up
|
||||
- `gg`: Jump to the top
|
||||
- `G`: Jump to the bottom
|
||||
- `i`: Edit value (cursor at start)
|
||||
- `i`: Edit value (cursor at start). If selected is a group, enters rename mode.
|
||||
- `a`: Edit value (cursor at end)
|
||||
- `s`: Substitute value (clear and edit)
|
||||
- `r`: Rename the current key
|
||||
- `o`: Append a new item (as a sibling or array element)
|
||||
- `O`: Prepend a new item
|
||||
- `alt+o` / `alt+O`: Append/Prepend a new group/object
|
||||
- `t`: Toggle between group/object and standard value
|
||||
- `dd`: Delete the currently selected variable or group (removes all nested children)
|
||||
- `s` / `S`: Substitute value (clear and edit)
|
||||
- `r`: Rename the current key or group. (Cannot rename array indices).
|
||||
- `o`: Append a new item (as a sibling or array element). Enters rename mode for non-array items.
|
||||
- `O`: Prepend a new item (as a sibling or array element). Enters rename mode for non-array items.
|
||||
- `alt+o`: Append a new group/object as a child. Enters rename mode for the new group.
|
||||
- `alt+O`: Prepend a new group/object as a child. Enters rename mode for the new group.
|
||||
- `t`: Toggle the selected item between a group/object and a standard variable.
|
||||
- `dd`: Delete the currently selected variable or group (removes all nested children).
|
||||
- `u`: Undo the last change
|
||||
- `U`: Redo the reverted change
|
||||
- `a`: Add missing value from template to active config
|
||||
@@ -96,8 +97,8 @@ Open any configuration file in Neovim and run `:Mould`. It will launch a floatin
|
||||
- **Insert / Rename Modes**
|
||||
- Type your value/key string.
|
||||
- Arrow keys: Navigate within the input field
|
||||
- `Enter`: Commit the value and return to Normal Mode
|
||||
- `Esc`: Cancel edits and return to Normal Mode
|
||||
- `Enter`: Commit the value/key and return to Normal Mode. If renaming, checks for key collisions.
|
||||
- `Esc`: Cancel edits and return to Normal Mode. Reverts changes to the current field.
|
||||
|
||||
---
|
||||
|
||||
@@ -160,28 +161,54 @@ toggle_group = "t"
|
||||
|
||||
`mould` is written in Rust and architected to decouple the file format parsing from the UI representation. This allows the TUI to render complex, nested configuration files in a unified tree-view.
|
||||
|
||||
### Core Architecture
|
||||
### Core Architectural Principles:
|
||||
|
||||
1. **State Management & Undo Tree (`src/app.rs` & `src/undo.rs`)**
|
||||
- The central state is maintained in the `App` struct, which tracks the currently loaded configuration variables, application modes (`Normal`, `Insert`, `InsertKey`, `Search`), and user input buffer.
|
||||
- It integrates an **UndoTree**, providing non-linear, branching history tracking for complex edits (additions, deletions, nested renaming).
|
||||
- **Separation of Concerns**: Clear boundaries between UI rendering, application state, input handling, and file format logic.
|
||||
- **Unified Data Model**: All parsed configuration data is normalized into a single `Vec<ConfigItem>` structure, simplifying application logic across different file types.
|
||||
- **Vim-inspired Modality**: The application operates in distinct modes (`Normal`, `Insert`, `InsertKey`, `Search`), each with specific keybinding behaviors, enabling efficient interaction.
|
||||
- **Non-linear Undo/Redo**: A robust undo tree allows users to revert and re-apply changes across complex branching edit histories.
|
||||
|
||||
2. **Unified Data Model (`src/format/mod.rs`)**
|
||||
- Regardless of the underlying format, all data is translated into a flattened `Vec<ConfigItem>`.
|
||||
- A `ConfigItem` contains its structural path (`Vec<PathSegment>` handling nested Object Keys and Array Indices), values, type metadata (`ValueType`), and template comparison statuses (e.g., `MissingFromActive`).
|
||||
### Key Components
|
||||
|
||||
3. **Format Handlers (`src/format/*`)**
|
||||
- **`env.rs` & `properties.rs`**: Handlers for flat key-value files.
|
||||
- **`hierarchical.rs`**: A generalized processor leveraging `serde_json::Value` as an intermediary layer to parse and write nested `JSON`, `YAML`, `TOML`, and even `XML` (via `quick-xml` transposition).
|
||||
- **`ini.rs`**: Handles traditional `[Section]` based INI configurations.
|
||||
1. **State Management & Undo Tree (`src/app.rs` & `src/undo.rs`)**
|
||||
* The central state is maintained in the `App` struct, which tracks the currently loaded configuration variables, application modes, and user input buffer.
|
||||
* It integrates an **UndoTree**, providing non-linear, branching history tracking for complex edits (additions, deletions, nested renaming). Each significant state change (`save_undo_state`) pushes a snapshot to this tree.
|
||||
|
||||
4. **Template Resolver (`src/resolver.rs`)**
|
||||
- Automatically determines structural pairings without explicit instruction.
|
||||
- Uses hardcoded exact rules (e.g., `compose.yml` -> `compose.override.yml`) and generic fallback rules to strip `.example` or `.template` suffixes to find target output files dynamically.
|
||||
2. **Unified Data Model (`src/format/mod.rs`)**
|
||||
* Regardless of the underlying file format (JSON, YAML, .env, etc.), all data is translated into a flattened `Vec<ConfigItem>`.
|
||||
* A `ConfigItem` represents a single configuration entry. It contains:
|
||||
* `key`: The display key (e.g., `port` or `[0]`).
|
||||
* `path`: A `Vec<PathSegment>` (composed of `PathSegment::Key(String)` for object keys and `PathSegment::Index(usize)` for array indices) that defines its full hierarchical location.
|
||||
* `value`: `Option<String>` holding the actual value.
|
||||
* `is_group`: A boolean indicating if this item is a structural node (object or array).
|
||||
* `status`: (`ItemStatus::Present`, `MissingFromActive`, `Modified`) reflecting comparison with a template.
|
||||
* `value_type`: (`ValueType::String`, `Number`, `Bool`, `Null`) to ensure type preservation during writes.
|
||||
|
||||
5. **Terminal UI & Event Loop (`src/ui.rs` & `src/runner.rs`)**
|
||||
- **UI Rendering**: Powered by `ratatui`. Renders a conditional side-by-side or vertical layout consisting of a styled hierarchical List, an active Input field, and a status bar indicating keybind availability.
|
||||
- **Event Runner**: Powered by `crossterm`. Intercepts keystrokes, resolves sequences (like `dd` or `gg`), delegates to the `tui-input` backend during active editing, and interacts with the internal API to mutate the configuration tree.
|
||||
3. **Format Handlers (`src/format/*`)**
|
||||
* Each file format has a dedicated handler (`EnvHandler`, `IniHandler`, `HierarchicalHandler`, `PropertiesHandler`) implementing the `FormatHandler` trait.
|
||||
* **`HierarchicalHandler`**: A generalized processor leveraging `serde_json::Value` as an intermediary layer to parse and write nested `JSON`, `YAML`, `TOML`, and even `XML` (via `quick-xml` transposition). This allows complex structures to be flattened for editing and then re-nested accurately.
|
||||
* These handlers are responsible for translating between the file's native format and the `Vec<ConfigItem>` internal representation.
|
||||
|
||||
6. **Neovim Plugin (`lua/mould/init.lua`)**
|
||||
- Implements a Lua wrapper that calculates terminal geometries and launches the CLI `mould` binary inside an ephemeral, floating terminal buffer, triggering automatic Neovim `checktime` syncs on exit.
|
||||
4. **Template Resolver (`src/resolver.rs`)**
|
||||
* Automatically determines template-active file pairings without explicit user instruction.
|
||||
* Uses hardcoded exact rules (e.g., `compose.yml` -> `compose.override.yml`) and generic fallback rules to strip `.example` or `.template` suffixes to find target output files dynamically.
|
||||
|
||||
5. **Terminal UI & Event Loop (`src/ui.rs` & `src/runner.rs`)**
|
||||
* **UI Rendering (`src/ui.rs`)**: Powered by the `ratatui` library. Renders a flexible layout consisting of a styled hierarchical list, an active input field for editing, and a dynamic status bar.
|
||||
* **Event Runner (`src/runner.rs`)**: Powered by `crossterm`. It intercepts raw keyboard events, resolves multi-key sequences (like `dd` or `gg`), delegates character input to the `tui-input` backend during active editing, and dispatches actions to mutate the `App` state. It includes logic to prevent "one-key-behind" issues and manage complex keybindings like `alt+o`.
|
||||
|
||||
6. **Neovim Plugin (`lua/mould/init.lua`)**
|
||||
* Implements a Lua wrapper that calculates terminal geometries and launches the CLI `mould` binary inside an ephemeral, floating terminal buffer, ensuring automatic Neovim `checktime` synchronization upon `mould`'s exit.
|
||||
|
||||
### Development Process Highlights:
|
||||
|
||||
- **Iterative Refinement**: Features like key renaming, group creation, and advanced undo/redo were developed iteratively, responding to user feedback and progressively enhancing the core data model and interaction logic.
|
||||
- **Robust Error Handling**: Key functions (`commit_input`, `enter_insert_key`) include collision detection and validation to ensure data integrity during user modifications.
|
||||
- **Modality-driven Design**: The introduction of `InsertKey` mode and careful handling of `InsertVariant` demonstrates a commitment to a precise, context-aware user experience, minimizing ambiguity during editing.
|
||||
- **Debugging and Performance**: Issues like UI "hangs" were traced to subtle interactions in key event processing and input buffer management, leading to refactored key sequence logic for improved responsiveness.
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
|
||||
|
||||
Reference in New Issue
Block a user