Skip to content

Commit

Permalink
Move defaultMain and startWithCliArgs to Termonad.Startup module
Browse files Browse the repository at this point in the history
  • Loading branch information
cdepillabout committed Oct 24, 2023
1 parent 2a61acc commit 7a8eabf
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 135 deletions.
5 changes: 3 additions & 2 deletions src/Termonad.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
-- Stability : experimental
-- Portability : POSIX
--
-- This module exposes termonad's basic configuration options, as well as 'defaultMain', 'startWithCliArgs', and 'start'.
-- 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".

Expand All @@ -16,5 +16,6 @@ module Termonad
, module Config
) where

import Termonad.App (defaultMain, start, startWithCliArgs)
import Termonad.App (start)
import Termonad.Config as Config
import Termonad.Startup (defaultMain, startWithCliArgs)
135 changes: 2 additions & 133 deletions src/Termonad/App.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ module Termonad.App where

import Termonad.Prelude

import Config.Dyre (wrapMain, newParams)
import Control.Lens ((^.), (^..), over, set, view, ix)
import Control.Lens ((^.), (^..), set, view, ix)
import Data.FileEmbed (embedFile)
import Data.FocusList (focusList, moveFromToFL, updateFocusFL)
import Data.Sequence (findIndexR)
Expand Down Expand Up @@ -93,8 +92,6 @@ import GI.Vte
, terminalSearchSetWrapAround
, terminalSetFont
)
import System.IO.Error (doesNotExistErrorType, ioeGetErrorType, ioeGetFileName, tryIOError)
import Termonad.Cli (parseCliArgs, applyCliArgs)
import Termonad.Gtk (appNew, imgToPixbuf, objFromBuildUnsafe)
import Termonad.Keys (handleKeyPress)
import Termonad.Lenses
Expand Down Expand Up @@ -637,7 +634,7 @@ 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.
Expand All @@ -649,131 +646,3 @@ start tmConfig = do
void $ onApplicationStartup app (appStartup app)
void $ onApplicationActivate app (appActivate tmConfig app)
void $ applicationRun app Nothing

-- | 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 '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 '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 '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)
149 changes: 149 additions & 0 deletions src/Termonad/Startup.hs
Original file line number Diff line number Diff line change
@@ -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)
1 change: 1 addition & 0 deletions termonad.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ library
, Termonad.Preferences
, Termonad.Preferences.File
, Termonad.Prelude
, Termonad.Startup
, Termonad.Term
, Termonad.Types
, Termonad.XML
Expand Down

0 comments on commit 7a8eabf

Please sign in to comment.