mirror of
https://github.com/IllusionMan1212/ffui.git
synced 2026-10-24 02:12:35 +00:00
fix: natsort files in ascending order
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/charmbracelet/bubbles/progress"
|
"github.com/charmbracelet/bubbles/progress"
|
||||||
@@ -138,6 +139,9 @@ type initUi struct {
|
|||||||
func (m *model) statFile() tea.Msg {
|
func (m *model) statFile() tea.Msg {
|
||||||
if m.IsDirectory {
|
if m.IsDirectory {
|
||||||
entries, _ := os.ReadDir(m.Path)
|
entries, _ := os.ReadDir(m.Path)
|
||||||
|
|
||||||
|
sort.Sort(DirEntrySlice(entries))
|
||||||
|
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
fullFilePath := filepath.Join(m.Path, entry.Name())
|
fullFilePath := filepath.Join(m.Path, entry.Name())
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/fs"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Less does a 'natural' comparison on the two strings.
|
||||||
|
//
|
||||||
|
// This is occasionally nicknamed 'natsort'.
|
||||||
|
//
|
||||||
|
// It treats decimal numbers as value, so that Less("10", "2") return true.
|
||||||
|
func Less(a, b string) bool {
|
||||||
|
for {
|
||||||
|
if a == b {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if p := commonPrefix(a, b); p != 0 {
|
||||||
|
a = a[p:]
|
||||||
|
b = b[p:]
|
||||||
|
}
|
||||||
|
if ia := digits(a); ia > 0 {
|
||||||
|
if ib := digits(b); ib > 0 {
|
||||||
|
// Both sides have digits.
|
||||||
|
an, aerr := strconv.ParseUint(a[:ia], 10, 64)
|
||||||
|
bn, berr := strconv.ParseUint(b[:ib], 10, 64)
|
||||||
|
if aerr == nil && berr == nil {
|
||||||
|
if an != bn {
|
||||||
|
return an > bn
|
||||||
|
}
|
||||||
|
// Semantically the same digits, e.g. "00" == "0", "01" == "1". In
|
||||||
|
// this case, only continue processing if there's trailing data on
|
||||||
|
// both sides, otherwise do lexical comparison.
|
||||||
|
if ia != len(a) && ib != len(b) {
|
||||||
|
a = a[ia:]
|
||||||
|
b = b[ib:]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return a < b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DirEntrySlice attaches the methods of Interface to []string, sorting in
|
||||||
|
// increasing order using natural order.
|
||||||
|
type DirEntrySlice []fs.DirEntry
|
||||||
|
|
||||||
|
func (p DirEntrySlice) Len() int { return len(p) }
|
||||||
|
func (p DirEntrySlice) Less(i, j int) bool { return Less(p[i].Name(), p[j].Name()) }
|
||||||
|
func (p DirEntrySlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
// commonPrefix returns the common prefix except for digits.
|
||||||
|
func commonPrefix(a, b string) int {
|
||||||
|
m := len(a)
|
||||||
|
if n := len(b); n < m {
|
||||||
|
m = n
|
||||||
|
}
|
||||||
|
if m == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
_ = a[m-1]
|
||||||
|
_ = b[m-1]
|
||||||
|
for i := 0; i < m; i++ {
|
||||||
|
ca := a[i]
|
||||||
|
cb := b[i]
|
||||||
|
if (ca >= '0' && ca <= '9') || (cb >= '0' && cb <= '9') || ca != cb {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func digits(s string) int {
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
c := s[i]
|
||||||
|
if c < '0' || c > '9' {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len(s)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user