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(``, 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) %} -
  • - - {%s util.BeautifulName(path.Base(s.name)) %} - - {% if s.directSubhyphaeCount > 0 %} - - {%d s.directSubhyphaeCount %} - - {% endif %} - {% if s.indirectSubhyphaeCount > 0 %} - - ({%d s.indirectSubhyphaeCount %}) - - {% endif %} - - -
  • -{% endfunc %} diff --git a/tree/view.qtpl.go b/tree/view.qtpl.go index b8627c5..1c1c89a 100644 --- a/tree/view.qtpl.go +++ b/tree/view.qtpl.go @@ -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(` -
  • - - `) -//line tree/view.qtpl:37 - qw422016.E().S(util.BeautifulName(path.Base(s.name))) -//line tree/view.qtpl:37 - qw422016.N().S(` - - `) -//line tree/view.qtpl:39 - if s.directSubhyphaeCount > 0 { -//line tree/view.qtpl:39 - qw422016.N().S(` - - `) -//line tree/view.qtpl:41 - qw422016.N().D(s.directSubhyphaeCount) -//line tree/view.qtpl:41 - qw422016.N().S(` - - `) -//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(` - - (`) -//line tree/view.qtpl:46 - qw422016.N().D(s.indirectSubhyphaeCount) -//line tree/view.qtpl:46 - qw422016.N().S(`) - - `) -//line tree/view.qtpl:48 - } -//line tree/view.qtpl:48 - qw422016.N().S(` - - -
  • -`) -//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 -} diff --git a/views/readers.qtpl b/views/readers.qtpl index c8c2da2..e525f39 100644 --- a/views/readers.qtpl +++ b/views/readers.qtpl @@ -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 %}
    @@ -141,12 +141,6 @@ If you rename .prevnext, change the docs too.
    {%s= categories.CategoryCard(meta, h.CanonicalName()) %} -{% if cfg.UseSiblingHyphaeSidebar %} - -{% endif %} {%= viewScripts() %} {% endfunc %} diff --git a/views/readers.qtpl.go b/views/readers.qtpl.go index c6dfd99..89cc234 100644 --- a/views/readers.qtpl.go +++ b/views/readers.qtpl.go @@ -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 { -//line views/readers.qtpl:144 - qw422016.N().S(` - -`) -//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 +//line views/readers.qtpl:144 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(`

    `) -//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(` `) -//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(`

    `) -//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(`
    `) -//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(` `) -//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 }