Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Owl: A toolkit for writing command-line user interfaces in Elixir (hexdocs.pm)
223 points by clessg on Jan 8, 2023 | hide | past | favorite | 67 comments


An oblique thing I love about the Elixir ecosystem is that there is a strong focus on visual and aesthetic attention to detail. I mean look at those multibars in the asciinema. They're gorgeous for a console. In this, I'm reminded of R vs Python, where the former simply has far better graphics capabilities than the latter. In the Elixir case, I can't help but compare the look and feel of Livebooks compared with Jupyter Notebooks. The former are miles ahead in terms of a modern visual experience. It's very pleasant especially if you're expected to have an audience for your output, which kind of contrasts with python which always feels like it's built for engineers (and there's nothing wrong with that, but it is a different culture).


Building a cross-platform CLI from a python script in 2009 required unrelated open-source tools to package for each of the three major operating systems. I remember asking Dropbox guys what they were using. Having an official way to do it is much better.

Regardless of technology, I think CLI's tend to maintain their original size, or get smaller over time. If you choose to use a CLI built with Elixir, I imagine it could gain a web-based GUI without a large increase, if each build already includes a runtime environment and system libraries. Or if a CLI is written in another language and advertised as very compact, I imagine its size will also stay consistent, but might not gain the same fancy features. And in any case, popular compilers or packaging tools tend gain optimization improvements over time.


What kind of tools were needed for building CLI apps? Or do you mean for packaging those apps for end users, e.g. PyInstaller and equivalent?


Uh? What unreleased tools did you need in 2009?

Everything worked fine for me then.


Did you misread "unrelated" for "unreleased" in the first sentence?


Yes


This looks great!

If you're building CLI tooling in Elixir, you may also be interested in TableRex, my ASCII-table drawing library. [1]

[1] https://github.com/djm/table_rex


I love using Elixir but I also like to think "right tool for the job" and imho Elixir is generally not the right tool for the job for command-line user interfaces. It's fun to experiment with though, of course.

Having said all of that that, something like this might be useful when writing custom Mix tasks inside Elixir projects!


Elixir is having a big push into machine learning (checkout Nx and Axon) and generally is also great for doing data streaming processing so you could imagine tools cropping up that might have it's primary interface be a CLI... this would be a great fit for those use cases.


I rewrote all my CLI scripts in Elixir, it's best in class IMO. With Mix.install now it's just amazing. Fast, free and simple concurrency, low startup time, great ecosystem, very good system level abstractions and functions in the stdlib.


I completely agree with GP in that Elixir isn't really _designed_ for CLI tools, but I agree with you that it does happen to be great for it. I don't doubt there are some facilities it lacks that would make ones life easier, but overwhelmingly its standard library is more than sufficient.


Are any of these published or would you share an example?


Nothing published, they're typically not very complex.

Things of interest for CLI stuff:

    #!/usr/bin/env elixir
Use Mix.install like so

    Mix.install([
      {:jason, "~> 1.4"},
    ])
Execute shell commands

    {output, status_code} = System.cmd("ls", ["-la"])
For handling files and paths:

    Path.join/2
    __ENV__.file
    Path.dirname/1
    Path.expand/1
    File.lstat/1
    File.read/1
Parsing arguments

    argv = System.argv()
    OptionParser.parse(argv, [strict: [switch: :boolean], aliases: [s: :switch]])
    exit({:shutdown, status_code}) # for shutting down with an error
For printing colors (from docs)

    iex> IO.ANSI.format(["Hello, ", :red, :bright, "world!"], true)


> imho Elixir is generally not the right tool for the job for command-line user interfaces

why? what factors lead you to this conclusion?

there's so mamy examples of low grade opinion sharing in the comments. going just a little further to say why you think something, what factoes are good or bad, can provide a real starting point where folks can learn & engage usefully, rather than just subject each other to utterly shallow opinion. another example from elsewhere:

> Elixir is ill-suited to command line apps out of the box.

we should have actual substance to our conversations; again, why?

(my own guess is that beam vm has to get started & is mind of heavyweight... i dunno if that cost even necessarily has to be paid for each program launch or no, maybe there's some trickery to quickly start new cli processes in existing vms. just guessing, not my scene. but what would be negative factors? no one says.)


I have no horses in this race, but a good language for a CLI is a language that generates small binaries that use little memory and start up very fast.

I can think of three languages that I would use based on that: Go, Rust and if I was feeling adventurous or wanted to be able to execute scripts, Common Lisp (it's surprisingly fast, in the same league as Rust, for small programs).

Does Elixir compare positively to those in these categories?

EDIT: some people on this thread say it takes 200ms just to start an Elixir program. That's three times slower than Java, which is generally not considered a good language for CLIs.


I completely agree with your points about shallow comments. In a similar vein, while we’re asking for a bit more effort, I’d like to ask you to re-read what you write before posting. There are a half dozen typos and no capitalization. It helps ESL users, gives your subconscious another chance to refine your comment, and makes it easier for each reader to focus on your ideas without distraction.


One of the great things about Elixir is that it encourages you to think of your application as the code that executed the purpose of your system and everything else as an interface to it.

So a web interface, an API interface, a CLI interface, etc are all treated the same way since the code doing the work isn’t tightly integrated to any of them.

From that perspective, Elixir can be great for CLI.


Either I don't understand what you are saying, or this is not unique to Elixir at all? Or both lol


With Elixir/Erlang the various BEAM nodes can connect and call each other so the code internally tends to reflect the same approach.

The equivalent approach in most other languages would be to create a single web API and have everything talk to it via REST, etc.

It’s closer to thinking of everything having an RPC interface by default I suppose.


And not all CLI tools are isolated UNIXy bins you install. It could be an interface to a larger app running on the system like a database.


It's not. I keep factoring my CLI scripts to something that's very MVC. Everytime.


brightball is perhaps alluding that the BEAM VM environment itself is treated more as an operating system within an operating system rather than just another process in an operating system.

The BEAM VM is unique (at least compared to mainstream languages) in that everything is run as a preempted, stackful coroutine. The result is an environment reminiscent of an operating system.


As long as you aren’t severely memory constrained or trying to do tasks that only take a few ms, it’s totally fine. It’s even desirable in a lot of cases. You can do a lot of tasks in about the time it takes python, or faster if it’s a parallelizable problem.


You absolutely can strip beams memory usage if required.

There are a number of applications(Erlang term) that start by default that may not be required, which can be disabled.


I know you can do that, but I’m not sure how much memory it saves in practice.


> I love using Elixir but I also like to think "right tool for the job" and imho Elixir is generally not the right tool for the job for command-line user interfaces

Unless you're writing a CLI utility that natively interacts with BEAM VM services without having to de/serialize JSON via a REST API first


I wonder which one is currently the king (include all arbitrary metrics you can think of)? I guess 1.Go 2.Rust


As of last year, Meta recommends internally that CLI tools be implemented in Rust:

https://engineering.fb.com/2022/07/27/developer-tools/progra...


Python is by far the world most popular language, and is used a lot for command-line scripts.


Its awful package management makes using Python for CLI applications more painful than it has a right to be. Despite this egregious shortcoming, it's popular for scripts only because it comes with a quite extensive standard library.

These days I'd rather suffer through the verbosity of Go or strict memory semantics of Rust (which are no concern in most CLI applications) than write more than a dozen lines of Python. Personally, while I think the compiled world has settled onto a few very good languages, the scripting ecosystem still to this day leaves a lot to be desired.


Bash?


Won't work on windows outside of WSL, at least that has been a reason I've heard for not using Bash for simple stuff.

For complex applications bash (or shellscript in general) is also rather ill-suited as it has a lot of footguns and can be hard to maintain.


You can also use Bash in Cygwin/MSYS environments, like Git for Windows. I've been using Bash for writing cross-platform Git scripts :)


For decades. Bash even runs in DOS.


I have no idea if Bash has library? It's more like for managing host stuff rather than compute wide range of application.


How problematic is the BEAM startup time for this? I made a command line tool once and it took a while to start the VM but this was on a much older machine...


It's going to completely depend on the tool. I can start an elixir app in half a second, which is going to be unacceptable in many situations.

That said, there are also many situations where that is a tradeoff absolutely worth making!


I wonder if you can tree-shake unnecessary modules in the release. There's a lot of stuff in the otp beam release you probably don't need in any given CLI app and it should be easy to parse bytecode and figure out dependencies.


That's one of the goals of Firefly[1]

> It can compile code more efficiently than the BEAM by stripping out dead code and compiling only what’s necessary for an application.

Though, they only mention faster compilation and smaller digital footprint, not faster startup.

[1] https://dockyard.com/blog/2022/09/01/dockyard-r-d-firefly-op...


Hello friend, I'm chasing you down from a previous comment, did you get anywhere with that elixir/liveview text ui ?


I did not. Too busy at work.


I am still very keen on this, even if its not a 'web app' style tui code. There has also been interest on genserver.social too.

Thank you for taking the time to respond.


I think there may be someone else in the community working on this


found it, even has the same name: https://github.com/E-xyza/ex_term


Its amusing that you both came to the same conclusion on naming :)


Shouldn’t be necessary if you configure your release to start in interactive move instead of embedded mode as modules would then get loaded lazily


If you have several commands you're likely to use and possibly pipe together, it might make sense to have lightweight compiled C/Rust command client stubs invoke an Elixir server, so you'd pay the BEAM startup cost only once, in exchange for some complexity.


~200-250ms on my machine


This is very welcome. Elixir is ill-suited to command line apps out of the box.


We have an FTXUI for C++. https://github.com/ArthurSonzogni/FTXUI


It seems that every ShowHN that features an Elixir project is well-polished, has a sensical API, and has friendly, solid documentation. Is this a function of the nature of the language, the community, or a mix of both?


I use Elixir as my primary language in my day job and I'd say it's a mix of the community and the ecosystem. Most modules seem to have great documentation, so if you're producing one you also put in the effort. However, ExDoc (the documentation module) is also really solid with loads of great features, including the ability to run your examples as unit tests.

That said, it's not all that uncommon to be searching for something like an implementation of a SaaS API and find a totally undocumented module. It's not the norm by any stretch though.


Absolutely both.

But...the issue is packaging/distributing a CLI built with Elixir. Comparatively to building a CLI in something like Rust, there is a lot of overhead that comes with a VM-based language and framework. Especially if you want to target multiple OS and processor architectures (or distributions). Not to say that it is impossible, just maybe not as simple. It is one thing to run Mix tasks, or access the Owl API from REPL, it is another to run an Owl-based app on macOS, Linux and Windows and get it there.


Well, `mix release` (https://hexdocs.pm/mix/Mix.Tasks.Release.html) exists to address this very issue.

It still has limitations (the biggest one is the requirement for the os&architecture to match between the builder and the deployment target) — but the result is a standalone binary which not only embeds the VM and preloads the app's bytecode, but even "trims" the stdlib to only ship the required functions.


Right, so the moral of the story centers on the target user of the CLI tool. If you're building something for the Elixir community - game on I suppose, though there is still the complexity of build-env per OS/arch.

I wonder where WASM/container enters the discussion.


> Firefly compiles Elixir applications faster and more efficiently than the BEAM can, and introduces WASI targeting to run applications in resource-constrained environments.

https://dockyard.com/blog/2022/09/01/dockyard-r-d-firefly-op...

Containers are already solved, its trivial to build and boot a mix release - but whether that's appropriate for a CLI tool depends on the complexity of the tool I guess, but not too far from flatpaks etc no?


Burrito is supposed to close the gap even further, though I've never used it.


Undeniably it's not going to be as convenient, but the divide isn't what it used to be. BEAM apps can be compiled to a binary, and as long as that binary was compiled for the platform, that should be good enough.

I'm doubtful I'll see it used much outside the BEAM community, but then again it's been a "successful despite a lack of mass usage" community for awhile.


The Elixir community has good internal (and official!) tooling around libraries and documentation. I would say it's a positive feedback loop. The nice community resources attract good programmers, good programmers make nice community resources.


Or it's the way upvotes work for the most part?


Both. Best of Ruby (community, docs, pleasant to use) and Erlang (functional, value oriented, BEAM).



Github user interface is really not good in this case. Need a visible verticle line between begin..end block.


Is there something like this for Java?


https://github.com/remkop/picocli

"Picocli is a one-file framework for creating Java command line applications with almost zero code. Picocli aims to be the easiest way to create rich command line applications that can run on and off the JVM.

Picocli supports a variety of command line syntax styles including POSIX, GNU, MS-DOS and more. It generates highly customizable usage help messages with ANSI colors and styles. Picocli-based applications can have command line TAB completion showing available options, option parameters and subcommands, for any level of nested subcommands. Picocli-based applications can be ahead-of-time compiled to a GraalVM native image, with extremely fast startup time and lower memory requirements, which can be distributed as a single executable file.

Picocli generates beautiful documentation for your application (HTML, PDF and Unix man pages)."

https://picocli.info/quick-guide.html


Many, yes. You can pair a CLI arg parser with a logger that supports colored output, and add a TUI library if you needed that. There are "command line frameworks" as well, like picocli that can be paired with something like Jbang for distribution.


JLine has a complete terminal library and includes a demo which is a full editor: https://github.com/jline/jline3




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: