Как правильно принимать многострочный ввод с терминала, используя Elixir? - PullRequest
0 голосов
/ 19 мая 2019

На практике я пытаюсь написать небольшой скрипт на 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 Ответ

3 голосов
/ 19 мая 2019

Вы можете использовать потоки для обхода устройства ввода-вывода и записи в файл:

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, который добавляет эту опцию, хотя будет приветствоваться).

В идеальном мире я был бы в состоянии принять ввод в аналогичномfashion to Discord (или какая-либо другая служба сообщений), где вводы новой строки могут быть выполнены с помощью shift-enter, и, как правило, с помощью enter обычно завершит сообщение

AFAIK, это невозможно, поскольку shift-enter ивойти никак не различаются до терминала?Но вы можете использовать Ctrl + D для отправки инструкции EOF, в результате чего IO.stream завершится.Это просто работает в приведенном выше фрагменте, но вы также можете изменить свою программу для соответствующей обработки Ctrl + D.

...