From 01fc30233fb215c6ff0d364d67fb8421fbec59d3 Mon Sep 17 00:00:00 2001 From: Thijs Vermeir Date: Sat, 24 Feb 2024 12:58:25 +0100 Subject: [PATCH 1/2] add support for literal multi-line strings --- CHANGELOG.md | 2 + src/Yaml/Parser.elm | 2 +- src/Yaml/Parser/Util.elm | 94 ++++++++++++++++++++++++++++++++++++++-- tests/TestParser.elm | 28 +++++++++++- 4 files changed, 121 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dbf7e19..28a9fee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Fixed +- Added support for literal multi-line strings ([#36](https://github.com/MaybeJustJames/yaml/pull/36)) ## [2.1.4] ### Changed diff --git a/src/Yaml/Parser.elm b/src/Yaml/Parser.elm index 49b06f7..7df7740 100644 --- a/src/Yaml/Parser.elm +++ b/src/Yaml/Parser.elm @@ -340,7 +340,7 @@ quotedString indent = withQuote quote = P.oneOf [ recordProperty indent quote - , P.succeed (Ast.String_ <| U.postProcessString quote) + , P.succeed (Ast.String_ <| U.postProcessFoldedString quote) ] in P.succeed identity diff --git a/src/Yaml/Parser/Util.elm b/src/Yaml/Parser/Util.elm index 6493e05..76729eb 100644 --- a/src/Yaml/Parser/Util.elm +++ b/src/Yaml/Parser/Util.elm @@ -16,6 +16,8 @@ module Yaml.Parser.Util exposing , multiline , neither , neither3 + , postProcessFoldedString + , postProcessLiteralString , postProcessString , remaining , singleQuotes @@ -196,11 +198,14 @@ multilineStep indent lines = let multilineString : List String -> String multilineString lines_ = - String.join " " (List.reverse lines_) + String.join "\n" (List.reverse lines_) - conclusion line indent_ = + conclusion line emptyLineCount indent_ = if indent_ > indent then - P.Loop (line :: lines) + P.Loop + ((line ++ String.repeat emptyLineCount "\n") + :: lines + ) else P.Done (multilineString (line :: lines)) @@ -210,11 +215,27 @@ multilineStep indent lines = |= characters (not << isNewLine) |. P.chompIf isNewLine |. spaces + |= emptyLines |= P.getCol , P.succeed (P.Done <| multilineString lines) ] +emptyLines : P.Parser Int +emptyLines = + P.loop 0 emptyLinesStep + + +emptyLinesStep : Int -> P.Parser (P.Step Int Int) +emptyLinesStep count = + P.oneOf + [ P.succeed (P.Loop (count + 1)) + |. P.chompIf isNewLine + |. spaces + , P.succeed (P.Done count) + ] + + {-| -} characters : (Char -> Bool) -> P.Parser String characters isOk = @@ -282,6 +303,17 @@ remaining = postProcessString : String -> String postProcessString str = + if isLiteralString str then + postProcessLiteralString str + + else + str + |> String.replace "\n" " " + |> postProcessFoldedString + + +postProcessFoldedString : String -> String +postProcessFoldedString str = let regexFromString : String -> Regex regexFromString = @@ -298,6 +330,62 @@ postProcessString str = ) +isLiteralString : String -> Bool +isLiteralString str = + str + |> String.split "\n" + |> List.head + |> (==) (Just "|") + + +postProcessLiteralString : String -> String +postProcessLiteralString str = + case String.left 2 str of + "|\n" -> + let + content = + String.dropLeft 2 str + in + content + |> countLeadingSpacesInMultiline + |> removeLeadingSpaces content + + _ -> + str + + +removeLeadingSpaces : String -> Int -> String +removeLeadingSpaces str count = + str + |> String.split "\n" + |> List.map (String.dropLeft count) + |> String.join "\n" + + +countLeadingSpacesInMultiline : String -> Int +countLeadingSpacesInMultiline str = + str + |> String.split "\n" + |> List.head + |> Maybe.withDefault "" + |> countLeadingSpacesInString + + +countLeadingSpacesInString : String -> Int +countLeadingSpacesInString str = + let + countHelper : String -> Int -> Int + countHelper s count = + case String.uncons s of + Just ( ' ', rest ) -> + countHelper rest (count + 1) + + _ -> + count + in + countHelper str 0 + + -- INDENT diff --git a/tests/TestParser.elm b/tests/TestParser.elm index 2cd2e5f..ba4cb00 100644 --- a/tests/TestParser.elm +++ b/tests/TestParser.elm @@ -59,7 +59,6 @@ suite = Ast.Float_ x , Test.test "a single-quoted string" <| \_ -> - -- TODO is this right? expectValue """'hey i am a @@ -109,6 +108,33 @@ suite = """ <| Ast.String_ "how does one teach self-respect? how does one teach curiousity? if you have the answers, call me" + , Test.test + "a literal multi-line string" + <| + \_ -> + expectValue "|\n literal\n \ttext" <| + Ast.String_ "literal\n\ttext" + , Test.test "a record with literal string" <| + \_ -> + expectValue + """ + aaa: | + hello + world + """ + <| + Ast.Record_ (Dict.fromList [ ( "aaa", Ast.String_ "hello\nworld" ) ]) + , Test.test "a record with literal string with empty lines" <| + \_ -> + expectValue + """ + aaa: | + hello + + world + """ + <| + Ast.Record_ (Dict.fromList [ ( "aaa", Ast.String_ "hello\n\nworld" ) ]) , Test.test "a empty inline list" <| \_ -> expectValue "[]" <| From 6208b92b75482f1ddcec3ed9f3cf1b4f43024ddd Mon Sep 17 00:00:00 2001 From: James Collier Date: Thu, 5 Dec 2024 20:58:52 +0100 Subject: [PATCH 2/2] Credit contribution by lovebug356 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28a9fee..521d9a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Fixed -- Added support for literal multi-line strings ([#36](https://github.com/MaybeJustJames/yaml/pull/36)) +- Added support for literal multi-line strings ([#36](https://github.com/MaybeJustJames/yaml/pull/36) by [lovebug356](https://github.com/lovebug356)) ## [2.1.4] ### Changed