1
- module NOM.IO (interact , processTextStream , StreamParser , Stream ) where
1
+ module NOM.IO (interact , processTextStream , StreamParser , Stream , Window , Output ) where
2
2
3
3
import 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
6
import Data.ByteString qualified as ByteString
7
7
import Data.ByteString.Builder qualified as Builder
8
8
import Data.ByteString.Char8 qualified as ByteString
@@ -11,6 +11,7 @@ import Data.Time (ZonedTime, getZonedTime)
11
11
import NOM.Error (NOMError )
12
12
import NOM.Print (Config (.. ))
13
13
import NOM.Print.Table as Table (bold , displayWidth , displayWidthBS , markup , red , truncate )
14
+ import NOM.State (PrintNameStyle (.. ), PrintState (.. ), initPrintState )
14
15
import NOM.Update.Monad (UpdateMonad , getNow )
15
16
import Relude
16
17
import Streamly.Data.Fold qualified as Fold
@@ -28,7 +29,7 @@ type Output = Text
28
29
29
30
type UpdateFunc update state = forall m . (UpdateMonad m ) = > update -> StateT state m ([NOMError ], ByteString , Bool )
30
31
31
- type OutputFunc state = state -> Maybe Window -> (ZonedTime , Double ) -> Output
32
+ type OutputFunc state = state -> PrintState -> Maybe Window -> (ZonedTime , Double ) -> Output
32
33
33
34
type Finalizer state = forall m . (UpdateMonad m ) = > StateT state m ()
34
35
@@ -59,13 +60,14 @@ writeStateToScreen ::
59
60
Bool ->
60
61
TVar Int ->
61
62
TMVar state ->
63
+ TMVar PrintState ->
62
64
TVar [ByteString ] ->
63
65
TVar Bool ->
64
66
(Double -> state -> state ) ->
65
67
OutputFunc state ->
66
68
Handle ->
67
69
IO ()
68
- writeStateToScreen pad printed_lines_var nom_state_var nix_output_buffer_var refresh_display_var maintenance printer output_handle = do
70
+ writeStateToScreen pad printed_lines_var nom_state_var print_state_var nix_output_buffer_var refresh_display_var maintenance printer output_handle = do
69
71
nowClock <- getZonedTime
70
72
now <- getNow
71
73
terminalSize <-
@@ -88,11 +90,10 @@ writeStateToScreen pad printed_lines_var nom_state_var nix_output_buffer_var ref
88
90
nix_output_raw <- swapTVar nix_output_buffer_var []
89
91
pure (nom_state, nix_output_raw)
90
92
-- ====
91
-
93
+ print_state <- atomically $ readTMVar print_state_var
92
94
let nix_output = ByteString. lines $ ByteString. concat $ reverse nix_output_raw
93
95
nix_output_length = length nix_output
94
-
95
- nom_output = ByteString. lines $ encodeUtf8 $ truncateOutput terminalSize (printer nom_state terminalSize (nowClock, now))
96
+ nom_output = ByteString. lines $ encodeUtf8 $ truncateOutput terminalSize (printer nom_state print_state terminalSize (nowClock, now))
96
97
nom_output_length = length nom_output
97
98
98
99
-- We will try to calculate how many lines we can draw without reaching the end
@@ -214,6 +215,14 @@ minFrameDuration =
214
215
-- feel to sluggish for the eye, for me.
215
216
60_000 -- ~17 times per second
216
217
218
+ getKey :: IO [Char ]
219
+ getKey = reverse <$> getKey' " "
220
+ where
221
+ getKey' chars = do
222
+ char <- System.IO. getChar
223
+ more <- System.IO. hReady stdin
224
+ (if more then getKey' else return ) (char : chars)
225
+
217
226
processTextStream ::
218
227
forall update state .
219
228
Config ->
@@ -227,6 +236,8 @@ processTextStream ::
227
236
IO state
228
237
processTextStream config parser updater maintenance printerMay finalize initialState inputStream = do
229
238
state_var <- newTMVarIO initialState
239
+ print_state_var <- newTMVarIO initPrintState
240
+ input_received <- newEmptyTMVarIO
230
241
output_builder_var <- newTVarIO []
231
242
refresh_display_var <- newTVarIO False
232
243
let keepProcessing :: IO ()
@@ -240,13 +251,35 @@ processTextStream config parser updater maintenance printerMay finalize initialS
240
251
waitForInput = atomically $ check =<< readTVar refresh_display_var
241
252
printerMay & maybe keepProcessing \ (printer, output_handle) -> do
242
253
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
254
+ let keepProcessingStdin :: IO ()
255
+ keepProcessingStdin = forever $ do
256
+ key <- getKey
257
+ case key of
258
+ " n" -> do
259
+ atomically $ do
260
+ print_state <- readTMVar print_state_var
261
+ let print_state_style = if print_state. printName == PrintName then PrintDerivationPath else PrintName
262
+ writeTMVar print_state_var $ print_state{printName = print_state_style}
263
+ writeTMVar input_received ()
264
+ " ?" -> do
265
+ atomically $ do
266
+ print_state <- takeTMVar print_state_var
267
+ putTMVar print_state_var $ print_state{printHelp = True }
268
+ writeTMVar input_received ()
269
+ _ -> pure ()
270
+ writeToScreen :: IO ()
271
+ writeToScreen = writeStateToScreen (not config. silent) linesVar state_var print_state_var output_builder_var refresh_display_var maintenance printer output_handle
245
272
keepPrinting :: IO ()
246
273
keepPrinting = forever do
247
- race_ (concurrently_ (threadDelay minFrameDuration) waitForInput) (threadDelay maxFrameDuration)
274
+ runConcurrently
275
+ $ (Concurrently (threadDelay minFrameDuration) *> Concurrently waitForInput)
276
+ <|> Concurrently (threadDelay maxFrameDuration)
277
+ <|> Concurrently (atomically $ takeTMVar input_received)
248
278
writeToScreen
249
- race_ keepProcessing keepPrinting
279
+ runConcurrently
280
+ $ Concurrently keepProcessing
281
+ <|> Concurrently keepProcessingStdin
282
+ <|> Concurrently keepPrinting
250
283
atomically (takeTMVar state_var) >>= execStateT finalize >>= atomically . putTMVar state_var
251
284
writeToScreen
252
285
(if isNothing printerMay then (>>= execStateT finalize) else id ) $ atomically $ takeTMVar state_var
0 commit comments