mirror of
https://github.com/osmarks/mycorrhiza.git
synced 2024-12-12 13:30:26 +00:00
Find backlinks on wiki start
This commit is contained in:
parent
9d89923ee5
commit
d9cc757546
@ -110,6 +110,7 @@ func handlerHypha(w http.ResponseWriter, rq *http.Request) {
|
|||||||
naviTitle(hyphaName),
|
naviTitle(hyphaName),
|
||||||
contents,
|
contents,
|
||||||
treeHTML,
|
treeHTML,
|
||||||
|
h.BackLinkEntriesHTML(),
|
||||||
prevHypha, nextHypha,
|
prevHypha, nextHypha,
|
||||||
hasAmnt),
|
hasAmnt),
|
||||||
u,
|
u,
|
||||||
|
72
hyphae/backlink.go
Normal file
72
hyphae/backlink.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -49,8 +49,8 @@ type Hypha struct {
|
|||||||
Exists bool
|
Exists bool
|
||||||
TextPath string
|
TextPath string
|
||||||
BinaryPath string
|
BinaryPath string
|
||||||
OutLinks []*Hypha // not used yet
|
OutLinks []*Hypha
|
||||||
BackLinks []*Hypha // not used yet
|
BackLinks []*Hypha
|
||||||
}
|
}
|
||||||
|
|
||||||
var byNames = make(map[string]*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.
|
// YieldExistingHyphae iterates over all hyphae and yields all existing ones.
|
||||||
func YieldExistingHyphae() chan *Hypha {
|
func YieldExistingHyphae() chan *Hypha {
|
||||||
ch := make(chan *Hypha)
|
ch := make(chan *Hypha)
|
||||||
go func(ch chan *Hypha) {
|
go func() {
|
||||||
for _, h := range byNames {
|
for _, h := range byNames {
|
||||||
if h.Exists {
|
if h.Exists {
|
||||||
ch <- h
|
ch <- h
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
close(ch)
|
close(ch)
|
||||||
}(ch)
|
}()
|
||||||
return 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.
|
// Subhyphae returns slice of subhyphae.
|
||||||
func (h *Hypha) Subhyphae() []*Hypha {
|
func (h *Hypha) Subhyphae() []*Hypha {
|
||||||
hyphae := []*Hypha{}
|
hyphae := []*Hypha{}
|
||||||
@ -138,6 +152,18 @@ func (h *Hypha) InsertIfNew() (justCreated bool) {
|
|||||||
return false
|
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() {
|
func (h *Hypha) delete() {
|
||||||
byNamesMutex.Lock()
|
byNamesMutex.Lock()
|
||||||
h.Lock()
|
h.Lock()
|
||||||
|
2
main.go
2
main.go
@ -175,6 +175,8 @@ func main() {
|
|||||||
log.Println("Wiki storage directory is", WikiDir)
|
log.Println("Wiki storage directory is", WikiDir)
|
||||||
hyphae.Index(WikiDir)
|
hyphae.Index(WikiDir)
|
||||||
log.Println("Indexed", hyphae.Count(), "hyphae")
|
log.Println("Indexed", hyphae.Count(), "hyphae")
|
||||||
|
hyphae.FindAllBacklinks()
|
||||||
|
log.Println("Found all backlinks")
|
||||||
|
|
||||||
history.Start(WikiDir)
|
history.Start(WikiDir)
|
||||||
hyphae.SetHeaderLinks()
|
hyphae.SetHeaderLinks()
|
||||||
|
@ -166,7 +166,7 @@ launchpadState:
|
|||||||
switch {
|
switch {
|
||||||
case startsWith("=>"):
|
case startsWith("=>"):
|
||||||
href, text, class := Rocketlink(line, state.name)
|
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("```"):
|
case startsWith("```"):
|
||||||
state.where = "pre"
|
state.where = "pre"
|
||||||
addLine(state.buf + "</ul>")
|
addLine(state.buf + "</ul>")
|
||||||
|
56
markup/outlink.go
Normal file
56
markup/outlink.go
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -58,7 +58,18 @@ var navEntries = []navEntry{
|
|||||||
|
|
||||||
{% func relativeHyphae(relatives string) %}
|
{% func relativeHyphae(relatives string) %}
|
||||||
<aside class="relative-hyphae layout-card">
|
<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 %}
|
{%s= relatives %}
|
||||||
</aside>
|
</aside>
|
||||||
{% endfunc %}
|
{% 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 %}
|
||||||
|
@ -217,7 +217,7 @@ func streamrelativeHyphae(qw422016 *qt422016.Writer, relatives string) {
|
|||||||
//line templates/common.qtpl:59
|
//line templates/common.qtpl:59
|
||||||
qw422016.N().S(`
|
qw422016.N().S(`
|
||||||
<aside class="relative-hyphae layout-card">
|
<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
|
//line templates/common.qtpl:62
|
||||||
qw422016.N().S(relatives)
|
qw422016.N().S(relatives)
|
||||||
@ -253,3 +253,49 @@ func relativeHyphae(relatives string) string {
|
|||||||
return qs422016
|
return qs422016
|
||||||
//line templates/common.qtpl:64
|
//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
|
||||||
|
}
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
{% endfunc %}
|
{% endfunc %}
|
||||||
|
|
||||||
If `contents` == "", a helpful message is shown instead.
|
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") %}
|
{%= navHTML(rq, hyphaName, "page") %}
|
||||||
<div class="layout">
|
<div class="layout">
|
||||||
<main class="main-width">
|
<main class="main-width">
|
||||||
@ -65,5 +65,6 @@ If `contents` == "", a helpful message is shown instead.
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</main>
|
</main>
|
||||||
{%= relativeHyphae(relatives) %}
|
{%= relativeHyphae(relatives) %}
|
||||||
|
{%= backlinks(backlinkEntries) %}
|
||||||
</div>
|
</div>
|
||||||
{% endfunc %}
|
{% endfunc %}
|
||||||
|
@ -148,7 +148,7 @@ func RevisionHTML(rq *http.Request, hyphaName, naviTitle, contents, relatives, r
|
|||||||
// If `contents` == "", a helpful message is shown instead.
|
// If `contents` == "", a helpful message is shown instead.
|
||||||
|
|
||||||
//line templates/readers.qtpl:33
|
//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
|
//line templates/readers.qtpl:33
|
||||||
qw422016.N().S(`
|
qw422016.N().S(`
|
||||||
`)
|
`)
|
||||||
@ -273,33 +273,38 @@ func StreamPageHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName, navi
|
|||||||
streamrelativeHyphae(qw422016, relatives)
|
streamrelativeHyphae(qw422016, relatives)
|
||||||
//line templates/readers.qtpl:67
|
//line templates/readers.qtpl:67
|
||||||
qw422016.N().S(`
|
qw422016.N().S(`
|
||||||
|
`)
|
||||||
|
//line templates/readers.qtpl:68
|
||||||
|
streambacklinks(qw422016, backlinkEntries)
|
||||||
|
//line templates/readers.qtpl:68
|
||||||
|
qw422016.N().S(`
|
||||||
</div>
|
</div>
|
||||||
`)
|
`)
|
||||||
//line templates/readers.qtpl:69
|
//line templates/readers.qtpl:70
|
||||||
}
|
}
|
||||||
|
|
||||||
//line templates/readers.qtpl:69
|
//line templates/readers.qtpl:70
|
||||||
func WritePageHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName, naviTitle, contents, relatives, prevHyphaName, nextHyphaName string, hasAmnt bool) {
|
func WritePageHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName, naviTitle, contents, relatives, backlinkEntries, prevHyphaName, nextHyphaName string, hasAmnt bool) {
|
||||||
//line templates/readers.qtpl:69
|
//line templates/readers.qtpl:70
|
||||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||||
//line templates/readers.qtpl:69
|
//line templates/readers.qtpl:70
|
||||||
StreamPageHTML(qw422016, rq, hyphaName, naviTitle, contents, relatives, prevHyphaName, nextHyphaName, hasAmnt)
|
StreamPageHTML(qw422016, rq, hyphaName, naviTitle, contents, relatives, backlinkEntries, prevHyphaName, nextHyphaName, hasAmnt)
|
||||||
//line templates/readers.qtpl:69
|
//line templates/readers.qtpl:70
|
||||||
qt422016.ReleaseWriter(qw422016)
|
qt422016.ReleaseWriter(qw422016)
|
||||||
//line templates/readers.qtpl:69
|
//line templates/readers.qtpl:70
|
||||||
}
|
}
|
||||||
|
|
||||||
//line templates/readers.qtpl:69
|
//line templates/readers.qtpl:70
|
||||||
func PageHTML(rq *http.Request, hyphaName, naviTitle, contents, relatives, prevHyphaName, nextHyphaName string, hasAmnt bool) string {
|
func PageHTML(rq *http.Request, hyphaName, naviTitle, contents, relatives, backlinkEntries, prevHyphaName, nextHyphaName string, hasAmnt bool) string {
|
||||||
//line templates/readers.qtpl:69
|
//line templates/readers.qtpl:70
|
||||||
qb422016 := qt422016.AcquireByteBuffer()
|
qb422016 := qt422016.AcquireByteBuffer()
|
||||||
//line templates/readers.qtpl:69
|
//line templates/readers.qtpl:70
|
||||||
WritePageHTML(qb422016, rq, hyphaName, naviTitle, contents, relatives, prevHyphaName, nextHyphaName, hasAmnt)
|
WritePageHTML(qb422016, rq, hyphaName, naviTitle, contents, relatives, backlinkEntries, prevHyphaName, nextHyphaName, hasAmnt)
|
||||||
//line templates/readers.qtpl:69
|
//line templates/readers.qtpl:70
|
||||||
qs422016 := string(qb422016.B)
|
qs422016 := string(qb422016.B)
|
||||||
//line templates/readers.qtpl:69
|
//line templates/readers.qtpl:70
|
||||||
qt422016.ReleaseByteBuffer(qb422016)
|
qt422016.ReleaseByteBuffer(qb422016)
|
||||||
//line templates/readers.qtpl:69
|
//line templates/readers.qtpl:70
|
||||||
return qs422016
|
return qs422016
|
||||||
//line templates/readers.qtpl:69
|
//line templates/readers.qtpl:70
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user