diff --git a/pkg/parser/delimited_block_test.go b/pkg/parser/delimited_block_test.go index 651a05a6..c3fd5bc0 100644 --- a/pkg/parser/delimited_block_test.go +++ b/pkg/parser/delimited_block_test.go @@ -581,7 +581,7 @@ and on the + ` It("should apply the default substitution", func() { - s := strings.ReplaceAll(source, "[subs=\"$SUBS\"]", "") + s := strings.ReplaceAll(source, "[subs=\"$SUBS\"]\n", "") expected := types.DraftDocument{ Attributes: types.Attributes{ "github-url": "https://github.com", @@ -592,7 +592,6 @@ and on the + Value: "https://github.com", }, types.BlankLine{}, - types.BlankLine{}, types.ExampleBlock{ Elements: []interface{}{ types.Paragraph{ @@ -2734,7 +2733,7 @@ another paragraph` // share the same implementation source := `:github-url: https://github.com - + [subs="$SUBS"] ---- a link to https://example.com[] <1> @@ -2748,7 +2747,7 @@ and on the + ` It("should apply the default substitution", func() { - s := strings.ReplaceAll(source, "[subs=\"$SUBS\"]", "") + s := strings.ReplaceAll(source, "[subs=\"$SUBS\"]\n", "") // remove the 'subs' attribute expected := types.DraftDocument{ Attributes: types.Attributes{ "github-url": "https://github.com", @@ -2759,7 +2758,6 @@ and on the + Value: "https://github.com", }, types.BlankLine{}, - types.BlankLine{}, types.ListingBlock{ Lines: [][]interface{}{ { @@ -4176,7 +4174,7 @@ ____ ` It("should apply the default substitution", func() { - s := strings.ReplaceAll(source, "[subs=\"$SUBS\"]", "") + s := strings.ReplaceAll(source, "[subs=\"$SUBS\"]\n", "") expected := types.DraftDocument{ Attributes: types.Attributes{ "github-url": "https://github.com", @@ -4187,7 +4185,6 @@ ____ Value: "https://github.com", }, types.BlankLine{}, - types.BlankLine{}, types.VerseBlock{ Attributes: types.Attributes{ types.AttrKind: types.Verse, diff --git a/pkg/parser/document_processing_apply_substitutions.go b/pkg/parser/document_processing_apply_substitutions.go index c1df7ab4..a32a5469 100644 --- a/pkg/parser/document_processing_apply_substitutions.go +++ b/pkg/parser/document_processing_apply_substitutions.go @@ -139,6 +139,7 @@ var defaultSubstitutionsForBlockLines = []elementsSubstitution{ } var defaultFencedBlockSubstitutions = defaultSubstitutionsForBlockLines var defaultListingBlockSubstitutions = defaultSubstitutionsForBlockLines +var defaultLiteralBlockSubstitutions = defaultSubstitutionsForBlockLines // other blocks var defaultPassthroughBlockSubstitutions = []elementsSubstitution{} @@ -252,6 +253,8 @@ func defaultSubstitutionsFor(block interface{}) ([]elementsSubstitution, error) return defaultListingBlockSubstitutions, nil case types.VerseBlock: return defaultVerseBlockSubstitutions, nil + case types.LiteralBlock: + return defaultLiteralBlockSubstitutions, nil case types.PassthroughBlock: return defaultPassthroughBlockSubstitutions, nil case types.CommentBlock: diff --git a/pkg/parser/literal_block_test.go b/pkg/parser/literal_block_test.go index f21e64c9..82280186 100644 --- a/pkg/parser/literal_block_test.go +++ b/pkg/parser/literal_block_test.go @@ -258,5 +258,492 @@ a normal paragraph.` Expect(result).To(MatchDraftDocument(expected)) }) }) + + Context("with custom substitutions", func() { + + // testing custom substitutions on a literal block only + + It("should apply the default substitution on block with delimiter", func() { + source := `:github-url: https://github.com + +.... +a link to https://example.com[] <1> +and on the + +*next* lines with a link to {github-url}[] + +* not a list item +.... + +<1> a callout +` + expected := types.DraftDocument{ + Attributes: types.Attributes{ + "github-url": "https://github.com", + }, + Elements: []interface{}{ + types.AttributeDeclaration{ + Name: "github-url", + Value: "https://github.com", + }, + types.BlankLine{}, + types.LiteralBlock{ + Attributes: types.Attributes{ + types.AttrKind: types.Literal, + types.AttrLiteralBlockType: types.LiteralBlockWithDelimiter, + }, + Lines: [][]interface{}{ + { + types.StringElement{ + Content: "a link to https://example.com[] ", + }, + types.Callout{ + Ref: 1, + }, + }, + { + types.StringElement{ + Content: "and ", + }, + types.SpecialCharacter{ + Name: "<", + }, + types.StringElement{ + Content: "more text", + }, + types.SpecialCharacter{ + Name: ">", + }, + types.StringElement{ + Content: " on the +", + }, + }, + { + types.StringElement{ + Content: "*next* lines with a link to {github-url}[]", + }, + }, + {}, + { + types.StringElement{ + Content: "* not a list item", + }, + }, + }, + }, + types.BlankLine{}, + types.CalloutListItem{ + Ref: 1, + Elements: []interface{}{ + types.Paragraph{ + Lines: [][]interface{}{ + { + types.StringElement{ + Content: "a callout", + }, + }, + }, + }, + }, + }, + }, + } + Expect(ParseDraftDocument(source)).To(MatchDraftDocument(expected)) + }) + It("should apply the 'normal' substitution on block with delimiter", func() { + source := `:github-url: https://github.com + +[subs="normal"] +.... +a link to https://example.com[] <1> +and on the + +*next* lines with a link to {github-url}[] + +* not a list item +.... + +<1> a callout +` + expected := types.DraftDocument{ + Attributes: types.Attributes{ + "github-url": "https://github.com", + }, + Elements: []interface{}{ + types.AttributeDeclaration{ + Name: "github-url", + Value: "https://github.com", + }, + types.BlankLine{}, + types.LiteralBlock{ + Attributes: types.Attributes{ + types.AttrKind: types.Literal, + types.AttrLiteralBlockType: types.LiteralBlockWithDelimiter, + types.AttrSubstitutions: "normal", + }, + Lines: [][]interface{}{ + { + types.StringElement{ + Content: "a link to ", + }, + types.InlineLink{ + Location: types.Location{ + Scheme: "https://", + Path: []interface{}{ + types.StringElement{ + Content: "example.com", + }, + }, + }, + }, + types.StringElement{ + Content: " ", + }, + types.SpecialCharacter{ // callout is not detected with the `normal` susbtitution + Name: "<", + }, + types.StringElement{ + Content: "1", + }, + types.SpecialCharacter{ + Name: ">", + }, + }, + { + types.StringElement{ + Content: "and ", + }, + types.SpecialCharacter{ + Name: "<", + }, + types.StringElement{ + Content: "more text", + }, + types.SpecialCharacter{ + Name: ">", + }, + types.StringElement{ + Content: " on the", + }, + types.LineBreak{}, + }, + { + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{ + Content: "next", + }, + }, + }, + types.StringElement{ + Content: " lines with a link to ", + }, + types.InlineLink{ + Location: types.Location{ + Scheme: "https://", + Path: []interface{}{ + types.StringElement{ + Content: "github.com", + }, + }, + }, + }, + }, + {}, + { + types.StringElement{ + Content: "* not a list item", + }, + }, + }, + }, + types.BlankLine{}, + types.CalloutListItem{ + Ref: 1, + Elements: []interface{}{ + types.Paragraph{ + Lines: [][]interface{}{ + { + types.StringElement{ + Content: "a callout", + }, + }, + }, + }, + }, + }, + }, + } + Expect(ParseDraftDocument(source)).To(MatchDraftDocument(expected)) + }) + + It("should apply the 'quotes,macros' substitution on block with delimiter", func() { + source := `:github-url: https://github.com + +[subs="quotes,macros"] +.... +a link to https://example.com[] <1> +and on the + +*next* lines with a link to {github-url}[] + +* not a list item +.... + +<1> a callout +` + expected := types.DraftDocument{ + Attributes: types.Attributes{ + "github-url": "https://github.com", + }, + Elements: []interface{}{ + types.AttributeDeclaration{ + Name: "github-url", + Value: "https://github.com", + }, + types.BlankLine{}, + types.LiteralBlock{ + Attributes: types.Attributes{ + types.AttrKind: types.Literal, + types.AttrLiteralBlockType: types.LiteralBlockWithDelimiter, + types.AttrSubstitutions: "quotes,macros", + }, + Lines: [][]interface{}{ + { + types.StringElement{ + Content: "a link to ", + }, + types.InlineLink{ + Location: types.Location{ + Scheme: "https://", + Path: []interface{}{ + types.StringElement{ + Content: "example.com", + }, + }, + }, + }, + types.StringElement{ + Content: " <1>", + }, + }, + { + types.StringElement{ + Content: "and on the +", + }, + }, + { + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{ + Content: "next", + }, + }, + }, + types.StringElement{ + Content: " lines with a link to {github-url}[]", + }, + }, + {}, + { + types.StringElement{ + Content: "* not a list item", + }, + }, + }, + }, + types.BlankLine{}, + types.CalloutListItem{ + Ref: 1, + Elements: []interface{}{ + types.Paragraph{ + Lines: [][]interface{}{ + { + types.StringElement{ + Content: "a callout", + }, + }, + }, + }, + }, + }, + }, + } + Expect(ParseDraftDocument(source)).To(MatchDraftDocument(expected)) + }) + + It("should apply the 'quotes,macros' substitution on block with spaces", func() { + source := `:github-url: https://github.com + +[subs="quotes,macros"] + a link to https://example.com[] <1> + and on the + + *next* lines with a link to {github-url}[] + +<1> a callout +` + expected := types.DraftDocument{ + Attributes: types.Attributes{ + "github-url": "https://github.com", + }, + Elements: []interface{}{ + types.AttributeDeclaration{ + Name: "github-url", + Value: "https://github.com", + }, + types.BlankLine{}, + types.LiteralBlock{ + Attributes: types.Attributes{ + types.AttrKind: types.Literal, + types.AttrLiteralBlockType: types.LiteralBlockWithSpacesOnFirstLine, + types.AttrSubstitutions: "quotes,macros", + }, + Lines: [][]interface{}{ + { + types.StringElement{ + Content: " a link to ", + }, + types.InlineLink{ + Location: types.Location{ + Scheme: "https://", + Path: []interface{}{ + types.StringElement{ + Content: "example.com", + }, + }, + }, + }, + types.StringElement{ + Content: " <1> ", + }, + }, + { + types.StringElement{ + Content: " and on the +", + }, + }, + { + types.StringElement{ + Content: " ", + }, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{ + Content: "next", + }, + }, + }, + types.StringElement{ + Content: " lines with a link to {github-url}[]", + }, + }, + }, + }, + types.BlankLine{}, + types.CalloutListItem{ + Ref: 1, + Elements: []interface{}{ + types.Paragraph{ + Lines: [][]interface{}{ + { + types.StringElement{ + Content: "a callout", + }, + }, + }, + }, + }, + }, + }, + } + Expect(ParseDraftDocument(source)).To(MatchDraftDocument(expected)) + }) + + It("should apply the 'quotes,macros' substitution on block with attribute", func() { + source := `:github-url: https://github.com + +[subs="quotes,macros"] +[literal] +a link to https://example.com[] <1> +and on the + +*next* lines with a link to {github-url}[] + +<1> a callout +` + expected := types.DraftDocument{ + Attributes: types.Attributes{ + "github-url": "https://github.com", + }, + Elements: []interface{}{ + types.AttributeDeclaration{ + Name: "github-url", + Value: "https://github.com", + }, + types.BlankLine{}, + types.LiteralBlock{ + Attributes: types.Attributes{ + types.AttrKind: types.Literal, + types.AttrLiteralBlockType: types.LiteralBlockWithAttribute, + types.AttrSubstitutions: "quotes,macros", + }, + Lines: [][]interface{}{ + { + types.StringElement{ + Content: "a link to ", + }, + types.InlineLink{ + Location: types.Location{ + Scheme: "https://", + Path: []interface{}{ + types.StringElement{ + Content: "example.com", + }, + }, + }, + }, + types.StringElement{ + Content: " <1>", + }, + }, + { + types.StringElement{ + Content: "and on the +", + }, + }, + { + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{ + Content: "next", + }, + }, + }, + types.StringElement{ + Content: " lines with a link to {github-url}[]", + }, + }, + }, + }, + types.BlankLine{}, + types.CalloutListItem{ + Ref: 1, + Elements: []interface{}{ + types.Paragraph{ + Lines: [][]interface{}{ + { + types.StringElement{ + Content: "a callout", + }, + }, + }, + }, + }, + }, + }, + } + Expect(ParseDraftDocument(source)).To(MatchDraftDocument(expected)) + }) + }) }) }) diff --git a/pkg/renderer/sgml/html5/literal_block_test.go b/pkg/renderer/sgml/html5/literal_block_test.go index f1c7ec91..3802ce38 100644 --- a/pkg/renderer/sgml/html5/literal_block_test.go +++ b/pkg/renderer/sgml/html5/literal_block_test.go @@ -158,4 +158,165 @@ on two lines. }) }) + Context("with custom substitutions", func() { + + // testing custom substitutions on a literal block only + + It("should apply the default substitution on block with delimiter", func() { + source := `:github-url: https://github.com + +.... +a link to https://example.com[] <1> +and on the + +*next* lines with a link to {github-url}[] + +* not a list item +.... + +<1> a callout +` + expected := `
+
+
a link to https://example.com[] (1)
+and <more text> on the +
+*next* lines with a link to {github-url}[]
+
+* not a list item
+
+
+
+
    +
  1. +

    a callout

    +
  2. +
+
+` + Expect(RenderHTML(source)).To(MatchHTML(expected)) + }) + It("should apply the 'normal' substitution on block with delimiter", func() { + source := `:github-url: https://github.com + +[subs="normal"] +.... +a link to https://example.com[] <1> +and on the + +*next* lines with a link to {github-url}[] + +* not a list item +.... + +<1> a callout +` + expected := `
+
+
a link to https://example.com <1>
+and <more text> on the
+next lines with a link to https://github.com + +* not a list item
+
+
+
+
    +
  1. +

    a callout

    +
  2. +
+
+` + Expect(RenderHTML(source)).To(MatchHTML(expected)) + }) + + It("should apply the 'quotes,macros' substitution on block with delimiter", func() { + source := `:github-url: https://github.com + +[subs="quotes,macros"] +.... +a link to https://example.com[] <1> +and on the + +*next* lines with a link to {github-url}[] + +* not a list item +.... + +<1> a callout +` + expected := `
+
+
a link to https://example.com <1>
+and  on the +
+next lines with a link to {github-url}[]
+
+* not a list item
+
+
+
+
    +
  1. +

    a callout

    +
  2. +
+
+` + Expect(RenderHTML(source)).To(MatchHTML(expected)) + }) + + It("should apply the 'quotes,macros' substitution on block with spaces", func() { + source := `:github-url: https://github.com + +[subs="quotes,macros"] + a link to https://example.com[] <1> + and on the + + *next* lines with a link to {github-url}[] + +<1> a callout +` + expected := `
+
+
a link to https://example.com <1>
+and  on the +
+next lines with a link to {github-url}[]
+
+
+
+
    +
  1. +

    a callout

    +
  2. +
+
+` + Expect(RenderHTML(source)).To(MatchHTML(expected)) + }) + + It("should apply the 'quotes,macros' substitution on block with attribute", func() { + source := `:github-url: https://github.com + +[subs="quotes,macros"] +[literal] +a link to https://example.com[] <1> +and on the + +*next* lines with a link to {github-url}[] + +<1> a callout +` + expected := `
+
+
a link to https://example.com <1>
+and  on the +
+next lines with a link to {github-url}[]
+
+
+
+
    +
  1. +

    a callout

    +
  2. +
+
+` + Expect(RenderHTML(source)).To(MatchHTML(expected)) + }) + }) }) diff --git a/pkg/types/types.go b/pkg/types/types.go index 725275a0..a190f6f4 100644 --- a/pkg/types/types.go +++ b/pkg/types/types.go @@ -1178,10 +1178,12 @@ func (p Paragraph) SubstitutionsToApply() string { return p.Attributes.GetAsStringWithDefault(AttrSubstitutions, "") } +// LinesToSubstitute returns the lines of this ExampleBlock so that substitutions can be applied onto them func (p Paragraph) LinesToSubstitute() [][]interface{} { return p.Lines } +// ReplaceLines replaces the elements in this example block func (p Paragraph) ReplaceLines(lines [][]interface{}) interface{} { p.Lines = lines return p @@ -1848,6 +1850,24 @@ func NewLiteralBlock(origin string, lines []interface{}, attributes interface{}) }, nil } +var _ BlockWithLineSubstitution = LiteralBlock{} + +// SubstitutionsToApply returns the name of the substitutions to apply +func (b LiteralBlock) SubstitutionsToApply() string { + return b.Attributes.GetAsStringWithDefault(AttrSubstitutions, "") +} + +// LinesToSubstitute returns the lines of this ExampleBlock so that substitutions can be applied onto them +func (b LiteralBlock) LinesToSubstitute() [][]interface{} { + return b.Lines +} + +// ReplaceLines replaces the elements in this example block +func (b LiteralBlock) ReplaceLines(lines [][]interface{}) interface{} { + b.Lines = lines + return b +} + // ------------------------------------------ // Thematic breaks // ------------------------------------------