diff --git a/app/Main.hs b/app/Main.hs index cab89ec..01f468f 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -31,7 +31,7 @@ dconf2nix (ProcessTimeout t) fa successMsg = timeout (t * 1000000) fa >>= \case main :: IO () main = runArgs >>= \case - FileInput (FileArgs i o r t v) -> - dconf2nix t (dconf2nixFile i o r v) (Just "🚀 Successfully Nixified! ❄️") - StdinInput (StdinArgs r t v) -> - dconf2nix t (dconf2nixStdin r v) Nothing + FileInput (FileArgs i o r t e v) -> + dconf2nix t (dconf2nixFile i o r e v) (Just "🚀 Successfully Nixified! ❄️") + StdinInput (StdinArgs r t e v) -> + dconf2nix t (dconf2nixStdin r e v) Nothing diff --git a/data/emoji.settings b/data/emoji.settings new file mode 100644 index 0000000..cd791e1 --- /dev/null +++ b/data/emoji.settings @@ -0,0 +1,3 @@ +[ org/gnome/Characters ] +recent-characters=['💡'] +some-other-character=['🤓'] diff --git a/dconf2nix.cabal b/dconf2nix.cabal index beb5c02..56468b0 100644 --- a/dconf2nix.cabal +++ b/dconf2nix.cabal @@ -21,6 +21,7 @@ library other-modules: Paths_dconf2nix build-depends: base , containers + , emojis , optparse-applicative , parsec , text diff --git a/output/emoji.nix b/output/emoji.nix new file mode 100644 index 0000000..3f141a4 --- /dev/null +++ b/output/emoji.nix @@ -0,0 +1,14 @@ +# Generated via dconf2nix: https://github.com/gvolpe/dconf2nix +{ lib, ... }: + +with lib.hm.gvariant; + +{ + dconf.settings = { + "org/gnome/Characters" = { + recent-characters = [ "💡" ]; + some-other-character = [ "🤓" ]; + }; + + }; +} diff --git a/src/CommandLine.hs b/src/CommandLine.hs index 9825f8a..a1bc439 100644 --- a/src/CommandLine.hs +++ b/src/CommandLine.hs @@ -19,12 +19,14 @@ data FileArgs = FileArgs , fileOutput :: OutputFilePath , fileRoot :: Root , fileTimeout :: ProcessTimeout + , fileEmojiSupport :: EmojiSupport , fileVerbosity :: Verbosity } data StdinArgs = StdinArgs { stdinRoot :: Root , stdinTimeout :: ProcessTimeout + , stdinEmojiSupport :: EmojiSupport , stdinVerbosity :: Verbosity } @@ -38,6 +40,10 @@ verbosityArgs :: Parser Verbosity verbosityArgs = flag Normal Verbose (long "verbose" <> help "Verbose mode (debug)") +emojiArgs :: Parser EmojiSupport +emojiArgs = + flag Disabled Enabled (long "emoji" <> short 'e' <> help "Enable emoji support (adds a bit of overhead)") + rootArgs :: Parser Root rootArgs = Root <$> strOption (long "root" <> short 'r' <> value T.empty <> help @@ -56,11 +62,12 @@ fileArgs = fmap FileInput $ FileArgs ) <*> rootArgs <*> timeoutArgs + <*> emojiArgs <*> verbosityArgs stdinArgs :: Parser Input stdinArgs = - StdinInput <$> (StdinArgs <$> rootArgs <*> timeoutArgs <*> verbosityArgs) + StdinInput <$> (StdinArgs <$> rootArgs <*> timeoutArgs <*> emojiArgs <*> verbosityArgs) versionInfo :: String versionInfo = unlines diff --git a/src/DConf.hs b/src/DConf.hs index c759269..24f7621 100644 --- a/src/DConf.hs +++ b/src/DConf.hs @@ -12,6 +12,7 @@ import qualified Data.Map as Map import Data.Text ( Text ) import qualified Data.Text as T import DConf.Data +import Text.Emoji ( emojis ) import Text.Parsec type Parser @@ -48,22 +49,30 @@ vInt64 = try $ do many1 (string "int64 ") >> spaces I64 . read <$> many1 digit -vTuple :: Parsec Text () Value -vTuple = try $ do +vTuple :: EmojiSupport -> Parsec Text () Value +vTuple es = try $ do char '(' - rs <- manyTill (dconf manyTill `sepBy` (string "," >> spaces)) (char ')') + rs <- manyTill (dconf es manyTill `sepBy` (string "," >> spaces)) (char ')') case concat rs of (x : y : _) -> pure $ T x y _ -> fail "Not a tuple" -vTupleInList :: Parsec Text () Value -vTupleInList = vTuple <&> \case +vTupleInList :: EmojiSupport -> Parsec Text () Value +vTupleInList es = vTuple es <&> \case T x y -> TL x y a -> a vEmptyString :: Parsec Text () Value vEmptyString = S "" <$ (try (string "''") <|> try (string "\"\"")) +vEmoji :: Parsec Text () Value +vEmoji = + let e = T.head . snd <$> emojis + f = choice $ char <$> e + s = many1 (string "'") *> f <* (string "'") + d = many1 (char '"') *> f <* (char '"') + in Emo <$> try (s <|> d) + vString :: Parser -> Parsec Text () Value vString parser = try $ do S . T.pack . concat <$> (single <|> double) @@ -78,9 +87,11 @@ vString parser = try $ do vAny :: Parsec Text () Value vAny = S . T.pack <$> manyTill anyChar (try $ lookAhead endOfLine) -dconf :: Parser -> Parsec Text () Value -dconf p = choice - [vBool, vInt, vDouble, vUint32, vInt64, vEmptyString, vString p, vTuple, vAny] +dconf :: EmojiSupport -> Parser -> Parsec Text () Value +dconf Enabled p = choice + [vBool, vInt, vDouble, vUint32, vInt64, vEmptyString, vEmoji, vString p, vTuple Enabled, vAny] +dconf Disabled p = choice + [vBool, vInt, vDouble, vUint32, vInt64, vEmptyString, vString p, vTuple Disabled, vAny] -- There is no support for variants in HM yet so we parse them as a string vListOfVariant :: Parsec Text () Value @@ -94,11 +105,11 @@ vListOfVariant = manyTill anyToken (try $ lookAhead $ string "\"") <* char '"' in S . T.pack <$> (variant1 <|> variant2) -vList :: Parsec Text () Value -vList = try $ do +vList :: EmojiSupport -> Parsec Text () Value +vList es = try $ do char '[' L . concat <$> manyTill - ((vTupleInList <|> vJson <|> dconf manyTill) `sepBy` (string "," >> spaces)) + ((vTupleInList es <|> vJson <|> dconf es manyTill) `sepBy` (string "," >> spaces)) (char ']') vJson :: Parsec Text () Value @@ -117,19 +128,19 @@ dconfHeader = do T.pack . concat <$> manyTill tokens (string " ]" <|> string "]") where tokens = choice $ many1 <$> [oneOf "/.-:_", alphaNum] -dconfValue :: Parsec Text () Value -dconfValue = vListOfVariant <|> vList <|> vEmptyList <|> vJson <|> dconf endBy +dconfValue :: EmojiSupport -> Parsec Text () Value +dconfValue es = vListOfVariant <|> vList es <|> vEmptyList <|> vJson <|> dconf es endBy vKey :: Parsec Text () Key vKey = Key . T.pack <$> manyTill (choice [alphaNum, char '-']) (char '=') -entryParser :: Parsec Text () Entry -entryParser = do +entryParser :: EmojiSupport -> Parsec Text () Entry +entryParser es = do h <- dconfHeader <* endOfLine - kv <- many1 ((,) <$> vKey <*> (dconfValue <* endOfLine)) + kv <- many1 ((,) <$> vKey <*> (dconfValue es <* endOfLine)) optional endOfLine pure $ Entry h (Map.fromList kv) -dconfParser :: Verbosity -> Parsec Text () [Entry] -dconfParser Normal = manyTill entryParser eof -dconfParser Verbose = parserTraced "dconf" $ dconfParser Normal +dconfParser :: EmojiSupport -> Verbosity -> Parsec Text () [Entry] +dconfParser es Normal = manyTill (entryParser es) eof +dconfParser es Verbose = parserTraced "dconf" $ dconfParser es Normal diff --git a/src/DConf/Data.hs b/src/DConf/Data.hs index fde4bd6..815f876 100644 --- a/src/DConf/Data.hs +++ b/src/DConf/Data.hs @@ -7,6 +7,7 @@ newtype InputFilePath = InputFilePath FilePath deriving Show newtype OutputFilePath = OutputFilePath FilePath deriving Show newtype ProcessTimeout = ProcessTimeout Int deriving Show +data EmojiSupport = Enabled | Disabled data Verbosity = Normal | Verbose newtype Nix = Nix { unNix :: Text } deriving Show @@ -21,6 +22,7 @@ data Value = S Text -- String | I32 Int -- Int32 | I64 Int -- Int64 | D Double -- Double + | Emo Char -- Emoji (Unicode char) | T Value Value -- Tuple | TL Value Value -- Tuple within a list | L [Value] -- List of values diff --git a/src/DConf2Nix.hs b/src/DConf2Nix.hs index 14d1ffa..dfb8933 100644 --- a/src/DConf2Nix.hs +++ b/src/DConf2Nix.hs @@ -13,16 +13,16 @@ import Text.Parsec ( ParseError , runParser ) -dconf2nixFile :: InputFilePath -> OutputFilePath -> Root -> Verbosity -> IO () -dconf2nixFile (InputFilePath input) (OutputFilePath output) root v = +dconf2nixFile :: InputFilePath -> OutputFilePath -> Root -> EmojiSupport -> Verbosity -> IO () +dconf2nixFile (InputFilePath input) (OutputFilePath output) root es v = let run = handler (T.writeFile output) (T.appendFile output) root - parse = parseFromFile (dconfParser v) input + parse = parseFromFile (dconfParser es v) input in run =<< parse -dconf2nixStdin :: Root -> Verbosity -> IO () -dconf2nixStdin root v = +dconf2nixStdin :: Root -> EmojiSupport -> Verbosity -> IO () +dconf2nixStdin root es v = let run = handler T.putStr T.putStr root - parse = runParser (dconfParser v) () "" + parse = runParser (dconfParser es v) () "" in run . parse =<< T.getContents handler diff --git a/src/Nix.hs b/src/Nix.hs index 5c72319..9bb28bf 100644 --- a/src/Nix.hs +++ b/src/Nix.hs @@ -62,6 +62,7 @@ renderValue raw = Nix $ renderValue' raw <> ";" renderValue' (B v) = T.toLower . T.pack $ show v renderValue' (I v) = T.pack $ show v renderValue' (D v) = T.pack $ show v + renderValue' (Emo v) = "\"" <> T.singleton v <> "\"" renderValue' (I32 v) = "mkUint32 " <> T.pack (show v) renderValue' (I64 v) = "mkInt64 " <> T.pack (show v) renderValue' (T x y) = diff --git a/test/DConf2NixTest.hs b/test/DConf2NixTest.hs index 661d6c5..4b8ec89 100644 --- a/test/DConf2NixTest.hs +++ b/test/DConf2NixTest.hs @@ -17,8 +17,8 @@ import Text.Parsec ( runParser ) prop_dconf2nix :: Property prop_dconf2nix = withTests (10 :: TestLimit) dconf2nix -baseProperty :: FilePath -> FilePath -> Root -> Property -baseProperty i o root = property $ do +baseProperty :: FilePath -> FilePath -> Root -> EmojiSupport -> Property +baseProperty i o root es = property $ do input <- evalIO $ T.readFile i output <- evalIO $ T.readFile o ref <- evalIO $ newIORef T.empty @@ -26,7 +26,7 @@ baseProperty i o root = property $ do result <- evalIO $ readIORef ref result === output where - entries = runParser (dconfParser Normal) () "" + entries = runParser (dconfParser es Normal) () "" writer ref x = modifyIORef ref (`T.append` x) dconf2nix :: Property @@ -34,7 +34,7 @@ dconf2nix = let input = "data/dconf.settings" output = "output/dconf.nix" root = Root T.empty - in baseProperty input output root + in baseProperty input output root Disabled prop_dconf2nix_custom_root :: Property prop_dconf2nix_custom_root = withTests (10 :: TestLimit) dconf2nixCustomRoot @@ -44,7 +44,7 @@ dconf2nixCustomRoot = let input = "data/custom.settings" output = "output/custom.nix" root = Root "ca/desrt/dconf-editor" - in baseProperty input output root + in baseProperty input output root Disabled prop_dconf2nix_custom_nested_root :: Property prop_dconf2nix_custom_nested_root = @@ -55,14 +55,14 @@ dconf2nixCustomNestedRoot = let input = "data/nested.settings" output = "output/nested.nix" root = Root "org/gnome/desktop/peripherals" - in baseProperty input output root + in baseProperty input output root Disabled dconf2nixIndexer :: Property dconf2nixIndexer = let input = "data/indexer.settings" output = "output/indexer.nix" root = Root T.empty - in baseProperty input output root + in baseProperty input output root Disabled prop_dconf2nix_indexer :: Property prop_dconf2nix_indexer = withTests (10 :: TestLimit) dconf2nixIndexer @@ -72,7 +72,7 @@ dconf2nixNegative = let input = "data/negative.settings" output = "output/negative.nix" root = Root T.empty - in baseProperty input output root + in baseProperty input output root Disabled prop_dconf2nix_negative :: Property prop_dconf2nix_negative = withTests (10 :: TestLimit) dconf2nixNegative @@ -82,7 +82,7 @@ dconf2nixJson = let input = "data/json.settings" output = "output/json.nix" root = Root T.empty - in baseProperty input output root + in baseProperty input output root Disabled prop_dconf2nix_json :: Property prop_dconf2nix_json = withTests (10 :: TestLimit) dconf2nixJson @@ -92,7 +92,7 @@ dconf2nixClocks = let input = "data/clocks.settings" output = "output/clocks.nix" root = Root T.empty - in baseProperty input output root + in baseProperty input output root Disabled prop_dconf2nix_clocks :: Property prop_dconf2nix_clocks = withTests (10 :: TestLimit) dconf2nixClocks @@ -102,7 +102,7 @@ dconf2nixKeybindings = let input = "data/keybindings.settings" output = "output/keybindings.nix" root = Root T.empty - in baseProperty input output root + in baseProperty input output root Disabled prop_dconf2nix_keybindings :: Property prop_dconf2nix_keybindings = withTests (10 :: TestLimit) dconf2nixKeybindings @@ -112,7 +112,7 @@ dconf2nixScientificNotation = let input = "data/scientific-notation.settings" output = "output/scientific-notation.nix" root = Root T.empty - in baseProperty input output root + in baseProperty input output root Disabled prop_dconf2nix_scientific_notation :: Property prop_dconf2nix_scientific_notation = @@ -123,11 +123,22 @@ dconf2nixHeaders = let input = "data/headers.settings" output = "output/headers.nix" root = Root T.empty - in baseProperty input output root + in baseProperty input output root Disabled prop_dconf2nix_headers :: Property prop_dconf2nix_headers = withTests (10 :: TestLimit) dconf2nixHeaders +dconf2nixEmoji :: Property +dconf2nixEmoji = + let input = "data/emoji.settings" + output = "output/emoji.nix" + root = Root T.empty + in baseProperty input output root Enabled + +prop_dconf2nix_emoji :: Property +prop_dconf2nix_emoji = + withTests (10 :: TestLimit) dconf2nixEmoji + dconf2nixTests :: Group dconf2nixTests = $$(discover) diff --git a/test/DConfTest.hs b/test/DConfTest.hs index f3b52db..a73d9d3 100644 --- a/test/DConfTest.hs +++ b/test/DConfTest.hs @@ -18,7 +18,7 @@ prop_simple_parser = withTests (100 :: TestLimit) simpleParser simpleParser :: Property simpleParser = - let entries = runParser (dconfParser Normal) () "" testInput + let entries = runParser (dconfParser Disabled Normal) () "" testInput in property $ entries === Right [testOutput] testInput :: Text