@@ -32,6 +32,7 @@ module Ide.PluginUtils
32
32
handleMaybe ,
33
33
handleMaybeM ,
34
34
throwPluginError ,
35
+ unescape ,
35
36
)
36
37
where
37
38
@@ -43,10 +44,12 @@ import Control.Monad.Trans.Except (ExceptT, runExceptT, throwE)
43
44
import Data.Algorithm.Diff
44
45
import Data.Algorithm.DiffOutput
45
46
import Data.Bifunctor (Bifunctor (first ))
47
+ import Data.Char (isPrint , showLitChar )
48
+ import Data.Functor (void )
46
49
import qualified Data.HashMap.Strict as H
47
- import Data.List (find )
48
50
import Data.String (IsString (fromString ))
49
51
import qualified Data.Text as T
52
+ import Data.Void (Void )
50
53
import Ide.Plugin.Config
51
54
import Ide.Plugin.Properties
52
55
import Ide.Types
@@ -57,6 +60,9 @@ import Language.LSP.Types hiding
57
60
SemanticTokensEdit (_start ))
58
61
import qualified Language.LSP.Types as J
59
62
import Language.LSP.Types.Capabilities
63
+ import qualified Text.Megaparsec as P
64
+ import qualified Text.Megaparsec.Char as P
65
+ import qualified Text.Megaparsec.Char.Lexer as P
60
66
61
67
-- ---------------------------------------------------------------------
62
68
@@ -255,3 +261,34 @@ pluginResponse :: Monad m => ExceptT String m a -> m (Either ResponseError a)
255
261
pluginResponse =
256
262
fmap (first (\ msg -> ResponseError InternalError (fromString msg) Nothing ))
257
263
. runExceptT
264
+
265
+ -- ---------------------------------------------------------------------
266
+
267
+ type TextParser = P. Parsec Void T. Text
268
+
269
+ -- | Unescape printable escape sequences within double quotes.
270
+ -- This is useful if you have to call 'show' indirectly, and it escapes some characters which you would prefer to
271
+ -- display as is.
272
+ unescape :: T. Text -> T. Text
273
+ unescape input =
274
+ case P. runParser escapedTextParser " inline" input of
275
+ Left _ -> input
276
+ Right strs -> T. pack strs
277
+
278
+ -- | Parser for a string that contains double quotes. Returns unescaped string.
279
+ escapedTextParser :: TextParser String
280
+ escapedTextParser = concat <$> P. many (outsideStringLiteral P. <|> stringLiteral)
281
+ where
282
+ outsideStringLiteral :: TextParser String
283
+ outsideStringLiteral = P. someTill (P. anySingleBut ' "' ) (P. lookAhead (void (P. char ' "' ) P. <|> P. eof))
284
+
285
+ stringLiteral :: TextParser String
286
+ stringLiteral = do
287
+ inside <- P. char ' "' >> P. manyTill P. charLiteral (P. char ' "' )
288
+ let f ' "' = " \\\" " -- double quote should still be escaped
289
+ -- Despite the docs, 'showLitChar' and 'showLitString' from 'Data.Char' DOES ESCAPE unicode printable
290
+ -- characters. So we need to call 'isPrint' from 'Data.Char' manually.
291
+ f ch = if isPrint ch then [ch] else showLitChar ch " "
292
+ inside' = concatMap f inside
293
+
294
+ pure $ " \" " <> inside' <> " \" "
0 commit comments