readline

package module
v4.0.0 Latest Latest
Warning

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

Go to latest
Published: Feb 9, 2025 License: Apache-2.0 Imports: 21 Imported by: 0

README

lmorg/readline

Preface

This project began a few years prior to this git commit history as an API for Murex, an alternative UNIX shell, because I wasn't satisfied with the state of existing Go packages for readline (at that time they were either bugger and/or poorly maintained, or lacked features I desired). The state of things for readline in Go may have changed since then however own package had also matured and grown to include many more features that has arisen during the development of Murex. So it seemed only fair to give back to the community considering it was other peoples readline libraries that allowed me rapidly prototype Murex during it's early stages of development

readline In Action

asciicast

This is a very rough and ready recording but it does demonstrate a few of the features available in readline. These features include:

  • hint text (the blue status text below the prompt - however the colour is configurable)
  • syntax highlighting (albeit there isn't much syntax to highlight in the example)
  • tab-completion in gridded mode (seen when typing cd)
  • tab-completion in list view (seen when selecting an process name to kill and the process ID was substituted when selected)
  • regex searching through the tab-completion suggestions (seen in both cd and kill - enabled by pressing [CTRL+f])
  • line editing using $EDITOR (vi in the example - enabled by pressing [ESC] followed by [v])
  • readline's warning before pasting multiple lines of data into the buffer
  • the preview option that's available as part of the aforementioned warning
  • and VIM keys (enabled by pressing [ESC])

Example Code

Using readline is as simple as:

func main() {
    rl := readline.NewInstance()

    for {
        line, err := rl.Readline()
        
        if err != nil {
            fmt.Println("Error:", err)
            return
        }

        fmt.Printf("You just typed: '%s'\n", line)
    }
}

However I suggest you read through the examples in /examples for help using some of the more advanced features in readline.

The source for readline will also be documented in godoc: https://godoc.org/github.com/lmorg/readline

Version Information

Because the last thing a developer wants is to do is fix breaking changes after updating modules, I will make the following guarantees:

  • The version string will be based on Semantic Versioning. ie version numbers will be formatted (major).(minor).(patch) - for example 2.0.1

  • major releases will have breaking changes. Be sure to read CHANGES.md for upgrade instructions

  • minor releases will contain new APIs or introduce new user facing features which may affect useability from an end user perspective. However minor releases will not break backwards compatibility at the source code level and nor will it break existing expected user-facing behavior. These changes will be documented in CHANGES.md too

  • patch releases will be bug fixes and such like. Where the code has changed but both API endpoints and user experience will remain the same (except where expected user experience was broken due to a bug, then that would be bumped to either a minor or major depending on the significance of the bug and the significance of the change to the user experience)

  • Any updates to documentation, comments within code or the example code will not result in a version bump because they will not affect the output of the go compiler. However if this concerns you then I recommend pinning your project to the git commit hash rather than a patch release

My recommendation is to pin to either the minor or patch release and I will endeavour to keep breaking changes to an absolute minimum.

Change Log

v4.0.0 marks a breaking change to the tab completion function.

Earlier versions expected multiple parameters to be returned however from v4.0.0 onwards, a pointer to a structure is instead expected:

type TabCompleterReturnT struct {
	Prefix       string
	Suggestions  []string
	Descriptions map[string]string
	DisplayType  TabDisplayType
	HintCache    HintCacheFuncT
	Preview      PreviewFuncT
}

This allows for more configurability and without the cost of copying multiple different pieces of data nor future breaking changes whenever additional new features are added.

The full changelog can be viewed at CHANGES.md

License Information

readline is licensed Apache 2.0. All the example code and documentation in /examples is public domain.

Documentation

Overview

Package readline is a pure-Go re-imagining of the UNIX readline API

Index

Constants

View Source
const (
	EventModeInputDefault        = "Normal"
	EventModeInputVimKeys        = "VimKeys"
	EventModeInputVimReplaceOnce = "VimReplaceOnce"
	EventModeInputVimReplaceMany = "VimReplaceMany"
	EventModeInputVimDelete      = "VimDelete"
	EventModeInputVimCommand     = "VimCommand"
	EventModeInputAutocomplete   = "Autocomplete"
	EventModeInputFuzzyFind      = "FuzzyFind"
)
View Source
const (
	EventModePreviewOff     = "Disabled"
	EventModePreviewItem    = "Autocomplete"
	EventModePreviewLine    = "CmdLine"
	EventModePreviewUnknown = "Unknown"
)
View Source
const (
	// TabDisplayGrid is the default. It's where the screen below the prompt is
	// divided into a grid with each suggestion occupying an individual cell.
	TabDisplayGrid = iota

	// TabDisplayList is where suggestions are displayed as a list with a
	// description. The suggestion gets highlighted but both are searchable (ctrl+f)
	TabDisplayList

	// TabDisplayMap is where suggestions are displayed as a list with a
	// description however the description is what gets highlighted and only
	// that is searchable (ctrl+f). The benefit of TabDisplayMap is when your
	// autocomplete suggestions are IDs rather than human terms.
	TabDisplayMap
)

Variables

View Source
var (
	// CtrlC is returned when ctrl+c is pressed
	ErrCtrlC = errors.New(_CtrlC)

	// EOF is returned when ctrl+d is pressed.
	// (this is actually the same value as io.EOF)
	ErrEOF = errors.New(_EOF)
)
View Source
var ForceCrLf = true

Functions

func GetSize

func GetSize(fd int) (width, height int, err error)

GetSize returns the dimensions of the given terminal.

func GetTermWidth

func GetTermWidth() (termWidth int)

GetTermWidth returns the width of Stdout or 80 if the width cannot be established

func HkFnCancelAction

func HkFnCancelAction(rl *Instance)

func HkFnClearAfterCursor

func HkFnClearAfterCursor(rl *Instance)

func HkFnClearLine

func HkFnClearLine(rl *Instance)

func HkFnClearScreen

func HkFnClearScreen(rl *Instance)

func HkFnCursorJumpBackwards

func HkFnCursorJumpBackwards(rl *Instance)

func HkFnCursorJumpForwards

func HkFnCursorJumpForwards(rl *Instance)

func HkFnCursorMoveToEndOfLine

func HkFnCursorMoveToEndOfLine(rl *Instance)

func HkFnCursorMoveToStartOfLine

func HkFnCursorMoveToStartOfLine(rl *Instance)

func HkFnModeAutocomplete

func HkFnModeAutocomplete(rl *Instance)

func HkFnModeFuzzyFind

func HkFnModeFuzzyFind(rl *Instance)

func HkFnModePreviewLine

func HkFnModePreviewLine(rl *Instance)

func HkFnModePreviewToggle

func HkFnModePreviewToggle(rl *Instance)

func HkFnModeSearchHistory

func HkFnModeSearchHistory(rl *Instance)

func HkFnRecallWord1

func HkFnRecallWord1(rl *Instance)

func HkFnRecallWord10

func HkFnRecallWord10(rl *Instance)

func HkFnRecallWord11

func HkFnRecallWord11(rl *Instance)

func HkFnRecallWord12

func HkFnRecallWord12(rl *Instance)

func HkFnRecallWord2

func HkFnRecallWord2(rl *Instance)

func HkFnRecallWord3

func HkFnRecallWord3(rl *Instance)

func HkFnRecallWord4

func HkFnRecallWord4(rl *Instance)

func HkFnRecallWord5

func HkFnRecallWord5(rl *Instance)

func HkFnRecallWord6

func HkFnRecallWord6(rl *Instance)

func HkFnRecallWord7

func HkFnRecallWord7(rl *Instance)

func HkFnRecallWord8

func HkFnRecallWord8(rl *Instance)

func HkFnRecallWord9

func HkFnRecallWord9(rl *Instance)

func HkFnRecallWordLast

func HkFnRecallWordLast(rl *Instance)

func HkFnUndo

func HkFnUndo(rl *Instance)

func IsTerminal

func IsTerminal(fd int) bool

IsTerminal returns true if the given file descriptor is a terminal.

func Restore

func Restore(fd int, state *State) error

Restore restores the terminal connected to the given file descriptor to a previous state.

Types

type DelayedTabContext

type DelayedTabContext struct {
	Context context.Context
	// contains filtered or unexported fields
}

DelayedTabContext is a custom context interface for async updates to the tab completions

func (*DelayedTabContext) AppendDescriptions

func (dtc *DelayedTabContext) AppendDescriptions(suggestions map[string]string)

AppendDescriptions updates the tab completions with additional suggestions + descriptions asynchronously

func (*DelayedTabContext) AppendSuggestions

func (dtc *DelayedTabContext) AppendSuggestions(suggestions []string)

AppendSuggestions updates the tab completions with additional suggestions asynchronously

type EventReturn

type EventReturn struct {
	Actions    []func(rl *Instance)
	HintText   []rune
	SetLine    []rune
	SetPos     int
	Continue   bool
	MoreEvents bool
}

EventReturn is a structure returned by the callback event function. This is used by readline to determine what state the API should return to after the readline event.

type EventState

type EventState struct {
	Line        string
	CursorPos   int
	KeyPress    string
	IsMasked    bool
	InputMode   string
	PreviewMode string
}

EventState presents a simplified view of the current readline state

type ExampleHistory

type ExampleHistory struct {
	// contains filtered or unexported fields
}

ExampleHistory is an example of a LineHistory interface:

func (*ExampleHistory) Dump

func (h *ExampleHistory) Dump() interface{}

Dump returns the entire history

func (*ExampleHistory) GetLine

func (h *ExampleHistory) GetLine(i int) (string, error)

GetLine returns a line from history

func (*ExampleHistory) Len

func (h *ExampleHistory) Len() int

Len returns the number of lines in history

func (*ExampleHistory) Write

func (h *ExampleHistory) Write(s string) (int, error)

Write to history

type HintCacheFuncT

type HintCacheFuncT func(prefix string, items []string) []string

type History

type History interface {
	// Append takes the line and returns an updated number of lines or an error
	Write(string) (int, error)

	// GetLine takes the historic line number and returns the line or an error
	GetLine(int) (string, error)

	// Len returns the number of history lines
	Len() int

	// Dump returns everything in readline. The return is an interface{} because
	// not all LineHistory implementations will want to structure the history in
	// the same way. And since Dump() is not actually used by the readline API
	// internally, this methods return can be structured in whichever way is most
	// convenient for your own applications (or even just create an empty
	//function which returns `nil` if you don't require Dump() either)
	Dump() interface{}
}

History is an interface to allow you to write your own history logging tools. eg sqlite backend instead of a file system. By default readline will just use the dummyLineHistory interface which only logs the history to memory ([]string to be precise).

type Instance

type Instance struct {
	Active bool

	// PasswordMask is what character to hide password entry behind.
	// Once enabled, set to 0 (zero) to disable the mask again.
	PasswordMask rune

	// SyntaxHighlight is a helper function to provide syntax highlighting.
	// Once enabled, set to nil to disable again.
	SyntaxHighlighter func([]rune) string

	// History is an interface for querying the readline history.
	// This is exposed as an interface to allow you the flexibility to define how
	// you want your history managed (eg file on disk, database, cloud, or even
	// no history at all). By default it uses a dummy interface that only stores
	// historic items in memory.
	History History

	// HistoryAutoWrite defines whether items automatically get written to
	// history.
	// Enabled by default. Set to false to disable.
	HistoryAutoWrite bool

	// TabCompleter is a function that offers completion suggestions.
	TabCompleter func([]rune, int, DelayedTabContext) *TabCompleterReturnT

	MinTabItemLength int
	MaxTabItemLength int

	// MaxTabCompletionRows is the maximum number of rows to display in the tab
	// completion grid.
	MaxTabCompleterRows int

	// SyntaxCompletion is used to autocomplete code syntax (like braces and
	// quotation marks). If you want to complete words or phrases then you might
	// be better off using the TabCompletion function.
	// SyntaxCompletion takes the line ([]rune), change (string) and cursor
	// position, and returns the new line and cursor position.
	SyntaxCompleter func([]rune, string, int) ([]rune, int)

	// DelayedSyntaxWorker allows for syntax highlighting happen to the line
	// after the line has been drawn.
	DelayedSyntaxWorker func([]rune) []rune

	// HintText is a helper function which displays hint text the prompt.
	// HintText takes the line input from the prompt and the cursor position.
	// It returns the hint text to display.
	HintText func([]rune, int) []rune

	// HintColor any ANSI escape codes you wish to use for hint formatting. By
	// default this will just be blue.
	HintFormatting string

	// AutocompleteHistory is another customization allowing for alternative
	// results when [ctrl]+[r]
	AutocompleteHistory func(string) ([]string, map[string]string)

	// TempDirectory is the path to write temporary files when editing a line in
	// $EDITOR. This will default to os.TempDir()
	TempDirectory string

	// GetMultiLine is a callback to your host program. Since multiline support
	// is handled by the application rather than readline itself, this callback
	// is required when calling $EDITOR. However if this function is not set
	// then readline will just use the current line.
	GetMultiLine func([]rune) []rune

	MaxCacheSize int

	ScreenRefresh func()

	PreviewInit func()

	PreviewImages bool

	PreviewLine PreviewFuncT

	//ForceCrLf          bool
	EnableGetCursorPos bool
	// contains filtered or unexported fields
}

Instance is used to encapsulate the parameter group and run time of any given readline instance so that you can reuse the readline API for multiple entry captures without having to repeatedly unload configuration.

func NewInstance

func NewInstance() *Instance

NewInstance is used to create a readline instance and initialise it with sane defaults.

func (*Instance) AddEvent

func (rl *Instance) AddEvent(keyPress string, callback keyPressEventCallbackT)

AddEvent registers a new keypress handler

func (*Instance) DelEvent

func (rl *Instance) DelEvent(keyPress string)

DelEvent deregisters an existing keypress handler

func (*Instance) ForceHintTextUpdate

func (rl *Instance) ForceHintTextUpdate(s string)

ForceHintTextUpdate is a nasty function for force writing a new hint text. Use sparingly!

func (*Instance) Readline

func (rl *Instance) Readline() (string, error)

Readline displays the readline prompt. It will return a string (user entered data) or an error.

func (*Instance) ReadlineWithDefault

func (rl *Instance) ReadlineWithDefault(defaultValue string) (string, error)

Readline displays the readline prompt primed with a default value. It will return a string (user entered data) or an error. Discussion: https://github.com/lmorg/readline/issues/12

func (*Instance) SetPrompt

func (rl *Instance) SetPrompt(s string)

SetPrompt will define the readline prompt string. It also calculates the runes in the string as well as any non-printable escape codes.

type NullHistory

type NullHistory struct{}

NullHistory is a null History interface for when you don't want line entries remembered eg password input.

func (*NullHistory) Dump

func (h *NullHistory) Dump() interface{}

Dump returns the entire history

func (*NullHistory) GetLine

func (h *NullHistory) GetLine(i int) (string, error)

GetLine returns a line from history

func (*NullHistory) Len

func (h *NullHistory) Len() int

Len returns the number of lines in history

func (*NullHistory) Write

func (h *NullHistory) Write(s string) (int, error)

Write to history

type PreviewFuncCallbackT

type PreviewFuncCallbackT func(lines []string, pos int, err error)

type PreviewFuncT

type PreviewFuncT func(ctx context.Context, line []rune, item string, incImages bool, size *PreviewSizeT, callback PreviewFuncCallbackT)

type PreviewSizeT

type PreviewSizeT struct {
	Height  int
	Width   int
	Forward int
}

type State

type State struct {
	// contains filtered or unexported fields
}

State contains the state of a terminal.

func GetState

func GetState(fd int) (*State, error)

GetState returns the current state of a terminal which may be useful to restore the terminal after a signal.

func MakeRaw

func MakeRaw(fd int) (*State, error)

MakeRaw put the terminal connected to the given file descriptor into raw mode and returns the previous state of the terminal so that it can be restored.

type TabCompleterReturnT

type TabCompleterReturnT struct {
	Prefix       string
	Suggestions  []string
	Descriptions map[string]string
	DisplayType  TabDisplayType
	HintCache    HintCacheFuncT
	Preview      PreviewFuncT
}

type TabDisplayType

type TabDisplayType int

TabDisplayType defines how the autocomplete suggestions display

type UnicodeT

type UnicodeT struct {
	// contains filtered or unexported fields
}

func (*UnicodeT) CellLen

func (u *UnicodeT) CellLen() int

func (*UnicodeT) CellPos

func (u *UnicodeT) CellPos() int

func (*UnicodeT) Duplicate

func (u *UnicodeT) Duplicate() *UnicodeT

func (*UnicodeT) RuneLen

func (u *UnicodeT) RuneLen() int

func (*UnicodeT) RunePos

func (u *UnicodeT) RunePos() int

func (*UnicodeT) Runes

func (u *UnicodeT) Runes() []rune

func (*UnicodeT) Set

func (u *UnicodeT) Set(rl *Instance, r []rune)

func (*UnicodeT) SetCellPos

func (u *UnicodeT) SetCellPos(cPos int)

func (*UnicodeT) SetRunePos

func (u *UnicodeT) SetRunePos(i int)

func (*UnicodeT) String

func (u *UnicodeT) String() string

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

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