mirror of
https://github.com/sbrow/envr.git
synced 2026-10-25 08:41:55 -04:00
feat: Added view command for opening files.
This commit is contained in:
+157
@@ -0,0 +1,157 @@
|
||||
package main
|
||||
|
||||
import "core:fmt"
|
||||
import "core:io"
|
||||
import "core:os"
|
||||
import "core:path/filepath"
|
||||
import "core:strconv"
|
||||
import "core:strings"
|
||||
import "core:terminal"
|
||||
|
||||
cmd_view :: proc(cmd: ^Command) -> bool {
|
||||
if len(cmd.args) > 1 {
|
||||
print_command_help(cmd)
|
||||
return false
|
||||
}
|
||||
|
||||
path := len(cmd.args) == 1 ? cmd.args[0] : ""
|
||||
|
||||
db := db_open(cmd.flags.config_file) or_return
|
||||
defer db_close(&db)
|
||||
|
||||
files := db_list(&db) or_return
|
||||
paths := make([]string, len(files), context.temp_allocator)
|
||||
for file, i in files do paths[i] = file.path
|
||||
resolved_path := choose_view_path(path, paths, cmd.err) or_return
|
||||
|
||||
file := db_fetch(&db, resolved_path) or_return
|
||||
|
||||
if cmd.flags.stdout || !terminal.is_terminal(os.stdout) {
|
||||
fmt.wprintf(cmd.out, "%s", file.contents, flush = false)
|
||||
return true
|
||||
}
|
||||
|
||||
page_file_contents(file.contents, cmd.err)
|
||||
return true
|
||||
}
|
||||
|
||||
choose_view_path :: proc(path: string, paths: []string, err_out: io.Writer) -> (string, bool) {
|
||||
if len(strings.trim_space(path)) > 0 {
|
||||
resolved, _, _, is_remote, path_ok := normalize_remote_identity(path)
|
||||
if is_remote && !path_ok do return "", false
|
||||
if !is_remote {
|
||||
abs_path, abs_err := filepath.abs(path, context.temp_allocator)
|
||||
if abs_err == nil do resolved = abs_path
|
||||
}
|
||||
for stored in paths {
|
||||
if stored == resolved do return stored, true
|
||||
}
|
||||
if number, number_ok := strconv.parse_int(path, 10);
|
||||
number_ok && number > 0 && number <= len(paths) {
|
||||
return paths[number - 1], true
|
||||
}
|
||||
}
|
||||
|
||||
matches := matching_view_paths(path, paths)
|
||||
if len(matches) == 0 {
|
||||
fmt.wprintf(err_out, "No backed-up file matches: %s\n", path, flush = false)
|
||||
return "", false
|
||||
}
|
||||
if len(path) > 0 && len(matches) == 1 {
|
||||
return matches[0], true
|
||||
}
|
||||
if !terminal.is_terminal(os.stdin) || !terminal.is_terminal(os.stderr) {
|
||||
fmt.wprintln(
|
||||
err_out,
|
||||
"An interactive terminal is required to choose a backup; pass a more specific path.",
|
||||
flush = false,
|
||||
)
|
||||
return "", false
|
||||
}
|
||||
selected := single_select("Select a backed-up file:", matches[:])
|
||||
if selected < 0 {
|
||||
return "", false
|
||||
}
|
||||
return matches[selected], true
|
||||
}
|
||||
|
||||
matching_view_paths :: proc(path: string, paths: []string) -> [dynamic]string {
|
||||
matches := make([dynamic]string, 0, len(paths), context.temp_allocator)
|
||||
needle := strings.to_lower(path, context.temp_allocator)
|
||||
for stored in paths {
|
||||
if strings.contains(strings.to_lower(stored, context.temp_allocator), needle) {
|
||||
append(&matches, stored)
|
||||
}
|
||||
}
|
||||
return matches
|
||||
}
|
||||
|
||||
page_file_contents :: proc(contents: string, err_out: io.Writer) {
|
||||
pager := os.get_env("PAGER", context.temp_allocator)
|
||||
if len(strings.trim_space(pager)) == 0 {
|
||||
when ODIN_OS == .Windows {
|
||||
pager = "more"
|
||||
} else {
|
||||
pager = "less"
|
||||
}
|
||||
}
|
||||
|
||||
parts := strings.split(strings.trim_space(pager), " ", context.temp_allocator)
|
||||
command := make([dynamic]string, 0, len(parts) + 1, context.temp_allocator)
|
||||
for part in parts {
|
||||
if len(part) > 0 {
|
||||
append(&command, part)
|
||||
}
|
||||
}
|
||||
if len(command) == 0 {
|
||||
append(&command, "less")
|
||||
}
|
||||
when ODIN_OS == .Windows {
|
||||
if command[0] != "more" do append(&command, "-")
|
||||
} else {
|
||||
append(&command, "-")
|
||||
}
|
||||
|
||||
read_end, write_end, pipe_err := os.pipe()
|
||||
if pipe_err != nil {
|
||||
fmt.wprintf(err_out, "Error creating pager pipe: %v\n", pipe_err, flush = false)
|
||||
return
|
||||
}
|
||||
defer os.close(write_end)
|
||||
|
||||
desc := os.Process_Desc {
|
||||
command = command[:],
|
||||
stdin = read_end,
|
||||
stdout = os.stdout,
|
||||
stderr = os.stderr,
|
||||
}
|
||||
process, start_err := os.process_start(desc)
|
||||
os.close(read_end)
|
||||
if start_err != nil {
|
||||
fmt.wprintf(err_out, "Error starting pager %q: %v\n", command[0], start_err, flush = false)
|
||||
return
|
||||
}
|
||||
|
||||
remaining := transmute([]u8)contents
|
||||
write_err: os.Error
|
||||
for len(remaining) > 0 {
|
||||
written, err := os.write(write_end, remaining)
|
||||
if err != nil {
|
||||
write_err = err
|
||||
break
|
||||
}
|
||||
if written == 0 do break
|
||||
remaining = remaining[written:]
|
||||
}
|
||||
os.close(write_end)
|
||||
state, wait_err := os.process_wait(process)
|
||||
if write_err != nil {
|
||||
fmt.wprintf(err_out, "Error writing to pager: %v\n", write_err, flush = false)
|
||||
}
|
||||
if wait_err != nil {
|
||||
fmt.wprintf(err_out, "Error waiting for pager: %v\n", wait_err, flush = false)
|
||||
} else if state.exit_code != 0 {
|
||||
fmt.wprintf(err_out, "Pager exited with status %d\n", state.exit_code, flush = false)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user