mirror of
https://github.com/vlang/v.git
synced 2025-09-08 23:07:19 -04:00
readline: add completion support (#20559)
This commit is contained in:
parent
4b0a2cb7c9
commit
8d5f95d604
@ -21,16 +21,20 @@ struct Winsize {
|
||||
// Example: import readline { Readline }
|
||||
pub struct Readline {
|
||||
mut:
|
||||
is_raw bool
|
||||
orig_termios termios.Termios // Linux
|
||||
current []rune // Line being edited
|
||||
cursor int // Cursor position
|
||||
overwrite bool
|
||||
cursor_row_offset int
|
||||
prompt string
|
||||
prompt_offset int
|
||||
previous_lines [][]rune
|
||||
skip_empty bool // skip the empty lines when calling .history_previous()
|
||||
search_index int
|
||||
is_tty bool
|
||||
is_raw bool
|
||||
orig_termios termios.Termios // Linux
|
||||
current []rune // Line being edited
|
||||
cursor int // Cursor position
|
||||
overwrite bool
|
||||
cursor_row_offset int
|
||||
prompt string
|
||||
prompt_offset int
|
||||
previous_lines [][]rune
|
||||
skip_empty bool // skip the empty lines when calling .history_previous()
|
||||
search_index int
|
||||
is_tty bool
|
||||
last_prefix_completion []rune
|
||||
last_completion_offset int
|
||||
completion_list []string
|
||||
completion_callback fn (string) []string = unsafe { nil }
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ enum Action {
|
||||
overwrite
|
||||
clear_screen
|
||||
suspend
|
||||
completion
|
||||
}
|
||||
|
||||
// enable_raw_mode enables the raw mode of the terminal.
|
||||
@ -174,7 +175,7 @@ pub fn read_line(prompt string) !string {
|
||||
}
|
||||
|
||||
// analyse returns an `Action` based on the type of input byte given in `c`.
|
||||
fn (r Readline) analyse(c int) Action {
|
||||
fn (mut r Readline) analyse(c int) Action {
|
||||
if c > 255 {
|
||||
return Action.insert_character
|
||||
}
|
||||
@ -183,8 +184,12 @@ fn (r Readline) analyse(c int) Action {
|
||||
return .eof
|
||||
} // NUL, End of Text, End of Transmission
|
||||
`\n`, `\r` {
|
||||
r.last_prefix_completion.clear()
|
||||
return .commit_line
|
||||
}
|
||||
`\t` {
|
||||
return .completion
|
||||
}
|
||||
`\f` {
|
||||
return .clear_screen
|
||||
} // CTRL + L
|
||||
@ -211,6 +216,7 @@ fn (r Readline) analyse(c int) Action {
|
||||
} // CTRL + Z, SUB
|
||||
else {
|
||||
if c >= ` ` {
|
||||
r.last_prefix_completion.clear()
|
||||
return Action.insert_character
|
||||
}
|
||||
return Action.nothing
|
||||
@ -299,6 +305,7 @@ fn (mut r Readline) execute(a Action, c int) bool {
|
||||
.overwrite { r.switch_overwrite() }
|
||||
.clear_screen { r.clear_screen() }
|
||||
.suspend { r.suspend() }
|
||||
.completion { r.completion() }
|
||||
else {}
|
||||
}
|
||||
return false
|
||||
@ -416,6 +423,7 @@ fn (mut r Readline) delete_character() {
|
||||
r.cursor--
|
||||
r.current.delete(r.cursor)
|
||||
r.refresh_line()
|
||||
r.completion_clear()
|
||||
}
|
||||
|
||||
fn (mut r Readline) delete_word_left() {
|
||||
@ -450,12 +458,14 @@ fn (mut r Readline) delete_word_left() {
|
||||
|
||||
r.current.delete_many(r.cursor, orig_cursor - r.cursor)
|
||||
r.refresh_line()
|
||||
r.completion_clear()
|
||||
}
|
||||
|
||||
fn (mut r Readline) delete_line() {
|
||||
r.current = []
|
||||
r.cursor = 0
|
||||
r.refresh_line()
|
||||
r.completion_clear()
|
||||
}
|
||||
|
||||
// suppr_character removes (suppresses) the character in front of the cursor.
|
||||
@ -577,6 +587,56 @@ fn (mut r Readline) history_next() {
|
||||
r.refresh_line()
|
||||
}
|
||||
|
||||
// completion implements the tab completion feature
|
||||
fn (mut r Readline) completion() {
|
||||
// check if completion is used
|
||||
if r.completion_list.len == 0 && r.completion_callback == unsafe { nil } {
|
||||
return
|
||||
}
|
||||
// use last prefix for completion or current input
|
||||
prefix := if r.last_prefix_completion.len > 0 { r.last_prefix_completion } else { r.current }
|
||||
if prefix.len == 0 {
|
||||
return
|
||||
}
|
||||
// filtering by prefix
|
||||
opts := if r.completion_list.len > 0 {
|
||||
sprefix := prefix.string()
|
||||
r.completion_list.filter(it.starts_with(sprefix))
|
||||
} else if r.completion_callback != unsafe { nil } {
|
||||
r.completion_callback(prefix.string())
|
||||
} else {
|
||||
[]string{}
|
||||
}
|
||||
if opts.len == 0 {
|
||||
r.completion_clear()
|
||||
return
|
||||
}
|
||||
|
||||
// moving for next possible completion match using saved prefix
|
||||
if r.last_prefix_completion.len != 0 {
|
||||
if opts.len > r.last_completion_offset + 1 {
|
||||
r.last_completion_offset += 1
|
||||
} else {
|
||||
// reset for initial option in completion list
|
||||
r.last_completion_offset = 0
|
||||
}
|
||||
} else {
|
||||
// save current prefix before tab'ing
|
||||
r.last_prefix_completion = r.current
|
||||
}
|
||||
|
||||
// set the text to the current completion match in the completion list
|
||||
r.current = opts[r.last_completion_offset].runes()
|
||||
r.cursor = r.current.len
|
||||
r.refresh_line()
|
||||
}
|
||||
|
||||
// completion_clear resets the completion state
|
||||
fn (mut r Readline) completion_clear() {
|
||||
r.last_prefix_completion.clear()
|
||||
r.last_completion_offset = 0
|
||||
}
|
||||
|
||||
// suspend sends the `SIGSTOP` signal to the terminal.
|
||||
fn (mut r Readline) suspend() {
|
||||
is_standalone := os.getenv('VCHILD') != 'true'
|
||||
|
Loading…
x
Reference in New Issue
Block a user