如何使用Elixir从终端干净地获取多行输入?

时间:2019-05-19 18:15:58

标签: windows file terminal io elixir

作为实践,我正在尝试编写一个小的Elixir脚本,该脚本将从终端接收用户输入并将其写入文件。我的目标是能够一次从终端接受多行用户输入(在此当前迭代中,后面带有一些终结符)。

就当前的初始任务而言,我目前相对较幼稚的方法确实有效:我有一个递归get_line/2函数,它将接受一行输入,并将其连接到先前输入的所有输入中,然后会自称。如果输入的行是指定的“终止符”(在这种情况下为":done\n"),则它将所有连接的输入写入文件。

这确实可行,但是我想知道是否有更好的方法,因为与将文件读入终端的程序相比,这是一个相当复杂的程序,实际上只有两行左右。

代码:

# Mission: find a way to accept multiple lines of input from the
# terminal at once, and write the input into an md file 'my_file.md'.

# Naive approach: read line-by-line in a loop until a terminator is
# reached.

defmodule Term2file do
  def get_input() do
    IO.gets("> ")
    |> get_line()
  end

  defp get_line(line, data \\ "") do
    case line do
      ":done\n" ->
        File.write!("./my_file.md", data, [:append])
      _ ->
        new_data = data <> line
        get_line(IO.gets("> "), new_data)
    end
  end
end

Term2file.get_input()

在理想的世界中,我将能够以类似于Discord(或其他消息服务)的方式接受输入,其中可以使用shift-enter输入换行符,而通常使用enter可以“ '消息-允许在输入之前甚至在换行符之间都可以编辑整个输入。我认为这可能是不合理的,并且感觉这需要对终端本身的性质进行很多“斗争”,但是也许我的直觉是错误的。

无论如何,我想知道我是否使该解决方案过于复杂,以及是否错过了一种更简单或更直接的习惯用法。

1 个答案:

答案 0 :(得分:3)

您可以使用流来遍历I / O设备并写入文件:

defmodule Term2file do
  def get_input() do
    IO.stream(:stdio, :line)
    |> Stream.take_while(& &1 != ":done\n")
    |> Enum.into(File.stream!("./my_file.md", [:append]))
  end
end

Term2file.get_input()

这意味着您将在输入行时写入文件。您也不必担心管理资源。唯一的缺点是您无法拥有自定义提示(尽管可以接受,但可以添加此选项的PR)。

  

在理想的世界中,我将能够以与Discord(或其他消息服务)相似的方式接受输入,其中可以使用shift-enter输入换行符,而通常使用enter可以“完成”消息

AFAIK,这是不可能的,因为shift-enter和enter与终端没有任何区别吗?但是您可以使用Ctrl + D发送EOF指令,从而导致IO.stream终止。这仅适用于上面的代码段,但您也可以更改程序以相应地处理Ctrl + D输出。