Skip to content

Commit e604c55

Browse files
committed
wip
1 parent bc991cc commit e604c55

15 files changed

+400
-182
lines changed

.hlint.yaml

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,17 @@
5656
# Ignore some builtin hints
5757
# - ignore: {name: Use let}
5858
# - ignore: {name: Use const, within: SpecialModule} # Only within certain modules
59-
- ignore: {name: Use forM_}
60-
- ignore: {name: Use join}
59+
- ignore: {name: "Eta reduce"}
60+
- ignore: {name: "Redundant pure"}
61+
- ignore: {name: "Replace case with maybe"}
62+
- ignore: {name: "Use <$>"}
63+
- ignore: {name: "Use <$>"}
64+
- ignore: {name: "Use forM_"}
65+
- ignore: {name: "Use foldr"}
66+
- ignore: {name: "Use infix"}
67+
- ignore: {name: "Use join"}
68+
- ignore: {name: "Use uncurry"}
69+
6170

6271

6372
# Define some custom infix operators

src/Termonad/App.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -436,13 +436,13 @@ setupTermonad tmConfig app win builder = do
436436
newTabAction <- simpleActionNew "newtab" Nothing
437437
void $ onSimpleActionActivate newTabAction $ \_ -> void $ createTerm handleKeyPress mvarTMState
438438
actionMapAddAction app newTabAction
439-
applicationSetAccelsForAction app "app.newtab" ["<Shift><Ctrl>T"]
439+
applicationSetAccelsForAction app "win.newtab" ["<Shift><Ctrl>T"]
440440

441441
nextPageAction <- simpleActionNew "nextpage" Nothing
442442
void $ onSimpleActionActivate nextPageAction $ \_ ->
443443
termNextPage mvarTMState
444444
actionMapAddAction app nextPageAction
445-
applicationSetAccelsForAction app "app.nextpage" ["<Ctrl>Page_Down"]
445+
applicationSetAccelsForAction app "win.nextpage" ["<Ctrl>Page_Down"]
446446

447447
prevPageAction <- simpleActionNew "prevpage" Nothing
448448
void $ onSimpleActionActivate prevPageAction $ \_ ->

src/Termonad/Cli.hs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@ module Termonad.Cli where
1515

1616
import Termonad.Prelude
1717

18+
import Control.Applicative ((<|>), (<**>))
19+
import Data.Text (pack)
20+
import GI.Vte (CursorBlinkMode)
1821
import Options.Applicative (fullDesc, info, helper, progDesc, ParserInfo, execParser, Parser, Mod, OptionFields, option, str, value, short, long, metavar, help, ReadM, maybeReader, auto, flag')
1922
import Termonad.Types (ConfigOptions (..), Option (Set, Unset), ShowScrollbar, FontSize (..), ShowTabBar, showScrollbarFromString, showTabBarFromString, cursorBlinkModeFromString, FontConfig (..))
20-
import GI.Vte (CursorBlinkMode)
2123

2224

2325
-- | A data type that contains arguments from the command line.

src/Termonad/Config/Colour.hs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,12 @@ showColourCube matrix =
661661
showCol :: AlphaColour Double -> String -> String
662662
showCol col str = sRGB32show col <> str
663663

664+
-- A version of head that gives a better error message.
665+
headEx :: forall b. [b] -> b
666+
headEx = \case
667+
[] -> error "showColourCube: error in headEx, passed empty list, this is likely a logic error"
668+
(h : _) -> h
669+
664670
-- | A List of a grey scale. Default value for 'FullPalette'.
665671
--
666672
-- >>> fmap sRGB32show defaultGreyscale

src/Termonad/Gtk.hs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import Termonad.Prelude
1919

2020
import Control.Monad.Fail (MonadFail, fail)
2121
import Data.GI.Base (ManagedPtr, withManagedPtr)
22+
import Data.Text (unpack)
2223
import GHC.Stack (HasCallStack)
2324
import GI.Gdk
2425
( GObject
@@ -42,15 +43,11 @@ objFromBuildUnsafe ::
4243
objFromBuildUnsafe builder name constructor = do
4344
maybePlainObj <- builderGetObject builder name
4445
case maybePlainObj of
45-
Nothing -> error $ "Couldn't get " <> unpack name <> " from builder!"
46+
Nothing -> error $ unpack $ "Couldn't get " <> name <> " from builder!"
4647
Just plainObj -> do
4748
maybeNewObj <- castTo constructor plainObj
4849
case maybeNewObj of
49-
Nothing ->
50-
error $
51-
"Got " <>
52-
unpack name <>
53-
" from builder, but couldn't convert to object!"
50+
Nothing -> error $ unpack $ "Got " <> name <> " from builder, but couldn't convert to object!"
5451
Just obj -> pure obj
5552

5653
-- | Unsafely creates a new 'Application'. This calls 'fail' if it cannot

src/Termonad/IdMap.hs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
-- | Module : Termonad.IdMap
2+
-- Description : A Map that keeps track of the ID of values
3+
-- Copyright : (c) Dennis Gosnell, 2023
4+
-- License : BSD3
5+
-- Stability : experimental
6+
-- Portability : POSIX
7+
8+
module Termonad.IdMap
9+
( IdMapKey
10+
, IdMap
11+
, emptyIdMap
12+
, singletonIdMap
13+
, insertIdMap
14+
, lookupIdMap
15+
) where
16+
17+
import Termonad.IdMap.Internal

src/Termonad/IdMap/Internal.hs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
-- | Module : Termonad.IdMap
2+
-- Description : A Map that keeps track of the ID of values
3+
-- Copyright : (c) Dennis Gosnell, 2023
4+
-- License : BSD3
5+
-- Stability : experimental
6+
-- Portability : POSIX
7+
8+
module Termonad.IdMap.Internal where
9+
10+
import Termonad.Prelude
11+
12+
import Control.Lens (FoldableWithIndex, ifoldMap, Index, IxValue, Traversal', Ixed (ix))
13+
import qualified Data.Foldable as Foldable
14+
import Data.IntMap.Strict (IntMap)
15+
import qualified Data.IntMap.Strict as IntMap
16+
17+
-- TODO: Write tests for this!
18+
19+
newtype IdMapKey = IdMapKey { unIdMapKey :: Int }
20+
deriving stock Show
21+
22+
data IdMap a = IdMap
23+
{ idMap :: !(IntMap a)
24+
, nextId :: !Int
25+
}
26+
deriving stock Show
27+
28+
instance Functor IdMap where
29+
fmap f IdMap{idMap, nextId} = IdMap { idMap = fmap f idMap, nextId }
30+
31+
instance Foldable IdMap where
32+
foldMap f m = Foldable.foldMap f $ idMap m
33+
34+
instance FoldableWithIndex Int IdMap where
35+
ifoldMap f m = ifoldMap f $ idMap m
36+
37+
instance Traversable IdMap where
38+
traverse f IdMap{idMap, nextId} =
39+
fmap (\m -> IdMap { idMap = m, nextId }) (traverse f idMap)
40+
41+
type instance Index (IdMap a) = IdMapKey
42+
type instance IxValue (IdMap a) = a
43+
44+
instance Ixed (IdMap a) where
45+
ix :: IdMapKey -> Traversal' (IdMap a) a
46+
ix (IdMapKey i) f IdMap{idMap, nextId} =
47+
case IntMap.lookup i idMap of
48+
Just v -> fmap update (f v) -- f v <&> \v' -> IntMap.insert k v' m
49+
Nothing -> pure IdMap{idMap, nextId}
50+
where
51+
update :: a -> IdMap a
52+
update v' =
53+
IdMap
54+
{ idMap = IntMap.adjust (const v') i idMap
55+
, nextId
56+
}
57+
58+
initialId :: Int
59+
initialId = 0
60+
61+
succId :: Int -> Int
62+
succId i = i + 1
63+
64+
emptyIdMap :: IdMap a
65+
emptyIdMap = IdMap { idMap = mempty, nextId = 0 }
66+
67+
insertIdMap :: a -> IdMap a -> (IdMapKey, IdMap a)
68+
insertIdMap a IdMap {idMap, nextId} =
69+
let newMap = IntMap.insert nextId a idMap
70+
newNextId = nextId + 1
71+
in (IdMapKey nextId, IdMap { idMap = newMap, nextId = newNextId })
72+
73+
singletonIdMap :: a -> (IdMapKey, IdMap a)
74+
singletonIdMap a = insertIdMap a emptyIdMap
75+
76+
lookupIdMap :: IdMapKey -> IdMap a -> Maybe a
77+
lookupIdMap (IdMapKey k) IdMap {idMap} = IntMap.lookup k idMap

src/Termonad/Keys.hs

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ module Termonad.Keys where
44
import Termonad.Prelude
55

66
import Control.Lens (imap)
7+
import Data.Map.Strict (Map)
8+
import qualified Data.Map.Strict as Map
9+
import Data.Set (Set)
10+
import qualified Data.Set as Set
711
import GI.Gdk
812
( EventKey
913
, pattern KEY_0
@@ -27,7 +31,7 @@ import GI.Gdk
2731
)
2832

2933
import Termonad.Term (altNumSwitchTerm)
30-
import Termonad.Types (TMState)
34+
import Termonad.Types (TMState, TMWindowId)
3135

3236

3337
showKeys :: EventKey -> IO Bool
@@ -41,28 +45,29 @@ showKeys eventKey = do
4145
keycode <- getEventKeyHardwareKeycode eventKey
4246

4347
putStrLn "key press event:"
44-
putStrLn $ " type = " <> tshow eventType
45-
putStrLn $ " str = " <> tshow maybeString
46-
putStrLn $ " mods = " <> tshow modifiers
47-
putStrLn $ " isMod = " <> tshow isMod
48-
putStrLn $ " len = " <> tshow len
49-
putStrLn $ " keyval = " <> tshow keyval
50-
putStrLn $ " keycode = " <> tshow keycode
48+
putStrLn $ " type = " <> show eventType
49+
putStrLn $ " str = " <> show maybeString
50+
putStrLn $ " mods = " <> show modifiers
51+
putStrLn $ " isMod = " <> show isMod
52+
putStrLn $ " len = " <> show len
53+
putStrLn $ " keyval = " <> show keyval
54+
putStrLn $ " keycode = " <> show keycode
5155
putStrLn ""
5256

5357
pure True
5458

5559
data Key = Key
56-
{ keyVal :: Word32
57-
, keyMods :: Set ModifierType
60+
{ keyVal :: !Word32
61+
, keyMods :: !(Set ModifierType)
5862
} deriving (Eq, Ord, Show)
5963

6064
toKey :: Word32 -> Set ModifierType -> Key
6165
toKey = Key
6266

63-
keyMap :: Map Key (TMState -> IO Bool)
67+
keyMap :: Map Key (TMState -> TMWindowId -> IO Bool)
6468
keyMap =
65-
let numKeys =
69+
let numKeys :: [Word32]
70+
numKeys =
6671
[ KEY_1
6772
, KEY_2
6873
, KEY_3
@@ -74,21 +79,23 @@ keyMap =
7479
, KEY_9
7580
, KEY_0
7681
]
82+
altNumKeys :: [(Key, TMState -> TMWindowId -> IO Bool)]
7783
altNumKeys =
7884
imap
7985
(\i k ->
8086
(toKey k [ModifierTypeMod1Mask], stopProp (altNumSwitchTerm i))
8187
)
8288
numKeys
8389
in
84-
mapFromList altNumKeys
90+
Map.fromList altNumKeys
8591

86-
stopProp :: (TMState -> IO a) -> TMState -> IO Bool
87-
stopProp callback terState = callback terState $> True
92+
stopProp :: (TMState -> TMWindowId -> IO a) -> TMState -> TMWindowId -> IO Bool
93+
stopProp callback terState tmWinId = callback terState tmWinId $> True
8894

8995
removeStrangeModifiers :: Key -> Key
9096
removeStrangeModifiers Key{keyVal, keyMods} =
91-
let reservedModifiers =
97+
let reservedModifiers :: Set ModifierType
98+
reservedModifiers =
9299
[ ModifierTypeModifierReserved13Mask
93100
, ModifierTypeModifierReserved14Mask
94101
, ModifierTypeModifierReserved15Mask
@@ -104,17 +111,17 @@ removeStrangeModifiers Key{keyVal, keyMods} =
104111
, ModifierTypeModifierReserved25Mask
105112
, ModifierTypeModifierReserved29Mask
106113
]
107-
in Key keyVal (difference keyMods reservedModifiers)
114+
in Key keyVal (Set.difference keyMods reservedModifiers)
108115

109116

110-
handleKeyPress :: TMState -> EventKey -> IO Bool
111-
handleKeyPress terState eventKey = do
117+
handleKeyPress :: TMState -> TMWindowId -> EventKey -> IO Bool
118+
handleKeyPress terState tmWindowId eventKey = do
112119
-- void $ showKeys eventKey
113120
keyval <- getEventKeyKeyval eventKey
114121
modifiers <- getEventKeyState eventKey
115-
let oldKey = toKey keyval (setFromList modifiers)
122+
let oldKey = toKey keyval (Set.fromList modifiers)
116123
newKey = removeStrangeModifiers oldKey
117-
maybeAction = lookup newKey keyMap
124+
maybeAction = Map.lookup newKey keyMap
118125
case maybeAction of
119-
Just action -> action terState
126+
Just action -> action terState tmWindowId
120127
Nothing -> pure False

src/Termonad/Lenses.hs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,18 @@ $(makeLensesFor
2828
''TMNotebook
2929
)
3030

31+
$(makeLensesFor
32+
[ ("tmWindowAppWin", "lensTMWindowAppWin")
33+
, ("tmWindowNotebook", "lensTMWindowNotebook")
34+
]
35+
''TMWindow
36+
)
37+
3138
$(makeLensesFor
3239
[ ("tmStateApp", "lensTMStateApp")
33-
, ("tmStateAppWin", "lensTMStateAppWin")
34-
, ("tmStateNotebook", "lensTMStateNotebook")
3540
, ("tmStateFontDesc", "lensTMStateFontDesc")
3641
, ("tmStateConfig", "lensTMStateConfig")
37-
, ("tmStateUserReqExit", "lensTMStateUserReqExit")
42+
, ("tmStateWindows", "lensTMStateWindows")
3843
]
3944
''TMState'
4045
)

src/Termonad/PreferencesFile.hs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,18 @@ import Data.Aeson (Result(..), fromJSON)
99
#if MIN_VERSION_aeson(2, 0, 0)
1010
import qualified Data.Aeson.KeyMap as KeyMap
1111
#endif
12+
import qualified Data.ByteString as ByteString
1213
import qualified Data.HashMap.Strict as HashMap
14+
import Data.Text (pack)
1315
import Data.Yaml (ParseException, ToJSON (toJSON), decodeFileEither, encode, prettyPrintParseException)
1416
import Data.Yaml.Aeson (Value(..))
15-
1617
import System.Directory
1718
( XdgDirectory(XdgConfig)
1819
, createDirectoryIfMissing
1920
, doesFileExist
2021
, getXdgDirectory
2122
)
22-
23+
import System.FilePath ((</>))
2324
import Termonad.Types
2425
( ConfigOptions
2526
, TMConfig(TMConfig, hooks, options)
@@ -184,7 +185,7 @@ writePreferencesFile confFile options = do
184185
"# The settings in this file will be ignored if you have a\n" <>
185186
"# termonad.hs file in this same directory.\n\n" <>
186187
yaml
187-
writeFile confFile yamlWithComment
188+
ByteString.writeFile confFile yamlWithComment
188189

189190
-- | Save the configuration to the preferences file
190191
-- @~\/.config\/termonad\/termonad.yaml@

src/Termonad/Prelude.hs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,40 @@
1+
2+
-- | This is a basic prelude-like module that adds a bunch of common datatypes
3+
-- and functions to the 'Prelude'.
4+
15
module Termonad.Prelude
26
( module X
37
, hPutStrLn
48
, whenJust
9+
, stderr
10+
, tshow
511
) where
612

13+
import Control.Concurrent.MVar as X (MVar, modifyMVar, newMVar, readMVar, withMVar)
14+
import Control.Exception as X (IOException, try)
715
import Control.Lens as X ((&))
16+
import Control.Monad as X (unless, void, when)
17+
import Control.Monad.IO.Class as X
818
import Control.Monad.Trans.Maybe as X (MaybeT(MaybeT), runMaybeT)
9-
import ClassyPrelude as X
19+
import Data.Function as X (on)
20+
import Data.Functor as X (($>))
21+
import Data.Int as X (Int32)
22+
import Data.Maybe as X (catMaybes, fromMaybe)
1023
import Data.Proxy as X
24+
import Data.String as X (IsString)
25+
import Data.Text as X (Text)
26+
import Data.Text (pack)
1127
import qualified Data.Text.IO as TextIO
28+
import Data.Word as X (Word8, Word32)
29+
import GHC.Generics as X (Generic)
30+
import Prelude as X
31+
import System.IO (Handle, stderr)
1232

1333
whenJust :: Monoid m => Maybe a -> (a -> m) -> m
1434
whenJust = flip foldMap
1535

1636
hPutStrLn :: MonadIO m => Handle -> Text -> m ()
1737
hPutStrLn hndl = liftIO . TextIO.hPutStrLn hndl
38+
39+
tshow :: Show a => a -> Text
40+
tshow = pack . show

0 commit comments

Comments
 (0)