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

figure out a way for the user to set default key bindings #83

Open
cdepillabout opened this issue Nov 15, 2018 · 2 comments
Open

figure out a way for the user to set default key bindings #83

cdepillabout opened this issue Nov 15, 2018 · 2 comments

Comments

@cdepillabout
Copy link
Owner

@cdepillabout cdepillabout commented Nov 15, 2018

It would be nice for the user to be able to set default key bindings in their termonad.hs configuration file.

Currently there are two types of key bindings:

  • Key bindings to the current menu actions, like new tab, close tab, copy, paste, etc. These are set in the following function:

    applicationSetAccelsForAction app "app.newtab" ["<Shift><Ctrl>T"]

  • Other key bindings that aren't associated with a menu action, like Alt-1 for switching to the first terminal tab. These are set in the following function:

    handleKeyPress :: TMState -> EventKey -> IO Bool

    keyMap :: Map Key (TMState -> IO Bool)

It would be nice to give the user the ability to change both of these key bindings.

That is to say, the user should be able to change the key associated with the menu actions (like new tab). The user should also be able to change key bindings that aren't associated with a menu action (like Alt-1 for switching to the first terminal). Finally, the user should be able to add new key bindings that aren't associated with a menu action to call arbitrary functions they define.

@burumaj

This comment has been minimized.

Copy link

@burumaj burumaj commented Nov 16, 2018

To start of with I really like the idea for this feature. I recently came across Termonad and like using it.
This should be fairly simple I imagine. An easy way to do this, I think, is via similar construction like the keyMap allready present. After looking at the source code letting the user define their own Map Key (TMState -> IO Bool) and adding it to the TMConfig should not be to much effort.

Then in App.hs we could do something like union keyMap userKeyMap to generate the final final key map. This will keep the Alt-n combinations, should the user try to define them, and adds all bindings.

The last thing to do is let the user define their own bindings for menu actions. This could be done by exposing a function like
createMenuAction :: MonadIO m => Action -> [Accelarator] -> (Application -> m () )

Where Action is something like

data Action = NewTab
            | CloseTab 
            | ...

toText :: Action -> Text
toText NewTab = "app.newtab"
toText CloseTab = "app.closetab"
...

This way I assume it is fairly easy to write a function that adds all accelerators to the application.

However keep in mind I'm quite new to Haskell.

@cdepillabout

This comment has been minimized.

Copy link
Owner Author

@cdepillabout cdepillabout commented Nov 17, 2018

@burumaj Thanks for thinking about this!

To start of with I really like the idea for this feature. I recently came across Termonad and like using it.
This should be fairly simple I imagine. An easy way to do this, I think, is via similar construction like the keyMap allready present. After looking at the source code letting the user define their own Map Key (TMState -> IO Bool) and adding it to the TMConfig should not be to much effort.

Then in App.hs we could do something like union keyMap userKeyMap to generate the final final key map. This will keep the Alt-n combinations, should the user try to define them, and adds all bindings.

This sounds like a good idea. Here are a couple small additions:

  • Adding to TMConfig is a good idea. Maybe you could add it as a field called something like keys or extraKeys:

    data TMConfig = TMConfig

  • By default, it could have the value keymap. I guess the stopProp function should also be exposed to the end user.

  • I think presenting the default extraKeys value to the user from defaultTMConfig, and then letting them override it as needed is sufficient. I don't think we necessarily need to union the two keymaps. It is possible the user wants to completely disable the Alt-n key combinations.

The last thing to do is let the user define their own bindings for menu actions. This could be done by exposing a function like createMenuAction :: MonadIO m => Action -> [Accelarator] -> (Application -> m ())

I think this is a little more tricky. If all we want to do is to let the user change key bindings for menu actions, then we need a mapping like the following:

data MenuAction = NewTab | CloseTab | Quit | Copy | Paste

defaultMenuActionMap :: Map MenuAction String
defaultMenuActionMap =
  mapFromList
    [ (NewTab, "<Shift><Ctrl>T")
    , (CloseTab, "<Shift><Ctrl>W")
    , ...
    ]

This should be relatively easy to implement.

However, if we also want to let the user override the actual action that is called, maybe we could have additional hooks:

-- | Hooks into certain termonad operations and VTE events. Used to modify
-- termonad's behaviour in order to implement new functionality. Fields should
-- have sane @Semigroup@ and @Monoid@ instances so that config extensions can
-- be combined uniformly and new hooks can be added without incident.
data ConfigHooks = ConfigHooks {
-- | Produce an IO action to run on creation of new @Terminal@, given @TMState@
-- and the @Terminal@ in question.
createTermHook :: TMState -> Terminal -> IO ()
}

For instance, instead of:

newTabAction <- simpleActionNew "newtab" Nothing
void $ onSimpleActionActivate newTabAction $ \_ -> void $ createTerm handleKeyPress mvarTMState
actionMapAddAction app newTabAction
applicationSetAccelsForAction app "app.newtab" ["<Shift><Ctrl>T"]

we could have the following code:

newTabAction <- simpleActionNew "newtab" Nothing
void $ onSimpleActionActivate newTabAction $ \_ -> newTabHook
actionMapAddAction app newTabAction
applicationSetAccelsForAction app "app.newtab" ["<Shift><Ctrl>T"]

I guess we could also have a function like you suggest ( createMenuAction :: MonadIO m => Action -> [Accelarator] -> (Application -> m () )), but I feel like it might just be simpler to have different hooks for each action.

This would be a little more involved then the previous change, but it would make it much more customizable for the end-user.


The next step would be making it fully customizable, so that the end-user could even define which menu options are shown.

Currently the menu is defined in XML here:

menuDoc :: Document
menuDoc =
[xmlRaw|
<?xml version="1.0"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<menu id="menubar">
<submenu>
<attribute name="label" translatable="yes">File</attribute>
<section>
<item>
<attribute name="label" translatable="yes">New _Tab</attribute>
<attribute name="action">app.newtab</attribute>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">_Close Tab</attribute>
<attribute name="action">app.closetab</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_Quit</attribute>
<attribute name="action">app.quit</attribute>
</item>
</section>
</submenu>
<submenu>
<attribute name="label" translatable="yes">Edit</attribute>
<item>
<attribute name="label" translatable="yes">_Copy</attribute>
<attribute name="action">app.copy</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_Paste</attribute>
<attribute name="action">app.paste</attribute>
</item>
</submenu>
<submenu>
<attribute name="label" translatable="yes">Help</attribute>
<item>
<attribute name="label" translatable="yes">_About</attribute>
<attribute name="action">app.about</attribute>
</item>
</submenu>
</menu>
</interface>
|]

This would have to be removed and redone completely in Haskell code. Then it could be made customizable and exposed to the user. I haven't given this a lot of thought, but eventually it would be nice to do.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants
You can’t perform that action at this time.