split into packages
This commit is contained in:
parent
2b56832843
commit
c5d41b0965
26 changed files with 328 additions and 449 deletions
112
pkg/index/index.go
Normal file
112
pkg/index/index.go
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
// Copyright (C) 2017 Marius Schellenberger
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/blevesearch/bleve"
|
||||
"github.com/blevesearch/bleve/document"
|
||||
)
|
||||
|
||||
type IndexPage struct {
|
||||
Title string `json:"title"`
|
||||
Search string `json:"search"`
|
||||
}
|
||||
|
||||
func indexErr(i interface{}) error {
|
||||
return fmt.Errorf("index: %s", i)
|
||||
}
|
||||
|
||||
type Index struct {
|
||||
i bleve.Index
|
||||
}
|
||||
|
||||
func NewIndex(path string) (i *Index, err error) {
|
||||
var bi bleve.Index
|
||||
if _, err = os.Stat(path); os.IsNotExist(err) {
|
||||
mapping := bleve.NewIndexMapping()
|
||||
bi, err = bleve.New(path, mapping)
|
||||
if err != nil {
|
||||
err = indexErr(err)
|
||||
return
|
||||
}
|
||||
i = &Index{index: bi}
|
||||
_, err = i.Index(indexName, welcome, defUser, true)
|
||||
if err != nil {
|
||||
err = indexErr(err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
bi, err = bleve.Open(path)
|
||||
if err != nil {
|
||||
err = indexErr(err)
|
||||
return
|
||||
}
|
||||
i = &Index{index: bi}
|
||||
}
|
||||
i.cache = NewIndexCache()
|
||||
return
|
||||
}
|
||||
|
||||
func NewDumpIndex(path string) (i *Index, err error) {
|
||||
bi, err := bleve.OpenUsing(path, map[string]interface{}{"read_only": true})
|
||||
if err != nil {
|
||||
err = indexErr(err)
|
||||
return
|
||||
}
|
||||
i = &Index{index: bi}
|
||||
return
|
||||
}
|
||||
|
||||
func (i *Index) Close() error {
|
||||
return i.i.Close()
|
||||
}
|
||||
|
||||
func (i *Index) Add(ip IndexPage) error {
|
||||
doc, _ := i.i.Document(ip.Title)
|
||||
if doc != nil {
|
||||
err := i.Delete(ip.Title)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return i.i.Index(ip.Title, ip)
|
||||
}
|
||||
|
||||
func (i *Index) Delete(title string) error {
|
||||
return i.i.Delete(title)
|
||||
}
|
||||
|
||||
type Result struct {
|
||||
Title string
|
||||
Text string
|
||||
}
|
||||
|
||||
func (i *Index) Search(search string) (results []Result, err error) {
|
||||
req := bleve.NewSearchRequest(bleve.NewQueryStringQuery("title:" + search + " search:" + search))
|
||||
req.Highlight = bleve.NewHighlightWithStyle("html")
|
||||
req.Size = maxSearchResult
|
||||
res, err := i.i.Search(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, hit := range res.Hits {
|
||||
if hit == nil {
|
||||
continue
|
||||
}
|
||||
title := hit.ID
|
||||
text := ""
|
||||
for fragField, frags := range hit.Fragments {
|
||||
if fragField == "title" || fragField == "search" {
|
||||
for _, f := range frags {
|
||||
text += f
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
results = append(results, Result{title, text})
|
||||
}
|
||||
return
|
||||
}
|
||||
154
pkg/index/render.go
Normal file
154
pkg/index/render.go
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
// Copyright (C) 2017 Marius Schellenberger
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/blevesearch/bleve/analysis"
|
||||
htmlFilter "github.com/blevesearch/bleve/analysis/char_filters/html_char_filter"
|
||||
"github.com/russross/blackfriday"
|
||||
)
|
||||
|
||||
var filter = makeFilter()
|
||||
|
||||
func makeFilter() analysis.CharFilter {
|
||||
f, _ := htmlFilter.CharFilterConstructor(nil, nil)
|
||||
return f
|
||||
}
|
||||
|
||||
var (
|
||||
reHeader = regexp.MustCompile("(<h[1-6])>(.+)(</h[1-6]>)")
|
||||
reLink = regexp.MustCompile(`id="(.+)">`)
|
||||
whiteSpace = regexp.MustCompile(`\s+`)
|
||||
reIndex = regexp.MustCompile("<h([1-6])>(.+)</h[1-6]>")
|
||||
titleRe = regexp.MustCompile("[^a-zA-Z0-9 -]+")
|
||||
)
|
||||
|
||||
type rendered struct {
|
||||
Index template.HTML
|
||||
Text template.HTML
|
||||
MD string
|
||||
Raw []byte
|
||||
}
|
||||
|
||||
func (r *rendered) Article() *Article {
|
||||
return &Article{
|
||||
Index: r.Index,
|
||||
Text: r.Text,
|
||||
MD: r.MD,
|
||||
Search: whiteSpace.ReplaceAllString(string(filter.Filter(r.Raw)), " "),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *rendered) Snippet() *Snippet {
|
||||
return &Snippet{
|
||||
Index: r.Index,
|
||||
Text: r.Text,
|
||||
MD: r.MD,
|
||||
}
|
||||
}
|
||||
|
||||
func render(text string) *rendered {
|
||||
rend := blackfriday.MarkdownCommon([]byte(text))
|
||||
index, html := buildIndex(string(rend))
|
||||
html = strings.Replace(html, "<table>", `<table class="table">`, -1)
|
||||
html = strings.Replace(html, "</h1>", `</h1><hr>`, -1)
|
||||
html = strings.Replace(html, "<a", `<a target="_blank"`, -1)
|
||||
return &rendered{
|
||||
Index: template.HTML(index),
|
||||
Text: template.HTML(html),
|
||||
MD: text,
|
||||
Raw: rend,
|
||||
}
|
||||
}
|
||||
|
||||
func spaceReplace(s string) string {
|
||||
return whiteSpace.ReplaceAllString(s, "+")
|
||||
//TODO remove
|
||||
//return strings.Replace(s, " ", "+", -1)
|
||||
}
|
||||
|
||||
func makeLinkTitle(t string) (newTitle string, title string) {
|
||||
title = titleRe.ReplaceAllString(t, "")
|
||||
newTitle = spaceReplace(title)
|
||||
return
|
||||
}
|
||||
|
||||
func buildIndex(html string) (string, string) {
|
||||
var ret string
|
||||
m := make(map[string]int)
|
||||
hn := reIndex.FindAllStringSubmatch(html, -1)
|
||||
html = reHeader.ReplaceAllString(html, `${1} id="${2}">${2}${3}`)
|
||||
html = reLink.ReplaceAllStringFunc(html, spaceReplace)
|
||||
for k, v := range hn {
|
||||
link, _ := makeLinkTitle(v[2])
|
||||
i := m[link]
|
||||
m[link] = i + 1
|
||||
newLink := link + strconv.Itoa(i)
|
||||
html = strings.Replace(html, link+`"`, newLink+`"`, 1)
|
||||
ret += before(hn, k)
|
||||
ret += `<li><a href="#` + newLink + `">` + v[2] + "</a>"
|
||||
ret += after(hn, k)
|
||||
}
|
||||
return ret, html
|
||||
}
|
||||
|
||||
func before(arr [][]string, i int) string {
|
||||
c, _ := strconv.Atoi(arr[i][1])
|
||||
if c == 1 {
|
||||
return `<ul type="circle">`
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func after(arr [][]string, i int) string {
|
||||
c, _ := strconv.Atoi(arr[i][1])
|
||||
if len(arr) <= i+1 {
|
||||
return closeTag(c-1) + "</ul>"
|
||||
}
|
||||
n, _ := strconv.Atoi(arr[i+1][1])
|
||||
if n == 1 {
|
||||
return closeTag(c-n) + "</ul>"
|
||||
} else if n < c {
|
||||
return closeTag(c - n)
|
||||
} else if n > c {
|
||||
return openTag(n - c)
|
||||
} else if n == c {
|
||||
return "</li>"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func openTag(j int) (ret string) {
|
||||
for i := 0; i < j; i++ {
|
||||
ret += `<ul type="circle"><li>`
|
||||
}
|
||||
if j > 1 {
|
||||
ret = strings.Replace(ret, "circle", "none", j-1)
|
||||
}
|
||||
ret = ret[0 : len(ret)-4]
|
||||
return
|
||||
}
|
||||
|
||||
func closeTag(j int) (ret string) {
|
||||
for i := 0; i < j; i++ {
|
||||
ret += "</li></ul></li>"
|
||||
}
|
||||
if j > 1 {
|
||||
ret = strings.Replace(ret, "</li></li>", "</li>", -1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func renderResult(res []Result) (html string) {
|
||||
//TODO fmt.Sprintf ?
|
||||
for r := range res {
|
||||
html += `<a href="/` + r.LinkTitle + `"><b>` + r.Title + "</b></a>" +
|
||||
`<pre style="white-space: pre-wrap">` + r.Text + "</pre><br>"
|
||||
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue