Compare commits

...

12 Commits

Author SHA1 Message Date
glepnir
0531e07c0d
Merge c14954a840 into 738320188f 2024-12-18 11:10:08 +02:00
zeertzjq
738320188f
test(old): fix incorrect comment in test_preview.vim (#31619) 2024-12-18 10:21:52 +08:00
zeertzjq
38f554e9c4
vim-patch:a977883: runtime(doc): Fix style in fold.txt (#31617)
closes: vim/vim#16236

a977883ef3

Co-authored-by: h-east <h.east.727@gmail.com>
2024-12-18 09:12:04 +08:00
zeertzjq
f7c42433c5
vim-patch:9.1.0940: Wrong cursor shape with "gq" and 'indentexpr' executes :normal (#31616)
Problem:  Wrong cursor shape with "gq" and 'indentexpr' executes :normal
Solution: Update cursor and mouse shape after restoring old_State.
          (zeertzjq)

closes: vim/vim#16241

Solution: Update cursor and mouse shape after restoring old_State.

6c3027744e
2024-12-18 09:04:32 +08:00
zeertzjq
51c380238c
Merge pull request #31615 from zeertzjq/vim-9.1.0936
vim-patch:9.1.{0936,0941,0942}: ComplMatchIns highlight
2024-12-18 08:40:23 +08:00
zeertzjq
b7da54aa9e vim-patch:9.1.0942: a few typos were found
Problem:  a few typos were found
Solution: fix them (zeertzjq)

closes: vim/vim#16232

d32bf0a067
2024-12-18 08:15:31 +08:00
zeertzjq
2f7b385f2e vim-patch:9.1.0941: ComplMatchIns doesn't work after multibyte chars
Problem:  ComplMatchIns doesn't work after multibyte chars
          (after v9.1.0936)
Solution: Use (ptr - line) instead of wlv.col (zeertzjq).

closes: vim/vim#16233

f4ccada5c3
2024-12-18 08:15:31 +08:00
zeertzjq
c830901e8c vim-patch:9.1.0936: cannot highlight completed text
Problem:  cannot highlight completed text
Solution: (optionally) highlight auto-completed text using the
          ComplMatchIns highlight group (glepnir)

closes: vim/vim#16173

6a38aff218

Co-authored-by: glepnir <glephunter@gmail.com>
2024-12-18 08:15:31 +08:00
Gregory Anders
0dd933265f
feat(terminal)!: cursor shape and blink (#31562)
When a terminal application running inside the terminal emulator sets
the cursor shape or blink status of the cursor, update the cursor in the
parent terminal to match.

This removes the "virtual cursor" that has been in use by the terminal
emulator since the beginning. The original rationale for using the
virtual cursor was to avoid having to support additional UI methods to
change the cursor color for other (non-TUI) UIs, instead relying on the
TermCursor and TermCursorNC highlight groups.

The TermCursor highlight group is now used in the default 'guicursor'
value, which has a new entry for Terminal mode. However, the
TermCursorNC highlight group is no longer supported: since terminal
windows now use the real cursor, when the window is not focused there is
no cursor displayed in the window at all, so there is nothing to
highlight. Users can still use the StatusLineTermNC highlight group to
differentiate non-focused terminal windows.

BREAKING CHANGE: The TermCursorNC highlight group is no longer supported.
2024-12-17 07:11:41 -06:00
Shougo
df367cf91c
test: unreliable test "messages &messagesopt wait" #31548 2024-12-17 04:19:55 -08:00
luukvbaal
6bf2a6fc5b
refactor(api): always use TRY_WRAP #31600
Problem:  Two separate try/end wrappers, that only marginally differ by
          restoring a few variables. Wrappers that don't restore
          previous state are dangerous to use in "api-fast" functions.
Solution: Remove wrappers that don't restore the previous state.
          Always use TRY_WRAP.
2024-12-17 04:12:22 -08:00
glepnir
c14954a840 feat(option): add winborder option
Problem:
There is currently no global option to define the default border style for floating windows. This leads to repetitive code when developers need consistent styling across multiple floating windows.

Solution:
Introduce a global option winborder to specify the default border style for floating windows. When a floating window is created without explicitly specifying a border style, the value of the winborder option will be used. This simplifies configuration and ensures consistency in floating window appearance.
2024-12-10 15:05:01 +08:00
71 changed files with 1764 additions and 1053 deletions

View File

@ -60,6 +60,7 @@ hi('PmenuMatch', { link = 'Pmenu' })
hi('PmenuMatchSel', { link = 'PmenuSel' })
hi('PmenuExtra', { link = 'Pmenu' })
hi('PmenuExtraSel', { link = 'PmenuSel' })
hi('ComplMatchIns', { link = 'Normal' })
hi('Substitute', { link = 'Search' })
hi('Whitespace', { link = 'NonText' })
hi('MsgSeparator', { link = 'StatusLine' })

View File

@ -3236,28 +3236,20 @@ nvim_open_win({buffer}, {enter}, {config}) *nvim_open_win()*
`eob` flag of 'fillchars' to a space char, and clearing
the |hl-EndOfBuffer| region in 'winhighlight'.
• border: Style of (optional) window border. This can either
be a string or an array. The string values are
• "none": No border (default).
• "single": A single line box.
• "double": A double line box.
• "rounded": Like "single", but with rounded corners
("╭" etc.).
• "solid": Adds padding by a single whitespace cell.
• "shadow": A drop shadow effect by blending with the
background.
• If it is an array, it should have a length of eight or
any divisor of eight. The array will specify the eight
chars building up the border in a clockwise fashion
starting with the top-left corner. As an example, the
double box style could be specified as: >
[ "╔", "═" ,"╗", "║", "╝", "═", "╚", "║" ].
be a string or an array. The string values are the same as
those described in 'winborder'. If it is an array, it
should have a length of eight or any divisor of eight. The
array will specify the eight chars building up the border
in a clockwise fashion starting with the top-left corner.
As an example, the double box style could be specified as: >
[ "╔", "═" ,"╗", "║", "╝", "═", "╚", "║" ].
<
If the number of chars are less than eight, they will be
repeated. Thus an ASCII border could be specified as >
[ "/", "-", \"\\\\\", "|" ],
If the number of chars are less than eight, they will be
repeated. Thus an ASCII border could be specified as >
[ "/", "-", \"\\\\\", "|" ],
<
or all chars the same as >
[ "x" ].
or all chars the same as >
[ "x" ].
<
An empty string can be used to turn off a specific border,
for instance, >

View File

@ -38,6 +38,10 @@ DIAGNOSTICS
- The "cursor_position" parameter of |vim.diagnostic.JumpOpts| is renamed to
"pos"
HIGHLIGHTS
• *TermCursorNC* As of Nvim 0.11, unfocused |terminal| windows no
longer have any cursor.
TREESITTER
• *TSNode:child_containing_descendant()* Use
|TSNode:child_with_descendant()| instead; it is identical except that it can

View File

@ -101,7 +101,8 @@ The result of foldexpr then determines the fold level as follows:
"<1", "<2", .. a fold with this level ends at this line
">1", ">2", .. a fold with this level starts at this line
The result values "=", "s" and "a" are more expensive, please see |fold-expr-slow|.
The result values "=", "s" and "a" are more expensive, please see
|fold-expr-slow|.
It is not required to mark the start (end) of a fold with ">1" ("<1"), a fold
will also start (end) when the fold level is higher (lower) than the fold
@ -117,7 +118,7 @@ For debugging the 'debug' option can be set to "msg", the error messages will
be visible then.
If the 'foldexpr' expression starts with s: or |<SID>|, then it is replaced
with the script ID (|local-function|). Examples: >
with the script ID (|local-function|). Examples: >
set foldexpr=s:MyFoldExpr()
set foldexpr=<SID>SomeFoldExpr()
<
@ -141,7 +142,7 @@ end in that line.
It may happen that folds are not updated properly. You can use |zx| or |zX|
to force updating folds.
Minimizing Computational Cost *fold-expr-slow*
MINIMIZING COMPUTATIONAL COST *fold-expr-slow*
Due to its computational cost, this fold method can make Vim unresponsive,
especially when the fold level of all lines have to be initially computed.
@ -149,13 +150,15 @@ Afterwards, after each change, Vim restricts the computation of foldlevels
to those lines whose fold level was affected by it (and reuses the known
foldlevels of all the others).
The fold expression should therefore strive to minimize the number of dependent
lines needed for the computation of a given line: For example, try to avoid the
"=", "a" and "s" return values, because these will require the evaluation of the
fold levels on previous lines until an independent fold level is found.
The fold expression should therefore strive to minimize the number of
dependent lines needed for the computation of a given line: For example, try
to avoid the "=", "a" and "s" return values, because these will require the
evaluation of the fold levels on previous lines until an independent fold
level is found.
If this proves difficult, the next best thing could be to cache all fold levels
in a buffer-local variable (b:foldlevels) that is only updated on |b:changedtick|:
If this proves difficult, the next best thing could be to cache all fold
levels in a buffer-local variable (b:foldlevels) that is only updated on
|b:changedtick|:
>vim
func MyFoldFunc()
if b:lasttick == b:changedtick
@ -406,8 +409,8 @@ zX Undo manually opened and closed folds: re-apply 'foldlevel'.
Also forces recomputing folds, like |zx|.
*zm*
zm Fold more: Subtract |v:count1| from 'foldlevel'. If 'foldlevel' was
already zero nothing happens.
zm Fold more: Subtract |v:count1| from 'foldlevel'. If
'foldlevel' was already zero nothing happens.
'foldenable' will be set.
*zM*
@ -471,7 +474,7 @@ zk Move upwards to the end of the previous fold. A closed fold
EXECUTING COMMANDS ON FOLDS ~
:[range]foldd[oopen] {cmd} *:foldd* *:folddo* *:folddoopen*
:[range]foldd[oopen] {cmd} *:foldd* *:folddo* *:folddoopen*
Execute {cmd} on all lines that are not in a closed fold.
When [range] is given, only these lines are used.
Each time {cmd} is executed the cursor is positioned on the
@ -559,7 +562,7 @@ When there is room after the text, it is filled with the character specified
by 'fillchars'.
If the 'foldtext' expression starts with s: or |<SID>|, then it is replaced
with the script ID (|local-function|). Examples: >
with the script ID (|local-function|). Examples: >
set foldtext=s:MyFoldText()
set foldtext=<SID>SomeFoldText()
<

View File

@ -118,8 +118,8 @@ Note that when using ":" any motion becomes charwise exclusive.
*inclusive-motion-selection-exclusive*
When 'selection' is "exclusive", |Visual| mode is active and an inclusive
motion has been used, the cursor position will be adjusted by another
character to the right, so that visual selction includes the expected text and
can be acted upon.
character to the right, so that the Visual selection includes the expected
text and can be acted upon.
*forced-motion*
FORCING A MOTION TO BE LINEWISE, CHARWISE OR BLOCKWISE

View File

@ -87,6 +87,11 @@ EVENTS
• |vim.ui_attach()| callbacks for |ui-messages| `msg_show` events are executed in
|api-fast| context.
HIGHLIGHTS
• |TermCursorNC| is removed and no longer supported. Unfocused terminals no
longer have a cursor.
LSP
• Improved rendering of LSP hover docs. |K-lsp-default|
@ -211,6 +216,7 @@ EDITOR
• On Windows, filename arguments on the command-line prefixed with "~\" or
"~/" are now expanded to the user's profile directory, not a relative path
to a literal "~" directory.
• |hl-ComplMatchIns| shows matched text of the currently inserted completion.
• |hl-PmenuMatch| and |hl-PmenuMatchSel| show matched text in completion popup.
EVENTS
@ -281,6 +287,12 @@ TERMINAL
'scrollback' are not reflown.
• The |terminal| now supports OSC 8 escape sequences and will display
hyperlinks in supporting host terminals.
• The |terminal| now uses the actual cursor, rather than a "virtual" cursor.
This means that escape codes sent by applications running in a terminal
buffer can change the cursor shape and visibility. However, it also
means that the |TermCursorNC| highlight group is no longer supported: an
unfocused terminal window will have no cursor at all (so there is nothing to
highlight).
TREESITTER

View File

@ -2977,7 +2977,7 @@ A jump table for the options with a short description can be found at |Q_op|.
An |OptionSet| autocmd can be used to set it up to match automatically.
*'guicursor'* *'gcr'* *E545* *E546* *E548* *E549*
'guicursor' 'gcr' string (default "n-v-c-sm:block,i-ci-ve:ver25,r-cr-o:hor20")
'guicursor' 'gcr' string (default "n-v-c-sm:block,i-ci-ve:ver25,r-cr-o:hor20,t:block-blinkon500-blinkoff500-TermCursor")
global
Configures the cursor style for each mode. Works in the GUI and many
terminals. See |tui-cursor-shape|.
@ -3005,6 +3005,7 @@ A jump table for the options with a short description can be found at |Q_op|.
ci Command-line Insert mode
cr Command-line Replace mode
sm showmatch in Insert mode
t Terminal mode
a all modes
The argument-list is a dash separated list of these arguments:
hor{N} horizontal bar, {N} percent of the character height
@ -3021,7 +3022,8 @@ A jump table for the options with a short description can be found at |Q_op|.
cursor is not shown. Times are in msec. When one of
the numbers is zero, there is no blinking. E.g.: >vim
set guicursor=n:blinkon0
< - Default is "blinkon0" for each mode.
<
Default is "blinkon0" for each mode.
{group-name}
Highlight group that decides the color and font of the
cursor.
@ -7123,6 +7125,18 @@ A jump table for the options with a short description can be found at |Q_op|.
UI-dependent. Works best with RGB colors. 'termguicolors'
*'winborder'*
'winborder' string (default "")
global
Defines the default border style of floating windows. The default value
is empty, which is equivalent to "none". Valid values include:
- "none": No border.
- "single": A single line box.
- "double": A double line box.
- "rounded": Like "single", but with rounded corners ("╭" etc.).
- "solid": Adds padding by a single whitespace cell.
- "shadow": A drop shadow effect by blending with the background.
*'window'* *'wi'*
'window' 'wi' number (default screen height - 1)
global

View File

@ -5162,8 +5162,6 @@ EndOfBuffer Filler lines (~) after the end of the buffer.
By default, this is highlighted like |hl-NonText|.
*hl-TermCursor*
TermCursor Cursor in a focused terminal.
*hl-TermCursorNC*
TermCursorNC Cursor in an unfocused terminal.
*hl-ErrorMsg*
ErrorMsg Error messages on the command line.
*hl-WinSeparator*
@ -5245,6 +5243,8 @@ PmenuMatch Popup menu: Matched text in normal item. Combined with
*hl-PmenuMatchSel*
PmenuMatchSel Popup menu: Matched text in selected item. Combined with
|hl-PmenuMatch| and |hl-PmenuSel|.
*hl-ComplMatchIns*
ComplMatchIns Matched text of the currently inserted completion.
*hl-Question*
Question |hit-enter| prompt and yes/no questions.
*hl-QuickFixLine*

View File

@ -101,7 +101,7 @@ Configuration *terminal-config*
Options: 'modified', 'scrollback'
Events: |TermOpen|, |TermEnter|, |TermLeave|, |TermClose|
Highlight groups: |hl-TermCursor|, |hl-TermCursorNC|
Highlight groups: |hl-TermCursor|
Terminal sets local defaults for some options, which may differ from your
global configuration.

View File

@ -325,7 +325,6 @@ Highlight groups:
- |hl-MsgSeparator| highlights separator for scrolled messages
- |hl-Substitute|
- |hl-TermCursor|
- |hl-TermCursorNC|
- |hl-WinSeparator| highlights window separators
- |hl-Whitespace| highlights 'listchars' whitespace
- |hl-WinBar| highlights 'winbar'

View File

@ -1804,17 +1804,11 @@ function vim.api.nvim_open_term(buffer, opts) end
--- 'fillchars' to a space char, and clearing the
--- `hl-EndOfBuffer` region in 'winhighlight'.
--- - border: Style of (optional) window border. This can either be a string
--- or an array. The string values are
--- - "none": No border (default).
--- - "single": A single line box.
--- - "double": A double line box.
--- - "rounded": Like "single", but with rounded corners ("╭" etc.).
--- - "solid": Adds padding by a single whitespace cell.
--- - "shadow": A drop shadow effect by blending with the background.
--- - If it is an array, it should have a length of eight or any divisor of
--- eight. The array will specify the eight chars building up the border
--- in a clockwise fashion starting with the top-left corner. As an
--- example, the double box style could be specified as:
--- or an array. The string values are the same as those described in 'winborder'.
--- If it is an array, it should have a length of eight or any divisor of
--- eight. The array will specify the eight chars building up the border
--- in a clockwise fashion starting with the top-left corner. As an
--- example, the double box style could be specified as:
--- ```
--- [ "╔", "═" ,"╗", "║", "╝", "═", "╚", "║" ].
--- ```

View File

@ -2783,6 +2783,7 @@ vim.go.gp = vim.go.grepprg
--- ci Command-line Insert mode
--- cr Command-line Replace mode
--- sm showmatch in Insert mode
--- t Terminal mode
--- a all modes
--- The argument-list is a dash separated list of these arguments:
--- hor{N} horizontal bar, {N} percent of the character height
@ -2802,7 +2803,8 @@ vim.go.gp = vim.go.grepprg
--- ```vim
--- set guicursor=n:blinkon0
--- ```
--- - Default is "blinkon0" for each mode.
---
--- Default is "blinkon0" for each mode.
--- {group-name}
--- Highlight group that decides the color and font of the
--- cursor.
@ -2848,7 +2850,7 @@ vim.go.gp = vim.go.grepprg
---
---
--- @type string
vim.o.guicursor = "n-v-c-sm:block,i-ci-ve:ver25,r-cr-o:hor20"
vim.o.guicursor = "n-v-c-sm:block,i-ci-ve:ver25,r-cr-o:hor20,t:block-blinkon500-blinkoff500-TermCursor"
vim.o.gcr = vim.o.guicursor
vim.go.guicursor = vim.o.guicursor
vim.go.gcr = vim.go.guicursor
@ -7796,6 +7798,19 @@ vim.o.winbl = vim.o.winblend
vim.wo.winblend = vim.o.winblend
vim.wo.winbl = vim.wo.winblend
--- Defines the default border style of floating windows. The default value
--- is empty, which is equivalent to "none". Valid values include:
--- - "none": No border.
--- - "single": A single line box.
--- - "double": A double line box.
--- - "rounded": Like "single", but with rounded corners ("╭" etc.).
--- - "solid": Adds padding by a single whitespace cell.
--- - "shadow": A drop shadow effect by blending with the background.
---
--- @type string
vim.o.winborder = ""
vim.go.winborder = vim.o.winborder
--- Window height used for `CTRL-F` and `CTRL-B` when there is only one
--- window and the value is smaller than 'lines' minus one. The screen
--- will scroll 'window' minus two lines, with a minimum of one.

View File

@ -63,7 +63,7 @@ syn keyword vimGroup contained Comment Constant String Character Number Boolean
syn keyword vimHLGroup contained ErrorMsg IncSearch ModeMsg NonText StatusLine StatusLineNC EndOfBuffer VertSplit DiffText PmenuSbar TabLineSel TabLineFill Cursor lCursor QuickFixLine CursorLineSign CursorLineFold CurSearch PmenuKind PmenuKindSel PmenuMatch PmenuMatchSel PmenuExtra PmenuExtraSel Normal Directory LineNr CursorLineNr MoreMsg Question Search SpellBad SpellCap SpellRare SpellLocal PmenuThumb Pmenu PmenuSel SpecialKey Title WarningMsg WildMenu Folded FoldColumn SignColumn Visual DiffAdd DiffChange DiffDelete TabLine CursorColumn CursorLine ColorColumn MatchParen StatusLineTerm StatusLineTermNC CursorIM LineNrAbove LineNrBelow
syn match vimHLGroup contained "\<Conceal\>"
syn keyword vimOnlyHLGroup contained Menu Scrollbar ToolbarButton ToolbarLine Tooltip VisualNOS
syn keyword nvimHLGroup contained FloatBorder FloatFooter FloatTitle MsgSeparator NormalFloat NormalNC Substitute TermCursor TermCursorNC VisualNC Whitespace WinBar WinBarNC WinSeparator
syn keyword nvimHLGroup contained FloatBorder FloatFooter FloatTitle MsgSeparator NormalFloat NormalNC Substitute TermCursor VisualNC Whitespace WinBar WinBarNC WinSeparator
"}}}2
syn case match

View File

@ -360,93 +360,91 @@ void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integ
memchrsub(lines[i], NUL, NL, l.size);
}
try_start();
if (!MODIFIABLE(buf)) {
api_set_error(err, kErrorTypeException, "Buffer is not 'modifiable'");
goto end;
}
if (u_save_buf(buf, (linenr_T)(start - 1), (linenr_T)end) == FAIL) {
api_set_error(err, kErrorTypeException, "Failed to save undo information");
goto end;
}
bcount_t deleted_bytes = get_region_bytecount(buf, (linenr_T)start, (linenr_T)end, 0, 0);
// If the size of the range is reducing (ie, new_len < old_len) we
// need to delete some old_len. We do this at the start, by
// repeatedly deleting line "start".
size_t to_delete = (new_len < old_len) ? old_len - new_len : 0;
for (size_t i = 0; i < to_delete; i++) {
if (ml_delete_buf(buf, (linenr_T)start, false) == FAIL) {
api_set_error(err, kErrorTypeException, "Failed to delete line");
goto end;
}
}
if (to_delete > 0) {
extra -= (ptrdiff_t)to_delete;
}
// For as long as possible, replace the existing old_len with the
// new old_len. This is a more efficient operation, as it requires
// less memory allocation and freeing.
size_t to_replace = old_len < new_len ? old_len : new_len;
bcount_t inserted_bytes = 0;
for (size_t i = 0; i < to_replace; i++) {
int64_t lnum = start + (int64_t)i;
VALIDATE(lnum < MAXLNUM, "%s", "Index out of bounds", {
goto end;
});
if (ml_replace_buf(buf, (linenr_T)lnum, lines[i], false, true) == FAIL) {
api_set_error(err, kErrorTypeException, "Failed to replace line");
TRY_WRAP(err, {
if (!MODIFIABLE(buf)) {
api_set_error(err, kErrorTypeException, "Buffer is not 'modifiable'");
goto end;
}
inserted_bytes += (bcount_t)strlen(lines[i]) + 1;
}
// Now we may need to insert the remaining new old_len
for (size_t i = to_replace; i < new_len; i++) {
int64_t lnum = start + (int64_t)i - 1;
VALIDATE(lnum < MAXLNUM, "%s", "Index out of bounds", {
goto end;
});
if (ml_append_buf(buf, (linenr_T)lnum, lines[i], 0, false) == FAIL) {
api_set_error(err, kErrorTypeException, "Failed to insert line");
if (u_save_buf(buf, (linenr_T)(start - 1), (linenr_T)end) == FAIL) {
api_set_error(err, kErrorTypeException, "Failed to save undo information");
goto end;
}
inserted_bytes += (bcount_t)strlen(lines[i]) + 1;
bcount_t deleted_bytes = get_region_bytecount(buf, (linenr_T)start, (linenr_T)end, 0, 0);
extra++;
}
// Adjust marks. Invalidate any which lie in the
// changed range, and move any in the remainder of the buffer.
linenr_T adjust = end > start ? MAXLNUM : 0;
mark_adjust_buf(buf, (linenr_T)start, (linenr_T)(end - 1), adjust, (linenr_T)extra,
true, true, kExtmarkNOOP);
extmark_splice(buf, (int)start - 1, 0, (int)(end - start), 0,
deleted_bytes, (int)new_len, 0, inserted_bytes,
kExtmarkUndo);
changed_lines(buf, (linenr_T)start, 0, (linenr_T)end, (linenr_T)extra, true);
FOR_ALL_TAB_WINDOWS(tp, win) {
if (win->w_buffer == buf) {
fix_cursor(win, (linenr_T)start, (linenr_T)end, (linenr_T)extra);
// If the size of the range is reducing (ie, new_len < old_len) we
// need to delete some old_len. We do this at the start, by
// repeatedly deleting line "start".
size_t to_delete = (new_len < old_len) ? old_len - new_len : 0;
for (size_t i = 0; i < to_delete; i++) {
if (ml_delete_buf(buf, (linenr_T)start, false) == FAIL) {
api_set_error(err, kErrorTypeException, "Failed to delete line");
goto end;
}
}
}
end:
try_end(err);
if (to_delete > 0) {
extra -= (ptrdiff_t)to_delete;
}
// For as long as possible, replace the existing old_len with the
// new old_len. This is a more efficient operation, as it requires
// less memory allocation and freeing.
size_t to_replace = old_len < new_len ? old_len : new_len;
bcount_t inserted_bytes = 0;
for (size_t i = 0; i < to_replace; i++) {
int64_t lnum = start + (int64_t)i;
VALIDATE(lnum < MAXLNUM, "%s", "Index out of bounds", {
goto end;
});
if (ml_replace_buf(buf, (linenr_T)lnum, lines[i], false, true) == FAIL) {
api_set_error(err, kErrorTypeException, "Failed to replace line");
goto end;
}
inserted_bytes += (bcount_t)strlen(lines[i]) + 1;
}
// Now we may need to insert the remaining new old_len
for (size_t i = to_replace; i < new_len; i++) {
int64_t lnum = start + (int64_t)i - 1;
VALIDATE(lnum < MAXLNUM, "%s", "Index out of bounds", {
goto end;
});
if (ml_append_buf(buf, (linenr_T)lnum, lines[i], 0, false) == FAIL) {
api_set_error(err, kErrorTypeException, "Failed to insert line");
goto end;
}
inserted_bytes += (bcount_t)strlen(lines[i]) + 1;
extra++;
}
// Adjust marks. Invalidate any which lie in the
// changed range, and move any in the remainder of the buffer.
linenr_T adjust = end > start ? MAXLNUM : 0;
mark_adjust_buf(buf, (linenr_T)start, (linenr_T)(end - 1), adjust, (linenr_T)extra,
true, true, kExtmarkNOOP);
extmark_splice(buf, (int)start - 1, 0, (int)(end - start), 0,
deleted_bytes, (int)new_len, 0, inserted_bytes,
kExtmarkUndo);
changed_lines(buf, (linenr_T)start, 0, (linenr_T)end, (linenr_T)extra, true);
FOR_ALL_TAB_WINDOWS(tp, win) {
if (win->w_buffer == buf) {
fix_cursor(win, (linenr_T)start, (linenr_T)end, (linenr_T)extra);
}
}
end:;
});
}
/// Sets (replaces) a range in the buffer
@ -593,101 +591,99 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In
new_byte += (bcount_t)(last_item.size) + 1;
}
try_start();
if (!MODIFIABLE(buf)) {
api_set_error(err, kErrorTypeException, "Buffer is not 'modifiable'");
goto end;
}
// Small note about undo states: unlike set_lines, we want to save the
// undo state of one past the end_row, since end_row is inclusive.
if (u_save_buf(buf, (linenr_T)start_row - 1, (linenr_T)end_row + 1) == FAIL) {
api_set_error(err, kErrorTypeException, "Failed to save undo information");
goto end;
}
ptrdiff_t extra = 0; // lines added to text, can be negative
size_t old_len = (size_t)(end_row - start_row + 1);
// If the size of the range is reducing (ie, new_len < old_len) we
// need to delete some old_len. We do this at the start, by
// repeatedly deleting line "start".
size_t to_delete = (new_len < old_len) ? old_len - new_len : 0;
for (size_t i = 0; i < to_delete; i++) {
if (ml_delete_buf(buf, (linenr_T)start_row, false) == FAIL) {
api_set_error(err, kErrorTypeException, "Failed to delete line");
goto end;
}
}
if (to_delete > 0) {
extra -= (ptrdiff_t)to_delete;
}
// For as long as possible, replace the existing old_len with the
// new old_len. This is a more efficient operation, as it requires
// less memory allocation and freeing.
size_t to_replace = old_len < new_len ? old_len : new_len;
for (size_t i = 0; i < to_replace; i++) {
int64_t lnum = start_row + (int64_t)i;
VALIDATE((lnum < MAXLNUM), "%s", "Index out of bounds", {
goto end;
});
if (ml_replace_buf(buf, (linenr_T)lnum, lines[i], false, true) == FAIL) {
api_set_error(err, kErrorTypeException, "Failed to replace line");
goto end;
}
}
// Now we may need to insert the remaining new old_len
for (size_t i = to_replace; i < new_len; i++) {
int64_t lnum = start_row + (int64_t)i - 1;
VALIDATE((lnum < MAXLNUM), "%s", "Index out of bounds", {
goto end;
});
if (ml_append_buf(buf, (linenr_T)lnum, lines[i], 0, false) == FAIL) {
api_set_error(err, kErrorTypeException, "Failed to insert line");
TRY_WRAP(err, {
if (!MODIFIABLE(buf)) {
api_set_error(err, kErrorTypeException, "Buffer is not 'modifiable'");
goto end;
}
extra++;
}
// Small note about undo states: unlike set_lines, we want to save the
// undo state of one past the end_row, since end_row is inclusive.
if (u_save_buf(buf, (linenr_T)start_row - 1, (linenr_T)end_row + 1) == FAIL) {
api_set_error(err, kErrorTypeException, "Failed to save undo information");
goto end;
}
colnr_T col_extent = (colnr_T)(end_col
- ((end_row == start_row) ? start_col : 0));
ptrdiff_t extra = 0; // lines added to text, can be negative
size_t old_len = (size_t)(end_row - start_row + 1);
// Adjust marks. Invalidate any which lie in the
// changed range, and move any in the remainder of the buffer.
// Do not adjust any cursors. need to use column-aware logic (below)
linenr_T adjust = end_row >= start_row ? MAXLNUM : 0;
mark_adjust_buf(buf, (linenr_T)start_row, (linenr_T)end_row, adjust, (linenr_T)extra,
true, true, kExtmarkNOOP);
extmark_splice(buf, (int)start_row - 1, (colnr_T)start_col,
(int)(end_row - start_row), col_extent, old_byte,
(int)new_len - 1, (colnr_T)last_item.size, new_byte,
kExtmarkUndo);
changed_lines(buf, (linenr_T)start_row, 0, (linenr_T)end_row + 1, (linenr_T)extra, true);
FOR_ALL_TAB_WINDOWS(tp, win) {
if (win->w_buffer == buf) {
if (win->w_cursor.lnum >= start_row && win->w_cursor.lnum <= end_row) {
fix_cursor_cols(win, (linenr_T)start_row, (colnr_T)start_col, (linenr_T)end_row,
(colnr_T)end_col, (linenr_T)new_len, (colnr_T)last_item.size);
} else {
fix_cursor(win, (linenr_T)start_row, (linenr_T)end_row, (linenr_T)extra);
// If the size of the range is reducing (ie, new_len < old_len) we
// need to delete some old_len. We do this at the start, by
// repeatedly deleting line "start".
size_t to_delete = (new_len < old_len) ? old_len - new_len : 0;
for (size_t i = 0; i < to_delete; i++) {
if (ml_delete_buf(buf, (linenr_T)start_row, false) == FAIL) {
api_set_error(err, kErrorTypeException, "Failed to delete line");
goto end;
}
}
}
end:
try_end(err);
if (to_delete > 0) {
extra -= (ptrdiff_t)to_delete;
}
// For as long as possible, replace the existing old_len with the
// new old_len. This is a more efficient operation, as it requires
// less memory allocation and freeing.
size_t to_replace = old_len < new_len ? old_len : new_len;
for (size_t i = 0; i < to_replace; i++) {
int64_t lnum = start_row + (int64_t)i;
VALIDATE((lnum < MAXLNUM), "%s", "Index out of bounds", {
goto end;
});
if (ml_replace_buf(buf, (linenr_T)lnum, lines[i], false, true) == FAIL) {
api_set_error(err, kErrorTypeException, "Failed to replace line");
goto end;
}
}
// Now we may need to insert the remaining new old_len
for (size_t i = to_replace; i < new_len; i++) {
int64_t lnum = start_row + (int64_t)i - 1;
VALIDATE((lnum < MAXLNUM), "%s", "Index out of bounds", {
goto end;
});
if (ml_append_buf(buf, (linenr_T)lnum, lines[i], 0, false) == FAIL) {
api_set_error(err, kErrorTypeException, "Failed to insert line");
goto end;
}
extra++;
}
colnr_T col_extent = (colnr_T)(end_col
- ((end_row == start_row) ? start_col : 0));
// Adjust marks. Invalidate any which lie in the
// changed range, and move any in the remainder of the buffer.
// Do not adjust any cursors. need to use column-aware logic (below)
linenr_T adjust = end_row >= start_row ? MAXLNUM : 0;
mark_adjust_buf(buf, (linenr_T)start_row, (linenr_T)end_row, adjust, (linenr_T)extra,
true, true, kExtmarkNOOP);
extmark_splice(buf, (int)start_row - 1, (colnr_T)start_col,
(int)(end_row - start_row), col_extent, old_byte,
(int)new_len - 1, (colnr_T)last_item.size, new_byte,
kExtmarkUndo);
changed_lines(buf, (linenr_T)start_row, 0, (linenr_T)end_row + 1, (linenr_T)extra, true);
FOR_ALL_TAB_WINDOWS(tp, win) {
if (win->w_buffer == buf) {
if (win->w_cursor.lnum >= start_row && win->w_cursor.lnum <= end_row) {
fix_cursor_cols(win, (linenr_T)start_row, (colnr_T)start_col, (linenr_T)end_row,
(colnr_T)end_col, (linenr_T)new_len, (colnr_T)last_item.size);
} else {
fix_cursor(win, (linenr_T)start_row, (linenr_T)end_row, (linenr_T)extra);
}
}
}
end:;
});
}
/// Gets a range from the buffer.
@ -965,26 +961,27 @@ void nvim_buf_set_name(Buffer buffer, String name, Error *err)
return;
}
try_start();
int ren_ret = OK;
TRY_WRAP(err, {
const bool is_curbuf = buf == curbuf;
const int save_acd = p_acd;
if (!is_curbuf) {
// Temporarily disable 'autochdir' when setting file name for another buffer.
p_acd = false;
}
const bool is_curbuf = buf == curbuf;
const int save_acd = p_acd;
if (!is_curbuf) {
// Temporarily disable 'autochdir' when setting file name for another buffer.
p_acd = false;
}
// Using aucmd_*: autocommands will be executed by rename_buffer
aco_save_T aco;
aucmd_prepbuf(&aco, buf);
ren_ret = rename_buffer(name.data);
aucmd_restbuf(&aco);
// Using aucmd_*: autocommands will be executed by rename_buffer
aco_save_T aco;
aucmd_prepbuf(&aco, buf);
int ren_ret = rename_buffer(name.data);
aucmd_restbuf(&aco);
if (!is_curbuf) {
p_acd = save_acd;
}
});
if (!is_curbuf) {
p_acd = save_acd;
}
if (try_end(err)) {
if (ERROR_SET(err)) {
return;
}
@ -1204,15 +1201,18 @@ Object nvim_buf_call(Buffer buffer, LuaRef fun, Error *err)
if (!buf) {
return NIL;
}
try_start();
aco_save_T aco;
aucmd_prepbuf(&aco, buf);
Array args = ARRAY_DICT_INIT;
Object res = nlua_call_ref(fun, NULL, args, kRetLuaref, NULL, err);
Object res = OBJECT_INIT;
TRY_WRAP(err, {
aco_save_T aco;
aucmd_prepbuf(&aco, buf);
Array args = ARRAY_DICT_INIT;
res = nlua_call_ref(fun, NULL, args, kRetLuaref, NULL, err);
aucmd_restbuf(&aco);
});
aucmd_restbuf(&aco);
try_end(err);
return res;
}

View File

@ -42,8 +42,10 @@
/// Start block that may cause Vimscript exceptions while evaluating another code
///
/// Used when caller is supposed to be operating when other Vimscript code is being
/// processed and that “other Vimscript code” must not be affected.
/// Used just in case caller is supposed to be operating when other Vimscript code
/// is being processed and that “other Vimscript code” must not be affected.
///
/// @warning Avoid calling directly; use TRY_WRAP instead.
///
/// @param[out] tstate Location where try state should be saved.
void try_enter(TryState *const tstate)
@ -55,75 +57,33 @@ void try_enter(TryState *const tstate)
.current_exception = current_exception,
.msg_list = (const msglist_T *const *)msg_list,
.private_msg_list = NULL,
.trylevel = trylevel,
.got_int = got_int,
.did_throw = did_throw,
.need_rethrow = need_rethrow,
.did_emsg = did_emsg,
};
// `msg_list` controls the collection of abort-causing non-exception errors,
// which would otherwise be ignored. This pattern is from do_cmdline().
msg_list = &tstate->private_msg_list;
current_exception = NULL;
trylevel = 1;
got_int = false;
did_throw = false;
need_rethrow = false;
did_emsg = false;
}
/// End try block, set the error message if any and restore previous state
///
/// @warning Return is consistent with most functions (false on error), not with
/// try_end (true on error).
///
/// @param[in] tstate Previous state to restore.
/// @param[out] err Location where error should be saved.
///
/// @return false if error occurred, true otherwise.
bool try_leave(const TryState *const tstate, Error *const err)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
const bool ret = !try_end(err);
assert(trylevel == 0);
assert(!need_rethrow);
assert(!got_int);
assert(!did_throw);
assert(!did_emsg);
assert(msg_list == &tstate->private_msg_list);
assert(*msg_list == NULL);
assert(current_exception == NULL);
msg_list = (msglist_T **)tstate->msg_list;
current_exception = tstate->current_exception;
trylevel = tstate->trylevel;
got_int = tstate->got_int;
did_throw = tstate->did_throw;
need_rethrow = tstate->need_rethrow;
did_emsg = tstate->did_emsg;
return ret;
}
/// Starts a block that may cause Vimscript exceptions; must be mirrored by `try_end()` call.
///
/// Note: use `TRY_WRAP` instead (except in `FUNC_API_FAST` functions such as nvim_get_runtime_file).
///
/// To be used as a replacement of `:try … catch … endtry` in C code, in cases
/// when error flag could not already be set. If there may be pending error
/// state at the time try_start() is executed which needs to be preserved,
/// try_enter()/try_leave() pair should be used instead.
void try_start(void)
{
trylevel++;
}
/// Ends a `try_start` block; sets error message if any and returns true if an error occurred.
/// Ends a `try_enter` block; sets error message if any.
///
/// Note: use `TRY_WRAP` instead (except in `FUNC_API_FAST` functions such as nvim_get_runtime_file).
/// @warning Avoid calling directly; use TRY_WRAP instead.
///
/// @param err Pointer to the stack-allocated error object
/// @return true if an error occurred
bool try_end(Error *err)
/// @param[out] err Pointer to the stack-allocated error object
void try_leave(const TryState *const tstate, Error *const err)
FUNC_ATTR_NONNULL_ALL
{
// Note: all globals manipulated here should be saved/restored in
// try_enter/try_leave.
assert(trylevel > 0);
trylevel--;
// Set by emsg(), affects aborting(). See also enter_cleanup().
@ -166,7 +126,20 @@ bool try_end(Error *err)
discard_current_exception();
}
return ERROR_SET(err);
assert(msg_list == &tstate->private_msg_list);
assert(*msg_list == NULL);
assert(current_exception == NULL);
assert(!got_int);
assert(!did_throw);
assert(!need_rethrow);
assert(!did_emsg);
// Restore the exception context.
msg_list = (msglist_T **)tstate->msg_list;
current_exception = tstate->current_exception;
got_int = tstate->got_int;
did_throw = tstate->did_throw;
need_rethrow = tstate->need_rethrow;
did_emsg = tstate->did_emsg;
}
/// Recursively expands a vimscript value in a dict

View File

@ -147,27 +147,19 @@ typedef struct {
except_T *current_exception;
msglist_T *private_msg_list;
const msglist_T *const *msg_list;
int trylevel;
int got_int;
bool did_throw;
int need_rethrow;
int did_emsg;
} TryState;
// `msg_list` controls the collection of abort-causing non-exception errors,
// which would otherwise be ignored. This pattern is from do_cmdline().
//
// TODO(bfredl): prepare error-handling at "top level" (nv_event).
#define TRY_WRAP(err, code) \
do { \
msglist_T **saved_msg_list = msg_list; \
msglist_T *private_msg_list; \
msg_list = &private_msg_list; \
private_msg_list = NULL; \
try_start(); \
TryState tstate; \
try_enter(&tstate); \
code; \
try_end(err); \
msg_list = saved_msg_list; /* Restore the exception context. */ \
try_leave(&tstate, err); \
} while (0)
// Execute code with cursor position saved and restored and textlock active.

View File

@ -146,11 +146,9 @@ void nvim_tabpage_set_win(Tabpage tabpage, Window win, Error *err)
}
if (tp == curtab) {
try_start();
win_goto(wp);
if (!try_end(err) && curwin != wp) {
api_set_error(err, kErrorTypeException, "Failed to switch to window %d", win);
}
TRY_WRAP(err, {
win_goto(wp);
});
} else if (tp->tp_curwin != wp) {
tp->tp_prevwin = tp->tp_curwin;
tp->tp_curwin = wp;

View File

@ -594,12 +594,10 @@ ArrayOf(String) nvim_get_runtime_file(String name, Boolean all, Arena *arena, Er
kvi_init(cookie.rv);
int flags = DIP_DIRFILE | (all ? DIP_ALL : 0);
TryState tstate;
// XXX: intentionally not using `TRY_WRAP`, to avoid `did_emsg=false` in `try_end`.
try_enter(&tstate);
do_in_runtimepath((name.size ? name.data : ""), flags, find_runtime_cb, &cookie);
vim_ignored = try_leave(&tstate, err);
TRY_WRAP(err, {
do_in_runtimepath((name.size ? name.data : ""), flags, find_runtime_cb, &cookie);
});
return arena_take_arraybuilder(arena, &cookie.rv);
}
@ -952,68 +950,70 @@ void nvim_set_current_win(Window window, Error *err)
Buffer nvim_create_buf(Boolean listed, Boolean scratch, Error *err)
FUNC_API_SINCE(6)
{
try_start();
// Block autocommands for now so they don't mess with the buffer before we
// finish configuring it.
block_autocmds();
Buffer ret = 0;
TRY_WRAP(err, {
// Block autocommands for now so they don't mess with the buffer before we
// finish configuring it.
block_autocmds();
buf_T *buf = buflist_new(NULL, NULL, 0,
BLN_NOOPT | BLN_NEW | (listed ? BLN_LISTED : 0));
if (buf == NULL) {
unblock_autocmds();
goto fail;
}
// Open the memline for the buffer. This will avoid spurious autocmds when
// a later nvim_buf_set_lines call would have needed to "open" the buffer.
if (ml_open(buf) == FAIL) {
unblock_autocmds();
goto fail;
}
// Set last_changedtick to avoid triggering a TextChanged autocommand right
// after it was added.
buf->b_last_changedtick = buf_get_changedtick(buf);
buf->b_last_changedtick_i = buf_get_changedtick(buf);
buf->b_last_changedtick_pum = buf_get_changedtick(buf);
// Only strictly needed for scratch, but could just as well be consistent
// and do this now. Buffer is created NOW, not when it later first happens
// to reach a window or aucmd_prepbuf() ..
buf_copy_options(buf, BCO_ENTER | BCO_NOHELP);
if (scratch) {
set_option_direct_for(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("hide"), OPT_LOCAL, 0,
kOptScopeBuf, buf);
set_option_direct_for(kOptBuftype, STATIC_CSTR_AS_OPTVAL("nofile"), OPT_LOCAL, 0,
kOptScopeBuf, buf);
assert(buf->b_ml.ml_mfp->mf_fd < 0); // ml_open() should not have opened swapfile already
buf->b_p_swf = false;
buf->b_p_ml = false;
}
buf_T *buf = buflist_new(NULL, NULL, 0,
BLN_NOOPT | BLN_NEW | (listed ? BLN_LISTED : 0));
if (buf == NULL) {
unblock_autocmds();
goto fail;
}
// Open the memline for the buffer. This will avoid spurious autocmds when
// a later nvim_buf_set_lines call would have needed to "open" the buffer.
if (ml_open(buf) == FAIL) {
unblock_autocmds();
goto fail;
}
bufref_T bufref;
set_bufref(&bufref, buf);
if (apply_autocmds(EVENT_BUFNEW, NULL, NULL, false, buf)
&& !bufref_valid(&bufref)) {
goto fail;
}
if (listed
&& apply_autocmds(EVENT_BUFADD, NULL, NULL, false, buf)
&& !bufref_valid(&bufref)) {
goto fail;
}
// Set last_changedtick to avoid triggering a TextChanged autocommand right
// after it was added.
buf->b_last_changedtick = buf_get_changedtick(buf);
buf->b_last_changedtick_i = buf_get_changedtick(buf);
buf->b_last_changedtick_pum = buf_get_changedtick(buf);
ret = buf->b_fnum;
fail:;
});
// Only strictly needed for scratch, but could just as well be consistent
// and do this now. Buffer is created NOW, not when it later first happens
// to reach a window or aucmd_prepbuf() ..
buf_copy_options(buf, BCO_ENTER | BCO_NOHELP);
if (scratch) {
set_option_direct_for(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("hide"), OPT_LOCAL, 0,
kOptScopeBuf, buf);
set_option_direct_for(kOptBuftype, STATIC_CSTR_AS_OPTVAL("nofile"), OPT_LOCAL, 0,
kOptScopeBuf, buf);
assert(buf->b_ml.ml_mfp->mf_fd < 0); // ml_open() should not have opened swapfile already
buf->b_p_swf = false;
buf->b_p_ml = false;
}
unblock_autocmds();
bufref_T bufref;
set_bufref(&bufref, buf);
if (apply_autocmds(EVENT_BUFNEW, NULL, NULL, false, buf)
&& !bufref_valid(&bufref)) {
goto fail;
}
if (listed
&& apply_autocmds(EVENT_BUFADD, NULL, NULL, false, buf)
&& !bufref_valid(&bufref)) {
goto fail;
}
try_end(err);
return buf->b_fnum;
fail:
if (!try_end(err)) {
if (ret == 0 && !ERROR_SET(err)) {
api_set_error(err, kErrorTypeException, "Failed to create buffer");
}
return 0;
return ret;
}
/// Open a terminal instance in a buffer

View File

@ -78,24 +78,24 @@ String exec_impl(uint64_t channel_id, String src, Dict(exec_opts) *opts, Error *
capture_ga = &capture_local;
}
try_start();
if (opts->output) {
msg_silent++;
msg_col = 0; // prevent leading spaces
}
TRY_WRAP(err, {
if (opts->output) {
msg_silent++;
msg_col = 0; // prevent leading spaces
}
const sctx_T save_current_sctx = api_set_sctx(channel_id);
const sctx_T save_current_sctx = api_set_sctx(channel_id);
do_source_str(src.data, "nvim_exec2()");
if (opts->output) {
capture_ga = save_capture_ga;
msg_silent = save_msg_silent;
// Put msg_col back where it was, since nothing should have been written.
msg_col = save_msg_col;
}
do_source_str(src.data, "nvim_exec2()");
if (opts->output) {
capture_ga = save_capture_ga;
msg_silent = save_msg_silent;
// Put msg_col back where it was, since nothing should have been written.
msg_col = save_msg_col;
}
current_sctx = save_current_sctx;
try_end(err);
current_sctx = save_current_sctx;
});
if (ERROR_SET(err)) {
goto theend;

View File

@ -160,17 +160,11 @@
/// 'fillchars' to a space char, and clearing the
/// |hl-EndOfBuffer| region in 'winhighlight'.
/// - border: Style of (optional) window border. This can either be a string
/// or an array. The string values are
/// - "none": No border (default).
/// - "single": A single line box.
/// - "double": A double line box.
/// - "rounded": Like "single", but with rounded corners ("╭" etc.).
/// - "solid": Adds padding by a single whitespace cell.
/// - "shadow": A drop shadow effect by blending with the background.
/// - If it is an array, it should have a length of eight or any divisor of
/// eight. The array will specify the eight chars building up the border
/// in a clockwise fashion starting with the top-left corner. As an
/// example, the double box style could be specified as:
/// or an array. The string values are the same as those described in 'winborder'.
/// If it is an array, it should have a length of eight or any divisor of
/// eight. The array will specify the eight chars building up the border
/// in a clockwise fashion starting with the top-left corner. As an
/// example, the double box style could be specified as:
/// ```
/// [ "╔", "═" ,"╗", "║", "╝", "═", "╚", "║" ].
/// ```
@ -937,11 +931,11 @@ static void parse_border_style(Object style, WinConfig *fconfig, Error *err)
char chars[8][MAX_SCHAR_SIZE];
bool shadow_color;
} defaults[] = {
{ "double", { "", "", "", "", "", "", "", "" }, false },
{ "single", { "", "", "", "", "", "", "", "" }, false },
{ "shadow", { "", "", " ", " ", " ", " ", " ", "" }, true },
{ "rounded", { "", "", "", "", "", "", "", "" }, false },
{ "solid", { " ", " ", " ", " ", " ", " ", " ", " " }, false },
{ opt_winborder_values[0], { "", "", "", "", "", "", "", "" }, false },
{ opt_winborder_values[1], { "", "", "", "", "", "", "", "" }, false },
{ opt_winborder_values[2], { "", "", " ", " ", " ", " ", " ", "" }, true },
{ opt_winborder_values[3], { "", "", "", "", "", "", "", "" }, false },
{ opt_winborder_values[4], { " ", " ", " ", " ", " ", " ", " ", " " }, false },
{ NULL, { { NUL } }, false },
};
@ -1282,12 +1276,13 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
}
}
if (HAS_KEY_X(config, border)) {
if (HAS_KEY_X(config, border) || *p_winbd != NUL) {
if (is_split) {
api_set_error(err, kErrorTypeValidation, "non-float cannot have 'border'");
goto fail;
}
parse_border_style(config->border, fconfig, err);
Object style = config->border.type != kObjectTypeNil ? config->border : CSTR_AS_OBJ(p_winbd);
parse_border_style(style, fconfig, err);
if (ERROR_SET(err)) {
goto fail;
}

View File

@ -368,19 +368,16 @@ void nvim_win_hide(Window window, Error *err)
}
tabpage_T *tabpage = win_find_tabpage(win);
TryState tstate;
try_enter(&tstate);
// Never close the autocommand window.
if (is_aucmd_win(win)) {
emsg(_(e_autocmd_close));
} else if (tabpage == curtab) {
win_close(win, false, false);
} else {
win_close_othertab(win, false, tabpage);
}
vim_ignored = try_leave(&tstate, err);
TRY_WRAP(err, {
// Never close the autocommand window.
if (is_aucmd_win(win)) {
emsg(_(e_autocmd_close));
} else if (tabpage == curtab) {
win_close(win, false, false);
} else {
win_close_othertab(win, false, tabpage);
}
});
}
/// Closes the window (like |:close| with a |window-ID|).
@ -400,10 +397,9 @@ void nvim_win_close(Window window, Boolean force, Error *err)
}
tabpage_T *tabpage = win_find_tabpage(win);
TryState tstate;
try_enter(&tstate);
ex_win_close(force, win, tabpage == curtab ? NULL : tabpage);
vim_ignored = try_leave(&tstate, err);
TRY_WRAP(err, {
ex_win_close(force, win, tabpage == curtab ? NULL : tabpage);
});
}
/// Calls a function with window as temporary current window.

View File

@ -341,9 +341,11 @@ void check_cursor_col(win_T *win)
} else if (win->w_cursor.col >= len) {
// Allow cursor past end-of-line when:
// - in Insert mode or restarting Insert mode
// - in Terminal mode
// - in Visual mode and 'selection' isn't "old"
// - 'virtualedit' is set
if ((State & MODE_INSERT) || restart_edit
|| (State & MODE_TERMINAL)
|| (VIsual_active && *p_sel != 'o')
|| (cur_ve_flags & kOptVeFlagOnemore)
|| virtual_active(win)) {

View File

@ -45,6 +45,7 @@ cursorentry_T shape_table[SHAPE_IDX_COUNT] = {
{ "more", 0, 0, 0, 0, 0, 0, 0, 0, "m", SHAPE_MOUSE },
{ "more_lastline", 0, 0, 0, 0, 0, 0, 0, 0, "ml", SHAPE_MOUSE },
{ "showmatch", 0, 0, 0, 100, 100, 100, 0, 0, "sm", SHAPE_CURSOR },
{ "terminal", 0, 0, 0, 0, 0, 0, 0, 0, "t", SHAPE_CURSOR },
};
/// Converts cursor_shapes into an Array of Dictionaries
@ -321,6 +322,8 @@ int cursor_get_mode_idx(void)
{
if (State == MODE_SHOWMATCH) {
return SHAPE_IDX_SM;
} else if (State == MODE_TERMINAL) {
return SHAPE_IDX_TERM;
} else if (State & VREPLACE_FLAG) {
return SHAPE_IDX_R;
} else if (State & REPLACE_FLAG) {

View File

@ -23,7 +23,8 @@ typedef enum {
SHAPE_IDX_MORE = 14, ///< Hit-return or More
SHAPE_IDX_MOREL = 15, ///< Hit-return or More in last line
SHAPE_IDX_SM = 16, ///< showing matching paren
SHAPE_IDX_COUNT = 17,
SHAPE_IDX_TERM = 17, ///< Terminal mode
SHAPE_IDX_COUNT = 18,
} ModeShape;
typedef enum {

View File

@ -31,6 +31,7 @@
#include "nvim/highlight_defs.h"
#include "nvim/highlight_group.h"
#include "nvim/indent.h"
#include "nvim/insexpand.h"
#include "nvim/mark_defs.h"
#include "nvim/marktree_defs.h"
#include "nvim/match.h"
@ -934,6 +935,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
colnr_T vcol_prev = -1; // "wlv.vcol" of previous character
ScreenGrid *grid = &wp->w_grid; // grid specific to the window
const bool in_curline = wp == curwin && lnum == curwin->w_cursor.lnum;
const bool has_fold = foldinfo.fi_level != 0 && foldinfo.fi_lines > 0;
const bool has_foldtext = has_fold && *wp->w_p_fdt != NUL;
@ -1117,7 +1119,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
}
// Check if the char under the cursor should be inverted (highlighted).
if (!highlight_match && lnum == curwin->w_cursor.lnum && wp == curwin
if (!highlight_match && in_curline
&& cursor_is_block_during_visual(*p_sel == 'e')) {
noinvcur = true;
}
@ -1629,8 +1631,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
}
// When still displaying '$' of change command, stop at cursor.
if (dollar_vcol >= 0 && wp == curwin
&& lnum == wp->w_cursor.lnum && wlv.vcol >= wp->w_virtcol) {
if (dollar_vcol >= 0 && in_curline && wlv.vcol >= wp->w_virtcol) {
draw_virt_text(wp, buf, win_col_offset, &wlv.col, wlv.row);
// don't clear anything after wlv.col
wlv_put_linebuf(wp, &wlv, wlv.col, false, bg_attr, 0);
@ -1786,6 +1787,16 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
wlv.char_attr = hl_combine_attr(char_attr_base, char_attr_pri);
}
// Apply ComplMatchIns highlight if needed.
if (wlv.filler_todo <= 0
&& (State & MODE_INSERT) && in_curline && ins_compl_active()) {
int ins_match_attr = ins_compl_col_range_attr((int)(ptr - line));
if (ins_match_attr > 0) {
char_attr_pri = hl_combine_attr(char_attr_pri, ins_match_attr);
wlv.char_attr = hl_combine_attr(char_attr_base, char_attr_pri);
}
}
if (draw_folded && has_foldtext && wlv.n_extra == 0 && wlv.col == win_col_offset) {
const int v = (int)(ptr - line);
linenr_T lnume = lnum + foldinfo.fi_lines - 1;
@ -2446,8 +2457,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
// With 'virtualedit' we may never reach cursor position, but we still
// need to correct the cursor column, so do that at end of line.
if (!did_wcol && wlv.filler_todo <= 0
&& wp == curwin && lnum == wp->w_cursor.lnum
&& conceal_cursor_line(wp)
&& in_curline && conceal_cursor_line(wp)
&& (wlv.vcol + wlv.skip_cells >= wp->w_virtcol || mb_schar == NUL)) {
wp->w_wcol = wlv.col - wlv.boguscols;
if (wlv.vcol + wlv.skip_cells < wp->w_virtcol) {
@ -2640,7 +2650,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
// Update w_cline_height and w_cline_folded if the cursor line was
// updated (saves a call to plines_win() later).
if (wp == curwin && lnum == curwin->w_cursor.lnum) {
if (in_curline) {
curwin->w_cline_row = startrow;
curwin->w_cline_height = wlv.row - startrow;
curwin->w_cline_folded = has_fold;

View File

@ -787,9 +787,7 @@ static uint8_t *command_line_enter(int firstc, int count, int indent, bool clear
setmouse();
setcursor();
TryState tstate;
Error err = ERROR_INIT;
bool tl_ret = true;
char firstcbuf[2];
firstcbuf[0] = (char)(firstc > 0 ? firstc : '-');
firstcbuf[1] = 0;
@ -802,20 +800,19 @@ static uint8_t *command_line_enter(int firstc, int count, int indent, bool clear
tv_dict_add_str(dict, S_LEN("cmdtype"), firstcbuf);
tv_dict_add_nr(dict, S_LEN("cmdlevel"), ccline.level);
tv_dict_set_keys_readonly(dict);
try_enter(&tstate);
TRY_WRAP(&err, {
apply_autocmds(EVENT_CMDLINEENTER, firstcbuf, firstcbuf, false, curbuf);
restore_v_event(dict, &save_v_event);
});
apply_autocmds(EVENT_CMDLINEENTER, firstcbuf, firstcbuf, false, curbuf);
restore_v_event(dict, &save_v_event);
tl_ret = try_leave(&tstate, &err);
if (!tl_ret && ERROR_SET(&err)) {
if (ERROR_SET(&err)) {
msg_putchar('\n');
msg_scroll = true;
msg_puts_hl(err.msg, HLF_E, true);
api_clear_error(&err);
redrawcmd();
}
tl_ret = true;
err = ERROR_INIT;
}
may_trigger_modechanged();
@ -873,10 +870,10 @@ static uint8_t *command_line_enter(int firstc, int count, int indent, bool clear
// not readonly:
tv_dict_add_bool(dict, S_LEN("abort"),
s->gotesc ? kBoolVarTrue : kBoolVarFalse);
try_enter(&tstate);
apply_autocmds(EVENT_CMDLINELEAVE, firstcbuf, firstcbuf, false, curbuf);
// error printed below, to avoid redraw issues
tl_ret = try_leave(&tstate, &err);
TRY_WRAP(&err, {
apply_autocmds(EVENT_CMDLINELEAVE, firstcbuf, firstcbuf, false, curbuf);
// error printed below, to avoid redraw issues
});
if (tv_dict_get_number(dict, "abort") != 0) {
s->gotesc = true;
}
@ -929,7 +926,7 @@ static uint8_t *command_line_enter(int firstc, int count, int indent, bool clear
msg_scroll = s->save_msg_scroll;
redir_off = false;
if (!tl_ret && ERROR_SET(&err)) {
if (ERROR_SET(&err)) {
msg_putchar('\n');
emsg(err.msg);
did_emsg = false;
@ -937,7 +934,7 @@ static uint8_t *command_line_enter(int firstc, int count, int indent, bool clear
}
// When the command line was typed, no need for a wait-return prompt.
if (s->some_key_typed && tl_ret) {
if (s->some_key_typed && !ERROR_SET(&err)) {
need_wait_return = false;
}
@ -2315,11 +2312,13 @@ static win_T *cmdpreview_open_win(buf_T *cmdpreview_buf)
win_T *preview_win = curwin;
Error err = ERROR_INIT;
int result = OK;
// Switch to preview buffer
try_start();
int result = do_buffer(DOBUF_GOTO, DOBUF_FIRST, FORWARD, cmdpreview_buf->handle, 0);
if (try_end(&err) || result == FAIL) {
TRY_WRAP(&err, {
result = do_buffer(DOBUF_GOTO, DOBUF_FIRST, FORWARD, cmdpreview_buf->handle, 0);
});
if (ERROR_SET(&err) || result == FAIL) {
api_clear_error(&err);
return NULL;
}
@ -2600,9 +2599,10 @@ static bool cmdpreview_may_show(CommandLineState *s)
// open the preview window. The preview callback also handles doing the changes and highlights for
// the preview.
Error err = ERROR_INIT;
try_start();
cmdpreview_type = execute_cmd(&ea, &cmdinfo, true);
if (try_end(&err)) {
TRY_WRAP(&err, {
cmdpreview_type = execute_cmd(&ea, &cmdinfo, true);
});
if (ERROR_SET(&err)) {
api_clear_error(&err);
cmdpreview_type = 0;
}
@ -2643,7 +2643,6 @@ end:
static void do_autocmd_cmdlinechanged(int firstc)
{
if (has_event(EVENT_CMDLINECHANGED)) {
TryState tstate;
Error err = ERROR_INIT;
save_v_event_T save_v_event;
dict_T *dict = get_v_event(&save_v_event);
@ -2656,13 +2655,11 @@ static void do_autocmd_cmdlinechanged(int firstc)
tv_dict_add_str(dict, S_LEN("cmdtype"), firstcbuf);
tv_dict_add_nr(dict, S_LEN("cmdlevel"), ccline.level);
tv_dict_set_keys_readonly(dict);
try_enter(&tstate);
apply_autocmds(EVENT_CMDLINECHANGED, firstcbuf, firstcbuf, false, curbuf);
restore_v_event(dict, &save_v_event);
bool tl_ret = try_leave(&tstate, &err);
if (!tl_ret && ERROR_SET(&err)) {
TRY_WRAP(&err, {
apply_autocmds(EVENT_CMDLINECHANGED, firstcbuf, firstcbuf, false, curbuf);
restore_v_event(dict, &save_v_event);
});
if (ERROR_SET(&err)) {
msg_putchar('\n');
msg_scroll = true;
msg_puts_hl(err.msg, HLF_E, true);
@ -3179,11 +3176,9 @@ static bool color_cmdline(CmdlineInfo *colored_ccline)
static int prev_prompt_errors = 0;
Callback color_cb = CALLBACK_NONE;
bool can_free_cb = false;
TryState tstate;
Error err = ERROR_INIT;
const char *err_errmsg = e_intern2;
bool dgc_ret = true;
bool tl_ret = true;
if (colored_ccline->prompt_id != prev_prompt_id) {
prev_prompt_errors = 0;
@ -3196,16 +3191,16 @@ static bool color_cmdline(CmdlineInfo *colored_ccline)
assert(colored_ccline->input_fn);
color_cb = colored_ccline->highlight_callback;
} else if (colored_ccline->cmdfirstc == ':') {
try_enter(&tstate);
err_errmsg = N_("E5408: Unable to get g:Nvim_color_cmdline callback: %s");
dgc_ret = tv_dict_get_callback(&globvardict, S_LEN("Nvim_color_cmdline"),
&color_cb);
tl_ret = try_leave(&tstate, &err);
TRY_WRAP(&err, {
err_errmsg = N_("E5408: Unable to get g:Nvim_color_cmdline callback: %s");
dgc_ret = tv_dict_get_callback(&globvardict, S_LEN("Nvim_color_cmdline"),
&color_cb);
});
can_free_cb = true;
} else if (colored_ccline->cmdfirstc == '=') {
color_expr_cmdline(colored_ccline, ccline_colors);
}
if (!tl_ret || !dgc_ret) {
if (ERROR_SET(&err) || !dgc_ret) {
goto color_cmdline_error;
}
@ -3226,20 +3221,22 @@ static bool color_cmdline(CmdlineInfo *colored_ccline)
// correct, with msg_col it just misses leading `:`. Since `redraw!` in
// callback lags this is least of the user problems.
//
// Also using try_enter() because error messages may overwrite typed
// Also using TRY_WRAP because error messages may overwrite typed
// command-line which is not expected.
getln_interrupted_highlight = false;
try_enter(&tstate);
err_errmsg = N_("E5407: Callback has thrown an exception: %s");
const int saved_msg_col = msg_col;
msg_silent++;
const bool cbcall_ret = callback_call(&color_cb, 1, &arg, &tv);
msg_silent--;
msg_col = saved_msg_col;
if (got_int) {
getln_interrupted_highlight = true;
}
if (!try_leave(&tstate, &err) || !cbcall_ret) {
bool cbcall_ret = true;
TRY_WRAP(&err, {
err_errmsg = N_("E5407: Callback has thrown an exception: %s");
const int saved_msg_col = msg_col;
msg_silent++;
cbcall_ret = callback_call(&color_cb, 1, &arg, &tv);
msg_silent--;
msg_col = saved_msg_col;
if (got_int) {
getln_interrupted_highlight = true;
}
});
if (ERROR_SET(&err) || !cbcall_ret) {
goto color_cmdline_error;
}
if (tv.v_type != VAR_LIST) {

View File

@ -15,7 +15,6 @@ EXTERN const char *hlf_names[] INIT( = {
[HLF_8] = "SpecialKey",
[HLF_EOB] = "EndOfBuffer",
[HLF_TERM] = "TermCursor",
[HLF_TERMNC] = "TermCursorNC",
[HLF_AT] = "NonText",
[HLF_D] = "Directory",
[HLF_E] = "ErrorMsg",

View File

@ -63,7 +63,6 @@ typedef enum {
///< displayed different from what it is
HLF_EOB, ///< after the last line in the buffer
HLF_TERM, ///< terminal cursor focused
HLF_TERMNC, ///< terminal cursor unfocused
HLF_AT, ///< @ characters at end of screen, characters that don't really exist in the text
HLF_D, ///< directories in CTRL-D listing
HLF_E, ///< error messages

View File

@ -173,12 +173,12 @@ static const char *highlight_init_both[] = {
"default link PmenuKind Pmenu",
"default link PmenuKindSel PmenuSel",
"default link PmenuSbar Pmenu",
"default link ComplMatchIns Normal",
"default link Substitute Search",
"default link StatusLineTerm StatusLine",
"default link StatusLineTermNC StatusLineNC",
"default link TabLine StatusLineNC",
"default link TabLineFill TabLine",
"default link TermCursorNC NONE",
"default link VertSplit WinSeparator",
"default link VisualNOS Visual",
"default link Whitespace NonText",

View File

@ -256,6 +256,7 @@ static pos_T compl_startpos;
static int compl_length = 0;
static colnr_T compl_col = 0; ///< column where the text starts
///< that is being completed
static colnr_T compl_ins_end_col = 0;
static char *compl_orig_text = NULL; ///< text as it was before
///< completion started
/// Undo information to restore extmarks for original text.
@ -282,6 +283,11 @@ static size_t spell_bad_len = 0; // length of located bad word
static int compl_selected_item = -1;
// "compl_match_array" points the currently displayed list of entries in the
// popup menu. It is NULL when there is no popup menu.
static pumitem_T *compl_match_array = NULL;
static int compl_match_arraysize;
/// CTRL-X pressed in Insert mode.
void ins_ctrl_x(void)
{
@ -943,6 +949,30 @@ static bool ins_compl_equal(compl_T *match, char *str, size_t len)
return strncmp(match->cp_str, str, len) == 0;
}
/// when len is -1 mean use whole length of p otherwise part of p
static void ins_compl_insert_bytes(char *p, int len)
FUNC_ATTR_NONNULL_ALL
{
if (len == -1) {
len = (int)strlen(p);
}
assert(len >= 0);
ins_bytes_len(p, (size_t)len);
compl_ins_end_col = curwin->w_cursor.col - 1;
}
/// Checks if the column is within the currently inserted completion text
/// column range. If it is, it returns a special highlight attribute.
/// -1 mean normal item.
int ins_compl_col_range_attr(int col)
{
if (col >= compl_col && col < compl_ins_end_col) {
return syn_name2attr("ComplMatchIns");
}
return -1;
}
/// Reduce the longest common string for match "match".
static void ins_compl_longest_match(compl_T *match)
{
@ -952,7 +982,7 @@ static void ins_compl_longest_match(compl_T *match)
bool had_match = (curwin->w_cursor.col > compl_col);
ins_compl_delete(false);
ins_bytes(compl_leader + get_compl_len());
ins_compl_insert_bytes(compl_leader + get_compl_len(), -1);
ins_redraw(false);
// When the match isn't there (to avoid matching itself) remove it
@ -986,7 +1016,7 @@ static void ins_compl_longest_match(compl_T *match)
*p = NUL;
bool had_match = (curwin->w_cursor.col > compl_col);
ins_compl_delete(false);
ins_bytes(compl_leader + get_compl_len());
ins_compl_insert_bytes(compl_leader + get_compl_len(), -1);
ins_redraw(false);
// When the match isn't there (to avoid matching itself) remove it
@ -1058,11 +1088,6 @@ unsigned get_cot_flags(void)
return curbuf->b_cot_flags != 0 ? curbuf->b_cot_flags : cot_flags;
}
/// "compl_match_array" points the currently displayed list of entries in the
/// popup menu. It is NULL when there is no popup menu.
static pumitem_T *compl_match_array = NULL;
static int compl_match_arraysize;
/// Remove any popup menu.
static void ins_compl_del_pum(void)
{
@ -1678,6 +1703,7 @@ void ins_compl_clear(void)
compl_cont_status = 0;
compl_started = false;
compl_matches = 0;
compl_ins_end_col = 0;
XFREE_CLEAR(compl_pattern);
compl_patternlen = 0;
XFREE_CLEAR(compl_leader);
@ -1802,7 +1828,7 @@ static void ins_compl_new_leader(void)
{
ins_compl_del_pum();
ins_compl_delete(true);
ins_bytes(compl_leader + get_compl_len());
ins_compl_insert_bytes(compl_leader + get_compl_len(), -1);
compl_used_match = false;
if (compl_started) {
@ -2137,7 +2163,7 @@ static bool ins_compl_stop(const int c, const int prev_mode, bool retval)
const int compl_len = get_compl_len();
const int len = (int)strlen(p);
if (len > compl_len) {
ins_bytes_len(p + compl_len, (size_t)(len - compl_len));
ins_compl_insert_bytes(p + compl_len, len - compl_len);
}
}
restore_orig_extmarks();
@ -3639,7 +3665,7 @@ void ins_compl_insert(bool in_compl_func)
// Make sure we don't go over the end of the string, this can happen with
// illegal bytes.
if (compl_len < (int)strlen(compl_shown_match->cp_str)) {
ins_bytes(compl_shown_match->cp_str + compl_len);
ins_compl_insert_bytes(compl_shown_match->cp_str + compl_len, -1);
}
compl_used_match = !match_at_original_text(compl_shown_match);
@ -3888,14 +3914,15 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match
// Insert the text of the new completion, or the compl_leader.
if (compl_no_insert && !started) {
ins_bytes(compl_orig_text + get_compl_len());
ins_compl_insert_bytes(compl_orig_text + get_compl_len(), -1);
compl_used_match = false;
restore_orig_extmarks();
} else if (insert_match) {
if (!compl_get_longest || compl_used_match) {
ins_compl_insert(in_compl_func);
} else {
ins_bytes(compl_leader + get_compl_len());
assert(compl_leader != NULL);
ins_compl_insert_bytes(compl_leader + get_compl_len(), -1);
}
if (!strcmp(compl_curr_match->cp_str, compl_orig_text)) {
restore_orig_extmarks();

View File

@ -623,38 +623,32 @@ static int nlua_with(lua_State *L)
cmdmod.cmod_flags = flags;
apply_cmdmod(&cmdmod);
if (buf || win) {
try_start();
}
aco_save_T aco;
win_execute_T win_execute_args;
Error err = ERROR_INIT;
TRY_WRAP(&err, {
aco_save_T aco;
win_execute_T win_execute_args;
if (win) {
tabpage_T *tabpage = win_find_tabpage(win);
if (!win_execute_before(&win_execute_args, win, tabpage)) {
goto end;
if (win) {
tabpage_T *tabpage = win_find_tabpage(win);
if (!win_execute_before(&win_execute_args, win, tabpage)) {
goto end;
}
} else if (buf) {
aucmd_prepbuf(&aco, buf);
}
} else if (buf) {
aucmd_prepbuf(&aco, buf);
}
int s = lua_gettop(L);
lua_pushvalue(L, 2);
status = lua_pcall(L, 0, LUA_MULTRET, 0);
rets = lua_gettop(L) - s;
int s = lua_gettop(L);
lua_pushvalue(L, 2);
status = lua_pcall(L, 0, LUA_MULTRET, 0);
rets = lua_gettop(L) - s;
if (win) {
win_execute_after(&win_execute_args);
} else if (buf) {
aucmd_restbuf(&aco);
}
end:
if (buf || win) {
try_end(&err);
}
if (win) {
win_execute_after(&win_execute_args);
} else if (buf) {
aucmd_restbuf(&aco);
}
end:;
});
undo_cmdmod(&cmdmod);
cmdmod = save_cmdmod;

View File

@ -3933,7 +3933,7 @@ static bool switch_option_context(void *const ctx, OptScope scope, void *const f
== FAIL) {
restore_win_noblock(switchwin, true);
if (try_end(err)) {
if (ERROR_SET(err)) {
return false;
}
api_set_error(err, kErrorTypeException, "Problem while switching windows");

View File

@ -12,7 +12,7 @@
// option_vars.h: definition of global variables for settable options
#define HIGHLIGHT_INIT \
"8:SpecialKey,~:EndOfBuffer,z:TermCursor,Z:TermCursorNC,@:NonText,d:Directory,e:ErrorMsg," \
"8:SpecialKey,~:EndOfBuffer,z:TermCursor,@:NonText,d:Directory,e:ErrorMsg," \
"i:IncSearch,l:Search,y:CurSearch,m:MoreMsg,M:ModeMsg,n:LineNr,a:LineNrAbove,b:LineNrBelow," \
"N:CursorLineNr,G:CursorLineSign,O:CursorLineFold,r:Question,s:StatusLine,S:StatusLineNC," \
"c:VertSplit,t:Title,v:Visual,V:VisualNOS,w:WarningMsg,W:WildMenu,f:Folded,F:FoldColumn," \
@ -608,6 +608,7 @@ EXTERN OptInt p_wcm; ///< 'wildcharm'
EXTERN int p_wic; ///< 'wildignorecase'
EXTERN char *p_wim; ///< 'wildmode'
EXTERN int p_wmnu; ///< 'wildmenu'
EXTERN char *p_winbd; ///< 'winborder'
EXTERN OptInt p_wh; ///< 'winheight'
EXTERN OptInt p_wmh; ///< 'winminheight'
EXTERN OptInt p_wmw; ///< 'winminwidth'

View File

@ -3631,7 +3631,9 @@ return {
{
abbreviation = 'gcr',
cb = 'did_set_guicursor',
defaults = { if_true = 'n-v-c-sm:block,i-ci-ve:ver25,r-cr-o:hor20' },
defaults = {
if_true = 'n-v-c-sm:block,i-ci-ve:ver25,r-cr-o:hor20,t:block-blinkon500-blinkoff500-TermCursor',
},
deny_duplicates = true,
desc = [=[
Configures the cursor style for each mode. Works in the GUI and many
@ -3660,6 +3662,7 @@ return {
ci Command-line Insert mode
cr Command-line Replace mode
sm showmatch in Insert mode
t Terminal mode
a all modes
The argument-list is a dash separated list of these arguments:
hor{N} horizontal bar, {N} percent of the character height
@ -3676,7 +3679,8 @@ return {
cursor is not shown. Times are in msec. When one of
the numbers is zero, there is no blinking. E.g.: >vim
set guicursor=n:blinkon0
< - Default is "blinkon0" for each mode.
<
Default is "blinkon0" for each mode.
{group-name}
Highlight group that decides the color and font of the
cursor.
@ -10190,6 +10194,26 @@ return {
short_desc = N_('Controls transparency level for floating windows'),
type = 'number',
},
{
defaults = { if_true = '' },
cb = 'did_set_winborder',
values = { 'double', 'single', 'shadow', 'rounded', 'solid', 'none' },
desc = [=[
Defines the default border style of floating windows. The default value
is empty, which is equivalent to "none". Valid values include:
- "none": No border.
- "single": A single line box.
- "double": A double line box.
- "rounded": Like "single", but with rounded corners ("" etc.).
- "solid": Adds padding by a single whitespace cell.
- "shadow": A drop shadow effect by blending with the background.
]=],
full_name = 'winborder',
scope = { 'global' },
short_desc = N_('border of floating window'),
type = 'string',
varname = 'p_winbd',
},
{
abbreviation = 'wi',
cb = 'did_set_window',

View File

@ -2536,6 +2536,15 @@ const char *did_set_winhighlight(optset_T *args)
return NULL;
}
/// The 'winborder' option is changed.
const char *did_set_winborder(optset_T *args)
{
if (check_opt_strings(p_winbd, opt_winborder_values, true) != OK) {
return e_invarg;
}
return NULL;
}
int expand_set_winhighlight(optexpand_T *args, int *numMatches, char ***matches)
{
return expand_set_opt_generic(args, get_highlight_name, numMatches, matches);

View File

@ -138,14 +138,20 @@ void state_handle_k_event(void)
/// Return true if in the current mode we need to use virtual.
bool virtual_active(win_T *wp)
{
unsigned cur_ve_flags = get_ve_flags(wp);
// While an operator is being executed we return "virtual_op", because
// VIsual_active has already been reset, thus we can't check for "block"
// being used.
if (virtual_op != kNone) {
return virtual_op;
}
// In Terminal mode the cursor can be positioned anywhere by the application
if (State & MODE_TERMINAL) {
return true;
}
unsigned cur_ve_flags = get_ve_flags(wp);
return cur_ve_flags == kOptVeFlagAll
|| ((cur_ve_flags & kOptVeFlagBlock) && VIsual_active && VIsual_mode == Ctrl_V)
|| ((cur_ve_flags & kOptVeFlagInsert) && (State & MODE_INSERT));

View File

@ -52,6 +52,7 @@
#include "nvim/channel.h"
#include "nvim/channel_defs.h"
#include "nvim/cursor.h"
#include "nvim/cursor_shape.h"
#include "nvim/drawline.h"
#include "nvim/drawscreen.h"
#include "nvim/eval.h"
@ -160,15 +161,19 @@ struct terminal {
int invalid_start, invalid_end; // invalid rows in libvterm screen
struct {
int row, col;
int shape;
bool visible;
bool blink;
} cursor;
bool pending_resize; // pending width/height
struct {
bool resize; ///< pending width/height
bool cursor; ///< pending cursor shape or blink change
StringBuilder *send; ///< When there is a pending TermRequest autocommand, block and store input.
} pending;
bool color_set[16];
// When there is a pending TermRequest autocommand, block and store input.
StringBuilder *pending_send;
char *selection_buffer; /// libvterm selection buffer
StringBuilder selection; /// Growable array containing full selection data
@ -207,24 +212,24 @@ static void emit_termrequest(void **argv)
apply_autocmds_group(EVENT_TERMREQUEST, NULL, NULL, false, AUGROUP_ALL, buf, NULL, &data);
xfree(payload);
StringBuilder *term_pending_send = term->pending_send;
term->pending_send = NULL;
StringBuilder *term_pending_send = term->pending.send;
term->pending.send = NULL;
if (kv_size(*pending_send)) {
terminal_send(term, pending_send->items, pending_send->size);
kv_destroy(*pending_send);
}
if (term_pending_send != pending_send) {
term->pending_send = term_pending_send;
term->pending.send = term_pending_send;
}
xfree(pending_send);
}
static void schedule_termrequest(Terminal *term, char *payload, size_t payload_length)
{
term->pending_send = xmalloc(sizeof(StringBuilder));
kv_init(*term->pending_send);
term->pending.send = xmalloc(sizeof(StringBuilder));
kv_init(*term->pending.send);
multiqueue_put(main_loop.events, emit_termrequest, term, payload, (void *)payload_length,
term->pending_send);
term->pending.send);
}
static int parse_osc8(VTermStringFragment frag, int *attr)
@ -363,7 +368,7 @@ void terminal_open(Terminal **termpp, buf_T *buf, TerminalOptions opts)
// Create a new terminal instance and configure it
Terminal *term = *termpp = xcalloc(1, sizeof(Terminal));
term->opts = opts;
term->cursor.visible = true;
// Associate the terminal instance with the new buffer
term->buf_handle = buf->handle;
buf->terminal = term;
@ -387,6 +392,28 @@ void terminal_open(Terminal **termpp, buf_T *buf, TerminalOptions opts)
vterm_state_set_selection_callbacks(state, &vterm_selection_callbacks, term,
term->selection_buffer, SELECTIONBUF_SIZE);
VTermValue cursor_shape;
switch (shape_table[SHAPE_IDX_TERM].shape) {
case SHAPE_BLOCK:
cursor_shape.number = VTERM_PROP_CURSORSHAPE_BLOCK;
break;
case SHAPE_HOR:
cursor_shape.number = VTERM_PROP_CURSORSHAPE_UNDERLINE;
break;
case SHAPE_VER:
cursor_shape.number = VTERM_PROP_CURSORSHAPE_BAR_LEFT;
break;
}
vterm_state_set_termprop(state, VTERM_PROP_CURSORSHAPE, &cursor_shape);
VTermValue cursor_blink;
if (shape_table[SHAPE_IDX_TERM].blinkon != 0 && shape_table[SHAPE_IDX_TERM].blinkoff != 0) {
cursor_blink.boolean = true;
} else {
cursor_blink.boolean = false;
}
vterm_state_set_termprop(state, VTERM_PROP_CURSORBLINK, &cursor_blink);
// force a initial refresh of the screen to ensure the buffer will always
// have as many lines as screen rows when refresh_scrollback is called
term->invalid_start = 0;
@ -565,7 +592,7 @@ void terminal_check_size(Terminal *term)
vterm_set_size(term->vt, height, width);
vterm_screen_flush_damage(term->vts);
term->pending_resize = true;
term->pending.resize = true;
invalidate_terminal(term, -1, -1);
}
@ -614,16 +641,28 @@ bool terminal_enter(void)
curwin->w_p_so = 0;
curwin->w_p_siso = 0;
// Save the existing cursor entry since it may be modified by the application
cursorentry_T save_cursorentry = shape_table[SHAPE_IDX_TERM];
// Update the cursor shape table and flush changes to the UI
s->term->pending.cursor = true;
refresh_cursor(s->term);
adjust_topline(s->term, buf, 0); // scroll to end
// erase the unfocused cursor
invalidate_terminal(s->term, s->term->cursor.row, s->term->cursor.row + 1);
showmode();
curwin->w_redr_status = true; // For mode() in statusline. #8323
redraw_custom_title_later();
ui_busy_start();
if (!s->term->cursor.visible) {
// Hide cursor if it should be hidden
ui_busy_start();
}
ui_cursor_shape();
apply_autocmds(EVENT_TERMENTER, NULL, NULL, false, curbuf);
may_trigger_modechanged();
// Tell the terminal it has focus
terminal_focus(s->term, true);
s->state.execute = terminal_execute;
s->state.check = terminal_check;
state_enter(&s->state);
@ -635,6 +674,9 @@ bool terminal_enter(void)
RedrawingDisabled = s->save_rd;
apply_autocmds(EVENT_TERMLEAVE, NULL, NULL, false, curbuf);
shape_table[SHAPE_IDX_TERM] = save_cursorentry;
ui_mode_info_set();
if (save_curwin == curwin->handle) { // Else: window was closed.
curwin->w_p_cul = save_w_p_cul;
if (save_w_p_culopt) {
@ -649,8 +691,9 @@ bool terminal_enter(void)
free_string_option(save_w_p_culopt);
}
// draw the unfocused cursor
invalidate_terminal(s->term, s->term->cursor.row, s->term->cursor.row + 1);
// Tell the terminal it lost focus
terminal_focus(s->term, false);
if (curbuf->terminal == s->term && !s->close) {
terminal_check_cursor();
}
@ -659,7 +702,11 @@ bool terminal_enter(void)
} else {
unshowmode(true);
}
ui_busy_stop();
if (!s->term->cursor.visible) {
// If cursor was hidden, show it again
ui_busy_stop();
}
ui_cursor_shape();
if (s->close) {
bool wipe = s->term->buf_handle != 0;
s->term->destroy = true;
@ -810,6 +857,19 @@ static int terminal_execute(VimState *state, int key)
return 0;
}
if (s->term != curbuf->terminal) {
// Active terminal buffer changed, flush terminal's cursor state to the UI
curbuf->terminal->pending.cursor = true;
if (!s->term->cursor.visible) {
// If cursor was hidden, show it again
ui_busy_stop();
}
if (!curbuf->terminal->cursor.visible) {
// Hide cursor if it should be hidden
ui_busy_start();
}
invalidate_terminal(s->term, s->term->cursor.row, s->term->cursor.row + 1);
invalidate_terminal(curbuf->terminal,
curbuf->terminal->cursor.row,
@ -857,8 +917,8 @@ static void terminal_send(Terminal *term, const char *data, size_t size)
if (term->closed) {
return;
}
if (term->pending_send) {
kv_concat_len(*term->pending_send, data, size);
if (term->pending.send) {
kv_concat_len(*term->pending.send, data, size);
return;
}
term->opts.write_cb(data, size, term->opts.data);
@ -1063,14 +1123,6 @@ void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr, int *te
attr_id = hl_combine_attr(attr_id, cell.uri);
}
if (term->cursor.visible && term->cursor.row == row
&& term->cursor.col == col) {
attr_id = hl_combine_attr(attr_id,
is_focused(term) && wp == curwin
? win_hl_attr(wp, HLF_TERM)
: win_hl_attr(wp, HLF_TERMNC));
}
term_attrs[col] = attr_id;
}
}
@ -1085,6 +1137,17 @@ bool terminal_running(const Terminal *term)
return !term->closed;
}
static void terminal_focus(const Terminal *term, bool focus)
FUNC_ATTR_NONNULL_ALL
{
VTermState *state = vterm_obtain_state(term->vt);
if (focus) {
vterm_state_focus_in(state);
} else {
vterm_state_focus_out(state);
}
}
// }}}
// libvterm callbacks {{{
@ -1106,8 +1169,7 @@ static int term_movecursor(VTermPos new_pos, VTermPos old_pos, int visible, void
Terminal *term = data;
term->cursor.row = new_pos.row;
term->cursor.col = new_pos.col;
invalidate_terminal(term, old_pos.row, old_pos.row + 1);
invalidate_terminal(term, new_pos.row, new_pos.row + 1);
invalidate_terminal(term, -1, -1);
return 1;
}
@ -1135,8 +1197,17 @@ static int term_settermprop(VTermProp prop, VTermValue *val, void *data)
break;
case VTERM_PROP_CURSORVISIBLE:
if (is_focused(term)) {
if (!val->boolean && term->cursor.visible) {
// Hide the cursor
ui_busy_start();
} else if (val->boolean && !term->cursor.visible) {
// Unhide the cursor
ui_busy_stop();
}
invalidate_terminal(term, -1, -1);
}
term->cursor.visible = val->boolean;
invalidate_terminal(term, term->cursor.row, term->cursor.row + 1);
break;
case VTERM_PROP_TITLE: {
@ -1172,6 +1243,18 @@ static int term_settermprop(VTermProp prop, VTermValue *val, void *data)
term->forward_mouse = (bool)val->number;
break;
case VTERM_PROP_CURSORBLINK:
term->cursor.blink = val->boolean;
term->pending.cursor = true;
invalidate_terminal(term, -1, -1);
break;
case VTERM_PROP_CURSORSHAPE:
term->cursor.shape = val->number;
term->pending.cursor = true;
invalidate_terminal(term, -1, -1);
break;
default:
return 0;
}
@ -1849,12 +1932,47 @@ static void refresh_terminal(Terminal *term)
refresh_size(term, buf);
refresh_scrollback(term, buf);
refresh_screen(term, buf);
refresh_cursor(term);
aucmd_restbuf(&aco);
int ml_added = buf->b_ml.ml_line_count - ml_before;
adjust_topline(term, buf, ml_added);
}
static void refresh_cursor(Terminal *term)
FUNC_ATTR_NONNULL_ALL
{
if (!is_focused(term) || !term->pending.cursor) {
return;
}
term->pending.cursor = false;
if (term->cursor.blink) {
// For the TUI, this value doesn't actually matter, as long as it's non-zero. The terminal
// emulator dictates the blink frequency, not the application.
// For GUIs we just pick an arbitrary value, for now.
shape_table[SHAPE_IDX_TERM].blinkon = 500;
shape_table[SHAPE_IDX_TERM].blinkoff = 500;
} else {
shape_table[SHAPE_IDX_TERM].blinkon = 0;
shape_table[SHAPE_IDX_TERM].blinkoff = 0;
}
switch (term->cursor.shape) {
case VTERM_PROP_CURSORSHAPE_BLOCK:
shape_table[SHAPE_IDX_TERM].shape = SHAPE_BLOCK;
break;
case VTERM_PROP_CURSORSHAPE_UNDERLINE:
shape_table[SHAPE_IDX_TERM].shape = SHAPE_HOR;
break;
case VTERM_PROP_CURSORSHAPE_BAR_LEFT:
shape_table[SHAPE_IDX_TERM].shape = SHAPE_VER;
break;
}
ui_mode_info_set();
}
/// Calls refresh_terminal() on all invalidated_terminals.
static void refresh_timer_cb(TimeWatcher *watcher, void *data)
{
@ -1875,11 +1993,11 @@ static void refresh_timer_cb(TimeWatcher *watcher, void *data)
static void refresh_size(Terminal *term, buf_T *buf)
{
if (!term->pending_resize || term->closed) {
if (!term->pending.resize || term->closed) {
return;
}
term->pending_resize = false;
term->pending.resize = false;
int width, height;
vterm_get_size(term->vt, &height, &width);
term->invalid_start = 0;

View File

@ -35,6 +35,7 @@
#include "nvim/strings.h"
#include "nvim/textformat.h"
#include "nvim/textobject.h"
#include "nvim/ui.h"
#include "nvim/undo.h"
#include "nvim/vim_defs.h"
#include "nvim/window.h"
@ -1049,12 +1050,18 @@ void format_lines(linenr_T line_count, bool avoid_fex)
State = MODE_INSERT; // for open_line()
smd_save = p_smd;
p_smd = false;
insertchar(NUL, INSCHAR_FORMAT
+ (do_comments ? INSCHAR_DO_COM : 0)
+ (do_comments && do_comments_list ? INSCHAR_COM_LIST : 0)
+ (avoid_fex ? INSCHAR_NO_FEX : 0), second_indent);
State = old_State;
p_smd = smd_save;
// Cursor shape may have been updated (e.g. by :normal) in insertchar(),
// so it needs to be updated here.
ui_cursor_shape();
second_indent = -1;
// at end of par.: need to set indent of next par.
need_set_indent = is_end_par;

View File

@ -1339,7 +1339,7 @@ static void tui_set_mode(TUIData *tui, ModeShape mode)
case SHAPE_VER:
shape = 5; break;
}
UNIBI_SET_NUM_VAR(tui->params[0], shape + (int)(c.blinkon == 0));
UNIBI_SET_NUM_VAR(tui->params[0], shape + (int)(c.blinkon == 0 || c.blinkoff == 0));
unibi_out_ext(tui, tui->unibi_ext.set_cursor_style);
}

View File

@ -3785,7 +3785,7 @@ describe('API', function()
screen:expect {
grid = [[
|
{1:~}{102: }{4: }{1: }|
{1:~}{4:^ }{1: }|
{1:~}{4: }{1: }|*4
{1:~ }|*3
{5:-- TERMINAL --} |
@ -3801,7 +3801,7 @@ describe('API', function()
screen:expect {
grid = [[
|
{1:~}{4:herrejösses!}{102: }{4: }{1: }|
{1:~}{4:herrejösses!^ }{1: }|
{1:~}{4: }{1: }|*4
{1:~ }|*3
{5:-- TERMINAL --} |

View File

@ -47,7 +47,7 @@ describe('autoread TUI FocusGained/FocusLost', function()
screen:expect {
grid = [[
{1: } |
^ |
{4:~ }|*3
{5:[No Name] }|
|
@ -57,7 +57,7 @@ describe('autoread TUI FocusGained/FocusLost', function()
feed_command('edit ' .. path)
screen:expect {
grid = [[
{1: } |
^ |
{4:~ }|*3
{5:xtest-foo }|
:edit xtest-foo |
@ -68,7 +68,7 @@ describe('autoread TUI FocusGained/FocusLost', function()
feed_data('\027[O')
screen:expect {
grid = [[
{1: } |
^ |
{4:~ }|*3
{5:xtest-foo }|
:edit xtest-foo |
@ -83,7 +83,7 @@ describe('autoread TUI FocusGained/FocusLost', function()
screen:expect {
grid = [[
{1:l}ine 1 |
^line 1 |
line 2 |
line 3 |
line 4 |

View File

@ -1198,7 +1198,7 @@ describe('jobs', function()
})
-- Wait for startup to complete, so that all terminal responses are received.
screen:expect([[
{1: } |
^ |
~ |*3
{1:[No Name] 0,0-1 All}|
|
@ -1208,7 +1208,7 @@ describe('jobs', function()
feed(':q<CR>')
screen:expect([[
|
[Process exited 0]{1: } |
[Process exited 0]^ |
|*4
{3:-- TERMINAL --} |
]])

View File

@ -46,7 +46,7 @@ describe('log', function()
env = env,
})
screen:expect([[
{1: } |
^ |
~ |*4
|
{3:-- TERMINAL --} |

View File

@ -120,7 +120,7 @@ describe('command-line option', function()
feed('i:cq<CR>')
screen:expect([[
|
[Process exited 1]{2: } |
[Process exited 1]^ |
|*5
{5:-- TERMINAL --} |
]])

View File

@ -1153,7 +1153,7 @@ describe('user config init', function()
-- `i` to enter Terminal mode, `a` to allow
feed('ia')
screen:expect([[
|
^ |
~ |*4
[No Name] 0,0-1 All|
|
@ -1162,7 +1162,7 @@ describe('user config init', function()
feed(':echo g:exrc_file<CR>')
screen:expect(string.format(
[[
|
^ |
~ |*4
[No Name] 0,0-1 All|
%s%s|

View File

@ -29,8 +29,8 @@ describe(':highlight', function()
|
TermCursor {2:xxx} {18:cterm=}reverse |
{18:gui=}reverse |
TermCursorNC xxx cleared |
NonText {1:xxx} {18:ctermfg=}12 |
{18:gui=}bold |
{6:-- More --}^ |
]])
feed('q')

View File

@ -709,7 +709,7 @@ describe('messages', function()
feed('<CR>')
-- Check no hit-enter prompt when "wait:" is set
command('set messagesopt=wait:100,history:500')
command('set messagesopt=wait:500,history:500')
feed(":echo 'foo' | echo 'bar' | echo 'baz'\n")
screen:expect({
grid = [[
@ -720,7 +720,7 @@ describe('messages', function()
bar |
baz |
]],
timeout = 100,
timeout = 500,
})
screen:expect([[
^ |

View File

@ -263,7 +263,7 @@ describe('vim.ui_attach', function()
]],
messages = {
{
content = { { 'E122: Function Foo already exists, add ! to replace it', 9, 7 } },
content = { { 'E122: Function Foo already exists, add ! to replace it', 9, 6 } },
kind = 'emsg',
},
},
@ -280,7 +280,7 @@ describe('vim.ui_attach', function()
]],
messages = {
{
content = { { 'replace with Replacement (y/n/a/q/l/^E/^Y)?', 6, 19 } },
content = { { 'replace with Replacement (y/n/a/q/l/^E/^Y)?', 6, 18 } },
kind = 'confirm_sub',
},
},
@ -348,7 +348,7 @@ describe('vim.ui_attach', function()
foo^ |
{1:~ }|*4
]],
showmode = { { '-- INSERT --', 5, 12 } },
showmode = { { '-- INSERT --', 5, 11 } },
})
feed('<esc>:1mes clear<cr>:mes<cr>')
screen:expect({
@ -375,7 +375,7 @@ describe('vim.ui_attach', function()
{
'Error executing vim.schedule lua callback: [string "<nvim>"]:2: attempt to index global \'err\' (a nil value)\nstack traceback:\n\t[string "<nvim>"]:2: in function <[string "<nvim>"]:2>',
9,
7,
6,
},
},
kind = 'lua_error',
@ -385,13 +385,13 @@ describe('vim.ui_attach', function()
{
'Error executing vim.schedule lua callback: [string "<nvim>"]:2: attempt to index global \'err\' (a nil value)\nstack traceback:\n\t[string "<nvim>"]:2: in function <[string "<nvim>"]:2>',
9,
7,
6,
},
},
kind = 'lua_error',
},
{
content = { { 'Press ENTER or type command to continue', 100, 19 } },
content = { { 'Press ENTER or type command to continue', 100, 18 } },
kind = 'return_prompt',
},
},

View File

@ -35,13 +35,13 @@ describe(':terminal altscreen', function()
line6 |
line7 |
line8 |
{1: } |
^ |
{3:-- TERMINAL --} |
]])
enter_altscreen()
screen:expect([[
|*5
{1: } |
^ |
{3:-- TERMINAL --} |
]])
eq(10, api.nvim_buf_line_count(0))
@ -68,7 +68,7 @@ describe(':terminal altscreen', function()
line6 |
line7 |
line8 |
{1: } |
^ |
{3:-- TERMINAL --} |
]])
feed('<c-\\><c-n>gg')
@ -103,7 +103,7 @@ describe(':terminal altscreen', function()
line14 |
line15 |
line16 |
{1: } |
^ |
{3:-- TERMINAL --} |
]])
end)
@ -132,7 +132,7 @@ describe(':terminal altscreen', function()
screen:expect([[
|*2
rows: 4, cols: 50 |
{1: } |
^ |
{3:-- TERMINAL --} |
]])
end
@ -160,7 +160,7 @@ describe(':terminal altscreen', function()
line5 |
line6 |
line7 |
line8 |
^line8 |
{3:-- TERMINAL --} |
]])
end)

View File

@ -33,7 +33,7 @@ describe('api', function()
it('qa! RPC request during insert-mode', function()
screen:expect {
grid = [[
{1: } |
^ |
{4:~ }|*4
|
{3:-- TERMINAL --} |
@ -45,7 +45,7 @@ describe('api', function()
-- Wait for socket creation.
screen:expect([[
{1: } |
^ |
{4:~ }|*4
]] .. socket_name .. [[ |
{3:-- TERMINAL --} |
@ -57,7 +57,7 @@ describe('api', function()
tt.feed_data('i[tui] insert-mode')
-- Wait for stdin to be processed.
screen:expect([[
[tui] insert-mode{1: } |
[tui] insert-mode^ |
{4:~ }|*4
{3:-- INSERT --} |
{3:-- TERMINAL --} |
@ -73,7 +73,7 @@ describe('api', function()
[tui] insert-mode |
[socket 1] this is more t |
han 25 columns |
[socket 2] input{1: } |
[socket 2] input^ |
{4:~ } |
{3:-- INSERT --} |
{3:-- TERMINAL --} |

View File

@ -89,7 +89,7 @@ describe(':terminal buffer', function()
feed('<c-\\><c-n>')
screen:expect([[
tty ready |
{2:^ } |
^ |
|*5
]])
end)
@ -109,7 +109,7 @@ describe(':terminal buffer', function()
feed('<c-\\><c-n>dd')
screen:expect([[
tty ready |
{2:^ } |
^ |
|*4
{8:E21: Cannot make changes, 'modifiable' is off} |
]])
@ -122,7 +122,7 @@ describe(':terminal buffer', function()
screen:expect([[
^tty ready |
appended tty ready |*2
{2: } |
|
|*2
:let @a = "appended " . @a |
]])
@ -142,7 +142,7 @@ describe(':terminal buffer', function()
screen:expect([[
^tty ready |
appended tty ready |
{2: } |
|
|*3
:put a |
]])
@ -151,7 +151,7 @@ describe(':terminal buffer', function()
screen:expect([[
tty ready |
appended tty ready |*2
{2: } |
|
|
^ |
:6put a |
@ -198,7 +198,7 @@ describe(':terminal buffer', function()
{4:~ }|
{5:========== }|
rows: 2, cols: 50 |
{2: } |
|
{18:========== }|
|
]])
@ -234,7 +234,7 @@ describe(':terminal buffer', function()
command('set rightleft')
screen:expect([[
ydaer ytt|
{1:a}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
|*4
{3:-- TERMINAL --} |
]])
@ -277,7 +277,7 @@ describe(':terminal buffer', function()
screen:expect {
grid = [[
tty ready |
{2:^ } |
^ |
|*4
{3:-- (terminal) --} |
]],
@ -288,7 +288,7 @@ describe(':terminal buffer', function()
screen:expect {
grid = [[
tty ready |
{2: } |
|
|*4
:let g:x = 17^ |
]],
@ -298,7 +298,7 @@ describe(':terminal buffer', function()
screen:expect {
grid = [[
tty ready |
{1: } |
^ |
|*4
{3:-- TERMINAL --} |
]],
@ -534,7 +534,7 @@ describe('terminal input', function()
'while 1 | redraw | echo keytrans(getcharstr()) | endwhile',
})
screen:expect([[
{1: } |
^ |
{4:~ }|*3
{5:[No Name] 0,0-1 All}|
|
@ -594,7 +594,7 @@ describe('terminal input', function()
|
{4:~ }|*3
{5:[No Name] 0,0-1 All}|
%s{1: }{MATCH: *}|
%s^ {MATCH: *}|
{3:-- TERMINAL --} |
]]):format(key))
end
@ -624,7 +624,7 @@ if is_os('win') then
> :: appended :: tty ready |
> :: tty ready |
> :: appended :: tty ready |
^> {2: } |
^> |
:let @a = @a . "\n:: appended " . @a . "\n\n" |
]])
-- operator count is also taken into consideration
@ -635,7 +635,7 @@ if is_os('win') then
> :: appended :: tty ready |
> :: tty ready |
> :: appended :: tty ready |
^> {2: } |
^> |
:let @a = @a . "\n:: appended " . @a . "\n\n" |
]])
end)
@ -649,7 +649,7 @@ if is_os('win') then
|
> :: tty ready |
> :: appended :: tty ready |
> {2: } |
> |
|
^ |
:put a |
@ -662,7 +662,7 @@ if is_os('win') then
> :: appended :: tty ready |
> :: tty ready |
> :: appended :: tty ready |
^> {2: } |
^> |
:6put a |
]])
end)

View File

@ -1,13 +1,12 @@
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
local Screen = require('test.functional.ui.screen')
local tt = require('test.functional.testterm')
local feed, clear = n.feed, n.clear
local testprg, command = n.testprg, n.command
local eq, eval = t.eq, n.eval
local matches = t.matches
local poke_eventloop = n.poke_eventloop
local call = n.call
local hide_cursor = tt.hide_cursor
local show_cursor = tt.show_cursor
local is_os = t.is_os
@ -25,7 +24,7 @@ describe(':terminal cursor', function()
tt.feed_data('testing cursor')
screen:expect([[
tty ready |
testing cursor{1: } |
testing cursor^ |
|*4
{3:-- TERMINAL --} |
]])
@ -35,7 +34,7 @@ describe(':terminal cursor', function()
feed('<c-\\><c-n>')
screen:expect([[
tty ready |
{2:^ } |
^ |
|*5
]])
end)
@ -49,7 +48,7 @@ describe(':terminal cursor', function()
screen:expect([[
{7: 1 }tty ready |
{7: 2 }^rows: 6, cols: 46 |
{7: 3 }{2: } |
{7: 3 } |
{7: 4 } |
{7: 5 } |
{7: 6 } |
@ -61,7 +60,7 @@ describe(':terminal cursor', function()
screen:expect([[
{7: 1 }tty ready |
{7: 2 }^rows: 6, cols: 46 |
{7: 3 }{2: } |
{7: 3 } |
{7: 4 } |
{7: 5 } |
{7: 6 } |
@ -72,7 +71,7 @@ describe(':terminal cursor', function()
screen:expect([[
{7: 1 }tty ready |
{7: 2 }rows: 6, cols: 46 |
{7: 3 }{1: } |
{7: 3 }^ |
{7: 4 } |
{7: 5 } |
{7: 6 } |
@ -82,8 +81,8 @@ describe(':terminal cursor', function()
end)
describe('when invisible', function()
it('is not highlighted and is detached from screen cursor', function()
skip(is_os('win'))
it('is not highlighted', function()
skip(is_os('win'), '#31587')
hide_cursor()
screen:expect([[
tty ready |
@ -93,58 +92,238 @@ describe(':terminal cursor', function()
show_cursor()
screen:expect([[
tty ready |
{1: } |
^ |
|*4
{3:-- TERMINAL --} |
]])
-- same for when the terminal is unfocused
feed('<c-\\><c-n>')
hide_cursor()
screen:expect({
grid = [[
tty ready |
^ |
|*5
]],
unchanged = true,
})
show_cursor()
screen:expect({
grid = [[
tty ready |
^ |
|*5
]],
unchanged = true,
})
end)
it('becomes visible when exiting Terminal mode', function()
skip(is_os('win'), '#31587')
hide_cursor()
screen:expect([[
tty ready |
|*5
{3:-- TERMINAL --} |
]])
feed('<c-\\><c-n>')
screen:expect([[
tty ready |
^ |
|*5
]])
show_cursor()
feed('i')
screen:expect([[
tty ready |
{2:^ } |
|*5
{3:-- TERMINAL --} |
]])
end)
end)
end)
describe('cursor with customized highlighting', function()
local screen
it('can be modified by application #3681', function()
skip(is_os('win'), '#31587')
local idx ---@type number
for i, v in ipairs(screen._mode_info) do
if v.name == 'terminal' then
idx = i
end
end
assert(idx)
before_each(function()
clear()
command('highlight TermCursor ctermfg=45 ctermbg=46 cterm=NONE')
command('highlight TermCursorNC ctermfg=55 ctermbg=56 cterm=NONE')
screen = Screen.new(50, 7, { rgb = false })
screen:set_default_attr_ids({
[1] = { foreground = 45, background = 46 },
[2] = { foreground = 55, background = 56 },
[3] = { bold = true },
})
command('call termopen(["' .. testprg('tty-test') .. '"])')
feed('i')
poke_eventloop()
local states = {
[1] = { blink = true, shape = 'block' },
[2] = { blink = false, shape = 'block' },
[3] = { blink = true, shape = 'horizontal' },
[4] = { blink = false, shape = 'horizontal' },
[5] = { blink = true, shape = 'vertical' },
[6] = { blink = false, shape = 'vertical' },
}
for k, v in pairs(states) do
tt.feed_csi(('%d q'):format(k))
screen:expect({
grid = [[
tty ready |
^ |
|*4
{3:-- TERMINAL --} |
]],
condition = function()
if v.blink then
eq(500, screen._mode_info[idx].blinkon)
eq(500, screen._mode_info[idx].blinkoff)
else
eq(0, screen._mode_info[idx].blinkon)
eq(0, screen._mode_info[idx].blinkoff)
end
eq(v.shape, screen._mode_info[idx].cursor_shape)
end,
})
end
feed([[<C-\><C-N>]])
screen:expect([[
tty ready |
^ |
|*5
]])
-- Cursor returns to default on TermLeave
eq(500, screen._mode_info[idx].blinkon)
eq(500, screen._mode_info[idx].blinkoff)
eq('block', screen._mode_info[idx].cursor_shape)
end)
it('overrides the default highlighting', function()
screen:expect([[
it('can be modified per terminal', function()
skip(is_os('win'), '#31587')
local idx ---@type number
for i, v in ipairs(screen._mode_info) do
if v.name == 'terminal' then
idx = i
end
end
assert(idx)
-- Set cursor to vertical bar with blink
tt.feed_csi('5 q')
screen:expect({
grid = [[
tty ready |
{1: } |
^ |
|*4
{3:-- TERMINAL --} |
]])
feed('<c-\\><c-n>')
screen:expect([[
]],
condition = function()
eq(500, screen._mode_info[idx].blinkon)
eq(500, screen._mode_info[idx].blinkoff)
eq('vertical', screen._mode_info[idx].cursor_shape)
end,
})
tt.hide_cursor()
screen:expect({
grid = [[
tty ready |
{2:^ } |
|*5
|
|*4
{3:-- TERMINAL --} |
]],
condition = function()
eq(500, screen._mode_info[idx].blinkon)
eq(500, screen._mode_info[idx].blinkoff)
eq('vertical', screen._mode_info[idx].cursor_shape)
end,
})
-- Exit terminal mode to reset terminal cursor settings to default and
-- create a new terminal window
feed([[<C-\><C-N>]])
command('set statusline=~~~')
command('new')
call('termopen', { testprg('tty-test') })
feed('i')
screen:expect({
grid = [[
tty ready |
^ |
{17:~~~ }|
rows: 2, cols: 50 |
|
{18:~~~ }|
{3:-- TERMINAL --} |
]],
condition = function()
-- New terminal, cursor resets to defaults
eq(500, screen._mode_info[idx].blinkon)
eq(500, screen._mode_info[idx].blinkoff)
eq('block', screen._mode_info[idx].cursor_shape)
end,
})
-- Set cursor to underline, no blink
tt.feed_csi('4 q')
screen:expect({
grid = [[
tty ready |
^ |
{17:~~~ }|
rows: 2, cols: 50 |
|
{18:~~~ }|
{3:-- TERMINAL --} |
]],
condition = function()
eq(0, screen._mode_info[idx].blinkon)
eq(0, screen._mode_info[idx].blinkoff)
eq('horizontal', screen._mode_info[idx].cursor_shape)
end,
})
-- Switch back to first terminal, cursor should still be hidden
command('wincmd p')
screen:expect({
grid = [[
tty ready |
|
{18:~~~ }|
rows: 2, cols: 50 |
|
{17:~~~ }|
{3:-- TERMINAL --} |
]],
condition = function()
eq(500, screen._mode_info[idx].blinkon)
eq(500, screen._mode_info[idx].blinkoff)
eq('vertical', screen._mode_info[idx].cursor_shape)
end,
})
end)
it('can be positioned arbitrarily', function()
clear()
screen = tt.setup_child_nvim({
'-u',
'NONE',
'-i',
'NONE',
'--cmd',
n.nvim_set .. ' noshowmode',
})
screen:expect([[
^ |
~ |*4
|
{3:-- TERMINAL --} |
]])
feed('i<Tab>')
screen:expect([[
^ |
~ |*4
|
{3:-- TERMINAL --} |
]])
end)
end)
@ -183,7 +362,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
:{2:^ } |
:^ |
{3:-- TERMINAL --} |
]])
end
@ -200,7 +379,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
:aaaaaaaa{2:^ } |
:aaaaaaaa^ |
{3:-- TERMINAL --} |
]])
eq({ 6, 9 }, eval('nvim_win_get_cursor(0)'))
@ -208,7 +387,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
:aaaaaaa^a{4: } |
:aaaaaaa^a |
|
]])
eq({ 6, 8 }, eval('nvim_win_get_cursor(0)'))
@ -219,7 +398,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
:aaaaaa{2:^a}a |
:aaaaaa^aa |
{3:-- TERMINAL --} |
]])
eq({ 6, 7 }, eval('nvim_win_get_cursor(0)'))
@ -227,7 +406,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
:aaaaa^a{4:a}a |
:aaaaa^aaa |
|
]])
eq({ 6, 6 }, eval('nvim_win_get_cursor(0)'))
@ -238,7 +417,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
:a{2:^a}aaaaaa |
:a^aaaaaaa |
{3:-- TERMINAL --} |
]])
eq({ 6, 2 }, eval('nvim_win_get_cursor(0)'))
@ -246,7 +425,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
:^a{4:a}aaaaaa |
:^aaaaaaaa |
|
]])
eq({ 6, 1 }, eval('nvim_win_get_cursor(0)'))
@ -263,7 +442,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
:µµµµµµµµ{2:^ } |
:µµµµµµµµ^ |
{3:-- TERMINAL --} |
]])
eq({ 6, 17 }, eval('nvim_win_get_cursor(0)'))
@ -271,7 +450,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
:µµµµµµµ^µ{4: } |
:µµµµµµµ^µ |
|
]])
eq({ 6, 15 }, eval('nvim_win_get_cursor(0)'))
@ -282,7 +461,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
:µµµµµµ{2:^µ}µ |
:µµµµµµ^µµ |
{3:-- TERMINAL --} |
]])
eq({ 6, 13 }, eval('nvim_win_get_cursor(0)'))
@ -290,7 +469,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
:µµµµµ^µ{4:µ}µ |
:µµµµµ^µµµ |
|
]])
eq({ 6, 11 }, eval('nvim_win_get_cursor(0)'))
@ -301,7 +480,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
:µ{2:^µ}µµµµµµ |
:µ^µµµµµµµ |
{3:-- TERMINAL --} |
]])
eq({ 6, 3 }, eval('nvim_win_get_cursor(0)'))
@ -309,7 +488,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
:^µ{4:µ}µµµµµµ |
:^µµµµµµµµ |
|
]])
eq({ 6, 1 }, eval('nvim_win_get_cursor(0)'))
@ -326,7 +505,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
:µ̳µ̳µ̳µ̳µ̳µ̳µ̳µ̳{2:^ } |
:µ̳µ̳µ̳µ̳µ̳µ̳µ̳µ̳^ |
{3:-- TERMINAL --} |
]])
eq({ 6, 33 }, eval('nvim_win_get_cursor(0)'))
@ -334,7 +513,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
:µ̳µ̳µ̳µ̳µ̳µ̳µ̳^µ̳{4: } |
:µ̳µ̳µ̳µ̳µ̳µ̳µ̳^µ̳ |
|
]])
eq({ 6, 29 }, eval('nvim_win_get_cursor(0)'))
@ -346,7 +525,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
:µ̳µ̳µ̳µ̳µ̳µ̳{2:^µ̳}µ̳ |
:µ̳µ̳µ̳µ̳µ̳µ̳^µ̳µ̳ |
{3:-- TERMINAL --} |
]])
eq({ 6, 25 }, eval('nvim_win_get_cursor(0)'))
@ -354,7 +533,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
:µ̳µ̳µ̳µ̳µ̳^µ̳{4:µ̳}µ̳ |
:µ̳µ̳µ̳µ̳µ̳^µ̳µ̳µ̳ |
|
]])
eq({ 6, 21 }, eval('nvim_win_get_cursor(0)'))
@ -366,7 +545,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
:µ̳{2:^µ̳}µ̳µ̳µ̳µ̳µ̳µ̳ |
:µ̳^µ̳µ̳µ̳µ̳µ̳µ̳µ̳ |
{3:-- TERMINAL --} |
]])
eq({ 6, 5 }, eval('nvim_win_get_cursor(0)'))
@ -374,7 +553,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
:^µ̳{4:µ̳}µ̳µ̳µ̳µ̳µ̳µ̳ |
:^µ̳µ̳µ̳µ̳µ̳µ̳µ̳µ̳ |
|
]])
eq({ 6, 1 }, eval('nvim_win_get_cursor(0)'))
@ -391,7 +570,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
:{2:^ } |
:^ |
{3:-- TERMINAL --} |
]])
eq({ 6, 25 }, eval('nvim_win_get_cursor(0)'))
@ -399,7 +578,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
:^{4: } |
:^ |
|
]])
eq({ 6, 22 }, eval('nvim_win_get_cursor(0)'))
@ -410,7 +589,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
:{2:^} |
:^ |
{3:-- TERMINAL --} |
]])
eq({ 6, 19 }, eval('nvim_win_get_cursor(0)'))
@ -418,7 +597,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
:^{4:} |
:^ |
|
]])
eq({ 6, 16 }, eval('nvim_win_get_cursor(0)'))
@ -429,7 +608,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
:{2:^} |
:^ |
{3:-- TERMINAL --} |
]])
eq({ 6, 4 }, eval('nvim_win_get_cursor(0)'))
@ -437,7 +616,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
:^{4:} |
:^ |
|
]])
eq({ 6, 1 }, eval('nvim_win_get_cursor(0)'))
@ -450,7 +629,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
:aaaaaaaa {2:^ } |
:aaaaaaaa ^ |
{3:-- TERMINAL --} |
]])
matches('^:aaaaaaaa [ ]*$', eval('nvim_get_current_line()'))
@ -459,7 +638,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
:aaaaaaaa ^ {4: } |
:aaaaaaaa ^ |
|
]])
eq({ 6, 12 }, eval('nvim_win_get_cursor(0)'))
@ -504,7 +683,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
{7: 6 }:{2:^ } |
{7: 6 }:^ |
{3:-- TERMINAL --} |
]])
end
@ -527,7 +706,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
{7: 6 }:aaaaaaaa{2:^ } |
{7: 6 }:aaaaaaaa^ |
{3:-- TERMINAL --} |
]])
eq({ 6, 9 }, eval('nvim_win_get_cursor(0)'))
@ -538,7 +717,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
{7: 6 }:aaaaaaa^a{4: } |
{7: 6 }:aaaaaaa^a |
|
]])
eq({ 6, 8 }, eval('nvim_win_get_cursor(0)'))
@ -552,7 +731,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
{7: 6 }:aaaaaa{2:^a}a |
{7: 6 }:aaaaaa^aa |
{3:-- TERMINAL --} |
]])
eq({ 6, 7 }, eval('nvim_win_get_cursor(0)'))
@ -563,7 +742,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
{7: 6 }:aaaaa^a{4:a}a |
{7: 6 }:aaaaa^aaa |
|
]])
eq({ 6, 6 }, eval('nvim_win_get_cursor(0)'))
@ -577,7 +756,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
{7: 6 }:a{2:^a}aaaaaa |
{7: 6 }:a^aaaaaaa |
{3:-- TERMINAL --} |
]])
eq({ 6, 2 }, eval('nvim_win_get_cursor(0)'))
@ -588,7 +767,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
{7: 6 }:^a{4:a}aaaaaa |
{7: 6 }:^aaaaaaaa |
|
]])
eq({ 6, 1 }, eval('nvim_win_get_cursor(0)'))
@ -608,7 +787,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
{7: 6 }:µµµµµµµµ{2:^ } |
{7: 6 }:µµµµµµµµ^ |
{3:-- TERMINAL --} |
]])
eq({ 6, 17 }, eval('nvim_win_get_cursor(0)'))
@ -619,7 +798,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
{7: 6 }:µµµµµµµ^µ{4: } |
{7: 6 }:µµµµµµµ^µ |
|
]])
eq({ 6, 15 }, eval('nvim_win_get_cursor(0)'))
@ -633,7 +812,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
{7: 6 }:µµµµµµ{2:^µ}µ |
{7: 6 }:µµµµµµ^µµ |
{3:-- TERMINAL --} |
]])
eq({ 6, 13 }, eval('nvim_win_get_cursor(0)'))
@ -644,7 +823,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
{7: 6 }:µµµµµ^µ{4:µ}µ |
{7: 6 }:µµµµµ^µµµ |
|
]])
eq({ 6, 11 }, eval('nvim_win_get_cursor(0)'))
@ -658,7 +837,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
{7: 6 }:µ{2:^µ}µµµµµµ |
{7: 6 }:µ^µµµµµµµ |
{3:-- TERMINAL --} |
]])
eq({ 6, 3 }, eval('nvim_win_get_cursor(0)'))
@ -669,7 +848,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
{7: 6 }:^µ{4:µ}µµµµµµ |
{7: 6 }:^µµµµµµµµ |
|
]])
eq({ 6, 1 }, eval('nvim_win_get_cursor(0)'))
@ -689,7 +868,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
{7: 6 }:µ̳µ̳µ̳µ̳µ̳µ̳µ̳µ̳{2:^ } |
{7: 6 }:µ̳µ̳µ̳µ̳µ̳µ̳µ̳µ̳^ |
{3:-- TERMINAL --} |
]])
eq({ 6, 33 }, eval('nvim_win_get_cursor(0)'))
@ -700,7 +879,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
{7: 6 }:µ̳µ̳µ̳µ̳µ̳µ̳µ̳^µ̳{4: } |
{7: 6 }:µ̳µ̳µ̳µ̳µ̳µ̳µ̳^µ̳ |
|
]])
eq({ 6, 29 }, eval('nvim_win_get_cursor(0)'))
@ -715,7 +894,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
{7: 6 }:µ̳µ̳µ̳µ̳µ̳µ̳{2:^µ̳}µ̳ |
{7: 6 }:µ̳µ̳µ̳µ̳µ̳µ̳^µ̳µ̳ |
{3:-- TERMINAL --} |
]])
eq({ 6, 25 }, eval('nvim_win_get_cursor(0)'))
@ -726,7 +905,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
{7: 6 }:µ̳µ̳µ̳µ̳µ̳^µ̳{4:µ̳}µ̳ |
{7: 6 }:µ̳µ̳µ̳µ̳µ̳^µ̳µ̳µ̳ |
|
]])
eq({ 6, 21 }, eval('nvim_win_get_cursor(0)'))
@ -741,7 +920,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
{7: 6 }:µ̳{2:^µ̳}µ̳µ̳µ̳µ̳µ̳µ̳ |
{7: 6 }:µ̳^µ̳µ̳µ̳µ̳µ̳µ̳µ̳ |
{3:-- TERMINAL --} |
]])
eq({ 6, 5 }, eval('nvim_win_get_cursor(0)'))
@ -752,7 +931,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
{7: 6 }:^µ̳{4:µ̳}µ̳µ̳µ̳µ̳µ̳µ̳ |
{7: 6 }:^µ̳µ̳µ̳µ̳µ̳µ̳µ̳µ̳ |
|
]])
eq({ 6, 1 }, eval('nvim_win_get_cursor(0)'))
@ -772,7 +951,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
{7: 6 }:{2:^ } |
{7: 6 }:^ |
{3:-- TERMINAL --} |
]])
eq({ 6, 25 }, eval('nvim_win_get_cursor(0)'))
@ -783,7 +962,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
{7: 6 }:^{4: } |
{7: 6 }:^ |
|
]])
eq({ 6, 22 }, eval('nvim_win_get_cursor(0)'))
@ -797,7 +976,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
{7: 6 }:{2:^} |
{7: 6 }:^ |
{3:-- TERMINAL --} |
]])
eq({ 6, 19 }, eval('nvim_win_get_cursor(0)'))
@ -808,7 +987,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
{7: 6 }:^{4:} |
{7: 6 }:^ |
|
]])
eq({ 6, 16 }, eval('nvim_win_get_cursor(0)'))
@ -822,7 +1001,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
{7: 6 }:{2:^} |
{7: 6 }:^ |
{3:-- TERMINAL --} |
]])
eq({ 6, 4 }, eval('nvim_win_get_cursor(0)'))
@ -833,7 +1012,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
{7: 6 }:^{4:} |
{7: 6 }:^ |
|
]])
eq({ 6, 1 }, eval('nvim_win_get_cursor(0)'))
@ -849,7 +1028,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
{7: 6 }:aaaaaaaa {2:^ } |
{7: 6 }:aaaaaaaa ^ |
{3:-- TERMINAL --} |
]])
matches('^:aaaaaaaa [ ]*$', eval('nvim_get_current_line()'))
@ -861,7 +1040,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
{7: 6 }:aaaaaaaa ^ {4: } |
{7: 6 }:aaaaaaaa ^ |
|
]])
eq({ 6, 12 }, eval('nvim_win_get_cursor(0)'))

View File

@ -37,7 +37,7 @@ describe(':terminal highlight', function()
feed('i')
screen:expect([[
tty ready |
{10: } |
^ |
|*4
{5:-- TERMINAL --} |
]])
@ -61,7 +61,7 @@ describe(':terminal highlight', function()
skip(is_os('win'))
screen:expect(sub([[
tty ready |
{NUM:text}text{10: } |
{NUM:text}text^ |
|*4
{5:-- TERMINAL --} |
]]))
@ -84,7 +84,7 @@ describe(':terminal highlight', function()
line6 |
line7 |
line8 |
{10: } |
^ |
{5:-- TERMINAL --} |
]])
feed('<c-\\><c-n>gg')
@ -195,7 +195,7 @@ it('CursorLine and CursorColumn work in :terminal buffer in Normal mode', functi
local screen = Screen.new(50, 7)
screen:set_default_attr_ids({
[1] = { background = Screen.colors.Grey90 }, -- CursorLine, CursorColumn
[2] = { reverse = true }, -- TermCursor
[2] = { reverse = true },
[3] = { bold = true }, -- ModeMsg
[4] = { background = Screen.colors.Grey90, reverse = true },
[5] = { background = Screen.colors.Red },
@ -234,7 +234,7 @@ it('CursorLine and CursorColumn work in :terminal buffer in Normal mode', functi
foobar foobar foobar foobar foobar foobar foobar f|
oobar foobar foobar foobar foobar foobar foobar fo|
obar foobar foobar foobar foobar foobar foobar foo|
bar foobar{2: } |
bar foobar^ |
{3:-- TERMINAL --} |
]])
-- Leaving terminal mode restores old values.
@ -248,46 +248,60 @@ it('CursorLine and CursorColumn work in :terminal buffer in Normal mode', functi
{1:bar fooba^r }|
|
]])
-- CursorLine and CursorColumn are combined with TermCursorNC.
command('highlight TermCursorNC gui=reverse')
-- Skip the rest of these tests on Windows #31587
if is_os('win') then
return
end
-- CursorLine and CursorColumn are combined with terminal colors.
tt.set_reverse()
tt.feed_data(' foobar')
tt.clear_attrs()
screen:expect([[
tty ready{1: } |
foobar f{1:o}obar foobar foobar foobar foobar foobar |
foobar fo{1:o}bar foobar foobar foobar foobar foobar f|
oobar foo{1:b}ar foobar foobar foobar foobar foobar fo|
obar foob{1:a}r foobar foobar foobar foobar foobar foo|
{1:bar fooba^r}{4: }{1: }|
{1:bar fooba^r}{4: foobar}{1: }|
|
]])
feed('2gg11|')
feed('2gg15|')
screen:expect([[
tty ready {1: } |
{1: foobar fo^obar foobar foobar foobar foobar foobar }|
foobar foo{1:b}ar foobar foobar foobar foobar foobar f|
oobar foob{1:a}r foobar foobar foobar foobar foobar fo|
obar fooba{1:r} foobar foobar foobar foobar foobar foo|
bar foobar{4: } |
tty ready {1: } |
{1: foobar foobar^ foobar foobar foobar foobar foobar }|
foobar foobar {1:f}oobar foobar foobar foobar foobar f|
oobar foobar f{1:o}obar foobar foobar foobar foobar fo|
obar foobar fo{1:o}bar foobar foobar foobar foobar foo|
bar foobar{2: foo}{4:b}{2:ar} |
|
]])
-- TermCursorNC has higher precedence.
command('highlight TermCursorNC gui=NONE guibg=Red')
-- Set bg color to red
tt.feed_csi('48;2;255:0:0m')
tt.feed_data(' foobar')
tt.clear_attrs()
feed('2gg20|')
-- Terminal color has higher precedence
screen:expect([[
tty ready {1: } |
{1: foobar fo^obar foobar foobar foobar foobar foobar }|
foobar foo{1:b}ar foobar foobar foobar foobar foobar f|
oobar foob{1:a}r foobar foobar foobar foobar foobar fo|
obar fooba{1:r} foobar foobar foobar foobar foobar foo|
bar foobar{5: } |
tty ready {1: } |
{1: foobar foobar foob^ar foobar foobar foobar foobar }|
foobar foobar fooba{1:r} foobar foobar foobar foobar f|
oobar foobar foobar{1: }foobar foobar foobar foobar fo|
obar foobar foobar {1:f}oobar foobar foobar foobar foo|
bar foobar{2: foobar}{5: foobar} |
|
]])
feed('G$')
screen:expect([[
tty ready{1: } |
foobar f{1:o}obar foobar foobar foobar foobar foobar |
foobar fo{1:o}bar foobar foobar foobar foobar foobar f|
oobar foo{1:b}ar foobar foobar foobar foobar foobar fo|
obar foob{1:a}r foobar foobar foobar foobar foobar foo|
{1:bar fooba^r}{5: }{1: }|
tty ready {1: } |
foobar foobar foobar f{1:o}obar foobar foobar foobar |
foobar foobar foobar fo{1:o}bar foobar foobar foobar f|
oobar foobar foobar foo{1:b}ar foobar foobar foobar fo|
obar foobar foobar foob{1:a}r foobar foobar foobar foo|
{1:bar foobar}{4: foobar}{5: fooba^r}{1: }|
|
]])
end)
@ -300,18 +314,17 @@ describe(':terminal highlight forwarding', function()
screen = Screen.new(50, 7)
screen:set_rgb_cterm(true)
screen:set_default_attr_ids({
[1] = { { reverse = true }, { reverse = true } },
[2] = { { bold = true }, { bold = true } },
[3] = { { fg_indexed = true, foreground = tonumber('0xe0e000') }, { foreground = 3 } },
[4] = { { foreground = tonumber('0xff8000') }, {} },
[1] = { { bold = true }, { bold = true } },
[2] = { { fg_indexed = true, foreground = tonumber('0xe0e000') }, { foreground = 3 } },
[3] = { { foreground = tonumber('0xff8000') }, {} },
})
command(("enew | call termopen(['%s'])"):format(testprg('tty-test')))
feed('i')
screen:expect([[
tty ready |
{1: } |
^ |
|*4
{2:-- TERMINAL --} |
{1:-- TERMINAL --} |
]])
end)
@ -326,9 +339,9 @@ describe(':terminal highlight forwarding', function()
screen:expect {
grid = [[
tty ready |
{3:text}{4:color}text{1: } |
{2:text}{3:color}text^ |
|*4
{2:-- TERMINAL --} |
{1:-- TERMINAL --} |
]],
}
end)
@ -355,7 +368,7 @@ describe(':terminal highlight with custom palette', function()
feed('i')
screen:expect([[
tty ready |
{7: } |
^ |
|*4
{9:-- TERMINAL --} |
]])
@ -369,7 +382,7 @@ describe(':terminal highlight with custom palette', function()
tt.feed_data('text')
screen:expect([[
tty ready |
{1:text}text{7: } |
{1:text}text^ |
|*4
{9:-- TERMINAL --} |
]])

View File

@ -32,7 +32,7 @@ describe(':terminal mouse', function()
line28 |
line29 |
line30 |
{1: } |
^ |
{3:-- TERMINAL --} |
]])
end)
@ -107,7 +107,7 @@ describe(':terminal mouse', function()
line29 |
line30 |
mouse enabled |
{1: } |
^ |
{3:-- TERMINAL --} |
]])
end)
@ -121,7 +121,7 @@ describe(':terminal mouse', function()
line29 |
line30 |
mouse enabled |
"#{1: } |
"#^ |
{3:-- TERMINAL --} |
]])
feed('<LeftDrag><2,2>')
@ -131,7 +131,7 @@ describe(':terminal mouse', function()
line29 |
line30 |
mouse enabled |
@##{1: } |
@##^ |
{3:-- TERMINAL --} |
]])
feed('<LeftDrag><3,2>')
@ -141,7 +141,7 @@ describe(':terminal mouse', function()
line29 |
line30 |
mouse enabled |
@$#{1: } |
@$#^ |
{3:-- TERMINAL --} |
]])
feed('<LeftRelease><3,2>')
@ -151,7 +151,7 @@ describe(':terminal mouse', function()
line29 |
line30 |
mouse enabled |
#$#{1: } |
#$#^ |
{3:-- TERMINAL --} |
]])
end)
@ -165,7 +165,7 @@ describe(':terminal mouse', function()
line29 |
line30 |
mouse enabled |
`!!{1: } |
`!!^ |
{3:-- TERMINAL --} |
]])
end)
@ -179,7 +179,7 @@ describe(':terminal mouse', function()
line29 |
line30 |
mouse enabled |
"#{1: } |
"#^ |
{3:-- TERMINAL --} |
]])
feed('<ScrollWheelUp><1,2>')
@ -189,7 +189,7 @@ describe(':terminal mouse', function()
line29 |
line30 |
mouse enabled |
`"#{1: } |
`"#^ |
{3:-- TERMINAL --} |
]])
feed('<LeftDrag><2,2>')
@ -199,7 +199,7 @@ describe(':terminal mouse', function()
line29 |
line30 |
mouse enabled |
@##{1: } |
@##^ |
{3:-- TERMINAL --} |
]])
feed('<ScrollWheelUp><2,2>')
@ -209,7 +209,7 @@ describe(':terminal mouse', function()
line29 |
line30 |
mouse enabled |
`##{1: } |
`##^ |
{3:-- TERMINAL --} |
]])
feed('<LeftRelease><2,2>')
@ -219,7 +219,7 @@ describe(':terminal mouse', function()
line29 |
line30 |
mouse enabled |
###{1: } |
###^ |
{3:-- TERMINAL --} |
]])
end)
@ -237,7 +237,7 @@ describe(':terminal mouse', function()
{7: 13 }line30 |
{7: 14 }mouse enabled |
{7: 15 }rows: 6, cols: 46 |
{7: 16 }{2: } |
{7: 16 } |
|
]])
-- If click on the coordinate (0,1) of the region of the terminal
@ -249,7 +249,7 @@ describe(':terminal mouse', function()
{7: 13 }line30 |
{7: 14 }mouse enabled |
{7: 15 }rows: 6, cols: 46 |
{7: 16 } !"{1: } |
{7: 16 } !"^ |
{3:-- TERMINAL --} |
]])
end)
@ -261,7 +261,7 @@ describe(':terminal mouse', function()
line30 |
mouse enabled |
rows: 5, cols: 50 |
{1: } |
^ |
========== |
{3:-- TERMINAL --} |
]])
@ -271,7 +271,7 @@ describe(':terminal mouse', function()
line30 |
mouse enabled |
rows: 5, cols: 50 |
{2:^ } |
^ |
========== |
|
]])
@ -280,7 +280,7 @@ describe(':terminal mouse', function()
mouse enabled |
rows: 5, cols: 50 |
rows: 4, cols: 50 |
{2:^ } |
^ |
========== |
|*2
]])
@ -293,7 +293,7 @@ describe(':terminal mouse', function()
line30 {4:~ }|
mouse enabled {4:~ }|
rows: 5, cols: 24 {4:~ }|
{1: } {4:~ }|
^ {4:~ }|
========== ========== |
{3:-- TERMINAL --} |
]])
@ -303,7 +303,7 @@ describe(':terminal mouse', function()
line30 {4:~ }|
mouse enabled {4:~ }|
rows: 5, cols: 24 {4:~ }|
{2:^ } {4:~ }|
^ {4:~ }|
========== ========== |
|
]])
@ -313,7 +313,7 @@ describe(':terminal mouse', function()
mouse enabled {4:~ }|
rows: 5, cols: 24 {4:~ }|
rows: 5, cols: 23 {4:~ }|
{2:^ } {4:~ }|
^ {4:~ }|
========== ========== |
|
]])
@ -327,7 +327,7 @@ describe(':terminal mouse', function()
line30 |
mouse enabled |
rows: 5, cols: 50 |
{1: } |
^ |
{3:-- TERMINAL --} |
]])
feed('<LeftMouse><0,0>')
@ -337,7 +337,7 @@ describe(':terminal mouse', function()
line30 |
mouse enabled |
rows: 5, cols: 50 |
{2:^ } |
^ |
|
]])
command('set showtabline=2 tabline=TABLINE | startinsert')
@ -347,7 +347,7 @@ describe(':terminal mouse', function()
mouse enabled |
rows: 5, cols: 50 |
rows: 4, cols: 50 |
{1: } |
^ |
{3:-- TERMINAL --} |
]])
feed('<LeftMouse><0,0>')
@ -357,7 +357,7 @@ describe(':terminal mouse', function()
mouse enabled |
rows: 5, cols: 50 |
rows: 4, cols: 50 |
{2:^ } |
^ |
|
]])
command('setlocal winbar= | startinsert')
@ -367,7 +367,7 @@ describe(':terminal mouse', function()
rows: 5, cols: 50 |
rows: 4, cols: 50 |
rows: 5, cols: 50 |
{1: } |
^ |
{3:-- TERMINAL --} |
]])
feed('<LeftMouse><0,0>')
@ -377,7 +377,7 @@ describe(':terminal mouse', function()
rows: 5, cols: 50 |
rows: 4, cols: 50 |
rows: 5, cols: 50 |
{2:^ } |
^ |
|
]])
end)
@ -391,7 +391,7 @@ describe(':terminal mouse', function()
line29 line29 |
line30 line30 |
rows: 5, cols: 25 rows: 5, cols: 25 |
{2:^ } {2: } |
^ |
========== ========== |
:vsp |
]])
@ -401,7 +401,7 @@ describe(':terminal mouse', function()
{4:~ }line30 |
{4:~ }rows: 5, cols: 25 |
{4:~ }rows: 5, cols: 24 |
{4:~ }{2: } |
{4:~ } |
========== ========== |
:enew | set number |
]])
@ -411,7 +411,7 @@ describe(':terminal mouse', function()
{7: 28 }line line30 |
{7: 29 }line rows: 5, cols: 25 |
{7: 30 }line rows: 5, cols: 24 |
{7: 31 }^ {2: } |
{7: 31 }^ |
========== ========== |
|
]])
@ -421,7 +421,7 @@ describe(':terminal mouse', function()
{7: 28 }line line30 |
{7: 29 }line rows: 5, cols: 25 |
{7: 30 }line rows: 5, cols: 24 |
{7: 31 } {1: } |
{7: 31 } ^ |
========== ========== |
{3:-- TERMINAL --} |
]])
@ -434,7 +434,7 @@ describe(':terminal mouse', function()
{7: 28 }line rows: 5, cols: 25 |
{7: 29 }line rows: 5, cols: 24 |
{7: 30 }line mouse enabled |
{7: 31 } {1: } |
{7: 31 } ^ |
========== ========== |
{3:-- TERMINAL --} |
]])
@ -447,7 +447,7 @@ describe(':terminal mouse', function()
{7: 22 }line rows: 5, cols: 25 |
{7: 23 }line rows: 5, cols: 24 |
{7: 24 }line mouse enabled |
{7: 25 }line {1: } |
{7: 25 }line ^ |
========== ========== |
{3:-- TERMINAL --} |
]])
@ -457,7 +457,7 @@ describe(':terminal mouse', function()
{7: 27 }line rows: 5, cols: 25 |
{7: 28 }line rows: 5, cols: 24 |
{7: 29 }line mouse enabled |
{7: 30 }line {1: } |
{7: 30 }line ^ |
========== ========== |
{3:-- TERMINAL --} |
]])
@ -468,7 +468,7 @@ describe(':terminal mouse', function()
{7: 17 }line rows: 5, cols: 25 |
{7: 18 }line rows: 5, cols: 24 |
{7: 19 }line mouse enabled |
{7: 20 }line {1: } |
{7: 20 }line ^ |
========== ========== |
{3:-- TERMINAL --} |
]])
@ -483,7 +483,7 @@ describe(':terminal mouse', function()
{7: 2 }linelinelinelineline rows: 5, cols: 25 |
{7: 3 }linelinelinelineline rows: 5, cols: 24 |
{7: 4 }linelinelinelineline mouse enabled |
{7: 5 }linelinelinelineline {1: } |
{7: 5 }linelinelinelineline ^ |
========== ========== |
{3:-- TERMINAL --} |
]])
@ -493,7 +493,7 @@ describe(':terminal mouse', function()
{7: 2 }nelinelineline rows: 5, cols: 25 |
{7: 3 }nelinelineline rows: 5, cols: 24 |
{7: 4 }nelinelineline mouse enabled |
{7: 5 }nelinelineline {1: } |
{7: 5 }nelinelineline ^ |
========== ========== |
{3:-- TERMINAL --} |
]])
@ -504,7 +504,7 @@ describe(':terminal mouse', function()
{7: 2 }nelinelinelineline rows: 5, cols: 25 |
{7: 3 }nelinelinelineline rows: 5, cols: 24 |
{7: 4 }nelinelinelineline mouse enabled |
{7: 5 }nelinelinelineline {1: } |
{7: 5 }nelinelinelineline ^ |
========== ========== |
{3:-- TERMINAL --} |
]])
@ -517,7 +517,7 @@ describe(':terminal mouse', function()
{7: 28 }l^ine rows: 5, cols: 25 |
{7: 29 }line rows: 5, cols: 24 |
{7: 30 }line mouse enabled |
{7: 31 } {2: } |
{7: 31 } |
========== ========== |
|
]])
@ -531,7 +531,7 @@ describe(':terminal mouse', function()
{7: 28 }line rows: 5, cols: 25 |
{7: 29 }line rows: 5, cols: 24 |
{7: 30 }line mouse enabled |
{7: 31 }^ {2: } |
{7: 31 }^ |
========== ========== |
|
]])
@ -541,7 +541,7 @@ describe(':terminal mouse', function()
rows: 5, cols: 24 rows: 5, cols: 24 |
mouse enabled mouse enabled |
rows: 5, cols: 25 rows: 5, cols: 25 |
{2:^ } {2: } |
^ |
========== ========== |
:bn |
]])
@ -551,7 +551,7 @@ describe(':terminal mouse', function()
{7: 28 }line mouse enabled |
{7: 29 }line rows: 5, cols: 25 |
{7: 30 }line rows: 5, cols: 24 |
{7: 31 }^ {2: } |
{7: 31 }^ |
========== ========== |
:bn |
]])

View File

@ -39,7 +39,7 @@ describe(':terminal scrollback', function()
line28 |
line29 |
line30 |
{1: } |
^ |
{3:-- TERMINAL --} |
]])
end)
@ -67,7 +67,7 @@ describe(':terminal scrollback', function()
line2 |
line3 |
line4 |
{1: } |
^ |
{3:-- TERMINAL --} |
]])
end)
@ -84,7 +84,7 @@ describe(':terminal scrollback', function()
line3 |
line4 |
line5 |
{1: } |
^ |
{3:-- TERMINAL --} |
]])
eq(7, api.nvim_buf_line_count(0))
@ -102,7 +102,7 @@ describe(':terminal scrollback', function()
line5 |
line6 |
line7 |
line8{1: } |
line8^ |
{3:-- TERMINAL --} |
]])
@ -135,7 +135,7 @@ describe(':terminal scrollback', function()
line5 |
line6 |
line7 |
^line8{2: } |
^line8 |
|
]])
end)
@ -151,7 +151,7 @@ describe(':terminal scrollback', function()
line3 |
line4 |
rows: 5, cols: 28 |
{2:^ } |
^ |
|
]])
end
@ -168,7 +168,7 @@ describe(':terminal scrollback', function()
screen:expect([[
rows: 5, cols: 28 |
rows: 3, cols: 26 |
{2:^ } |
^ |
|
]])
eq(8, api.nvim_buf_line_count(0))
@ -201,7 +201,7 @@ describe(':terminal scrollback', function()
screen:expect([[
tty ready |
rows: 4, cols: 30 |
{1: } |
^ |
|
{3:-- TERMINAL --} |
]])
@ -220,7 +220,7 @@ describe(':terminal scrollback', function()
screen:expect([[
rows: 4, cols: 30 |
rows: 3, cols: 30 |
{1: } |
^ |
{3:-- TERMINAL --} |
]])
eq(4, api.nvim_buf_line_count(0))
@ -235,7 +235,7 @@ describe(':terminal scrollback', function()
screen:expect([[
rows: 4, cols: 30 |
rows: 3, cols: 30 |
{1: } |
^ |
{3:-- TERMINAL --} |
]])
end)
@ -252,14 +252,14 @@ describe(':terminal scrollback', function()
line2 |
line3 |
line4 |
{1: } |
^ |
{3:-- TERMINAL --} |
]])
screen:try_resize(screen._width, screen._height - 3)
screen:expect([[
line4 |
rows: 3, cols: 30 |
{1: } |
^ |
{3:-- TERMINAL --} |
]])
eq(7, api.nvim_buf_line_count(0))
@ -278,7 +278,7 @@ describe(':terminal scrollback', function()
line4 |
rows: 3, cols: 30 |
rows: 4, cols: 30 |
{1: } |
^ |
{3:-- TERMINAL --} |
]])
end
@ -300,7 +300,7 @@ describe(':terminal scrollback', function()
rows: 3, cols: 30 |
rows: 4, cols: 30 |
rows: 7, cols: 30 |
{1: } |
^ |
{3:-- TERMINAL --} |
]])
eq(9, api.nvim_buf_line_count(0))
@ -337,7 +337,7 @@ describe(':terminal scrollback', function()
rows: 4, cols: 30 |
rows: 7, cols: 30 |
rows: 11, cols: 30 |
{1: } |
^ |
|
{3:-- TERMINAL --} |
]])
@ -362,7 +362,7 @@ describe(':terminal prints more lines than the screen height and exits', functio
line8 |
line9 |
|
[Process exited 0]{2: } |
[Process exited 0]^ |
{5:-- TERMINAL --} |
]])
feed('<cr>')
@ -454,7 +454,7 @@ describe("'scrollback' option", function()
39: line |
40: line |
|
${1: } |
$^ |
{3:-- TERMINAL --} |
]],
}
@ -493,7 +493,7 @@ describe("'scrollback' option", function()
line28 |
line29 |
line30 |
{1: } |
^ |
{3:-- TERMINAL --} |
]])
local term_height = 6 -- Actual terminal screen height, not the scrollback
@ -634,7 +634,7 @@ describe('pending scrollback line handling', function()
screen:expect [[
hi |*4
|
[Process exited 0]{2: } |
[Process exited 0]^ |
{3:-- TERMINAL --} |
]]
assert_alive()

File diff suppressed because it is too large Load Diff

View File

@ -62,7 +62,7 @@ describe(':terminal window', function()
screen:expect([[
{7:1 }tty ready |
{7:2 }rows: 6, cols: 48 |
{7:3 }{1: } |
{7:3 }^ |
{7:4 } |
{7:5 } |
{7:6 } |
@ -73,7 +73,7 @@ describe(':terminal window', function()
{7:1 }tty ready |
{7:2 }rows: 6, cols: 48 |
{7:3 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUV|
{7:4 }WXYZ{1: } |
{7:4 }WXYZ^ |
{7:5 } |
{7:6 } |
{3:-- TERMINAL --} |
@ -87,7 +87,7 @@ describe(':terminal window', function()
{7: 2 }rows: 6, cols: 48 |
{7: 3 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO|
{7: 4 }PQRSTUVWXYZrows: 6, cols: 41 |
{7: 5 }{1: } |
{7: 5 }^ |
{7: 6 } |
{3:-- TERMINAL --} |
]])
@ -98,7 +98,7 @@ describe(':terminal window', function()
{7: 3 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO|
{7: 4 }PQRSTUVWXYZrows: 6, cols: 41 |
{7: 5 } abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMN|
{7: 6 }OPQRSTUVWXYZ{1: } |
{7: 6 }OPQRSTUVWXYZ^ |
{3:-- TERMINAL --} |
]])
end)
@ -110,7 +110,7 @@ describe(':terminal window', function()
screen:expect([[
{7:++1 }tty ready |
{7:++2 }rows: 6, cols: 45 |
{7:++3 }{1: } |
{7:++3 }^ |
{7:++4 } |
{7:++5 } |
{7:++6 } |
@ -123,7 +123,7 @@ describe(':terminal window', function()
{7:++6 } |
{7:++7 } |
{7:++8 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRS|
{7:++9 }TUVWXYZ{1: } |
{7:++9 }TUVWXYZ^ |
{3:-- TERMINAL --} |
]])
feed_data('\nabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
@ -133,7 +133,7 @@ describe(':terminal window', function()
{7:++ 9 }STUVWXYZ |
{7:++10 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR|
{7:++11 }STUVWXYZrows: 6, cols: 44 |
{7:++12 }{1: } |
{7:++12 }^ |
{3:-- TERMINAL --} |
]])
end)
@ -144,7 +144,7 @@ describe(':terminal window', function()
feed([[<C-\><C-N>]])
screen:expect([[
tty ready |
{2:^ } |
^ |
|*5
]])
feed(':set colorcolumn=20<CR>i')
@ -153,7 +153,7 @@ describe(':terminal window', function()
it('wont show the color column', function()
screen:expect([[
tty ready |
{1: } |
^ |
|*4
{3:-- TERMINAL --} |
]])
@ -170,7 +170,7 @@ describe(':terminal window', function()
line2 |
line3 |
line4 |
{1: } |
^ |
{3:-- TERMINAL --} |
]])
end)
@ -184,7 +184,7 @@ describe(':terminal window', function()
line2 |
line3 |
line4 |
{2: } |
|
|
]])
end)
@ -206,7 +206,7 @@ describe(':terminal with multigrid', function()
[3:--------------------------------------------------]|
## grid 2
tty ready |
{1: } |
^ |
|*4
## grid 3
{3:-- TERMINAL --} |
@ -223,7 +223,7 @@ describe(':terminal with multigrid', function()
## grid 2
tty ready |
rows: 10, cols: 20 |
{1: } |
^ |
|*7
## grid 3
{3:-- TERMINAL --} |
@ -241,7 +241,7 @@ describe(':terminal with multigrid', function()
## grid 2
rows: 10, cols: 20 |
rows: 3, cols: 70 |
{1: } |
^ |
## grid 3
{3:-- TERMINAL --} |
]])
@ -260,7 +260,7 @@ describe(':terminal with multigrid', function()
rows: 10, cols: 20 |
rows: 3, cols: 70 |
rows: 6, cols: 50 |
{1: } |
^ |
|
## grid 3
{3:-- TERMINAL --} |

View File

@ -49,7 +49,7 @@ describe(':terminal', function()
========== |
tty ready |
rows: 5, cols: 50 |
{2: } |
|
|*2
========== |
:2split |
@ -61,7 +61,7 @@ describe(':terminal', function()
========== |
^tty ready |
rows: 5, cols: 50 |
{2: } |
|
|*2
========== |
:wincmd p |
@ -77,7 +77,7 @@ describe(':terminal', function()
command('bprevious')
screen:expect([[
tty ready |
^foo{2: } |
^foo |
|*8
]])
end)
@ -102,7 +102,7 @@ describe(':terminal', function()
screen:expect([[
tty ready |
rows: 7, cols: 47 |
{2: } |
|
|*3
^ |
|
@ -112,7 +112,7 @@ describe(':terminal', function()
tty ready |
rows: 7, cols: 47 |
rows: 4, cols: 41 |
{2:^ } |
^ |
|
]])
end)

View File

@ -29,6 +29,10 @@ function M.feed_termcode(data)
M.feed_data('\027' .. data)
end
function M.feed_csi(data)
M.feed_termcode('[' .. data)
end
function M.make_lua_executor(session)
return function(code, ...)
local status, rv = session:request('nvim_exec_lua', code, { ... })
@ -78,6 +82,9 @@ end
function M.set_undercurl()
M.feed_termcode('[4:3m')
end
function M.set_reverse()
M.feed_termcode('[7m')
end
function M.set_strikethrough()
M.feed_termcode('[9m')
end
@ -108,7 +115,6 @@ function M.setup_screen(extra_rows, cmd, cols, env, screen_opts)
cols = cols and cols or 50
api.nvim_command('highlight TermCursor cterm=reverse')
api.nvim_command('highlight TermCursorNC ctermbg=11')
api.nvim_command('highlight StatusLineTerm ctermbg=2 ctermfg=0')
api.nvim_command('highlight StatusLineTermNC ctermbg=2 ctermfg=8')
@ -154,7 +160,7 @@ function M.setup_screen(extra_rows, cmd, cols, env, screen_opts)
local empty_line = (' '):rep(cols)
local expected = {
'tty ready' .. (' '):rep(cols - 9),
'{1: }' .. (' '):rep(cols - 1),
'^' .. (' '):rep(cols),
empty_line,
empty_line,
empty_line,

View File

@ -190,6 +190,19 @@ describe('ui/cursor', function()
attr_lm = {},
short_name = 'sm',
},
[18] = {
blinkoff = 500,
blinkon = 500,
blinkwait = 0,
cell_percentage = 0,
cursor_shape = 'block',
name = 'terminal',
hl_id = 3,
id_lm = 3,
attr = { reverse = true },
attr_lm = { reverse = true },
short_name = 't',
},
}
screen:expect(function()
@ -245,17 +258,20 @@ describe('ui/cursor', function()
end
end
if m.hl_id then
m.hl_id = 66
m.hl_id = 65
m.attr = { background = Screen.colors.DarkGray }
end
if m.id_lm then
m.id_lm = 73
m.id_lm = 72
m.attr_lm = {}
end
end
-- Assert the new expectation.
screen:expect(function()
eq(expected_mode_info, screen._mode_info)
for i, v in ipairs(expected_mode_info) do
eq(v, screen._mode_info[i])
end
eq(true, screen._cursor_style_enabled)
eq('normal', screen.mode)
end)

View File

@ -9621,6 +9621,116 @@ describe('float window', function()
})
end
end)
it('#winborder option', function()
local buf = api.nvim_create_buf(false,false)
local config = {relative='editor', width=4, height=4, row=2, col=2}
command('set winborder=single')
api.nvim_open_win(buf, true, config)
if multigrid then
screen:expect({
grid = [[
## grid 1
[2:----------------------------------------]|*6
[3:----------------------------------------]|
## grid 2
|
{0:~ }|*5
## grid 3
|
## grid 4
{5:}|
{5:}{1:^ }{5:}|
{5:}{2:~ }{5:}|*3
{5:}|
]], float_pos={
[4] = {1001, "NW", 1, 2, 2, true, 50};
}, win_viewport={
[2] = {win = 1000, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0};
[4] = {win = 1001, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0};
}, win_viewport_margins={
[2] = {
bottom = 0,
left = 0,
right = 0,
top = 0,
win = 1000
},
[4] = {
bottom = 1,
left = 1,
right = 1,
top = 1,
win = 1001
}
}
})
else
screen:expect({
grid = [[
{5:} |
{0:~ }{5:}{1:^ }{5:}{0: }|
{0:~ }{5:}{2:~ }{5:}{0: }|*3
{0:~ }{5:}{0: }|
|
]]
})
end
command('fclose')
command('set winborder=double')
api.nvim_open_win(buf, true, config)
if multigrid then
screen:expect({
grid = [[
## grid 1
[2:----------------------------------------]|*6
[3:----------------------------------------]|
## grid 2
|
{0:~ }|*5
## grid 3
|
## grid 5
{5:}|
{5:}{1:^ }{5:}|
{5:}{2:~ }{5:}|*3
{5:}|
]], float_pos={
[5] = {1002, "NW", 1, 2, 2, true, 50};
}, win_viewport={
[2] = {win = 1000, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0};
[5] = {win = 1002, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0};
}, win_viewport_margins={
[2] = {
bottom = 0,
left = 0,
right = 0,
top = 0,
win = 1000
},
[5] = {
bottom = 1,
left = 1,
right = 1,
top = 1,
win = 1002
}
}
})
else
screen:expect({
grid = [[
{5:} |
{0:~ }{5:}{1:^ }{5:}{0: }|
{0:~ }{5:}{2:~ }{5:}{0: }|*3
{0:~ }{5:}{0: }|
|
]]
})
end
command('fclose!')
end)
end
describe('with ext_multigrid', function()

View File

@ -227,7 +227,7 @@ describe('ext_hlstate detailed highlights', function()
command(("enew | call termopen(['%s'])"):format(testprg('tty-test')))
screen:expect([[
^tty ready |
{1: } |
|
|*5
{7: }|
]])
@ -242,7 +242,7 @@ describe('ext_hlstate detailed highlights', function()
screen:expect([[
^tty ready |
x {5:y z} |
{1: } |
|
|*4
{7: }|
]])
@ -250,7 +250,7 @@ describe('ext_hlstate detailed highlights', function()
screen:expect([[
^tty ready |
x {2:y }{3:z} |
{1: } |
|
|*4
{7: }|
]])
@ -268,7 +268,7 @@ describe('ext_hlstate detailed highlights', function()
else
screen:expect([[
^tty ready |
x {4:y}{2: }{3:z} |
x {2:y }{3:z} |
|*5
{7: }|
]])

View File

@ -49,7 +49,7 @@ describe('ui/ext_messages', function()
]],
messages = {
{
content = { { '\ntest\n[O]k: ', 6, 11 } },
content = { { '\ntest\n[O]k: ', 6, 10 } },
kind = 'confirm',
},
},
@ -77,7 +77,7 @@ describe('ui/ext_messages', function()
]],
messages = {
{
content = { { '\ntest\n[O]k: ', 6, 11 } },
content = { { '\ntest\n[O]k: ', 6, 10 } },
kind = 'confirm',
},
},
@ -91,7 +91,7 @@ describe('ui/ext_messages', function()
]],
messages = {
{
content = { { '\ntest\n[O]k: ', 6, 11 } },
content = { { '\ntest\n[O]k: ', 6, 10 } },
kind = 'confirm',
},
{
@ -99,7 +99,7 @@ describe('ui/ext_messages', function()
kind = 'echo',
},
{
content = { { 'Press ENTER or type command to continue', 6, 19 } },
content = { { 'Press ENTER or type command to continue', 6, 18 } },
kind = 'return_prompt',
},
},
@ -116,7 +116,7 @@ describe('ui/ext_messages', function()
]],
messages = {
{
content = { { 'replace with X (y/n/a/q/l/^E/^Y)?', 6, 19 } },
content = { { 'replace with X (y/n/a/q/l/^E/^Y)?', 6, 18 } },
kind = 'confirm_sub',
},
},
@ -135,7 +135,7 @@ describe('ui/ext_messages', function()
]],
messages = {
{
content = { { 'W10: Warning: Changing a readonly file', 19, 27 } },
content = { { 'W10: Warning: Changing a readonly file', 19, 26 } },
kind = 'wmsg',
},
},
@ -151,7 +151,7 @@ describe('ui/ext_messages', function()
]],
messages = {
{
content = { { 'search hit BOTTOM, continuing at TOP', 19, 27 } },
content = { { 'search hit BOTTOM, continuing at TOP', 19, 26 } },
kind = 'wmsg',
},
},
@ -167,15 +167,15 @@ describe('ui/ext_messages', function()
]],
messages = {
{
content = { { 'Error detected while processing :', 9, 7 } },
content = { { 'Error detected while processing :', 9, 6 } },
kind = 'emsg',
},
{
content = { { 'E605: Exception not caught: foo', 9, 7 } },
content = { { 'E605: Exception not caught: foo', 9, 6 } },
kind = 'emsg',
},
{
content = { { 'Press ENTER or type command to continue', 6, 19 } },
content = { { 'Press ENTER or type command to continue', 6, 18 } },
kind = 'return_prompt',
},
},
@ -225,15 +225,15 @@ describe('ui/ext_messages', function()
{
content = {
{ '\nErrorMsg ' },
{ 'xxx', 9, 7 },
{ 'xxx', 9, 6 },
{ ' ' },
{ 'ctermfg=', 18, 6 },
{ 'ctermfg=', 18, 5 },
{ '15 ' },
{ 'ctermbg=', 18, 6 },
{ 'ctermbg=', 18, 5 },
{ '1 ' },
{ 'guifg=', 18, 6 },
{ 'guifg=', 18, 5 },
{ 'White ' },
{ 'guibg=', 18, 6 },
{ 'guibg=', 18, 5 },
{ 'Red' },
},
kind = 'list_cmd',
@ -280,7 +280,7 @@ describe('ui/ext_messages', function()
{1:~ }|*4
]],
messages = { {
content = { { 'raa', 9, 7 } },
content = { { 'raa', 9, 6 } },
kind = 'echoerr',
} },
}
@ -307,15 +307,15 @@ describe('ui/ext_messages', function()
]],
messages = {
{
content = { { 'bork', 9, 7 } },
content = { { 'bork', 9, 6 } },
kind = 'echoerr',
},
{
content = { { 'fail', 9, 7 } },
content = { { 'fail', 9, 6 } },
kind = 'echoerr',
},
{
content = { { 'Press ENTER or type command to continue', 6, 19 } },
content = { { 'Press ENTER or type command to continue', 6, 18 } },
kind = 'return_prompt',
},
},
@ -329,19 +329,19 @@ describe('ui/ext_messages', function()
]],
messages = {
{
content = { { 'bork', 9, 7 } },
content = { { 'bork', 9, 6 } },
kind = 'echoerr',
},
{
content = { { 'fail', 9, 7 } },
content = { { 'fail', 9, 6 } },
kind = 'echoerr',
},
{
content = { { 'extrafail', 9, 7 } },
content = { { 'extrafail', 9, 6 } },
kind = 'echoerr',
},
{
content = { { 'Press ENTER or type command to continue', 6, 19 } },
content = { { 'Press ENTER or type command to continue', 6, 18 } },
kind = 'return_prompt',
},
},
@ -363,7 +363,7 @@ describe('ui/ext_messages', function()
{1:~ }|*4
]],
messages = { {
content = { { 'problem', 9, 7 } },
content = { { 'problem', 9, 6 } },
kind = 'echoerr',
} },
cmdline = {
@ -391,15 +391,15 @@ describe('ui/ext_messages', function()
{1:~ }|*4
]],
msg_history = {
{ kind = 'echoerr', content = { { 'raa', 9, 7 } } },
{ kind = 'echoerr', content = { { 'bork', 9, 7 } } },
{ kind = 'echoerr', content = { { 'fail', 9, 7 } } },
{ kind = 'echoerr', content = { { 'extrafail', 9, 7 } } },
{ kind = 'echoerr', content = { { 'problem', 9, 7 } } },
{ kind = 'echoerr', content = { { 'raa', 9, 6 } } },
{ kind = 'echoerr', content = { { 'bork', 9, 6 } } },
{ kind = 'echoerr', content = { { 'fail', 9, 6 } } },
{ kind = 'echoerr', content = { { 'extrafail', 9, 6 } } },
{ kind = 'echoerr', content = { { 'problem', 9, 6 } } },
},
messages = {
{
content = { { 'Press ENTER or type command to continue', 6, 19 } },
content = { { 'Press ENTER or type command to continue', 6, 18 } },
kind = 'return_prompt',
},
},
@ -424,7 +424,7 @@ describe('ui/ext_messages', function()
]],
messages = {
{
content = { { 'bork\nfail', 9, 7 } },
content = { { 'bork\nfail', 9, 6 } },
kind = 'echoerr',
},
},
@ -438,13 +438,13 @@ describe('ui/ext_messages', function()
]],
messages = {
{
content = { { 'Press ENTER or type command to continue', 6, 19 } },
content = { { 'Press ENTER or type command to continue', 6, 18 } },
kind = 'return_prompt',
},
},
msg_history = {
{
content = { { 'bork\nfail', 9, 7 } },
content = { { 'bork\nfail', 9, 6 } },
kind = 'echoerr',
},
},
@ -492,7 +492,7 @@ describe('ui/ext_messages', function()
{ content = { { 'x #1' } }, kind = 'list_cmd' },
{ content = { { 'y #2' } }, kind = 'list_cmd' },
{
content = { { 'Press ENTER or type command to continue', 6, 19 } },
content = { { 'Press ENTER or type command to continue', 6, 18 } },
kind = 'return_prompt',
},
},
@ -507,7 +507,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
showmode = { { '-- INSERT --', 5, 12 } },
showmode = { { '-- INSERT --', 5, 11 } },
}
feed('alphpabet<cr>alphanum<cr>')
@ -518,7 +518,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*2
]],
showmode = { { '-- INSERT --', 5, 12 } },
showmode = { { '-- INSERT --', 5, 11 } },
}
feed('<c-x>')
@ -529,7 +529,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*2
]],
showmode = { { '-- ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)', 5, 12 } },
showmode = { { '-- ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)', 5, 11 } },
}
feed('<c-p>')
@ -545,7 +545,7 @@ describe('ui/ext_messages', function()
items = { { 'alphpabet', '', '', '' }, { 'alphanum', '', '', '' } },
pos = 1,
},
showmode = { { '-- Keyword Local completion (^N^P) ', 5, 12 }, { 'match 1 of 2', 6, 19 } },
showmode = { { '-- Keyword Local completion (^N^P) ', 5, 11 }, { 'match 1 of 2', 6, 18 } },
}
-- echomsg and showmode don't overwrite each other, this is the same
@ -567,7 +567,7 @@ describe('ui/ext_messages', function()
content = { { 'stuff' } },
kind = 'echomsg',
} },
showmode = { { '-- Keyword Local completion (^N^P) ', 5, 12 }, { 'match 1 of 2', 6, 19 } },
showmode = { { '-- Keyword Local completion (^N^P) ', 5, 11 }, { 'match 1 of 2', 6, 18 } },
}
feed('<c-p>')
@ -587,7 +587,7 @@ describe('ui/ext_messages', function()
content = { { 'stuff' } },
kind = 'echomsg',
} },
showmode = { { '-- Keyword Local completion (^N^P) ', 5, 12 }, { 'match 2 of 2', 6, 19 } },
showmode = { { '-- Keyword Local completion (^N^P) ', 5, 11 }, { 'match 2 of 2', 6, 18 } },
}
feed('<esc>:messages<cr>')
@ -604,7 +604,7 @@ describe('ui/ext_messages', function()
} },
messages = {
{
content = { { 'Press ENTER or type command to continue', 6, 19 } },
content = { { 'Press ENTER or type command to continue', 6, 18 } },
kind = 'return_prompt',
},
},
@ -618,7 +618,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
showmode = { { 'recording @q', 5, 12 } },
showmode = { { 'recording @q', 5, 11 } },
}
feed('i')
@ -627,7 +627,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
showmode = { { '-- INSERT --recording @q', 5, 12 } },
showmode = { { '-- INSERT --recording @q', 5, 11 } },
}
feed('<esc>')
@ -636,7 +636,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
showmode = { { 'recording @q', 5, 12 } },
showmode = { { 'recording @q', 5, 11 } },
}
feed('q')
@ -655,7 +655,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
showmode = { { 'recording @q', 5, 12 } },
showmode = { { 'recording @q', 5, 11 } },
mode = 'normal',
}
@ -665,7 +665,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
showmode = { { 'recording @q', 5, 12 } },
showmode = { { 'recording @q', 5, 11 } },
mode = 'insert',
}
@ -675,7 +675,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
showmode = { { 'recording @q', 5, 12 } },
showmode = { { 'recording @q', 5, 11 } },
mode = 'normal',
}
@ -697,7 +697,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
ruler = { { '0,0-1 All', 9, 62 } },
ruler = { { '0,0-1 All', 9, 61 } },
})
command('hi clear MsgArea')
feed('i')
@ -706,7 +706,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
showmode = { { '-- INSERT --', 5, 12 } },
showmode = { { '-- INSERT --', 5, 11 } },
ruler = { { '0,1 All' } },
}
feed('abcde<cr>12345<esc>')
@ -744,7 +744,7 @@ describe('ui/ext_messages', function()
{17:123}45 |
{1:~ }|*3
]],
showmode = { { '-- VISUAL BLOCK --', 5, 12 } },
showmode = { { '-- VISUAL BLOCK --', 5, 11 } },
showcmd = { { '2x3' } },
ruler = { { '1,3 All' } },
})
@ -825,7 +825,7 @@ describe('ui/ext_messages', function()
{1:~ }|*4
]],
messages = { {
content = { { 'bork', 9, 7 } },
content = { { 'bork', 9, 6 } },
kind = 'echoerr',
} },
}
@ -850,7 +850,7 @@ describe('ui/ext_messages', function()
]],
messages = {
{
content = { { 'E117: Unknown function: nosuchfunction', 9, 7 } },
content = { { 'E117: Unknown function: nosuchfunction', 9, 6 } },
kind = 'emsg',
},
},
@ -865,12 +865,12 @@ describe('ui/ext_messages', function()
msg_history = {
{ kind = 'echomsg', content = { { 'howdy' } } },
{ kind = '', content = { { 'Type :qa and press <Enter> to exit Nvim' } } },
{ kind = 'echoerr', content = { { 'bork', 9, 7 } } },
{ kind = 'emsg', content = { { 'E117: Unknown function: nosuchfunction', 9, 7 } } },
{ kind = 'echoerr', content = { { 'bork', 9, 6 } } },
{ kind = 'emsg', content = { { 'E117: Unknown function: nosuchfunction', 9, 6 } } },
},
messages = {
{
content = { { 'Press ENTER or type command to continue', 6, 19 } },
content = { { 'Press ENTER or type command to continue', 6, 18 } },
kind = 'return_prompt',
},
},
@ -943,7 +943,7 @@ stack traceback:
[C]: in function 'error'
[string ":lua"]:1: in main chunk]],
9,
7,
6,
},
},
kind = 'lua_error',
@ -963,7 +963,7 @@ stack traceback:
messages = {
{
content = {
{ "Error invoking 'test_method' on channel 1:\ncomplete\nerror\n\nmessage", 9, 7 },
{ "Error invoking 'test_method' on channel 1:\ncomplete\nerror\n\nmessage", 9, 6 },
},
kind = 'rpc_error',
},
@ -1092,7 +1092,7 @@ stack traceback:
]],
messages = {
{
content = { { 'wow, ', 10, 9 }, { 'such\n\nvery ', 9, 7 }, { 'color', 8, 13 } },
content = { { 'wow, ', 10, 8 }, { 'such\n\nvery ', 9, 6 }, { 'color', 8, 12 } },
kind = 'echomsg',
},
},
@ -1117,13 +1117,13 @@ stack traceback:
]],
messages = {
{
content = { { 'Press ENTER or type command to continue', 6, 19 } },
content = { { 'Press ENTER or type command to continue', 6, 18 } },
kind = 'return_prompt',
},
},
msg_history = {
{
content = { { 'wow, ', 10, 9 }, { 'such\n\nvery ', 9, 7 }, { 'color', 8, 13 } },
content = { { 'wow, ', 10, 8 }, { 'such\n\nvery ', 9, 6 }, { 'color', 8, 12 } },
kind = 'echomsg',
},
},
@ -1783,7 +1783,7 @@ describe('ui/ext_messages', function()
{1:~ }type :help iccf{18:<Enter>} for information {1: }|
{1:~ }|*5
]]
local showmode = { { '-- INSERT --', 5, 12 } }
local showmode = { { '-- INSERT --', 5, 11 } }
screen:expect(introscreen)
-- <c-l> (same as :mode) does _not_ clear intro message
@ -1858,7 +1858,7 @@ describe('ui/ext_messages', function()
]],
messages = {
{
content = { { 'Press ENTER or type command to continue', 6, 19 } },
content = { { 'Press ENTER or type command to continue', 6, 18 } },
kind = 'return_prompt',
},
},

View File

@ -94,6 +94,46 @@ describe('ui mode_change event', function()
}
end)
-- oldtest: Test_indent_norm_with_gq()
it('is restored to Normal mode after "gq" indents using :normal #12309', function()
screen:try_resize(60, 6)
n.exec([[
func Indent()
exe "normal! \<Ignore>"
return 0
endfunc
setlocal indentexpr=Indent()
call setline(1, [repeat('a', 80), repeat('b', 80)])
]])
feed('ggVG')
screen:expect {
grid = [[
{17:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
{17:aaaaaaaaaaaaaaaaaaaa} |
^b{17:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb}|
{17:bbbbbbbbbbbbbbbbbbbb} |
{1:~ }|
{5:-- VISUAL LINE --} |
]],
mode = 'visual',
}
feed('gq')
screen:expect {
grid = [[
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
aaaaaaaaaaaaaaaaaaaa |
^bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|
bbbbbbbbbbbbbbbbbbbb |
{1:~ }|
|
]],
mode = 'normal',
}
end)
it('works in insert mode', function()
feed('i')
screen:expect {

View File

@ -34,7 +34,7 @@ describe('shell command :!', function()
n.nvim_set .. ' notermguicolors',
})
screen:expect([[
{1: } |
^ |
{4:~ }|*4
|
{3:-- TERMINAL --} |
@ -78,7 +78,7 @@ describe('shell command :!', function()
29999: foo |
30000: foo |
|
{10:Press ENTER or type command to continue}{1: } |
{10:Press ENTER or type command to continue}^ |
{3:-- TERMINAL --} |
]],
{

View File

@ -5561,6 +5561,71 @@ describe('builtin popupmenu', function()
]])
feed('<C-E><ESC>')
end)
-- oldtest: Test_pum_matchins_highlight()
it('with ComplMatchIns highlight', function()
exec([[
func Omni_test(findstart, base)
if a:findstart
return col(".")
endif
return [#{word: "foo"}, #{word: "bar"}, #{word: "你好"}]
endfunc
set omnifunc=Omni_test
hi ComplMatchIns guifg=red
]])
feed('Sαβγ <C-X><C-O>')
screen:expect([[
αβγ {8:foo}^ |
{1:~ }{s: foo }{1: }|
{1:~ }{n: bar }{1: }|
{1:~ }{n: }{1: }|
{1:~ }|*15
{2:-- }{5:match 1 of 3} |
]])
feed('<C-E><Esc>')
feed('Sαβγ <C-X><C-O><C-N>')
screen:expect([[
αβγ {8:bar}^ |
{1:~ }{n: foo }{1: }|
{1:~ }{s: bar }{1: }|
{1:~ }{n: }{1: }|
{1:~ }|*15
{2:-- }{5:match 2 of 3} |
]])
feed('<C-E><Esc>')
feed('Sαβγ <C-X><C-O><C-N><C-N>')
screen:expect([[
αβγ {8:}^ |
{1:~ }{n: foo }{1: }|
{1:~ }{n: bar }{1: }|
{1:~ }{s: }{1: }|
{1:~ }|*15
{2:-- }{5:match 3 of 3} |
]])
feed('<C-E><Esc>')
-- restore after accept
feed('Sαβγ <C-X><C-O><C-Y>')
screen:expect([[
αβγ foo^ |
{1:~ }|*18
{2:-- INSERT --} |
]])
feed('<Esc>')
-- restore after cancel completion
feed('Sαβγ <C-X><C-O><Space>')
screen:expect([[
αβγ foo ^ |
{1:~ }|*18
{2:-- INSERT --} |
]])
feed('<Esc>')
end)
end
end

View File

@ -967,11 +967,11 @@ function Screen:_handle_mode_info_set(cursor_style_enabled, mode_info)
self._cursor_style_enabled = cursor_style_enabled
for _, item in pairs(mode_info) do
-- attr IDs are not stable, but their value should be
if item.attr_id ~= nil then
if item.attr_id ~= nil and self._attr_table[item.attr_id] ~= nil then
item.attr = self._attr_table[item.attr_id][1]
item.attr_id = nil
end
if item.attr_id_lm ~= nil then
if item.attr_id_lm ~= nil and self._attr_table[item.attr_id_lm] ~= nil then
item.attr_lm = self._attr_table[item.attr_id_lm][1]
item.attr_id_lm = nil
end

View File

@ -75,6 +75,7 @@ let test_values = {
\ 'shada': [['', '''50', '"30'], ['xxx']],
\ 'termpastefilter': [['BS', 'HT', 'FF', 'ESC', 'DEL', 'C0', 'C1', 'C0,C1'],
\ ['xxx', 'C0,C1,xxx']],
\ 'winborder': [['rounded', 'none', 'single', 'solid'], ['xxx']],
\ 'winhighlight': [['', 'a:b', 'a:', 'a:b,c:d'],
\ ['a', ':', ':b', 'a:b:c', 'a:/', '/:b', ',', 'a:b,,', 'a:b,c']],
\

View File

@ -1,5 +1,8 @@
" Test for various indent options
source shared.vim
source check.vim
func Test_preserveindent()
new
" Test for autoindent copying indent from the previous line
@ -303,4 +306,50 @@ func Test_indent_overflow_count2()
close!
endfunc
" Test that mouse shape is restored to Normal mode after using "gq" when
" 'indentexpr' executes :normal.
func Test_indent_norm_with_gq()
CheckFeature mouseshape
CheckCanRunGui
let lines =<< trim END
func Indent()
exe "normal! \<Ignore>"
return 0
endfunc
setlocal indentexpr=Indent()
END
call writefile(lines, 'Xindentexpr.vim', 'D')
let lines =<< trim END
vim9script
var mouse_shapes = []
setline(1, [repeat('a', 80), repeat('b', 80)])
feedkeys('ggVG')
timer_start(50, (_) => {
mouse_shapes += [getmouseshape()]
timer_start(50, (_) => {
feedkeys('gq')
timer_start(50, (_) => {
mouse_shapes += [getmouseshape()]
timer_start(50, (_) => {
writefile(mouse_shapes, 'Xmouseshapes')
quit!
})
})
})
})
END
call writefile(lines, 'Xmouseshape.vim', 'D')
call RunVim([], [], "-g -S Xindentexpr.vim -S Xmouseshape.vim")
call WaitForAssert({-> assert_equal(['rightup-arrow', 'arrow'],
\ readfile('Xmouseshapes'))}, 300)
call delete('Xmouseshapes')
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@ -1713,4 +1713,49 @@ func Test_pum_keep_select()
call StopVimInTerminal(buf)
endfunc
func Test_pum_matchins_highlight()
CheckScreendump
let lines =<< trim END
func Omni_test(findstart, base)
if a:findstart
return col(".")
endif
return [#{word: "foo"}, #{word: "bar"}, #{word: "你好"}]
endfunc
set omnifunc=Omni_test
hi ComplMatchIns ctermfg=red
END
call writefile(lines, 'Xscript', 'D')
let buf = RunVimInTerminal('-S Xscript', {})
call TermWait(buf)
call term_sendkeys(buf, "Sαβγ \<C-X>\<C-O>")
call VerifyScreenDump(buf, 'Test_pum_matchins_01', {})
call term_sendkeys(buf, "\<C-E>\<Esc>")
call TermWait(buf)
call term_sendkeys(buf, "Sαβγ \<C-X>\<C-O>\<C-N>")
call VerifyScreenDump(buf, 'Test_pum_matchins_02', {})
call term_sendkeys(buf, "\<C-E>\<Esc>")
call TermWait(buf)
call term_sendkeys(buf, "Sαβγ \<C-X>\<C-O>\<C-N>\<C-N>")
call VerifyScreenDump(buf, 'Test_pum_matchins_03', {})
call term_sendkeys(buf, "\<C-E>\<Esc>")
" restore after accept
call TermWait(buf)
call term_sendkeys(buf, "Sαβγ \<C-X>\<C-O>\<C-Y>")
call VerifyScreenDump(buf, 'Test_pum_matchins_04', {})
call term_sendkeys(buf, "\<C-E>\<Esc>")
" restore after cancel completion
call TermWait(buf)
call term_sendkeys(buf, "Sαβγ \<C-X>\<C-O>\<Space>")
call VerifyScreenDump(buf, 'Test_pum_matchins_05', {})
call term_sendkeys(buf, "\<C-E>\<Esc>")
call StopVimInTerminal(buf)
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@ -59,7 +59,8 @@ func Test_window_preview_terminal()
CheckFeature quickfix
" CheckFeature terminal
term " ++curwin
" term ++curwin
term
const buf_num = bufnr('$')
call assert_equal(1, winnr('$'))
exe 'pbuffer' . buf_num