From c984790d3d72773d3fca5baf7402809331d91c9f Mon Sep 17 00:00:00 2001 From: bouncepaw Date: Thu, 26 Nov 2020 23:41:26 +0500 Subject: [PATCH] Reimplement images --- hypha.go | 3 +- main.go | 2 +- markup/img.go | 280 +++++++++++++++++++++++++++++------------- markup/lexer.go | 16 ++- markup/parser.go | 2 + metarrhiza | 2 +- templates/css.qtpl | 5 +- templates/css.qtpl.go | 31 ++--- 8 files changed, 236 insertions(+), 105 deletions(-) diff --git a/hypha.go b/hypha.go index 0e6e583..e412c14 100644 --- a/hypha.go +++ b/hypha.go @@ -32,6 +32,7 @@ func init() { } return } + markup.HyphaIterate = IterateHyphaNamesWith } // GetHyphaData finds a hypha addressed by `hyphaName` and returns its `hyphaData`. `hyphaData` is set to a zero value if this hypha does not exist. `isOld` is false if this hypha does not exist. @@ -190,7 +191,7 @@ func binaryHtmlBlock(hyphaName string, hd *HyphaData) string { case ".jpg", ".gif", ".png", ".webp", ".svg", ".ico": return fmt.Sprintf(`
- +
`, hyphaName) case ".ogg", ".webm", ".mp4": return fmt.Sprintf(` diff --git a/main.go b/main.go index aa29c7f..51d7610 100644 --- a/main.go +++ b/main.go @@ -23,7 +23,7 @@ import ( var WikiDir string // HyphaPattern is a pattern which all hyphae must match. -var HyphaPattern = regexp.MustCompile(`[^?!:#@><*|"\'&%]+`) +var HyphaPattern = regexp.MustCompile(`[^?!:#@><*|"\'&%{}]+`) // HyphaStorage is a mapping between canonical hypha names and their meta information. var HyphaStorage = make(map[string]*HyphaData) diff --git a/markup/img.go b/markup/img.go index 244451b..6445ed1 100644 --- a/markup/img.go +++ b/markup/img.go @@ -13,53 +13,169 @@ func MatchesImg(line string) bool { } type imgEntry struct { - path string - sizeH string - sizeV string - desc string + trimmedPath string + path strings.Builder + sizeW strings.Builder + sizeH strings.Builder + desc strings.Builder } +func (entry *imgEntry) descriptionAsHtml(hyphaName string) (html string) { + if entry.desc.Len() == 0 { + return "" + } + lines := strings.Split(entry.desc.String(), "\n") + for _, line := range lines { + if line = strings.TrimSpace(line); line != "" { + if html != "" { + html += `
` + } + html += ParagraphToHtml(hyphaName, line) + } + } + return `
` + html + `
` +} + +func (entry *imgEntry) sizeWAsAttr() string { + if entry.sizeW.Len() == 0 { + return "" + } + return ` width="` + entry.sizeW.String() + `"` +} + +func (entry *imgEntry) sizeHAsAttr() string { + if entry.sizeH.Len() == 0 { + return "" + } + return ` height="` + entry.sizeH.String() + `"` +} + +type imgState int + +const ( + inRoot imgState = iota + inName + inDimensionsW + inDimensionsH + inDescription +) + type Img struct { entries []imgEntry - inDesc bool + currEntry imgEntry hyphaName string + state imgState +} + +func (img *Img) pushEntry() { + if strings.TrimSpace(img.currEntry.path.String()) != "" { + img.entries = append(img.entries, img.currEntry) + img.currEntry = imgEntry{} + img.currEntry.path.Reset() + } } 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 { + stateToProcessor := map[imgState]func(rune) bool{ + inRoot: img.processInRoot, + inName: img.processInName, + inDimensionsW: img.processInDimensionsW, + inDimensionsH: img.processInDimensionsH, + inDescription: img.processInDescription, + } + for _, r := range line { + if shouldReturnTrue := stateToProcessor[img.state](r); shouldReturnTrue { 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{ +func (img *Img) processInDescription(r rune) (shouldReturnTrue bool) { + switch r { + case '}': + img.state = inName + default: + img.currEntry.desc.WriteRune(r) + } + return false +} + +func (img *Img) processInRoot(r rune) (shouldReturnTrue bool) { + switch r { + case '}': + img.pushEntry() + return true + case '\n', '\r': + img.pushEntry() + case ' ', '\t': + default: + img.state = inName + img.currEntry = imgEntry{} + img.currEntry.path.Reset() + img.currEntry.path.WriteRune(r) + } + return false +} + +func (img *Img) processInName(r rune) (shouldReturnTrue bool) { + switch r { + case '}': + img.pushEntry() + return true + case '|': + img.state = inDimensionsW + case '{': + img.state = inDescription + case '\n', '\r': + img.pushEntry() + img.state = inRoot + default: + img.currEntry.path.WriteRune(r) + } + return false +} + +func (img *Img) processInDimensionsW(r rune) (shouldReturnTrue bool) { + switch r { + case '}': + img.pushEntry() + return true + case '*': + img.state = inDimensionsH + case ' ', '\t', '\n': + case '{': + img.state = inDescription + default: + img.currEntry.sizeW.WriteRune(r) + } + return false +} + +func (img *Img) processInDimensionsH(r rune) (shouldGoBackToNormal bool) { + switch r { + case '}': + img.pushEntry() + return true + case ' ', '\t', '\n': + case '{': + img.state = inDescription + default: + img.currEntry.sizeH.WriteRune(r) + } + return false +} + +func ImgFromFirstLine(line, hyphaName string) (img *Img, shouldGoBackToNormal bool) { + 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 + line = line[strings.IndexRune(line, '{')+1:] + return img, img.Process(line) } -func (img *Img) canonicalPathFor(path string) string { +func (img *Img) binaryPathFor(path string) string { path = strings.TrimSpace(path) if strings.IndexRune(path, ':') != -1 || strings.IndexRune(path, '/') == 0 { return path @@ -68,73 +184,71 @@ func (img *Img) canonicalPathFor(path string) string { } } -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) +func (img *Img) pagePathFor(path string) string { + path = strings.TrimSpace(path) + if strings.IndexRune(path, ':') != -1 || strings.IndexRune(path, '/') == 0 { + return path } 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] - } + return "/page/" + xclCanonicalName(img.hyphaName, path) } - img.entries = append(img.entries, entry) - return } -func parseDimensions(dimensions string) (sizeH, sizeV string) { +func parseDimensions(dimensions string) (sizeW, sizeH string) { xIndex := strings.IndexRune(dimensions, '*') if xIndex == -1 { // If no x in dimensions - sizeH = strings.TrimSpace(dimensions) + sizeW = strings.TrimSpace(dimensions) } else { - sizeH = strings.TrimSpace(dimensions[:xIndex]) - sizeV = strings.TrimSpace(strings.TrimPrefix(dimensions, dimensions[:xIndex+1])) + sizeW = strings.TrimSpace(dimensions[:xIndex]) + sizeH = strings.TrimSpace(strings.TrimPrefix(dimensions, dimensions[:xIndex+1])) } return } -func (img Img) ToHtml() (html string) { - for _, entry := range img.entries { - html += fmt.Sprintf(`
- -`, entry.path, entry.sizeH, entry.sizeV) - if entry.desc != "" { - html += `
` - for i, line := range strings.Split(entry.desc, "\n") { - if line != "" { - if i > 0 { - html += `
` - } - html += ParagraphToHtml(img.hyphaName, line) - } - } - html += `
` +func (img *Img) checkLinks() map[string]bool { + m := make(map[string]bool) + for i, entry := range img.entries { + // Also trim them for later use + entry.trimmedPath = strings.TrimSpace(entry.path.String()) + isAbsoluteUrl := strings.ContainsRune(entry.trimmedPath, ':') + if !isAbsoluteUrl { + entry.trimmedPath = canonicalName(entry.trimmedPath) } + img.entries[i] = entry + m[entry.trimmedPath] = isAbsoluteUrl + } + HyphaIterate(func(hyphaName string) { + for _, entry := range img.entries { + if hyphaName == entry.trimmedPath { + m[entry.trimmedPath] = true + } + } + }) + return m +} + +func (img *Img) ToHtml() (html string) { + linkAvailabilityMap := img.checkLinks() + isOneImageOnly := len(img.entries) == 1 && img.entries[0].desc.Len() == 0 + if isOneImageOnly { + html += `