2017-04-04 31 views
0

我用這個小編輯我的項目的基礎上,我做的:https://github.com/antirez/kilo當退出終端rawmode我的內容停留在屏幕

編輯器使用的終端rawmode和使用VT100轉義序列寫道: ,但退出程序時,顯示的內容將保持顯示。 退出前... ​​

退出後... After exiting

正如你可以看到提示再次出現,但所剩下的編輯在那裏等待直到覆蓋。

// Low level terminal handling 
void disable_raw_mode(int fd) 
{ 
     // dont bother checking the return value as its too late 
     if (Editor.rawmode) { 
       tcsetattr(fd, TCSAFLUSH, &orig_termios); 
       Editor.rawmode = 0; 
     } 
} 


void editor_at_exit(void) 
{ 
     disable_raw_mode(STDIN_FILENO); 
} 

int enable_raw_mode(int fd) 
{ 
     struct termios raw; 

     if(Editor.rawmode) return 0; //already enabled 
     if(!isatty(STDIN_FILENO)) goto fatal; 
     atexit(editor_at_exit); 
     if(tcgetattr(fd, &orig_termios) == -1) goto fatal; 

     raw = orig_termios; // modify the original mode 
     /* input modes: no break, no CR to NL, no parity check, no strip char, 
     *  * no start/stop output control. */ 
     raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); 

     // output modes - disable post processing 
     raw.c_oflag &= ~(OPOST); 

     //control modes - set 8 bit chars 
     raw.c_cflag |= (CS8); 

     //local modes, choing off, canonical off, no extended functions, no signal chars (, etc) 
     raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); 

     //control chars - set return condition: min number of bytes and a timer 
     raw.c_cc[VMIN] = 0; // return each byte, or zero for a timeout 
     raw.c_cc[VTIME] = 1; //100ms timeout 

     //put terminal in raw mode after flushing 
     if(tcsetattr(fd, TCSAFLUSH, &raw) < 0) goto fatal; 
     Editor.rawmode = 1; 
     return 0; 

fatal: 
     errno = ENOTTY; 
     return -1; 
} 

據我瞭解,當程序退出atexit(editor_at_exit)函數被調用,並在該函數的原始模式被禁用。我錯過了將終端打掃回到編輯器打開之前的狀態。我不是隻看整個終端的clear

+0

這也許https://www.gnu.org/software/screen /manual/screen.html#Copy –

+0

除了清除屏幕外,還有什麼不重新設置?你正在用原始終端設置做一個'tcsetattr' - 這是行不通的嗎? –

+0

@ChrisTurner讓編輯器的全屏模式在退出後保持不變,即使我使用'tcsetattr'和'&orig_termios'。 –

回答

5

你正在尋找的功能被稱爲「備用屏幕緩衝區」,它起源於xterm但現在大多數的終端支持。

備用屏幕緩衝區旨在爲全屏終端程序提供此功能。在正常操作中,輸出被添加到回滾緩衝區(並且大多數終端可以讓用戶回滾到前一行)。切換到備用屏幕緩衝區時,回滾緩衝區保持獨立,並且備用屏幕緩衝區輸出不會添加到回滾緩衝區。從備用屏幕緩衝區返回時,恢復原始的回滾緩衝區狀態。這就是nano使用的全屏應用程序。

要切換到備用屏幕緩衝器,我建議寫(該C字符串)
      "\033[?1049h\033[2J\033[H"(15個字符)
到終端。如果終端仿真程序支持備用屏幕緩衝區,則更改爲該屏幕緩衝區,將其清除並將光標移動到左上角。如果終端仿真器不支持它,這將清除屏幕並將光標移動到左上角。

要從備用屏幕緩衝區返回,我建議寫(該C字符串)
      "\033[2J\033[H\033[?1049l"(15個字符)
到終端。如果終端仿真程序支持備用屏幕緩衝區,則首先清除備用屏幕緩衝區,然後返回到原始的回滾緩衝區(例如nano)。如果終端仿真器不支持它,這將清除屏幕並將光標移動到左上角。

我推薦該對("\033[?1049h\033[2J\033[H""\033[2J\033[H\033[?1049l"),因爲它在一個合理的方式工作,無論終端仿真器是否支持備用屏幕緩衝或沒有,不離開全屏應用程序狀態可見之後。

如果標準輸入是一個終端,我也推薦使用例如,因爲標準C I/O函數可能無法寫入標準輸入(畢竟僅用於只讀),所以要將字符串寫入終端。上述功能非常小心,忽略了信號傳輸(如果標準輸入是非阻塞的,甚至在需要時甚至忙碌循環),甚至保持完整的errno;它也是異步信號安全的,這意味着它可以安全地用於信號處理程序(儘管我建議不要改變終端緩衝模式或信號處理程序中的設置,因爲這樣做會很複雜,無法正確執行)。

(業務方案的代碼可能有一個合適的低級別的I/O功能已經實現,但是一個沒有在問題中。)

+0

你會建議保留我現有的'enable_raw_mode'和'disable_raw_mode',還是可以完全替換掉你剛纔寫的兩個轉義序列? –

+0

@CaseyWilliams:我會保留你現有的函數,在''enable_raw_mode()''的末尾/附近添加相當於'write_term(「\ 033 [?1049h \ 033 [2J \ 033 [H」);和'write_term(「\ 033 [2J \ 033 [H \ 033 [?1049l」);''disable_raw_mode()''中的if子句內的'disable_raw_mode()'。 –

+1

@CaseyWilliams:查看github源代碼,你應該將'isatty(STDIN_FILENO)'改爲'isatty(fd)',並添加'write(fd,「\ 033 [?1049h \ 033 [2J \ 033 [H」,15 );'in/to'enable_raw_mode()';並在'disable_raw_mode()'的if子句中添加'write(fd,「\ 033 [2J \ 033 [H \ 033 [?1049l」,15);'以保持「千」編碼風格。 –