Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/beshrkayali/loki
A small library for writing line-oriented command interpreters in Nim.
https://github.com/beshrkayali/loki
cli nim nim-lang prompt shell
Last synced: 6 days ago
JSON representation
A small library for writing line-oriented command interpreters in Nim.
- Host: GitHub
- URL: https://github.com/beshrkayali/loki
- Owner: beshrkayali
- License: zlib
- Created: 2020-01-29T21:44:20.000Z (almost 5 years ago)
- Default Branch: master
- Last Pushed: 2021-04-02T20:12:26.000Z (over 3 years ago)
- Last Synced: 2024-08-02T07:17:19.297Z (3 months ago)
- Topics: cli, nim, nim-lang, prompt, shell
- Language: Nim
- Homepage:
- Size: 152 KB
- Stars: 32
- Watchers: 5
- Forks: 1
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-cli-frameworks - loki - oriented command interpreters in Nim. ([Nim](https://nim-lang.org/) / Useful awesome list for Go cli)
- awesome-nim - loki - A small library for writing line-oriented command interpreters in Nim. (Development Tools / Command-Line Interface Automation)
README
Loki
----
[![](https://github.com/beshrkayali/loki/workflows/CI/badge.svg)](https://github.com/beshrkayali/loki/actions?query=workflow%3AC)**loki**: line oriented (k)ommand interpreter
Loki is a small library for writing line-oriented
command interpreters (or cli programs) in Nim, that is inspired
by Python's cmd lib.Example
=======```nim
import loki, strutils, options
from sequtils import ziploki(myHandler, input):
do_greet name:
## Get a nice greeting!
if isSome(name):
echo("Hello ", name.get, "!")
else:
echo("Hello there!")
do_add num1, num2:
if isSome(num1) and isSome(num2):
echo("Result is ", parseInt(num1.get) + parseInt(num2.get))
else:
echo("Provide two numbers to add them")
do_EOF:
write(stdout, "Bye!\n")
return true
default:
write(stdout, "*** Unknown syntax: ", input.text , " ***\n")let myCmd = newLoki(
handler=myHandler,
intro="Welcome to my CLI!\n",
)myCmd.cmdLoop
```Compile with something like:
```sh
nim c --threads:on cmd.nim
```And an example run:
[![asciicast](https://asciinema.org/a/iMA7pIq2f7sy8X44pkCPhNmOt.svg)](https://asciinema.org/a/iMA7pIq2f7sy8X44pkCPhNmOt)
### How it works?
Loki uses the powerful macro system in Nim. Macros in Nim are functions that
execute at compile-time and can transform a syntax tree into a different one.The `loki` macro block in the example above would expand into something like this:
```nim
proc do_greet(line: Line; name: Option[string] = none(string)): bool =
## Get a nice greeting!
if isSome(name):
echo(["Hello ", get(name), "!"])
else:
echo(["Hello!"])
proc do_add(line: Line; num1: Option[string] = none(string);
num2: Option[string] = none(string)): bool =
if isSome(num1) and isSome(num2):
echo(["Result is ", parseInt(get(num1)) + parseInt(get(num2))])
else:
echo(["Provide two numbers to add them"])proc do_EOF(line: Line): bool =
write(stdout, "Bye!\n")
return trueproc default(line: Line): bool =
write(stdout, ["*** Unknown syntax: ", line.text, " ***\n"])proc help(input: Line): bool =
var undocced: seq[string] = @["add"]
var docced: seq[string] = @["greet"]
var docs = @["d1", "d2"]
if isSome(input.args):
var cmdarg = pick(input.args, 0)
if isSome(cmdarg):
var cmd = get(cmdarg)
if contains(undocced, cmd):
write(stdout, "*** No help on for this")
else:
for pair in items(zip(docced, docs)):
let (docced_cmd, doc) = pair
if cmd == docced_cmd:
write(stdout, doc)
break
return
write(stdout, "\nDocumented commands (type help ):\n")
write(stdout, "========================================\n")
write(stdout, join(docced, " \t "))
write(stdout, "\n\nUndocumented commands:\n")
write(stdout, "======================\n")
write(stdout, join(undocced, " \t "))
write(stdout, "\n")proc cmdHandler(line: Line): bool =
case line.command
of "greet":
if isSome(line.args):
return do_greet(line, pick(line.args, 0))
else:
return do_greet(line, none(string))
of "add":
if isSome(line.args):
return do_add(line, pick(line.args, 0), pick(line.args, 1))
else:
return do_add(line, none(string), none(string))
of "EOF":
if isSome(line.args):
return do_EOF(line)
else:
return do_EOF(line)
of "help":
return help(line)
else:
return default(line)
```Tip: The expanded code above (of the `loki` macro) can be printed using
[`expandMacros`](https://nim-lang.org/docs/macros.html#expandMacros.m%2Ctyped )
which can be helpful when debugging your code to see what's going on.### Changelog
### [0.3.0] Apr 2021
- Automatically generate TOC and help for handler commands### [0.2.1] Jun 2020
- Fix for handling extra args (thanks @hugosenari)### [0.1.1] Feb 2020
- Run tests on GH actions
- Minor docs### [0.1.0] Feb 2020
- Initial release