Skip to content
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

New keybindings #143

Merged
merged 7 commits into from
Jul 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion etc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ include $(TOPDIR)/build/system-inc.mk
######################################

ETC = cfg_notion.lua cfg_notioncore.lua cfg_kludges.lua cfg_defaults.lua \
cfg_tiling.lua cfg_query.lua cfg_menu.lua \
cfg_tiling.lua cfg_query.lua cfg_menu.lua cfg_bindings.lua \
cfg_notion3_bindings.lua cfg_notion3_tiling.lua \
cfg_statusbar.lua cfg_dock.lua cfg_layouts.lua \
look_brownsteel.lua look_clean.lua look_dusky.lua \
look_greyviolet.lua look_ios.lua look_cleanviolet.lua \
Expand Down
371 changes: 371 additions & 0 deletions etc/cfg_bindings.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,371 @@
--
-- Notion core configuration file
--


--
-- Bindings. This includes global bindings and bindings common to
-- screens and all types of frames only. See modules' configuration
-- files for other bindings.
--


-- WScreen context bindings
--
-- The bindings in this context are available all the time.
--
-- The variable META should contain a string of the form 'Mod4+'
-- where Mod4 maybe replaced with the modifier you want to use for most
-- of the bindings. Similarly ALTMETA may be redefined to add a
-- modifier to some of the F-key bindings.

defbindings("WScreen", {
bdoc("Switch to n:th object (workspace, full screen client window) "..
"within current screen."),
kpress(META.."1", "WScreen.switch_nth(_, 0)"),
kpress(META.."2", "WScreen.switch_nth(_, 1)"),
kpress(META.."3", "WScreen.switch_nth(_, 2)"),
kpress(META.."4", "WScreen.switch_nth(_, 3)"),
kpress(META.."5", "WScreen.switch_nth(_, 4)"),
kpress(META.."6", "WScreen.switch_nth(_, 5)"),
kpress(META.."7", "WScreen.switch_nth(_, 6)"),
kpress(META.."8", "WScreen.switch_nth(_, 7)"),
kpress(META.."9", "WScreen.switch_nth(_, 8)"),
kpress(META.."0", "WScreen.switch_nth(_, 9)"),

bdoc("Switch to next/previous object within current screen."),
kpress(META.."grave", "WScreen.switch_next(_)"),
kpress(ALTMETA.."asciitilde", "WScreen.switch_prev(_)"),

submap(META.."O", {
bdoc("Open first region demanding attention or previously active one."),
kpress("O", "mod_menu.grabmenu(_, _sub, 'focuslist')"),
-- Alternative without (cyclable) menu
--kpress("O", "ioncore.goto_activity() or ioncore.goto_previous()"),

--bdoc("Go to previous active object."),
--kpress("O", "ioncore.goto_previous()"),

--bdoc("Go to first object on activity/urgency list."),
--kpress("I", "ioncore.goto_activity()"),

}),

bdoc("Go to n:th screen on multihead setup."),
raboof marked this conversation as resolved.
Show resolved Hide resolved
kpress(META.."Shift+1", "ioncore.goto_nth_screen(0)"),
kpress(META.."F1", "ioncore.goto_nth_screen(0)"),
kpress(META.."Shift+2", "ioncore.goto_nth_screen(1)"),
kpress(META.."F2", "ioncore.goto_nth_screen(1)"),
kpress(META.."Shift+3", "ioncore.goto_nth_screen(2)"),
kpress(META.."F3", "ioncore.goto_nth_screen(2)"),
kpress(META.."Shift+4", "ioncore.goto_nth_screen(3)"),
-- kpress(META.."F4", "ioncore.goto_nth_screen(3)"),

bdoc("Go to next/previous screen on multihead setup."),
kpress(ALTMETA.."Escape", "ioncore.goto_prev_screen()"),
Copy link
Collaborator

Choose a reason for hiding this comment

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

In WMoveResize mode, AnyModifier+Escape is bound to cancel resizing.. Does this still work if (ALT)META.."Escape" is bound to switch screens?

Copy link
Owner Author

Choose a reason for hiding this comment

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

it does look like it (but I don't have a second monitor handy to really test this right now)

kpress(META.."Escape", "ioncore.goto_next_screen()"),
raboof marked this conversation as resolved.
Show resolved Hide resolved

bdoc("Create a new workspace of chosen default type."),
kpress(META.."F9", "ioncore.create_ws(_)"),

bdoc("Display the main menu."),
kpress("F12", "mod_menu.menu(_, _sub, 'mainmenu', {big=true})"),
kpress(META.."F12", "mod_query.query_menu(_, _sub, 'mainmenu', 'Main menu:')"),
mpress("Button3", "mod_menu.pmenu(_, _sub, 'mainmenu')"),

bdoc("Display the window list menu."),
mpress("Button2", "mod_menu.pmenu(_, _sub, 'windowlist')"),

bdoc("Forward-circulate focus."),
-- '_chld' used here stands to for an actual child window that may not
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think a link to the documentation for _chld, _sub and _ in the context of keybinding config would be really helpful here.

-- be managed by the screen itself, unlike '_sub', that is likely to be
-- the managing group of that window. The right/left directions are
-- used instead of next/prev, because they work better in conjunction
-- with tilings.
kpress(META.."Tab", "ioncore.goto_next(_chld, 'right')",
"_chld:non-nil"),

bdoc("Backward-circulate focus."),
kpress(ALTMETA.."Tab", "ioncore.goto_next(_chld, 'left')",
"_chld:non-nil"),

bdoc("Raise focused object, if possible."),
kpress(ALTMETA.."R", "WRegion.rqorder(_chld, 'front')",
"_chld:non-nil"),
})


-- Client window bindings
--
-- These bindings affect client windows directly.

defbindings("WClientWin", {
bdoc("Nudge the client window. This might help with some "..
"programs' resizing problems."),
kpress_wait(ALTMETA.."L", "WClientWin.nudge(_)"),

bdoc("Kill client owning the client window."),
kpress(ALTMETA.."C", "WClientWin.kill(_)"),

bdoc("Send next key press to the client window. "..
"Some programs may not allow this by default."),
kpress(ALTMETA.."Q", "WClientWin.quote_next(_)"),
})


-- Client window group bindings

defbindings("WGroupCW", {
bdoc("Toggle client window group full-screen mode"),
kpress_wait(META.."Q", "WGroup.set_fullscreen(_, 'toggle')"),
})


-- WMPlex context bindings
--
-- These bindings work in frames and on screens. The innermost of such
-- contexts/objects always gets to handle the key press.

defbindings("WMPlex", {
bdoc("Close current object."),
kpress_wait(META.."C", "WRegion.rqclose_propagate(_, _sub)"),

bdoc("Detach (float) or reattach an object to its previous location."),
-- By using _chld instead of _sub, we can detach/reattach queries
-- attached to a group. The detach code checks if the parameter
-- (_chld) is a group 'bottom' and detaches the whole group in that
-- case.
kpress(ALTMETA.."D", "ioncore.detach(_chld, 'toggle')", "_chld:non-nil"),
})

-- Frames for transient windows ignore this bindmap

defbindings("WMPlex.toplevel", {
bdoc("Toggle tag of current object."),
kpress(META.."T", "WRegion.set_tagged(_sub, 'toggle')", "_sub:non-nil"),

bdoc("Clear all tags."),
kpress(ALTMETA.."T", "ioncore.clear_tags()"),

bdoc("Lock screen"),
kpress(META.."L", "notioncore.exec_on(_, notioncore.lookup_script('notion-lock'))"),

bdoc("Run a terminal emulator."),
kpress(META.."Return", "mod_query.exec_on_merr(_, XTERM or 'xterm')"),
kpress("F2", "mod_query.exec_on_merr(_, XTERM or 'xterm')"),

bdoc("Query for command line to execute."),
kpress(META.."J", "mod_query.query_exec(_)"),

bdoc("Query for Lua code to execute."),
kpress(ALTMETA.."J", "mod_query.query_lua(_)"),

bdoc("Query for host to connect to with SSH."),
kpress(ALTMETA.."F4", "mod_query.query_ssh(_, ':ssh')"),

bdoc("Query for file to edit."),
kpress(ALTMETA.."F5",
"mod_query.query_editfile(_, 'run-mailcap --action=edit')"),
wilhelmy marked this conversation as resolved.
Show resolved Hide resolved

bdoc("Query for file to view."),
kpress(ALTMETA.."F6",
"mod_query.query_runfile(_, 'run-mailcap --action=view')"),

bdoc("Query for workspace to go to or create a new one."),
kpress(ALTMETA.."F9", "mod_query.query_workspace(_)"),

bdoc("Query for a client window to go to."),
kpress(META.."G", "mod_query.query_gotoclient(_)"),

bdoc("Display context menu."),
kpress(META.."M", "mod_menu.menu(_, _sub, 'ctxmenu')"),
kpress(ALTMETA.."M", "mod_query.query_menu(_, _sub, 'ctxmenu', 'Context menu:')"),

bdoc("Query for manual page to be displayed."),
kpress(META.."slash", "mod_query.query_man(_, ':man')"),
})

-- WFrame context bindings
--
-- These bindings are common to all types of frames. Some additional
-- frame bindings are found in some modules' configuration files.

defbindings("WFrame", {
bdoc("Maximize the frame horizontally/vertically."),
kpress(ALTMETA.."H", "WFrame.maximize_horiz(_)"),
kpress(ALTMETA.."V", "WFrame.maximize_vert(_)"),

bdoc("Display context menu."),
mpress("Button3", "mod_menu.pmenu(_, _sub, 'ctxmenu')"),

bdoc("Begin move/resize mode."),
kpress(META.."R", "WFrame.begin_kbresize(_)"),

bdoc("Switch the frame to display the object indicated by the tab."),
mclick("Button1@tab", "WFrame.p_switch_tab(_)"),
mclick("Button2@tab", "WFrame.p_switch_tab(_)"),

bdoc("Resize the frame."),
mdrag("Button1@border", "WFrame.p_resize(_)"),
mdrag(META.."Button3", "WFrame.p_resize(_)"),

bdoc("Move the frame."),
mdrag(META.."Button1", "WFrame.p_move(_)"),

bdoc("Move objects between frames by dragging and dropping the tab."),
mdrag("Button1@tab", "WFrame.p_tabdrag(_)"),
mdrag("Button2@tab", "WFrame.p_tabdrag(_)"),

bdoc("Switch to next/previous object within the frame."),
-- See docs on how to disable capslock caps behaviour
kpress(META.."Caps_Lock", "WFrame.switch_next(_)"),
mclick(META.."Button4", "WFrame.switch_next(_)"),
mclick(META.."Button5", "WFrame.switch_prev(_)"),
})

-- Frames for transient windows ignore this bindmap

defbindings("WFrame.toplevel", {
bdoc("Query for a client window to attach ('nick')."),
kpress(META.."N", "mod_query.query_attachclient(_)"),

kpress(META.."A", "WFrame.switch_nth(_, 0)"),
kpress(META.."S", "WFrame.switch_nth(_, 1)"),
kpress(META.."D", "WFrame.switch_nth(_, 2)"),
kpress(META.."F", "WFrame.switch_nth(_, 3)"),

Copy link
Collaborator

Choose a reason for hiding this comment

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

How about META..[F1…F9] to change workspaces and META..[1…9] to change client windows (or the other way around because changing workspaces is probably used more often and thus should be closer to the home row)?

Copy link
Owner Author

@raboof raboof Jul 2, 2019

Choose a reason for hiding this comment

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

The general concept is:

  • META..[Esc,F1...F9] switches screens
  • META..[`,1..9] switches workspace within a screen
  • META..[Tab-Q] switches between tiles
  • META..[CapsLocak,A-F] switches between tabs within a tile

Copy link
Collaborator

Choose a reason for hiding this comment

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

I usually have less than 10 screens but more than 5 tabs. F1…12 is a second range of consecutive number keys, I'd say it would be best to use them as such, with everything else on the keyboard being random letters, some of which we might want to use as a mnemonic (the way vim does, "o"=open, "a"=append etc.), which makes it complicated to allocate let's say the whole Q…P row for tab 1…n (besides, those keys are usually shuffled around pseudorandomly in a non-US-keymap).

After all, the keyboard layout is the first thing a new user sees about notion, so I feel it should be as memorable as possible in order to make it easy to get going (this is why I'm proposing "A" for "attach" again).

I'm also a bit conflicted about the META.."K" submap in general, it seems this was used as a place for everything that didn't fit anywhere else (like C-x in emacs), and does not have any meaning? I think it would make more sense to have submaps (if we're going to have any at all in the new keybinding setup) to operate on a type of object, like tabs, e.g. all tab keybindings in META.."T", all workspace keybindings in META.."W", all "go to window by property" (urgent or title) in META.."G" and so on?

Just my two cents, feel free to do something else entirely ;)

Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe META.."`" could be the submap for whatever object is going to be on META..[0…9] (workspaces)
and META.."Escape" could be the submap for whatever object is going to be on META..[F1…F12] (screens or windows?)

Copy link
Owner Author

Choose a reason for hiding this comment

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

Just my two cents, feel free to do something else entirely ;)

Thanks! I really value the discussion, even though I've been experimenting with this for a while so there are some concepts that I'm reluctant to change :)

the keyboard layout is the first thing a new user sees about notion, so I feel it should be as memorable as possible in order to make it easy to get going

I agree (I wonder if some companion app like #112 could help here, too)

everything else on the keyboard being random letters

Part of idea behind this binding is that all basic 'direct' keys are at the left hand (navigation, fullscreen, scratchpad, etc), and more rarely used keys (e.g. anything that opens a query) are at the right hand. I think this would greatly improve how memorable the keys are. I agree using mnemonics is a useful tool as well, but I think that should be a secondary concern.

some of which we might want to use as a mnemonic (the way vim does, "o"=open, "a"=append etc.)

vim is a bit of an unfortunate example, with hjkl having special meaning there :)

those keys are usually shuffled around pseudorandomly in a non-US-keymap

This is definitely a downside, but I think we should just leave it up to the community to come up with bindings for use with different keymaps.

I'm also a bit conflicted about the META.."K" submap in general

I'm not a fan either. I wonder if we could get away with putting everything under META and META+Shift and drop META+K entirely.

Copy link
Owner Author

@raboof raboof Jul 2, 2019

Choose a reason for hiding this comment

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

Maybe META.."`" could be the submap for whatever object is going to be on META..[0…9] (workspaces)
and META.."Escape" could be the submap for whatever object is going to be on META..[F1…F12] (screens or windows?)

For those I had in mind 'next' (so META+Escape=next screen, META+`=next ws, META+Tab=next frame, META+CapsLock=next tab)

Copy link
Collaborator

@wilhelmy wilhelmy Jul 2, 2019

Choose a reason for hiding this comment

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

Thanks! I really value the discussion, even though I've been experimenting with this for a while so there are some concepts that I'm reluctant to change :)

I understand. I'm most likely not going to use this new setup (except for parts that I like more than what we had in my own modified version of the notion3 standard keymap) because I don't like changing my habits for no good reason, but I think new users should have it easy. If you think you have that figured out, I'm not going to cause you some bikeshed discussion about it.

I agree (I wonder if some companion app like #112 could help here, too)

I think so. vimtutor helped me getting started with vim, at least. This would be very easy to integrate into notion on first start thanks to the lua interface. "Would you like to try the tutorial mode? (y/n)".

Part of idea behind this binding is that all basic 'direct' keys are at the left hand (navigation, fullscreen, scratchpad, etc), and more rarely used keys (e.g. anything that opens a query) are at the right hand. I think this would greatly improve how memorable the keys are. I agree using mnemonics is a useful tool as well, but I think that should be a secondary concern.

I'm inclined to say that mnemonics and similarity to other tools (something that old-school *nix generally does rather badly compared to, say, OS X) help me more than anything else getting used to another keyboard-driven program with a very full keymap. (YMMV and actually I'd be interested in what helps you personally grok a new tool.)

vim is a bit of an unfortunate example, with hjkl having special meaning there :)

Back in the day computers did not have arrow keys (and we had to walk uphill to school both ways—kidding, I'm not old enough to have witnessed this).

Other than hjkl, vi's keyboard layout mostly makes sense imo, and is a good example for keyboard-driven software (albeit taking some time getting used to), perhaps because it has had some level of influence on the rest of the *nix software ecosystem over the decades.

For those I had in mind 'next' (so META+Escape=next screen, META+`=next ws, META+Tab=next frame, META+CapsLock=next tab)

Makes sense this way as well.

I trust you to make the right decisions, and maybe there isn't much value in "adding my own mustard" as we say here.

bdoc("Move current object within the frame left/right."),
kpress(ALTMETA.."comma", "WFrame.dec_index(_, _sub)", "_sub:non-nil"),
kpress(ALTMETA.."period", "WFrame.inc_index(_, _sub)", "_sub:non-nil"),

bdoc("Maximize the frame horizontally/vertically."),
kpress(ALTMETA.."H", "WFrame.maximize_horiz(_)"),
kpress(ALTMETA.."V", "WFrame.maximize_vert(_)"),

bdoc("Attach tagged objects to this frame."),
kpress(META.."Y", "ioncore.tagged_attach(_)"),
})

-- Bindings for floating frames

defbindings("WFrame.floating", {
bdoc("Toggle shade mode"),
mdblclick("Button1@tab", "WFrame.set_shaded(_, 'toggle')"),

bdoc("Raise the frame."),
mpress("Button1@tab", "WRegion.rqorder(_, 'front')"),
mpress("Button1@border", "WRegion.rqorder(_, 'front')"),
mclick(META.."Button1", "WRegion.rqorder(_, 'front')"),

bdoc("Lower the frame."),
mclick(META.."Button3", "WRegion.rqorder(_, 'back')"),

bdoc("Move the frame."),
mdrag("Button1@tab", "WFrame.p_move(_)"),
})


-- WMoveresMode context bindings
--
-- These bindings are available keyboard move/resize mode. The mode
-- is activated on frames with the command begin_kbresize (bound to
-- META.."R" above by default).

defbindings("WMoveresMode", {
bdoc("Cancel the resize mode."),
kpress("AnyModifier+Escape","WMoveresMode.cancel(_)"),

bdoc("End the resize mode."),
kpress("AnyModifier+Return","WMoveresMode.finish(_)"),

bdoc("Grow in specified direction."),
kpress("Left", "WMoveresMode.resize(_, 1, 0, 0, 0)"),
kpress("Right", "WMoveresMode.resize(_, 0, 1, 0, 0)"),
kpress("Up", "WMoveresMode.resize(_, 0, 0, 1, 0)"),
kpress("Down", "WMoveresMode.resize(_, 0, 0, 0, 1)"),
kpress("F", "WMoveresMode.resize(_, 1, 0, 0, 0)"),
kpress("B", "WMoveresMode.resize(_, 0, 1, 0, 0)"),
kpress("P", "WMoveresMode.resize(_, 0, 0, 1, 0)"),
kpress("N", "WMoveresMode.resize(_, 0, 0, 0, 1)"),

bdoc("Shrink in specified direction."),
kpress("Shift+Left", "WMoveresMode.resize(_,-1, 0, 0, 0)"),
kpress("Shift+Right", "WMoveresMode.resize(_, 0,-1, 0, 0)"),
kpress("Shift+Up", "WMoveresMode.resize(_, 0, 0,-1, 0)"),
kpress("Shift+Down", "WMoveresMode.resize(_, 0, 0, 0,-1)"),
kpress("Shift+F", "WMoveresMode.resize(_,-1, 0, 0, 0)"),
kpress("Shift+B", "WMoveresMode.resize(_, 0,-1, 0, 0)"),
kpress("Shift+P", "WMoveresMode.resize(_, 0, 0,-1, 0)"),
kpress("Shift+N", "WMoveresMode.resize(_, 0, 0, 0,-1)"),

bdoc("Move in specified direction."),
kpress(META.."Left", "WMoveresMode.move(_,-1, 0)"),
kpress(META.."Right", "WMoveresMode.move(_, 1, 0)"),
kpress(META.."Up", "WMoveresMode.move(_, 0,-1)"),
kpress(META.."Down", "WMoveresMode.move(_, 0, 1)"),
kpress(META.."F", "WMoveresMode.move(_,-1, 0)"),
kpress(META.."B", "WMoveresMode.move(_, 1, 0)"),
kpress(META.."P", "WMoveresMode.move(_, 0,-1)"),
kpress(META.."N", "WMoveresMode.move(_, 0, 1)"),
})


--
-- Menu definitions
--


-- Main menu
defmenu("mainmenu", {
menuentry("Run...", "mod_query.query_exec(_)"),
menuentry("Terminal", "mod_query.exec_on_merr(_, XTERM or 'xterm')"),
menuentry("Lock screen",
"notioncore.exec_on(_, notioncore.lookup_script('notion-lock'))"),
menuentry("Help", "mod_query.query_man(_)"),
menuentry("About Notion", "mod_query.show_about_ion(_)"),
submenu("Styles", "stylemenu"),
submenu("Session", "sessionmenu"),
})


-- Session control menu
defmenu("sessionmenu", {
menuentry("Save", "ioncore.snapshot()"),
menuentry("Restart", "ioncore.restart()"),
menuentry("Restart TWM", "ioncore.restart_other('twm')"),
menuentry("Exit", "ioncore.shutdown()"),
})


-- Context menu (frame actions etc.)
defctxmenu("WFrame", "Frame", {
-- Note: this propagates the close to any subwindows; it does not
-- destroy the frame itself, unless empty. An entry to destroy tiled
-- frames is configured in cfg_tiling.lua.
menuentry("Close", "WRegion.rqclose_propagate(_, _sub)"),
-- Low-priority entries
menuentry("Attach tagged", "ioncore.tagged_attach(_)", { priority = 0 }),
menuentry("Clear tags", "ioncore.clear_tags()", { priority = 0 }),
menuentry("Window info", "mod_query.show_tree(_, _sub)", { priority = 0 }),
})


-- Context menu for groups (workspaces, client windows)
defctxmenu("WGroup", "Group", {
menuentry("Toggle tag", "WRegion.set_tagged(_, 'toggle')"),
menuentry("De/reattach", "ioncore.detach(_, 'toggle')"),
})


-- Context menu for workspaces
defctxmenu("WGroupWS", "Workspace", {
menuentry("Close", "WRegion.rqclose(_)"),
menuentry("Rename", "mod_query.query_renameworkspace(nil, _)"),
menuentry("Attach tagged", "ioncore.tagged_attach(_)"),
})


-- Context menu for client windows
defctxmenu("WClientWin", "Client window", {
menuentry("Kill", "WClientWin.kill(_)"),
})
4 changes: 3 additions & 1 deletion etc/cfg_defaults.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
-- Notion default settings
--

dopath("cfg_notioncore")
dopath("cfg_kludges")
dopath("cfg_layouts")

Expand All @@ -15,3 +14,6 @@ dopath("mod_notionflux")
dopath("mod_xrandr")

dopath("net_client_list")

-- loads cfg_bindings
dopath("cfg_notioncore")
Loading