From 753db879fa49fd0ed5af928662f379a816c7c251 Mon Sep 17 00:00:00 2001 From: Jan Tojnar Date: Tue, 16 Apr 2024 01:59:38 +0200 Subject: [PATCH] Implement dictionary support --- data/dict.settings | 9 +++++++++ output/dconf.nix | 10 ++++----- output/dict.nix | 47 +++++++++++++++++++++++++++++++++++++++++++ output/headers.nix | 6 +++--- output/typed.nix | 4 ++-- src/DConf.hs | 37 ++++++++++++++++++++++++++-------- src/DConf/Data.hs | 3 ++- src/Nix.hs | 4 +++- test/DConf2NixTest.hs | 10 +++++++++ 9 files changed, 110 insertions(+), 20 deletions(-) create mode 100644 data/dict.settings create mode 100644 output/dict.nix diff --git a/data/dict.settings b/data/dict.settings new file mode 100644 index 0000000..ce78802 --- /dev/null +++ b/data/dict.settings @@ -0,0 +1,9 @@ +[dict] +dict={1: "one", 2: "two", 3: "three"} +empty-dict=@a{sv} {} +empty-arr-dict=@a{sv} [] +dict-entry={1, "one"} +entry-arr=[{1, "one"}, {2, "two"}, {3, "three"}] +nested=[{'org.gnome.Contacts.desktop': <{'position': <0>}>, 'org.gnome.Maps.desktop': <{'position': <1>}>, 'org.gnome.Calculator.desktop': <{'position': <2>}>}] +alarms=[{'name': <''>, 'id': <'39d68c6c283032ad5549c9bd5f5161c4'>, 'active': , 'hour': <17>, 'minute': <50>, 'days': <@ai []>, 'snooze_minutes': <10>, 'ring_minutes': <5>}] +timers=[{'duration': <300>, 'name': <''>}] diff --git a/output/dconf.nix b/output/dconf.nix index 45a7270..30c882d 100644 --- a/output/dconf.nix +++ b/output/dconf.nix @@ -384,11 +384,11 @@ with lib.hm.gvariant; }; "issue28/org/gnome/clocks" = { - world-clocks = [ { - location = mkVariant (mkTuple [ (mkUint32 2) (mkVariant (mkTuple [ "Houston" "KHOU" false [ (mkTuple [ 0.5172719570598194 (-1.6629933445314968) ]) ] [ (mkTuple [ 0.5172719570598194 (-1.6629933445314968) ]) ] ])) ]); - } { - location = mkVariant (mkTuple [ (mkUint32 2) (mkVariant (mkTuple [ "Singapore" "WSAP" true [ (mkTuple [ 2.3852838928353343e-2 1.8136879868485383 ]) ] [ (mkTuple [ 2.2568084612667797e-2 1.8126262332513803 ]) ] ])) ]); - } ]; + world-clocks = [ [ + (mkDictionaryEntry ["location" (mkVariant (mkTuple [ (mkUint32 2) (mkVariant (mkTuple [ "Houston" "KHOU" false [ (mkTuple [ 0.5172719570598194 (-1.6629933445314968) ]) ] [ (mkTuple [ 0.5172719570598194 (-1.6629933445314968) ]) ] ])) ]))]) + ] [ + (mkDictionaryEntry ["location" (mkVariant (mkTuple [ (mkUint32 2) (mkVariant (mkTuple [ "Singapore" "WSAP" true [ (mkTuple [ 2.3852838928353343e-2 1.8136879868485383 ]) ] [ (mkTuple [ 2.2568084612667797e-2 1.8126262332513803 ]) ] ])) ]))]) + ] ]; }; "org/gnome/shell/extensions/arcmenu" = { diff --git a/output/dict.nix b/output/dict.nix new file mode 100644 index 0000000..7898bb4 --- /dev/null +++ b/output/dict.nix @@ -0,0 +1,47 @@ +# Generated via dconf2nix: https://github.com/nix-commmunity/dconf2nix +{ lib, ... }: + +with lib.hm.gvariant; + +{ + dconf.settings = { + "dict" = { + alarms = [ [ + (mkDictionaryEntry ["name" (mkVariant "")]) + (mkDictionaryEntry ["id" (mkVariant "39d68c6c283032ad5549c9bd5f5161c4")]) + (mkDictionaryEntry ["active" (mkVariant false)]) + (mkDictionaryEntry ["hour" (mkVariant 17)]) + (mkDictionaryEntry ["minute" (mkVariant 50)]) + (mkDictionaryEntry ["days" (mkVariant (mkArray "i" []))]) + (mkDictionaryEntry ["snooze_minutes" (mkVariant 10)]) + (mkDictionaryEntry ["ring_minutes" (mkVariant 5)]) + ] ]; + dict = [ + (mkDictionaryEntry [1 "one"]) + (mkDictionaryEntry [2 "two"]) + (mkDictionaryEntry [3 "three"]) + ]; + dict-entry = mkDictionaryEntry [1 "one"]; + empty-arr-dict = mkArray "{sv}" []; + empty-dict = mkTyped "a{sv}" [ + ]; + entry-arr = [ (mkDictionaryEntry [1 "one"]) (mkDictionaryEntry [2 "two"]) (mkDictionaryEntry [3 "three"]) ]; + nested = [ [ + (mkDictionaryEntry ["org.gnome.Contacts.desktop" (mkVariant [ + (mkDictionaryEntry ["position" (mkVariant 0)]) + ])]) + (mkDictionaryEntry ["org.gnome.Maps.desktop" (mkVariant [ + (mkDictionaryEntry ["position" (mkVariant 1)]) + ])]) + (mkDictionaryEntry ["org.gnome.Calculator.desktop" (mkVariant [ + (mkDictionaryEntry ["position" (mkVariant 2)]) + ])]) + ] ]; + timers = [ [ + (mkDictionaryEntry ["duration" (mkVariant 300)]) + (mkDictionaryEntry ["name" (mkVariant "")]) + ] ]; + }; + + }; +} diff --git a/output/headers.nix b/output/headers.nix index 9220ca2..8ad5379 100644 --- a/output/headers.nix +++ b/output/headers.nix @@ -16,9 +16,9 @@ with lib.hm.gvariant; "uk/co/ibboard/cawbird" = { round-avatars = false; startup-accounts = [ "account_name" ]; - window-geometry = { - account_name = mkTuple [ 30 26 694 1182 ]; - }; + window-geometry = [ + (mkDictionaryEntry ["account_name" (mkTuple [ 30 26 694 1182 ])]) + ]; }; "org/gnome/shell/extensions/bluetooth_battery_indicator" = { diff --git a/output/typed.nix b/output/typed.nix index 3f4e75f..8db2761 100644 --- a/output/typed.nix +++ b/output/typed.nix @@ -10,8 +10,8 @@ with lib.hm.gvariant; doubletime = mkUint32 7; empty-arr = mkArray "(dd)" []; empty-array-dict = mkArray "{sv}" []; - empty-dict = mkTyped "a{sv}" { - }; + empty-dict = mkTyped "a{sv}" [ + ]; just-empty-str = mkTyped "ms" ""; just-str = mkTyped "ms" "hello"; ui32 = mkUint32 7; diff --git a/src/DConf.hs b/src/DConf.hs index 113dff1..507ca8b 100644 --- a/src/DConf.hs +++ b/src/DConf.hs @@ -117,9 +117,13 @@ vString = T.pack <$> (single <|> double) inputs :: [Char] -> Parsec Text () String inputs extra = catMaybes <$> (many $ qchar <|> (Just <$> lchar extra)) +baseValue :: Parsec Text () Value +baseValue = choice + [vBool, vInt, vDouble, vUint32, vInt64, fmap S vString] + value :: Parsec Text () Value value = choice - [vTyped, vRecord, vList, vJson, vBool, vInt, vDouble, vUint32, vInt64, fmap S vString, vTuple, vVariant] + [vTyped, vDictDictEntry, vList, vJson, baseValue, vTuple, vVariant] vVariant :: Parsec Text () Value vVariant = fmap V $ bracket "<" ">" value @@ -165,13 +169,30 @@ vJson = try $ bracket "'" "'" $ do js <- many (charExcept "\r\n\'") pure $ Json (T.pack js) -vRecord :: Parsec Text () Value -vRecord = fmap R $ bracket "{" "}" $ commaSeparated $ do - k <- vString - _ <- char ':' - _ <- spaces - v <- value - return (k,v) +-- | Parses a dictionary (@{k1: v1, k2: v2}@) or single dictionary entry (@{k, v}@) +vDictDictEntry :: Parsec Text () Value +vDictDictEntry = bracket "{" "}" $ do + (do + { + ; k <- baseValue + ; isEntry <- (char ':' *> pure False) <|> (char ',' *> pure True) + ; _ <- spaces + ; v <- value + ; if isEntry then + return (DE k v) + else do + kvs <- (comma *> commaSeparated kvPair) <|> return [] + return (R ((k,v):kvs)) + } + <|> return (R [])) + + where + kvPair = do + k <- baseValue + _ <- char ':' + _ <- spaces + v <- value + return (k,v) dconfHeader :: Parsec Text () Header dconfHeader = bracket "[" "]" $ do diff --git a/src/DConf/Data.hs b/src/DConf/Data.hs index b00235b..18e127a 100644 --- a/src/DConf/Data.hs +++ b/src/DConf/Data.hs @@ -24,7 +24,8 @@ data Value = S Text -- String | Ty String Value -- Typed value | L [Value] -- List of values | V Value -- Variant - | R [(Text,Value)] -- Record + | R [(Value,Value)] -- Dictionary + | DE Value Value -- Dictionary entry | Json Text -- Json value deriving (Eq, Show) diff --git a/src/Nix.hs b/src/Nix.hs index 120ccc0..2fd2264 100644 --- a/src/Nix.hs +++ b/src/Nix.hs @@ -61,6 +61,7 @@ renderValue raw = Nix $ renderValue' raw <> ";" needsParen (Ty "as" (L [])) = False needsParen (Ty _ _) = True needsParen (V _) = True + needsParen (DE _ _) = True needsParen _ = False renderItem :: Value -> T.Text @@ -90,7 +91,8 @@ renderValue raw = Nix $ renderValue' raw <> ";" renderValue' (Json v) = "''\n" <> mkSpaces 8 <> T.strip v <> "\n" <> mkSpaces 6 <> "''" renderValue' (R kvs) = - "{\n" <> mconcat (fmap (\(k,v) -> mkSpaces 8 <> k <> " = " <> renderValue' v <> ";\n") kvs) <> mkSpaces 6 <> "}" + "[\n" <> mconcat (fmap (\(k,v) -> mkSpaces 8 <> renderItem (DE k v) <> "\n") kvs) <> mkSpaces 6 <> "]" + renderValue' (DE k v) = "mkDictionaryEntry [" <> renderItem k <> " " <> renderItem v <> "]" renderString :: T.Text -> T.Text renderString text = "\"" <> escaped <> "\"" diff --git a/test/DConf2NixTest.hs b/test/DConf2NixTest.hs index 101e3ca..b83e292 100644 --- a/test/DConf2NixTest.hs +++ b/test/DConf2NixTest.hs @@ -57,6 +57,16 @@ dconf2nixCustomNestedRoot = root = Root "org/gnome/desktop/peripherals" in baseProperty input output root +dconf2nixDict :: Property +dconf2nixDict = + let input = "data/dict.settings" + output = "output/dict.nix" + root = Root T.empty + in baseProperty input output root + +prop_dconf2nix_dict :: Property +prop_dconf2nix_dict = withTests (10 :: TestLimit) dconf2nixDict + dconf2nixIndexer :: Property dconf2nixIndexer = let input = "data/indexer.settings"