forked from reeflective/readline
-
Notifications
You must be signed in to change notification settings - Fork 0
/
instance.go
196 lines (157 loc) · 8.32 KB
/
instance.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
package readline
import (
"os"
"regexp"
"sync"
)
// 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.
type Instance struct {
// The prompt supports all oh-my-posh prompt types (primary/rprompt/secondary/transient/tooltip)
// In addition, the shell offers some functions to refresh the prompt on demand, with varying
// behavior options (refresh below a message, or in place, etc)
Prompt *Prompt
// Configuration stores all keymaps, prompt styles and other completion/helper settings.
config *Config
//
// Keymaps ------------------------------------------------------------------------------------
main keymapMode // The main/global keymap, partially overridden by any local keymap.
local keymapMode // The local keymap is used when completing menus, using Vim operators, etc.
widgets map[keymapMode]widgets // Widgets wrapped into EventCallbacks at bind time
// widgetPrefixMatched is a widget that perfectly matched a given input key, but was also
// found along other widgets matching the key only as prefix. This is used so that when reading
// the next key, if no match is found, the key is used by this widget.
widgetPrefixMatched EventCallback
// interruptHandlers are all special handlers being called when the shell receives an interrupt
// signal key, like CtrlC/CtrlD. These are not directly assigned in the various keymaps, and are
// matched against input keys before any other keymap.
interruptHandlers map[rune]func() error
//
// Vim Operating Parameters -------------------------------------------------------------------
iterations string // Global iterations.
negativeArg bool // Emacs supports negative iterations.
registers *registers // All memory text registers, can be consulted with Alt"
registersComplete bool // When the completer is for registers, used to reset
isViopp bool // Keeps track of vi operator pending mode BEFORE trying to match the current key.
pendingActions []action // Widgets that have registered themselves as waiting for another action to be ran.
viinsEnterPos int // The index at which insert mode was entered
// Input Line ---------------------------------------------------------------------------------
// 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
// EnableGetCursorPos will allow the shell to send a special sequence
// to the the terminal to get the current cursor X and Y coordinates.
// This is true by default, to enable smart completion estate use.
EnableGetCursorPos bool
// SyntaxHighlight is a helper function to provide syntax highlighting.
// Once enabled, set to nil to disable again.
SyntaxHighlighter func([]rune) string
// PasswordMask is what character to hide password entry behind.
// Once enabled, set to 0 (zero) to disable the mask again.
PasswordMask rune
// readline operating parameters
keys string // Contains all keys (input by user) not yet consumed by the shell widgets.
line []rune // This is the input line, with entered text: full line = mlnPrompt + line
accepted bool // Set by 'accept-line' widget, to notify return the line to the caller
err error // Errors returned by interrupt signal handlers
inferLine bool // When a "accept-line-and-down-history" widget wants to immediately retrieve/use a line.
pos int // Cursor position in the entire line.
posX int // Cursor position X
posY int // Cursor position Y (if multiple lines span)
fullX int // X coordinate of the full input line, including the prompt if needed.
fullY int // Y offset to the end of input line.
// Buffer received from host programs
multilineBuffer []byte
multilineSplit []string
skipStdinRead bool
// selection management
visualLine bool // Is the visual mode VISUAL_LINE
mark int // Visual selection mark. -1 when unactive
activeRegion bool // Is a current range region active ?
regions []region // Regions are some parts of the input line with special highlighting.
//
// Completion ---------------------------------------------------------------------------------
// Completer is a function that produces completions.
// It takes the readline line ([]rune) and cursor pos.
// It return a type holding all completions and their associated settings.
Completer func(line []rune, cursor int) Completions
// 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) and cursor position, and returns
// the new line and cursor position.
SyntaxCompleter func(line []rune, cursor int) ([]rune, int)
// Asynchronously highlight/process the input line
DelayedSyntaxWorker func([]rune) []rune
delayedSyntaxCount int64
// The current completer to use to produce completions: normal/history/registers
// Used so that autocomplete can use the correct completer all along.
completer func()
// tab completion operating parameters
tcGroups []*comps // All of our suggestions tree is in here
tcPrefix string // The current tab completion prefix against which to build candidates
tcUsedY int // Comprehensive offset of the currently built completions
comp []rune // The currently selected item, not yet a real part of the input line.
compSuffix suffixMatcher // The suffix matcher is kept for removal after actually inserting the candidate.
compLine []rune // Same as rl.line, but with the currentComp inserted.
tfLine []rune // The current search pattern entered
tfPos int // Cursor position in the isearch buffer
isearch *regexp.Regexp // Holds the current search regex match
//
// History -----------------------------------------------------------------------------------
// Current line undo/redo history.
undoHistory []undoItem
undoPos int
isUndoing bool
undoSkipAppend bool
// Past history
histories map[string]History // Sources of history lines
historyNames []string // Names of histories stored in rl.histories
historySourcePos int // The index of the currently used history
lineBuf string // The current line saved when we are on another history line
histPos int // Index used for navigating the history lines with arrows/j/k
histHint []rune // We store a hist hint, for dual history sources
histSuggested []rune // The last matching history line matching the current input.
//
// Hints -------------------------------------------------------------------------------------
// HintText is a helper function which displays hint text the prompt.
// HintText takes the line input from the promt and the cursor position.
// It returns the hint text to display.
HintText func([]rune, int) []rune
hint []rune // The actual hint text
hintY int // Offset to hints, if it spans multiple lines
//
// Other -------------------------------------------------------------------------------------
// TempDirectory is the path to write temporary files when
// editing a line in $EDITOR. This will default to os.TempDir().
TempDirectory string
// concurency
mutex sync.Mutex
}
// NewInstance is used to create a readline instance and initialise it with sane defaults.
func NewInstance() *Instance {
rl := new(Instance)
// Prompt
rl.Prompt = &Prompt{
primary: "$ ",
}
rl.Prompt.compute(rl)
// Keymaps and configuration
rl.loadDefaultConfig()
rl.bindWidgets()
rl.loadInterruptHandlers()
// Line
rl.initLine()
rl.initRegisters()
// History
rl.historyNames = append(rl.historyNames, "local history")
rl.histories = make(map[string]History)
rl.histories["local history"] = new(MemoryHistory)
// Others
rl.TempDirectory = os.TempDir()
rl.EnableGetCursorPos = true
return rl
}