Improve key handling in TUI, fixes #875
This commit is contained in:
parent
d14526059b
commit
452ca8cca2
@ -94,7 +94,7 @@ data BrickState = BrickState
|
|||||||
|
|
||||||
|
|
||||||
keyHandlers :: KeyBindings
|
keyHandlers :: KeyBindings
|
||||||
-> [ ( Vty.Key
|
-> [ ( KeyCombination
|
||||||
, BrickSettings -> String
|
, BrickSettings -> String
|
||||||
, BrickState -> EventM String BrickState ()
|
, BrickState -> EventM String BrickState ()
|
||||||
)
|
)
|
||||||
@ -131,6 +131,9 @@ showKey Vty.KUp = "↑"
|
|||||||
showKey Vty.KDown = "↓"
|
showKey Vty.KDown = "↓"
|
||||||
showKey key = tail (show key)
|
showKey key = tail (show key)
|
||||||
|
|
||||||
|
showMod :: Vty.Modifier -> String
|
||||||
|
showMod = tail . show
|
||||||
|
|
||||||
|
|
||||||
ui :: AttrMap -> BrickState -> Widget String
|
ui :: AttrMap -> BrickState -> Widget String
|
||||||
ui dimAttrs BrickState{ appSettings = as@BrickSettings{}, ..}
|
ui dimAttrs BrickState{ appSettings = as@BrickSettings{}, ..}
|
||||||
@ -147,7 +150,7 @@ ui dimAttrs BrickState{ appSettings = as@BrickSettings{}, ..}
|
|||||||
. txtWrap
|
. txtWrap
|
||||||
. T.pack
|
. T.pack
|
||||||
. foldr1 (\x y -> x <> " " <> y)
|
. foldr1 (\x y -> x <> " " <> y)
|
||||||
. fmap (\(key, s, _) -> showKey key <> ":" <> s as)
|
. fmap (\(KeyCombination key mods, s, _) -> intercalate "+" (showKey key : (showMod <$> mods)) <> ":" <> s as)
|
||||||
$ keyHandlers appKeys
|
$ keyHandlers appKeys
|
||||||
header =
|
header =
|
||||||
minHSize 2 emptyWidget
|
minHSize 2 emptyWidget
|
||||||
@ -321,12 +324,12 @@ eventHandler st@BrickState{..} ev = do
|
|||||||
(MouseDown _ Vty.BScrollDown _ _) ->
|
(MouseDown _ Vty.BScrollDown _ _) ->
|
||||||
put (BrickState { appState = moveCursor 1 appState Down, .. })
|
put (BrickState { appState = moveCursor 1 appState Down, .. })
|
||||||
(VtyEvent (Vty.EvResize _ _)) -> put st
|
(VtyEvent (Vty.EvResize _ _)) -> put st
|
||||||
(VtyEvent (Vty.EvKey Vty.KUp _)) ->
|
(VtyEvent (Vty.EvKey Vty.KUp [])) ->
|
||||||
put BrickState{ appState = moveCursor 1 appState Up, .. }
|
put BrickState{ appState = moveCursor 1 appState Up, .. }
|
||||||
(VtyEvent (Vty.EvKey Vty.KDown _)) ->
|
(VtyEvent (Vty.EvKey Vty.KDown [])) ->
|
||||||
put BrickState{ appState = moveCursor 1 appState Down, .. }
|
put BrickState{ appState = moveCursor 1 appState Down, .. }
|
||||||
(VtyEvent (Vty.EvKey key _)) ->
|
(VtyEvent (Vty.EvKey key mods)) ->
|
||||||
case find (\(key', _, _) -> key' == key) (keyHandlers kb) of
|
case find (\(keyCombo, _, _) -> keyCombo == KeyCombination key mods) (keyHandlers kb) of
|
||||||
Nothing -> put st
|
Nothing -> put st
|
||||||
Just (_, _, handler) -> handler st
|
Just (_, _, handler) -> handler st
|
||||||
_ -> put st
|
_ -> put st
|
||||||
|
@ -16,6 +16,11 @@ gpg-setting: GPGNone # GPGStrict | GPGLax | GPGNone
|
|||||||
# TUI key bindings,
|
# TUI key bindings,
|
||||||
# see https://hackage.haskell.org/package/vty-5.31/docs/Graphics-Vty-Input-Events.html#t:Key
|
# see https://hackage.haskell.org/package/vty-5.31/docs/Graphics-Vty-Input-Events.html#t:Key
|
||||||
# for possible values.
|
# for possible values.
|
||||||
|
# It's also possible to define key+modifier, e.g.:
|
||||||
|
# quit:
|
||||||
|
# Key:
|
||||||
|
# KChar: c
|
||||||
|
# Mods: [MCtrl]
|
||||||
key-bindings:
|
key-bindings:
|
||||||
up:
|
up:
|
||||||
KUp: []
|
KUp: []
|
||||||
|
@ -22,6 +22,7 @@ module GHCup.Types
|
|||||||
( module GHCup.Types
|
( module GHCup.Types
|
||||||
#if defined(BRICK)
|
#if defined(BRICK)
|
||||||
, Key(..)
|
, Key(..)
|
||||||
|
, Modifier(..)
|
||||||
#endif
|
#endif
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
@ -39,14 +40,13 @@ import Optics ( makeLenses )
|
|||||||
import Text.PrettyPrint.HughesPJClass (Pretty, pPrint, text)
|
import Text.PrettyPrint.HughesPJClass (Pretty, pPrint, text)
|
||||||
import URI.ByteString
|
import URI.ByteString
|
||||||
#if defined(BRICK)
|
#if defined(BRICK)
|
||||||
import Graphics.Vty ( Key(..) )
|
import Graphics.Vty ( Key(..), Modifier(..) )
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
import qualified Data.ByteString.Lazy as BL
|
import qualified Data.ByteString.Lazy as BL
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified GHC.Generics as GHC
|
import qualified GHC.Generics as GHC
|
||||||
import qualified Data.List.NonEmpty as NE
|
import qualified Data.List.NonEmpty as NE
|
||||||
import Data.Foldable (foldMap)
|
|
||||||
|
|
||||||
#if !defined(BRICK)
|
#if !defined(BRICK)
|
||||||
data Key = KEsc | KChar Char | KBS | KEnter
|
data Key = KEsc | KChar Char | KBS | KEnter
|
||||||
@ -55,8 +55,14 @@ data Key = KEsc | KChar Char | KBS | KEnter
|
|||||||
| KFun Int | KBackTab | KPrtScr | KPause | KIns
|
| KFun Int | KBackTab | KPrtScr | KPause | KIns
|
||||||
| KHome | KPageUp | KDel | KEnd | KPageDown | KBegin | KMenu
|
| KHome | KPageUp | KDel | KEnd | KPageDown | KBegin | KMenu
|
||||||
deriving (Eq,Show,Read,Ord,GHC.Generic)
|
deriving (Eq,Show,Read,Ord,GHC.Generic)
|
||||||
|
|
||||||
|
data Modifier = MShift | MCtrl | MMeta | MAlt
|
||||||
|
deriving (Eq,Show,Read,Ord,GHC.Generic)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
data KeyCombination = KeyCombination { key :: Key, mods :: [Modifier] }
|
||||||
|
deriving (Eq,Show,Read,Ord,GHC.Generic)
|
||||||
|
|
||||||
|
|
||||||
--------------------
|
--------------------
|
||||||
--[ GHCInfo Tree ]--
|
--[ GHCInfo Tree ]--
|
||||||
@ -415,47 +421,51 @@ fromSettings Settings{..} (Just KeyBindings{..}) =
|
|||||||
}
|
}
|
||||||
|
|
||||||
data UserKeyBindings = UserKeyBindings
|
data UserKeyBindings = UserKeyBindings
|
||||||
{ kUp :: Maybe Key
|
{ kUp :: Maybe KeyCombination
|
||||||
, kDown :: Maybe Key
|
, kDown :: Maybe KeyCombination
|
||||||
, kQuit :: Maybe Key
|
, kQuit :: Maybe KeyCombination
|
||||||
, kInstall :: Maybe Key
|
, kInstall :: Maybe KeyCombination
|
||||||
, kUninstall :: Maybe Key
|
, kUninstall :: Maybe KeyCombination
|
||||||
, kSet :: Maybe Key
|
, kSet :: Maybe KeyCombination
|
||||||
, kChangelog :: Maybe Key
|
, kChangelog :: Maybe KeyCombination
|
||||||
, kShowAll :: Maybe Key
|
, kShowAll :: Maybe KeyCombination
|
||||||
, kShowAllTools :: Maybe Key
|
, kShowAllTools :: Maybe KeyCombination
|
||||||
}
|
}
|
||||||
deriving (Show, GHC.Generic)
|
deriving (Show, GHC.Generic)
|
||||||
|
|
||||||
data KeyBindings = KeyBindings
|
data KeyBindings = KeyBindings
|
||||||
{ bUp :: Key
|
{ bUp :: KeyCombination
|
||||||
, bDown :: Key
|
, bDown :: KeyCombination
|
||||||
, bQuit :: Key
|
, bQuit :: KeyCombination
|
||||||
, bInstall :: Key
|
, bInstall :: KeyCombination
|
||||||
, bUninstall :: Key
|
, bUninstall :: KeyCombination
|
||||||
, bSet :: Key
|
, bSet :: KeyCombination
|
||||||
, bChangelog :: Key
|
, bChangelog :: KeyCombination
|
||||||
, bShowAllVersions :: Key
|
, bShowAllVersions :: KeyCombination
|
||||||
, bShowAllTools :: Key
|
, bShowAllTools :: KeyCombination
|
||||||
}
|
}
|
||||||
deriving (Show, GHC.Generic)
|
deriving (Show, GHC.Generic)
|
||||||
|
|
||||||
instance NFData KeyBindings
|
instance NFData KeyBindings
|
||||||
#if defined(IS_WINDOWS) || !defined(BRICK)
|
#if defined(IS_WINDOWS) || !defined(BRICK)
|
||||||
instance NFData Key
|
instance NFData Key
|
||||||
|
|
||||||
|
instance NFData Modifier
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
instance NFData KeyCombination
|
||||||
|
|
||||||
defaultKeyBindings :: KeyBindings
|
defaultKeyBindings :: KeyBindings
|
||||||
defaultKeyBindings = KeyBindings
|
defaultKeyBindings = KeyBindings
|
||||||
{ bUp = KUp
|
{ bUp = KeyCombination { key = KUp , mods = [] }
|
||||||
, bDown = KDown
|
, bDown = KeyCombination { key = KDown , mods = [] }
|
||||||
, bQuit = KChar 'q'
|
, bQuit = KeyCombination { key = KChar 'q', mods = [] }
|
||||||
, bInstall = KChar 'i'
|
, bInstall = KeyCombination { key = KChar 'i', mods = [] }
|
||||||
, bUninstall = KChar 'u'
|
, bUninstall = KeyCombination { key = KChar 'u', mods = [] }
|
||||||
, bSet = KChar 's'
|
, bSet = KeyCombination { key = KChar 's', mods = [] }
|
||||||
, bChangelog = KChar 'c'
|
, bChangelog = KeyCombination { key = KChar 'c', mods = [] }
|
||||||
, bShowAllVersions = KChar 'a'
|
, bShowAllVersions = KeyCombination { key = KChar 'a', mods = [] }
|
||||||
, bShowAllTools = KChar 't'
|
, bShowAllTools = KeyCombination { key = KChar 't', mods = [] }
|
||||||
}
|
}
|
||||||
|
|
||||||
data AppState = AppState
|
data AppState = AppState
|
||||||
|
@ -349,15 +349,13 @@ deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Versio
|
|||||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''GHCupInfo
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''GHCupInfo
|
||||||
deriveToJSON defaultOptions { sumEncoding = ObjectWithSingleField } ''URLSource
|
deriveToJSON defaultOptions { sumEncoding = ObjectWithSingleField } ''URLSource
|
||||||
deriveJSON defaultOptions { sumEncoding = ObjectWithSingleField } ''Key
|
deriveJSON defaultOptions { sumEncoding = ObjectWithSingleField } ''Key
|
||||||
deriveJSON defaultOptions { fieldLabelModifier = \str' -> maybe str' T.unpack . T.stripPrefix (T.pack "k-") . T.pack . kebab $ str' } ''UserKeyBindings
|
deriveJSON defaultOptions { sumEncoding = ObjectWithSingleField } ''Modifier
|
||||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel, unwrapUnaryRecords = True } ''Port
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel, unwrapUnaryRecords = True } ''Port
|
||||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel, unwrapUnaryRecords = True } ''Host
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel, unwrapUnaryRecords = True } ''Host
|
||||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''UserInfo
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''UserInfo
|
||||||
deriveJSON defaultOptions { fieldLabelModifier = \str' -> maybe str' (T.unpack . T.toLower) . T.stripPrefix (T.pack "authority") . T.pack $ str' } ''Authority
|
deriveJSON defaultOptions { fieldLabelModifier = \str' -> maybe str' (T.unpack . T.toLower) . T.stripPrefix (T.pack "authority") . T.pack $ str' } ''Authority
|
||||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''DownloadMirror
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''DownloadMirror
|
||||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''DownloadMirrors
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''DownloadMirrors
|
||||||
deriveToJSON defaultOptions { fieldLabelModifier = kebab } ''Settings
|
|
||||||
deriveToJSON defaultOptions { fieldLabelModifier = drop 2 . kebab } ''KeyBindings -- move under key-bindings key
|
|
||||||
|
|
||||||
instance FromJSON URLSource where
|
instance FromJSON URLSource where
|
||||||
parseJSON v =
|
parseJSON v =
|
||||||
@ -391,4 +389,21 @@ instance FromJSON URLSource where
|
|||||||
r :: [Either GHCupInfo URI] <- o .: "AddSource"
|
r :: [Either GHCupInfo URI] <- o .: "AddSource"
|
||||||
pure (AddSource r)
|
pure (AddSource r)
|
||||||
|
|
||||||
|
instance FromJSON KeyCombination where
|
||||||
|
parseJSON v = proper v <|> simple v
|
||||||
|
where
|
||||||
|
simple = withObject "KeyCombination" $ \o -> do
|
||||||
|
k <- parseJSON (Object o)
|
||||||
|
pure (KeyCombination k [])
|
||||||
|
proper = withObject "KeyCombination" $ \o -> do
|
||||||
|
k <- o .: "Key"
|
||||||
|
m <- o .: "Mods"
|
||||||
|
pure $ KeyCombination k m
|
||||||
|
|
||||||
|
instance ToJSON KeyCombination where
|
||||||
|
toJSON (KeyCombination k m) = object ["Key" .= k, "Mods" .= m]
|
||||||
|
|
||||||
|
deriveToJSON defaultOptions { fieldLabelModifier = drop 2 . kebab } ''KeyBindings -- move under key-bindings key
|
||||||
|
deriveJSON defaultOptions { fieldLabelModifier = \str' -> maybe str' T.unpack . T.stripPrefix (T.pack "k-") . T.pack . kebab $ str' } ''UserKeyBindings
|
||||||
deriveJSON defaultOptions { fieldLabelModifier = \str' -> maybe str' T.unpack . T.stripPrefix (T.pack "u-") . T.pack . kebab $ str' } ''UserSettings
|
deriveJSON defaultOptions { fieldLabelModifier = \str' -> maybe str' T.unpack . T.stripPrefix (T.pack "u-") . T.pack . kebab $ str' } ''UserSettings
|
||||||
|
deriveToJSON defaultOptions { fieldLabelModifier = kebab } ''Settings
|
||||||
|
Loading…
Reference in New Issue
Block a user