注:機翻,未校。
vim terminal “raw” mode
Vim 終端 “raw” 模式
1. 原始模式與已處理模式的區別
We know vim puts the terminal in “raw” mode where it receives keystrokes as they are typed, opposed to “cooked” mode where the command is not processed fully unless the end-user enters it in the terminal.
我們知道,vim 會將終端置于“原始”模式,在這種模式下,終端會即時接收按鍵輸入,與“已處理”模式不同,在“已處理”模式下,命令只有在終端中輸入后才會被完全處理。
2. 模式切換的機制
How does the shell distinguish when to go into either mode? How does this switch happen? Is there a mode in between “raw” and “cooked” mode?
那么,shell 是如何區分何時進入這兩種模式的呢?這種切換是如何發生的?在“原始”模式和“已處理”模式之間是否存在一種中間模式?
To clarify, any process that has access to a terminal can change that terminal’s settings, simply by calling tcsetattr() with the appropriate attributes (the same call used by the termstate_ functions in cush).
需要明確的是,任何能夠訪問終端的進程都可以通過調用 tcsetattr() 并設置適當的屬性來更改該終端的設置(cush 中的 termstate_ 函數也使用了相同的調用)。
vim is an example of a process that does that. Raw mode is also entered by the readline() function cush (and bash) uses. That’s why, for instance, Ctrl-A and Ctrl-E work and many other readline shortcuts. When readline() returns, the terminal is set back into whatever state it was in before the call, so we don’t notice. If we had implemented our shell with, say, scanf() and printf() only, we wouldn’t have put the terminal into the raw state, so a shell could be implemented without raw mode, albeit with less user comfort.
vim 是一個會這樣做的進程的例子。cush(以及 bash)使用的 readline() 函數也會進入原始模式。這就是為什么,例如,Ctrl-A 和 Ctrl-E 以及許多其他 readline 快捷鍵可以正常工作。當 readline() 返回時,終端會恢復到調用之前的狀態,所以我們察覺不到。如果我們只用 scanf() 和 printf() 來實現我們的 shell,我們就不會將終端置于原始狀態,因此雖然可以實現一個沒有原始模式的 shell,但用戶體驗會差很多。
3. POSIX 中的原始模式定義
As to what “raw” mode is and how to enter it. It turns out that “raw” vs “cooked” mode isn’t actually the official term (anymore). The terms come from Unix System 7. In POSIX, what’s commonly called “raw” mode is a combination of switches. tcsetattr(3) describes it as:
關于“原始”模式是什么以及如何進入它的問題。事實證明,“原始”模式與“已處理”模式并不是官方術語(至少不再是)。這些術語來源于 Unix System 7。在 POSIX 中,通常所說的“原始”模式實際上是一組組合開關。tcsetattr(3) 對其描述如下:
3.1 原始模式的設置
Raw mode
原始模式
cfmakeraw() sets the terminal to something like the “raw” mode of the old Version 7 terminal driver: input is available character by character, echoing is disabled, and all special processing of terminal input and output characters is disabled. The terminal attributes are set as follows:
cfmakeraw() 將終端設置為類似于舊版 Version 7 終端驅動程序中的“原始”模式:輸入是逐字符可用的,回顯被禁用,并且終端輸入和輸出字符的所有特殊處理都被禁用。終端屬性被設置如下:
termios_p->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP| INLCR | IGNCR | ICRNL | IXON);
termios_p->c_oflag &= ~OPOST;
termios_p->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
termios_p->c_cflag &= ~(CSIZE | PARENB);
termios_p->c_cflag |= CS8;
You can look up what all these attributes mean, but the key attribute here is ICANON, and that’s how POSIX refers to line-by-line vs key-by-key processing mode, as “canonical” (line-by-line) and “non-canonical” mode.
您可以查閱這些屬性的具體含義,但其中的關鍵屬性是 ICANON,POSIX 就是通過它來區分逐行處理模式與逐鍵處理模式的,分別稱為“規范”(逐行)模式和“非規范”模式。
4. 實踐原始模式
If you want to try out raw mode yourself, here’s a short program:
如果你想自己嘗試原始模式,這里有一個簡短的程序:
4.1 示例代碼
// raw.c
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>int
main()
{int terminal_fd = open(ctermid(NULL), O_RDWR);assert (terminal_fd != -1);struct termios tty_state;int rc = tcgetattr(terminal_fd, &tty_state);struct termios saved_tty_state = tty_state;assert (rc == 0);tty_state.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP| INLCR | IGNCR | ICRNL | IXON);tty_state.c_oflag &= ~OPOST;tty_state.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);tty_state.c_cflag &= ~(CSIZE | PARENB);tty_state.c_cflag |= CS8;printf("press ctrl-d to exit\n");rc = tcsetattr(terminal_fd, TCSANOW, &tty_state);assert (rc == 0);char c; while (read(0, &c, 1) == 1 && c != 0x4)write(1, &c, 1);// restore sane state on exitrc = tcsetattr(terminal_fd, TCSANOW, &saved_tty_state);assert (rc == 0);
}
4.2 編譯與運行
Compile with gcc -o raw raw.c and then you can start it with ./raw. Everything input is echoed back. Ctrl-C and Ctrl-Z don’t work anymore. If you type Enter it goes to the beginning of the line (type Ctrl-J to go to the next line). Type Ctrl-D (0x4) to exit.
使用 gcc -o raw raw.c 編譯該程序,然后可以通過 ./raw 啟動它。輸入的所有內容都會被回顯。Ctrl-C 和 Ctrl-Z 不再起作用。如果你按下回車鍵,光標會回到行首(按下 Ctrl-J 可以移到下一行)。按下 Ctrl-D(0x4)退出。
5. 原始模式與已處理模式的應用
The program above demonstrates how to set a terminal into raw mode and restore its original state upon exit. It reads input character by character and echoes them back to the terminal. This behavior is typical of raw mode, where the terminal processes input and output at the character level without any special handling of control characters like Ctrl-C or Ctrl-Z.
上述程序演示了如何將終端設置為原始模式,并在退出時恢復其原始狀態。它逐字符讀取輸入并將它們回顯到終端。這種行為是原始模式的典型特征,在這種模式下,終端會在字符級別處理輸入和輸出,而不會對像 Ctrl-C 或 Ctrl-Z 這樣的控制字符進行特殊處理。
This is particularly useful for applications like text editors (e.g., vim) or interactive shells that require fine-grained control over user input and terminal output. By disabling canonical processing (ICANON) and other terminal attributes, these applications can implement their own input handling mechanisms, such as key bindings and command-line editing features.
這對于像文本編輯器(例如 vim)或交互式 shell 這樣的應用程序特別有用,因為它們需要對用戶輸入和終端輸出進行精細控制。通過禁用規范處理(ICANON)和其他終端屬性,這些應用程序可以實現自己的輸入處理機制,例如按鍵綁定和命令行編輯功能。
In contrast, “cooked” mode (or canonical mode) is the default mode for most terminal applications. In this mode, the terminal buffers input until a newline character is received, allowing for line editing and processing of special control characters. This mode is more user-friendly for command-line interfaces where users expect to be able to edit their input before executing a command.
相比之下,“已處理”模式(或規范模式)是大多數終端應用程序的默認模式。在這種模式下,終端會將輸入緩沖起來,直到接收到換行符,從而允許進行行編輯和處理特殊控制字符。在這種模式下,用戶可以在執行命令之前編輯輸入,因此對于命令行界面來說,這種模式更加用戶友好。
6. 總結
To summarize, the distinction between raw and cooked modes lies in how the terminal handles input and output. Raw mode provides direct, character-by-character access, while cooked mode processes input line by line and interprets control characters. The ability to switch between these modes allows applications to tailor their behavior to the specific needs of the user interface they are implementing.
總之,原始模式和已處理模式的區別在于終端如何處理輸入和輸出。原始模式提供直接的逐字符訪問,而已處理模式逐行處理輸入并解釋控制字符。能夠在這些模式之間切換,使得應用程序可以根據它們所實現的用戶界面的具體需求來調整行為。
【Linux】vim 三種模式的切換、常用命令總結
冰冷的希望于 2023-08-25 23:04:37 發布
vim 是一個非常強大而且常用的 Linux 文本工具。
1. 模式
vim 主要有三種模式,分別是命令模式、輸入模式、末行模式,三者切換關系如下:
默認是命令模式,按 i
、a
或 o
進入輸入模式,再按 ESC
返回到命令模式。在命令模式輸入 :
切換到末行模式,再按 ESC
又返回到命令模式。輸入模式和末行模式之間不能直接切換,只能通過命令模式切換。
2. 命令模式
命令 | 說明 |
---|---|
x 、X | x 是刪除下一個字符,X 是刪除上一個字符 |
數字 + x | 刪除指定數量的字符,例如 10x 表示刪除 10 個字符 |
dd | 剪切(刪除)光標所在行 |
數字 + dd | 刪除指定數量的行,例如 20dd 表示刪除 20 行 |
yy | 復制光標所在行 |
數字 + yy | 復制指定數量的行,例如 20yy 表示復制 20 行 |
p 、P | p 是粘貼到下一行,P 是粘貼到上一行 |
u | 撤銷 |
Ctrl+r | 反撤銷 |
. (小數點) | 重復上一個動作 |
gg 、G | gg 是回到第一行,G 是回到最后一行 |
數字 + G | 跳轉到指定行,例如 20G 表示跳轉到第 20 行 |
y1G 、yG | y1G 是復制當前行前面的所有數據,yG 是復制當前行之后的全部數據 |
d1G 、dG | d1G 是刪除當前行前面的所有數據,dG 是刪除當前行之后的全部數據 |
v 、V 、Ctrl+v | v 是光標起始和結束之間的文本會被選中,V 是光標起始和結束之間的所有行被選中,Ctrl+v 是光標起始和結束之間構成的矩形區域被選中 |
3. 輸入模式
命令 | 說明 |
---|---|
i 、I | i 是從光標所在位置開始輸入,I 是從光標所在行第一個非空白字符開始輸入 |
a 、A | a 是從光標所在的下一個字符開始輸入,A 是從光標所在行的最后一個字符開始輸入 |
o 、O | o 是從光標所在行的下一行新的一行開始輸入,O 是從光標所在行的上一行新的一行開始輸入 |
r 、R | r 是取代光標所在的字符一次,R 是依次取代光標所在字符 |
4. 末行模式
命令 | 說明 |
---|---|
:w | 保存 |
:q | 退出 |
:wq 或 ZZ | 保存并退出 |
:q! 或 ZQ | 不保存退出 |
:set nu | 顯示行號 |
:set nonu | 隱藏行號 |
:/搜索的文本 | 搜索指定文本 |
:%s/要替換的字符/替換后的字符/g | 全局替換文本,% 表示對整個文件進行操作,g 表示全局替換 |
via:
-
CS3214 Computer Systems - Spring 2025
https://courses.cs.vt.edu/cs3214/spring2025/questions/rawmode -
How to avoid vim set terminal to raw mode when stdin is /dev/null? · Issue #15893 · vim/vim · GitHub
https://github.com/vim/vim/issues/15893 -
【Linux】vim 三種模式的切換、常用命令總結_描述一下 vim 命令的狀態,不同狀態之間的切換方式?-CSDN 博客
https://blog.csdn.net/qq_39147299/article/details/108972206