Add persistent history
This commit is contained in:
parent
50b0e6e641
commit
a3e9ee9807
1 changed files with 42 additions and 20 deletions
62
cli/cli.odin
62
cli/cli.odin
|
|
@ -6,6 +6,7 @@ import "core:log"
|
||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
import "core:mem"
|
import "core:mem"
|
||||||
import "core:slice"
|
import "core:slice"
|
||||||
|
import "core:bytes"
|
||||||
import "core:strings"
|
import "core:strings"
|
||||||
import "core:sys/posix"
|
import "core:sys/posix"
|
||||||
import "core:path/filepath"
|
import "core:path/filepath"
|
||||||
|
|
@ -21,11 +22,12 @@ Term :: struct {
|
||||||
min_pos: i32,
|
min_pos: i32,
|
||||||
history: [dynamic][]rune,
|
history: [dynamic][]rune,
|
||||||
history_pos: Maybe(i32),
|
history_pos: Maybe(i32),
|
||||||
|
history_file: string,
|
||||||
written_line: Maybe([]rune),
|
written_line: Maybe([]rune),
|
||||||
orig_mode: posix.termios
|
orig_mode: posix.termios
|
||||||
}
|
}
|
||||||
|
|
||||||
term := Term{pos = 0, min_pos = 0, history_pos = nil}
|
term := Term{pos = 0, min_pos = 0, history_pos = nil, written_line = nil}
|
||||||
|
|
||||||
init_cli :: proc () {
|
init_cli :: proc () {
|
||||||
mem_err: mem.Allocator_Error
|
mem_err: mem.Allocator_Error
|
||||||
|
|
@ -38,13 +40,18 @@ init_cli :: proc () {
|
||||||
home_path := string(posix.getenv("HOME"))
|
home_path := string(posix.getenv("HOME"))
|
||||||
log.assertf(home_path != "", "Home path not found")
|
log.assertf(home_path != "", "Home path not found")
|
||||||
|
|
||||||
history_file := filepath.join({home_path, HISTORY_FILE}, context.allocator)
|
term.history_file = filepath.join({home_path, HISTORY_FILE}, context.allocator) //todo deinit
|
||||||
log.assertf(mem_err == nil, "Memory allocation failed")
|
log.assertf(mem_err == nil, "Memory allocation failed")
|
||||||
defer delete(history_file)
|
|
||||||
|
|
||||||
history_content, err := os.read_entire_file_from_filename_or_err(history_file, context.allocator)
|
if !os.exists(term.history_file) {
|
||||||
|
handle, ferr := os.open(term.history_file, os.O_CREATE | os.O_RDWR, 0o600)
|
||||||
|
log.assertf(ferr == nil, "Failed to create history file")
|
||||||
|
os.close(handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
history_content, err := os.read_entire_file_from_filename_or_err(term.history_file, context.allocator)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.printfln("skal: Couldn't read history file, continuing without history...")
|
fmt.printfln("skal: Couldn't read history file: %s, because of: %s, continuing without history...", term.history_file, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer delete(history_content)
|
defer delete(history_content)
|
||||||
|
|
@ -102,11 +109,6 @@ get_prompt_prefix :: proc() -> string {
|
||||||
return prompt
|
return prompt
|
||||||
}
|
}
|
||||||
|
|
||||||
@(private)
|
|
||||||
get_input :: proc() -> string {
|
|
||||||
return utf8.runes_to_string(term.input_buffer[:])
|
|
||||||
}
|
|
||||||
|
|
||||||
@(private)
|
@(private)
|
||||||
reset_prompt :: proc() {
|
reset_prompt :: proc() {
|
||||||
clear(&term.input_buffer)
|
clear(&term.input_buffer)
|
||||||
|
|
@ -160,10 +162,11 @@ handle_nav :: proc(in_stream: ^io.Stream) {
|
||||||
}
|
}
|
||||||
|
|
||||||
history_pos += 1
|
history_pos += 1
|
||||||
|
history_pos_max := i32(len(term.history)-1)
|
||||||
new_input: []rune
|
new_input: []rune
|
||||||
if history_pos > i32(len(term.history)-1) {
|
if history_pos > history_pos_max {
|
||||||
term.history_pos = nil
|
term.history_pos = nil
|
||||||
history_pos = i32(len(term.history)-1)
|
history_pos = history_pos_max
|
||||||
new_input, ok = term.written_line.?; assert(ok)
|
new_input, ok = term.written_line.?; assert(ok)
|
||||||
term.written_line = nil
|
term.written_line = nil
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -189,13 +192,14 @@ handle_nav :: proc(in_stream: ^io.Stream) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(private)
|
||||||
backwards :: proc() {
|
backwards :: proc() {
|
||||||
DELETE_AND_REVERSE :: "\b \b"
|
DELETE_AND_REVERSE :: "\b \b"
|
||||||
|
|
||||||
if term.pos == term.min_pos do return
|
if term.pos == term.min_pos do return
|
||||||
|
|
||||||
last_rune := term.input_buffer[len(term.input_buffer)-1]
|
last_rune := term.input_buffer[len(term.input_buffer)-1]
|
||||||
_, _, width := utf8.grapheme_count(utf8.runes_to_string({last_rune}))
|
_, _, width := utf8.grapheme_count(utf8.runes_to_string({last_rune}, context.temp_allocator))
|
||||||
resize(&term.input_buffer, len(term.input_buffer)-1)
|
resize(&term.input_buffer, len(term.input_buffer)-1)
|
||||||
|
|
||||||
for _ in 0..<width {
|
for _ in 0..<width {
|
||||||
|
|
@ -205,6 +209,24 @@ backwards :: proc() {
|
||||||
term.pos -=1
|
term.pos -=1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(private)
|
||||||
|
append_history_file :: proc(data: []rune) {
|
||||||
|
append(&term.history, slice.clone(data))
|
||||||
|
term.history_pos = nil
|
||||||
|
term.written_line = nil
|
||||||
|
|
||||||
|
fd, err := os.open(term.history_file, os.O_WRONLY | os.O_APPEND | os.O_CREATE)
|
||||||
|
defer os.close(fd)
|
||||||
|
if err != nil {
|
||||||
|
fmt.eprintfln("skal: Couldn't write to history file")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
history_data := strings.concatenate({utf8.runes_to_string(data[:]), "\n"}, context.temp_allocator)
|
||||||
|
_, werr := os.write_string(fd, history_data)
|
||||||
|
log.ensuref(werr == nil, "skal: Couldn't write to history file")
|
||||||
|
}
|
||||||
|
|
||||||
skip_and_clear :: proc() {
|
skip_and_clear :: proc() {
|
||||||
reset_prompt()
|
reset_prompt()
|
||||||
prompt_prefix := get_prompt_prefix()
|
prompt_prefix := get_prompt_prefix()
|
||||||
|
|
@ -214,11 +236,6 @@ skip_and_clear :: proc() {
|
||||||
term.pos = term.min_pos
|
term.pos = term.min_pos
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_and_print :: proc(input: []rune) {
|
|
||||||
skip_and_clear()
|
|
||||||
append(&term.input_buffer, ..input[:])
|
|
||||||
}
|
|
||||||
|
|
||||||
run_prompt :: proc() -> string {
|
run_prompt :: proc() -> string {
|
||||||
enable_raw_mode()
|
enable_raw_mode()
|
||||||
|
|
||||||
|
|
@ -232,8 +249,13 @@ run_prompt :: proc() -> string {
|
||||||
|
|
||||||
switch rn {
|
switch rn {
|
||||||
case '\n':
|
case '\n':
|
||||||
fmt.println()
|
fmt.println()
|
||||||
return get_input()
|
if len(term.input_buffer) == 0 do return ""
|
||||||
|
|
||||||
|
append_history_file(term.input_buffer[:])
|
||||||
|
input := utf8.runes_to_string(term.input_buffer[:], context.temp_allocator)
|
||||||
|
|
||||||
|
return input
|
||||||
|
|
||||||
case '\f':
|
case '\f':
|
||||||
fmt.println()
|
fmt.println()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue