tonini / alchemist.el

Elixir Tooling Integration Into Emacs
http://www.alchemist-elixir.org
906 stars 103 forks source link

IEx: No secondary prompt, hang after multiline input #56

Closed andreas-roehler closed 8 years ago

andreas-roehler commented 9 years ago

Can't put in a form like:

if true do "asdf" end

IEx hangs, resp. echos the input, but not the expected result. Whilst when iex is called from bash, "asdf" appears as expected.

Thanks!

jtmoulia commented 9 years ago

Hey @andreas-roehler -- I just tried your example in the IEx prompt started by elixir-mode-iex and found the same issue. I'd give that a try, and if you find that you still have the issue then elixir-lang/emacs-elixir is probably the culprit rather than alchemist.

jtmoulia commented 9 years ago

Sorry -- scratch what I said. What command are you using for newlines? I found that I was actually using electric-newline-maybe-indent. comint-send-input, however, works like a charm.

andreas-roehler commented 9 years ago

So do I, after "end" RET, which does comint-send-input. Still hangs...

andreas-roehler commented 9 years ago

BTW: it's the only example bug shows up - commonly iex works well from alchemist.

tonini commented 9 years ago

@andreas-roehler thanks for reporting, this looks really like a bug and I'll try to find the issue.

Thanks @jtmoulia for helping :heart:

gleb commented 8 years ago

I did some investigating and somehow comint and IEx don't get along.

Here's the minimal test case:

(apply 'make-comint "IEX"
              "/usr/local/bin/iex" nil nil)

got to IEX buffer and paste

"""
foo
"""

and IEX appears to hang.

Erl works fine.

(apply 'make-comint "ERL"
              "/usr/bin/erl" nil nil)

and paste

"""
foo
"""
.

I was wondering if it was something about the prompt. To rule it out I setup .iex.exs

IEx.configure(alive_prompt: "%counter>", default_prompt: "%counter>",)

This makes IEx prompt the same as erl's default prompt. Still hangs with multiline input.

gleb commented 8 years ago

The problem may be in IEx itself.

iex | cat

paste a multi-line expression, get a hang

gleb commented 8 years ago

Jose confirms problem in IEx: https://groups.google.com/forum/#!topic/elixir-lang-talk/HoTY3YZP3y8

tonini commented 8 years ago

Thanks a lot guys for all the effort you put into hunting the issue.

My apology for respond a but late, but all these holidays and my kids were ill too made my days a bit busy. :-)

I have kind of an idea to fix this issue, I'll get back to you if I have a branch for testing ready.

gleb commented 8 years ago

@tonini What's the idea? Tell us more :-)

Still waiting for a reply from Jose on what's the underlying problem with IEx.

Meanwhile I hacked together an IEx wrapper script that seems to workaround the problem. The idea is to always wait for a prompt (maybe secondary prompt) before sending another line of input. Seems to work, even if there are potential corner case correctness issues.

Edit: cleaned up the script


#!/usr/bin/env ruby

# based on http://stackoverflow.com/questions/2730642/wrapper-around-bash-control-stdin-and-stdout

require 'pty'
require 'thread'

mutex = Mutex.new
saw_prompt = ConditionVariable.new

system('stty -echo') if ENV['Emacs']

PTY.spawn("/usr/local/bin/iex") do |p_read, p_write|
  Thread.new do
    loop do
      mutex.synchronize {
        saw_prompt.wait(mutex)
        input = STDIN.gets
#      puts "== read from STDIN: #{input}"
#      STDOUT.flush
        p_write.print input
#      puts "== wrote to process: #{input}"
      }
    end
  end

  loop do
    output = p_read.sysread(512)
#    puts "== read from process: #{output}"
    print output
#    puts "wrote to STDOUT: #{output}"
    STDOUT.flush
    saw_prompt.signal if output.include?("iex(") || output.include?("...(")
  end
end
tonini commented 8 years ago

@gleb If the underlaying problem could be fixed Elixir wise that would be great!

On the other hand I realized that there is an issue that we have to wait until the IEx prompt is showed up again after an input. So what I did is sending just always one line to the running IEx process instead the whole block including newlines and then always wait until the prompt is visible again. Works actually solid so far.

I will push the branch soon so you guys could test it.

tonini commented 8 years ago

@gleb @andreas-roehler is fixed on master

gleb commented 8 years ago

@tonini Works for me. Thanks! Will use/test it more, and let you know if anything comes up.