diff --git a/hyphae/iteration/iteration.go b/hyphae/iteration/iteration.go
deleted file mode 100644
index 90b4071..0000000
--- a/hyphae/iteration/iteration.go
+++ /dev/null
@@ -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
-)
diff --git a/tree/tree.go b/tree/tree.go
index 97b519e..7f00a3c 100644
--- a/tree/tree.go
+++ b/tree/tree.go
@@ -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, '/')
- )
- 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
- }
-
- i7n = iteration.NewIteration()
+ root = child{hyphaName, true, make([]child, 0)}
+ descendantPrefix = hyphaName + "/"
+ parent = path.Dir(hyphaName) // Beware, it might be . and whatnot.
+ slashCount = strings.Count(hyphaName, "/")
)
- siblingsMap[hyphaName] = true
-
- 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
- }
- }
- 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()
- )
- 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
+ // Skipping non-siblings.
+ if !(path.Dir(name) == parent && slashCount == strings.Count(name, "/")) {
+ continue
+ }
- 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(`
%s
`, util.BeautifulName(path.Base(hyphaName)))
- } else {
- siblingsHTML += siblingHTML(s)
+ if (name < hyphaName) && (name > prev) {
+ prev = name
+ } else if (name > hyphaName) && (name < next || next == "") {
+ next = name
}
}
- 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(`
%s
`, 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
diff --git a/tree/view.qtpl b/tree/view.qtpl
index 4d85ae0..f6fe3ef 100644
--- a/tree/view.qtpl
+++ b/tree/view.qtpl
@@ -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:
{% endfunc %}
-
-{% func siblingHTML(s *sibling) %}
-