How to Launch an Editor from Escript?

I’d like to launch an editor (like vim or emacs) from my command-line script.

In Ruby I’d use exec "vim".

In Elixir, when I try System.cmd "vim", [] with various options, I run into terminal I/O issues.

Can anyone recommend best practice to launch vim or emacs from Elixir?

I don’t run a common terminal(sakura) so this may look odd

System.cmd(“sakura”,["-e", “vim”])

or

System.cmd(“sakura”,["-x", “vim”])

Thanks for that tip - clever! I got it to work using System.cmd("terminator", ["-x", "vim", "/path/to/file"]) But this approach doesn’t work over ssh, and requires the script to know what terminal program is installed. :thumbsdown:

Still looking for an exec solution that launches the editor in the console. This is simple in bash or ruby - can it be done in elixir/erlang?

I spent a while playing with this and couldn’t find a way to make it work :frowning: - I can really understand the need for this so it’s sad it doesn’t seem possible. I deleted my previous post as it turned out to be unhelpful :slight_smile:

Maybe someone more experienced with elixir internals will come and offer you a holy grail :stuck_out_tongue:.

Can you be a bit more specific about your “terminal issues”? I would just do a System.cmd.

To test for yourself: fire up iex and type System.cmd "vim", []

I see these errors:

Vim: Warning: Output is not to a terminal
Vim: Warning: Input is not from a terminal

You can try System.cmd("vim", [], into: IO.stream(:stdio, :line)) That writes the vim startup page to the terminal, but no keyboard input.

I’ve also tried: System.cmd("bash", ["-c", "vim"]), System.cmd("exec", ["-c", "vim"]) and a bunch of other variations.

I think launching an editor requires unix fork/exec from erlang/elixir, but I couldn’t find any reference showing how to do this.

I’m using Ubuntu 16.04, bash 4.3, terminator 0.98, erlang 19, elixir 1.3.4.

If you have any ideas/suggestions I’m all ears!! :slight_smile:

You can do something else if you really want. You can run the vim in tmux in background detached mode, and then attach it into different console/ssh conection like:

$ tmux new -d -s foo vim # convert this to System.cmd from elixir
$ tmux attach -t foo # execute this from different console as the same user

Can confirm System.cmd "tmux" ["split-window"] works. Given that, we have many tmux scripting options - nice idea!!

You can detect that you are running under a tmux session using System.get_env("TMUX"). So if running under tmux, launch the editor, otherwise show an error message. That will work.

Still - it would be nicer to drop the tmux dependency and just exec vim like you can do in Bash or Ruby. Can anyone confirm if this is possible in Elixir? Or if not possible, explain why?

@hubertlepicki thank you for the tmux tip!

1 Like

Ok–see “output is not to a terminal”, “input is not from a
terminal”–that’s the more specific I was thinking of. I don’t have an
ubuntu image handy to test this but I did just try this with emacs on
Windows and it works just fine.

System.cmd “/usr/bin/emacs/bin/runemacs”, []

Yes I know I’m discussing Windows vs Ubuntu and vim vs. emacs- but since
you seemed to be asking how to open the editor in general this does seem an
appropriate test. If on the other hand you’re asking for more than simply
opening up the editor then again please add more detail to your question.

My point is that I don’t think the problem is System.cmd; System.cmd works
just fine. I think the issue is that you’re trying to do more than just
fire up vim and that’s fine but that seems to be an issue with Vim–not
Elixir. Check this link


for that “Output is not to a terminal” message. And here

for more on “Input is not from a terminal”.

Basically it looks as if you’re trying to do more than simply start Vim
(perhaps unintentionally) and if that’s the case then you need to spell out
what it is that you’re trying to do. At any rate I don’t think this is an
Elixir issue.

oc

1 Like

You’re showing your windows bias. There is actually a real problem here; processes run by System.cmd on unix based systems don’t have a tty attached to stdin/stdout. You can’t run anything that needs “editor like” access to the tty.( at least with the default settings).

There are a bunch of ways to get around this ( xterm -c , tmux, etc… ), but System.cmd has some real limitations on unix compared to languages like Ruby. You can easily open an editor in a windowing environment (tmux is ascii windows more or less ), but in the classic glass tty mode, you can’t.

To be honest, wanting to do this kind of seems like a screwhammer approach, but regardless there isn’t a straightforward way to open a tty based editor on unix on the BEAM. We aren’t doing any favors to anybody in pretending that the problem doesn’t exist.

2 Likes

No - just trying to start vim on ubuntu using System.cmd "vim", [].

Interesting to hear that it worked on windows!! I would like an approach that works for all platforms and editors.

FYI on Ubuntu I also failed to launch emacs and nano - seems that this is more than a vim-specific issue.

Thanks for posting the links.

Even if the tty was accessible System.cmd doesn’t have the correct semantics to work with an editor. It doesn’t work with ed for example, because System.cmd is meant to run a command and capture stdout. It swallows all stdout until the process exits.

The other issue I can think off the top of my head is that by default I/O is line based from STDIN. (i.e. the stdin I/O handler does not send input to a process until \n is entered). There are ways to enable char based input to do curses like apps. (Does anyone out there remember line-mode telnet?)

There is no direct interface to fork/exec available on the BEAM. Ports come close, but they use stdin/out of the sub-process to communicate. I’m not sure there’s any way access the tty of the controlling BEAM process.

If you REALLY need to use an editor, I’d suggest running the escript as a subprocess of another scripting language and capture the output of the escript using various expect style libraries.

Have the escript output “edit filename”, and the wrapper script edit the file. The escript should wait for input like “edit filename done” and the wrapper will need to send that when finished.

Does all that feel like pounding screws with a hammer? 'Cause as much as I really like using Elixir for cli type stuff, there are some problems that it just doesn’t match up well with.

Thanks for your feedback. Seems like launching an editor or any type of curses interface isn’t going to happen direct from Escript.

Besides this I/O issue, I find Elixir to be very nice for building CLI. My Escripts tend to have a very thin ‘CLI’ layer, very decoupled from the app. It would be simple to write a CLI layer in another language, at the cost of extra complexity in distribution & installation.

Another idea: I found a couple of NIF based packages to integrate Erlang & Ncurses. See https://github.com/sofuture/encurses and https://github.com/mazenharake/cecho . Perhaps it would be possible to use NIF to create a ‘Launch an Editor’ package(?)

For now, I’ll use the tmux workaround.

James Smith (not sure if he’s on the forum) gave a talk at the first ElixirConf in which he drove a rogue-like game via Elixir. I think it was with ports. That might give you some more ideas to try.

http://confreaks.tv/videos/elixirconf2014-writing-command-line-applications-with-elixir

1 Like

Not really my windows bias Booker–my ignorance of behavior on *nix. :slight_smile: I
just assumed that if Windows was capable of handling this then surely *nix
would be. My bad for making an assumption.

oc

As ex_top demonstrates, https://github.com/utkarshkukreti/ex_top, you can certainly use curses from within Elixir. So I guess you could port a minimal editor environment to Elixir.

I’m not sure NIFS would help all that much. You need to dup stdin/out or somehow grab access to the process groups ttys.

For future reference …

Here’s a function to detect the presence of TMUX:

defp using_tmux?(), do: System.get_env("TMUX") != nil

Here’s a function to launch vim in a TMUX split-window:

defp launch_vim_for(file_path) do
  System.cmd "tmux", ["split-window", "vim", file_path]
end

This thread seems rather old… however I am looking to do the same thing. Did anyone ever figure this out?

The question of it becomes “how do you launch an editor when you don’t have stdin/stdout?” in essence. :slight_smile:

Being that, do you prefer a GUI editor, or a terminal editor? And if a terminal editor do you want a new tab? Or if a console editor would another tmux session be fine?

1 Like

A terminal editor is fine. My issue is that this tool that I am making will be available and used by all the devs in my organization. I can’t be sure that everyone has and is running a tmux session.