yi-core-0.19.3: src/Yi/UI/Common.hs
{-# LANGUAGE Rank2Types #-}
module Yi.UI.Common where
import System.Exit (ExitCode)
{- | Record presenting a frontend's interface.
The functions 'layout' and 'refresh' are both run by the editor's main loop,
in response to user actions and so on. Their relation is a little subtle, and
is discussed here:
* to see some code, look at the function @refreshEditor@ in "Yi.Core".
This is the only place where 'layout' and 'refresh' are used.
* the function 'layout' is responsible for updating the 'Editor' with the
width and height of the windows. Some frontends, such as Pango, need to
modify their internal state to do this, and will consequently change
their display. This is expected.
* the function 'refresh' should cause the UI to update its display with
the information given in the 'Editor'.
* the functionalities of 'layout' and 'refresh' overlap to some extent, in
the sense that both may cause the frontend to update its display. The Yi core
provides the following guarantees which the frontend may take advantage of:
* in the main editor loop (i.e. in the @refreshEditor@ function),
'layout' will be run (possibly multiple times) and then 'refresh' will
be run. This guarantee will hold even in the case of threading (the
function @refreshEditor@ will always be run atomically, using @MVar@s).
* between the last run of 'layout' and the run of 'refresh', some changes
may be made to the 'Editor'. However, the text, text attributes, and
(displayed) window region of all windows will remain the same. However,
the cursor location may change.
This guarantee allows frontends which calculate rendering of the text
during the 'layout' stage to avoid recalculating the render again during
'refresh'. Pango is an example of such a frontend.
The Yi core provides no guarantee about the OS thread from which the functions
'layout' and 'refresh' are called from. In particular, subprocesses (e.g. compilation,
ghci) will run 'layout' and 'refresh' from new OS threads (see @startSubprocessWatchers@
in "Yi.Core"). The frontend must be prepared for this: for instance, Gtk-based frontends
should wrap GUI updates in @postGUIAsync@.
-}
data UI e = UI
{ main :: IO () -- ^ Main loop
, end :: Maybe ExitCode -> IO () -- ^ Clean up, and also terminate if given an exit code.
, suspend :: IO () -- ^ Suspend (or minimize) the program
, refresh :: e -> IO () -- ^ Refresh the UI with the given state
, userForceRefresh :: IO () -- ^ User force-refresh (in case the screen has been messed up from outside)
, layout :: e -> IO e -- ^ Set window width and height
, reloadProject :: FilePath -> IO () -- ^ Reload cabal project views
}
dummyUI :: UI e
dummyUI = UI
{ main = return ()
, end = const (return ())
, suspend = return ()
, refresh = const (return ())
, userForceRefresh = return ()
, layout = return
, reloadProject = const (return ())
}