Files
oxkerclone/pkg/config/config.go
T
Niko Syring aac139368f refactor: move internal/ to pkg/ for external importability
Moves all packages from internal/ to pkg/ so they can be imported
by external modules (needed for claude-pm integration).

- internal/app/ → pkg/app/
- internal/docker/ → pkg/docker/
- internal/config/ → pkg/config/
- internal/utils/ → pkg/utils/

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 07:05:59 +01:00

646 lines
27 KiB
Go

package config
import (
"encoding/json"
"os"
"path/filepath"
"strings"
"github.com/BurntSushi/toml"
)
type AppColors struct {
Borders Borders `toml:"borders,omitempty" json:"borders,omitempty"`
ChartCPU ChartCPU `toml:"chart_cpu,omitempty" json:"chart_cpu,omitempty"`
ChartMemory ChartMemory `toml:"chart_memory,omitempty" json:"chart_memory,omitempty"`
ChartBandwidth ChartBandwidth `toml:"chart_bandwidth,omitempty" json:"chart_bandwidth,omitempty"`
ChartPorts ChartPorts `toml:"chart_ports,omitempty" json:"chart_ports,omitempty"`
Commands Commands `toml:"commands,omitempty" json:"commands,omitempty"`
ContainerState ContainerState `toml:"container_state,omitempty" json:"container_state,omitempty"`
Containers Containers `toml:"containers,omitempty" json:"containers,omitempty"`
LogSearch LogSearch `toml:"log_search,omitempty" json:"log_search,omitempty"`
Filter Filter `toml:"filter,omitempty" json:"filter,omitempty"`
HeadersBar HeadersBar `toml:"headers_bar,omitempty" json:"headers_bar,omitempty"`
Logs Logs `toml:"logs,omitempty" json:"logs,omitempty"`
PopupDelete PopupDelete `toml:"popup_delete,omitempty" json:"popup_delete,omitempty"`
PopupError PopupError `toml:"popup_error,omitempty" json:"popup_error,omitempty"`
PopupHelp PopupHelp `toml:"popup_help,omitempty" json:"popup_help,omitempty"`
PopupInfo PopupInfo `toml:"popup_info,omitempty" json:"popup_info,omitempty"`
}
type Borders struct {
Selected string `toml:"selected,omitempty" json:"selected,omitempty"`
Unselected string `toml:"unselected,omitempty" json:"unselected,omitempty"`
}
type ChartCPU struct {
Background string `toml:"background,omitempty" json:"background,omitempty"`
Border string `toml:"border,omitempty" json:"border,omitempty"`
Title string `toml:"title,omitempty" json:"title,omitempty"`
Max string `toml:"max,omitempty" json:"max,omitempty"`
Points string `toml:"points,omitempty" json:"points,omitempty"`
YAxis string `toml:"y_axis,omitempty" json:"y_axis,omitempty"`
}
type ChartMemory struct {
Background string `toml:"background,omitempty" json:"background,omitempty"`
Border string `toml:"border,omitempty" json:"border,omitempty"`
Title string `toml:"title,omitempty" json:"title,omitempty"`
Max string `toml:"max,omitempty" json:"max,omitempty"`
Points string `toml:"points,omitempty" json:"points,omitempty"`
YAxis string `toml:"y_axis,omitempty" json:"y_axis,omitempty"`
}
type ChartBandwidth struct {
Background string `toml:"background,omitempty" json:"background,omitempty"`
Border string `toml:"border,omitempty" json:"border,omitempty"`
MaxRX string `toml:"max_rx,omitempty" json:"max_rx,omitempty"`
MaxTX string `toml:"max_tx,omitempty" json:"max_tx,omitempty"`
PointsRX string `toml:"points_rx,omitempty" json:"points_rx,omitempty"`
PointsTX string `toml:"points_tx,omitempty" json:"points_tx,omitempty"`
TitleRX string `toml:"title_rx,omitempty" json:"title_rx,omitempty"`
TitleTX string `toml:"title_tx,omitempty" json:"title_tx,omitempty"`
YAxis string `toml:"y_axis,omitempty" json:"y_axis,omitempty"`
}
type ChartPorts struct {
Background string `toml:"background,omitempty" json:"background,omitempty"`
Border string `toml:"border,omitempty" json:"border,omitempty"`
Title string `toml:"title,omitempty" json:"title,omitempty"`
Headings string `toml:"headings,omitempty" json:"headings,omitempty"`
Text string `toml:"text,omitempty" json:"text,omitempty"`
}
type Commands struct {
Background string `toml:"background,omitempty" json:"background,omitempty"`
Pause string `toml:"pause,omitempty" json:"pause,omitempty"`
Restart string `toml:"restart,omitempty" json:"restart,omitempty"`
Stop string `toml:"stop,omitempty" json:"stop,omitempty"`
Delete string `toml:"delete,omitempty" json:"delete,omitempty"`
Resume string `toml:"resume,omitempty" json:"resume,omitempty"`
Start string `toml:"start,omitempty" json:"start,omitempty"`
}
type ContainerState struct {
Dead string `toml:"dead,omitempty" json:"dead,omitempty"`
Exited string `toml:"exited,omitempty" json:"exited,omitempty"`
Paused string `toml:"paused,omitempty" json:"paused,omitempty"`
Removing string `toml:"removing,omitempty" json:"removing,omitempty"`
Restarting string `toml:"restarting,omitempty" json:"restarting,omitempty"`
RunningHealthy string `toml:"running_healthy,omitempty" json:"running_healthy,omitempty"`
RunningUnhealthy string `toml:"running_unhealthy,omitempty" json:"running_unhealthy,omitempty"`
Unknown string `toml:"unknown,omitempty" json:"unknown,omitempty"`
}
type Containers struct {
Background string `toml:"background,omitempty" json:"background,omitempty"`
Icon string `toml:"icon,omitempty" json:"icon,omitempty"`
Text string `toml:"text,omitempty" json:"text,omitempty"`
TextRX string `toml:"text_rx,omitempty" json:"text_rx,omitempty"`
TextTX string `toml:"text_tx,omitempty" json:"text_tx,omitempty"`
}
type LogSearch struct {
Background string `toml:"background,omitempty" json:"background,omitempty"`
Text string `toml:"text,omitempty" json:"text,omitempty"`
ButtonText string `toml:"button_text,omitempty" json:"button_text,omitempty"`
Highlight string `toml:"highlight,omitempty" json:"highlight,omitempty"`
}
type Filter struct {
Background string `toml:"background,omitempty" json:"background,omitempty"`
Text string `toml:"text,omitempty" json:"text,omitempty"`
SelectedFilterBackground string `toml:"selected_filter_background,omitempty" json:"selected_filter_background,omitempty"`
SelectedFilterText string `toml:"selected_filter_text,omitempty" json:"selected_filter_text,omitempty"`
Highlight string `toml:"highlight,omitempty" json:"highlight,omitempty"`
}
type HeadersBar struct {
Background string `toml:"background,omitempty" json:"background,omitempty"`
LoadingSpinner string `toml:"loading_spinner,omitempty" json:"loading_spinner,omitempty"`
Text string `toml:"text,omitempty" json:"text,omitempty"`
TextSelected string `toml:"text_selected,omitempty" json:"text_selected,omitempty"`
}
type Logs struct {
Background string `toml:"background,omitempty" json:"background,omitempty"`
Text string `toml:"text,omitempty" json:"text,omitempty"`
}
type PopupDelete struct {
Background string `toml:"background,omitempty" json:"background,omitempty"`
Text string `toml:"text,omitempty" json:"text,omitempty"`
TextHighlight string `toml:"text_highlight,omitempty" json:"text_highlight,omitempty"`
}
type PopupError struct {
Background string `toml:"background,omitempty" json:"background,omitempty"`
Text string `toml:"text,omitempty" json:"text,omitempty"`
}
type PopupHelp struct {
Background string `toml:"background,omitempty" json:"background,omitempty"`
Text string `toml:"text,omitempty" json:"text,omitempty"`
TextHighlight string `toml:"text_highlight,omitempty" json:"text_highlight,omitempty"`
}
type PopupInfo struct {
Background string `toml:"background,omitempty" json:"background,omitempty"`
Text string `toml:"text,omitempty" json:"text,omitempty"`
}
type Keymap struct {
Clear []string `toml:"clear,omitempty" json:"clear,omitempty"`
ClearSecondary []string `toml:"-" json:"-"`
DeleteConfirm []string `toml:"delete_confirm,omitempty" json:"delete_confirm,omitempty"`
DeleteConfirmSecondary []string `toml:"-" json:"-"`
DeleteDeny []string `toml:"delete_deny,omitempty" json:"delete_deny,omitempty"`
DeleteDenySecondary []string `toml:"-" json:"-"`
Exec []string `toml:"exec,omitempty" json:"exec,omitempty"`
ExecSecondary []string `toml:"-" json:"-"`
FilterMode []string `toml:"filter_mode,omitempty" json:"filter_mode,omitempty"`
FilterModeSecondary []string `toml:"-" json:"-"`
Inspect []string `toml:"inspect,omitempty" json:"inspect,omitempty"`
InspectSecondary []string `toml:"-" json:"-"`
ForceRedraw []string `toml:"force_redraw,omitempty" json:"force_redraw,omitempty"`
ForceRedrawSecondary []string `toml:"-" json:"-"`
ScrollBack []string `toml:"scroll_back,omitempty" json:"scroll_back,omitempty"`
ScrollBackSecondary []string `toml:"-" json:"-"`
ScrollForward []string `toml:"scroll_forward,omitempty" json:"scroll_forward,omitempty"`
ScrollForwardSecondary []string `toml:"-" json:"-"`
LogSearchMode []string `toml:"log_search_mode,omitempty" json:"log_search_mode,omitempty"`
LogSearchModeSecondary []string `toml:"-" json:"-"`
LogSectionHeightDecrease []string `toml:"log_section_height_decrease,omitempty" json:"log_section_height_decrease,omitempty"`
LogSectionHeightDecreaseSecondary []string `toml:"-" json:"-"`
LogSectionHeightIncrease []string `toml:"log_section_height_increase,omitempty" json:"log_section_height_increase,omitempty"`
LogSectionHeightIncreaseSecondary []string `toml:"-" json:"-"`
LogSectionToggle []string `toml:"log_section_toggle,omitempty" json:"log_section_toggle,omitempty"`
LogSectionToggleSecondary []string `toml:"-" json:"-"`
Quit []string `toml:"quit,omitempty" json:"quit,omitempty"`
QuitSecondary []string `toml:"-" json:"-"`
SaveLogs []string `toml:"save_logs,omitempty" json:"save_logs,omitempty"`
SaveLogsSecondary []string `toml:"-" json:"-"`
ScrollDown []string `toml:"scroll_down,omitempty" json:"scroll_down,omitempty"`
ScrollDownSecondary []string `toml:"-" json:"-"`
ScrollEnd []string `toml:"scroll_end,omitempty" json:"scroll_end,omitempty"`
ScrollEndSecondary []string `toml:"-" json:"-"`
ScrollStart []string `toml:"scroll_start,omitempty" json:"scroll_start,omitempty"`
ScrollStartSecondary []string `toml:"-" json:"-"`
ScrollUp []string `toml:"scroll_up,omitempty" json:"scroll_up,omitempty"`
ScrollUpSecondary []string `toml:"-" json:"-"`
SelectNextPanel []string `toml:"select_next_panel,omitempty" json:"select_next_panel,omitempty"`
SelectNextPanelSecondary []string `toml:"-" json:"-"`
SelectPreviousPanel []string `toml:"select_previous_panel,omitempty" json:"select_previous_panel,omitempty"`
SelectPreviousPanelSecondary []string `toml:"-" json:"-"`
SortByName []string `toml:"sort_by_name,omitempty" json:"sort_by_name,omitempty"`
SortByNameSecondary []string `toml:"-" json:"-"`
SortByState []string `toml:"sort_by_state,omitempty" json:"sort_by_state,omitempty"`
SortByStateSecondary []string `toml:"-" json:"-"`
SortByStatus []string `toml:"sort_by_status,omitempty" json:"sort_by_status,omitempty"`
SortByStatusSecondary []string `toml:"-" json:"-"`
SortByCPU []string `toml:"sort_by_cpu,omitempty" json:"sort_by_cpu,omitempty"`
SortByCPUSecondary []string `toml:"-" json:"-"`
SortByMemory []string `toml:"sort_by_memory,omitempty" json:"sort_by_memory,omitempty"`
SortByMemorySecondary []string `toml:"-" json:"-"`
SortByID []string `toml:"sort_by_id,omitempty" json:"sort_by_id,omitempty"`
SortByIDSecondary []string `toml:"-" json:"-"`
SortByImage []string `toml:"sort_by_image,omitempty" json:"sort_by_image,omitempty"`
SortByImageSecondary []string `toml:"-" json:"-"`
SortByRX []string `toml:"sort_by_rx,omitempty" json:"sort_by_rx,omitempty"`
SortByRXSecondary []string `toml:"-" json:"-"`
SortByTX []string `toml:"sort_by_tx,omitempty" json:"sort_by_tx,omitempty"`
SortByTXSecondary []string `toml:"-" json:"-"`
SortReset []string `toml:"sort_reset,omitempty" json:"sort_reset,omitempty"`
SortResetSecondary []string `toml:"-" json:"-"`
ToggleHelp []string `toml:"toggle_help,omitempty" json:"toggle_help,omitempty"`
ToggleHelpSecondary []string `toml:"-" json:"-"`
ToggleMouseCapture []string `toml:"toggle_mouse_capture,omitempty" json:"toggle_mouse_capture,omitempty"`
ToggleMouseCaptureSecondary []string `toml:"-" json:"-"`
LogSectionToggleAlt []string `toml:"-" json:"-"`
ScrollMany string `toml:"scroll_many,omitempty" json:"scroll_many,omitempty"`
}
type Config struct {
AppColors AppColors `toml:"colors,omitempty" json:"colors,omitempty"`
ColorLogs bool `toml:"color_logs,omitempty" json:"color_logs,omitempty"`
DirSave string `toml:"save_dir,omitempty" json:"save_dir,omitempty"`
DirConfig string `toml:"-" json:"-"`
DockerIntervalMs int `toml:"docker_interval,omitempty" json:"docker_interval,omitempty"`
GUI bool `toml:"gui,omitempty" json:"gui,omitempty"`
Host string `toml:"host,omitempty" json:"host,omitempty"`
InContainer bool `toml:"-" json:"-"`
Keymap Keymap `toml:"keymap,omitempty" json:"keymap,omitempty"`
LogSearchCaseSensitive bool `toml:"log_search_case_sensitive,omitempty" json:"log_search_case_sensitive,omitempty"`
RawLogs bool `toml:"raw_logs,omitempty" json:"raw_logs,omitempty"`
ShowLogs bool `toml:"show_logs,omitempty" json:"show_logs,omitempty"`
ShowSelf bool `toml:"show_self,omitempty" json:"show_self,omitempty"`
ShowStdErr bool `toml:"show_std_err,omitempty" json:"show_std_err,omitempty"`
ShowTimestamp bool `toml:"show_timestamp,omitempty" json:"show_timestamp,omitempty"`
TimestampFormat string `toml:"timestamp_format,omitempty" json:"timestamp_format,omitempty"`
Timezone string `toml:"timezone,omitempty" json:"timezone,omitempty"`
UseCLI bool `toml:"use_cli,omitempty" json:"use_cli,omitempty"`
}
func NewConfig() *Config {
return &Config{
DockerIntervalMs: 1000,
ShowLogs: true,
ColorLogs: false,
RawLogs: false,
ShowTimestamp: true,
TimestampFormat: "%Y-%m-%dT%H:%M:%S.%8f",
Timezone: "UTC",
UseCLI: false,
GUI: true,
LogSearchCaseSensitive: true,
ShowSelf: false,
ShowStdErr: true,
DirSave: "",
Host: "",
}
}
func LoadConfigPath(path string, cfg *Config) error {
data, err := os.ReadFile(path)
if err != nil {
return err
}
content := string(data)
if strings.HasSuffix(path, ".toml") {
_, err = toml.Decode(content, cfg)
if err != nil {
return err
}
} else if strings.HasSuffix(path, ".jsonc") || strings.HasSuffix(path, ".json") {
err = parseJSONC(content, cfg)
if err != nil {
return err
}
}
cfg.DirConfig = path
return nil
}
func LoadConfig(path string) (*Config, error) {
cfg := NewConfig()
err := LoadConfigPath(path, cfg)
if err != nil {
return nil, err
}
return cfg, nil
}
func parseJSONC(content string, cfg *Config) error {
var raw map[string]interface{}
commentsRemoved := removeJSONCComments(content)
err := json.Unmarshal([]byte(commentsRemoved), &raw)
if err != nil {
return err
}
if colors, ok := raw["colors"].(map[string]interface{}); ok {
cfg.AppColors = parseAppColors(colors)
}
if keymap, ok := raw["keymap"].(map[string]interface{}); ok {
cfg.Keymap = parseKeymap(keymap)
}
if val, ok := raw["color_logs"].(bool); ok {
cfg.ColorLogs = val
}
if val, ok := raw["docker_interval"].(float64); ok {
cfg.DockerIntervalMs = int(val)
}
if val, ok := raw["gui"].(bool); ok {
cfg.GUI = val
}
if val, ok := raw["host"].(string); ok {
cfg.Host = val
}
if val, ok := raw["log_search_case_sensitive"].(bool); ok {
cfg.LogSearchCaseSensitive = val
}
if val, ok := raw["raw_logs"].(bool); ok {
cfg.RawLogs = val
}
if val, ok := raw["save_dir"].(string); ok {
cfg.DirSave = val
}
if val, ok := raw["show_logs"].(bool); ok {
cfg.ShowLogs = val
}
if val, ok := raw["show_self"].(bool); ok {
cfg.ShowSelf = val
}
if val, ok := raw["show_std_err"].(bool); ok {
cfg.ShowStdErr = val
}
if val, ok := raw["show_timestamp"].(bool); ok {
cfg.ShowTimestamp = val
}
if val, ok := raw["timestamp_format"].(string); ok {
cfg.TimestampFormat = val
}
if val, ok := raw["timezone"].(string); ok {
cfg.Timezone = val
}
if val, ok := raw["use_cli"].(bool); ok {
cfg.UseCLI = val
}
return nil
}
func removeJSONCComments(content string) string {
lines := strings.Split(content, "\n")
var result []string
for _, line := range lines {
trimmed := strings.TrimSpace(line)
if strings.HasPrefix(trimmed, "//") || strings.HasPrefix(trimmed, "/*") || strings.HasPrefix(trimmed, "*") || strings.HasPrefix(trimmed, "*/") {
continue
}
if idx := strings.Index(trimmed, "//"); idx >= 0 {
result = append(result, strings.TrimSpace(line[:idx]))
} else {
result = append(result, line)
}
}
return strings.Join(result, "\n")
}
func parseAppColors(colors map[string]interface{}) AppColors {
acc := AppColors{}
if borders, ok := colors["borders"].(map[string]interface{}); ok {
acc.Borders = Borders{
Selected: toString(borders["selected"]),
Unselected: toString(borders["unselected"]),
}
}
if chartCPU, ok := colors["chart_cpu"].(map[string]interface{}); ok {
acc.ChartCPU = ChartCPU{
Background: toString(chartCPU["background"]),
Border: toString(chartCPU["border"]),
Title: toString(chartCPU["title"]),
Max: toString(chartCPU["max"]),
Points: toString(chartCPU["points"]),
YAxis: toString(chartCPU["y_axis"]),
}
}
if chartMemory, ok := colors["chart_memory"].(map[string]interface{}); ok {
acc.ChartMemory = ChartMemory{
Background: toString(chartMemory["background"]),
Border: toString(chartMemory["border"]),
Title: toString(chartMemory["title"]),
Max: toString(chartMemory["max"]),
Points: toString(chartMemory["points"]),
YAxis: toString(chartMemory["y_axis"]),
}
}
if chartBandwidth, ok := colors["chart_bandwidth"].(map[string]interface{}); ok {
acc.ChartBandwidth = ChartBandwidth{
Background: toString(chartBandwidth["background"]),
Border: toString(chartBandwidth["border"]),
MaxRX: toString(chartBandwidth["max_rx"]),
MaxTX: toString(chartBandwidth["max_tx"]),
PointsRX: toString(chartBandwidth["points_rx"]),
PointsTX: toString(chartBandwidth["points_tx"]),
TitleRX: toString(chartBandwidth["title_rx"]),
TitleTX: toString(chartBandwidth["title_tx"]),
YAxis: toString(chartBandwidth["y_axis"]),
}
}
if chartPorts, ok := colors["chart_ports"].(map[string]interface{}); ok {
acc.ChartPorts = ChartPorts{
Background: toString(chartPorts["background"]),
Border: toString(chartPorts["border"]),
Title: toString(chartPorts["title"]),
Headings: toString(chartPorts["headings"]),
Text: toString(chartPorts["text"]),
}
}
if commands, ok := colors["commands"].(map[string]interface{}); ok {
acc.Commands = Commands{
Background: toString(commands["background"]),
Pause: toString(commands["pause"]),
Restart: toString(commands["restart"]),
Stop: toString(commands["stop"]),
Delete: toString(commands["delete"]),
Resume: toString(commands["resume"]),
Start: toString(commands["start"]),
}
}
if containerState, ok := colors["container_state"].(map[string]interface{}); ok {
acc.ContainerState = ContainerState{
Dead: toString(containerState["dead"]),
Exited: toString(containerState["exited"]),
Paused: toString(containerState["paused"]),
Removing: toString(containerState["removing"]),
Restarting: toString(containerState["restarting"]),
RunningHealthy: toString(containerState["running_healthy"]),
RunningUnhealthy: toString(containerState["running_unhealthy"]),
Unknown: toString(containerState["unknown"]),
}
}
if containers, ok := colors["containers"].(map[string]interface{}); ok {
acc.Containers = Containers{
Background: toString(containers["background"]),
Icon: toString(containers["icon"]),
Text: toString(containers["text"]),
TextRX: toString(containers["text_rx"]),
TextTX: toString(containers["text_tx"]),
}
}
if logSearch, ok := colors["log_search"].(map[string]interface{}); ok {
acc.LogSearch = LogSearch{
Background: toString(logSearch["background"]),
Text: toString(logSearch["text"]),
ButtonText: toString(logSearch["button_text"]),
Highlight: toString(logSearch["highlight"]),
}
}
if filter, ok := colors["filter"].(map[string]interface{}); ok {
acc.Filter = Filter{
Background: toString(filter["background"]),
Text: toString(filter["text"]),
SelectedFilterBackground: toString(filter["selected_filter_background"]),
SelectedFilterText: toString(filter["selected_filter_text"]),
Highlight: toString(filter["highlight"]),
}
}
if headersBar, ok := colors["headers_bar"].(map[string]interface{}); ok {
acc.HeadersBar = HeadersBar{
Background: toString(headersBar["background"]),
LoadingSpinner: toString(headersBar["loading_spinner"]),
Text: toString(headersBar["text"]),
TextSelected: toString(headersBar["text_selected"]),
}
}
if logs, ok := colors["logs"].(map[string]interface{}); ok {
acc.Logs = Logs{
Background: toString(logs["background"]),
Text: toString(logs["text"]),
}
}
if popupDelete, ok := colors["popup_delete"].(map[string]interface{}); ok {
acc.PopupDelete = PopupDelete{
Background: toString(popupDelete["background"]),
Text: toString(popupDelete["text"]),
TextHighlight: toString(popupDelete["text_highlight"]),
}
}
if popupError, ok := colors["popup_error"].(map[string]interface{}); ok {
acc.PopupError = PopupError{
Background: toString(popupError["background"]),
Text: toString(popupError["text"]),
}
}
if popupHelp, ok := colors["popup_help"].(map[string]interface{}); ok {
acc.PopupHelp = PopupHelp{
Background: toString(popupHelp["background"]),
Text: toString(popupHelp["text"]),
TextHighlight: toString(popupHelp["text_highlight"]),
}
}
if popupInfo, ok := colors["popup_info"].(map[string]interface{}); ok {
acc.PopupInfo = PopupInfo{
Background: toString(popupInfo["background"]),
Text: toString(popupInfo["text"]),
}
}
return acc
}
func parseKeymap(keymap map[string]interface{}) Keymap {
k := Keymap{}
applyKeymapEntry(&k.Clear, keymap, "clear")
applyKeymapEntry(&k.DeleteConfirm, keymap, "delete_confirm")
applyKeymapEntry(&k.DeleteDeny, keymap, "delete_deny")
applyKeymapEntry(&k.Exec, keymap, "exec")
applyKeymapEntry(&k.FilterMode, keymap, "filter_mode")
applyKeymapEntry(&k.Inspect, keymap, "inspect")
applyKeymapEntry(&k.ForceRedraw, keymap, "force_redraw")
applyKeymapEntry(&k.ScrollBack, keymap, "scroll_back")
applyKeymapEntry(&k.ScrollForward, keymap, "scroll_forward")
applyKeymapEntry(&k.LogSearchMode, keymap, "log_search_mode")
applyKeymapEntry(&k.LogSectionHeightDecrease, keymap, "log_section_height_decrease")
applyKeymapEntry(&k.LogSectionHeightIncrease, keymap, "log_section_height_increase")
applyKeymapEntry(&k.LogSectionToggle, keymap, "log_section_toggle")
applyKeymapEntry(&k.Quit, keymap, "quit")
applyKeymapEntry(&k.SaveLogs, keymap, "save_logs")
applyKeymapEntry(&k.ScrollDown, keymap, "scroll_down")
applyKeymapEntry(&k.ScrollEnd, keymap, "scroll_end")
applyKeymapEntry(&k.ScrollStart, keymap, "scroll_start")
applyKeymapEntry(&k.ScrollUp, keymap, "scroll_up")
applyKeymapEntry(&k.SelectNextPanel, keymap, "select_next_panel")
applyKeymapEntry(&k.SelectPreviousPanel, keymap, "select_previous_panel")
applyKeymapEntry(&k.SortByName, keymap, "sort_by_name")
applyKeymapEntry(&k.SortByState, keymap, "sort_by_state")
applyKeymapEntry(&k.SortByStatus, keymap, "sort_by_status")
applyKeymapEntry(&k.SortByCPU, keymap, "sort_by_cpu")
applyKeymapEntry(&k.SortByMemory, keymap, "sort_by_memory")
applyKeymapEntry(&k.SortByID, keymap, "sort_by_id")
applyKeymapEntry(&k.SortByImage, keymap, "sort_by_image")
applyKeymapEntry(&k.SortByRX, keymap, "sort_by_rx")
applyKeymapEntry(&k.SortByTX, keymap, "sort_by_tx")
applyKeymapEntry(&k.SortReset, keymap, "sort_reset")
applyKeymapEntry(&k.ToggleHelp, keymap, "toggle_help")
applyKeymapEntry(&k.ToggleMouseCapture, keymap, "toggle_mouse_capture")
if scrollMany, ok := keymap["scroll_many"].(string); ok {
k.ScrollMany = scrollMany
}
return k
}
func applyKeymapEntry(target *[]string, keymap map[string]interface{}, key string) {
if val, ok := keymap[key].([]interface{}); ok {
for _, v := range val {
if s, ok := v.(string); ok {
*target = append(*target, s)
}
}
}
}
func toString(val interface{}) string {
if s, ok := val.(string); ok {
return s
}
return ""
}
func (c *Config) SaveConfig() error {
path := c.DirConfig
if path == "" {
var err error
path, err = GetDefaultConfigPath()
if err != nil {
return err
}
}
file, err := os.Create(path)
if err != nil {
return err
}
defer file.Close()
if strings.HasSuffix(path, ".toml") {
return toml.NewEncoder(file).Encode(c)
} else if strings.HasSuffix(path, ".jsonc") || strings.HasSuffix(path, ".json") {
data, err := json.MarshalIndent(c, "", " ")
if err != nil {
return err
}
_, err = file.Write(data)
return err
}
return nil
}
func GetDefaultConfigPath() (string, error) {
home, err := os.UserHomeDir()
if err != nil {
return "", err
}
configDir := filepath.Join(home, ".config", "oxker")
return filepath.Join(configDir, "config.toml"), nil
}
func (c *Config) MergeCLIArgs(cliArgs *CLIArgs) {
if cliArgs == nil {
return
}
if cliArgs.DockerIntervalMs > 0 {
c.DockerIntervalMs = cliArgs.DockerIntervalMs
}
c.RawLogs = cliArgs.RawLogs
c.ColorLogs = cliArgs.ColorLogs
c.ShowTimestamp = !cliArgs.ShowTimestamp
c.UseCLI = cliArgs.UseCLI
c.GUI = !cliArgs.DebugMode
if cliArgs.Host != "" {
c.Host = cliArgs.Host
}
c.DirConfig = cliArgs.ConfigFile
}
type CLIArgs struct {
DockerIntervalMs int
RawLogs bool
ColorLogs bool
ShowTimestamp bool
ShowSelf bool
DebugMode bool
ConfigFile string
Host string
NoStdErr bool
SaveDir string
Timezone string
UseCLI bool
}