From 50ce408f1b1f3304b18df46c6dac34b2ad131c93 Mon Sep 17 00:00:00 2001 From: "M. E. Abdelsalam" Date: Wed, 18 Feb 2026 00:15:16 +0200 Subject: [PATCH] add: documentation comment above each function --- utils/action.go | 44 ++++++++++++++++++++++++++------------------ utils/config.go | 46 +++++----------------------------------------- utils/exec.go | 13 +++++++++++-- utils/print.go | 15 +++++++++++++++ utils/utils.go | 27 +++++++++++++++++++++++++++ 5 files changed, 84 insertions(+), 61 deletions(-) diff --git a/utils/action.go b/utils/action.go index 13320ee..653be17 100644 --- a/utils/action.go +++ b/utils/action.go @@ -4,24 +4,10 @@ import ( "github.com/mmoehabb/luci/types" ) -func GetShellConfig(c types.Config) *types.ShellConfig { - var shellConfig *types.ShellConfig - - switch GetShellType() { - case types.Bash: - shellConfig = &c.Bash - case types.Zshell: - shellConfig = &c.Zshell - case types.Bat: - shellConfig = &c.Bat - default: - shellConfig = &c.Bash - } - - return shellConfig -} - -// Return an Action or ActionRecord within the config c. +// Dig recursively traverses the configuration structure based on the provided +// input keys. It navigates through ShellConfig, AnnotatedAction, or map[string]any +// types to find and return the action matching the given inputs. Returns nil if +// no matching action is found. func Dig(action any, inputs []string) any { for i, input := range inputs { switch actTyped := action.(type) { @@ -56,3 +42,25 @@ func Dig(action any, inputs []string) any { return action } + +// MapToAnnotatedAction converts a generic map[string]any to an AnnotatedAction. +// It extracts the title, description, and value fields from the map and returns +// a properly typed AnnotatedAction struct. Fields that are not present default +// to empty strings. +func MapToAnnotatedAction(m map[string]any) types.AnnotatedAction { + title := "" + if m["title"] != nil { + title = m["title"].(string) + } + + description := "" + if m["description"] != nil { + description = m["description"].(string) + } + + return types.AnnotatedAction{ + Title: title, + Description: description, + Value: m["value"], + } +} diff --git a/utils/config.go b/utils/config.go index ac7e30a..cfeeb26 100644 --- a/utils/config.go +++ b/utils/config.go @@ -23,6 +23,10 @@ example = "echo Hello World!" example = "echo Hello World!" ` +// LoadDefaultConfig loads the application configuration from luci.config.toml. +// If the configuration file does not exist, it creates a default configuration +// file with example settings. The function returns a populated Config struct +// that contains all shell-specific settings and metadata. func LoadDefaultConfig() types.Config { const configPath = "luci.config.toml" @@ -44,46 +48,6 @@ func LoadDefaultConfig() types.Config { // Parse the json data and perform the action the user passes in the arguments c := types.Config{} - err = toml.Unmarshal(data, &c) - if err != nil { - panic(err) - } - - // Convert map[string]any maps with value keys to AnnotatedActions - shellc := *GetShellConfig(c) - digForAnnotatedActions(shellc) - + Must(toml.Unmarshal(data, &c)) return c } - -func digForAnnotatedActions(m map[string]any) { - for k, v := range m { - switch v := v.(type) { - case map[string]any: - if v["value"] == nil { - digForAnnotatedActions(v) - continue - } - annAct := MapToAnnotatedAction(v) - m[k] = annAct - } - } -} - -func MapToAnnotatedAction(m map[string]any) types.AnnotatedAction { - title := "" - if m["title"] != nil { - title = m["title"].(string) - } - - description := "" - if m["description"] != nil { - description = m["description"].(string) - } - - return types.AnnotatedAction{ - Title: title, - Description: description, - Value: m["value"], - } -} diff --git a/utils/exec.go b/utils/exec.go index 37df1c3..f68184e 100644 --- a/utils/exec.go +++ b/utils/exec.go @@ -9,6 +9,10 @@ import ( "github.com/mmoehabb/luci/types" ) +// Act is the main entry point for executing actions based on user input. +// It takes a configuration and a list of input arguments, resolves the appropriate +// action from the shell configuration, and executes it. If no matching action is found, +// it prints usage information or displays available actions. func Act(c types.Config, inputs []string) { shell := *GetShellConfig(c) action := Dig(shell, inputs) @@ -71,11 +75,16 @@ func execAction(action any) bool { case []string: var cmd *exec.Cmd var cmdStr = strings.Join(action, " && ") - if runtime.GOOS == "windows" { + + switch runtime.GOOS { + case "windows": cmd = exec.Command("cmd", "/C", cmdStr) - } else { + case "darwin": + cmd = exec.Command("/bin/zsh", "-c", cmdStr) + default: cmd = exec.Command("/bin/sh", "-c", cmdStr) } + PrintCommand(cmdStr) execCmd(cmd) return true diff --git a/utils/print.go b/utils/print.go index b6b63bf..f02158d 100644 --- a/utils/print.go +++ b/utils/print.go @@ -10,6 +10,9 @@ import ( "github.com/mmoehabb/luci/types" ) +// PrintHeader displays the application logo, title, and description from the +// provided configuration. It uses colored output to make the header visually +// distinctive and wraps the description text for better readability. func PrintHeader(c types.Config) { color.HiGreen(` /\\_/\\ @@ -25,6 +28,9 @@ func PrintHeader(c types.Config) { color.Yellow("\nUsage:\n\n") } +// PrintUsage prints the complete usage information, including the header and +// all available actions from the shell configuration. It iterates through +// each action in the configuration and displays them in a formatted manner. func PrintUsage(c types.Config) { PrintHeader(c) shell := *GetShellConfig(c) @@ -33,6 +39,9 @@ func PrintUsage(c types.Config) { } } +// PrintActionWithInputs resolves an action from the configuration using the +// provided inputs and prints it. It returns an error if the action cannot be +// found, otherwise nil on successful printing. func PrintActionWithInputs(c map[string]any, inputs []string, level int) error { action := Dig(c, inputs) if action == nil { @@ -42,6 +51,9 @@ func PrintActionWithInputs(c map[string]any, inputs []string, level int) error { return nil } +// PrintAction prints an action in a formatted way based on its type. It handles +// AnnotatedAction, map[string]any, []string, and string types, applying +// appropriate colors and indentation to display hierarchical action structures. func PrintAction(action any, inputs []string, level int) { switch action := action.(type) { case types.AnnotatedAction: @@ -79,6 +91,9 @@ func PrintAction(action any, inputs []string, level int) { } } +// PrintCommand displays the command that is about to be executed with a +// highlighted green background and white text, making it visually distinct +// in the terminal output. func PrintCommand(cmd string) { color.New(color.BgGreen, color.FgHiWhite).Printf("+ %s", cmd) fmt.Println() diff --git a/utils/utils.go b/utils/utils.go index 8335545..d0db84d 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -6,6 +6,9 @@ import ( "github.com/mmoehabb/luci/types" ) +// GetShellType detects and returns the appropriate shell type for the current +// operating system. It returns Bash for Linux, Zshell for macOS (darwin), +// Bat for Windows, and Unknown for any other OS. func GetShellType() types.ShellType { switch runtime.GOOS { case "linux": @@ -19,6 +22,30 @@ func GetShellType() types.ShellType { } } +// GetShellConfig returns a pointer to the shell-specific configuration section +// from the provided config based on the current operating system's shell type. +// It selects between Bash, Zshell, or Bat configurations, defaulting to Bash +// if the shell type is unknown. +func GetShellConfig(c types.Config) *types.ShellConfig { + var shellConfig *types.ShellConfig + + switch GetShellType() { + case types.Bash: + shellConfig = &c.Bash + case types.Zshell: + shellConfig = &c.Zshell + case types.Bat: + shellConfig = &c.Bat + default: + shellConfig = &c.Bash + } + + return shellConfig +} + +// Must panics if the provided error is not nil, otherwise it returns without error. +// This function is used for error handling in scenarios where errors indicate +// critical failures that should halt program execution. func Must(err error) { if err != nil { panic(err)