Compare commits

..

15 Commits

Author SHA1 Message Date
Hirohito Higashi
a5d9654620 patch 9.2.0180: possible crash with winminheight=0
Problem:  possible crash with winminheight=0
          (Emilien Breton)
Solution: Use <= instead of < when checking reserved room in
          frame_setheight() to correctly handle the zero-height
          boundary case (Hirohito Higashi).

In frame_setheight(), when shrinking the current window and the only
other window has 'winfixheight' with 'winminheight'=0, room_reserved
was not cleared because the condition used '<' instead of '<='.
The freed rows were discarded, leaving fr_height sum less than
topframe fr_height.  Subsequent resize operations then computed a
wrong room_cmdline that expanded topframe beyond the screen, causing
a crash.

fixes:  #19706
closes: #19712

Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
2026-03-16 21:44:17 +00:00
ichizok
e06d084735 patch 9.2.0179: MS-Windows: Compiler warning for converting from size_t to int
Problem:  MS-Windows: Compile warning for converting from size_t to int
          breaks the Appveyor CI (after v9.2.0168)
Solution: Explicitly cast to int in convert_string() (ichizok).

closes: #19722

Signed-off-by: ichizok <gclient.gaap@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
2026-03-16 21:31:14 +00:00
Foxe Chen
d737e24437 patch 9.2.0178: DEC mode requests are sent even when not in raw mode
Problem:  Vim sends DEC mode query requests (DECRQM) regardless of the
          terminal mode.
Solution: Only send DEC mode requests when cur_tmode is TMODE_RAW, but
          e.g not for gui mode (Foxe Chen).

fixes:  #19709
closes: #19710

Signed-off-by: Foxe Chen <chen.foxe@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
2026-03-16 21:25:10 +00:00
pyllyukko
36d0022b3b patch 9.2.0177: Vim9: Can set environment variables in restricted mode
Problem:  Vim9: Can set environment variables in restricted mode
Solution: Disallow settings variables in exec_instructions() when in
          restricted mode (pyllyukko)

related: #13394
closes:  #19705

Signed-off-by: pyllyukko <pyllyukko@maimed.org>
Signed-off-by: Christian Brabandt <cb@256bit.org>
2026-03-16 21:19:08 +00:00
pyllyukko
8faba24ca7 patch 9.2.0176: external diff is allowed in restricted mode
Problem:  When 'diffopt' does not include "internal", Vim attempts to
          execute an external diff command even in restricted mode.
          This could be used to bypass restricted mode.
Solution: Call check_restricted() in diff_file() before attempting to
          execute an external diff (pyllyukko).

closes: #19696

Signed-off-by: pyllyukko <pyllyukko@maimed.org>
Signed-off-by: Christian Brabandt <cb@256bit.org>
2026-03-16 19:49:35 +00:00
Christian Brabandt
e22b31887a patch 9.2.0175: No tests for what v9.2.0141 and v9.2.0156 fixes
Problem:  No tests for what v9.2.0141 and v9.2.0156 fixes
Solution: Add tests for using :perldo and rubeval() in sandbox mode

related: #19664
related: #19653
closes:  #19699

Signed-off-by: Christian Brabandt <cb@256bit.org>
2026-03-16 19:36:46 +00:00
HarshK97
42c6686c78 patch 9.2.0174: diff: inline word-diffs can be fragmented
Problem:  When using 'diffopt=inline:word', lines were excessively
          fragmented with punctuation creating separate highlight
          blocks, making it harder to read the diffs.
Solution: Added 'diff_refine_inline_word_highlight()' to merge
          adjacent diff blocks that are separated by small gaps of
          non-word characters (up to 5 bytes by default) (HarshK97).

When using inline:word diff mode, adjacent changed words separated by
punctuation or whitespace are now merged into a single highlight block
if the gap between them contains fewer than 5 non-word characters.

This creates more readable diffs and closely matches GitHub's own diff
display.

closes: #19098

Signed-off-by: HarshK97 <harshkapse1234@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
2026-03-16 19:32:21 +00:00
Christian Brabandt
e21c4a649a patch 9.2.0173: tests: Test_balloon_eval_term_visual is flaky
Problem:  tests: Test_balloon_eval_term_visual is flaky
Solution: Use redraw and WaitForAssert() to make it more reliable

Previously, it failed about 1 out of 4 runs for me, now I got it down to
1 out of 10. It's not perfect, but better than before.

closes: #19692

Signed-off-by: Christian Brabandt <cb@256bit.org>
2026-03-15 15:42:34 +00:00
Yasuhiro Matsumoto
a72926fa51 patch 9.2.0172: Missing semicolon in os_mac_conv.c
Problem:  Missing semicolon in os_mac_conv.c (after v9.2.0168)
Solution: Add it (Yasuhiro Matsumoto).

The missing semicolon was introduced in patch 9.2.0168
(b00f441e6), which breaks the macOS build.

closes: #19695

Signed-off-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
2026-03-15 15:39:34 +00:00
Mao-Yining
ca62f84503 patch 9.2.0171: MS-Windows: version detection is deprecated
Problem:  MS-Windows: GetVersionEx() is deprecated since Windows 8.
          Version checks for specific features (like dark mode or title
          bar colors) are duplicated across files using multiple boolean flags.
Solution: Use RtlGetVersion() to centralize detection in a single
          win_version variable. Use the MAKE_VER() macro to check
          against major, minor, and build numbers. Update titlebar
          colors and dark theme to use proper version thresholds
          (Mao-Yining).

closes: #19673

Signed-off-by: Mao-Yining <mao.yining@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
2026-03-15 09:49:33 +00:00
Murasame
98fe2b6c71 translation(zh_CN): Fix translation for 'paste' in zh_CN.UTF-8.po
Corrected the translation for 'paste' from '粘帖' to '粘贴'.

In Chinese, the correct term for the computer action "paste" is 粘贴
(zhān tiē). The original translation used 粘帖, which contains a very
common typo. The second character was mistakenly written as 帖 (which
means a note or invitation) instead of the correct character 贴 (which
means to stick or paste).

closes: #19689

Signed-off-by: Murasame <88932464+CuteMurasame@users.noreply.github.com>
Signed-off-by: Mao-Yining <mao.yining@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
2026-03-15 09:40:32 +00:00
Christian Brabandt
7a9548c400 runtime(doc): Update help tags references
related: #19691

Signed-off-by: Christian Brabandt <cb@256bit.org>
2026-03-15 09:35:35 +00:00
Yasuhiro Matsumoto
e05d897258 patch 9.2.0170: channel: some issues in ch_listen()
Problem:  channel: some issues in ch_listen()
          (char101, after v9.2.0153)
Solution: On MS-Windows, initialize using channel_init_winsock() and use
          SO_EXCLUSIVEADDRUSE instead of SO_REUSEADDR, allow to use port
          0 to have the OS assign a port (Yasuhiro Matsumoto).

related: #19231
closes:  #19690

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
2026-03-15 09:32:19 +00:00
Yasuhiro Matsumoto
751b59e539 runtime(doc): clarify :silent usage for system()/systemlist()
When system() or systemlist() is called without :silent from a
statusline expression, autocommand, or timer callback, the terminal
is temporarily set to cooked mode, which re-enables ECHO on the tty.
If a terminal response (e.g. DECRPM for cursor blink mode) arrives
during this window, the tty driver echoes it to the screen, leaving
stray characters that require CTRL-L to remove.

This behavior was intentionally addressed in patch 7.4.427 by
skipping cooked mode when :silent is prepended.  However, the
documentation only mentioned this for system() and did not cover
systemlist() at all.  The guidance to use :silent in non-interactive
contexts (statusline, autocommands, timers) was also not explicit.

closes #19691

Signed-off-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
2026-03-15 09:16:42 +00:00
Foxe Chen
a8052afcb6 patch 9.2.0169: assertion failure in syn_id2attr()
Problem:  assertion failure in syn_id2attr()
          (@julio-b, after v9.2.0093)
Solution: Set tp_curwin to a valid window in popup_close_tabpage()
          and return early in update_winhighlight() if there are
          no highlight overrides to update (Foxe Chen).

fixes:  #19650
closes: #19670

Signed-off-by: Foxe Chen <chen.foxe@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
2026-03-15 09:05:14 +00:00
31 changed files with 421 additions and 120 deletions

View File

@@ -1,4 +1,4 @@
*builtin.txt* For Vim version 9.2. Last change: 2026 Mar 13
*builtin.txt* For Vim version 9.2. Last change: 2026 Mar 15
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -11713,7 +11713,11 @@ system({expr} [, {input}]) *system()* *E677*
When prepended by |:silent| the terminal will not be set to
cooked mode. This is meant to be used for commands that do
not need the user to type. It avoids stray characters showing
up on the screen which require |CTRL-L| to remove. >
up on the screen which require |CTRL-L| to remove.
When calling system() from a 'statusline' expression, an
|autocommand| or a |timer| callback, you should use |:silent|
to avoid terminal responses (e.g. from cursor style queries)
being echoed on the screen. >
:silent let f = system('ls *.vim')
<
Note: Use |shellescape()| or |::S| with |expand()| or
@@ -11771,6 +11775,11 @@ systemlist({expr} [, {input}]) *systemlist()*
<
Returns an empty string on error.
Like |system()|, prepend |:silent| when the command does not
need user interaction and is called from a 'statusline'
expression, an |autocommand| or a |timer| callback. See
|system()| for details.
Can also be used as a |method|: >
:echo GetCmd()->systemlist()
<

View File

@@ -1,4 +1,4 @@
*options.txt* For Vim version 9.2. Last change: 2026 Mar 13
*options.txt* For Vim version 9.2. Last change: 2026 Mar 16
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -3210,7 +3210,10 @@ A jump table for the options with a short description can be found at |Q_op|.
difference. Non-alphanumeric
multi-byte characters such as emoji
and CJK characters are considered
individual words.
individual words. Small gaps of
non-word characters (5 bytes or less)
between changes are merged into a
single highlight block.
internal Use the internal diff library. This is
ignored when 'diffexpr' is set. *E960*

View File

@@ -1,4 +1,4 @@
*version9.txt* For Vim version 9.2. Last change: 2026 Mar 13
*version9.txt* For Vim version 9.2. Last change: 2026 Mar 16
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -52588,6 +52588,16 @@ Popups ~
- 'previewpopup' supports the same values as 'completepopup' (except for
"align").
Diff mode ~
---------
When using inline word diffs, adjacent changes are now merged if the gap
between them is small (5 bytes or less) and contains only non-word characters.
This prevents fragmented highlighting when only whitespace or punctuation
separates changes.
Using external diff mode is no longer allowed when Vim is running in
|restricted-mode|.
Other ~
-----
- The new |xdg.vim| script for full XDG compatibility is included.

View File

@@ -1440,7 +1440,7 @@ channel_listen_func(typval_T *argvars)
return NULL;
}
port = strtol((char *)(p + 1), &rest, 10);
if (port <= 0 || port >= 65536 || *rest != NUL)
if (port < 0 || port >= 65536 || *rest != NUL)
{
semsg(_(e_invalid_argument_str), address);
return NULL;
@@ -1459,7 +1459,7 @@ channel_listen_func(typval_T *argvars)
return NULL;
}
port = strtol((char *)(p + 1), &rest, 10);
if (port <= 0 || port >= 65536 || *rest != NUL)
if (port < 0 || port >= 65536 || *rest != NUL)
{
semsg(_(e_invalid_argument_str), address);
return NULL;
@@ -1511,6 +1511,10 @@ channel_listen(
int val = 1;
channel_T *channel;
#ifdef MSWIN
channel_init_winsock();
#endif
channel = add_channel();
if (channel == NULL)
{
@@ -1555,7 +1559,7 @@ channel_listen(
}
#ifdef MSWIN
if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR,
if (setsockopt(sd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
(const char *)&val, sizeof(val)) < 0)
#else
if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR,
@@ -1591,6 +1595,16 @@ channel_listen(
return NULL;
}
// When port 0 was specified, retrieve the actual port assigned by the OS.
if (port_in == 0)
{
struct sockaddr_in addr;
socklen_t addr_len = sizeof(addr);
if (getsockname(sd, (struct sockaddr *)&addr, &addr_len) == 0)
port_in = ntohs(addr.sin_port);
}
channel->ch_listen = TRUE;
channel->CH_SOCK_FD = (sock_T)sd;
channel->ch_nb_close_cb = nb_close_cb;

View File

@@ -49,6 +49,7 @@ static int diff_need_update = FALSE; // ex_diffupdate needs to be called
static int diff_flags = DIFF_INTERNAL | DIFF_FILLER | DIFF_CLOSE_OFF | DIFF_INLINE_CHAR;
static long diff_algorithm = XDF_INDENT_HEURISTIC;
static int diff_word_gap = 5; // gap threshold for inline:word
# define LBUFLEN 50 // length of line in diff file
@@ -1371,6 +1372,9 @@ diff_file(diffio_T *dio)
if (dio->dio_internal)
return diff_file_internal(dio);
if (check_restricted())
return FAIL;
len = STRLEN(tmp_orig) + STRLEN(tmp_new)
+ STRLEN(tmp_diff) + STRLEN(p_srr) + 27;
cmd = alloc(len);
@@ -3391,6 +3395,131 @@ diff_refine_inline_char_highlight(diff_T *dp_orig, garray_T *linemap, int idx1)
} while (pass++ < 4); // use limited number of passes to avoid excessive looping
}
/*
* Refine inline word diff blocks by merging blocks that are only separated
* by whitespace or punctuation. This creates more coherent highlighting.
*/
static void
diff_refine_inline_word_highlight(diff_T *dp_orig, garray_T *linemap, int idx1,
linenr_T start_lnum)
{
int pass = 1;
do
{
diff_T *dp = dp_orig;
while (dp != NULL && dp->df_next != NULL)
{
// Only merge blocks on the same line
if (dp->df_lnum[idx1] + dp->df_count[idx1] - 1 >= linemap[idx1]. ga_len
|| dp->df_next->df_lnum[idx1] - 1 >= linemap[idx1]. ga_len)
{
dp = dp->df_next;
continue;
}
linemap_entry_T *entry1 =
&((linemap_entry_T *)linemap[idx1].ga_data)[dp->df_lnum[idx1] + dp->df_count[idx1] - 2];
linemap_entry_T *entry2 =
&((linemap_entry_T *)linemap[idx1].ga_data)[dp->df_next->df_lnum[idx1] - 1];
// Skip if blocks are on different lines
if (entry1->lineoff != entry2->lineoff)
{
dp = dp->df_next;
continue;
}
// Calculate the gap between blocks
int gap_start = entry1->byte_start + entry1->num_bytes;
int gap_end = entry2->byte_start;
int gap_size = gap_end - gap_start;
// Merge adjacent diff blocks separated by small gaps to reduce visual
// fragmentation. Gap threshold is set to 5 bytes which handles most
// common separators (spaces, punctuation, short variable names) while
// still preserving visually distinct changes.
if (gap_size <= 0 || gap_size > diff_word_gap)
{
dp = dp->df_next;
continue;
}
// Get the text between the two blocks
char_u *line = ml_get_buf(curtab->tp_diffbuf[idx1],
start_lnum + entry1->lineoff, FALSE);
char_u *gap_text = line + gap_start;
// Check if gap contains only whitespace and/or punctuation
bool only_non_word = true;
bool has_content = false;
for (int i = 0; i < gap_size && gap_text[i] != NUL; i++)
{
has_content = true;
int char_class = mb_get_class_buf(gap_text + i,
curtab->tp_diffbuf[idx1]);
// class 2 is word characters, if we find any, don't merge
if (char_class == 2)
{
only_non_word = false;
break;
}
}
// Merge if the gap is small and contains only non-word characters
if (has_content && only_non_word)
{
long total_change_bytes = 0;
for (int i = 0; i < DB_COUNT; i++)
{
if (curtab->tp_diffbuf[i] != NULL)
{
// count bytes in the first block
for (int k = 0; k < dp->df_count[i]; k++)
{
int idx = dp->df_lnum[i] + k - 1;
if (idx < linemap[i].ga_len)
total_change_bytes +=
((linemap_entry_T *)linemap[i].ga_data)[idx].num_bytes;
}
// count bytes in the next block
for (int k = 0; k < dp->df_next->df_count[i]; k++)
{
int idx = dp->df_next->df_lnum[i] + k - 1;
if (idx < linemap[i].ga_len)
total_change_bytes +=
((linemap_entry_T *)linemap[i].ga_data)[idx].num_bytes;
}
}
}
if (total_change_bytes >= gap_size * 2)
{
// Merge the blocks by extending the first block to include the next
for (int i = 0; i < DB_COUNT; i++)
{
if (curtab->tp_diffbuf[i] != NULL)
{
dp->df_count[i] = dp->df_next->df_lnum[i]
+ dp->df_next->df_count[i] - dp->df_lnum[i];
}
}
diff_T *dp_next = dp->df_next;
dp->df_next = dp_next->df_next;
clear_diffblock(dp_next);
// Don't advance dp, check if can merge with the next block too
continue;
}
}
dp = dp->df_next;
}
} while (pass++ < 4); // use limited number of passes to avoid excessive looping
}
/*
* Find the inline difference within a diff block among different buffers. Do
* this by splitting each block's content into characters or words, and then
@@ -3656,7 +3785,9 @@ diff_find_change_inline_diff(
}
diff_T *new_diff = curtab->tp_first_diff;
if (diff_flags & DIFF_INLINE_CHAR && file1_idx != -1)
if (diff_flags & DIFF_INLINE_WORD && file1_idx != -1)
diff_refine_inline_word_highlight(new_diff, linemap, file1_idx, dp->df_lnum[file1_idx]);
else if (diff_flags & DIFF_INLINE_CHAR && file1_idx != -1)
diff_refine_inline_char_highlight(new_diff, linemap, file1_idx);
// After the diff, use the linemap to obtain the original line/col of the

View File

@@ -1572,7 +1572,7 @@ dyn_dwm_load(void)
}
}
extern BOOL win11_or_later; // this is in os_win32.c
extern DWORD win_version; // this is in os_mswin.c
/*
* Set TitleBar's color. Handle hl-TitleBar and hl-TitleBarNC.
@@ -1584,11 +1584,12 @@ extern BOOL win11_or_later; // this is in os_win32.c
void
gui_mch_set_titlebar_colors(void)
{
if (pDwmSetWindowAttribute == NULL || !win11_or_later)
#define DWMWA_COLOR_DEFAULT 0xFFFFFFFF
if (pDwmSetWindowAttribute == NULL || win_version < MAKE_VER(10, 0, 22000))
return;
guicolor_T captionColor = 0xFFFFFFFF;
guicolor_T textColor = 0xFFFFFFFF;
guicolor_T captionColor = DWMWA_COLOR_DEFAULT;
guicolor_T textColor = DWMWA_COLOR_DEFAULT;
if (vim_strchr(p_go, GO_TITLEBAR) != NULL)
{
@@ -1604,9 +1605,9 @@ gui_mch_set_titlebar_colors(void)
}
if (captionColor == INVALCOLOR)
captionColor = 0xFFFFFFFF;
captionColor = DWMWA_COLOR_DEFAULT;
if (textColor == INVALCOLOR)
textColor = 0xFFFFFFFF;
textColor = DWMWA_COLOR_DEFAULT;
}
pDwmSetWindowAttribute(s_hwnd, DWMWA_CAPTION_COLOR,
@@ -3131,22 +3132,17 @@ gui_mch_set_curtab(int nr)
#endif
#ifdef FEAT_GUI_DARKTHEME
extern BOOL win10_22H2_or_later; // this is in os_win32.c
void
gui_mch_set_dark_theme(int dark)
{
if (!win10_22H2_or_later)
return;
if (pDwmSetWindowAttribute != NULL)
if (pDwmSetWindowAttribute != NULL && win_version >= MAKE_VER(10, 0, 18985))
pDwmSetWindowAttribute(s_hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &dark,
sizeof(dark));
if (pSetPreferredAppMode != NULL)
if (pSetPreferredAppMode != NULL && win_version >= MAKE_VER(10, 0, 18362))
pSetPreferredAppMode(dark);
if (pFlushMenuThemes != NULL)
if (pFlushMenuThemes != NULL && win_version >= MAKE_VER(10, 0, 18362))
pFlushMenuThemes();
}

View File

@@ -5758,6 +5758,9 @@ update_winhighlight(win_T *wp, char_u *opt)
if (arr == NULL && err != NULL)
return err;
if (arr == NULL && wp->w_hl == NULL)
return NULL;
update_highlight_overrides(wp->w_hl, arr, num);
vim_free(wp->w_hl);

View File

@@ -354,7 +354,7 @@ mac_utf16_to_enc(
}
else
{
int len = utf8_len
int len = utf8_len;
result = string_convert(&conv, utf8_str, &len);
utf8_len = len;
vim_free(utf8_str);

View File

@@ -16,7 +16,6 @@
#include "vim.h"
#include <sys/types.h>
#include <signal.h>
#include <limits.h>
#include <process.h>
@@ -105,6 +104,34 @@ mch_exit_g(int r)
#endif // FEAT_GUI_MSWIN
/*
* Get version number including build number
*/
typedef BOOL (WINAPI *PfnRtlGetVersion)(LPOSVERSIONINFOW);
DWORD win_version;
static void
win_version_init(void)
{
OSVERSIONINFOW osver;
HMODULE hNtdll;
PfnRtlGetVersion pRtlGetVersion;
hNtdll = GetModuleHandle("ntdll.dll");
if (hNtdll == NULL)
return;
pRtlGetVersion =
(PfnRtlGetVersion) GetProcAddress(hNtdll, "RtlGetVersion");
if (pRtlGetVersion == NULL)
return;
osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
pRtlGetVersion(&osver);
win_version =
MAKE_VER(osver.dwMajorVersion, osver.dwMinorVersion,
osver.dwBuildNumber);
}
/*
* Init the tables for toupper() and tolower().
*/
@@ -113,6 +140,8 @@ mch_early_init(void)
{
int i;
win_version_init();
PlatformId();
// Init the tables for toupper() and tolower()

View File

@@ -160,42 +160,11 @@ static int suppress_winsize = 1; // don't fiddle with console
static WCHAR *exe_pathw = NULL;
static BOOL win8_or_later = FALSE;
BOOL win10_22H2_or_later = FALSE;
BOOL win11_or_later = FALSE; // used in gui_mch_set_titlebar_colors(void)
#if !defined(FEAT_GUI_MSWIN) || defined(VIMDLL)
static BOOL use_alternate_screen_buffer = FALSE;
#endif
/*
* Get version number including build number
*/
typedef BOOL (WINAPI *PfnRtlGetVersion)(LPOSVERSIONINFOW);
#define MAKE_VER(major, minor, build) \
(((major) << 24) | ((minor) << 16) | (build))
static DWORD
get_build_number(void)
{
OSVERSIONINFOW osver;
HMODULE hNtdll;
PfnRtlGetVersion pRtlGetVersion;
DWORD ver = MAKE_VER(0, 0, 0);
osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
hNtdll = GetModuleHandle("ntdll.dll");
if (hNtdll == NULL)
return ver;
pRtlGetVersion =
(PfnRtlGetVersion)GetProcAddress(hNtdll, "RtlGetVersion");
pRtlGetVersion(&osver);
ver = MAKE_VER(min(osver.dwMajorVersion, 255),
min(osver.dwMinorVersion, 255),
min(osver.dwBuildNumber, 32767));
return ver;
}
extern DWORD win_version; // this is in os_mswin.c
#if !defined(FEAT_GUI_MSWIN) || defined(VIMDLL)
static BOOL
@@ -257,7 +226,7 @@ read_console_input(
if (nLength == -2)
return (s_dwMax > 0) ? TRUE : FALSE;
if (!win8_or_later)
if (win_version < MAKE_VER(6, 2, 0)) // Before Windows 8
{
if (nLength == -1)
return PeekConsoleInputW(hInput, lpBuffer, 1, lpEvents);
@@ -918,39 +887,17 @@ win32_enable_privilege(LPTSTR lpszPrivilege)
}
#endif
#ifdef _MSC_VER
// Suppress the deprecation warning for using GetVersionEx().
// It is needed for implementing "windowsversion()".
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
/*
* Set "win8_or_later" and fill in "windowsVersion" if possible.
* Fill in "windowsVersion" if possible and enable security privilege for ACL.
*/
void
PlatformId(void)
{
OSVERSIONINFO ovi;
ovi.dwOSVersionInfoSize = sizeof(ovi);
if (!GetVersionEx(&ovi))
return;
#ifdef FEAT_EVAL
vim_snprintf(windowsVersion, sizeof(windowsVersion), "%d.%d",
(int)ovi.dwMajorVersion, (int)ovi.dwMinorVersion);
DWORD major = (win_version >> 24) & 0xFF;
DWORD minor = (win_version >> 16) & 0xFF;
vim_snprintf(windowsVersion, sizeof(windowsVersion), "%d.%d", major, minor);
#endif
if ((ovi.dwMajorVersion == 6 && ovi.dwMinorVersion >= 2)
|| ovi.dwMajorVersion > 6)
win8_or_later = TRUE;
if ((ovi.dwMajorVersion == 10 && ovi.dwBuildNumber >= 19045)
|| ovi.dwMajorVersion > 10)
win10_22H2_or_later = TRUE;
if ((ovi.dwMajorVersion == 10 && ovi.dwBuildNumber >= 22000)
|| ovi.dwMajorVersion > 10)
win11_or_later = TRUE;
#ifdef HAVE_ACL
// Enable privilege for getting or setting SACLs.
@@ -958,9 +905,6 @@ PlatformId(void)
return;
#endif
}
#ifdef _MSC_VER
# pragma warning(pop)
#endif
#if !defined(FEAT_GUI_MSWIN) || defined(VIMDLL)
@@ -8537,7 +8481,7 @@ mch_setenv(char *var, char *value, int x UNUSED)
* Support for 256 colors and 24-bit colors was added in Windows 10
* version 1703 (Creators update).
*/
#define VTP_FIRST_SUPPORT_BUILD MAKE_VER(10, 0, 15063)
#define VTP_FIRST_SUPPORT_BUILD MAKE_VER(10, 0, 15063)
/*
* Support for pseudo-console (ConPTY) was added in windows 10
@@ -8582,7 +8526,6 @@ mch_setenv(char *var, char *value, int x UNUSED)
static void
vtp_flag_init(void)
{
DWORD ver = get_build_number();
#if !defined(FEAT_GUI_MSWIN) || defined(VIMDLL)
DWORD mode;
HANDLE out;
@@ -8593,7 +8536,7 @@ vtp_flag_init(void)
{
out = GetStdHandle(STD_OUTPUT_HANDLE);
vtp_working = (ver >= VTP_FIRST_SUPPORT_BUILD) ? 1 : 0;
vtp_working = (win_version >= VTP_FIRST_SUPPORT_BUILD) ? 1 : 0;
GetConsoleMode(out, &mode);
mode |= (ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
if (SetConsoleMode(out, mode) == 0)
@@ -8601,26 +8544,26 @@ vtp_flag_init(void)
// VTP uses alternate screen buffer.
// But, not if running in a nested terminal
use_alternate_screen_buffer = win10_22H2_or_later && p_rs && vtp_working
&& !mch_getenv("VIM_TERMINAL");
use_alternate_screen_buffer = win_version >= MAKE_VER(10, 0, 19045)
&& p_rs && vtp_working && !mch_getenv("VIM_TERMINAL");
}
#endif
if (ver >= CONPTY_FIRST_SUPPORT_BUILD)
if (win_version >= CONPTY_FIRST_SUPPORT_BUILD)
conpty_working = 1;
if (ver >= CONPTY_STABLE_BUILD)
if (win_version >= CONPTY_STABLE_BUILD)
conpty_stable = 1;
if (ver <= CONPTY_INSIDER_BUILD)
if (win_version <= CONPTY_INSIDER_BUILD)
conpty_type = 3;
if (ver <= CONPTY_1909_BUILD)
if (win_version <= CONPTY_1909_BUILD)
conpty_type = 2;
if (ver <= CONPTY_1903_BUILD)
if (win_version <= CONPTY_1903_BUILD)
conpty_type = 2;
if (ver < CONPTY_FIRST_SUPPORT_BUILD)
if (win_version < CONPTY_FIRST_SUPPORT_BUILD)
conpty_type = 1;
if (ver >= CONPTY_NEXT_UPDATE_BUILD)
if (win_version >= CONPTY_NEXT_UPDATE_BUILD)
conpty_fix_type = 1;
}

View File

@@ -224,3 +224,7 @@ Trace(char *pszFormat, ...);
#endif
#define mch_getenv(x) (char_u *)getenv((char *)(x))
#define vim_mkdir(x, y) mch_mkdir(x)
// Windows Version
#define MAKE_VER(major, minor, build) \
((((major) & 0xFF) << 24) | (((minor) & 0xFF) << 16) | ((build) & 0x7FFF))

View File

@@ -2729,7 +2729,7 @@ msgid " Arabic"
msgstr " Arabic"
msgid " (paste)"
msgstr " (粘)"
msgstr " (粘)"
msgid " VISUAL"
msgstr " 可视"

View File

@@ -2729,7 +2729,7 @@ msgid " Arabic"
msgstr " Arabic"
msgid " (paste)"
msgstr " (粘)"
msgstr " (粘)"
msgid " VISUAL"
msgstr " 可视"

View File

@@ -2729,7 +2729,7 @@ msgid " Arabic"
msgstr " Arabic"
msgid " (paste)"
msgstr " (粘)"
msgstr " (粘)"
msgid " VISUAL"
msgstr " 可视"

View File

@@ -3283,6 +3283,12 @@ popup_close_tabpage(tabpage_T *tp, int id, int force)
}
back_to_prevwin(wp);
}
// Set curwin for tabpage to a valid window, in case we try
// accessing it later.
if (tp->tp_curwin == wp)
tp->tp_curwin = tp->tp_firstwin;
if (prev == NULL)
*root = wp->w_next;
else

View File

@@ -1218,7 +1218,7 @@ convert_string(string_T *str, char_u *from, char_u *to, string_T *ret)
}
else
{
int len = str->length;
int len = (int)str->length;
ret->string = string_convert(&vimconv, str->string, &len);
ret->length = len;
}

View File

@@ -4051,11 +4051,14 @@ starttermcap(void)
out_str(T_FE);
#endif
// Request setting of relevant DEC modes via DECRQM
for (int i = 0; i < (int)ARRAY_LENGTH(dec_modes); i++)
if (cur_tmode == TMODE_RAW)
{
vim_snprintf((char *)IObuff, IOSIZE, "\033[?%d$p", dec_modes[i]);
out_str(IObuff);
// Request setting of relevant DEC modes via DECRQM
for (int i = 0; i < (int)ARRAY_LENGTH(dec_modes); i++)
{
vim_snprintf((char *)IObuff, IOSIZE, "\033[?%d$p", dec_modes[i]);
out_str(IObuff);
}
}
out_flush();

View File

@@ -1,4 +1,4 @@
| +0#0000e05#a8a8a8255@1|a+2#0000000#ff404010|b|c|d|e|f| +0&#ffd7ff255|g+2&#ff404010|h|i| +0&#ffd7ff255|j+2&#ff404010|k| +0&#ffd7ff255|n| @19||+1&#ffffff0| +0#0000e05#a8a8a8255@1|a+2#0000000#ff404010|B|c|e|f| +0&#ffd7ff255|g+2&#ff404010|H|i| +0&#ffd7ff255|l+2&#ff404010|m| +0&#ffd7ff255|n| @20
| +0#0000e05#a8a8a8255@1|a+2#0000000#ff404010|b|c|d|e|f| |g|h|i| |j|k| +0&#ffd7ff255|n| @19||+1&#ffffff0| +0#0000e05#a8a8a8255@1|a+2#0000000#ff404010|B|c|e|f| |g|H|i| |l|m| +0&#ffd7ff255|n| @20
| +0#0000e05#a8a8a8255@1|x+0#0000000#5fd7ff255| @33||+1&#ffffff0| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34
| +0#0000e05#a8a8a8255@1|y+0#0000000#ffffff0| @33||+1&&| +0#0000e05#a8a8a8255@1|y+0#0000000#ffffff0| @33
| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34||+1#0000000#ffffff0| +0#0000e05#a8a8a8255@1|z+0#0000000#5fd7ff255| @33

View File

@@ -1,4 +1,4 @@
| +0#0000e05#a8a8a8255@1|T+2#0000000#ff404010|h|i|s|+|i|s|=+0&#ffd7ff255|a+2&#ff404010|-+0&#ffd7ff255|s|e|t|e|n|c|e| @5||+1&#ffffff0| +0#0000e05#a8a8a8255@1|T+2#0000000#ff404010|h|i|s|+|i|s|=+0&#ffd7ff255|a+2&#ff404010|n|o|t|h|e|r|-+0&#ffd7ff255|s|e|t|e|n|c||+1&#ffffff0| +0#0000e05#a8a8a8255@1|T+2#0000000#ff404010|h|a|t|+|i|s|=+0&#ffd7ff255|a+2&#ff404010|-+0&#ffd7ff255|s|e|t|e|n|c|e| @4
| +0#0000e05#a8a8a8255@1|T+2#0000000#ff404010|h|i|s|+|i|s|=|a|-+0&#ffd7ff255|s|e|t|e|n|c|e| @5||+1&#ffffff0| +0#0000e05#a8a8a8255@1|T+2#0000000#ff404010|h|i|s|+|i|s|=|a|n|o|t|h|e|r|-+0&#ffd7ff255|s|e|t|e|n|c||+1&#ffffff0| +0#0000e05#a8a8a8255@1|T+2#0000000#ff404010|h|a|t|+|i|s|=|a|-+0&#ffd7ff255|s|e|t|e|n|c|e| @4
|~+0#4040ff13#ffffff0| @23||+1#0000000&|~+0#4040ff13&| @22||+1#0000000&|~+0#4040ff13&| @22
|~| @23||+1#0000000&|~+0#4040ff13&| @22||+1#0000000&|~+0#4040ff13&| @22
|~| @23||+1#0000000&|~+0#4040ff13&| @22||+1#0000000&|~+0#4040ff13&| @22

View File

@@ -1,6 +1,6 @@
| +0#0000e05#a8a8a8255@1|t+0#0000000#ffd7ff255|h|i|s| @2|i|s| @25||+1&#ffffff0| +0#0000e05#a8a8a8255@1|t+0#0000000#ffd7ff255|h|i|s| |i|s| |s+2&#ff404010|o|m|e| +0&#ffd7ff255|t+2&#ff404010|e|s|t| +0&#ffd7ff255@17
| +0#0000e05#a8a8a8255@1|s+2#0000000#ff404010|o|m|e|t|e|s|t| +0&#ffd7ff255|t+2&#ff404010|e|x|t| +0&#ffd7ff255|f+2&#ff404010|o@1| +0&#ffd7ff255@17||+1&#ffffff0| +0#0000e05#a8a8a8255@1|t+2#0000000#ff404010|e|x|t|s| +0&#ffd7ff255@29
| +0#0000e05#a8a8a8255@1|b+2#0000000#ff404010|a|z| +0&#ffd7ff255|a+2&#ff404010|b|c| +0&#ffd7ff255|d+2&#ff404010|e|f| +0&#ffd7ff255@23||+1&#ffffff0| +0#0000e05#a8a8a8255@1|f+2#0000000#ff404010|o@1| +0&#ffd7ff255|b+2&#ff404010|a|r| +0&#ffd7ff255|a+2&#ff404010|b|X| +0&#ffd7ff255|Y+2&#ff404010|e|f| +0&#ffd7ff255@19
| +0#0000e05#a8a8a8255@1|t+0#0000000#ffd7ff255|h|i|s| @2|i|s| @25||+1&#ffffff0| +0#0000e05#a8a8a8255@1|t+0#0000000#ffd7ff255|h|i|s| |i|s| |s+2&#ff404010|o|m|e| |t|e|s|t| +0&#ffd7ff255@17
| +0#0000e05#a8a8a8255@1|s+2#0000000#ff404010|o|m|e|t|e|s|t| |t|e|x|t| |f|o@1| +0&#ffd7ff255@17||+1&#ffffff0| +0#0000e05#a8a8a8255@1|t+2#0000000#ff404010|e|x|t|s| +0&#ffd7ff255@29
| +0#0000e05#a8a8a8255@1|b+2#0000000#ff404010|a|z| |a|b|c| |d|e|f| +0&#ffd7ff255@23||+1&#ffffff0| +0#0000e05#a8a8a8255@1|f+2#0000000#ff404010|o@1| |b|a|r| |a|b|X| +0&#ffd7ff255|Y+2&#ff404010|e|f| +0&#ffd7ff255@19
| +0#0000e05#a8a8a8255@1|o+2#0000000#ff404010|n|e| +0&#ffd7ff255@31||+1&#ffffff0| +0#0000e05#a8a8a8255@1|o+2#0000000#ff404010|n|e|w|o|r|d| +0&#ffd7ff255|a|n|o|t|h|e|r| |w|o|r|d| @14
| +0#0000e05#a8a8a8255@1|w+2#0000000#ff404010|o|r|d| +0&#ffd7ff255|a|n|o|t|h|e|r| |w|o|r|d| @17||+1&#ffffff0| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34
| +0#0000e05#a8a8a8255@1|a+0#0000000#5fd7ff255|d@1|i|t|i|o|n|a|l| |l|i|n|e| @19||+1&#ffffff0| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34

View File

@@ -1,6 +1,6 @@
| +0#0000e05#a8a8a8255@1|t+0#0000000#ffd7ff255|h|i|s| | +0&#4040ff13@1|i+0&#ffd7ff255|s| @25||+1&#ffffff0| +0#0000e05#a8a8a8255@1|t+0#0000000#ffd7ff255|h|i|s| |i|s| |s+2&#ff404010|o|m|e| +0&#ffd7ff255|t+2&#ff404010|e|s|t| +0&#ffd7ff255@17
| +0#0000e05#a8a8a8255@1|s+2#0000000#ff404010|o|m|e|t|e|s|t| +0&#ffd7ff255|t+2&#ff404010|e|x|t| +0&#ffd7ff255|f|o@1| @17||+1&#ffffff0| +0#0000e05#a8a8a8255@1|t+2#0000000#ff404010|e|x|t|s| +0&#ffd7ff255@29
| +0#0000e05#a8a8a8255@1|b+2#0000000#ff404010|a|z| +0&#ffd7ff255|a+2&#ff404010|b|c| +0&#ffd7ff255|d+2&#ff404010|e|f| +0&#ffd7ff255@23||+1&#ffffff0| +0#0000e05#a8a8a8255@1|f+0#0000000#ffd7ff255|o@1| |b+2&#ff404010|a|r| +0&#ffd7ff255|a+2&#ff404010|b|X| +0&#ffd7ff255|Y+2&#ff404010|e|f| +0&#ffd7ff255@19
| +0#0000e05#a8a8a8255@1|t+0#0000000#ffd7ff255|h|i|s| | +0&#4040ff13@1|i+0&#ffd7ff255|s| @25||+1&#ffffff0| +0#0000e05#a8a8a8255@1|t+0#0000000#ffd7ff255|h|i|s| |i|s| |s+2&#ff404010|o|m|e| |t|e|s|t| +0&#ffd7ff255@17
| +0#0000e05#a8a8a8255@1|s+2#0000000#ff404010|o|m|e|t|e|s|t| |t|e|x|t| +0&#ffd7ff255|f|o@1| @17||+1&#ffffff0| +0#0000e05#a8a8a8255@1|t+2#0000000#ff404010|e|x|t|s| +0&#ffd7ff255@29
| +0#0000e05#a8a8a8255@1|b+2#0000000#ff404010|a|z| |a|b|c| |d|e|f| +0&#ffd7ff255@23||+1&#ffffff0| +0#0000e05#a8a8a8255@1|f+0#0000000#ffd7ff255|o@1| |b+2&#ff404010|a|r| |a|b|X| |Y|e|f| +0&#ffd7ff255@19
| +0#0000e05#a8a8a8255@1|o+2#0000000#ff404010|n|e| +0&#ffd7ff255@31||+1&#ffffff0| +0#0000e05#a8a8a8255@1|o+2#0000000#ff404010|n|e|w|o|r|d| +0&#ffd7ff255|a|n|o|t|h|e|r| |w|o|r|d| @14
| +0#0000e05#a8a8a8255@1|w+2#0000000#ff404010|o|r|d| +0&#ffd7ff255|a|n|o|t|h|e|r| |w|o|r|d| @17||+1&#ffffff0| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34
| +0#0000e05#a8a8a8255@1|a+0#0000000#5fd7ff255|d@1|i|t|i|o|n|a|l| |l|i|n|e| @19||+1&#ffffff0| +0#0000e05#a8a8a8255@1|-+0#4040ff13#afffff255@34

View File

@@ -1,4 +1,4 @@
| +0#0000e05#a8a8a8255@1|🚀*0#0000000#ffd7ff255|⛵️*2&#ff404010|一*0&#ffd7ff255|二|三*2&#ff404010|ひ*0&#ffd7ff255|ら|が*0&#4040ff13|な*0&#ffd7ff255|Δ+2&#ff404010|έ|λ|τ|α| +0&#ffd7ff255|Δ+2&#ff404010|e|l|t|a| +0&#ffd7ff255|f|o@1|b|a||+1&#ffffff0| +0#0000e05#a8a8a8255@1|🚀*0#0000000#ffd7ff255|🛸*2&#ff404010|一*0&#ffd7ff255|二|四*2&#ff404010|ひ*0&#ffd7ff255|ら|な|δ+2&#ff404010|έ|λ|τ|α| +0&#ffd7ff255|δ+2&#ff404010|e|l|t|a| +0&#ffd7ff255|f|o@1|b|a|r|
| +0#0000e05#a8a8a8255@1|🚀*0#0000000#ffd7ff255|⛵️*2&#ff404010|一*0&#ffd7ff255|二|三*2&#ff404010|ひ*0&#ffd7ff255|ら|が*2&#ff404010|な|Δ+&|έ|λ|τ|α| |Δ|e|l|t|a| +0&#ffd7ff255|f|o@1|b|a||+1&#ffffff0| +0#0000e05#a8a8a8255@1|🚀*0#0000000#ffd7ff255|🛸*2&#ff404010|一*0&#ffd7ff255|二|四*2&#ff404010|ひ*0&#ffd7ff255|ら|な*2&#ff404010|δ+&|έ|λ|τ|α| |e|l|t|a| +0&#ffd7ff255|f|o@1|b|a|r|
|~+0#4040ff13#ffffff0| @35||+1#0000000&|~+0#4040ff13&| @35
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|~| @35||+1#0000000&|~+0#4040ff13&| @35

View File

@@ -53,12 +53,15 @@ func Test_balloon_eval_term_visual()
" the balloon.
call writefile(s:common_script + [
\ 'call test_setmouse(3, 6)',
\ 'call feedkeys("3Gevfr\<MouseMove>\<Ignore>", "xt")',
\ 'call feedkeys("3Gevfr", "xt")',
\ 'redraw!',
\ 'call feedkeys("\<MouseMove>\<Ignore>", "xt")',
\ ], 'XTest_beval_visual', 'D')
" Check that the balloon shows up after a mouse move
let buf = RunVimInTerminal('-S XTest_beval_visual', {'rows': 10, 'cols': 50})
call TermWait(buf, 50)
call WaitForAssert({-> assert_match('-- VISUAL --', term_getline(buf, 10))})
call VerifyScreenDump(buf, 'Test_balloon_eval_term_02', {})
" clean up

View File

@@ -2798,8 +2798,11 @@ func Test_listen_invalid_address()
" port number too large
call assert_fails("call ch_listen('localhost:99999')", 'E475:')
" port number zero
call assert_fails("call ch_listen('localhost:0')", 'E475:')
" port number zero should let the OS assign an available port
let ch = ch_listen('localhost:0')
call assert_equal('open', ch_status(ch))
call assert_notequal(0, ch_info(ch).port)
call ch_close(ch)
" port number negative
call assert_fails("call ch_listen('localhost:-1')", 'E475:')

View File

@@ -371,6 +371,11 @@ func Test_perl_in_sandbox()
sandbox perl print 'test'
let messages = split(execute('message'), "\n")
call assert_match("'print' trapped by operation mask", messages[-1])
try
sandbox perldo print "hello sandbox"
call assert_report('perldo in the sandbox')
catch /^Vim\%((\S\+)\)\=:E48:/
endtry
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@@ -115,4 +115,49 @@ func Test_restricted_mode()
call delete('Xresult')
endfunc
" Test that external diff is blocked in restricted mode.
" Using :diffupdate with 'diffopt' excluding "internal" would call an external
" diff program via call_shell(), which must be blocked.
func Test_restricted_diff()
let lines =<< trim END
set diffopt=filler
call writefile(['line1', 'line2'], 'Xrfile1', 'D')
call writefile(['line1', 'line3'], 'Xrfile2', 'D')
edit Xrfile1
diffthis
split Xrfile2
diffthis
call assert_fails('diffupdate', 'E145:')
call writefile(v:errors, 'Xresult')
qa!
END
call writefile(lines, 'Xrestricteddiff', 'D')
if RunVim([], [], '-Z --clean -S Xrestricteddiff')
call assert_equal([], readfile('Xresult'))
endif
call delete('Xresult')
endfunc
func Test_restricted_vim9_env()
let lines =<< trim END
vim9script
def SetEnv()
$ENV = '123'
enddef
var result = 'okay'
try
SetEnv()
catch /^Vim\%((\S\+)\)\=:E145:/
result = 'not-allowed'
endtry
writefile([result], 'XResult_env')
qa!
END
call writefile(lines, 'Xrestrictedvim9', 'D')
if RunVim([], [], '-Z --clean -S Xrestrictedvim9')
call assert_equal(['not-allowed'], readfile('XResult_env'))
endif
call delete('XResult_env')
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@@ -428,6 +428,10 @@ func Test_rubyeval_error()
call assert_fails('call rubyeval("(")')
endfunc
func Test_rubyeval_sandbox()
call assert_fails('sandbox call rubyeval("1+1")', 'E48:')
endfunc
" Test for various heredoc syntax
func Test_ruby_heredoc()
ruby << END

View File

@@ -2374,4 +2374,68 @@ func Test_resize_from_another_tabpage()
call StopVimInTerminal(buf)
endfunc
" When shrinking a window and the only other window has 'winfixheight'
" with 'winminheight'=0, freed rows must go to the wfh window.
func Test_winfixheight_resize_wmh_zero()
set winminheight=0 laststatus=0
let id1 = win_getid()
copen
let id2 = win_getid()
wincmd w
wincmd _
let wi1 = getwininfo(id1)[0]
let wi2 = getwininfo(id2)[0]
let exp = &lines - wi1.status_height - wi2.height - wi2.status_height - &ch
call assert_equal([exp, 1], [wi1.height, wi1.status_height])
call assert_equal([0, 0], [wi2.height, wi2.status_height])
wincmd w " enter qf (height 0 -> 1)
let wi1 = getwininfo(id1)[0]
let wi2 = getwininfo(id2)[0]
let exp = &lines - wi1.status_height - wi2.height - wi2.status_height - &ch
call assert_equal(exp, wi1.height)
call assert_equal(1, wi2.height)
wincmd w
" Freed rows must go to qf (wfh, only other window).
" Before the fix, the rows were lost (fr_height sum < topframe fr_height),
" resulting in wrong window heights in subsequent operations.
1wincmd _
let wi1 = getwininfo(id1)[0]
let wi2 = getwininfo(id2)[0]
call assert_equal(1, wi1.height)
let exp = &lines - wi1.height - wi1.status_height - &ch
call assert_equal(exp, wi2.height)
wincmd w
99wincmd +
let wi1 = getwininfo(id1)[0]
let wi2 = getwininfo(id2)[0]
call assert_equal(0, wi1.height)
let exp = &lines - wi1.height - wi1.status_height - &ch
call assert_equal(exp, wi2.height)
99wincmd -
let wi1 = getwininfo(id1)[0]
let wi2 = getwininfo(id2)[0]
let exp = &lines - wi1.status_height - wi2.height - &ch
call assert_equal(exp, wi1.height)
call assert_equal(1, wi2.height)
" The original bug caused a crash here, but could not be reproduced in the
" test. Kept as-is, though it has no particular significance.
wincmd w
call feedkeys("999i\<CR>\<Esc>", 'tx')
call feedkeys("ggMi" .. repeat("\<CR>", 99) .. "\<Esc>", 'tx')
let wi1 = getwininfo(id1)[0]
let wi2 = getwininfo(id2)[0]
let exp = &lines - wi1.status_height - wi2.height - &ch
call assert_equal(exp, wi1.height)
call assert_equal(1, wi2.height)
cclose
set winminheight& laststatus&
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@@ -734,6 +734,30 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
180,
/**/
179,
/**/
178,
/**/
177,
/**/
176,
/**/
175,
/**/
174,
/**/
173,
/**/
172,
/**/
171,
/**/
170,
/**/
169,
/**/
168,
/**/

View File

@@ -4458,6 +4458,8 @@ exec_instructions(ectx_T *ectx)
// store $ENV
case ISN_STOREENV:
if (check_restricted())
goto theend;
--ectx->ec_stack.ga_len;
tv = STACK_TV_BOT(0);
vim_setenv_ext(iptr->isn_arg.string, tv_get_string(tv));

View File

@@ -6650,7 +6650,7 @@ frame_setheight(frame_T *curfrp, int height)
room_reserved = room + room_cmdline - height;
// If there is only a 'winfixheight' window and making the
// window smaller, need to make the other window taller.
if (take < 0 && room - curfrp->fr_height < room_reserved)
if (take < 0 && room - curfrp->fr_height <= room_reserved)
room_reserved = 0;
if (take > 0 && room_cmdline > 0)