Skip to content

Commit 45f6246

Browse files
Lucus16yorickvP
authored andcommitted
Fix escaping of interpolations after single quotes
1 parent 8bba3e1 commit 45f6246

File tree

3 files changed

+40
-7
lines changed

3 files changed

+40
-7
lines changed

nixfmt.cabal

+10-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,16 @@ library
6969
Nixfmt.Pretty
7070
Nixfmt.Types
7171
Nixfmt.Util
72-
other-extensions: OverloadedStrings, LambdaCase, FlexibleInstances, DeriveFoldable, DeriveFunctor, StandaloneDeriving
72+
73+
other-extensions:
74+
DeriveFoldable
75+
DeriveFunctor
76+
FlexibleInstances
77+
LambdaCase
78+
OverloadedStrings
79+
StandaloneDeriving
80+
TupleSections
81+
7382
hs-source-dirs: src
7483
build-depends:
7584
base >= 4.12.0 && < 4.15

src/Nixfmt/Pretty.hs

+6-5
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import Nixfmt.Types
2323
(Ann(..), Binder(..), Expression(..), File(..), Leaf, ParamAttr(..),
2424
Parameter(..), Selector(..), SimpleSelector(..), StringPart(..), Term(..),
2525
Token(..), TrailingComment(..), Trivia, Trivium(..), tokenText)
26-
import Nixfmt.Util (commonIndentation, isSpaces)
26+
import Nixfmt.Util (commonIndentation, isSpaces, replaceMultiple)
2727

2828
prettyCommentLine :: Text -> Doc
2929
prettyCommentLine l
@@ -395,10 +395,11 @@ prettyIndentedString parts = group $ base $
395395
text "''" <> line'
396396
<> nest 2 (sepBy newline (map (prettyLine escape unescapeInterpol) parts))
397397
<> text "''"
398-
where escape
399-
= Text.replace "$''${" "$${"
400-
. Text.replace "${" "''${"
401-
. Text.replace "''" "'''"
398+
where escape = replaceMultiple
399+
[ ("'${", "''\\'''${")
400+
, ("${", "''${")
401+
, ("''", "'''")
402+
]
402403

403404
unescapeInterpol t
404405
| Text.null t = t

src/Nixfmt/Util.hs

+24-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
- SPDX-License-Identifier: MPL-2.0
55
-}
66

7+
{-# LANGUAGE TupleSections #-}
8+
79
module Nixfmt.Util
810
( manyP
911
, someP
@@ -15,14 +17,18 @@ module Nixfmt.Util
1517
, identChar
1618
, isSpaces
1719
, pathChar
20+
, replaceMultiple
1821
, schemeChar
1922
, uriChar
2023
) where
2124

25+
import Control.Applicative ((<|>))
2226
import Data.Char (isAlpha, isDigit, isSpace)
27+
import Data.Foldable (asum)
28+
import Data.List (unfoldr)
2329
import Data.Maybe (fromMaybe)
2430
import Data.Text as Text
25-
(Text, all, commonPrefixes, concat, empty, stripEnd, stripPrefix, takeWhile)
31+
(Text, all, commonPrefixes, concat, empty, null, splitAt, stripEnd, stripPrefix, takeWhile)
2632
import Text.Megaparsec
2733
(ParsecT, Stream, Token, Tokens, many, some, takeWhile1P, takeWhileP)
2834

@@ -82,3 +88,20 @@ dropCommonIndentation unstrippedLines =
8288

8389
isSpaces :: Text -> Bool
8490
isSpaces = Text.all (==' ')
91+
92+
-- | Apply multiple independent replacements. This function passes over the text
93+
-- once and applies the first replacement it can find at each position. After a
94+
-- replacement is matched, the function continues after the replacement, not
95+
-- inside it.
96+
replaceMultiple :: [(Text, Text)] -> Text -> Text
97+
replaceMultiple replacements = mconcat . unfoldr replaceAny
98+
where
99+
-- | replaceAny assumes input is nonempty
100+
replaceAny :: Text -> Maybe (Text, Text)
101+
replaceAny t
102+
| Text.null t = Nothing
103+
| otherwise = asum (map (replaceStart t) replacements)
104+
<|> Just (Text.splitAt 1 t)
105+
106+
replaceStart :: Text -> (Text, Text) -> Maybe (Text, Text)
107+
replaceStart t (pat, rep) = (rep,) <$> Text.stripPrefix pat t

0 commit comments

Comments
 (0)