effectful-cli 0.2.7.0 → 0.2.8.0
raw patch · 5 files changed
+80/−10 lines, 5 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
+ Effectful.CLI.Config: showConfig :: forall a (es :: [Effect]). (FromValue a, ToTable a, IOE :> es, Error CLIError :> es) => FilePath -> Eff es Text
- Data.CLI.Config: class FromValue ConfigOf c => ConfigFile c where {
+ Data.CLI.Config: class (FromValue ConfigOf c, ToTable ConfigOf c) => ConfigFile c where {
Files
- CHANGELOG.md +6/−0
- effectful-cli.cabal +1/−1
- src/Data/CLI/Config.hs +11/−6
- src/Effectful/CLI/Config.hs +19/−1
- test/Spec.hs +43/−2
CHANGELOG.md view
@@ -1,3 +1,9 @@+## [2.8.0](https://github.com/haskell-github-trust/effectful-cli/compare/2.7.0...2.8.0) (2026-11-09)++### Features++* show all config in show command ([a9318f7](https://github.com/haskell-github-trust/effectful-cli/commit/a9318f7640627135fc8991f7bd5c835bcc47c55b))+ ## [2.7.0](https://github.com/haskell-github-trust/effectful-cli/compare/2.6.0...2.7.0) (2026-11-07) ### Features
effectful-cli.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: effectful-cli-version: 0.2.7.0+version: 0.2.8.0 synopsis: CLI helpers for the effectful ecosystem description: Please see the README at https://github.com/haskell-github-trust/effectful-cli category: CLI
src/Data/CLI/Config.hs view
@@ -14,19 +14,24 @@ import Data.Kind (Type) import Data.Text (Text) import Data.Text qualified as T-import Effectful.CLI.Config (getConfigKey, readConfigText, setConfigKey)+import Effectful.CLI.Config (getConfigKey, setConfigKey, showConfig) import Effectful.CLI.Exception (rethrowIO) import Effectful.CLI.IO (printOutputLn) import Effectful.Reader.Static (asks) import GHC.Enum (boundedEnumFrom, boundedEnumFromThen) import Options.Applicative (Parser, completer, listCompleter, metavar, strArgument)-import Toml.Schema (FromValue)+import Toml.Schema (FromValue, ToTable) -- | Application config @c@ that knows its config file and the type it decodes to. --+-- 'ToTable' is needed by 'ConfigShow'; defaults come from the 'FromValue'+-- instance filling missing keys.+-- -- @since 0.2.6.0-class FromValue (ConfigOf c) => ConfigFile c where+class (FromValue (ConfigOf c), ToTable (ConfigOf c)) => ConfigFile c where -- | Type the config file decodes to; 'ConfigSet' refuses to write anything else.+ --+ -- @since 0.2.8.0 type ConfigOf c :: Type -- | Path of the config file.@@ -42,7 +47,7 @@ -- -- @since 0.2.6.0 data ConfigCommand c e- = -- | Print the config file.+ = -- | Print the effective config: file values over the defaults. ConfigShow | -- | Print a dotted key's value. ConfigGet Text@@ -72,7 +77,7 @@ cmdname (ConfigGet _) = "get" cmdname (ConfigSet _ _) = "set" - doc ConfigShow = "Print the config file"+ doc ConfigShow = "Print the effective config (file merged over defaults)" doc (ConfigGet _) = "Print a dotted key's value (e.g. section.key)" doc (ConfigSet _ _) = "Set a dotted key to a TOML literal, or a string if not one" @@ -83,7 +88,7 @@ runner cmd = do path <- asks @c configFilePath rethrowIO (InputError . ("config file: " <>) . T.show) $ case cmd of- ConfigShow -> printOutputLn . T.stripEnd =<< readConfigText path+ ConfigShow -> printOutputLn =<< showConfig @(ConfigOf c) path ConfigGet k -> printOutputLn =<< getConfigKey path k ConfigSet k v -> setConfigKey @(ConfigOf c) (configKeys @c) path k v
src/Effectful/CLI/Config.hs view
@@ -4,6 +4,7 @@ -- | Read and edit a TOML config file by dotted key (@github.project.team@). module Effectful.CLI.Config ( readConfigText,+ showConfig, getConfigKey, setConfigKey, lookupKey,@@ -33,7 +34,7 @@ ) import Toml qualified import Toml.Pretty (prettyValue)-import Toml.Schema (FromValue)+import Toml.Schema (FromValue, ToTable (toTable)) -- | The config file's contents, empty if it does not exist. --@@ -45,6 +46,23 @@ readConfigText path = liftIO $ do exists <- doesFileExist path if exists then T.readFile path else pure ""++-- | The config file decoded as @a@ (so defaults fill missing keys, and a+-- missing file is all defaults), rendered back as TOML.+--+-- @since 0.2.8.0+showConfig+ :: forall a es+ . FromValue a+ => ToTable a+ => IOE :> es+ => Error CLIError :> es+ => FilePath+ -> Eff es Text+showConfig path =+ readConfigText path >>= \raw -> case Toml.decode @a raw of+ Failure es -> throwError (InputError ("invalid config: " <> T.stripEnd (T.pack (unlines es))))+ Success _ a -> pure (T.stripEnd (T.show (prettyToml (toTable a)))) -- | Render a dotted key's value: strings unquoted, tables as TOML sections. --
test/Spec.hs view
@@ -12,9 +12,17 @@ ) import Data.Error.CLI (CLIError (..), displayCLIError) import Data.List (isInfixOf)+import Data.Maybe (fromMaybe) import Effectful (Eff, IOE, liftIO, runEff) import Effectful.CLI.Conc (batchConcurrentlyWithIndex)-import Effectful.CLI.Config (getConfigKey, lookupKey, parseValue, setConfigKey, setKey)+import Effectful.CLI.Config (+ getConfigKey,+ lookupKey,+ parseValue,+ setConfigKey,+ setKey,+ showConfig,+ ) import Effectful.CLI.Exception (rethrowIO) import Effectful.CLI.IO (resolveIndex) import Effectful.Concurrent (runConcurrent)@@ -25,7 +33,18 @@ import Test.Hspec import Text.Megaparsec.Char (string) import Toml (Table, Table' (..), Value' (..))-import Toml.Schema (FromValue (..), parseTableFromValue, reqKey, reqKeyOf)+import Toml.Schema (+ FromValue (..),+ ToTable (..),+ ToValue (..),+ defaultTableToValue,+ optKey,+ parseTableFromValue,+ reqKey,+ reqKeyOf,+ table,+ (.=),+ ) isInputError :: Either CLIError a -> Bool isInputError (Left (InputError _)) = True@@ -151,6 +170,28 @@ r `shouldSatisfy` \case Left (InputError m) -> "sec is a section, set one of: sec.x, sec.y" `isInfixOf` show m _ -> False++ it "shows defaults for a missing file and file values over them" $ do+ dir <- getTemporaryDirectory+ let missing = dir </> "effectful-cli-config-missing.toml"+ present = dir </> "effectful-cli-config-show.toml"+ writeFile present "n = 3\n"+ r <-+ runEff . runErrorNoCallStack @CLIError $+ (,) <$> showConfig @Defaulted missing <*> showConfig @Defaulted present+ removeFile present+ r `shouldBe` Right ("n = 7", "n = 3")++newtype Defaulted = Defaulted Int++instance FromValue Defaulted where+ fromValue = parseTableFromValue (Defaulted . fromMaybe 7 <$> optKey "n")++instance ToValue Defaulted where+ toValue = defaultTableToValue++instance ToTable Defaulted where+ toTable (Defaulted n) = table ["n" .= n] newtype Section = Section Int