packages feed

termonad 4.5.0.0 → 4.6.0.0

raw patch · 30 files changed

+2451/−1324 lines, 30 filesdep +bytestringdep +gi-gdkpixbufdep +optparse-applicativedep −adjunctionsdep −classy-preludedep −constraintsdep ~dyrePVP ok

version bump matches the API change (PVP)

Dependencies added: bytestring, gi-gdkpixbuf, optparse-applicative

Dependencies removed: adjunctions, classy-prelude, constraints, distributive, genvalidity-containers, genvalidity-hspec, hedgehog, mono-traversable, tasty-hedgehog, tasty-hspec

Dependency ranges changed: dyre

API changes (from Hackage documentation)

- Termonad.App: adjustFontDescSize :: (FontSize -> FontSize) -> FontDescription -> IO ()
- Termonad.App: applyNewPreferences :: TMState -> IO ()
- Termonad.App: applyNewPreferencesToTab :: TMState -> TMNotebookTab -> IO ()
- Termonad.App: comboBoxFill :: forall a. Show a => ComboBoxText -> [(a, Text)] -> IO ()
- Termonad.App: comboBoxGetActive :: forall a. (Show a, Enum a) => ComboBoxText -> [a] -> IO (Maybe a)
- Termonad.App: comboBoxSetActive :: Show a => ComboBoxText -> a -> IO ()
- Termonad.App: compareScrolledWinAndTab :: ScrolledWindow -> TMNotebookTab -> Bool
- Termonad.App: createFontDesc :: FontSize -> Text -> IO FontDescription
- Termonad.App: createFontDescFromConfig :: TMConfig -> IO FontDescription
- Termonad.App: defaultMain :: TMConfig -> IO ()
- Termonad.App: doFind :: TMState -> IO ()
- Termonad.App: findAbove :: TMState -> IO ()
- Termonad.App: findBelow :: TMState -> IO ()
- Termonad.App: fontConfigFromFontDescription :: FontDescription -> IO (Maybe FontConfig)
- Termonad.App: fontSizeFromFontDescription :: FontDescription -> IO FontSize
- Termonad.App: modifyFontSizeForAllTerms :: (FontSize -> FontSize) -> TMState -> IO ()
- Termonad.App: setFontDescSize :: FontDescription -> FontSize -> IO ()
- Termonad.App: setShowMenuBar :: Application -> Bool -> IO ()
- Termonad.App: showAboutDialog :: Application -> IO ()
- Termonad.App: showFindDialog :: Application -> IO (Maybe Text)
- Termonad.App: showPreferencesDialog :: TMState -> IO ()
- Termonad.App: updateFLTabPos :: TMState -> Int -> Int -> IO ()
- Termonad.Lenses: lensTMStateAppWin :: Lens' TMState' ApplicationWindow
- Termonad.Lenses: lensTMStateNotebook :: Lens' TMState' TMNotebook
- Termonad.Pcre: inline_c_ffi_6989586621679107081 :: IO CUInt
- Termonad.PreferencesFile: getPreferencesFile :: IO FilePath
- Termonad.PreferencesFile: mergeObjVals :: Value -> Value -> Value
- Termonad.PreferencesFile: readFileWithDefaults :: FilePath -> IO (Either Text ConfigOptions)
- Termonad.PreferencesFile: saveToPreferencesFile :: TMConfig -> IO ()
- Termonad.PreferencesFile: tmConfigFromPreferencesFile :: IO TMConfig
- Termonad.PreferencesFile: writePreferencesFile :: FilePath -> ConfigOptions -> IO ()
- Termonad.Prelude: ($!!) :: NFData a => (a -> b) -> a -> b
- Termonad.Prelude: (&&&) :: Arrow a => a b c -> a b c' -> a b (c, c')
- Termonad.Prelude: (***) :: Arrow a => a b c -> a b' c' -> a (b, b') (c, c')
- Termonad.Prelude: (<&&>) :: Applicative a => a Bool -> a Bool -> a Bool
- Termonad.Prelude: (<&>) :: Functor f => f a -> (a -> b) -> f b
- Termonad.Prelude: (<**>) :: Applicative f => f a -> f (a -> b) -> f b
- Termonad.Prelude: (<.>) :: FilePath -> String -> FilePath
- Termonad.Prelude: (</>) :: FilePath -> FilePath -> FilePath
- Termonad.Prelude: (<|) :: SemiSequence seq => Element seq -> NonNull seq -> NonNull seq
- Termonad.Prelude: (<|>) :: Alternative f => f a -> f a -> f a
- Termonad.Prelude: (<||>) :: Applicative a => a Bool -> a Bool -> a Bool
- Termonad.Prelude: (>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
- Termonad.Prelude: (\\) :: SetContainer a => a -> a -> a
- Termonad.Prelude: --
- Termonad.Prelude: -- Since 0.2.0
- Termonad.Prelude: -- container, much like <a>PrimState</a> from primitive.
- Termonad.Prelude: -- e.g., the <a>IsMap</a> instance of associated lists.
- Termonad.Prelude: -- reference.
- Termonad.Prelude: -- | The type of the index of a sequence.
- Termonad.Prelude: AbsoluteSeek :: SeekMode
- Termonad.Prelude: AppendMode :: IOMode
- Termonad.Prelude: AsyncCancelled :: AsyncCancelled
- Termonad.Prelude: AsyncExceptionWrapper :: e -> AsyncExceptionWrapper
- Termonad.Prelude: BlockBuffering :: Maybe Int -> BufferMode
- Termonad.Prelude: Concurrently :: m a -> Concurrently (m :: Type -> Type) a
- Termonad.Prelude: Down :: a -> Down a
- Termonad.Prelude: EmptyWithNoAlternative :: ConcException
- Termonad.Prelude: Handler :: (e -> m a) -> Handler (m :: Type -> Type) a
- Termonad.Prelude: Identity :: a -> Identity a
- Termonad.Prelude: LineBuffering :: BufferMode
- Termonad.Prelude: ModifiedJulianDay :: Integer -> Day
- Termonad.Prelude: MutVar :: MutVar# s a -> MutVar s a
- Termonad.Prelude: NoBuffering :: BufferMode
- Termonad.Prelude: ReadMode :: IOMode
- Termonad.Prelude: ReadWriteMode :: IOMode
- Termonad.Prelude: ReaderT :: (r -> m a) -> ReaderT r (m :: Type -> Type) a
- Termonad.Prelude: RelativeSeek :: SeekMode
- Termonad.Prelude: SeekFromEnd :: SeekMode
- Termonad.Prelude: SomeAsyncException :: e -> SomeAsyncException
- Termonad.Prelude: SomeException :: e -> SomeException
- Termonad.Prelude: StringException :: String -> CallStack -> StringException
- Termonad.Prelude: SyncExceptionWrapper :: e -> SyncExceptionWrapper
- Termonad.Prelude: UTCTime :: Day -> DiffTime -> UTCTime
- Termonad.Prelude: UnliftIO :: (forall a. () => m a -> IO a) -> UnliftIO (m :: Type -> Type)
- Termonad.Prelude: WrappedPoly :: f a -> WrappedPoly (f :: Type -> Type) a
- Termonad.Prelude: WriteMode :: IOMode
- Termonad.Prelude: [WrappedMono] :: forall mono a. Element mono ~ a => mono -> WrappedMono mono a
- Termonad.Prelude: [getDown] :: Down a -> a
- Termonad.Prelude: [runConcurrently] :: Concurrently (m :: Type -> Type) a -> m a
- Termonad.Prelude: [runIdentity] :: Identity a -> a
- Termonad.Prelude: [runReaderT] :: ReaderT r (m :: Type -> Type) a -> r -> m a
- Termonad.Prelude: [toModifiedJulianDay] :: Day -> Integer
- Termonad.Prelude: [unliftIO] :: UnliftIO (m :: Type -> Type) -> forall a. () => m a -> IO a
- Termonad.Prelude: [unwrapPoly] :: WrappedPoly (f :: Type -> Type) a -> f a
- Termonad.Prelude: [utctDayTime] :: UTCTime -> DiffTime
- Termonad.Prelude: [utctDay] :: UTCTime -> Day
- Termonad.Prelude: adjustMap :: IsMap map => (MapValue map -> MapValue map) -> ContainerKey map -> map -> map
- Termonad.Prelude: adjustWithKey :: IsMap map => (ContainerKey map -> MapValue map -> MapValue map) -> ContainerKey map -> map -> map
- Termonad.Prelude: alreadyExistsErrorType :: IOErrorType
- Termonad.Prelude: alreadyInUseErrorType :: IOErrorType
- Termonad.Prelude: alterMap :: IsMap map => (Maybe (MapValue map) -> Maybe (MapValue map)) -> ContainerKey map -> map -> map
- Termonad.Prelude: annotateIOError :: IOError -> String -> Maybe Handle -> Maybe FilePath -> IOError
- Termonad.Prelude: ap :: Monad m => m (a -> b) -> m a -> m b
- Termonad.Prelude: applyDList :: DList a -> [a] -> [a]
- Termonad.Prelude: asBDeque :: BDeque s a -> BDeque s a
- Termonad.Prelude: asBRef :: BRef s a -> BRef s a
- Termonad.Prelude: asByteString :: ByteString -> ByteString
- Termonad.Prelude: asDLList :: DLList s a -> DLList s a
- Termonad.Prelude: asDList :: DList a -> DList a
- Termonad.Prelude: asHashMap :: HashMap k v -> HashMap k v
- Termonad.Prelude: asHashSet :: HashSet a -> HashSet a
- Termonad.Prelude: asIORef :: IORef a -> IORef a
- Termonad.Prelude: asIntMap :: IntMap v -> IntMap v
- Termonad.Prelude: asIntSet :: IntSet -> IntSet
- Termonad.Prelude: asLByteString :: LByteString -> LByteString
- Termonad.Prelude: asLText :: LText -> LText
- Termonad.Prelude: asList :: [a] -> [a]
- Termonad.Prelude: asMap :: Map k v -> Map k v
- Termonad.Prelude: asMaybe :: Maybe a -> Maybe a
- Termonad.Prelude: asMutVar :: MutVar s a -> MutVar s a
- Termonad.Prelude: asPRef :: PRef s a -> PRef s a
- Termonad.Prelude: asSDeque :: SDeque s a -> SDeque s a
- Termonad.Prelude: asSRef :: SRef s a -> SRef s a
- Termonad.Prelude: asSTRef :: STRef s a -> STRef s a
- Termonad.Prelude: asSVector :: SVector a -> SVector a
- Termonad.Prelude: asSet :: Set a -> Set a
- Termonad.Prelude: asString :: [Char] -> [Char]
- Termonad.Prelude: asText :: Text -> Text
- Termonad.Prelude: asUDeque :: UDeque s a -> UDeque s a
- Termonad.Prelude: asURef :: URef s a -> URef s a
- Termonad.Prelude: asUVector :: UVector a -> UVector a
- Termonad.Prelude: asVector :: Vector a -> Vector a
- Termonad.Prelude: ask :: MonadReader r m => m r
- Termonad.Prelude: askRunInIO :: MonadUnliftIO m => m (m a -> IO a)
- Termonad.Prelude: askUnliftIO :: MonadUnliftIO m => m (UnliftIO m)
- Termonad.Prelude: asks :: MonadReader r m => (r -> a) -> m a
- Termonad.Prelude: assert :: Bool -> a -> a
- Termonad.Prelude: asum :: (Foldable t, Alternative f) => t (f a) -> f a
- Termonad.Prelude: async :: MonadUnliftIO m => m a -> m (Async a)
- Termonad.Prelude: asyncBound :: MonadUnliftIO m => m a -> m (Async a)
- Termonad.Prelude: asyncExceptionFromException :: Exception e => SomeException -> Maybe e
- Termonad.Prelude: asyncExceptionToException :: Exception e => e -> SomeException
- Termonad.Prelude: asyncOn :: MonadUnliftIO m => Int -> m a -> m (Async a)
- Termonad.Prelude: asyncOnWithUnmask :: MonadUnliftIO m => Int -> ((forall b. () => m b -> m b) -> m a) -> m (Async a)
- Termonad.Prelude: asyncWithUnmask :: MonadUnliftIO m => ((forall b. () => m b -> m b) -> m a) -> m (Async a)
- Termonad.Prelude: atomicModifyIORef :: MonadIO m => IORef a -> (a -> (a, b)) -> m b
- Termonad.Prelude: atomicModifyIORef' :: MonadIO m => IORef a -> (a -> (a, b)) -> m b
- Termonad.Prelude: atomicModifyMutVar :: PrimMonad m => MutVar (PrimState m) a -> (a -> (a, b)) -> m b
- Termonad.Prelude: atomicModifyMutVar' :: PrimMonad m => MutVar (PrimState m) a -> (a -> (a, b)) -> m b
- Termonad.Prelude: atomicModifyRef :: (MutableAtomicRef c, PrimMonad m, PrimState m ~ MCState c) => c -> (RefElement c -> (RefElement c, a)) -> m a
- Termonad.Prelude: atomicModifyRef' :: (MutableAtomicRef c, PrimMonad m, PrimState m ~ MCState c) => c -> (RefElement c -> (RefElement c, a)) -> m a
- Termonad.Prelude: atomicWriteIORef :: MonadIO m => IORef a -> a -> m ()
- Termonad.Prelude: atomically :: MonadIO m => STM a -> m a
- Termonad.Prelude: bimap :: Bifunctor p => (a -> b) -> (c -> d) -> p a c -> p b d
- Termonad.Prelude: bool :: a -> a -> Bool -> a
- Termonad.Prelude: bracket :: MonadUnliftIO m => m a -> (a -> m b) -> (a -> m c) -> m c
- Termonad.Prelude: bracketOnError :: MonadUnliftIO m => m a -> (a -> m b) -> (a -> m c) -> m c
- Termonad.Prelude: bracketOnError_ :: MonadUnliftIO m => m a -> m b -> m c -> m c
- Termonad.Prelude: bracket_ :: MonadUnliftIO m => m a -> m b -> m c -> m c
- Termonad.Prelude: breakLine :: Textual t => t -> (t, t)
- Termonad.Prelude: breakWord :: Textual t => t -> (t, t)
- Termonad.Prelude: builderToLazy :: Builder builder lazy => builder -> lazy
- Termonad.Prelude: cancel :: MonadIO m => Async a -> m ()
- Termonad.Prelude: cancelWith :: (Exception e, MonadIO m) => Async a -> e -> m ()
- Termonad.Prelude: catch :: (MonadUnliftIO m, Exception e) => m a -> (e -> m a) -> m a
- Termonad.Prelude: catchAny :: MonadUnliftIO m => m a -> (SomeException -> m a) -> m a
- Termonad.Prelude: catchAnyDeep :: (NFData a, MonadUnliftIO m) => m a -> (SomeException -> m a) -> m a
- Termonad.Prelude: catchDeep :: (MonadUnliftIO m, Exception e, NFData a) => m a -> (e -> m a) -> m a
- Termonad.Prelude: catchIO :: MonadUnliftIO m => m a -> (IOException -> m a) -> m a
- Termonad.Prelude: catchJust :: (MonadUnliftIO m, Exception e) => (e -> Maybe b) -> m a -> (b -> m a) -> m a
- Termonad.Prelude: catchSyncOrAsync :: (MonadUnliftIO m, Exception e) => m a -> (e -> m a) -> m a
- Termonad.Prelude: catches :: MonadUnliftIO m => m a -> [Handler m a] -> m a
- Termonad.Prelude: catchesDeep :: (MonadUnliftIO m, NFData a) => m a -> [Handler m a] -> m a
- Termonad.Prelude: charToLower :: Char -> Char
- Termonad.Prelude: charToUpper :: Char -> Char
- Termonad.Prelude: checkSTM :: Bool -> STM ()
- Termonad.Prelude: class Applicative f => Alternative (f :: Type -> Type)
- Termonad.Prelude: class BiPolyMap (map :: Type -> Type -> Type) where {
- Termonad.Prelude: class Bifunctor (p :: Type -> Type -> Type)
- Termonad.Prelude: class Monoid builder => Builder builder lazy | builder -> lazy, lazy -> builder
- Termonad.Prelude: class (Typeable e, Show e) => Exception e
- Termonad.Prelude: class MonoFoldable mono => GrowingAppend mono
- Termonad.Prelude: class SetContainer set => HasKeysSet set where {
- Termonad.Prelude: class Eq a => Hashable a
- Termonad.Prelude: class (MonoTraversable map, SetContainer map) => IsMap map where {
- Termonad.Prelude: class (Monoid seq, MonoTraversable seq, SemiSequence seq, MonoPointed seq) => IsSequence seq
- Termonad.Prelude: class (SetContainer set, Element set ~ ContainerKey set) => IsSet set
- Termonad.Prelude: class (IsSequence lazy, IsSequence strict) => LazySequence lazy strict | lazy -> strict, strict -> lazy
- Termonad.Prelude: class (Alternative m, Monad m) => MonadPlus (m :: Type -> Type)
- Termonad.Prelude: class Monad m => MonadReader r (m :: Type -> Type) | m -> r
- Termonad.Prelude: class MonadIO m => MonadUnliftIO (m :: Type -> Type)
- Termonad.Prelude: class MonoFunctor mono => MonoComonad mono
- Termonad.Prelude: class MonoFoldable mono
- Termonad.Prelude: class MonoFunctor mono
- Termonad.Prelude: class MonoPointed mono
- Termonad.Prelude: class (MonoFunctor mono, MonoFoldable mono) => MonoTraversable mono
- Termonad.Prelude: class MonoFunctor mono => MonoZip mono
- Termonad.Prelude: class MutableRef c => MutableAtomicRef c
- Termonad.Prelude: class MutableContainer c => MutableCollection c where {
- Termonad.Prelude: class MutableContainer c where {
- Termonad.Prelude: class MutableCollection c => MutablePopBack c
- Termonad.Prelude: class MutableCollection c => MutablePopFront c
- Termonad.Prelude: class MutableCollection c => MutablePushBack c
- Termonad.Prelude: class MutableCollection c => MutablePushFront c
- Termonad.Prelude: class MutableContainer c => MutableRef c where {
- Termonad.Prelude: class NFData a
- Termonad.Prelude: class PolyMap (map :: Type -> Type)
- Termonad.Prelude: class Prim a
- Termonad.Prelude: class Monad m => PrimMonad (m :: Type -> Type) where {
- Termonad.Prelude: class (Integral Index seq, GrowingAppend seq) => SemiSequence seq where {
- Termonad.Prelude: class (Monoid set, Semigroup set, MonoFoldable set, Eq ContainerKey set, GrowingAppend set) => SetContainer set where {
- Termonad.Prelude: class Storable a
- Termonad.Prelude: class (IsSequence t, IsString t, Element t ~ Char) => Textual t
- Termonad.Prelude: class ToBuilder value builder
- Termonad.Prelude: class Typeable (a :: k)
- Termonad.Prelude: class (Vector Vector a, MVector MVector a) => Unbox a
- Termonad.Prelude: class (Textual textual, IsSequence binary) => Utf8 textual binary | textual -> binary, binary -> textual
- Termonad.Prelude: cloneTChan :: TChan a -> STM (TChan a)
- Termonad.Prelude: closeTBMChan :: TBMChan a -> STM ()
- Termonad.Prelude: closeTBMQueue :: TBMQueue a -> STM ()
- Termonad.Prelude: closeTMChan :: TMChan a -> STM ()
- Termonad.Prelude: closeTMQueue :: TMQueue a -> STM ()
- Termonad.Prelude: compareLength :: (MonoFoldable mono, Integral i) => mono -> i -> Ordering
- Termonad.Prelude: comparing :: Ord a => (b -> a) -> b -> b -> Ordering
- Termonad.Prelude: conc :: m a -> Conc m a
- Termonad.Prelude: concurrently :: MonadUnliftIO m => m a -> m b -> m (a, b)
- Termonad.Prelude: concurrently_ :: MonadUnliftIO m => m a -> m b -> m ()
- Termonad.Prelude: cons :: SemiSequence seq => Element seq -> seq -> seq
- Termonad.Prelude: data Async a
- Termonad.Prelude: data AsyncCancelled
- Termonad.Prelude: data AsyncExceptionWrapper
- Termonad.Prelude: data BRef s a
- Termonad.Prelude: data BufferMode
- Termonad.Prelude: data Chan a
- Termonad.Prelude: data Conc (m :: TYPE LiftedRep -> Type) a
- Termonad.Prelude: data ConcException
- Termonad.Prelude: data DLList s a
- Termonad.Prelude: data DList a
- Termonad.Prelude: data Deque (v :: Type -> Type -> Type) s a
- Termonad.Prelude: data Handle
- Termonad.Prelude: data Handler (m :: Type -> Type) a
- Termonad.Prelude: data HashMap k v
- Termonad.Prelude: data HashSet a
- Termonad.Prelude: data IOErrorType
- Termonad.Prelude: data IOMode
- Termonad.Prelude: data IORef a
- Termonad.Prelude: data Int64
- Termonad.Prelude: data IntMap a
- Termonad.Prelude: data IntSet
- Termonad.Prelude: data Map k a
- Termonad.Prelude: data Memoized a
- Termonad.Prelude: data MutVar s a
- Termonad.Prelude: data NonNull mono
- Termonad.Prelude: data PRef s a
- Termonad.Prelude: data QSem
- Termonad.Prelude: data QSemN
- Termonad.Prelude: data RealWorld
- Termonad.Prelude: data SRef s a
- Termonad.Prelude: data STM a
- Termonad.Prelude: data STRef s a
- Termonad.Prelude: data SeekMode
- Termonad.Prelude: data Seq a
- Termonad.Prelude: data Set a
- Termonad.Prelude: data SomeAsyncException
- Termonad.Prelude: data SomeException
- Termonad.Prelude: data StringException
- Termonad.Prelude: data SyncExceptionWrapper
- Termonad.Prelude: data TBChan a
- Termonad.Prelude: data TBMChan a
- Termonad.Prelude: data TBMQueue a
- Termonad.Prelude: data TBQueue a
- Termonad.Prelude: data TChan a
- Termonad.Prelude: data TMChan a
- Termonad.Prelude: data TMQueue a
- Termonad.Prelude: data TMVar a
- Termonad.Prelude: data TQueue a
- Termonad.Prelude: data TVar a
- Termonad.Prelude: data URef s a
- Termonad.Prelude: data UTCTime
- Termonad.Prelude: data Vector a
- Termonad.Prelude: data Word64
- Termonad.Prelude: data WrappedMono mono a
- Termonad.Prelude: data WrappedMonoid m
- Termonad.Prelude: decodeUtf8 :: Utf8 textual binary => binary -> textual
- Termonad.Prelude: deepseq :: NFData a => a -> b -> b
- Termonad.Prelude: defaultCons :: IsSequence seq => Element seq -> seq -> seq
- Termonad.Prelude: defaultFind :: MonoFoldable seq => (Element seq -> Bool) -> seq -> Maybe (Element seq)
- Termonad.Prelude: defaultIntersperse :: IsSequence seq => Element seq -> seq -> seq
- Termonad.Prelude: defaultReverse :: IsSequence seq => seq -> seq
- Termonad.Prelude: defaultSnoc :: IsSequence seq => seq -> Element seq -> seq
- Termonad.Prelude: defaultSortBy :: IsSequence seq => (Element seq -> Element seq -> Ordering) -> seq -> seq
- Termonad.Prelude: defaultSplitWhen :: IsSequence seq => (Element seq -> Bool) -> seq -> [seq]
- Termonad.Prelude: defaultTimeLocale :: TimeLocale
- Termonad.Prelude: delete :: (IsSequence seq, Eq (Element seq)) => Element seq -> seq -> seq
- Termonad.Prelude: deleteBy :: (IsSequence seq, Eq (Element seq)) => (Element seq -> Element seq -> Bool) -> Element seq -> seq -> seq
- Termonad.Prelude: deleteMap :: IsMap map => ContainerKey map -> map -> map
- Termonad.Prelude: deleteSet :: IsSet set => Element set -> set -> set
- Termonad.Prelude: difference :: SetContainer set => set -> set -> set
- Termonad.Prelude: differenceMap :: PolyMap map => map value1 -> map value2 -> map value1
- Termonad.Prelude: displayException :: Exception e => e -> String
- Termonad.Prelude: doesNotExistErrorType :: IOErrorType
- Termonad.Prelude: dropEnd :: IsSequence seq => Index seq -> seq -> seq
- Termonad.Prelude: dropPrefix :: (IsSequence seq, Eq (Element seq)) => seq -> seq -> seq
- Termonad.Prelude: dropSuffix :: (IsSequence seq, Eq (Element seq)) => seq -> seq -> seq
- Termonad.Prelude: dupChan :: MonadIO m => Chan a -> m (Chan a)
- Termonad.Prelude: dupTChan :: TChan a -> STM (TChan a)
- Termonad.Prelude: dupTMChan :: TMChan a -> STM (TMChan a)
- Termonad.Prelude: empty :: Alternative f => f a
- Termonad.Prelude: encodeUtf8 :: Utf8 textual binary => textual -> binary
- Termonad.Prelude: ensurePrefix :: (Eq (Element seq), IsSequence seq) => seq -> seq -> seq
- Termonad.Prelude: ensureSuffix :: (Eq (Element seq), IsSequence seq) => seq -> seq -> seq
- Termonad.Prelude: eofErrorType :: IOErrorType
- Termonad.Prelude: equating :: Eq a => (b -> a) -> b -> b -> Bool
- Termonad.Prelude: estimateFreeSlotsTBChan :: TBChan a -> STM Int
- Termonad.Prelude: estimateFreeSlotsTBMChan :: TBMChan a -> STM Int
- Termonad.Prelude: estimateFreeSlotsTBMQueue :: TBMQueue a -> STM Int
- Termonad.Prelude: evaluate :: MonadIO m => a -> m a
- Termonad.Prelude: evaluateDeep :: (MonadIO m, NFData a) => a -> m a
- Termonad.Prelude: filterM :: (IsSequence seq, Monad m) => (Element seq -> m Bool) -> seq -> m seq
- Termonad.Prelude: filterMap :: IsMap map => (MapValue map -> Bool) -> map -> map
- Termonad.Prelude: filterSet :: IsSet set => (Element set -> Bool) -> set -> set
- Termonad.Prelude: finally :: MonadUnliftIO m => m a -> m b -> m a
- Termonad.Prelude: find :: SemiSequence seq => (Element seq -> Bool) -> seq -> Maybe (Element seq)
- Termonad.Prelude: findWithDefault :: IsMap map => MapValue map -> ContainerKey map -> map -> MapValue map
- Termonad.Prelude: first :: Bifunctor p => (a -> b) -> p a c -> p b c
- Termonad.Prelude: flushBuilder :: Builder builder lazy => builder
- Termonad.Prelude: flushTBQueue :: TBQueue a -> STM [a]
- Termonad.Prelude: fold :: (MonoFoldable mono, Monoid (Element mono)) => mono -> Element mono
- Termonad.Prelude: foldM :: (MonoFoldable mono, Monad m) => (a -> Element mono -> m a) -> a -> mono -> m a
- Termonad.Prelude: foldMap1Ex :: (MonoFoldable mono, Semigroup m) => (Element mono -> m) -> mono -> m
- Termonad.Prelude: foldl' :: MonoFoldable mono => (a -> Element mono -> a) -> a -> mono -> a
- Termonad.Prelude: foldl1Ex' :: MonoFoldable mono => (Element mono -> Element mono -> Element mono) -> mono -> Element mono
- Termonad.Prelude: foldlM :: (MonoFoldable mono, Monad m) => (a -> Element mono -> m a) -> a -> mono -> m a
- Termonad.Prelude: foldr1Ex :: MonoFoldable mono => (Element mono -> Element mono -> Element mono) -> mono -> Element mono
- Termonad.Prelude: for :: (Traversable t, Applicative f) => t a -> (a -> f b) -> f (t b)
- Termonad.Prelude: forConcurrently :: (MonadUnliftIO m, Traversable t) => t a -> (a -> m b) -> m (t b)
- Termonad.Prelude: forConcurrently_ :: (MonadUnliftIO m, Foldable f) => f a -> (a -> m b) -> m ()
- Termonad.Prelude: forM :: (Traversable t, Monad m) => t a -> (a -> m b) -> m (t b)
- Termonad.Prelude: forM_ :: (MonoFoldable mono, Applicative m) => mono -> (Element mono -> m ()) -> m ()
- Termonad.Prelude: for_ :: (MonoFoldable mono, Applicative f) => mono -> (Element mono -> f b) -> f ()
- Termonad.Prelude: force :: NFData a => a -> a
- Termonad.Prelude: forever :: Applicative f => f a -> f b
- Termonad.Prelude: formatTime :: FormatTime t => TimeLocale -> String -> t -> String
- Termonad.Prelude: freeSlotsTBChan :: TBChan a -> STM Int
- Termonad.Prelude: freeSlotsTBMChan :: TBMChan a -> STM Int
- Termonad.Prelude: freeSlotsTBMQueue :: TBMQueue a -> STM Int
- Termonad.Prelude: fromByteVector :: SVector Word8 -> ByteString
- Termonad.Prelude: fromChunks :: LazySequence lazy strict => [strict] -> lazy
- Termonad.Prelude: fromEither :: (Exception e, MonadIO m) => Either e a -> m a
- Termonad.Prelude: fromEitherIO :: (Exception e, MonadIO m) => IO (Either e a) -> m a
- Termonad.Prelude: fromEitherM :: (Exception e, MonadIO m) => m (Either e a) -> m a
- Termonad.Prelude: fromException :: Exception e => SomeException -> Maybe e
- Termonad.Prelude: fromExceptionUnwrap :: Exception e => SomeException -> Maybe e
- Termonad.Prelude: fromGregorian :: Year -> MonthOfYear -> DayOfMonth -> Day
- Termonad.Prelude: fromList :: IsSequence seq => [Element seq] -> seq
- Termonad.Prelude: fromNonEmpty :: IsSequence seq => NonEmpty (Element seq) -> NonNull seq
- Termonad.Prelude: fromNullable :: MonoFoldable mono => mono -> Maybe (NonNull mono)
- Termonad.Prelude: fromStrict :: LazySequence lazy strict => strict -> lazy
- Termonad.Prelude: fromString :: IsString a => String -> a
- Termonad.Prelude: fullErrorType :: IOErrorType
- Termonad.Prelude: getArgs :: MonadIO m => m [Text]
- Termonad.Prelude: getChanContents :: MonadIO m => Chan a -> m [a]
- Termonad.Prelude: getCurrentTime :: IO UTCTime
- Termonad.Prelude: getMonotonicTime :: MonadIO m => m Double
- Termonad.Prelude: group :: (IsSequence seq, Eq (Element seq)) => seq -> [seq]
- Termonad.Prelude: groupAll :: (IsSequence seq, Eq (Element seq)) => seq -> [seq]
- Termonad.Prelude: groupAllOn :: (IsSequence seq, Eq b) => (Element seq -> b) -> seq -> [seq]
- Termonad.Prelude: groupBy :: IsSequence seq => (Element seq -> Element seq -> Bool) -> seq -> [seq]
- Termonad.Prelude: guard :: Alternative f => Bool -> f ()
- Termonad.Prelude: hClose :: MonadIO m => Handle -> m ()
- Termonad.Prelude: hFileSize :: MonadIO m => Handle -> m Integer
- Termonad.Prelude: hFlush :: MonadIO m => Handle -> m ()
- Termonad.Prelude: hGetBuffering :: MonadIO m => Handle -> m BufferMode
- Termonad.Prelude: hGetChunk :: MonadIO m => Handle -> m ByteString
- Termonad.Prelude: hGetContents :: MonadIO m => Handle -> m ByteString
- Termonad.Prelude: hGetEcho :: MonadIO m => Handle -> m Bool
- Termonad.Prelude: hIsClosed :: MonadIO m => Handle -> m Bool
- Termonad.Prelude: hIsEOF :: MonadIO m => Handle -> m Bool
- Termonad.Prelude: hIsOpen :: MonadIO m => Handle -> m Bool
- Termonad.Prelude: hIsReadable :: MonadIO m => Handle -> m Bool
- Termonad.Prelude: hIsSeekable :: MonadIO m => Handle -> m Bool
- Termonad.Prelude: hIsTerminalDevice :: MonadIO m => Handle -> m Bool
- Termonad.Prelude: hIsWritable :: MonadIO m => Handle -> m Bool
- Termonad.Prelude: hPut :: MonadIO m => Handle -> ByteString -> m ()
- Termonad.Prelude: hReady :: MonadIO m => Handle -> m Bool
- Termonad.Prelude: hSay :: MonadIO m => Handle -> Text -> m ()
- Termonad.Prelude: hSayShow :: (MonadIO m, Show a) => Handle -> a -> m ()
- Termonad.Prelude: hSayString :: MonadIO m => Handle -> String -> m ()
- Termonad.Prelude: hSeek :: MonadIO m => Handle -> SeekMode -> Integer -> m ()
- Termonad.Prelude: hSetBuffering :: MonadIO m => Handle -> BufferMode -> m ()
- Termonad.Prelude: hSetEcho :: MonadIO m => Handle -> Bool -> m ()
- Termonad.Prelude: hSetFileSize :: MonadIO m => Handle -> Integer -> m ()
- Termonad.Prelude: hTell :: MonadIO m => Handle -> m Integer
- Termonad.Prelude: hWaitForInput :: MonadIO m => Handle -> Int -> m Bool
- Termonad.Prelude: handle :: (MonadUnliftIO m, Exception e) => (e -> m a) -> m a -> m a
- Termonad.Prelude: handleAny :: MonadUnliftIO m => (SomeException -> m a) -> m a -> m a
- Termonad.Prelude: handleAnyDeep :: (MonadUnliftIO m, NFData a) => (SomeException -> m a) -> m a -> m a
- Termonad.Prelude: handleDeep :: (MonadUnliftIO m, Exception e, NFData a) => (e -> m a) -> m a -> m a
- Termonad.Prelude: handleIO :: MonadUnliftIO m => (IOException -> m a) -> m a -> m a
- Termonad.Prelude: handleJust :: (MonadUnliftIO m, Exception e) => (e -> Maybe b) -> (b -> m a) -> m a -> m a
- Termonad.Prelude: handleSyncOrAsync :: (MonadUnliftIO m, Exception e) => (e -> m a) -> m a -> m a
- Termonad.Prelude: hash :: Hashable a => a -> Int
- Termonad.Prelude: hashNub :: (Hashable a, Eq a) => [a] -> [a]
- Termonad.Prelude: hashWithSalt :: Hashable a => Int -> a -> Int
- Termonad.Prelude: headEx :: MonoFoldable mono => mono -> Element mono
- Termonad.Prelude: headMay :: MonoFoldable mono => mono -> Maybe (Element mono)
- Termonad.Prelude: illegalOperationErrorType :: IOErrorType
- Termonad.Prelude: impureNonNull :: MonoFoldable mono => mono -> NonNull mono
- Termonad.Prelude: impureThrow :: Exception e => e -> a
- Termonad.Prelude: index :: IsSequence seq => seq -> Index seq -> Maybe (Element seq)
- Termonad.Prelude: indexEx :: IsSequence seq => seq -> Index seq -> Element seq
- Termonad.Prelude: infixl 3 <|>
- Termonad.Prelude: infixr 7 <.>
- Termonad.Prelude: initDef :: IsSequence seq => seq -> seq
- Termonad.Prelude: initEx :: IsSequence seq => seq -> seq
- Termonad.Prelude: initMay :: IsSequence seq => seq -> Maybe seq
- Termonad.Prelude: insertLookupWithKey :: IsMap map => (ContainerKey map -> MapValue map -> MapValue map -> MapValue map) -> ContainerKey map -> MapValue map -> map -> (Maybe (MapValue map), map)
- Termonad.Prelude: insertMap :: IsMap map => ContainerKey map -> MapValue map -> map -> map
- Termonad.Prelude: insertSet :: IsSet set => Element set -> set -> set
- Termonad.Prelude: insertWith :: IsMap map => (MapValue map -> MapValue map -> MapValue map) -> ContainerKey map -> MapValue map -> map -> map
- Termonad.Prelude: insertWithKey :: IsMap map => (ContainerKey map -> MapValue map -> MapValue map -> MapValue map) -> ContainerKey map -> MapValue map -> map -> map
- Termonad.Prelude: intercalate :: (MonoFoldable mono, Monoid (Element mono)) => Element mono -> mono -> Element mono
- Termonad.Prelude: intersect :: SetContainer a => a -> a -> a
- Termonad.Prelude: intersection :: SetContainer set => set -> set -> set
- Termonad.Prelude: intersectionMap :: PolyMap map => map value1 -> map value2 -> map value1
- Termonad.Prelude: intersectionWithMap :: PolyMap map => (value1 -> value2 -> value3) -> map value1 -> map value2 -> map value3
- Termonad.Prelude: intersperse :: SemiSequence seq => Element seq -> seq -> seq
- Termonad.Prelude: ioeGetErrorString :: IOError -> String
- Termonad.Prelude: ioeGetErrorType :: IOError -> IOErrorType
- Termonad.Prelude: ioeGetFileName :: IOError -> Maybe FilePath
- Termonad.Prelude: ioeGetHandle :: IOError -> Maybe Handle
- Termonad.Prelude: ioeGetLocation :: IOError -> String
- Termonad.Prelude: ioeSetErrorString :: IOError -> String -> IOError
- Termonad.Prelude: ioeSetErrorType :: IOError -> IOErrorType -> IOError
- Termonad.Prelude: ioeSetFileName :: IOError -> FilePath -> IOError
- Termonad.Prelude: ioeSetHandle :: IOError -> Handle -> IOError
- Termonad.Prelude: ioeSetLocation :: IOError -> String -> IOError
- Termonad.Prelude: isAlreadyExistsError :: IOError -> Bool
- Termonad.Prelude: isAlreadyExistsErrorType :: IOErrorType -> Bool
- Termonad.Prelude: isAlreadyInUseError :: IOError -> Bool
- Termonad.Prelude: isAlreadyInUseErrorType :: IOErrorType -> Bool
- Termonad.Prelude: isAsyncException :: Exception e => e -> Bool
- Termonad.Prelude: isClosedTBMChan :: TBMChan a -> STM Bool
- Termonad.Prelude: isClosedTBMQueue :: TBMQueue a -> STM Bool
- Termonad.Prelude: isClosedTMChan :: TMChan a -> STM Bool
- Termonad.Prelude: isClosedTMQueue :: TMQueue a -> STM Bool
- Termonad.Prelude: isDoesNotExistError :: IOError -> Bool
- Termonad.Prelude: isDoesNotExistErrorType :: IOErrorType -> Bool
- Termonad.Prelude: isEOFError :: IOError -> Bool
- Termonad.Prelude: isEOFErrorType :: IOErrorType -> Bool
- Termonad.Prelude: isEmptyMVar :: MonadIO m => MVar a -> m Bool
- Termonad.Prelude: isEmptyTBChan :: TBChan a -> STM Bool
- Termonad.Prelude: isEmptyTBMChan :: TBMChan a -> STM Bool
- Termonad.Prelude: isEmptyTBMQueue :: TBMQueue a -> STM Bool
- Termonad.Prelude: isEmptyTBQueue :: TBQueue a -> STM Bool
- Termonad.Prelude: isEmptyTChan :: TChan a -> STM Bool
- Termonad.Prelude: isEmptyTMChan :: TMChan a -> STM Bool
- Termonad.Prelude: isEmptyTMQueue :: TMQueue a -> STM Bool
- Termonad.Prelude: isEmptyTMVar :: TMVar a -> STM Bool
- Termonad.Prelude: isEmptyTQueue :: TQueue a -> STM Bool
- Termonad.Prelude: isFullError :: IOError -> Bool
- Termonad.Prelude: isFullErrorType :: IOErrorType -> Bool
- Termonad.Prelude: isFullTBChan :: TBChan a -> STM Bool
- Termonad.Prelude: isFullTBMChan :: TBMChan a -> STM Bool
- Termonad.Prelude: isFullTBMQueue :: TBMQueue a -> STM Bool
- Termonad.Prelude: isFullTBQueue :: TBQueue a -> STM Bool
- Termonad.Prelude: isIllegalOperation :: IOError -> Bool
- Termonad.Prelude: isIllegalOperationErrorType :: IOErrorType -> Bool
- Termonad.Prelude: isInfixOf :: (IsSequence seq, Eq (Element seq)) => seq -> seq -> Bool
- Termonad.Prelude: isJust :: Maybe a -> Bool
- Termonad.Prelude: isNothing :: Maybe a -> Bool
- Termonad.Prelude: isPermissionError :: IOError -> Bool
- Termonad.Prelude: isPermissionErrorType :: IOErrorType -> Bool
- Termonad.Prelude: isPrefixOf :: (IsSequence seq, Eq (Element seq)) => seq -> seq -> Bool
- Termonad.Prelude: isResourceVanishedError :: IOError -> Bool
- Termonad.Prelude: isResourceVanishedErrorType :: IOErrorType -> Bool
- Termonad.Prelude: isSuffixOf :: (IsSequence seq, Eq (Element seq)) => seq -> seq -> Bool
- Termonad.Prelude: isSyncException :: Exception e => e -> Bool
- Termonad.Prelude: isUserError :: IOError -> Bool
- Termonad.Prelude: isUserErrorType :: IOErrorType -> Bool
- Termonad.Prelude: keys :: SetContainer set => set -> [ContainerKey set]
- Termonad.Prelude: keysSet :: HasKeysSet set => set -> KeySet set
- Termonad.Prelude: lastEx :: MonoFoldable mono => mono -> Element mono
- Termonad.Prelude: lastMay :: MonoFoldable mono => mono -> Maybe (Element mono)
- Termonad.Prelude: lefts :: [Either a b] -> [a]
- Termonad.Prelude: length64 :: MonoFoldable mono => mono -> Int64
- Termonad.Prelude: lengthIndex :: IsSequence seq => seq -> Index seq
- Termonad.Prelude: lengthTBQueue :: TBQueue a -> STM Natural
- Termonad.Prelude: liftA :: Applicative f => (a -> b) -> f a -> f b
- Termonad.Prelude: liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
- Termonad.Prelude: liftA3 :: Applicative f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d
- Termonad.Prelude: liftIOOp :: MonadUnliftIO m => (IO a -> IO b) -> m a -> m b
- Termonad.Prelude: liftM :: Monad m => (a1 -> r) -> m a1 -> m r
- Termonad.Prelude: liftM2 :: Monad m => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
- Termonad.Prelude: liftM3 :: Monad m => (a1 -> a2 -> a3 -> r) -> m a1 -> m a2 -> m a3 -> m r
- Termonad.Prelude: liftM4 :: Monad m => (a1 -> a2 -> a3 -> a4 -> r) -> m a1 -> m a2 -> m a3 -> m a4 -> m r
- Termonad.Prelude: liftM5 :: Monad m => (a1 -> a2 -> a3 -> a4 -> a5 -> r) -> m a1 -> m a2 -> m a3 -> m a4 -> m a5 -> m r
- Termonad.Prelude: link :: MonadIO m => Async a -> m ()
- Termonad.Prelude: link2 :: MonadIO m => Async a -> Async b -> m ()
- Termonad.Prelude: link2Async :: MonadIO m => Async a -> Async b -> m ()
- Termonad.Prelude: linkAsync :: MonadIO m => Async a -> m ()
- Termonad.Prelude: listToMaybe :: [a] -> Maybe a
- Termonad.Prelude: many :: Alternative f => f a -> f [a]
- Termonad.Prelude: mapConcurrently :: (MonadUnliftIO m, Traversable t) => (a -> m b) -> t a -> m (t b)
- Termonad.Prelude: mapConcurrently_ :: (MonadUnliftIO m, Foldable f) => (a -> m b) -> f a -> m ()
- Termonad.Prelude: mapExceptionM :: (Exception e1, Exception e2, MonadUnliftIO m) => (e1 -> e2) -> m a -> m a
- Termonad.Prelude: mapFromList :: IsMap map => [(ContainerKey map, MapValue map)] -> map
- Termonad.Prelude: mapKeysWith :: (BiPolyMap map, BPMKeyConstraint map k1, BPMKeyConstraint map k2) => (v -> v -> v) -> (k1 -> k2) -> map k1 v -> map k2 v
- Termonad.Prelude: mapMaybe :: (a -> Maybe b) -> [a] -> [b]
- Termonad.Prelude: mapNonNull :: (Functor f, MonoFoldable (f b)) => (a -> b) -> NonNull (f a) -> NonNull (f b)
- Termonad.Prelude: mapToList :: IsMap map => map -> [(ContainerKey map, MapValue map)]
- Termonad.Prelude: mapWithKey :: IsMap map => (ContainerKey map -> MapValue map -> MapValue map) -> map -> map
- Termonad.Prelude: mask :: MonadUnliftIO m => ((forall a. () => m a -> m a) -> m b) -> m b
- Termonad.Prelude: mask_ :: MonadUnliftIO m => m a -> m a
- Termonad.Prelude: maximumBy :: MonoFoldable mono => (Element mono -> Element mono -> Ordering) -> NonNull mono -> Element mono
- Termonad.Prelude: maximumByEx :: MonoFoldable mono => (Element mono -> Element mono -> Ordering) -> mono -> Element mono
- Termonad.Prelude: maximumByMay :: MonoFoldable mono => (Element mono -> Element mono -> Ordering) -> mono -> Maybe (Element mono)
- Termonad.Prelude: maximumEx :: (MonoFoldable mono, Ord (Element mono)) => mono -> Element mono
- Termonad.Prelude: maximumMay :: (MonoFoldable mono, Ord (Element mono)) => mono -> Maybe (Element mono)
- Termonad.Prelude: maybeToList :: Maybe a -> [a]
- Termonad.Prelude: member :: SetContainer set => ContainerKey set -> set -> Bool
- Termonad.Prelude: memoizeMVar :: MonadUnliftIO m => m a -> m (Memoized a)
- Termonad.Prelude: memoizeRef :: MonadUnliftIO m => m a -> m (Memoized a)
- Termonad.Prelude: minimumBy :: MonoFoldable mono => (Element mono -> Element mono -> Ordering) -> NonNull mono -> Element mono
- Termonad.Prelude: minimumByEx :: MonoFoldable mono => (Element mono -> Element mono -> Ordering) -> mono -> Element mono
- Termonad.Prelude: minimumByMay :: MonoFoldable mono => (Element mono -> Element mono -> Ordering) -> mono -> Maybe (Element mono)
- Termonad.Prelude: minimumEx :: (MonoFoldable mono, Ord (Element mono)) => mono -> Element mono
- Termonad.Prelude: minimumMay :: (MonoFoldable mono, Ord (Element mono)) => mono -> Maybe (Element mono)
- Termonad.Prelude: mkIOError :: IOErrorType -> String -> Maybe Handle -> Maybe FilePath -> IOError
- Termonad.Prelude: mkWeakIORef :: MonadUnliftIO m => IORef a -> m () -> m (Weak (IORef a))
- Termonad.Prelude: mkWeakMVar :: MonadUnliftIO m => MVar a -> m () -> m (Weak (MVar a))
- Termonad.Prelude: mkWeakTMVar :: MonadUnliftIO m => TMVar a -> m () -> m (Weak (TMVar a))
- Termonad.Prelude: mkWeakTVar :: MonadUnliftIO m => TVar a -> m () -> m (Weak (TVar a))
- Termonad.Prelude: modifyIOError :: (IOError -> IOError) -> IO a -> IO a
- Termonad.Prelude: modifyIORef :: MonadIO m => IORef a -> (a -> a) -> m ()
- Termonad.Prelude: modifyIORef' :: MonadIO m => IORef a -> (a -> a) -> m ()
- Termonad.Prelude: modifyMVarMasked :: MonadUnliftIO m => MVar a -> (a -> m (a, b)) -> m b
- Termonad.Prelude: modifyMVarMasked_ :: MonadUnliftIO m => MVar a -> (a -> m a) -> m ()
- Termonad.Prelude: modifyMutVar :: PrimMonad m => MutVar (PrimState m) a -> (a -> a) -> m ()
- Termonad.Prelude: modifyMutVar' :: PrimMonad m => MutVar (PrimState m) a -> (a -> a) -> m ()
- Termonad.Prelude: modifyRef :: (MutableRef c, PrimMonad m, PrimState m ~ MCState c) => c -> (RefElement c -> RefElement c) -> m ()
- Termonad.Prelude: modifyRef' :: (MutableRef c, PrimMonad m, PrimState m ~ MCState c) => c -> (RefElement c -> RefElement c) -> m ()
- Termonad.Prelude: modifyTVar :: TVar a -> (a -> a) -> STM ()
- Termonad.Prelude: modifyTVar' :: TVar a -> (a -> a) -> STM ()
- Termonad.Prelude: mplus :: MonadPlus m => m a -> m a -> m a
- Termonad.Prelude: mzero :: MonadPlus m => m a
- Termonad.Prelude: nReplicate :: IsSequence seq => Index seq -> Element seq -> NonNull seq
- Termonad.Prelude: ncons :: SemiSequence seq => Element seq -> seq -> NonNull seq
- Termonad.Prelude: newBroadcastTChan :: STM (TChan a)
- Termonad.Prelude: newBroadcastTChanIO :: MonadIO m => m (TChan a)
- Termonad.Prelude: newBroadcastTMChan :: STM (TMChan a)
- Termonad.Prelude: newBroadcastTMChanIO :: IO (TMChan a)
- Termonad.Prelude: newChan :: MonadIO m => m (Chan a)
- Termonad.Prelude: newColl :: (MutableCollection c, PrimMonad m, PrimState m ~ MCState c) => m c
- Termonad.Prelude: newEmptyMVar :: MonadIO m => m (MVar a)
- Termonad.Prelude: newEmptyTMVar :: STM (TMVar a)
- Termonad.Prelude: newEmptyTMVarIO :: MonadIO m => m (TMVar a)
- Termonad.Prelude: newIORef :: MonadIO m => a -> m (IORef a)
- Termonad.Prelude: newMutVar :: PrimMonad m => a -> m (MutVar (PrimState m) a)
- Termonad.Prelude: newQSem :: MonadIO m => Int -> m QSem
- Termonad.Prelude: newQSemN :: MonadIO m => Int -> m QSemN
- Termonad.Prelude: newRef :: (MutableRef c, PrimMonad m, PrimState m ~ MCState c) => RefElement c -> m c
- Termonad.Prelude: newTBChan :: Int -> STM (TBChan a)
- Termonad.Prelude: newTBChanIO :: Int -> IO (TBChan a)
- Termonad.Prelude: newTBMChan :: Int -> STM (TBMChan a)
- Termonad.Prelude: newTBMChanIO :: Int -> IO (TBMChan a)
- Termonad.Prelude: newTBMQueue :: Int -> STM (TBMQueue a)
- Termonad.Prelude: newTBMQueueIO :: Int -> IO (TBMQueue a)
- Termonad.Prelude: newTBQueue :: Natural -> STM (TBQueue a)
- Termonad.Prelude: newTBQueueIO :: MonadIO m => Natural -> m (TBQueue a)
- Termonad.Prelude: newTChan :: STM (TChan a)
- Termonad.Prelude: newTChanIO :: MonadIO m => m (TChan a)
- Termonad.Prelude: newTMChan :: STM (TMChan a)
- Termonad.Prelude: newTMChanIO :: IO (TMChan a)
- Termonad.Prelude: newTMQueue :: STM (TMQueue a)
- Termonad.Prelude: newTMQueueIO :: IO (TMQueue a)
- Termonad.Prelude: newTMVar :: a -> STM (TMVar a)
- Termonad.Prelude: newTMVarIO :: MonadIO m => a -> m (TMVar a)
- Termonad.Prelude: newTQueue :: STM (TQueue a)
- Termonad.Prelude: newTQueueIO :: MonadIO m => m (TQueue a)
- Termonad.Prelude: newTVar :: a -> STM (TVar a)
- Termonad.Prelude: newTVarIO :: MonadIO m => a -> m (TVar a)
- Termonad.Prelude: newtype Concurrently (m :: Type -> Type) a
- Termonad.Prelude: newtype Day
- Termonad.Prelude: newtype Down a
- Termonad.Prelude: newtype Identity a
- Termonad.Prelude: newtype ReaderT r (m :: Type -> Type) a
- Termonad.Prelude: newtype UnliftIO (m :: Type -> Type)
- Termonad.Prelude: newtype WrappedPoly (f :: Type -> Type) a
- Termonad.Prelude: nfilter :: IsSequence seq => (Element seq -> Bool) -> NonNull seq -> seq
- Termonad.Prelude: nfilterM :: (Monad m, IsSequence seq) => (Element seq -> m Bool) -> NonNull seq -> m seq
- Termonad.Prelude: nonNull :: MonoFoldable mono => mono -> NonNull mono
- Termonad.Prelude: notMember :: SetContainer set => ContainerKey set -> set -> Bool
- Termonad.Prelude: nuncons :: IsSequence seq => NonNull seq -> (Element seq, Maybe (NonNull seq))
- Termonad.Prelude: oall :: MonoFoldable mono => (Element mono -> Bool) -> mono -> Bool
- Termonad.Prelude: oand :: (Element mono ~ Bool, MonoFoldable mono) => mono -> Bool
- Termonad.Prelude: oany :: MonoFoldable mono => (Element mono -> Bool) -> mono -> Bool
- Termonad.Prelude: ocompareLength :: (MonoFoldable mono, Integral i) => mono -> i -> Ordering
- Termonad.Prelude: oconcat :: (MonoFoldable mono, Monoid (Element mono)) => mono -> Element mono
- Termonad.Prelude: oconcatMap :: (MonoFoldable mono, Monoid m) => (Element mono -> m) -> mono -> m
- Termonad.Prelude: oelem :: MonoFoldable mono => Element mono -> mono -> Bool
- Termonad.Prelude: oextend :: MonoComonad mono => (mono -> Element mono) -> mono -> mono
- Termonad.Prelude: oextract :: MonoComonad mono => mono -> Element mono
- Termonad.Prelude: ofold :: (MonoFoldable mono, Monoid (Element mono)) => mono -> Element mono
- Termonad.Prelude: ofold1 :: (MonoFoldable mono, Semigroup (Element mono)) => NonNull mono -> Element mono
- Termonad.Prelude: ofoldM :: (MonoFoldable mono, Monad m) => (a -> Element mono -> m a) -> a -> mono -> m a
- Termonad.Prelude: ofoldMUnwrap :: (Monad m, MonoFoldable mono) => (x -> Element mono -> m x) -> m x -> (x -> m b) -> mono -> m b
- Termonad.Prelude: ofoldMap :: (MonoFoldable mono, Monoid m) => (Element mono -> m) -> mono -> m
- Termonad.Prelude: ofoldMap1 :: (MonoFoldable mono, Semigroup m) => (Element mono -> m) -> NonNull mono -> m
- Termonad.Prelude: ofoldMap1Ex :: (MonoFoldable mono, Semigroup m) => (Element mono -> m) -> mono -> m
- Termonad.Prelude: ofoldl' :: MonoFoldable mono => (a -> Element mono -> a) -> a -> mono -> a
- Termonad.Prelude: ofoldl1' :: MonoFoldable mono => (Element mono -> Element mono -> Element mono) -> NonNull mono -> Element mono
- Termonad.Prelude: ofoldl1Ex' :: MonoFoldable mono => (Element mono -> Element mono -> Element mono) -> mono -> Element mono
- Termonad.Prelude: ofoldlM :: (MonoFoldable mono, Monad m) => (a -> Element mono -> m a) -> a -> mono -> m a
- Termonad.Prelude: ofoldlUnwrap :: MonoFoldable mono => (x -> Element mono -> x) -> x -> (x -> b) -> mono -> b
- Termonad.Prelude: ofoldr :: MonoFoldable mono => (Element mono -> b -> b) -> b -> mono -> b
- Termonad.Prelude: ofoldr1 :: MonoFoldable mono => (Element mono -> Element mono -> Element mono) -> NonNull mono -> Element mono
- Termonad.Prelude: ofoldr1Ex :: MonoFoldable mono => (Element mono -> Element mono -> Element mono) -> mono -> Element mono
- Termonad.Prelude: ofor :: (MonoTraversable mono, Applicative f) => mono -> (Element mono -> f (Element mono)) -> f mono
- Termonad.Prelude: oforM :: (MonoTraversable mono, Applicative f) => mono -> (Element mono -> f (Element mono)) -> f mono
- Termonad.Prelude: oforM_ :: (MonoFoldable mono, Applicative m) => mono -> (Element mono -> m ()) -> m ()
- Termonad.Prelude: ofor_ :: (MonoFoldable mono, Applicative f) => mono -> (Element mono -> f b) -> f ()
- Termonad.Prelude: ointercalate :: (MonoFoldable mono, Monoid (Element mono)) => Element mono -> mono -> Element mono
- Termonad.Prelude: olength :: MonoFoldable mono => mono -> Int
- Termonad.Prelude: olength64 :: MonoFoldable mono => mono -> Int64
- Termonad.Prelude: omap :: MonoFunctor mono => (Element mono -> Element mono) -> mono -> mono
- Termonad.Prelude: omapKeysWith :: IsMap map => (MapValue map -> MapValue map -> MapValue map) -> (ContainerKey map -> ContainerKey map) -> map -> map
- Termonad.Prelude: omapM :: (MonoTraversable mono, Applicative m) => (Element mono -> m (Element mono)) -> mono -> m mono
- Termonad.Prelude: omapM_ :: (MonoFoldable mono, Applicative m) => (Element mono -> m ()) -> mono -> m ()
- Termonad.Prelude: onException :: MonadUnliftIO m => m a -> m b -> m a
- Termonad.Prelude: onotElem :: MonoFoldable mono => Element mono -> mono -> Bool
- Termonad.Prelude: onull :: MonoFoldable mono => mono -> Bool
- Termonad.Prelude: oor :: (Element mono ~ Bool, MonoFoldable mono) => mono -> Bool
- Termonad.Prelude: openFile :: MonadIO m => FilePath -> IOMode -> m Handle
- Termonad.Prelude: opoint :: MonoPointed mono => Element mono -> mono
- Termonad.Prelude: oproduct :: (MonoFoldable mono, Num (Element mono)) => mono -> Element mono
- Termonad.Prelude: optional :: Alternative f => f a -> f (Maybe a)
- Termonad.Prelude: orElse :: STM a -> STM a -> STM a
- Termonad.Prelude: orElseSTM :: STM a -> STM a -> STM a
- Termonad.Prelude: ordNub :: Ord a => [a] -> [a]
- Termonad.Prelude: ordNubBy :: Ord b => (a -> b) -> (a -> a -> Bool) -> [a] -> [a]
- Termonad.Prelude: osequence_ :: (Applicative m, MonoFoldable mono, Element mono ~ m ()) => mono -> m ()
- Termonad.Prelude: osum :: (MonoFoldable mono, Num (Element mono)) => mono -> Element mono
- Termonad.Prelude: otoList :: MonoFoldable mono => mono -> [Element mono]
- Termonad.Prelude: otraverse :: (MonoTraversable mono, Applicative f) => (Element mono -> f (Element mono)) -> mono -> f mono
- Termonad.Prelude: otraverse_ :: (MonoFoldable mono, Applicative f) => (Element mono -> f b) -> mono -> f ()
- Termonad.Prelude: ounzip :: MonoZip mono => [(Element mono, Element mono)] -> (mono, mono)
- Termonad.Prelude: ozip :: MonoZip mono => mono -> mono -> [(Element mono, Element mono)]
- Termonad.Prelude: ozipWith :: MonoZip mono => (Element mono -> Element mono -> Element mono) -> mono -> mono -> mono
- Termonad.Prelude: pack :: IsSequence seq => [Element seq] -> seq
- Termonad.Prelude: parseTime :: ParseTime t => TimeLocale -> String -> String -> Maybe t
- Termonad.Prelude: parseTimeM :: (MonadFail m, ParseTime t) => Bool -> TimeLocale -> String -> String -> m t
- Termonad.Prelude: partition :: IsSequence seq => (Element seq -> Bool) -> seq -> (seq, seq)
- Termonad.Prelude: partitionEithers :: [Either a b] -> ([a], [b])
- Termonad.Prelude: peekTBChan :: TBChan a -> STM a
- Termonad.Prelude: peekTBMChan :: TBMChan a -> STM (Maybe a)
- Termonad.Prelude: peekTBMQueue :: TBMQueue a -> STM (Maybe a)
- Termonad.Prelude: peekTBQueue :: TBQueue a -> STM a
- Termonad.Prelude: peekTChan :: TChan a -> STM a
- Termonad.Prelude: peekTMChan :: TMChan a -> STM (Maybe a)
- Termonad.Prelude: peekTMQueue :: TMQueue a -> STM (Maybe a)
- Termonad.Prelude: peekTQueue :: TQueue a -> STM a
- Termonad.Prelude: permissionErrorType :: IOErrorType
- Termonad.Prelude: permutations :: IsSequence seq => seq -> [seq]
- Termonad.Prelude: point :: MonoPointed mono => Element mono -> mono
- Termonad.Prelude: poll :: MonadIO m => Async a -> m (Maybe (Either SomeException a))
- Termonad.Prelude: pollAsync :: MonadIO m => Async a -> m (Maybe (Either SomeException a))
- Termonad.Prelude: pollSTM :: Async a -> STM (Maybe (Either SomeException a))
- Termonad.Prelude: pooledForConcurrently :: (MonadUnliftIO m, Traversable t) => t a -> (a -> m b) -> m (t b)
- Termonad.Prelude: pooledForConcurrentlyN :: (MonadUnliftIO m, Traversable t) => Int -> t a -> (a -> m b) -> m (t b)
- Termonad.Prelude: pooledForConcurrentlyN_ :: (MonadUnliftIO m, Foldable t) => Int -> t a -> (a -> m b) -> m ()
- Termonad.Prelude: pooledForConcurrently_ :: (MonadUnliftIO m, Foldable f) => f a -> (a -> m b) -> m ()
- Termonad.Prelude: pooledMapConcurrently :: (MonadUnliftIO m, Traversable t) => (a -> m b) -> t a -> m (t b)
- Termonad.Prelude: pooledMapConcurrentlyN :: (MonadUnliftIO m, Traversable t) => Int -> (a -> m b) -> t a -> m (t b)
- Termonad.Prelude: pooledMapConcurrentlyN_ :: (MonadUnliftIO m, Foldable f) => Int -> (a -> m b) -> f a -> m ()
- Termonad.Prelude: pooledMapConcurrently_ :: (MonadUnliftIO m, Foldable f) => (a -> m b) -> f a -> m ()
- Termonad.Prelude: pooledReplicateConcurrently :: MonadUnliftIO m => Int -> m a -> m [a]
- Termonad.Prelude: pooledReplicateConcurrentlyN :: MonadUnliftIO m => Int -> Int -> m a -> m [a]
- Termonad.Prelude: pooledReplicateConcurrentlyN_ :: MonadUnliftIO m => Int -> Int -> m a -> m ()
- Termonad.Prelude: pooledReplicateConcurrently_ :: MonadUnliftIO m => Int -> m a -> m ()
- Termonad.Prelude: popBack :: (MutablePopBack c, PrimMonad m, PrimState m ~ MCState c) => c -> m (Maybe (CollElement c))
- Termonad.Prelude: popFront :: (MutablePopFront c, PrimMonad m, PrimState m ~ MCState c) => c -> m (Maybe (CollElement c))
- Termonad.Prelude: primToIO :: (PrimBase m, PrimState m ~ RealWorld) => m a -> IO a
- Termonad.Prelude: primToPrim :: (PrimBase m1, PrimMonad m2, PrimState m1 ~ PrimState m2) => m1 a -> m2 a
- Termonad.Prelude: primToST :: PrimBase m => m a -> ST (PrimState m) a
- Termonad.Prelude: pureTry :: a -> Either SomeException a
- Termonad.Prelude: pureTryDeep :: NFData a => a -> Either SomeException a
- Termonad.Prelude: pushBack :: (MutablePushBack c, PrimMonad m, PrimState m ~ MCState c) => c -> CollElement c -> m ()
- Termonad.Prelude: pushFront :: (MutablePushFront c, PrimMonad m, PrimState m ~ MCState c) => c -> CollElement c -> m ()
- Termonad.Prelude: putMVar :: MonadIO m => MVar a -> a -> m ()
- Termonad.Prelude: putTMVar :: TMVar a -> a -> STM ()
- Termonad.Prelude: race :: MonadUnliftIO m => m a -> m b -> m (Either a b)
- Termonad.Prelude: race_ :: MonadUnliftIO m => m a -> m b -> m ()
- Termonad.Prelude: readChan :: MonadIO m => Chan a -> m a
- Termonad.Prelude: readFileUtf8 :: MonadIO m => FilePath -> m Text
- Termonad.Prelude: readIORef :: MonadIO m => IORef a -> m a
- Termonad.Prelude: readMay :: (Element c ~ Char, MonoFoldable c, Read a) => c -> Maybe a
- Termonad.Prelude: readMutVar :: PrimMonad m => MutVar (PrimState m) a -> m a
- Termonad.Prelude: readRef :: (MutableRef c, PrimMonad m, PrimState m ~ MCState c) => c -> m (RefElement c)
- Termonad.Prelude: readTBChan :: TBChan a -> STM a
- Termonad.Prelude: readTBMChan :: TBMChan a -> STM (Maybe a)
- Termonad.Prelude: readTBMQueue :: TBMQueue a -> STM (Maybe a)
- Termonad.Prelude: readTBQueue :: TBQueue a -> STM a
- Termonad.Prelude: readTChan :: TChan a -> STM a
- Termonad.Prelude: readTMChan :: TMChan a -> STM (Maybe a)
- Termonad.Prelude: readTMQueue :: TMQueue a -> STM (Maybe a)
- Termonad.Prelude: readTMVar :: TMVar a -> STM a
- Termonad.Prelude: readTQueue :: TQueue a -> STM a
- Termonad.Prelude: readTVar :: TVar a -> STM a
- Termonad.Prelude: readTVarIO :: MonadIO m => TVar a -> m a
- Termonad.Prelude: registerDelay :: MonadIO m => Int -> m (TVar Bool)
- Termonad.Prelude: repack :: (MonoFoldable a, IsSequence b, Element a ~ Element b) => a -> b
- Termonad.Prelude: replaceElem :: (MonoFunctor mono, Eq (Element mono)) => Element mono -> Element mono -> mono -> mono
- Termonad.Prelude: replaceElemLazyText :: Char -> Char -> Text -> Text
- Termonad.Prelude: replaceElemStrictText :: Char -> Char -> Text -> Text
- Termonad.Prelude: replaceSeq :: (IsSequence seq, Eq (Element seq)) => seq -> seq -> seq -> seq
- Termonad.Prelude: replaceSeqLazyText :: Text -> Text -> Text -> Text
- Termonad.Prelude: replaceSeqStrictText :: Text -> Text -> Text -> Text
- Termonad.Prelude: replicateConcurrently :: MonadUnliftIO f => Int -> f a -> f [a]
- Termonad.Prelude: replicateConcurrently_ :: (Applicative m, MonadUnliftIO m) => Int -> m a -> m ()
- Termonad.Prelude: replicateM :: (IsSequence seq, Monad m) => Index seq -> m (Element seq) -> m seq
- Termonad.Prelude: replicateM_ :: Applicative m => Int -> m a -> m ()
- Termonad.Prelude: resourceVanishedErrorType :: IOErrorType
- Termonad.Prelude: retrySTM :: STM a
- Termonad.Prelude: rights :: [Either a b] -> [b]
- Termonad.Prelude: rnf :: NFData a => a -> ()
- Termonad.Prelude: runConc :: MonadUnliftIO m => Conc m a -> m a
- Termonad.Prelude: runMemoized :: MonadIO m => Memoized a -> m a
- Termonad.Prelude: say :: MonadIO m => Text -> m ()
- Termonad.Prelude: sayErr :: MonadIO m => Text -> m ()
- Termonad.Prelude: sayErrShow :: (MonadIO m, Show a) => a -> m ()
- Termonad.Prelude: sayErrString :: MonadIO m => String -> m ()
- Termonad.Prelude: sayShow :: (MonadIO m, Show a) => a -> m ()
- Termonad.Prelude: sayString :: MonadIO m => String -> m ()
- Termonad.Prelude: sconcat :: Semigroup a => NonEmpty a -> a
- Termonad.Prelude: second :: Bifunctor p => (b -> c) -> p a b -> p a c
- Termonad.Prelude: setFromList :: IsSet set => [Element set] -> set
- Termonad.Prelude: setToList :: IsSet set => set -> [Element set]
- Termonad.Prelude: signalQSem :: MonadIO m => QSem -> m ()
- Termonad.Prelude: signalQSemN :: MonadIO m => QSemN -> Int -> m ()
- Termonad.Prelude: singleton :: MonoPointed seq => Element seq -> seq
- Termonad.Prelude: singletonMap :: IsMap map => ContainerKey map -> MapValue map -> map
- Termonad.Prelude: singletonSet :: IsSet set => Element set -> set
- Termonad.Prelude: snoc :: SemiSequence seq => seq -> Element seq -> seq
- Termonad.Prelude: some :: Alternative f => f a -> f [a]
- Termonad.Prelude: sort :: (SemiSequence seq, Ord (Element seq)) => seq -> seq
- Termonad.Prelude: sortBy :: SemiSequence seq => (Element seq -> Element seq -> Ordering) -> seq -> seq
- Termonad.Prelude: sortOn :: (Ord o, SemiSequence seq) => (Element seq -> o) -> seq -> seq
- Termonad.Prelude: sortWith :: (Ord a, IsSequence c) => (Element c -> a) -> c -> c
- Termonad.Prelude: splitElem :: (IsSequence seq, Eq (Element seq)) => Element seq -> seq -> [seq]
- Termonad.Prelude: splitElemStrictBS :: Word8 -> ByteString -> [ByteString]
- Termonad.Prelude: splitFirst :: IsSequence seq => NonNull seq -> (Element seq, seq)
- Termonad.Prelude: splitSeq :: (IsSequence seq, Eq (Element seq)) => seq -> seq -> [seq]
- Termonad.Prelude: splitSeqLazyBS :: Word8 -> ByteString -> [ByteString]
- Termonad.Prelude: splitSeqLazyText :: Text -> Text -> [Text]
- Termonad.Prelude: splitSeqStrictText :: Text -> Text -> [Text]
- Termonad.Prelude: splitWhen :: IsSequence seq => (Element seq -> Bool) -> seq -> [seq]
- Termonad.Prelude: stateTVar :: TVar s -> (s -> (a, s)) -> STM a
- Termonad.Prelude: stdin :: Handle
- Termonad.Prelude: stdout :: Handle
- Termonad.Prelude: stimes :: (Semigroup a, Integral b) => b -> a -> a
- Termonad.Prelude: stringException :: HasCallStack => String -> StringException
- Termonad.Prelude: stripPrefix :: (IsSequence seq, Eq (Element seq)) => seq -> seq -> Maybe seq
- Termonad.Prelude: stripPrefixLazyBS :: ByteString -> ByteString -> Maybe ByteString
- Termonad.Prelude: stripPrefixStrictBS :: ByteString -> ByteString -> Maybe ByteString
- Termonad.Prelude: stripSuffix :: (IsSequence seq, Eq (Element seq)) => seq -> seq -> Maybe seq
- Termonad.Prelude: stripSuffixLazyBS :: ByteString -> ByteString -> Maybe ByteString
- Termonad.Prelude: stripSuffixStrictBS :: ByteString -> ByteString -> Maybe ByteString
- Termonad.Prelude: subsequences :: IsSequence seq => seq -> [seq]
- Termonad.Prelude: swap :: (a, b) -> (b, a)
- Termonad.Prelude: swapMVar :: MonadIO m => MVar a -> a -> m a
- Termonad.Prelude: swapTMVar :: TMVar a -> a -> STM a
- Termonad.Prelude: swapTVar :: TVar a -> a -> STM a
- Termonad.Prelude: tailDef :: IsSequence seq => seq -> seq
- Termonad.Prelude: tailEx :: IsSequence seq => seq -> seq
- Termonad.Prelude: tailMay :: IsSequence seq => seq -> Maybe seq
- Termonad.Prelude: takeMVar :: MonadIO m => MVar a -> m a
- Termonad.Prelude: takeTMVar :: TMVar a -> STM a
- Termonad.Prelude: terror :: HasCallStack => Text -> a
- Termonad.Prelude: textToBuilder :: ToBuilder Text builder => Text -> builder
- Termonad.Prelude: throwIO :: (MonadIO m, Exception e) => e -> m a
- Termonad.Prelude: throwString :: (MonadIO m, HasCallStack) => String -> m a
- Termonad.Prelude: throwTo :: (Exception e, MonadIO m) => ThreadId -> e -> m ()
- Termonad.Prelude: timeout :: MonadUnliftIO m => Int -> m a -> m (Maybe a)
- Termonad.Prelude: tlshow :: Show a => a -> LText
- Termonad.Prelude: toAsyncException :: Exception e => e -> SomeException
- Termonad.Prelude: toBuilder :: ToBuilder value builder => value -> builder
- Termonad.Prelude: toByteVector :: ByteString -> SVector Word8
- Termonad.Prelude: toCaseFold :: Textual t => t -> t
- Termonad.Prelude: toChunks :: LazySequence lazy strict => lazy -> [strict]
- Termonad.Prelude: toException :: Exception e => e -> SomeException
- Termonad.Prelude: toGregorian :: Day -> (Year, MonthOfYear, DayOfMonth)
- Termonad.Prelude: toIO :: MonadUnliftIO m => m a -> m (IO a)
- Termonad.Prelude: toList :: MonoFoldable mono => mono -> [Element mono]
- Termonad.Prelude: toLower :: Textual t => t -> t
- Termonad.Prelude: toMinList :: NonEmpty a -> NonNull [a]
- Termonad.Prelude: toNonEmpty :: MonoFoldable mono => NonNull mono -> NonEmpty (Element mono)
- Termonad.Prelude: toStrict :: LazySequence lazy strict => lazy -> strict
- Termonad.Prelude: toSyncException :: Exception e => e -> SomeException
- Termonad.Prelude: toUpper :: Textual t => t -> t
- Termonad.Prelude: trace :: String -> a -> a
- Termonad.Prelude: traceId :: String -> String
- Termonad.Prelude: traceM :: Monad m => String -> m ()
- Termonad.Prelude: traceShow :: Show a => a -> b -> b
- Termonad.Prelude: traceShowId :: Show a => a -> a
- Termonad.Prelude: traceShowM :: (Show a, Monad m) => a -> m ()
- Termonad.Prelude: traverse_ :: (MonoFoldable mono, Applicative f) => (Element mono -> f b) -> mono -> f ()
- Termonad.Prelude: tryAny :: MonadUnliftIO m => m a -> m (Either SomeException a)
- Termonad.Prelude: tryAnyDeep :: (MonadUnliftIO m, NFData a) => m a -> m (Either SomeException a)
- Termonad.Prelude: tryDeep :: (MonadUnliftIO m, Exception e, NFData a) => m a -> m (Either e a)
- Termonad.Prelude: tryIO :: MonadUnliftIO m => m a -> m (Either IOException a)
- Termonad.Prelude: tryIOError :: IO a -> IO (Either IOError a)
- Termonad.Prelude: tryJust :: (MonadUnliftIO m, Exception e) => (e -> Maybe b) -> m a -> m (Either b a)
- Termonad.Prelude: tryPeekTBChan :: TBChan a -> STM (Maybe a)
- Termonad.Prelude: tryPeekTBMChan :: TBMChan a -> STM (Maybe (Maybe a))
- Termonad.Prelude: tryPeekTBMQueue :: TBMQueue a -> STM (Maybe (Maybe a))
- Termonad.Prelude: tryPeekTBQueue :: TBQueue a -> STM (Maybe a)
- Termonad.Prelude: tryPeekTChan :: TChan a -> STM (Maybe a)
- Termonad.Prelude: tryPeekTMChan :: TMChan a -> STM (Maybe (Maybe a))
- Termonad.Prelude: tryPeekTMQueue :: TMQueue a -> STM (Maybe (Maybe a))
- Termonad.Prelude: tryPeekTQueue :: TQueue a -> STM (Maybe a)
- Termonad.Prelude: tryPutMVar :: MonadIO m => MVar a -> a -> m Bool
- Termonad.Prelude: tryPutTMVar :: TMVar a -> a -> STM Bool
- Termonad.Prelude: tryReadMVar :: MonadIO m => MVar a -> m (Maybe a)
- Termonad.Prelude: tryReadTBChan :: TBChan a -> STM (Maybe a)
- Termonad.Prelude: tryReadTBMChan :: TBMChan a -> STM (Maybe (Maybe a))
- Termonad.Prelude: tryReadTBMQueue :: TBMQueue a -> STM (Maybe (Maybe a))
- Termonad.Prelude: tryReadTBQueue :: TBQueue a -> STM (Maybe a)
- Termonad.Prelude: tryReadTChan :: TChan a -> STM (Maybe a)
- Termonad.Prelude: tryReadTMChan :: TMChan a -> STM (Maybe (Maybe a))
- Termonad.Prelude: tryReadTMQueue :: TMQueue a -> STM (Maybe (Maybe a))
- Termonad.Prelude: tryReadTMVar :: TMVar a -> STM (Maybe a)
- Termonad.Prelude: tryReadTQueue :: TQueue a -> STM (Maybe a)
- Termonad.Prelude: trySyncOrAsync :: (MonadUnliftIO m, Exception e) => m a -> m (Either e a)
- Termonad.Prelude: tryTakeMVar :: MonadIO m => MVar a -> m (Maybe a)
- Termonad.Prelude: tryTakeTMVar :: TMVar a -> STM (Maybe a)
- Termonad.Prelude: tryWriteTBChan :: TBChan a -> a -> STM Bool
- Termonad.Prelude: tryWriteTBMChan :: TBMChan a -> a -> STM (Maybe Bool)
- Termonad.Prelude: tryWriteTBMQueue :: TBMQueue a -> a -> STM (Maybe Bool)
- Termonad.Prelude: type BDeque = Deque MVector
- Termonad.Prelude: type BlazeBuilder = Builder
- Termonad.Prelude: type ByteStringBuilder = Builder
- Termonad.Prelude: type IOBRef = BRef PrimState IO
- Termonad.Prelude: type IOPRef = PRef PrimState IO
- Termonad.Prelude: type IOSRef = SRef PrimState IO
- Termonad.Prelude: type IOURef = URef PrimState IO
- Termonad.Prelude: type LByteString = ByteString
- Termonad.Prelude: type LText = Text
- Termonad.Prelude: type MutableDeque c = (MutableQueue c, MutablePushFront c, MutablePopBack c)
- Termonad.Prelude: type MutableQueue c = (MutablePopFront c, MutablePushBack c)
- Termonad.Prelude: type MutableStack c = (MutablePopFront c, MutablePushFront c)
- Termonad.Prelude: type Reader r = ReaderT r Identity
- Termonad.Prelude: type SDeque = Deque MVector
- Termonad.Prelude: type SVector = Vector
- Termonad.Prelude: type TextBuilder = Builder
- Termonad.Prelude: type UDeque = Deque MVector
- Termonad.Prelude: type UVector = Vector
- Termonad.Prelude: type family Index seq
- Termonad.Prelude: unGetTBChan :: TBChan a -> a -> STM ()
- Termonad.Prelude: unGetTBMChan :: TBMChan a -> a -> STM ()
- Termonad.Prelude: unGetTBMQueue :: TBMQueue a -> a -> STM ()
- Termonad.Prelude: unGetTBQueue :: TBQueue a -> a -> STM ()
- Termonad.Prelude: unGetTChan :: TChan a -> a -> STM ()
- Termonad.Prelude: unGetTMChan :: TMChan a -> a -> STM ()
- Termonad.Prelude: unGetTMQueue :: TMQueue a -> a -> STM ()
- Termonad.Prelude: unGetTQueue :: TQueue a -> a -> STM ()
- Termonad.Prelude: uncons :: IsSequence seq => seq -> Maybe (Element seq, seq)
- Termonad.Prelude: uninterruptibleCancel :: MonadIO m => Async a -> m ()
- Termonad.Prelude: uninterruptibleMask :: MonadUnliftIO m => ((forall a. () => m a -> m a) -> m b) -> m b
- Termonad.Prelude: uninterruptibleMask_ :: MonadUnliftIO m => m a -> m a
- Termonad.Prelude: union :: SetContainer set => set -> set -> set
- Termonad.Prelude: unionWith :: IsMap map => (MapValue map -> MapValue map -> MapValue map) -> map -> map -> map
- Termonad.Prelude: unionWithKey :: IsMap map => (ContainerKey map -> MapValue map -> MapValue map -> MapValue map) -> map -> map -> map
- Termonad.Prelude: unions :: (SetContainer set, MonoFoldable mono, Element mono ~ set) => mono -> set
- Termonad.Prelude: unionsWith :: IsMap map => (MapValue map -> MapValue map -> MapValue map) -> [map] -> map
- Termonad.Prelude: unlessM :: Monad m => m Bool -> m () -> m ()
- Termonad.Prelude: unpack :: MonoFoldable mono => mono -> [Element mono]
- Termonad.Prelude: unsafeDrop :: IsSequence seq => Index seq -> seq -> seq
- Termonad.Prelude: unsafeHead :: MonoFoldable mono => mono -> Element mono
- Termonad.Prelude: unsafeIndex :: IsSequence seq => seq -> Index seq -> Element seq
- Termonad.Prelude: unsafeInit :: IsSequence seq => seq -> seq
- Termonad.Prelude: unsafeLast :: MonoFoldable mono => mono -> Element mono
- Termonad.Prelude: unsafeSplitAt :: IsSequence seq => Index seq -> seq -> (seq, seq)
- Termonad.Prelude: unsafeTail :: IsSequence seq => seq -> seq
- Termonad.Prelude: unsafeTake :: IsSequence seq => Index seq -> seq -> seq
- Termonad.Prelude: unsnoc :: IsSequence seq => seq -> Maybe (seq, Element seq)
- Termonad.Prelude: unwrapMono :: WrappedMono mono a -> mono
- Termonad.Prelude: unzip4 :: Zip4 f => f (a, b, c, d) -> (f a, f b, f c, f d)
- Termonad.Prelude: unzip5 :: Zip5 f => f (a, b, c, d, e) -> (f a, f b, f c, f d, f e)
- Termonad.Prelude: unzip6 :: Zip6 f => f (a, b, c, d, e, g) -> (f a, f b, f c, f d, f e, f g)
- Termonad.Prelude: unzip7 :: Zip7 f => f (a, b, c, d, e, g, h) -> (f a, f b, f c, f d, f e, f g, f h)
- Termonad.Prelude: updateLookupWithKey :: IsMap map => (ContainerKey map -> MapValue map -> Maybe (MapValue map)) -> ContainerKey map -> map -> (Maybe (MapValue map), map)
- Termonad.Prelude: updateMap :: IsMap map => (MapValue map -> Maybe (MapValue map)) -> ContainerKey map -> map -> map
- Termonad.Prelude: updateWithKey :: IsMap map => (ContainerKey map -> MapValue map -> Maybe (MapValue map)) -> ContainerKey map -> map -> map
- Termonad.Prelude: userErrorType :: IOErrorType
- Termonad.Prelude: vectorSort :: (Vector v e, Ord e) => v e -> v e
- Termonad.Prelude: vectorSortBy :: Vector v e => (e -> e -> Ordering) -> v e -> v e
- Termonad.Prelude: wait :: MonadIO m => Async a -> m a
- Termonad.Prelude: waitAny :: MonadIO m => [Async a] -> m (Async a, a)
- Termonad.Prelude: waitAnyCancel :: MonadIO m => [Async a] -> m (Async a, a)
- Termonad.Prelude: waitAnyCatch :: MonadIO m => [Async a] -> m (Async a, Either SomeException a)
- Termonad.Prelude: waitAnyCatchCancel :: MonadIO m => [Async a] -> m (Async a, Either SomeException a)
- Termonad.Prelude: waitAnyCatchSTM :: [Async a] -> STM (Async a, Either SomeException a)
- Termonad.Prelude: waitAnySTM :: [Async a] -> STM (Async a, a)
- Termonad.Prelude: waitAsync :: MonadIO m => Async a -> m a
- Termonad.Prelude: waitBoth :: MonadIO m => Async a -> Async b -> m (a, b)
- Termonad.Prelude: waitBothSTM :: Async a -> Async b -> STM (a, b)
- Termonad.Prelude: waitCatch :: MonadIO m => Async a -> m (Either SomeException a)
- Termonad.Prelude: waitCatchAsync :: MonadIO m => Async a -> m (Either SomeException a)
- Termonad.Prelude: waitCatchSTM :: Async a -> STM (Either SomeException a)
- Termonad.Prelude: waitEither :: MonadIO m => Async a -> Async b -> m (Either a b)
- Termonad.Prelude: waitEitherCancel :: MonadIO m => Async a -> Async b -> m (Either a b)
- Termonad.Prelude: waitEitherCatch :: MonadIO m => Async a -> Async b -> m (Either (Either SomeException a) (Either SomeException b))
- Termonad.Prelude: waitEitherCatchCancel :: MonadIO m => Async a -> Async b -> m (Either (Either SomeException a) (Either SomeException b))
- Termonad.Prelude: waitEitherCatchSTM :: Async a -> Async b -> STM (Either (Either SomeException a) (Either SomeException b))
- Termonad.Prelude: waitEitherSTM :: Async a -> Async b -> STM (Either a b)
- Termonad.Prelude: waitEitherSTM_ :: Async a -> Async b -> STM ()
- Termonad.Prelude: waitEither_ :: MonadIO m => Async a -> Async b -> m ()
- Termonad.Prelude: waitQSem :: MonadIO m => QSem -> m ()
- Termonad.Prelude: waitQSemN :: MonadIO m => QSemN -> Int -> m ()
- Termonad.Prelude: waitSTM :: Async a -> STM a
- Termonad.Prelude: whenM :: Monad m => m Bool -> m () -> m ()
- Termonad.Prelude: withAsync :: MonadUnliftIO m => m a -> (Async a -> m b) -> m b
- Termonad.Prelude: withAsyncBound :: MonadUnliftIO m => m a -> (Async a -> m b) -> m b
- Termonad.Prelude: withAsyncOn :: MonadUnliftIO m => Int -> m a -> (Async a -> m b) -> m b
- Termonad.Prelude: withAsyncOnWithUnmask :: MonadUnliftIO m => Int -> ((forall c. () => m c -> m c) -> m a) -> (Async a -> m b) -> m b
- Termonad.Prelude: withAsyncWithUnmask :: MonadUnliftIO m => ((forall c. () => m c -> m c) -> m a) -> (Async a -> m b) -> m b
- Termonad.Prelude: withBinaryFile :: MonadUnliftIO m => FilePath -> IOMode -> (Handle -> m a) -> m a
- Termonad.Prelude: withException :: (MonadUnliftIO m, Exception e) => m a -> (e -> m b) -> m a
- Termonad.Prelude: withFile :: MonadUnliftIO m => FilePath -> IOMode -> (Handle -> m a) -> m a
- Termonad.Prelude: withMVarMasked :: MonadUnliftIO m => MVar a -> (a -> m b) -> m b
- Termonad.Prelude: withQSem :: MonadUnliftIO m => QSem -> m a -> m a
- Termonad.Prelude: withQSemN :: MonadUnliftIO m => QSemN -> Int -> m a -> m a
- Termonad.Prelude: withRunInIO :: MonadUnliftIO m => ((forall a. () => m a -> IO a) -> IO b) -> m b
- Termonad.Prelude: withSystemTempDirectory :: MonadUnliftIO m => String -> (FilePath -> m a) -> m a
- Termonad.Prelude: withSystemTempFile :: MonadUnliftIO m => String -> (FilePath -> Handle -> m a) -> m a
- Termonad.Prelude: withTempDirectory :: MonadUnliftIO m => FilePath -> String -> (FilePath -> m a) -> m a
- Termonad.Prelude: withTempFile :: MonadUnliftIO m => FilePath -> String -> (FilePath -> Handle -> m a) -> m a
- Termonad.Prelude: withUnliftIO :: MonadUnliftIO m => (UnliftIO m -> IO a) -> m a
- Termonad.Prelude: wrappedWithRunInIO :: MonadUnliftIO n => (n b -> m b) -> (forall a. () => m a -> n a) -> ((forall a. () => m a -> IO a) -> IO b) -> m b
- Termonad.Prelude: writeChan :: MonadIO m => Chan a -> a -> m ()
- Termonad.Prelude: writeFileUtf8 :: MonadIO m => FilePath -> Text -> m ()
- Termonad.Prelude: writeIORef :: MonadIO m => IORef a -> a -> m ()
- Termonad.Prelude: writeList2Chan :: MonadIO m => Chan a -> [a] -> m ()
- Termonad.Prelude: writeMutVar :: PrimMonad m => MutVar (PrimState m) a -> a -> m ()
- Termonad.Prelude: writeRef :: (MutableRef c, PrimMonad m, PrimState m ~ MCState c) => c -> RefElement c -> m ()
- Termonad.Prelude: writeTBChan :: TBChan a -> a -> STM ()
- Termonad.Prelude: writeTBMChan :: TBMChan a -> a -> STM ()
- Termonad.Prelude: writeTBMQueue :: TBMQueue a -> a -> STM ()
- Termonad.Prelude: writeTBQueue :: TBQueue a -> a -> STM ()
- Termonad.Prelude: writeTChan :: TChan a -> a -> STM ()
- Termonad.Prelude: writeTMChan :: TMChan a -> a -> STM ()
- Termonad.Prelude: writeTMQueue :: TMQueue a -> a -> STM ()
- Termonad.Prelude: writeTQueue :: TQueue a -> a -> STM ()
- Termonad.Prelude: writeTVar :: TVar a -> a -> STM ()
- Termonad.Prelude: yieldThread :: MonadIO m => m ()
- Termonad.Prelude: zip4 :: Zip4 f => f a -> f b -> f c -> f d -> f (a, b, c, d)
- Termonad.Prelude: zip5 :: Zip5 f => f a -> f b -> f c -> f d -> f e -> f (a, b, c, d, e)
- Termonad.Prelude: zip6 :: Zip6 f => f a -> f b -> f c -> f d -> f e -> f g -> f (a, b, c, d, e, g)
- Termonad.Prelude: zip7 :: Zip7 f => f a -> f b -> f c -> f d -> f e -> f g -> f h -> f (a, b, c, d, e, g, h)
- Termonad.Prelude: zipWith4 :: Zip4 f => (a -> b -> c -> d -> e) -> f a -> f b -> f c -> f d -> f e
- Termonad.Prelude: zipWith5 :: Zip5 f => (a -> b -> c -> d -> e -> g) -> f a -> f b -> f c -> f d -> f e -> f g
- Termonad.Prelude: zipWith6 :: Zip6 f => (a -> b -> c -> d -> e -> g -> h) -> f a -> f b -> f c -> f d -> f e -> f g -> f h
- Termonad.Prelude: zipWith7 :: Zip7 f => (a -> b -> c -> d -> e -> g -> h -> i) -> f a -> f b -> f c -> f d -> f e -> f g -> f h -> f i
- Termonad.Prelude: }
- Termonad.Types: [tmStateAppWin] :: TMState' -> !ApplicationWindow
- Termonad.Types: [tmStateNotebook] :: TMState' -> !TMNotebook
- Termonad.Types: newTMState :: TMConfig -> Application -> ApplicationWindow -> TMNotebook -> FontDescription -> IO TMState
- Termonad.Types: newTMStateSingleTerm :: TMConfig -> Application -> ApplicationWindow -> Notebook -> Label -> ScrolledWindow -> Terminal -> Int -> FontDescription -> IO TMState
+ Termonad: startWithCliArgs :: TMConfig -> IO ()
+ Termonad.App: setupAppCallbacks :: TMState -> TMConfig -> Application -> ApplicationWindow -> Notebook -> TMWindowId -> IO ()
+ Termonad.Cli: CliArgs :: CliConfigOptions -> ExtraCliArgs -> CliArgs
+ Termonad.Cli: CliConfigOptions :: !Option Text -> !Option FontSize -> !Option ShowScrollbar -> !Option Integer -> !Option Bool -> !Option Text -> !Option Bool -> !Option ShowTabBar -> !Option CursorBlinkMode -> !Option Bool -> !Option Bool -> !Option Bool -> CliConfigOptions
+ Termonad.Cli: ExtraCliArgs :: ExtraCliArgs
+ Termonad.Cli: [cliConfAllowBold] :: CliConfigOptions -> !Option Bool
+ Termonad.Cli: [cliConfBoldIsBright] :: CliConfigOptions -> !Option Bool
+ Termonad.Cli: [cliConfConfirmExit] :: CliConfigOptions -> !Option Bool
+ Termonad.Cli: [cliConfCursorBlinkMode] :: CliConfigOptions -> !Option CursorBlinkMode
+ Termonad.Cli: [cliConfEnableSixel] :: CliConfigOptions -> !Option Bool
+ Termonad.Cli: [cliConfFontFamily] :: CliConfigOptions -> !Option Text
+ Termonad.Cli: [cliConfFontSize] :: CliConfigOptions -> !Option FontSize
+ Termonad.Cli: [cliConfScrollbackLen] :: CliConfigOptions -> !Option Integer
+ Termonad.Cli: [cliConfShowMenu] :: CliConfigOptions -> !Option Bool
+ Termonad.Cli: [cliConfShowScrollbar] :: CliConfigOptions -> !Option ShowScrollbar
+ Termonad.Cli: [cliConfShowTabBar] :: CliConfigOptions -> !Option ShowTabBar
+ Termonad.Cli: [cliConfWordCharExceptions] :: CliConfigOptions -> !Option Text
+ Termonad.Cli: [cliConfigOptions] :: CliArgs -> CliConfigOptions
+ Termonad.Cli: [extraCliArgs] :: CliArgs -> ExtraCliArgs
+ Termonad.Cli: allowBoldParser :: Parser (Option Bool)
+ Termonad.Cli: applyCliArgs :: CliArgs -> ConfigOptions -> ConfigOptions
+ Termonad.Cli: boldIsBrightParser :: Parser (Option Bool)
+ Termonad.Cli: cliArgsParser :: Parser CliArgs
+ Termonad.Cli: cliArgsParserInfo :: ParserInfo CliArgs
+ Termonad.Cli: cliConfigOptionsParser :: Parser CliConfigOptions
+ Termonad.Cli: confirmExitParser :: Parser (Option Bool)
+ Termonad.Cli: cursorBlinkModeParser :: Parser (Option CursorBlinkMode)
+ Termonad.Cli: data CliArgs
+ Termonad.Cli: data CliConfigOptions
+ Termonad.Cli: data ExtraCliArgs
+ Termonad.Cli: defaultCliArgs :: CliArgs
+ Termonad.Cli: defaultCliConfigOptions :: CliConfigOptions
+ Termonad.Cli: defaultExtraCliArgs :: ExtraCliArgs
+ Termonad.Cli: enableSixelParser :: Parser (Option Bool)
+ Termonad.Cli: extraCliArgsParser :: Parser ExtraCliArgs
+ Termonad.Cli: fontFamilyParser :: Parser (Option Text)
+ Termonad.Cli: fontSizeParser :: Parser (Option FontSize)
+ Termonad.Cli: instance GHC.Classes.Eq Termonad.Cli.CliArgs
+ Termonad.Cli: instance GHC.Classes.Eq Termonad.Cli.CliConfigOptions
+ Termonad.Cli: instance GHC.Classes.Eq Termonad.Cli.ExtraCliArgs
+ Termonad.Cli: instance GHC.Show.Show Termonad.Cli.CliArgs
+ Termonad.Cli: instance GHC.Show.Show Termonad.Cli.CliConfigOptions
+ Termonad.Cli: instance GHC.Show.Show Termonad.Cli.ExtraCliArgs
+ Termonad.Cli: maybeTextReader :: (Text -> Maybe a) -> ReadM a
+ Termonad.Cli: option' :: ReadM a -> Mod OptionFields (Option a) -> Parser (Option a)
+ Termonad.Cli: optionFlag :: a -> a -> Char -> Char -> String -> String -> String -> Parser (Option a)
+ Termonad.Cli: parseCliArgs :: IO CliArgs
+ Termonad.Cli: scrollbackLenParser :: Parser (Option Integer)
+ Termonad.Cli: showMenuParser :: Parser (Option Bool)
+ Termonad.Cli: showScrollbarParser :: Parser (Option ShowScrollbar)
+ Termonad.Cli: showTabBarParser :: Parser (Option ShowTabBar)
+ Termonad.Cli: strOption' :: IsString s => Mod OptionFields (Option s) -> Parser (Option s)
+ Termonad.Cli: wordCharExceptionsParser :: Parser (Option Text)
+ Termonad.Gtk: imgToPixbuf :: ByteString -> IO Pixbuf
+ Termonad.IdMap: data IdMap a
+ Termonad.IdMap: data IdMapKey
+ Termonad.IdMap: deleteIdMap :: IdMapKey -> IdMap a -> IdMap a
+ Termonad.IdMap: emptyIdMap :: IdMap a
+ Termonad.IdMap: insertIdMap :: a -> IdMap a -> (IdMapKey, IdMap a)
+ Termonad.IdMap: keysIdMap :: IdMap a -> [IdMapKey]
+ Termonad.IdMap: lookupIdMap :: IdMapKey -> IdMap a -> Maybe a
+ Termonad.IdMap: singletonIdMap :: a -> (IdMapKey, IdMap a)
+ Termonad.IdMap.Internal: IdMap :: !IntMap a -> !Int -> IdMap a
+ Termonad.IdMap.Internal: IdMapKey :: Int -> IdMapKey
+ Termonad.IdMap.Internal: [idMap] :: IdMap a -> !IntMap a
+ Termonad.IdMap.Internal: [nextId] :: IdMap a -> !Int
+ Termonad.IdMap.Internal: [unIdMapKey] :: IdMapKey -> Int
+ Termonad.IdMap.Internal: data IdMap a
+ Termonad.IdMap.Internal: deleteIdMap :: IdMapKey -> IdMap a -> IdMap a
+ Termonad.IdMap.Internal: emptyIdMap :: IdMap a
+ Termonad.IdMap.Internal: initialId :: Int
+ Termonad.IdMap.Internal: insertIdMap :: a -> IdMap a -> (IdMapKey, IdMap a)
+ Termonad.IdMap.Internal: instance Control.Lens.At.Ixed (Termonad.IdMap.Internal.IdMap a)
+ Termonad.IdMap.Internal: instance Data.Foldable.Foldable Termonad.IdMap.Internal.IdMap
+ Termonad.IdMap.Internal: instance Data.Traversable.Traversable Termonad.IdMap.Internal.IdMap
+ Termonad.IdMap.Internal: instance GHC.Base.Functor Termonad.IdMap.Internal.IdMap
+ Termonad.IdMap.Internal: instance GHC.Classes.Eq Termonad.IdMap.Internal.IdMapKey
+ Termonad.IdMap.Internal: instance GHC.Classes.Eq a => GHC.Classes.Eq (Termonad.IdMap.Internal.IdMap a)
+ Termonad.IdMap.Internal: instance GHC.Show.Show Termonad.IdMap.Internal.IdMapKey
+ Termonad.IdMap.Internal: instance GHC.Show.Show a => GHC.Show.Show (Termonad.IdMap.Internal.IdMap a)
+ Termonad.IdMap.Internal: instance WithIndex.FoldableWithIndex GHC.Types.Int Termonad.IdMap.Internal.IdMap
+ Termonad.IdMap.Internal: keysIdMap :: IdMap a -> [IdMapKey]
+ Termonad.IdMap.Internal: lookupIdMap :: IdMapKey -> IdMap a -> Maybe a
+ Termonad.IdMap.Internal: newtype IdMapKey
+ Termonad.IdMap.Internal: singletonIdMap :: a -> (IdMapKey, IdMap a)
+ Termonad.IdMap.Internal: succId :: Int -> Int
+ Termonad.Lenses: lensTMStateWindows :: Lens' TMState' (IdMap TMWindow)
+ Termonad.Lenses: lensTMWindowAppWin :: Lens' TMWindow ApplicationWindow
+ Termonad.Lenses: lensTMWindowNotebook :: Lens' TMWindow TMNotebook
+ Termonad.Pcre: inline_c_ffi_6989586621679106705 :: IO CUInt
+ Termonad.Preferences: saveToPreferencesFile :: TMConfig -> IO ()
+ Termonad.Preferences: showPreferencesDialog :: TMState -> IO ()
+ Termonad.Preferences: tmConfigFromPreferencesFile :: IO TMConfig
+ Termonad.Preferences.File: getPreferencesFile :: IO FilePath
+ Termonad.Preferences.File: mergeObjVals :: Value -> Value -> Value
+ Termonad.Preferences.File: readFileWithDefaults :: FilePath -> IO (Either Text ConfigOptions)
+ Termonad.Preferences.File: saveToPreferencesFile :: TMConfig -> IO ()
+ Termonad.Preferences.File: tmConfigFromPreferencesFile :: IO TMConfig
+ Termonad.Preferences.File: writePreferencesFile :: FilePath -> ConfigOptions -> IO ()
+ Termonad.Prelude: (!!) :: HasCallStack => [a] -> Int -> a
+ Termonad.Prelude: appendFile :: FilePath -> String -> IO ()
+ Termonad.Prelude: class a ~# b => (a :: k) ~ (b :: k)
+ Termonad.Prelude: class Monad m => MonadFail (m :: Type -> Type)
+ Termonad.Prelude: cycle :: HasCallStack => [a] -> [a]
+ Termonad.Prelude: errorWithoutStackTrace :: forall (r :: RuntimeRep) (a :: TYPE r). [Char] -> a
+ Termonad.Prelude: fail :: MonadFail m => String -> m a
+ Termonad.Prelude: foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b
+ Termonad.Prelude: foldl1 :: Foldable t => (a -> a -> a) -> t a -> a
+ Termonad.Prelude: foldr1 :: Foldable t => (a -> a -> a) -> t a -> a
+ Termonad.Prelude: gcd :: Integral a => a -> a -> a
+ Termonad.Prelude: iterate :: (a -> a) -> a -> [a]
+ Termonad.Prelude: lcm :: Integral a => a -> a -> a
+ Termonad.Prelude: lex :: ReadS String
+ Termonad.Prelude: read :: Read a => String -> a
+ Termonad.Prelude: readIO :: Read a => String -> IO a
+ Termonad.Prelude: readList :: Read a => ReadS [a]
+ Termonad.Prelude: readLn :: Read a => IO a
+ Termonad.Prelude: readParen :: Bool -> ReadS a -> ReadS a
+ Termonad.Prelude: reads :: Read a => ReadS a
+ Termonad.Prelude: readsPrec :: Read a => Int -> ReadS a
+ Termonad.Prelude: scanl :: (b -> a -> b) -> b -> [a] -> [b]
+ Termonad.Prelude: scanl1 :: (a -> a -> a) -> [a] -> [a]
+ Termonad.Prelude: scanr :: (a -> b -> b) -> b -> [a] -> [b]
+ Termonad.Prelude: scanr1 :: (a -> a -> a) -> [a] -> [a]
+ Termonad.Prelude: showChar :: Char -> ShowS
+ Termonad.Prelude: showParen :: Bool -> ShowS -> ShowS
+ Termonad.Prelude: showString :: String -> ShowS
+ Termonad.Prelude: shows :: Show a => a -> ShowS
+ Termonad.Prelude: type ReadS a = String -> [(a, String)]
+ Termonad.Prelude: type ShowS = String -> String
+ Termonad.Startup: defaultMain :: TMConfig -> IO ()
+ Termonad.Startup: startWithCliArgs :: TMConfig -> IO ()
+ Termonad.Types: TMWinInvariantErr :: Int -> TMWinInvariantErr -> TMStateInvariantErr
+ Termonad.Types: TMWindow :: !ApplicationWindow -> !TMNotebook -> TMWindow
+ Termonad.Types: [tmStateWindows] :: TMState' -> !IdMap TMWindow
+ Termonad.Types: [tmWindowAppWin] :: TMWindow -> !ApplicationWindow
+ Termonad.Types: [tmWindowNotebook] :: TMWindow -> !TMNotebook
+ Termonad.Types: createFontDesc :: FontSize -> Text -> IO FontDescription
+ Termonad.Types: createFontDescFromConfig :: TMConfig -> IO FontDescription
+ Termonad.Types: createTMWindow :: ApplicationWindow -> TMNotebook -> TMWindow
+ Termonad.Types: cursorBlinkModeFromString :: Text -> Maybe CursorBlinkMode
+ Termonad.Types: cursorBlinkModeToString :: CursorBlinkMode -> Text
+ Termonad.Types: data TMWinInvariantErr
+ Termonad.Types: data TMWindow
+ Termonad.Types: fontConfigFromFontDescription :: FontDescription -> IO (Maybe FontConfig)
+ Termonad.Types: fontSizeFromFontDescription :: FontDescription -> IO FontSize
+ Termonad.Types: getNotebookFromTMState :: TMState -> TMWindowId -> IO Notebook
+ Termonad.Types: getNotebookFromTMState' :: TMState' -> TMWindowId -> IO Notebook
+ Termonad.Types: getTMNotebookFromTMState :: TMState -> TMWindowId -> IO TMNotebook
+ Termonad.Types: getTMNotebookFromTMState' :: TMState' -> TMWindowId -> IO TMNotebook
+ Termonad.Types: getTMWindowFromTMState :: TMState -> TMWindowId -> IO TMWindow
+ Termonad.Types: getTMWindowFromTMState' :: TMState' -> TMWindowId -> IO TMWindow
+ Termonad.Types: getTMWindowFromWins :: IdMap TMWindow -> TMWindowId -> IO TMWindow
+ Termonad.Types: instance GHC.Show.Show Termonad.Types.TMWinInvariantErr
+ Termonad.Types: instance GHC.Show.Show Termonad.Types.TMWindow
+ Termonad.Types: invariantTMWindow :: TMWindow -> IO [TMWinInvariantErr]
+ Termonad.Types: setFontDescSize :: FontDescription -> FontSize -> IO ()
+ Termonad.Types: showScrollbarFromString :: Text -> Maybe ShowScrollbar
+ Termonad.Types: showScrollbarToString :: ShowScrollbar -> Text
+ Termonad.Types: showTabBarFromString :: Text -> Maybe ShowTabBar
+ Termonad.Types: showTabBarToString :: ShowTabBar -> Text
+ Termonad.Types: type TMWindowId = IdMapKey
+ Termonad.Window: doFind :: TMState -> TMWindowId -> IO ()
+ Termonad.Window: findAbove :: TMState -> TMWindowId -> IO ()
+ Termonad.Window: findBelow :: TMState -> TMWindowId -> IO ()
+ Termonad.Window: modifyFontSizeForAllTerms :: (FontSize -> FontSize) -> TMState -> TMWindowId -> IO ()
+ Termonad.Window: notebookPageReorderedCallback :: TMState -> TMWindowId -> Widget -> Word32 -> IO ()
+ Termonad.Window: setupWindowCallbacks :: TMState -> Application -> ApplicationWindow -> Notebook -> TMWindowId -> IO ()
+ Termonad.Window: showAboutDialog :: ApplicationWindow -> IO ()
+ Termonad.Window: showFindDialog :: ApplicationWindow -> IO (Maybe Text)
+ Termonad.Window: updateFLTabPos :: TMState -> TMWindowId -> Int -> Int -> IO ()
- Termonad.Config: data CursorBlinkMode
+ Termonad.Config: data () => CursorBlinkMode
- Termonad.Config.Colour: data AlphaColour a
+ Termonad.Config.Colour: data () => AlphaColour a
- Termonad.Config.Colour: lensBackgroundColour :: forall c_a1m0Y. Lens' (ColourConfig c_a1m0Y) (Option c_a1m0Y)
+ Termonad.Config.Colour: lensBackgroundColour :: forall c_a1x60. Lens' (ColourConfig c_a1x60) (Option c_a1x60)
- Termonad.Config.Colour: lensCursorBgColour :: forall c_a1m0Y. Lens' (ColourConfig c_a1m0Y) (Option c_a1m0Y)
+ Termonad.Config.Colour: lensCursorBgColour :: forall c_a1x60. Lens' (ColourConfig c_a1x60) (Option c_a1x60)
- Termonad.Config.Colour: lensCursorFgColour :: forall c_a1m0Y. Lens' (ColourConfig c_a1m0Y) (Option c_a1m0Y)
+ Termonad.Config.Colour: lensCursorFgColour :: forall c_a1x60. Lens' (ColourConfig c_a1x60) (Option c_a1x60)
- Termonad.Config.Colour: lensForegroundColour :: forall c_a1m0Y. Lens' (ColourConfig c_a1m0Y) (Option c_a1m0Y)
+ Termonad.Config.Colour: lensForegroundColour :: forall c_a1x60. Lens' (ColourConfig c_a1x60) (Option c_a1x60)
- Termonad.Config.Colour: lensHighlightBgColour :: forall c_a1m0Y. Lens' (ColourConfig c_a1m0Y) (Option c_a1m0Y)
+ Termonad.Config.Colour: lensHighlightBgColour :: forall c_a1x60. Lens' (ColourConfig c_a1x60) (Option c_a1x60)
- Termonad.Config.Colour: lensHighlightFgColour :: forall c_a1m0Y. Lens' (ColourConfig c_a1m0Y) (Option c_a1m0Y)
+ Termonad.Config.Colour: lensHighlightFgColour :: forall c_a1x60. Lens' (ColourConfig c_a1x60) (Option c_a1x60)
- Termonad.Config.Colour: lensPalette :: forall c_a1m0Y. Lens' (ColourConfig c_a1m0Y) (Palette c_a1m0Y)
+ Termonad.Config.Colour: lensPalette :: forall c_a1x60. Lens' (ColourConfig c_a1x60) (Palette c_a1x60)
- Termonad.Keys: Key :: Word32 -> Set ModifierType -> Key
+ Termonad.Keys: Key :: !Word32 -> !Set ModifierType -> Key
- Termonad.Keys: [keyMods] :: Key -> Set ModifierType
+ Termonad.Keys: [keyMods] :: Key -> !Set ModifierType
- Termonad.Keys: [keyVal] :: Key -> Word32
+ Termonad.Keys: [keyVal] :: Key -> !Word32
- Termonad.Keys: handleKeyPress :: TMState -> EventKey -> IO Bool
+ Termonad.Keys: handleKeyPress :: TMState -> TMWindowId -> EventKey -> IO Bool
- Termonad.Keys: keyMap :: Map Key (TMState -> IO Bool)
+ Termonad.Keys: keyMap :: Map Key (TMState -> TMWindowId -> IO Bool)
- Termonad.Keys: stopProp :: (TMState -> IO a) -> TMState -> IO Bool
+ Termonad.Keys: stopProp :: (TMState -> TMWindowId -> IO a) -> TMState -> TMWindowId -> IO Bool
- Termonad.Prelude: (++) :: Monoid m => m -> m -> m
+ Termonad.Prelude: (++) :: [a] -> [a] -> [a]
- Termonad.Prelude: (.) :: forall (b :: k) (c :: k) (a :: k). Category cat => cat b c -> cat a b -> cat a c
+ Termonad.Prelude: (.) :: (b -> c) -> (a -> b) -> a -> c
- Termonad.Prelude: all :: MonoFoldable mono => (Element mono -> Bool) -> mono -> Bool
+ Termonad.Prelude: all :: Foldable t => (a -> Bool) -> t a -> Bool
- Termonad.Prelude: and :: (MonoFoldable mono, Element mono ~ Bool) => mono -> Bool
+ Termonad.Prelude: and :: Foldable t => t Bool -> Bool
- Termonad.Prelude: any :: MonoFoldable mono => (Element mono -> Bool) -> mono -> Bool
+ Termonad.Prelude: any :: Foldable t => (a -> Bool) -> t a -> Bool
- Termonad.Prelude: break :: IsSequence seq => (Element seq -> Bool) -> seq -> (seq, seq)
+ Termonad.Prelude: break :: (a -> Bool) -> [a] -> ([a], [a])
- Termonad.Prelude: catMaybes :: (IsSequence (f (Maybe t)), Functor f, Element (f (Maybe t)) ~ Maybe t) => f (Maybe t) -> f t
+ Termonad.Prelude: catMaybes :: [Maybe a] -> [a]
- Termonad.Prelude: class Bounded a
+ Termonad.Prelude: class () => Bounded a
- Termonad.Prelude: class Enum a
+ Termonad.Prelude: class () => Enum a
- Termonad.Prelude: class Eq a
+ Termonad.Prelude: class () => Eq a
- Termonad.Prelude: class Foldable (t :: TYPE LiftedRep -> Type)
+ Termonad.Prelude: class () => Foldable (t :: Type -> Type)
- Termonad.Prelude: class Functor (f :: Type -> Type)
+ Termonad.Prelude: class () => Functor (f :: Type -> Type)
- Termonad.Prelude: class Generic a
+ Termonad.Prelude: class () => Generic a
- Termonad.Prelude: class IsString a
+ Termonad.Prelude: class () => IsString a
- Termonad.Prelude: class Num a
+ Termonad.Prelude: class () => Num a
- Termonad.Prelude: class Read a
+ Termonad.Prelude: class () => Read a
- Termonad.Prelude: class Semigroup a
+ Termonad.Prelude: class () => Semigroup a
- Termonad.Prelude: class Show a
+ Termonad.Prelude: class () => Show a
- Termonad.Prelude: concat :: (MonoFoldable mono, Monoid (Element mono)) => mono -> Element mono
+ Termonad.Prelude: concat :: Foldable t => t [a] -> [a]
- Termonad.Prelude: concatMap :: (MonoFoldable mono, Monoid m) => (Element mono -> m) -> mono -> m
+ Termonad.Prelude: concatMap :: Foldable t => (a -> [b]) -> t a -> [b]
- Termonad.Prelude: data Bool
+ Termonad.Prelude: data () => Bool
- Termonad.Prelude: data ByteString
+ Termonad.Prelude: data () => ByteString
- Termonad.Prelude: data Char
+ Termonad.Prelude: data () => Char
- Termonad.Prelude: data Double
+ Termonad.Prelude: data () => Double
- Termonad.Prelude: data Either a b
+ Termonad.Prelude: data () => Either a b
- Termonad.Prelude: data Float
+ Termonad.Prelude: data () => Float
- Termonad.Prelude: data IO a
+ Termonad.Prelude: data () => IO a
- Termonad.Prelude: data IOException
+ Termonad.Prelude: data () => IOException
- Termonad.Prelude: data Int
+ Termonad.Prelude: data () => Int
- Termonad.Prelude: data Int32
+ Termonad.Prelude: data () => Int32
- Termonad.Prelude: data Integer
+ Termonad.Prelude: data () => Integer
- Termonad.Prelude: data KProxy t
+ Termonad.Prelude: data () => KProxy t
- Termonad.Prelude: data MVar a
+ Termonad.Prelude: data () => MVar a
- Termonad.Prelude: data Maybe a
+ Termonad.Prelude: data () => Maybe a
- Termonad.Prelude: data Ordering
+ Termonad.Prelude: data () => Ordering
- Termonad.Prelude: data Proxy (t :: k)
+ Termonad.Prelude: data () => Proxy (t :: k)
- Termonad.Prelude: data Text
+ Termonad.Prelude: data () => Text
- Termonad.Prelude: data Word
+ Termonad.Prelude: data () => Word
- Termonad.Prelude: data Word32
+ Termonad.Prelude: data () => Word32
- Termonad.Prelude: data Word8
+ Termonad.Prelude: data () => Word8
- Termonad.Prelude: drop :: IsSequence seq => Index seq -> seq -> seq
+ Termonad.Prelude: drop :: Int -> [a] -> [a]
- Termonad.Prelude: dropWhile :: IsSequence seq => (Element seq -> Bool) -> seq -> seq
+ Termonad.Prelude: dropWhile :: (a -> Bool) -> [a] -> [a]
- Termonad.Prelude: elem :: (MonoFoldable mono, Eq (Element mono)) => Element mono -> mono -> Bool
+ Termonad.Prelude: elem :: (Foldable t, Eq a) => a -> t a -> Bool
- Termonad.Prelude: filter :: IsSequence seq => (Element seq -> Bool) -> seq -> seq
+ Termonad.Prelude: filter :: (a -> Bool) -> [a] -> [a]
- Termonad.Prelude: foldMap :: (MonoFoldable mono, Monoid m) => (Element mono -> m) -> mono -> m
+ Termonad.Prelude: foldMap :: (Foldable t, Monoid m) => (a -> m) -> t a -> m
- Termonad.Prelude: foldr :: MonoFoldable mono => (Element mono -> b -> b) -> b -> mono -> b
+ Termonad.Prelude: foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
- Termonad.Prelude: getChar :: MonadIO m => m Char
+ Termonad.Prelude: getChar :: IO Char
- Termonad.Prelude: getContents :: MonadIO m => m LText
+ Termonad.Prelude: getContents :: IO String
- Termonad.Prelude: getLine :: MonadIO m => m Text
+ Termonad.Prelude: getLine :: IO String
- Termonad.Prelude: head :: MonoFoldable mono => NonNull mono -> Element mono
+ Termonad.Prelude: head :: HasCallStack => [a] -> a
- Termonad.Prelude: id :: forall (a :: k). Category cat => cat a a
+ Termonad.Prelude: id :: a -> a
- Termonad.Prelude: infix 4 <
+ Termonad.Prelude: infix 4 `notElem`
- Termonad.Prelude: infixl 0 `hashWithSalt`
+ Termonad.Prelude: infixl 0 `on`
- Termonad.Prelude: infixl 1 <&>
+ Termonad.Prelude: infixl 1 &
- Termonad.Prelude: infixl 4 <**>
+ Termonad.Prelude: infixl 4 $>
- Termonad.Prelude: infixl 6 -
+ Termonad.Prelude: infixl 6 +
- Termonad.Prelude: infixl 9 \\
+ Termonad.Prelude: infixl 9 !!
- Termonad.Prelude: infixr 0 $!!
+ Termonad.Prelude: infixr 0 $!
- Termonad.Prelude: infixr 2 <||>
+ Termonad.Prelude: infixr 2 ||
- Termonad.Prelude: infixr 3 <&&>
+ Termonad.Prelude: infixr 3 &&
- Termonad.Prelude: init :: IsSequence seq => NonNull seq -> seq
+ Termonad.Prelude: init :: HasCallStack => [a] -> [a]
- Termonad.Prelude: interact :: MonadIO m => (LText -> LText) -> m ()
+ Termonad.Prelude: interact :: (String -> String) -> IO ()
- Termonad.Prelude: last :: MonoFoldable mono => NonNull mono -> Element mono
+ Termonad.Prelude: last :: HasCallStack => [a] -> a
- Termonad.Prelude: length :: MonoFoldable mono => mono -> Int
+ Termonad.Prelude: length :: Foldable t => t a -> Int
- Termonad.Prelude: lines :: Textual t => t -> [t]
+ Termonad.Prelude: lines :: String -> [String]
- Termonad.Prelude: lookup :: IsMap map => ContainerKey map -> map -> Maybe (MapValue map)
+ Termonad.Prelude: lookup :: Eq a => a -> [(a, b)] -> Maybe b
- Termonad.Prelude: map :: Functor f => (a -> b) -> f a -> f b
+ Termonad.Prelude: map :: (a -> b) -> [a] -> [b]
- Termonad.Prelude: mapM_ :: (MonoFoldable mono, Applicative m) => (Element mono -> m ()) -> mono -> m ()
+ Termonad.Prelude: mapM_ :: (Foldable t, Monad m) => (a -> m b) -> t a -> m ()
- Termonad.Prelude: maximum :: (MonoFoldable mono, Ord (Element mono)) => NonNull mono -> Element mono
+ Termonad.Prelude: maximum :: (Foldable t, Ord a) => t a -> a
- Termonad.Prelude: minimum :: (MonoFoldable mono, Ord (Element mono)) => NonNull mono -> Element mono
+ Termonad.Prelude: minimum :: (Foldable t, Ord a) => t a -> a
- Termonad.Prelude: modifyMVar :: MonadUnliftIO m => MVar a -> (a -> m (a, b)) -> m b
+ Termonad.Prelude: modifyMVar :: MVar a -> (a -> IO (a, b)) -> IO b
- Termonad.Prelude: modifyMVar_ :: MonadUnliftIO m => MVar a -> (a -> m a) -> m ()
+ Termonad.Prelude: modifyMVar_ :: MVar a -> (a -> IO a) -> IO ()
- Termonad.Prelude: newMVar :: MonadIO m => a -> m (MVar a)
+ Termonad.Prelude: newMVar :: a -> IO (MVar a)
- Termonad.Prelude: newtype MaybeT (m :: Type -> Type) a
+ Termonad.Prelude: newtype () => MaybeT (m :: Type -> Type) a
- Termonad.Prelude: notElem :: (MonoFoldable mono, Eq (Element mono)) => Element mono -> mono -> Bool
+ Termonad.Prelude: notElem :: (Foldable t, Eq a) => a -> t a -> Bool
- Termonad.Prelude: null :: MonoFoldable mono => mono -> Bool
+ Termonad.Prelude: null :: Foldable t => t a -> Bool
- Termonad.Prelude: or :: (MonoFoldable mono, Element mono ~ Bool) => mono -> Bool
+ Termonad.Prelude: or :: Foldable t => t Bool -> Bool
- Termonad.Prelude: print :: (Show a, MonadIO m) => a -> m ()
+ Termonad.Prelude: print :: Show a => a -> IO ()
- Termonad.Prelude: product :: (MonoFoldable mono, Num (Element mono)) => mono -> Element mono
+ Termonad.Prelude: product :: (Foldable t, Num a) => t a -> a
- Termonad.Prelude: putChar :: MonadIO m => Char -> m ()
+ Termonad.Prelude: putChar :: Char -> IO ()
- Termonad.Prelude: putStr :: MonadIO m => Text -> m ()
+ Termonad.Prelude: putStr :: String -> IO ()
- Termonad.Prelude: putStrLn :: MonadIO m => Text -> m ()
+ Termonad.Prelude: putStrLn :: String -> IO ()
- Termonad.Prelude: readFile :: MonadIO m => FilePath -> m ByteString
+ Termonad.Prelude: readFile :: FilePath -> IO String
- Termonad.Prelude: readMVar :: MonadIO m => MVar a -> m a
+ Termonad.Prelude: readMVar :: MVar a -> IO a
- Termonad.Prelude: replicate :: IsSequence seq => Index seq -> Element seq -> seq
+ Termonad.Prelude: replicate :: Int -> a -> [a]
- Termonad.Prelude: reverse :: SemiSequence seq => seq -> seq
+ Termonad.Prelude: reverse :: [a] -> [a]
- Termonad.Prelude: sequence_ :: (Applicative m, MonoFoldable mono, Element mono ~ m ()) => mono -> m ()
+ Termonad.Prelude: sequence_ :: (Foldable t, Monad m) => t (m a) -> m ()
- Termonad.Prelude: span :: IsSequence seq => (Element seq -> Bool) -> seq -> (seq, seq)
+ Termonad.Prelude: span :: (a -> Bool) -> [a] -> ([a], [a])
- Termonad.Prelude: splitAt :: IsSequence seq => Index seq -> seq -> (seq, seq)
+ Termonad.Prelude: splitAt :: Int -> [a] -> ([a], [a])
- Termonad.Prelude: sum :: (MonoFoldable mono, Num (Element mono)) => mono -> Element mono
+ Termonad.Prelude: sum :: (Foldable t, Num a) => t a -> a
- Termonad.Prelude: tail :: IsSequence seq => NonNull seq -> seq
+ Termonad.Prelude: tail :: HasCallStack => [a] -> [a]
- Termonad.Prelude: take :: IsSequence seq => Index seq -> seq -> seq
+ Termonad.Prelude: take :: Int -> [a] -> [a]
- Termonad.Prelude: takeWhile :: IsSequence seq => (Element seq -> Bool) -> seq -> seq
+ Termonad.Prelude: takeWhile :: (a -> Bool) -> [a] -> [a]
- Termonad.Prelude: try :: (MonadUnliftIO m, Exception e) => m a -> m (Either e a)
+ Termonad.Prelude: try :: Exception e => IO a -> IO (Either e a)
- Termonad.Prelude: undefined :: HasCallStack => a
+ Termonad.Prelude: undefined :: forall (r :: RuntimeRep) (a :: TYPE r). HasCallStack => a
- Termonad.Prelude: unlines :: (Textual t, Element seq ~ t, MonoFoldable seq) => seq -> t
+ Termonad.Prelude: unlines :: [String] -> String
- Termonad.Prelude: unwords :: (Textual t, Element seq ~ t, MonoFoldable seq) => seq -> t
+ Termonad.Prelude: unwords :: [String] -> String
- Termonad.Prelude: unzip :: Zip f => f (a, b) -> (f a, f b)
+ Termonad.Prelude: unzip :: [(a, b)] -> ([a], [b])
- Termonad.Prelude: unzip3 :: Zip3 f => f (a, b, c) -> (f a, f b, f c)
+ Termonad.Prelude: unzip3 :: [(a, b, c)] -> ([a], [b], [c])
- Termonad.Prelude: withMVar :: MonadUnliftIO m => MVar a -> (a -> m b) -> m b
+ Termonad.Prelude: withMVar :: MVar a -> (a -> IO b) -> IO b
- Termonad.Prelude: words :: Textual t => t -> [t]
+ Termonad.Prelude: words :: String -> [String]
- Termonad.Prelude: writeFile :: MonadIO m => FilePath -> ByteString -> m ()
+ Termonad.Prelude: writeFile :: FilePath -> String -> IO ()
- Termonad.Prelude: zip :: Zip f => f a -> f b -> f (a, b)
+ Termonad.Prelude: zip :: [a] -> [b] -> [(a, b)]
- Termonad.Prelude: zip3 :: Zip3 f => f a -> f b -> f c -> f (a, b, c)
+ Termonad.Prelude: zip3 :: [a] -> [b] -> [c] -> [(a, b, c)]
- Termonad.Prelude: zipWith :: Zip f => (a -> b -> c) -> f a -> f b -> f c
+ Termonad.Prelude: zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
- Termonad.Prelude: zipWith3 :: Zip3 f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d
+ Termonad.Prelude: zipWith3 :: (a -> b -> c -> d) -> [a] -> [b] -> [c] -> [d]
- Termonad.Term: addPage :: TMState -> TMNotebookTab -> Box -> IO ()
+ Termonad.Term: addPage :: TMState -> TMWindowId -> TMNotebookTab -> Box -> IO ()
- Termonad.Term: altNumSwitchTerm :: Int -> TMState -> IO ()
+ Termonad.Term: altNumSwitchTerm :: Int -> TMState -> TMWindowId -> IO ()
- Termonad.Term: createTerm :: (TMState -> EventKey -> IO Bool) -> TMState -> IO TMTerm
+ Termonad.Term: createTerm :: (TMState -> TMWindowId -> EventKey -> IO Bool) -> TMState -> TMWindowId -> IO TMTerm
- Termonad.Term: focusTerm :: Int -> TMState -> IO ()
+ Termonad.Term: focusTerm :: Int -> TMState -> TMWindowId -> IO ()
- Termonad.Term: relabelTabs :: TMState -> IO ()
+ Termonad.Term: relabelTabs :: TMNotebook -> IO ()
- Termonad.Term: termClose :: TMNotebookTab -> TMState -> IO ()
+ Termonad.Term: termClose :: TMNotebookTab -> TMState -> TMWindowId -> IO ()
- Termonad.Term: termExit :: TMNotebookTab -> TMState -> IO ()
+ Termonad.Term: termExit :: TMNotebookTab -> TMState -> TMWindowId -> IO ()
- Termonad.Term: termExitFocused :: TMState -> IO ()
+ Termonad.Term: termExitFocused :: TMState -> TMWindowId -> IO ()
- Termonad.Term: termExitWithConfirmation :: TMNotebookTab -> TMState -> IO ()
+ Termonad.Term: termExitWithConfirmation :: TMNotebookTab -> TMState -> TMWindowId -> IO ()
- Termonad.Term: termNextPage :: TMState -> IO ()
+ Termonad.Term: termNextPage :: TMState -> TMWindowId -> IO ()
- Termonad.Term: termPrevPage :: TMState -> IO ()
+ Termonad.Term: termPrevPage :: TMState -> TMWindowId -> IO ()
- Termonad.Types: FocusNotSame :: FocusNotSameErr -> Int -> TMStateInvariantErr
+ Termonad.Types: FocusNotSame :: FocusNotSameErr -> Int -> TMWinInvariantErr
- Termonad.Types: TMState :: !Application -> !ApplicationWindow -> !TMNotebook -> !FontDescription -> !TMConfig -> TMState'
+ Termonad.Types: TMState :: !Application -> !TMConfig -> !FontDescription -> !IdMap TMWindow -> TMState'
- Termonad.Types: TabsDoNotMatch :: TabsDoNotMatch -> TMStateInvariantErr
+ Termonad.Types: TabsDoNotMatch :: TabsDoNotMatch -> TMWinInvariantErr
- Termonad.Types: getFocusedTermFromState :: TMState -> IO (Maybe Terminal)
+ Termonad.Types: getFocusedTermFromState :: TMState -> TMWindowId -> IO (Maybe Terminal)
- Termonad.Types: newEmptyTMState :: TMConfig -> Application -> ApplicationWindow -> Notebook -> FontDescription -> IO TMState
+ Termonad.Types: newEmptyTMState :: TMConfig -> Application -> ApplicationWindow -> Notebook -> FontDescription -> IO (TMState, TMWindowId)

Files

− .nix-helpers/nixops.nix
@@ -1,110 +0,0 @@-# This file can be used with `nixops` to create a virtual machine that has-# Termonad installed.-#-# I use this to test out Termonad in a desktop environment with a menubar.-#-# On my development machine, I use XMonad as a Window Manager, so there are-# no Window decorations for any X application.  This file creates a VM-# with Termonad installed in Gnome 3.  This lets you see what Termonad-# looks like when it has Window decorations, a title bar, etc.-#-# A virtual machine can be created based on this file with the following-# commands:-#-# $ nixops create --deployment termonad-test .nix-helpers/nixops.nix-# $ nixops deploy --deployment termonad-test-#-# This should open up a VirtualBox machine and start installing Gnome 3,-# Termonad, etc.-#-# You should be able to login with the username "myuser" and password "foobar".-#-# When you are done you can destroy the machine and delete the deployment:-#-# $ nixops destroy --deployment termonad-test-# $ nixops delete --deployment termonad-test-#--{-  network.description = "Gnome With Termonad";--  termonad-machine =-    { config, pkgs, ...}:-    {-      imports = [ ];--      deployment = {-        targetEnv = "virtualbox";-        virtualbox = {-          disks.disk1.size = 20480;-          headless = false;-          memorySize = 2024;-          vcpu = 1;-        };-      };--      environment = {-        systemPackages =-          let-            pkgList = with pkgs; [-              acpi aspell aspellDicts.en autojump bash bash-completion bc-              chromium curl dmenu emacs evince file firefoxWrapper gcc geeqie-              gimp gitAndTools.gitFull gitAndTools.hub gnumake gnupg hexchat-              htop imagemagick jq k2pdfopt ltrace manpages ncurses-              nix-bash-completions nixops p7zip pkgconfig psmisc python3-              redshift roxterm screen strace tree unzip usbutils vimHugeX wget-              wirelesstools xfce.terminal xorg.xbacklight xorg.xmodmap-              xscreensaver xterm zlib-            ];-            termonad = import ../default.nix { };-          in [ termonad ] ++ pkgList;-        variables.EDITOR = "vim";-      };--      fonts.fonts = with pkgs; [-        dejavu_fonts ipafont source-code-pro ttf_bitstream_vera-      ];--      i18n = {-        consoleFont = "Lat2-Terminus16";-        consoleKeyMap = "us";-        defaultLocale = "en_US.UTF-8";-        inputMethod = {-          enabled = "fcitx";-          fcitx.engines = with pkgs.fcitx-engines; [ mozc ];-        };-      };--      programs.bash.enableCompletion = true;--      services = {-        xserver = {-          enable = true;-          layout = "us";-          desktopManager.gnome3.enable = true;-        };-        openssh = {-          enable = true;-          forwardX11 = true;-          challengeResponseAuthentication = true;-          passwordAuthentication = true;-          permitRootLogin = "yes";-        };-      };--      security.sudo = {-        enable = true;-        extraConfig = ''-          %wheel      ALL=(ALL:ALL) NOPASSWD: ${pkgs.systemd}/bin/poweroff-          %wheel      ALL=(ALL:ALL) NOPASSWD: ${pkgs.systemd}/bin/reboot-          %wheel      ALL=(ALL:ALL) NOPASSWD: ${pkgs.systemd}/bin/systemctl suspend-        '';-      };--      users.extraUsers.myuser = {-        extraGroups = [ "audio" "systemd-journal" "video" "wheel" ];-        initialPassword = "foobar";-        isNormalUser = true;-      };-    };-}
+ .nix-helpers/nixos-vm.nix view
@@ -0,0 +1,110 @@++# This file is used to build a NixOS VM that can be used to test Termonad in a+# known-working desktop environment (DE) / window manager (WM).+#+# This is helpful for developers using a minimal WM (like XMonad), but want to+# check how Termonad looks in a more full-featured desktop environment.+#+# You can build the VM with the following command:+#+# $ nix-build "$(nix-instantiate --eval -E 'with import ./nixpkgs.nix {}; path')"/nixos -A vm -I nixpkgs=./nixpkgs.nix -I nixos-config=./nixos-vm.nix+#+# You can run the resulting VM with the following command:+#+# $ ./result/bin/run-termonad-nixos-vm-vm -m 4G+#+# The `-m` flag allows you to specify how much RAM is used.++{ config, pkgs, lib, ... }:++{+  nixpkgs.overlays = import ./overlays.nix;++  boot.loader.systemd-boot.enable = true;+  boot.loader.efi.canTouchEfiVariables = true;++  networking.hostName = "termonad-nixos-vm";+  networking.networkmanager.enable = true;+  networking.useDHCP = lib.mkDefault true;++  time.timeZone = "UTC";++  environment.systemPackages = with pkgs; [+    curl+    file+    firefox+    htop+    jq+    ltrace+    nix-bash-completions+    pkg-config+    psmisc+    screen+    strace+    termonad+    tree+    unzip+    vimHugeX+    wget+    xterm+  ];++  environment.variables = {+    EDITOR = "vim";+  };++  fonts.fonts = with pkgs; [+    dejavu_fonts ipafont+  ];++  i18n = {+    defaultLocale = "en_US.UTF-8";+    supportedLocales = [ "C.UTF-8/UTF-8" "en_US.UTF-8/UTF-8" "ja_JP.UTF-8/UTF-8" ];+    inputMethod = {+      enabled = "fcitx5";+      fcitx5.addons = with pkgs; [ fcitx5-mozc fcitx5-rime fcitx5-chinese-addons ];+    };+  };++  console = {+    font = "Lat2-Terminus16";+    keyMap = "us";+  };++  programs.bash.enableCompletion = true;++  services.xserver = {+    enable = true;+    layout = "us";+    desktopManager.gnome.enable = true;+  };++  services.openssh = {+    enable = true;+    settings = {+      X11Forwarding = true;+      KbdInteractiveAuthentication = true;+      ChallengeResponseAuthentication = true;+      PasswordAuthentication = true;+      PermitRootLogin = "yes";+      MaxAuthTries = 12;+    };+  };++  security.sudo = {+    enable = true;+    extraConfig = ''+      %wheel      ALL=(ALL:ALL) NOPASSWD: ${pkgs.systemd}/bin/poweroff+      %wheel      ALL=(ALL:ALL) NOPASSWD: ${pkgs.systemd}/bin/reboot+      %wheel      ALL=(ALL:ALL) NOPASSWD: ${pkgs.systemd}/bin/systemctl suspend+    '';+  };++  users.extraUsers.myuser = {+    extraGroups = [ "audio" "systemd-journal" "video" "wheel" ];+    initialPassword = "foobar";+    isNormalUser = true;+  };++  system.stateVersion = "23.05"; # Did you read the comment?+}
.nix-helpers/overlays.nix view
@@ -78,7 +78,7 @@     #     # Either this, or termonadKnownWorkingHaskellPkgSet can be changed in an overlay     # if you want to use a different GHC to build Termonad.-    termonadCompilerVersion = "ghc92";+    termonadCompilerVersion = "ghc94";      # A Haskell package set where we know the GHC version works to compile     # Termonad.  This is basically just a shortcut so that other Nix files@@ -146,7 +146,7 @@       lens     ]; -    termonad-with-packages =+    termonad =       let         # GHC environment that has termonad available, as well as the packages         # specified above in extraHaskellPackages.@@ -155,7 +155,7 @@             (hpkgs: [ hpkgs.termonad ] ++ self.termonadExtraHaskellPackages hpkgs);       in       self.stdenv.mkDerivation {-        name = "termonad-with-packages-ghc-${env.version}";+        name = "termonad-${self.termonadKnownWorkingHaskellPkgSet.termonad.version}-ghc-${env.version}";         buildInputs = [           self.gdk-pixbuf           self.gnome.adwaita-icon-theme@@ -178,6 +178,10 @@         preferLocalBuild = true;         allowSubstitutes = false;       };++    # This is just a small compatibility layer for people that used to use+    # termonad-with-packages instead of just termonad.+    termonad-with-packages = self.termonad;   }; in 
.nix-helpers/termonad-with-packages.nix view
@@ -100,4 +100,4 @@   }; in -pkgs.termonad-with-packages+pkgs.termonad
CHANGELOG.md view
@@ -1,3 +1,49 @@+## 4.6.0.0++*   The thing that may affect end users the most in this release is that the+    **`defaultMain` function moved from `Termonad.App` to `Termonad.Startup`**.+    (_However, it is also exported from the top-level `Termonad` module, so most+    users will likely want to get it from the top-level `Termonad` module_.)+    [#239](https://github.com/cdepillabout/termonad/pull/239)++*   There has been a big refactoring of the guts of Termonad.  As an end user,+    if you reach into any modules like `Termonad.App`, `Termonad.Term`, or+    `Termonad.Types`, you may notice some functions have moved around or gained+    new arguments.  Some data types have changed as well.  Most end users don't+    use these modules, so I don't expect that this refactoring will affect most+    users.++*   Add support for setting Termonad options with CLI arguments.  Add a whole+    CLI argument parser based on optparse-applicative.+    [#234](https://github.com/cdepillabout/termonad/pull/234)++    Check out `termonad --help` to see the options available to be set from the CLI.++    By default, passing CLI options will override options specified in the+    `termonad.hs` file, as well as options specified in the Preferences dialog.++    In your own `termonad.hs` file, if you want to not use this CLI argument+    funtionality, you should be able to use the `Termonad.start` function (in+    place of `Termonad.defaultMain`).++*   Embed the Termonad icon into the Termonad library (instead of having it set+    as a `data-file` in `termonad.cabal`).++    This fixes a problem some users were seeing when garbaging-collecting their+    Nix store and losing the required `termonad-lambda.png` file that their+    Termonad binary was referencing:+    [#165](https://github.com/cdepillabout/termonad/issues/165)++    Thanks [@refaelsh](https://github.com/refaelsh)! [#236](https://github.com/cdepillabout/termonad/pull/236)++*   Rename the `Termonad.PreferencesFile` module to `Termonad.Preferences.File`.++    Also, add a `Termonad.Preferences` module that re-exports everything helpful+    from the `Termonad.Preferences.File` module.  Also, some of the+    preferences-related functionality from `Termonad.App` has been moved into+    `Termonad.Preferences`.+    [#238](https://github.com/cdepillabout/termonad/pull/238)+ ## 4.5.0.0  *   Add an `allowBold` option (which defaults to `True`).  This can be used if
README.md view
@@ -292,35 +292,34 @@  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:+`termonad` binary will be in `~/.local/bin/`. If you have installed Termonad using+your Linux distro, the `termonad` binary will likely be in `/usr/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+$ /usr/bin/termonad ``` -The following section describes the default key bindings.- 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`. A following section gives an example configuration file. -If this configuration file exists, when the `~/.local/bin/termonad` binary+If this configuration file exists, when the `/usr/bin/termonad` binary launches, it will try to use GHC to compile the configuration file. If GHC is able to successfully compile the configuration file, a separate binary will be created 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+When you run `/usr/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+`/usr/bin/termonad` binary to be able to compile your `~/.config/termonad/termonad.hs` configuration file, Termonad 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.+some difficulties that will be discussed in one of the following sections.  ### Default Key Bindings @@ -341,31 +340,40 @@  ### Configuring Termonad -Termonad has two different ways to be configured.+Termonad has three different ways to be configured. -The first way is to use the built-in Preferences editor.  You can find this in-the `Preferences` menu under `Edit` in the menubar.+1.  Pass arguments on the command line.  For instance, run+    `termonad --no-show-menu` to never show the `File` menubar. -When opening Termonad for the first time, it will create a preferences file at-`~/.config/termonad/termonad.yaml`.  When you change a setting in the-Preferences editor, Termonad will update the setting in the preferences file.+    Arguments passed on the command line will normally override other+    configuration methods. -When running Termonad, it will load settings from the preferences file.-Do not edit the preferences file by hand, because it will be overwritten when-updating settings in the Preferences editor.+2.  Use the built-in Preferences editor.  You can find this in+    the `Preferences` menu under `Edit` in the menubar. -This method is perfect for users who only want to make small changes to the-Termonad settings, like the default font size.+    When opening Termonad for the first time, it will create a preferences file+    at `~/.config/termonad/termonad.yaml`.  When you change a setting in the+    Preferences editor, Termonad will update the setting in the preferences+    file. -The second way to configure Termonad is to use a Haskell-based settings file,-called `~/.config/termonad/termonad.hs` by default.  This method allows you to-make large, sweeping changes to Termonad.  This method is recommended for power-users.+    When running Termonad, it will load settings from the preferences file. Do+    not edit the preferences file by hand, because it will be overwritten when+    updating settings in the Preferences editor. +    This method is perfect for users who only want to make small changes to the+    Termonad settings, like the default font size.++3.  Use a Haskell-based settings file, called `~/.config/termonad/termonad.hs` by default.+    This method allows you to make large, sweeping changes to Termonad.  This+    method is recommended for power users.++    The rest of this section explains the `~/.config/termonad/termonad.hs` file.+ **WARNING: If you have a `~/.config/termonad/termonad.hs` file, then all settings from `~/.config/termonad/termonad.yaml` will be ignored.  If you want to set *ANY* settings in `~/.config/termonad/termonad.hs`, then you must-set *ALL* settings in `~/.config/termonad/termonad.hs`.**+set *ALL* settings in `~/.config/termonad/termonad.hs`.  However, as stated above,+CLI arguments will override settings in `~/.config/termonad/termonad.hs` by default.**  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@@ -378,11 +386,11 @@  module Main where -import Termonad.App (defaultMain)-import Termonad.Config+import Termonad   ( FontConfig, FontSize(FontSizePoints), Option(Set)   , ShowScrollbar(ShowScrollbarAlways), defaultConfigOptions, defaultFontConfig-  , defaultTMConfig, fontConfig, fontFamily, fontSize, options, showScrollbar+  , defaultMain, defaultTMConfig, fontConfig, fontFamily, fontSize, options+  , showScrollbar   ) import Termonad.Config.Colour   ( AlphaColour, ColourConfig, addColourExtension, createColour@@ -439,9 +447,9 @@  ### Compiling Local Settings -If you launch Termonad by calling `~/.local/bin/termonad`, it will try to+If you launch Termonad by calling `/usr/bin/termonad`, it will try to compile the `~/.config/termonad/termonad.hs` file if it exists.  The problem is-that `~/.local/bin/termonad` needs to be able to see GHC and the required+that `/usr/bin/termonad` needs to be able to see GHC and the required Haskell libraries to be able to compile `~/.config/termonad/termonad.hs`.  There are a couple solutions to this problem, listed in the sections below.@@ -452,9 +460,10 @@  #### Running with `stack` -If you originally compiled Termonad with `stack`, you can use `stack` to-execute Termonad.  First, you must change to the directory with the Termonad-source code.  From there, you can run `stack exec`:+If you originally compiled Termonad with `stack` and installed it to+`~/.local/bin/termonad`, you can use `stack` to execute Termonad.  First, you+must change to the directory with the Termonad source code.  From there, you+can run `stack exec`:  ```sh $ cd termonad/  # change to the termonad source code directory
default.nix view
@@ -24,5 +24,4 @@ , enableSixelSupport ? false }@args: -(import .nix-helpers/nixpkgs.nix args).termonad-with-packages-+(import .nix-helpers/nixpkgs.nix args).termonad
flake.lock view
@@ -2,11 +2,11 @@   "nodes": {     "nixpkgs": {       "locked": {-        "lastModified": 1680213900,-        "narHash": "sha256-cIDr5WZIj3EkKyCgj/6j3HBH4Jj1W296z7HTcWj1aMA=",+        "lastModified": 1704194953,+        "narHash": "sha256-RtDKd8Mynhe5CFnVT8s0/0yqtWFMM9LmCzXv/YKxnq4=",         "owner": "NixOS",         "repo": "nixpkgs",-        "rev": "e3652e0735fbec227f342712f180f4f21f0594f2",+        "rev": "bd645e8668ec6612439a9ee7e71f7eac4099d4f6",         "type": "github"       },       "original": {
flake.nix view
@@ -44,7 +44,7 @@         let           pkgs = nixpkgsFor.${system};         in {-          termonad = pkgs.termonad-with-packages;+          termonad = pkgs.termonad;         }       ); 
src/Termonad.hs view
@@ -5,15 +5,17 @@ -- Stability   : experimental -- Portability : POSIX ----- This module exposes termonad's basic configuration options, as well as 'defaultMain'.+-- This module exposes Termonad's basic configuration options, as well as 'defaultMain', 'startWithCliArgs', and 'start'. -- -- If you want to configure Termonad, please take a look at "Termonad.Config".  module Termonad   ( defaultMain+  , startWithCliArgs   , start   , module Config   ) where -import Termonad.App (defaultMain, start)+import Termonad.App (start) import Termonad.Config as Config+import Termonad.Startup (defaultMain, startWithCliArgs)
src/Termonad/App.hs view
@@ -1,13 +1,14 @@+{-# LANGUAGE TemplateHaskell #-}+ module Termonad.App where  import Termonad.Prelude -import Config.Dyre (defaultParams, projectName, realMain, showError, wrapMain)-import Control.Lens ((.~), (^.), (^..), over, set, view)-import Control.Monad.Fail (fail)-import Data.FocusList (focusList, moveFromToFL, updateFocusFL)-import Data.Sequence (findIndexR)-import GI.Gdk (castTo, managedForeignPtr, screenGetDefault)+import Control.Lens ((^.))+import Data.FileEmbed (embedFile)+import qualified Data.Text as Text+import Data.Text.Encoding (encodeUtf8)+import GI.Gdk (screenGetDefault) import GI.Gio   ( ApplicationFlags(ApplicationFlagsFlagsNone)   , MenuModel(MenuModel)@@ -23,20 +24,9 @@   ( Application   , ApplicationWindow(ApplicationWindow)   , Box(Box)-  , CheckButton(CheckButton)-  , ComboBoxText(ComboBoxText)-  , Dialog(Dialog)-  , Entry(Entry)-  , FontButton(FontButton)-  , Label(Label)-  , PolicyType(PolicyTypeAutomatic)-  , PositionType(PositionTypeRight)-  , ResponseType(ResponseTypeAccept, ResponseTypeNo, ResponseTypeYes)-  , ScrolledWindow(ScrolledWindow)-  , SpinButton(SpinButton)+  , Notebook+  , ResponseType(ResponseTypeNo, ResponseTypeYes)   , pattern STYLE_PROVIDER_PRIORITY_APPLICATION-  , aboutDialogNew-  , adjustmentNew   , applicationAddWindow   , applicationGetActiveWindow   , applicationSetAccelsForAction@@ -45,142 +35,55 @@   , boxPackStart   , builderNewFromString   , builderSetApplication-  , comboBoxGetActiveId-  , comboBoxSetActiveId-  , comboBoxTextAppend   , containerAdd   , cssProviderLoadFromData   , cssProviderNew   , dialogAddButton   , dialogGetContentArea   , dialogNew-  , dialogResponse   , dialogRun-  , entryBufferGetText-  , entryBufferSetText-  , entryGetText-  , entryNew-  , fontChooserSetFontDesc-  , fontChooserGetFontDesc-  , getEntryBuffer-  , gridAttachNextTo-  , gridNew   , labelNew   , notebookGetNPages   , notebookNew   , notebookSetShowBorder-  , onEntryActivate   , onNotebookPageRemoved-  , onNotebookPageReordered-  , onNotebookSwitchPage   , onWidgetDeleteEvent-  , scrolledWindowSetPolicy   , setWidgetMargin-  , spinButtonGetValueAsInt-  , spinButtonSetAdjustment-  , spinButtonSetValue   , styleContextAddProviderForScreen-  , toggleButtonGetActive-  , toggleButtonSetActive   , widgetDestroy   , widgetGrabFocus   , widgetSetCanFocus-  , widgetSetVisible   , widgetShow   , widgetShowAll   , windowPresent-  , windowSetDefaultIconFromFile+  , windowSetDefaultIcon   , windowSetTitle   , windowSetTransientFor   ) import qualified GI.Gtk as Gtk-import GI.Pango-  ( FontDescription-  , pattern SCALE-  , fontDescriptionGetFamily-  , fontDescriptionGetSize-  , fontDescriptionGetSizeIsAbsolute-  , fontDescriptionNew-  , fontDescriptionSetFamily-  , fontDescriptionSetSize-  , fontDescriptionSetAbsoluteSize-  )-import GI.Vte-  ( CursorBlinkMode(..)-  , catchRegexError-  , regexNewForSearch-  , terminalCopyClipboard-  , terminalPasteClipboard-  , terminalSearchFindNext-  , terminalSearchFindPrevious-  , terminalSearchSetRegex-  , terminalSearchSetWrapAround-  , terminalSetBoldIsBright-  , terminalSetCursorBlinkMode-  , terminalSetFont-  , terminalSetScrollbackLines-  , terminalSetWordCharExceptions-  , terminalSetAllowBold-  )-import System.Environment (getExecutablePath)-import System.FilePath (takeFileName)--import Paths_termonad (getDataFileName)-import Termonad.Gtk (appNew, objFromBuildUnsafe, terminalSetEnableSixelIfExists)+import Termonad.Gtk (appNew, imgToPixbuf, objFromBuildUnsafe) import Termonad.Keys (handleKeyPress) import Termonad.Lenses-  ( lensBoldIsBright-  , lensEnableSixel-  , lensAllowBold-  , lensConfirmExit-  , lensCursorBlinkMode-  , lensFontConfig+  ( lensConfirmExit   , lensOptions   , lensShowMenu-  , lensShowScrollbar-  , lensShowTabBar-  , lensScrollbackLen-  , lensTMNotebook-  , lensTMNotebookTabTermContainer-  , lensTMNotebookTabs-  , lensTMNotebookTabTerm   , lensTMStateApp-  , lensTMStateAppWin   , lensTMStateConfig-  , lensTMStateFontDesc-  , lensTMStateNotebook   , lensTerm-  , lensWordCharExceptions   )-import Termonad.PreferencesFile (saveToPreferencesFile)-import Termonad.Term-  ( createTerm-  , relabelTabs-  , termNextPage-  , termPrevPage-  , termExitFocused-  , setShowTabs-  , showScrollbarToPolicy-  )+import Termonad.Preferences (showPreferencesDialog)+import Termonad.Term (createTerm, setShowTabs) import Termonad.Types-  ( ConfigOptions(..)-  , FontConfig(..)-  , FontSize(FontSizePoints, FontSizeUnits)-  , ShowScrollbar(..)-  , ShowTabBar(..)-  , TMConfig-  , TMNotebookTab+  ( TMConfig   , TMState-  , TMState'(TMState)-  , getFocusedTermFromState+  , TMState'+  , TMWindowId+  , createFontDescFromConfig   , modFontSize   , newEmptyTMState-  , tmNotebookTabTermContainer-  , tmNotebookTabs-  , tmStateApp-  , tmStateNotebook   )-import Termonad.XML (interfaceText, menuText, preferencesText)+import Termonad.XML (interfaceText, menuText)+import Termonad.Window (showAboutDialog, modifyFontSizeForAllTerms, setupWindowCallbacks)  setupScreenStyle :: IO () setupScreenStyle = do@@ -219,95 +122,13 @@             , "  background-color: transparent;"             , "}"             ]-      let styleData = encodeUtf8 (unlines textLines :: Text)+      let styleData = encodeUtf8 (Text.unlines textLines)       cssProviderLoadFromData cssProvider styleData       styleContextAddProviderForScreen         screen         cssProvider         (fromIntegral STYLE_PROVIDER_PRIORITY_APPLICATION) -createFontDescFromConfig :: TMConfig -> IO FontDescription-createFontDescFromConfig tmConfig = do-  let fontConf = tmConfig ^. lensOptions . lensFontConfig-  createFontDesc (fontSize fontConf) (fontFamily fontConf)--createFontDesc :: FontSize -> Text -> IO FontDescription-createFontDesc fontSz fontFam = do-  fontDesc <- fontDescriptionNew-  fontDescriptionSetFamily fontDesc fontFam-  setFontDescSize fontDesc fontSz-  pure fontDesc--setFontDescSize :: FontDescription -> FontSize -> IO ()-setFontDescSize fontDesc (FontSizePoints points) =-  fontDescriptionSetSize fontDesc $ fromIntegral (points * fromIntegral SCALE)-setFontDescSize fontDesc (FontSizeUnits units) =-  fontDescriptionSetAbsoluteSize fontDesc $ units * fromIntegral SCALE--adjustFontDescSize :: (FontSize -> FontSize) -> FontDescription -> IO ()-adjustFontDescSize f fontDesc = do-  currFontSz <- fontSizeFromFontDescription fontDesc-  let newFontSz = f currFontSz-  setFontDescSize fontDesc newFontSz--modifyFontSizeForAllTerms :: (FontSize -> FontSize) -> TMState -> IO ()-modifyFontSizeForAllTerms modFontSizeFunc mvarTMState = do-  tmState <- readMVar mvarTMState-  let fontDesc = tmState ^. lensTMStateFontDesc-  adjustFontDescSize modFontSizeFunc fontDesc-  let terms =-        tmState ^..-          lensTMStateNotebook .-          lensTMNotebookTabs .-          traverse .-          lensTMNotebookTabTerm .-          lensTerm-  foldMap (\vteTerm -> terminalSetFont vteTerm (Just fontDesc)) terms--fontSizeFromFontDescription :: FontDescription -> IO FontSize-fontSizeFromFontDescription fontDesc = do-  currSize <- fontDescriptionGetSize fontDesc-  currAbsolute <- fontDescriptionGetSizeIsAbsolute fontDesc-  return $ if currAbsolute-             then FontSizeUnits $ fromIntegral currSize / fromIntegral SCALE-             else-               let fontRatio :: Double = fromIntegral currSize / fromIntegral SCALE-               in FontSizePoints $ round fontRatio--fontConfigFromFontDescription :: FontDescription -> IO (Maybe FontConfig)-fontConfigFromFontDescription fontDescription = do-  fontSize <- fontSizeFromFontDescription fontDescription-  maybeFontFamily <- fontDescriptionGetFamily fontDescription-  return $ (`FontConfig` fontSize) <$> maybeFontFamily--compareScrolledWinAndTab :: ScrolledWindow -> TMNotebookTab -> Bool-compareScrolledWinAndTab scrollWin flTab =-  let ScrolledWindow managedPtrFLTab = tmNotebookTabTermContainer flTab-      foreignPtrFLTab = managedForeignPtr managedPtrFLTab-      ScrolledWindow managedPtrScrollWin = scrollWin-      foreignPtrScrollWin = managedForeignPtr managedPtrScrollWin-  in foreignPtrFLTab == foreignPtrScrollWin--updateFLTabPos :: TMState -> Int -> Int -> IO ()-updateFLTabPos mvarTMState oldPos newPos =-  modifyMVar_ mvarTMState $ \tmState -> do-    let tabs = tmState ^. lensTMStateNotebook . lensTMNotebookTabs-        maybeNewTabs = moveFromToFL oldPos newPos tabs-    case maybeNewTabs of-      Nothing -> do-        putStrLn $-          "in updateFLTabPos, Strange error: couldn't move tabs.\n" <>-          "old pos: " <> tshow oldPos <> "\n" <>-          "new pos: " <> tshow newPos <> "\n" <>-          "tabs: " <> tshow tabs <> "\n" <>-          "maybeNewTabs: " <> tshow maybeNewTabs <> "\n" <>-          "tmState: " <> tshow tmState-        pure tmState-      Just newTabs ->-        pure $-          tmState &-            lensTMStateNotebook . lensTMNotebookTabs .~ newTabs- -- | Try to figure out whether Termonad should exit.  This also used to figure -- out if Termonad should close a given terminal. --@@ -369,23 +190,16 @@   let app = tmState ^. lensTMStateApp   applicationQuit app -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 <- createFontDescFromConfig tmConfig-  note <- notebookNew-  widgetSetCanFocus note False-  -- If this is not set to False, then there will be a one pixel white border-  -- shown around the notebook.-  notebookSetShowBorder note False-  boxPackStart box note True True 0--  mvarTMState <- newEmptyTMState tmConfig app win note fontDesc-  terminal <- createTerm handleKeyPress mvarTMState+setupAppCallbacks :: TMState -> TMConfig -> Application -> ApplicationWindow -> Notebook -> TMWindowId -> IO ()+setupAppCallbacks mvarTMState tmConfig app win note tmWinId = do+  newWindowAction <- simpleActionNew "newwin" Nothing+  void $ onSimpleActionActivate newWindowAction $ \_ ->+    pure ()+    -- void $ createTerm handleKeyPress mvarTMState tmWinId+  actionMapAddAction app newWindowAction+  -- TODO: Uncomment this when adding the actual functionality+  -- for creating new windows.+  -- applicationSetAccelsForAction app "app.newwin" ["<Shift><Ctrl>N"]    void $ onNotebookPageRemoved note $ \_ _ -> do     pages <- notebookGetNPages note@@ -393,65 +207,6 @@       then forceQuit mvarTMState       else setShowTabs tmConfig note -  void $ onNotebookSwitchPage note $ \_ pageNum -> do-    modifyMVar_ mvarTMState $ \tmState -> do-      let notebook = tmStateNotebook tmState-          tabs = tmNotebookTabs notebook-          maybeNewTabs = updateFocusFL (fromIntegral pageNum) tabs-      case maybeNewTabs of-        Nothing -> pure tmState-        Just (tab, newTabs) -> do-          widgetGrabFocus $ tab ^. lensTMNotebookTabTerm . lensTerm-          pure $-            tmState &-              lensTMStateNotebook . lensTMNotebookTabs .~ newTabs--  void $ onNotebookPageReordered note $ \childWidg pageNum -> do-    maybeScrollWin <- castTo ScrolledWindow childWidg-    case maybeScrollWin of-      Nothing ->-        fail $-          "In setupTermonad, in callback for onNotebookPageReordered, " <>-          "child widget is not a ScrolledWindow.\n" <>-          "Don't know how to continue.\n"-      Just scrollWin -> do-        TMState{tmStateNotebook} <- readMVar mvarTMState-        let fl = tmStateNotebook ^. lensTMNotebookTabs-        let maybeOldPosition =-              findIndexR (compareScrolledWinAndTab scrollWin) (focusList fl)-        case maybeOldPosition of-          Nothing ->-            fail $-              "In setupTermonad, in callback for onNotebookPageReordered, " <>-              "the ScrolledWindow is not already in the FocusList.\n" <>-              "Don't know how to continue.\n"-          Just oldPos -> do-            updateFLTabPos mvarTMState oldPos (fromIntegral pageNum)-            relabelTabs mvarTMState--  newTabAction <- simpleActionNew "newtab" Nothing-  void $ onSimpleActionActivate newTabAction $ \_ -> void $ createTerm handleKeyPress mvarTMState-  actionMapAddAction app newTabAction-  applicationSetAccelsForAction app "app.newtab" ["<Shift><Ctrl>T"]--  nextPageAction <- simpleActionNew "nextpage" Nothing-  void $ onSimpleActionActivate nextPageAction $ \_ ->-    termNextPage mvarTMState-  actionMapAddAction app nextPageAction-  applicationSetAccelsForAction app "app.nextpage" ["<Ctrl>Page_Down"]--  prevPageAction <- simpleActionNew "prevpage" Nothing-  void $ onSimpleActionActivate prevPageAction $ \_ ->-    termPrevPage mvarTMState-  actionMapAddAction app prevPageAction-  applicationSetAccelsForAction app "app.prevpage" ["<Ctrl>Page_Up"]--  closeTabAction <- simpleActionNew "closetab" Nothing-  void $ onSimpleActionActivate closeTabAction $ \_ ->-    termExitFocused mvarTMState-  actionMapAddAction app closeTabAction-  applicationSetAccelsForAction app "app.closetab" ["<Shift><Ctrl>W"]-   quitAction <- simpleActionNew "quit" Nothing   void $ onSimpleActionActivate quitAction $ \_ -> do     shouldExit <- askShouldExit mvarTMState@@ -459,63 +214,26 @@   actionMapAddAction app quitAction   applicationSetAccelsForAction app "app.quit" ["<Shift><Ctrl>Q"] -  copyAction <- simpleActionNew "copy" Nothing-  void $ onSimpleActionActivate copyAction $ \_ -> do-    maybeTerm <- getFocusedTermFromState mvarTMState-    maybe (pure ()) terminalCopyClipboard maybeTerm-  actionMapAddAction app copyAction-  applicationSetAccelsForAction app "app.copy" ["<Shift><Ctrl>C"]--  pasteAction <- simpleActionNew "paste" Nothing-  void $ onSimpleActionActivate pasteAction $ \_ -> do-    maybeTerm <- getFocusedTermFromState mvarTMState-    maybe (pure ()) terminalPasteClipboard maybeTerm-  actionMapAddAction app pasteAction-  applicationSetAccelsForAction app "app.paste" ["<Shift><Ctrl>V"]-   preferencesAction <- simpleActionNew "preferences" Nothing   void $ onSimpleActionActivate preferencesAction (const $ showPreferencesDialog mvarTMState)   actionMapAddAction app preferencesAction    enlargeFontAction <- simpleActionNew "enlargefont" Nothing   void $ onSimpleActionActivate enlargeFontAction $ \_ ->-    modifyFontSizeForAllTerms (modFontSize 1) mvarTMState+    modifyFontSizeForAllTerms (modFontSize 1) mvarTMState tmWinId   actionMapAddAction app enlargeFontAction   applicationSetAccelsForAction app "app.enlargefont" ["<Ctrl>plus"]    reduceFontAction <- simpleActionNew "reducefont" Nothing   void $ onSimpleActionActivate reduceFontAction $ \_ ->-    modifyFontSizeForAllTerms (modFontSize (-1)) mvarTMState+    modifyFontSizeForAllTerms (modFontSize (-1)) mvarTMState tmWinId   actionMapAddAction app reduceFontAction   applicationSetAccelsForAction app "app.reducefont" ["<Ctrl>minus"] -  findAction <- simpleActionNew "find" Nothing-  void $ onSimpleActionActivate findAction $ \_ -> doFind mvarTMState-  actionMapAddAction app findAction-  applicationSetAccelsForAction app "app.find" ["<Shift><Ctrl>F"]--  findAboveAction <- simpleActionNew "findabove" Nothing-  void $ onSimpleActionActivate findAboveAction $ \_ -> findAbove mvarTMState-  actionMapAddAction app findAboveAction-  applicationSetAccelsForAction app "app.findabove" ["<Shift><Ctrl>P"]--  findBelowAction <- simpleActionNew "findbelow" Nothing-  void $ onSimpleActionActivate findBelowAction $ \_ -> findBelow mvarTMState-  actionMapAddAction app findBelowAction-  applicationSetAccelsForAction app "app.findbelow" ["<Shift><Ctrl>I"]-   aboutAction <- simpleActionNew "about" Nothing-  void $ onSimpleActionActivate aboutAction $ \_ -> showAboutDialog app+  void $ onSimpleActionActivate aboutAction $ \_ -> showAboutDialog win   actionMapAddAction app aboutAction -  menuBuilder <- builderNewFromString menuText $ fromIntegral (length menuText)-  menuModel <- objFromBuildUnsafe menuBuilder "menubar" MenuModel-  applicationSetMenubar app (Just menuModel)-  let showMenu = tmConfig ^. lensOptions . lensShowMenu-  applicationWindowSetShowMenubar win showMenu--  windowSetTitle win "Termonad"-   -- This event will happen if the user requests that the top-level Termonad   -- window be closed through their window manager. It will also happen   -- normally when the user tries to close Termonad through normal methods,@@ -531,349 +249,57 @@         ResponseTypeYes -> False         _ -> True +setupTermonad :: TMConfig -> Application -> ApplicationWindow -> Gtk.Builder -> IO ()+setupTermonad tmConfig app win builder = do+  setupScreenStyle+  box <- objFromBuildUnsafe builder "content_box" Box+  fontDesc <- createFontDescFromConfig tmConfig+  note <- notebookNew+  widgetSetCanFocus note False+  -- If this is not set to False, then there will be a one pixel white border+  -- shown around the notebook.+  notebookSetShowBorder note False+  boxPackStart box note True True 0++  (mvarTMState, tmWinId) <- newEmptyTMState tmConfig app win note fontDesc+  terminal <- createTerm handleKeyPress mvarTMState tmWinId++  setupAppCallbacks mvarTMState tmConfig app win note tmWinId+  setupWindowCallbacks mvarTMState app win note tmWinId++  menuBuilder <- builderNewFromString menuText $ fromIntegral (Text.length menuText)+  menuModel <- objFromBuildUnsafe menuBuilder "menubar" MenuModel+  applicationSetMenubar app (Just menuModel)+  let showMenu = tmConfig ^. lensOptions . lensShowMenu+  applicationWindowSetShowMenubar win showMenu++  windowSetTitle win "Termonad"+   widgetShowAll win   widgetGrabFocus $ terminal ^. lensTerm  appActivate :: TMConfig -> Application -> IO () appActivate tmConfig app = do+  let img = $(embedFile "img/termonad-lambda.png")+  iconPixbuf <- imgToPixbuf img+  windowSetDefaultIcon iconPixbuf   uiBuilder <--    builderNewFromString interfaceText $ fromIntegral (length interfaceText)+    builderNewFromString interfaceText $ fromIntegral (Text.length interfaceText)   builderSetApplication uiBuilder app   appWin <- objFromBuildUnsafe uiBuilder "appWin" ApplicationWindow   applicationAddWindow app appWin   setupTermonad tmConfig app appWin uiBuilder   windowPresent appWin -showAboutDialog :: Application -> IO ()-showAboutDialog app = do-  win <- applicationGetActiveWindow app-  aboutDialog <- aboutDialogNew-  windowSetTransientFor aboutDialog win-  void $ dialogRun aboutDialog-  widgetDestroy aboutDialog--showFindDialog :: Application -> IO (Maybe Text)-showFindDialog app = do-  win <- applicationGetActiveWindow app-  dialog <- dialogNew-  box <- dialogGetContentArea dialog-  grid <- gridNew--  searchForLabel <- labelNew (Just "Search for regex:")-  containerAdd grid searchForLabel-  widgetShow searchForLabel-  setWidgetMargin searchForLabel 10--  searchEntry <- entryNew-  gridAttachNextTo grid searchEntry (Just searchForLabel) PositionTypeRight 1 1-  widgetShow searchEntry-  setWidgetMargin searchEntry 10-  -- setWidgetMarginBottom searchEntry 20-  void $-    onEntryActivate searchEntry $-      dialogResponse dialog (fromIntegral (fromEnum ResponseTypeYes))--  void $-    dialogAddButton-      dialog-      "Close"-      (fromIntegral (fromEnum ResponseTypeNo))-  void $-    dialogAddButton-      dialog-      "Find"-      (fromIntegral (fromEnum ResponseTypeYes))--  containerAdd box grid-  widgetShow grid-  windowSetTransientFor dialog win-  res <- dialogRun dialog--  searchString <- entryGetText searchEntry-  let maybeSearchString =-        case toEnum (fromIntegral res) of-          ResponseTypeYes -> Just searchString-          _ -> Nothing--  widgetDestroy dialog--  pure maybeSearchString--doFind :: TMState -> IO ()-doFind mvarTMState = do-  tmState <- readMVar mvarTMState-  let app = tmStateApp tmState-  maybeSearchString <- showFindDialog app-  -- putStrLn $ "trying to find: " <> tshow maybeSearchString-  maybeTerminal <- getFocusedTermFromState mvarTMState-  case (maybeSearchString, maybeTerminal) of-    (Just searchString, Just terminal) -> do-      -- TODO: Figure out how to import the correct pcre flags.-      ---      -- If you don't pass the pcre2Multiline flag, VTE gives-      -- the following warning:-      ---      -- (termonad-linux-x86_64:18792): Vte-WARNING **:-      -- 21:56:31.193: (vtegtk.cc:2269):void-      -- vte_terminal_search_set_regex(VteTerminal*,-      -- VteRegex*, guint32): runtime check failed:-      -- (regex == nullptr ||-      -- _vte_regex_get_compile_flags(regex) & PCRE2_MULTILINE)-      ---      -- However, if you do add the pcre2Multiline flag,-      -- the terminalSearchSetRegex appears to just completely-      -- not work.-      let pcreFlags = 0-      let newRegex =-            regexNewForSearch-              searchString-              (fromIntegral $ length searchString)-              pcreFlags-      eitherRegex <--        catchRegexError-          (fmap Right newRegex)-          (\_ errMsg -> pure (Left errMsg))-      case eitherRegex of-        Left errMsg -> do-          let msg = "error when creating regex: " <> errMsg-          hPutStrLn stderr msg-        Right regex -> do-          terminalSearchSetRegex terminal (Just regex) pcreFlags-          terminalSearchSetWrapAround terminal True-          _matchFound <- terminalSearchFindPrevious terminal-          -- TODO: Setup an actual logging framework to show these-          -- kinds of log messages.  Also make a similar change in-          -- findAbove and findBelow.-          -- putStrLn $ "was match found: " <> tshow matchFound-          pure ()-    _ -> pure ()--findAbove :: TMState -> IO ()-findAbove mvarTMState = do-  maybeTerminal <- getFocusedTermFromState mvarTMState-  case maybeTerminal of-    Nothing -> pure ()-    Just terminal -> do-      _matchFound <- terminalSearchFindPrevious terminal-      -- putStrLn $ "was match found: " <> tshow matchFound-      pure ()--findBelow :: TMState -> IO ()-findBelow mvarTMState = do-  maybeTerminal <- getFocusedTermFromState mvarTMState-  case maybeTerminal of-    Nothing -> pure ()-    Just terminal -> do-      _matchFound <- terminalSearchFindNext terminal-      -- putStrLn $ "was match found: " <> tshow matchFound-      pure ()--setShowMenuBar :: Application -> Bool -> IO ()-setShowMenuBar app visible = do-  void $ runMaybeT $ do-    win <- MaybeT $ applicationGetActiveWindow app-    appWin <- MaybeT $ castTo ApplicationWindow win-    lift $ applicationWindowSetShowMenubar appWin visible---- | Fill a combo box with ids and labels------ The ids are stored in the combobox as 'Text', so their type should be an--- instance of the 'Show' type class.-comboBoxFill :: forall a. Show a => ComboBoxText -> [(a, Text)] -> IO ()-comboBoxFill comboBox = mapM_ go-  where-    go :: (a, Text) -> IO ()-    go (value, textId) =-      comboBoxTextAppend comboBox (Just $ tshow value) textId---- | Set the current active item in a combobox given an input id.-comboBoxSetActive :: Show a => ComboBoxText -> a -> IO ()-comboBoxSetActive cb item = void $ comboBoxSetActiveId cb (Just $ tshow item)---- | Get the current active item in a combobox------ The list of values to be searched in the combobox must be given as a--- parameter. These values are converted to Text then compared to the current--- id.-comboBoxGetActive-  :: forall a. (Show a, Enum a) => ComboBoxText -> [a] -> IO (Maybe a)-comboBoxGetActive cb values = findEnumFromMaybeId <$> comboBoxGetActiveId cb-  where-    findEnumFromMaybeId :: Maybe Text -> Maybe a-    findEnumFromMaybeId maybeId = maybeId >>= findEnumFromId--    findEnumFromId :: Text -> Maybe a-    findEnumFromId label = find (\x -> tshow x == label) values--applyNewPreferences :: TMState -> IO ()-applyNewPreferences mvarTMState = do-  tmState <- readMVar mvarTMState-  let appWin = tmState ^. lensTMStateAppWin-      config = tmState ^. lensTMStateConfig-      notebook = tmState ^. lensTMStateNotebook . lensTMNotebook-      tabFocusList = tmState ^. lensTMStateNotebook . lensTMNotebookTabs-      showMenu = config  ^. lensOptions . lensShowMenu-  applicationWindowSetShowMenubar appWin showMenu-  setShowTabs config notebook-  -- Sets the remaining preferences to each tab-  foldMap (applyNewPreferencesToTab mvarTMState) tabFocusList--applyNewPreferencesToTab :: TMState -> TMNotebookTab -> IO ()-applyNewPreferencesToTab mvarTMState tab = do-  tmState <- readMVar mvarTMState-  let fontDesc = tmState ^. lensTMStateFontDesc-      term = tab ^. lensTMNotebookTabTerm . lensTerm-      scrolledWin = tab ^. lensTMNotebookTabTermContainer-      options = tmState ^. lensTMStateConfig . lensOptions-  terminalSetFont term (Just fontDesc)-  terminalSetCursorBlinkMode term (cursorBlinkMode options)-  terminalSetWordCharExceptions term (wordCharExceptions options)-  terminalSetScrollbackLines term (fromIntegral (scrollbackLen options))-  terminalSetBoldIsBright term (boldIsBright options)-  terminalSetEnableSixelIfExists term (enableSixel options)-  terminalSetAllowBold term (allowBold options)--  let vScrollbarPolicy = showScrollbarToPolicy (options ^. lensShowScrollbar)-  scrolledWindowSetPolicy scrolledWin PolicyTypeAutomatic vScrollbarPolicy---- | Show the preferences dialog.------ When the user clicks on the Ok button, it copies the new settings to TMState.--- Then apply them to the current terminals.-showPreferencesDialog :: TMState -> IO ()-showPreferencesDialog mvarTMState = do-  -- Get app out of mvar-  tmState <- readMVar mvarTMState-  let app = tmState ^. lensTMStateApp--  -- Create the preference dialog and get some widgets-  preferencesBuilder <--    builderNewFromString preferencesText $ fromIntegral (length preferencesText)-  preferencesDialog <--    objFromBuildUnsafe preferencesBuilder "preferences" Dialog-  confirmExitCheckButton <--    objFromBuildUnsafe preferencesBuilder "confirmExit" CheckButton-  showMenuCheckButton <--    objFromBuildUnsafe preferencesBuilder "showMenu" CheckButton-  boldIsBrightCheckButton <--    objFromBuildUnsafe preferencesBuilder "boldIsBright" CheckButton-  enableSixelCheckButton <--    objFromBuildUnsafe preferencesBuilder "enableSixel" CheckButton-  allowBoldCheckButton <--    objFromBuildUnsafe preferencesBuilder "allowBold" CheckButton-  wordCharExceptionsEntryBuffer <--    objFromBuildUnsafe preferencesBuilder "wordCharExceptions" Entry >>=-      getEntryBuffer-  fontButton <- objFromBuildUnsafe preferencesBuilder "font" FontButton-  showScrollbarComboBoxText <--    objFromBuildUnsafe preferencesBuilder "showScrollbar" ComboBoxText-  comboBoxFill-    showScrollbarComboBoxText-    [ (ShowScrollbarNever, "Never")-    , (ShowScrollbarAlways, "Always")-    , (ShowScrollbarIfNeeded, "If needed")-    ]-  showTabBarComboBoxText <--    objFromBuildUnsafe preferencesBuilder "showTabBar" ComboBoxText-  comboBoxFill-    showTabBarComboBoxText-    [ (ShowTabBarNever, "Never")-    , (ShowTabBarAlways, "Always")-    , (ShowTabBarIfNeeded, "If needed")-    ]-  cursorBlinkModeComboBoxText <--    objFromBuildUnsafe preferencesBuilder "cursorBlinkMode" ComboBoxText-  comboBoxFill-    cursorBlinkModeComboBoxText-    [ (CursorBlinkModeSystem, "System")-    , (CursorBlinkModeOn, "On")-    , (CursorBlinkModeOff, "Off")-    ]-  scrollbackLenSpinButton <--    objFromBuildUnsafe preferencesBuilder "scrollbackLen" SpinButton-  adjustmentNew 0 0 (fromIntegral (maxBound :: Int)) 1 10 0 >>=-    spinButtonSetAdjustment scrollbackLenSpinButton-  warningLabel <- objFromBuildUnsafe preferencesBuilder "warning" Label--  -- We show the warning label only if the user has launched termonad with a-  -- termonad.hs file-  executablePath <- getExecutablePath-  let hasTermonadHs = takeFileName executablePath == "termonad-linux-x86_64"-  widgetSetVisible warningLabel hasTermonadHs--  -- Make the dialog modal-  maybeWin <- applicationGetActiveWindow app-  windowSetTransientFor preferencesDialog maybeWin--  -- Init with current state-  fontChooserSetFontDesc fontButton (tmState ^. lensTMStateFontDesc)-  let options = tmState ^. lensTMStateConfig . lensOptions-  comboBoxSetActive showScrollbarComboBoxText $ showScrollbar options-  comboBoxSetActive showTabBarComboBoxText $ showTabBar options-  comboBoxSetActive cursorBlinkModeComboBoxText $ cursorBlinkMode options-  spinButtonSetValue scrollbackLenSpinButton (fromIntegral $ scrollbackLen options)-  toggleButtonSetActive confirmExitCheckButton $ confirmExit options-  toggleButtonSetActive showMenuCheckButton $ showMenu options-  toggleButtonSetActive boldIsBrightCheckButton $ boldIsBright options-  toggleButtonSetActive enableSixelCheckButton $ enableSixel options-  toggleButtonSetActive allowBoldCheckButton $ allowBold options-  entryBufferSetText wordCharExceptionsEntryBuffer (wordCharExceptions options) (-1)--  -- Run dialog then close-  res <- dialogRun preferencesDialog--  -- When closing the dialog get the new settings-  when (toEnum (fromIntegral res) == ResponseTypeAccept) $ do-    maybeFontDesc <- fontChooserGetFontDesc fontButton-    maybeFontConfig <--      join <$> mapM fontConfigFromFontDescription maybeFontDesc-    maybeShowScrollbar <--      comboBoxGetActive showScrollbarComboBoxText [ShowScrollbarNever ..]-    maybeShowTabBar <--      comboBoxGetActive showTabBarComboBoxText [ShowTabBarNever ..]-    maybeCursorBlinkMode <--      comboBoxGetActive cursorBlinkModeComboBoxText [CursorBlinkModeSystem ..]-    scrollbackLenVal <--      fromIntegral <$> spinButtonGetValueAsInt scrollbackLenSpinButton-    confirmExitVal <- toggleButtonGetActive confirmExitCheckButton-    showMenuVal <- toggleButtonGetActive showMenuCheckButton-    boldIsBrightVal <- toggleButtonGetActive boldIsBrightCheckButton-    enableSixelVal <- toggleButtonGetActive enableSixelCheckButton-    allowBoldVal <- toggleButtonGetActive allowBoldCheckButton-    wordCharExceptionsVal <- entryBufferGetText wordCharExceptionsEntryBuffer--    -- Apply the changes to mvarTMState-    modifyMVar_ mvarTMState $ pure-      . over lensTMStateFontDesc (`fromMaybe` maybeFontDesc)-      . over (lensTMStateConfig . lensOptions)-        ( set lensConfirmExit confirmExitVal-        . set lensShowMenu showMenuVal-        . set lensBoldIsBright boldIsBrightVal-        . set lensEnableSixel enableSixelVal-        . set lensAllowBold allowBoldVal-        . set lensWordCharExceptions wordCharExceptionsVal-        . over lensFontConfig (`fromMaybe` maybeFontConfig)-        . set lensScrollbackLen scrollbackLenVal-        . over lensShowScrollbar (`fromMaybe` maybeShowScrollbar)-        . over lensShowTabBar (`fromMaybe` maybeShowTabBar)-        . over lensCursorBlinkMode (`fromMaybe` maybeCursorBlinkMode)-        )--    -- Save the changes to the preferences files-    withMVar mvarTMState $ saveToPreferencesFile . view lensTMStateConfig--    -- Update the app with new settings-    applyNewPreferences mvarTMState--  widgetDestroy preferencesDialog- appStartup :: Application -> IO () appStartup _app = pure ()  -- | Run Termonad with the given 'TMConfig'. ----- Do not perform any of the recompilation operations that the 'defaultMain'+-- Do not perform any of the recompilation operations that the 'Termonad.Startup.defaultMain' -- function does.+--+-- This function __does not__ parse command line arguments. start :: TMConfig -> IO () start tmConfig = do   -- app <- appNew (Just "haskell.termonad") [ApplicationFlagsFlagsNone]@@ -882,81 +308,3 @@   void $ onApplicationStartup app (appStartup app)   void $ onApplicationActivate app (appActivate tmConfig app)   void $ applicationRun app Nothing---- | Run Termonad with the given 'TMConfig'.------ This function will check if there is a @~\/.config\/termonad\/termonad.hs@ file--- and a @~\/.cache\/termonad\/termonad-linux-x86_64@ binary.  Termonad will--- perform different actions based on whether or not these two files exist.------ Here are the four different possible actions based on the existence of these--- two files.------ - @~\/.config\/termonad\/termonad.hs@ exists, @~\/.cache\/termonad\/termonad-linux-x86_64@ exists------     The timestamps of these two files are checked.  If the---     @~\/.config\/termonad\/termonad.hs@ file has been modified after the---     @~\/.cache\/termonad\/termonad-linux-x86_64@ binary, then Termonad will use---     GHC to recompile the @~\/.config\/termonad\/termonad.hs@ file, producing a---     new binary at @~\/.cache\/termonad\/termonad-linux-x86_64@.  This new binary---     will be re-executed.  The 'TMConfig' passed to this 'defaultMain' will be---     effectively thrown away.------     If GHC fails to recompile the @~\/.config\/termonad\/termonad.hs@ file, then---     Termonad will just execute 'start' with the 'TMConfig' passed in.------     If the @~\/.cache\/termonad\/termonad-linux-x86_64@ binary has been modified---     after the @~\/.config\/termonad\/termonad.hs@ file, then Termonad will---     re-exec the @~\/.cache\/termonad\/termonad-linux-x86_64@ binary.  The---     'TMConfig' passed to this 'defaultMain' will be effectively thrown away.------ - @~\/.config\/termonad\/termonad.hs@ exists, @~\/.cache\/termonad\/termonad-linux-x86_64@ does not exist------     Termonad will use GHC to recompile the @~\/.config\/termonad\/termonad.hs@---     file, producing a new binary at @~\/.cache\/termonad\/termonad-linux-x86_64@.---     This new binary will be re-executed.  The 'TMConfig' passed to this---     'defaultMain' will be effectively thrown away.------     If GHC fails to recompile the @~\/.config\/termonad\/termonad.hs@ file, then---     Termonad will just execute 'start' with the 'TMConfig' passed in.------ - @~\/.config\/termonad\/termonad.hs@ does not exist, @~\/.cache\/termonad\/termonad-linux-x86_64@ exists------     Termonad will ignore the @~\/.cache\/termonad\/termonad-linux-x86_64@ binary---     and just run 'start' with the 'TMConfig' passed to this function.------ - @~\/.config\/termonad\/termonad.hs@ does not exist, @~\/.cache\/termonad\/termonad-linux-x86_64@ does not exist------     Termonad will run 'start' with the 'TMConfig' passed to this function.------ Other notes:------ 1. That the locations of @~\/.config\/termonad\/termonad.hs@ and---    @~\/.cache\/termonad\/termonad-linux-x86_64@ may differ depending on your---    system.------ 2. In your own @~\/.config\/termonad\/termonad.hs@ file, you can use either---    'defaultMain' or 'start'.  As long as you always execute the system-wide---    @termonad@ binary (instead of the binary produced as---    @~\/.cache\/termonad\/termonad-linux-x86_64@), the effect should be the same.-defaultMain :: TMConfig -> IO ()-defaultMain tmConfig = do-  let params =-        defaultParams-          { projectName = "termonad"-          , showError = \(cfg, oldErrs) newErr -> (cfg, oldErrs <> "\n" <> newErr)-          , realMain = \(cfg, errs) -> putStrLn (pack errs) *> start cfg-          }-  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/Cli.hs view
@@ -0,0 +1,434 @@+-- | Module    : Termonad.Cli+-- Description : Termonad CLI argument parsing module.+-- Copyright   : (c) Dennis Gosnell, 2023+-- License     : BSD3+-- Stability   : experimental+-- Portability : POSIX+--+-- This module exposes Termonad's CLI argument parsing functionality.+--+-- The main function for parsing CLI arguments is 'parseCliArgs'.  The function+-- that knows how to combine CLI arguments with normal 'ConfigOptions' is+-- 'applyCliArgs'.++module Termonad.Cli where++import Termonad.Prelude++import Control.Applicative ((<|>), (<**>))+import Data.Text (pack)+import GI.Vte (CursorBlinkMode)+import Options.Applicative (fullDesc, info, helper, progDesc, ParserInfo, execParser, Parser, Mod, OptionFields, option, str, value, short, long, metavar, help, ReadM, maybeReader, auto, flag')+import Termonad.Types (ConfigOptions (..), Option (Set, Unset), ShowScrollbar, FontSize (..), ShowTabBar, showScrollbarFromString, showTabBarFromString, cursorBlinkModeFromString, FontConfig (..))+++-- | A data type that contains arguments from the command line.+data CliArgs = CliArgs+  { cliConfigOptions :: CliConfigOptions+  , extraCliArgs :: ExtraCliArgs+  } deriving (Eq, Show)++-- | The default 'CliArgs'.  This corresponds to the value 'CliArgs' will+-- become when no CLI arguments have been passed.+--+-- >>> :{+--   let defCliArgs =+--         CliArgs+--           { cliConfigOptions = defaultCliConfigOptions+--           , extraCliArgs = defaultExtraCliArgs+--           }+--   in defaultCliArgs == defCliArgs+-- :}+-- True+defaultCliArgs :: CliArgs+defaultCliArgs =+  CliArgs+    { cliConfigOptions = defaultCliConfigOptions+    , extraCliArgs = defaultExtraCliArgs+    }++-- | CLI arguments that correspond to fields in 'ConfigOptions'.+--+-- See 'ConfigOptions' for what each of these options mean.+data CliConfigOptions = CliConfigOptions+  { cliConfFontFamily :: !(Option Text)+  , cliConfFontSize :: !(Option FontSize)+  , cliConfShowScrollbar :: !(Option ShowScrollbar)+  , cliConfScrollbackLen :: !(Option Integer)+  , cliConfConfirmExit :: !(Option Bool)+  , cliConfWordCharExceptions :: !(Option Text)+  , cliConfShowMenu :: !(Option Bool)+  , cliConfShowTabBar :: !(Option ShowTabBar)+  , cliConfCursorBlinkMode :: !(Option CursorBlinkMode)+  , cliConfBoldIsBright :: !(Option Bool)+  , cliConfEnableSixel :: !(Option Bool)+  , cliConfAllowBold :: !(Option Bool)+  } deriving (Eq, Show)++-- | The default 'CliConfigOptions'.  All 'Option's are 'Unset', which means+-- they won't override options from 'ConfigOptions' in 'applyCliArgs'.+--+-- >>> :{+--   let defCliConfOpt =+--         CliConfigOptions+--           { cliConfFontFamily = Unset+--           , cliConfFontSize = Unset+--           , cliConfShowScrollbar = Unset+--           , cliConfScrollbackLen = Unset+--           , cliConfConfirmExit = Unset+--           , cliConfWordCharExceptions = Unset+--           , cliConfShowMenu = Unset+--           , cliConfShowTabBar = Unset+--           , cliConfCursorBlinkMode = Unset+--           , cliConfBoldIsBright = Unset+--           , cliConfEnableSixel = Unset+--           , cliConfAllowBold = Unset+--           }+--   in defaultCliConfigOptions == defCliConfOpt+-- :}+-- True+defaultCliConfigOptions :: CliConfigOptions+defaultCliConfigOptions =+  CliConfigOptions+    { cliConfFontFamily = Unset+    , cliConfFontSize = Unset+    , cliConfShowScrollbar = Unset+    , cliConfScrollbackLen = Unset+    , cliConfConfirmExit = Unset+    , cliConfWordCharExceptions = Unset+    , cliConfShowMenu = Unset+    , cliConfShowTabBar = Unset+    , cliConfCursorBlinkMode = Unset+    , cliConfBoldIsBright = Unset+    , cliConfEnableSixel = Unset+    , cliConfAllowBold = Unset+    }++-- | Extra CLI arguments for values that don't make sense in 'ConfigOptions'.+data ExtraCliArgs = ExtraCliArgs+  deriving (Eq, Show)++-- | The default 'ExtraCliArgs'.+--+-- >>> :{+--   let defExtraCliArgs =+--         ExtraCliArgs+--   in defaultExtraCliArgs == defExtraCliArgs+-- :}+-- True+defaultExtraCliArgs :: ExtraCliArgs+defaultExtraCliArgs = ExtraCliArgs++-- | Similar to 'Options.Applicative.strOption', but specifically work on a+-- value that is an 'Option'.+strOption' :: IsString s => Mod OptionFields (Option s) -> Parser (Option s)+strOption' mods = option (fmap Set str) (value Unset <> mods)++-- | Similar to 'Options.Applicative.option', but specifically work on a+-- value that is an 'Option'.+option' :: ReadM a -> Mod OptionFields (Option a) -> Parser (Option a)+option' readM mods = option (fmap Set readM) (value Unset <> mods)++-- | Similar to 'Options.Applicative.maybeReader', but work on 'Text' instead+-- of 'String'.+maybeTextReader :: (Text -> Maybe a) -> ReadM a+maybeTextReader f = maybeReader (f . pack)++-- | Helper for making a 'flag' CLI argument that optionally takes a @no-@ prefix.+--+-- Example:+--+-- > 'optionFlag' 'True' 'False' 'f' 'n' "foo" "Does foo" "Does not do foo" :: Parser (Option Bool)+--+-- This creates a 'Parser' that accepts both a @--foo@ and a @--no-foo@ flag.+-- Passing @--foo@ returns @'Set' 'True'@, while passing @--no-foo@ returns+-- @'Set' 'False'@.  Passing neither @--foo@ nor @--no-foo@ returns 'Unset'.+--+-- TODO: This doesn't quite work.  If the user passes both @--foo@ and+-- @--no-foo@ flags, this should ideally take the value of the last flag+-- passed.  However, it appears that if you pass both flags, the second+-- flag is just not recognized and optparse-applicative raises an error.+optionFlag+  :: a -- ^ Value when specified /without/ @no-@ prefix.+  -> a -- ^ Value when specified /with/ @no-@ prefix.+  -> Char -- ^ Short flag for /without/ @no-@ prefix.+  -> Char -- ^ Short flag for /with/ @no-@ prefix.+  -> String -- ^ Long flag.+  -> String -- ^ Help text for /without/ @no-@ prefix option.+  -> String -- ^ Help text for /with/ @no-@ prefix option.+  -> Parser (Option a)+optionFlag valNormal valNo shortNormal shortNo longFlag helpNormal helpNo =+  flagNormal <|> flagNo <|> pure Unset+  where+    flagNormal =+      flag' (Set valNormal) (short shortNormal <> long longFlag <> help helpNormal)+    flagNo =+      flag' (Set valNo) (short shortNo <> long ("no-" <> longFlag) <> help helpNo)++cliConfigOptionsParser :: Parser CliConfigOptions+cliConfigOptionsParser =+  CliConfigOptions+    <$> fontFamilyParser+    <*> fontSizeParser+    <*> showScrollbarParser+    <*> scrollbackLenParser+    <*> confirmExitParser+    <*> wordCharExceptionsParser+    <*> showMenuParser+    <*> showTabBarParser+    <*> cursorBlinkModeParser+    <*> boldIsBrightParser+    <*> enableSixelParser+    <*> allowBoldParser++fontFamilyParser :: Parser (Option Text)+fontFamilyParser =+  strOption'+    ( short 'f' <>+      long "font-family" <>+      metavar "FONT_FAMILY" <>+      help+        "Font family to use. Defaults to \"Monospace\". Examples: \+        \\"DejaVu Sans Mono\", \"Source Code Pro\""+    )++fontSizeParser :: Parser (Option FontSize)+fontSizeParser = f <$> pointsParser <*> unitsParser+  where+    f :: Option Int -> Option Double -> Option FontSize+    f optionPoints optionUnits =+      case (fmap FontSizePoints optionPoints, fmap FontSizeUnits optionUnits) of+        (Unset, units) -> units+        (points, _) -> points++    pointsParser :: Parser (Option Int)+    pointsParser =+      option'+        auto+        ( short 'p' <>+          long "font-size-points" <>+          metavar "POINTS" <>+          help+            "Font size in POINTS. Defaults to \"12\" if not specified. \+            \If you specify both --font-size-points and --font-size-units, \+            \--font-size-points will take priority.  --font-size-points \+            \should be similar to font sizes you may be \+            \familiar with from other applications."+        )++    unitsParser :: Parser (Option Double)+    unitsParser =+      option'+        auto+        ( short 'u' <>+          long "font-size-units" <>+          metavar "UNITS" <>+          help+            "Font size in device units/pixels. Example: \"20.5\", \+            \\"30\".  If not specified, the default from \+            \--font-size-points is used."+        )++showScrollbarParser :: Parser (Option ShowScrollbar)+showScrollbarParser =+  option'+    (maybeTextReader showScrollbarFromString)+    ( short 'l' <>+      long "show-scrollbar" <>+      metavar "SHOW_SCROLLBAR" <>+      help+        "Whether or not to show a scrollbar in the terminal. \+        \Defaults to \"if-needed\".  Possible values = \"never\": \+        \never show the scrollbar, \"always\": always show the \+        \scrollbar, \"if-needed\": only show the scrollbar if \+        \enough text on the screen"+    )++scrollbackLenParser :: Parser (Option Integer)+scrollbackLenParser =+  option'+    auto+    ( short 'b' <>+      long "scrollback-length" <>+      metavar "SCROLLBACK_LENGTH" <>+      help+        "Number of lines to keep in the scrollback buffer in the \+        \terminal.  Defaults to 10000 lines.  Examples: \"200\", \+        \\"3000\""+    )++confirmExitParser :: Parser (Option Bool)+confirmExitParser =+  optionFlag+    True+    False+    'x'+    'C'+    "confirm-exit"+    "Ask for confirmation when closing terminals or Termonad itself. \+    \Defaults to asking for confirmation if not specified."+    "Do not ask for confirmation when closing terminals or Termonad \+    \itself. Defaults to asking for confirmation if not specified."++wordCharExceptionsParser :: Parser (Option Text)+wordCharExceptionsParser =+  strOption'+    ( short 'w' <>+      long "word-char-exceptions" <>+      metavar "EXCEPTIONS" <>+      help+        "The characters in this list will be counted as part of a word \+        \when double-clicking to select text in the terminal. Defaults \+        \to \"-#%&+,./=?@\\_~:\""+    )++showMenuParser :: Parser (Option Bool)+showMenuParser =+  optionFlag+    True+    False+    'm'+    'u'+    "show-menu"+    "Show the menu bar.  Defaults to showing the menu bar when not \+    \specified."+    "Do not show the menu bar.  Defaults to showing the menu bar when \+    \not specified."++showTabBarParser :: Parser (Option ShowTabBar)+showTabBarParser =+  option'+    (maybeTextReader showTabBarFromString)+    ( short 'l' <>+      long "show-tab-bar" <>+      metavar "SHOW_TAB_BAR" <>+      help+        "Whether or not to show the tab bar in the terminal. \+        \Defaults to \"if-needed\".  Possible values = \"never\": \+        \never show the tab bar, \"always\": always show the \+        \tab bar, \"if-needed\": only show the tab bar if \+        \multiple tabs are open."+    )++cursorBlinkModeParser :: Parser (Option CursorBlinkMode)+cursorBlinkModeParser =+  option'+    (maybeTextReader cursorBlinkModeFromString)+    ( short 'n' <>+      long "cursor-blink" <>+      metavar "BLINK_MODE" <>+      help+        "How to handle cursor blink.  Defaults to \"on\". Possible \+        \values = \"system\": follow system settings, \"on\": cursor \+        \blinks, \"off\": no cursor blink."+    )++boldIsBrightParser :: Parser (Option Bool)+boldIsBrightParser =+  optionFlag+    True+    False+    'd'+    'r'+    "bold-is-bright"+    "Force bold text to use bright colors.  Defaults to not forcing \+    \bold text to use bright colors."+    "Do not force bold text to use bright colors.  Defaults to not forcing \+    \bold text to use bright colors."++enableSixelParser :: Parser (Option Bool)+enableSixelParser =+  optionFlag+    True+    False+    's'+    'i'+    "sixel"+    "Enable SIXEL support.  Note that you need to build Termonad with \+    \a VTE with SIXEL support for this to work.  Defaults to not \+    \enabling SIXEL."+    "Disable SIXEL support.  Defaults to disabling SIXEL support."++allowBoldParser :: Parser (Option Bool)+allowBoldParser =+  optionFlag+    True+    False+    'a'+    'o'+    "allow-bold"+    "Allow Termonad to show bold text.  Defaults to enabled."+    "Disable Termonad from showing text as bold.  Defaults to \+    \allow showing text as bold."++extraCliArgsParser :: Parser ExtraCliArgs+extraCliArgsParser = pure ExtraCliArgs++cliArgsParser :: Parser CliArgs+cliArgsParser =+  CliArgs <$> cliConfigOptionsParser <*> extraCliArgsParser++cliArgsParserInfo :: ParserInfo CliArgs+cliArgsParserInfo =+  info+    (cliArgsParser <**> helper)+    ( fullDesc <>+      progDesc "A VTE-based terminal emulator configurable in Haskell"+    )++-- | Parse and return CliArguments.+parseCliArgs :: IO CliArgs+parseCliArgs = execParser cliArgsParserInfo++-- | Overwrite the arguments in 'ConfigOptions' that have been 'Set' in+-- 'CliArgs'.+--+-- >>> import Termonad.Types (defaultConfigOptions)+-- >>> let cliConfOpts = defaultCliConfigOptions { cliConfScrollbackLen = Set 50 }+-- >>> let cliArgs = defaultCliArgs { cliConfigOptions = cliConfOpts }+-- >>> let overwrittenConfOpts = defaultConfigOptions { scrollbackLen = 50 }+-- >>> applyCliArgs cliArgs defaultConfigOptions == overwrittenConfOpts+-- True+applyCliArgs :: CliArgs -> ConfigOptions -> ConfigOptions+applyCliArgs cliArgs confOpts =+  let oldFontConf = fontConfig confOpts+      newFontConfig =+        oldFontConf+          { fontFamily =+              fromOption+                (fontFamily oldFontConf)+                (cliConfFontFamily cliConfOpts)+          , fontSize =+              fromOption+                (fontSize oldFontConf)+                (cliConfFontSize cliConfOpts)+          }+  in+  confOpts+    { fontConfig = newFontConfig+    , showScrollbar = fromOpt showScrollbar cliConfShowScrollbar+    , scrollbackLen = fromOpt scrollbackLen cliConfScrollbackLen+    , confirmExit = fromOpt confirmExit cliConfConfirmExit+    , wordCharExceptions = fromOpt wordCharExceptions cliConfWordCharExceptions+    , showMenu = fromOpt showMenu cliConfShowMenu+    , showTabBar = fromOpt showTabBar cliConfShowTabBar+    , cursorBlinkMode = fromOpt cursorBlinkMode cliConfCursorBlinkMode+    , boldIsBright = fromOpt boldIsBright cliConfBoldIsBright+    , enableSixel = fromOpt enableSixel cliConfEnableSixel+    , allowBold = fromOpt allowBold cliConfAllowBold+    }+  where+    fromOpt+      :: forall a. (ConfigOptions -> a) -> (CliConfigOptions -> Option a) -> a+    fromOpt getConfVal getCliVal =+      fromOption+        (getConfVal confOpts)+        (getCliVal cliConfOpts)++    fromOption :: forall b. b -> Option b -> b+    fromOption defVal = \case+      Set a -> a+      Unset -> defVal++    cliConfOpts :: CliConfigOptions+    cliConfOpts = cliConfigOptions cliArgs
src/Termonad/Config.hs view
@@ -21,10 +21,12 @@ -- --  main :: IO () --  main = 'start' $ 'defaultTMConfig'---    { 'showScrollbar' = 'ShowScrollbarNever'---    , 'confirmExit' = False---    , 'showMenu' = False---    , 'cursorBlinkMode' = 'CursorBlinkModeOff'+--    { 'options' = 'defaultConfigOptions'+--      { 'showScrollbar' = 'ShowScrollbarNever'+--      , 'confirmExit' = False+--      , 'showMenu' = False+--      , 'cursorBlinkMode' = 'CursorBlinkModeOff'+--      } --    } -- @ --@@ -59,5 +61,5 @@  import GI.Vte (CursorBlinkMode(..)) -import Termonad.PreferencesFile (tmConfigFromPreferencesFile)+import Termonad.Preferences (tmConfigFromPreferencesFile) import Termonad.Types
src/Termonad/Config/Colour.hs view
@@ -87,7 +87,7 @@     -- $setup   ) where -import Termonad.Prelude hiding ((\\), index)+import Termonad.Prelude  import Control.Lens ((%~), makeLensesFor) import Data.Colour@@ -124,9 +124,6 @@   , terminalSetColorHighlight   , terminalSetColorHighlightForeground   )-import Text.Printf (printf)-import Text.Show (showString)- import Termonad.Lenses (lensCreateTermHook, lensHooks) import Termonad.Types   ( Option(Unset)@@ -134,6 +131,7 @@   , TMState   , whenSet   )+import Text.Printf (printf)  -- $setup -- >>> import Data.Colour.Names (green, red)@@ -552,7 +550,7 @@     coef x = fromIntegral x / 5 -- | A matrix of a 6 x 6 x 6 color cube. Default value for 'ColourCubePalette'. ----- >>> putStrLn $ pack $ showColourCube defaultColourCube+-- >>> putStrLn $ showColourCube defaultColourCube -- [ [ #000000ff, #00005fff, #000087ff, #0000afff, #0000d7ff, #0000ffff --   , #005f00ff, #005f5fff, #005f87ff, #005fafff, #005fd7ff, #005fffff --   , #008700ff, #00875fff, #008787ff, #0087afff, #0087d7ff, #0087ffff@@ -660,6 +658,12 @@      showCol :: AlphaColour Double -> String -> String     showCol col str = sRGB32show col <> str++    -- A version of head that gives a better error message.+    headEx :: forall b. [b] -> b+    headEx = \case+      [] -> error "showColourCube: error in headEx, passed empty list, this is likely a logic error"+      (h : _) -> h  -- | A List of a grey scale.  Default value for 'FullPalette'. --
src/Termonad/Gtk.hs view
@@ -17,14 +17,16 @@  import Termonad.Prelude -import Control.Monad.Fail (MonadFail, fail) import Data.GI.Base (ManagedPtr, withManagedPtr)+import Data.Text (unpack) import GHC.Stack (HasCallStack) import GI.Gdk   ( GObject   , castTo   )-import GI.Gio (ApplicationFlags)+import GI.GdkPixbuf (Pixbuf, pixbufNewFromStream)+import GI.Gio (ApplicationFlags, Cancellable)+import GI.Gio.Objects.MemoryInputStream (memoryInputStreamNewFromData) import GI.Gtk (Application, IsWidget, Widget(Widget), applicationNew, builderGetObject, toWidget) import qualified GI.Gtk as Gtk import GI.Vte@@ -33,22 +35,18 @@   , terminalSetEnableSixel #endif   )-+import System.Exit (die)  objFromBuildUnsafe ::      GObject o => Gtk.Builder -> Text -> (ManagedPtr o -> o) -> IO o objFromBuildUnsafe builder name constructor = do   maybePlainObj <- builderGetObject builder name   case maybePlainObj of-    Nothing -> error $ "Couldn't get " <> unpack name <> " from builder!"+    Nothing -> error $ unpack $ "Couldn't get " <> name <> " from builder!"     Just plainObj -> do       maybeNewObj <- castTo constructor plainObj       case maybeNewObj of-        Nothing ->-          error $-            "Got " <>-            unpack name <>-            " from builder, but couldn't convert to object!"+        Nothing -> error $ unpack $ "Got " <> name <> " from builder, but couldn't convert to object!"         Just obj -> pure obj  -- | Unsafely creates a new 'Application'.  This calls 'fail' if it cannot@@ -93,3 +91,15 @@   terminalSetEnableSixel t b #endif   pure ()++-- | Load an image in a 'ByteString' into a 'Pixbuf'.+--+-- Supports all image types that 'pixbufNewFromStream' supports.+imgToPixbuf :: ByteString -> IO Pixbuf+imgToPixbuf imgByteString = do+  inputStream <- memoryInputStreamNewFromData imgByteString Nothing+  maybePixbuf <- pixbufNewFromStream inputStream (Nothing :: Maybe Cancellable)+  case maybePixbuf of+    Nothing ->+      die "imgToPixbuf: Unexpected error when trying to convert an image to a Pixbuf"+    Just pixbuf -> pure pixbuf
+ src/Termonad/IdMap.hs view
@@ -0,0 +1,25 @@+-- | Module    : Termonad.IdMap+-- Description : A Map that keeps track of the ID of values+-- Copyright   : (c) Dennis Gosnell, 2023+-- License     : BSD3+-- Stability   : experimental+-- Portability : POSIX+--+-- An 'IdMap' is a combination between an 'IntMap' and a 'Set'.+--+-- An 'IdMap' allows adding an arbitrary number of things to be tracked.  It+-- returns an 'IdMapKey' whenever a new item is added to the set.  This+-- 'IdMapKey' can then be used to lookup items already in the set.++module Termonad.IdMap+  ( IdMapKey+  , IdMap+  , emptyIdMap+  , singletonIdMap+  , insertIdMap+  , lookupIdMap+  , keysIdMap+  , deleteIdMap+  ) where++import Termonad.IdMap.Internal
+ src/Termonad/IdMap/Internal.hs view
@@ -0,0 +1,165 @@+-- | Module    : Termonad.IdMap+-- Description : A Map that keeps track of the ID of values+-- Copyright   : (c) Dennis Gosnell, 2023+-- License     : BSD3+-- Stability   : experimental+-- Portability : POSIX++module Termonad.IdMap.Internal where++import Termonad.Prelude++import Control.Lens (FoldableWithIndex, ifoldMap, Index, IxValue, Traversal', Ixed (ix))+import qualified Data.Foldable as Foldable+import Data.IntMap.Strict (IntMap)+import qualified Data.IntMap.Strict as IntMap++newtype IdMapKey = IdMapKey { unIdMapKey :: Int }+  deriving stock (Eq, Show)++data IdMap a = IdMap+  { idMap :: !(IntMap a)+  , nextId :: !Int+  }+  deriving stock Show++-- | 'IdMap's are equal if they contain the same elements at the same keys.+--+-- >>> let (helloKey, idmapA) = insertIdMap "hello" emptyIdMap+-- >>> let (_, idmapB) = singletonIdMap "hello"+-- >>> idmapA == idmapB+-- True+--+-- Note that if you delete and reinsert a value, it will get a different key,+-- so will no longer be equal.+--+-- >>> let (_, idmapA') = insertIdMap "hello" $ deleteIdMap helloKey idmapA+-- >>> idmapA' == idmapB+-- False+--+-- However, 'IdMap's don't check the 'nextId' field when determining equality.+--+-- >>> let (byeKey, idmapA'') = insertIdMap "bye" idmapA+-- >>> let idmapA''' = deleteIdMap byeKey idmapA''+-- >>> idmapA''' == idmapB+-- True+instance Eq a => Eq (IdMap a) where+  (IdMap idMapA _) == (IdMap idMapB _) = idMapA == idMapB++instance Functor IdMap where+  fmap f IdMap{idMap, nextId} = IdMap { idMap = fmap f idMap, nextId }++instance Foldable IdMap where+  foldMap f m = Foldable.foldMap f $ idMap m++instance FoldableWithIndex Int IdMap where+  ifoldMap f m = ifoldMap f $ idMap m++instance Traversable IdMap where+  traverse f IdMap{idMap, nextId} =+    fmap (\m -> IdMap { idMap = m, nextId }) (traverse f idMap)++type instance Index (IdMap a) = IdMapKey+type instance IxValue (IdMap a) = a++instance Ixed (IdMap a) where+  ix :: IdMapKey -> Traversal' (IdMap a) a+  ix (IdMapKey i) f IdMap{idMap, nextId} =+    case IntMap.lookup i idMap of+      Just v -> fmap update (f v) -- f v <&> \v' -> IntMap.insert k v' m+      Nothing -> pure IdMap{idMap, nextId}+    where+      update :: a -> IdMap a+      update v' =+        IdMap+          { idMap = IntMap.adjust (const v') i idMap+          , nextId+          }++initialId :: Int+initialId = 0++-- | Get the next available ID.+--+-- >>> succId 3+-- 4+succId :: Int -> Int+succId i = i + 1++-- | An initial 'IdMap' with no values.+--+-- >>> emptyIdMap+-- IdMap {idMap = fromList [], nextId = 0}+emptyIdMap :: IdMap a+emptyIdMap = IdMap { idMap = mempty, nextId = 0 }++-- | Insert a value into an 'IdMap'.  Returns the key for the newly inserted+-- item.+--+-- >>> let (key, idmap) = insertIdMap "hello" emptyIdMap+-- >>> (key, idmap)+-- (IdMapKey {unIdMapKey = 0},IdMap {idMap = fromList [(0,"hello")], nextId = 1})+--+-- >>> insertIdMap "zoom" idmap+-- (IdMapKey {unIdMapKey = 1},IdMap {idMap = fromList [(0,"hello"),(1,"zoom")], nextId = 2})+insertIdMap :: a -> IdMap a -> (IdMapKey, IdMap a)+insertIdMap a IdMap {idMap, nextId} =+  let newMap = IntMap.insert nextId a idMap+      newNextId = nextId + 1+  in (IdMapKey nextId, IdMap { idMap = newMap, nextId = newNextId })++-- | Create an 'IdMap' with a single value.+--+-- >>> singletonIdMap "hello"+-- (IdMapKey {unIdMapKey = 0},IdMap {idMap = fromList [(0,"hello")], nextId = 1})+--+-- prop> \a -> insertIdMap a emptyIdMap == singletonIdMap a+singletonIdMap :: a -> (IdMapKey, IdMap a)+singletonIdMap a = insertIdMap a emptyIdMap++-- | Lookup the given key in an 'IdMap'.+--+-- >>> let (key, idmap) = insertIdMap "hello" emptyIdMap+-- >>> lookupIdMap key idmap+-- Just "hello"+--+-- Trying to lookup keys that don't exist returns 'Nothing':+--+-- >>> let idmap' = deleteIdMap key idmap+-- >>> lookupIdMap key idmap'+-- Nothing+lookupIdMap :: IdMapKey -> IdMap a -> Maybe a+lookupIdMap (IdMapKey k) IdMap {idMap} = IntMap.lookup k idMap++-- | List all keys in an 'IdMap'.+--+-- >>> let (_, idmap) = singletonIdMap "hello"+-- >>> let (_, idmap') = insertIdMap "bye" idmap+-- >>> keysIdMap idmap'+-- [IdMapKey {unIdMapKey = 0},IdMapKey {unIdMapKey = 1}]+--+-- Returns the empty list when passed an empty 'IdMap':+--+-- >>> keysIdMap emptyIdMap+-- []+keysIdMap :: IdMap a -> [IdMapKey]+keysIdMap IdMap {idMap} = fmap IdMapKey $ IntMap.keys idMap++-- | Delete a key and its value from the map. When the key is not a member of+-- the map, the original map is returned.+--+-- >>> let (key, idmap) = singletonIdMap "hello"+-- >>> let (_, idmap') = insertIdMap "bye" idmap+-- >>> deleteIdMap key idmap'+-- IdMap {idMap = fromList [(1,"bye")], nextId = 2}+--+-- Deleting a key that does not exist just returns the old map:+--+-- >>> deleteIdMap key idmap'+-- IdMap {idMap = fromList [(1,"bye")], nextId = 2}+deleteIdMap :: IdMapKey -> IdMap a -> IdMap a+deleteIdMap (IdMapKey k) IdMap {idMap, nextId} =+  IdMap+    { idMap = IntMap.delete k idMap+    , nextId+    }
src/Termonad/Keys.hs view
@@ -4,6 +4,10 @@ import Termonad.Prelude  import Control.Lens (imap)+import Data.Map.Strict (Map)+import qualified Data.Map.Strict as Map+import Data.Set (Set)+import qualified Data.Set as Set import GI.Gdk   ( EventKey   , pattern KEY_0@@ -27,7 +31,7 @@   )  import Termonad.Term (altNumSwitchTerm)-import Termonad.Types (TMState)+import Termonad.Types (TMState, TMWindowId)   showKeys :: EventKey -> IO Bool@@ -41,28 +45,29 @@   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 $ "  type = " <> show eventType+  putStrLn $ "  str = " <> show maybeString+  putStrLn $ "  mods = " <> show modifiers+  putStrLn $ "  isMod = " <> show isMod+  putStrLn $ "  len = " <> show len+  putStrLn $ "  keyval = " <> show keyval+  putStrLn $ "  keycode = " <> show keycode   putStrLn ""    pure True  data Key = Key-  { keyVal :: Word32-  , keyMods :: Set ModifierType+  { keyVal :: !Word32+  , keyMods :: !(Set ModifierType)   } deriving (Eq, Ord, Show)  toKey :: Word32 -> Set ModifierType -> Key toKey = Key -keyMap :: Map Key (TMState -> IO Bool)+keyMap :: Map Key (TMState -> TMWindowId -> IO Bool) keyMap =-  let numKeys =+  let numKeys :: [Word32]+      numKeys =         [ KEY_1         , KEY_2         , KEY_3@@ -74,6 +79,7 @@         , KEY_9         , KEY_0         ]+      altNumKeys :: [(Key, TMState -> TMWindowId -> IO Bool)]       altNumKeys =         imap           (\i k ->@@ -81,14 +87,15 @@           )           numKeys   in-  mapFromList altNumKeys+  Map.fromList altNumKeys -stopProp :: (TMState -> IO a) -> TMState -> IO Bool-stopProp callback terState = callback terState $> True+stopProp :: (TMState -> TMWindowId -> IO a) -> TMState -> TMWindowId -> IO Bool+stopProp callback terState tmWinId = callback terState tmWinId $> True  removeStrangeModifiers :: Key -> Key removeStrangeModifiers Key{keyVal, keyMods} =-  let reservedModifiers =+  let reservedModifiers :: Set ModifierType+      reservedModifiers =         [ ModifierTypeModifierReserved13Mask         , ModifierTypeModifierReserved14Mask         , ModifierTypeModifierReserved15Mask@@ -104,17 +111,17 @@         , ModifierTypeModifierReserved25Mask         , ModifierTypeModifierReserved29Mask         ]-  in Key keyVal (difference keyMods reservedModifiers)+  in Key keyVal (Set.difference keyMods reservedModifiers)  -handleKeyPress :: TMState -> EventKey -> IO Bool-handleKeyPress terState eventKey = do+handleKeyPress :: TMState -> TMWindowId -> EventKey -> IO Bool+handleKeyPress terState tmWindowId eventKey = do   -- void $ showKeys eventKey   keyval <- getEventKeyKeyval eventKey   modifiers <- getEventKeyState eventKey-  let oldKey = toKey keyval (setFromList modifiers)+  let oldKey = toKey keyval (Set.fromList modifiers)       newKey = removeStrangeModifiers oldKey-      maybeAction = lookup newKey keyMap+      maybeAction = Map.lookup newKey keyMap   case maybeAction of-    Just action -> action terState+    Just action -> action terState tmWindowId     Nothing -> pure False
src/Termonad/Lenses.hs view
@@ -29,12 +29,17 @@  )  $(makeLensesFor+    [ ("tmWindowAppWin", "lensTMWindowAppWin")+    , ("tmWindowNotebook", "lensTMWindowNotebook")+    ]+    ''TMWindow+ )++$(makeLensesFor     [ ("tmStateApp", "lensTMStateApp")-    , ("tmStateAppWin", "lensTMStateAppWin")-    , ("tmStateNotebook", "lensTMStateNotebook")     , ("tmStateFontDesc", "lensTMStateFontDesc")     , ("tmStateConfig", "lensTMStateConfig")-    , ("tmStateUserReqExit", "lensTMStateUserReqExit")+    , ("tmStateWindows", "lensTMStateWindows")     ]     ''TMState'  )
+ src/Termonad/Preferences.hs view
@@ -0,0 +1,315 @@+{-# LANGUAGE CPP #-}++-- | Description : Controls the Preferences dialog and setting app preferences+-- Copyright     : (c) Dennis Gosnell, 2023+-- License       : BSD3+-- Stability     : experimental+-- Portability   : POSIX+--+-- This module controls the Preferences dialog, which lets you set Termonad+-- preferences at run-time.+--+-- It also exports helpful functions from "Termonad.Preferences.File".++module Termonad.Preferences+  ( module Termonad.Preferences.File+  , showPreferencesDialog+  ) where++import Termonad.Prelude++import Control.Lens ((^.), over, set, view)+import qualified Data.List as List+import qualified Data.Text as Text+import GI.Gtk+  ( CheckButton(CheckButton)+  , ComboBoxText(ComboBoxText)+  , Dialog(Dialog)+  , Entry(Entry)+  , FontButton(FontButton)+  , Label(Label)+  , PolicyType(PolicyTypeAutomatic)+  , ResponseType(ResponseTypeAccept)+  , SpinButton(SpinButton)+  , adjustmentNew+  , applicationGetActiveWindow+  , applicationWindowSetShowMenubar+  , builderNewFromString+  , comboBoxGetActiveId+  , comboBoxSetActiveId+  , comboBoxTextAppend+  , dialogRun+  , entryBufferGetText+  , entryBufferSetText+  , fontChooserSetFontDesc+  , fontChooserGetFontDesc+  , getEntryBuffer+  , scrolledWindowSetPolicy+  , spinButtonGetValueAsInt+  , spinButtonSetAdjustment+  , spinButtonSetValue+  , toggleButtonGetActive+  , toggleButtonSetActive+  , widgetDestroy+  , widgetSetVisible+  , windowSetTransientFor+  )+import GI.Vte+  ( CursorBlinkMode(..)+  , terminalSetBoldIsBright+  , terminalSetCursorBlinkMode+  , terminalSetFont+  , terminalSetScrollbackLines+  , terminalSetWordCharExceptions+  , terminalSetAllowBold+  )+import System.Environment (getExecutablePath)+import System.FilePath (takeFileName)+import Termonad.Gtk (objFromBuildUnsafe, terminalSetEnableSixelIfExists)+import Termonad.Lenses+  ( lensBoldIsBright+  , lensEnableSixel+  , lensAllowBold+  , lensConfirmExit+  , lensCursorBlinkMode+  , lensFontConfig+  , lensOptions+  , lensShowMenu+  , lensShowScrollbar+  , lensShowTabBar+  , lensScrollbackLen+  , lensTMNotebookTabTermContainer+  , lensTMNotebookTabTerm+  , lensTMStateApp+  , lensTMStateConfig+  , lensTMStateFontDesc+  , lensTerm+  , lensWordCharExceptions+  )+import Termonad.Preferences.File (saveToPreferencesFile, tmConfigFromPreferencesFile)+import Termonad.Term+  ( setShowTabs+  , showScrollbarToPolicy+  )+import Termonad.Types+  ( ConfigOptions(..)+  , ShowScrollbar(..)+  , ShowTabBar(..)+  , TMNotebookTab+  , TMState+  , TMWindowId+  , fontConfigFromFontDescription+  , getTMWindowFromTMState'+  , tmNotebook+  , tmNotebookTabs+  , tmStateWindows+  , tmWindowAppWin+  , tmWindowNotebook+  )+import Termonad.XML (preferencesText)+import Termonad.IdMap (keysIdMap)++-- | Fill a combo box with ids and labels+--+-- The ids are stored in the combobox as 'Text', so their type should be an+-- instance of the 'Show' type class.+comboBoxFill :: forall a. Show a => ComboBoxText -> [(a, Text)] -> IO ()+comboBoxFill comboBox = mapM_ go+  where+    go :: (a, Text) -> IO ()+    go (value, textId) =+      comboBoxTextAppend comboBox (Just $ tshow value) textId++-- | Set the current active item in a combobox given an input id.+comboBoxSetActive :: Show a => ComboBoxText -> a -> IO ()+comboBoxSetActive cb item = void $ comboBoxSetActiveId cb (Just $ tshow item)++-- | Get the current active item in a combobox+--+-- The list of values to be searched in the combobox must be given as a+-- parameter. These values are converted to Text then compared to the current+-- id.+comboBoxGetActive+  :: forall a. (Show a, Enum a) => ComboBoxText -> [a] -> IO (Maybe a)+comboBoxGetActive cb values = findEnumFromMaybeId <$> comboBoxGetActiveId cb+  where+    findEnumFromMaybeId :: Maybe Text -> Maybe a+    findEnumFromMaybeId maybeId = maybeId >>= findEnumFromId++    findEnumFromId :: Text -> Maybe a+    findEnumFromId label = List.find (\x -> tshow x == label) values++applyNewPreferencesToTab :: TMState -> TMNotebookTab -> IO ()+applyNewPreferencesToTab mvarTMState tab = do+  tmState <- readMVar mvarTMState+  let fontDesc = tmState ^. lensTMStateFontDesc+      term = tab ^. lensTMNotebookTabTerm . lensTerm+      scrolledWin = tab ^. lensTMNotebookTabTermContainer+      options = tmState ^. lensTMStateConfig . lensOptions+  terminalSetFont term (Just fontDesc)+  terminalSetCursorBlinkMode term (cursorBlinkMode options)+  terminalSetWordCharExceptions term (wordCharExceptions options)+  terminalSetScrollbackLines term (fromIntegral (scrollbackLen options))+  terminalSetBoldIsBright term (boldIsBright options)+  terminalSetEnableSixelIfExists term (enableSixel options)+  terminalSetAllowBold term (allowBold options)++  let vScrollbarPolicy = showScrollbarToPolicy (options ^. lensShowScrollbar)+  scrolledWindowSetPolicy scrolledWin PolicyTypeAutomatic vScrollbarPolicy++applyNewPreferencesToWindow :: TMState -> TMWindowId -> IO ()+applyNewPreferencesToWindow mvarTMState tmWinId = do+  tmState <- readMVar mvarTMState+  tmWin <- getTMWindowFromTMState' tmState tmWinId+  let appWin = tmWindowAppWin tmWin+      config = tmState ^. lensTMStateConfig+      notebook = tmWindowNotebook tmWin+      tabFocusList = tmNotebookTabs notebook+      showMenu = config  ^. lensOptions . lensShowMenu+  applicationWindowSetShowMenubar appWin showMenu+  setShowTabs config (tmNotebook notebook)+  -- Sets the remaining preferences to each tab+  foldMap (applyNewPreferencesToTab mvarTMState) tabFocusList++-- | Takes a 'TMState', and looks at the 'TMConfig' within.+-- Take all the configuration options from the 'TMConfig' and apply them to the+-- current 'Application', 'Window's, and 'Term's.+--+-- This function is meant to be used after a big update to the 'TMConfig' within a+-- 'TMState'.+applyNewPreferences :: TMState -> IO ()+applyNewPreferences mvarTMState = do+  tmState <- readMVar mvarTMState+  let windows = tmStateWindows tmState+  foldMap (applyNewPreferencesToWindow mvarTMState) (keysIdMap windows)++-- | Show the preferences dialog.+--+-- When the user clicks on the Ok button, it copies the new settings to TMState.+-- Then apply them to the current terminals.+showPreferencesDialog :: TMState -> IO ()+showPreferencesDialog mvarTMState = do+  -- Get app out of mvar+  tmState <- readMVar mvarTMState+  let app = tmState ^. lensTMStateApp++  -- Create the preference dialog and get some widgets+  preferencesBuilder <-+    builderNewFromString preferencesText $ fromIntegral (Text.length preferencesText)+  preferencesDialog <-+    objFromBuildUnsafe preferencesBuilder "preferences" Dialog+  confirmExitCheckButton <-+    objFromBuildUnsafe preferencesBuilder "confirmExit" CheckButton+  showMenuCheckButton <-+    objFromBuildUnsafe preferencesBuilder "showMenu" CheckButton+  boldIsBrightCheckButton <-+    objFromBuildUnsafe preferencesBuilder "boldIsBright" CheckButton+  enableSixelCheckButton <-+    objFromBuildUnsafe preferencesBuilder "enableSixel" CheckButton+  allowBoldCheckButton <-+    objFromBuildUnsafe preferencesBuilder "allowBold" CheckButton+  wordCharExceptionsEntryBuffer <-+    objFromBuildUnsafe preferencesBuilder "wordCharExceptions" Entry >>=+      getEntryBuffer+  fontButton <- objFromBuildUnsafe preferencesBuilder "font" FontButton+  showScrollbarComboBoxText <-+    objFromBuildUnsafe preferencesBuilder "showScrollbar" ComboBoxText+  comboBoxFill+    showScrollbarComboBoxText+    [ (ShowScrollbarNever, "Never")+    , (ShowScrollbarAlways, "Always")+    , (ShowScrollbarIfNeeded, "If needed")+    ]+  showTabBarComboBoxText <-+    objFromBuildUnsafe preferencesBuilder "showTabBar" ComboBoxText+  comboBoxFill+    showTabBarComboBoxText+    [ (ShowTabBarNever, "Never")+    , (ShowTabBarAlways, "Always")+    , (ShowTabBarIfNeeded, "If needed")+    ]+  cursorBlinkModeComboBoxText <-+    objFromBuildUnsafe preferencesBuilder "cursorBlinkMode" ComboBoxText+  comboBoxFill+    cursorBlinkModeComboBoxText+    [ (CursorBlinkModeSystem, "System")+    , (CursorBlinkModeOn, "On")+    , (CursorBlinkModeOff, "Off")+    ]+  scrollbackLenSpinButton <-+    objFromBuildUnsafe preferencesBuilder "scrollbackLen" SpinButton+  adjustmentNew 0 0 (fromIntegral (maxBound :: Int)) 1 10 0 >>=+    spinButtonSetAdjustment scrollbackLenSpinButton+  warningLabel <- objFromBuildUnsafe preferencesBuilder "warning" Label++  -- We show the warning label only if the user has launched termonad with a+  -- termonad.hs file+  executablePath <- getExecutablePath+  let hasTermonadHs = takeFileName executablePath == "termonad-linux-x86_64"+  widgetSetVisible warningLabel hasTermonadHs++  -- Make the dialog modal+  maybeWin <- applicationGetActiveWindow app+  windowSetTransientFor preferencesDialog maybeWin++  -- Init with current state+  fontChooserSetFontDesc fontButton (tmState ^. lensTMStateFontDesc)+  let options = tmState ^. lensTMStateConfig . lensOptions+  comboBoxSetActive showScrollbarComboBoxText $ showScrollbar options+  comboBoxSetActive showTabBarComboBoxText $ showTabBar options+  comboBoxSetActive cursorBlinkModeComboBoxText $ cursorBlinkMode options+  spinButtonSetValue scrollbackLenSpinButton (fromIntegral $ scrollbackLen options)+  toggleButtonSetActive confirmExitCheckButton $ confirmExit options+  toggleButtonSetActive showMenuCheckButton $ showMenu options+  toggleButtonSetActive boldIsBrightCheckButton $ boldIsBright options+  toggleButtonSetActive enableSixelCheckButton $ enableSixel options+  toggleButtonSetActive allowBoldCheckButton $ allowBold options+  entryBufferSetText wordCharExceptionsEntryBuffer (wordCharExceptions options) (-1)++  -- Run dialog then close+  res <- dialogRun preferencesDialog++  -- When closing the dialog get the new settings+  when (toEnum (fromIntegral res) == ResponseTypeAccept) $ do+    maybeFontDesc <- fontChooserGetFontDesc fontButton+    maybeFontConfig <-+      join <$> mapM fontConfigFromFontDescription maybeFontDesc+    maybeShowScrollbar <-+      comboBoxGetActive showScrollbarComboBoxText [ShowScrollbarNever ..]+    maybeShowTabBar <-+      comboBoxGetActive showTabBarComboBoxText [ShowTabBarNever ..]+    maybeCursorBlinkMode <-+      comboBoxGetActive cursorBlinkModeComboBoxText [CursorBlinkModeSystem ..]+    scrollbackLenVal <-+      fromIntegral <$> spinButtonGetValueAsInt scrollbackLenSpinButton+    confirmExitVal <- toggleButtonGetActive confirmExitCheckButton+    showMenuVal <- toggleButtonGetActive showMenuCheckButton+    boldIsBrightVal <- toggleButtonGetActive boldIsBrightCheckButton+    enableSixelVal <- toggleButtonGetActive enableSixelCheckButton+    allowBoldVal <- toggleButtonGetActive allowBoldCheckButton+    wordCharExceptionsVal <- entryBufferGetText wordCharExceptionsEntryBuffer++    -- Apply the changes to mvarTMState+    modifyMVar_ mvarTMState $ pure+      . over lensTMStateFontDesc (`fromMaybe` maybeFontDesc)+      . over (lensTMStateConfig . lensOptions)+        ( set lensConfirmExit confirmExitVal+        . set lensShowMenu showMenuVal+        . set lensBoldIsBright boldIsBrightVal+        . set lensEnableSixel enableSixelVal+        . set lensAllowBold allowBoldVal+        . set lensWordCharExceptions wordCharExceptionsVal+        . over lensFontConfig (`fromMaybe` maybeFontConfig)+        . set lensScrollbackLen scrollbackLenVal+        . over lensShowScrollbar (`fromMaybe` maybeShowScrollbar)+        . over lensShowTabBar (`fromMaybe` maybeShowTabBar)+        . over lensCursorBlinkMode (`fromMaybe` maybeCursorBlinkMode)+        )++    -- Save the changes to the preferences files+    withMVar mvarTMState $ saveToPreferencesFile . view lensTMStateConfig++    -- Update the app with new settings+    applyNewPreferences mvarTMState++  widgetDestroy preferencesDialog
+ src/Termonad/Preferences/File.hs view
@@ -0,0 +1,209 @@+{-# LANGUAGE CPP #-}++-- | Description : Read and write to the Preferences file+-- Copyright     : (c) Dennis Gosnell, 2023+-- License       : BSD3+-- Stability     : experimental+-- Portability   : POSIX+--+-- This module contains functions for reading and writing to the preferences file.+--+-- The preferences file is generally stored in+-- @~/.config/termonad/termonad.yaml@.  It stores run-time preferences that+-- have been set through the Preferences dialog.  Preferences are loaded on+-- app startup, but only if the @termonad.hs@ configuration file doesn't exist.++module Termonad.Preferences.File where++import Termonad.Prelude++import Control.Monad.Trans.Except (ExceptT(..), runExceptT, throwE, withExceptT)+import Data.Aeson (Result(..), fromJSON)+#if MIN_VERSION_aeson(2, 0, 0)+import qualified Data.Aeson.KeyMap as KeyMap+#endif+import qualified Data.ByteString as ByteString+import qualified Data.HashMap.Strict as HashMap+import Data.Text (pack)+import Data.Yaml (ParseException, ToJSON (toJSON), decodeFileEither, encode, prettyPrintParseException)+import Data.Yaml.Aeson (Value(..))+import System.Directory+  ( XdgDirectory(XdgConfig)+  , createDirectoryIfMissing+  , doesFileExist+  , getXdgDirectory+  )+import System.FilePath ((</>))+import Termonad.Types+  ( ConfigOptions+  , TMConfig(TMConfig, hooks, options)+  , defaultConfigHooks+  , defaultConfigOptions+  )++-- $setup+--+-- >>> import Data.Aeson(object, (.=))++-- | Get the path to the preferences file @~\/.config\/termonad\/termonad.yaml@.+getPreferencesFile :: IO FilePath+getPreferencesFile = do+  -- Get the termonad config directory+  confDir <- getXdgDirectory XdgConfig "termonad"+  createDirectoryIfMissing True confDir+  pure $ confDir </> "termonad.yaml"++-- | Read the configuration for the preferences file+-- @~\/.config\/termonad\/termonad.yaml@. This file stores only the 'options' of+-- 'TMConfig' so 'hooks' are initialized with 'defaultConfigHooks'.  If the+-- file doesn't exist, create it with the default values.+--+-- Any options that do not exist will get initialized with values from+-- 'defaultConfigOptions'.+tmConfigFromPreferencesFile :: IO TMConfig+tmConfigFromPreferencesFile = do+  confFile <- getPreferencesFile+  -- If there is no preferences file we create it with the default values+  exists <- doesFileExist confFile+  unless exists $ writePreferencesFile confFile defaultConfigOptions+  -- Read the configuration file+  eitherOptions <- readFileWithDefaults confFile+  options <-+    case eitherOptions of+      Left err -> do+        hPutStrLn stderr $ "Error parsing file " <> pack confFile <> ": " <> err+        pure defaultConfigOptions+      Right options -> pure options+  pure TMConfig { options = options, hooks = defaultConfigHooks }++-- | Read the 'ConfigOptions' out of a configuration file.+--+-- Merge the raw 'ConfigOptions' with 'defaultConfigOptions'.  This makes sure+-- that old versions of the configuration file will still be able to be read+-- even if new options are added to 'ConfigOptions' in new versions of+-- Termonad.+readFileWithDefaults :: FilePath -> IO (Either Text ConfigOptions)+readFileWithDefaults file = runExceptT $ do+  -- Read the configuration file as a JSON object+  optsFromFile :: Value <-+    withExceptT parseExceptionToText . ExceptT $ decodeFileEither file+  let optsDefault :: Value = toJSON defaultConfigOptions+  -- Then merge it with the default options in JSON before converting it to+  -- a 'ConfigOptions'+  resultToExcept . fromJSON $ mergeObjVals optsFromFile optsDefault+  where+    parseExceptionToText :: ParseException -> Text+    parseExceptionToText = pack . prettyPrintParseException++    resultToExcept :: Result a -> ExceptT Text IO a+    resultToExcept (Success v) = pure v+    resultToExcept (Error str) = throwE (pack str)++-- | Merge 'Value's recursively.+--+-- This merges 'Value's recursively in 'Object' values, taking values that+-- have been explicitly over the defaults.  The defaults are only used if+-- there is no value that has been explicitly set.+--+-- For 'Array', 'String', 'Number', 'Bool', and 'Null', take the first 'Value'+-- (the one that has been explicitly set in the user's config file):+--+-- >>> mergeObjVals (Array [Number 1, Number 2]) (Array [String "hello"])+-- Array [Number 1.0,Number 2.0]+-- >>> mergeObjVals (String "hello") (String "bye")+-- String "hello"+-- >>> mergeObjVals (Number 1) (Number 2)+-- Number 1.0+-- >>> mergeObjVals (Bool True) (Bool False)+-- Bool True+-- >>> mergeObjVals Null Null+-- Null+--+-- Note that 'Value's in 'Array's are not recursed into:+--+-- >>> let obj1 = object ["hello" .= Number 2]+-- >>> let obj2 = object ["hello" .= String "bye"]+-- >>> mergeObjVals (Array [obj1]) (Array [obj2])+-- Array [Object (fromList [("hello",Number 2.0)])]+--+-- 'Object's are recursed into.  Unique keys from both Maps will be used.+-- Keys that are in both Maps will be merged according to the rules above:+--+-- >>> let object1 = object ["hello" .= Number 1, "bye" .= Number 100]+-- >>> let object2 = object ["hello" .= Number 2, "goat" .= String "chicken"]+-- >>> mergeObjVals object1 object2+-- Object (fromList [("bye",Number 100.0),("goat",String "chicken"),("hello",Number 1.0)])+--+-- 'Value's of different types will use the second 'Value':+--+-- >>> mergeObjVals Null (String "bye")+-- String "bye"+-- >>> mergeObjVals (Bool True) (Number 2)+-- Number 2.0+-- >>> mergeObjVals (Object mempty) (Bool False)+-- Bool False+mergeObjVals+  :: Value+     -- ^ Value that has been set explicitly in the User's configuration+     -- file.+  -> Value+     -- ^ Default value that will be used if no explicitly set value.+  -> Value+     -- ^ Merged values.+mergeObjVals optsFromFile optsDefault =+  case (optsFromFile, optsDefault) of+    -- Both the options from the file and the default options are an Object+    -- here.  Recursively merge the keys and values.+    (Object optsFromFileKeyMap, Object optsDefaultKeyMap) ->+      let+#if MIN_VERSION_aeson(2, 0, 0)+          hashMapFromKeyMap = KeyMap.toHashMap+          keyMapFromHashMap = KeyMap.fromHashMap+#else+          hashMapFromKeyMap = id+          keyMapFromHashMap = id+#endif+          optsFromFileHashMap = hashMapFromKeyMap optsFromFileKeyMap+          optsDefaultHashMap = hashMapFromKeyMap optsDefaultKeyMap+          optsResultHashMap = HashMap.unionWith mergeObjVals+                                optsFromFileHashMap+                                optsDefaultHashMap+          optsResultKeyMap = keyMapFromHashMap optsResultHashMap+      in Object optsResultKeyMap+    -- Both the value from the file and the default value are the same type.+    -- Use the value from the file.+    --+    -- XXX: This will end up causing readFileWithDefaults to fail if the value+    -- from the file is old and can no longer properly be decoded into a value+    -- expected by ConfigOptions.+    (Array fromFile, Array _) -> Array fromFile+    (String fromFile, String _) -> String fromFile+    (Number fromFile, Number _) -> Number fromFile+    (Bool fromFile, Bool _) -> Bool fromFile+    (Null, Null) -> Null+    -- The value from the file and the default value are different types. Just+    -- use the default value.+    (_, defVal) -> defVal++writePreferencesFile :: FilePath -> ConfigOptions -> IO ()+writePreferencesFile confFile options = do+  let yaml = encode options+      yamlWithComment =+        "# DO NOT EDIT THIS FILE BY HAND!\n" <>+        "#\n" <>+        "# This file is generated automatically by the Preferences dialog\n" <>+        "# in Termonad.  Please open the Preferences dialog if you wish to\n" <>+        "# modify this file.\n" <>+        "#\n" <>+        "# The settings in this file will be ignored if you have a\n" <>+        "# termonad.hs file in this same directory.\n\n" <>+        yaml+  ByteString.writeFile confFile yamlWithComment++-- | Save the configuration to the preferences file+-- @~\/.config\/termonad\/termonad.yaml@+saveToPreferencesFile :: TMConfig -> IO ()+saveToPreferencesFile TMConfig { options = options } = do+  confFile <- getPreferencesFile+  writePreferencesFile confFile options+
− src/Termonad/PreferencesFile.hs
@@ -1,195 +0,0 @@-{-# LANGUAGE CPP #-}--module Termonad.PreferencesFile where--import Termonad.Prelude--import Control.Monad.Trans.Except (ExceptT(..), runExceptT, throwE, withExceptT)-import Data.Aeson (Result(..), fromJSON)-#if MIN_VERSION_aeson(2, 0, 0)-import qualified Data.Aeson.KeyMap as KeyMap-#endif-import qualified Data.HashMap.Strict as HashMap-import Data.Yaml (ParseException, ToJSON (toJSON), decodeFileEither, encode, prettyPrintParseException)-import Data.Yaml.Aeson (Value(..))--import System.Directory-  ( XdgDirectory(XdgConfig)-  , createDirectoryIfMissing-  , doesFileExist-  , getXdgDirectory-  )--import Termonad.Types-  ( ConfigOptions-  , TMConfig(TMConfig, hooks, options)-  , defaultConfigHooks-  , defaultConfigOptions-  )---- $setup------ >>> import Data.Aeson(object, (.=))---- | Get the path to the preferences file @~\/.config\/termonad\/termonad.yaml@.-getPreferencesFile :: IO FilePath-getPreferencesFile = do-  -- Get the termonad config directory-  confDir <- getXdgDirectory XdgConfig "termonad"-  createDirectoryIfMissing True confDir-  pure $ confDir </> "termonad.yaml"---- | Read the configuration for the preferences file--- @~\/.config\/termonad\/termonad.yaml@. This file stores only the 'options' of--- 'TMConfig' so 'hooks' are initialized with 'defaultConfigHooks'.  If the--- file doesn't exist, create it with the default values.------ Any options that do not exist will get initialized with values from--- 'defaultConfigOptions'.-tmConfigFromPreferencesFile :: IO TMConfig-tmConfigFromPreferencesFile = do-  confFile <- getPreferencesFile-  -- If there is no preferences file we create it with the default values-  exists <- doesFileExist confFile-  unless exists $ writePreferencesFile confFile defaultConfigOptions-  -- Read the configuration file-  eitherOptions <- readFileWithDefaults confFile-  options <--    case eitherOptions of-      Left err -> do-        hPutStrLn stderr $ "Error parsing file " <> pack confFile <> ": " <> err-        pure defaultConfigOptions-      Right options -> pure options-  pure TMConfig { options = options, hooks = defaultConfigHooks }---- | Read the 'ConfigOptions' out of a configuration file.------ Merge the raw 'ConfigOptions' with 'defaultConfigOptions'.  This makes sure--- that old versions of the configuration file will still be able to be read--- even if new options are added to 'ConfigOptions' in new versions of--- Termonad.-readFileWithDefaults :: FilePath -> IO (Either Text ConfigOptions)-readFileWithDefaults file = runExceptT $ do-  -- Read the configuration file as a JSON object-  optsFromFile :: Value <--    withExceptT parseExceptionToText . ExceptT $ decodeFileEither file-  let optsDefault :: Value = toJSON $ defaultConfigOptions-  -- Then merge it with the default options in JSON before converting it to-  -- a 'ConfigOptions'-  resultToExcept . fromJSON $ mergeObjVals optsFromFile optsDefault-  where-    parseExceptionToText :: ParseException -> Text-    parseExceptionToText = pack . prettyPrintParseException--    resultToExcept :: Result a -> ExceptT Text IO a-    resultToExcept (Success v) = pure v-    resultToExcept (Error str) = throwE (pack str)---- | Merge 'Value's recursively.------ This merges 'Value's recursively in 'Object' values, taking values that--- have been explicitly over the defaults.  The defaults are only used if--- there is no value that has been explicitly set.------ For 'Array', 'String', 'Number', 'Bool', and 'Null', take the first 'Value'--- (the one that has been explicitly set in the user's config file):------ >>> mergeObjVals (Array [Number 1, Number 2]) (Array [String "hello"])--- Array [Number 1.0,Number 2.0]--- >>> mergeObjVals (String "hello") (String "bye")--- String "hello"--- >>> mergeObjVals (Number 1) (Number 2)--- Number 1.0--- >>> mergeObjVals (Bool True) (Bool False)--- Bool True--- >>> mergeObjVals Null Null--- Null------ Note that 'Value's in 'Array's are not recursed into:------ >>> let obj1 = object ["hello" .= Number 2]--- >>> let obj2 = object ["hello" .= String "bye"]--- >>> mergeObjVals (Array [obj1]) (Array [obj2])--- Array [Object (fromList [("hello",Number 2.0)])]------ 'Object's are recursed into.  Unique keys from both Maps will be used.--- Keys that are in both Maps will be merged according to the rules above:------ >>> let object1 = object ["hello" .= Number 1, "bye" .= Number 100]--- >>> let object2 = object ["hello" .= Number 2, "goat" .= String "chicken"]--- >>> mergeObjVals object1 object2--- Object (fromList [("bye",Number 100.0),("goat",String "chicken"),("hello",Number 1.0)])------ 'Value's of different types will use the second 'Value':------ >>> mergeObjVals Null (String "bye")--- String "bye"--- >>> mergeObjVals (Bool True) (Number 2)--- Number 2.0--- >>> mergeObjVals (Object mempty) (Bool False)--- Bool False----mergeObjVals-  :: Value-     -- ^ Value that has been set explicitly in the User's configuration-     -- file.-  -> Value-     -- ^ Default value that will be used if no explicitly set value.-  -> Value-     -- ^ Merged values.-mergeObjVals optsFromFile optsDefault =-  case (optsFromFile, optsDefault) of-    -- Both the options from the file and the default options are an Object-    -- here.  Recursively merge the keys and values.-    (Object optsFromFileKeyMap, Object optsDefaultKeyMap) ->-      let-#if MIN_VERSION_aeson(2, 0, 0)-          hashMapFromKeyMap = KeyMap.toHashMap-          keyMapFromHashMap = KeyMap.fromHashMap-#else-          hashMapFromKeyMap = id-          keyMapFromHashMap = id-#endif-          optsFromFileHashMap = hashMapFromKeyMap optsFromFileKeyMap-          optsDefaultHashMap = hashMapFromKeyMap optsDefaultKeyMap-          optsResultHashMap = HashMap.unionWith mergeObjVals-                                optsFromFileHashMap-                                optsDefaultHashMap-          optsResultKeyMap = keyMapFromHashMap optsResultHashMap-      in Object optsResultKeyMap-    -- Both the value from the file and the default value are the same type.-    -- Use the value from the file.-    ---    -- XXX: This will end up causing readFileWithDefaults to fail if the value-    -- from the file is old and can no longer properly be decoded into a value-    -- expected by ConfigOptions.-    (Array fromFile, Array _) -> Array fromFile-    (String fromFile, String _) -> String fromFile-    (Number fromFile, Number _) -> Number fromFile-    (Bool fromFile, Bool _) -> Bool fromFile-    (Null, Null) -> Null-    -- The value from the file and the default value are different types. Just-    -- use the default value.-    (_, defVal) -> defVal--writePreferencesFile :: FilePath -> ConfigOptions -> IO ()-writePreferencesFile confFile options = do-  let yaml = encode options-      yamlWithComment =-        "# DO NOT EDIT THIS FILE BY HAND!\n" <>-        "#\n" <>-        "# This file is generated automatically by the Preferences dialog\n" <>-        "# in Termonad.  Please open the Preferences dialog if you wish to\n" <>-        "# modify this file.\n" <>-        "#\n" <>-        "# The settings in this file will be ignored if you have a\n" <>-        "# termonad.hs file in this same directory.\n\n" <>-        yaml-  writeFile confFile yamlWithComment---- | Save the configuration to the preferences file--- @~\/.config\/termonad\/termonad.yaml@-saveToPreferencesFile :: TMConfig -> IO ()-saveToPreferencesFile TMConfig { options = options } = do-  confFile <- getPreferencesFile-  writePreferencesFile confFile options
src/Termonad/Prelude.hs view
@@ -1,17 +1,42 @@++-- | This is a basic prelude-like module that adds a bunch of common datatypes+-- and functions to the 'Prelude'.+ module Termonad.Prelude   ( module X   , hPutStrLn   , whenJust+  , stderr+  , tshow   ) where +import Control.Concurrent.MVar as X (MVar, modifyMVar, modifyMVar_, newMVar, readMVar, withMVar)+import Control.Exception as X (IOException, try) import Control.Lens as X ((&))+import Control.Monad as X (join, unless, void, when, (<=<))+import Control.Monad.IO.Class as X+import Control.Monad.Trans.Class as X (lift) import Control.Monad.Trans.Maybe as X (MaybeT(MaybeT), runMaybeT)-import ClassyPrelude as X+import Data.ByteString as X (ByteString)+import Data.Function as X (on)+import Data.Functor as X (($>))+import Data.Int as X (Int32)+import Data.Maybe as X (catMaybes, fromMaybe) import Data.Proxy as X+import Data.String as X (IsString)+import Data.Text as X (Text)+import Data.Text (pack) import qualified Data.Text.IO as TextIO+import Data.Word as X (Word8, Word32)+import GHC.Generics as X (Generic)+import Prelude as X+import System.IO (Handle, stderr)  whenJust :: Monoid m => Maybe a -> (a -> m) -> m whenJust = flip foldMap  hPutStrLn :: MonadIO m => Handle -> Text -> m () hPutStrLn hndl = liftIO . TextIO.hPutStrLn hndl++tshow :: Show a => a -> Text+tshow = pack . show
+ src/Termonad/Startup.hs view
@@ -0,0 +1,149 @@++-- | Description : Functions for starting up Termonad.+-- Copyright     : (c) Dennis Gosnell, 2023+-- License       : BSD3+-- Stability     : experimental+-- Portability   : POSIX+--+-- This module contains functions for starting up Termonad.++module Termonad.Startup where++import Termonad.Prelude++import Config.Dyre (wrapMain, newParams)+import Control.Lens (over)+import System.IO.Error (doesNotExistErrorType, ioeGetErrorType, ioeGetFileName, tryIOError)+import Termonad.App (start)+import Termonad.Cli (parseCliArgs, applyCliArgs)+import Termonad.Lenses (lensOptions)+import Termonad.Types (TMConfig)+++-- | Run Termonad with the given 'TMConfig'.+--+-- Do not perform any of the recompilation operations that the 'defaultMain'+-- function does.+--+-- This function __does__ parse command line arguments, and then calls 'Termonad.App.start'.+startWithCliArgs :: TMConfig -> IO ()+startWithCliArgs tmConfig = do+  cliArgs <- parseCliArgs+  start (over lensOptions (applyCliArgs cliArgs) tmConfig)++-- | Run Termonad with the given 'TMConfig'.+--+-- This function will check if there is a @~\/.config\/termonad\/termonad.hs@ file+-- and a @~\/.cache\/termonad\/termonad-linux-x86_64@ binary.  Termonad will+-- perform different actions based on whether or not these two files exist.+--+-- Here are the four different possible actions based on the existence of these+-- two files.+--+-- - @~\/.config\/termonad\/termonad.hs@ exists, @~\/.cache\/termonad\/termonad-linux-x86_64@ exists+--+--     The timestamps of these two files are checked.  If the+--     @~\/.config\/termonad\/termonad.hs@ file has been modified after the+--     @~\/.cache\/termonad\/termonad-linux-x86_64@ binary, then Termonad will use+--     GHC to recompile the @~\/.config\/termonad\/termonad.hs@ file, producing a+--     new binary at @~\/.cache\/termonad\/termonad-linux-x86_64@.  This new binary+--     will be re-executed.  The 'TMConfig' passed to this 'defaultMain' will be+--     effectively thrown away, however all command line options will be passed+--     on to this new Termonad process.+--+--     If GHC fails to recompile the @~\/.config\/termonad\/termonad.hs@ file, then+--     Termonad will just execute 'startWithCliArgs' with the 'TMConfig' passed in.+--+--     If the @~\/.cache\/termonad\/termonad-linux-x86_64@ binary has been modified+--     after the @~\/.config\/termonad\/termonad.hs@ file, then Termonad will+--     re-exec the @~\/.cache\/termonad\/termonad-linux-x86_64@ binary.  The+--     'TMConfig' passed to this 'defaultMain' will be effectively thrown away,+--     however all command line options will be passed on to this new Termonad+--     process.+--+-- - @~\/.config\/termonad\/termonad.hs@ exists, @~\/.cache\/termonad\/termonad-linux-x86_64@ does not exist+--+--     Termonad will use GHC to recompile the @~\/.config\/termonad\/termonad.hs@+--     file, producing a new binary at @~\/.cache\/termonad\/termonad-linux-x86_64@.+--     This new binary will be re-executed.  The 'TMConfig' passed to this+--     'defaultMain' will be effectively thrown away, however all command line+--     options will be passed on to this new Termonad process.+--+--     If GHC fails to recompile the @~\/.config\/termonad\/termonad.hs@ file, then+--     Termonad will just execute 'startWithCliArgs' with the 'TMConfig' passed in.+--+-- - @~\/.config\/termonad\/termonad.hs@ does not exist, @~\/.cache\/termonad\/termonad-linux-x86_64@ exists+--+--     Termonad will ignore the @~\/.cache\/termonad\/termonad-linux-x86_64@ binary+--     and just run 'startWithCliArgs' with the 'TMConfig' passed to this function.+--+-- - @~\/.config\/termonad\/termonad.hs@ does not exist, @~\/.cache\/termonad\/termonad-linux-x86_64@ does not exist+--+--     Termonad will run 'startWithCliArgs' with the 'TMConfig' passed to this function.+--+-- Other notes:+--+-- 1. That the locations of @~\/.config\/termonad\/termonad.hs@ and+--    @~\/.cache\/termonad\/termonad-linux-x86_64@ may differ depending on your+--    system.+--+-- 2. In your own @~\/.config\/termonad\/termonad.hs@ file, you can use either+--    'defaultMain' or 'startWithCliArgs'.  As long as you always+--    execute the system-wide @termonad@ binary (instead of the binary produced+--    as @~\/.cache\/termonad\/termonad-linux-x86_64@), the effect should be+--    similar.+--+-- 3. If you directly run the cached termonad binary (e.g.+--    @~\/.cache\/termonad\/termonad-linux-x86_64@) instead of the+--    system-installed Termonad binary (e.g. @\/usr\/bin\/termonad@), the Termonad+--    /will/ recompile the the configuration file+--    @~\/.config\/termonad\/termonad.hs@ according to the above logic (while+--    possibly overwriting the executable file for the binary you're currently+--    running), but it /will not/ re-exec into the newly built @termonad@ binary.+--+-- 4. When running the system-wide @termonad@ binary, the initial 'TMConfig'+--    that gets passed into this function comes from+--    'Termonad.PreferencesFile.tmConfigFromPreferencesFile'.  As stated above,+--    this initial 'TMConfig' gets ignored if users have a+--    @~\/.config\/termonad\/termonad.hs@ file that gets recompiled and re-execed.+--+--    End users generally call 'defaultMain' in their+--    @~\/.config\/termonad\/termonad.hs@ file.+--+--    'defaultMain' interally calls 'startWithCliArgs', which parses CLI arguments+--    and combines them with the passed-in 'TMConfig'.  'startWithCliArgs' then+--    internally calls 'Termonad.App.start'.+--+--    If you don't want the re-compiling and re-exec functionality, you can directly+--    use 'startWithCliArgs'.  If you also don't want the CLI argument parsing+--    functionality, you can directly use 'Termonad.App.start'.+defaultMain :: TMConfig -> IO ()+defaultMain tmConfig = do+  let params = newParams "termonad" realMainFunc collectErrs+  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."+          startWithCliArgs tmConfig+      | otherwise -> do+          putStrLn "IO error occurred when trying to run termonad:"+          print ioErr+          putStrLn "Don't know how to recover.  Exiting."+    Right _ -> pure ()+  where+    -- The real main function+    realMainFunc :: (TMConfig, String) -> IO ()+    realMainFunc (cfg, errs) =+      case errs of+        "" -> startWithCliArgs cfg+        _ -> do+          putStrLn $ "Errors from dyre when recompiling Termonad:" <> errs+          putStrLn "Continuing with Termonad without re-execing into recompiled binary..."+          startWithCliArgs cfg++    -- A function that can easily collect errors from dyre+    collectErrs :: (TMConfig, String) -> String -> (TMConfig, String)+    collectErrs (cfg, oldErrs) newErr = (cfg, oldErrs <> "\n" <> newErr)
src/Termonad/Term.hs view
@@ -4,9 +4,13 @@  import Termonad.Prelude -import Control.Lens ((^.), (.~), set, to)+import Control.Lens ((^.), ix, set)+import Data.Coerce (coerce) import Data.Colour.SRGB (Colour, RGB(RGB), toSRGB) import Data.FocusList (appendFL, deleteFL, getFocusItemFL)+import Data.GI.Base (toManagedPtr)+import Data.Text (pack)+import qualified Data.Text as Text import GI.Gdk   ( Event (Event)   , EventButton@@ -109,7 +113,7 @@   ) import System.Directory (getSymbolicLinkTarget) import System.Environment (lookupEnv)-+import System.FilePath ((</>)) import Termonad.Gtk (terminalSetEnableSixelIfExists) import Termonad.Lenses   ( lensConfirmExit@@ -122,9 +126,9 @@   , lensTMNotebookTabs   , lensTMStateApp   , lensTMStateConfig-  , lensTMStateNotebook-  , lensTerm+  , lensTerm, lensTMStateWindows, lensTMWindowNotebook   )+import Termonad.Pcre (pcre2Multiline) import Termonad.Types   ( ConfigHooks(createTermHook)   , ConfigOptions(scrollbackLen, wordCharExceptions, cursorBlinkMode, boldIsBright, enableSixel, allowBold)@@ -134,57 +138,64 @@   , TMNotebook   , TMNotebookTab   , TMState-  , TMState'(TMState, tmStateAppWin, tmStateConfig, tmStateFontDesc, tmStateNotebook)+  , TMState'(TMState, tmStateConfig, tmStateFontDesc)   , TMTerm+  , TMWindowId   , assertInvariantTMState   , createTMNotebookTab+  , getNotebookFromTMState+  , getTMNotebookFromTMState+  , getTMNotebookFromTMState'+  , getTMWindowFromTMState+  , getTMWindowFromWins   , newTMTerm   , pid   , tmNotebook   , tmNotebookTabTerm   , tmNotebookTabTermContainer   , tmNotebookTabs+  , tmStateWindows+  , tmWindowAppWin+  , tmWindowNotebook   )-import Data.Coerce (coerce)-import Data.GI.Base (toManagedPtr)-import Termonad.Pcre (pcre2Multiline) -focusTerm :: Int -> TMState -> IO ()-focusTerm i mvarTMState = do-  note <- tmNotebook . tmStateNotebook <$> readMVar mvarTMState+focusTerm :: Int -> TMState -> TMWindowId -> IO ()+focusTerm i mvarTMState tmWinId = do+  note <- getNotebookFromTMState mvarTMState tmWinId   notebookSetCurrentPage note (fromIntegral i) -altNumSwitchTerm :: Int -> TMState -> IO ()+altNumSwitchTerm :: Int -> TMState -> TMWindowId -> IO () altNumSwitchTerm = focusTerm -termNextPage :: TMState -> IO ()-termNextPage mvarTMState = do-  note <- tmNotebook . tmStateNotebook <$> readMVar mvarTMState+-- | Change focus to the next tab.+termNextPage :: TMState -> TMWindowId -> IO ()+termNextPage mvarTMState tmWinId = do+  note <- getNotebookFromTMState mvarTMState tmWinId   notebookNextPage note -termPrevPage :: TMState -> IO ()-termPrevPage mvarTMState = do-  note <- tmNotebook . tmStateNotebook <$> readMVar mvarTMState+-- | Change focus to the previous tab.+termPrevPage :: TMState -> TMWindowId -> IO ()+termPrevPage mvarTMState tmWinId = do+  note <- getNotebookFromTMState mvarTMState tmWinId   notebookPrevPage note -termExitFocused :: TMState -> IO ()-termExitFocused mvarTMState = do-  tmState <- readMVar mvarTMState-  let maybeTab =-        tmState ^. lensTMStateNotebook . lensTMNotebookTabs . to getFocusItemFL+termExitFocused :: TMState -> TMWindowId -> IO ()+termExitFocused mvarTMState tmWinId = do+  note <- getTMNotebookFromTMState mvarTMState tmWinId+  let maybeTab = getFocusItemFL $ tmNotebookTabs note   case maybeTab of     Nothing -> pure ()-    Just tab -> termClose tab mvarTMState+    Just tab -> termClose tab mvarTMState tmWinId -termClose :: TMNotebookTab -> TMState -> IO ()-termClose tab mvarTMState = do+termClose :: TMNotebookTab -> TMState -> TMWindowId -> IO ()+termClose tab mvarTMState tmWindowId = do   tmState <- readMVar mvarTMState   let confirm = tmState ^. lensTMStateConfig . lensOptions . lensConfirmExit       close = if confirm then termExitWithConfirmation else termExit-  close tab mvarTMState+  close tab mvarTMState tmWindowId -termExitWithConfirmation :: TMNotebookTab -> TMState -> IO ()-termExitWithConfirmation tab mvarTMState = do+termExitWithConfirmation :: TMNotebookTab -> TMState -> TMWindowId -> IO ()+termExitWithConfirmation tab mvarTMState tmWinId = do   tmState <- readMVar mvarTMState   let app = tmState ^. lensTMStateApp   win <- applicationGetActiveWindow app@@ -208,30 +219,34 @@   res <- dialogRun dialog   widgetDestroy dialog   case toEnum (fromIntegral res) of-    ResponseTypeYes -> termExit tab mvarTMState+    ResponseTypeYes -> termExit tab mvarTMState tmWinId     _ -> pure () -termExit :: TMNotebookTab -> TMState -> IO ()-termExit tab mvarTMState = do+termExit :: TMNotebookTab -> TMState -> TMWindowId -> IO ()+termExit tab mvarTMState tmWinId = do   detachTabAction <-     modifyMVar mvarTMState $ \tmState -> do-      let notebook = tmStateNotebook tmState+      tmNote <- getTMNotebookFromTMState' tmState tmWinId+      let detachTabAction :: IO ()           detachTabAction =             notebookDetachTab-              (tmNotebook notebook)+              (tmNotebook tmNote)               (tmNotebookTabTermContainer tab)-      let newTabs = deleteFL tab (tmNotebookTabs notebook)-      let newTMState =-            set (lensTMStateNotebook . lensTMNotebookTabs) newTabs tmState+          newTabs = deleteFL tab (tmNotebookTabs tmNote)+          newTMState =+            set+              (lensTMStateWindows . ix tmWinId . lensTMWindowNotebook . lensTMNotebookTabs)+              newTabs+              tmState       pure (newTMState, detachTabAction)   detachTabAction-  relabelTabs mvarTMState+  tmWin <- getTMWindowFromTMState mvarTMState tmWinId+  relabelTabs (tmWindowNotebook tmWin) -relabelTabs :: TMState -> IO ()-relabelTabs mvarTMState = do-  TMState{tmStateNotebook} <- readMVar mvarTMState-  let notebook = tmNotebook tmStateNotebook-      tabFocusList = tmNotebookTabs tmStateNotebook+relabelTabs :: TMNotebook -> IO ()+relabelTabs tmNote = do+  let notebook = tmNotebook tmNote+      tabFocusList = tmNotebookTabs tmNote   foldMap (go notebook) tabFocusList   where     go :: Notebook -> TMNotebookTab -> IO ()@@ -411,12 +426,13 @@ -- | Add a page to the notebook and switch to it. addPage   :: TMState+  -> TMWindowId   -> TMNotebookTab   -> Box   -- ^ The GTK Object holding the label we want to show for the tab of the   -- newly created page of the notebook.   -> IO ()-addPage mvarTMState notebookTab tabLabelBox = do+addPage mvarTMState tmWinId notebookTab tabLabelBox = do   -- Append a new notebook page and update the TMState to reflect this.   (note, pageIndex) <- modifyMVar mvarTMState appendNotebookPage @@ -425,8 +441,8 @@   where     appendNotebookPage :: TMState' -> IO (TMState', (Notebook, Int32))     appendNotebookPage tmState = do-      let notebook = tmStateNotebook tmState-          note = tmNotebook notebook+      notebook <- getTMNotebookFromTMState' tmState tmWinId+      let note = tmNotebook notebook           tabs = tmNotebookTabs notebook           scrolledWin = tmNotebookTabTermContainer notebookTab       pageIndex <- notebookAppendPage note scrolledWin (Just tabLabelBox)@@ -434,7 +450,10 @@       setShowTabs (tmState ^. lensTMStateConfig) note       let newTabs = appendFL tabs notebookTab           newTMState =-            tmState & lensTMStateNotebook . lensTMNotebookTabs .~ newTabs+            set+              (lensTMStateWindows . ix tmWinId . lensTMWindowNotebook . lensTMNotebookTabs)+              newTabs+              tmState       pure (newTMState, (note, pageIndex))  -- | Set the keyboard focus on a vte terminal@@ -445,17 +464,23 @@  -- | Create a new 'TMTerm', setting it up and adding it to the GTKNotebook. createTerm-  :: (TMState -> EventKey -> IO Bool)+  :: (TMState -> TMWindowId -> EventKey -> IO Bool)   -- ^ Funtion for handling key presses on the terminal.   -> TMState+  -> TMWindowId   -> IO TMTerm-createTerm handleKeyPress mvarTMState = do+createTerm handleKeyPress mvarTMState tmWinId = do   -- Check preconditions   assertInvariantTMState mvarTMState    -- Read needed data in TMVar-  TMState{tmStateAppWin, tmStateFontDesc, tmStateConfig, tmStateNotebook=currNote} <-+  -- TMState{tmStateAppWin, tmStateFontDesc, tmStateConfig, tmStateNotebook=currNote} <-+  --   readMVar mvarTMState+  TMState{tmStateFontDesc, tmStateConfig, tmStateWindows} <-     readMVar mvarTMState+  tmWin <- getTMWindowFromWins tmStateWindows tmWinId+  let appWin = tmWindowAppWin tmWin+      currNote = tmWindowNotebook tmWin    -- Create a new terminal and launch a shell in it   vteTerm <- createAndInitVteTerm tmStateFontDesc (options tmStateConfig)@@ -474,7 +499,7 @@   let notebookTab = createTMNotebookTab tabLabel scrolledWin tmTerm    -- Add the new notebooktab to the notebook.-  addPage mvarTMState notebookTab tabLabelBox+  addPage mvarTMState tmWinId notebookTab tabLabelBox    -- Setup the initial label for the notebook tab.  This needs to happen   -- after we add the new page to the notebook, so that the page can get labelled@@ -482,15 +507,13 @@   relabelTab (tmNotebook currNote) tabLabel scrolledWin vteTerm    -- Connect callbacks-  void $ onButtonClicked tabCloseButton $ termClose notebookTab mvarTMState+  void $ onButtonClicked tabCloseButton $ termClose notebookTab mvarTMState tmWinId   void $ onTerminalWindowTitleChanged vteTerm $ do-    TMState{tmStateNotebook} <- readMVar mvarTMState-    let notebook = tmNotebook tmStateNotebook-    relabelTab notebook tabLabel scrolledWin vteTerm-  void $ onWidgetKeyPressEvent vteTerm $ handleKeyPress mvarTMState-  void $ onWidgetKeyPressEvent scrolledWin $ handleKeyPress mvarTMState-  void $ onWidgetButtonPressEvent vteTerm $ handleMousePress tmStateAppWin vteTerm-  void $ onTerminalChildExited vteTerm $ \_ -> termExit notebookTab mvarTMState+    relabelTab (tmNotebook currNote) tabLabel scrolledWin vteTerm+  void $ onWidgetKeyPressEvent vteTerm $ handleKeyPress mvarTMState tmWinId+  void $ onWidgetKeyPressEvent scrolledWin $ handleKeyPress mvarTMState tmWinId+  void $ onWidgetButtonPressEvent vteTerm $ handleMousePress appWin vteTerm+  void $ onTerminalChildExited vteTerm $ \_ -> termExit notebookTab mvarTMState tmWinId    -- Underline URLs so that the user can see they are right-clickable.   --@@ -506,11 +529,11 @@         "(?:http(s)?:\\/\\/)[\\w.-]+(?:\\.[\\w\\.-]+)+[\\w\\-\\._~:/?#[\\]@!\\$&'\\(\\)\\*\\+,;=.]+"   -- We must set the pcre2Multiline option, otherwise VTE prints a warning.   let pcreFlags = fromIntegral pcre2Multiline-  regex <- regexNewForMatch regexPat (fromIntegral $ length regexPat) pcreFlags+  regex <- regexNewForMatch regexPat (fromIntegral $ Text.length regexPat) pcreFlags   void $ terminalMatchAddRegex vteTerm regex 0    -- Put the keyboard focus on the term-  setFocusOn tmStateAppWin vteTerm+  setFocusOn appWin vteTerm    -- Make sure the state is still right   assertInvariantTMState mvarTMState
src/Termonad/Types.hs view
@@ -4,8 +4,9 @@  import Termonad.Prelude -import Control.Monad.Fail (fail)-import Data.FocusList (FocusList, emptyFL, singletonFL, getFocusItemFL, lengthFL)+import Control.Lens (ifoldMap)+import Data.FocusList (FocusList, emptyFL, getFocusItemFL, lengthFL)+import Data.Foldable (toList) import Data.Unique (Unique, hashUnique, newUnique) import Data.Yaml   ( FromJSON(parseJSON)@@ -25,12 +26,11 @@   , notebookGetNthPage   , notebookGetNPages   )-import GI.Pango (FontDescription)+import GI.Pango (FontDescription, fontDescriptionGetSize, fontDescriptionGetSizeIsAbsolute, pattern SCALE, fontDescriptionGetFamily, fontDescriptionNew, fontDescriptionSetFamily, fontDescriptionSetSize, fontDescriptionSetAbsoluteSize) import GI.Vte (Terminal, CursorBlinkMode(..))-import Text.Pretty.Simple (pPrint)-import Text.Show (ShowS, showParen, showString)- import Termonad.Gtk (widgetEq)+import Termonad.IdMap (IdMap, IdMapKey, singletonIdMap, lookupIdMap)+import Text.Pretty.Simple (pPrint)  -- | A wrapper around a VTE 'Terminal'.  This also stores the process ID of the -- process running on this terminal, as well as a 'Unique' that can be used for@@ -107,12 +107,71 @@       showsPrec (d + 1) tmNotebookTabs .       showString "}" +getNotebookFromTMState :: TMState -> TMWindowId -> IO Notebook+getNotebookFromTMState mvarTMState tmWinId = do+  tmNote <- getTMNotebookFromTMState mvarTMState tmWinId+  pure $ tmNotebook tmNote++getNotebookFromTMState' :: TMState' -> TMWindowId -> IO Notebook+getNotebookFromTMState' tmState tmWinId = do+  tmNote <- getTMNotebookFromTMState' tmState tmWinId+  pure $ tmNotebook tmNote++getTMNotebookFromTMState :: TMState -> TMWindowId -> IO TMNotebook+getTMNotebookFromTMState mvarTMState tmWinId = do+  tmWin <- getTMWindowFromTMState mvarTMState tmWinId+  pure $ tmWindowNotebook tmWin++getTMNotebookFromTMState' :: TMState' -> TMWindowId -> IO TMNotebook+getTMNotebookFromTMState' tmState tmWinId = do+  tmWin <- getTMWindowFromTMState' tmState tmWinId+  pure $ tmWindowNotebook tmWin++data TMWindow = TMWindow+  { tmWindowAppWin :: !ApplicationWindow+  , tmWindowNotebook :: !TMNotebook+  }++instance Show TMWindow where+  showsPrec :: Int -> TMWindow -> ShowS+  showsPrec d TMWindow{..} =+    showParen (d > 10) $+      showString "TMWindow {" .+      showString "tmWindowAppWin = " .+      showString "(GI.GTK.ApplicationWindow)" .+      showString ", " .+      showString "tmWindowNotebook = " .+      showsPrec (d + 1) tmWindowNotebook .+      showString "}"++type TMWindowId = IdMapKey++-- | Get a given 'TMWindow' from a set of 'TMWindow's given a 'TMWindowId'.+--+-- This throws an error if the 'TMWindowId' can't be found within the 'IdMap'.+getTMWindowFromWins :: IdMap TMWindow -> TMWindowId -> IO TMWindow+getTMWindowFromWins tmWins tmWinId =+  case lookupIdMap tmWinId tmWins of+    Nothing -> error $ "getTMWindowFromWins: trying to get id " <> show tmWinId <> " from wins, but doesn't exist: " <> show tmWins+    Just tmWin -> pure tmWin++-- | Get a given 'TMWindow' froma a 'TMState' given a 'TMWindowId'.+--+-- This throws an error if the 'TMWindowId' can't be found within the 'TMState'.+getTMWindowFromTMState :: TMState -> TMWindowId -> IO TMWindow+getTMWindowFromTMState mvarTMState tmWinId = do+  TMState{tmStateWindows} <- readMVar mvarTMState+  getTMWindowFromWins tmStateWindows tmWinId++getTMWindowFromTMState' :: TMState' -> TMWindowId -> IO TMWindow+getTMWindowFromTMState' tmState tmWinId =+  getTMWindowFromWins (tmStateWindows tmState) tmWinId+ data TMState' = TMState   { tmStateApp :: !Application-  , tmStateAppWin :: !ApplicationWindow-  , tmStateNotebook :: !TMNotebook-  , tmStateFontDesc :: !FontDescription   , tmStateConfig :: !TMConfig+  , tmStateFontDesc :: !FontDescription+  , tmStateWindows :: !(IdMap TMWindow)   }  instance Show TMState' where@@ -123,17 +182,14 @@       showString "tmStateApp = " .       showString "(GI.GTK.Application)" .       showString ", " .-      showString "tmStateAppWin = " .-      showString "(GI.GTK.ApplicationWindow)" .-      showString ", " .-      showString "tmStateNotebook = " .-      showsPrec (d + 1) tmStateNotebook .+      showString "tmStateConfig = " .+      showsPrec (d + 1) tmStateConfig .       showString ", " .       showString "tmStateFontDesc = " .       showString "(GI.Pango.FontDescription)" .       showString ", " .-      showString "tmStateConfig = " .-      showsPrec (d + 1) tmStateConfig .+      showString "tmStateWindows = " .+      showsPrec (d + 1) tmStateWindows .       showString "}"  type TMState = MVar TMState'@@ -157,14 +213,14 @@ newTMTerm :: Terminal -> Int -> IO TMTerm newTMTerm trm pd = createTMTerm trm pd <$> newUnique -getFocusedTermFromState :: TMState -> IO (Maybe Terminal)-getFocusedTermFromState mvarTMState =+getFocusedTermFromState :: TMState -> TMWindowId -> IO (Maybe Terminal)+getFocusedTermFromState mvarTMState tmWinId =   withMVar mvarTMState go   where     go :: TMState' -> IO (Maybe Terminal)     go tmState = do-      let maybeNotebookTab =-            getFocusItemFL $ tmNotebookTabs $ tmStateNotebook tmState+      tmNote <- getTMNotebookFromTMState' tmState tmWinId+      let maybeNotebookTab = getFocusItemFL $ tmNotebookTabs tmNote       pure $ fmap (term . tmNotebookTabTerm) maybeNotebookTab  createTMNotebookTab :: Label -> ScrolledWindow -> TMTerm -> TMNotebookTab@@ -195,50 +251,27 @@             Nothing -> pure acc             Just notePage' -> unfoldHelper (index32 + 1) (acc ++ [notePage']) -newTMState :: TMConfig -> Application -> ApplicationWindow -> TMNotebook -> FontDescription -> IO TMState-newTMState tmConfig app appWin note fontDesc =-  newMVar $-    TMState-      { tmStateApp = app-      , tmStateAppWin = appWin-      , tmStateNotebook = note-      , tmStateFontDesc = fontDesc-      , tmStateConfig = tmConfig-      }--newEmptyTMState :: TMConfig -> Application -> ApplicationWindow -> Notebook -> FontDescription -> IO TMState-newEmptyTMState tmConfig app appWin note fontDesc =-  newMVar $-    TMState-      { tmStateApp = app-      , tmStateAppWin = appWin-      , tmStateNotebook = createEmptyTMNotebook note-      , tmStateFontDesc = fontDesc-      , tmStateConfig = tmConfig-      }--newTMStateSingleTerm ::-     TMConfig-  -> Application-  -> ApplicationWindow-  -> Notebook-  -> Label-  -> ScrolledWindow-  -> Terminal-  -> Int-  -> FontDescription-  -> IO TMState-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-  newTMState tmConfig app appWin tmNote fontDesc+createTMWindow :: ApplicationWindow -> TMNotebook -> TMWindow+createTMWindow appwin notebook =+  TMWindow+    { tmWindowAppWin = appwin+    , tmWindowNotebook = notebook+    } -traceShowMTMState :: TMState -> IO ()-traceShowMTMState mvarTMState = do-  tmState <- readMVar mvarTMState-  print tmState+newEmptyTMState :: TMConfig -> Application -> ApplicationWindow -> Notebook -> FontDescription -> IO (TMState, TMWindowId)+newEmptyTMState tmConfig app appWin note fontDesc = do+  let tmnote = createEmptyTMNotebook note+      tmwin = createTMWindow appWin tmnote+      (tmwinId, tmwins) = singletonIdMap tmwin+  tmState <-+    newMVar $+      TMState+        { tmStateApp = app+        , tmStateConfig = tmConfig+        , tmStateFontDesc = fontDesc+        , tmStateWindows = tmwins+        }+  pure (tmState, tmwinId)  ------------ -- Config --@@ -299,6 +332,42 @@   let newUnits = oldUnits + fromIntegral i   in FontSizeUnits $ if newUnits < 1 then oldUnits else newUnits +fontSizeFromFontDescription :: FontDescription -> IO FontSize+fontSizeFromFontDescription fontDesc = do+  currSize <- fontDescriptionGetSize fontDesc+  currAbsolute <- fontDescriptionGetSizeIsAbsolute fontDesc+  pure $+    if currAbsolute+    then FontSizeUnits $ fromIntegral currSize / fromIntegral SCALE+    else+      let fontRatio :: Double = fromIntegral currSize / fromIntegral SCALE+      in FontSizePoints $ round fontRatio++-- | Create a 'FontDescription' from a 'FontSize' and font family.+createFontDesc+  :: FontSize+  -> Text+  -- ^ font family+  -> IO FontDescription+createFontDesc fontSz fontFam = do+  fontDesc <- fontDescriptionNew+  fontDescriptionSetFamily fontDesc fontFam+  setFontDescSize fontDesc fontSz+  pure fontDesc++-- | Set the size of a 'FontDescription' from a 'FontSize'.+setFontDescSize :: FontDescription -> FontSize -> IO ()+setFontDescSize fontDesc (FontSizePoints points) =+  fontDescriptionSetSize fontDesc $ fromIntegral (points * fromIntegral SCALE)+setFontDescSize fontDesc (FontSizeUnits units) =+  fontDescriptionSetAbsoluteSize fontDesc $ units * fromIntegral SCALE++-- | Create a 'FontDescription' from the 'fontSize' and 'fontFamily' inside a 'TMConfig'.+createFontDescFromConfig :: TMConfig -> IO FontDescription+createFontDescFromConfig tmConfig = do+  let fontConf = fontConfig (options tmConfig)+  createFontDesc (fontSize fontConf) (fontFamily fontConf)+ -- | Settings for the font to be used in Termonad. data FontConfig = FontConfig   { fontFamily :: !Text@@ -318,6 +387,12 @@     , fontSize = defaultFontSize     } +fontConfigFromFontDescription :: FontDescription -> IO (Maybe FontConfig)+fontConfigFromFontDescription fontDescription = do+  fontSize <- fontSizeFromFontDescription fontDescription+  maybeFontFamily <- fontDescriptionGetFamily fontDescription+  return $ (`FontConfig` fontSize) <$> maybeFontFamily+ -- | This data type represents an option that can either be 'Set' or 'Unset'. -- -- This data type is used in situations where leaving an option unset results@@ -327,7 +402,8 @@ -- supplied by the 'ColourConfig' @ConfigExtension@.  By default, -- 'cursorFgColour' and 'cursorBgColour' are both 'Unset'.  However, when -- 'cursorBgColour' is 'Set', 'cursorFgColour' defaults to the color of the text--- underneath.  There is no way to represent this by setting 'cursorFgColour'.+-- underneath.  There is no way to represent this by explicitly setting+-- 'cursorFgColour'. data Option a = Unset | Set !a   deriving (Show, Read, Eq, Ord, Functor, Foldable) @@ -354,6 +430,19 @@                           -- lines on the terminal to show all at once.   deriving (Enum, Eq, Generic, FromJSON, Show, ToJSON) +showScrollbarToString :: ShowScrollbar -> Text+showScrollbarToString = \case+  ShowScrollbarNever -> "never"+  ShowScrollbarAlways -> "always"+  ShowScrollbarIfNeeded -> "if-needed"++showScrollbarFromString :: Text -> Maybe ShowScrollbar+showScrollbarFromString = \case+  "never" -> Just ShowScrollbarNever+  "always" -> Just ShowScrollbarAlways+  "if-needed" -> Just ShowScrollbarIfNeeded+  _ -> Nothing+ -- | Whether or not to show the tab bar for switching tabs. data ShowTabBar   = ShowTabBarNever -- ^ Never show the tab bar, even if there are multiple tabs@@ -362,6 +451,19 @@   | ShowTabBarIfNeeded  -- ^ Only show the tab bar if you have multiple tabs open.   deriving (Enum, Eq, Generic, FromJSON, Show, ToJSON) +showTabBarToString :: ShowTabBar -> Text+showTabBarToString = \case+  ShowTabBarNever -> "never"+  ShowTabBarAlways -> "always"+  ShowTabBarIfNeeded -> "if-needed"++showTabBarFromString :: Text -> Maybe ShowTabBar+showTabBarFromString = \case+  "never" -> Just ShowTabBarNever+  "always" -> Just ShowTabBarAlways+  "if-needed" -> Just ShowTabBarIfNeeded+  _ -> Nothing+ -- | Configuration options for Termonad. -- -- See 'defaultConfigOptions' for the default values.@@ -424,6 +526,20 @@     -- doesn't look good when bold.   } deriving (Eq, Generic, FromJSON, Show, ToJSON) +cursorBlinkModeToString :: CursorBlinkMode -> Text+cursorBlinkModeToString = \case+  CursorBlinkModeSystem -> "system"+  CursorBlinkModeOn -> "on"+  CursorBlinkModeOff -> "off"+  AnotherCursorBlinkMode _ -> "other"++cursorBlinkModeFromString :: Text -> Maybe CursorBlinkMode+cursorBlinkModeFromString = \case+  "system" -> Just CursorBlinkModeSystem+  "on" -> Just CursorBlinkModeOn+  "off" -> Just CursorBlinkModeOff+  _ -> Nothing+ instance FromJSON CursorBlinkMode where   parseJSON = withText "CursorBlinkMode" $ \c -> do     case (c :: Text) of@@ -543,32 +659,36 @@                                 -- the actual GTK 'Notebook' and the 'FocusList'.   deriving (Show) -data TMStateInvariantErr+-- | An invariant error on a given 'TMWindow'.+data TMWinInvariantErr   = FocusNotSame FocusNotSameErr Int   | TabsDoNotMatch TabsDoNotMatch   deriving Show --- | Gather up the invariants for 'TMState' and return them as a list.------ If no invariants have been violated, then this function should return an--- empty list.-invariantTMState' :: TMState' -> IO [TMStateInvariantErr]-invariantTMState' tmState =+-- | An invariant error on a whole 'TMState'.+data TMStateInvariantErr+  = TMWinInvariantErr Int TMWinInvariantErr+    -- ^ An invariant error with a given 'TMWindow'.  The 'Int' indicates+    -- which window it is as an index into 'tmStateWindows'.+  deriving Show++invariantTMWindow :: TMWindow -> IO [TMWinInvariantErr]+invariantTMWindow tmWin =   runInvariants     [ invariantFocusSame     , invariantTMTabLength     , invariantTabsAllMatch     ]   where-    runInvariants :: [IO (Maybe TMStateInvariantErr)] -> IO [TMStateInvariantErr]+    runInvariants :: [IO (Maybe TMWinInvariantErr)] -> IO [TMWinInvariantErr]     runInvariants = fmap catMaybes . sequence -    invariantFocusSame :: IO (Maybe TMStateInvariantErr)+    invariantFocusSame :: IO (Maybe TMWinInvariantErr)     invariantFocusSame = do-      let tmNote = tmNotebook $ tmStateNotebook tmState+      let tmNote = tmNotebook $ tmWindowNotebook tmWin       index32 <- notebookGetCurrentPage tmNote       maybeWidgetFromNote <- notebookGetNthPage tmNote index32-      let focusList = tmNotebookTabs $ tmStateNotebook tmState+      let focusList = tmNotebookTabs $ tmWindowNotebook tmWin           maybeScrollWinFromFL =             tmNotebookTabTermContainer <$> getFocusItemFL focusList           idx = fromIntegral index32@@ -591,12 +711,12 @@                 Just $                   FocusNotSame NotebookTabWidgetDiffersFromFocusListFocus idx -    invariantTMTabLength :: IO (Maybe TMStateInvariantErr)+    invariantTMTabLength :: IO (Maybe TMWinInvariantErr)     invariantTMTabLength = do-      let tmNote = tmNotebook $ tmStateNotebook tmState+      let tmNote = tmNotebook $ tmWindowNotebook tmWin       noteLength32 <- notebookGetNPages tmNote       let noteLength = fromIntegral noteLength32-          focusListLength = lengthFL $ tmNotebookTabs $ tmStateNotebook tmState+          focusListLength = lengthFL $ tmNotebookTabs $ tmWindowNotebook tmWin           lengthEqual = focusListLength == noteLength       if lengthEqual         then pure Nothing@@ -606,10 +726,10 @@                  TabLengthsDifferent noteLength focusListLength      -- Turns a FocusList and Notebook into two lists of widgets and compares each widget for equality-    invariantTabsAllMatch :: IO (Maybe TMStateInvariantErr)+    invariantTabsAllMatch :: IO (Maybe TMWinInvariantErr)     invariantTabsAllMatch = do-      let tmNote = tmNotebook $ tmStateNotebook tmState-          focusList = tmNotebookTabs $ tmStateNotebook tmState+      let tmNote = tmNotebook $ tmWindowNotebook tmWin+          focusList = tmNotebookTabs $ tmWindowNotebook tmWin           flList = tmNotebookTabTermContainer <$> toList focusList       noteList <- notebookToList tmNote       tabsMatch noteList flList@@ -619,16 +739,30 @@            . (IsWidget a, IsWidget b)           => [a]           -> [b]-          -> IO (Maybe TMStateInvariantErr)+          -> IO (Maybe TMWinInvariantErr)         tabsMatch xs ys = foldr go (pure Nothing) (zip3 xs ys [0..])           where-            go :: (a, b, Int) -> IO (Maybe TMStateInvariantErr) -> IO (Maybe TMStateInvariantErr)+            go :: (a, b, Int) -> IO (Maybe TMWinInvariantErr) -> IO (Maybe TMWinInvariantErr)             go (x, y, i) acc = do               isEq <- widgetEq x y               if isEq                 then acc                 else pure . Just $ TabsDoNotMatch (TabAtIndexDifferent i) +-- | Gather up the invariants for 'TMState' and return them as a list.+--+-- If no invariants have been violated, then this function should return an+-- empty list.+invariantTMState' :: TMState' -> IO [TMStateInvariantErr]+invariantTMState' tmState = do+  let tmWindows = tmStateWindows tmState+  ifoldMap go tmWindows+  where+    go :: Int -> TMWindow -> IO [TMStateInvariantErr]+    go idx tmWin = do+      tmWinErrs <- invariantTMWindow tmWin+      pure $ fmap (TMWinInvariantErr idx) tmWinErrs+ -- | Check the invariants for 'TMState', and call 'fail' if we find that they -- have been violated. assertInvariantTMState :: TMState -> IO ()@@ -650,3 +784,8 @@ pPrintTMState mvarTMState = do   tmState <- readMVar mvarTMState   pPrint tmState++traceShowMTMState :: TMState -> IO ()+traceShowMTMState mvarTMState = do+  tmState <- readMVar mvarTMState+  print tmState
+ src/Termonad/Window.hs view
@@ -0,0 +1,386 @@++module Termonad.Window where++import Termonad.Prelude++import Control.Lens ((^.), (^..), set, view, ix)+import Data.FocusList (focusList, moveFromToFL, updateFocusFL)+import Data.Sequence (findIndexR)+import qualified Data.Text as Text+import GI.Gdk (castTo, managedForeignPtr)+import GI.Gio+  ( actionMapAddAction+  , onSimpleActionActivate+  , simpleActionNew+  )+import GI.Gtk+  ( Application+  , ApplicationWindow+  , Notebook+  , PositionType(PositionTypeRight)+  , ResponseType(ResponseTypeNo, ResponseTypeYes)+  , ScrolledWindow(ScrolledWindow)+  , Widget+  , aboutDialogNew+  , applicationSetAccelsForAction+  , containerAdd+  , dialogAddButton+  , dialogGetContentArea+  , dialogNew+  , dialogResponse+  , dialogRun+  , entryGetText+  , entryNew+  , gridAttachNextTo+  , gridNew+  , labelNew+  , onEntryActivate+  , onNotebookPageReordered+  , onNotebookSwitchPage+  , setWidgetMargin+  , widgetDestroy+  , widgetGrabFocus+  , widgetShow+  , windowSetTransientFor+  )+import GI.Pango (FontDescription)+import GI.Vte+  ( catchRegexError+  , regexNewForSearch+  , terminalCopyClipboard+  , terminalPasteClipboard+  , terminalSearchFindNext+  , terminalSearchFindPrevious+  , terminalSearchSetRegex+  , terminalSearchSetWrapAround+  , terminalSetFont+  )+import Termonad.Keys (handleKeyPress)+import Termonad.Lenses+  ( lensTMNotebookTabs+  , lensTMNotebookTabTerm+  , lensTMStateFontDesc+  , lensTerm+  , lensTMStateWindows+  , lensTMWindowNotebook+  )+import Termonad.Term+  ( createTerm+  , relabelTabs+  , termNextPage+  , termPrevPage+  , termExitFocused+  )+import Termonad.Types+  ( FontSize+  , TMNotebookTab+  , TMState+  , TMWindowId+  , fontSizeFromFontDescription+  , getFocusedTermFromState+  , getTMNotebookFromTMState+  , getTMNotebookFromTMState'+  , getTMWindowFromTMState+  , setFontDescSize+  , tmNotebookTabTermContainer+  , tmNotebookTabs+  , tmWindowAppWin+  )++modifyFontSizeForAllTerms :: (FontSize -> FontSize) -> TMState -> TMWindowId -> IO ()+modifyFontSizeForAllTerms modFontSizeFunc mvarTMState tmWinId = do+  tmState <- readMVar mvarTMState+  let fontDesc = tmState ^. lensTMStateFontDesc+  adjustFontDescSize modFontSizeFunc fontDesc+  let terms =+        tmState ^..+          lensTMStateWindows .+          ix tmWinId .+          lensTMWindowNotebook .+          lensTMNotebookTabs .+          traverse .+          lensTMNotebookTabTerm .+          lensTerm+  foldMap (\vteTerm -> terminalSetFont vteTerm (Just fontDesc)) terms+  where+    adjustFontDescSize :: (FontSize -> FontSize) -> FontDescription -> IO ()+    adjustFontDescSize f fontDesc = do+      currFontSz <- fontSizeFromFontDescription fontDesc+      let newFontSz = f currFontSz+      setFontDescSize fontDesc newFontSz++-- | This is the callback for when a page in a 'Notebook' has been reordered+-- (normally caused by a drag-and-drop event).+notebookPageReorderedCallback+  :: TMState+  -> TMWindowId+  -> Widget+  -- ^ The child widget that is in the Notebook page.+  -> Word32+  -- ^ The new index of the Notebook page.+  -> IO ()+notebookPageReorderedCallback mvarTMState tmWinId childWidg pageNum = do+  maybeScrollWin <- castTo ScrolledWindow childWidg+  case maybeScrollWin of+    Nothing ->+      fail $+        "In setupTermonad, in callback for onNotebookPageReordered, " <>+        "child widget is not a ScrolledWindow.\n" <>+        "Don't know how to continue.\n"+    Just scrollWin -> do+      tmNote <- getTMNotebookFromTMState mvarTMState tmWinId+      let fl = view lensTMNotebookTabs tmNote+      let maybeOldPosition =+            findIndexR (compareScrolledWinAndTab scrollWin) (focusList fl)+      case maybeOldPosition of+        Nothing ->+          fail $+            "In setupTermonad, in callback for onNotebookPageReordered, " <>+            "the ScrolledWindow is not already in the FocusList.\n" <>+            "Don't know how to continue.\n"+        Just oldPos -> do+          updateFLTabPos mvarTMState tmWinId oldPos (fromIntegral pageNum)+          tmNote' <- getTMNotebookFromTMState mvarTMState tmWinId+          relabelTabs tmNote'+  where+    compareScrolledWinAndTab :: ScrolledWindow -> TMNotebookTab -> Bool+    compareScrolledWinAndTab scrollWin flTab =+      let ScrolledWindow managedPtrFLTab = tmNotebookTabTermContainer flTab+          foreignPtrFLTab = managedForeignPtr managedPtrFLTab+          ScrolledWindow managedPtrScrollWin = scrollWin+          foreignPtrScrollWin = managedForeignPtr managedPtrScrollWin+      in foreignPtrFLTab == foreignPtrScrollWin++-- | Move a 'TMNotebookTab' from one position to another.+--+-- If the current position index is out of bounds, or the new index is out of+-- bounds, then nothing will be done.+--+-- Note that this function doesn't change anything about the 'tmNotebook'.+-- This function is meant to be used as a call-back for when a 'Notebook's+-- tab-order has been changed.+updateFLTabPos+  :: TMState+  -> TMWindowId+  -> Int+  -- ^ Current position index.+  -> Int+  -- ^ New position index.+  -> IO ()+updateFLTabPos mvarTMState tmWinId oldPos newPos =+  modifyMVar_ mvarTMState $ \tmState -> do+    note <- getTMNotebookFromTMState' tmState tmWinId+    let tabs = tmNotebookTabs note+        maybeNewTabs = moveFromToFL oldPos newPos tabs+    case maybeNewTabs of+      Nothing -> do+        putStrLn $+          "in updateFLTabPos, Strange error: couldn't move tabs.\n" <>+          "old pos: " <> show oldPos <> "\n" <>+          "new pos: " <> show newPos <> "\n" <>+          "tabs: " <> show tabs <> "\n" <>+          "maybeNewTabs: " <> show maybeNewTabs <> "\n" <>+          "tmState: " <> show tmState+        pure tmState+      Just newTabs ->+        pure $+          set+            (lensTMStateWindows . ix tmWinId . lensTMWindowNotebook . lensTMNotebookTabs)+            newTabs+            tmState++showAboutDialog :: ApplicationWindow -> IO ()+showAboutDialog win = do+  aboutDialog <- aboutDialogNew+  windowSetTransientFor aboutDialog (Just win)+  void $ dialogRun aboutDialog+  widgetDestroy aboutDialog++showFindDialog :: ApplicationWindow -> IO (Maybe Text)+showFindDialog win = do+  dialog <- dialogNew+  box <- dialogGetContentArea dialog+  grid <- gridNew++  searchForLabel <- labelNew (Just "Search for regex:")+  containerAdd grid searchForLabel+  widgetShow searchForLabel+  setWidgetMargin searchForLabel 10++  searchEntry <- entryNew+  gridAttachNextTo grid searchEntry (Just searchForLabel) PositionTypeRight 1 1+  widgetShow searchEntry+  setWidgetMargin searchEntry 10+  -- setWidgetMarginBottom searchEntry 20+  void $+    onEntryActivate searchEntry $+      dialogResponse dialog (fromIntegral (fromEnum ResponseTypeYes))++  void $+    dialogAddButton+      dialog+      "Close"+      (fromIntegral (fromEnum ResponseTypeNo))+  void $+    dialogAddButton+      dialog+      "Find"+      (fromIntegral (fromEnum ResponseTypeYes))++  containerAdd box grid+  widgetShow grid+  windowSetTransientFor dialog (Just win)+  res <- dialogRun dialog++  searchString <- entryGetText searchEntry+  let maybeSearchString =+        case toEnum (fromIntegral res) of+          ResponseTypeYes -> Just searchString+          _ -> Nothing++  widgetDestroy dialog++  pure maybeSearchString++doFind :: TMState -> TMWindowId -> IO ()+doFind mvarTMState tmWinId = do+  tmWin <- getTMWindowFromTMState mvarTMState tmWinId+  let win = tmWindowAppWin tmWin+  maybeSearchString <- showFindDialog win+  -- putStrLn $ "trying to find: " <> tshow maybeSearchString+  maybeTerminal <- getFocusedTermFromState mvarTMState tmWinId+  case (maybeSearchString, maybeTerminal) of+    (Just searchString, Just terminal) -> do+      -- TODO: Figure out how to import the correct pcre flags.+      --+      -- If you don't pass the pcre2Multiline flag, VTE gives+      -- the following warning:+      --+      -- (termonad-linux-x86_64:18792): Vte-WARNING **:+      -- 21:56:31.193: (vtegtk.cc:2269):void+      -- vte_terminal_search_set_regex(VteTerminal*,+      -- VteRegex*, guint32): runtime check failed:+      -- (regex == nullptr ||+      -- _vte_regex_get_compile_flags(regex) & PCRE2_MULTILINE)+      --+      -- However, if you do add the pcre2Multiline flag,+      -- the terminalSearchSetRegex appears to just completely+      -- not work.+      let pcreFlags = 0+      let newRegex =+            regexNewForSearch+              searchString+              (fromIntegral $ Text.length searchString)+              pcreFlags+      eitherRegex <-+        catchRegexError+          (fmap Right newRegex)+          (\_ errMsg -> pure (Left errMsg))+      case eitherRegex of+        Left errMsg -> do+          let msg = "error when creating regex: " <> errMsg+          hPutStrLn stderr msg+        Right regex -> do+          terminalSearchSetRegex terminal (Just regex) pcreFlags+          terminalSearchSetWrapAround terminal True+          _matchFound <- terminalSearchFindPrevious terminal+          -- TODO: Setup an actual logging framework to show these+          -- kinds of log messages.  Also make a similar change in+          -- findAbove and findBelow.+          -- putStrLn $ "was match found: " <> tshow matchFound+          pure ()+    _ -> pure ()++findAbove :: TMState -> TMWindowId -> IO ()+findAbove mvarTMState tmWinId = do+  maybeTerminal <- getFocusedTermFromState mvarTMState tmWinId+  case maybeTerminal of+    Nothing -> pure ()+    Just terminal -> do+      _matchFound <- terminalSearchFindPrevious terminal+      -- putStrLn $ "was match found: " <> tshow matchFound+      pure ()++findBelow :: TMState -> TMWindowId -> IO ()+findBelow mvarTMState tmWinId = do+  maybeTerminal <- getFocusedTermFromState mvarTMState tmWinId+  case maybeTerminal of+    Nothing -> pure ()+    Just terminal -> do+      _matchFound <- terminalSearchFindNext terminal+      -- putStrLn $ "was match found: " <> tshow matchFound+      pure ()++setupWindowCallbacks :: TMState -> Application -> ApplicationWindow -> Notebook -> TMWindowId -> IO ()+setupWindowCallbacks mvarTMState app win note tmWinId = do++  void $ onNotebookSwitchPage note $ \_ pageNum -> do+    modifyMVar_ mvarTMState $ \tmState -> do+      tmNote <- getTMNotebookFromTMState' tmState tmWinId+      let tabs = tmNotebookTabs tmNote+          maybeNewTabs = updateFocusFL (fromIntegral pageNum) tabs+      case maybeNewTabs of+        Nothing -> pure tmState+        Just (tab, newTabs) -> do+          widgetGrabFocus $ tab ^. lensTMNotebookTabTerm . lensTerm+          pure $+            set+              (lensTMStateWindows . ix tmWinId . lensTMWindowNotebook . lensTMNotebookTabs)+              newTabs+              tmState++  void $ onNotebookPageReordered note $ \childWidg pageNum ->+    notebookPageReorderedCallback mvarTMState tmWinId childWidg pageNum++  newTabAction <- simpleActionNew "newtab" Nothing+  void $ onSimpleActionActivate newTabAction $ \_ ->+    void $ createTerm handleKeyPress mvarTMState tmWinId+  actionMapAddAction win newTabAction+  applicationSetAccelsForAction app "win.newtab" ["<Shift><Ctrl>T"]++  nextPageAction <- simpleActionNew "nextpage" Nothing+  void $ onSimpleActionActivate nextPageAction $ \_ ->+    termNextPage mvarTMState tmWinId+  actionMapAddAction win nextPageAction+  applicationSetAccelsForAction app "win.nextpage" ["<Ctrl>Page_Down"]++  prevPageAction <- simpleActionNew "prevpage" Nothing+  void $ onSimpleActionActivate prevPageAction $ \_ ->+    termPrevPage mvarTMState tmWinId+  actionMapAddAction win prevPageAction+  applicationSetAccelsForAction app "win.prevpage" ["<Ctrl>Page_Up"]++  closeTabAction <- simpleActionNew "closetab" Nothing+  void $ onSimpleActionActivate closeTabAction $ \_ ->+    termExitFocused mvarTMState tmWinId+  actionMapAddAction win closeTabAction+  applicationSetAccelsForAction app "win.closetab" ["<Shift><Ctrl>W"]++  copyAction <- simpleActionNew "copy" Nothing+  void $ onSimpleActionActivate copyAction $ \_ -> do+    maybeTerm <- getFocusedTermFromState mvarTMState tmWinId+    maybe (pure ()) terminalCopyClipboard maybeTerm+  actionMapAddAction win copyAction+  applicationSetAccelsForAction app "win.copy" ["<Shift><Ctrl>C"]++  pasteAction <- simpleActionNew "paste" Nothing+  void $ onSimpleActionActivate pasteAction $ \_ -> do+    maybeTerm <- getFocusedTermFromState mvarTMState tmWinId+    maybe (pure ()) terminalPasteClipboard maybeTerm+  actionMapAddAction win pasteAction+  applicationSetAccelsForAction app "win.paste" ["<Shift><Ctrl>V"]++  findAction <- simpleActionNew "find" Nothing+  void $ onSimpleActionActivate findAction $ \_ -> doFind mvarTMState tmWinId+  actionMapAddAction win findAction+  applicationSetAccelsForAction app "win.find" ["<Shift><Ctrl>F"]++  findAboveAction <- simpleActionNew "findabove" Nothing+  void $ onSimpleActionActivate findAboveAction $ \_ -> findAbove mvarTMState tmWinId+  actionMapAddAction win findAboveAction+  applicationSetAccelsForAction app "win.findabove" ["<Shift><Ctrl>P"]++  findBelowAction <- simpleActionNew "findbelow" Nothing+  void $ onSimpleActionActivate findBelowAction $ \_ -> findBelow mvarTMState tmWinId+  actionMapAddAction win findBelowAction+  applicationSetAccelsForAction app "win.findbelow" ["<Shift><Ctrl>I"]
src/Termonad/XML.hs view
@@ -7,6 +7,8 @@  import Data.Default (def) import Data.FileEmbed (embedFile)+import Data.Text.Encoding (decodeUtf8)+import qualified Data.Text.Lazy as LText import Text.XML (renderText) import Text.XML.QQ (Document, xmlRaw) @@ -23,7 +25,7 @@     <interface>       <!-- interface-requires gtk+ 3.8 -->       <object id="appWin" class="GtkApplicationWindow">-        <property name="title" translatable="yes">Example Application</property>+        <property name="title" translatable="yes">Termonad</property>         <property name="default-width">600</property>         <property name="default-height">400</property>         <child>@@ -42,7 +44,7 @@    |]  interfaceText :: Text-interfaceText = toStrict $ renderText def interfaceDoc+interfaceText = LText.toStrict $ renderText def interfaceDoc  menuDoc :: Document menuDoc =@@ -54,15 +56,24 @@         <submenu>           <attribute name="label" translatable="yes">File</attribute>           <section>+            <!-- TODO: Uncomment this when adding functionality for creating new+                 windows+            -->+            <!--             <item>+              <attribute name="label" translatable="yes">_New Window</attribute>+              <attribute name="action">app.newwin</attribute>+            </item>+            -->+            <item>               <attribute name="label" translatable="yes">New _Tab</attribute>-              <attribute name="action">app.newtab</attribute>+              <attribute name="action">win.newtab</attribute>             </item>           </section>           <section>             <item>               <attribute name="label" translatable="yes">_Close Tab</attribute>-              <attribute name="action">app.closetab</attribute>+              <attribute name="action">win.closetab</attribute>             </item>             <item>               <attribute name="label" translatable="yes">_Quit</attribute>@@ -74,11 +85,11 @@           <attribute name="label" translatable="yes">Edit</attribute>           <item>             <attribute name="label" translatable="yes">_Copy</attribute>-            <attribute name="action">app.copy</attribute>+            <attribute name="action">win.copy</attribute>           </item>           <item>             <attribute name="label" translatable="yes">_Paste</attribute>-            <attribute name="action">app.paste</attribute>+            <attribute name="action">win.paste</attribute>           </item>           <item>             <attribute name="label" translatable="yes">_Preferences</attribute>@@ -100,15 +111,15 @@           <attribute name="label" translatable="yes">Search</attribute>           <item>             <attribute name="label" translatable="yes">_Find...</attribute>-            <attribute name="action">app.find</attribute>+            <attribute name="action">win.find</attribute>           </item>           <item>             <attribute name="label" translatable="yes">Find Above</attribute>-            <attribute name="action">app.findabove</attribute>+            <attribute name="action">win.findabove</attribute>           </item>           <item>             <attribute name="label" translatable="yes">Find Below</attribute>-            <attribute name="action">app.findbelow</attribute>+            <attribute name="action">win.findbelow</attribute>           </item>         </submenu>         <submenu>@@ -123,7 +134,7 @@    |]  menuText :: Text-menuText = toStrict $ renderText def menuDoc+menuText = LText.toStrict $ renderText def menuDoc  aboutDoc :: Document aboutDoc =@@ -201,7 +212,7 @@    |]  aboutText :: Text-aboutText = toStrict $ renderText def aboutDoc+aboutText = LText.toStrict $ renderText def aboutDoc  closeTabDoc :: Document closeTabDoc =@@ -258,7 +269,7 @@    |]  closeTabText :: Text-closeTabText = toStrict $ renderText def closeTabDoc+closeTabText = LText.toStrict $ renderText def closeTabDoc  preferencesText :: Text preferencesText = decodeUtf8 $(embedFile "glade/preferences.glade")
termonad.cabal view
@@ -1,5 +1,5 @@ name:                termonad-version:             4.5.0.0+version:             4.6.0.0 synopsis:            Terminal emulator configurable in Haskell description:   Termonad is a terminal emulator configurable in Haskell.  It is extremely@@ -28,13 +28,13 @@                    , glade/preferences.glade                    , glade/README.md                    , img/termonad.png-                   , .nix-helpers/nixops.nix+                   , img/termonad-lambda.png+                   , .nix-helpers/nixos-vm.nix                    , .nix-helpers/nixpkgs.nix                    , .nix-helpers/overlays.nix                    , .nix-helpers/stack-shell.nix                    , .nix-helpers/termonad-with-packages.nix                    , shell.nix-data-files:          img/termonad-lambda.png custom-setup                    -- Hackage apparently gives an error if you don't specify an                    -- upper bound on your setup-depends. But I don't want to@@ -59,33 +59,37 @@   hs-source-dirs:      src   exposed-modules:     Termonad                      , Termonad.App+                     , Termonad.Cli                      , Termonad.Config                      , Termonad.Config.Colour                      , Termonad.Gtk+                     , Termonad.IdMap+                     , Termonad.IdMap.Internal                      , Termonad.Keys                      , Termonad.Lenses                      , Termonad.Pcre-                     , Termonad.PreferencesFile+                     , Termonad.Preferences+                     , Termonad.Preferences.File                      , Termonad.Prelude+                     , Termonad.Startup                      , Termonad.Term                      , Termonad.Types+                     , Termonad.Window                      , Termonad.XML   other-modules:       Paths_termonad   build-depends:       base >= 4.13 && < 5-                     , adjunctions                      , aeson-                     , classy-prelude+                     , bytestring                      , colour-                     , constraints                      , containers                      , data-default                      , directory >= 1.3.1.0-                     , distributive-                     , dyre+                     , dyre >= 0.9                      , file-embed                      , filepath                      , focuslist                      , gi-gdk+                     , gi-gdkpixbuf                      , gi-gio                      , gi-glib                      , gi-gtk >= 3.0.24@@ -94,9 +98,8 @@                      , haskell-gi-base >= 0.21.2                      , inline-c                      , lens-                     , mono-traversable+                     , optparse-applicative                      , pretty-simple-                     , QuickCheck                      , text                      , transformers                      , unordered-containers@@ -104,7 +107,7 @@                      , xml-html-qq                      , yaml   default-language:    Haskell2010-  ghc-options:         -Wall -Wincomplete-uni-patterns -Wincomplete-record-updates+  ghc-options:         -Wall -Wincomplete-uni-patterns -Wincomplete-record-updates -Wunused-packages   default-extensions:  DataKinds                      , DefaultSignatures                      , DeriveAnyClass@@ -167,15 +170,8 @@   main-is:             Test.hs   hs-source-dirs:      test   build-depends:       base-                     , genvalidity-containers-                     , genvalidity-hspec-                     , hedgehog-                     , lens-                     , QuickCheck                      , termonad                      , tasty-                     , tasty-hedgehog-                     , tasty-hspec   default-language:    Haskell2010   ghc-options:         -Wall -Wincomplete-uni-patterns -Wincomplete-record-updates -threaded -rtsopts -with-rtsopts=-N   default-extensions:  DataKinds
test/readme/README.lhs view
@@ -292,35 +292,34 @@  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:+`termonad` binary will be in `~/.local/bin/`. If you have installed Termonad using+your Linux distro, the `termonad` binary will likely be in `/usr/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+$ /usr/bin/termonad ``` -The following section describes the default key bindings.- 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`. A following section gives an example configuration file. -If this configuration file exists, when the `~/.local/bin/termonad` binary+If this configuration file exists, when the `/usr/bin/termonad` binary launches, it will try to use GHC to compile the configuration file. If GHC is able to successfully compile the configuration file, a separate binary will be created 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+When you run `/usr/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+`/usr/bin/termonad` binary to be able to compile your `~/.config/termonad/termonad.hs` configuration file, Termonad 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.+some difficulties that will be discussed in one of the following sections.  ### Default Key Bindings @@ -341,31 +340,40 @@  ### Configuring Termonad -Termonad has two different ways to be configured.+Termonad has three different ways to be configured. -The first way is to use the built-in Preferences editor.  You can find this in-the `Preferences` menu under `Edit` in the menubar.+1.  Pass arguments on the command line.  For instance, run+    `termonad --no-show-menu` to never show the `File` menubar. -When opening Termonad for the first time, it will create a preferences file at-`~/.config/termonad/termonad.yaml`.  When you change a setting in the-Preferences editor, Termonad will update the setting in the preferences file.+    Arguments passed on the command line will normally override other+    configuration methods. -When running Termonad, it will load settings from the preferences file.-Do not edit the preferences file by hand, because it will be overwritten when-updating settings in the Preferences editor.+2.  Use the built-in Preferences editor.  You can find this in+    the `Preferences` menu under `Edit` in the menubar. -This method is perfect for users who only want to make small changes to the-Termonad settings, like the default font size.+    When opening Termonad for the first time, it will create a preferences file+    at `~/.config/termonad/termonad.yaml`.  When you change a setting in the+    Preferences editor, Termonad will update the setting in the preferences+    file. -The second way to configure Termonad is to use a Haskell-based settings file,-called `~/.config/termonad/termonad.hs` by default.  This method allows you to-make large, sweeping changes to Termonad.  This method is recommended for power-users.+    When running Termonad, it will load settings from the preferences file. Do+    not edit the preferences file by hand, because it will be overwritten when+    updating settings in the Preferences editor. +    This method is perfect for users who only want to make small changes to the+    Termonad settings, like the default font size.++3.  Use a Haskell-based settings file, called `~/.config/termonad/termonad.hs` by default.+    This method allows you to make large, sweeping changes to Termonad.  This+    method is recommended for power users.++    The rest of this section explains the `~/.config/termonad/termonad.hs` file.+ **WARNING: If you have a `~/.config/termonad/termonad.hs` file, then all settings from `~/.config/termonad/termonad.yaml` will be ignored.  If you want to set *ANY* settings in `~/.config/termonad/termonad.hs`, then you must-set *ALL* settings in `~/.config/termonad/termonad.hs`.**+set *ALL* settings in `~/.config/termonad/termonad.hs`.  However, as stated above,+CLI arguments will override settings in `~/.config/termonad/termonad.hs` by default.**  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@@ -378,11 +386,11 @@  module Main where -import Termonad.App (defaultMain)-import Termonad.Config+import Termonad   ( FontConfig, FontSize(FontSizePoints), Option(Set)   , ShowScrollbar(ShowScrollbarAlways), defaultConfigOptions, defaultFontConfig-  , defaultTMConfig, fontConfig, fontFamily, fontSize, options, showScrollbar+  , defaultMain, defaultTMConfig, fontConfig, fontFamily, fontSize, options+  , showScrollbar   ) import Termonad.Config.Colour   ( AlphaColour, ColourConfig, addColourExtension, createColour@@ -439,9 +447,9 @@  ### Compiling Local Settings -If you launch Termonad by calling `~/.local/bin/termonad`, it will try to+If you launch Termonad by calling `/usr/bin/termonad`, it will try to compile the `~/.config/termonad/termonad.hs` file if it exists.  The problem is-that `~/.local/bin/termonad` needs to be able to see GHC and the required+that `/usr/bin/termonad` needs to be able to see GHC and the required Haskell libraries to be able to compile `~/.config/termonad/termonad.hs`.  There are a couple solutions to this problem, listed in the sections below.@@ -452,9 +460,10 @@  #### Running with `stack` -If you originally compiled Termonad with `stack`, you can use `stack` to-execute Termonad.  First, you must change to the directory with the Termonad-source code.  From there, you can run `stack exec`:+If you originally compiled Termonad with `stack` and installed it to+`~/.local/bin/termonad`, you can use `stack` to execute Termonad.  First, you+must change to the directory with the Termonad source code.  From there, you+can run `stack exec`:  ```sh $ cd termonad/  # change to the termonad source code directory