aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--_doc/SPECS.adoc12
-rw-r--r--element.go94
-rw-r--r--element_image.go163
-rw-r--r--element_image_test.go38
-rw-r--r--html_backend.go41
-rw-r--r--inline_parser.go30
-rw-r--r--testdata/element_image_test.txt35
7 files changed, 246 insertions, 167 deletions
diff --git a/_doc/SPECS.adoc b/_doc/SPECS.adoc
index 20567ee..55e2615 100644
--- a/_doc/SPECS.adoc
+++ b/_doc/SPECS.adoc
@@ -346,12 +346,13 @@ ABSOLUTE_PATH = "/" WORD *( "/" WORD )
RELATIVE_PATH = ( "." / ".." ) "/" WORD * ( "/" WORD )
----
+
== Images
-=== Inline image
+=== Block image
----
-IMAGE_INLINE = "image:" URL "[" (IMAGE_ATTRS) "]"
+BLOCK_IMAGE = "image::" URL "[" IMAGE_ATTRS "]"
IMAGE_ATTRS = TEXT ("," IMAGE_WIDTH ("," IMAGE_HEIGHT)) *("," IMAGE_OPTS)
@@ -360,6 +361,13 @@ IMAGE_OPTS = IMAGE_OPT_KEY "=" 1*VCHAR
IMAGE_OPT_KEY = "title" / "float" / "align" / "role" / "link"
----
+=== Inline image
+
+----
+IMAGE_INLINE = "image:" URL "[" (IMAGE_ATTRS) "]"
+----
+
+
== Video
----
diff --git a/element.go b/element.go
index 498524c..9f77633 100644
--- a/element.go
+++ b/element.go
@@ -301,100 +301,6 @@ func (el *element) parseBlockAudio(doc *Document, line []byte) bool {
return true
}
-// parseBlockImage parse the image block or line.
-// The line parameter must not have "image::" block or "image:" macro prefix.
-func (el *element) parseBlockImage(doc *Document, line []byte) bool {
- var (
- attrBegin = bytes.IndexByte(line, '[')
-
- attr string
- key string
- val string
- kv []string
-
- attrs [][]byte
- src []byte
- battr []byte
- alt []byte
-
- attrEnd int
- dot int
- x int
- )
-
- if attrBegin < 0 {
- return false
- }
- attrEnd = bytes.IndexByte(line, ']')
- if attrEnd < 0 {
- return false
- }
-
- src = bytes.TrimRight(line[:attrBegin], " \t")
-
- if el.Attrs == nil {
- el.Attrs = make(map[string]string)
- }
- src = applySubstitutions(doc, src)
- el.Attrs[attrNameSrc] = string(src)
-
- attrs = bytes.Split(line[attrBegin+1:attrEnd], []byte(`,`))
- if el.Attrs == nil {
- el.Attrs = make(map[string]string)
- }
- var hasWidth bool
- for x, battr = range attrs {
- attr = string(battr)
- if x == 0 {
- alt = bytes.TrimSpace(attrs[0])
- if len(alt) == 0 {
- dot = bytes.IndexByte(src, '.')
- if dot > 0 {
- alt = src[:dot]
- }
- }
- el.Attrs[attrNameAlt] = string(alt)
- continue
- }
- if x == 1 {
- if ascii.IsDigits(attrs[1]) {
- el.Attrs[attrNameWidth] = string(attrs[1])
- hasWidth = true
- continue
- }
- }
- if hasWidth && x == 2 {
- if ascii.IsDigits(attrs[2]) {
- el.Attrs[attrNameHeight] = string(attrs[2])
- }
- }
- kv = strings.SplitN(attr, `=`, 2)
- if len(kv) != 2 {
- continue
- }
- key = strings.TrimSpace(kv[0])
- val = strings.Trim(kv[1], `"`)
- switch key {
- case attrNameFloat, attrNameAlign, attrNameRole:
- if val == `center` {
- val = `text-center`
- }
- el.addRole(val)
- default:
- el.Attrs[key] = val
- }
- }
-
- for key, val = range el.Attrs {
- if key == attrNameLink {
- val = string(applySubstitutions(doc, []byte(val)))
- el.Attrs[key] = val
- }
- }
-
- return true
-}
-
func (el *element) parseInlineMarkup(doc *Document, kind int) {
if len(el.raw) == 0 {
return
diff --git a/element_image.go b/element_image.go
new file mode 100644
index 0000000..d98bb61
--- /dev/null
+++ b/element_image.go
@@ -0,0 +1,163 @@
+// SPDX-FileCopyrightText: 2024 M. Shulhan <ms@kilabit.info>
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package asciidoctor
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "strings"
+
+ "git.sr.ht/~shulhan/pakakeh.go/lib/ascii"
+)
+
+// parseBlockImage parse the image block or line.
+// The line parameter must not contains the "image::" block or "image:"
+// macro prefix.
+func (el *element) parseBlockImage(doc *Document, line []byte) bool {
+ var attrBegin = bytes.IndexByte(line, '[')
+ if attrBegin < 0 {
+ return false
+ }
+ var attrEnd = bytes.IndexByte(line, ']')
+ if attrEnd < 0 {
+ return false
+ }
+
+ var link = bytes.TrimRight(line[:attrBegin], " \t")
+ link = applySubstitutions(doc, link)
+
+ if el.Attrs == nil {
+ el.Attrs = make(map[string]string)
+ }
+ el.Attrs[attrNameSrc] = string(link)
+
+ var listAttribute = bytes.Split(line[attrBegin+1:attrEnd], []byte(`,`))
+ if el.Attrs == nil {
+ el.Attrs = make(map[string]string)
+ }
+
+ var (
+ x int
+ battr []byte
+ hasWidth bool
+ )
+ for x, battr = range listAttribute {
+ if x == 0 {
+ var alt = bytes.TrimSpace(listAttribute[0])
+ if len(alt) == 0 {
+ var dot = bytes.IndexByte(link, '.')
+ if dot > 0 {
+ alt = link[:dot]
+ }
+ }
+ el.Attrs[attrNameAlt] = string(alt)
+ continue
+ }
+ if x == 1 {
+ if ascii.IsDigits(listAttribute[1]) {
+ el.Attrs[attrNameWidth] = string(listAttribute[1])
+ hasWidth = true
+ continue
+ }
+ }
+ if hasWidth && x == 2 {
+ if ascii.IsDigits(listAttribute[2]) {
+ el.Attrs[attrNameHeight] = string(listAttribute[2])
+ }
+ }
+
+ var attr = string(battr)
+ var kv = strings.SplitN(attr, `=`, 2)
+ if len(kv) != 2 {
+ continue
+ }
+ var key = strings.TrimSpace(kv[0])
+ var val = strings.Trim(kv[1], `"`)
+
+ switch key {
+ case attrNameFloat, attrNameAlign, attrNameRole:
+ if val == `center` {
+ val = `text-center`
+ }
+ el.addRole(val)
+
+ case attrNameLink:
+ val = string(applySubstitutions(doc, []byte(val)))
+ el.Attrs[key] = val
+
+ default:
+ el.Attrs[key] = val
+ }
+ }
+ return true
+}
+
+func parseInlineImage(doc *Document, content []byte) (el *element, n int) {
+ // If the next character is ':' (as in block "image::") mark it as
+ // invalid inline image, since this is block image that has been
+ // parsed but invalid (probably missing '[]').
+ if content[0] == ':' {
+ return nil, 0
+ }
+
+ _, n = indexByteUnescape(content, ']')
+ if n < 0 {
+ return nil, 0
+ }
+
+ var lineImage = content[:n+1]
+ el = &element{
+ elementAttribute: elementAttribute{
+ Attrs: make(map[string]string),
+ },
+ kind: elKindInlineImage,
+ }
+ if el.parseBlockImage(doc, lineImage) {
+ return el, n + 2
+ }
+ return nil, 0
+}
+
+func htmlWriteInlineImage(el *element, out io.Writer) {
+ var (
+ classes = strings.TrimSpace(`image ` + el.htmlClasses())
+
+ link string
+ withLink bool
+ )
+
+ fmt.Fprintf(out, `<span class=%q>`, classes)
+ link, withLink = el.Attrs[attrNameLink]
+ if withLink {
+ fmt.Fprintf(out, `<a class=%q href=%q>`, attrValueImage, link)
+ }
+
+ var (
+ src = el.Attrs[attrNameSrc]
+ alt = el.Attrs[attrNameAlt]
+
+ width string
+ height string
+ ok bool
+ )
+
+ width, ok = el.Attrs[attrNameWidth]
+ if ok {
+ width = fmt.Sprintf(` width="%s"`, width)
+ }
+ height, ok = el.Attrs[attrNameHeight]
+ if ok {
+ height = fmt.Sprintf(` height="%s"`, height)
+ }
+
+ fmt.Fprintf(out, `<img src=%q alt=%q%s%s>`, src, alt, width, height)
+
+ if withLink {
+ fmt.Fprint(out, `</a>`)
+ }
+
+ fmt.Fprint(out, `</span>`)
+}
diff --git a/element_image_test.go b/element_image_test.go
new file mode 100644
index 0000000..a548501
--- /dev/null
+++ b/element_image_test.go
@@ -0,0 +1,38 @@
+// SPDX-FileCopyrightText: 2024 M. Shulhan <ms@kilabit.info>
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package asciidoctor
+
+import (
+ "bytes"
+ "testing"
+
+ "git.sr.ht/~shulhan/pakakeh.go/lib/test"
+)
+
+func TestElementParseBlockImage(t *testing.T) {
+ var (
+ tdata *test.Data
+ err error
+ )
+ tdata, err = test.LoadData(`testdata/element_image_test.txt`)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var (
+ caseName string
+ input []byte
+ got bytes.Buffer
+ )
+ for caseName, input = range tdata.Input {
+ var doc = Parse(input)
+
+ got.Reset()
+ doc.ToHTMLEmbedded(&got)
+
+ var exp = string(tdata.Output[caseName])
+ test.Assert(t, caseName, exp, got.String())
+ }
+}
diff --git a/html_backend.go b/html_backend.go
index b404ba7..14137e5 100644
--- a/html_backend.go
+++ b/html_backend.go
@@ -1063,47 +1063,6 @@ func htmlWriteHeader(doc *Document, out io.Writer) {
fmt.Fprint(out, "\n</div>")
}
-func htmlWriteInlineImage(el *element, out io.Writer) {
- var (
- classes = strings.TrimSpace(`image ` + el.htmlClasses())
-
- link string
- withLink bool
- )
-
- fmt.Fprintf(out, `<span class=%q>`, classes)
- link, withLink = el.Attrs[attrNameLink]
- if withLink {
- fmt.Fprintf(out, `<a class=%q href=%q>`, attrValueImage, link)
- }
-
- var (
- src = el.Attrs[attrNameSrc]
- alt = el.Attrs[attrNameAlt]
-
- width string
- height string
- ok bool
- )
-
- width, ok = el.Attrs[attrNameWidth]
- if ok {
- width = fmt.Sprintf(` width="%s"`, width)
- }
- height, ok = el.Attrs[attrNameHeight]
- if ok {
- height = fmt.Sprintf(` height="%s"`, height)
- }
-
- fmt.Fprintf(out, `<img src=%q alt=%q%s%s>`, src, alt, width, height)
-
- if withLink {
- fmt.Fprint(out, `</a>`)
- }
-
- fmt.Fprint(out, `</span>`)
-}
-
func htmlWriteInlinePass(doc *Document, el *element, out io.Writer) {
var text = htmlSubs(doc, el)
diff --git a/inline_parser.go b/inline_parser.go
index 2f18aaf..561cab7 100644
--- a/inline_parser.go
+++ b/inline_parser.go
@@ -694,36 +694,6 @@ func (pi *inlineParser) parseFormatUnconstrained(
return false
}
-func parseInlineImage(doc *Document, content []byte) (elImage *element, n int) {
- var (
- lineImage []byte
- )
-
- // If the next character is ':' (as in block "image::") mark it as
- // invalid inline image, since this is block image that has been
- // parsed but invalid (probably missing '[]').
- if content[0] == ':' {
- return nil, 0
- }
-
- _, n = indexByteUnescape(content, ']')
- if n < 0 {
- return nil, 0
- }
-
- lineImage = content[:n+1]
- elImage = &element{
- elementAttribute: elementAttribute{
- Attrs: make(map[string]string),
- },
- kind: elKindInlineImage,
- }
- if elImage.parseBlockImage(doc, lineImage) {
- return elImage, n + 2
- }
- return nil, 0
-}
-
func (pi *inlineParser) parseMacro() bool {
var (
el *element
diff --git a/testdata/element_image_test.txt b/testdata/element_image_test.txt
new file mode 100644
index 0000000..ae15cbb
--- /dev/null
+++ b/testdata/element_image_test.txt
@@ -0,0 +1,35 @@
+>>> empty_block_image
+
+image::[]
+
+<<< empty_block_image
+
+<div class="imageblock">
+<div class="content">
+<img src="" alt="">
+</div>
+</div>
+
+>>> with_absolute_path
+
+image::/absolute/path.png[Image alt text]
+
+<<< with_absolute_path
+
+<div class="imageblock">
+<div class="content">
+<img src="/absolute/path.png" alt="Image alt text">
+</div>
+</div>
+
+>>> with_attr_link
+
+image::/image/path.png[Image alt text,link="{dummy}/link"]
+
+<<< with_attr_link
+
+<div class="imageblock">
+<div class="content">
+<img src="/image/path.png" alt="Image alt text">
+</div>
+</div>