gocli

package module
v1.0.14 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 11, 2024 License: MIT Imports: 3 Imported by: 0

README

Gocli

This project consists of a Go module aimed at simplifying the development of applications based on interactive command-line interfaces. The module provides a function that opens a CLI which returns the entered command as a result. The CLI includes features such as autocompletion, suggestions, command history, and shortcuts like CTRL+C, CTRL+V (see the complete list in the Special Commands section at the end of the doc).

Learn by example

Initial config

Here is a basic configuration, but covering most of the available options. We will define commands, options for those commands and some modifiers to make a param required or default. Also we configure the prompt, bypass character and control keys to be triggered.

package main

import (
 "fmt"
 "strconv"

 gc "github.com/vcharco/gocli"
)

func main() {

  // Here we declare the commands and their params
  commands := []gc.Command {
    // We may set a description to commands and params for the help
    {Name: "foo", Description: "Perform foo operations", Params: []gc.Param {
      // If no type defined, it will be a flag (Ej: -f, --help, --get-history)
      {Name: "-f", Description: "foo flag"},
      // We set types for param validation (Ej: --foo foobar, --limit 20, -l 20)
      {Name: "--foo", Type: gc.Text},
      // This is a required numeric param (int). Check complete type list in a section below
      {Name: "--num", Type: gc.Number, Modifier: gc.REQUIRED},
      // This is how we specify a default value (max 1) and set it to required
      {Name: "fooDefault", Type: gc.Number, Modifier: gc.DEFAULT | gc.REQUIRED},
    }},
    // This is how we set a hidden command. This is a valid command with autcompletion
    // as the rest of the params, but will not be displayed in the suggestions when tab
    {Name: "exit", Hidden: true},
  }

  // Configuration
  cli := gc.Terminal {
    Styles:          TerminalStyles{}, // Default styles
    Commands:        commands,
    BypassCharacter: ":", // Allows to execute commands by the OS -> :ls -l
    CtrlKeys:        []byte{gc.Ctrl_A, gc.Ctrl_B}, // CRTL keys to caputure
  }

  for {
    // Gets the user input
    response := cli.Get()

    // Also we may pass a text what will be appended after the prompt
    // response := cli.Get("text sent to the CLI")

    // Here you handle the user input
  }
}
Customizing the terminal

Styling is optional, as default values are applied. But you will get a better user experience changing this default values. Note that we use Bg prefixed color names for BackgroundColor and SelBackgroundColor.

// First, define a new TerminalStyles objects and fill only what you want
styles := gc.TerminalStyles {
  Prompt:                 "Gocli> "           // Text to be displayed in the prompt
  PromptColor:            gc.Blue,            // Color of the prompt
  Cursor:                 gc.CursorBlock,     // CursorBlock, CursorBar or CursorUnderline
  ForegroundColor:        gc.White,           // Color of the text when not selected
  BackgroundColor:        gu.BgTransparent,   // Background color of the terminal
  SelForegroundColor:     gc.Blue,            // Color of the text when selected
  SelBackgroundColor:     gc.BgLightBlue,     // Color of the selection
  HelpTextForeground:     gu.LightGray        // Color of the help (?) text
  HelpTitlesForeground:   gu.Blue             // Color of the title sections in the help
  HelpCommandForeground:  gu.White            // Color of the command in the help display
  HelpParamsForeground:   gu.Yellow           // Color of the params in the help display
  HelpRequiredForeground: gu.Red              // Color of (REQUIRED) param flag in help
  HelpLineColor:          gu.Blue             // Color of the line in the help display
}

// Finally, add this configuration to you Terminal object
cli := gc.Terminal {
  Styles:          styles,                // Our custom styles
  Commands:        commands,
  BypassCharacter: ":",
  CtrlKeys:        []byte{gc.Ctrl_A, gc.Ctrl_B},
}
Playing with the response

Here it's an example of how to use the response received.

// First, we get the user input
response := cli.Get()

// Second, we check the response is a valid command
if response.Type == gc.Cmd {
  // Now we check what command was typed by the user
  switch response.Command {
    case "foo":
      // This is how we retrieve values. First is the name and then the default value
      fooDefault := response.GetParam("fooDefault", "").(string)
      fooVal := response.GetParam("--foo", "foo default value").(string)

      // For flag params, default value must be a boolean. Normally set to false
      fVal := response.GetParam("-f", false).(bool)

      // For numeric (Number or FloatNumber) we cast to int or float64
      numVal := response.GetParam("--num", 0).(int)

      fmt.Printf("default: %v; -f: %v; --foo: %v\n", fooDefault, fVal, fooVal)
  }
}
Command history

The cli has a default command history. We use the UP/DOWN arrow keys to get the previuos command or the next command in the history as in any other cli.

// This is how we print the history (20 last commands)
cli.PrintHistory(20)

// This is how we clear the history
cli.ClearHistory()

// This is how we get the number of commands in the history
numCmds := cli.CountHistory()

// This is how we get all commands in history ([]string)
historyCommands := cli.GetHistory()

// This is how we get an specific command in history
historyCommand := cli.GetHistoryAt(5)
Checking response errors

There are several kind of errors, but we may trigger all of them by checking the value of the Error attribute. Then, we may check the type of error.

if response.Error != nil {
  switch response.Type {
    // The command doesn't match to any of declared in the Options
    case gc.CmdError:
      fmt.Printf("Invalid command: %v\n", response.Error.Error())
    // Some parameter has an invalid value or the param doesn't exist
    case gc.ParamError:
      fmt.Printf("Invalid parameters: %v\n", response.Error.Error())
    // This is an internal error, should never happen
    case gc.ExecutionError:
      fmt.Printf("Internal error: %v\n", response.Error.Error())
   }
}
Handle CTRL+Key Combinations
// First, configure what keys you want to trigger
cli := gc.Terminal {
  // ...
  CtrlKeys:     []byte{gc.Ctrl_A, gc.Ctrl_B},
}

// Get the response
response := cli.Get()

// Now check what CTRL+Key combination was triggered
if response.Type == gc.CtrlKey {
  switch response.CtrlKey {
  case gc.Ctrl_a:
    fmt.Println("Captured CTRL+A")
  case gc.Ctrl_b:
    fmt.Println("Captured CTRL+B")
  }
}
Commands bypassed to the OS

Commands with response type OsCmd mean that were executed by the operative system's terminal. Normally, we just pass (continue if in a loop) when we receive this, as the main pupose is just to be executed by the underlaying OS terminal, but we still may perform some actions if needed. Just know that in this kind of responses, we only have the RawInput attribute available.

// First, configure what character will be used to bypass commands. Colon (':') is used by default.
cli := gc.Terminal {
  // ...
  BypassCharacter:  ":",
}

// Get the response
response := cli.Get()

if response.Type == gc.OsCmd {
  userInput := response.RawInput
  fmt.Printf("Comman executed by the OS: %v\n", userInput)
}

Types, values and other usefull information

Configuration
  • Prompt: This is the text at the beggining of the line.
  • Styles: Customize the appearance of the cli.
  • Commands: This list of commands is used for autocompletion and suggestions. It contains a sublist of valid parameters for each command.
  • BypassCharacter: Gocli checks if the input starts with this character, and in that case, instead of processing it, it sends it directly to the operating system's console. This allows you to execute OS commands without leaving Gocli.
    • Example for BypassCharacter :: Prompt> :ls -l
  • CtrlKeys: A list of CTRL+Key combinations you want to override. When one of these combinations is detected, gocli will respond with the Type CtrlKey and the value of the detected combination will be available in the reponse property CtrlKey.
Commands

They are the commands available for your custom cli. Each command must be provided with a Name. Optionally, you may provide a list of parameters. If you set the Hidden attribute, the command still be valid, but won't be displayed in the suggestions when pressing tabulator.

Parameters should be provided with a Name. You may provide a Type, this will validate if the value provided next to the parameter match the type or not. Several types are supported right now, see below. For Number or FloatNumber types, the casting is performed automatically. As the returned type is an interface{} type, you must make the assertions .(string), .(int), .(float64) or .(bool) If no Type is specified, then it will be a boolean flag, which means that it cannot receive any value. If the property is present, value is true, else, false. Finally, you may add a modifier as a binary flag (that means that you hav to provide this values separated by a |).

Parameter Types
  • None: No validations will be performed (default)
  • Date: Must match the pattern YYYY-MM-DD
  • Domain: Domain name. Ej: some.example.com
  • Email: Ej: some@example.com
  • Ipv4: Ej: 192.168.0.12
  • Ipv6: Ej: 2001:0db8:85a3:0000:0000:8a2e:0370:7334
  • Number: Only integer numbers. Ej: 14, 43, 22, 17
  • FloatNumber: Float numbers. Ej: 14.3, 43.234, 22.0
  • Phone: Phone number. May start with +. Ej: +34 612345678
  • Text: Not empty text
  • Time: Must match the pattern HH:mm
  • Url: Url, including schema (http/https), hostname, path and params
  • UUID: UUID version 4
Modifiers
  • DEFAULT: If this modifier is set, you don't need to type the name of the parameter, you only have to write a value whitout paramter name and it will be automatically binded. You only are able to set one parameter with this flag.
  • REQUIRED: If this flag is set, the parameter must be supplied, in other case, an error will be prompted and the command will fail.

Response

type TerminalResponse struct {
  Command  string                // The command executed by Gocli
  Param  map[string]interface{}  // Parameters that follow the command (validated)
  RawInput string                // The user input without validations neither splits
  Type     TerminalResponseType  // It tells you what happened, see below
  CtrlKey  byte                  // If Type = CtrlKey, this is the CTRL+key combination
  Error    error                 // Nil or the error ocurred
}
TerminalResponseType
  • Cmd: The command was successfully executed
  • OsCmd: The command was executed by the OS terminal
  • CmdHelp: User has printed the help
  • CtrlKey: A registered Ctrl key has been pressed
  • CmdError: Error validating the command
  • ParamError: Error validating some parameter
  • ExecutionError: Internal error, should not happen

Special commands and characters

There are several shortcuts listed down here to make more fluid your interaction (you may override this shortcuts, but is not recommended in most cases).

  • CTRL+C: Copy the selected text to the clipboard. If no text is selected, it copies the full line.
  • CTRL+V: Paste the clipboard.
  • CTRL+L: Clear the screen.
  • CTRL+X: Exit the cli (safely)
  • CTRL+A: Move the cursor at the beginning of the line
  • CTRL+E: Move the cursor at the end of the line

There are two special characters.

  • BypassCharacter: This character must be declared in order to bypass commands to the OS terminal. Let's say we set this charcter to :.
    • CLI> :ls -l
    • CLI> :whoami
    • CLI> :grep root /etc/passwd
  • ?: This is a special character for displaying help. Its usage is simple, type this character after a command or while you type the command and then press Enter. If this character is detected at the end of the input, the terminal will recognize the command and will display all available information like required and non required params, flags, default params and, of course, all the descriptions provided when we declared the Options.
    • CLI> print-history?: It displays the help for the command print-history.
    • CLI> print-hi? : We don't need to end the command if there are no conflicts with other commands.
    • CLI> print-history 20 ?: We may display the command help even if we have already type parameters.

Documentation

Index

Constants

View Source
const (
	Date        = gt.Date
	Domain      = gt.Domain
	Email       = gt.Email
	Ipv4        = gt.Ipv4
	Ipv6        = gt.Ipv6
	Number      = gt.Number
	FloatNumber = gt.FloatNumber
	Phone       = gt.Phone
	Text        = gt.Text
	Time        = gt.Time
	Url         = gt.Url
	UUID        = gt.UUID
)
View Source
const (
	Cmd            = gg.Cmd
	OsCmd          = gg.OsCmd
	CmdHelp        = gg.CmdHelp
	CmdError       = gg.CmdError
	CtrlKey        = gg.CtrlKey
	ParamError     = gg.ParamError
	ExecutionError = gg.ExecutionError
)
View Source
const (
	Reset           = gu.Reset
	BgReset         = gu.BgReset
	Red             = gu.Red
	Green           = gu.Green
	Yellow          = gu.Yellow
	Blue            = gu.Blue
	Magenta         = gu.Magenta
	Cyan            = gu.Cyan
	White           = gu.White
	Black           = gu.Black
	Gray            = gu.Gray
	DarkGray        = gu.DarkGray
	BrightRed       = gu.BrightRed
	BrightGreen     = gu.BrightGreen
	BrightYellow    = gu.BrightYellow
	BrightBlue      = gu.BrightBlue
	BrightMagenta   = gu.BrightMagenta
	BrightCyan      = gu.BrightCyan
	BrightWhite     = gu.BrightWhite
	LightBlue       = gu.LightBlue
	LightGreen      = gu.LightGreen
	LightYellow     = gu.LightYellow
	LightRed        = gu.LightRed
	LightMagenta    = gu.LightMagenta
	LightCyan       = gu.LightCyan
	LightGray       = gu.LightGray
	BgTransparent   = gu.BgTransparent
	BgRed           = gu.BgRed
	BgGreen         = gu.BgGreen
	BgYellow        = gu.BgYellow
	BgBlue          = gu.BgBlue
	BgMagenta       = gu.BgMagenta
	BgCyan          = gu.BgCyan
	BgWhite         = gu.BgWhite
	BgBlack         = gu.BgBlack
	BgBrightRed     = gu.BgBrightRed
	BgBrightGreen   = gu.BgBrightGreen
	BgBrightYellow  = gu.BgBrightYellow
	BgBrightBlue    = gu.BgBrightBlue
	BgBrightMagenta = gu.BgBrightMagenta
	BgBrightCyan    = gu.BgBrightCyan
	BgBrightWhite   = gu.BgBrightWhite
	BgLightBlue     = gu.BgLightBlue
	BgLightGreen    = gu.BgLightGreen
	BgLightYellow   = gu.BgLightYellow
	BgLightRed      = gu.BgLightRed
	BgLightMagenta  = gu.BgLightMagenta
	BgLightCyan     = gu.BgLightCyan
	BgLightGray     = gu.BgLightGray
	BgGray          = gu.BgGray
	BgDarkGray      = gu.BgDarkGray
)
View Source
const (
	CursorBlock     = gu.CursorBlock
	CursorBar       = gu.CursorBar
	CursorUnderline = gu.CursorUnderline
)
View Source
const (
	DEFAULT  = gt.DEFAULT
	REQUIRED = gt.REQUIRED
)
View Source
const (
	Ctrl_A = gt.Ctrl_A
	Ctrl_B = gt.Ctrl_B
	Ctrl_C = gt.Ctrl_C
	Ctrl_D = gt.Ctrl_D
	Ctrl_E = gt.Ctrl_E
	Ctrl_F = gt.Ctrl_F
	Ctrl_G = gt.Ctrl_G
	Ctrl_H = gt.Ctrl_H
	Ctrl_I = gt.Ctrl_I
	Ctrl_J = gt.Ctrl_J
	Ctrl_K = gt.Ctrl_K
	Ctrl_L = gt.Ctrl_L
	Ctrl_M = gt.Ctrl_M
	Ctrl_N = gt.Ctrl_N
	Ctrl_O = gt.Ctrl_O
	Ctrl_P = gt.Ctrl_P
	Ctrl_Q = gt.Ctrl_Q
	Ctrl_R = gt.Ctrl_R
	Ctrl_S = gt.Ctrl_S
	Ctrl_T = gt.Ctrl_T
	Ctrl_U = gt.Ctrl_U
	Ctrl_V = gt.Ctrl_V
	Ctrl_W = gt.Ctrl_W
	Ctrl_X = gt.Ctrl_X
	Ctrl_Y = gt.Ctrl_Y
	Ctrl_Z = gt.Ctrl_Z
	Escape = gt.Escape
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Command added in v1.0.9

type Command = gt.Command

type Param added in v1.0.9

type Param = gt.Param

type ParamModifier added in v1.0.9

type ParamModifier = gt.ParamModifier

type ParamType added in v1.0.9

type ParamType = gt.ParamType

type Terminal

type Terminal = gg.Terminal

type TerminalResponse

type TerminalResponse = gg.TerminalResponse

type TerminalResponseType

type TerminalResponseType = gg.TerminalResponseType

type TerminalStyles added in v1.0.10

type TerminalStyles = gg.TerminalStyles

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL