获取光标在命令行中的位置(Elixir)

获取光标在命令行中的位置(Elixir),elixir,Elixir,我想知道是否有一种方法可以捕捉光标的绝对位置 在Elixir的命令行中 我知道我必须使用以下ansi转义序列\033[6n, 执行后: echo -en "\033[6n" 打印出我想要的内容,但我不确定如何从Elixir获得命令响应 谢谢!如果您知道系统命令,请使用Elixir执行该命令。我最接近的方法是: ~C(bash -c "echo -en '\033[6n'") |> :os.cmd 但是,它返回的是'\e[6n'而不是光标位置。必须是:os.cmd/1函数中包含转义符号

我想知道是否有一种方法可以捕捉光标的绝对位置 在Elixir的命令行中

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

echo -en "\033[6n" 
打印出我想要的内容,但我不确定如何从Elixir获得命令响应


谢谢!

如果您知道系统命令,请使用Elixir执行该命令。

我最接近的方法是:

~C(bash -c "echo -en '\033[6n'") |> :os.cmd
但是,它返回的是
'\e[6n'
而不是光标位置。必须是
:os.cmd/1
函数中包含转义符号的内容,不确定


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

我知道这是一个奇怪的宏东西,但它可以工作!;)我在研究IO.ANSI.Sequence.home()函数的实现时发现了它

特别感谢一位也是唯一一位

然后简单地打电话:
IO.puts Foo.bar

这一条几乎让我发疯,我不得不挖掘太多无法分辨的线程。我将添加所有与解决方案相关的线程,它们都值得一读

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

iex(1)> System.cmd("tty", [])
{"not a tty\n", 1}
我们要做的是需要一个TTY,所以对于同一个TTY,很少有有趣的库

但这对TTY也不起作用

iex(1)> Porcelain.shell("tty")
%Porcelain.Result{err: nil, out: "not a tty\n", status: 1}
然后来到另一个图书馆

这一个似乎与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"
它还改变屏幕坐标以获取它们,这不是我们想要的。但问题是坐标控制字符需要由您的shell而不是子shell处理。我尝试使用

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项目中了

你们也应该看看下面的项目

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

参考资料


中介绍了在erlang中获取命令响应的一种方法,但您必须将其转换为Elixir。这与
def bar,do:“\e[6n”
。问题是如何将终端在响应时打印的值转换为变量。
def bar,do:“\e[6n”
似乎只有在我的模块
:ok
原子和光标位置时才返回字符串(至少在iex中运行时是这样)我猜:
var=IO.gets Foo.bar
有了这个
def bar
,你也需要做
IO.puts Foo.bar
。不幸的是,IO.get无法读取输出。(我刚刚试过,收到了
“4;1R\n”
-所以我们就快到了,只需要重新格式化;)不幸的是,是的。今天晚些时候我会检查我们能做些什么。
spawn
编写并使其休眠的过程!当然!很好。感谢您查看此过程。如果用户需要按enter键,这是否比只按
IO.put(“\e[6n”);IO.get(”)更好
?@Dogbert,不是在我发布的最后一个案例中,
$EXISTING=$(stty-g);stty-echo-echonl-imaxbel-isig-icanon最小1次0;/cursorpos;stty$EXISTING“\e[24;1”
。正如您所看到的,这个输出来自我们的
检查

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