{"id":13812606,"url":"https://github.com/twof/CLSwift","last_synced_at":"2025-05-14T22:30:47.591Z","repository":{"id":85705643,"uuid":"103332176","full_name":"twof/CLSwift","owner":"twof","description":"A framework for writing command line tools in Swift","archived":false,"fork":false,"pushed_at":"2018-11-13T19:08:21.000Z","size":1298,"stargazers_count":9,"open_issues_count":8,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-05-10T14:09:22.442Z","etag":null,"topics":["commandline","macos","swift"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/twof.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2017-09-12T23:57:53.000Z","updated_at":"2023-11-15T16:02:28.000Z","dependencies_parsed_at":"2023-07-18T16:22:59.563Z","dependency_job_id":null,"html_url":"https://github.com/twof/CLSwift","commit_stats":null,"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/twof%2FCLSwift","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/twof%2FCLSwift/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/twof%2FCLSwift/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/twof%2FCLSwift/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/twof","download_url":"https://codeload.github.com/twof/CLSwift/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254239455,"owners_count":22037713,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["commandline","macos","swift"],"created_at":"2024-08-04T04:00:53.714Z","updated_at":"2025-05-14T22:30:47.084Z","avatar_url":"https://github.com/twof.png","language":"Swift","funding_links":[],"categories":["The Index"],"sub_categories":["Command Line UI tools"],"readme":"# CLSwift\nA Swift framework for writing commandline tools\n\n### Inspiration\nThere are a large number of really useful commandline tools that work on Linux, but were never ported to macOS. One of those was `xdotool` which is a UI automation tool for things like typing and moving a mouse around. Something similar doesn't exist on macOS so I started porting it over with the intent to make a drop in replacement and called it `osxdotool`. `xdotool` is a large and very mature tool so the complexity got to me early on and I knew I needed a way to orginize everything coherently, but nothing that achieved that well IMO for Swift. `CLSwift` was born.\n\n## Features\n* Ingest and parse commandline input into `Command`s, `Option`s, and the parameters associated with each\n* Typecast parameters upfront according to expected input\n* Validate input by expected number and type of parameters\n* Built for modularity. Easily split up argument and flag definitions however you like\n* Highly testible. Built to take in example input\n* Generated help messages on command misuse\n\n## Examples\n\n### Options\nOptions are used to alter the functionality of an argument. This is done by getting a dictionary representing state from the argument and changing values within that dictionary. The closure parameter is executed when one of the  `triggers` is found in the commandline input and parameters are validated. `Flag` is an `Option` that takes no parameters.\n\n```swift\nlet flag = Flag(\n    triggers: [\"-f\"],\n    help: \"Replaces foo value with baz\",\n    state: [\"foo\": \"bar\"]\n) { (params, state)  -\u003e State in\n    var newState = state\n    newState[\"foo\"] = \"baz\"\n    return newState\n}\n\nlet legsOption = Option\u003cInt\u003e(\n    triggers: [\"-l\"],\n    help: \"Sets leg number of legs\",\n    state: [\"legs\": 2],\n    numParams: .number(1)\n) { (params, state) -\u003e State in\n    var newState = state\n    newState[\"legs\"] = params[0]\n    return newState\n}\n```\n\n### Commands\nJust like `Option`, the closure parameter is executed when one of the  `triggers` is found in the commandline input and parameters are validated. `Option`s are attatched to an argument by passing them in on initialization. This is nice because if you have many arguments that use the same option, you can reuse the exact same `Option` instance.\n\n```swift\nlet command = Command\u003cInt\u003e(\n    triggers: [\"hello\"],\n    help: \"Takes foo, hello and legs and does foobar\",\n    numParams: .number(2),\n    options: [flag, legsOption]\n) { (vals, state) in\n    if state[\"foo\"] as? String == \"baz\" {\n        print(\"-f flag used\")\n    }\n    if state[\"legs\"] as? Int != 2 {\n        print(\"-l flag used\")\n    }\n}\n```\n    \n### Command Center\nThe following is the typical use case in which `CommandLine.arguments` is used for input, but you can also supply your own input for testing purposes by simply replacing `CommandLine.arguments` with your own array of strings.\n\nThe first step is figuring out which of your commands was triggered if any. Then you call `.execute()` on that command which executes the closure supplied on initialization.\n\n`CommandCenter` takes your input and breaks it up into more usable objects which are stored in `commandCenter.input`.\n\n```swift\nlet commandCenter = CommandCenter(commands: [command], input: CommandLine.arguments)\nlet triggeredCommand = commandCenter.check()\n\nif let triggeredCommand = triggeredCommand {\n    triggeredCommand.execute(commandline: commandCenter.input)\n}\n```\n    \n### Help message\nThe help message for the above looks like this\n\n```bash\nUsage: hello \u003cInt, Int\u003e [options]\n\nDescription:\nTakes foo, hello and legs and does foobar\n\n-f          Replaces foo value with baz\n-l \u003cInt\u003e    Sets leg number of legs\n```\n\nThis could be triggered if no parameters were supplied for `-l` for example which would look like this\n\n```bash\n$ ./example hello 1 2 -f -l\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftwof%2FCLSwift","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftwof%2FCLSwift","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftwof%2FCLSwift/lists"}