feat: add list command with global filters
This commit is contained in:
21
internal/output/factory.go
Normal file
21
internal/output/factory.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package output
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Format identifiers mirrored from listing package to avoid import cycle.
|
||||
const (
|
||||
FormatTable = "table"
|
||||
FormatPlain = "plain"
|
||||
)
|
||||
|
||||
// NewFormatter selects the appropriate renderer based on format key.
|
||||
func NewFormatter(format string) (Formatter, error) {
|
||||
switch format {
|
||||
case FormatPlain:
|
||||
return NewPlainFormatter(), nil
|
||||
case FormatTable, "":
|
||||
return NewTableFormatter(), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported format %q", format)
|
||||
}
|
||||
}
|
||||
52
internal/output/formatter.go
Normal file
52
internal/output/formatter.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package output
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Formatter renders listing entries in a chosen representation.
|
||||
type Formatter interface {
|
||||
Begin(w io.Writer) error
|
||||
WriteEntry(w io.Writer, entry Entry) error
|
||||
WriteSummary(w io.Writer, summary Summary) error
|
||||
}
|
||||
|
||||
// Entry represents a single listing output record in a formatter-agnostic form.
|
||||
type Entry struct {
|
||||
Path string
|
||||
Type string
|
||||
SizeBytes int64
|
||||
Depth int
|
||||
MatchedExtension string
|
||||
}
|
||||
|
||||
// Summary aggregates counts for final reporting.
|
||||
type Summary struct {
|
||||
Files int
|
||||
Directories int
|
||||
Symlinks int
|
||||
}
|
||||
|
||||
// Add records a new entry in the summary counters.
|
||||
func (s *Summary) Add(entry Entry) {
|
||||
switch entry.Type {
|
||||
case "file":
|
||||
s.Files++
|
||||
case "directory":
|
||||
s.Directories++
|
||||
case "symlink":
|
||||
s.Symlinks++
|
||||
}
|
||||
}
|
||||
|
||||
// Total returns the sum of all entry classifications.
|
||||
func (s Summary) Total() int {
|
||||
return s.Files + s.Directories + s.Symlinks
|
||||
}
|
||||
|
||||
// DefaultSummaryLine produces a human-readable summary string for any format.
|
||||
func DefaultSummaryLine(summary Summary) string {
|
||||
return fmt.Sprintf("Total: %d entries (files: %d, directories: %d, symlinks: %d)",
|
||||
summary.Total(), summary.Files, summary.Directories, summary.Symlinks)
|
||||
}
|
||||
28
internal/output/plain.go
Normal file
28
internal/output/plain.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package output
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// plainFormatter emits one entry per line suitable for piping into other tools.
|
||||
type plainFormatter struct{}
|
||||
|
||||
// NewPlainFormatter constructs a formatter for plain output.
|
||||
func NewPlainFormatter() Formatter {
|
||||
return &plainFormatter{}
|
||||
}
|
||||
|
||||
func (plainFormatter) Begin(io.Writer) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (plainFormatter) WriteEntry(w io.Writer, entry Entry) error {
|
||||
_, err := fmt.Fprintln(w, entry.Path)
|
||||
return err
|
||||
}
|
||||
|
||||
func (plainFormatter) WriteSummary(w io.Writer, summary Summary) error {
|
||||
_, err := fmt.Fprintln(w, DefaultSummaryLine(summary))
|
||||
return err
|
||||
}
|
||||
48
internal/output/table.go
Normal file
48
internal/output/table.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package output
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"text/tabwriter"
|
||||
)
|
||||
|
||||
// tableFormatter renders aligned columns for human-friendly review.
|
||||
type tableFormatter struct {
|
||||
writer *tabwriter.Writer
|
||||
}
|
||||
|
||||
// NewTableFormatter constructs a table formatter.
|
||||
func NewTableFormatter() Formatter {
|
||||
return &tableFormatter{}
|
||||
}
|
||||
|
||||
func (f *tableFormatter) Begin(w io.Writer) error {
|
||||
f.writer = tabwriter.NewWriter(w, 0, 4, 2, ' ', 0)
|
||||
_, err := fmt.Fprintln(f.writer, "PATH\tTYPE\tSIZE")
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *tableFormatter) WriteEntry(w io.Writer, entry Entry) error {
|
||||
if f.writer == nil {
|
||||
return fmt.Errorf("table formatter not initialized")
|
||||
}
|
||||
|
||||
size := "-"
|
||||
if entry.Type == "file" && entry.SizeBytes >= 0 {
|
||||
size = fmt.Sprintf("%d", entry.SizeBytes)
|
||||
}
|
||||
|
||||
_, err := fmt.Fprintf(f.writer, "%s\t%s\t%s\n", entry.Path, entry.Type, size)
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *tableFormatter) WriteSummary(w io.Writer, summary Summary) error {
|
||||
if f.writer == nil {
|
||||
return fmt.Errorf("table formatter not initialized")
|
||||
}
|
||||
if err := f.writer.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := fmt.Fprintln(w, DefaultSummaryLine(summary))
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user