Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improving file panel rendering. #589

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 55 additions & 60 deletions src/internal/function.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"os"
"path/filepath"
"regexp"
"slices"
"sort"
"strconv"
"strings"
Expand Down Expand Up @@ -41,104 +42,98 @@ func returnFocusType(focusPanel focusPanelType) filePanelFocusType {
return secondFocus
}

func returnFolderElement(location string, displayDotFile bool, sortOptions sortOptionsModelData) (directoryElement []element) {

files, err := os.ReadDir(location)
if len(files) == 0 {
func returnDirElement(location string, displayDotFile bool, sortOptions sortOptionsModelData) (directoryElement []element) {
dirEntries, err := os.ReadDir(location)
if err != nil {
outPutLog("Return folder element function error", err)
return directoryElement
}

if err != nil {
outPutLog("Return folder element function error", err)
dirEntries = slices.DeleteFunc(dirEntries, func(e os.DirEntry) bool {
// Entries not needed to be considered
_, err := e.Info()
return err != nil || (strings.HasPrefix(e.Name(), ".") && !displayDotFile)
})

// No files/directoes to process
if len(dirEntries) == 0 {
return directoryElement
}

// Sort files
var order func(i, j int) bool
reversed := sortOptions.reversed

// Todo : These strings should not be hardcoded here, but defined as constants
switch sortOptions.options[sortOptions.selected] {
case "Name":
order = func(i, j int) bool {
_, errI := os.ReadDir(location + "/" + files[i].Name())
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We dont need to do ReadDir syscall here at all. We can just decide based on IsDir()

_, errJ := os.ReadDir(location + "/" + files[j].Name())
if (files[i].IsDir() || errI == nil) && (!files[j].IsDir() && errJ != nil) {
return true
}
if (!files[i].IsDir() && errI != nil) && (files[j].IsDir() || errJ == nil) {
return false
slog.Debug("sort func", "i", i, "j", j)

// One of them is a directory, and other is not
if dirEntries[i].IsDir() != dirEntries[j].IsDir() {
return dirEntries[i].IsDir()
}

if Config.CaseSensitiveSort {
return files[i].Name() < files[j].Name() != reversed
return dirEntries[i].Name() < dirEntries[j].Name() != reversed
} else {
return strings.ToLower(files[i].Name()) < strings.ToLower(files[j].Name()) != reversed
return strings.ToLower(dirEntries[i].Name()) < strings.ToLower(dirEntries[j].Name()) != reversed
}
}
case "Size":
order = func(i, j int) bool {
// Directories at the top sorted by direct child count (not recursive)
// Files sorted by size
fileInfoI, _ := files[i].Info()
fileInfoJ, _ := files[j].Info()
_, errI := os.ReadDir(location + "/" + files[i].Name())
_, errJ := os.ReadDir(location + "/" + files[j].Name())

if (files[i].IsDir() || errI == nil) && (!files[j].IsDir() && errJ != nil) {
return true
}
if (!files[i].IsDir() && errI != nil) && (files[j].IsDir() || errJ == nil) {
return false
// One of them is a directory, and other is not
if dirEntries[i].IsDir() != dirEntries[j].IsDir() {
return dirEntries[i].IsDir()
}
if files[i].IsDir() && files[j].IsDir() {
filesI, err := os.ReadDir(filepath.Join(location, files[i].Name()))

// This needs to be improved, and we should sort by actual size only
// Repeated recursive read would be slow, so we could cache
if dirEntries[i].IsDir() && dirEntries[j].IsDir() {
filesI, err := os.ReadDir(filepath.Join(location, dirEntries[i].Name()))
// No need of early return, we only call len() on filesI, so nil would
// just result in 0
if err != nil {
outPutLog("Error when reading directory", err)
outPutLog("Error when reading directory during sort", err)
}
filesJ, err := os.ReadDir(filepath.Join(location, files[j].Name()))
filesJ, err := os.ReadDir(filepath.Join(location, dirEntries[j].Name()))
if err != nil {
outPutLog("Error when reading directory", err)
outPutLog("Error when reading directory during sort", err)
}
return len(filesI) < len(filesJ) != reversed
} else {
// No need for err check, we already filtered out dirEntries with err != nil in Info() call
fileInfoI, _ := dirEntries[i].Info()
fileInfoJ, _ := dirEntries[j].Info()
return fileInfoI.Size() < fileInfoJ.Size() != reversed
}
return fileInfoI.Size() < fileInfoJ.Size() != reversed

}
case "Date Modified":
order = func(i, j int) bool {
fileInfoI, _ := files[i].Info()
fileInfoJ, _ := files[j].Info()
// No need for err check, we already filtered out dirEntries with err != nil in Info() call
fileInfoI, _ := dirEntries[i].Info()
fileInfoJ, _ := dirEntries[j].Info()
return fileInfoI.ModTime().After(fileInfoJ.ModTime()) != reversed
}
}

sort.Slice(files, order)

for _, item := range files {
fileInfo, err := item.Info()
Copy link
Collaborator Author

@lazysegtree lazysegtree Feb 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need of filtering dirEntries after. Filtered them before the sort.

if err != nil {
continue
}

if !displayDotFile && strings.HasPrefix(fileInfo.Name(), ".") {
continue
}
if fileInfo == nil {
continue
}
newElement := element{
sort.Slice(dirEntries, order)
for _, item := range dirEntries {
directoryElement = append(directoryElement, element{
name: item.Name(),
directory: item.IsDir(),
}
if location == "/" {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is redundant. filepath.Join() handles location being "/"

newElement.location = location + item.Name()
} else {
newElement.location = filepath.Join(location, item.Name())
}
directoryElement = append(directoryElement, newElement)
location: filepath.Join(location, item.Name()),
})
}

return directoryElement
}

func returnFolderElementBySearchString(location string, displayDotFile bool, searchString string) (folderElement []element) {
func returnDirElementBySearchString(location string, displayDotFile bool, searchString string) (dirElement []element) {

items, err := os.ReadDir(location)
if err != nil {
Expand Down Expand Up @@ -182,15 +177,15 @@ func returnFolderElementBySearchString(location string, displayDotFile bool, sea
for _, item := range result.Matches {
resultItem := folderElementMap[item.Key]
resultItem.matchRate = float64(item.Score)
folderElement = append(folderElement, resultItem)
dirElement = append(dirElement, resultItem)
}

// Sort folders and files by match rate
sort.Slice(folderElement, func(i, j int) bool {
return folderElement[i].matchRate > folderElement[j].matchRate
sort.Slice(dirElement, func(i, j int) bool {
return dirElement[i].matchRate > dirElement[j].matchRate
})

return folderElement
return dirElement
}

func panelElementHeight(mainPanelHeight int) int {
Expand Down
2 changes: 1 addition & 1 deletion src/internal/get_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ func getDirectories() []directory {
location: "Disks+-*/=?",
})
directories = append(directories, getExternalMediaFolders()...)

return directories
}

Expand Down Expand Up @@ -66,6 +65,7 @@ func getPinnedDirectories() []directory {
jsonData, err := os.ReadFile(variable.PinnedFile)
if err != nil {
outPutLog("Read superfile data error", err)
return directories
}

// Check if the data is in the old format
Expand Down
4 changes: 2 additions & 2 deletions src/internal/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -433,9 +433,9 @@ func (m *model) getFilePanelItems() {

// Get file names based on search bar filter
if filePanel.searchBar.Value() != "" {
fileElement = returnFolderElementBySearchString(filePanel.location, m.toggleDotFile, filePanel.searchBar.Value())
fileElement = returnDirElementBySearchString(filePanel.location, m.toggleDotFile, filePanel.searchBar.Value())
} else {
fileElement = returnFolderElement(filePanel.location, m.toggleDotFile, filePanel.sortOptions.data)
fileElement = returnDirElement(filePanel.location, m.toggleDotFile, filePanel.sortOptions.data)
}
// Update file panel list
filePanel.element = fileElement
Expand Down
Loading