Skip to content

Commit

Permalink
feat(nav): cache traverse item dir status (#413)
Browse files Browse the repository at this point in the history
  • Loading branch information
plastikfan committed Jan 18, 2024
1 parent 83147eb commit 2504d1a
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 93 deletions.
13 changes: 7 additions & 6 deletions xfs/nav/error-handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,13 @@ func (h *notifyCallbackErrorHandler) accept(params *fileSystemErrorParams) error
},
)

callbackErr := params.frame.proxy(&TraverseItem{
Path: params.path,
Info: params.info,
Error: err,
Children: []fs.DirEntry{},
}, nil)
callbackErr := params.frame.proxy(newTraverseItem(
params.path,
nil,
params.info,
nil,
err,
), nil)

return callbackErr
}
26 changes: 14 additions & 12 deletions xfs/nav/navigation-agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,13 @@ func (a *navigationAgent) top(params *agentTopParams) (*TraverseResult, error) {
frame: params.frame,
})
} else {
item := &TraverseItem{
Path: params.top, Info: info,
Children: []fs.DirEntry{},
}
item := newTraverseItem(
params.top,
nil,
info,
nil,
nil,
)

_, le = params.impl.traverse(&traverseParams{
current: item,
Expand Down Expand Up @@ -156,14 +159,13 @@ func (a *navigationAgent) traverse(params *agentTraverseParams) (*TraverseItem,
}

if current == nil {
current = &TraverseItem{
Path: path,
Info: info,
Entry: entry,
Error: e,
Children: []fs.DirEntry{},
Parent: params.parent,
}
current = newTraverseItem(
path,
entry,
info,
params.parent,
e,
)
}

if skipItem, err := params.impl.traverse(&traverseParams{
Expand Down
14 changes: 7 additions & 7 deletions xfs/nav/sampling-while-iterator.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,13 +180,13 @@ func (i *directoryEntryWhileIt) enumerate() *DirectoryContents {
}

path := filepath.Join(parent.Path, entry.Name())
child := &TraverseItem{
Path: path,
Info: info,
Entry: entry,
Error: err,
Parent: parent,
}
child := newTraverseItem(
path,
entry,
info,
parent,
err,
)

stash := i.navigator.inspect(&traverseParams{ // preview
current: child,
Expand Down
68 changes: 0 additions & 68 deletions xfs/nav/traverse-defs.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,74 +8,6 @@ import (
"github.com/snivilised/extendio/xfs/utils"
)

// ExtendedItem provides extended information if the client requests
// it by setting the DoExtend boolean in the traverse options.
type ExtendedItem struct {
Depth int // traversal depth relative to the root
IsLeaf bool // defines whether this node a leaf node
Name string // derived as the leaf segment from filepath.Split
Parent string // derived as the directory from filepath.Split
SubPath string // represents the path between the root and the current item
NodeScope FilterScopeBiEnum // type of folder corresponding to the Filter Scope
Custom any // to be set and used by the client
}

// TraverseItem info provided for each file system entity encountered
// during traversal. The root item does not have a DirEntry because it is
// not created as a result of a readDir invoke. Therefore, the client has
// to know that when its function is called back, they will be no DirEntry
// for the root entity.
type TraverseItem struct {
Path string
Entry fs.DirEntry // contains a FileInfo via Info() function
Info fs.FileInfo // optional file info instance
Extension ExtendedItem // extended information about the file system node, if requested
Error error
Children []fs.DirEntry
filteredOut bool
Parent *TraverseItem
admit bool
}

// clone makes shallow copy of TraverseItem (except the error).
func (ti *TraverseItem) clone() *TraverseItem {
return &TraverseItem{
Path: ti.Path,
Entry: ti.Entry,
Info: ti.Info,
Extension: ti.Extension,
Children: ti.Children,
}
}

func (ti *TraverseItem) IsDir() bool {
if !utils.IsNil(ti.Entry) {
return ti.Entry.IsDir()
} else if !utils.IsNil(ti.Info) {
return ti.Info.IsDir()
}
// only get here in error scenario, because neither Entry or Info is set
//
return false
}

func (ti *TraverseItem) filtered() {
// 📚 filtered is used by sampling functions to mark an item as already having
// been filtered. Sampling functions require the ability to 'Preview' an item
// so that it can be filtered, but doing so means there is potential for a
// child item to be double filtered. By marking an item is being pre-filtered,
// when the navigation process reaches the child entry in its own right (as
// opposed to being previewed), the filter can be bypassed and the client
// callback for this item can be invoked; ie if an item passes filtering at
// the preview stage, it does not needed to be filtered again.
//
ti.admit = true
}

func (ti *TraverseItem) key() string {
return ti.Extension.SubPath
}

// TraverseSubscription type to define traversal subscription (for which file system
// items the client defined callback are invoked for).
type TraverseSubscription uint
Expand Down
96 changes: 96 additions & 0 deletions xfs/nav/traverse-item.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package nav

import (
"io/fs"

"github.com/snivilised/extendio/xfs/utils"
)

// ExtendedItem provides extended information if the client requests
// it by setting the DoExtend boolean in the traverse options.
type ExtendedItem struct {
Depth int // traversal depth relative to the root
IsLeaf bool // defines whether this node a leaf node
Name string // derived as the leaf segment from filepath.Split
Parent string // derived as the directory from filepath.Split
SubPath string // represents the path between the root and the current item
NodeScope FilterScopeBiEnum // type of folder corresponding to the Filter Scope
Custom any // to be set and used by the client
}

// TraverseItem info provided for each file system entity encountered
// during traversal. The root item does not have a DirEntry because it is
// not created as a result of a readDir invoke. Therefore, the client has
// to know that when its function is called back, they will be no DirEntry
// for the root entity.
type TraverseItem struct {
Path string
Entry fs.DirEntry // contains a FileInfo via Info() function
Info fs.FileInfo // optional file info instance
Extension ExtendedItem // extended information about the file system node, if requested
Error error
Children []fs.DirEntry
filteredOut bool
Parent *TraverseItem
admit bool
dir bool
}

func isDir(item *TraverseItem) bool {
if !utils.IsNil(item.Entry) {
return item.Entry.IsDir()
} else if !utils.IsNil(item.Info) {
return item.Info.IsDir()
}
// only get here in error scenario, because neither Entry or Info is set
//
return false
}

func newTraverseItem(
path string, entry fs.DirEntry, info fs.FileInfo, parent *TraverseItem, err error,
) *TraverseItem {
item := &TraverseItem{
Path: path,
Entry: entry,
Info: info,
Parent: parent,
Children: []fs.DirEntry{},
Error: err,
}
item.dir = isDir(item)

return item
}

// clone makes shallow copy of TraverseItem (except the error).
func (ti *TraverseItem) clone() *TraverseItem {
return &TraverseItem{
Path: ti.Path,
Entry: ti.Entry,
Info: ti.Info,
Extension: ti.Extension,
Children: ti.Children,
}
}

func (ti *TraverseItem) IsDir() bool {
return ti.dir
}

func (ti *TraverseItem) filtered() {
// 📚 filtered is used by sampling functions to mark an item as already having
// been filtered. Sampling functions require the ability to 'Preview' an item
// so that it can be filtered, but doing so means there is potential for a
// child item to be double filtered. By marking an item is being pre-filtered,
// when the navigation process reaches the child entry in its own right (as
// opposed to being previewed), the filter can be bypassed and the client
// callback for this item can be invoked; ie if an item passes filtering at
// the preview stage, it does not needed to be filtered again.
//
ti.admit = true
}

func (ti *TraverseItem) key() string {
return ti.Extension.SubPath
}

0 comments on commit 2504d1a

Please sign in to comment.