diff --git a/Makefile b/Makefile index 87e1a562c0..a9fdfe15bc 100644 --- a/Makefile +++ b/Makefile @@ -111,7 +111,7 @@ JUVIX_PACKAGES_IN_REPO=$(shell find \ | awk -F'/Package.juvix' '{print $$1}' | sort -u) JUVIXFORMATFLAGS?=--in-place -JUVIXTYPECHECKFLAGS?=--only-errors +JUVIXTYPECHECKFLAGS?=--log-level warn .PHONY: format-juvix-files format-juvix-files: diff --git a/app/App.hs b/app/App.hs index 8ecb788a36..21b05a56de 100644 --- a/app/App.hs +++ b/app/App.hs @@ -37,8 +37,7 @@ data App :: Effect where GetMainFileMaybe :: Maybe (AppPath File) -> App m (Maybe (Path Abs File)) FromAppPathDir :: AppPath Dir -> App m (Path Abs Dir) RenderStdOut :: (HasAnsiBackend a, HasTextBackend a) => a -> App m () - Say :: Text -> App m () - SayRaw :: ByteString -> App m () + RenderStdOutRaw :: ByteString -> App m () data RunAppIOArgs = RunAppIOArgs { _runAppIOArgsGlobalOptions :: GlobalOptions, @@ -48,9 +47,11 @@ data RunAppIOArgs = RunAppIOArgs makeSem ''App makeLenses ''RunAppIOArgs +type AppEffects = '[Logger, TaggedLock, Files, App, EmbedIO] + runAppIO :: forall r a. - (Members '[EmbedIO, TaggedLock] r) => + (Members '[EmbedIO, Logger, TaggedLock] r) => RunAppIOArgs -> Sem (App ': r) a -> Sem r a @@ -60,7 +61,7 @@ runAppIO args = evalSingletonCache (readPackageRootIO root) . reAppIO args reAppIO :: forall r a. - (Members '[EmbedIO, TaggedLock] r) => + (Members '[EmbedIO, TaggedLock, Logger] r) => RunAppIOArgs -> Sem (App ': r) a -> Sem (SCache Package ': r) a @@ -74,11 +75,10 @@ reAppIO args@RunAppIOArgs {..} = GetMainFile m -> getMainFile' m GetMainFileMaybe m -> getMainFileMaybe' m FromAppPathDir p -> liftIO (prepathToAbsDir invDir (p ^. pathPath)) - RenderStdOut t - | _runAppIOArgsGlobalOptions ^. globalOnlyErrors -> return () - | otherwise -> do - sup <- liftIO (Ansi.hSupportsANSIColor stdout) - renderIO (not (_runAppIOArgsGlobalOptions ^. globalNoColors) && sup) t + RenderStdOut t -> do + sup <- liftIO (Ansi.hSupportsANSIColor stdout) + renderIO (not (_runAppIOArgsGlobalOptions ^. globalNoColors) && sup) t + RenderStdOutRaw b -> liftIO (ByteString.putStr b) AskGlobalOptions -> return _runAppIOArgsGlobalOptions AskPackage -> getPkg AskArgs -> return args @@ -86,27 +86,25 @@ reAppIO args@RunAppIOArgs {..} = AskInvokeDir -> return invDir AskPkgDir -> return (_runAppIOArgsRoot ^. rootRootDir) AskBuildDir -> return (resolveAbsBuildDir (_runAppIOArgsRoot ^. rootRootDir) (_runAppIOArgsRoot ^. rootBuildDir)) - Say t - | g ^. globalOnlyErrors -> return () - | otherwise -> putStrLn t PrintJuvixError e -> printErr e ExitJuvixError e -> do printErr e exitFailure ExitMsg exitCode t -> exitMsg' (exitWith exitCode) t ExitFailMsg t -> exitMsg' exitFailure t - SayRaw b -> liftIO (ByteString.putStr b) where getPkg :: (Members '[SCache Package] r') => Sem r' Package getPkg = cacheSingletonGet - exitMsg' :: (Members '[EmbedIO] r') => IO x -> Text -> Sem r' x - exitMsg' onExit t = liftIO (putStrLn t >> hFlush stdout >> onExit) + exitMsg' :: forall r' x. (Members '[EmbedIO, Logger] r') => IO x -> Text -> Sem r' x + exitMsg' onExit t = do + logError (mkAnsiText t) + liftIO (hFlush stderr >> onExit) fromAppFile' :: (Members '[EmbedIO] r') => AppPath File -> Sem r' (Path Abs File) fromAppFile' f = prepathToAbsFile invDir (f ^. pathPath) - getMainFile' :: (Members '[SCache Package, EmbedIO] r') => Maybe (AppPath File) -> Sem r' (Path Abs File) + getMainFile' :: (Members '[Logger, SCache Package, EmbedIO] r') => Maybe (AppPath File) -> Sem r' (Path Abs File) getMainFile' = getMainAppFile' >=> fromAppFile' getMainFileMaybe' :: (Members '[SCache Package, EmbedIO] r') => Maybe (AppPath File) -> Sem r' (Maybe (Path Abs File)) @@ -126,10 +124,10 @@ reAppIO args@RunAppIOArgs {..} = } Nothing -> Nothing - getMainAppFile' :: (Members '[SCache Package, EmbedIO] r') => Maybe (AppPath File) -> Sem r' (AppPath File) + getMainAppFile' :: (Members '[SCache Package, EmbedIO, Logger] r') => Maybe (AppPath File) -> Sem r' (AppPath File) getMainAppFile' = fromMaybeM missingMainErr . getMainAppFileMaybe' - missingMainErr :: (Members '[EmbedIO] r') => Sem r' x + missingMainErr :: (Members '[EmbedIO, Logger] r') => Sem r' x missingMainErr = exitMsg' exitFailure @@ -137,14 +135,19 @@ reAppIO args@RunAppIOArgs {..} = <> pack (toFilePath juvixYamlFile) <> " file" ) + invDir = _runAppIOArgsRoot ^. rootInvokeDir + g :: GlobalOptions g = _runAppIOArgsGlobalOptions + + printErr :: forall r'. (Members '[Logger] r') => JuvixError -> Sem r' () printErr e = - hPutStrLn stderr + logError + . mkAnsiText . run . runReader (project' @GenericOptions g) - $ Error.render (not (_runAppIOArgsGlobalOptions ^. globalNoColors)) (g ^. globalOnlyErrors) e + $ Error.render (not (_runAppIOArgsGlobalOptions ^. globalNoColors)) (g ^. globalIdeEndErrorChar) e getEntryPoint' :: (Members '[App, EmbedIO, TaggedLock] r) => @@ -162,7 +165,7 @@ getEntryPoint' RunAppIOArgs {..} inputFile = do set entryPointStdin estdin <$> entryPointFromGlobalOptionsPre root ((^. pathPath) <$> mainFile) opts runPipelineEither :: - (Members '[EmbedIO, TaggedLock, ProgressLog, App] r, EntryPointOptions opts) => + (Members '[EmbedIO, TaggedLock, Logger, App] r, EntryPointOptions opts) => opts -> Maybe (AppPath File) -> Sem (PipelineEff r) a -> @@ -220,69 +223,55 @@ getEntryPointStdin = do getEntryPointStdin' RunAppIOArgs {..} runPipelineTermination :: - (Members '[EmbedIO, App, TaggedLock] r) => + (Members '[EmbedIO, App, Logger, TaggedLock] r) => Maybe (AppPath File) -> Sem (Termination ': PipelineEff r) a -> Sem r (PipelineResult a) -runPipelineTermination input_ p = ignoreProgressLog $ do +runPipelineTermination input_ p = silenceProgressLog $ do r <- runPipelineEither () input_ (evalTermination iniTerminationState (inject p)) >>= fromRightJuvixError return (snd r) -appRunProgressLog :: (Members '[EmbedIO, App] r) => Sem (ProgressLog ': r) a -> Sem r a -appRunProgressLog m = do - g <- askGlobalOptions - let opts = - ProgressLogOptions - { _progressLogOptionsUseColors = not (g ^. globalNoColors), - _progressLogOptionsShowThreadId = g ^. globalDevShowThreadIds - } - if - | g ^. globalOnlyErrors -> ignoreProgressLog m - | otherwise -> runProgressLogIO opts m - runPipelineNoOptions :: - (Members '[App, EmbedIO, TaggedLock] r) => + (Members '[App, EmbedIO, Logger, TaggedLock] r) => Maybe (AppPath File) -> Sem (PipelineEff r) a -> Sem r a runPipelineNoOptions = runPipeline () -runPipelineProgress :: - (Members '[App, EmbedIO, ProgressLog, TaggedLock] r, EntryPointOptions opts) => +runPipelineLogger :: + (Members '[App, EmbedIO, Logger, TaggedLock] r, EntryPointOptions opts) => opts -> Maybe (AppPath File) -> Sem (PipelineEff r) a -> Sem r a -runPipelineProgress opts input_ p = do +runPipelineLogger opts input_ p = do r <- runPipelineEither opts input_ (inject p) >>= fromRightJuvixError return (snd r ^. pipelineResult) runPipeline :: - (Members '[App, EmbedIO, TaggedLock] r, EntryPointOptions opts) => + (Members '[App, EmbedIO, Logger, TaggedLock] r, EntryPointOptions opts) => opts -> Maybe (AppPath File) -> Sem (PipelineEff r) a -> Sem r a runPipeline opts input_ = - appRunProgressLog - . runPipelineProgress opts input_ + runPipelineLogger opts input_ . inject runPipelineHtml :: - (Members '[App, EmbedIO, TaggedLock] r) => + (Members '[App, EmbedIO, Logger, TaggedLock] r) => Bool -> Maybe (AppPath File) -> Sem r (InternalTypedResult, [InternalTypedResult]) runPipelineHtml bNonRecursive input_ = - appRunProgressLog $ - if - | bNonRecursive -> do - r <- runPipelineNoOptions input_ upToInternalTyped - return (r, []) - | otherwise -> do - args <- askArgs - entry <- getEntryPoint' args input_ - runReader defaultPipelineOptions (runPipelineHtmlEither entry) >>= fromRightJuvixError + if + | bNonRecursive -> do + r <- runPipelineNoOptions input_ upToInternalTyped + return (r, []) + | otherwise -> do + args <- askArgs + entry <- getEntryPoint' args input_ + runReader defaultPipelineOptions (runPipelineHtmlEither entry) >>= fromRightJuvixError runPipelineOptions :: (Members '[App] r) => Sem (Reader PipelineOptions ': r) a -> Sem r a runPipelineOptions m = do @@ -293,23 +282,26 @@ runPipelineOptions m = do } runReader opt m -runPipelineEntry :: (Members '[App, ProgressLog, EmbedIO, TaggedLock] r) => EntryPoint -> Sem (PipelineEff r) a -> Sem r a +runPipelineEntry :: (Members '[App, Logger, EmbedIO, TaggedLock] r) => EntryPoint -> Sem (PipelineEff r) a -> Sem r a runPipelineEntry entry p = runPipelineOptions $ do r <- runIOEither entry (inject p) >>= fromRightJuvixError return (snd r ^. pipelineResult) runPipelineSetup :: - (Members '[App, EmbedIO, Reader PipelineOptions, TaggedLock] r) => + (Members '[App, EmbedIO, Logger, Reader PipelineOptions, TaggedLock] r) => Sem (PipelineEff' r) a -> Sem r a -runPipelineSetup p = ignoreProgressLog $ do +runPipelineSetup p = do args <- askArgs entry <- getEntryPointStdin' args r <- runIOEitherPipeline entry (inject p) >>= fromRightJuvixError return (snd r) +renderStdOutLn :: forall a r. (Member App r, HasAnsiBackend a, HasTextBackend a) => a -> Sem r () +renderStdOutLn txt = renderStdOut txt >> newline + newline :: (Member App r) => Sem r () -newline = say "" +newline = renderStdOut @Text "\n" printSuccessExit :: (Member App r) => Text -> Sem r a printSuccessExit = exitMsg ExitSuccess diff --git a/app/Commands/Compile.hs b/app/Commands/Compile.hs index 7d96dacc9a..1d6cb9cf79 100644 --- a/app/Commands/Compile.hs +++ b/app/Commands/Compile.hs @@ -13,7 +13,7 @@ import Commands.Compile.RiscZeroRust qualified as RiscZeroRust import Commands.Compile.Vampir qualified as Vampir import Commands.Compile.Wasi qualified as Wasi -runCommand :: (Members '[EmbedIO, App, TaggedLock] r) => CompileCommand -> Sem r () +runCommand :: (Members AppEffects r) => CompileCommand -> Sem r () runCommand = \case Native opts -> Native.runCommand opts Wasi opts -> Wasi.runCommand opts diff --git a/app/Commands/Compile/Anoma.hs b/app/Commands/Compile/Anoma.hs index f8147e3e59..3a0547bdd5 100644 --- a/app/Commands/Compile/Anoma.hs +++ b/app/Commands/Compile/Anoma.hs @@ -6,7 +6,7 @@ import Commands.Extra.NewCompile import Juvix.Compiler.Nockma.Pretty qualified as Nockma import Juvix.Compiler.Nockma.Translation.FromTree qualified as Nockma -runCommand :: (Members '[App, EmbedIO, TaggedLock] r) => AnomaOptions 'InputMain -> Sem r () +runCommand :: (Members AppEffects r) => AnomaOptions 'InputMain -> Sem r () runCommand opts = do let opts' = opts ^. anomaCompileCommonOptions inputFile = opts' ^. compileInputFile @@ -20,7 +20,8 @@ runCommand opts = do runReader entryPoint . runError @JuvixError . coreToAnoma - $ coreRes ^. coreResultModule + $ coreRes + ^. coreResultModule res <- getRight r outputAnomaResult nockmaFile res diff --git a/app/Commands/Compile/Cairo.hs b/app/Commands/Compile/Cairo.hs index 31687fbec1..1cdec4f10e 100644 --- a/app/Commands/Compile/Cairo.hs +++ b/app/Commands/Compile/Cairo.hs @@ -5,7 +5,7 @@ import Commands.Compile.Cairo.Options import Commands.Extra.NewCompile import Data.Aeson qualified as JSON -runCommand :: (Members '[App, TaggedLock, EmbedIO] r) => CairoOptions 'InputMain -> Sem r () +runCommand :: (Members AppEffects r) => CairoOptions 'InputMain -> Sem r () runCommand opts = do let opts' = opts ^. cairoCompileCommonOptions inputFile = opts' ^. compileInputFile @@ -19,6 +19,7 @@ runCommand opts = do runReader entryPoint . runError @JuvixError . coreToCairo - $ coreRes ^. coreResultModule + $ coreRes + ^. coreResultModule res <- getRight r liftIO (JSON.encodeFile (toFilePath cairoFile) res) diff --git a/app/Commands/Compile/Native.hs b/app/Commands/Compile/Native.hs index 2321899104..2c4879d15f 100644 --- a/app/Commands/Compile/Native.hs +++ b/app/Commands/Compile/Native.hs @@ -6,7 +6,7 @@ import Commands.Compile.NativeWasiHelper as Helper runCommand :: forall r. - (Members '[App, TaggedLock, EmbedIO] r) => + (Members AppEffects r) => NativeOptions 'InputMain -> Sem r () runCommand = Helper.runCommand . nativeHelperOptions diff --git a/app/Commands/Compile/NativeWasiHelper.hs b/app/Commands/Compile/NativeWasiHelper.hs index b76924d424..ab47bda4bd 100644 --- a/app/Commands/Compile/NativeWasiHelper.hs +++ b/app/Commands/Compile/NativeWasiHelper.hs @@ -36,12 +36,12 @@ helperOutputFile opts = let baseOutputFile = invokeDir filename inputFile return ((opts ^. helperDefaultOutputFile) inputFile baseOutputFile) -runCommand :: forall r. (Members '[App, TaggedLock, EmbedIO] r) => HelperOptions 'InputMain -> Sem r () +runCommand :: forall r. (Members AppEffects r) => HelperOptions 'InputMain -> Sem r () runCommand opts = concreteToC opts >>= fromC opts concreteToC :: forall r. - (Members '[App, TaggedLock, EmbedIO] r) => + (Members AppEffects r) => HelperOptions 'InputMain -> Sem r C.MiniCResult concreteToC opts = do diff --git a/app/Commands/Compile/RiscZeroRust.hs b/app/Commands/Compile/RiscZeroRust.hs index ee7667bda4..f8f38bcbb3 100644 --- a/app/Commands/Compile/RiscZeroRust.hs +++ b/app/Commands/Compile/RiscZeroRust.hs @@ -6,7 +6,7 @@ import Commands.Extra.NewCompile import Data.FileEmbed qualified as FE import Juvix.Compiler.Backend.Rust.Data.Result -runCommand :: forall r. (Members '[App, TaggedLock, EmbedIO] r) => RiscZeroRustOptions 'InputMain -> Sem r () +runCommand :: forall r. (Members AppEffects r) => RiscZeroRustOptions 'InputMain -> Sem r () runCommand opts = do let opts' = opts ^. riscZeroRustCompileCommonOptions inputFile = opts' ^. compileInputFile diff --git a/app/Commands/Compile/Vampir.hs b/app/Commands/Compile/Vampir.hs index 393037d905..4a08e45aa6 100644 --- a/app/Commands/Compile/Vampir.hs +++ b/app/Commands/Compile/Vampir.hs @@ -5,7 +5,7 @@ import Commands.Compile.Vampir.Options import Commands.Extra.NewCompile import Juvix.Compiler.Backend.VampIR.Translation qualified as VampIR -runCommand :: (Members '[App, TaggedLock, EmbedIO] r) => VampirOptions 'InputMain -> Sem r () +runCommand :: (Members AppEffects r) => VampirOptions 'InputMain -> Sem r () runCommand opts = do let opts' = opts ^. vampirCompileCommonOptions inputFile = opts' ^. compileInputFile @@ -19,6 +19,7 @@ runCommand opts = do runReader entryPoint . runError @JuvixError . coreToVampIR - $ coreRes ^. coreResultModule + $ coreRes + ^. coreResultModule VampIR.Result {..} <- getRight r writeFileEnsureLn vampirFile _resultCode diff --git a/app/Commands/Compile/Wasi.hs b/app/Commands/Compile/Wasi.hs index c548befe11..4d13fe00e1 100644 --- a/app/Commands/Compile/Wasi.hs +++ b/app/Commands/Compile/Wasi.hs @@ -6,7 +6,7 @@ import Commands.Compile.Wasi.Options runCommand :: forall r. - (Members '[App, TaggedLock, EmbedIO] r) => + (Members AppEffects r) => WasiOptions 'InputMain -> Sem r () runCommand = Helper.runCommand . wasiHelperOptions diff --git a/app/Commands/Dependencies.hs b/app/Commands/Dependencies.hs index 3375df48c2..4bf713c99e 100644 --- a/app/Commands/Dependencies.hs +++ b/app/Commands/Dependencies.hs @@ -8,6 +8,6 @@ import Commands.Base import Commands.Dependencies.Options import Commands.Dependencies.Update qualified as Update -runCommand :: (Members '[EmbedIO, TaggedLock, App] r) => DependenciesCommand -> Sem r () +runCommand :: (Members AppEffects r) => DependenciesCommand -> Sem r () runCommand = \case Update -> Update.runCommand diff --git a/app/Commands/Dependencies/Update.hs b/app/Commands/Dependencies/Update.hs index 23a4909b1c..40a9a059dd 100644 --- a/app/Commands/Dependencies/Update.hs +++ b/app/Commands/Dependencies/Update.hs @@ -3,7 +3,7 @@ module Commands.Dependencies.Update where import Commands.Base import Juvix.Compiler.Pipeline.Loader.PathResolver -runCommand :: (Members '[EmbedIO, TaggedLock, App] r) => Sem r () +runCommand :: (Members AppEffects r) => Sem r () runCommand = do let opts = set (pipelineDependenciesConfig . dependenciesConfigForceUpdateLockfile) True defaultPipelineOptions runReader opts . runPipelineSetup $ return () diff --git a/app/Commands/Dev.hs b/app/Commands/Dev.hs index 04ae4e40eb..759638f3cd 100644 --- a/app/Commands/Dev.hs +++ b/app/Commands/Dev.hs @@ -24,7 +24,7 @@ import Commands.Dev.Termination qualified as Termination import Commands.Dev.Tree qualified as Tree import Commands.Repl qualified as Repl -runCommand :: (Members '[EmbedIO, App, TaggedLock] r) => DevCommand -> Sem r () +runCommand :: (Members AppEffects r) => DevCommand -> Sem r () runCommand = \case ImportTree opts -> ImportTree.runCommand opts Highlight opts -> Highlight.runCommand opts diff --git a/app/Commands/Dev/Core.hs b/app/Commands/Dev/Core.hs index 9aa3c34af8..01fb3e8ea0 100644 --- a/app/Commands/Dev/Core.hs +++ b/app/Commands/Dev/Core.hs @@ -11,7 +11,7 @@ import Commands.Dev.Core.Read as Read import Commands.Dev.Core.Repl as Repl import Commands.Dev.Core.Strip as Strip -runCommand :: forall r. (Members '[EmbedIO, App, TaggedLock] r) => CoreCommand -> Sem r () +runCommand :: forall r. (Members AppEffects r) => CoreCommand -> Sem r () runCommand = \case Repl opts -> Repl.runCommand opts Eval opts -> Eval.runCommand opts diff --git a/app/Commands/Dev/Core/FromConcrete.hs b/app/Commands/Dev/Core/FromConcrete.hs index a7624e2e8f..bd27912c88 100644 --- a/app/Commands/Dev/Core/FromConcrete.hs +++ b/app/Commands/Dev/Core/FromConcrete.hs @@ -11,10 +11,10 @@ import Juvix.Compiler.Core.Transformation qualified as Core import Juvix.Compiler.Core.Transformation.DisambiguateNames (disambiguateNames') import Juvix.Compiler.Core.Translation -runCommand :: forall r. (Members '[EmbedIO, TaggedLock, App] r) => CoreFromConcreteOptions -> Sem r () +runCommand :: forall r. (Members AppEffects r) => CoreFromConcreteOptions -> Sem r () runCommand coreOpts = do gopts <- askGlobalOptions - md <- (^. coreResultModule) <$> ignoreProgressLog (runPipelineProgress () (Just (coreOpts ^. coreFromConcreteInputFile)) upToCore) + md <- (^. coreResultModule) <$> silenceProgressLog (runPipelineLogger () (Just (coreOpts ^. coreFromConcreteInputFile)) upToCore) path :: Path Abs File <- fromAppPathFile (coreOpts ^. coreFromConcreteInputFile) let r = run diff --git a/app/Commands/Dev/DevCompile.hs b/app/Commands/Dev/DevCompile.hs index dd5da1471d..117274b475 100644 --- a/app/Commands/Dev/DevCompile.hs +++ b/app/Commands/Dev/DevCompile.hs @@ -10,7 +10,7 @@ import Commands.Dev.DevCompile.Reg qualified as Reg import Commands.Dev.DevCompile.Rust qualified as Rust import Commands.Dev.DevCompile.Tree qualified as Tree -runCommand :: (Members '[App, EmbedIO, TaggedLock] r) => DevCompileCommand -> Sem r () +runCommand :: (Members AppEffects r) => DevCompileCommand -> Sem r () runCommand = \case Core opts -> Core.runCommand opts Reg opts -> Reg.runCommand opts diff --git a/app/Commands/Dev/DevCompile/Asm.hs b/app/Commands/Dev/DevCompile/Asm.hs index e06605dd37..b8f256942b 100644 --- a/app/Commands/Dev/DevCompile/Asm.hs +++ b/app/Commands/Dev/DevCompile/Asm.hs @@ -6,7 +6,7 @@ import Commands.Extra.NewCompile import Juvix.Compiler.Asm.Data.InfoTable import Juvix.Compiler.Asm.Pretty -runCommand :: (Members '[App, TaggedLock, EmbedIO] r) => AsmOptions 'InputMain -> Sem r () +runCommand :: (Members AppEffects r) => AsmOptions 'InputMain -> Sem r () runCommand opts = do let inputFile = opts ^. asmCompileCommonOptions . compileInputFile moutputFile = opts ^. asmCompileCommonOptions . compileOutputFile diff --git a/app/Commands/Dev/DevCompile/Casm.hs b/app/Commands/Dev/DevCompile/Casm.hs index 6386160a55..49a81d0714 100644 --- a/app/Commands/Dev/DevCompile/Casm.hs +++ b/app/Commands/Dev/DevCompile/Casm.hs @@ -6,7 +6,7 @@ import Commands.Extra.NewCompile import Juvix.Compiler.Casm.Data.Result import Juvix.Compiler.Casm.Pretty -runCommand :: (Members '[App, TaggedLock, EmbedIO] r) => CasmOptions 'InputMain -> Sem r () +runCommand :: (Members AppEffects r) => CasmOptions 'InputMain -> Sem r () runCommand opts = do let inputFile = opts ^. casmCompileCommonOptions . compileInputFile moutputFile = opts ^. casmCompileCommonOptions . compileOutputFile diff --git a/app/Commands/Dev/DevCompile/Core.hs b/app/Commands/Dev/DevCompile/Core.hs index 89e991a68f..d77c1d3239 100644 --- a/app/Commands/Dev/DevCompile/Core.hs +++ b/app/Commands/Dev/DevCompile/Core.hs @@ -12,7 +12,7 @@ compileTransformations = [Core.CombineInfoTables, Core.FilterUnreachable, Core.D runCommand :: forall r. - (Members '[App, TaggedLock, EmbedIO] r) => + (Members AppEffects r) => CoreOptions 'InputMain -> Sem r () runCommand opts = do diff --git a/app/Commands/Dev/DevCompile/NativeRust.hs b/app/Commands/Dev/DevCompile/NativeRust.hs index 2184da278c..27ee0233f4 100644 --- a/app/Commands/Dev/DevCompile/NativeRust.hs +++ b/app/Commands/Dev/DevCompile/NativeRust.hs @@ -8,7 +8,7 @@ import Data.FileEmbed qualified as FE import Juvix.Compiler.Backend.Rust.Data.Result runCommand :: - (Members '[App, EmbedIO, TaggedLock] r) => + (Members AppEffects r) => NativeRustOptions 'InputMain -> Sem r () runCommand opts = do diff --git a/app/Commands/Dev/DevCompile/Reg.hs b/app/Commands/Dev/DevCompile/Reg.hs index 42bb076f45..3cddc4ac45 100644 --- a/app/Commands/Dev/DevCompile/Reg.hs +++ b/app/Commands/Dev/DevCompile/Reg.hs @@ -7,7 +7,7 @@ import Juvix.Compiler.Reg.Data.InfoTable import Juvix.Compiler.Reg.Pretty runCommand :: - (Members '[App, EmbedIO, TaggedLock] r) => + (Members AppEffects r) => RegOptions 'InputMain -> Sem r () runCommand opts = do diff --git a/app/Commands/Dev/DevCompile/Rust.hs b/app/Commands/Dev/DevCompile/Rust.hs index 1c27b2210a..5a8d2aab6e 100644 --- a/app/Commands/Dev/DevCompile/Rust.hs +++ b/app/Commands/Dev/DevCompile/Rust.hs @@ -6,7 +6,7 @@ import Commands.Extra.NewCompile import Juvix.Compiler.Backend.Rust.Data.Result runCommand :: - (Members '[App, EmbedIO, TaggedLock] r) => + (Members AppEffects r) => RustOptions 'InputMain -> Sem r () runCommand opts = do diff --git a/app/Commands/Dev/DevCompile/Tree.hs b/app/Commands/Dev/DevCompile/Tree.hs index 4733222734..e1bcb0ebee 100644 --- a/app/Commands/Dev/DevCompile/Tree.hs +++ b/app/Commands/Dev/DevCompile/Tree.hs @@ -7,7 +7,7 @@ import Juvix.Compiler.Tree.Data.InfoTable import Juvix.Compiler.Tree.Pretty runCommand :: - (Members '[App, TaggedLock, EmbedIO] r) => + (Members AppEffects r) => TreeOptions 'InputMain -> Sem r () runCommand opts = do diff --git a/app/Commands/Dev/DisplayRoot.hs b/app/Commands/Dev/DisplayRoot.hs index eab4db4b3b..ea66586bf8 100644 --- a/app/Commands/Dev/DisplayRoot.hs +++ b/app/Commands/Dev/DisplayRoot.hs @@ -6,10 +6,10 @@ import Commands.Extra.Package runCommand :: forall r. (Members '[EmbedIO, App] r) => RootOptions -> Sem r () runCommand RootOptions {..} = do - askPkgDir >>= say . pack . toFilePath + askPkgDir >>= renderStdOutLn . pack . toFilePath when _rootPrintPackage printPackage where printPackage :: Sem r () printPackage = do - say "+----------------------------+" - askPackage >>= say . renderPackage + renderStdOutLn @Text "+----------------------------+" + askPackage >>= renderStdOutLn . renderPackage diff --git a/app/Commands/Dev/Highlight.hs b/app/Commands/Dev/Highlight.hs index 006e422576..e8faa4f018 100644 --- a/app/Commands/Dev/Highlight.hs +++ b/app/Commands/Dev/Highlight.hs @@ -4,12 +4,12 @@ import Commands.Base import Commands.Dev.Highlight.Options import Juvix.Compiler.Concrete.Data.Highlight qualified as Highlight -runCommand :: (Members '[EmbedIO, App, TaggedLock] r) => HighlightOptions -> Sem r () -runCommand HighlightOptions {..} = ignoreProgressLog . runPipelineOptions $ do +runCommand :: (Members AppEffects r) => HighlightOptions -> Sem r () +runCommand HighlightOptions {..} = silenceProgressLog . runPipelineOptions $ do entry <- getEntryPoint (Just _highlightInputFile) inputFile <- fromAppPathFile _highlightInputFile hinput <- Highlight.filterInput inputFile <$> runPipelineHighlight entry upToInternalTyped - sayRaw (Highlight.highlight _highlightBackend hinput) + renderStdOutRaw (Highlight.highlight _highlightBackend hinput) diff --git a/app/Commands/Dev/ImportTree.hs b/app/Commands/Dev/ImportTree.hs index e2407ae241..88d3ffc662 100644 --- a/app/Commands/Dev/ImportTree.hs +++ b/app/Commands/Dev/ImportTree.hs @@ -5,7 +5,7 @@ import Commands.Dev.ImportTree.Options import Commands.Dev.ImportTree.Print qualified as Print import Commands.Dev.ImportTree.ScanFile qualified as ScanFile -runCommand :: (Members '[EmbedIO, App, TaggedLock] r) => ImportTreeCommand -> Sem r () +runCommand :: (Members AppEffects r) => ImportTreeCommand -> Sem r () runCommand = \case Print opts -> Print.runCommand opts ScanFile opts -> ScanFile.runCommand opts diff --git a/app/Commands/Dev/ImportTree/Print.hs b/app/Commands/Dev/ImportTree/Print.hs index 67fe38a264..b412a1356b 100644 --- a/app/Commands/Dev/ImportTree/Print.hs +++ b/app/Commands/Dev/ImportTree/Print.hs @@ -6,7 +6,7 @@ import Juvix.Compiler.Concrete.Print import Juvix.Compiler.Pipeline.Loader.PathResolver import Juvix.Compiler.Pipeline.Loader.PathResolver.ImportTree -runCommand :: (Members '[EmbedIO, App, TaggedLock] r) => PrintOptions -> Sem r () +runCommand :: (Members AppEffects r) => PrintOptions -> Sem r () runCommand PrintOptions {..} = runReader opts . runPipelineSetup $ do tree <- case _printInputFile of Nothing -> ask diff --git a/app/Commands/Dev/Internal.hs b/app/Commands/Dev/Internal.hs index 30e3910559..ed50b16abf 100644 --- a/app/Commands/Dev/Internal.hs +++ b/app/Commands/Dev/Internal.hs @@ -5,7 +5,7 @@ import Commands.Dev.Internal.Options import Commands.Dev.Internal.Pretty qualified as Pretty import Commands.Dev.Internal.Typecheck qualified as Typecheck -runCommand :: (Members '[EmbedIO, App, TaggedLock] r) => InternalCommand -> Sem r () +runCommand :: (Members AppEffects r) => InternalCommand -> Sem r () runCommand = \case Pretty opts -> Pretty.runCommand opts TypeCheck opts -> Typecheck.runCommand opts diff --git a/app/Commands/Dev/Internal/Pretty.hs b/app/Commands/Dev/Internal/Pretty.hs index 481d604e58..b8c1c3f962 100644 --- a/app/Commands/Dev/Internal/Pretty.hs +++ b/app/Commands/Dev/Internal/Pretty.hs @@ -5,7 +5,7 @@ import Commands.Dev.Internal.Pretty.Options import Juvix.Compiler.Internal.Pretty qualified as Internal import Juvix.Compiler.Internal.Translation.FromConcrete qualified as Internal -runCommand :: (Members '[EmbedIO, App, TaggedLock] r) => InternalPrettyOptions -> Sem r () +runCommand :: (Members AppEffects r) => InternalPrettyOptions -> Sem r () runCommand opts = do globalOpts <- askGlobalOptions intern <- (^. pipelineResult . Internal.resultModule) <$> runPipelineTermination (opts ^. internalPrettyInputFile) upToInternal diff --git a/app/Commands/Dev/Internal/Typecheck.hs b/app/Commands/Dev/Internal/Typecheck.hs index 9130369c7c..2e123785e0 100644 --- a/app/Commands/Dev/Internal/Typecheck.hs +++ b/app/Commands/Dev/Internal/Typecheck.hs @@ -5,11 +5,11 @@ import Commands.Dev.Internal.Typecheck.Options import Juvix.Compiler.Internal.Pretty qualified as Internal import Juvix.Compiler.Internal.Translation.FromInternal.Analysis.TypeChecking qualified as InternalTyped -runCommand :: (Members '[EmbedIO, TaggedLock, App] r) => InternalTypeOptions -> Sem r () +runCommand :: (Members AppEffects r) => InternalTypeOptions -> Sem r () runCommand localOpts = do globalOpts <- askGlobalOptions res <- runPipelineNoOptions (localOpts ^. internalTypeInputFile) upToInternalTyped - say "Well done! It type checks" + logInfo "Well done! It type checks" when (localOpts ^. internalTypePrint) $ do let checkedModule = res ^. InternalTyped.resultModule renderStdOut (Internal.ppOut globalOpts checkedModule) diff --git a/app/Commands/Dev/Nockma.hs b/app/Commands/Dev/Nockma.hs index 67e8dbe974..3157fc49b8 100644 --- a/app/Commands/Dev/Nockma.hs +++ b/app/Commands/Dev/Nockma.hs @@ -7,7 +7,7 @@ import Commands.Dev.Nockma.Options import Commands.Dev.Nockma.Repl as Repl import Commands.Dev.Nockma.Run as Run -runCommand :: forall r. (Members '[EmbedIO, App] r) => NockmaCommand -> Sem r () +runCommand :: forall r. (Members AppEffects r) => NockmaCommand -> Sem r () runCommand = \case NockmaRepl opts -> Repl.runCommand opts NockmaEval opts -> Eval.runCommand opts diff --git a/app/Commands/Dev/Nockma/Eval.hs b/app/Commands/Dev/Nockma/Eval.hs index e196fa373f..961d604cfe 100644 --- a/app/Commands/Dev/Nockma/Eval.hs +++ b/app/Commands/Dev/Nockma/Eval.hs @@ -7,7 +7,7 @@ import Juvix.Compiler.Nockma.Evaluator import Juvix.Compiler.Nockma.Pretty import Juvix.Compiler.Nockma.Translation.FromSource qualified as Nockma -runCommand :: forall r. (Members '[EmbedIO, App] r) => NockmaEvalOptions -> Sem r () +runCommand :: forall r. (Members AppEffects r) => NockmaEvalOptions -> Sem r () runCommand opts = do afile <- fromAppPathFile file parsedTerm <- Nockma.parseTermFile afile @@ -17,7 +17,7 @@ runCommand opts = do (counts, res) <- runOpCounts . runReader defaultEvalOptions - . runOutputSem @(Term Natural) (say . ppTrace) + . runOutputSem @(Term Natural) (logInfo . mkAnsiText . ppTrace) $ evalCompiledNock' (c ^. cellLeft) (c ^. cellRight) putStrLn (ppPrint res) let statsFile = replaceExtension' ".profile" afile diff --git a/app/Commands/Dev/Nockma/Run.hs b/app/Commands/Dev/Nockma/Run.hs index 7fa7299c98..de1797a526 100644 --- a/app/Commands/Dev/Nockma/Run.hs +++ b/app/Commands/Dev/Nockma/Run.hs @@ -9,7 +9,7 @@ import Juvix.Compiler.Nockma.Pretty import Juvix.Compiler.Nockma.Translation.FromSource qualified as Nockma import Juvix.Parser.Error -runCommand :: forall r. (Members '[EmbedIO, App] r) => NockmaRunOptions -> Sem r () +runCommand :: forall r. (Members AppEffects r) => NockmaRunOptions -> Sem r () runCommand opts = do afile <- fromAppPathFile inputFile argsFile <- mapM fromAppPathFile (opts ^. nockmaRunArgs) @@ -21,7 +21,7 @@ runCommand opts = do (counts, res) <- runOpCounts . runReader defaultEvalOptions - . runOutputSem @(Term Natural) (say . ppTrace) + . runOutputSem @(Term Natural) (logInfo . mkAnsiText . ppTrace) $ evalCompiledNock' t formula putStrLn (ppPrint res) let statsFile = replaceExtension' ".profile" afile diff --git a/app/Commands/Dev/Parse.hs b/app/Commands/Dev/Parse.hs index 466da9a25b..8977b36632 100644 --- a/app/Commands/Dev/Parse.hs +++ b/app/Commands/Dev/Parse.hs @@ -5,9 +5,9 @@ import Commands.Dev.Parse.Options import Juvix.Compiler.Concrete.Translation.FromSource qualified as Parser import Text.Show.Pretty (ppShow) -runCommand :: (Members '[EmbedIO, App, TaggedLock] r) => ParseOptions -> Sem r () +runCommand :: (Members AppEffects r) => ParseOptions -> Sem r () runCommand opts = do m <- (^. Parser.resultModule) <$> runPipelineNoOptions (opts ^. parseOptionsInputFile) upToParsing - if opts ^. parseOptionsNoPrettyShow then say (show m) else say (pack (ppShow m)) + if opts ^. parseOptionsNoPrettyShow then renderStdOutLn @String (show m) else renderStdOut (pack (ppShow m)) diff --git a/app/Commands/Dev/Scope.hs b/app/Commands/Dev/Scope.hs index 5dfe07bc2d..8ee8090d5d 100644 --- a/app/Commands/Dev/Scope.hs +++ b/app/Commands/Dev/Scope.hs @@ -7,7 +7,7 @@ import Juvix.Compiler.Concrete.Print qualified as Print import Juvix.Compiler.Concrete.Translation.FromParsed.Analysis.Scoping qualified as Scoper import Juvix.Prelude.Pretty -runCommand :: (Members '[EmbedIO, TaggedLock, App] r) => ScopeOptions -> Sem r () +runCommand :: (Members AppEffects r) => ScopeOptions -> Sem r () runCommand opts = do globalOpts <- askGlobalOptions res :: Scoper.ScoperResult <- runPipelineNoOptions (opts ^. scopeInputFile) upToScopingEntry @@ -20,5 +20,5 @@ runCommand opts = do when (opts ^. scopeListComments) $ do newline newline - say "Comments:" - say (prettyText (Scoper.getScoperResultComments res)) + renderStdOutLn @Text "Comments:" + renderStdOutLn (prettyText (Scoper.getScoperResultComments res)) diff --git a/app/Commands/Dev/Termination.hs b/app/Commands/Dev/Termination.hs index c02a40a6bf..80007aace3 100644 --- a/app/Commands/Dev/Termination.hs +++ b/app/Commands/Dev/Termination.hs @@ -5,7 +5,7 @@ import Commands.Dev.Termination.CallGraph qualified as CallGraph import Commands.Dev.Termination.Calls qualified as Calls import Commands.Dev.Termination.Options -runCommand :: (Members '[EmbedIO, TaggedLock, App] r) => TerminationCommand -> Sem r () +runCommand :: (Members AppEffects r) => TerminationCommand -> Sem r () runCommand = \case Calls opts -> Calls.runCommand opts CallGraph opts -> CallGraph.runCommand opts diff --git a/app/Commands/Dev/Termination/CallGraph.hs b/app/Commands/Dev/Termination/CallGraph.hs index 2f4077dd2b..16864fd74a 100644 --- a/app/Commands/Dev/Termination/CallGraph.hs +++ b/app/Commands/Dev/Termination/CallGraph.hs @@ -9,7 +9,7 @@ import Juvix.Compiler.Internal.Translation.FromInternal.Analysis.TypeChecking.Da import Juvix.Compiler.Store.Extra qualified as Stored import Juvix.Prelude.Pretty -runCommand :: (Members '[EmbedIO, TaggedLock, App] r) => CallGraphOptions -> Sem r () +runCommand :: (Members AppEffects r) => CallGraphOptions -> Sem r () runCommand CallGraphOptions {..} = do globalOpts <- askGlobalOptions PipelineResult {..} <- runPipelineTermination _graphInputFile upToInternalTyped @@ -18,7 +18,9 @@ runCommand CallGraphOptions {..} = do toAnsiText' = toAnsiText (not (globalOpts ^. globalNoColors)) infotable = Internal.computeCombinedInfoTable (Stored.getInternalModuleTable _pipelineResultImports) - <> _pipelineResult ^. Internal.resultInternalModule . Internal.internalModuleInfoTable + <> _pipelineResult + ^. Internal.resultInternalModule + . Internal.internalModuleInfoTable callMap = Termination.buildCallMap mainModule completeGraph = Termination.completeCallGraph callMap filteredGraph = diff --git a/app/Commands/Dev/Termination/Calls.hs b/app/Commands/Dev/Termination/Calls.hs index adfceb094e..2d40ba836c 100644 --- a/app/Commands/Dev/Termination/Calls.hs +++ b/app/Commands/Dev/Termination/Calls.hs @@ -6,7 +6,7 @@ import Juvix.Compiler.Internal.Pretty qualified as Internal import Juvix.Compiler.Internal.Translation.FromConcrete qualified as Internal import Juvix.Compiler.Internal.Translation.FromInternal.Analysis.Termination qualified as Termination -runCommand :: (Members '[EmbedIO, TaggedLock, App] r) => CallsOptions -> Sem r () +runCommand :: (Members AppEffects r) => CallsOptions -> Sem r () runCommand localOpts@CallsOptions {..} = do globalOpts <- askGlobalOptions PipelineResult {..} <- runPipelineTermination _callsInputFile upToInternal diff --git a/app/Commands/Eval.hs b/app/Commands/Eval.hs index e5758b3aa2..4134f58f4b 100644 --- a/app/Commands/Eval.hs +++ b/app/Commands/Eval.hs @@ -6,12 +6,12 @@ import Evaluator qualified as Eval import Juvix.Compiler.Core qualified as Core import Juvix.Extra.Strings qualified as Str -runCommand :: (Members '[EmbedIO, TaggedLock, App] r) => EvalOptions -> Sem r () +runCommand :: (Members AppEffects r) => EvalOptions -> Sem r () runCommand opts@EvalOptions {..} = do gopts <- askGlobalOptions root <- askRoot entryPoint <- maybe (entryPointFromGlobalOptionsNoFile root gopts) (fromAppPathFile >=> \f -> entryPointFromGlobalOptions root (Just f) gopts) _evalInputFile - Core.CoreResult {..} <- ignoreProgressLog (runPipelineProgress () _evalInputFile upToCore) + Core.CoreResult {..} <- silenceProgressLog (runPipelineLogger () _evalInputFile upToCore) let r = run . runReader entryPoint diff --git a/app/Commands/Extra/NewCompile.hs b/app/Commands/Extra/NewCompile.hs index 613a3e035d..243b44a43a 100644 --- a/app/Commands/Extra/NewCompile.hs +++ b/app/Commands/Extra/NewCompile.hs @@ -42,7 +42,7 @@ getOutputDir ext inp = \case return $ pathFileToPathDir baseOutputDir compileToCore :: - (Members '[App, EmbedIO, TaggedLock] r) => + (Members '[App, EmbedIO, Logger, TaggedLock] r) => CompileCommonOptions ('InputExtension 'FileExtJuvix) -> Sem r CoreResult compileToCore opts = runPipeline opts (Just (opts ^. compileInputFile)) upToCore diff --git a/app/Commands/Format.hs b/app/Commands/Format.hs index a9f8385df8..e891956237 100644 --- a/app/Commands/Format.hs +++ b/app/Commands/Format.hs @@ -49,9 +49,9 @@ targetFromOptions opts = do -- | Formats the project on the root formatProject :: forall r. - (Members '[App, EmbedIO, TaggedLock, Files, Output FormattedFileInfo] r) => + (Members '[App, EmbedIO, TaggedLock, Logger, Files, Output FormattedFileInfo] r) => Sem r FormatResult -formatProject = runPipelineOptions . runPipelineSetup $ do +formatProject = silenceProgressLog . runPipelineOptions . runPipelineSetup $ do pkg <- askPackage res :: [(ImportNode, PipelineResult ModuleInfo)] <- processProject res' :: [(ImportNode, SourceCode)] <- runReader pkg . forM res $ \(node, nfo) -> do @@ -59,7 +59,7 @@ formatProject = runPipelineOptions . runPipelineSetup $ do return (node, src) formatProjectSourceCode res' -runCommand :: forall r. (Members '[EmbedIO, App, TaggedLock, Files] r) => FormatOptions -> Sem r () +runCommand :: forall r. (Members AppEffects r) => FormatOptions -> Sem r () runCommand opts = do target <- targetFromOptions opts runOutputSem (renderFormattedOutput target opts) . runScopeFileApp $ do @@ -106,10 +106,10 @@ renderFormattedOutput target opts fInfo = do $ writeFileEnsureLn' _formattedFileInfoPath (i ^. formattedFileInfoContents) NoEdit m -> case m of ReformattedFile ts -> renderStdOut ts - InputPath p -> say (pack (toFilePath p)) + InputPath p -> renderStdOutLn @String (toFilePath p) Silent -> return () -runScopeFileApp :: (Members '[App, EmbedIO, TaggedLock] r) => Sem (ScopeEff ': r) a -> Sem r a +runScopeFileApp :: (Members AppEffects r) => Sem (ScopeEff ': r) a -> Sem r a runScopeFileApp = interpret $ \case ScopeFile p -> do let appFile = @@ -117,5 +117,5 @@ runScopeFileApp = interpret $ \case { _pathPath = mkPrepath (toFilePath p), _pathIsInput = False } - ignoreProgressLog (runPipelineProgress () (Just appFile) upToScopingEntry) - ScopeStdin e -> ignoreProgressLog (runPipelineEntry e upToScopingEntry) + silenceProgressLog (runPipelineLogger () (Just appFile) upToScopingEntry) + ScopeStdin e -> silenceProgressLog (runPipelineEntry e upToScopingEntry) diff --git a/app/Commands/Html.hs b/app/Commands/Html.hs index 5491b0e26d..750f1b74c3 100644 --- a/app/Commands/Html.hs +++ b/app/Commands/Html.hs @@ -14,7 +14,7 @@ import Juvix.Compiler.Internal.Translation.FromInternal.Analysis.TypeChecking.Da import Juvix.Extra.Process import System.Process qualified as Process -runGenOnlySourceHtml :: (Members '[EmbedIO, TaggedLock, App] r) => HtmlOptions -> Sem r () +runGenOnlySourceHtml :: (Members AppEffects r) => HtmlOptions -> Sem r () runGenOnlySourceHtml HtmlOptions {..} = do res <- runPipelineNoOptions _htmlInputFile upToScopingEntry let m = res ^. Scoper.resultModule @@ -50,7 +50,7 @@ resultToJudocCtx res = where sres = res ^. resultInternal . resultScoper -runCommand :: forall r. (Members '[EmbedIO, TaggedLock, App] r) => HtmlOptions -> Sem r () +runCommand :: forall r. (Members AppEffects r) => HtmlOptions -> Sem r () runCommand HtmlOptions {..} | _htmlOnlySource = runGenOnlySourceHtml HtmlOptions {..} | otherwise = do @@ -77,7 +77,7 @@ runCommand HtmlOptions {..} _judocArgsFolderStructure = _htmlFolderStructure } when _htmlOpen $ case openCmd of - Nothing -> say "Could not recognize the 'open' command for your OS" + Nothing -> logError "Could not recognize the 'open' command for your operating system" Just opencmd -> liftIO . void diff --git a/app/Commands/Init.hs b/app/Commands/Init.hs index 08a9be4d14..f83f54f938 100644 --- a/app/Commands/Init.hs +++ b/app/Commands/Init.hs @@ -1,5 +1,6 @@ module Commands.Init where +import App import Commands.Extra.Package import Commands.Init.Options import Data.Text qualified as Text @@ -23,19 +24,19 @@ parse p t = mapLeft ppErr (P.runParser p "" t) ppErr :: P.ParseErrorBundle Text Void -> Text ppErr = pack . errorBundlePretty -init :: forall r. (Members '[EmbedIO] r) => InitOptions -> Sem r () +init :: forall r. (Members '[EmbedIO, App] r) => InitOptions -> Sem r () init opts = do checkNotInProject cwd <- getCurrentDir - when isInteractive (say ("creating " <> pack (toFilePath packageFilePath))) + when isInteractive (renderStdOutLn ("creating " <> pack (toFilePath packageFilePath))) if | opts ^. initOptionsBasic -> writeBasicPackage cwd | otherwise -> do pkg <- if | isInteractive -> do - say "✨ Your next Juvix adventure is about to begin! ✨" - say "I will help you set it up" + renderStdOutLn @Text "✨ Your next Juvix adventure is about to begin! ✨" + renderStdOutLn @Text "I will help you set it up" getPackage | otherwise -> do projectName <- getDefaultProjectName @@ -45,34 +46,34 @@ init opts = do Just n -> emptyPkg {_packageName = n} writePackageFile cwd pkg checkPackage - when isInteractive (say "you are all set") + when isInteractive (renderStdOutLn @Text "you are all set") where isInteractive :: Bool isInteractive = not (opts ^. initOptionsNonInteractive) && not (opts ^. initOptionsBasic) -checkNotInProject :: forall r. (Members '[EmbedIO] r) => Sem r () +checkNotInProject :: forall r. (Members '[EmbedIO, App] r) => Sem r () checkNotInProject = whenM (orM [doesFileExist juvixYamlFile, doesFileExist packageFilePath]) err where err :: Sem r () err = do - say "You are already in a Juvix project" + renderStdOutLn @Text "You are already in a Juvix project" exitFailure -checkPackage :: forall r. (Members '[EmbedIO] r) => Sem r () +checkPackage :: forall r. (Members '[EmbedIO, App] r) => Sem r () checkPackage = do cwd <- getCurrentDir ep <- runError @JuvixError (runTaggedLockPermissive (loadPackageFileIO cwd DefaultBuildDir)) case ep of Left {} -> do - say "Package.juvix is invalid. Please raise an issue at https://github.com/anoma/juvix/issues" + renderStdOutLn @Text "Package.juvix is invalid. Please raise an issue at https://github.com/anoma/juvix/issues" exitFailure Right {} -> return () -getPackage :: forall r. (Members '[EmbedIO] r) => Sem r Package +getPackage :: forall r. (Members '[EmbedIO, App] r) => Sem r Package getPackage = do tproj <- getProjName - say "Write the version of your project [leave empty for 0.0.0]" + renderStdOutLn @Text "Write the version of your project [leave empty for 0.0.0]" tversion :: SemVer <- getVersion cwd <- getCurrentDir return @@ -91,17 +92,17 @@ getDefaultProjectName = runFail $ do dir <- map toLower . dropTrailingPathSeparator . toFilePath . dirname <$> getCurrentDir Fail.fromRight (parse projectNameParser (pack dir)) -getProjName :: forall r. (Members '[EmbedIO] r) => Sem r Text +getProjName :: forall r. (Members '[EmbedIO, App] r) => Sem r Text getProjName = do d <- getDefaultProjectName let defMsg :: Text defMsg = case d of Nothing -> mempty Just d' -> " [leave empty for '" <> d' <> "']" - say + renderStdOutLn ( "Write the name of your project" <> defMsg - <> " (lower case letters, numbers and dashes are allowed): " + <> " (lower case letters, numbers and dashes are allowed):" ) readName d where @@ -118,10 +119,10 @@ getProjName = do Right p | Text.length p <= projextNameMaxLength -> return p | otherwise -> do - say ("The project name cannot exceed " <> prettyText projextNameMaxLength <> " characters") + renderStdOutLn ("The project name cannot exceed " <> prettyText projextNameMaxLength <> " characters") retry Left err -> do - say err + renderStdOut err retry where retry :: Sem r Text @@ -129,13 +130,10 @@ getProjName = do tryAgain go -say :: (Members '[EmbedIO] r) => Text -> Sem r () -say = putStrLn +tryAgain :: (Members '[App] r) => Sem r () +tryAgain = renderStdOutLn @Text "Please, try again:" -tryAgain :: (Members '[EmbedIO] r) => Sem r () -tryAgain = say "Please, try again:" - -getVersion :: forall r. (Members '[EmbedIO] r) => Sem r SemVer +getVersion :: forall r. (Members '[App, EmbedIO] r) => Sem r SemVer getVersion = do txt <- getLine if @@ -143,8 +141,8 @@ getVersion = do | otherwise -> case parse semver' txt of Right r -> return r Left err -> do - say err - say "The version must follow the 'Semantic Versioning 2.0.0' specification" + renderStdOutLn err + renderStdOutLn @Text "The version must follow the 'Semantic Versioning 2.0.0' specification" retry where retry :: Sem r SemVer diff --git a/app/Commands/Isabelle.hs b/app/Commands/Isabelle.hs index 98ab281ad0..c2731fc2a1 100644 --- a/app/Commands/Isabelle.hs +++ b/app/Commands/Isabelle.hs @@ -7,7 +7,7 @@ import Juvix.Compiler.Backend.Isabelle.Language import Juvix.Compiler.Backend.Isabelle.Pretty runCommand :: - (Members '[EmbedIO, TaggedLock, App] r) => + (Members AppEffects r) => IsabelleOptions -> Sem r () runCommand opts = do diff --git a/app/Commands/Markdown.hs b/app/Commands/Markdown.hs index 4172226630..3d83b67f11 100644 --- a/app/Commands/Markdown.hs +++ b/app/Commands/Markdown.hs @@ -12,7 +12,7 @@ import Juvix.Compiler.Concrete.Translation.FromParsed.Analysis.Scoping qualified import Juvix.Extra.Assets (writeAssets) runCommand :: - (Members '[EmbedIO, TaggedLock, App] r) => + (Members AppEffects r) => MarkdownOptions -> Sem r () runCommand opts = do diff --git a/app/Commands/Repl.hs b/app/Commands/Repl.hs index 1da191a99d..296b723550 100644 --- a/app/Commands/Repl.hs +++ b/app/Commands/Repl.hs @@ -428,7 +428,7 @@ catchAll = Repline.dontCrash . catchJuvixError . hPutStrLn stderr . run . runReader (project' @GenericOptions opts) - $ Error.render (not (opts ^. globalNoColors) && hasAnsi) False e + $ Error.render (not (opts ^. globalNoColors) && hasAnsi) Nothing e catchErrorS :: ReplS () -> ReplS () catchErrorS = (`Except.catchError` printErrorS) diff --git a/app/Commands/Typecheck.hs b/app/Commands/Typecheck.hs index 4a8d818902..5eeefa2043 100644 --- a/app/Commands/Typecheck.hs +++ b/app/Commands/Typecheck.hs @@ -3,9 +3,9 @@ module Commands.Typecheck where import Commands.Base import Commands.Typecheck.Options -runCommand :: (Members '[EmbedIO, TaggedLock, App] r) => TypecheckOptions -> Sem r () +runCommand :: (Members AppEffects r) => TypecheckOptions -> Sem r () runCommand localOpts = do case localOpts ^. typecheckInputFile of Just _inputFile -> void (runPipelineNoOptions (localOpts ^. typecheckInputFile) upToCoreTypecheck) Nothing -> void (runPipelineOptions . runPipelineSetup $ processProject) - say "Well done! It type checks" + logInfo "Well done! It type checks" diff --git a/app/CommonOptions.hs b/app/CommonOptions.hs index e1f1c33003..ce44903665 100644 --- a/app/CommonOptions.hs +++ b/app/CommonOptions.hs @@ -136,6 +136,14 @@ somePreFileOrDirOpt = mkPrepath <$> str somePreFileOpt :: ReadM (Prepath File) somePreFileOpt = mkPrepath <$> str +readMChar :: ReadM Char +readMChar = eitherReader aux + where + aux :: String -> Either String Char + aux = \case + [c] -> Right c + s -> Left $ s <> " is not a single character" + someFileOpt :: ReadM (SomeBase File) someFileOpt = eitherReader aux where diff --git a/app/GlobalOptions.hs b/app/GlobalOptions.hs index a797cba5dc..b7d67ac2be 100644 --- a/app/GlobalOptions.hs +++ b/app/GlobalOptions.hs @@ -17,7 +17,7 @@ data GlobalOptions = GlobalOptions { _globalNoColors :: Bool, _globalShowNameIds :: Bool, _globalBuildDir :: Maybe (AppPath Dir), - _globalOnlyErrors :: Bool, + _globalIdeEndErrorChar :: Maybe Char, _globalStdin :: Bool, _globalNoTermination :: Bool, _globalNoPositivity :: Bool, @@ -27,6 +27,7 @@ data GlobalOptions = GlobalOptions _globalNumThreads :: NumThreads, _globalFieldSize :: Maybe Natural, _globalOffline :: Bool, + _globalLogLevel :: LogLevel, _globalDevShowThreadIds :: Bool } deriving stock (Eq, Show) @@ -61,11 +62,12 @@ defaultGlobalOptions = { _globalNoColors = False, _globalNumThreads = defaultNumThreads, _globalShowNameIds = False, - _globalOnlyErrors = False, + _globalIdeEndErrorChar = Nothing, _globalNoTermination = False, _globalBuildDir = Nothing, _globalStdin = False, _globalNoPositivity = False, + _globalLogLevel = LogLevelProgress, _globalNoCoverage = False, _globalNoStdlib = False, _globalUnrollLimit = defaultUnrollLimit, @@ -95,11 +97,13 @@ parseGlobalFlags = do ( long "stdin" <> help "Read from Stdin" ) - _globalOnlyErrors <- - switch - ( long "only-errors" - <> help "Only print errors in a uniform format (used by juvix-mode)" - ) + _globalIdeEndErrorChar <- + optional $ + option + readMChar + ( long "ide-end-error-char" + <> help "End error message with the given character in order to facilitate parsing" + ) _globalNoTermination <- switch ( long "no-termination" @@ -139,6 +143,18 @@ parseGlobalFlags = do ( long "offline" <> help "Disable access to network resources" ) + _globalLogLevel <- + option + (enumReader Proxy) + ( long "log-level" + <> metavar "LOG_LEVEL" + <> completer (enumCompleter @LogLevel Proxy) + <> value defaultLogLevel + <> help + ( "Determines how much log the compiler produces." + <> intercalate " < " [show l | l <- allElements @LogLevel] + ) + ) _globalShowNameIds <- switch ( long "show-name-ids" diff --git a/app/Main.hs b/app/Main.hs index de4e5a583b..b1c8176d9d 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -6,6 +6,7 @@ import Data.String.Interpolate (i) import GHC.Conc qualified as GHC import GlobalOptions import Juvix.Compiler.Pipeline.Root +import Juvix.Prelude.Pretty (mkAnsiText) import TopCommand import TopCommand.Options @@ -17,17 +18,24 @@ main = do numThreads (_runAppIOArgsGlobalOptions ^. globalNumThreads) >>= GHC.setNumCapabilities mbuildDir <- mapM (prepathToAbsDir invokeDir) (_runAppIOArgsGlobalOptions ^? globalBuildDir . _Just . pathPath) mainFile <- topCommandInputPath cli - mapM_ checkMainFile mainFile + let loggerOpts = + LoggerOptions + { _loggerLevel = _runAppIOArgsGlobalOptions ^. globalLogLevel, + _loggerUseColors = not (_runAppIOArgsGlobalOptions ^. globalNoColors) + } runM . runTaggedLockPermissive + . runLoggerIO loggerOpts + . runFilesIO $ do + mapM_ checkMainFile mainFile _runAppIOArgsRoot <- findRootAndChangeDir (containingDir <$> mainFile) mbuildDir invokeDir runAppIO RunAppIOArgs {..} (runTopCommand cli) where - checkMainFile :: SomePath b -> IO () - checkMainFile p = unlessM (doesSomePathExist p) err + checkMainFile :: forall r b. (Members '[Logger, EmbedIO] r) => SomePath b -> Sem r () + checkMainFile p = unlessM (liftIO (doesSomePathExist p)) err where - err :: IO () + err :: Sem r () err = do - hPutStrLn stderr [i|The input path #{p} does not exist|] + logError (mkAnsiText @Text [i|The input path #{p} does not exist|]) exitFailure diff --git a/app/TopCommand.hs b/app/TopCommand.hs index 5c7ab1c89d..5b0ea29942 100644 --- a/app/TopCommand.hs +++ b/app/TopCommand.hs @@ -28,7 +28,7 @@ showHelpText = do runTopCommand :: forall r. - (Members '[EmbedIO, App, TaggedLock] r) => + (Members AppEffects r) => TopCommand -> Sem r () runTopCommand = \case @@ -37,14 +37,14 @@ runTopCommand = \case DisplayHelp -> showHelpText Doctor opts -> runLogIO (Doctor.runCommand opts) Isabelle opts -> Isabelle.runCommand opts - Init opts -> runLogIO (Init.init opts) + Init opts -> Init.init opts Dev opts -> Dev.runCommand opts Typecheck opts -> Typecheck.runCommand opts Compile opts -> Compile.runCommand opts - Clean opts -> runFilesIO (Clean.runCommand opts) + Clean opts -> Clean.runCommand opts Eval opts -> Eval.runCommand opts Html opts -> Html.runCommand opts Markdown opts -> Markdown.runCommand opts JuvixRepl opts -> Repl.runCommand opts - JuvixFormat opts -> runFilesIO (Format.runCommand opts) + JuvixFormat opts -> Format.runCommand opts Dependencies opts -> Dependencies.runCommand opts diff --git a/juvix-stdlib b/juvix-stdlib index 16211500dc..6999b0b35f 160000 --- a/juvix-stdlib +++ b/juvix-stdlib @@ -1 +1 @@ -Subproject commit 16211500dc59a944f851fbaeeef703fdd09163fa +Subproject commit 6999b0b35fe946de28fc4061038ea4d8e4615265 diff --git a/src/Juvix/Compiler/Pipeline.hs b/src/Juvix/Compiler/Pipeline.hs index 14d05918b0..46f5e82b74 100644 --- a/src/Juvix/Compiler/Pipeline.hs +++ b/src/Juvix/Compiler/Pipeline.hs @@ -56,7 +56,7 @@ import Juvix.Data.Effect.Process import Juvix.Data.Field import Parallel.ProgressLog (ProgressLog) -type PipelineAppEffects = '[TaggedLock, Reader PipelineOptions, ProgressLog, EmbedIO] +type PipelineAppEffects = '[TaggedLock, Reader PipelineOptions, Logger, EmbedIO] type PipelineLocalEff = '[ ModuleInfoCache, @@ -74,6 +74,7 @@ type PipelineLocalEff = Error GitProcessError, Process, Log, + ProgressLog, Reader EntryPoint, Files, Error JuvixError, diff --git a/src/Juvix/Compiler/Pipeline/Repl.hs b/src/Juvix/Compiler/Pipeline/Repl.hs index 9569b9e07c..671afdb0d5 100644 --- a/src/Juvix/Compiler/Pipeline/Repl.hs +++ b/src/Juvix/Compiler/Pipeline/Repl.hs @@ -44,7 +44,9 @@ upToInternalExpression p = do . runStateArtifacts artifactScoperState . runReader pkg $ runNameIdGenArtifacts (Scoper.scopeCheckExpression (Store.getScopedModuleTable mtab) scopeTable p) - >>= runNameIdGenArtifacts . runReader scopeTable . Internal.fromConcreteExpression + >>= runNameIdGenArtifacts + . runReader scopeTable + . Internal.fromConcreteExpression expressionUpToAtomsParsed :: (Members '[State Artifacts, Error JuvixError] r) => diff --git a/src/Juvix/Compiler/Pipeline/Run.hs b/src/Juvix/Compiler/Pipeline/Run.hs index 3967b36554..6b4155ba9e 100644 --- a/src/Juvix/Compiler/Pipeline/Run.hs +++ b/src/Juvix/Compiler/Pipeline/Run.hs @@ -106,7 +106,7 @@ runPathResolverInput m = do runIOEitherPipeline' :: forall a r. - (Members '[Reader PipelineOptions, ProgressLog, TaggedLock, EmbedIO] r) => + (Members '[Reader PipelineOptions, Logger, TaggedLock, EmbedIO] r) => EntryPoint -> Sem (PipelineEff' r) a -> Sem r (HighlightInput, (Either JuvixError (ResolverState, a))) @@ -120,6 +120,7 @@ runIOEitherPipeline' entry a = do . runJuvixError . runFilesIO . runReader entry + . runProgressLog defaultProgressLogOptions . runLogIO . runProcessIO . mapError (JuvixError @GitProcessError) diff --git a/src/Juvix/Data.hs b/src/Juvix/Data.hs index 322280be72..0528b976cf 100644 --- a/src/Juvix/Data.hs +++ b/src/Juvix/Data.hs @@ -14,6 +14,7 @@ module Juvix.Data module Juvix.Data.Pragmas, module Juvix.Data.Processed, module Juvix.Data.Uid, + module Juvix.Data.Logger, module Juvix.Data.Universe, module Juvix.Data.Wildcard, module Juvix.Data.WithLoc, @@ -36,6 +37,7 @@ import Juvix.Data.Irrelevant import Juvix.Data.IsImplicit import Juvix.Data.Keyword import Juvix.Data.Loc +import Juvix.Data.Logger import Juvix.Data.NameId qualified import Juvix.Data.NumThreads import Juvix.Data.Pragmas diff --git a/src/Juvix/Data/Error/GenericError.hs b/src/Juvix/Data/Error/GenericError.hs index d643118a33..2b27218dd3 100644 --- a/src/Juvix/Data/Error/GenericError.hs +++ b/src/Juvix/Data/Error/GenericError.hs @@ -55,7 +55,7 @@ errorIntervals e = do e' <- genericError e return (e' ^. genericErrorIntervals) -render :: (ToGenericError e, Member (Reader GenericOptions) r) => Bool -> Bool -> e -> Sem r Text +render :: (ToGenericError e, Member (Reader GenericOptions) r) => Bool -> Maybe Char -> e -> Sem r Text render ansi endChar err = do g <- genericError err let gMsg = g ^. genericErrorMessage @@ -66,20 +66,18 @@ render ansi endChar err = do | otherwise -> return $ helper renderStrict (toTextDoc gMsg) where lastChar :: Doc a - lastChar - | endChar = "ת" - | otherwise = "" + lastChar = maybe "" pretty endChar -- | Render the error to Text. renderText :: (ToGenericError e, Member (Reader GenericOptions) r) => e -> Sem r Text -renderText = render False False +renderText = render False Nothing renderTextDefault :: (ToGenericError e) => e -> Text renderTextDefault = run . runReader defaultGenericOptions . renderText -- | Render the error with Ansi formatting (if any). renderAnsiText :: (ToGenericError e, Member (Reader GenericOptions) r) => e -> Sem r Text -renderAnsiText = render True False +renderAnsiText = render True Nothing printErrorAnsi :: (ToGenericError e, Members '[EmbedIO, Reader GenericOptions] r) => e -> Sem r () printErrorAnsi e = renderAnsiText e >>= \txt -> hPutStrLn stderr txt diff --git a/src/Juvix/Data/Logger.hs b/src/Juvix/Data/Logger.hs new file mode 100644 index 0000000000..6fe9ec0370 --- /dev/null +++ b/src/Juvix/Data/Logger.hs @@ -0,0 +1,114 @@ +module Juvix.Data.Logger + ( defaultLoggerOptions, + defaultLogLevel, + Logger, + LoggerOptions (..), + LogLevel (..), + logError, + logProgress, + logInfo, + logWarn, + logDebug, + runLoggerIO, + ignoreLogger, + localLogger, + loggerUseColors, + loggerLevel, + silenceProgressLog, + ) +where + +import Juvix.Prelude.Base.Foundation +import Juvix.Prelude.Effects.Base +import Juvix.Prelude.Effects.Output +import Juvix.Prelude.Pretty +import Prelude (show) + +data LogLevel + = LogLevelError + | LogLevelWarn + | LogLevelInfo + | LogLevelProgress + | LogLevelDebug + deriving stock (Eq, Ord, Enum, Bounded) + +instance Show LogLevel where + show = \case + LogLevelError -> "error" + LogLevelWarn -> "warn" + LogLevelInfo -> "info" + LogLevelProgress -> "progress" + LogLevelDebug -> "debug" + +instance Pretty LogLevel where + pretty = pretty . Prelude.show + +data Logger :: Effect where + LogMessage :: LogLevel -> AnsiText -> Logger m () + LocalLogger :: ((LogLevel -> Bool) -> LogLevel -> Bool) -> m a -> Logger m a + +data LoggerOptions = LoggerOptions + { _loggerUseColors :: Bool, + _loggerLevel :: LogLevel + } + +defaultLogLevel :: LogLevel +defaultLogLevel = LogLevelProgress + +defaultLoggerOptions :: LoggerOptions +defaultLoggerOptions = + LoggerOptions + { _loggerUseColors = True, + _loggerLevel = defaultLogLevel + } + +makeSem ''Logger +makeLenses ''LoggerOptions + +logError :: (Members '[Logger] r) => AnsiText -> Sem r () +logError = logMessage LogLevelError + +logWarn :: (Members '[Logger] r) => AnsiText -> Sem r () +logWarn = logMessage LogLevelWarn + +logInfo :: (Members '[Logger] r) => AnsiText -> Sem r () +logInfo = logMessage LogLevelInfo + +logProgress :: (Members '[Logger] r) => AnsiText -> Sem r () +logProgress = logMessage LogLevelProgress + +logDebug :: (Members '[Logger] r) => AnsiText -> Sem r () +logDebug = logMessage LogLevelDebug + +silenceProgressLog :: (Members '[Logger] r) => Sem r a -> Sem r a +silenceProgressLog = localLogger (\f -> f .&&. (/= LogLevelProgress)) + +runLoggerIO :: forall r a. (Members '[EmbedIO] r) => LoggerOptions -> Sem (Logger ': r) a -> Sem r a +runLoggerIO opts = interp . re + where + interp :: Sem (Output AnsiText ': Reader (LogLevel -> Bool) ': r) a -> Sem r a + interp = runReader (<= (opts ^. loggerLevel)) . runOutputSem printMsg + + printMsg :: forall r'. (Members '[EmbedIO] r') => AnsiText -> Sem r' () + printMsg = hRenderIO (opts ^. loggerUseColors) stderr + +re :: Sem (Logger ': r) a -> Sem (Output AnsiText ': Reader (LogLevel -> Bool) ': r) a +re = interpretTop2H handler + +handler :: + EffectHandler Logger (Output AnsiText ': Reader (LogLevel -> Bool) ': r) +handler localEnv = + \case + LocalLogger adjustPred localLog -> + localSeqUnlift localEnv $ \unlift -> + local adjustPred (unlift localLog) + LogMessage lvl msg -> do + loggerPredicate <- ask + when (loggerPredicate lvl) (output (msg <> ansiTextNewline)) + +ignoreLogger :: forall r a. Sem (Logger ': r) a -> Sem r a +ignoreLogger = interpretH $ \localEnv -> \case + LogMessage {} -> return () + LocalLogger _ localLog -> + localSeqUnlift localEnv $ \unlift -> + unlift localLog diff --git a/src/Juvix/Prelude/Pretty.hs b/src/Juvix/Prelude/Pretty.hs index 29e98871bb..e5d205f2f8 100644 --- a/src/Juvix/Prelude/Pretty.hs +++ b/src/Juvix/Prelude/Pretty.hs @@ -58,6 +58,12 @@ mkAnsiText = AnsiText . pure . AnsiTextAtom makeLenses ''AnsiText +ansiTextNewline :: AnsiText +ansiTextNewline = mkAnsiText @Text "\n" + +instance IsString AnsiText where + fromString = mkAnsiText + instance HasTextBackend String where toTextStream = toTextStream . pretty toTextDoc = toTextDoc . pretty diff --git a/src/Parallel/ProgressLog.hs b/src/Parallel/ProgressLog.hs index 2a5c873dc0..ed9a74e3b3 100644 --- a/src/Parallel/ProgressLog.hs +++ b/src/Parallel/ProgressLog.hs @@ -2,14 +2,14 @@ module Parallel.ProgressLog where import GHC.Conc (ThreadId) import Juvix.Data.CodeAnn +import Juvix.Data.Logger import Juvix.Prelude.Base data ProgressLog :: Effect where ProgressLog :: LogItem -> ProgressLog m () -data ProgressLogOptions = ProgressLogOptions - { _progressLogOptionsUseColors :: Bool, - _progressLogOptionsShowThreadId :: Bool +newtype ProgressLogOptions = ProgressLogOptions + { _progressLogOptionsShowThreadId :: Bool } data LogItem = LogItem @@ -21,13 +21,19 @@ makeSem ''ProgressLog makeLenses ''ProgressLogOptions makeLenses ''LogItem -runProgressLogIO :: (Members '[EmbedIO] r) => ProgressLogOptions -> Sem (ProgressLog ': r) a -> Sem r a -runProgressLogIO ProgressLogOptions {..} = interpret $ \case +defaultProgressLogOptions :: ProgressLogOptions +defaultProgressLogOptions = + ProgressLogOptions + { _progressLogOptionsShowThreadId = False + } + +runProgressLog :: (Members '[Logger] r) => ProgressLogOptions -> Sem (ProgressLog ': r) a -> Sem r a +runProgressLog ProgressLogOptions {..} = interpret $ \case ProgressLog LogItem {..} -> do let threadDoc :: Maybe (Doc CodeAnn) = do guard _progressLogOptionsShowThreadId return (kwBracketL <> show _logItemThreadId <> kwBracketR) - hRenderIO _progressLogOptionsUseColors stderr (threadDoc _logItemMessage <> hardline) + logProgress (mkAnsiText (threadDoc _logItemMessage)) ignoreProgressLog :: Sem (ProgressLog ': r) a -> Sem r a ignoreProgressLog = interpret $ \case diff --git a/test/Base.hs b/test/Base.hs index 4d961d04ec..01758b7249 100644 --- a/test/Base.hs +++ b/test/Base.hs @@ -24,7 +24,6 @@ import Juvix.Extra.Paths hiding (rootBuildDir) import Juvix.Prelude hiding (assert) import Juvix.Prelude.Env import Juvix.Prelude.Pretty (prettyString) -import Parallel.ProgressLog import System.Process qualified as P import Test.Tasty import Test.Tasty.HUnit hiding (assertFailure) @@ -92,7 +91,7 @@ assertCmdExists cmd = testTaggedLockedToIO :: (MonadIO m) => Sem PipelineAppEffects a -> m a testTaggedLockedToIO = runM - . ignoreProgressLog + . ignoreLogger . runReader testPipelineOptions . runTaggedLock LockModeExclusive diff --git a/tests/smoke/Commands/clean.smoke.yaml b/tests/smoke/Commands/clean.smoke.yaml index 2084301f57..9440ff5534 100644 --- a/tests/smoke/Commands/clean.smoke.yaml +++ b/tests/smoke/Commands/clean.smoke.yaml @@ -42,7 +42,7 @@ tests: configDir="$config/juvix/$version" cd $temp cp "$baseDir/examples/milestone/HelloWorld/HelloWorld.juvix" . - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix [ -d $configDir ] juvix clean [ -d $configDir ] @@ -59,7 +59,7 @@ tests: temp=$(mktemp -d) trap 'rm -rf -- "$temp"' EXIT cd ./examples/milestone/HelloWorld - juvix --only-errors compile native -o $temp/Hello HelloWorld.juvix + juvix --log-level error compile native -o $temp/Hello HelloWorld.juvix juvix clean [ -d $temp/.juvix-build ] stdout: "" @@ -75,7 +75,7 @@ tests: temp_build_dir=$(mktemp -d) trap 'rm -rf -- "$temp_build_dir"' EXIT cd ./examples/milestone/HelloWorld - juvix --only-errors compile native -o $temp/Hello HelloWorld.juvix --internal-build-dir "$temp_build_dir" + juvix --log-level error compile native -o $temp/Hello HelloWorld.juvix --internal-build-dir "$temp_build_dir" juvix --internal-build-dir "$temp_build_dir" clean [ -d $temp_build_dir ] stdout: "" @@ -92,7 +92,7 @@ tests: trap 'rm -rf -- "$temp_build_dir"' EXIT cp -r ./examples/milestone/HelloWorld/. $temp cd $temp - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix juvix --internal-build-dir "$temp_build_dir" clean [ -d $temp/.juvix-build ] stdout: "" diff --git a/tests/smoke/Commands/compile-dependencies-package-juvix.smoke.yaml b/tests/smoke/Commands/compile-dependencies-package-juvix.smoke.yaml index 50821a38e9..8f94b6e903 100644 --- a/tests/smoke/Commands/compile-dependencies-package-juvix.smoke.yaml +++ b/tests/smoke/Commands/compile-dependencies-package-juvix.smoke.yaml @@ -57,7 +57,7 @@ tests: EOF # compile project - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix if [ ! -f "juvix.lock.yaml" ]; then exit 1 fi @@ -122,14 +122,14 @@ tests: EOF # compile project - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix # Delete the dependency rm -rf $temp/dep rm HelloWorld # Compile using the offline clone - juvix --only-errors --offline compile native HelloWorld.juvix + juvix --log-level error --offline compile native HelloWorld.juvix ./HelloWorld stdout: contains: Hello from dep @@ -191,7 +191,7 @@ tests: EOF # compile project the first time - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix # update the dependency cd $temp/dep @@ -228,7 +228,7 @@ tests: # compile with the new hash rm juvix.lock.yaml - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix ./HelloWorld stdout: contains: This is from the second commit @@ -375,7 +375,7 @@ tests: cd $temp/base # compile with the new hash - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix ./HelloWorld stdout: contains: "Hello from dep1\nHello from dep2" @@ -437,7 +437,7 @@ tests: EOF # compile project - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix # update dependency cd $temp/dep @@ -456,7 +456,7 @@ tests: cd $temp/base juvix clean - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix ./HelloWorld stdout: contains: Hello from dep @@ -532,7 +532,7 @@ tests: # compile project and generate the lockfile # that uses $dep1hash1 - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix cd $temp/base @@ -556,7 +556,7 @@ tests: juvix dependencies update # compile should now use $dep1hash2 - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix ./HelloWorld stdout: contains: Hello from commit 2 @@ -674,7 +674,7 @@ tests: EOF # compile and run the project - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix ./HelloWorld stdout: contains: "Hello from dep1\nHello from dep2" @@ -750,7 +750,7 @@ tests: # compile project the first time # It should use code from the first commit - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix output=$(./HelloWorld) if [ "$output" != "Hello from dep" ]; then @@ -776,7 +776,7 @@ tests: EOF rm juvix.lock.yaml - juvix --only-errors --offline compile native HelloWorld.juvix + juvix --log-level error --offline compile native HelloWorld.juvix ./HelloWorld stdout: contains: This is from the second commit @@ -836,7 +836,7 @@ tests: EOF # compile project - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix stderr: contains: invalid-ref stdout: @@ -882,7 +882,7 @@ tests: EOF # compile project - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix stderr: contains: Error stdout: @@ -928,7 +928,7 @@ tests: EOF # compile project - juvix --only-errors --offline compile native HelloWorld.juvix + juvix --log-level error --offline compile native HelloWorld.juvix stderr: contains: Failed to obtain remote dependencies stdout: @@ -999,13 +999,13 @@ tests: EOF # compile project - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix # corrupt the clone find $XDG_CONFIG_HOME -type d -name '.git' -exec rm -rf {} + # compile project - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix stderr: contains: juvix clean stdout: @@ -1052,7 +1052,7 @@ tests: EOF # compile project - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix stdout: contains: "" stderr: @@ -1115,13 +1115,13 @@ tests: EOF # compile project - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix # delete the dependency to check that it's not required rm -rf $temp/dep # compile project - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix stderr: "" stdout: contains: Cloning diff --git a/tests/smoke/Commands/compile-dependencies.smoke.yaml b/tests/smoke/Commands/compile-dependencies.smoke.yaml index d61a8f9875..87e5b57a2d 100644 --- a/tests/smoke/Commands/compile-dependencies.smoke.yaml +++ b/tests/smoke/Commands/compile-dependencies.smoke.yaml @@ -53,7 +53,7 @@ tests: EOF # compile project - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix if [ ! -f "juvix.lock.yaml" ]; then exit 1 fi @@ -114,14 +114,14 @@ tests: EOF # compile project - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix # Delete the dependency rm -rf $temp/dep rm HelloWorld # Compile using the offline clone - juvix --only-errors --offline compile native HelloWorld.juvix + juvix --log-level error --offline compile native HelloWorld.juvix ./HelloWorld stdout: contains: Hello from dep @@ -179,7 +179,7 @@ tests: EOF # compile project the first time - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix # update the dependency cd $temp/dep @@ -212,7 +212,7 @@ tests: # compile with the new hash rm juvix.lock.yaml - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix ./HelloWorld stdout: contains: This is from the second commit @@ -351,7 +351,7 @@ tests: cd $temp/base # compile with the new hash - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix ./HelloWorld stdout: contains: "Hello from dep1\nHello from dep2" @@ -409,7 +409,7 @@ tests: EOF # compile project - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix # update dependency cd $temp/dep @@ -428,7 +428,7 @@ tests: cd $temp/base juvix clean - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix ./HelloWorld stdout: contains: Hello from dep @@ -500,7 +500,7 @@ tests: # compile project and generate the lockfile # that uses $dep1hash1 - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix cd $temp/base @@ -520,7 +520,7 @@ tests: juvix dependencies update # compile should now use $dep1hash2 - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix ./HelloWorld stdout: contains: Hello from commit 2 @@ -630,7 +630,7 @@ tests: EOF # compile and run the project - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix ./HelloWorld stdout: contains: "Hello from dep1\nHello from dep2" @@ -702,7 +702,7 @@ tests: # compile project the first time # It should use code from the first commit - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix output=$(./HelloWorld) if [ "$output" != "Hello from dep" ]; then @@ -724,7 +724,7 @@ tests: EOF rm juvix.lock.yaml - juvix --only-errors --offline compile native HelloWorld.juvix + juvix --log-level error --offline compile native HelloWorld.juvix ./HelloWorld stdout: contains: This is from the second commit @@ -780,7 +780,7 @@ tests: EOF # compile project - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix stderr: contains: invalid-ref stdout: @@ -822,7 +822,7 @@ tests: EOF # compile project - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix stderr: contains: Error stdout: @@ -864,7 +864,7 @@ tests: EOF # compile project - juvix --only-errors --offline compile native HelloWorld.juvix + juvix --log-level error --offline compile native HelloWorld.juvix stderr: contains: Failed to obtain remote dependencies stdout: @@ -931,13 +931,13 @@ tests: EOF # compile project - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix # corrupt the clone find $XDG_CONFIG_HOME -type d -name '.git' -exec rm -rf {} + # compile project - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix stderr: contains: juvix clean stdout: @@ -983,7 +983,7 @@ tests: EOF # compile project - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix stdout: contains: "" stderr: @@ -1039,7 +1039,7 @@ tests: EOF # compile project to create lock file - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix cd $temp/dep cat <<-EOF > HelloDep.juvix @@ -1053,14 +1053,14 @@ tests: cd $temp/base juvix clean --global - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix ./HelloWorld # Update the Package file and recompile # it should use the latest commit echo "-- comment" >> Package.juvix juvix clean --global - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix ./HelloWorld stderr: "" @@ -1123,13 +1123,13 @@ tests: EOF # compile project - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix # delete the dependency to check that it's not required rm -rf $temp/dep # compile project - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix stderr: "" stdout: contains: Cloning diff --git a/tests/smoke/Commands/compile.smoke.yaml b/tests/smoke/Commands/compile.smoke.yaml index 4b465c84b8..10db0acf7e 100644 --- a/tests/smoke/Commands/compile.smoke.yaml +++ b/tests/smoke/Commands/compile.smoke.yaml @@ -18,7 +18,7 @@ tests: - bash script: | cd ./examples/milestone/HelloWorld - juvix --only-errors compile native + juvix --log-level error compile native ./HelloWorld exit-status: 0 stdout: | @@ -35,9 +35,9 @@ tests: cp -r HelloWorld "$temp" cd "$temp/HelloWorld" sed -i'.bak' 's/just \"HelloWorld.juvix\"/nothing/' Package.juvix - juvix --only-errors compile native + juvix --log-level error compile native exit-status: 1 - stdout: | + stderr: | A path to the main file must be given in the CLI or specified in the `main` field of the juvix.yaml file - name: hello-world @@ -46,7 +46,7 @@ tests: - bash script: | cd ./examples/milestone/HelloWorld - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix ./HelloWorld exit-status: 0 stdout: | @@ -60,7 +60,7 @@ tests: temp=$(mktemp -d) trap 'rm -rf -- "$temp"' EXIT cd ./examples/milestone/HelloWorld - juvix --only-errors compile native -o $temp/Hello HelloWorld.juvix + juvix --log-level error compile native -o $temp/Hello HelloWorld.juvix $temp/Hello exit-status: 0 stdout: | @@ -80,7 +80,7 @@ tests: touch "$rootDir/juvix.yaml" cd "$rootDir" - juvix --only-errors compile native HelloWorld.juvix --internal-build-dir "$buildDir" + juvix --log-level error compile native HelloWorld.juvix --internal-build-dir "$buildDir" num_files=$(ls -1qA "$buildDir" | wc -l) if [ $num_files -le 0 ]; then @@ -106,7 +106,7 @@ tests: echo "dependencies: [.juvix-build/stdlib]" >> "$rootDir/juvix.yaml" cd "$rootDir" - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix if [ ! -d "$rootDir/.juvix-build" ]; then exit 1 @@ -123,7 +123,7 @@ tests: trap 'rm -rf -- "$temp"' EXIT testdir=$PWD/examples/milestone/HelloWorld cd $temp - juvix --only-errors compile native $testdir/HelloWorld.juvix + juvix --log-level error compile native $testdir/HelloWorld.juvix ./HelloWorld stdout: | hello world! @@ -138,7 +138,7 @@ tests: trap 'rm -rf -- "$temp"' EXIT testdir=$PWD/examples/milestone/HelloWorld cd $temp - juvix --only-errors compile wasi $testdir/HelloWorld.juvix + juvix --log-level error compile wasi $testdir/HelloWorld.juvix [ -f HelloWorld.wasm ] stdout: "" exit-status: 0 @@ -152,7 +152,7 @@ tests: trap 'rm -rf -- "$temp"' EXIT testdir=$PWD/tests/Anoma/Compilation/positive cd $temp - juvix --only-errors compile anoma $testdir/test001.juvix + juvix --log-level error compile anoma $testdir/test001.juvix [ -f test001.nockma ] juvix dev nockma repl test001.nockma stdout: @@ -170,7 +170,7 @@ tests: trap 'rm -rf -- "$temp"' EXIT testdir=$PWD/tests/VampIR/positive/Compilation cd $temp - juvix --only-errors compile vampir $testdir/test001.juvix + juvix --log-level error compile vampir $testdir/test001.juvix grep -q 'VampIR runtime for Juvix (safe version)' test001.pir stdout: "" exit-status: 0 @@ -184,7 +184,7 @@ tests: trap 'rm -rf -- "$temp"' EXIT testdir=$PWD/tests/VampIR/positive/Compilation cd $temp - juvix --only-errors compile vampir $testdir/test001.juvix --unsafe + juvix --log-level error compile vampir $testdir/test001.juvix --unsafe grep -q 'VampIR runtime for Juvix (unsafe version)' test001.pir stdout: "" exit-status: 0 @@ -215,7 +215,7 @@ tests: cd $temp cp "$base"/examples/milestone/HelloWorld/HelloWorld.juvix . export XDG_CONFIG_HOME="$config/symlink" - juvix --only-errors compile native HelloWorld.juvix + juvix --log-level error compile native HelloWorld.juvix ./HelloWorld exit-status: 0 stdout: | diff --git a/tests/smoke/Commands/dev/internal.smoke.yaml b/tests/smoke/Commands/dev/internal.smoke.yaml index 848888d1f6..b9fe649197 100644 --- a/tests/smoke/Commands/dev/internal.smoke.yaml +++ b/tests/smoke/Commands/dev/internal.smoke.yaml @@ -19,7 +19,7 @@ tests: - typecheck args: - positive/Internal/Simple.juvix - stdout: + stderr: contains: | Well done! It type checks exit-status: 0 @@ -27,7 +27,8 @@ tests: - name: internal-typecheck-only-errors command: - juvix - - --only-errors + - --log-level + - error - dev - internal - typecheck diff --git a/tests/smoke/Commands/eval.smoke.yaml b/tests/smoke/Commands/eval.smoke.yaml index 1a4051805e..30c4a06d1e 100644 --- a/tests/smoke/Commands/eval.smoke.yaml +++ b/tests/smoke/Commands/eval.smoke.yaml @@ -16,5 +16,5 @@ tests: - eval - positive/LambdaCalculus.juvix stdin: "" - stdout: "function not found: main\n" + stderr: "function not found: main\n" exit-status: 1 diff --git a/tests/smoke/Commands/format.smoke.yaml b/tests/smoke/Commands/format.smoke.yaml index 22ec5b48a7..880fa76409 100644 --- a/tests/smoke/Commands/format.smoke.yaml +++ b/tests/smoke/Commands/format.smoke.yaml @@ -361,7 +361,7 @@ tests: - juvix - format stdin: 'module OtherFormat; import Stdlib.Prelude open; main : Nat := 5module OtherFormat; import Stdlib.Prelude open; main : Nat := 5;; ' - stdout: + stderr: contains: juvix format error exit-status: 1 diff --git a/tests/smoke/Commands/init.smoke.yaml b/tests/smoke/Commands/init.smoke.yaml index 1ac0444215..da11a90254 100644 --- a/tests/smoke/Commands/init.smoke.yaml +++ b/tests/smoke/Commands/init.smoke.yaml @@ -11,8 +11,13 @@ tests: cd $temp echo -e 'abc\n\n\n' | juvix init juvix typecheck Package.juvix + stderr: + contains: Well done! It type checks stdout: - contains: type checks + matches: + regex: .* + options: + - dot-all exit-status: 0 - name: init-non-interactive-name command: diff --git a/tests/smoke/Commands/markdown.smoke.yaml b/tests/smoke/Commands/markdown.smoke.yaml index 6b638ca7ed..b4b1931465 100644 --- a/tests/smoke/Commands/markdown.smoke.yaml +++ b/tests/smoke/Commands/markdown.smoke.yaml @@ -4,7 +4,8 @@ tests: - name: markdown-help-theme command: - juvix - - --only-errors + - --log-level + - error - markdown - --help stdout: @@ -21,7 +22,7 @@ tests: cp Test.juvix.md $temp cd $temp touch juvix.yaml - juvix --only-errors markdown Test.juvix.md --stdout + juvix --log-level error markdown Test.juvix.md --stdout stdout: contains:

@@ -37,7 +38,7 @@ tests:
         cp Test.juvix.md $temp
         cd $temp
         touch juvix.yaml
-        juvix --only-errors markdown Test.juvix.md --output-dir=OUT
+        juvix --log-level error markdown Test.juvix.md --output-dir=OUT
         [ -d OUT ]
         [ -f OUT/Test.md ]
     stdout: ''
@@ -53,7 +54,7 @@ tests:
         cp Test.juvix.md $temp
         cd $temp
         touch juvix.yaml
-        juvix --only-errors markdown Test.juvix.md --prefix-id="XYZ"
+        juvix --log-level error markdown Test.juvix.md --prefix-id="XYZ"
         cat markdown/Test.md
     stdout:
       matches: |
@@ -70,7 +71,7 @@ tests:
         cp Test.juvix.md $temp
         cd $temp
         touch juvix.yaml
-        juvix --only-errors markdown Test.juvix.md --no-path --stdout
+        juvix --log-level error markdown Test.juvix.md --no-path --stdout
     stdout:
       matches: |
         .*href="#Test:[0-9]+".*
@@ -86,7 +87,7 @@ tests:
         cp Test.juvix.md $temp
         cd $temp
         touch juvix.yaml
-        juvix --only-errors markdown Test.juvix.md --no-path --prefix-url Y --prefix-id X --stdout
+        juvix --log-level error markdown Test.juvix.md --no-path --prefix-url Y --prefix-id X --stdout
     stdout:
       matches: |
         .*href="Y#XTest:[0-9]+".*
diff --git a/tests/smoke/Commands/typecheck.smoke.yaml b/tests/smoke/Commands/typecheck.smoke.yaml
index 782d3227b7..656fd9927a 100644
--- a/tests/smoke/Commands/typecheck.smoke.yaml
+++ b/tests/smoke/Commands/typecheck.smoke.yaml
@@ -15,14 +15,15 @@ tests:
       - typecheck
     args:
       - positive/Internal/Simple.juvix
-    stdout:
+    stderr:
       equals: "Well done! It type checks\n"
     exit-status: 0
 
   - name: flag-only-errors
     command:
       - juvix
-      - --only-errors
+      - --log-level
+      - error
       - typecheck
     args:
       - positive/Internal/Simple.juvix
@@ -51,13 +52,8 @@ tests:
         trap 'rm -rf -- "$temp"' EXIT
         export XDG_CONFIG_HOME="$temp"
         HOME="home" JUVIX_TEST_PATH="other dep" juvix typecheck positive/FancyPaths/Main.juvix
-    stdout:
-      equals: "Well done! It type checks\n"
     stderr:
-      matches:
-        regex: .*
-        options:
-          - dot-all
+      contains: "Well done! It type checks\n"
     exit-status: 0
 
   - name: typecheck-global-package
@@ -76,7 +72,7 @@ tests:
         cd $projDir
         echo 'module foo;' > foo.juvix
         juvix typecheck foo.juvix
-    stdout:
+    stderr:
       equals: "Well done! It type checks\n"
     exit-status: 0
 
@@ -100,13 +96,8 @@ tests:
         globalPackageDir=$(juvix dev root)
         packagePackageDir="$(dirname $globalPackageDir)"/package
         juvix typecheck "$packagePackageDir/PackageDescription/V2.juvix"
-    stdout:
-      equals: "Well done! It type checks\n"
     stderr:
-      matches:
-        regex: .*
-        options:
-          - dot-all
+      contains: "Well done! It type checks\n"
     exit-status: 0
 
   - name: typecheck-stdin
diff --git a/tests/smoke/global.smoke.yaml b/tests/smoke/global.smoke.yaml
new file mode 100644
index 0000000000..279523d84a
--- /dev/null
+++ b/tests/smoke/global.smoke.yaml
@@ -0,0 +1,15 @@
+working-directory: ../../tests
+
+tests:
+  - name: ide-end-error-char
+    command:
+      - juvix
+      - --ide-end-error-char
+      - ת
+      - typecheck
+    args:
+      - negative/NoDependencies/InvalidImport.juvix
+    stderr:
+      contains: |
+        ת
+    exit-status: 1