1
0
mirror of https://github.com/osmarks/mycorrhiza.git synced 2024-12-12 05:20:26 +00:00

Find backlinks on wiki start

This commit is contained in:
bouncepaw 2021-02-19 14:23:57 +05:00
parent 9d89923ee5
commit d9cc757546
10 changed files with 246 additions and 26 deletions

View File

@ -110,6 +110,7 @@ func handlerHypha(w http.ResponseWriter, rq *http.Request) {
naviTitle(hyphaName),
contents,
treeHTML,
h.BackLinkEntriesHTML(),
prevHypha, nextHypha,
hasAmnt),
u,

72
hyphae/backlink.go Normal file
View File

@ -0,0 +1,72 @@
package hyphae
import (
"fmt"
"io/ioutil"
"github.com/bouncepaw/mycorrhiza/link"
"github.com/bouncepaw/mycorrhiza/markup"
"github.com/bouncepaw/mycorrhiza/util"
)
func (h *Hypha) BackLinkEntriesHTML() (html string) {
for _, backlinkHypha := range h.BackLinks {
_ = link.Link{}
html += fmt.Sprintf(`<li class="backlinks__entry">
<a class="backlinks__link" href="/hypha/%s">%s</a>`, backlinkHypha.Name, util.BeautifulName(backlinkHypha.Name))
}
return
}
func (h *Hypha) outlinksThis(oh *Hypha) bool {
for _, outlink := range h.OutLinks {
if outlink == oh {
return true
}
}
return false
}
func (h *Hypha) backlinkedBy(oh *Hypha) bool {
for _, backlink := range h.BackLinks {
if backlink == oh {
return true
}
}
return false
}
// FindAllBacklinks iterates over all hyphae that have text parts, sets their outlinks and then sets backlinks.
func FindAllBacklinks() {
for h := range FilterTextHyphae(YieldExistingHyphae()) {
findBacklinkWorker(h)
}
}
func findBacklinkWorker(h *Hypha) {
h.Lock()
defer h.Unlock()
textContents, err := ioutil.ReadFile(h.TextPath)
if err == nil {
for outlink := range markup.Doc(h.Name, string(textContents)).OutLinks() {
outlink := outlink
outlinkHypha := ByName(outlink)
if outlinkHypha == h {
continue
}
outlinkHypha.Lock()
if !outlinkHypha.backlinkedBy(h) {
outlinkHypha.BackLinks = append(outlinkHypha.BackLinks, h)
outlinkHypha.InsertIfNewKeepExistence()
}
outlinkHypha.Unlock()
// Insert outlinkHypha if unique
if !h.outlinksThis(outlinkHypha) {
h.OutLinks = append(h.OutLinks, outlinkHypha)
}
}
}
}

View File

@ -49,8 +49,8 @@ type Hypha struct {
Exists bool
TextPath string
BinaryPath string
OutLinks []*Hypha // not used yet
BackLinks []*Hypha // not used yet
OutLinks []*Hypha
BackLinks []*Hypha
}
var byNames = make(map[string]*Hypha)
@ -59,17 +59,31 @@ var byNamesMutex = sync.Mutex{}
// YieldExistingHyphae iterates over all hyphae and yields all existing ones.
func YieldExistingHyphae() chan *Hypha {
ch := make(chan *Hypha)
go func(ch chan *Hypha) {
go func() {
for _, h := range byNames {
if h.Exists {
ch <- h
}
}
close(ch)
}(ch)
}()
return ch
}
// FilterTextHyphae filters the source channel and yields only those hyphae than have text parts.
func FilterTextHyphae(src chan *Hypha) chan *Hypha {
sink := make(chan *Hypha)
go func() {
for h := range src {
if h.TextPath != "" {
sink <- h
}
}
close(sink)
}()
return sink
}
// Subhyphae returns slice of subhyphae.
func (h *Hypha) Subhyphae() []*Hypha {
hyphae := []*Hypha{}
@ -138,6 +152,18 @@ func (h *Hypha) InsertIfNew() (justCreated bool) {
return false
}
func (h *Hypha) InsertIfNewKeepExistence() {
hp := ByName(h.Name)
byNamesMutex.Lock()
defer byNamesMutex.Unlock()
if hp.Exists {
hp = h
} else {
byNames[h.Name] = h
}
}
func (h *Hypha) delete() {
byNamesMutex.Lock()
h.Lock()

View File

@ -175,6 +175,8 @@ func main() {
log.Println("Wiki storage directory is", WikiDir)
hyphae.Index(WikiDir)
log.Println("Indexed", hyphae.Count(), "hyphae")
hyphae.FindAllBacklinks()
log.Println("Found all backlinks")
history.Start(WikiDir)
hyphae.SetHeaderLinks()

View File

@ -166,7 +166,7 @@ launchpadState:
switch {
case startsWith("=>"):
href, text, class := Rocketlink(line, state.name)
state.buf += fmt.Sprintf(` <li class="launchpad__entry"><a class="rocketlink %s" href="%s">%s</a></li>`, class, href, text)
state.buf += fmt.Sprintf(` <li class="launchpad__entry"><a href="%s" class="rocketlink %s">%s</a></li>`, href, class, text)
case startsWith("```"):
state.where = "pre"
addLine(state.buf + "</ul>")

56
markup/outlink.go Normal file
View File

@ -0,0 +1,56 @@
package markup
import (
"regexp"
"strings"
"github.com/bouncepaw/mycorrhiza/link"
)
// OutLinks returns a channel of names of hyphae this mycodocument links.
// Links include:
// * Regular links
// * Rocketlinks
// * Transclusion
// * Image galleries
func (md *MycoDoc) OutLinks() chan string {
ch := make(chan string)
if !md.parsedAlready {
md.Lex(0)
}
go func() {
for _, line := range md.ast {
switch v := line.contents.(type) {
case string:
if strings.HasPrefix(v, "<p") || strings.HasPrefix(v, "<ul class='launchpad'") {
extractLinks(v, ch)
}
case Transclusion:
ch <- v.name
case Img:
extractImageLinks(v, ch)
}
}
close(ch)
}()
return ch
}
var reLinks = regexp.MustCompile(`<a href="/hypha/([^"]*)".*?</a>`)
func extractLinks(html string, ch chan string) {
if results := reLinks.FindAllStringSubmatch(html, -1); results != nil {
for _, result := range results {
// result[0] is always present at this point and is not needed, because it is the whole matched substring (which we don't need)
ch <- result[1]
}
}
}
func extractImageLinks(img Img, ch chan string) {
for _, entry := range img.entries {
if entry.srclink.Kind == link.LinkLocalHypha {
ch <- entry.srclink.Address
}
}
}

View File

@ -58,7 +58,18 @@ var navEntries = []navEntry{
{% func relativeHyphae(relatives string) %}
<aside class="relative-hyphae layout-card">
<h1 class="relative-hyphae__title layout-card__title">Relative hyphae</h1>
<h2 class="relative-hyphae__title layout-card__title">Relative hyphae</h2>
{%s= relatives %}
</aside>
{% endfunc %}
{% func backlinks(backlinkEntries string) %}
<aside class="backlinks layout-card">
<h2 class="backlinks__title layout-card__title">Backlinks</h2>
<nav class="backlinks__nav">
<ul class="backlinks__list">
{%s= backlinkEntries %}
</ul>
</nav>
</aside>
{% endfunc %}

View File

@ -217,7 +217,7 @@ func streamrelativeHyphae(qw422016 *qt422016.Writer, relatives string) {
//line templates/common.qtpl:59
qw422016.N().S(`
<aside class="relative-hyphae layout-card">
<h1 class="relative-hyphae__title layout-card__title">Relative hyphae</h1>
<h2 class="relative-hyphae__title layout-card__title">Relative hyphae</h2>
`)
//line templates/common.qtpl:62
qw422016.N().S(relatives)
@ -253,3 +253,49 @@ func relativeHyphae(relatives string) string {
return qs422016
//line templates/common.qtpl:64
}
//line templates/common.qtpl:66
func streambacklinks(qw422016 *qt422016.Writer, backlinkEntries string) {
//line templates/common.qtpl:66
qw422016.N().S(`
<aside class="backlinks layout-card">
<h2 class="backlinks__title layout-card__title">Backlinks</h2>
<nav class="backlinks__nav">
<ul class="backlinks__list">
`)
//line templates/common.qtpl:71
qw422016.N().S(backlinkEntries)
//line templates/common.qtpl:71
qw422016.N().S(`
</ul>
</nav>
</aside>
`)
//line templates/common.qtpl:75
}
//line templates/common.qtpl:75
func writebacklinks(qq422016 qtio422016.Writer, backlinkEntries string) {
//line templates/common.qtpl:75
qw422016 := qt422016.AcquireWriter(qq422016)
//line templates/common.qtpl:75
streambacklinks(qw422016, backlinkEntries)
//line templates/common.qtpl:75
qt422016.ReleaseWriter(qw422016)
//line templates/common.qtpl:75
}
//line templates/common.qtpl:75
func backlinks(backlinkEntries string) string {
//line templates/common.qtpl:75
qb422016 := qt422016.AcquireByteBuffer()
//line templates/common.qtpl:75
writebacklinks(qb422016, backlinkEntries)
//line templates/common.qtpl:75
qs422016 := string(qb422016.B)
//line templates/common.qtpl:75
qt422016.ReleaseByteBuffer(qb422016)
//line templates/common.qtpl:75
return qs422016
//line templates/common.qtpl:75
}

View File

@ -30,7 +30,7 @@
{% endfunc %}
If `contents` == "", a helpful message is shown instead.
{% func PageHTML(rq *http.Request, hyphaName, naviTitle, contents, relatives, prevHyphaName, nextHyphaName string, hasAmnt bool) %}
{% func PageHTML(rq *http.Request, hyphaName, naviTitle, contents, relatives, backlinkEntries, prevHyphaName, nextHyphaName string, hasAmnt bool) %}
{%= navHTML(rq, hyphaName, "page") %}
<div class="layout">
<main class="main-width">
@ -65,5 +65,6 @@ If `contents` == "", a helpful message is shown instead.
{% endif %}
</main>
{%= relativeHyphae(relatives) %}
{%= backlinks(backlinkEntries) %}
</div>
{% endfunc %}

View File

@ -148,7 +148,7 @@ func RevisionHTML(rq *http.Request, hyphaName, naviTitle, contents, relatives, r
// If `contents` == "", a helpful message is shown instead.
//line templates/readers.qtpl:33
func StreamPageHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName, naviTitle, contents, relatives, prevHyphaName, nextHyphaName string, hasAmnt bool) {
func StreamPageHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName, naviTitle, contents, relatives, backlinkEntries, prevHyphaName, nextHyphaName string, hasAmnt bool) {
//line templates/readers.qtpl:33
qw422016.N().S(`
`)
@ -273,33 +273,38 @@ func StreamPageHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName, navi
streamrelativeHyphae(qw422016, relatives)
//line templates/readers.qtpl:67
qw422016.N().S(`
`)
//line templates/readers.qtpl:68
streambacklinks(qw422016, backlinkEntries)
//line templates/readers.qtpl:68
qw422016.N().S(`
</div>
`)
//line templates/readers.qtpl:69
//line templates/readers.qtpl:70
}
//line templates/readers.qtpl:69
func WritePageHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName, naviTitle, contents, relatives, prevHyphaName, nextHyphaName string, hasAmnt bool) {
//line templates/readers.qtpl:69
//line templates/readers.qtpl:70
func WritePageHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName, naviTitle, contents, relatives, backlinkEntries, prevHyphaName, nextHyphaName string, hasAmnt bool) {
//line templates/readers.qtpl:70
qw422016 := qt422016.AcquireWriter(qq422016)
//line templates/readers.qtpl:69
StreamPageHTML(qw422016, rq, hyphaName, naviTitle, contents, relatives, prevHyphaName, nextHyphaName, hasAmnt)
//line templates/readers.qtpl:69
//line templates/readers.qtpl:70
StreamPageHTML(qw422016, rq, hyphaName, naviTitle, contents, relatives, backlinkEntries, prevHyphaName, nextHyphaName, hasAmnt)
//line templates/readers.qtpl:70
qt422016.ReleaseWriter(qw422016)
//line templates/readers.qtpl:69
//line templates/readers.qtpl:70
}
//line templates/readers.qtpl:69
func PageHTML(rq *http.Request, hyphaName, naviTitle, contents, relatives, prevHyphaName, nextHyphaName string, hasAmnt bool) string {
//line templates/readers.qtpl:69
//line templates/readers.qtpl:70
func PageHTML(rq *http.Request, hyphaName, naviTitle, contents, relatives, backlinkEntries, prevHyphaName, nextHyphaName string, hasAmnt bool) string {
//line templates/readers.qtpl:70
qb422016 := qt422016.AcquireByteBuffer()
//line templates/readers.qtpl:69
WritePageHTML(qb422016, rq, hyphaName, naviTitle, contents, relatives, prevHyphaName, nextHyphaName, hasAmnt)
//line templates/readers.qtpl:69
//line templates/readers.qtpl:70
WritePageHTML(qb422016, rq, hyphaName, naviTitle, contents, relatives, backlinkEntries, prevHyphaName, nextHyphaName, hasAmnt)
//line templates/readers.qtpl:70
qs422016 := string(qb422016.B)
//line templates/readers.qtpl:69
//line templates/readers.qtpl:70
qt422016.ReleaseByteBuffer(qb422016)
//line templates/readers.qtpl:69
//line templates/readers.qtpl:70
return qs422016
//line templates/readers.qtpl:69
//line templates/readers.qtpl:70
}