termonad 0.1.0.0 → 0.2.0.0
raw patch · 8 files changed
+370/−61 lines, 8 filesdep +directorydep +filepathdep ~gi-gtkdep ~gi-vtebinary-added
Dependencies added: directory, filepath
Dependency ranges changed: gi-gtk, gi-vte
Files
- CHANGELOG.md +10/−0
- README.md +175/−2
- img/termonad-lambda.png binary
- src/Termonad/App.hs +46/−5
- src/Termonad/Keys.hs +50/−28
- src/Termonad/Term.hs +35/−8
- src/Termonad/Types.hs +45/−13
- termonad.cabal +9/−5
CHANGELOG.md view
@@ -1,2 +1,12 @@+## 0.2.0.0 +* Open dialog asking if you want to quit when you try to use your WM to quit.+* Termonad will attempt to open up a new terminal in the working directory of+ the current terminal.+* Make sure termonad won't crash if dyre can't find GHC.+* Add a few more ways to compile on NixOS.+* Add an icon for termonad.+ ## 0.1.0.0++* Initial release.
README.md view
@@ -8,8 +8,181 @@ [](http://stackage.org/nightly/package/termonad)  -TODO+Termonad is a terminal emulator configurable in Haskell. It is extremely+customizable and provides hooks to modify the default behavior. It can be+thought of as the "XMonad" of terminal emulators. -<!-- markdown-toc start - Run M-x markdown-toc-generate-toc again or edit manually. -->+<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc --> **Table of Contents**++- [Termonad](#termonad)+ - [Installation](#installation)+ - [Arch Linux](#arch-linux)+ - [Ubuntu / Debian](#ubuntu--debian)+ - [NixOS](#nixos)+ - [How to use Termonad](#how-to-use-termonad)+ - [Goals](#goals)+ - [Maintainers](#maintainers)+ <!-- markdown-toc end -->++## Installation++Termonad can be able to be installed on any system as long as the necessary GTK+libraries are installed. The following lists instructions for a few+distributions. If the given steps don't work for you, or you want to add+instructions for an additional distribution, please send a pull request.++The following steps use the+[`stack`](https://docs.haskellstack.org/en/stable/README/) build tool to build+Termonad, but [`cabal`](https://www.haskell.org/cabal/) can be used as well.+If `cabal` doesn't work for you, please open an issue or send a pull request.++### Arch Linux++First, you must install the required GTK system libraries:++```sh+$ pacman -S vte3+```++You must have `stack` to be able to build Termonad. Steps for+installing `stack` can be found on+[this page](https://docs.haskellstack.org/en/stable/install_and_upgrade/).++In order to install Termonad, clone this repository and run `stack install`.+This will install the `termonad` binary to `~/.local/bin/`:++```sh+$ git clone https://github.com/cdepillabout/termonad+$ cd termonad/+$ stack install+```++### Ubuntu / Debian++First, you must install the required GTK system libraries:++```sh+$ apt-get install gobject-introspection libgirepository1.0-dev libgtk-3-dev libvte-2.91-dev+```++You must have `stack` to be able to build Termonad. Steps for+installing `stack` can be found on+[this page](https://docs.haskellstack.org/en/stable/install_and_upgrade/).++In order to install Termonad, clone this repository and run `stack install`.+This will install the `termonad` binary to `~/.local/bin/`:++```sh+$ git clone https://github.com/cdepillabout/termonad+$ cd termonad/+$ stack install+```++### NixOS++There are two methods to build Termonad on NixOS.++The first is using `stack`. The following commands install `stack` for your+user, clone this repository, and install the `termonad` binary to `~/.local/bin/`:++```sh+$ nix-env -i stack+$ git clone https://github.com/cdepillabout/termonad+$ cd termonad/+$ stack --nix install+```++The second is using the normal `nix-build` machinery. The following commands+clone this repository and build the `termonad` binary at `./result/bin/`:++```sh+$ git clone https://github.com/cdepillabout/termonad+$ cd termonad/+$ nix-build+```++## How to use Termonad++Termonad is similar to XMonad. The above steps will install a `termonad` binary+somewhere on your system. If you have installed Termonad using `stack`, the+`termonad` binary will be in `~/.local/bin/`. This binary is a version of+Termonad configured with default settings. You can try running it to get an idea+of what Termonad is like:++```sh+$ ~/.local/bin/termonad+```++If you would like to configure termonad with your own settings, first you will+need to create a Haskell file called `~/.config/termonad/termonad.hs`. The+next section gives an example configuration file.++If this file exists, when the `~/.local/bin/termonad` binary launches, it will+try to compile it. If it succeeds, it will create a separate binary file called+something like `~/.cache/termonad/termonad-linux-x86_64`. This binary file can+be thought of as your own personal Termonad, configured with all your own+settings.++When you run `~/.local/bin/termonad`, it will re-exec+`~/.cache/termonad/termonad-linux-x86_64` if it exists.++However, there is one difficulty with this setup. In order for the+`~/.local/bin/termonad` binary to be able to compile your+`~/.config/termonad/termonad.hs` file, it needs to know where GHC is, as well as+where all your Haskell packages live. This presents some difficulties that will+be discussed in a following section.++### Configuring Termonad++The following is an example Termonad configuration file. You should save this to+`~/.config/termonad/termonad.hs`. You can find more information on the available+configuration options within the+[`Termonad.Config`](https://hackage.haskell.org/package/termonad/docs/Termonad-Config.html)+module.++```haskell+{-# LANGUAGE OverloadedStrings #-}++module Main where++import Data.Colour.SRGB (Colour, sRGB24)+import Termonad.App (defaultMain)+import Termonad.Config+ ( FontConfig, ShowScrollbar(ShowScrollbarAlways), cursorColor+ , defaultFontConfig, defaultTMConfig, fontConfig, fontFamily+ , fontSize, showScrollbar+ )++-- | This sets the color of the cursor in the terminal.+--+-- This uses the "Data.Colour" module to define a dark-red color.+-- There are many default colors defined in "Data.Colour.Names".+cursColor :: Colour Double+cursColor = sRGB24 204 0 0++-- | This defines the font for the terminal.+fontConf :: FontConfig+fontConf =+ defaultFontConfig+ { fontFamily = "DejaVu Sans Mono"+ , fontSize = 13+ }++main :: IO ()+main = do+ let termonadConf =+ defaultTMConfig+ { cursorColor = cursColor+ , fontConfig = fontConf+ , showScrollbar = ShowScrollbarAlways+ }+ defaultMain termonadConf+```++## Goals++## Maintainers++- [Dennis Gosnell](https://github.com/cdepillabout)
+ img/termonad-lambda.png view
binary file changed (absent → 23829 bytes)
src/Termonad/App.hs view
@@ -45,6 +45,7 @@ , onNotebookPageRemoved , onNotebookPageReordered , onNotebookSwitchPage+ , onWidgetDeleteEvent , onWidgetDestroy , setWidgetMargin , styleContextAddProviderForScreen@@ -55,6 +56,7 @@ , widgetShowAll , windowClose , windowPresent+ , windowSetDefaultIconFromFile , windowSetTransientFor ) import qualified GI.Gtk as Gtk@@ -70,6 +72,7 @@ , terminalPasteClipboard ) +import Paths_termonad (getDataFileName) import Termonad.Config ( FontConfig(fontFamily, fontSize) , TMConfig@@ -83,13 +86,16 @@ ( TMNotebookTab , TMState , TMState'(TMState)+ , UserRequestedExit(UserRequestedExit, UserDidNotRequestExit) , getFocusedTermFromState+ , getUserRequestedExit , lensTMNotebookTabs , lensTMNotebookTabTerm , lensTMStateApp , lensTMStateNotebook , lensTerm , newEmptyTMState+ , setUserRequestedExit , tmNotebookTabTermContainer , tmNotebookTabs , tmStateNotebook@@ -178,6 +184,15 @@ exitWithConfirmation :: TMState -> IO () exitWithConfirmation mvarTMState = do+ respType <- exitWithConfirmationDialog mvarTMState+ case respType of+ ResponseTypeYes -> do+ setUserRequestedExit mvarTMState+ quit mvarTMState+ _ -> pure ()++exitWithConfirmationDialog :: TMState -> IO ResponseType+exitWithConfirmationDialog mvarTMState = do tmState <- readMVar mvarTMState let app = tmState ^. lensTMStateApp win <- applicationGetActiveWindow app@@ -200,9 +215,7 @@ windowSetTransientFor dialog win res <- dialogRun dialog widgetDestroy dialog- case toEnum (fromIntegral res) of- ResponseTypeYes -> quit mvarTMState- _ -> pure ()+ pure $ toEnum (fromIntegral res) quit :: TMState -> IO () quit mvarTMState = do@@ -215,6 +228,9 @@ setupTermonad :: TMConfig -> Application -> ApplicationWindow -> Gtk.Builder -> IO () setupTermonad tmConfig app win builder = do+ termonadIconPath <- getDataFileName "img/termonad-lambda.png"+ windowSetDefaultIconFromFile termonadIconPath+ setupScreenStyle box <- objFromBuildUnsafe builder "content_box" Box fontDesc <- createFontDesc tmConfig@@ -227,7 +243,9 @@ void $ onNotebookPageRemoved note $ \_ _ -> do pages <- notebookGetNPages note- when (pages == 0) $ quit mvarTMState+ when (pages == 0) $ do+ setUserRequestedExit mvarTMState+ quit mvarTMState void $ onNotebookSwitchPage note $ \_ pageNum -> do maybeRes <- tryTakeMVar mvarTMState@@ -308,6 +326,17 @@ menuModel <- objFromBuildUnsafe menuBuilder "menubar" MenuModel applicationSetMenubar app (Just menuModel) + void $ onWidgetDeleteEvent win $ \_ -> do+ userRequestedExit <- getUserRequestedExit mvarTMState+ case userRequestedExit of+ UserRequestedExit -> pure False+ UserDidNotRequestExit -> do+ respType <- exitWithConfirmationDialog mvarTMState+ let stopOtherHandlers =+ case respType of+ ResponseTypeYes -> False+ _ -> True+ pure stopOtherHandlers void $ onWidgetDestroy win $ quit mvarTMState widgetShowAll win@@ -351,4 +380,16 @@ , showError = \(cfg, oldErrs) newErr -> (cfg, oldErrs <> "\n" <> newErr) , realMain = \(cfg, errs) -> putStrLn (pack errs) *> start cfg }- wrapMain params (tmConfig, "")+ eitherRes <- tryIOError $ wrapMain params (tmConfig, "")+ case eitherRes of+ Left ioErr+ | ioeGetErrorType ioErr == doesNotExistErrorType && ioeGetFileName ioErr == Just "ghc" -> do+ putStrLn $+ "Could not find ghc on your PATH. Ignoring your termonad.hs " <>+ "configuration file and running termonad with default settings."+ start tmConfig+ | otherwise -> do+ putStrLn $ "IO error occurred when trying to run termonad:"+ print ioErr+ putStrLn "Don't know how to recover. Exiting."+ Right _ -> pure ()
src/Termonad/Keys.hs view
@@ -16,35 +16,40 @@ , pattern KEY_8 , pattern KEY_9 , ModifierType(..)+ , getEventKeyHardwareKeycode+ , getEventKeyIsModifier , getEventKeyKeyval+ , getEventKeyLength , getEventKeyState+ , getEventKeyString+ , getEventKeyType ) import Termonad.Term (altNumSwitchTerm) import Termonad.Types (TMState) --- showKeys :: EventKey -> IO Bool--- showKeys eventKey = do--- eventType <- get eventKey #type--- maybeString <- get eventKey #string--- modifiers <- get eventKey #state--- len <- get eventKey #length--- keyval <- get eventKey #keyval--- isMod <- get eventKey #isModifier--- keycode <- get eventKey #hardwareKeycode+showKeys :: EventKey -> IO Bool+showKeys eventKey = do+ eventType <- getEventKeyType eventKey+ maybeString <- getEventKeyString eventKey+ modifiers <- getEventKeyState eventKey+ len <- getEventKeyLength eventKey+ keyval <- getEventKeyKeyval eventKey+ isMod <- getEventKeyIsModifier eventKey+ keycode <- getEventKeyHardwareKeycode eventKey --- putStrLn "key press event:"--- putStrLn $ " type = " <> tshow eventType--- putStrLn $ " str = " <> tshow maybeString--- putStrLn $ " mods = " <> tshow modifiers--- putStrLn $ " isMod = " <> tshow isMod--- putStrLn $ " len = " <> tshow len--- putStrLn $ " keyval = " <> tshow keyval--- putStrLn $ " keycode = " <> tshow keycode--- putStrLn ""+ putStrLn "key press event:"+ putStrLn $ " type = " <> tshow eventType+ putStrLn $ " str = " <> tshow maybeString+ putStrLn $ " mods = " <> tshow modifiers+ putStrLn $ " isMod = " <> tshow isMod+ putStrLn $ " len = " <> tshow len+ putStrLn $ " keyval = " <> tshow keyval+ putStrLn $ " keycode = " <> tshow keycode+ putStrLn "" --- pure True+ pure True data Key = Key { keyVal :: Word32@@ -74,23 +79,40 @@ ) numKeys in- mapFromList $- -- [ ( toKey KEY_T [ModifierTypeControlMask, ModifierTypeShiftMask]- -- , stopProp createTerm- -- )- -- ] <>- altNumKeys+ mapFromList altNumKeys stopProp :: (TMState -> IO a) -> TMState -> IO Bool stopProp callback terState = callback terState $> True +removeStrangeModifiers :: Key -> Key+removeStrangeModifiers Key{keyVal, keyMods} =+ let reservedModifiers =+ [ ModifierTypeModifierReserved13Mask+ , ModifierTypeModifierReserved14Mask+ , ModifierTypeModifierReserved15Mask+ , ModifierTypeModifierReserved16Mask+ , ModifierTypeModifierReserved17Mask+ , ModifierTypeModifierReserved18Mask+ , ModifierTypeModifierReserved19Mask+ , ModifierTypeModifierReserved20Mask+ , ModifierTypeModifierReserved21Mask+ , ModifierTypeModifierReserved22Mask+ , ModifierTypeModifierReserved23Mask+ , ModifierTypeModifierReserved24Mask+ , ModifierTypeModifierReserved25Mask+ , ModifierTypeModifierReserved29Mask+ ]+ in Key keyVal (difference keyMods reservedModifiers)++ handleKeyPress :: TMState -> EventKey -> IO Bool handleKeyPress terState eventKey = do- -- keyval <- get eventKey #keyval+ -- void $ showKeys eventKey keyval <- getEventKeyKeyval eventKey modifiers <- getEventKeyState eventKey- let key = toKey keyval (setFromList modifiers)- maybeAction = lookup key keyMap+ let oldKey = toKey keyval (setFromList modifiers)+ newKey = removeStrangeModifiers oldKey+ maybeAction = lookup newKey keyMap case maybeAction of Just action -> action terState Nothing -> pure False
src/Termonad/Term.hs view
@@ -79,6 +79,8 @@ , terminalSetScrollbackLines , terminalSpawnSync )+import System.FilePath ((</>))+import System.Directory (getSymbolicLinkTarget) import Termonad.Config (ShowScrollbar(..), TMConfig(cursorColor, scrollbackLen), lensShowScrollbar) import Termonad.FocusList (appendFL, deleteFL, getFLFocusItem)@@ -97,8 +99,10 @@ , lensTMStateConfig , lensTMStateNotebook , newTMTerm+ , pid , tmNotebook , tmNotebookTabs+ , tmNotebookTabTerm , tmNotebookTabTermContainer ) @@ -174,13 +178,13 @@ go notebook tmNotebookTab = do let label = tmNotebookTab ^. lensTMNotebookTabLabel scrolledWin = tmNotebookTab ^. lensTMNotebookTabTermContainer- term = tmNotebookTab ^. lensTMNotebookTabTerm . lensTerm- relabelTab notebook label scrolledWin term+ term' = tmNotebookTab ^. lensTMNotebookTabTerm . lensTerm+ relabelTab notebook label scrolledWin term' relabelTab :: Notebook -> Label -> ScrolledWindow -> Terminal -> IO ()-relabelTab notebook label scrolledWin term = do+relabelTab notebook label scrolledWin term' = do pageNum <- notebookPageNum notebook scrolledWin- title <- terminalGetWindowTitle term+ title <- terminalGetWindowTitle term' labelSetLabel label $ tshow (pageNum + 1) <> ". " <> title showScrollbarToPolicy :: ShowScrollbar -> PolicyType@@ -231,10 +235,33 @@ setRGBABlue rgba blue pure rgba +-- | TODO: This should probably be implemented in an external package,+-- since it is a generally useful utility.+--+-- It should also be implemented for windows and osx.+cwdOfPid :: Int -> IO (Maybe Text)+cwdOfPid pd = do+#ifdef mingw32_HOST_OS+ pure Nothing+#else+#ifdef darwin_HOST_OS+ pure Nothing+#else+ let pidPath = "/proc" </> show pd </> "cwd"+ eitherLinkTarget <- try $ getSymbolicLinkTarget pidPath+ case eitherLinkTarget of+ Left (_ :: IOException) -> pure Nothing+ Right linkTarget -> pure $ Just $ pack linkTarget+#endif+#endif++ createTerm :: (TMState -> EventKey -> IO Bool) -> TMState -> IO TMTerm createTerm handleKeyPress mvarTMState = do scrolledWin <- createScrolledWin mvarTMState- TMState{tmStateFontDesc, tmStateConfig} <- readMVar mvarTMState+ TMState{tmStateFontDesc, tmStateConfig, tmStateNotebook=currNote} <- readMVar mvarTMState+ let maybeCurrFocusedTabPid = pid . tmNotebookTabTerm <$> getFLFocusItem (tmNotebookTabs currNote)+ maybeCurrDir <- maybe (pure Nothing) cwdOfPid maybeCurrFocusedTabPid vteTerm <- terminalNew terminalSetFont vteTerm (Just tmStateFontDesc) terminalSetScrollbackLines vteTerm (fromIntegral (scrollbackLen tmStateConfig))@@ -243,17 +270,17 @@ terminalSetCursorBlinkMode vteTerm CursorBlinkModeOn widgetShow vteTerm widgetGrabFocus $ vteTerm- _termResVal <-+ terminalProcPid <- terminalSpawnSync vteTerm [PtyFlagsDefault]- Nothing+ maybeCurrDir ["/usr/bin/env", "bash"] Nothing ([SpawnFlagsDefault] :: [SpawnFlags]) Nothing noCancellable- tmTerm <- newTMTerm vteTerm+ tmTerm <- newTMTerm vteTerm (fromIntegral terminalProcPid) containerAdd scrolledWin vteTerm (tabLabelBox, tabLabel, tabCloseButton) <- createNotebookTabLabel let notebookTab = createTMNotebookTab tabLabel scrolledWin tmTerm
src/Termonad/Types.hs view
@@ -4,7 +4,7 @@ import Termonad.Prelude -import Control.Lens (firstOf, makeLensesFor)+import Control.Lens ((&), (.~), (^.), firstOf, makeLensesFor) import Data.Unique (Unique, hashUnique, newUnique) import GI.Gtk ( Application@@ -22,8 +22,9 @@ import Termonad.FocusList (FocusList, emptyFL, focusItemGetter, singletonFL) data TMTerm = TMTerm- { term :: Terminal- , unique :: Unique+ { term :: !Terminal+ , pid :: !Int+ , unique :: !Unique } instance Show TMTerm where@@ -34,21 +35,25 @@ showString "term = " . showString "(GI.GTK.Terminal)" . showString ", " .+ showString "pid = " .+ showsPrec (d + 1) pid .+ showString ", " . showString "unique = " . showsPrec (d + 1) (hashUnique unique) . showString "}" $(makeLensesFor [ ("term", "lensTerm")+ , ("pid", "lensPid") , ("unique", "lensUnique") ] ''TMTerm ) data TMNotebookTab = TMNotebookTab- { tmNotebookTabTermContainer :: ScrolledWindow- , tmNotebookTabTerm :: TMTerm- , tmNotebookTabLabel :: Label+ { tmNotebookTabTermContainer :: !ScrolledWindow+ , tmNotebookTabTerm :: !TMTerm+ , tmNotebookTabLabel :: !Label } instance Show TMNotebookTab where@@ -98,12 +103,21 @@ ''TMNotebook ) +data UserRequestedExit = UserRequestedExit | UserDidNotRequestExit deriving (Eq, Show)+ data TMState' = TMState { tmStateApp :: !Application , tmStateAppWin :: !ApplicationWindow , tmStateNotebook :: !TMNotebook , tmStateFontDesc :: !FontDescription , tmStateConfig :: !TMConfig+ , tmStateUserReqExit :: !UserRequestedExit+ -- ^ This signifies whether or not the user has requested that Termonad+ -- exit by either closing all terminals or clicking the exit button. If so,+ -- 'tmStateUserReqExit' should have a value of 'UserRequestedExit'. However,+ -- if the window manager requested Termonad to exit (probably through the user+ -- trying to close Termonad through their window manager), then this will be+ -- set to 'UserDidNotRequestExit'. } instance Show TMState' where@@ -125,6 +139,9 @@ showString ", " . showString "tmStateConfig = " . showsPrec (d + 1) tmStateConfig .+ showString ", " .+ showString "tmStateUserReqExit = " .+ showsPrec (d + 1) tmStateUserReqExit . showString "}" $(makeLensesFor@@ -133,6 +150,7 @@ , ("tmStateNotebook", "lensTMStateNotebook") , ("tmStateFontDesc", "lensTMStateFontDesc") , ("tmStateConfig", "lensTMStateConfig")+ , ("tmStateUserReqExit", "lensTMStateUserReqExit") ] ''TMState' )@@ -147,17 +165,18 @@ (==) :: TMNotebookTab -> TMNotebookTab -> Bool (==) = (==) `on` tmNotebookTabTerm -createTMTerm :: Terminal -> Unique -> TMTerm-createTMTerm trm unq =+createTMTerm :: Terminal -> Int -> Unique -> TMTerm+createTMTerm trm pd unq = TMTerm { term = trm+ , pid = pd , unique = unq } -newTMTerm :: Terminal -> IO TMTerm-newTMTerm trm = do+newTMTerm :: Terminal -> Int -> IO TMTerm+newTMTerm trm pd = do unq <- newUnique- pure $ createTMTerm trm unq+ pure $ createTMTerm trm pd unq createTMNotebookTab :: Label -> ScrolledWindow -> TMTerm -> TMNotebookTab createTMNotebookTab tabLabel scrollWin trm =@@ -186,6 +205,7 @@ , tmStateNotebook = note , tmStateFontDesc = fontDesc , tmStateConfig = tmConfig+ , tmStateUserReqExit = UserDidNotRequestExit } newEmptyTMState :: TMConfig -> Application -> ApplicationWindow -> Notebook -> FontDescription -> IO TMState@@ -197,6 +217,7 @@ , tmStateNotebook = createEmptyTMNotebook note , tmStateFontDesc = fontDesc , tmStateConfig = tmConfig+ , tmStateUserReqExit = UserDidNotRequestExit } newTMStateSingleTerm ::@@ -207,10 +228,11 @@ -> Label -> ScrolledWindow -> Terminal+ -> Int -> FontDescription -> IO TMState-newTMStateSingleTerm tmConfig app appWin note label scrollWin trm fontDesc = do- tmTerm <- newTMTerm trm+newTMStateSingleTerm tmConfig app appWin note label scrollWin trm pd fontDesc = do+ tmTerm <- newTMTerm trm pd let tmNoteTab = createTMNotebookTab label scrollWin tmTerm tabs = singletonFL tmNoteTab tmNote = createTMNotebook note tabs@@ -240,3 +262,13 @@ lensTerm ) )++setUserRequestedExit :: TMState -> IO ()+setUserRequestedExit mvarTMState = do+ modifyMVar_ mvarTMState $ \tmState -> do+ pure $ tmState & lensTMStateUserReqExit .~ UserRequestedExit++getUserRequestedExit :: TMState -> IO UserRequestedExit+getUserRequestedExit mvarTMState = do+ tmState <- readMVar mvarTMState+ pure $ tmState ^. lensTMStateUserReqExit
termonad.cabal view
@@ -1,5 +1,5 @@ name: termonad-version: 0.1.0.0+version: 0.2.0.0 synopsis: Terminal emulator configurable in Haskell description: Please see <https://github.com/cdepillabout/termonad#readme README.md>. homepage: https://github.com/cdepillabout/termonad@@ -10,10 +10,10 @@ copyright: 2017 Dennis Gosnell category: Text build-type: Custom+cabal-version: >=1.12 extra-source-files: README.md , CHANGELOG.md-cabal-version: >=1.12-+data-files: img/termonad-lambda.png custom-setup setup-depends: base , Cabal@@ -31,18 +31,21 @@ , Termonad.Term , Termonad.Types , Termonad.XML+ other-modules: Paths_termonad build-depends: base >= 4.7 && < 5 , classy-prelude , colour , constraints , data-default+ , directory >= 1.3.1.0 , dyre+ , filepath , gi-gdk , gi-gio , gi-glib- , gi-gtk+ , gi-gtk >= 3.0.24 , gi-pango- , gi-vte+ , gi-vte >= 2.91.18 , haskell-gi-base , lens , pretty-simple@@ -70,6 +73,7 @@ , TypeFamilies , TypeOperators other-extensions: TemplateHaskell+ pkgconfig-depends: gtk+-3.0 executable termonad main-is: Main.hs