[mike@maginot]
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
// dx — count files and directories, mwx'2016
|
||||
//
|
||||
// Go-Portierung des Perl-Originals (dx 1.0.2), Ausgabe eingefärbt nach der
|
||||
// mwxcol-Palette (~/src/mwxcol). Ohne Terminal (Pipe, NO_COLOR, --color=never)
|
||||
// bleibt die Ausgabe unverändert einfarbig.
|
||||
// Go port of the Perl original (dx 1.0.2), output coloured after the mwxcol
|
||||
// palette (~/src/mwxcol). Without a terminal (pipe, NO_COLOR, --color=never)
|
||||
// the output stays plain, exactly as it was.
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -22,9 +22,9 @@ import (
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
|
||||
// version ist eine var (keine const), damit build.sh die gebaute Nummer per
|
||||
// -ldflags "-X main.version=…" einsetzen kann. Der Wert hier erscheint nur bei
|
||||
// einem nackten `go build`; die wirklich gebaute Version steht in version.txt.
|
||||
// version is a var, not a const, so build.sh can put the built number in via
|
||||
// -ldflags "-X main.version=…". The value here only ever shows up in a bare
|
||||
// `go build`; the version actually built is the one in version.txt.
|
||||
var version = "2.1.0"
|
||||
|
||||
// ------------------------------------------------------------------ Palette
|
||||
@@ -48,7 +48,7 @@ var (
|
||||
func plain(c rgb) *color.Color { return color.RGB(c.r, c.g, c.b) }
|
||||
func bold(c rgb) *color.Color { return color.New(color.Bold).AddRGB(c.r, c.g, c.b) }
|
||||
|
||||
// Rollen wie im eza-Theme, damit dx und eza dieselbe Datei gleich einfärben.
|
||||
// The roles of the eza theme, so that dx and eza colour the same file alike.
|
||||
var (
|
||||
cWhite = plain(white)
|
||||
cYellow = plain(yellow)
|
||||
@@ -61,8 +61,8 @@ var (
|
||||
cGrey = plain(grey)
|
||||
cDark = plain(dark)
|
||||
cDarker = plain(darker)
|
||||
cDirB = bold(blue) // Verzeichnis
|
||||
cExecB = bold(green) // ausführbar
|
||||
cDirB = bold(blue) // directory
|
||||
cExecB = bold(green) // executable
|
||||
cWhiteB = bold(white)
|
||||
cYellowB = bold(yellow)
|
||||
cOrangeB = bold(orange)
|
||||
@@ -71,14 +71,14 @@ var (
|
||||
cDarkB = bold(dark)
|
||||
)
|
||||
|
||||
// ------------------------------------------------------------------- Zählen
|
||||
// ----------------------------------------------------------------- Counting
|
||||
|
||||
type entry struct {
|
||||
name string // Anzeigename, Verzeichnisse mit "/"
|
||||
name string // display name, directories with a "/"
|
||||
col *color.Color
|
||||
n int64
|
||||
size int64
|
||||
agg bool // Sammelzeile aus -t, kein echter Eintrag
|
||||
agg bool // the summary line from -t, not a real entry
|
||||
}
|
||||
|
||||
type result struct {
|
||||
@@ -103,7 +103,7 @@ func scan(dir string, onlyDirs bool) (result, error) {
|
||||
name := de.Name()
|
||||
path := filepath.Join(dir, name)
|
||||
|
||||
// Perls -d/-f folgen Symlinks; ein toter Link fällt durch beide Tests.
|
||||
// Perl's -d/-f follow symlinks; a dead link fails both tests.
|
||||
st, err := os.Stat(path)
|
||||
if err != nil {
|
||||
atomic.AddInt64(&res.unreadbl, 1)
|
||||
@@ -117,7 +117,7 @@ func scan(dir string, onlyDirs bool) (result, error) {
|
||||
sem <- struct{}{}
|
||||
defer func() { <-sem }()
|
||||
|
||||
// WalkDir folgt Symlinks nicht — wie `find <pfad> -type f`.
|
||||
// WalkDir does not follow symlinks — like `find <path> -type f`.
|
||||
n, size := walk(path, &res.unreadbl)
|
||||
|
||||
col := cDirB
|
||||
@@ -154,7 +154,7 @@ func walk(root string, unreadable *int64) (n, size int64) {
|
||||
atomic.AddInt64(unreadable, 1)
|
||||
return nil
|
||||
}
|
||||
if !d.Type().IsRegular() { // wie find -type f
|
||||
if !d.Type().IsRegular() { // like find -type f
|
||||
return nil
|
||||
}
|
||||
info, err := d.Info()
|
||||
@@ -169,10 +169,10 @@ func walk(root string, unreadable *int64) (n, size int64) {
|
||||
return
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------ Ausgabe
|
||||
// ------------------------------------------------------------------- Output
|
||||
|
||||
// Schwellen wie im Perl-Original; unterhalb von 10 der jeweiligen Einheit
|
||||
// jedoch mit einer Nachkommastelle — "1.9G" statt "2G".
|
||||
// The thresholds of the Perl original; below 10 of the unit in question,
|
||||
// though, with one decimal — "1.9G" instead of "2G".
|
||||
func formSize(b int64) string {
|
||||
const k = 1024
|
||||
f := float64(b)
|
||||
@@ -186,7 +186,7 @@ func formSize(b int64) string {
|
||||
case b > k:
|
||||
return scaled(f/k, "K")
|
||||
default:
|
||||
return fmt.Sprintf("%.0f", f) // ganze Bytes, nie gebrochen
|
||||
return fmt.Sprintf("%.0f", f) // whole bytes, never fractions
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,7 +197,8 @@ func scaled(v float64, unit string) string {
|
||||
return fmt.Sprintf("%.0f%s", v, unit)
|
||||
}
|
||||
|
||||
// Größenrampe wie im eza-Theme: byte/kilo grün, mega gelb, giga orange, huge rot.
|
||||
// The size ramp of the eza theme: byte/kilo green, mega yellow, giga orange,
|
||||
// huge red.
|
||||
func sizeColor(b int64, strong bool) *color.Color {
|
||||
switch {
|
||||
case b == 0:
|
||||
@@ -242,7 +243,7 @@ func pad(s string, w int) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Anteilsbalken in Achtelschritten, feste Breite barCells.
|
||||
// Share bar in eighths of a cell, barCells wide throughout.
|
||||
const barCells = 10
|
||||
|
||||
var eighths = []rune{' ', '▏', '▎', '▍', '▌', '▋', '▊', '▉'}
|
||||
@@ -251,7 +252,7 @@ func bar(frac float64) string {
|
||||
if frac > 1 {
|
||||
frac = 1
|
||||
}
|
||||
if !(frac > 0) { // fängt auch NaN
|
||||
if !(frac > 0) { // catches NaN too
|
||||
return strings.Repeat(" ", barCells)
|
||||
}
|
||||
units := int(frac*barCells*8 + 0.5)
|
||||
@@ -288,10 +289,10 @@ func printDir(w *bufio.Writer, dir string, res result, o opts) {
|
||||
if ka, kb := metric(a), metric(b); ka != kb {
|
||||
return ka < kb
|
||||
}
|
||||
return a.name < b.name // Perl ließ Gleichstände der Hash-Ordnung
|
||||
return a.name < b.name // Perl left ties to the order of the hash
|
||||
})
|
||||
|
||||
// -t N: nur die N größten zeigen, der Rest wird zu einer Zeile.
|
||||
// -t N: show only the N largest, the rest becomes a single line.
|
||||
rows := res.entries
|
||||
var rest *entry
|
||||
if o.top > 0 && len(rows) > o.top {
|
||||
@@ -310,7 +311,7 @@ func printDir(w *bufio.Writer, dir string, res result, o opts) {
|
||||
rows[i], rows[j] = rows[j], rows[i]
|
||||
}
|
||||
}
|
||||
if rest != nil { // Restzeile bleibt am kleinen Ende
|
||||
if rest != nil { // the summary line stays at the small end
|
||||
if o.reverse {
|
||||
rows = append(rows, *rest)
|
||||
} else {
|
||||
@@ -347,12 +348,12 @@ func printDir(w *bufio.Writer, dir string, res result, o opts) {
|
||||
if total > 0 {
|
||||
frac = float64(metric(e)) / float64(total)
|
||||
}
|
||||
// Balken trägt die Farbe der Spalte, deren Anteil er zeigt.
|
||||
// The bar takes the colour of the column whose share it shows.
|
||||
col := sizeColor(e.size, false)
|
||||
if o.byCount {
|
||||
col = countColor(e.n)
|
||||
}
|
||||
if e.agg { // Sammelzeile bleibt zurückhaltend
|
||||
if e.agg { // the summary line keeps quiet
|
||||
col = cDark
|
||||
}
|
||||
fmt.Fprintf(w, " %s %s",
|
||||
@@ -368,7 +369,7 @@ type opts struct {
|
||||
byCount bool // -n
|
||||
onlyDirs bool // -d
|
||||
reverse bool // -r
|
||||
top int // -t N, 0 = alle
|
||||
top int // -t N, 0 = all
|
||||
bar bool
|
||||
}
|
||||
|
||||
@@ -398,7 +399,7 @@ func die(format string, a ...any) {
|
||||
|
||||
func main() {
|
||||
var o opts
|
||||
var barSet bool // sonst folgt der Balken der Farbentscheidung
|
||||
var barSet bool // otherwise the bar follows the colour decision
|
||||
var dir string
|
||||
when := "auto"
|
||||
|
||||
@@ -429,7 +430,7 @@ func main() {
|
||||
os.Exit(1)
|
||||
}
|
||||
return
|
||||
case a == updateRefreshFlag: // der Hintergrundlauf, nicht in der Hilfe
|
||||
case a == updateRefreshFlag: // the background run, not in the help
|
||||
selfUpdate.refresh()
|
||||
return
|
||||
case a == "--number":
|
||||
@@ -450,7 +451,7 @@ func main() {
|
||||
when = strings.TrimPrefix(a, "--color=")
|
||||
case len(a) > 1 && a[0] == '-':
|
||||
flags := a[1:]
|
||||
for j := 0; j < len(flags); j++ { // Bündelung wie Getopt::Std: -dn
|
||||
for j := 0; j < len(flags); j++ { // bundling as in Getopt::Std: -dn
|
||||
switch flags[j] {
|
||||
case 'n':
|
||||
o.byCount = true
|
||||
@@ -461,7 +462,7 @@ func main() {
|
||||
case 'h':
|
||||
usage(os.Stdout)
|
||||
return
|
||||
case 't': // Wert klebt am Flag (-t5) oder folgt (-t 5)
|
||||
case 't': // the value sticks to the flag (-t5) or follows (-t 5)
|
||||
val := flags[j+1:]
|
||||
if val == "" {
|
||||
if i+1 >= len(args) {
|
||||
@@ -488,7 +489,7 @@ func main() {
|
||||
color.NoColor = false
|
||||
case "never":
|
||||
color.NoColor = true
|
||||
case "auto": // fatih/color entscheidet per isatty und NO_COLOR
|
||||
case "auto": // fatih/color decides, by isatty and NO_COLOR
|
||||
default:
|
||||
die("--color: expected auto|always|never, got %q", when)
|
||||
}
|
||||
@@ -513,8 +514,8 @@ func main() {
|
||||
if res.unreadbl > 0 {
|
||||
fmt.Fprintln(os.Stderr, cDark.Sprintf("dx: %d unreadable entries skipped", res.unreadbl))
|
||||
}
|
||||
// Kostet nichts: der Hinweis stammt aus dem Merkzettel, gefragt wird
|
||||
// höchstens einmal am Tag und dann im Hintergrund.
|
||||
// Costs nothing: the hint comes from the note in the cache, and the asking
|
||||
// happens once a day at most, in the background.
|
||||
if hint := selfUpdate.daily(); hint != "" {
|
||||
fmt.Fprintln(os.Stderr, cDark.Sprint(hint))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user