From a8e48d9655a66b33be8aa2bbf10e3ac9ee76fd6f Mon Sep 17 00:00:00 2001 From: Jonathan Daugherty Date: Thu, 9 Jul 2020 15:10:12 -0700 Subject: [PATCH] customMain: restore initial terminal input state on shutdown This change ensures that the initial terminal input state flags are restored on shutdown (regardless of exceptions) even if changes to the state flags have occurred via 'suspendAndResume'. Prior to this change, breaking changes to the input state flags in the last 'suspendAndResume' before program exit were propagated to the end user's terminal environment which could lead to broken or garbled terminal I/O. For more details, see https://github.com/jtdaugherty/vty/issues/187 This change also increases the lower bound on 'vty' to get access to the API required to support this behavior. --- brick.cabal | 2 +- src/Brick/Main.hs | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/brick.cabal b/brick.cabal index 50b8039..49da84b 100644 --- a/brick.cabal +++ b/brick.cabal @@ -114,7 +114,7 @@ library Brick.Widgets.Internal build-depends: base <= 4.14.0.0, - vty >= 5.24, + vty >= 5.29, transformers, data-clist >= 0.1, directory >= 1.2.5.0, diff --git a/src/Brick/Main.hs b/src/Brick/Main.hs index b5e975d..05b1907 100644 --- a/src/Brick/Main.hs +++ b/src/Brick/Main.hs @@ -75,6 +75,8 @@ import Graphics.Vty , nextEvent , mkVty , defaultConfig + , restoreInputState + , inputIface ) import Graphics.Vty.Attributes (defAttr) @@ -202,6 +204,10 @@ runWithVty vty brickChan mUserChan app initialRS initialSt = do -- | The custom event loop entry point to use when the simpler ones -- don't permit enough control. Returns the final application state -- after the application halts. +-- +-- Note that this function guarantees that the terminal input state +-- prior to the first Vty initialization is the terminal input state +-- that is restored on shutdown (regardless of exceptions). customMain :: (Ord n) => Vty -- ^ The initial Vty handle to use. @@ -221,8 +227,13 @@ customMain :: (Ord n) -- ^ The initial application state. -> IO s customMain initialVty buildVty mUserChan app initialAppState = do + let restoreInitialState = restoreInputState $ inputIface initialVty + (s, vty) <- customMainWithVty initialVty buildVty mUserChan app initialAppState + `E.catch` (\(e::E.SomeException) -> restoreInitialState >> E.throw e) + shutdown vty + restoreInitialState return s -- | Like 'customMain', except the last 'Vty' handle used by the @@ -526,5 +537,10 @@ halt = return . Halt -- specified action. When it returns an application state value, restore -- the terminal state, empty the rendering cache, redraw the application -- from the new state, and resume the event loop. +-- +-- Note that any changes made to the terminal's input state are ignored +-- when Brick resumes execution and are not preserved in the final +-- terminal input state after the Brick application returns the terminal +-- to the user. suspendAndResume :: IO s -> EventM n (Next s) suspendAndResume = return . SuspendAndResume