wiki/util.go

196 lines
4.7 KiB
Go
Raw Normal View History

2021-08-07 17:13:10 +00:00
/*
* Wiki - A wiki with editor
* Copyright (c) 2021 Peter Stuifzand
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
2018-11-24 12:34:51 +00:00
package main
import (
2020-05-16 20:15:36 +00:00
"bufio"
"encoding/json"
2021-01-17 20:31:26 +00:00
"errors"
2020-07-19 13:18:03 +00:00
"fmt"
"log"
2018-11-24 12:34:51 +00:00
"math/rand"
2020-05-07 13:20:36 +00:00
"regexp"
2021-01-17 20:31:26 +00:00
"strconv"
2020-05-07 13:20:36 +00:00
"strings"
2019-02-25 19:09:52 +00:00
"time"
2018-11-24 12:34:51 +00:00
)
var (
2021-01-17 20:31:26 +00:00
MetaKV = regexp.MustCompile(`(\w+)::\s+(.*)`)
niceDateParseRE = regexp.MustCompile(`^(\d{1,2})_([a-z]+)_(\d{4})$`)
ParseFailed = errors.New("parse failed")
Months = []string{
"",
"januari",
"februari",
"maart",
"april",
"mei",
"juni",
"juli",
"augustus",
"september",
"oktober",
"november",
"december",
}
)
2020-05-07 13:20:36 +00:00
type ParsedLink struct {
2020-07-01 14:40:10 +00:00
ID string `json:"ID"`
2020-08-31 09:50:03 +00:00
Name string `json:"title"`
PageName string `json:"name"`
Line string `json:"line"`
Href string `json:"href"`
2020-05-07 13:20:36 +00:00
}
2018-11-24 12:34:51 +00:00
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
func RandStringBytes(n int) string {
b := make([]byte, n)
for i := range b {
b[i] = letterBytes[rand.Intn(len(letterBytes))]
}
return string(b)
}
2020-05-07 13:20:36 +00:00
func ParseLinks(blockId string, content string) ([]ParsedLink, error) {
2020-05-16 20:15:36 +00:00
hrefRE := regexp.MustCompile(`(#?\[\[\s*([^\]]+)\s*\]\])`)
2020-10-07 08:16:13 +00:00
keywordsRE := regexp.MustCompile(`(\w+)::`)
2020-05-07 13:20:36 +00:00
2020-05-16 20:15:36 +00:00
scanner := bufio.NewScanner(strings.NewReader(content))
scanner.Split(bufio.ScanLines)
2020-05-07 13:20:36 +00:00
var result []ParsedLink
2020-05-16 20:15:36 +00:00
for scanner.Scan() {
line := scanner.Text()
2020-05-07 13:20:36 +00:00
2021-08-08 21:44:02 +00:00
keywords := keywordsRE.FindAllStringSubmatch(line, -1)
for _, matches := range keywords {
link := matches[1]
l := cleanNameURL(link)
result = append(result, ParsedLink{blockId, link, l, line, ""})
}
2020-05-16 20:15:36 +00:00
links := hrefRE.FindAllStringSubmatch(line, -1)
for _, matches := range links {
link := matches[0]
2020-05-07 13:20:36 +00:00
2020-05-16 20:15:36 +00:00
if link[0] == '#' {
link = strings.TrimPrefix(link, "#[[")
} else {
link = strings.TrimPrefix(link, "[[")
}
link = strings.TrimSuffix(link, "]]")
link = strings.TrimSpace(link)
l := cleanNameURL(link)
2020-08-31 09:50:03 +00:00
result = append(result, ParsedLink{blockId, link, l, line, ""})
2020-05-16 20:15:36 +00:00
}
2020-05-07 13:20:36 +00:00
}
return result, nil
}
2020-05-13 20:36:03 +00:00
func cleanNameURL(name string) string {
return strings.Replace(name, " ", "_", -1)
}
func cleanTitle(name string) string {
return strings.Replace(name, "_", " ", -1)
}
type stopwatch struct {
start time.Time
label string
}
func (sw *stopwatch) Start(label string) {
sw.start = time.Now()
sw.label = label
}
func (sw *stopwatch) Stop() {
endTime := time.Now()
d := endTime.Sub(sw.start)
log.Printf("%-20s: %s\n", sw.label, d.String())
}
2020-07-19 13:18:03 +00:00
func todayPage() string {
now := time.Now()
2021-01-17 16:36:17 +00:00
return formatDatePageName(now)
2021-01-17 14:38:48 +00:00
}
func formatDateTitle(date time.Time) string {
2021-01-17 20:31:26 +00:00
return fmt.Sprintf("%d %s %d", date.Day(), Months[date.Month()], date.Year())
2021-01-17 16:36:17 +00:00
}
func formatDatePageName(date time.Time) string {
2021-01-17 20:31:26 +00:00
return fmt.Sprintf("%d_%s_%d", date.Day(), Months[date.Month()], date.Year())
2020-07-19 13:18:03 +00:00
}
func PageTitle(pageText string) (string, error) {
var listItems []struct {
Indented int
Text string
}
err := json.NewDecoder(strings.NewReader(pageText)).Decode(&listItems)
if err != nil {
return "", fmt.Errorf("while decoding page text: %w", err)
}
for _, li := range listItems {
if matches := MetaKV.FindStringSubmatch(li.Text); matches != nil {
if matches[1] == "Title" {
return matches[2], nil
}
}
}
return "", fmt.Errorf("no meta title found in page text")
}
2021-01-17 20:31:26 +00:00
func parseMonth(month string) (time.Month, error) {
for i, m := range Months {
if m == month {
return time.Month(i), nil
}
}
return time.Month(0), fmt.Errorf("parseMonth: %q is not a recognized month", month)
}
func ParseDatePageName(name string) (time.Time, error) {
if matches := niceDateParseRE.FindStringSubmatch(name); matches != nil {
day, err := strconv.Atoi(matches[1])
if err != nil {
return time.Time{}, fmt.Errorf("%q: %s: %w", name, err, ParseFailed)
}
month, err := parseMonth(matches[2])
if err != nil {
return time.Time{}, fmt.Errorf("%q: %s: %w", name, err, ParseFailed)
}
year, err := strconv.Atoi(matches[3])
if err != nil {
return time.Time{}, fmt.Errorf("%q: %s: %w", name, err, ParseFailed)
}
return time.Date(year, month, day, 0, 0, 0, 0, time.Local), nil
}
return time.Time{}, fmt.Errorf("%q: invalid syntax: %w", name, ParseFailed)
}