@@ -16,7 +16,7 @@ import qualified System.Exit as Exit
16
16
17
17
usage :: String
18
18
usage =
19
- " StrLit [ --explicit-nl --{add,remove,toggle}-{backslash,lines} ]\n \
19
+ " StrLit [ --wrapped --{add,remove,toggle}-{backslash,lines} ]\n \
20
20
\\n \
21
21
\Convert between plain text and either backslash-continued string\n \
22
22
\literals, or list of lines style strings. This is to work around\n \
@@ -34,7 +34,7 @@ data Operation = Add | Remove deriving (Eq, Show)
34
34
data Kind = Backslash | Lines deriving (Eq , Show )
35
35
36
36
parseArgs :: [String ] -> Maybe (Bool , Maybe Operation , Kind )
37
- parseArgs args = add <$> case filter (/= " --explicit-nl " ) args of
37
+ parseArgs args = add <$> case filter (/= " --wrapped " ) args of
38
38
[" --toggle-backslash" ] -> Just (Nothing , Backslash )
39
39
[" --add-backslash" ] -> Just (Just Add , Backslash )
40
40
[" --remove-backslash" ] -> Just (Just Remove , Backslash )
@@ -43,22 +43,22 @@ parseArgs args = add <$> case filter (/="--explicit-nl") args of
43
43
[" --remove-lines" ] -> Just (Just Remove , Lines )
44
44
_ -> Nothing
45
45
where
46
- add (b, c) = (explicitNl , b, c)
47
- explicitNl = " --explicit-nl " `elem` args
46
+ add (b, c) = (wrapped , b, c)
47
+ wrapped = " --wrapped " `elem` args
48
48
49
49
process :: (Bool , Maybe Operation , Kind ) -> [Text ] -> [Text ]
50
- process (explicitNl , op, kind) = case (explicitNl , op, kind) of
50
+ process (wrapped , op, kind) = case (wrapped , op, kind) of
51
51
(_, Nothing , Backslash ) -> \ lines -> if inferBackslashed lines
52
- then process (explicitNl , Just Remove , kind) lines
53
- else process (explicitNl , Just Add , kind) lines
52
+ then process (wrapped , Just Remove , kind) lines
53
+ else process (wrapped , Just Add , kind) lines
54
54
(_, Nothing , Lines ) -> \ lines -> if inferList lines
55
- then process (explicitNl , Just Remove , kind) lines
56
- else process (explicitNl , Just Add , kind) lines
55
+ then process (wrapped , Just Remove , kind) lines
56
+ else process (wrapped , Just Add , kind) lines
57
57
58
58
(False , Just Add , Backslash ) -> addBackslash
59
59
(False , Just Remove , Backslash ) -> removeBackslash
60
- (True , Just Add , Backslash ) -> addBackslashExplicit
61
- (True , Just Remove , Backslash ) -> removeBackslashExplicit
60
+ (True , Just Add , Backslash ) -> addBackslashWrapped
61
+ (True , Just Remove , Backslash ) -> removeBackslashWrapped
62
62
(_, Just Add , Lines ) -> addLines
63
63
(_, Just Remove , Lines ) -> removeLines
64
64
@@ -71,9 +71,12 @@ inferBackslashed :: [Text] -> Bool
71
71
inferBackslashed [] = False
72
72
inferBackslashed (line: _) = " \" " `Text.isPrefixOf` Text. stripStart line
73
73
74
- {- |
74
+ {- | Add backslashes assuming the text will be wrapped by someone else later.
75
+
75
76
An extra newline becomes a leading \n. A leading space is added if
76
- there is no leading \n, except for the first line.
77
+ there is no leading \n, except for the first line. Other than that,
78
+ leading and trailing spaces are stripped, since the assumption is that
79
+ this is just a list of words.
77
80
78
81
> this is
79
82
> raw
@@ -86,12 +89,14 @@ inferBackslashed (line:_) = "\"" `Text.isPrefixOf` Text.stripStart line
86
89
> \ raw\
87
90
> \\ntext"
88
91
-}
89
- addBackslashExplicit :: [Text ] -> [Text ]
90
- addBackslashExplicit = indent . map3 add1 addn end . collectNewlines . dedent
92
+ addBackslashWrapped :: [Text ] -> [Text ]
93
+ addBackslashWrapped =
94
+ indent . mapAround start middle end only . collectNewlines . dedentAll
91
95
where
92
- add1 s = " \" " <> s <> " \\ "
93
- addn s = " \\ " <> leadingSpace s <> " \\ "
94
- end s = " \\ " <> leadingSpace s <> " \" "
96
+ start = surround " \" " " \\ "
97
+ middle = surround " \\ " " \\ " . leadingSpace
98
+ end = surround " \\ " " \" " . leadingSpace
99
+ only = surround " \" " " \" "
95
100
leadingSpace s
96
101
| " \\ n" `Text.isPrefixOf` s = s
97
102
| otherwise = " " <> s
@@ -104,20 +109,21 @@ collectNewlines = filter (not . Text.null) . snd . List.mapAccumL collect 0
104
109
| otherwise = (0 , Text. replicate newlines " \\ n" <> line)
105
110
106
111
107
- {- Invert 'addBackslashExplicit '. Drop a leading space unless there was
112
+ {- | Invert 'addBackslashWrapped '. Drop a leading space unless there was
108
113
a leading \n.
109
114
-}
110
- removeBackslashExplicit :: [Text ] -> [Text ]
111
- removeBackslashExplicit =
115
+ removeBackslashWrapped :: [Text ] -> [Text ]
116
+ removeBackslashWrapped =
112
117
indent . map stripLeadingSpace . zipPrev . concatMap addNewlines
113
- . map3 remove1 removen end . dedent
118
+ . mapAround start middle end only . dedent
114
119
where
115
120
addNewlines s =
116
121
replicate (length pre) " " ++ [Text. intercalate " \\ n" post]
117
122
where (pre, post) = span Text. null $ Text. splitOn " \\ n" s
118
- remove1 = stripPrefix " \" " . stripSuffix " \\ "
119
- removen = stripPrefix " \\ " . stripSuffix " \\ "
120
- end = stripPrefix " \\ " . stripSuffix " \" "
123
+ start = strip " \" " " \\ "
124
+ middle = strip " \\ " " \\ "
125
+ end = strip " \\ " " \" "
126
+ only = strip " \" " " \" "
121
127
stripLeadingSpace (Just " " , s) = s
122
128
stripLeadingSpace (_, s)
123
129
| ' ' : c : _ <- Text. unpack s, c /= ' ' = Text. drop 1 s
@@ -132,10 +138,10 @@ addBackslash = indent . map3 add1 addn end . map quote . dedent
132
138
end s = " \\ " <> s <> " \\ n\" "
133
139
134
140
removeBackslash :: [Text ] -> [Text ]
135
- removeBackslash = indent . map unquote . map3 remove1 removen end . dedent
141
+ removeBackslash = indent . map unquote . map3 start middle end . dedent
136
142
where
137
- remove1 = stripPrefix " \" " . spaces . nl
138
- removen = stripPrefix " \\ " . spaces . nl
143
+ start = stripPrefix " \" " . spaces . nl
144
+ middle = stripPrefix " \\ " . spaces . nl
139
145
end = stripPrefix " \\ " . spaces . stripSuffix " \\ n\" "
140
146
spaces = Text. dropWhile (== ' ' )
141
147
nl = stripSuffix " \\ n\\ "
@@ -154,11 +160,11 @@ addLines = map3 add1 addn end . map quote . dedent
154
160
end line = addn line <> " \n " <> indentation <> " ]"
155
161
156
162
removeLines :: [Text ] -> [Text ]
157
- removeLines = map unquote . map3 remove1 removen id . dropLast
163
+ removeLines = map unquote . map3 start middle id . dropLast
158
164
where
159
165
remove = Text. dropWhile (== ' ' ) . stripSuffix " \" "
160
- remove1 = stripPrefix " [ \" " . remove
161
- removen = stripPrefix " , \" " . remove
166
+ start = stripPrefix " [ \" " . remove
167
+ middle = stripPrefix " , \" " . remove
162
168
-- The last line should be ']'
163
169
dropLast [] = []
164
170
dropLast xs = List. init xs
@@ -175,22 +181,15 @@ dedent lines = map (Text.drop indentation) lines
175
181
map (Text. length . Text. takeWhile Char. isSpace) $
176
182
filter (not . Text. all Char. isSpace) lines
177
183
184
+ dedentAll :: [Text ] -> [Text ]
185
+ dedentAll = map (Text. dropWhile (== ' ' ) . Text. stripEnd)
186
+
178
187
quote :: Text -> Text
179
188
quote = Text. replace " \" " " \\\" "
180
189
181
190
unquote :: Text -> Text
182
191
unquote = Text. replace " \\\" " " \" "
183
192
184
- -- | Apply separate transformations to initial, middle, and final elements.
185
- -- If there are 2 elements, middle loses out, and if there is 1, both
186
- -- initial and final functions are applied.
187
- -- map3 :: (a -> b) -> (a -> b) -> (a -> Maybe b) -> [a] -> [b]
188
- -- map3 initial middle final xs = case xs of
189
- -- [] -> []
190
- -- [x] -> [initial (final x)]
191
- -- x : xs -> initial x : go xs
192
- -- where
193
-
194
193
map3 :: (a -> b ) -> (a -> b ) -> (a -> b ) -> [a ] -> [b ]
195
194
map3 _ _ _ [] = []
196
195
map3 initial middle end (x: xs) = initial x : go xs
@@ -199,6 +198,38 @@ map3 initial middle end (x:xs) = initial x : go xs
199
198
go [x] = [end x]
200
199
go (x: xs) = middle x : go xs
201
200
201
+ -- | Apply separate transformations to start, middle, end, or only elements.
202
+ -- If there are 2 elements, middle loses out, and if there is 1, the @only@
203
+ -- function is applied.
204
+ mapAround :: (a -> b ) -> (a -> b ) -> (a -> b ) -> (a -> b ) -> [a ] -> [b ]
205
+ mapAround start middle end only xs = case xs of
206
+ [] -> []
207
+ [x] -> [only x]
208
+ x : xs -> start x : go xs
209
+ where
210
+ go xs = case xs of
211
+ [] -> []
212
+ [x] -> [end x]
213
+ x : xs -> middle x : go xs
214
+
215
+ surround :: Text -> Text -> Text -> Text
216
+ surround s e x = s <> x <> e
217
+
218
+ strip :: HasCallStack => Text -> Text -> Text -> Text
219
+ strip s e = stripPrefix s . stripSuffix e
220
+
221
+ -- surround :: (Text, Text) -> (Text, Text) -> (Text, Text) -> (Text, Text)
222
+ -- -> [Text] -> [Text]
223
+ -- surround start middle end only xs = case xs of
224
+ -- [x] -> [add only x]
225
+ -- x : xs -> add start x : go xs
226
+ -- where
227
+ -- go xs = case xs of
228
+ -- [] -> []
229
+ -- [x] -> [add end x]
230
+ -- x : xs -> add middle x : go xs
231
+ -- add (s, e) x = s <> x <> e
232
+
202
233
stripSuffix :: HasCallStack => Text -> Text -> Text
203
234
stripSuffix s text =
204
235
maybe (error $ " expected suffix " <> show s <> " on " <> show text) id $
0 commit comments