import "core:net"
import "core:os"
import "core:strings"
+import "core:sync"
+import "core:thread"
import fpath "core:path/filepath"
-import nc "ncurses"
+import nc "../ncurses"
-import "../common"
+COLOR_FIRST :: 16
+COLOR_SECOND :: 17
+COLOR_THIRD :: 18
+COLOR_FOURTH :: 19
Config :: struct {
selected_profile: Maybe(string),
config_update :: proc(config: Config) {
home_path := os.get_env("HOME")
- storage_path := fpath.join({ home_path, "mesange-cli" }, context.temp_allocator)
+ storage_path := fpath.join({ home_path, "mesange" }, context.temp_allocator)
config_path := fpath.join({ storage_path, "config.json" }, context.temp_allocator)
config_file, err1 := os.open(config_path, os.O_WRONLY | os.O_CREATE | os.O_TRUNC, 0777)
}
App :: struct {
+ mutex: sync.Mutex,
+ running: bool,
+
screen: ^nc.Window,
storage_path: string,
state: State,
box_message: Maybe(^nc.Window),
info_bar: ^nc.Window,
+ input_window: ^nc.Window,
config: Config,
profile_password: Maybe(string),
app_init :: proc() -> App {
screen := nc.initscr()
+ nc.cbreak()
nc.keypad(screen, true)
nc.curs_set(0)
+ nc.use_default_colors()
+ nc.start_color()
+
+ nc.init_color(COLOR_FIRST, 800, 800, 800)
+ nc.init_color(COLOR_SECOND, 500, 500, 500)
+ nc.init_color(COLOR_THIRD, 200, 200, 200)
+ nc.init_color(COLOR_FOURTH, 000, 000, 000)
+
+ nc.init_pair(1, COLOR_FIRST, COLOR_THIRD)
+ nc.init_pair(2, COLOR_FIRST, COLOR_FOURTH)
+
screen_height, screen_width := nc.getmaxyx(screen)
- info_bar := nc.newwin(0, 0, 3, screen_width)
+ info_bar := nc.newwin(1, screen_width, screen_height - 2, 0)
+ input_window := nc.newwin(1, screen_width, screen_height - 1, 0)
- nc.box(info_bar, 0, 0)
- nc.wrefresh(info_bar)
+ nc.refresh()
home_path := os.get_env("HOME")
storage_path := fpath.join({ home_path, "mesange" })
}
}
- return {
+ app := App{
+ running = true,
+
screen = screen,
storage_path = storage_path,
+
+ info_bar = info_bar,
+ input_window = input_window,
}
+
+ app_clear_info_bar(app)
+
+ return app
}
app_deinit :: proc(app: App) {
config_deinit(app.config)
+ nc.delwin(app.input_window)
nc.delwin(app.info_bar)
if box_message, ok := app.box_message.?; ok {
nc.clear()
nc.refresh()
+ app_clear_info_bar(app^)
+
app.state = state
}
app_set_info_bar :: proc(app: ^App, content: string) {
-
+ app_clear_info_bar(app^)
+
+ c_content := strings.clone_to_cstring(content, context.temp_allocator)
+
+ nc.wattron(app.info_bar, nc.COLOR_PAIR(1))
+ nc.wprintw(app.info_bar, c_content)
+ nc.wattroff(app.info_bar, nc.COLOR_PAIR(1))
+
+ nc.wrefresh(app.info_bar)
}
app_set_box_message :: proc(app: ^App, lines: []string) {
(screen_width - width) / 2,
)
+ color := nc.COLOR_PAIR(2)
+
+ nc.wattron(box_message, color)
+
for line, i in lines {
c_line := strings.clone_to_cstring(line, context.temp_allocator)
nc.mvwprintw(box_message, i32(i + 1), 1, c_line)
}
nc.box(box_message, 0, 0)
+ nc.wattroff(box_message, color)
+
nc.wrefresh(box_message)
+ sync.mutex_lock(&app.mutex)
app.box_message = box_message
+ sync.mutex_unlock(&app.mutex)
}
app_clear_info_bar :: proc(app: App) {
-
+ height, width := nc.getmaxyx(app.info_bar)
+ color := nc.COLOR_PAIR(1)
+
+ nc.wclear(app.info_bar)
+ nc.wattron(app.info_bar, color)
+
+ for _ in 0..<width {
+ nc.waddch(app.info_bar, ' ')
+ }
+
+ nc.wattroff(app.info_bar, color)
+ nc.wrefresh(app.info_bar)
}
app_clear_box_message :: proc(app: ^App) {
app_get_input :: proc(app: App, allocator := context.allocator) -> string {
context.allocator = allocator
+ nc.wclear(app.input_window)
+ nc.wrefresh(app.input_window)
+
buffer: [256]u8
screen_height, screen_width := nc.getmaxyx(app.screen)
nc.curs_set(1)
- nc.mvgetnstr(screen_height - 1, 0, raw_data(buffer[:]), len(buffer))
+ nc.wgetnstr(app.input_window, raw_data(buffer[:]), len(buffer))
nc.curs_set(0)
return strings.clone_from_cstring(cstring(raw_data(&buffer)))
}
+handle_state :: proc(app: ^App) {
+ for {
+ switch app.state {
+ case .Load_Config: state_load_config(app)
+ case .Ask_Config: state_ask_config(app)
+
+ case .Load_Profile: state_load_profile(app)
+ case .Ask_Profile: state_ask_profile(app)
+ case .Ask_Profile_Password: state_ask_profile_password(app)
+ case .Ask_Profile_Seed_Phrase: state_ask_profile_seed_phrase(app)
+ }
+ }
+}
+
main :: proc() {
app := app_init()
defer app_deinit(app)
- for {
- switch app.state {
- case .Load_Config: state_load_config(&app)
- case .Ask_Config: state_ask_config(&app)
+ handle_state_thread := thread.create_and_start_with_poly_data(&app, handle_state, context)
+ defer thread.terminate(handle_state_thread, 0)
+
+ for app.running {
- case .Load_Profile: state_load_profile(&app)
- case .Ask_Profile: state_ask_profile(&app)
- case .Ask_Profile_Password: state_ask_profile_password(&app)
- case .Ask_Profile_Seed_Phrase: state_ask_profile_seed_phrase(&app)
- }
}
}