From 8671d5a6c0bc0cdf90e8855fc0112e2c2ba0eaf0 Mon Sep 17 00:00:00 2001 From: soulomoon Date: Tue, 4 Jan 2022 22:43:32 +0000 Subject: [PATCH 1/5] Escape ${ in strings when printing Nix expressions --- src/Nix/Pretty.hs | 9 +++++++-- tests/PrettyTests.hs | 2 +- tests/eval-compare/ind-string-18.nix | 2 ++ tests/eval-compare/ind-string-19.nix | 4 ++++ 4 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 tests/eval-compare/ind-string-18.nix create mode 100644 tests/eval-compare/ind-string-19.nix diff --git a/src/Nix/Pretty.hs b/src/Nix/Pretty.hs index 90ee8f574..07ef9ef15 100644 --- a/src/Nix/Pretty.hs +++ b/src/Nix/Pretty.hs @@ -104,10 +104,11 @@ prettyString (DoubleQuoted parts) = "\"" <> foldMap prettyPart parts <> "\"" where -- It serializes Text -> String, because the helper code is done for String, -- please, can someone break that code. - prettyPart (Plain t) = pretty . foldMap escape . toString $ t + prettyPart (Plain t) = pretty . dollarEscape . toText . foldMap escape . toString $ t prettyPart EscapedNewline = "''\\n" prettyPart (Antiquoted r) = "${" <> withoutParens r <> "}" escape '"' = "\\\"" + escape '$' = "$" -- do not print $ as \$ if no { is following escape x = maybe (one x) @@ -382,6 +383,10 @@ prettyNThunk t = "(" <> fold (one "thunk from: " <> (prettyOriginExpr . _originExpr <$> ps)) <> ")" ] +-- | dollarEscape for double quoted string +dollarEscape :: Text -> Text +dollarEscape = replace "${" "\\${" + -- | This function is used only by the testing code. printNix :: forall t f m . MonadDataContext f m => NValue t f m -> Text printNix = iterNValueByDiscardWith thk phi @@ -390,7 +395,7 @@ printNix = iterNValueByDiscardWith thk phi phi :: NValue' t f m Text -> Text phi (NVConstant' a ) = atomText a - phi (NVStr' ns) = show $ ignoreContext ns + phi (NVStr' ns) = dollarEscape $ show $ ignoreContext ns phi (NVList' l ) = "[ " <> unwords l <> " ]" phi (NVSet' _ s) = "{ " <> diff --git a/tests/PrettyTests.hs b/tests/PrettyTests.hs index cafa6e707..0af007264 100644 --- a/tests/PrettyTests.hs +++ b/tests/PrettyTests.hs @@ -23,7 +23,7 @@ case_string_antiquotation = do assertPretty (mkStr "echo $foo") - "\"echo \\$foo\"" + "\"echo $foo\"" assertPretty (mkStr "echo ${foo}") "\"echo \\${foo}\"" diff --git a/tests/eval-compare/ind-string-18.nix b/tests/eval-compare/ind-string-18.nix new file mode 100644 index 000000000..f8b5e6927 --- /dev/null +++ b/tests/eval-compare/ind-string-18.nix @@ -0,0 +1,2 @@ +# to observe the upstream nix behavior for dollar sign excape in doublequote string +"\${foo $foo" diff --git a/tests/eval-compare/ind-string-19.nix b/tests/eval-compare/ind-string-19.nix new file mode 100644 index 000000000..6564aa043 --- /dev/null +++ b/tests/eval-compare/ind-string-19.nix @@ -0,0 +1,4 @@ +# to observe the upstream nix behavior for dollar excape in Indented string +'' +''$ ''${ +'' From 60e473263fa810b7127b2557893884a2c30b871a Mon Sep 17 00:00:00 2001 From: Patrick Date: Wed, 5 Jan 2022 08:46:33 +0800 Subject: [PATCH 2/5] refactor pretty.hs to avoid using Text -> String Using ViewPatterns, PatternSynonyms, OverloadedStrings to achieve a readable code `escapeDoubleQuoteString` to escape nix double quoted string in both `prettyString` and `printNix` --- src/Nix/Pretty.hs | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/Nix/Pretty.hs b/src/Nix/Pretty.hs index 07ef9ef15..8f9879fb0 100644 --- a/src/Nix/Pretty.hs +++ b/src/Nix/Pretty.hs @@ -1,5 +1,7 @@ {-# language CPP #-} {-# language AllowAmbiguousTypes #-} +{-# language ViewPatterns, PatternSynonyms, OverloadedStrings #-} + {-# options_ghc -fno-warn-name-shadowing #-} @@ -99,21 +101,27 @@ wrapPath op sub = ("\"${" <> withoutParens sub <> "}\"") (wasPath sub) + +infixr 5 :< +pattern (:<) :: Char -> Text -> Text +pattern t :< ts <- (Text.uncons -> Just (t, ts)) + where (:<) = Text.cons + +escapeDoubleQuoteString :: Text -> Text +escapeDoubleQuoteString ('"': escapeDoubleQuoteString xs +escapeDoubleQuoteString ('$':<'{': escapeDoubleQuoteString xs +escapeDoubleQuoteString ('$': escapeDoubleQuoteString xs +escapeDoubleQuoteString a = a + + prettyString :: NString (NixDoc ann) -> Doc ann prettyString (DoubleQuoted parts) = "\"" <> foldMap prettyPart parts <> "\"" where - -- It serializes Text -> String, because the helper code is done for String, - -- please, can someone break that code. - prettyPart (Plain t) = pretty . dollarEscape . toText . foldMap escape . toString $ t + prettyPart (Plain t) = pretty $ escapeDoubleQuoteString t prettyPart EscapedNewline = "''\\n" prettyPart (Antiquoted r) = "${" <> withoutParens r <> "}" - escape '"' = "\\\"" - escape '$' = "$" -- do not print $ as \$ if no { is following - escape x = - maybe - (one x) - (('\\' :) . one) - (toEscapeCode x) prettyString (Indented _ parts) = group $ nest 2 $ vcat ["''", content, "''"] where @@ -383,9 +391,6 @@ prettyNThunk t = "(" <> fold (one "thunk from: " <> (prettyOriginExpr . _originExpr <$> ps)) <> ")" ] --- | dollarEscape for double quoted string -dollarEscape :: Text -> Text -dollarEscape = replace "${" "\\${" -- | This function is used only by the testing code. printNix :: forall t f m . MonadDataContext f m => NValue t f m -> Text @@ -395,7 +400,7 @@ printNix = iterNValueByDiscardWith thk phi phi :: NValue' t f m Text -> Text phi (NVConstant' a ) = atomText a - phi (NVStr' ns) = dollarEscape $ show $ ignoreContext ns + phi (NVStr' ns) = "\"" <> escapeDoubleQuoteString (ignoreContext ns) <> "\"" phi (NVList' l ) = "[ " <> unwords l <> " ]" phi (NVSet' _ s) = "{ " <> From b5a10b79d4c3a786af7bb8de1371787ccd549918 Mon Sep 17 00:00:00 2001 From: soulomoon Date: Wed, 5 Jan 2022 21:38:38 +0000 Subject: [PATCH 3/5] update ind-string-18 and ind-string-19 to make it more demonstrated --- tests/eval-compare/ind-string-18.nix | 2 +- tests/eval-compare/ind-string-19.nix | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/eval-compare/ind-string-18.nix b/tests/eval-compare/ind-string-18.nix index f8b5e6927..8f992e9a2 100644 --- a/tests/eval-compare/ind-string-18.nix +++ b/tests/eval-compare/ind-string-18.nix @@ -1,2 +1,2 @@ # to observe the upstream nix behavior for dollar sign excape in doublequote string -"\${foo $foo" +"\${foo \$ $foo" diff --git a/tests/eval-compare/ind-string-19.nix b/tests/eval-compare/ind-string-19.nix index 6564aa043..aec913bd8 100644 --- a/tests/eval-compare/ind-string-19.nix +++ b/tests/eval-compare/ind-string-19.nix @@ -1,4 +1,4 @@ # to observe the upstream nix behavior for dollar excape in Indented string '' -''$ ''${ +''$ $ ''${ '' From da3b1ce7a7823f33575890358c6762b06da26db0 Mon Sep 17 00:00:00 2001 From: soulomoon Date: Wed, 5 Jan 2022 21:52:46 +0000 Subject: [PATCH 4/5] ban eval-okay-ind-string.exp for the test itself has wrong result --- tests/NixLanguageTests.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/NixLanguageTests.hs b/tests/NixLanguageTests.hs index bfbb618b1..a4e29d603 100644 --- a/tests/NixLanguageTests.hs +++ b/tests/NixLanguageTests.hs @@ -61,6 +61,7 @@ newFailingTests = Set.fromList , "eval-okay-path" -- #128 , "eval-okay-types" , "eval-okay-fromTOML" + , "eval-okay-ind-string" -- #1000 #610 ] -- | Upstream tests that test cases that HNix disaded as a misfeature that is used so rarely From f97d97ddc5276aaf2b54e4c5076fd0f1de812944 Mon Sep 17 00:00:00 2001 From: soulomoon Date: Wed, 5 Jan 2022 22:15:53 +0000 Subject: [PATCH 5/5] format escapeDoubleQuoteString --- src/Nix/Pretty.hs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Nix/Pretty.hs b/src/Nix/Pretty.hs index 8f9879fb0..f47cdefa6 100644 --- a/src/Nix/Pretty.hs +++ b/src/Nix/Pretty.hs @@ -108,12 +108,12 @@ pattern t :< ts <- (Text.uncons -> Just (t, ts)) where (:<) = Text.cons escapeDoubleQuoteString :: Text -> Text -escapeDoubleQuoteString ('"': escapeDoubleQuoteString xs +escapeDoubleQuoteString ('"': escapeDoubleQuoteString xs escapeDoubleQuoteString ('$':<'{': escapeDoubleQuoteString xs -escapeDoubleQuoteString ('$': escapeDoubleQuoteString xs -escapeDoubleQuoteString a = a +escapeDoubleQuoteString ('$': escapeDoubleQuoteString xs +escapeDoubleQuoteString a = a prettyString :: NString (NixDoc ann) -> Doc ann