aboutsummaryrefslogtreecommitdiffstats
path: root/src/parser.rs
AgeCommit message (Collapse)Author
2018-11-03parser: Remove unnecessary `expected` definition in testTeddy Wing
2018-11-03parser::mode(): Remove comment about verifying '}'Teddy Wing
This functions correctly. No need for the TODO.
2018-11-03parser: Add a failing test for parse errors in the middle of linesTeddy Wing
We currently correctly report errors in the middle of the first line (problems with the trigger, problems with special keys in an action), but for all subsequent lines, the error message is limited to the first character on the line. This means that even if you write "map", "cmd", or "mode", which are all correct, the error message will refer to "column 1", even though the actual error is in a different part of the parser. Not sure why that's happening, nor why it doesn't happen for the first line. But at least we have a test for it now. The test will need to be modified once I can actually get the error messages propagating correctly, as the `Expected` lines are going to be wrong. They were just copy-pasted from the test above this one.
2018-11-03parser: Remove `map_kind()` parserTeddy Wing
This was split into two new functions, `map_kind_map()` and `map_kind_cmd()`, in 7776832ec11ee7d4e62cfd2a6ad7735f323ab5bc. As such, this function is no longer used or needed. Update the tests to use the new parser functions.
2018-11-03parser: Remove `MapAction::parse()` etc. code from second parser passTeddy Wing
Revert changes from 75d52e385fa66d6e151c9baa2cf22c2223c39ff0. These are obsolete. Now that we parse actions right in the main parser (7776832ec11ee7d4e62cfd2a6ad7735f323ab5bc), get rid of all code related to the second pass parser from `Action::String`s into `Action::Map`s, as it's obsolete. All of this action parsing is now handled by the main `map_group()` parser.
2018-11-03parser: Parse `Action::Map`s at the same time as everything elseTeddy Wing
Was having a hell of a time trying to return a `Result` from `MapAction::parse()` in 75d52e385fa66d6e151c9baa2cf22c2223c39ff0. After struggling with it, I started to think if there was a different way to go about this. Previously I had tried and failed to parse map actions in the main parser. If I could get that working, then this whole `MapAction::parse()` method would be obsolete. No need to muss with `Result`s and borrowed strings at all. When I originally wrote the parser code, I thought in terms of: "How do I get the parsed result of the `map()` parser into the `action()` parser so that it can conditionally parse one way for the `map` keyword, and another for the `cmd` keyword?". In hindsight, this was incredibly idiotic, but I guess I was too close to the code and too deep in the details. Obviously the answer to parsing differently depending on `map` or `cmd` is not to get the parsed result of `map()` into `action()`. These are parser combinators. _Of course_ we can just make two map definition parsers, one for `map` and another for `cmd`. Can't believe I never thought of that last time. Who knows how much time I wasted trying and failing, then writing a sub-optimal solution. Oh well, I guess I should just be thankful that a niggling logging problem (in `MapAction::parse()`) that turned into a maddening journey to a giant brick wall in search of a `Result` return value with correct borrows finally enlightened me to the fact that I was doing the wrong thing all along. * Comment out double-parsing code related to `MapAction::parse()` because we want to parse in a single go. No more two-pass parsing. * Split the `map_kind()` parser into two separate parsers for `map` and `cmd`. Similarly, split the `map()` parser into `map_map()` and `map_cmd()` for the same reason. Our new parser tree looks like this: map(): map definition line -> map_map(): `map` definitions -> map_kind_map(): `map` -> map_cmd(): `cmd` definitions -> map_kind_cmd(): `cmd` * Up the `recursion_limit` to 256 from 128 because I was getting stack size errors randomly when I was updating the tests for this code change. * Update `action_character()` to not parse `\n` newlines. Otherwise the newline gets included as a real `Character` in the `KeyboardKeyWithModifiers` vector. * The `map_collection_fails_without_terminating_newline()` test fails as a result of the `action_character()` parser change. Previously it relied on `map` lines parsing to `Action::String`s, which fail if there's no terminating newline. Now that `map`s parse to `Action::Map`s, the newline isn't checked by the map line parser (`map_map()`). Because the newline doesn't matter for `map` definitions, the parser would return `Ok`, failing this test even though the behaviour was correct. Change the map line to a `cmd` to have the test check the behaviour it was previously testing. * Update the tests to use parsed `Action::Map` instead of `Action::String`s where appropriate. Used this program to convert the strings into the correct source code: # action_string_to_action_map.py #!/usr/bin/env python3 import sys action_string = sys.argv[1] action = '' action += 'action: Action::Map(vec![\n' for c in action_string: action += ' KeyboardKeyWithModifiers::new(\n' action += " KeyboardKey::Character(Character::new('{}')),\n".format(c) action += ' vec![],\n' action += ' ),\n' action += ']),' print(action)
2018-11-02MapAction::parse(): Try to return a `Result` (WIP)Teddy Wing
Want to be able to return a `Result` here so we can print the error from the `ffi` module so we don't have to permit 'stderrlog' on this parser module. Beset with errors like this: error[E0506]: cannot assign to `self.action` because it is borrowed --> src/parser.rs:188:21 | 176 | Action::String(ref s) => { | ----- borrow of `self.action` occurs here ... 188 | self.action = action; | ^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.action` occurs here error: aborting due to previous error Even cloning the `Action` doesn't work because the Combine error `Result` needs an `&str` reference to the parser input, and if we reassign `self.action`, that string reference would disappear. Need to figure out a different way of dealing with this, but I at least want to commit what I have because the next step is going to be something different.
2018-11-01parser::map_group(): Always parse to end of inputTeddy Wing
Previously, the modified input in `map_group_with_invalid_input_fails()` in this commit would fail with a result of `Ok` instead of `Err`. The `map_group()` parser would parse the first, correct line, and ignore the second, incorrect one. That's wrong. We want the whole parser to fail because it contains an invalid sequence. Do this by ensuring `eof()` follows all `definitions()`. This way we're guaranteed to always parse the whole input, and any errors within get surfaced.
2018-11-01parser: Reuse `SourcePosition` importTeddy Wing
This type is already imported. No need to use the full path.
2018-11-01parser: Restore `Map` structTeddy Wing
In 13e90c090923a209e5e26fb3e609d5d12f737f53 I decided to make `Map` a type alias to a tuple containing the key-value pair used by `MapCollection`. Here I've decided that I prefer the type as it was before. Sure, it was more of an intermediary type, but it did have a name that was used consistently. We do have to leave in our custom `HashMap` building, so perhaps this isn't the ideal solution, but I'm going with it, at least for now.
2018-11-01map_group(): Parse input full of `blank()` to `MapGroup` defaultTeddy Wing
An input with all mixed whitespace and comments should behave the same as empty input.
2018-11-01parser: Parsing an empty string gives a default `MapGroup`Teddy Wing
Since the most recent `many1` change (09c0a432fb339a2218096bb9a4398fb86301488f), the parser fails on end-of-input, or an empty string. In that case, it should instead return the default `MapGroup`. Add a special case for this.
2018-11-01parser: Propagate errors to the root parserTeddy Wing
Thanks to Arnavion on Mozilla#rust for clueing me into this: > The documentation starts with "A parser in this library can be > described as a function which takes some input and if it is > successful, returns a value together with the remaining input." > Key phrase being "with the remaining input" > So I assume it just matches as best as it can (which is nothing, in > your case) > Maybe you want to use some one-or-more combinator rather than many > which is a zero-or-more combinator > Then add your own check that "the remaining input" is empty Replacing my `many()` parsers with `many1()` correctly propagates errors up from sub-parers. Nice! This will fail when we try to parse an empty string, but we can just add a special case for that to parse successfully.
2018-11-01parser: Change `Map` to a tuple type aliasTeddy Wing
Investigating why I'm not getting error messages in my parsed result. The layer where I stop getting them is when parsing to a `MapCollection`. Split the list of `map()` parser out from `map_collection()` to get more information. Turns out that the new `maps()` parser is now where parse errors get discarded. In an attempt to get the errors to appear, I tried to replicate the structure of Combine's INI example parser: https://github.com/Marwes/combine/blob/921202a018000041c9d3e8b12b7c1a53d0252f67/examples/ini.rs That program makes a `property()` parser which outputs a 2-tuple of `(String, String)`, and a `properties()` parser which outputs a `HashMap<String, String>`, using the values in the tuple to construct the HashMap. Unfortunately, this change didn't solve the problem of the non-bubbling error messages. Unsure about whether or not to keep this change.
2018-10-30parser::key_code(): Remove old commented codeTeddy Wing
This was here for reference. No longer needed.
2018-10-30parser::map_group(): Use default `MapGroup` as a baseTeddy Wing
This means that if any of `<Up>`, `<Play>`, or `<Down>` are undefined in the mappings file definition, they will be set to their default action values (as set in `MapGroup::default()`). To get rid of the default, map the button trigger to `<Nop>`. Update a test that didn't map `<Up>` to give it the default mapping.
2018-10-30If no 'mappings.dkmap' file is found, use default mappingsTeddy Wing
If a mappings file is found but is empty, no mappings will be set. Hmm, that sounds wrong. We still want to keep the defaults even if only some button triggers are mapped. Making buttons do nothing is what `<Nop>` is for, not this behaviour. Darn.
2018-10-29KeyboardKeyWithModifiers.tap(): Remove old commented codeTeddy Wing
This idea is replaced by code from 'autopilot', which lives in the `autopilot_internal` module.
2018-10-28MapAction::parse(): Use `error!` instead of `dkeprintln!` to log errorTeddy Wing
Seemed to make more sense as it will be printed to the daemon's stderr log when reloading mappings.
2018-10-28MapAction::parse(): Log error instead of unwrappingTeddy Wing
Don't panic on error. Instead display the error to the user.
2018-10-28MapGroup: Move `parse_action()` to `MapAction`Teddy Wing
Looking at the function, it makes more sense to put it inside a `MapAction` impl since it operates on a `MapAction`.
2018-10-28MapGroup::parse_action(): Accept `MapKind::Command` variant handlerTeddy Wing
I had written that TODO when I thought we were going to be parsing `Action::Command`s. I ended up completely getting rid of `Action::Command`, and putting commands in `Action::String`s instead.
2018-10-28parser: Remove old commented `Action` typeTeddy Wing
2018-10-27parser: Make `KeyboardKey` privateTeddy Wing
Get rid of these warnings: warning: private type `parser::Character` in public interface (error E0446) --> src/parser.rs:72:15 | 72 | Character(Character), | ^^^^^^^^^ | = note: #[warn(private_in_public)] on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537> warning: private type `parser::KeyCode` in public interface (error E0446) --> src/parser.rs:73:13 | 73 | KeyCode(KeyCode), | ^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537>
2018-10-27Action: Remove `Action::Command` variantTeddy Wing
I wasn't using it. At first I added it because it made sense, but ultimately I ended up using `Action::String` for commands instead because that was easier.
2018-10-27Remove `Action` implTeddy Wing
This function isn't used
2018-10-27Delete unused importsTeddy Wing
2018-10-18Add a `<Nop>` pseudo-keyTeddy Wing
This "key" creates an empty action that doesn't do anything. Allows users to clear the default behaviour of a headphone button.
2018-10-18parser: Add a basic test for `NXKey` parsingTeddy Wing
2018-10-18Parse `NXKey`sTeddy Wing
Add a new parser for `NXKey`s. I originally thought I was going to add this to the `key_code()` parser, but that one parses to `KeyCode`s. Seemed like it would be easier to make a brand new parser to handle the different type. Need to add tests for this.
2018-10-18Add `NXKey` to `KeyboardKeyWithModifiers`Teddy Wing
Add this new key type to the enum and enable it to be `tap()`ped like the others. Made `NXKey` a type alias instead of a struct to allow us to refer to any of the NX key constants using the `NXKey` type. This also meant moving those NX constants outside of the `NXKey` impl and into the top level. May end up wrapping them back up in some kind of namespace later. Adjusted the public-ness of some functions to support this change.
2018-10-03Remove `action_parses_command_to_vec_of_words()` testTeddy Wing
Commands now stay `Action::String`s without getting re-parsed to `Action::Command`s (as per 79dfb6c8cd536e9448f05421d5018785a8b590ce). This test is therefore unnecessary.
2018-10-03parse_actions(): Parse `Action::Map` for mode mapsTeddy Wing
Previously I had only implemented it for top-level maps. Get it working for in-mode maps too. Move the parsing code to a function so it can be re-used in both places.
2018-10-03Remove old code from 52398f0c8507fdb5fe4a680bbbb841232b396ae7Teddy Wing
Non-working attempts.
2018-10-03run_key_action_for_mode(): Tap keys using `KeyboardKeyWithModifiers`Teddy Wing
Use `autopilot::key::tap()` to simulate each key and modifier in an action. Originally tried to do this using a method that takes a closure to access the `KeyCodeConvertible` types inside `KeyboardKey`. Ended up with a much cleaner API solution that only requires a single method call.
2018-10-03KeyboardKeyWithModifiers: Remove `Option` from `flags` fieldTeddy Wing
I originally wrapped the contained `Vec` in an `Option` to that we wouldn't have to initialise whole new empty `Vec` for every key in an `Action` list. However, this made less sense once I wrote the parser and ended up with an empty `Vec` by default that I then had to convert into an `Option`. Now I've started the code to type keys including modifiers, and the `Option` no longer makes any sense at all. In order to type keys (including modifiers), I'll be using Autopilot's `tap()` function: pub fn tap<T: KeyCodeConvertible + Copy>(key: T, flags: &[Flag], delay_ms: u64) { This function requires a slice, so I ended up getting a `Vec` from my parser, converting it to an Option to satisfy my original interface, and now would have to convert it back into a `Vec` or slice in order to be able to pass it into `tap()`. Talk about unnecessary. Get rid of the `Option` because it's more work for absolutely no reason.
2018-10-03Clean up old code from 48fcb96befe65ca30bfd91f4194afb9e99258f4aTeddy Wing
Get rid of old commented code now that we have a working version.
2018-10-02Re-parse map `Action::String`s to `Action::Map`s (WIP)Teddy Wing
First, `MapGroup::parse` parses actions to `Action::String`s. We then run a second pass on the parsed actions to parse them into `Action::Map`s. A few failed attempts but finally got it working. Tried a few ways of doing it and kept running into various borrowing problems. Glad it's working now.
2018-10-01Revert "Add <Bslash> and <lt> escapes for action (WIP)"Teddy Wing
This reverts commit 5ef2443642a2d8b223afdf169200a725d2809b76. See that commit for details.
2018-10-01Add <Bslash> and <lt> escapes for action (WIP)Teddy Wing
Trying to add new escape special keys for '\' and '<' but having a bit of trouble. Looks like I'm not using `and` `satisfy` correctly, as I'm getting this error: error[E0271]: type mismatch resolving `<(impl combine::Parser, combine::combinator::Satisfy<_, [closure@src/parser.rs:263:56: 263:68]>) as combine::Parser>::Output == char` --> src/parser.rs:260:18 | 260 | (choice!( | __________________^ 261 | | try(string_case_insensitive("Bslash")).map(|_| '\\'), 262 | | try(string_case_insensitive("lt")).map(|_| '<'), 263 | | try(action_character().and(satisfy(|c| c != '>'))) 264 | | ).map(|c| | |_________________^ expected tuple, found char | = note: expected type `(char, _)` found type `char` = note: required because of the requirements on the impl of `combine::Parser` for `combine::combinator::Try<(impl combine::Parser, combine::combinator::Satisfy<_, [closure@src/parser.rs:263:56: 263:68]>)>` = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) I had added the `satisfy` not '>' after getting this test failure without it: ---- parser::tests::action_parses_map_with_bslash_and_lt_special_keys stdout ---- thread 'parser::tests::action_parses_map_with_bslash_and_lt_special_keys' panicked at 'assertion failed: `(left == right)` left: `Err(Errors { position: PointerOffset(4332007031), errors: [Unexpected(Token('l')), Expected(Token('>'))] })`, right: `Ok(Map([KeyboardKeyWithModifiers { key: Character(Character(Character('a'))), flags: None }, KeyboardKeyWithModifiers { key: Character(Character(Character('\\'))), flags: None }, KeyboardKeyWithModifiers { key: Character(Character(Character('A'))), flags: None }, KeyboardKeyWithModifiers { key: Character(Character(Character('N'))), flags: None }, KeyboardKeyWithModifiers { key: Character(Character(Character('D'))), flags: None }, KeyboardKeyWithModifiers { key: Character(Character(Character('<'))), flags: None }, KeyboardKeyWithModifiers { key: Character(Character(Character('>'))), flags: None }, KeyboardKeyWithModifiers { key: Character(Character(Character('\\'))), flags: Some([Control]) }, KeyboardKeyWithModifiers { key: Character(Character(Character('<'))), flags: Some([Meta, Shift]) }]))`', src/parser.rs:928:9 as I suspected this was a problem with `<lt>`. But now that I think about it, it could just as easily have been a problem with `<Bslash>`. Not sure. Anyway, I'm thinking of dropping these escapes because they're redundant (we already have '\' escaping) and because I'm tired of these errors.
2018-10-01Fill in `action_parses_map_with_simple_characters()` testTeddy Wing
A simple test to check parsing of a simple string without any special keys or modifiers.
2018-09-30Fill in `action_parses_map_with_multiple_modifiers()`Teddy Wing
Make this test do something, validating that it parses multiple modifier prefixes in a special key.
2018-09-30action_parses_map_with_less_than_escape(): Add `>` to end of test stringTeddy Wing
Add a '>' closing bracket to the end of the test string to make sure that the '<' gets escaped even with a '>' following it.
2018-09-30special_key(): Handle modifier + character special keysTeddy Wing
Previously we were able to parse modifier + KeyCode (`<C-Enter>`) special keys and plain KeyCode ones (`<Esc>`). This change adds parsing support for the final type of special key, modifier + character (e.g. `<C-l>`). action_character(): Move the `map` outside of this function and into `action_map()` to allow us to reuse the parsed `char` in `special_key()`. key_modifier(): * Move the `many()` parser and `Option` handling outside of this function and into `special_key()`. Doing so enables us to say: <C-l> // Character special keys _require_ a modifier (thus // `many1`) <[C-]Left> // KeyCode special keys may or may not have a modifier // (thus `many`) * Rename from `key_modifiers()` to singular now that it only parses a single modifier. special_key(): Parse both character and KeyCode special keys with modifiers. action_parses_map_with_modifier(): Change input string to include a KeyCode-style special key with a modifier since we didn't have one previously. This ensures we test both kinds of special keys.
2018-09-30Try to parse modifier keys (WIP)Teddy Wing
Add some parsing code for modifier keys inside special keys (`<`- `>`-wrapped keys). Currently only works for special keys defined in `special_key()`. Needs to be extended to work for modified character keys (e.g. <C-l>), thus the test in this commit doesn't pass.
2018-09-30action_map(): Add backslash escapingTeddy Wing
Escape '<' and '\' by prepending a backslash. Since special characters are enclosed in '<' '>' brackets, in order to type a literal '<', we need a way to escape it. Use backslash, like in Vim.
2018-09-30Extract action normal character parsing to a functionTeddy Wing
Splits up the `action_map()` function and gives the parser a name.
2018-09-30Get `action_map()` parser workingTeddy Wing
Additionally, fix a problem in `key_code()` when using special key names that start with the same character (like any of the F keys, or Enter and Esc). The parser would discard the first character, like in the `definitions()` parser. Use the same solution here, by wrapping the parser choices in `try()`s. Add `Esc` to the test to confirm that it fails not just for the F keys but for all key names that start similarly.
2018-09-30parser: Add `key_code` and `special_key` parsersTeddy Wing
Still need to test them though. They'll be used in conjunction with another new parser, `action_map`, which will parser map-type action strings. `key_code` parses `autopilot::key::KeyCode`s, basically all special keys and modifiers. `special_key` parses key codes inside `<` `>` braces. Change the test to use `easy_parse` to give a clear error message. Add `recursion_limit` to the crate on the advice of the compiler in order for the `choice!` macro in `key_code()` to work properly. Otherwise it spits out a giant error message complaining about `rustc --explain E0277`. If I remove a handful of elements from the `choice!`, it compiles, so it seems there's an upper bound restricted by the recursion limit. Modifier keys are included in a commented section as these are part of the 'autopilot' `KeyCode` enum, but they'll be handled in a separate parser.
2018-09-29Start filling new action parser testsTeddy Wing
* Some stub ideas for test text * Fill in the test for special keys * Add some convenience methods to more easily create the expected test result objects