mirror of
https://github.com/rclone/rclone.git
synced 2024-12-22 23:22:08 +01:00
ncdu: add support for modification time
This commit is contained in:
parent
528fc899fb
commit
64cdbb67b5
@ -89,11 +89,12 @@ func helpText() (tr []string) {
|
||||
" ↑,↓ or k,j to Move",
|
||||
" →,l to enter",
|
||||
" ←,h to return",
|
||||
" c toggle counts",
|
||||
" g toggle graph",
|
||||
" c toggle counts",
|
||||
" a toggle average size in directory",
|
||||
" m toggle modified time",
|
||||
" u toggle human-readable format",
|
||||
" n,s,C,A sort by name,size,count,average size",
|
||||
" n,s,C,A,M sort by name,size,count,asize,mtime",
|
||||
" d delete file/directory",
|
||||
" v select file/directory",
|
||||
" V enter visual select mode",
|
||||
@ -131,12 +132,14 @@ type UI struct {
|
||||
showGraph bool // toggle showing graph
|
||||
showCounts bool // toggle showing counts
|
||||
showDirAverageSize bool // toggle average size
|
||||
showModTime bool // toggle showing timestamps
|
||||
humanReadable bool // toggle human-readable format
|
||||
visualSelectMode bool // toggle visual selection mode
|
||||
sortByName int8 // +1 for normal, 0 for off, -1 for reverse
|
||||
sortBySize int8
|
||||
sortByName int8 // +1 for normal (lexical), 0 for off, -1 for reverse
|
||||
sortBySize int8 // +1 for normal (largest first), 0 for off, -1 for reverse (smallest first)
|
||||
sortByCount int8
|
||||
sortByAverageSize int8
|
||||
sortByModTime int8 // +1 for normal (newest first), 0 for off, -1 for reverse (oldest first)
|
||||
dirPosMap map[string]dirPos // store for directory positions
|
||||
selectedEntries map[string]dirPos // selected entries of current directory
|
||||
}
|
||||
@ -332,6 +335,7 @@ func (u *UI) hasEmptyDir() bool {
|
||||
|
||||
// Draw the current screen
|
||||
func (u *UI) Draw() error {
|
||||
ctx := context.Background()
|
||||
w, h := termbox.Size()
|
||||
u.dirListHeight = h - 3
|
||||
|
||||
@ -365,7 +369,13 @@ func (u *UI) Draw() error {
|
||||
if y >= h-1 {
|
||||
break
|
||||
}
|
||||
attrs, err := u.d.AttrI(u.sortPerm[n])
|
||||
var attrs scan.Attrs
|
||||
var err error
|
||||
if u.showModTime {
|
||||
attrs, err = u.d.AttrWithModTimeI(ctx, u.sortPerm[n])
|
||||
} else {
|
||||
attrs, err = u.d.AttrI(u.sortPerm[n])
|
||||
}
|
||||
_, isSelected := u.selectedEntries[entry.String()]
|
||||
fg := termbox.ColorWhite
|
||||
if attrs.EntriesHaveErrors {
|
||||
@ -421,6 +431,9 @@ func (u *UI) Draw() error {
|
||||
extras += strings.Repeat(" ", len(ss))
|
||||
}
|
||||
}
|
||||
if u.showModTime {
|
||||
extras += attrs.ModTime.Local().Format("2006-01-02 15:04:05") + " "
|
||||
}
|
||||
if showEmptyDir {
|
||||
if attrs.IsDir && attrs.Count == 0 && fileFlag == ' ' {
|
||||
fileFlag = 'e'
|
||||
@ -656,8 +669,15 @@ type ncduSort struct {
|
||||
// Less is part of sort.Interface.
|
||||
func (ds *ncduSort) Less(i, j int) bool {
|
||||
var iAvgSize, jAvgSize float64
|
||||
iattrs, _ := ds.d.AttrI(ds.sortPerm[i])
|
||||
jattrs, _ := ds.d.AttrI(ds.sortPerm[j])
|
||||
var iattrs, jattrs scan.Attrs
|
||||
if ds.u.sortByModTime != 0 {
|
||||
ctx := context.Background()
|
||||
iattrs, _ = ds.d.AttrWithModTimeI(ctx, ds.sortPerm[i])
|
||||
jattrs, _ = ds.d.AttrWithModTimeI(ctx, ds.sortPerm[j])
|
||||
} else {
|
||||
iattrs, _ = ds.d.AttrI(ds.sortPerm[i])
|
||||
jattrs, _ = ds.d.AttrI(ds.sortPerm[j])
|
||||
}
|
||||
iname, jname := ds.entries[ds.sortPerm[i]].Remote(), ds.entries[ds.sortPerm[j]].Remote()
|
||||
if iattrs.Count > 0 {
|
||||
iAvgSize = iattrs.AverageSize()
|
||||
@ -679,6 +699,14 @@ func (ds *ncduSort) Less(i, j int) bool {
|
||||
if iattrs.Size != jattrs.Size {
|
||||
return iattrs.Size > jattrs.Size
|
||||
}
|
||||
case ds.u.sortByModTime < 0:
|
||||
if iattrs.ModTime != jattrs.ModTime {
|
||||
return iattrs.ModTime.Before(jattrs.ModTime)
|
||||
}
|
||||
case ds.u.sortByModTime > 0:
|
||||
if iattrs.ModTime != jattrs.ModTime {
|
||||
return iattrs.ModTime.After(jattrs.ModTime)
|
||||
}
|
||||
case ds.u.sortByCount < 0:
|
||||
if iattrs.Count != jattrs.Count {
|
||||
return iattrs.Count < jattrs.Count
|
||||
@ -847,8 +875,9 @@ func NewUI(f fs.Fs) *UI {
|
||||
showCounts: false,
|
||||
showDirAverageSize: false,
|
||||
humanReadable: true,
|
||||
sortByName: 0, // +1 for normal, 0 for off, -1 for reverse
|
||||
sortBySize: 1,
|
||||
sortByName: 0,
|
||||
sortBySize: 1, // Sort by largest first
|
||||
sortByModTime: 0,
|
||||
sortByCount: 0,
|
||||
dirPosMap: make(map[string]dirPos),
|
||||
selectedEntries: make(map[string]dirPos),
|
||||
@ -937,6 +966,8 @@ outer:
|
||||
u.enter()
|
||||
case 'c':
|
||||
u.showCounts = !u.showCounts
|
||||
case 'm':
|
||||
u.showModTime = !u.showModTime
|
||||
case 'g':
|
||||
u.showGraph = !u.showGraph
|
||||
case 'a':
|
||||
@ -945,6 +976,8 @@ outer:
|
||||
u.toggleSort(&u.sortByName)
|
||||
case 's':
|
||||
u.toggleSort(&u.sortBySize)
|
||||
case 'M':
|
||||
u.toggleSort(&u.sortByModTime)
|
||||
case 'v':
|
||||
u.toggleSelectForCursor()
|
||||
case 'V':
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"path"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/rclone/rclone/fs"
|
||||
"github.com/rclone/rclone/fs/walk"
|
||||
@ -31,6 +32,7 @@ type Dir struct {
|
||||
// in the total count. They are not included in the size, i.e. treated
|
||||
// as empty files, which means the size may be underestimated.
|
||||
type Attrs struct {
|
||||
ModTime time.Time
|
||||
Size int64
|
||||
Count int64
|
||||
CountUnknownSize int64
|
||||
@ -193,20 +195,33 @@ func (d *Dir) Attr() (size int64, count int64) {
|
||||
return d.size, d.count
|
||||
}
|
||||
|
||||
// attrI returns the size, count and flags for the i-th directory entry
|
||||
func (d *Dir) attrI(i int) (attrs Attrs, err error) {
|
||||
subDir, isDir := d.getDir(i)
|
||||
if !isDir {
|
||||
return Attrs{time.Time{}, d.entries[i].Size(), 0, 0, false, true, d.entriesHaveErrors}, d.readError
|
||||
}
|
||||
if subDir == nil {
|
||||
return Attrs{time.Time{}, 0, 0, 0, true, false, false}, nil
|
||||
}
|
||||
size, count := subDir.Attr()
|
||||
return Attrs{time.Time{}, size, count, subDir.countUnknownSize, true, true, subDir.entriesHaveErrors}, subDir.readError
|
||||
}
|
||||
|
||||
// AttrI returns the size, count and flags for the i-th directory entry
|
||||
func (d *Dir) AttrI(i int) (attrs Attrs, err error) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
subDir, isDir := d.getDir(i)
|
||||
return d.attrI(i)
|
||||
}
|
||||
|
||||
if !isDir {
|
||||
return Attrs{d.entries[i].Size(), 0, 0, false, true, d.entriesHaveErrors}, d.readError
|
||||
}
|
||||
if subDir == nil {
|
||||
return Attrs{0, 0, 0, true, false, false}, nil
|
||||
}
|
||||
size, count := subDir.Attr()
|
||||
return Attrs{size, count, subDir.countUnknownSize, true, true, subDir.entriesHaveErrors}, subDir.readError
|
||||
// AttrWithModTimeI returns the modtime, size, count and flags for the i-th directory entry
|
||||
func (d *Dir) AttrWithModTimeI(ctx context.Context, i int) (attrs Attrs, err error) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
attrs, err = d.attrI(i)
|
||||
attrs.ModTime = d.entries[i].ModTime(ctx)
|
||||
return
|
||||
}
|
||||
|
||||
// Scan the Fs passed in, returning a root directory channel and an
|
||||
|
Loading…
Reference in New Issue
Block a user