-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Interpretation/handling of abstract commands feels unnecessarily strict #148
Comments
Thanks for the suggestions.
|
Number 2 is now crossed over. It sounds like it would have potential for breaking things. 🙂 |
I am also not entirely sure yet about 1. Not allowing unmapped abstract commands helps to spot typos like the following:
The user likely wants to map the |
Ah but I meant the other way around. To have abstract actions defined but not used in any mappings. 🙂 |
For instance, my use case is that I might have a set of abstract actions defined like below. Notice I have [class = JetBrainsIDE]
close_tab >> Alt{W}
close_tool_window >> Shift{Escape}
find >> Control{F}
find_in_files >> (Control Shift){F}
replace >> Control{R}
replace_in_files >> (Control Shift){R}
show_actions >> _Alt{A}
show_context_actions >> _Alt{Enter}
show_hover_info >> Control{F1}
show_quick_documentation >> Control{Q}
toggle_terminal >> ^ Alt{T}
toggle_problems >> ^ Alt{8}
goto_file >> Alt{P}
goto_symbol >> Alt{S}
goto_declaration >> Control{B}
goto_type_declaration >> (Control Shift){B}
goto_implementation >> Control{Alt{B}}
jump_to_text_start >> Control{Home}
jump_to_text_end >> Control{End}
jump_to_top >> Control{PageUp}
jump_to_bottom >> Control{PageDown}
jump_to_line >> Control{G}
jump_to_character >> Alt{Comma}
jump_to_word >> Control{Comma}
jump_to_matching_brace >> Control{Shift{M}}
jump_to_last_edit_loc >> Alt{Shift{E}}
next_error >> !Escape _Alt{Escape}
prev_error >> !Escape _Alt{Shift{Escape}}
next_function >> _Alt{ArrowDown}
prev_function >> _Alt{ArrowUp}
rollback_change >> (Control Alt){Z}
next_change >> (Control Alt){ArrowDown}
prev_change >> (Control Alt){ArrowUp}
next_difference >> (Control Alt){ArrowDown}
prev_difference >> (Control Alt){ArrowUp}
compare_next_file >> (Alt Shift){N}
compare_prev_file >> (Alt Shift){J}
extend_selection >> _Alt{W}
shrink_selection >> _Alt{Shift{W}}
cut_to_line_end >> !AltGr (Shift Control Alt){Delete}
delete_to_line_end >> !AltGr (Control Alt){Delete}
# join_lines >> _Control{J}
toggle_comment >> !Escape _Control{7}
toggle_block_comment >> !Escape _Control{Shift{7}}
accept_completion >> ^ Tab |
The other way round it would also have drawbacks. Allowing One could use something like the following to temporarily disable a command:
|
I see the issue now and agree it'd just make the situation worse. One way around this would be to enforce this recommendation from the documentation: Line 148 in 6b84248
This could be behind a "strict mode" startup flag or introduced as a breaking change. What do you think? Personally, I doubt the convenience would be worth the trouble for this alone. However, enforcing lower case initial letter for abstract actions sounds like an improvement in itself. It would for example:
|
Neat workaround. I personally would find that a bit cluttering as often the case has been that I want to use the keybinding for some other action. But using the same idea, I will definitely start doing this: None = Virtual99
None >> join_lines
None >> toggle_comment It can be a useful indicator of "TODO" items also. 👍 |
@houmain Ok to close this? |
I am thinking about adding directives some time.
Then I can also add a directive for allowing not mapped identifiers or enforcing some naming conventions. |
Great idea! |
@ristomatti did you see the new directives
|
Yup I've noticed! I've just installed yesterday evening. My plan was to test the new features and report back. Instead, I ended up doing a long overdue TODO item of extracting my Keymapper config and related scripts from my crowded dotfiles repo into a separate one. It ended up taking fair bit of time as I first had to learn how to use I can test the directives after sending this, perhaps also the other new features as well! The release notes also mentioned these changes which potentially sound like something I just bumped into a few days prior to the release. Could you give a couple of more examples on what this means in practice:
I'd also be interested in examples of issues these aim to fixed:
I'm asking since any one of these sound like potential fixes to some unexpected things I ran across. |
Happy to report both The only problem (for me) is that the fact that |
Perhaps Just to be sure I got it right, here's an example config to reflect my current understanding: # Aliases
CursorDown = J
CursorLeft = H
CursorRight = L
# Context block
[class = /chrome/i]
# Mapping to command "next_tab"
AltRight{CursorRight} >> next_tab
# Mapping to an undefined command
AltRight{CursorUp} >> move_tab_left
# Command
next_tab >> Control{PageDown}
# Unmapped command
previous_tab >> Control{PageUp} |
To further expand the above to cover more of the terms: # Directive
@enforce-lowercase-commands
# Command that launches an app / executes an external command
new_terminal >> $(xterm)
# Forwarded (modifier) key
Meta >> Meta
# Mapping to type a string literal
Meta{F1} >> 'Hello world'
# Logical alias
CursorDirection = CursorUp | CursorDown | CursorLeft | CursorRight
# Parameterized alias / macro
Hold = $0{250ms}
DoubleTap = $0 !200ms $0
# Partially matched input expression
? A S D F >> F D S A
# Mapping that releases the pressed key before typing
Shift{Space} >> !Shift Backspace |
String literals as input is pretty cool. I guess it doesn't add anything that couldn't have been done already but it makes it a lot easier to use (and read) mappings consisting of a sequence of keys. For example: AltRight 'w1' >> Meta{1}
AltRight 'w2' >> Meta{2} I tried something like this as well and it worked: Repeat3x = $0 $0 $0
? 'asdf' >> Repeat3x[Backspace] 'fdsa' I also tried this: Alt{'123'} >> '456' That gave me an error, but I didn't even expect it work. 🙂 |
Sorry, now in 4.7.0 it should.
I would say that
This did not work correctly, since pressing
Allow to undo ! in input. e.g. !Shift A Shift{B}: Preserving order of hold back output.
I would rather call these no-partial-match input expressions (internally they are called no-might-match expression). |
In 4.7.0 there is now a built-in repeat macro, so this would also work:
And also a
|
Just read the release notes 🤯. That sounds pretty sweet. I'll do a round of testing after I've installed my new ergo gear that just got delivered. 😁 |
First observation. After upgrading, my config failed validation due to an error I haven't encountered before: [device = Mouse]
Mouse = /Mouse|Logitech USB Receiver|G502/i The issue went away by renaming the macro to be something that doesn't exist in the value. Is this intentional or a bug? The macro evaluation seems a bit "too eager" now? 🙂 |
Perhaps you're thinking about it based on how it's handled in the implementation rather than what it seems like to a user? 😬
It does indeed! 👍 The new directives now solve the grievanses this issue was originally about, so I'm closing this. I'll probably still post some quick feedback on the newly added features here, just to keep the discussion in one place. |
This is pure gold. The substitution happens so fast it feels as if I've just typed the substituted string 😂. Does the evaluation of I'm asking because I've tried using them as part of some tricky to get right alternative modifier mappings. I don't remember the specific expressions I tried but it ended up creating a huge lag in all input. Most recent time was during an attempt to use SpaceMeta = Virtual8
Modifier = ControlLeft | ControlRight | MetaLeft | MetaRight | AltLeft | AltRight | ShiftLeft | ShiftRight
[default]
Shift >> Shift
[modifier = "SpaceMeta"]
Modifier >> (Meta Modifier)
Any >> Meta{Any}
[modifier = "!Modifier"]
Space{!150ms} >> Space ^
Space{150ms} >> SpaceMeta ^ SpaceMeta
[default]
Shift{Space} >> Space
Space >> Space |
Just out of curiosity, I tried to simulate Espanso's string substitution with command output. It's not as elegant as few lines of YAML, but it can be done! 😁 Time = Virtual50
subst_virtual = ? "$0" >> repeat[Backspace, sub[length["$0"], 1]] $1
[default]
ContextActive >> $(while true ; do (keymapperctl --instance time --wait-toggled "Time" --type $(date +"%H:%M:%S") &) ; sleep 1 ; done)
subst_virtual[":time", Time] |
Thanks for the feedback! Yes, this is a bug.
I think no more than the other mapping.
I do not know of any performance problems. I would be glad for a configuration to reproduce. Why not "simply" (I have not tested it)? subst = ? "$0" >> repeat[Backspace, sub[length["$0"], 1]] $1
Time = $(keymapperctl --type $(date +"%H:%M:%S"))
subst[":time", Time] |
I blame the late hours (testing around 3-4am...). I didn't test yet myself but surely it will work. My first idea yesterday was using something like
I'll check if some version of it ended up on to a commit before deletion. |
To completeness sake, here's an Espanso config snippet: matches:
- trigger: ":tel"
replace: "+1234567890"
- trigger: ":gm"
replace: "[email protected]"
- trigger: ":dts"
replace: "{{datetime}}"
vars:
- name: datetime
type: date
params:
format: "%Y-%m-%d-%H-%M"
- trigger: ":ds"
replace: "{{date}}"
vars:
- name: date
type: date
params:
format: "%Y-%m-%d"
- trigger: ":now"
replace: "{{time}}"
vars:
- name: time
type: date
params:
format: "%H:%M" The same ported over to Keymapper format: type = $(keymapperctl --type $0)
format_date = $(date +"$0")
replace = ? "$0" >> repeat[Backspace, sub[length["$0"], 1]] $1
[default]
replace[":tel" type["+1234567890"]]
replace[":gm", type["[email protected]"]]
replace[":now", type[format_date["%H:%M:%S"]]]
replace[":dts" type[format_date["%Y-%m-%d-%H-%M"]]]
replace[":ds", type[format_date["%Y-%m-%d"]]] |
@houmain While cobbling that together, I ran across this rather unexpected issue: subst_str = ? "$0" >> repeat[Backspace, sub[length["$0"], 1]] "$1"
subst = ? "$0" >> repeat[Backspace, sub[length["$0"], 1]] $1
Time = $(keymapperctl --type $(date +"%H:%M:%S"))
subst_str = [":gm", "[email protected]"] # ✅
subst[":time", Time] # ✅
subst[":tel", "+1234567890"] # ❌
# ERROR: Key name expected at '+' at "Backspace Backspace Backspace +1234567890" in file '@)duU Is this a bug or expected behavior? I'd have expected |
Would it simplify parsing macros with parameters if there was an explicit syntax to do that? Something like a lambda expression: subst = [$input, $output] -> ? "$input" >> repeat[Backspace, sub[length["$input"], 1]] $output To my programmer brain this would feel easier to read, but not sure if that would be the case for non-programmers. That line becomes quite long though, it would be a nice have to be able to use e.g. shell command style string splitting. 😉 subst = [$input, $output] -> ? "$input" >> \
repeat[Backspace, sub[length["$input"], 1]] $output |
I've fiddled with the configs enough for today, but I found some earlier revisions that still had some of the potentially problematic no-might-match expressions. It might have been this one: https://github.com/ristomatti/keymapper-config/blob/29a4d248db1c5f93166426274730b078cc75ae9a/keymapper.conf#L310. IIRC all the related mappings are within the section marked "Stage 0" at the time. BTW - in case you still want to link to my config in README.md, I've moved it from GIST into it's own repo (together with some related scripts etc.): https://github.com/ristomatti/keymapper-config. It also includes the gnarly commit history since I found Keymapper (extracted from my private dotfiles repo using |
Damn, I just casually threw in the idea 5 hours ago and you just went on an implemented it. 💪! |
This should be fixed in 4.7.1.
Great, that does not look too bad to me!
This is the intended behavior. The quotes are not part of the parameter value. They are only for passing strings containing trailing spaces, a comma, ... macro = $0
# these are the same:
macro["Abcd"]
macro[Abcd]
# these are not:
macro["A, B"]
macro[A, B] So the macro decides, if the value should be in quotes or not: macro = $(echo "$0")
macro = $(echo $0)
I don't think, it would simplify the code. Maybe the usage. But I thould bash also did not need more sophisticated parameter passing...
I threw these lines in my config, but did not notice a problem so far: VSpace = Virtual10
SpaceModifier = Control | Alt | Shift | Meta | Escape
SpaceModifier{Space} >> SpaceModifier{Space}
? SpaceModifier Space >> SpaceModifier Space
? Space Space >> VSpace
Link updated!
This should also work now in 4.7.1. |
Crazy, I think the last ten github accounts which starred keymapper are bots or something. Several joined github on the same day and most have the same incomplete README... |
Thanks for the clarification on macro behavior, it makes a lot more sense now.
Valid point! |
Weird! Maybe some backlinking scheme? I've also got some obscure followers on my profile. Most are people I know but there's some that I have no clue why they'd follow me. |
BTW, v4.7.1 seemed to break a lot of stuff. I'm getting errors at sections that have been untouched for ages. Also the just added text expansion config reports an error. I don't know if these are all the errors but:
|
I had backquotes within two |
I've got only couple of minor uncommitted changes to what's on my repo, so the config from there should error as well.
|
Oops, I removed the release. |
Not sure if relevant but note that regex matchers might contain backquotes as well. |
I've downgraded back to 4.7.0, take your time. 🙂 |
Here's a snippet to paste in place of the
->
|
Crap, I forgot to warn about the parts that modify input settings and write stuff to Commenting this out from # Startup sequence
[default]
ContextActive >> on_startup
on_startup >> createStateDir applyInputDeviceConfig |
Please give the new 4.7.1 a try! There is one breaking change though:
|
I consider this an improvement. It was rather unexpected behavior to begin with. 👍 Breaking lines with Great work as always! |
I believe the current handling of abstract commands is too strict and has some limitations that I've found a bit unexpected. This is about two separate issues, but I still decided to create only a single issue. I can split these into separate issues if that's preferred.
1. Unused abstract command makes the config invalid
In some situations this behavior is useful, but it can also create a jarring user experience. I think a warning would be more appropriate. This feels also inconsistent as an unused alias doesn't make the config invalid, even though they can sometimes be used for the same purpose.
There's two situations when I find this especially jarring. First example: when I start remapping a new app, I'd like to first write all the abstract commands I'm expecting to remap. Coming up with intuitive remappings some times takes some time so I might not do them all at once. I then have to comment out the commands and uncomment the commands, while I'd prefer them to be there when I need them.
The other type of situation I find this jarring is when some remap I've done turns out interfering with some other functionality while I'm working. I then usually just comment it out to be fixed later, but I then end up with an invalid config and have to go back and also comment out the abstract command.
2. Abstract commands cannot be combined with other output mappingsA couple of examples which illustrate how this can feel inconsistent or confusing.
Example 1:
✅ Base config
❌ Naive attempt to use abstract command, invalid
✅ The above would be valid using an alias
Example 2:
✅ Debugging a config
❌ Further debugging, invalid config
✅ Same with an alias, valid
The text was updated successfully, but these errors were encountered: