From 0b2e52b99bca716aad83edf4fe786d05b369415b Mon Sep 17 00:00:00 2001 From: Mikhail Chekan Date: Wed, 1 Sep 2021 01:12:55 +0800 Subject: [PATCH] Separate pathographic sorting code --- hyphae/iterators.go | 35 +++++++++++++++++++++++++++++++++++ shroom/search.go | 28 +++------------------------- 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/hyphae/iterators.go b/hyphae/iterators.go index 8e5fcd5..4c06216 100644 --- a/hyphae/iterators.go +++ b/hyphae/iterators.go @@ -3,6 +3,7 @@ package hyphae import ( "strings" + "sort" ) // YieldExistingHyphae iterates over all hyphae and yields all existing ones. @@ -33,6 +34,40 @@ func FilterTextHyphae(src chan *Hypha) chan *Hypha { return sink } +// PathographicSort sorts paths inside the source channel, preserving the path tree structure +func PathographicSort(src chan string) <-chan string { + out := make(chan string) + go func() { + // To make it unicode-friendly and lean, we cast every string into rune slices, sort, and only then cast them back + raw := make([][]rune, 0) + for h := range src { + raw = append(raw, []rune(h)) + } + sort.Slice(raw, func(i, j int) bool { + const slash rune = 47 // == '/' + // Classic lexicographical sort with a twist + c := 0 + for { + if c == len(raw[i]) { return true } + if c == len(raw[j]) { return false } + if raw[i][c] == raw[j][c] { + c++ + } else { + // The twist: subhyphae-awareness is about pushing slash upwards + if raw[i][c] == slash { return true } + if raw[j][c] == slash { return false } + return raw[i][c] < raw[j][c] + } + } + }) + for _, name := range raw { + out <- string(name) + } + close(out) + }() + return out +} + // Subhyphae returns slice of subhyphae. func (h *Hypha) Subhyphae() []*Hypha { hyphae := []*Hypha{} diff --git a/shroom/search.go b/shroom/search.go index bdce218..1497ad8 100644 --- a/shroom/search.go +++ b/shroom/search.go @@ -1,7 +1,6 @@ package shroom import ( - "sort" "strings" "github.com/bouncepaw/mycorrhiza/hyphae" @@ -11,37 +10,16 @@ import ( func YieldHyphaNamesContainingString(query string) <-chan string { query = util.CanonicalName(query) out := make(chan string) + sorted := hyphae.PathographicSort(out) go func() { - // To make it unicode-friendly and lean, we cast every string into rune slices, sort, and only then cast them back - raw := make([][]rune, 0) for h := range hyphae.YieldExistingHyphae() { if hyphaNameMatchesString(h.Name, query) { - raw = append(raw, []rune(h.Name)) + out <- h.Name } } - sort.Slice(raw, func(i, j int) bool { - const slash rune = 47 // == '/' - // Classic lexicographical sort with a twist - c := 0 - for { - if c == len(raw[i]) { return true } - if c == len(raw[j]) { return false } - if raw[i][c] == raw[j][c] { - c++ - } else { - // The twist: subhyphae-awareness is about pushing slash upwards - if raw[i][c] == slash { return true } - if raw[j][c] == slash { return false } - return raw[i][c] < raw[j][c] - } - } - }) - for _, name := range raw { - out <- string(name) - } close(out) }() - return out + return sorted } // This thing gotta be changed one day, when a hero has time to implement a good searching algorithm.