Version: v0.0.0-...-c97c800 Latest Latest

This package is not in the latest version of its module.

Go to latest
Published: Feb 6, 2019 License: BSD-3-Clause Imports: 6 Imported by: 0



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.



This section is empty.


View Source
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.


This section is empty.


type Completer

type Completer interface {
	Complete(s string) (string, []string, error)

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

func NewEnvCompleter(s string) (Completer, error)

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

func NewFileCompleter(s string) Completer

NewFileCompleter returns a FileCompleter for a single directory.

func NewMultiCompleter

func NewMultiCompleter(c Completer, cc ...Completer) Completer

NewMultiCompleter returns a MultiCompleter created from one or more Completers. It is perfectly legal to include a MultiCompleter.

func NewPathCompleter

func NewPathCompleter() (Completer, error)

NewPathCompleter calls NewEnvCompleter with "PATH" as the variable name. It can be used to create completers for shells.

func NewStringCompleter

func NewStringCompleter(s []string) Completer

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.

func (*FileCompleter) Complete

func (f *FileCompleter) Complete(s string) (string, []string, error)

Complete implements complete for a file starting at a directory.

type InOut

type InOut interface {
	// Push one or more strings onto the InOut
	// 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.

func NewLine

func NewLine() InOut

NewLine returns an empty Line struct

type Line

type Line struct {
	L []string

Line is used to implement an InOut based on an array of strings.

func (*Line) Pop

func (l *Line) Pop() (s string)

Pop implements Pop for a Line

func (*Line) PopAll

func (l *Line) PopAll() (s []string)

PopAll implements PopAll for a Line

func (*Line) Push

func (l *Line) Push(s ...string)

Push implements Push for a Line

func (*Line) ReadAll

func (l *Line) ReadAll() ([]byte, error)

ReadAll implements ReadAll for a Line. There are no errors.

func (*Line) Write

func (l *Line) Write(b []byte) (int, error)

Write implements Write for a Line. There are no errors.

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

func NewLineReader(c Completer, r io.Reader, w io.Writer) *LineReader

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.

func (*MultiCompleter) Complete

func (m *MultiCompleter) Complete(s string) (string, []string, error)

Complete Returns a []string consisting of the results of calling all the Completers.

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL