1
0
mirror of https://github.com/osmarks/mycorrhiza.git synced 2024-12-04 18:19:54 +00:00

Tree: Drop the sibling sidebar

Because of that, I could reimplement the rest of the package tree more straight-forward. Also deleted the package iteration because it is no longer used anywhere.
This commit is contained in:
Timur Ismagilov 2022-08-06 13:45:10 +05:00
parent e577b79d67
commit ac4c4d665c
6 changed files with 91 additions and 395 deletions

View File

@ -1,55 +0,0 @@
// Package iteration provides a handy API for making multiple checks on all hyphae in one go.
package iteration
import (
"github.com/bouncepaw/mycorrhiza/hyphae"
"sync"
)
// Iteration represents an iteration over all existing hyphae in the storage. Iteration is done on all existing hyphae. The order of hyphae is not specified. For all hyphae, checks are made.
type Iteration struct {
sync.Mutex
checks []func(h hyphae.Hypha) CheckResult
}
// NewIteration constructs an iteration without checks.
func NewIteration() *Iteration {
return &Iteration{
checks: make([]func(h hyphae.Hypha) CheckResult, 0),
}
}
// AddCheck adds the check to the iteration. It is concurrent-safe. Checks are meant to have side-effects.
func (i7n *Iteration) AddCheck(check func(h hyphae.Hypha) CheckResult) {
i7n.Lock()
i7n.checks = append(i7n.checks, check)
i7n.Unlock()
}
func (i7n *Iteration) removeCheck(i int) {
i7n.checks[i] = i7n.checks[len(i7n.checks)-1]
i7n.checks = i7n.checks[:len(i7n.checks)-1]
}
// Ignite does the iteration by walking over all hyphae yielded by the iterator used and calling all checks on the hypha. Ignited iterations are not concurrent-safe.
//
// After ignition, you should not use the same Iteration again.
func (i7n *Iteration) Ignite() {
for h := range hyphae.YieldExistingHyphae() {
for i, check := range i7n.checks {
if res := check(h); res == CheckForgetMe {
i7n.removeCheck(i)
}
}
}
}
// CheckResult is a result of an iteration check.
type CheckResult int
const (
// CheckContinue is returned when the check wants to be used next time too.
CheckContinue CheckResult = iota
// CheckForgetMe is returned when the check wants to be forgotten and not used anymore.
CheckForgetMe
)

View File

@ -1,127 +1,41 @@
package tree
import (
"fmt"
"github.com/bouncepaw/mycorrhiza/hyphae/iteration"
"github.com/bouncepaw/mycorrhiza/hyphae"
"path"
"sort"
"strings"
"sync"
"github.com/bouncepaw/mycorrhiza/hyphae"
"github.com/bouncepaw/mycorrhiza/util"
)
func findSiblings(hyphaName string) []*sibling {
parentHyphaName := ""
if hyphaRawDir := path.Dir(hyphaName); hyphaRawDir != "." {
parentHyphaName = hyphaRawDir
}
// Tree returns the subhypha matrix as HTML and names of the next and previous hyphae (or empty strings).
func Tree(hyphaName string) (childrenHTML, prev, next string) {
var (
siblingsMap = make(map[string]bool)
siblingCheck = func(h hyphae.Hypha) iteration.CheckResult {
switch {
case h.CanonicalName() == hyphaName, // NonEmptyHypha is no sibling of itself
h.CanonicalName() == parentHyphaName: // Parent hypha is no sibling of its child
return iteration.CheckContinue
}
if (parentHyphaName != "" && strings.HasPrefix(h.CanonicalName(), parentHyphaName+"/")) ||
(parentHyphaName == "") {
var (
rawSubPath = strings.TrimPrefix(h.CanonicalName(), parentHyphaName)[1:]
slashIdx = strings.IndexRune(rawSubPath, '/')
root = child{hyphaName, true, make([]child, 0)}
descendantPrefix = hyphaName + "/"
parent = path.Dir(hyphaName) // Beware, it might be . and whatnot.
slashCount = strings.Count(hyphaName, "/")
)
if slashIdx > -1 {
var sibPath = h.CanonicalName()[:slashIdx+len(parentHyphaName)+1]
if _, exists := siblingsMap[sibPath]; !exists {
siblingsMap[sibPath] = false
}
} else { // it is a straight sibling
siblingsMap[h.CanonicalName()] = true
}
}
return iteration.CheckContinue
for h := range hyphae.YieldExistingHyphae() {
name := h.CanonicalName()
if strings.HasPrefix(name, descendantPrefix) {
var subPath = strings.TrimPrefix(name, descendantPrefix)
addHyphaToChild(name, subPath, &root)
// A child is not a sibling, so we skip the rest.
continue
}
i7n = iteration.NewIteration()
)
siblingsMap[hyphaName] = true
// Skipping non-siblings.
if !(path.Dir(name) == parent && slashCount == strings.Count(name, "/")) {
continue
}
i7n.AddCheck(siblingCheck)
i7n.Ignite()
siblings := make([]*sibling, len(siblingsMap))
sibIdx := 0
for sibName, exists := range siblingsMap {
siblings[sibIdx] = &sibling{sibName, 0, 0, exists}
sibIdx++
}
sort.Slice(siblings, func(i, j int) bool {
return siblings[i].name < siblings[j].name
})
return siblings
}
func countSubhyphae(siblings []*sibling) {
var (
subhyphaCheck = func(h hyphae.Hypha) iteration.CheckResult {
for _, s := range siblings {
if path.Dir(h.CanonicalName()) == s.name {
s.directSubhyphaeCount++
return iteration.CheckContinue
} else if strings.HasPrefix(h.CanonicalName(), s.name+"/") {
s.indirectSubhyphaeCount++
return iteration.CheckContinue
if (name < hyphaName) && (name > prev) {
prev = name
} else if (name > hyphaName) && (name < next || next == "") {
next = name
}
}
return iteration.CheckContinue
}
i7n = iteration.NewIteration()
)
i7n.AddCheck(subhyphaCheck)
i7n.Ignite()
}
// Tree generates a tree for `hyphaName` as html and returns next and previous hyphae if any.
func Tree(hyphaName string) (siblingsHTML, childrenHTML, prev, next string) {
children := make([]child, 0)
I := 0
// The tree is generated in two iterations of hyphae storage:
// 1. Find all siblings (sorted)
// 2. Count how many subhyphae siblings have
//
// We also have to figure out what is going on with the descendants: who is a child of whom. We do that in parallel with (2) because we can.
// One of the siblings is the hypha with name `hyphaName`
var siblings []*sibling
wg := sync.WaitGroup{}
wg.Add(2)
go func() {
siblings = findSiblings(hyphaName)
countSubhyphae(siblings)
wg.Done()
}()
go func() {
children = figureOutChildren(hyphaName).children
wg.Done()
}()
wg.Wait()
for i, s := range siblings {
if s.name == hyphaName {
I = i
siblingsHTML += fmt.Sprintf(`<li class="sibling-hyphae__entry sibling-hyphae__entry_this"><span>%s</span></li>`, util.BeautifulName(path.Base(hyphaName)))
} else {
siblingsHTML += siblingHTML(s)
}
}
if I != 0 && len(siblings) > 1 {
prev = siblings[I-1].name
}
if I != len(siblings)-1 && len(siblings) > 1 {
next = siblings[I+1].name
}
return fmt.Sprintf(`<ul class="sibling-hyphae__list">%s</ul>`, siblingsHTML), subhyphaeMatrix(children), prev, next
return subhyphaeMatrix(root.children), prev, next
}
type child struct {
@ -130,23 +44,6 @@ type child struct {
children []child
}
func figureOutChildren(hyphaName string) child {
var (
descPrefix = hyphaName + "/"
child = child{hyphaName, true, make([]child, 0)}
)
for desc := range hyphae.YieldExistingHyphae() {
var descName = desc.CanonicalName()
if strings.HasPrefix(descName, descPrefix) {
var subPath = strings.TrimPrefix(descName, descPrefix)
addHyphaToChild(descName, subPath, &child)
}
}
return child
}
func addHyphaToChild(hyphaName, subPath string, child *child) {
// when hyphaName = "root/a/b", subPath = "a/b", and child.name = "root"
// addHyphaToChild("root/a/b", "b", child{"root/a"})
@ -181,13 +78,6 @@ func findOrCreateSubchild(name string, baseChild *child) *child {
return &baseChild.children[len(baseChild.children)-1]
}
type sibling struct {
name string
directSubhyphaeCount int
indirectSubhyphaeCount int
exists bool
}
func subhyphaeMatrix(children []child) (html string) {
sort.Slice(children, func(i, j int) bool {
return children[i].name < children[j].name

View File

@ -5,7 +5,7 @@
Subhyphae links are recursive. It may end up looking like that if drawn with
pseudographics:
╔══════════════╗
║Foo ║ The presented hyphae are foo and foo/bar
║Foo ║ The presented hyphae are ./foo and ./foo/bar
║╔════════════╗║
║║Bar ║║
║╚════════════╝║
@ -30,23 +30,3 @@ pseudographics:
</li>
{% endfunc %}
{% func siblingHTML(s *sibling) %}
<li class="sibling-hyphae__entry">
<a class="sibling-hyphae__link {% if !s.exists %}wikilink_new{% endif %}" href="/hypha/{%s s.name %}">
{%s util.BeautifulName(path.Base(s.name)) %}
<span class="sibling-hyphae__count">
{% if s.directSubhyphaeCount > 0 %}
<span class="sibling-hyphae__direct-count">
{%d s.directSubhyphaeCount %}
</span>
{% endif %}
{% if s.indirectSubhyphaeCount > 0 %}
<span class="sibling-hyphae__indirect-count">
({%d s.indirectSubhyphaeCount %})
</span>
{% endif %}
</span>
</a>
</li>
{% endfunc %}

View File

@ -16,7 +16,7 @@ import "github.com/bouncepaw/mycorrhiza/util"
// Subhyphae links are recursive. It may end up looking like that if drawn with
// pseudographics:
// ╔══════════════╗
// ║Foo ║ The presented hyphae are foo and foo/bar
// ║Foo ║ The presented hyphae are ./foo and ./foo/bar
// ║╔════════════╗║
// ║║Bar ║║
// ║╚════════════╝║
@ -124,94 +124,3 @@ func childHTML(c *child) string {
return qs422016
//line tree/view.qtpl:31
}
//line tree/view.qtpl:34
func streamsiblingHTML(qw422016 *qt422016.Writer, s *sibling) {
//line tree/view.qtpl:34
qw422016.N().S(`
<li class="sibling-hyphae__entry">
<a class="sibling-hyphae__link `)
//line tree/view.qtpl:36
if !s.exists {
//line tree/view.qtpl:36
qw422016.N().S(`wikilink_new`)
//line tree/view.qtpl:36
}
//line tree/view.qtpl:36
qw422016.N().S(`" href="/hypha/`)
//line tree/view.qtpl:36
qw422016.E().S(s.name)
//line tree/view.qtpl:36
qw422016.N().S(`">
`)
//line tree/view.qtpl:37
qw422016.E().S(util.BeautifulName(path.Base(s.name)))
//line tree/view.qtpl:37
qw422016.N().S(`
<span class="sibling-hyphae__count">
`)
//line tree/view.qtpl:39
if s.directSubhyphaeCount > 0 {
//line tree/view.qtpl:39
qw422016.N().S(`
<span class="sibling-hyphae__direct-count">
`)
//line tree/view.qtpl:41
qw422016.N().D(s.directSubhyphaeCount)
//line tree/view.qtpl:41
qw422016.N().S(`
</span>
`)
//line tree/view.qtpl:43
}
//line tree/view.qtpl:43
qw422016.N().S(`
`)
//line tree/view.qtpl:44
if s.indirectSubhyphaeCount > 0 {
//line tree/view.qtpl:44
qw422016.N().S(`
<span class="sibling-hyphae__indirect-count">
(`)
//line tree/view.qtpl:46
qw422016.N().D(s.indirectSubhyphaeCount)
//line tree/view.qtpl:46
qw422016.N().S(`)
</span>
`)
//line tree/view.qtpl:48
}
//line tree/view.qtpl:48
qw422016.N().S(`
</span>
</a>
</li>
`)
//line tree/view.qtpl:52
}
//line tree/view.qtpl:52
func writesiblingHTML(qq422016 qtio422016.Writer, s *sibling) {
//line tree/view.qtpl:52
qw422016 := qt422016.AcquireWriter(qq422016)
//line tree/view.qtpl:52
streamsiblingHTML(qw422016, s)
//line tree/view.qtpl:52
qt422016.ReleaseWriter(qw422016)
//line tree/view.qtpl:52
}
//line tree/view.qtpl:52
func siblingHTML(s *sibling) string {
//line tree/view.qtpl:52
qb422016 := qt422016.AcquireByteBuffer()
//line tree/view.qtpl:52
writesiblingHTML(qb422016, s)
//line tree/view.qtpl:52
qs422016 := string(qb422016.B)
//line tree/view.qtpl:52
qt422016.ReleaseByteBuffer(qb422016)
//line tree/view.qtpl:52
return qs422016
//line tree/view.qtpl:52
}

View File

@ -88,7 +88,7 @@ If `contents` == "", a helpful message is shown instead.
If you rename .prevnext, change the docs too.
{% func Hypha(meta viewutil.Meta, h hyphae.Hypha, contents string) %}
{% code
siblings, subhyphae, prevHyphaName, nextHyphaName := tree.Tree(h.CanonicalName())
subhyphae, prevHyphaName, nextHyphaName := tree.Tree(h.CanonicalName())
lc := meta.Lc
%}
<main class="main-width">
@ -141,12 +141,6 @@ If you rename .prevnext, change the docs too.
</section>
</main>
{%s= categories.CategoryCard(meta, h.CanonicalName()) %}
{% if cfg.UseSiblingHyphaeSidebar %}
<aside class="sibling-hyphae layout-card">
<h2 class="sibling-hyphae__title layout-card__title">{%s lc.Get("ui.sibling_hyphae") %}</h2>
{%s= siblings %}
</aside>
{% endif %}
{%= viewScripts() %}
{% endfunc %}

View File

@ -323,7 +323,7 @@ func StreamHypha(qw422016 *qt422016.Writer, meta viewutil.Meta, h hyphae.Hypha,
qw422016.N().S(`
`)
//line views/readers.qtpl:91
siblings, subhyphae, prevHyphaName, nextHyphaName := tree.Tree(h.CanonicalName())
subhyphae, prevHyphaName, nextHyphaName := tree.Tree(h.CanonicalName())
lc := meta.Lc
//line views/readers.qtpl:93
@ -501,176 +501,154 @@ func StreamHypha(qw422016 *qt422016.Writer, meta viewutil.Meta, h hyphae.Hypha,
qw422016.N().S(`
`)
//line views/readers.qtpl:144
if cfg.UseSiblingHyphaeSidebar {
streamviewScripts(qw422016)
//line views/readers.qtpl:144
qw422016.N().S(`
<aside class="sibling-hyphae layout-card">
<h2 class="sibling-hyphae__title layout-card__title">`)
//line views/readers.qtpl:146
qw422016.E().S(lc.Get("ui.sibling_hyphae"))
//line views/readers.qtpl:146
qw422016.N().S(`</h2>
`)
//line views/readers.qtpl:147
qw422016.N().S(siblings)
//line views/readers.qtpl:147
qw422016.N().S(`
</aside>
`)
//line views/readers.qtpl:149
}
//line views/readers.qtpl:149
qw422016.N().S(`
`)
//line views/readers.qtpl:150
streamviewScripts(qw422016)
//line views/readers.qtpl:150
qw422016.N().S(`
`)
//line views/readers.qtpl:151
//line views/readers.qtpl:145
}
//line views/readers.qtpl:151
//line views/readers.qtpl:145
func WriteHypha(qq422016 qtio422016.Writer, meta viewutil.Meta, h hyphae.Hypha, contents string) {
//line views/readers.qtpl:151
//line views/readers.qtpl:145
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/readers.qtpl:151
//line views/readers.qtpl:145
StreamHypha(qw422016, meta, h, contents)
//line views/readers.qtpl:151
//line views/readers.qtpl:145
qt422016.ReleaseWriter(qw422016)
//line views/readers.qtpl:151
//line views/readers.qtpl:145
}
//line views/readers.qtpl:151
//line views/readers.qtpl:145
func Hypha(meta viewutil.Meta, h hyphae.Hypha, contents string) string {
//line views/readers.qtpl:151
//line views/readers.qtpl:145
qb422016 := qt422016.AcquireByteBuffer()
//line views/readers.qtpl:151
//line views/readers.qtpl:145
WriteHypha(qb422016, meta, h, contents)
//line views/readers.qtpl:151
//line views/readers.qtpl:145
qs422016 := string(qb422016.B)
//line views/readers.qtpl:151
//line views/readers.qtpl:145
qt422016.ReleaseByteBuffer(qb422016)
//line views/readers.qtpl:151
//line views/readers.qtpl:145
return qs422016
//line views/readers.qtpl:151
//line views/readers.qtpl:145
}
//line views/readers.qtpl:153
//line views/readers.qtpl:147
func StreamRevision(qw422016 *qt422016.Writer, meta viewutil.Meta, h hyphae.Hypha, contents, revHash string) {
//line views/readers.qtpl:153
//line views/readers.qtpl:147
qw422016.N().S(`
<main class="main-width">
<section>
<p>`)
//line views/readers.qtpl:156
//line views/readers.qtpl:150
qw422016.E().S(meta.Lc.Get("ui.revision_warning"))
//line views/readers.qtpl:156
//line views/readers.qtpl:150
qw422016.N().S(` <a href="/rev-text/`)
//line views/readers.qtpl:156
//line views/readers.qtpl:150
qw422016.E().S(revHash)
//line views/readers.qtpl:156
//line views/readers.qtpl:150
qw422016.N().S(`/`)
//line views/readers.qtpl:156
//line views/readers.qtpl:150
qw422016.E().S(h.CanonicalName())
//line views/readers.qtpl:156
//line views/readers.qtpl:150
qw422016.N().S(`">`)
//line views/readers.qtpl:156
//line views/readers.qtpl:150
qw422016.E().S(meta.Lc.Get("ui.revision_link"))
//line views/readers.qtpl:156
//line views/readers.qtpl:150
qw422016.N().S(`</a></p>
`)
//line views/readers.qtpl:157
//line views/readers.qtpl:151
qw422016.N().S(hypview.NaviTitle(meta, h.CanonicalName()))
//line views/readers.qtpl:157
//line views/readers.qtpl:151
qw422016.N().S(`
`)
//line views/readers.qtpl:158
//line views/readers.qtpl:152
qw422016.N().S(contents)
//line views/readers.qtpl:158
//line views/readers.qtpl:152
qw422016.N().S(`
</section>
</main>
`)
//line views/readers.qtpl:161
//line views/readers.qtpl:155
streamviewScripts(qw422016)
//line views/readers.qtpl:161
//line views/readers.qtpl:155
qw422016.N().S(`
`)
//line views/readers.qtpl:162
//line views/readers.qtpl:156
}
//line views/readers.qtpl:162
//line views/readers.qtpl:156
func WriteRevision(qq422016 qtio422016.Writer, meta viewutil.Meta, h hyphae.Hypha, contents, revHash string) {
//line views/readers.qtpl:162
//line views/readers.qtpl:156
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/readers.qtpl:162
//line views/readers.qtpl:156
StreamRevision(qw422016, meta, h, contents, revHash)
//line views/readers.qtpl:162
//line views/readers.qtpl:156
qt422016.ReleaseWriter(qw422016)
//line views/readers.qtpl:162
//line views/readers.qtpl:156
}
//line views/readers.qtpl:162
//line views/readers.qtpl:156
func Revision(meta viewutil.Meta, h hyphae.Hypha, contents, revHash string) string {
//line views/readers.qtpl:162
//line views/readers.qtpl:156
qb422016 := qt422016.AcquireByteBuffer()
//line views/readers.qtpl:162
//line views/readers.qtpl:156
WriteRevision(qb422016, meta, h, contents, revHash)
//line views/readers.qtpl:162
//line views/readers.qtpl:156
qs422016 := string(qb422016.B)
//line views/readers.qtpl:162
//line views/readers.qtpl:156
qt422016.ReleaseByteBuffer(qb422016)
//line views/readers.qtpl:162
//line views/readers.qtpl:156
return qs422016
//line views/readers.qtpl:162
//line views/readers.qtpl:156
}
//line views/readers.qtpl:164
//line views/readers.qtpl:158
func streamviewScripts(qw422016 *qt422016.Writer) {
//line views/readers.qtpl:164
//line views/readers.qtpl:158
qw422016.N().S(`
`)
//line views/readers.qtpl:165
//line views/readers.qtpl:159
for _, scriptPath := range cfg.ViewScripts {
//line views/readers.qtpl:165
//line views/readers.qtpl:159
qw422016.N().S(`
<script src="`)
//line views/readers.qtpl:166
//line views/readers.qtpl:160
qw422016.E().S(scriptPath)
//line views/readers.qtpl:166
//line views/readers.qtpl:160
qw422016.N().S(`"></script>
`)
//line views/readers.qtpl:167
//line views/readers.qtpl:161
}
//line views/readers.qtpl:167
//line views/readers.qtpl:161
qw422016.N().S(`
`)
//line views/readers.qtpl:168
//line views/readers.qtpl:162
}
//line views/readers.qtpl:168
//line views/readers.qtpl:162
func writeviewScripts(qq422016 qtio422016.Writer) {
//line views/readers.qtpl:168
//line views/readers.qtpl:162
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/readers.qtpl:168
//line views/readers.qtpl:162
streamviewScripts(qw422016)
//line views/readers.qtpl:168
//line views/readers.qtpl:162
qt422016.ReleaseWriter(qw422016)
//line views/readers.qtpl:168
//line views/readers.qtpl:162
}
//line views/readers.qtpl:168
//line views/readers.qtpl:162
func viewScripts() string {
//line views/readers.qtpl:168
//line views/readers.qtpl:162
qb422016 := qt422016.AcquireByteBuffer()
//line views/readers.qtpl:168
//line views/readers.qtpl:162
writeviewScripts(qb422016)
//line views/readers.qtpl:168
//line views/readers.qtpl:162
qs422016 := string(qb422016.B)
//line views/readers.qtpl:168
//line views/readers.qtpl:162
qt422016.ReleaseByteBuffer(qb422016)
//line views/readers.qtpl:168
//line views/readers.qtpl:162
return qs422016
//line views/readers.qtpl:168
//line views/readers.qtpl:162
}