mirror of
https://github.com/vim/vim.git
synced 2025-09-26 04:04:07 -04:00
patch 7.4.851
Problem: Saving and restoring the console buffer does not work properly. Solution: Instead of ReadConsoleOutputA/WriteConsoleOutputA use CreateConsoleScreenBuffer and SetConsoleActiveScreenBuffer. (Ken Takata)
This commit is contained in:
189
src/os_win32.c
189
src/os_win32.c
@@ -2192,8 +2192,7 @@ typedef struct ConsoleBufferStruct
|
|||||||
{
|
{
|
||||||
BOOL IsValid;
|
BOOL IsValid;
|
||||||
CONSOLE_SCREEN_BUFFER_INFO Info;
|
CONSOLE_SCREEN_BUFFER_INFO Info;
|
||||||
PCHAR_INFO Buffer;
|
HANDLE handle;
|
||||||
COORD BufferSize;
|
|
||||||
} ConsoleBuffer;
|
} ConsoleBuffer;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2210,77 +2209,81 @@ typedef struct ConsoleBufferStruct
|
|||||||
SaveConsoleBuffer(
|
SaveConsoleBuffer(
|
||||||
ConsoleBuffer *cb)
|
ConsoleBuffer *cb)
|
||||||
{
|
{
|
||||||
DWORD NumCells;
|
|
||||||
COORD BufferCoord;
|
|
||||||
SMALL_RECT ReadRegion;
|
|
||||||
WORD Y, Y_incr;
|
|
||||||
|
|
||||||
if (cb == NULL)
|
if (cb == NULL)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (!GetConsoleScreenBufferInfo(g_hConOut, &cb->Info))
|
if (!GetConsoleScreenBufferInfo(cb->handle, &cb->Info))
|
||||||
{
|
{
|
||||||
cb->IsValid = FALSE;
|
cb->IsValid = FALSE;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
cb->IsValid = TRUE;
|
cb->IsValid = TRUE;
|
||||||
|
|
||||||
/*
|
return TRUE;
|
||||||
* Allocate a buffer large enough to hold the entire console screen
|
|
||||||
* buffer. If this ConsoleBuffer structure has already been initialized
|
|
||||||
* with a buffer of the correct size, then just use that one.
|
|
||||||
*/
|
|
||||||
if (!cb->IsValid || cb->Buffer == NULL ||
|
|
||||||
cb->BufferSize.X != cb->Info.dwSize.X ||
|
|
||||||
cb->BufferSize.Y != cb->Info.dwSize.Y)
|
|
||||||
{
|
|
||||||
cb->BufferSize.X = cb->Info.dwSize.X;
|
|
||||||
cb->BufferSize.Y = cb->Info.dwSize.Y;
|
|
||||||
NumCells = cb->BufferSize.X * cb->BufferSize.Y;
|
|
||||||
vim_free(cb->Buffer);
|
|
||||||
cb->Buffer = (PCHAR_INFO)alloc(NumCells * sizeof(CHAR_INFO));
|
|
||||||
if (cb->Buffer == NULL)
|
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We will now copy the console screen buffer into our buffer.
|
* CopyOldConsoleBuffer()
|
||||||
* ReadConsoleOutput() seems to be limited as far as how much you
|
* Description:
|
||||||
* can read at a time. Empirically, this number seems to be about
|
* Copies the old console buffer contents to the current console buffer.
|
||||||
* 12000 cells (rows * columns). Start at position (0, 0) and copy
|
* This is used when 'restorescreen' is off.
|
||||||
* in chunks until it is all copied. The chunks will all have the
|
* Returns:
|
||||||
* same horizontal characteristics, so initialize them now. The
|
* TRUE on success
|
||||||
* height of each chunk will be (12000 / width).
|
|
||||||
*/
|
*/
|
||||||
BufferCoord.X = 0;
|
static BOOL
|
||||||
ReadRegion.Left = 0;
|
CopyOldConsoleBuffer(
|
||||||
ReadRegion.Right = cb->Info.dwSize.X - 1;
|
ConsoleBuffer *cb,
|
||||||
Y_incr = 12000 / cb->Info.dwSize.X;
|
HANDLE hConOld)
|
||||||
for (Y = 0; Y < cb->BufferSize.Y; Y += Y_incr)
|
|
||||||
{
|
{
|
||||||
|
COORD BufferCoord;
|
||||||
|
COORD BufferSize;
|
||||||
|
PCHAR_INFO Buffer;
|
||||||
|
DWORD NumCells;
|
||||||
|
SMALL_RECT ReadRegion;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read into position (0, Y) in our buffer.
|
* Before copying the buffer contents, clear the current buffer, and
|
||||||
|
* restore the window information. Doing this now prevents old buffer
|
||||||
|
* contents from "flashing" onto the screen.
|
||||||
*/
|
*/
|
||||||
BufferCoord.Y = Y;
|
ClearConsoleBuffer(cb->Info.wAttributes);
|
||||||
/*
|
|
||||||
* Read the region whose top left corner is (0, Y) and whose bottom
|
/* We only need to copy the window area, not whole buffer. */
|
||||||
* right corner is (width - 1, Y + Y_incr - 1). This should define
|
BufferSize.X = cb->Info.srWindow.Right - cb->Info.srWindow.Left + 1;
|
||||||
* a region of size width by Y_incr. Don't worry if this region is
|
BufferSize.Y = cb->Info.srWindow.Bottom - cb->Info.srWindow.Top + 1;
|
||||||
* too large for the remaining buffer; it will be cropped.
|
ReadRegion.Left = 0;
|
||||||
*/
|
ReadRegion.Right = BufferSize.X - 1;
|
||||||
ReadRegion.Top = Y;
|
ReadRegion.Top = 0;
|
||||||
ReadRegion.Bottom = Y + Y_incr - 1;
|
ReadRegion.Bottom = BufferSize.Y - 1;
|
||||||
if (!ReadConsoleOutput(g_hConOut, /* output handle */
|
|
||||||
cb->Buffer, /* our buffer */
|
NumCells = BufferSize.X * BufferSize.Y;
|
||||||
cb->BufferSize, /* dimensions of our buffer */
|
Buffer = (PCHAR_INFO)alloc(NumCells * sizeof(CHAR_INFO));
|
||||||
|
if (Buffer == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
BufferCoord.X = 0;
|
||||||
|
BufferCoord.Y = 0;
|
||||||
|
|
||||||
|
if (!ReadConsoleOutputW(hConOld, /* output handle */
|
||||||
|
Buffer, /* our buffer */
|
||||||
|
BufferSize, /* dimensions of our buffer */
|
||||||
BufferCoord, /* offset in our buffer */
|
BufferCoord, /* offset in our buffer */
|
||||||
&ReadRegion)) /* region to save */
|
&ReadRegion)) /* region to save */
|
||||||
{
|
{
|
||||||
vim_free(cb->Buffer);
|
vim_free(Buffer);
|
||||||
cb->Buffer = NULL;
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
if (!WriteConsoleOutputW(g_hConOut, /* output handle */
|
||||||
|
Buffer, /* our buffer */
|
||||||
|
BufferSize, /* dimensions of our buffer */
|
||||||
|
BufferCoord, /* offset in our buffer */
|
||||||
|
&ReadRegion)) /* region to restore */
|
||||||
|
{
|
||||||
|
vim_free(Buffer);
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
vim_free(Buffer);
|
||||||
|
SetConsoleWindowInfo(g_hConOut, TRUE, &ReadRegion);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@@ -2299,67 +2302,20 @@ RestoreConsoleBuffer(
|
|||||||
ConsoleBuffer *cb,
|
ConsoleBuffer *cb,
|
||||||
BOOL RestoreScreen)
|
BOOL RestoreScreen)
|
||||||
{
|
{
|
||||||
COORD BufferCoord;
|
HANDLE hConOld;
|
||||||
SMALL_RECT WriteRegion;
|
|
||||||
|
|
||||||
if (cb == NULL || !cb->IsValid)
|
if (cb == NULL || !cb->IsValid)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
/*
|
hConOld = g_hConOut;
|
||||||
* Before restoring the buffer contents, clear the current buffer, and
|
g_hConOut = cb->handle;
|
||||||
* restore the cursor position and window information. Doing this now
|
if (!RestoreScreen && exiting)
|
||||||
* prevents old buffer contents from "flashing" onto the screen.
|
CopyOldConsoleBuffer(cb, hConOld);
|
||||||
*/
|
SetConsoleActiveScreenBuffer(g_hConOut);
|
||||||
if (RestoreScreen)
|
|
||||||
ClearConsoleBuffer(cb->Info.wAttributes);
|
|
||||||
|
|
||||||
FitConsoleWindow(cb->Info.dwSize, TRUE);
|
|
||||||
if (!SetConsoleScreenBufferSize(g_hConOut, cb->Info.dwSize))
|
|
||||||
return FALSE;
|
|
||||||
if (!SetConsoleTextAttribute(g_hConOut, cb->Info.wAttributes))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
if (!RestoreScreen)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* No need to restore the screen buffer contents, so we're done.
|
|
||||||
*/
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!SetConsoleCursorPosition(g_hConOut, cb->Info.dwCursorPosition))
|
|
||||||
return FALSE;
|
|
||||||
if (!SetConsoleWindowInfo(g_hConOut, TRUE, &cb->Info.srWindow))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Restore the screen buffer contents.
|
|
||||||
*/
|
|
||||||
if (cb->Buffer != NULL)
|
|
||||||
{
|
|
||||||
BufferCoord.X = 0;
|
|
||||||
BufferCoord.Y = 0;
|
|
||||||
WriteRegion.Left = 0;
|
|
||||||
WriteRegion.Top = 0;
|
|
||||||
WriteRegion.Right = cb->Info.dwSize.X - 1;
|
|
||||||
WriteRegion.Bottom = cb->Info.dwSize.Y - 1;
|
|
||||||
if (!WriteConsoleOutput(g_hConOut, /* output handle */
|
|
||||||
cb->Buffer, /* our buffer */
|
|
||||||
cb->BufferSize, /* dimensions of our buffer */
|
|
||||||
BufferCoord, /* offset in our buffer */
|
|
||||||
&WriteRegion)) /* region to restore */
|
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define FEAT_RESTORE_ORIG_SCREEN
|
|
||||||
#ifdef FEAT_RESTORE_ORIG_SCREEN
|
|
||||||
static ConsoleBuffer g_cbOrig = { 0 };
|
|
||||||
#endif
|
|
||||||
static ConsoleBuffer g_cbNonTermcap = { 0 };
|
static ConsoleBuffer g_cbNonTermcap = { 0 };
|
||||||
static ConsoleBuffer g_cbTermcap = { 0 };
|
static ConsoleBuffer g_cbTermcap = { 0 };
|
||||||
|
|
||||||
@@ -2498,9 +2454,6 @@ static DWORD g_cmodeout = 0;
|
|||||||
void
|
void
|
||||||
mch_init(void)
|
mch_init(void)
|
||||||
{
|
{
|
||||||
#ifndef FEAT_RESTORE_ORIG_SCREEN
|
|
||||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
|
||||||
#endif
|
|
||||||
#ifndef __MINGW32__
|
#ifndef __MINGW32__
|
||||||
extern int _fmode;
|
extern int _fmode;
|
||||||
#endif
|
#endif
|
||||||
@@ -2521,16 +2474,14 @@ mch_init(void)
|
|||||||
else
|
else
|
||||||
create_conin();
|
create_conin();
|
||||||
g_hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
g_hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
g_cbNonTermcap.handle = g_hConOut;
|
||||||
|
g_cbTermcap.handle = CreateConsoleScreenBuffer(
|
||||||
|
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
|
NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
|
||||||
|
|
||||||
#ifdef FEAT_RESTORE_ORIG_SCREEN
|
|
||||||
/* Save the initial console buffer for later restoration */
|
|
||||||
SaveConsoleBuffer(&g_cbOrig);
|
|
||||||
g_attrCurrent = g_attrDefault = g_cbOrig.Info.wAttributes;
|
|
||||||
#else
|
|
||||||
/* Get current text attributes */
|
/* Get current text attributes */
|
||||||
GetConsoleScreenBufferInfo(g_hConOut, &csbi);
|
SaveConsoleBuffer(&g_cbNonTermcap);
|
||||||
g_attrCurrent = g_attrDefault = csbi.wAttributes;
|
g_attrCurrent = g_attrDefault = g_cbNonTermcap.Info.wAttributes;
|
||||||
#endif
|
|
||||||
if (cterm_normal_fg_color == 0)
|
if (cterm_normal_fg_color == 0)
|
||||||
cterm_normal_fg_color = (g_attrCurrent & 0xf) + 1;
|
cterm_normal_fg_color = (g_attrCurrent & 0xf) + 1;
|
||||||
if (cterm_normal_bg_color == 0)
|
if (cterm_normal_bg_color == 0)
|
||||||
@@ -2630,6 +2581,8 @@ mch_exit(int r)
|
|||||||
SetConsoleMode(g_hConIn, g_cmodein);
|
SetConsoleMode(g_hConIn, g_cmodein);
|
||||||
SetConsoleMode(g_hConOut, g_cmodeout);
|
SetConsoleMode(g_hConOut, g_cmodeout);
|
||||||
|
|
||||||
|
CloseHandle(g_cbTermcap.handle);
|
||||||
|
|
||||||
#ifdef DYNAMIC_GETTEXT
|
#ifdef DYNAMIC_GETTEXT
|
||||||
dyn_libintl_end();
|
dyn_libintl_end();
|
||||||
#endif
|
#endif
|
||||||
@@ -5002,6 +4955,8 @@ termcap_mode_start(void)
|
|||||||
* screen buffer, and resize the buffer to match the current window
|
* screen buffer, and resize the buffer to match the current window
|
||||||
* size. We will use this as the size of our editing environment.
|
* size. We will use this as the size of our editing environment.
|
||||||
*/
|
*/
|
||||||
|
g_hConOut = g_cbTermcap.handle;
|
||||||
|
SetConsoleActiveScreenBuffer(g_hConOut);
|
||||||
ClearConsoleBuffer(g_attrCurrent);
|
ClearConsoleBuffer(g_attrCurrent);
|
||||||
ResizeConBufAndWindow(g_hConOut, Columns, Rows);
|
ResizeConBufAndWindow(g_hConOut, Columns, Rows);
|
||||||
}
|
}
|
||||||
@@ -5045,11 +5000,7 @@ termcap_mode_end(void)
|
|||||||
cmodein &= ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT);
|
cmodein &= ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT);
|
||||||
SetConsoleMode(g_hConIn, cmodein);
|
SetConsoleMode(g_hConIn, cmodein);
|
||||||
|
|
||||||
#ifdef FEAT_RESTORE_ORIG_SCREEN
|
|
||||||
cb = exiting ? &g_cbOrig : &g_cbNonTermcap;
|
|
||||||
#else
|
|
||||||
cb = &g_cbNonTermcap;
|
cb = &g_cbNonTermcap;
|
||||||
#endif
|
|
||||||
RestoreConsoleBuffer(cb, p_rs);
|
RestoreConsoleBuffer(cb, p_rs);
|
||||||
SetConsoleCursorInfo(g_hConOut, &g_cci);
|
SetConsoleCursorInfo(g_hConOut, &g_cci);
|
||||||
|
|
||||||
|
@@ -741,6 +741,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
851,
|
||||||
/**/
|
/**/
|
||||||
850,
|
850,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user