Documentation ¶
Overview ¶
Package complete implements a simple completion package designed to be used in shells and other programs. It currently offers completion functions to implement table-based and file search path based completion. It also offers a multi completion capability so that you can construct completions from other completions.
Goals: small code base, so it can easily be embedded in firmware
easily embedded in other programs, like the ip command
friendly to mixed modes, i.e. if we say ip l and stdin is interactive, it would be nice if ip dropped into a command line prompt and let you use completion to get the rest of the line, instead of printing out a bnf
The structs should be very light weight and hence cheap to build, use, and throw away. They should NOT have lots of state.
Rely on the fact that system calls and kernels are fast and cache file system info so you should not. This means that we don't need to put huge effort into building in-memory structs representing file system information. Just ask the kernel.
Non-Goals: be just like bash or zsh
do extensive caching from the file system or environment. There was a time (the 1970s as it happens) when extensive in-shell hash tables made sense. Disco balls were also big. We don't need either.
Use: see the code, but basically, you can create completer and call a function to read one word. The intent is that completers are so cheap that just creating them on demand costs nothing. So far this seems to work.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ( Debug = func(s string, v ...interface{}) {} ErrEOL = errors.New("EOL") ErrEmptyEnv = errors.New("Empty environment variable") )
Debug is a package level variable which can be set to, e.g., log.Printf if you want lots of debug.
Functions ¶
This section is empty.
Types ¶
type Completer ¶
Completer is an interface for completion functions. It is passed a string and returns a string for an exact match, a []string with all glob matches and an error.
func NewEnvCompleter ¶
NewEnvCompleter creates a MultiCompleter consisting of one or more FileCompleters. It is given an environment variable, which it splits on :. If there are only zero entries, it returns an error; else it returns a MultiCompleter. N.B. it does *not* check for whether a directory exists or not; directories can come and go.
func NewFileCompleter ¶
NewFileCompleter returns a FileCompleter for a single directory.
func NewMultiCompleter ¶
NewMultiCompleter returns a MultiCompleter created from one or more Completers. It is perfectly legal to include a MultiCompleter.
func NewPathCompleter ¶
NewPathCompleter calls NewEnvCompleter with "PATH" as the variable name. It can be used to create completers for shells.
func NewStringCompleter ¶
NewStringCompleter returns a StringCompleter from the []string.
type FileCompleter ¶
type FileCompleter struct { // Root is the starting point for this Completer. Root string }
FileCompleter is used to implement a Completer for a single directory in a file system.
type InOut ¶
type InOut interface { // Push one or more strings onto the InOut Push(...string) // Pop a string fom the InOut. Pop() string // Pop all strings from the Inout. PopAll() []string // ReadAll implements io.ReadAll for an InOut. ReadAll() ([]byte, error) // Write implements io.Write for an InOut Write([]byte) (int, error) }
InOut is a stack-like interface used for IO. We are no longer sure we need it.
type Line ¶
type Line struct {
L []string
}
Line is used to implement an InOut based on an array of strings.
type LineReader ¶
type LineReader struct { // Completer for this LineReader C Completer // R is used for input. Most characters are stored in the // Line, while some initiate special processing. R io.Reader // W is used for output, usually for showing completions. W io.Writer // Lines holds incoming data as it is read. Line string // Exact is the exact match. // It can be "" if there is not one. Exact string // Candidates are any completion candidates. // The UI can decide how to handle them. Candidates []string EOF bool Fields int }
LineReader has three things and returns one string. The three things are an io.Reader, an io.Writer, and a Completer Bytes are read one at a time, and depending on their value, are written to the io.Writer. If the completer returns 0 or 1 answers, a 0 or 1 length string is returned. If there are two or more answers, they are printed and the line is printed out again. Most characters are just echoed. Special handling: newline or space returns. tab tries to complete backspace erases. Since everything is ansi, we assume ansi.
LineReader is used to implement input for a Completer. It uses a Completer, io.Reader, io.Writer, and bytes.Buffer. bytes are read from the reader, processed, held in the bytes.Buffer and, as a side effect, some information is written to the io.Writer.
func NewLineReader ¶
NewLineReader returns a LineReader.
func (*LineReader) ReadChar ¶
func (l *LineReader) ReadChar(b byte) (err error)
ReadChar reads one character and processes it. It is inflexible by design.
func (*LineReader) ReadLine ¶
func (l *LineReader) ReadLine() error
ReadLine reads until an error occurs
type MultiCompleter ¶
type MultiCompleter struct {
Completers []Completer
}
MultiCompleter is a Completer consisting of one or more Completers Why do this? We need it for paths, anyway, but consider a shell which has builtins and metacharacters such as >, &, etc. You can build a MultiCompleter which has a string completer and a set of file completers, so you don't need to special case anything.
type StringCompleter ¶
type StringCompleter struct { // Names is the list of possible completions. Names []string }
A StringCompleter performs completions against an array of strings. It can be used for, e.g., shell builtins.
func (*StringCompleter) Complete ¶
func (f *StringCompleter) Complete(s string) (string, []string, error)
Complete returns a []string for each string of which the passed in string is a prefix. The error for now is always nil. If there is an exact match, only that match is returned, which is arguably wrong.