114 lines
3.7 KiB
Go
114 lines
3.7 KiB
Go
// Package categories provides category management.
|
|
//
|
|
// As per the long pondering, this is how categories (cats for short)
|
|
// work in Mycorrhiza:
|
|
//
|
|
// - Cats are not hyphae. Cats are separate entities. This is not as
|
|
// vibeful as I would have wanted, but seems to be more practical
|
|
// due to //the reasons//.
|
|
// - Cats are stored outside of git. Instead, they are stored in a
|
|
// JSON file, path to which is determined by files.CategoriesJSON.
|
|
// - Due to not being stored in git, no cat history is tracked, and
|
|
// cat operations are not mentioned on the recent changes page.
|
|
// - For cat A, if there are 0 hyphae in the cat, cat A does not
|
|
// exist. If there are 1 or more hyphae in the cat, cat A exists.
|
|
//
|
|
// List of things to do with categories later:
|
|
//
|
|
// - Forbid / in cat names.
|
|
// - Rename categories.
|
|
// - Delete categories.
|
|
// - Bind hyphae.
|
|
package categories
|
|
|
|
import "sync"
|
|
|
|
// listOfCategories returns unsorted names of all categories.
|
|
func listOfCategories() (categoryList []string) {
|
|
mutex.RLock()
|
|
for cat, _ := range categoryToHyphae {
|
|
categoryList = append(categoryList, cat)
|
|
}
|
|
mutex.RUnlock()
|
|
return categoryList
|
|
}
|
|
|
|
// categoriesWithHypha returns what categories have the given hypha. The hypha name must be canonical.
|
|
func categoriesWithHypha(hyphaName string) (categoryList []string) {
|
|
mutex.RLock()
|
|
defer mutex.RUnlock()
|
|
if node, ok := hyphaToCategories[hyphaName]; ok {
|
|
return node.categoryList
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// hyphaeInCategory returns what hyphae are in the category. If the returned slice is empty, the category does not exist, and vice versa. The category name must be canonical.
|
|
func hyphaeInCategory(catName string) (hyphaList []string) {
|
|
mutex.RLock()
|
|
defer mutex.RUnlock()
|
|
if node, ok := categoryToHyphae[catName]; ok {
|
|
return node.hyphaList
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
var mutex sync.RWMutex
|
|
|
|
// AddHyphaToCategory adds the hypha to the category and updates the records on the disk. If the hypha is already in the category, nothing happens. Pass canonical names.
|
|
func AddHyphaToCategory(hyphaName, catName string) {
|
|
mutex.Lock()
|
|
if node, ok := hyphaToCategories[hyphaName]; ok {
|
|
node.storeCategory(catName)
|
|
} else {
|
|
hyphaToCategories[hyphaName] = &hyphaNode{categoryList: []string{catName}}
|
|
}
|
|
|
|
if node, ok := categoryToHyphae[catName]; ok {
|
|
node.storeHypha(hyphaName)
|
|
} else {
|
|
categoryToHyphae[catName] = &categoryNode{hyphaList: []string{hyphaName}}
|
|
}
|
|
mutex.Unlock()
|
|
go saveToDisk()
|
|
}
|
|
|
|
// removeHyphaFromCategory removes the hypha from the category and updates the records on the disk. If the hypha is not in the category, nothing happens. Pass canonical names.
|
|
func removeHyphaFromCategory(hyphaName, catName string) {
|
|
mutex.Lock()
|
|
if node, ok := hyphaToCategories[hyphaName]; ok {
|
|
node.removeCategory(catName)
|
|
if len(node.categoryList) == 0 {
|
|
delete(hyphaToCategories, hyphaName)
|
|
}
|
|
}
|
|
|
|
if node, ok := categoryToHyphae[catName]; ok {
|
|
node.removeHypha(hyphaName)
|
|
if len(node.hyphaList) == 0 {
|
|
delete(categoryToHyphae, catName)
|
|
}
|
|
}
|
|
mutex.Unlock()
|
|
go saveToDisk()
|
|
}
|
|
|
|
// RenameHyphaInAllCategories finds all mentions of oldName and replaces them with newName. Pass canonical names. Make sure newName is not taken. If oldName is not in any category, RenameHyphaInAllCategories is a no-op.
|
|
func RenameHyphaInAllCategories(oldName, newName string) {
|
|
mutex.Lock()
|
|
defer mutex.Unlock()
|
|
if node, ok := hyphaToCategories[oldName]; ok {
|
|
hyphaToCategories[newName] = node
|
|
delete(hyphaToCategories, oldName) // node should still be in memory 🙏
|
|
for _, catName := range node.categoryList {
|
|
if catNode, ok := categoryToHyphae[catName]; ok {
|
|
catNode.removeHypha(oldName)
|
|
catNode.storeHypha(newName)
|
|
}
|
|
}
|
|
}
|
|
go saveToDisk()
|
|
}
|