Repository: helix-editor/helix (language: rust)

Issue:
Invalid key code when mapping "-"
### Summary

Trying to map a `"-"` key to an action causes parsing failure.

Looking at the code, this is because `'-'` is used as a modifier separator and `"minus"` should be used instead. This restriction is not clear from docs alone, but imho rather than documenting it, it would be better to improve the parser to allow it as there is no ambiguity:

- without a modifier `"-"`: on it's own it is clear we're binding to this char
- with a modifier `"A--": arguably not as readable as `"A-minus"`, but the middle '-' must be a separator and the '-' the key code
- invalid binding `"A-"`: missing key code

### Reproduction Steps

trying to map a "-" key to an action with e.g.:

```toml
[keys.normal.space.w]
"-" = "hsplit"
```

causes a failure

```
Bad config: TOML parse error at line x, column y
    |
x | "-" = "hsplit"
    | ^^^
Invalid key code ''
```

### Helix log

_No response_

### Platform

cross-platform

### Terminal Emulator

any

### Installation Method

source

### Helix Version

helix 24.7 (cf81e153)


Discussion / hints:

Fix patch:
diff --git a/helix-view/src/input.rs b/helix-view/src/input.rs
index 5f5067eac9f8..bd737f231fa5 100644
--- a/helix-view/src/input.rs
+++ b/helix-view/src/input.rs
@@ -387,6 +387,23 @@ impl std::str::FromStr for KeyEvent {
                     .then_some(KeyCode::F(function))
                     .ok_or_else(|| anyhow!("Invalid function key '{}'", function))?
             }
+            // Checking that the last token is empty ensures that this branch is only taken if
+            // `-` is used as a code. For example this branch will not be taken for `S-` (which is
+            // missing a code).
+            _ if s.ends_with('-') && tokens.last().is_some_and(|t| t.is_empty()) => {
+                if s == "-" {
+                    return Ok(KeyEvent {
+                        code: KeyCode::Char('-'),
+                        modifiers: KeyModifiers::empty(),
+                    });
+                } else {
+                    let suggestion = format!("{}-{}", s.trim_end_matches('-'), keys::MINUS);
+                    return Err(anyhow!(
+                        "Key '-' cannot be used with modifiers, use '{}' instead",
+                        suggestion
+                    ));
+                }
+            }
             invalid => return Err(anyhow!("Invalid key code '{}'", invalid)),
         };
 
@@ -661,6 +678,13 @@ mod test {
                 modifiers: KeyModifiers::NONE
             }
         );
+        assert_eq!(
+            str::parse::<KeyEvent>("-").unwrap(),
+            KeyEvent {
+                code: KeyCode::Char('-'),
+                modifiers: KeyModifiers::NONE,
+            }
+        );
     }
 
     #[test]
@@ -721,6 +745,7 @@ mod test {
         assert!(str::parse::<KeyEvent>("FU").is_err());
         assert!(str::parse::<KeyEvent>("123").is_err());
         assert!(str::parse::<KeyEvent>("S--").is_err());
+        assert!(str::parse::<KeyEvent>("S-").is_err());
         assert!(str::parse::<KeyEvent>("S-percent").is_err());
     }
 


Test patch: