Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CLI parser API implementation #28

Merged
merged 5 commits into from
Oct 6, 2023
Merged

CLI parser API implementation #28

merged 5 commits into from
Oct 6, 2023

Conversation

jgmdev
Copy link
Member

@jgmdev jgmdev commented Sep 25, 2023

This is an initial work in progress implementation of the CLI parser that was discussed on #19 (comment)

Plugins should be able to register commands to provide additional CLI functionality using cli.register(...).

API

The api in core.cli is as follows:

---@alias core.cli.flag_type
---|>'"empty"'   # Does not needs a value
---| '"number"'  # A numerical value
---| '"string"'  # Any string value
---| '"boolean"' # 0,1,false,true
---| '"list"'    # Comma separated values

---Representation of a command line flag.
---@class core.cli.flag
---Long name of the flag eg: my-flag for --my-flag
---@field name string
---Short name eg: m for -m
---@field short_name string
---Description used for the flag when running `app help mycommand`
---@field description string
---Data type of the flag if an argument/value can be given to it
---@field type? core.cli.flag_type
---Value assigned to the flag
---@field value? number|string|boolean|table

---Representation of a command line subcommand.
---@class core.cli.command
---Subcommand name invoked with `app mycommand`
---@field command string
---Description used for the command when running `app help`
---@field description string
---Optional more detailed description that shows how to use the command
---@field long_description? string
---Description of the arguments printed on command help.
---@field arguments? table<string,string>
---Single line brief of using the command, eg: [options] [<argument>]
---@field usage? string
---The minimum amount of arguments required for the command
---@field min_arguments? integer
---The maximum amount of arguments required for the command where -1 is any
---@field max_arguments? integer
---Flag true by default which causes the editor to not launch when command is executed
---@field exit_editor? boolean
---Optional list of flags that can be used as part of the command
---@field flags? core.cli.flag[]
---Optional list of subcommands that belong to the parent subcommand
---@field subcommands? core.cli.command[]
---Function called when the command is invoked by the user
---@field execute? fun(flags:core.cli.flag[], arguments:string[])

---@class core.cli
---Application name
---@field app_name string
---Application version
---@field app_version string
---Application description
---@field app_description string
---List of registered commands
---@field commands table<string,core.cli.command>

---Add a new command to the cli parser.
---@param command core.cli.command
---@param overwrite? boolean
function cli.register(command, overwrite) end

---Removes an existing command from the cli parser.
---@param command string
function cli.unregister(command) end

---Get the default command used by the CLI parser.
---@return core.cli.command?
function cli.get_default() end

---Set the default command used by the CLI parser.
---@param command core.cli.command
function cli.set_default(command) end

---Adds color to given text on non windows systems.
---@param text string
---@param color "red" | "green" | "yellow" | "purple" | "blue" | "liteblue" | "gray"
---@return string colorized_text
function cli.colorize(text, color) end

---Display the generated application help or a specific command help.
---@param command core.cli.command?
function cli.print_help(command) end

---Parse the command line arguments and execute the applicable commands.
---@param args string[]
function cli.parse(args) end

Example Usage

local cli = require "core.cli"

-- Register greet command
cli.register {
  command = "greet",
  description = "A custom command to print a hello message.",
  usage = "[--name=some_name] [<extra_names...>]",
  flags = {
    {
      type = "string",
      name = "name",
      short_name = "n",
      description = "The name to greet"
    }
  },
  subcommands = {
    {
      command = "love",
      description = "A subcommand of greet with a love touch.",
      usage = "[--name=some_name] [<extra_names...>]",
      flags = {
        {
          type = "string",
          name = "name",
          short_name = "n",
          description = "The name to greet"
        }
      },
      usage = "[--name=some_name] [<extra_names...>]",
      execute = function(flags, arguments)
        local name = "stranger"
        for _, flag in ipairs(flags) do
          if flag.name == "name" then
            name = flag.value
          end
        end
        for _, arg in ipairs(arguments) do
          name = name .. " and " .. arg
        end
        print("Hello beautiful " .. name .. "!")
      end
    }
  },
  execute = function(flags, arguments)
    local name = "stranger"
    for _, flag in ipairs(flags) do
      if flag.name == "name" then
        name = flag.value
      end
    end
    for _, arg in ipairs(arguments) do
      name = name .. " and " .. arg
    end
    print("Hello " .. name .. "!")
  end
}

Usage:

pragtical greet --name=Joe Mary
pragtical greet love --name Joe Mary

TODO

  • if the user runs pragtical help and help is actually a directory/file on cwd then skip the command
  • skip previous behaviour by using -- to always force not checking if arguments are directories/files eg: pragtical -- help

Screenshot

pragtical-cli

@jgmdev jgmdev changed the title Initial CLI parser implementation CLI parser API implementation Sep 27, 2023
This was referenced Sep 27, 2023
* Added special `--` flag to always execute commands even if a file or
  directory with the same name exists.
@jgmdev jgmdev merged commit 37dc6f3 into pragtical:master Oct 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant