diff --git a/parser/asciidoc-grammar.peg b/parser/asciidoc-grammar.peg index dee4663a..2f649604 100644 --- a/parser/asciidoc-grammar.peg +++ b/parser/asciidoc-grammar.peg @@ -124,8 +124,8 @@ Paragraph <- metadata:(MetadataElement)* lines:(InlineContent)+ { } // an inline content element may begin and end with spaces, -// but it must contain at least a quoted text, an external link or a word -InlineContent <- elements:(WS* (QuotedText / ExternalLink / Word) WS*)+ EOL { +// but it must contain at least an image, a quoted text, an external link or a word +InlineContent <- elements:(WS* (InlineImage / QuotedText / ExternalLink / Word) WS*)+ EOL { return types.NewInlineContent(c.text, elements.([]interface{})) } @@ -168,15 +168,20 @@ ExternalLink <- url:(URL_SCHEME URL) text:('[' (URL_TEXT)* ']')? { // ------------------------------------------ BlockImage <- metadata:(MetadataElement)* image:BlockImageMacro WS* EOL { // here we can ignore the blank line in the returned element - return types.NewBlockImage(c.text, *image.(*types.BlockImageMacro), metadata.([]interface{})) + return types.NewBlockImage(c.text, *image.(*types.ImageMacro), metadata.([]interface{})) } BlockImageMacro <- "image::" path:(URL) '[' attributes:(URL_TEXT?) ']' { - if attributes != nil { - attrs := attributes.(string) - return types.NewBlockImageMacro(c.text, path.(string), &attrs) - } - return types.NewBlockImageMacro(c.text, path.(string), nil) + return types.NewImageMacro(c.text, path.(string), attributes) +} + +InlineImage <- image:InlineImageMacro { + // here we can ignore the blank line in the returned element + return types.NewInlineImage(c.text, *image.(*types.ImageMacro)) +} + +InlineImageMacro <- "image:" !":" path:(URL) '[' attributes:(URL_TEXT?) ']' { + return types.NewImageMacro(c.text, path.(string), attributes) } // ------------------------------------------ diff --git a/parser/asciidoc_parser_test.go b/parser/asciidoc_parser_test.go index 2968c558..554b2667 100644 --- a/parser/asciidoc_parser_test.go +++ b/parser/asciidoc_parser_test.go @@ -74,7 +74,7 @@ var _ = Describe("Parsing content", func() { }) func verify(t GinkgoTInterface, expectedDocument *types.Document, content string) { - log.Debugf("processing:\n%s", content) + log.Debugf("processing: %s", content) reader := strings.NewReader(content) result, err := ParseReader("", reader) if err != nil { @@ -83,7 +83,7 @@ func verify(t GinkgoTInterface, expectedDocument *types.Document, content string require.Nil(t, err) actualDocument := result.(*types.Document) t.Logf("actual document structure: %+v", actualDocument.Elements) - t.Logf("actual document: %s", actualDocument.String(0)) - t.Logf("expected document: %s", expectedDocument.String(0)) + t.Logf("actual document: `%s`", actualDocument.String(0)) + t.Logf("expected document: `%s`", expectedDocument.String(0)) assert.EqualValues(t, *expectedDocument, *actualDocument) } diff --git a/parser/blank_line_test.go b/parser/blank_line_test.go index f54de200..83b297a3 100644 --- a/parser/blank_line_test.go +++ b/parser/blank_line_test.go @@ -5,7 +5,7 @@ import ( . "github.com/onsi/ginkgo" ) -var _ = Describe("Rendering Blank lines", func() { +var _ = Describe("Blank lines", func() { It("blank line between 2 paragraphs", func() { actualDocument := `first paragraph diff --git a/parser/block_image_test.go b/parser/block_image_test.go deleted file mode 100644 index eea2edbf..00000000 --- a/parser/block_image_test.go +++ /dev/null @@ -1,159 +0,0 @@ -package parser_test - -import ( - "github.com/bytesparadise/libasciidoc/types" - . "github.com/onsi/ginkgo" -) - -var _ = Describe("Parsing Block Images", func() { - Context("Correct behaviour", func() { - - It("block image with empty alt", func() { - actualContent := "image::images/foo.png[]" - expectedDocument := &types.Document{ - Elements: []types.DocElement{ - &types.BlockImage{ - Macro: types.BlockImageMacro{ - Path: "images/foo.png", - Alt: "foo", - }, - }, - }, - } - verify(GinkgoT(), expectedDocument, actualContent) - }) - - It("block image with empty alt and trailing spaces", func() { - actualContent := "image::images/foo.png[] \t\t " - expectedDocument := &types.Document{ - Elements: []types.DocElement{ - &types.BlockImage{ - Macro: types.BlockImageMacro{ - Path: "images/foo.png", - Alt: "foo", - }, - }, - }, - } - verify(GinkgoT(), expectedDocument, actualContent) - }) - - It("block image with line return", func() { - // line return here is not considered as a blank line - actualContent := `image::images/foo.png[] -` - expectedDocument := &types.Document{ - Elements: []types.DocElement{ - &types.BlockImage{ - Macro: types.BlockImageMacro{ - Path: "images/foo.png", - Alt: "foo", - }, - }, - }, - } - verify(GinkgoT(), expectedDocument, actualContent) - }) - - It("block image with 1 empty blank line", func() { - // here, there's a real blank line with some spaces - actualContent := `image::images/foo.png[] - ` - expectedDocument := &types.Document{ - Elements: []types.DocElement{ - &types.BlockImage{ - Macro: types.BlockImageMacro{ - Path: "images/foo.png", - Alt: "foo", - }, - }, - // &types.BlankLine{}, - }, - } - verify(GinkgoT(), expectedDocument, actualContent) - }) - - It("block image with 2 blank lines with spaces and tabs", func() { - actualContent := `image::images/foo.png[] - - ` - expectedDocument := &types.Document{ - Elements: []types.DocElement{ - &types.BlockImage{ - Macro: types.BlockImageMacro{ - Path: "images/foo.png", - Alt: "foo", - }, - }, - // &types.BlankLine{}, - // &types.BlankLine{}, - }, - } - verify(GinkgoT(), expectedDocument, actualContent) - }) - - It("block image with alt", func() { - actualContent := "image::images/foo.png[the foo.png image]" - expectedDocument := &types.Document{ - Elements: []types.DocElement{ - &types.BlockImage{ - Macro: types.BlockImageMacro{ - Path: "images/foo.png", - Alt: "the foo.png image", - }, - }, - }, - } - verify(GinkgoT(), expectedDocument, actualContent) - }) - - It("block image with dimensions and i d link title meta", func() { - actualContent := "[#img-foobar]\n" + - ".A title to foobar\n" + - "[link=http://foo.bar]\n" + - "image::images/foo.png[the foo.png image, 600, 400]" - width := "600" - height := "400" - expectedDocument := &types.Document{ - Elements: []types.DocElement{ - &types.BlockImage{ - Macro: types.BlockImageMacro{ - Path: "images/foo.png", - Alt: "the foo.png image", - Width: &width, - Height: &height, - }, - ID: &types.ElementID{Value: "img-foobar"}, - Title: &types.ElementTitle{Value: "A title to foobar"}, - Link: &types.ElementLink{Path: "http://foo.bar"}, - }, - }, - } - verify(GinkgoT(), expectedDocument, actualContent) - }) - }) - Context("Errors", func() { - It("block image appending inline content", func() { - actualContent := "a paragraph\nimage::images/foo.png[]" - expectedDocument := &types.Document{ - Elements: []types.DocElement{ - &types.Paragraph{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.DocElement{ - &types.StringElement{Content: "a paragraph"}, - }, - }, - &types.InlineContent{ - Elements: []types.DocElement{ - &types.StringElement{Content: "image::images/foo.png[]"}, - }, - }, - }, - }, - }, - } - verify(GinkgoT(), expectedDocument, actualContent) - }) - }) -}) diff --git a/parser/delimited_block_test.go b/parser/delimited_block_test.go index 564e48ba..c05e904c 100644 --- a/parser/delimited_block_test.go +++ b/parser/delimited_block_test.go @@ -5,7 +5,7 @@ import ( . "github.com/onsi/ginkgo" ) -var _ = Describe("Parsing Delimited Blocks", func() { +var _ = Describe("Delimited Blocks", func() { It("delimited source block with single line", func() { content := "some source code" diff --git a/parser/external_link_test.go b/parser/external_link_test.go index 582ee83b..7aea9754 100644 --- a/parser/external_link_test.go +++ b/parser/external_link_test.go @@ -5,7 +5,7 @@ import ( . "github.com/onsi/ginkgo" ) -var _ = Describe("Parsing External Links", func() { +var _ = Describe("External Links", func() { It("external link", func() { actualContent := "a link to https://foo.bar" diff --git a/parser/image_test.go b/parser/image_test.go new file mode 100644 index 00000000..f38f3a84 --- /dev/null +++ b/parser/image_test.go @@ -0,0 +1,291 @@ +package parser_test + +import ( + "github.com/bytesparadise/libasciidoc/types" + . "github.com/onsi/ginkgo" +) + +var _ = Describe("Images", func() { + Context("Block Images", func() { + Context("Correct behaviour", func() { + + It("block image with empty alt", func() { + actualContent := "image::images/foo.png[]" + expectedDocument := &types.Document{ + Elements: []types.DocElement{ + &types.BlockImage{ + Macro: types.ImageMacro{ + Path: "images/foo.png", + Alt: "foo", + }, + }, + }, + } + verify(GinkgoT(), expectedDocument, actualContent) + }) + + It("block image with empty alt and trailing spaces", func() { + actualContent := "image::images/foo.png[] \t\t " + expectedDocument := &types.Document{ + Elements: []types.DocElement{ + &types.BlockImage{ + Macro: types.ImageMacro{ + Path: "images/foo.png", + Alt: "foo", + }, + }, + }, + } + verify(GinkgoT(), expectedDocument, actualContent) + }) + + It("block image with line return", func() { + // line return here is not considered as a blank line + actualContent := `image::images/foo.png[] +` + expectedDocument := &types.Document{ + Elements: []types.DocElement{ + &types.BlockImage{ + Macro: types.ImageMacro{ + Path: "images/foo.png", + Alt: "foo", + }, + }, + }, + } + verify(GinkgoT(), expectedDocument, actualContent) + }) + + It("block image with 1 empty blank line", func() { + // here, there's a real blank line with some spaces + actualContent := `image::images/foo.png[] + ` + expectedDocument := &types.Document{ + Elements: []types.DocElement{ + &types.BlockImage{ + Macro: types.ImageMacro{ + Path: "images/foo.png", + Alt: "foo", + }, + }, + // &types.BlankLine{}, + }, + } + verify(GinkgoT(), expectedDocument, actualContent) + }) + + It("block image with 2 blank lines with spaces and tabs", func() { + actualContent := `image::images/foo.png[] + + ` + expectedDocument := &types.Document{ + Elements: []types.DocElement{ + &types.BlockImage{ + Macro: types.ImageMacro{ + Path: "images/foo.png", + Alt: "foo", + }, + }, + // &types.BlankLine{}, + // &types.BlankLine{}, + }, + } + verify(GinkgoT(), expectedDocument, actualContent) + }) + + It("block image with alt", func() { + actualContent := "image::images/foo.png[the foo.png image]" + expectedDocument := &types.Document{ + Elements: []types.DocElement{ + &types.BlockImage{ + Macro: types.ImageMacro{ + Path: "images/foo.png", + Alt: "the foo.png image", + }, + }, + }, + } + verify(GinkgoT(), expectedDocument, actualContent) + }) + + It("block image with dimensions and i d link title meta", func() { + actualContent := "[#img-foobar]\n" + + ".A title to foobar\n" + + "[link=http://foo.bar]\n" + + "image::images/foo.png[the foo.png image, 600, 400]" + width := "600" + height := "400" + expectedDocument := &types.Document{ + Elements: []types.DocElement{ + &types.BlockImage{ + Macro: types.ImageMacro{ + Path: "images/foo.png", + Alt: "the foo.png image", + Width: &width, + Height: &height, + }, + ID: &types.ElementID{Value: "img-foobar"}, + Title: &types.ElementTitle{Value: "A title to foobar"}, + Link: &types.ElementLink{Path: "http://foo.bar"}, + }, + }, + } + verify(GinkgoT(), expectedDocument, actualContent) + }) + }) + Context("Errors", func() { + It("block image appending inline content", func() { + actualContent := "a paragraph\nimage::images/foo.png[]" + expectedDocument := &types.Document{ + Elements: []types.DocElement{ + &types.Paragraph{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.DocElement{ + &types.StringElement{Content: "a paragraph"}, + }, + }, + &types.InlineContent{ + Elements: []types.DocElement{ + &types.StringElement{Content: "image::images/foo.png[]"}, + }, + }, + }, + }, + }, + } + verify(GinkgoT(), expectedDocument, actualContent) + }) + }) + }) + + Context("Inline Images", func() { + Context("Correct behaviour", func() { + + It("inline image with empty alt", func() { + actualContent := "image:images/foo.png[]" + expectedDocument := &types.Document{ + Elements: []types.DocElement{ + &types.Paragraph{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.DocElement{ + &types.InlineImage{ + Macro: types.ImageMacro{ + Path: "images/foo.png", + Alt: "foo", + }, + }, + }, + }, + }, + }, + }, + } + verify(GinkgoT(), expectedDocument, actualContent) + }) + + It("inline image with empty alt and trailing spaces", func() { + actualContent := "image:images/foo.png[] \t\t " + expectedDocument := &types.Document{ + Elements: []types.DocElement{ + &types.Paragraph{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.DocElement{ + &types.InlineImage{ + Macro: types.ImageMacro{ + Path: "images/foo.png", + Alt: "foo", + }, + }, + &types.StringElement{ + Content: " \t\t ", + }, + }, + }, + }, + }, + }, + } + verify(GinkgoT(), expectedDocument, actualContent) + }) + + It("inline image surrounded with test", func() { + actualContent := "a foo image:images/foo.png[] bar..." + expectedDocument := &types.Document{ + Elements: []types.DocElement{ + &types.Paragraph{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.DocElement{ + &types.StringElement{ + Content: "a foo ", + }, + &types.InlineImage{ + Macro: types.ImageMacro{ + Path: "images/foo.png", + Alt: "foo", + }, + }, + &types.StringElement{ + Content: " bar...", + }, + }, + }, + }, + }, + }, + } + verify(GinkgoT(), expectedDocument, actualContent) + }) + + It("inline image with alt", func() { + actualContent := "image:images/foo.png[the foo.png image]" + expectedDocument := &types.Document{ + Elements: []types.DocElement{ + &types.Paragraph{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.DocElement{ + &types.InlineImage{ + Macro: types.ImageMacro{ + Path: "images/foo.png", + Alt: "the foo.png image", + }, + }, + }, + }, + }, + }, + }, + } + verify(GinkgoT(), expectedDocument, actualContent) + }) + }) + Context("Errors", func() { + It("inline image appending inline content", func() { + actualContent := "a paragraph\nimage::images/foo.png[]" + expectedDocument := &types.Document{ + Elements: []types.DocElement{ + &types.Paragraph{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.DocElement{ + &types.StringElement{Content: "a paragraph"}, + }, + }, + &types.InlineContent{ + Elements: []types.DocElement{ + &types.StringElement{Content: "image::images/foo.png[]"}, + }, + }, + }, + }, + }, + } + verify(GinkgoT(), expectedDocument, actualContent) + }) + }) + }) +}) diff --git a/parser/list_test.go b/parser/list_test.go index f99ce011..7b5fc2f6 100644 --- a/parser/list_test.go +++ b/parser/list_test.go @@ -5,22 +5,24 @@ import ( . "github.com/onsi/ginkgo" ) -var _ = Describe("Parsing Unordered List Items", func() { +var _ = Describe("List Items", func() { - Context("Valid content", func() { - It("1 list with a single item", func() { - actualContent := "* a list item" - expectedDocument := &types.Document{ - Elements: []types.DocElement{ - &types.List{ - Items: []*types.ListItem{ - &types.ListItem{ - Level: 1, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.DocElement{ - &types.StringElement{Content: "a list item"}, + Context("Unordered ", func() { + Context("Valid content", func() { + It("1 list with a single item", func() { + actualContent := "* a list item" + expectedDocument := &types.Document{ + Elements: []types.DocElement{ + &types.List{ + Items: []*types.ListItem{ + &types.ListItem{ + Level: 1, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.DocElement{ + &types.StringElement{Content: "a list item"}, + }, }, }, }, @@ -28,25 +30,25 @@ var _ = Describe("Parsing Unordered List Items", func() { }, }, }, - }, - } - verify(GinkgoT(), expectedDocument, actualContent) - }) - It("1 list with an ID and a single item", func() { - actualContent := "[#listID]\n" + - "* a list item" - expectedDocument := &types.Document{ - Elements: []types.DocElement{ - &types.List{ - ID: &types.ElementID{Value: "listID"}, - Items: []*types.ListItem{ - &types.ListItem{ - Level: 1, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.DocElement{ - &types.StringElement{Content: "a list item"}, + } + verify(GinkgoT(), expectedDocument, actualContent) + }) + It("1 list with an ID and a single item", func() { + actualContent := "[#listID]\n" + + "* a list item" + expectedDocument := &types.Document{ + Elements: []types.DocElement{ + &types.List{ + ID: &types.ElementID{Value: "listID"}, + Items: []*types.ListItem{ + &types.ListItem{ + Level: 1, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.DocElement{ + &types.StringElement{Content: "a list item"}, + }, }, }, }, @@ -54,40 +56,40 @@ var _ = Describe("Parsing Unordered List Items", func() { }, }, }, - }, - } - verify(GinkgoT(), expectedDocument, actualContent) - }) + } + verify(GinkgoT(), expectedDocument, actualContent) + }) - It("1 list with 2 items with stars", func() { - actualContent := "* a first item\n" + - "* a second item with *bold content*" - expectedDocument := &types.Document{ - Elements: []types.DocElement{ - &types.List{ - Items: []*types.ListItem{ - &types.ListItem{ - Level: 1, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.DocElement{ - &types.StringElement{Content: "a first item"}, + It("1 list with 2 items with stars", func() { + actualContent := "* a first item\n" + + "* a second item with *bold content*" + expectedDocument := &types.Document{ + Elements: []types.DocElement{ + &types.List{ + Items: []*types.ListItem{ + &types.ListItem{ + Level: 1, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.DocElement{ + &types.StringElement{Content: "a first item"}, + }, }, }, }, }, - }, - &types.ListItem{ - Level: 1, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.DocElement{ - &types.StringElement{Content: "a second item with "}, - &types.QuotedText{Kind: types.Bold, - Elements: []types.DocElement{ - &types.StringElement{Content: "bold content"}, + &types.ListItem{ + Level: 1, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.DocElement{ + &types.StringElement{Content: "a second item with "}, + &types.QuotedText{Kind: types.Bold, + Elements: []types.DocElement{ + &types.StringElement{Content: "bold content"}, + }, }, }, }, @@ -97,39 +99,39 @@ var _ = Describe("Parsing Unordered List Items", func() { }, }, }, - }, - } - verify(GinkgoT(), expectedDocument, actualContent) - }) - It("1 list with 2 items with carets", func() { - actualContent := "- a first item\n" + - "- a second item with *bold content*" - expectedDocument := &types.Document{ - Elements: []types.DocElement{ - &types.List{ - Items: []*types.ListItem{ - &types.ListItem{ - Level: 1, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.DocElement{ - &types.StringElement{Content: "a first item"}, + } + verify(GinkgoT(), expectedDocument, actualContent) + }) + It("1 list with 2 items with carets", func() { + actualContent := "- a first item\n" + + "- a second item with *bold content*" + expectedDocument := &types.Document{ + Elements: []types.DocElement{ + &types.List{ + Items: []*types.ListItem{ + &types.ListItem{ + Level: 1, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.DocElement{ + &types.StringElement{Content: "a first item"}, + }, }, }, }, }, - }, - &types.ListItem{ - Level: 1, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.DocElement{ - &types.StringElement{Content: "a second item with "}, - &types.QuotedText{Kind: types.Bold, - Elements: []types.DocElement{ - &types.StringElement{Content: "bold content"}, + &types.ListItem{ + Level: 1, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.DocElement{ + &types.StringElement{Content: "a second item with "}, + &types.QuotedText{Kind: types.Bold, + Elements: []types.DocElement{ + &types.StringElement{Content: "bold content"}, + }, }, }, }, @@ -139,41 +141,41 @@ var _ = Describe("Parsing Unordered List Items", func() { }, }, }, - }, - } - verify(GinkgoT(), expectedDocument, actualContent) - }) - It("1 list with 2 items with empty line in-between", func() { - // fist line after list item is swallowed - actualContent := "* a first item\n" + - "\n" + - "* a second item with *bold content*" - expectedDocument := &types.Document{ - Elements: []types.DocElement{ - &types.List{ - Items: []*types.ListItem{ - &types.ListItem{ - Level: 1, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.DocElement{ - &types.StringElement{Content: "a first item"}, + } + verify(GinkgoT(), expectedDocument, actualContent) + }) + It("1 list with 2 items with empty line in-between", func() { + // fist line after list item is swallowed + actualContent := "* a first item\n" + + "\n" + + "* a second item with *bold content*" + expectedDocument := &types.Document{ + Elements: []types.DocElement{ + &types.List{ + Items: []*types.ListItem{ + &types.ListItem{ + Level: 1, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.DocElement{ + &types.StringElement{Content: "a first item"}, + }, }, }, }, }, - }, - &types.ListItem{ - Level: 1, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.DocElement{ - &types.StringElement{Content: "a second item with "}, - &types.QuotedText{Kind: types.Bold, - Elements: []types.DocElement{ - &types.StringElement{Content: "bold content"}, + &types.ListItem{ + Level: 1, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.DocElement{ + &types.StringElement{Content: "a second item with "}, + &types.QuotedText{Kind: types.Bold, + Elements: []types.DocElement{ + &types.StringElement{Content: "bold content"}, + }, }, }, }, @@ -183,48 +185,48 @@ var _ = Describe("Parsing Unordered List Items", func() { }, }, }, - }, - } - verify(GinkgoT(), expectedDocument, actualContent) - }) - It("1 list with 2 items on multiple lines", func() { - actualContent := "* item 1\n" + - " on 2 lines.\n" + - "* item 2\n" + - "on 2 lines, too." - expectedDocument := &types.Document{ - Elements: []types.DocElement{ - &types.List{ - Items: []*types.ListItem{ - &types.ListItem{ - Level: 1, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.DocElement{ - &types.StringElement{Content: "item 1"}, + } + verify(GinkgoT(), expectedDocument, actualContent) + }) + It("1 list with 2 items on multiple lines", func() { + actualContent := "* item 1\n" + + " on 2 lines.\n" + + "* item 2\n" + + "on 2 lines, too." + expectedDocument := &types.Document{ + Elements: []types.DocElement{ + &types.List{ + Items: []*types.ListItem{ + &types.ListItem{ + Level: 1, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.DocElement{ + &types.StringElement{Content: "item 1"}, + }, }, - }, - &types.InlineContent{ - Elements: []types.DocElement{ - &types.StringElement{Content: " on 2 lines."}, + &types.InlineContent{ + Elements: []types.DocElement{ + &types.StringElement{Content: " on 2 lines."}, + }, }, }, }, }, - }, - &types.ListItem{ - Level: 1, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.DocElement{ - &types.StringElement{Content: "item 2"}, + &types.ListItem{ + Level: 1, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.DocElement{ + &types.StringElement{Content: "item 2"}, + }, }, - }, - &types.InlineContent{ - Elements: []types.DocElement{ - &types.StringElement{Content: "on 2 lines, too."}, + &types.InlineContent{ + Elements: []types.DocElement{ + &types.StringElement{Content: "on 2 lines, too."}, + }, }, }, }, @@ -232,44 +234,44 @@ var _ = Describe("Parsing Unordered List Items", func() { }, }, }, - }, - } - verify(GinkgoT(), expectedDocument, actualContent) - }) - It("2 lists with 2 empty lines in-between", func() { - // the first blank lines after the first list is swallowed (for the list item) - actualContent := "* an item in the first list\n" + - "\n" + - "\n" + - "* an item in the second list" - expectedDocument := &types.Document{ - Elements: []types.DocElement{ - &types.List{ - Items: []*types.ListItem{ - &types.ListItem{ - Level: 1, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.DocElement{ - &types.StringElement{Content: "an item in the first list"}, + } + verify(GinkgoT(), expectedDocument, actualContent) + }) + It("2 lists with 2 empty lines in-between", func() { + // the first blank lines after the first list is swallowed (for the list item) + actualContent := "* an item in the first list\n" + + "\n" + + "\n" + + "* an item in the second list" + expectedDocument := &types.Document{ + Elements: []types.DocElement{ + &types.List{ + Items: []*types.ListItem{ + &types.ListItem{ + Level: 1, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.DocElement{ + &types.StringElement{Content: "an item in the first list"}, + }, }, }, }, }, }, }, - }, - // &types.BlankLine{}, - &types.List{ - Items: []*types.ListItem{ - &types.ListItem{ - Level: 1, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.DocElement{ - &types.StringElement{Content: "an item in the second list"}, + // &types.BlankLine{}, + &types.List{ + Items: []*types.ListItem{ + &types.ListItem{ + Level: 1, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.DocElement{ + &types.StringElement{Content: "an item in the second list"}, + }, }, }, }, @@ -277,73 +279,73 @@ var _ = Describe("Parsing Unordered List Items", func() { }, }, }, - }, - } - verify(GinkgoT(), expectedDocument, actualContent) - }) + } + verify(GinkgoT(), expectedDocument, actualContent) + }) - }) + }) - Context("List of multiple levels", func() { - It("a list with items on 3 levels", func() { - actualContent := "* item 1\n" + - "** item 1.1\n" + - "** item 1.2\n" + - "*** item 1.2.1\n" + - "** item 1.3\n" + - "** item 1.4\n" + - "* item 2\n" + - "** item 2.1\n" - expectedDocument := &types.Document{ - Elements: []types.DocElement{ - &types.List{ - Items: []*types.ListItem{ - &types.ListItem{ - Level: 1, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.DocElement{ - &types.StringElement{Content: "item 1"}, + Context("List of multiple levels", func() { + It("a list with items on 3 levels", func() { + actualContent := "* item 1\n" + + "** item 1.1\n" + + "** item 1.2\n" + + "*** item 1.2.1\n" + + "** item 1.3\n" + + "** item 1.4\n" + + "* item 2\n" + + "** item 2.1\n" + expectedDocument := &types.Document{ + Elements: []types.DocElement{ + &types.List{ + Items: []*types.ListItem{ + &types.ListItem{ + Level: 1, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.DocElement{ + &types.StringElement{Content: "item 1"}, + }, }, }, }, - }, - Children: &types.List{ - Items: []*types.ListItem{ - &types.ListItem{ - Level: 2, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ + Children: &types.List{ + Items: []*types.ListItem{ + &types.ListItem{ + Level: 2, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ - Elements: []types.DocElement{ - &types.StringElement{Content: "item 1.1"}, + Elements: []types.DocElement{ + &types.StringElement{Content: "item 1.1"}, + }, }, }, }, }, - }, - &types.ListItem{ - Level: 2, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.DocElement{ - &types.StringElement{Content: "item 1.2"}, + &types.ListItem{ + Level: 2, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.DocElement{ + &types.StringElement{Content: "item 1.2"}, + }, }, }, }, - }, - Children: &types.List{ - Items: []*types.ListItem{ - &types.ListItem{ - Level: 3, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.DocElement{ - &types.StringElement{Content: "item 1.2.1"}, + Children: &types.List{ + Items: []*types.ListItem{ + &types.ListItem{ + Level: 3, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.DocElement{ + &types.StringElement{Content: "item 1.2.1"}, + }, }, }, }, @@ -351,26 +353,26 @@ var _ = Describe("Parsing Unordered List Items", func() { }, }, }, - }, - &types.ListItem{ - Level: 2, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.DocElement{ - &types.StringElement{Content: "item 1.3"}, + &types.ListItem{ + Level: 2, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.DocElement{ + &types.StringElement{Content: "item 1.3"}, + }, }, }, }, }, - }, - &types.ListItem{ - Level: 2, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.DocElement{ - &types.StringElement{Content: "item 1.4"}, + &types.ListItem{ + Level: 2, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.DocElement{ + &types.StringElement{Content: "item 1.4"}, + }, }, }, }, @@ -378,27 +380,27 @@ var _ = Describe("Parsing Unordered List Items", func() { }, }, }, - }, - &types.ListItem{ - Level: 1, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.DocElement{ - &types.StringElement{Content: "item 2"}, + &types.ListItem{ + Level: 1, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.DocElement{ + &types.StringElement{Content: "item 2"}, + }, }, }, }, - }, - Children: &types.List{ - Items: []*types.ListItem{ - &types.ListItem{ - Level: 2, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.DocElement{ - &types.StringElement{Content: "item 2.1"}, + Children: &types.List{ + Items: []*types.ListItem{ + &types.ListItem{ + Level: 2, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.DocElement{ + &types.StringElement{Content: "item 2.1"}, + }, }, }, }, @@ -409,57 +411,57 @@ var _ = Describe("Parsing Unordered List Items", func() { }, }, }, - }, - } - verify(GinkgoT(), expectedDocument, actualContent) - }) + } + verify(GinkgoT(), expectedDocument, actualContent) + }) - }) + }) - Context("Invalid content", func() { - It("a list with items on 2 levels - bad numbering", func() { - actualContent := "* item 1\n" + - "*** item 1.1\n" + - "*** item 1.1.1\n" + - "** item 1.2\n" + - "* item 2" - expectedDocument := &types.Document{ - Elements: []types.DocElement{ - &types.List{ - Items: []*types.ListItem{ - &types.ListItem{ - Level: 1, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.DocElement{ - &types.StringElement{Content: "item 1"}, + Context("Invalid content", func() { + It("a list with items on 2 levels - bad numbering", func() { + actualContent := "* item 1\n" + + "*** item 1.1\n" + + "*** item 1.1.1\n" + + "** item 1.2\n" + + "* item 2" + expectedDocument := &types.Document{ + Elements: []types.DocElement{ + &types.List{ + Items: []*types.ListItem{ + &types.ListItem{ + Level: 1, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.DocElement{ + &types.StringElement{Content: "item 1"}, + }, }, }, }, - }, - Children: &types.List{ - Items: []*types.ListItem{ - &types.ListItem{ - Level: 2, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.DocElement{ - &types.StringElement{Content: "item 1.1"}, + Children: &types.List{ + Items: []*types.ListItem{ + &types.ListItem{ + Level: 2, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.DocElement{ + &types.StringElement{Content: "item 1.1"}, + }, }, }, }, - }, - Children: &types.List{ - Items: []*types.ListItem{ - &types.ListItem{ - Level: 3, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.DocElement{ - &types.StringElement{Content: "item 1.1.1"}, + Children: &types.List{ + Items: []*types.ListItem{ + &types.ListItem{ + Level: 3, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.DocElement{ + &types.StringElement{Content: "item 1.1.1"}, + }, }, }, }, @@ -467,14 +469,14 @@ var _ = Describe("Parsing Unordered List Items", func() { }, }, }, - }, - &types.ListItem{ - Level: 2, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.DocElement{ - &types.StringElement{Content: "item 1.2"}, + &types.ListItem{ + Level: 2, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.DocElement{ + &types.StringElement{Content: "item 1.2"}, + }, }, }, }, @@ -482,14 +484,14 @@ var _ = Describe("Parsing Unordered List Items", func() { }, }, }, - }, - &types.ListItem{ - Level: 1, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.DocElement{ - &types.StringElement{Content: "item 2"}, + &types.ListItem{ + Level: 1, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.DocElement{ + &types.StringElement{Content: "item 2"}, + }, }, }, }, @@ -497,28 +499,27 @@ var _ = Describe("Parsing Unordered List Items", func() { }, }, }, - }, - } - verify(GinkgoT(), expectedDocument, actualContent) - }) + } + verify(GinkgoT(), expectedDocument, actualContent) + }) - It("invalid list item", func() { - actualContent := "*an invalid list item" - expectedDocument := &types.Document{ - Elements: []types.DocElement{ - &types.Paragraph{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.DocElement{ - &types.StringElement{Content: "*an invalid list item"}, + It("invalid list item", func() { + actualContent := "*an invalid list item" + expectedDocument := &types.Document{ + Elements: []types.DocElement{ + &types.Paragraph{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.DocElement{ + &types.StringElement{Content: "*an invalid list item"}, + }, }, }, }, }, - }, - } - verify(GinkgoT(), expectedDocument, actualContent) + } + verify(GinkgoT(), expectedDocument, actualContent) + }) }) }) - }) diff --git a/parser/meta_elements_test.go b/parser/meta_elements_test.go index 93995992..3e6dc21a 100644 --- a/parser/meta_elements_test.go +++ b/parser/meta_elements_test.go @@ -5,11 +5,11 @@ import ( . "github.com/onsi/ginkgo" ) -var _ = Describe("Parsing Meta Elements", func() { +var _ = Describe("Meta Elements", func() { - Context("element link", func() { + Context("Element link", func() { - It("element link", func() { + It("element link alone", func() { actualContent := "[link=http://foo.bar]" expectedDocument := &types.Document{ Elements: []types.DocElement{ diff --git a/parser/paragraph_test.go b/parser/paragraph_test.go index 3a03c9f3..614a6d97 100644 --- a/parser/paragraph_test.go +++ b/parser/paragraph_test.go @@ -5,7 +5,7 @@ import ( . "github.com/onsi/ginkgo" ) -var _ = Describe("Parsing Paragraphs", func() { +var _ = Describe("Paragraphs", func() { It("paragraph with 1 word", func() { actualContent := "hello" diff --git a/parser/quoted_text_test.go b/parser/quoted_text_test.go index 4b89dfb4..69f44969 100644 --- a/parser/quoted_text_test.go +++ b/parser/quoted_text_test.go @@ -5,7 +5,7 @@ import ( . "github.com/onsi/ginkgo" ) -var _ = Describe("Parsing Quoted Texts", func() { +var _ = Describe("Quoted Texts", func() { It("bold text of 1 word", func() { actualContent := "*hello*" diff --git a/parser/section_test.go b/parser/section_test.go index aebc0b8e..59f697f6 100644 --- a/parser/section_test.go +++ b/parser/section_test.go @@ -5,7 +5,7 @@ import ( . "github.com/onsi/ginkgo" ) -var _ = Describe("Parsing Sections", func() { +var _ = Describe("Sections", func() { Context("Valid document", func() { diff --git a/renderer/html5/image.go b/renderer/html5/image.go index addf3eb0..274bac0e 100644 --- a/renderer/html5/image.go +++ b/renderer/html5/image.go @@ -11,6 +11,7 @@ import ( ) var blockImageTmpl *template.Template +var inlineImageTmpl *template.Template // initializes the templates func init() { @@ -21,6 +22,7 @@ func init() {
{{.Title.Value}}
{{else}} {{end}}`) + inlineImageTmpl = newTemplate("inline image", `{{.Macro.Alt}}`) } func renderBlockImage(ctx context.Context, img types.BlockImage) ([]byte, error) { @@ -32,3 +34,13 @@ func renderBlockImage(ctx context.Context, img types.BlockImage) ([]byte, error) log.Debugf("rendered block image: %s", result.Bytes()) return result.Bytes(), nil } + +func renderInlineImage(ctx context.Context, img types.InlineImage) ([]byte, error) { + result := bytes.NewBuffer(make([]byte, 0)) + err := inlineImageTmpl.Execute(result, img) + if err != nil { + return nil, errors.Wrapf(err, "unable to render inline image") + } + log.Debugf("rendered inline image: %s", result.Bytes()) + return result.Bytes(), nil +} diff --git a/renderer/html5/image_test.go b/renderer/html5/image_test.go index 2a3d3bcf..420f614a 100644 --- a/renderer/html5/image_test.go +++ b/renderer/html5/image_test.go @@ -2,48 +2,99 @@ package html5_test import . "github.com/onsi/ginkgo" -var _ = Describe("Rendering Block Images", func() { - It("image alone", func() { - - content := "image::foo.png[]" - expected := `
-
-foo -
-
` - verify(GinkgoT(), expected, content) - }) - It("image with alt", func() { - - content := "image::foo.png[foo image]" - expected := `
-
-foo image -
-
` - verify(GinkgoT(), expected, content) - }) - It("image with alt and dimensions", func() { - - content := "image::foo.png[foo image, 600, 400]" - expected := `
-
-foo image -
-
` - verify(GinkgoT(), expected, content) +var _ = Describe("Rendering Images", func() { + Context("Block Images", func() { + + It("block image alone", func() { + + content := "image::foo.png[]" + expected := `
+
+ foo +
+
` + verify(GinkgoT(), expected, content) + }) + + It("block image with alt", func() { + + content := "image::foo.png[foo image]" + expected := `
+
+ foo image +
+
` + verify(GinkgoT(), expected, content) + }) + + It("block image with alt and dimensions", func() { + + content := "image::foo.png[foo image, 600, 400]" + expected := `
+
+ foo image +
+
` + verify(GinkgoT(), expected, content) + }) + + It("block image with alt and dimensions", func() { + content := "[#img-foobar]\n.A title to foobar\n[link=http://foo.bar]\nimage::images/foo.png[the foo.png image,600,400]" + expected := `
+
+ the foo.png image +
+
A title to foobar
+
` + verify(GinkgoT(), expected, content) + }) }) - It("image with alt and dimensions", func() { - content := `[#img-foobar] -.A title to foobar -[link=http://foo.bar] -image::images/foo.png[the foo.png image,600,400]` - expected := `
-
-the foo.png image -
-
A title to foobar
-
` - verify(GinkgoT(), expected, content) + + Context("Inline Images", func() { + Context("Valid Inline Images", func() { + + It("inline image alone", func() { + content := "image:foo.png[]" + expected := `
+

foo

+
` + verify(GinkgoT(), expected, content) + }) + + It("inline image with alt", func() { + content := "image:foo.png[foo image]" + expected := `
+

foo image

+
` + verify(GinkgoT(), expected, content) + }) + + It("inline image with alt and dimensions", func() { + content := "image:foo.png[foo image, 600, 400]" + expected := `
+

foo image

+
` + verify(GinkgoT(), expected, content) + }) + + It("paragraph with inline image with alt and dimensions", func() { + content := "a foo image:foo.png[foo image, 600, 400] bar" + expected := `
+

a foo foo image bar

+
` + verify(GinkgoT(), expected, content) + }) + }) + + Context("Invalid Inline Images", func() { + + It("paragraph with block image with alt and dimensions", func() { + content := "a foo image::foo.png[foo image, 600, 400] bar" + expected := `
+

a foo image::foo.png[foo image, 600, 400] bar

+
` + verify(GinkgoT(), expected, content) + }) + }) }) }) diff --git a/renderer/html5/renderer.go b/renderer/html5/renderer.go index 5ddd856f..445c7030 100644 --- a/renderer/html5/renderer.go +++ b/renderer/html5/renderer.go @@ -37,6 +37,8 @@ func renderElement(ctx context.Context, element types.DocElement) ([]byte, error return renderQuotedText(ctx, *element.(*types.QuotedText)) case *types.BlockImage: return renderBlockImage(ctx, *element.(*types.BlockImage)) + case *types.InlineImage: + return renderInlineImage(ctx, *element.(*types.InlineImage)) case *types.DelimitedBlock: return renderDelimitedBlock(ctx, *element.(*types.DelimitedBlock)) case *types.InlineContent: diff --git a/renderer/html5/renderer_test.go b/renderer/html5/renderer_test.go index 8c904fec..bf2101b6 100644 --- a/renderer/html5/renderer_test.go +++ b/renderer/html5/renderer_test.go @@ -14,6 +14,7 @@ import ( ) func verify(t GinkgoTInterface, expected, content string) { + expected = strings.Replace(expected, "\t", "", -1) t.Logf("processing '%s'", content) reader := strings.NewReader(content) doc, err := parser.ParseReader("", reader) @@ -27,7 +28,7 @@ func verify(t GinkgoTInterface, expected, content string) { require.Empty(t, err) result := string(buff.Bytes()) t.Logf("** Actual output:\n`%s`\n", result) - t.Logf("** Expected output:\n`%s`\n", expected) + t.Logf("** Expected output:\n`%s`\n", expected) // remove tabs that can be inserted by VSCode while formatting the tests code assert.Equal(t, expected, result) } diff --git a/types/types.go b/types/types.go index 05ae1096..1511ecde 100644 --- a/types/types.go +++ b/types/types.go @@ -464,7 +464,7 @@ func NewInlineContent(text []byte, elements []interface{}) (*InlineContent, erro mergedElements = append(mergedElements, e.(DocElement)) } result := &InlineContent{Elements: mergedElements} - log.Debugf("Initialized new InlineContent: '%s'", result.String(0)) + log.Debugf("Initialized new InlineContent with %d elements: '%s'", len(result.Elements), result.String(0)) return &InlineContent{Elements: mergedElements}, nil } @@ -511,14 +511,14 @@ func (c *InlineContent) Accept(v Visitor) error { // BlockImage the structure for the block images type BlockImage struct { - Macro BlockImageMacro + Macro ImageMacro ID *ElementID Title *ElementTitle Link *ElementLink } //NewBlockImage initializes a new `BlockImage` -func NewBlockImage(input []byte, imageMacro BlockImageMacro, metadata []interface{}) (*BlockImage, error) { +func NewBlockImage(input []byte, imageMacro ImageMacro, metadata []interface{}) (*BlockImage, error) { log.Debugf("Initializing a new BlockImage from '%s'", input) id, title, link := newMetaElements(metadata) return &BlockImage{ @@ -531,7 +531,7 @@ func NewBlockImage(input []byte, imageMacro BlockImageMacro, metadata []interfac //String implements the DocElement#String() method func (i *BlockImage) String(indentLevel int) string { - return fmt.Sprintf("%s<%v> %v", indent(indentLevel), reflect.TypeOf(i), i.Macro) + return fmt.Sprintf("%s<%v> %s", indent(indentLevel), reflect.TypeOf(i), i.Macro.String(0)) } func (i *BlockImage) elements() []Visitable { @@ -562,23 +562,62 @@ func (i *BlockImage) Accept(v Visitor) error { return nil } -// BlockImageMacro the structure for the block image macros -type BlockImageMacro struct { +// InlineImage the structure for the inline image macros +type InlineImage struct { + Macro ImageMacro +} + +//NewInlineImage initializes a new `InlineImage` (similar to BlockImage, but without Metadata) +func NewInlineImage(input []byte, imageMacro ImageMacro) (*InlineImage, error) { + log.Debugf("Initializing a new InlineImage from '%s'", input) + return &InlineImage{ + Macro: imageMacro, + }, nil +} + +//String implements the DocElement#String() method +func (i *InlineImage) String(indentLevel int) string { + return fmt.Sprintf("%s<%v> %s", indent(indentLevel), reflect.TypeOf(i), i.Macro.String(0)) +} + +//Accept implements DocElement#Accept(Visitor) +func (i *InlineImage) Accept(v Visitor) error { + err := v.BeforeVisit(i) + if err != nil { + return errors.Wrapf(err, "error while pre-visiting inline image") + } + err = v.Visit(i) + if err != nil { + return errors.Wrapf(err, "error while visiting inline image") + } + err = i.Macro.Accept(v) + if err != nil { + return errors.Wrapf(err, "error while visiting block image element") + } + err = v.AfterVisit(i) + if err != nil { + return errors.Wrapf(err, "error while post-visiting block image") + } + return nil +} + +// ImageMacro the structure for the block image macros +type ImageMacro struct { Path string Alt string Width *string Height *string } -//NewBlockImageMacro initializes a new `BlockImageMacro` -func NewBlockImageMacro(input []byte, path string, attributes *string) (*BlockImageMacro, error) { - log.Debugf("Initializing a new BlockImageMacro from '%s'", input) +//NewImageMacro initializes a new `ImageMacro` +func NewImageMacro(input []byte, path string, attributes interface{}) (*ImageMacro, error) { + log.Debugf("Initializing a new ImageMacro from '%s'", input) var alt string var width, height *string if attributes != nil { // optionally, the width and height can be specified in the alt text, using `,` as a separator // eg: `image::foo.png[a title,200,100]` - splittedAttributes := strings.Split(*attributes, ",") + splittedAttributes := strings.Split(attributes.(string), ",") // naively assume that if the splitted 'alt' contains more than 3 elements, the 2 last ones are for the width and height splitCount := len(splittedAttributes) alt = splittedAttributes[0] @@ -601,7 +640,7 @@ func NewBlockImageMacro(input []byte, path string, attributes *string) (*BlockIm } alt = path[offset : len(path)-len(extension)] } - return &BlockImageMacro{ + return &ImageMacro{ Path: path, Alt: alt, Width: width, @@ -609,7 +648,7 @@ func NewBlockImageMacro(input []byte, path string, attributes *string) (*BlockIm } //String implements the DocElement#String() method -func (m *BlockImageMacro) String(indentLevel int) string { +func (m *ImageMacro) String(indentLevel int) string { var width, height string if m.Width != nil { width = *m.Width @@ -617,11 +656,11 @@ func (m *BlockImageMacro) String(indentLevel int) string { if m.Height != nil { height = *m.Height } - return fmt.Sprintf("%s<%v> %s[%s,w=%s h=%s]", indent(indentLevel), reflect.TypeOf(m), m.Path, m.Alt, width, height) + return fmt.Sprintf("%s<%v> %s['%s', w='%s' h='%s']", indent(indentLevel), reflect.TypeOf(m), m.Path, m.Alt, width, height) } //Accept implements DocElement#Accept(Visitor) -func (m *BlockImageMacro) Accept(v Visitor) error { +func (m *ImageMacro) Accept(v Visitor) error { err := v.BeforeVisit(m) if err != nil { return errors.Wrapf(err, "error while pre-visiting block image macro") @@ -832,7 +871,7 @@ func NewStringElement(content interface{}) *StringElement { //String implements the DocElement#String() method func (s *StringElement) String(indentLevel int) string { - return fmt.Sprintf("%s%s", indent(indentLevel), s.Content) + return fmt.Sprintf("%s`%s`", indent(indentLevel), s.Content) } //Accept implements DocElement#Accept(Visitor)