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>
This commit is contained in:
@@ -0,0 +1,645 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user