Skip to content

Commit

Permalink
feat(nav): add poly filter (#381)
Browse files Browse the repository at this point in the history
  • Loading branch information
plastikfan committed Dec 15, 2023
1 parent 1007eb2 commit 7d1de56
Show file tree
Hide file tree
Showing 7 changed files with 456 additions and 3 deletions.
24 changes: 24 additions & 0 deletions xfs/nav/filter-defs.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ const (

// FilterTypeCustomEn client definable filter
FilterTypeCustomEn

// FilterTypePolyEn poly filter
FilterTypePolyEn
)

type allOrderedFilterScopeEnums collections.OrderedKeysMap[FilterScopeBiEnum, string]
Expand Down Expand Up @@ -103,6 +106,16 @@ func (f FilterScopeBiEnum) String() string {
return strings.Join(result, "|")
}

// Set sets the bit position indicated by mask
func (f *FilterScopeBiEnum) Set(mask FilterScopeBiEnum) {
*f |= mask
}

// Clear clears the bit position indicated by mask
func (f *FilterScopeBiEnum) Clear(mask FilterScopeBiEnum) {
*f &^= mask
}

// TraverseFilter filter that can be applied to file system entries. When specified,
// the callback will only be invoked for file system nodes that pass the filter.
type TraverseFilter interface {
Expand Down Expand Up @@ -152,6 +165,17 @@ type FilterDef struct {
// its the client's responsibility to restore this themselves (see
// PersistenceRestorer)
Custom TraverseFilter `json:"-"`

// Poly allows for the definition of a PolyFilter which contains separate
// filters that target files and folders separately. If present, then
// all other fields are redundant, since the filter definitions inside
// Poly should be referred to instead.
Poly *PolyFilterDef
}

type PolyFilterDef struct {
File FilterDef
Folder FilterDef
}

// CompoundTraverseFilter filter that can be applied to a folder's collection of entries
Expand Down
8 changes: 8 additions & 0 deletions xfs/nav/filter-init.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package nav

import "fmt"

// InitFiltersHookFn is the default filter initialiser. This can be overridden or extended
// by the client if the need arises. To extend this behaviour rather than replace it,
// call this function from inside the custom function set on o.Hooks.Filter. To
Expand All @@ -16,6 +18,12 @@ func InitFiltersHookFn(o *TraverseOptions, frame *navigationFrame) {
frame.filters = &NavigationFilters{}

if o.isFilteringActive() {
if o.Store.FilterDefs.Node.Poly != nil {
if (o.Store.Subscription == SubscribeFolders) || (o.Store.Subscription == SubscribeFoldersWithFiles) {
panic(fmt.Errorf("invalid subscription type for poly filter"))
}
}

o.useExtendHook()
applyNodeFilterDecoration(&o.Store.FilterDefs.Node, frame)
}
Expand Down
77 changes: 77 additions & 0 deletions xfs/nav/filter-poly.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package nav

import (
"fmt"
)

// PolyFilter is a dual filter that allows files and folders to be filtered
// independently. The Folder filter only applies when the current item
// is a file. This is because, filtering doesn't affect navigation, it only
// controls wether the client callback is invoked or not. That is to say, if
// a particular folder fails to pass a filter, the callback will not be
// invoked for that folder, but we still descend into it and navigate its
// children. This is the reason why the poly filter is only active when the
// the current item is a filter as the client callback will only be invoked
// for the file if its parent folder passes the poly folder filter and
// the file passes the poly file filter.
type PolyFilter struct {
// File is the filter that applies to a file. Note that the client does
// not have to set the File scope as this is enforced automatically as
// well as ensuring that the Folder scope has not been set. The client is
// still free to set other scopes.
File TraverseFilter

// Folder is the filter that applies to a folder. Note that the client does
// not have to set the Folder scope as this is enforced automatically as
// well as ensuring that the File scope has not been set. The client is
// still free to set other scopes.
Folder TraverseFilter
}

// Description
func (f *PolyFilter) Description() string {
return fmt.Sprintf("Poly - FILE: '%v', FOLDER: '%v'",
f.File.Description(), f.Folder.Description(),
)
}

// Validate ensures that both filters definition are valid, panics when invalid
func (f *PolyFilter) Validate() {
f.File.Validate()
f.Folder.Validate()
}

// Source returns the Sources of both the File and Folder filters separated
// by a '##'
func (f *PolyFilter) Source() string {
return fmt.Sprintf("%v##%v",
f.File.Source(), f.Folder.Source(),
)
}

// IsMatch returns true if the current item is a file and both the current
// file matches the poly file filter and the file's parent folder matches
// the poly folder filter. Returns true of the current item is a folder.
func (f *PolyFilter) IsMatch(item *TraverseItem) bool {
if !item.IsDir() {
return f.Folder.IsMatch(item.Parent) && f.File.IsMatch(item)
}

return true
}

// IsApplicable returns the result of applying IsApplicable to
// the poly Filter filter if the current item is a file, returns false
// for folders.
func (f *PolyFilter) IsApplicable(item *TraverseItem) bool {
if !item.IsDir() {
return f.File.IsApplicable(item)
}

return false
}

// Scope is a bitwise OR combination of both filters
func (f *PolyFilter) Scope() FilterScopeBiEnum {
return f.File.Scope() | f.Folder.Scope()
}
Loading

0 comments on commit 7d1de56

Please sign in to comment.