Skip to content

feat: add customizable keyboard shortcuts via textpod.toml#54

Open
SandroPacella wants to merge 2 commits intofreetonik:mainfrom
SandroPacella:feat/customizable-shortcuts
Open

feat: add customizable keyboard shortcuts via textpod.toml#54
SandroPacella wants to merge 2 commits intofreetonik:mainfrom
SandroPacella:feat/customizable-shortcuts

Conversation

@SandroPacella
Copy link
Copy Markdown

Summary

Resolves #46.

  • Adds an optional textpod.toml config file that users place in the working directory alongside notes.md
  • Shortcuts are defined under a [shortcuts] section (e.g. save = "Cmd+Enter")
  • Supported modifiers: Ctrl, Cmd, Alt, Shift, combinable with any key name
  • If no config file is present, defaults to Ctrl+Enter — fully backwards-compatible
  • Invalid TOML logs a warning and falls back to defaults
  • Placeholder text in the textarea updates to reflect the configured shortcut

Implementation

Reuses the existing {{FAVICON}} template injection pattern: the backend reads textpod.toml on startup, serializes the shortcuts config to JSON, and injects it into the HTML via {{SHORTCUTS_CONFIG}} and {{SAVE_SHORTCUT_DISPLAY}} template variables. The frontend matchShortcut() function parses the binding string and matches it against KeyboardEvent properties.

Config example

[shortcuts]
save = "Cmd+Enter"

Test plan

  • No config file: default Ctrl+Enter saves notes, placeholder says "Ctrl+Enter to save."
  • With save = "Cmd+Enter": Cmd+Enter saves, Ctrl+Enter does not, placeholder says "Cmd+Enter to save."
  • Invalid TOML: error logged, app starts with defaults
  • Tested on Chrome and Firefox on macOS

Reads an optional textpod.toml config file from the working directory
on startup. Shortcuts are defined under a [shortcuts] section (e.g.
save = "Cmd+Enter") and injected into the frontend via template
variables, reusing the existing {{FAVICON}} replacement pattern.

Defaults to Ctrl+Enter when no config file is present, keeping full
backwards compatibility. Resolves freetonik#46.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request adds customizable keyboard shortcuts to Textpod by introducing an optional textpod.toml configuration file. The implementation addresses issue #46, where users reported that the hardcoded Ctrl+Enter shortcut conflicts with Firefox on Mac. The feature maintains full backward compatibility by using Ctrl+Enter as the default when no config file is present.

Changes:

  • Added TOML-based configuration system for keyboard shortcuts with graceful fallback to defaults
  • Implemented frontend shortcut matching logic that supports Ctrl, Cmd, Alt, and Shift modifiers
  • Updated UI placeholder text to dynamically display the configured save shortcut

Reviewed changes

Copilot reviewed 4 out of 5 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/main.rs Added Config and ShortcutsConfig structs, TOML parsing at startup, and template injection for shortcuts
src/index.html Added matchShortcut() function and updated keydown handler to use configurable shortcuts
README.md Added Configuration section documenting the textpod.toml format and supported modifiers
Cargo.toml Added toml and serde_json dependencies
Cargo.lock Updated dependency tree with new packages

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +123 to +133
function matchShortcut(event, binding) {
const parts = binding.split('+');
const key = parts.pop();
const mods = parts.map(m => m.toLowerCase());
return (
event.key === key &&
event.ctrlKey === mods.includes('ctrl') &&
event.metaKey === mods.includes('cmd') &&
event.altKey === mods.includes('alt') &&
event.shiftKey === mods.includes('shift')
);
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The matchShortcut function has a case-sensitivity issue. The event.key property returns capitalized key names (e.g., "Enter", "Escape") but the function performs a strict equality comparison without normalizing the case. This means a configuration like save = "Cmd+enter" (lowercase) would fail to match. Consider normalizing both sides to lowercase for the key comparison, or document that key names must match the exact case returned by event.key (e.g., "Enter" not "enter").

Copilot uses AI. Check for mistakes.
Comment on lines +62 to +84
#[derive(Deserialize, Default)]
struct Config {
#[serde(default)]
shortcuts: ShortcutsConfig,
}

#[derive(Deserialize, Serialize)]
struct ShortcutsConfig {
#[serde(default = "default_save_shortcut")]
save: String,
}

impl Default for ShortcutsConfig {
fn default() -> Self {
Self {
save: default_save_shortcut(),
}
}
}

fn default_save_shortcut() -> String {
"Ctrl+Enter".to_string()
}
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no validation of the shortcut configuration value. If a user provides an invalid shortcut string (e.g., empty string, malformed format, or invalid key names), the application will still accept it and inject it into the HTML, potentially causing the shortcut functionality to silently fail. Consider adding validation to ensure the shortcut string follows the expected format (modifiers+key) and providing a warning or error if it's invalid.

Copilot uses AI. Check for mistakes.
@freetonik
Copy link
Copy Markdown
Owner

Huh, I've tried this new copilot code review feature. I did not focus-read the suggestions yet, but on a brief scan some of them at least sound relevant.

… default browser behavior when save shortcut is triggered

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@SandroPacella
Copy link
Copy Markdown
Author

SandroPacella commented Feb 26, 2026

Huh, I've tried this new copilot code review feature. I did not focus-read the suggestions yet, but on a brief scan some of them at least sound relevant.

I like these suggestions copilot made:

For e.preventDefault() —> I just pushed a commit. Without it the browser could intercept the shortcut before we ever see it.

On the case-sensitivity and validation points: both valid imo, and I want to address them. I’d rather not tack them onto this PR since they’d expand the scope pretty quickly. Would it make more sense to open follow-up issues so we can track properly, or do you want them handled here first?​​​​​​​​​​​​​​​​


An afterthought: I use StackEdit often and I hate when its key bindings override mine, so that's something I'll keep in mind here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Customizable shortcuts

3 participants