1- module NOM.IO (interact , processTextStream , StreamParser , Stream ) where
1+ module NOM.IO (interact , processTextStream , StreamParser , Stream , Window , Output ) where
22
33import Control.Concurrent (threadDelay )
4- import Control.Concurrent.Async (concurrently_ , race_ )
5- import Control.Concurrent.STM (check , swapTVar )
4+ import Control.Concurrent.Async (Concurrently (Concurrently , runConcurrently ))
5+ import Control.Concurrent.STM (check , swapTVar , writeTMVar )
6+ import Control.Exception (bracket )
67import Data.ByteString qualified as ByteString
78import Data.ByteString.Builder qualified as Builder
89import Data.ByteString.Char8 qualified as ByteString
@@ -11,6 +12,7 @@ import Data.Time (ZonedTime, getZonedTime)
1112import NOM.Error (NOMError )
1213import NOM.Print (Config (.. ))
1314import NOM.Print.Table as Table (bold , displayWidth , displayWidthBS , markup , red , truncate )
15+ import NOM.State (PrintNameStyle (.. ), PrintState (.. ), initPrintState )
1416import NOM.Update.Monad (UpdateMonad , getNow )
1517import Relude
1618import Streamly.Data.Fold qualified as Fold
@@ -28,7 +30,7 @@ type Output = Text
2830
2931type UpdateFunc update state = forall m . (UpdateMonad m ) = > update -> StateT state m ([NOMError ], ByteString , Bool )
3032
31- type OutputFunc state = state -> Maybe Window -> (ZonedTime , Double ) -> Output
33+ type OutputFunc state = state -> PrintState -> Maybe Window -> (ZonedTime , Double ) -> Output
3234
3335type Finalizer state = forall m . (UpdateMonad m ) = > StateT state m ()
3436
@@ -59,13 +61,14 @@ writeStateToScreen ::
5961 Bool ->
6062 TVar Int ->
6163 TMVar state ->
64+ TMVar PrintState ->
6265 TVar [ByteString ] ->
6366 TVar Bool ->
6467 (Double -> state -> state ) ->
6568 OutputFunc state ->
6669 Handle ->
6770 IO ()
68- writeStateToScreen pad printed_lines_var nom_state_var nix_output_buffer_var refresh_display_var maintenance printer output_handle = do
71+ writeStateToScreen pad printed_lines_var nom_state_var print_state_var nix_output_buffer_var refresh_display_var maintenance printer output_handle = do
6972 nowClock <- getZonedTime
7073 now <- getNow
7174 terminalSize <-
@@ -88,11 +91,10 @@ writeStateToScreen pad printed_lines_var nom_state_var nix_output_buffer_var ref
8891 nix_output_raw <- swapTVar nix_output_buffer_var []
8992 pure (nom_state, nix_output_raw)
9093 -- ====
91-
94+ print_state <- atomically $ readTMVar print_state_var
9295 let nix_output = ByteString. lines $ ByteString. concat $ reverse nix_output_raw
9396 nix_output_length = length nix_output
94-
95- nom_output = ByteString. lines $ encodeUtf8 $ truncateOutput terminalSize (printer nom_state terminalSize (nowClock, now))
97+ nom_output = ByteString. lines $ encodeUtf8 $ truncateOutput terminalSize (printer nom_state print_state terminalSize (nowClock, now))
9698 nom_output_length = length nom_output
9799
98100 -- We will try to calculate how many lines we can draw without reaching the end
@@ -214,6 +216,14 @@ minFrameDuration =
214216 -- feel to sluggish for the eye, for me.
215217 60_000 -- ~17 times per second
216218
219+ getKey :: IO [Char ]
220+ getKey = reverse <$> getKey' " "
221+ where
222+ getKey' chars = do
223+ char <- System.IO. getChar
224+ more <- System.IO. hReady stdin
225+ (if more then getKey' else return ) (char : chars)
226+
217227processTextStream ::
218228 forall update state .
219229 Config ->
@@ -227,6 +237,8 @@ processTextStream ::
227237 IO state
228238processTextStream config parser updater maintenance printerMay finalize initialState inputStream = do
229239 state_var <- newTMVarIO initialState
240+ print_state_var <- newTMVarIO initPrintState
241+ input_received <- newEmptyTMVarIO
230242 output_builder_var <- newTVarIO []
231243 refresh_display_var <- newTVarIO False
232244 let keepProcessing :: IO ()
@@ -240,13 +252,47 @@ processTextStream config parser updater maintenance printerMay finalize initialS
240252 waitForInput = atomically $ check =<< readTVar refresh_display_var
241253 printerMay & maybe keepProcessing \ (printer, output_handle) -> do
242254 linesVar <- newTVarIO 0
243- let writeToScreen :: IO ()
244- writeToScreen = writeStateToScreen (not config. silent) linesVar state_var output_builder_var refresh_display_var maintenance printer output_handle
255+ let keepProcessingStdin :: IO ()
256+ keepProcessingStdin = bracket setBuffering restoreBuffering $ const processStdinForeverLoop
257+ where
258+ setBuffering = do
259+ buff <- System.IO. hGetBuffering stdin
260+ setEcho <- System.IO. hGetEcho stdin
261+ System.IO. hSetBuffering stdin NoBuffering
262+ System.IO. hSetEcho stdin False
263+ pure (buff, setEcho)
264+ restoreBuffering (buff, setEcho) = do
265+ System.IO. hSetBuffering stdin buff
266+ System.IO. hSetEcho stdin setEcho
267+ processStdinForeverLoop :: IO ()
268+ processStdinForeverLoop = forever $ do
269+ key <- getKey
270+ case key of
271+ " n" -> do
272+ atomically $ do
273+ print_state <- readTMVar print_state_var
274+ let print_state_style = if print_state. printName == PrintName then PrintDerivationPath else PrintName
275+ writeTMVar print_state_var $ print_state{printName = print_state_style}
276+ writeTMVar input_received ()
277+ " ?" -> do
278+ atomically $ do
279+ print_state <- takeTMVar print_state_var
280+ putTMVar print_state_var $ print_state{printHelp = True }
281+ writeTMVar input_received ()
282+ _ -> pure ()
283+ writeToScreen :: IO ()
284+ writeToScreen = writeStateToScreen (not config. silent) linesVar state_var print_state_var output_builder_var refresh_display_var maintenance printer output_handle
245285 keepPrinting :: IO ()
246286 keepPrinting = forever do
247- race_ (concurrently_ (threadDelay minFrameDuration) waitForInput) (threadDelay maxFrameDuration)
287+ runConcurrently
288+ $ (Concurrently (threadDelay minFrameDuration) *> Concurrently waitForInput)
289+ <|> Concurrently (threadDelay maxFrameDuration)
290+ <|> Concurrently (atomically $ takeTMVar input_received)
248291 writeToScreen
249- race_ keepProcessing keepPrinting
292+ runConcurrently
293+ $ Concurrently keepProcessing
294+ <|> Concurrently keepProcessingStdin
295+ <|> Concurrently keepPrinting
250296 atomically (takeTMVar state_var) >>= execStateT finalize >>= atomically . putTMVar state_var
251297 writeToScreen
252298 (if isNothing printerMay then (>>= execStateT finalize) else id ) $ atomically $ takeTMVar state_var
0 commit comments