【问题标题】:Get cursor position in command line (Elixir)在命令行中获取光标位置(Elixir)
【发布时间】:2018-03-21 03:28:44
【问题描述】:

我想知道是否有捕获绝对光标位置的方法 在 Elixir 的命令行中。

我知道我必须使用下面的 ansi 转义序列 \033[6n, 并在执行后:

echo -en "\033[6n" 

打印出我正在寻找的内容,但我不确定如何从 Elixir 获得命令响应。

谢谢!

【问题讨论】:

标签: elixir


【解决方案1】:

我设法实现的最接近的事情是这一行:

~C(bash -c "echo -en '\033[6n'") |> :os.cmd

但是,它返回 '\e[6n' 而不是光标位置。一定是:os.cmd/1函数内部有转义符号的东西,不确定。

虽然这不是一个完整的答案,但还是希望它有所帮助。

【讨论】:

    【解决方案2】:

    这个差点把我逼疯了,我不得不挖这么多我说不清的线索。我将添加与解决方案相关的所有线程,它们都值得一读。

    首先,我们不能使用System.cmd,System.cmd 是在没有 tty 的情况下运行的

    iex(1)> System.cmd("tty", [])
    {"not a tty\n", 1}
    

    我们正在尝试做的事情需要一个 TTY。所以很少有相同的有趣库

    https://github.com/alco/porcelain

    但这也不适用于 TTY

    iex(1)> Porcelain.shell("tty")
    %Porcelain.Result{err: nil, out: "not a tty\n", status: 1}
    

    然后来到另一个图书馆

    https://github.com/aleandros/shell_stream

    这个好像是共享TTY的

    iex(3)> ShellStream.shell("tty") |> Enum.to_list
    ["/dev/pts/6"]
    

    这个TTY与当前终端的TTY相同,表示该TTY正在传播到子进程

    接下来是检查我们是否可以得到坐标

    iex(8)> ShellStream.shell("echo -en '033[6n'") |> Enum.to_list
    []
    

    所以经过多次尝试和尝试,我想出了一个方法

    defmodule CursorPos do
    
      def get_pos do
          settings = ShellStream.shell("stty -g") |> Enum.to_list
    
          #ShellStream.shell("stty -echo -echoctl -imaxbel -isig -icanon min 1 time 0")
          ShellStream.shell("stty raw -echo")
          #settings |> IO.inspect
          spawn(fn ->
                IO.write "\e[6n"
                #ShellStream.shell "echo -en \"\033[6n\" > `tty`"
                :timer.sleep(50)
                IO.write "\n"
               end)
          io = IO.stream(:stdio,1)
          data = io |> Stream.take_while(&(&1 != "R"))
          data|> Enum.join  |> IO.inspect
          ShellStream.shell("stty #{settings}")
      end
    
      def main(args) do
          get_pos
      end
    end
    

    这种工作,但仍然需要你按回车来阅读stdio

    $ ./cursorpos
    ^[[24;1R
    
    "\e[24;1"
    

    它还会改变屏幕坐标来获取它们,这不是人们想要的。但问题是坐标控制字符需要由您的外壳而不是子外壳处理。我尝试使用

    ShellStream.shell("stty -echo -echoctl -imaxbel -isig -icanon min 1 time 0")
    

    不起作用,因为 stty 不会影响我们需要获取坐标的父 shell。所以下一个可能的解决方案是在下面做

    $ EXISTING=$(stty -g);stty -echo -echonl -imaxbel -isig -icanon min 1 time 0; ./cursorpos ; stty $EXISTING
    "\e[24;1"
    

    这是因为我们能够改变当前 tty 的属性。现在您可能想要更深入地挖掘并从代码中找到如何做到这一点。

    我已经把我所有的代码放到 Github 项目下面了

    https://github.com/tarunlalwani/elixir-get-current-cursor-position

    你也应该看看下面的项目

    https://github.com/henrik/progress_bar

    如果您获取光标位置并不重要,那么您可以自己将光标固定到某个位置。

    参考文献

    https://unix.stackexchange.com/questions/88296/get-vertical-cursor-position

    How to get the cursor position in bash?

    https://groups.google.com/forum/#!topic/elixir-lang-talk/9B1oe3KgjnE

    https://hexdocs.pm/elixir/IO.html#getn/3

    https://unix.stackexchange.com/questions/264920/why-doesnt-the-enter-key-send-eol

    http://man7.org/linux/man-pages/man1/stty.1.html

    https://github.com/jfreeze/ex_ncurses

    How can I get the cursor's position in an ANSI terminal?

    Get console user input as typed, char by char

    【讨论】:

    • spawn 写入并使其休眠的进程!当然!不错。
    • 感谢您对此进行调查。如果用户需要按回车,这是否比 IO.puts("\e[6n"); IO.gets("") 更好?
    • @Dogbert,不是我发布的最后一个案例$ EXISTING=$(stty -g);stty -echo -echonl -imaxbel -isig -icanon min 1 time 0; ./cursorpos ; stty $EXISTING "\e[24;1"。如您所见,此输出来自我们的inspect
    【解决方案3】:

    我知道这是很奇怪的宏,但它确实有效! ;) 我在研究 IO.ANSI.Sequence.home() 函数 here 的实现时发现了它。

    特别感谢唯一一位Thijs

    defmodule Foo do                          
      import IO.ANSI.Sequence                   
      IO.ANSI.Sequence.defsequence :bar, 6, "n" 
    end
    

    然后简单地调用: IO.puts Foo.bar

    【讨论】:

    • 这和def bar, do: "\e[6n"完全一样。问题是关于获取终端打印的值以响应变量。
    • def bar, do: "\e[6n" 似乎只在我的模块 :ok 原子和光标位置时返回一个字符串(至少当我在 iex 中运行它时)。位置可以被 IO.gets 我猜:var = IO.gets Foo.bar
    • 有了def bar,你也需要做IO.puts Foo.bar。不幸的是 IO.gets 无法读取该输出。 :(
    • 我刚刚尝试过并收到了"4;1R\n" - 所以我们快到了,它只需要重新格式化;)
    • 不幸的是,是的。今天晚些时候我会检查一下我们能做些什么。
    【解决方案4】:

    如果您知道系统命令,请使用System module 从 Elixir 执行它

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-17
      • 2017-07-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多