如何在Golang中保持终端输入始终在底部?

huangapple go评论69阅读模式
英文:

How to keep terminal input always at bottom in Golang?

问题

我正在尝试创建一个程序,它可以从某个数据源获取实时更新。我还希望能够等待用户输入,就像普通终端一样。目前,每当有更新时,我会打印内容并打印输入提示消息,就像这样:

输入命令 > 
这是一个实时更新消息

输入命令 > 
这是一个多行实时更新消息

输入命令 > quit
再见!

问题是,对于我收到的每条实时消息,我都会打印它,并且"输入命令 >"会一次又一次地显示出来,这是不希望的。我希望实时更新在终端的主要部分更新,而"输入命令 >"始终保持在底部。

我在Github上找到的最接近的包是https://github.com/gizak/termui,但里面的大多数示例都是用来显示文本、仪表盘和图表的。所以我不太确定如何入手。

有没有任何包或者termui包的示例可以实现这个功能?谢谢。

英文:

I am trying to create a program which will have live updates from some data source. And I also want to wait for user input just like a normal terminal. Right now, whenever there is update, I will print the content and print the prompt message for input again which create something like this:

Enter command > 
This is a live update message

Enter command > 
This is a multi-line li......
......ve update message

Enter command > quit
Bye bye!

The problem is that for every live message I received, I will print it and the "Enter command >" will be displayed again again and again, which is not desired. I want the live update to be update on the main part of the terminal, while the "Enter command >" always stay at the bottom

The closest package I can found on Github is https://github.com/gizak/termui but most of the examples inside is trying to display text, gauge and graphs. So I am not quite sure how to get started.

Is there any package or example of the termui package to achieve this? Thank you.

答案1

得分: 7

使用github.com/gizak/termui,你正在朝着正确的方向前进。

要理解为什么你无法实现以下功能:

> 我希望主要部分的实时更新在终端的底部,而"输入命令>"始终保持在底部

需要稍微了解一下计算机历史。;-)

事实是,你的终端仿真器的工作模式¹默认情况下是如何工作的,它起源于计算机在字母数字显示器出现之前与操作员进行通信的方式 - 它们会使用行打印机打印响应。现在想象一下:行打印机的工作方式是这样的:它会在一卷纸上打印发送给它的任何内容。输出的内容总是在旧内容的下方。

当字母数字显示器(屏幕)出现时,它们自然而然地继续支持这种模式:要输出的行文本在屏幕底部呈现,上面的文本向上滚动。当你在终端仿真器的命令行中工作时(例如运行在仿真器窗口中的bash),你一直看到的就是这种模式。终端的默认工作模式称为"规范模式"或"cooked模式"。

然后出现了更先进的显示器,可以更改屏幕上的单个位置 - 通过列和行号进行标识。这改变了信息输出的范式:所谓的"全屏应用程序"的概念诞生了。它们的典型示例是Vim和Emacs等文本编辑器。

为了支持全屏文本输出,终端(和终端仿真器)通过实现某些扩展来进行了适应。

全屏应用程序首先请求终端切换到另一种称为"原始模式"的模式,在该模式下,终端将用户输入的大部分内容直接发送给运行在终端上的程序。程序处理此输入并命令终端在何处以及如何绘制。你可以阅读这篇很好的总结来了解这两种模式之间的区别。

正如你现在可能怀疑的那样,为了能够将某个信息块保持在终端文本屏幕的特定固定位置,你希望你的程序是一个全屏程序,并使用终端的原始模式和其特殊命令来直接修改特定字符单元的文本。

现在的问题是,不同的终端(和终端仿真器)有不同的命令来实现这一点,因此存在一些库来将程序与这些复杂的细节隔离开来。它们依赖于特殊的"终端信息数据库"来确定终端具有哪些功能以及如何使其执行程序的要求。有关更多背景信息,请参阅man terminfo

最广为人知的这种库(用C编写)称为ncurses,并且存在着原生的Go解决方案,其中最明显的一个是github.com/nsf/termbox-go

github.com/gizak/termui使用了termbox-go,但对你来说,直接使用后者可能就足够了。


¹ 很有可能你现在不是坐在连接到UNIX®机器的真实硬件终端,而是在像GNOME Terminal、xterm或Termial.app等GUI应用程序中工作。这些不是真正的"终端",而是终端仿真器 - 即,模拟硬件终端的软件部分。

英文:

With github.com/gizak/termui you're heading in the correct direction.

To understand why you can't get that

> I want the live update to be update on the main part of the terminal, while the "Enter command >" always stay at the bottom

part sorted out, a little excursion to the history of computing is due. 如何在Golang中保持终端输入始终在底部?

The thing is, the mode your teminal emulator¹ works by default originated
in how computers would communicate to the operator in the era which predated
alphanumeric displays — they would print their responses using a line printer. Now think of it: a line printer works like this: it prints whatever is sent to it on a roll of paper. What was output, was output.
The new output always appears physically below the older.

When alphanumeric displays (screens) came into existence they
naturally continued to support this mode:
the line text to be output was rendered at the bottom of the screen
with the text above it scrolled upwards.
That's what you see in your typical terminal emulator all the time when you're working in the command line of a shell (such as bash) running by the emulator window.
This, default, work mode of a terminal is called "canonical" or "cooked".

Then came more advanced displays, for which it was possible to change
individual positions on the screen — identified by their column and
row numbers.
This changed the paradigm of how the information was output: the concept
of a so-called "full-screen application" was born.
Typical examples of them are text editors such as Vim and Emacs.

To support full-screen text output, terminals (and terminal emulators)
were adapted by implementing certain extensions to their protocols.

A full-screen application first requests the terminal to switch into another
mode called "raw", in which the terminal sends most of what is input by the
user directly to the program running on the terminal.
The program handles this input and orders the terminal where and what
to draw.
You can read this good summary
of the distinction between the both modes.

As you are supposedly suspecting by now, to be able to keep some block
of information at a certain fixed place of the terminal's text screen,
you want your program to be a full-screen program and use the terminal's
raw mode and its special commands allowing you to directly modify
text at certain character cells.

Now the problem is that different terminals (and terminal emulators)
have different commands to do that, so there exist libraries to isolate
the programs from these gory details. They rely on the special "terminal
information databases" to figure out what capabilities a terminal has
and how to make it do what the program asks.
See man terminfo for more background.

The most widely known such library (written in C) is called ncurses,
and there exist native solutions for Go with supposedly the most visible
one being github.com/nsf/termbox-go.

The github.com/gizak/termui makes use of termbox-go but for you it might
suffice to use the latter directly.


¹ Chances are very high you're not sitting at
a real hardware terminal
connected to a UNIX® machine but are rather working in a GUI application
such as GNOME Terminal or xterm or Termial.app etc.
These are not "terminals" per se but are rather
terminal emulators
that is, pieces of software emulating a hardware terminal.

huangapple
  • 本文由 发表于 2017年4月11日 17:04:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/43341350.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定