{"id":13532604,"url":"https://github.com/beshrkayali/loki","last_synced_at":"2025-04-01T21:30:44.841Z","repository":{"id":53170100,"uuid":"237088394","full_name":"beshrkayali/loki","owner":"beshrkayali","description":"A small library for writing line-oriented command interpreters in Nim.","archived":false,"fork":false,"pushed_at":"2021-04-02T20:12:26.000Z","size":156,"stargazers_count":32,"open_issues_count":2,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-29T12:08:24.700Z","etag":null,"topics":["cli","nim","nim-lang","prompt","shell"],"latest_commit_sha":null,"homepage":"","language":"Nim","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"zlib","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/beshrkayali.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-01-29T21:44:20.000Z","updated_at":"2024-07-09T00:27:02.000Z","dependencies_parsed_at":"2022-09-14T09:51:12.573Z","dependency_job_id":null,"html_url":"https://github.com/beshrkayali/loki","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beshrkayali%2Floki","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beshrkayali%2Floki/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beshrkayali%2Floki/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beshrkayali%2Floki/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/beshrkayali","download_url":"https://codeload.github.com/beshrkayali/loki/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246712928,"owners_count":20821819,"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":["cli","nim","nim-lang","prompt","shell"],"created_at":"2024-08-01T07:01:12.222Z","updated_at":"2025-04-01T21:30:44.557Z","avatar_url":"https://github.com/beshrkayali.png","language":"Nim","funding_links":[],"categories":["Development Tools","[Nim](https://nim-lang.org/)"],"sub_categories":["Command-Line Interface Automation","Useful awesome list for Go cli"],"readme":"Loki\n----\n[![](https://github.com/beshrkayali/loki/workflows/CI/badge.svg)](https://github.com/beshrkayali/loki/actions?query=workflow%3AC)\n\n\n**loki**: line oriented (k)ommand interpreter\n\nLoki is a small library for writing line-oriented\ncommand interpreters (or cli programs) in Nim, that is inspired\nby Python's cmd lib.\n\nExample\n=======\n\n```nim\nimport loki, strutils, options\nfrom sequtils import zip\n\nloki(myHandler, input):\n  do_greet name:\n   ## Get a nice greeting!\n   if isSome(name):\n    echo(\"Hello \", name.get, \"!\")\n   else:\n    echo(\"Hello there!\")\n  do_add num1, num2:\n    if isSome(num1) and isSome(num2):\n      echo(\"Result is \", parseInt(num1.get) + parseInt(num2.get))\n    else:\n      echo(\"Provide two numbers to add them\")\n  do_EOF:\n    write(stdout, \"Bye!\\n\")\n    return true\n  default:\n    write(stdout, \"*** Unknown syntax: \", input.text , \" ***\\n\")\n\nlet myCmd = newLoki(\n  handler=myHandler,\n  intro=\"Welcome to my CLI!\\n\",\n)\n\nmyCmd.cmdLoop\n```\n\nCompile with something like:\n\n```sh\nnim c --threads:on cmd.nim\n```\n\nAnd an example run:\n\n[![asciicast](https://asciinema.org/a/iMA7pIq2f7sy8X44pkCPhNmOt.svg)](https://asciinema.org/a/iMA7pIq2f7sy8X44pkCPhNmOt)\n\n\n### How it works?\n\nLoki uses the powerful macro system in Nim. Macros in Nim are functions that\nexecute at compile-time and can transform a syntax tree into a different one.\n\nThe `loki` macro block in the example above would expand into something like this: \n\n```nim\nproc do_greet(line: Line; name: Option[string] = none(string)): bool =\n  ## Get a nice greeting!\n  if isSome(name):\n    echo([\"Hello \", get(name), \"!\"])\n  else:\n    echo([\"Hello!\"])\n  \nproc do_add(line: Line; num1: Option[string] = none(string);\n            num2: Option[string] = none(string)): bool =\n  if isSome(num1) and isSome(num2):\n    echo([\"Result is \", parseInt(get(num1)) + parseInt(get(num2))])\n  else:\n    echo([\"Provide two numbers to add them\"])\n\nproc do_EOF(line: Line): bool =\n  write(stdout, \"Bye!\\n\")\n  return true\n\nproc default(line: Line): bool =\n  write(stdout, [\"*** Unknown syntax: \", line.text, \" ***\\n\"])\n\nproc help(input: Line): bool =\n  var undocced: seq[string] = @[\"add\"]\n  var docced: seq[string] = @[\"greet\"]\n  var docs = @[\"d1\", \"d2\"]\n  if isSome(input.args):\n    var cmdarg = pick(input.args, 0)\n    if isSome(cmdarg):\n      var cmd = get(cmdarg)\n      if contains(undocced, cmd):\n        write(stdout, \"*** No help on for this\")\n      else:\n        for pair in items(zip(docced, docs)):\n          let (docced_cmd, doc) = pair\n          if cmd == docced_cmd:\n            write(stdout, doc)\n            break\n      return\n  write(stdout, \"\\nDocumented commands (type help \u003ctopic\u003e):\\n\")\n  write(stdout, \"========================================\\n\")\n  write(stdout, join(docced, \" \\t \"))\n  write(stdout, \"\\n\\nUndocumented commands:\\n\")\n  write(stdout, \"======================\\n\")\n  write(stdout, join(undocced, \" \\t \"))\n  write(stdout, \"\\n\")\n\nproc cmdHandler(line: Line): bool =\n  case line.command\n  of \"greet\":\n    if isSome(line.args):\n      return do_greet(line, pick(line.args, 0))\n    else:\n      return do_greet(line, none(string))\n  of \"add\":\n    if isSome(line.args):\n      return do_add(line, pick(line.args, 0), pick(line.args, 1))\n    else:\n      return do_add(line, none(string), none(string))\n  of \"EOF\":\n    if isSome(line.args):\n      return do_EOF(line)\n    else:\n      return do_EOF(line)\n  of \"help\":\n    return help(line)\n  else:\n    return default(line)\n```\n\nTip: The expanded code above (of the `loki` macro) can be printed using\n[`expandMacros`](https://nim-lang.org/docs/macros.html#expandMacros.m%2Ctyped )\nwhich can be helpful when debugging your code to see what's going on.\n\n\n### Changelog\n\n### [0.3.0] Apr 2021\n- Automatically generate TOC and help for handler commands\n\n### [0.2.1] Jun 2020\n- Fix for handling extra args (thanks @hugosenari)\n\n### [0.1.1] Feb 2020\n- Run tests on GH actions\n- Minor docs\n\n### [0.1.0] Feb 2020\n- Initial release\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbeshrkayali%2Floki","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbeshrkayali%2Floki","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbeshrkayali%2Floki/lists"}