Skip to content

lispyclouds/bblgum

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

44 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

bblgum

License: MIT bb compatible

An extremely tiny and simple wrapper around the awesome gum.

This is intended for babashka and JVM clojure and provides an idiomatic and data driven wrapper around the CLI tool.

Requirements

  • Gum should be installed
  • Babashka or the Clojure JVM runtime, latest recommended

Usage

Add this to your bb.edn or deps.edn:

{:deps {io.github.lispyclouds/bblgum {:git/sha "1d4de3d49b84f64d1b71930fa1161f8d2622a4d9"}}}

Sample babashka usage:

$ bb -Sdeps '{:deps {io.github.lispyclouds/bblgum {:git/sha "1d4de3d49b84f64d1b71930fa1161f8d2622a4d9"}}}' \
     -e "(require '[bblgum.core :as b]) (b/gum :input :placeholder \"User name:\")"

Interaction

This follows the same section on the gum repo and all params should work verbatim. Run gum <cmd> --help to discover all the params and args.

This lib only has one public fn: bblgum.core/gum.

Standard Usage

gum tries to closely mimic the usage of the CLI tool, so it works like (gum :COMMAND), (gum :COMMAND [ARGS]) or (gum :COMMAND [ARGS] :OPTION VALUE :OPTION2 VALUE)

(require '[bblgum.core :as b])

Examples:

;; Command only:
(b/gum :file)

;; Command with args:
(b/gum :choose ["arg1" "arg2"])

;; Command with opts:
(b/gum :file :directory true)

;; Command with opts and args:
(b/gum :choose ["arg1" "arg2"] :header "Choose an option")

There are several special opts, that are handled by the library:

  • :in: An input stream than can be passed to gum
  • :as: Coerce the output. Currently supports :bool, :ignored or defaults to a seq of strings
  • :gum-path: Path to the gum binary. Defaults to gum

All other opts are passed to the CLI. Consult gum CMD --help to see available options. To pass flags like --directory use :directory true. Always use full names of the options.

Note: In the event of a name collision with a special opt and a command opt, use the low level API.

Example with special options:

(gum :table :in (clojure.java.io/input-stream f) :height 10)

Usage Examples

input

(b/gum :choose ["foo" "bar" "baz"] :no-limit true)

{:status 0 :result ("foo" "baz")}

write

(b/gum :write)

filter

(b/gum :filter :in (clojure.java.io/input-stream "flavours.txt"))

(b/gum :filter :in (clojure.java.io/input-stream "flavours.txt") :no-limit true)

;; Since bblgum uses babashka/process, the following are possible as well
(b/gum :filter :in "a string that will be streamed into the stdin char by char")

(b/gum :filter :in (clojure.string/join "\n" ["can" "be" "used" "as" "a" "filtering" "choose" "alternative"]))

confirm

(b/gum :confirm :as  :bool)

file

(b/gum :file ["src"])

pager

(b/gum :pager :as :ignored :in (clojure.java.io/input-stream "README.md"))

spin

(b/gum :spin ["sleep" "5"] :spinner "line" :title "Buying Bubble Gum...")

table

(b/gum :table :in (clojure.java.io/input-stream "flavours.csv"))

All of the rest of the options and usecases should work ™. Please raise issues/PRs for any improvements. Much appreciated!

Caveats

  • Since this uses gum which expects an interactive TTY like terminal, this is not possible to be used from editor REPLs like Conjure, CIDER, Calva etc when jacked-in. To use this from an editor REPL:
    • First start the REPL in a terminal, for example in bb for nREPL on port 1667: bb nrepl-server 1667.
    • Connect to the port from the editor of your choice, for example with neovim and conjure: :ConjureConnect 1667.
    • Perform the usual REPL interactions and all the gum output would appear on the terminal and not your editor but the result should be on the editor as expected.

Low-level API

This was standard in previous versions of gum, we kept it for full backward compatibility.

Convention:

  • The main command should be passed as a keyword or string to :cmd. Required
  • Passing opts:
    • The --opts are to be passed as :opts
    • Use the full forms of the opts: --spinner not -s
    • Seqs can be passed to opts taking multiple params as well
    • Pass boolean flags like --password as {:password true}
  • All positional args to be passed as :args.
  • An input stream can be passed to :in. Useful for commands like filter
  • Corece the output:
    • Treat non-zero exit codes from gum as a booleans passing :as :bool
    • Ignore it with :ignored. This ignores parsing of the stdout
    • :bool is useful for commands like confirm
    • :ignored is useful for pager. Ignoring the parsing of the output helps the pager actually draw things
    • Defaults to a seq of strings
  • Override the default gum path of gum by passing it via :gum-path

The gum fn returns a map of exit status of calling gum and the result either as a seq of lines or coerced via :as. Exceptions are not thrown unless calling gum itself does, the status code is intended for programming for failures.

(b/gum {:cmd :choose
        :opts {:no-limit true}
        :args ["foo" "bar" "baz"]})

{:status 0 :result ("foo" "baz")}

License

Copyright © 2023- Rahul De.

Distributed under the MIT License. See LICENSE.