Skip to content

Commit

Permalink
Add img tag
Browse files Browse the repository at this point in the history
  • Loading branch information
bouncepaw committed Nov 3, 2020
1 parent 9ad22b5 commit 3620c6e
Show file tree
Hide file tree
Showing 10 changed files with 250 additions and 19 deletions.
140 changes: 140 additions & 0 deletions markup/img.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package markup

import (
"fmt"
"regexp"
"strings"
)

var imgRe = regexp.MustCompile(`^img\s+{`)

func MatchesImg(line string) bool {
return imgRe.MatchString(line)
}

type imgEntry struct {
path string
sizeH string
sizeV string
desc string
}

type Img struct {
entries []imgEntry
inDesc bool
hyphaName string
}

func (img *Img) Process(line string) (shouldGoBackToNormal bool) {
if img.inDesc {
rightBraceIndex := strings.IndexRune(line, '}')
if cnt := len(img.entries); rightBraceIndex == -1 && cnt != 0 {
img.entries[cnt-1].desc += "\n" + line
} else if rightBraceIndex != -1 && cnt != 0 {
img.entries[cnt-1].desc += "\n" + line[:rightBraceIndex]
img.inDesc = false
}
if strings.Count(line, "}") > 1 {
return true
}
} else if s := strings.TrimSpace(line); s != "" {
if s[0] == '}' {
return true
}
img.parseStartOfEntry(line)
}
return false
}

func ImgFromFirstLine(line, hyphaName string) Img {
img := Img{
hyphaName: hyphaName,
entries: make([]imgEntry, 0),
}
line = line[strings.IndexRune(line, '{'):]
if len(line) == 1 { // if { only
} else {
line = line[1:] // Drop the {
}
return img
}

func (img *Img) canonicalPathFor(path string) string {
path = strings.TrimSpace(path)
if strings.IndexRune(path, ':') != -1 || strings.IndexRune(path, '/') == 0 {
return path
} else {
return "/binary/" + xclCanonicalName(img.hyphaName, path)
}
}

func (img *Img) parseStartOfEntry(line string) (entry imgEntry, followedByDesc bool) {
pipeIndex := strings.IndexRune(line, '|')
if pipeIndex == -1 { // If no : in string
entry.path = img.canonicalPathFor(line)
} else {
entry.path = img.canonicalPathFor(line[:pipeIndex])
line = strings.TrimPrefix(line, line[:pipeIndex+1])

var (
leftBraceIndex = strings.IndexRune(line, '{')
rightBraceIndex = strings.IndexRune(line, '}')
dimensions string
)

if leftBraceIndex == -1 {
dimensions = line
} else {
dimensions = line[:leftBraceIndex]
}

sizeH, sizeV := parseDimensions(dimensions)
entry.sizeH = sizeH
entry.sizeV = sizeV

if leftBraceIndex != -1 && rightBraceIndex == -1 {
img.inDesc = true
followedByDesc = true
entry.desc = strings.TrimPrefix(line, line[:leftBraceIndex+1])
} else if leftBraceIndex != -1 && rightBraceIndex != -1 {
entry.desc = line[leftBraceIndex+1 : rightBraceIndex]
}
}
img.entries = append(img.entries, entry)
return
}

func parseDimensions(dimensions string) (sizeH, sizeV string) {
xIndex := strings.IndexRune(dimensions, '*')
if xIndex == -1 { // If no x in dimensions
sizeH = strings.TrimSpace(dimensions)
} else {
sizeH = strings.TrimSpace(dimensions[:xIndex])
sizeV = strings.TrimSpace(strings.TrimPrefix(dimensions, dimensions[:xIndex+1]))
}
return
}

func (img Img) ToHtml() (html string) {
for _, entry := range img.entries {
html += fmt.Sprintf(`<figure>
<img src="%s" width="%s" height="%s">
`, entry.path, entry.sizeH, entry.sizeV)
if entry.desc != "" {
html += ` <figcaption>`
for i, line := range strings.Split(entry.desc, "\n") {
if line != "" {
if i > 0 {
html += `<br>`
}
html += ParagraphToHtml(line)
}
}
html += `</figcaption>`
}
html += `</figure>`
}
return `<section class="img-gallery">
` + html + `
</section>`
}
47 changes: 47 additions & 0 deletions markup/img_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package markup

import (
"fmt"
"testing"
)

func TestParseStartOfEntry(t *testing.T) {
img := ImgFromFirstLine("img {", "h")
tests := []struct {
line string
entry imgEntry
followedByDesc bool
}{
{"apple", imgEntry{"apple", "", "", ""}, false},
{"pear:", imgEntry{"pear", "", "", ""}, false},
{"яблоко: 30*60", imgEntry{"яблоко", "30", "60", ""}, false},
{"груша : 65 ", imgEntry{"груша", "65", "", ""}, false},
{"жеронимо : 30 { full desc }", imgEntry{"жеронимо", "30", "", " full desc "}, false},
{"жорно жованна : *5555 {partial description", imgEntry{"жорно_жованна", "", "5555", "partial description"}, true},
{"иноске : {full}", imgEntry{"иноске", "", "", "full"}, false},
{"j:{partial", imgEntry{"j", "", "", "partial"}, true},
}
for _, triplet := range tests {
entry, followedByDesc := img.parseStartOfEntry(triplet.line)
if entry != triplet.entry || followedByDesc != triplet.followedByDesc {
t.Error(fmt.Sprintf("%q:%q != %q; %v != %v", triplet.line, entry, triplet.entry, followedByDesc, triplet.followedByDesc))
}
}
}

func TestParseDimensions(t *testing.T) {
tests := [][]string{
{"500", "500", ""},
{"3em", "3em", ""},
{"500*", "500", ""},
{"*500", "", "500"},
{"800*520", "800", "520"},
{"17%*5rem", "17%", "5rem"},
}
for _, triplet := range tests {
sizeH, sizeV := parseDimensions(triplet[0])
if sizeH != triplet[1] || sizeV != triplet[2] {
t.Error(sizeH, "*", sizeV, " != ", triplet[1], "*", triplet[2])
}
}
}
14 changes: 14 additions & 0 deletions markup/lexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ type GemLexerState struct {
// Line id
id int
buf string
// Temporaries
img Img
}

type Line struct {
Expand Down Expand Up @@ -99,6 +101,8 @@ func geminiLineToAST(line string, state *GemLexerState, ast *[]Line) {

// Beware! Usage of goto. Some may say it is considered evil but in this case it helped to make a better-structured code.
switch state.where {
case "img":
goto imgState
case "pre":
goto preformattedState
case "list":
Expand All @@ -107,6 +111,13 @@ func geminiLineToAST(line string, state *GemLexerState, ast *[]Line) {
goto normalState
}

imgState:
if shouldGoBackToNormal := state.img.Process(line); shouldGoBackToNormal {
state.where = ""
addLine(state.img)
}
return

preformattedState:
switch {
case startsWith("```"):
Expand Down Expand Up @@ -178,6 +189,9 @@ normalState:
addLine(parseTransclusion(line, state.name))
case line == "----":
*ast = append(*ast, Line{id: -1, contents: "<hr/>"})
case MatchesImg(line):
state.where = "img"
state.img = ImgFromFirstLine(line, state.name)
default:
addLine(fmt.Sprintf("<p id='%d'>%s</p>", state.id, ParagraphToHtml(line)))
}
Expand Down
18 changes: 14 additions & 4 deletions markup/lexer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ func TestLex(t *testing.T) {
return
}
for i, e := range ast {
if e != expectedAst[i] {
t.Error("Mismatch when lexing", name, "\nExpected:", expectedAst[i], "\nGot:", e)
if !reflect.DeepEqual(e, expectedAst[i]) {
t.Error(fmt.Sprintf("Expected: %q\nGot:%q", expectedAst[i], e))
}
}
}
Expand All @@ -43,15 +43,25 @@ func TestLex(t *testing.T) {
{7, "<p id='7'>more text</p>"},
{8, `<p><a id='8' class='wikilink_internal' href="/page/Pear">some link</a></p>`},
{9, `<ul id='9'>
<li>li\n"+</li>
<li>lin&#34;+</li>
</ul>`},
{10, `<pre id='10' alt='alt text goes here' class='codeblock'><code>=&gt; preformatted text
where markup is not lexed</code></pre>`},
{11, `<p><a id='11' class='wikilink_internal' href="/page/linking">linking</a></p>`},
{12, "<p id='12'>text</p>"},
{13, `<pre id='13' alt='' class='codeblock'><code>()
/\</code></pre>`},
// More thorough testing of xclusions is done in xclusion_test.go
{14, Transclusion{"apple", 1, 3}},
{15, Img{
hyphaName: "Apple",
inDesc: false,
entries: []imgEntry{
{"hypha1", "", "", ""},
{"hypha2", "", "", ""},
{"hypha3", "60", "", ""},
{"hypha4", "", "", " line1\nline2\n"},
{"hypha5", "", "", "\nstate of minnesota\n"},
},
}},
})
}
2 changes: 1 addition & 1 deletion markup/paragraph_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func TestParagraphToHtml(t *testing.T) {
{"Embedded //italic//", "Embedded <em>italic</em>"},
{"double //italian// //text//", "double <em>italian</em> <em>text</em>"},
{"it has `mono`", "it has <code>mono</code>"},
{"this is a left **bold", "this is a left <strong>bold"},
{"this is a left **bold", "this is a left <strong>bold</strong>"},
{"this line has a ,comma, two of them", "this line has a ,comma, two of them"},
{"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."},
}
Expand Down
2 changes: 2 additions & 0 deletions markup/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ func Parse(ast []Line, from, to int, state GemParserState) (html string) {
switch v := line.contents.(type) {
case Transclusion:
html += Transclude(v, state)
case Img:
html += v.ToHtml()
case string:
html += v
}
Expand Down
14 changes: 14 additions & 0 deletions markup/testdata/test.myco
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,17 @@ text
/\
```
<= Apple : 1..3

img {
hypha1
hypha2:
hypha3: 60
hypha4: { line1
line2
} this is ignored

hypha5: {
state of minnesota
}
}

2 changes: 1 addition & 1 deletion metarrhiza
Submodule metarrhiza updated 1 files
+28 −1 mycomarkup.myco
2 changes: 2 additions & 0 deletions templates/css.qtpl
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ p code {background-color:#eee; padding: .1rem .3rem; border-radius: .25rem; font
.binary-container_with-video video,
.binary-container_with-audio audio {width: 100%}
.navi-title a {text-decoration:none;}
.img-gallery img { max-width: 100%; }
figure { margin: 0; }

nav ul {display:flex; padding-left:0; flex-wrap:wrap; margin-top:0;}
nav ul li {list-style-type:none;margin-right:1rem;}
Expand Down
28 changes: 15 additions & 13 deletions templates/css.qtpl.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 3620c6e

Please sign in to comment.