diff --git a/src/GHCMod/Options/ShellParse.hs b/src/GHCMod/Options/ShellParse.hs index 5799906..acd609b 100644 --- a/src/GHCMod/Options/ShellParse.hs +++ b/src/GHCMod/Options/ShellParse.hs @@ -16,35 +16,20 @@ module GHCMod.Options.ShellParse (parseCmdLine) where import Data.Char -import Data.Maybe +import Data.List -isQuote :: Char -> Bool -isQuote = (==) '"' - -isEscapeChar :: Char -> Bool -isEscapeChar = (==) '\\' - -isEscapable :: Char -> Bool -isEscapable c = any ($ c) [isSpace, isQuote, isEscapeChar] - -go :: String -> String -> [String] -> Maybe Char -> [String] +go :: String -> String -> [String] -> Bool -> [String] -- result go [] curarg accargs _ = reverse $ reverse curarg : accargs --- escaped character -go (esc:c:cl) curarg accargs quote - | isEscapeChar esc - = if isEscapable c - then go cl (c:curarg) accargs quote - else go (c:cl) (esc:curarg) accargs quote go (c:cl) curarg accargs quotes - -- quote character -- opens quotes - | isQuote c, isNothing quotes - = go cl curarg accargs (Just c) + -- open quotes + | c == '\STX', not quotes + = go cl curarg accargs True -- close quotes - | quotes == Just c - = go cl curarg accargs Nothing - -- space separates argumetns outside quotes - | isSpace c, isNothing quotes + | c == '\ETX', quotes + = go cl curarg accargs False + -- space separates arguments outside quotes + | isSpace c, not quotes = if null curarg then go cl curarg accargs quotes else go cl [] (reverse curarg : accargs) quotes @@ -52,4 +37,8 @@ go (c:cl) curarg accargs quotes | otherwise = go cl (c:curarg) accargs quotes parseCmdLine :: String -> [String] -parseCmdLine comline = go comline [] [] Nothing +parseCmdLine comline' + | Just comline <- stripPrefix "ascii-escape " $ dropWhile isSpace comline' + = go (dropWhile isSpace comline) [] [] False +parseCmdLine [] = [""] +parseCmdLine comline = words comline diff --git a/test/ShellParseSpec.hs b/test/ShellParseSpec.hs index 3d02f43..2c5cefe 100644 --- a/test/ShellParseSpec.hs +++ b/test/ShellParseSpec.hs @@ -8,29 +8,27 @@ import Test.Hspec spec :: Spec spec = describe "parseCmdLine" $ do - it "splits arguments" $ + it "splits arguments" $ do parseCmdLine "test command line" `shouldBe` ["test", "command", "line"] - it "honors double quotes" $ - parseCmdLine "test command line \"with double quotes\"" - `shouldBe` ["test", "command", "line", "with double quotes"] - it "escapes spaces" $ do - parseCmdLine "with\\ spaces" - `shouldBe` ["with spaces"] - parseCmdLine "\"with\\ spaces\"" - `shouldBe` ["with spaces"] - it "escapes '\\'" $ do - parseCmdLine "\\\\" - `shouldBe` ["\\"] - parseCmdLine "\"\\\\\"" - `shouldBe` ["\\"] - it "escapes double quotes" $ do - parseCmdLine "\\\"" - `shouldBe` ["\""] - parseCmdLine "\"\\\"\"" - `shouldBe` ["\""] - it "doesn't escape random characters" $ - parseCmdLine "\\a\\b\\c" - `shouldBe` ["\\a\\b\\c"] - it "squashes multiple spaces" $ + parseCmdLine "ascii-escape test command line" `shouldBe` ["test", "command", "line"] + it "honors quoted segments if turned on" $ + parseCmdLine "ascii-escape test command line \STXwith quoted segment\ETX" + `shouldBe` ["test", "command", "line", "with quoted segment"] + it "doesn't honor quoted segments if turned off" $ + parseCmdLine "test command line \STXwith quoted segment\ETX" + `shouldBe` words "test command line \STXwith quoted segment\ETX" + it "squashes multiple spaces" $ do parseCmdLine "test command" `shouldBe` ["test", "command"] + parseCmdLine "ascii-escape test command" + `shouldBe` ["test", "command"] + it "ingores leading spaces" $ do + parseCmdLine " test command" + `shouldBe` ["test", "command"] + parseCmdLine " ascii-escape test command" + `shouldBe` ["test", "command"] + it "parses empty string as no argument" $ do + parseCmdLine "" + `shouldBe` [""] + parseCmdLine "ascii-escape " + `shouldBe` [""]