mirror of
https://github.com/sbrow/envr.git
synced 2026-08-26 09:53:32 -04:00
refactor: Removed hardcoded colors.
This commit is contained in:
@@ -24,7 +24,7 @@
|
||||
|
||||
12. Rewrite `write_command_help` to use text/tables
|
||||
|
||||
13. Instead of using a writer to strip colors, just don't print the colors.
|
||||
13. Consider getting rid of color global.
|
||||
|
||||
14. Add a text filter to the multi_select.
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ parse_args :: proc(args: []string, out: io.Stream, err: io.Stream) -> (cmd: Comm
|
||||
cmd.flags.color = terminal.is_terminal(os.stdout) ? .Always : .Never
|
||||
}
|
||||
if cmd.flags.color == .Never {
|
||||
cmd.out = make_ansi_strip_writer(cmd.out)
|
||||
disable_color = true
|
||||
}
|
||||
|
||||
if cmd.flags.config_file == "" {
|
||||
@@ -141,36 +141,23 @@ write_command_help :: proc(name: string, w: io.Writer) -> bool {
|
||||
|
||||
fmt.wprintf(
|
||||
w,
|
||||
"%s\n\n\n" +
|
||||
COLOR_HEADINGS +
|
||||
"Usage:" +
|
||||
ANSI_RESET +
|
||||
"\n\n " +
|
||||
COLOR_FLAGS +
|
||||
"%s" +
|
||||
ANSI_RESET +
|
||||
" [flags]\n\n",
|
||||
"%s\n\n\n%s\n\n %s [flags]\n\n",
|
||||
info.short,
|
||||
info.usage,
|
||||
colorize(.Heading, "Usage:"),
|
||||
colorize(.Flag, info.usage),
|
||||
flush = false,
|
||||
)
|
||||
|
||||
if len(info.aliases) > 0 {
|
||||
fmt.wprintf(
|
||||
w,
|
||||
"\n" +
|
||||
COLOR_HEADINGS +
|
||||
"Aliases:" +
|
||||
ANSI_RESET +
|
||||
"\n\n " +
|
||||
COLOR_COMMANDS +
|
||||
"%s" +
|
||||
ANSI_RESET,
|
||||
info.name,
|
||||
"\n%s\n\n %s",
|
||||
colorize(.Heading, "Aliases:"),
|
||||
colorize(.Command, info.name),
|
||||
flush = false,
|
||||
)
|
||||
for a in info.aliases {
|
||||
fmt.wprintf(w, ", " + COLOR_COMMANDS + "%s" + ANSI_RESET, a, flush = false)
|
||||
fmt.wprintf(w, ", %s", colorize(.Command, a), flush = false)
|
||||
}
|
||||
fmt.wprintf(w, "\n", flush = false)
|
||||
}
|
||||
@@ -181,21 +168,14 @@ write_command_help :: proc(name: string, w: io.Writer) -> bool {
|
||||
|
||||
fmt.wprintf(
|
||||
w,
|
||||
"\n" +
|
||||
COLOR_HEADINGS +
|
||||
"Flags:" +
|
||||
ANSI_RESET +
|
||||
"\n\n " +
|
||||
COLOR_FLAGS +
|
||||
"-h, --help" +
|
||||
ANSI_RESET +
|
||||
" help for %s\n " +
|
||||
COLOR_FLAGS +
|
||||
"-c, --config-file" +
|
||||
ANSI_RESET +
|
||||
` <path> config file (default "~/.envr/config.json")
|
||||
"\n%s\n\n %s" +
|
||||
` help for %s
|
||||
%s <path> config file (default "~/.envr/config.json")
|
||||
`,
|
||||
colorize(.Heading, "Flags:"),
|
||||
colorize(.Flag, "-h, --help"),
|
||||
info.name,
|
||||
colorize(.Flag, "-c, --config-file"),
|
||||
flush = false,
|
||||
)
|
||||
return true
|
||||
@@ -250,15 +230,13 @@ at before, restore your backup with:
|
||||
|
||||
> envr restore ~/<path to repository>/.env
|
||||
|
||||
%sUsage:%s
|
||||
%s
|
||||
|
||||
%senvr%s [command]
|
||||
%s [command]
|
||||
|
||||
`,
|
||||
COLOR_HEADINGS,
|
||||
ANSI_RESET,
|
||||
COLOR_FLAGS,
|
||||
ANSI_RESET,
|
||||
colorize(.Heading, "Usage:"),
|
||||
colorize(.Flag, "envr"),
|
||||
flush = false,
|
||||
)
|
||||
|
||||
@@ -274,7 +252,7 @@ at before, restore your backup with:
|
||||
for a in c.aliases {
|
||||
name = strings.join([]string{name, a}, ", ", tbl.format_allocator)
|
||||
}
|
||||
table.row(&tbl, table.format(&tbl, "%s%s%s", COLOR_COMMANDS, name, ANSI_RESET), c.short)
|
||||
table.row(&tbl, colorize(.Command, name, tbl.format_allocator), c.short)
|
||||
}
|
||||
|
||||
write_borderless_table(w, &tbl)
|
||||
@@ -282,29 +260,40 @@ at before, restore your backup with:
|
||||
|
||||
table.caption(&tbl, "Flags:")
|
||||
|
||||
table.row(&tbl, COLOR_FLAGS + "-h, --help" + ANSI_RESET, `show this documentation`)
|
||||
table.row(&tbl, colorize(.Flag, "-h, --help", tbl.format_allocator), `show this documentation`)
|
||||
table.row(
|
||||
&tbl,
|
||||
COLOR_FLAGS + "-c, --config-file" + ANSI_RESET + " <path>",
|
||||
table.format(
|
||||
&tbl,
|
||||
"%s <path>",
|
||||
colorize(.Flag, "-c, --config-file", tbl.format_allocator),
|
||||
),
|
||||
`config file (default "~/.envr/config.json")`,
|
||||
)
|
||||
table.row(
|
||||
&tbl,
|
||||
COLOR_FLAGS + "-o, --output" + ANSI_RESET + " 'table'|'json'",
|
||||
`the format of output data. (default 'table')`,
|
||||
table.format(
|
||||
&tbl,
|
||||
"%s 'table'|'json'",
|
||||
colorize(.Flag, "-o, --output", tbl.format_allocator),
|
||||
),
|
||||
`The format of output data. (default 'table')`,
|
||||
)
|
||||
table.row(
|
||||
&tbl,
|
||||
COLOR_FLAGS + "--color" + ANSI_RESET + " 'auto'|'always'|'never'",
|
||||
table.format(
|
||||
&tbl,
|
||||
"%s 'auto'|'always'|'never'",
|
||||
colorize(.Flag, "--color", tbl.format_allocator),
|
||||
),
|
||||
`Whether or not to colorize output. (default 'auto')`,
|
||||
)
|
||||
write_borderless_table(w, &tbl)
|
||||
|
||||
fmt.wprintf(
|
||||
w,
|
||||
`Use "%senvr%s [command] --help" for more information about a command.`,
|
||||
COLOR_FLAGS,
|
||||
ANSI_RESET,
|
||||
`Use "%s [command] --help" for more information about a command.`,
|
||||
colorize(.Flag, "envr", tbl.format_allocator),
|
||||
flush = false,
|
||||
)
|
||||
}
|
||||
|
||||
+1
-5
@@ -38,11 +38,7 @@ Generate one with: ssh-keygen -t ed25519`,
|
||||
selected, result := multi_select("Select SSH private keys:", keys[:])
|
||||
defer delete(selected)
|
||||
if result == .Cancel {
|
||||
fmt.wprintln(
|
||||
cmd.out,
|
||||
ansi.CSI + ansi.FAINT + ansi.SGR + "Cancelled." + ANSI_RESET,
|
||||
flush = false,
|
||||
)
|
||||
fmt.wprintln(cmd.out, colorize(.Message, "Cancelled."), flush = false)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -32,8 +32,8 @@ cmd_list :: proc(cmd: ^Command) {
|
||||
table.aligned_header_of_values(
|
||||
&t,
|
||||
.Center,
|
||||
COLOR_TABLE_HEADING + "Directory" + ANSI_RESET,
|
||||
COLOR_TABLE_HEADING + "Path" + ANSI_RESET,
|
||||
colorize(.Table_Heading, "Directory"),
|
||||
colorize(.Table_Heading, "Path"),
|
||||
)
|
||||
|
||||
for row in rows {
|
||||
|
||||
+7
-21
@@ -4,7 +4,6 @@ import "core:encoding/json"
|
||||
import "core:fmt"
|
||||
import "core:os"
|
||||
import "core:terminal"
|
||||
import "core:terminal/ansi"
|
||||
|
||||
cmd_scan :: proc(cmd: ^Command) {
|
||||
db, db_ok := db_open(cmd.flags.config_file)
|
||||
@@ -72,11 +71,7 @@ cmd_scan :: proc(cmd: ^Command) {
|
||||
selected, result := multi_select("Select .env files to backup:", files[:])
|
||||
defer delete(selected)
|
||||
if result == .Cancel {
|
||||
fmt.wprintln(
|
||||
cmd.out,
|
||||
ansi.CSI + ansi.FAINT + ansi.SGR + "Cancelled." + ANSI_RESET,
|
||||
flush = false,
|
||||
)
|
||||
fmt.wprintln(cmd.out, colorize(.Message, "Cancelled."), flush = false)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -100,25 +95,16 @@ cmd_scan :: proc(cmd: ^Command) {
|
||||
}
|
||||
|
||||
if added_count > 0 {
|
||||
fmt.wprintf(
|
||||
fmt.wprintln(
|
||||
cmd.out,
|
||||
ansi.CSI +
|
||||
ansi.BOLD +
|
||||
";" +
|
||||
ansi.FG_GREEN +
|
||||
ansi.SGR +
|
||||
"Successfully added %d file(s) to backup." +
|
||||
ANSI_RESET +
|
||||
"\n",
|
||||
added_count,
|
||||
colorize(
|
||||
.Sucess,
|
||||
fmt.tprintf("Successfully added %d file(s) to backup.", added_count),
|
||||
),
|
||||
flush = false,
|
||||
)
|
||||
} else {
|
||||
fmt.wprintln(
|
||||
cmd.out,
|
||||
ansi.CSI + ansi.FAINT + ansi.SGR + "No files were added." + ANSI_RESET,
|
||||
flush = false,
|
||||
)
|
||||
fmt.wprintln(cmd.out, colorize(.Message, "No files were added."), flush = false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -54,8 +54,8 @@ cmd_sync :: proc(cmd: ^Command) {
|
||||
table.aligned_header_of_values(
|
||||
&t,
|
||||
.Center,
|
||||
COLOR_TABLE_HEADING + "File" + ANSI_RESET,
|
||||
COLOR_TABLE_HEADING + "Status" + ANSI_RESET,
|
||||
colorize(.Table_Heading, "File"),
|
||||
colorize(.Table_Heading, "Status"),
|
||||
)
|
||||
|
||||
for res in results {
|
||||
|
||||
+50
-70
@@ -1,86 +1,66 @@
|
||||
package main
|
||||
|
||||
import "core:io"
|
||||
import "base:runtime"
|
||||
import "core:strings"
|
||||
import "core:terminal/ansi"
|
||||
|
||||
COLOR_HEADINGS ::
|
||||
ansi.CSI + ansi.FG_BRIGHT_GREEN + ";" + ansi.BOLD + ";" + ansi.UNDERLINE + ansi.SGR
|
||||
Color_Code :: enum {
|
||||
Heading,
|
||||
Command,
|
||||
// Example
|
||||
Flag,
|
||||
Table_Heading,
|
||||
Message,
|
||||
Sucess,
|
||||
Caret,
|
||||
Option_Label,
|
||||
}
|
||||
|
||||
COLOR_COMMANDS :: ansi.CSI + ansi.FG_BRIGHT_CYAN + ";" + ansi.BOLD + ansi.SGR
|
||||
|
||||
COLOR_EXAMPLE :: ansi.CSI + ansi.ITALIC + ansi.SGR
|
||||
|
||||
COLOR_FLAGS :: ansi.CSI + ansi.BOLD + ";" + ansi.FG_BRIGHT_WHITE + ansi.SGR
|
||||
|
||||
COLOR_TABLE_HEADING :: ansi.CSI + ansi.FG_BRIGHT_GREEN + ansi.SGR
|
||||
// COLOR_EXAMPLE :: ansi.CSI + ansi.ITALIC + ansi.SGR
|
||||
|
||||
@(private = "file")
|
||||
ANSI_RESET :: ansi.CSI + ansi.RESET + ansi.SGR
|
||||
|
||||
ANSI_Strip_State :: enum { Normal, GotESC, InCSI }
|
||||
disable_color := false
|
||||
|
||||
ANSI_Strip_Data :: struct {
|
||||
inner: io.Writer,
|
||||
state: ANSI_Strip_State,
|
||||
}
|
||||
|
||||
ansi_strip_proc :: proc(
|
||||
stream_data: rawptr,
|
||||
mode: io.Stream_Mode,
|
||||
p: []byte,
|
||||
offset: i64,
|
||||
whence: io.Seek_From,
|
||||
) -> (n: i64, err: io.Error) {
|
||||
data := cast(^ANSI_Strip_Data) stream_data
|
||||
|
||||
#partial switch mode {
|
||||
case .Write:
|
||||
start := 0
|
||||
for i in 0..<len(p) {
|
||||
b := p[i]
|
||||
|
||||
switch data.state {
|
||||
case .Normal:
|
||||
if b == 0x1b {
|
||||
if i > start {
|
||||
io.write(data.inner, p[start:i])
|
||||
}
|
||||
data.state = .GotESC
|
||||
}
|
||||
|
||||
case .GotESC:
|
||||
if b == '[' {
|
||||
data.state = .InCSI
|
||||
colorize :: proc(
|
||||
color: Color_Code,
|
||||
text: string,
|
||||
allocator := context.temp_allocator,
|
||||
disable := disable_color,
|
||||
) -> (
|
||||
string,
|
||||
runtime.Allocator_Error,
|
||||
) #optional_allocator_error {
|
||||
if disable {
|
||||
return text, nil
|
||||
} else {
|
||||
start = i
|
||||
data.state = .Normal
|
||||
return strings.concatenate(
|
||||
{ansi.CSI, color_code(color), ansi.SGR, text, ANSI_RESET},
|
||||
allocator,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
case .InCSI:
|
||||
if b >= 0x40 && b <= 0x7E {
|
||||
start = i + 1
|
||||
data.state = .Normal
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if data.state == .Normal && len(p) > start {
|
||||
io.write(data.inner, p[start:])
|
||||
}
|
||||
|
||||
n = i64(len(p))
|
||||
return
|
||||
|
||||
case .Flush:
|
||||
return 0, io.flush(data.inner)
|
||||
case .Close:
|
||||
return 0, io.close(data.inner)
|
||||
@(private = "file")
|
||||
color_code :: proc(code: Color_Code) -> string {
|
||||
switch code {
|
||||
case .Heading:
|
||||
return ansi.BOLD + ";" + ansi.UNDERLINE + ";" + ansi.FG_BRIGHT_GREEN
|
||||
case .Command:
|
||||
return ansi.BOLD + ";" + ansi.FG_BRIGHT_CYAN
|
||||
case .Flag:
|
||||
return ansi.BOLD + ";" + ansi.FG_BRIGHT_WHITE
|
||||
case .Table_Heading:
|
||||
return ansi.FG_BRIGHT_GREEN
|
||||
case .Message:
|
||||
return ansi.FAINT
|
||||
case .Sucess, .Caret:
|
||||
return ansi.BOLD + ";" + ansi.FG_GREEN
|
||||
case .Option_Label:
|
||||
return ansi.BOLD + ";" + ansi.FG_CYAN
|
||||
case:
|
||||
return data.inner.procedure(data.inner.data, mode, p, offset, whence)
|
||||
panic("Unknown case")
|
||||
}
|
||||
}
|
||||
|
||||
make_ansi_strip_writer :: proc(inner: io.Writer) -> io.Writer {
|
||||
data := new(ANSI_Strip_Data, context.temp_allocator)
|
||||
data.inner = inner
|
||||
return io.Writer{procedure = ansi_strip_proc, data = rawptr(data)}
|
||||
}
|
||||
|
||||
+19
-5
@@ -66,11 +66,17 @@ multi_select :: proc(
|
||||
case .Space:
|
||||
selected[cursor] = !selected[cursor]
|
||||
case .Enter:
|
||||
fmt.printf(ansi.CSI + "%d" + ansi.CUU + ansi.CSI + ansi.ED + ansi.CSI + ansi.DECTCEM_SHOW, visible + 1)
|
||||
fmt.printf(
|
||||
ansi.CSI + "%d" + ansi.CUU + ansi.CSI + ansi.ED + ansi.CSI + ansi.DECTCEM_SHOW,
|
||||
visible + 1,
|
||||
)
|
||||
result = .Confirm
|
||||
return
|
||||
case .Escape:
|
||||
fmt.printf(ansi.CSI + "%d" + ansi.CUU + ansi.CSI + ansi.ED + ansi.CSI + ansi.DECTCEM_SHOW, visible + 1)
|
||||
fmt.printf(
|
||||
ansi.CSI + "%d" + ansi.CUU + ansi.CSI + ansi.ED + ansi.CSI + ansi.DECTCEM_SHOW,
|
||||
visible + 1,
|
||||
)
|
||||
result = .Cancel
|
||||
return
|
||||
case .Unknown:
|
||||
@@ -89,7 +95,10 @@ render_options :: proc(
|
||||
cursor: int,
|
||||
scroll_offset: int,
|
||||
) -> int {
|
||||
fmt.printf(ansi.CSI + ansi.BOLD + ";" + ansi.FG_CYAN + ansi.SGR + "%s" + ANSI_RESET + " (↑/↓ move, space select, enter confirm)\r\n", prompt)
|
||||
fmt.printf(
|
||||
"%s (↑/↓ move, space select, enter confirm)\r\n",
|
||||
colorize(.Option_Label, prompt),
|
||||
)
|
||||
|
||||
end := scroll_offset + MAX_VISIBLE
|
||||
if end > len(options) {
|
||||
@@ -102,9 +111,14 @@ render_options :: proc(
|
||||
checkbox = "x"
|
||||
}
|
||||
if i == cursor {
|
||||
fmt.printf(ansi.CSI + ansi.BOLD + ";" + ansi.FG_GREEN + ansi.SGR + "> " + ANSI_RESET + "[" + ansi.CSI + ansi.FG_GREEN + ansi.SGR + "%s" + ANSI_RESET + "] %s\r\n", checkbox, options[i])
|
||||
fmt.printf(
|
||||
"%s [%s] %s\r\n",
|
||||
colorize(.Caret, ">"),
|
||||
colorize(.Sucess, checkbox),
|
||||
options[i],
|
||||
)
|
||||
} else {
|
||||
fmt.printf(" [" + ansi.CSI + ansi.FAINT + ansi.SGR + "%s" + ANSI_RESET + "] %s\r\n", checkbox, options[i])
|
||||
fmt.printf(" [%s] %s\r\n", colorize(.Sucess, checkbox), options[i])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ write_borderless_table :: proc(w: io.Writer, t: ^table.Table) {
|
||||
if t.caption != "" {
|
||||
table.write_text_align(
|
||||
w,
|
||||
fmt.tprintf("%s%s%s", COLOR_HEADINGS, t.caption, ANSI_RESET),
|
||||
colorize(.Heading, t.caption),
|
||||
.Left,
|
||||
0, //t.lpad,
|
||||
0, //t.rpad,
|
||||
|
||||
+10
-2
@@ -2,6 +2,7 @@
|
||||
|
||||
package main
|
||||
|
||||
import "core:strings"
|
||||
import "core:testing"
|
||||
|
||||
@(test)
|
||||
@@ -16,7 +17,7 @@ test_ansi_aware_width_empty :: proc(t: ^testing.T) {
|
||||
|
||||
@(test)
|
||||
test_ansi_aware_width_with_color_codes :: proc(t: ^testing.T) {
|
||||
colored := COLOR_TABLE_HEADING + "Directory" + ANSI_RESET
|
||||
colored := colorize(.Heading, "Directory", disable = false)
|
||||
testing.expect_value(t, ansi_aware_width(colored), 9)
|
||||
}
|
||||
|
||||
@@ -28,6 +29,13 @@ test_ansi_aware_width_multibyte :: proc(t: ^testing.T) {
|
||||
|
||||
@(test)
|
||||
test_ansi_aware_width_multiple_escape_sequences :: proc(t: ^testing.T) {
|
||||
colored := COLOR_TABLE_HEADING + "a" + ANSI_RESET + "b" + COLOR_TABLE_HEADING + "c" + ANSI_RESET
|
||||
colored := strings.concatenate(
|
||||
{
|
||||
colorize(.Heading, "a", disable = false),
|
||||
colorize(.Heading, "b", disable = false),
|
||||
colorize(.Heading, "c", disable = false),
|
||||
},
|
||||
)
|
||||
testing.expect_value(t, ansi_aware_width(colored), 3)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user