Documentation
¶
Overview ¶
Package dired formats a directory listing for nem's dired mode: reading entries, ordering them, laying out the buffer text and colouring it, plus the file operations dired performs.
It is pure in the sense that matters to the editor: it holds no editor state. Reading and formatting are separate steps so the editor can re-format the same entries when the user toggles hidden files, details or the sort order, without touching the disk again, and so the layout can be tested against fixed Entry values and a fixed clock rather than a real directory.
Index ¶
- Constants
- func Copy(src, dst string) error
- func FormatEntry(e Entry, mark rune, opts Options, now time.Time) (string, []syntax.Span)
- func Move(src, dst string) error
- func NameColumn(opts Options) int
- func NameEnd(e Entry, opts Options) int
- func Remove(path string) error
- func RenameAll(dir string, rs []Rename) error
- func ShownName(e Entry) string
- type Entry
- type Listing
- type Options
- type Rename
- type SortKey
Constants ¶
const FirstEntry = 2
FirstEntry is the buffer line of the first entry: line 0 is the header, line 1 is blank.
const MarkColumn = 1
MarkColumn is the rune column of the mark on an entry line.
const ParentName = ".."
ParentName names the entry for the directory above, which Read lists so a listing can be left the same way it was entered: by RET on a directory.
Variables ¶
This section is empty.
Functions ¶
func Copy ¶
Copy copies src to dst without following a symlink at src.
A file keeps its contents, permission bits and, where the filesystem allows, its modification time. A directory is copied recursively. A symlink is recreated with the same link text. Copy refuses when dst exists (an error satisfying errors.Is(err, fs.ErrExist)), and when dst is src or lies inside it, since copying a directory into itself would never finish.
A file is written to a temporary name beside dst and renamed into place, so a failure part-way never leaves a truncated dst that looks complete. A directory copy that fails part-way may leave a partial tree.
func FormatEntry ¶
FormatEntry lays out one entry line exactly as Format would put it in a listing, so the editor can redraw a single line when its mark changes without re-formatting the whole directory.
func Move ¶
Move renames src to dst, falling back to copy-then-remove when they are on different filesystems, which rename cannot cross. It refuses exactly what Copy refuses.
func NameColumn ¶
NameColumn is the rune column at which an entry's name starts on its line. It depends only on opts: everything before the name is fixed-width.
func NameEnd ¶ added in v0.5.0
NameEnd is the rune column just past an entry's name on its line. What follows, if anything, is a symlink's target.
func Remove ¶
Remove deletes path: a directory with everything in it, anything else on its own. A symlink to a directory removes the link and never touches the target's contents. Unlike os.RemoveAll, a path that does not exist is an error wrapping fs.ErrNotExist: the user asked to delete something they saw, and it silently not being there is worth telling them.
func RenameAll ¶ added in v0.5.0
RenameAll renames files as if all at the same instant, which is what editing a listing's names as text asks for: a name one file gives up can be taken by another, so two files can swap names, or a numbered run shift along by one.
Nothing is overwritten, and nothing moves until every rename has been checked: no two may take one name, a name may be taken only if one of the renames frees it, and a file may go only into a directory that exists and is not itself being renamed. Then each file goes to a temporary name beside it, and from there to its new one. If a step fails, everything already moved is moved back, so either all of it happens or none of it does - short of the moving back failing too, which the error then says.
Errors name the files as the renames give them, since they are meant for the user who typed those names.
Types ¶
type Entry ¶
type Entry struct {
// Name is the base name as it is on disk, unsanitised: it is what file
// operations are given, so it must round-trip exactly.
Name string
// Mode comes from Lstat, so a symlink carries fs.ModeSymlink rather than
// its target's type.
Mode fs.FileMode
// Size is the Lstat size; for a symlink that is the length of its text.
Size int64
ModTime time.Time
// Target is a symlink's link text (os.Readlink), and "" for anything else.
Target string
// Broken reports a symlink whose target does not exist.
Broken bool
// IsDir is true for a directory, and for a symlink that resolves to one:
// both are things the user can descend into.
IsDir bool
// contains filtered or unexported fields
}
Entry is one directory entry.
func Read ¶
Read lists every entry of dir (not recursive), hidden ones included; Format does the filtering and ordering, so toggling either needs no second read. Unless dir is a filesystem root, the list also holds a ParentName entry for the directory above.
An entry whose Lstat fails - it vanished between readdir and lstat, or the directory is readable but not searchable - is still listed with its name and zero Mode, Size and ModTime. Dropping it would hide from the user a file they can see with ls. The error is only for failing to read the directory itself; entries read before such a failure are returned alongside it.
func (Entry) Executable ¶
Executable reports whether the entry is a regular file, or a symlink to one, with any execute bit set. Directories are excluded: their x bit means "searchable", and colouring every directory as a program would be noise.
type Listing ¶
type Listing struct {
// Dir is the directory, absolute and cleaned.
Dir string
// Lines are the header, a blank line, then one line per shown entry - or a
// single placeholder line when nothing is shown.
Lines []string
// Spans colour Lines; len(Spans) == len(Lines).
Spans [][]syntax.Span
// Entries are the shown entries in display order; Entries[i] is on line
// FirstEntry+i.
Entries []Entry
// Hidden counts the hidden entries this listing omits (0 when ShowHidden).
Hidden int
}
Listing is a formatted directory: the buffer text line by line and, line for line, how to colour it.
func Format ¶
func Format(dir string, entries []Entry, marks map[string]rune, opts Options, now time.Time, home string) *Listing
Format lays out entries (as Read returns them, in any order) for display.
marks maps an entry's Name to its mark: ' ' or absent is unmarked, '*' is marked, 'D' is flagged for deletion, and any other rune is shown as it is and coloured like '*'. now decides between showing a time and a year, and is a parameter so a test's output does not depend on when it runs. home, if not "", is abbreviated to "~" in the header. The caller passes an absolute dir.
type Options ¶
type Options struct {
ShowHidden bool
HideDetails bool
Sort SortKey
// Icons puts a Nerd Font glyph before each name. Off in the zero value
// because it needs a font this package cannot know the terminal has.
Icons bool
}
Options controls what a listing shows. The zero value is the default: details shown, hidden entries omitted, sorted by name, no icons.
type Rename ¶ added in v0.5.0
type Rename struct{ From, To string }
Rename is one file's new name, for RenameAll. Both are relative to the directory RenameAll is given, or absolute.
type SortKey ¶
type SortKey int
SortKey orders a listing. Directories always come before everything else, whatever the key, because the first thing a user scans a listing for is where they can go next.
const ( // ByName is case-insensitive and ignores one leading dot, so ".bashrc" // sorts among the b's rather than in a clump at the top. Ties are broken // by the raw name, which makes the order total. ByName SortKey = iota // ByTime puts the newest first; ties fall back to name order. ByTime // BySize puts the largest first; directories, grouped first anyway, are // ordered by name since their size says nothing about their contents. // Ties fall back to name order. BySize )