Hi,

As mattn mentioned, currently vim.exe uses
ReadConsoleOutputA/WriteConsoleOutputA to save and restore the console buffer.
But I think using CreateConsoleScreenBuffer and SetConsoleActiveScreenBuffer
is a straight forward way. We don't need to save the console buffer by ourself
if we use these APIs, because it is a matter of an OS.

I attached patches for this.
The first patch implements this and just comments out old codes.
The second patch removes the old codes.
I separated the patches because of readability.

Actually, these patches still use ReadConsoleOutputW/WriteConsoleOutputW for
'norestorescreen'. We need to copy the last Vim screen to the original console
buffer when 'restorescreen' is not set.

Note: These patches won't work on Win9x, because I used Unicode version of
Win32 APIs directly. I don't think it matters, because no one complains that
the official 7.4 binary doesn't work on Win9x. (VC2005 is the last VC which
supports Win9x, but the official binary is built by VC2008.)

Regards,
Ken Takata

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.
# HG changeset patch
# Parent  ef3a0777611909a644632527aba4f6bdc5b94208

diff --git a/src/os_win32.c b/src/os_win32.c
--- a/src/os_win32.c
+++ b/src/os_win32.c
@@ -2168,8 +2168,11 @@ typedef struct ConsoleBufferStruct
 {
     BOOL			IsValid;
     CONSOLE_SCREEN_BUFFER_INFO	Info;
+#if 0
     PCHAR_INFO			Buffer;
     COORD			BufferSize;
+#endif
+    HANDLE			handle;
 } ConsoleBuffer;
 
 /*
@@ -2186,21 +2189,24 @@ typedef struct ConsoleBufferStruct
 SaveConsoleBuffer(
     ConsoleBuffer *cb)
 {
+#if 0
     DWORD NumCells;
     COORD BufferCoord;
     SMALL_RECT ReadRegion;
     WORD Y, Y_incr;
+#endif
 
     if (cb == NULL)
 	return FALSE;
 
-    if (!GetConsoleScreenBufferInfo(g_hConOut, &cb->Info))
+    if (!GetConsoleScreenBufferInfo(cb->handle, &cb->Info))
     {
 	cb->IsValid = FALSE;
 	return FALSE;
     }
     cb->IsValid = TRUE;
 
+#if 0
     /*
      * Allocate a buffer large enough to hold the entire console screen
      * buffer.  If this ConsoleBuffer structure has already been initialized
@@ -2257,6 +2263,73 @@ SaveConsoleBuffer(
 	    return FALSE;
 	}
     }
+#endif
+
+    return TRUE;
+}
+
+/*
+ * CopyOldConsoleBuffer()
+ * Description:
+ *  Copies the old console buffer contents to the current console buffer.
+ *  This is used when 'restorescreen' is off.
+ * Returns:
+ *  TRUE on success
+ */
+    static BOOL
+CopyOldConsoleBuffer(
+    ConsoleBuffer   *cb,
+    HANDLE	    hConOld)
+{
+    COORD		    BufferCoord;
+    COORD		    BufferSize;
+    PCHAR_INFO		    Buffer;
+    DWORD		    NumCells;
+    SMALL_RECT		    ReadRegion;
+
+    /*
+     * 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.
+     */
+    ClearConsoleBuffer(cb->Info.wAttributes);
+
+    /* We only need to copy the window area, not whole buffer. */
+    BufferSize.X = cb->Info.srWindow.Right - cb->Info.srWindow.Left + 1;
+    BufferSize.Y = cb->Info.srWindow.Bottom - cb->Info.srWindow.Top + 1;
+    ReadRegion.Left = 0;
+    ReadRegion.Right = BufferSize.X - 1;
+    ReadRegion.Top = 0;
+    ReadRegion.Bottom = BufferSize.Y - 1;
+
+    NumCells = BufferSize.X * BufferSize.Y;
+    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 */
+		&ReadRegion))		    /* region to save */
+    {
+	vim_free(Buffer);
+	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;
 }
@@ -2275,12 +2348,22 @@ RestoreConsoleBuffer(
     ConsoleBuffer   *cb,
     BOOL	    RestoreScreen)
 {
+#if 0
     COORD BufferCoord;
     SMALL_RECT WriteRegion;
+#endif
+    HANDLE hConOld;
 
     if (cb == NULL || !cb->IsValid)
 	return FALSE;
 
+    hConOld = g_hConOut;
+    g_hConOut = cb->handle;
+    if (!RestoreScreen && exiting)
+	CopyOldConsoleBuffer(cb, hConOld);
+    SetConsoleActiveScreenBuffer(g_hConOut);
+
+#if 0
     /*
      * Before restoring the buffer contents, clear the current buffer, and
      * restore the cursor position and window information.  Doing this now
@@ -2328,11 +2411,14 @@ RestoreConsoleBuffer(
 	    return FALSE;
 	}
     }
+#endif
 
     return TRUE;
 }
 
+#if 0
 #define FEAT_RESTORE_ORIG_SCREEN
+#endif
 #ifdef FEAT_RESTORE_ORIG_SCREEN
 static ConsoleBuffer g_cbOrig = { 0 };
 #endif
@@ -2474,7 +2560,7 @@ static DWORD g_cmodeout = 0;
     void
 mch_init(void)
 {
-#ifndef FEAT_RESTORE_ORIG_SCREEN
+#if 0
     CONSOLE_SCREEN_BUFFER_INFO csbi;
 #endif
 #ifndef __MINGW32__
@@ -2497,15 +2583,20 @@ mch_init(void)
     else
 	create_conin();
     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
+    g_cbOrig.handle = g_hConOut;
     /* Save the initial console buffer for later restoration */
     SaveConsoleBuffer(&g_cbOrig);
     g_attrCurrent = g_attrDefault = g_cbOrig.Info.wAttributes;
 #else
     /* Get current text attributes */
-    GetConsoleScreenBufferInfo(g_hConOut, &csbi);
-    g_attrCurrent = g_attrDefault = csbi.wAttributes;
+    SaveConsoleBuffer(&g_cbNonTermcap);
+    g_attrCurrent = g_attrDefault = g_cbNonTermcap.Info.wAttributes;
 #endif
     if (cterm_normal_fg_color == 0)
 	cterm_normal_fg_color = (g_attrCurrent & 0xf) + 1;
@@ -2606,6 +2697,8 @@ mch_exit(int r)
     SetConsoleMode(g_hConIn,  g_cmodein);
     SetConsoleMode(g_hConOut, g_cmodeout);
 
+    CloseHandle(g_cbTermcap.handle);
+
 #ifdef DYNAMIC_GETTEXT
     dyn_libintl_end();
 #endif
@@ -5001,6 +5094,8 @@ termcap_mode_start(void)
 	 * screen buffer, and resize the buffer to match the current window
 	 * size.  We will use this as the size of our editing environment.
 	 */
+	g_hConOut = g_cbTermcap.handle;
+	SetConsoleActiveScreenBuffer(g_hConOut);
 	ClearConsoleBuffer(g_attrCurrent);
 	ResizeConBufAndWindow(g_hConOut, Columns, Rows);
     }
# HG changeset patch
# Parent  9f5910b18e4b36ef3d923dd66497f0c89f2e6dd1

diff --git a/src/os_win32.c b/src/os_win32.c
--- a/src/os_win32.c
+++ b/src/os_win32.c
@@ -2168,10 +2168,6 @@ typedef struct ConsoleBufferStruct
 {
     BOOL			IsValid;
     CONSOLE_SCREEN_BUFFER_INFO	Info;
-#if 0
-    PCHAR_INFO			Buffer;
-    COORD			BufferSize;
-#endif
     HANDLE			handle;
 } ConsoleBuffer;
 
@@ -2189,13 +2185,6 @@ typedef struct ConsoleBufferStruct
 SaveConsoleBuffer(
     ConsoleBuffer *cb)
 {
-#if 0
-    DWORD NumCells;
-    COORD BufferCoord;
-    SMALL_RECT ReadRegion;
-    WORD Y, Y_incr;
-#endif
-
     if (cb == NULL)
 	return FALSE;
 
@@ -2206,65 +2195,6 @@ SaveConsoleBuffer(
     }
     cb->IsValid = TRUE;
 
-#if 0
-    /*
-     * 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.
-     * ReadConsoleOutput() seems to be limited as far as how much you
-     * can read at a time.  Empirically, this number seems to be about
-     * 12000 cells (rows * columns).  Start at position (0, 0) and copy
-     * in chunks until it is all copied.  The chunks will all have the
-     * same horizontal characteristics, so initialize them now.  The
-     * height of each chunk will be (12000 / width).
-     */
-    BufferCoord.X = 0;
-    ReadRegion.Left = 0;
-    ReadRegion.Right = cb->Info.dwSize.X - 1;
-    Y_incr = 12000 / cb->Info.dwSize.X;
-    for (Y = 0; Y < cb->BufferSize.Y; Y += Y_incr)
-    {
-	/*
-	 * Read into position (0, Y) in our buffer.
-	 */
-	BufferCoord.Y = Y;
-	/*
-	 * Read the region whose top left corner is (0, Y) and whose bottom
-	 * right corner is (width - 1, Y + Y_incr - 1).  This should define
-	 * a region of size width by Y_incr.  Don't worry if this region is
-	 * too large for the remaining buffer; it will be cropped.
-	 */
-	ReadRegion.Top = Y;
-	ReadRegion.Bottom = Y + Y_incr - 1;
-	if (!ReadConsoleOutput(g_hConOut,	/* output handle */
-		cb->Buffer,			/* our buffer */
-		cb->BufferSize,			/* dimensions of our buffer */
-		BufferCoord,			/* offset in our buffer */
-		&ReadRegion))			/* region to save */
-	{
-	    vim_free(cb->Buffer);
-	    cb->Buffer = NULL;
-	    return FALSE;
-	}
-    }
-#endif
-
     return TRUE;
 }
 
@@ -2348,10 +2278,6 @@ RestoreConsoleBuffer(
     ConsoleBuffer   *cb,
     BOOL	    RestoreScreen)
 {
-#if 0
-    COORD BufferCoord;
-    SMALL_RECT WriteRegion;
-#endif
     HANDLE hConOld;
 
     if (cb == NULL || !cb->IsValid)
@@ -2363,65 +2289,9 @@ RestoreConsoleBuffer(
 	CopyOldConsoleBuffer(cb, hConOld);
     SetConsoleActiveScreenBuffer(g_hConOut);
 
-#if 0
-    /*
-     * Before restoring the buffer contents, clear the current buffer, and
-     * restore the cursor position and window information.  Doing this now
-     * prevents old buffer contents from "flashing" onto the screen.
-     */
-    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;
-	}
-    }
-#endif
-
     return TRUE;
 }
 
-#if 0
-#define FEAT_RESTORE_ORIG_SCREEN
-#endif
-#ifdef FEAT_RESTORE_ORIG_SCREEN
-static ConsoleBuffer g_cbOrig = { 0 };
-#endif
 static ConsoleBuffer g_cbNonTermcap = { 0 };
 static ConsoleBuffer g_cbTermcap = { 0 };
 
@@ -2560,9 +2430,6 @@ static DWORD g_cmodeout = 0;
     void
 mch_init(void)
 {
-#if 0
-    CONSOLE_SCREEN_BUFFER_INFO csbi;
-#endif
 #ifndef __MINGW32__
     extern int _fmode;
 #endif
@@ -2588,16 +2455,9 @@ mch_init(void)
 	    GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
 	    NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
 
-#ifdef FEAT_RESTORE_ORIG_SCREEN
-    g_cbOrig.handle = g_hConOut;
-    /* Save the initial console buffer for later restoration */
-    SaveConsoleBuffer(&g_cbOrig);
-    g_attrCurrent = g_attrDefault = g_cbOrig.Info.wAttributes;
-#else
     /* Get current text attributes */
     SaveConsoleBuffer(&g_cbNonTermcap);
     g_attrCurrent = g_attrDefault = g_cbNonTermcap.Info.wAttributes;
-#endif
     if (cterm_normal_fg_color == 0)
 	cterm_normal_fg_color = (g_attrCurrent & 0xf) + 1;
     if (cterm_normal_bg_color == 0)
@@ -5139,11 +4999,7 @@ termcap_mode_end(void)
     cmodein &= ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT);
     SetConsoleMode(g_hConIn, cmodein);
 
-#ifdef FEAT_RESTORE_ORIG_SCREEN
-    cb = exiting ? &g_cbOrig : &g_cbNonTermcap;
-#else
     cb = &g_cbNonTermcap;
-#endif
     RestoreConsoleBuffer(cb, p_rs);
     SetConsoleCursorInfo(g_hConOut, &g_cci);
 

Raspunde prin e-mail lui