packages feed

reflex-vty 1.0.0.1 → 1.1.0.0

raw patch · 4 files changed

+91/−26 lines, 4 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Reflex.Vty.Host: type Signal = CInt
+ Reflex.Vty.Host: AppSignal_Hangup :: AppSignal
+ Reflex.Vty.Host: AppSignal_Interrupt :: AppSignal
+ Reflex.Vty.Host: AppSignal_Platform :: CInt -> AppSignal
+ Reflex.Vty.Host: AppSignal_Terminate :: AppSignal
+ Reflex.Vty.Host: data AppSignal
- Reflex.Vty.Host: type VtyApp t (m :: Type -> Type) = MonadVtyApp t m => DisplayRegion -> Event t Event -> Event t Signal -> m VtyResult t
+ Reflex.Vty.Host: type VtyApp t (m :: Type -> Type) = MonadVtyApp t m => DisplayRegion -> Event t Event -> Event t AppSignal -> m VtyResult t

Files

ChangeLog.md view
@@ -1,5 +1,9 @@ # Revision history for reflex-vty +## 1.1.0.0++* *Breaking change*: reflex-vty now builds on Windows. OS signals are handled through a platform-agnostic type called `AppSignal`. This changes `VtyApp`'s signal argument (`Event t AppSignal` instead of `Event t Signal` (synonym for `CInt`)).+ ## 1.0.0.1  * Add some more examples, especially of the new canvas features
reflex-vty.cabal view
@@ -1,11 +1,11 @@ cabal-version: 3.0 name: reflex-vty-version: 1.0.0.1+version: 1.1.0.0 synopsis: Reflex FRP host and widgets for VTY applications description:   Build terminal applications using functional reactive programming (FRP) with Reflex FRP (<https://reflex-frp.org>).   .-  <<https://i.imgur.com/FULQNtu.gif>>+  <<https://vhs.charm.sh/vhs-1QNXpqEc9fg8E2WKtkDsD9.gif>> license: BSD-3-Clause license-file: LICENSE author: Obsidian Systems LLC@@ -44,7 +44,8 @@                  , Reflex.Vty.Widget.Text                  , Data.Text.Zipper                  , Control.Monad.NodeId-  other-modules:  Reflex.Vty.Host.Trigger+  other-modules:  Reflex.Vty.Host.Signal+                , Reflex.Vty.Host.Trigger   build-depends:     base >= 4.10.0 && < 4.22,     bimap >= 0.3.3 && < 0.6,@@ -65,9 +66,10 @@     ref-tf >= 0.4.0 && < 0.6,     reflex >= 0.9.2 && < 1,     time >= 1.8.0 && < 1.15,-    unix >= 2.7 && < 2.10,-    vty >= 6.0 && < 6.5,-    vty-crossplatform >= 0.1 && < 0.5+    vty >= 6.0 && < 6.7,+    vty-crossplatform >= 0.1 && < 0.6+  if !os(windows)+    build-depends: unix >= 2.7 && < 2.10   hs-source-dirs: src   default-language: Haskell2010   ghc-options: -Wall
src/Reflex/Vty/Host.hs view
@@ -11,7 +11,7 @@   , setCursorStyle   , ScreenMode (..)   , setScreenMode-  , Signal+  , AppSignal (..)   , getDefaultVty   , runVtyApp   , runVtyAppWithHandle@@ -38,15 +38,11 @@ import qualified Graphics.Vty.CrossPlatform as V import Reflex import Reflex.Host.Class-import System.Posix.Signals-  ( Handler (..)-  , Signal-  , installHandler-  , sigHUP-  , sigINT-  , sigTERM-  ) +import Reflex.Vty.Host.Signal+  ( AppSignal (..)+  , installAppSignalHandlers+  ) import Reflex.Vty.Host.Trigger   ( closeBoundedEventQueue   , drainBoundedEventQueue@@ -101,9 +97,10 @@   -- ^ The initial display size (updates to this come as events)   -> Event t V.Event   -- ^ Vty input events.-  -> Event t Signal-  -- ^ POSIX signal events (SIGINT, SIGTERM, SIGHUP). All three automatically-  -- trigger shutdown; apps can observe them for custom handling before exit.+  -> Event t AppSignal+  -- ^ OS signal events, normalized across platforms. 'AppSignal_Interrupt',+  -- 'AppSignal_Terminate', and 'AppSignal_Hangup' all trigger shutdown.+  -- NOTE: This behavior will be configurable in the future.   -> m (VtyResult t)   -- ^ The output of the 'VtyApp'. The application runs in a context that,   --   among other things, allows new events to be created and triggered@@ -159,7 +156,7 @@     -- once, when the application starts.     (postBuild, postBuildTriggerRef) <- newEventWithTriggerRef -    -- Create an 'Event' for POSIX signals.+    -- Create an 'Event' for OS signals.     (signalEvent, signalTriggerRef) <- newEventWithTriggerRef      -- A bounded, closeable queue into which external triggers write their@@ -194,7 +191,7 @@     -- The guest app is provided the     -- initial display region, an     -- 'Event' of vty inputs, and an-    -- 'Event' of POSIX signals.+    -- 'Event' of OS signals.      -- Reads the current value of the 'Picture' behavior and updates the     -- display with it. This will be called whenever we determine that a@@ -219,7 +216,7 @@     -- request application shutdown. We'll check whether this 'Event' is firing     -- to determine whether to terminate. SIGINT, SIGTERM, and SIGHUP from the     -- host also trigger shutdown.-    let sigShutdown = () <$ ffilter (\s -> s == sigINT || s == sigTERM || s == sigHUP) signalEvent+    let sigShutdown = () <$ ffilter (\s -> s == AppSignal_Interrupt || s == AppSignal_Terminate || s == AppSignal_Hangup) signalEvent     shutdown <- subscribeEvent $ leftmost [_vtyResult_shutdown vtyResult, sigShutdown]      -- Fork a thread and continuously get the next vty input event, and then@@ -241,11 +238,9 @@       -- practice input never saturates it.)       atomically $ writeBoundedEventQueue pending [triggerRef :=> triggerInvocation] -    -- Install POSIX signal handlers. Each handler writes the signal value-    -- into the bounded FRP event queue. The RTS runs 'Catch' actions in a-    -- separate thread, so the STM write is safe here.-    liftIO $ forM_ [sigINT, sigTERM, sigHUP] $ \sig ->-      installHandler sig (Catch $ atomically $ writeBoundedEventQueue pending [EventTriggerRef signalTriggerRef :=> TriggerInvocation sig (return ())]) Nothing+    -- Install OS signal handlers.+    liftIO $ installAppSignalHandlers $ \appSignal ->+      atomically $ writeBoundedEventQueue pending [EventTriggerRef signalTriggerRef :=> TriggerInvocation appSignal (return ())]      -- The main application loop. We block until at least one batch of events     -- is available, then drain every other batch that has accumulated in the
+ src/Reflex/Vty/Host/Signal.hs view
@@ -0,0 +1,64 @@+{-# LANGUAGE CPP #-}++-- |+-- Module: Reflex.Vty.Host.Signal+-- Description: Cross-platform OS signal handling for reflex-vty.+module Reflex.Vty.Host.Signal+  ( AppSignal (..)+  , installAppSignalHandlers+  ) where++import Foreign.C.Types (CInt)++#if defined(mingw32_HOST_OS)+import Control.Monad (void)+import qualified GHC.ConsoleHandler as Console+#else+import Control.Monad (forM_)+import System.Posix.Signals (Handler (Catch), installHandler, sigHUP, sigINT, sigTERM)+#endif++-- | An OS-level signal delivered to a running application.+--+--   * 'AppSignal_Interrupt': POSIX @SIGINT@ or Windows @ControlC@+--   * 'AppSignal_Terminate': POSIX @SIGTERM@ or Windows @Shutdown@+--   * 'AppSignal_Hangup': POSIX @SIGHUP@ or Windows @Close@ or Windows @Logoff@+--+-- All other signals can be shoved into the 'AppSignal_Platform' escape hatch.+data AppSignal+  = AppSignal_Interrupt+  | AppSignal_Terminate+  | AppSignal_Hangup+  | AppSignal_Platform CInt+  deriving (Eq, Show)++-- | Install handlers for OS signals+installAppSignalHandlers :: (AppSignal -> IO ()) -> IO ()++#if defined(mingw32_HOST_OS)++-- via 'GHC.ConsoleHandler'+installAppSignalHandlers fire =+  void $ Console.installHandler $ Console.Catch (fire . toAppSignal)+  where+    toAppSignal :: Console.ConsoleEvent -> AppSignal+    toAppSignal ev = case ev of+      Console.ControlC -> AppSignal_Interrupt -- Ctrl-C: same intent as SIGINT.+      Console.Break -> AppSignal_Interrupt -- Ctrl-Break: closest to an interrupt.+      Console.Close -> AppSignal_Hangup -- console window closed: terminal going away.+      Console.Logoff -> AppSignal_Hangup -- user logging off: session going away.+      Console.Shutdown -> AppSignal_Terminate -- system shutting down: clean termination.++#else++installAppSignalHandlers fire =+  forM_ signals $ \(sig, appSignal) ->+    installHandler sig (Catch (fire appSignal)) Nothing+  where+    signals =+      [ (sigINT, AppSignal_Interrupt)+      , (sigTERM, AppSignal_Terminate)+      , (sigHUP, AppSignal_Hangup)+      ]++#endif