Setting IRM will cause characters to be inserted, discarding anything
that goes beyond the edge.

Turn off the wrap flag when the cursor moves.

SM/RM allow more than one parameter.
This commit is contained in:
Jason Hood 2017-12-17 11:13:12 +10:00
parent 66c527a624
commit 80d9e7da78
4 changed files with 162 additions and 119 deletions

148
ANSI.c
View File

@ -152,7 +152,7 @@
remove wcstok, avoiding potential interference with the host; remove wcstok, avoiding potential interference with the host;
similarly, use a private heap instead of malloc. similarly, use a private heap instead of malloc.
v1.80, 26 October to 16 December, 2017: v1.80, 26 October to 17 December, 2017:
fix unloading; fix unloading;
revert back to (re)storing buffer cursor position; revert back to (re)storing buffer cursor position;
increase cache to five handles; increase cache to five handles;
@ -172,7 +172,8 @@
an explicit zero parameter should still default to one; an explicit zero parameter should still default to one;
restrict parameters to a maximum value of 32767; restrict parameters to a maximum value of 32767;
added tab handling; added tab handling;
added the bright SGR colors, recognised the system indices. added the bright SGR colors, recognised the system indices;
added insert mode.
*/ */
#include "ansicon.h" #include "ansicon.h"
@ -218,6 +219,7 @@ int es_argv[MAX_ARG]; // escape sequence args
TCHAR Pt_arg[MAX_PATH*2]; // text parameter for Operating System Command TCHAR Pt_arg[MAX_PATH*2]; // text parameter for Operating System Command
int Pt_len; int Pt_len;
BOOL shifted, G0_special, SaveG0; BOOL shifted, G0_special, SaveG0;
BOOL im; // insert mode?
int screen_top = -1; // initial window top when cleared int screen_top = -1; // initial window top when cleared
@ -555,7 +557,7 @@ void FlushBuffer( void )
if (nCharInBuffer <= 0) return; if (nCharInBuffer <= 0) return;
if (pState->crm) if (pState->crm && !im)
{ {
SetConsoleMode( hConOut, cache[0].mode & ~ENABLE_PROCESSED_OUTPUT ); SetConsoleMode( hConOut, cache[0].mode & ~ENABLE_PROCESSED_OUTPUT );
WriteConsole( hConOut, ChBuffer, nCharInBuffer, &nWritten, NULL ); WriteConsole( hConOut, ChBuffer, nCharInBuffer, &nWritten, NULL );
@ -566,8 +568,9 @@ void FlushBuffer( void )
HANDLE hConWrap; HANDLE hConWrap;
CONSOLE_CURSOR_INFO cci; CONSOLE_CURSOR_INFO cci;
CONSOLE_SCREEN_BUFFER_INFO csbi; CONSOLE_SCREEN_BUFFER_INFO csbi;
COORD here;
if (nCharInBuffer < 4) if (nCharInBuffer < 4 && !im)
{ {
LPWSTR b = ChBuffer; LPWSTR b = ChBuffer;
do do
@ -596,16 +599,38 @@ void FlushBuffer( void )
// Ensure the buffer is the same width (it gets created using the window // Ensure the buffer is the same width (it gets created using the window
// width) and more than one line. // width) and more than one line.
GetConsoleScreenBufferInfo( hConOut, &csbi ); GetConsoleScreenBufferInfo( hConOut, &csbi );
here = csbi.dwCursorPosition;
csbi.dwSize.Y = csbi.srWindow.Bottom - csbi.srWindow.Top + 2; csbi.dwSize.Y = csbi.srWindow.Bottom - csbi.srWindow.Top + 2;
SetConsoleScreenBufferSize( hConWrap, csbi.dwSize ); SetConsoleScreenBufferSize( hConWrap, csbi.dwSize );
// Put the cursor on the top line, in the same column. // Put the cursor on the top line, in the same column.
csbi.dwCursorPosition.Y = 0; csbi.dwCursorPosition.Y = 0;
SetConsoleCursorPosition( hConWrap, csbi.dwCursorPosition ); SetConsoleCursorPosition( hConWrap, csbi.dwCursorPosition );
if (pState->crm)
SetConsoleMode( hConWrap, ENABLE_WRAP_AT_EOL_OUTPUT );
WriteConsole( hConWrap, ChBuffer, nCharInBuffer, &nWritten, NULL ); WriteConsole( hConWrap, ChBuffer, nCharInBuffer, &nWritten, NULL );
GetConsoleScreenBufferInfo( hConWrap, &csbi ); GetConsoleScreenBufferInfo( hConWrap, &csbi );
if (csbi.dwCursorPosition.Y != 0) if (csbi.dwCursorPosition.Y != 0)
fWrapped = TRUE; fWrapped = TRUE;
CloseHandle( hConWrap ); CloseHandle( hConWrap );
if (im && !fWrapped)
{
SMALL_RECT sr, cr;
CHAR_INFO ci; // unused, but necessary
sr.Top = sr.Bottom = csbi.dwCursorPosition.Y = here.Y;
sr.Left = here.X;
sr.Right = csbi.dwSize.X - 1;
cr = sr;
cr.Left = csbi.dwCursorPosition.X;
ScrollConsoleScreenBuffer(hConOut, &sr,&cr, csbi.dwCursorPosition, &ci);
}
if (pState->crm)
{
SetConsoleMode( hConOut, cache[0].mode & ~ENABLE_PROCESSED_OUTPUT );
WriteConsole( hConOut, ChBuffer, nCharInBuffer, &nWritten, NULL );
SetConsoleMode( hConOut, cache[0].mode );
}
else
WriteConsole( hConOut, ChBuffer, nCharInBuffer, &nWritten, NULL ); WriteConsole( hConOut, ChBuffer, nCharInBuffer, &nWritten, NULL );
} }
} }
@ -747,6 +772,15 @@ void init_tabs( int size )
} }
// Set the cursor position, resetting the wrap flag.
void set_pos( SHORT x, SHORT y )
{
COORD pos = { x, y };
SetConsoleCursorPosition( hConOut, pos );
fWrapped = FALSE;
}
// ========== Print functions // ========== Print functions
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -798,14 +832,14 @@ void InterpretEscSeq( void )
{ {
if (suffix == 'h' || suffix == 'l') if (suffix == 'h' || suffix == 'l')
{ {
if (es_argc != 1) return; for (i = 0; i < es_argc; i++)
switch (es_argv[0]) switch (es_argv[i])
{ {
case 25: case 25:
GetConsoleCursorInfo( hConOut, &CursInfo ); GetConsoleCursorInfo( hConOut, &CursInfo );
CursInfo.bVisible = (suffix == 'h'); CursInfo.bVisible = (suffix == 'h');
SetConsoleCursorInfo( hConOut, &CursInfo ); SetConsoleCursorInfo( hConOut, &CursInfo );
return; break;
case 7: case 7:
mode = cache[0].mode; mode = cache[0].mode;
@ -814,11 +848,11 @@ void InterpretEscSeq( void )
else else
mode &= ~ENABLE_WRAP_AT_EOL_OUTPUT; mode &= ~ENABLE_WRAP_AT_EOL_OUTPUT;
SetConsoleMode( hConOut, mode ); SetConsoleMode( hConOut, mode );
return; break;
case 95: case 95:
pState->noclear = (suffix == 'h'); pState->noclear = (suffix == 'h');
return; break;
case 3: case 3:
{ {
@ -826,7 +860,7 @@ void InterpretEscSeq( void )
SMALL_RECT win; SMALL_RECT win;
buf.X = (suffix == 'l') ? pState->buf_width : 132; buf.X = (suffix == 'l') ? pState->buf_width : 132;
if (buf.X == 0) if (buf.X == 0)
return; break;
GetConsoleScreenBufferInfo( hConOut, &Info ); GetConsoleScreenBufferInfo( hConOut, &Info );
buf.Y = HEIGHT; buf.Y = HEIGHT;
win.Left = 0; win.Left = 0;
@ -843,8 +877,8 @@ void InterpretEscSeq( void )
win.Right = pState->win_width; win.Right = pState->win_width;
pState->buf_width = 0; pState->buf_width = 0;
} }
// The buffer cannot be smaller than the window; the window cannot // The buffer cannot be smaller than the window; the window
// be bigger than the buffer. // cannot be bigger than the buffer.
if (WIN.Right - WIN.Left > win.Right) if (WIN.Right - WIN.Left > win.Right)
{ {
SetConsoleWindowInfo( hConOut, TRUE, &win ); SetConsoleWindowInfo( hConOut, TRUE, &win );
@ -860,10 +894,8 @@ void InterpretEscSeq( void )
if (pState->noclear && if (pState->noclear &&
(suffix2 == '+' || (TOP == screen_top && CUR.Y != LAST))) (suffix2 == '+' || (TOP == screen_top && CUR.Y != LAST)))
{ {
CUR.X = LEFT; set_pos( LEFT, (SHORT)(suffix2 == '+' ? 0 : TOP) );
CUR.Y = (suffix2 == '+') ? 0 : TOP; break;
SetConsoleCursorPosition( hConOut, CUR );
return;
} }
prefix2 = 0; prefix2 = 0;
es_argv[0] = 2; es_argv[0] = 2;
@ -1089,12 +1121,10 @@ void InterpretEscSeq( void )
len = (bottom - top + 1) * WIDTH; len = (bottom - top + 1) * WIDTH;
FillBlank( len, Pos ); FillBlank( len, Pos );
// Not technically correct, but perhaps expected. // Not technically correct, but perhaps expected.
SetConsoleCursorPosition( hConOut, Pos ); set_pos( Pos.X, Pos.Y );
return;
default:
return; return;
} }
return;
case 'K': case 'K':
if (es_argc > 1) return; // ESC[K == ESC[0K if (es_argc > 1) return; // ESC[K == ESC[0K
@ -1116,10 +1146,8 @@ void InterpretEscSeq( void )
Pos.Y = CUR.Y; Pos.Y = CUR.Y;
FillBlank( WIDTH, Pos ); FillBlank( WIDTH, Pos );
return; return;
default:
return;
} }
return;
case 'X': // ESC[#X Erase # characters. case 'X': // ESC[#X Erase # characters.
if (es_argc > 1) return; // ESC[X == ESC[1X if (es_argc > 1) return; // ESC[X == ESC[1X
@ -1185,8 +1213,7 @@ void InterpretEscSeq( void )
if (es_argc > 1) return; // ESC[A == ESC[1A if (es_argc > 1) return; // ESC[A == ESC[1A
Pos.Y = CUR.Y - p1; Pos.Y = CUR.Y - p1;
if (Pos.Y < top) Pos.Y = top; if (Pos.Y < top) Pos.Y = top;
Pos.X = CUR.X; set_pos( CUR.X, Pos.Y );
SetConsoleCursorPosition( hConOut, Pos );
return; return;
case 'e': // ESC[#e case 'e': // ESC[#e
@ -1194,8 +1221,7 @@ void InterpretEscSeq( void )
if (es_argc > 1) return; // ESC[B == ESC[1B if (es_argc > 1) return; // ESC[B == ESC[1B
Pos.Y = CUR.Y + p1; Pos.Y = CUR.Y + p1;
if (Pos.Y > bottom) Pos.Y = bottom; if (Pos.Y > bottom) Pos.Y = bottom;
Pos.X = CUR.X; set_pos( CUR.X, Pos.Y );
SetConsoleCursorPosition( hConOut, Pos );
return; return;
case 'a': // ESC[#a case 'a': // ESC[#a
@ -1203,8 +1229,7 @@ void InterpretEscSeq( void )
if (es_argc > 1) return; // ESC[C == ESC[1C if (es_argc > 1) return; // ESC[C == ESC[1C
Pos.X = CUR.X + p1; Pos.X = CUR.X + p1;
if (Pos.X > RIGHT) Pos.X = RIGHT; if (Pos.X > RIGHT) Pos.X = RIGHT;
Pos.Y = CUR.Y; set_pos( Pos.X, CUR.Y );
SetConsoleCursorPosition( hConOut, Pos );
return; return;
case 'j': // ESC[#j case 'j': // ESC[#j
@ -1212,24 +1237,21 @@ void InterpretEscSeq( void )
if (es_argc > 1) return; // ESC[D == ESC[1D if (es_argc > 1) return; // ESC[D == ESC[1D
Pos.X = CUR.X - p1; Pos.X = CUR.X - p1;
if (Pos.X < LEFT) Pos.X = LEFT; if (Pos.X < LEFT) Pos.X = LEFT;
Pos.Y = CUR.Y; set_pos( Pos.X, CUR.Y );
SetConsoleCursorPosition( hConOut, Pos );
return; return;
case 'E': // ESC[#E Moves cursor down # lines, column 1. case 'E': // ESC[#E Moves cursor down # lines, column 1.
if (es_argc > 1) return; // ESC[E == ESC[1E if (es_argc > 1) return; // ESC[E == ESC[1E
Pos.Y = CUR.Y + p1; Pos.Y = CUR.Y + p1;
if (Pos.Y > bottom) Pos.Y = bottom; if (Pos.Y > bottom) Pos.Y = bottom;
Pos.X = LEFT; set_pos( LEFT, Pos.Y );
SetConsoleCursorPosition( hConOut, Pos );
return; return;
case 'F': // ESC[#F Moves cursor up # lines, column 1. case 'F': // ESC[#F Moves cursor up # lines, column 1.
if (es_argc > 1) return; // ESC[F == ESC[1F if (es_argc > 1) return; // ESC[F == ESC[1F
Pos.Y = CUR.Y - p1; Pos.Y = CUR.Y - p1;
if (Pos.Y < top) Pos.Y = top; if (Pos.Y < top) Pos.Y = top;
Pos.X = LEFT; set_pos( LEFT, Pos.Y );
SetConsoleCursorPosition( hConOut, Pos );
return; return;
case '`': // ESC[#` case '`': // ESC[#`
@ -1237,9 +1259,7 @@ void InterpretEscSeq( void )
if (es_argc > 1) return; // ESC[G == ESC[1G if (es_argc > 1) return; // ESC[G == ESC[1G
Pos.X = p1 - 1; Pos.X = p1 - 1;
if (Pos.X > RIGHT) Pos.X = RIGHT; if (Pos.X > RIGHT) Pos.X = RIGHT;
if (Pos.X < LEFT) Pos.X = LEFT; set_pos( Pos.X, CUR.Y );
Pos.Y = CUR.Y;
SetConsoleCursorPosition( hConOut, Pos );
return; return;
case 'd': // ESC[#d Moves cursor row #, current column. case 'd': // ESC[#d Moves cursor row #, current column.
@ -1247,19 +1267,18 @@ void InterpretEscSeq( void )
Pos.Y = top + p1 - 1; Pos.Y = top + p1 - 1;
if (Pos.Y < top) Pos.Y = top; if (Pos.Y < top) Pos.Y = top;
if (Pos.Y > bottom) Pos.Y = bottom; if (Pos.Y > bottom) Pos.Y = bottom;
SetConsoleCursorPosition( hConOut, Pos ); set_pos( CUR.X, Pos.Y );
return; return;
case 'f': // ESC[#;#f case 'f': // ESC[#;#f
case 'H': // ESC[#;#H Moves cursor to line #, column # case 'H': // ESC[#;#H Moves cursor to line #, column #
if (es_argc > 2) return; // ESC[H == ESC[1;1H ESC[#H == ESC[#;1H if (es_argc > 2) return; // ESC[H == ESC[1;1H ESC[#H == ESC[#;1H
Pos.X = p2 - 1; Pos.X = p2 - 1;
if (Pos.X < LEFT) Pos.X = LEFT;
if (Pos.X > RIGHT) Pos.X = RIGHT; if (Pos.X > RIGHT) Pos.X = RIGHT;
Pos.Y = top + p1 - 1; Pos.Y = top + p1 - 1;
if (Pos.Y < top) Pos.Y = top; if (Pos.Y < top) Pos.Y = top;
if (Pos.Y > bottom) Pos.Y = bottom; if (Pos.Y > bottom) Pos.Y = bottom;
SetConsoleCursorPosition( hConOut, Pos ); set_pos( Pos.X, Pos.Y );
return; return;
case 'g': case 'g':
@ -1279,10 +1298,8 @@ void InterpretEscSeq( void )
case 8: // ESC[8g Let console handle tabs case 8: // ESC[8g Let console handle tabs
pState->tabs = FALSE; pState->tabs = FALSE;
return; return;
default:
return;
} }
return;
case 'I': // ESC[#I Moves cursor forward # tabs case 'I': // ESC[#I Moves cursor forward # tabs
if (es_argc > 1) return; // ESC[I == ESC[1I if (es_argc > 1) return; // ESC[I == ESC[1I
@ -1295,12 +1312,12 @@ void InterpretEscSeq( void )
else else
Pos.X = (CUR.X & -8) + p1 * 8; Pos.X = (CUR.X & -8) + p1 * 8;
if (Pos.X > RIGHT) Pos.X = RIGHT; if (Pos.X > RIGHT) Pos.X = RIGHT;
// Don't use set_pos, the tabs could be discarded.
SetConsoleCursorPosition( hConOut, Pos ); SetConsoleCursorPosition( hConOut, Pos );
return; return;
case 'Z': // ESC[#Z Moves cursor back # tabs case 'Z': // ESC[#Z Moves cursor back # tabs
if (es_argc > 1) return; // ESC[Z == ESC[1Z if (es_argc > 1) return; // ESC[Z == ESC[1Z
Pos.Y = CUR.Y;
if (pState->tabs) if (pState->tabs)
{ {
Pos.X = (CUR.X < MAX_TABS) ? CUR.X : MAX_TABS; Pos.X = (CUR.X < MAX_TABS) ? CUR.X : MAX_TABS;
@ -1312,9 +1329,9 @@ void InterpretEscSeq( void )
Pos.X = CUR.X - p1 * 8; Pos.X = CUR.X - p1 * 8;
else else
Pos.X = (CUR.X & -8) - (p1 - 1) * 8; Pos.X = (CUR.X & -8) - (p1 - 1) * 8;
}
if (Pos.X < LEFT) Pos.X = LEFT; if (Pos.X < LEFT) Pos.X = LEFT;
SetConsoleCursorPosition( hConOut, Pos ); }
set_pos( Pos.X, CUR.Y );
return; return;
case 'b': // ESC[#b Repeat character case 'b': // ESC[#b Repeat character
@ -1333,7 +1350,7 @@ void InterpretEscSeq( void )
Pos = pState->SavePos; Pos = pState->SavePos;
if (Pos.X > RIGHT) Pos.X = RIGHT; if (Pos.X > RIGHT) Pos.X = RIGHT;
if (Pos.Y > LAST) Pos.Y = LAST; if (Pos.Y > LAST) Pos.Y = LAST;
SetConsoleCursorPosition( hConOut, Pos ); set_pos( Pos.X, Pos.Y );
return; return;
case 'c': // ESC[#c Device attributes case 'c': // ESC[#c Device attributes
@ -1358,10 +1375,8 @@ void InterpretEscSeq( void )
SendSequence( buf ); SendSequence( buf );
} }
return; return;
default:
return;
} }
return;
case 't': // ESC[#t Window manipulation case 't': // ESC[#t Window manipulation
if (es_argc != 1) return; if (es_argc != 1) return;
@ -1381,12 +1396,28 @@ void InterpretEscSeq( void )
return; return;
case 'h': // ESC[#h Set Mode case 'h': // ESC[#h Set Mode
if (es_argc == 1 && es_argv[0] == 3) for (i = 0; i < es_argc; i++)
switch (es_argv[i])
{
case 3:
pState->crm = TRUE; pState->crm = TRUE;
break;
case 4:
im = TRUE;
break;
}
return; return;
case 'l': // ESC[#l Reset Mode case 'l': // ESC[#l Reset Mode
return; // ESC[3l is handled during parsing for (i = 0; i < es_argc; i++)
switch (es_argv[i]) // ESC[3l is handled during parsing
{
case 4:
im = FALSE;
break;
}
return;
case '~': case '~':
if (suffix2 == ',') // ESC[#;#;#...,~ Play Sound if (suffix2 == ',') // ESC[#;#;#...,~ Play Sound
@ -1691,7 +1722,7 @@ ParseAndPrintString( HANDLE hDev,
{ {
hConOut = hDev; hConOut = hDev;
state = 1; state = 1;
shifted = G0_special = FALSE; im = shifted = G0_special = FALSE;
} }
for (i = nNumberOfBytesToWrite, s = (LPCTSTR)lpBuffer; i > 0; i--, s++) for (i = nNumberOfBytesToWrite, s = (LPCTSTR)lpBuffer; i > 0; i--, s++)
{ {
@ -1720,8 +1751,15 @@ ParseAndPrintString( HANDLE hDev,
GetConsoleScreenBufferInfo( hConOut, &Info ); GetConsoleScreenBufferInfo( hConOut, &Info );
while (++CUR.X < MAX_TABS && !pState->tab_stop[CUR.X]) ; while (++CUR.X < MAX_TABS && !pState->tab_stop[CUR.X]) ;
if (CUR.X > RIGHT) CUR.X = RIGHT; if (CUR.X > RIGHT) CUR.X = RIGHT;
// Don't use set_pos, the tab could be discarded.
SetConsoleCursorPosition( hConOut, CUR ); SetConsoleCursorPosition( hConOut, CUR );
} }
else if (im && (c == HT || c == '\r' || c == '\b' || c == '\n'))
{
FlushBuffer();
PushBuffer( (WCHAR)c );
FlushBuffer();
}
else PushBuffer( (WCHAR)c ); else PushBuffer( (WCHAR)c );
} }
else if (state == 2) else if (state == 2)
@ -1793,7 +1831,7 @@ ParseAndPrintString( HANDLE hDev,
CUR = pState->SavePos; CUR = pState->SavePos;
if (CUR.X > RIGHT) CUR.X = RIGHT; if (CUR.X > RIGHT) CUR.X = RIGHT;
if (CUR.Y > LAST) CUR.Y = LAST; if (CUR.Y > LAST) CUR.Y = LAST;
SetConsoleCursorPosition( hConOut, CUR ); set_pos( CUR.X, CUR.Y );
if (pState->SaveAttr != 0) // assume 0 means not saved if (pState->SaveAttr != 0) // assume 0 means not saved
{ {
pState->sgr = pState->SaveSgr; pState->sgr = pState->SaveSgr;

View File

@ -91,7 +91,7 @@
use -pu to unload from the parent. use -pu to unload from the parent.
*/ */
#define PDATE L"16 December, 2017" #define PDATE L"17 December, 2017"
#include "ansicon.h" #include "ansicon.h"
#include "version.h" #include "version.h"

View File

@ -202,6 +202,8 @@ Sequences Recognised
\e[#@ ICH Insert Character \e[#@ ICH Insert Character
\e[#L IL Insert Line \e[#L IL Insert Line
\eD IND Index \eD IND Index
\e[4h IRM Insertion Replacement Mode (insert)
\e[4l IRM Insertion Replacement Mode (replace)
SI LS0 Locking-shift Zero (see below) SI LS0 Locking-shift Zero (see below)
SO LS1 Locking-shift One SO LS1 Locking-shift One
\eE NEL Next Line \eE NEL Next Line
@ -310,7 +312,7 @@ Version History
Legend: + added, - bug-fixed, * changed. Legend: + added, - bug-fixed, * changed.
1.80 - 16 December, 2017: 1.80 - 17 December, 2017:
- fix unloading; - fix unloading;
- fix -e et al when redirecting to CON; - fix -e et al when redirecting to CON;
- hook CreateFile and CreateConsoleScreenBuffer to force read/write access - hook CreateFile and CreateConsoleScreenBuffer to force read/write access
@ -332,7 +334,8 @@ Version History
+ added -pu to unload from the parent; + added -pu to unload from the parent;
+ added IND, NEL, RI, DA, DECCOLM, DECNCSM, DECSC & DECRC; + added IND, NEL, RI, DA, DECCOLM, DECNCSM, DECSC & DECRC;
+ added SCS, but only for special/ASCII (same as Win10); + added SCS, but only for special/ASCII (same as Win10);
+ added tab handling (HT, HTS, TBC & DECST8C). + added tab handling (HT, HTS, TBC & DECST8C);
+ added IRM.
1.72 - 24 December, 2015: 1.72 - 24 December, 2015:
- handle STD_OUTPUT_HANDLE & STD_ERROR_HANDLE in WriteFile; - handle STD_OUTPUT_HANDLE & STD_ERROR_HANDLE in WriteFile;
@ -561,4 +564,4 @@ Distribution
============================== ==============================
Jason Hood, 16 December, 2017. Jason Hood, 17 December, 2017.

View File

@ -157,6 +157,8 @@ H set tab stop
[3h display control characters (LF is also performed) [3h display control characters (LF is also performed)
[3l perform control functions (the only such recognised during above) [3l perform control functions (the only such recognised during above)
[4h insert characters
[4l replace characters
[?3h set 132 columns [?3h set 132 columns
[?3l restore original columns [?3l restore original columns
[?7h wrap lines at screen edge [?7h wrap lines at screen edge