Merge #10059 from jerdna-regeiz/vim-8.1.0614

vim-patch:8.1.0614,8.1.0632,8.1.0644,8.1.0658,8.1.0660,8.1.0669,8.1.0673,8.1.0679,8.1.0697,8.1.0701,8.1.0702,8.1.0709,8.1.0717,8.1.0750,8.1.0767,8.1.0772,8.1.0039
This commit is contained in:
Justin M. Keyes 2019-05-26 20:59:28 +02:00 committed by GitHub
commit 1ca84897a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 3988 additions and 1280 deletions

View File

@ -2028,6 +2028,8 @@ cursor({lnum}, {col} [, {off}])
cursor({list}) Number move cursor to position in {list}
deepcopy({expr} [, {noref}]) any make a full copy of {expr}
delete({fname} [, {flags}]) Number delete the file or directory {fname}
deletebufline({expr}, {first}[, {last}])
Number delete lines from buffer {expr}
dictwatcheradd({dict}, {pattern}, {callback})
Start watching a dictionary
dictwatcherdel({dict}, {pattern}, {callback})
@ -2289,6 +2291,17 @@ shellescape({string} [, {special}])
String escape {string} for use as shell
command argument
shiftwidth() Number effective value of 'shiftwidth'
sign_define({name} [, {dict}]) Number define or update a sign
sign_getdefined([{name}]) List get a list of defined signs
sign_getplaced([{expr} [, {dict}]])
List get a list of placed signs
sign_jump({id}, {group}, {expr})
Number jump to a sign
sign_place({id}, {group}, {name}, {expr} [, {dict}])
Number place a sign
sign_undefine([{name}]) Number undefine a sign
sign_unplace({group} [, {dict}])
Number unplace a sign
simplify({filename}) String simplify filename as much as possible
sin({expr}) Float sine of {expr}
sinh({expr}) Float hyperbolic sine of {expr}
@ -3198,6 +3211,17 @@ delete({fname} [, {flags}]) *delete()*
The result is a Number, which is 0 if the delete operation was
successful and -1 when the deletion failed or partly failed.
deletebufline({expr}, {first}[, {last}]) *deletebufline()*
Delete lines {first} to {last} (inclusive) from buffer {expr}.
If {last} is omitted then delete line {first} only.
On success 0 is returned, on failure 1 is returned.
For the use of {expr}, see |bufname()| above.
{first} and {last} are used like with |setline()|. Note that
when using |line()| this refers to the current buffer. Use "$"
to refer to the last line in buffer {expr}.
dictwatcheradd({dict}, {pattern}, {callback}) *dictwatcheradd()*
Adds a watcher to a dictionary. A dictionary watcher is
identified by three components:
@ -3572,20 +3596,24 @@ extend({expr1}, {expr2} [, {expr3}]) *extend()*
feedkeys({string} [, {mode}]) *feedkeys()*
Characters in {string} are queued for processing as if they
come from a mapping or were typed by the user.
By default the string is added to the end of the typeahead
buffer, thus if a mapping is still being executed the
characters come after them. Use the 'i' flag to insert before
other characters, they will be executed next, before any
characters from a mapping.
The function does not wait for processing of keys contained in
{string}.
To include special keys into {string}, use double-quotes
and "\..." notation |expr-quote|. For example,
feedkeys("\<CR>") simulates pressing of the <Enter> key. But
feedkeys('\<CR>') pushes 5 characters.
If {mode} is absent, keys are remapped.
{mode} is a String, which can contain these character flags:
'm' Remap keys. This is default.
'm' Remap keys. This is default. If {mode} is absent,
keys are remapped.
'n' Do not remap keys.
't' Handle keys as if typed; otherwise they are handled as
if coming from a mapping. This matters for undo,
@ -3599,6 +3627,9 @@ feedkeys({string} [, {mode}]) *feedkeys()*
will behave as if <Esc> is typed, to avoid getting
stuck, waiting for a character to be typed before the
script continues.
Note that if you manage to call feedkeys() while
executing commands, thus calling it recursively, the
all typehead will be consumed by the last call.
'!' When used with 'x' will not end Insert mode. Can be
used in a test when a timer is set to exit Insert mode
a little later. Useful for testing CursorHoldI.
@ -7349,7 +7380,246 @@ shiftwidth() *shiftwidth()*
endif
< And then use s:sw() instead of &sw.
sign_define({name} [, {dict}]) *sign_define()*
Define a new sign named {name} or modify the attributes of an
existing sign. This is similar to the |:sign-define| command.
Prefix {name} with a unique text to avoid name collisions.
There is no {group} like with placing signs.
The {name} can be a String or a Number. The optional {dict}
argument specifies the sign attributes. The following values
are supported:
icon full path to the bitmap file for the sign.
linehl highlight group used for the whole line the
sign is placed in.
text text that is displayed when there is no icon
or the GUI is not being used.
texthl highlight group used for the text item
numhl highlight group used for 'number' column at the
associated line. Overrides |hl-LineNr|,
|hl-CursorLineNr|.
If the sign named {name} already exists, then the attributes
of the sign are updated.
Returns 0 on success and -1 on failure.
Examples: >
call sign_define("mySign", {"text" : "=>", "texthl" :
\ "Error", "linehl" : "Search"})
<
sign_getdefined([{name}]) *sign_getdefined()*
Get a list of defined signs and their attributes.
This is similar to the |:sign-list| command.
If the {name} is not supplied, then a list of all the defined
signs is returned. Otherwise the attribute of the specified
sign is returned.
Each list item in the returned value is a dictionary with the
following entries:
icon full path to the bitmap file of the sign
linehl highlight group used for the whole line the
sign is placed in.
name name of the sign
text text that is displayed when there is no icon
or the GUI is not being used.
texthl highlight group used for the text item
numhl highlight group used for 'number' column at the
associated line. Overrides |hl-LineNr|,
|hl-CursorLineNr|.
Returns an empty List if there are no signs and when {name} is
not found.
Examples: >
" Get a list of all the defined signs
echo sign_getdefined()
" Get the attribute of the sign named mySign
echo sign_getdefined("mySign")
<
sign_getplaced([{expr} [, {dict}]]) *sign_getplaced()*
Return a list of signs placed in a buffer or all the buffers.
This is similar to the |:sign-place-list| command.
If the optional buffer name {expr} is specified, then only the
list of signs placed in that buffer is returned. For the use
of {expr}, see |bufname()|. The optional {dict} can contain
the following entries:
group select only signs in this group
id select sign with this identifier
lnum select signs placed in this line. For the use
of {lnum}, see |line()|.
If {group} is '*', then signs in all the groups including the
global group are returned. If {group} is not supplied or is an
empty string, then only signs in the global group are
returned. If no arguments are supplied, then signs in the
global group placed in all the buffers are returned.
See |sign-group|.
Each list item in the returned value is a dictionary with the
following entries:
bufnr number of the buffer with the sign
signs list of signs placed in {bufnr}. Each list
item is a dictionary with the below listed
entries
The dictionary for each sign contains the following entries:
group sign group. Set to '' for the global group.
id identifier of the sign
lnum line number where the sign is placed
name name of the defined sign
priority sign priority
The returned signs in a buffer are ordered by their line
number.
Returns an empty list on failure or if there are no placed
signs.
Examples: >
" Get a List of signs placed in eval.c in the
" global group
echo sign_getplaced("eval.c")
" Get a List of signs in group 'g1' placed in eval.c
echo sign_getplaced("eval.c", {'group' : 'g1'})
" Get a List of signs placed at line 10 in eval.c
echo sign_getplaced("eval.c", {'lnum' : 10})
" Get sign with identifier 10 placed in a.py
echo sign_getplaced("a.py", {'id' : 10'})
" Get sign with id 20 in group 'g1' placed in a.py
echo sign_getplaced("a.py", {'group' : 'g1',
\ 'id' : 20'})
" Get a List of all the placed signs
echo sign_getplaced()
<
*sign_jump()*
sign_jump({id}, {group}, {expr})
Open the buffer {expr} or jump to the window that contains
{expr} and position the cursor at sign {id} in group {group}.
This is similar to the |:sign-jump| command.
For the use of {expr}, see |bufname()|.
Returns the line number of the sign. Returns -1 if the
arguments are invalid.
Example: >
" Jump to sign 10 in the current buffer
call sign_jump(10, '', '')
<
*sign_place()*
sign_place({id}, {group}, {name}, {expr} [, {dict}])
Place the sign defined as {name} at line {lnum} in file {expr}
and assign {id} and {group} to sign. This is similar to the
|:sign-place| command.
If the sign identifier {id} is zero, then a new identifier is
allocated. Otherwise the specified number is used. {group} is
the sign group name. To use the global sign group, use an
empty string. {group} functions as a namespace for {id}, thus
two groups can use the same IDs. Refer to |sign-identifier|
for more information.
{name} refers to a defined sign.
{expr} refers to a buffer name or number. For the accepted
values, see |bufname()|.
The optional {dict} argument supports the following entries:
lnum line number in the buffer {expr} where
the sign is to be placed. For the
accepted values, see |line()|.
priority priority of the sign. See
|sign-priority| for more information.
If the optional {dict} is not specified, then it modifies the
placed sign {id} in group {group} to use the defined sign
{name}.
Returns the sign identifier on success and -1 on failure.
Examples: >
" Place a sign named sign1 with id 5 at line 20 in
" buffer json.c
call sign_place(5, '', 'sign1', 'json.c',
\ {'lnum' : 20})
" Updates sign 5 in buffer json.c to use sign2
call sign_place(5, '', 'sign2', 'json.c')
" Place a sign named sign3 at line 30 in
" buffer json.c with a new identifier
let id = sign_place(0, '', 'sign3', 'json.c',
\ {'lnum' : 30})
" Place a sign named sign4 with id 10 in group 'g3'
" at line 40 in buffer json.c with priority 90
call sign_place(10, 'g3', 'sign4', 'json.c',
\ {'lnum' : 40, 'priority' : 90})
<
sign_undefine([{name}]) *sign_undefine()*
Deletes a previously defined sign {name}. This is similar to
the |:sign-undefine| command. If {name} is not supplied, then
deletes all the defined signs.
Returns 0 on success and -1 on failure.
Examples: >
" Delete a sign named mySign
call sign_undefine("mySign")
" Delete all the signs
call sign_undefine()
<
sign_unplace({group} [, {dict}]) *sign_unplace()*
Remove a previously placed sign in one or more buffers. This
is similar to the |:sign-unplace()| command.
{group} is the sign group name. To use the global sign group,
use an empty string. If {group} is set to '*', then all the
groups including the global group are used.
The signs in {group} are selected based on the entries in
{dict}. The following optional entries in {dict} are
supported:
buffer buffer name or number. See |bufname()|.
id sign identifier
If {dict} is not supplied, then all the signs in {group} are
removed.
Returns 0 on success and -1 on failure.
Examples: >
" Remove sign 10 from buffer a.vim
call sign_unplace('', {'buffer' : "a.vim", 'id' : 10})
" Remove sign 20 in group 'g1' from buffer 3
call sign_unplace('g1', {'buffer' : 3, 'id' : 20})
" Remove all the signs in group 'g2' from buffer 10
call sign_unplace('g2', {'buffer' : 10})
" Remove sign 30 in group 'g3' from all the buffers
call sign_unplace('g3', {'id' : 30})
" Remove all the signs placed in buffer 5
call sign_unplace('*', {'buffer' : 5})
" Remove the signs in group 'g4' from all the buffers
call sign_unplace('g4')
" Remove sign 40 from all the buffers
call sign_unplace('*', {'id' : 40})
" Remove all the placed signs from all the buffers
call sign_unplace('*')
<
simplify({filename}) *simplify()*
Simplify the file name as much as possible without changing
the meaning. Shortcuts (on MS-Windows) or symbolic links (on
@ -8352,7 +8622,7 @@ undofile({name}) *undofile()*
If {name} is empty undofile() returns an empty string, since a
buffer without a file name will not write an undo file.
Useful in combination with |:wundo| and |:rundo|.
When compiled without the +persistent_undo option this always
When compiled without the |+persistent_undo| option this always
returns an empty string.
undotree() *undotree()*

View File

@ -45,6 +45,30 @@ The color of the column is set with the SignColumn group |hl-SignColumn|.
Example to set the color: >
:highlight SignColumn guibg=darkgrey
<
*sign-identifier*
Each placed sign is identified by a number called the sign identifier. This
identifier is used to jump to the sign or to remove the sign. The identifier
is assigned when placing the sign using the |sign-place| command or the
|sign_place()| function. Each sign identifier should be a unique number. If
multiple placed signs use the same identifier, then jumping to or removing a
sign becomes unpredictable. To avoid overlapping identifiers, sign groups can
be used. The |sign_place()| function can be called with a zero sign identifier
to allocate the next available identifier.
*sign-group*
Each placed sign can be assigned to either the global group or a named group.
When placing a sign, if a group name is not supplied, or an empty string is
used, then the sign is placed in the global group. Otherwise the sign is
placed in the named group. The sign identifier is unique within a group. The
sign group allows Vim plugins to use unique signs without interfering with
other plugins using signs.
*sign-priority*
Each placed sign is assigned a priority value. When multiple signs are placed
on the same line, the attributes of the sign with the highest priority is used
independent of the sign group. The default priority for a sign is 10. The
priority is assigned at the time of placing a sign.
==============================================================================
2. Commands *sign-commands* *:sig* *:sign*
@ -63,6 +87,8 @@ comment. If you do need that, use the |:execute| command.
DEFINING A SIGN. *:sign-define* *E255* *E160* *E612*
See |sign_define()| for the equivalent Vim script function.
:sign define {name} {argument}...
Define a new sign or set attributes for an existing sign.
The {name} can either be a number (all digits) or a name
@ -99,13 +125,18 @@ DEFINING A SIGN. *:sign-define* *E255* *E160* *E612*
DELETING A SIGN *:sign-undefine* *E155*
See |sign_undefine()| for the equivalent Vim script function.
:sign undefine {name}
Deletes a previously defined sign. If signs with this {name}
are still placed this will cause trouble.
LISTING SIGNS *:sign-list* *E156*
See |sign_getdefined()| for the equivalent Vim script function.
:sign list Lists all defined signs and their attributes.
:sign list {name}
@ -114,6 +145,8 @@ LISTING SIGNS *:sign-list* *E156*
PLACING SIGNS *:sign-place* *E158*
See |sign_place()| for the equivalent Vim script function.
:sign place {id} line={lnum} name={name} file={fname}
Place sign defined as {name} at line {lnum} in file {fname}.
*:sign-fname*
@ -129,8 +162,28 @@ PLACING SIGNS *:sign-place* *E158*
to be done several times and making changes may not work as
expected).
:sign place {id} line={lnum} name={name} buffer={nr}
Same, but use buffer {nr}.
The following optional sign attributes can be specified before
"file=":
group={group} Place sign in sign group {group}
priority={prio} Assign priority {prio} to sign
By default, the sign is placed in the global sign group.
By default, the sign is assigned a default priority of 10. To
assign a different priority value, use "priority={prio}" to
specify a value. The priority is used to determine the
highlight group used when multiple signs are placed on the
same line.
Examples: >
:sign place 5 line=3 name=sign1 file=a.py
:sign place 6 group=g2 line=2 name=sign2 file=x.py
:sign place 9 group=g2 priority=50 line=5
\ name=sign1 file=a.py
<
:sign place {id} line={lnum} name={name} [buffer={nr}]
Same, but use buffer {nr}. If the buffer argument is not
given, place the sign in the current buffer.
*E885*
:sign place {id} name={name} file={fname}
@ -139,50 +192,125 @@ PLACING SIGNS *:sign-place* *E158*
This can be used to change the displayed sign without moving
it (e.g., when the debugger has stopped at a breakpoint).
:sign place {id} name={name} buffer={nr}
Same, but use buffer {nr}.
The optional "group={group}" attribute can be used before
"file=" to select a sign in a particular group.
:sign place {id} name={name} [buffer={nr}]
Same, but use buffer {nr}. If the buffer argument is not
given, use the current buffer.
REMOVING SIGNS *:sign-unplace* *E159*
See |sign_unplace()| for the equivalent Vim script function.
:sign unplace {id} file={fname}
Remove the previously placed sign {id} from file {fname}.
See remark above about {fname} |:sign-fname|.
:sign unplace {id} group={group} file={fname}
Same but remove the sign {id} in sign group {group}.
:sign unplace {id} group=* file={fname}
Same but remove the sign {id} from all the sign groups.
:sign unplace * file={fname}
Remove all placed signs in file {fname}.
:sign unplace * group={group} file={fname}
Remove all placed signs in group {group} from file {fname}.
:sign unplace * group=* file={fname}
Remove all placed signs in all the groups from file {fname}.
:sign unplace {id} buffer={nr}
Remove the previously placed sign {id} from buffer {nr}.
:sign unplace {id} group={group} buffer={nr}
Remove the previously placed sign {id} in group {group} from
buffer {nr}.
:sign unplace {id} group=* buffer={nr}
Remove the previously placed sign {id} in all the groups from
buffer {nr}.
:sign unplace * buffer={nr}
Remove all placed signs in buffer {nr}.
:sign unplace * group={group} buffer={nr}
Remove all placed signs in group {group} from buffer {nr}.
:sign unplace * group=* buffer={nr}
Remove all placed signs in all the groups from buffer {nr}.
:sign unplace {id}
Remove the previously placed sign {id} from all files it
appears in.
:sign unplace {id} group={group}
Remove the previously placed sign {id} in group {group} from
all files it appears in.
:sign unplace {id} group=*
Remove the previously placed sign {id} in all the groups from
all the files it appears in.
:sign unplace *
Remove all placed signs.
Remove all placed signs in the global group from all the files.
:sign unplace * group={group}
Remove all placed signs in group {group} from all the files.
:sign unplace * group=*
Remove all placed signs in all the groups from all the files.
:sign unplace
Remove the placed sign at the cursor position.
Remove a placed sign at the cursor position. If multiple signs
are placed in the line, then only one is removed.
:sign unplace group={group}
Remove a placed sign in group {group} at the cursor
position.
:sign unplace group=*
Remove a placed sign in any group at the cursor position.
LISTING PLACED SIGNS *:sign-place-list*
See |sign_getplaced()| for the equivalent Vim script function.
:sign place file={fname}
List signs placed in file {fname}.
See remark above about {fname} |:sign-fname|.
:sign place group={group} file={fname}
List signs in group {group} placed in file {fname}.
:sign place group=* file={fname}
List signs in all the groups placed in file {fname}.
:sign place buffer={nr}
List signs placed in buffer {nr}.
:sign place List placed signs in all files.
:sign place group={group} buffer={nr}
List signs in group {group} placed in buffer {nr}.
:sign place group=* buffer={nr}
List signs in all the groups placed in buffer {nr}.
:sign place group={group}
List placed signs in all sign groups in all the files.
:sign place group=*
List placed signs in all sign groups in all files.
JUMPING TO A SIGN *:sign-jump* *E157*
See |sign_jump()| for the equivalent Vim script function.
:sign jump {id} file={fname}
Open the file {fname} or jump to the window that contains
{fname} and position the cursor at sign {id}.
@ -190,9 +318,16 @@ JUMPING TO A SIGN *:sign-jump* *E157*
If the file isn't displayed in window and the current file can
not be |abandon|ed this fails.
:sign jump {id} buffer={nr} *E934*
:sign jump {id} group={group} file={fname}
Same but jump to the sign in group {group}
:sign jump {id} [buffer={nr}] *E934*
Same, but use buffer {nr}. This fails if buffer {nr} does not
have a name.
have a name. If the buffer argument is not given, use the
current buffer.
:sign jump {id} group={group} [buffer={nr}]
Same but jump to the sign in group {group}
vim:tw=78:ts=8:noet:ft=help:norl:

View File

@ -916,6 +916,16 @@ Mappings: *mapping-functions*
maparg() get rhs of a mapping
wildmenumode() check if the wildmode is active
Signs: *sign-functions*
sign_define() define or update a sign
sign_getdefined() get a list of defined signs
sign_getplaced() get a list of placed signs
sign_jump() jump to a sign
sign_place() place a sign
sign_undefine() undefine a sign
sign_unplace() unplace a sign
Testing: *test-functions*
assert_equal() assert that two expressions values are equal
assert_notequal() assert that two expressions values are not equal

View File

@ -64,6 +64,7 @@
#include "nvim/quickfix.h"
#include "nvim/regexp.h"
#include "nvim/screen.h"
#include "nvim/sign.h"
#include "nvim/spell.h"
#include "nvim/strings.h"
#include "nvim/syntax.h"
@ -804,9 +805,9 @@ free_buffer_stuff(
vars_clear(&buf->b_vars->dv_hashtab); // free all internal variables
hash_init(&buf->b_vars->dv_hashtab);
buf_init_changedtick(buf);
uc_clear(&buf->b_ucmds); // clear local user commands
buf_delete_signs(buf); // delete any signs
bufhl_clear_all(buf); // delete any highligts
uc_clear(&buf->b_ucmds); // clear local user commands
buf_delete_signs(buf, (char_u *)"*"); // delete any signs
bufhl_clear_all(buf); // delete any highligts
map_clear_int(buf, MAP_ALL_MODES, true, false); // clear local mappings
map_clear_int(buf, MAP_ALL_MODES, true, true); // clear local abbrevs
XFREE_CLEAR(buf->b_start_fenc);
@ -5255,51 +5256,12 @@ bool find_win_for_buf(buf_T *buf, win_T **wp, tabpage_T **tp)
return false;
}
/*
* Insert the sign into the signlist.
*/
static void insert_sign(
buf_T *buf, // buffer to store sign in
signlist_T *prev, // previous sign entry
signlist_T *next, // next sign entry
int id, // sign ID
linenr_T lnum, // line number which gets the mark
int typenr // typenr of sign we are adding
)
{
signlist_T *newsign = xmalloc(sizeof(signlist_T));
newsign->id = id;
newsign->lnum = lnum;
newsign->typenr = typenr;
newsign->next = next;
newsign->prev = prev;
if (next != NULL) {
next->prev = newsign;
}
buf->b_signcols_max = -1;
if (prev == NULL) {
/* When adding first sign need to redraw the windows to create the
* column for signs. */
if (buf->b_signlist == NULL) {
redraw_buf_later(buf, NOT_VALID);
changed_cline_bef_curs();
}
// first sign in signlist
buf->b_signlist = newsign;
}
else {
prev->next = newsign;
}
}
static int sign_compare(const void *a1, const void *a2)
{
const signlist_T *s1 = *(const signlist_T **)a1;
const signlist_T *s2 = *(const signlist_T **)a2;
// Sort by line number and the by id
// Sort by line number, priority and id
if (s1->lnum > s2->lnum) {
return 1;
@ -5307,12 +5269,18 @@ static int sign_compare(const void *a1, const void *a2)
if (s1->lnum < s2->lnum) {
return -1;
}
if (s1->id > s2->id) {
if (s1->priority > s2->priority) {
return -1;
}
if (s1->priority < s2->priority) {
return 1;
}
if (s1->id < s2->id) {
if (s1->id > s2->id) {
return -1;
}
if (s1->id < s2->id) {
return 1;
}
return 0;
}
@ -5384,314 +5352,6 @@ int buf_signcols(buf_T *buf)
return buf->b_signcols;
}
/*
* Add the sign into the signlist. Find the right spot to do it though.
*/
void buf_addsign(
buf_T *buf, // buffer to store sign in
int id, // sign ID
linenr_T lnum, // line number which gets the mark
int typenr // typenr of sign we are adding
)
{
signlist_T **lastp; // pointer to pointer to current sign
signlist_T *sign; // a sign in the signlist
signlist_T *prev; // the previous sign
prev = NULL;
for (sign = buf->b_signlist; sign != NULL; sign = sign->next) {
if (lnum == sign->lnum && id == sign->id) {
sign->typenr = typenr;
return;
} else if ((lnum == sign->lnum && id != sign->id)
|| (id < 0 && lnum < sign->lnum)) {
// keep signs sorted by lnum: insert new sign at head of list for
// this lnum
while (prev != NULL && prev->lnum == lnum) {
prev = prev->prev;
}
if (prev == NULL) {
sign = buf->b_signlist;
} else {
sign = prev->next;
}
insert_sign(buf, prev, sign, id, lnum, typenr);
return;
}
prev = sign;
}
// insert new sign at head of list for this lnum
while (prev != NULL && prev->lnum == lnum) {
prev = prev->prev;
}
if (prev == NULL) {
sign = buf->b_signlist;
} else {
sign = prev->next;
}
insert_sign(buf, prev, sign, id, lnum, typenr);
// Having more than one sign with _the same type_ and on the _same line_ is
// unwanted, let's prevent it.
lastp = &buf->b_signlist;
for (sign = buf->b_signlist; sign != NULL; sign = sign->next) {
if (lnum == sign->lnum && sign->typenr == typenr && id != sign->id) {
*lastp = sign->next;
xfree(sign);
} else {
lastp = &sign->next;
}
}
}
// For an existing, placed sign "markId" change the type to "typenr".
// Returns the line number of the sign, or zero if the sign is not found.
linenr_T buf_change_sign_type(
buf_T *buf, // buffer to store sign in
int markId, // sign ID
int typenr // typenr of sign we are adding
)
{
signlist_T *sign; // a sign in the signlist
for (sign = buf->b_signlist; sign != NULL; sign = sign->next) {
if (sign->id == markId) {
sign->typenr = typenr;
return sign->lnum;
}
}
return (linenr_T)0;
}
/// Gets a sign from a given line.
///
/// @param buf Buffer in which to search
/// @param lnum Line in which to search
/// @param type Type of sign to look for
/// @param idx if there multiple signs, this index will pick the n-th
// out of the most `max_signs` sorted ascending by Id.
/// @param max_signs the number of signs, with priority for the ones
// with the highest Ids.
/// @return Identifier of the matching sign, or 0
int buf_getsigntype(buf_T *buf, linenr_T lnum, SignType type,
int idx, int max_signs)
{
signlist_T *sign; // a sign in a b_signlist
signlist_T *matches[9];
int nr_matches = 0;
for (sign = buf->b_signlist; sign != NULL; sign = sign->next) {
if (sign->lnum == lnum
&& (type == SIGN_ANY
|| (type == SIGN_TEXT
&& sign_get_text(sign->typenr) != NULL)
|| (type == SIGN_LINEHL
&& sign_get_attr(sign->typenr, SIGN_LINEHL) != 0)
|| (type == SIGN_NUMHL
&& sign_get_attr(sign->typenr, SIGN_NUMHL) != 0))) {
matches[nr_matches] = sign;
nr_matches++;
if (nr_matches == ARRAY_SIZE(matches)) {
break;
}
}
}
if (nr_matches > 0) {
if (nr_matches > max_signs) {
idx += nr_matches - max_signs;
}
if (idx >= nr_matches) {
return 0;
}
return matches[idx]->typenr;
}
return 0;
}
linenr_T buf_delsign(
buf_T *buf, // buffer sign is stored in
int id // sign id
)
{
signlist_T **lastp; // pointer to pointer to current sign
signlist_T *sign; // a sign in a b_signlist
signlist_T *next; // the next sign in a b_signlist
linenr_T lnum; // line number whose sign was deleted
buf->b_signcols_max = -1;
lastp = &buf->b_signlist;
lnum = 0;
for (sign = buf->b_signlist; sign != NULL; sign = next) {
next = sign->next;
if (sign->id == id) {
*lastp = next;
if (next != NULL) {
next->prev = sign->prev;
}
lnum = sign->lnum;
xfree(sign);
break;
} else {
lastp = &sign->next;
}
}
/* When deleted the last sign needs to redraw the windows to remove the
* sign column. */
if (buf->b_signlist == NULL) {
redraw_buf_later(buf, NOT_VALID);
changed_cline_bef_curs();
}
return lnum;
}
/*
* Find the line number of the sign with the requested id. If the sign does
* not exist, return 0 as the line number. This will still let the correct file
* get loaded.
*/
int buf_findsign(
buf_T *buf, // buffer to store sign in
int id // sign ID
)
{
signlist_T *sign; // a sign in the signlist
for (sign = buf->b_signlist; sign != NULL; sign = sign->next) {
if (sign->id == id) {
return (int)sign->lnum;
}
}
return 0;
}
int buf_findsign_id(
buf_T *buf, // buffer whose sign we are searching for
linenr_T lnum // line number of sign
)
{
signlist_T *sign; // a sign in the signlist
for (sign = buf->b_signlist; sign != NULL; sign = sign->next) {
if (sign->lnum == lnum) {
return sign->id;
}
}
return 0;
}
/*
* Delete signs in buffer "buf".
*/
void buf_delete_signs(buf_T *buf)
{
signlist_T *next;
// When deleting the last sign need to redraw the windows to remove the
// sign column. Not when curwin is NULL (this means we're exiting).
if (buf->b_signlist != NULL && curwin != NULL){
redraw_buf_later(buf, NOT_VALID);
changed_cline_bef_curs();
}
while (buf->b_signlist != NULL) {
next = buf->b_signlist->next;
xfree(buf->b_signlist);
buf->b_signlist = next;
}
buf->b_signcols_max = -1;
}
/*
* Delete all signs in all buffers.
*/
void buf_delete_all_signs(void)
{
FOR_ALL_BUFFERS(buf) {
if (buf->b_signlist != NULL) {
buf_delete_signs(buf);
}
}
}
/*
* List placed signs for "rbuf". If "rbuf" is NULL do it for all buffers.
*/
void sign_list_placed(buf_T *rbuf)
{
buf_T *buf;
signlist_T *p;
char lbuf[BUFSIZ];
MSG_PUTS_TITLE(_("\n--- Signs ---"));
msg_putchar('\n');
if (rbuf == NULL) {
buf = firstbuf;
} else {
buf = rbuf;
}
while (buf != NULL && !got_int) {
if (buf->b_signlist != NULL) {
vim_snprintf(lbuf, BUFSIZ, _("Signs for %s:"), buf->b_fname);
MSG_PUTS_ATTR(lbuf, HL_ATTR(HLF_D));
msg_putchar('\n');
}
for (p = buf->b_signlist; p != NULL && !got_int; p = p->next) {
vim_snprintf(lbuf, BUFSIZ, _(" line=%" PRId64 " id=%d name=%s"),
(int64_t)p->lnum, p->id, sign_typenr2name(p->typenr));
MSG_PUTS(lbuf);
msg_putchar('\n');
}
if (rbuf != NULL) {
break;
}
buf = buf->b_next;
}
}
/*
* Adjust a placed sign for inserted/deleted lines.
*/
void sign_mark_adjust(linenr_T line1, linenr_T line2, long amount, long amount_after)
{
signlist_T *sign; // a sign in a b_signlist
signlist_T *next; // the next sign in a b_signlist
signlist_T **lastp; // pointer to pointer to current sign
curbuf->b_signcols_max = -1;
lastp = &curbuf->b_signlist;
for (sign = curbuf->b_signlist; sign != NULL; sign = next) {
next = sign->next;
if (sign->lnum >= line1 && sign->lnum <= line2) {
if (amount == MAXLNUM) {
*lastp = next;
xfree(sign);
continue;
} else {
sign->lnum += amount;
}
} else if (sign->lnum > line2) {
sign->lnum += amount_after;
}
lastp = &sign->next;
}
}
// bufhl: plugin highlights associated with a buffer
/// Get reference to line in kbtree_t

View File

@ -769,15 +769,15 @@ struct file_buffer {
* spell buffer - used for spell info, never displayed and doesn't have a
* file name.
*/
bool b_help; /* TRUE for help file buffer (when set b_p_bt
is "help") */
bool b_spell; /* True for a spell file buffer, most fields
are not used! Use the B_SPELL macro to
access b_spell without #ifdef. */
bool b_help; // TRUE for help file buffer (when set b_p_bt
// is "help")
bool b_spell; // True for a spell file buffer, most fields
// are not used! Use the B_SPELL macro to
// access b_spell without #ifdef.
synblock_T b_s; /* Info related to syntax highlighting. w_s
* normally points to this, but some windows
* may use a different synblock_T. */
synblock_T b_s; // Info related to syntax highlighting. w_s
// normally points to this, but some windows
// may use a different synblock_T.
signlist_T *b_signlist; // list of signs to draw
int b_signcols_max; // cached maximum number of sign columns
@ -1144,12 +1144,12 @@ struct window_S {
int w_cline_row; /* starting row of the cursor line */
colnr_T w_virtcol; /* column number of the cursor in the
buffer line, as opposed to the column
number we're at on the screen. This
makes a difference on lines which span
more than one screen line or when
w_leftcol is non-zero */
colnr_T w_virtcol; // column number of the cursor in the
// buffer line, as opposed to the column
// number we're at on the screen. This
// makes a difference on lines which span
// more than one screen line or when
// w_leftcol is non-zero
/*
* w_wrow and w_wcol specify the cursor position in the window.

View File

@ -179,9 +179,9 @@ static int compl_no_insert = FALSE; /* FALSE: select & insert
static int compl_no_select = FALSE; /* FALSE: select & insert
TRUE: noselect */
static int compl_used_match; /* Selected one of the matches. When
FALSE the match was edited or using
the longest common string. */
static int compl_used_match; // Selected one of the matches. When
// FALSE the match was edited or using
// the longest common string.
static int compl_was_interrupted = FALSE; /* didn't finish finding
completions. */
@ -2599,8 +2599,9 @@ void ins_compl_show_pum(void)
do {
if ((compl->cp_flags & ORIGINAL_TEXT) == 0
&& (compl_leader == NULL
|| ins_compl_equal(compl, compl_leader, lead_len)))
++compl_match_arraysize;
|| ins_compl_equal(compl, compl_leader, lead_len))) {
compl_match_arraysize++;
}
compl = compl->cp_next;
} while (compl != NULL && compl != compl_first_match);
if (compl_match_arraysize == 0)

View File

@ -68,6 +68,7 @@
#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/sha256.h"
#include "nvim/sign.h"
#include "nvim/spell.h"
#include "nvim/state.h"
#include "nvim/strings.h"
@ -1113,6 +1114,19 @@ static void restore_vimvar(int idx, typval_T *save_tv)
}
}
/// If there is a window for "curbuf", make it the current window.
static void find_win_for_curbuf(void)
{
wininfo_T *wip;
for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next) {
if (wip->wi_win != NULL) {
curwin = wip->wi_win;
break;
}
}
}
/*
* Evaluate an expression to a list with suggestions.
* For the "expr:" part of 'spellsuggest'.
@ -1125,7 +1139,7 @@ list_T *eval_spell_expr(char_u *badword, char_u *expr)
list_T *list = NULL;
char_u *p = skipwhite(expr);
/* Set "v:val" to the bad word. */
// Set "v:val" to the bad word.
prepare_vimvar(VV_VAL, &save_val);
vimvars[VV_VAL].vv_type = VAR_STRING;
vimvars[VV_VAL].vv_str = badword;
@ -7183,7 +7197,7 @@ static buf_T *tv_get_buf(typval_T *tv, int curtab_only)
if (name[0] == '$' && name[1] == NUL)
return lastbuf;
/* Ignore 'magic' and 'cpoptions' here to make scripts portable */
// Ignore 'magic' and 'cpoptions' here to make scripts portable
save_magic = p_magic;
p_magic = TRUE;
save_cpo = p_cpo;
@ -7195,13 +7209,29 @@ static buf_T *tv_get_buf(typval_T *tv, int curtab_only)
p_magic = save_magic;
p_cpo = save_cpo;
/* If not found, try expanding the name, like done for bufexists(). */
if (buf == NULL)
// If not found, try expanding the name, like done for bufexists().
if (buf == NULL) {
buf = find_buffer(tv);
}
return buf;
}
/// Get the buffer from "arg" and give an error and return NULL if it is not
/// valid.
static buf_T * get_buf_arg(typval_T *arg)
{
buf_T *buf;
emsg_off++;
buf = tv_get_buf(arg, false);
emsg_off--;
if (buf == NULL) {
EMSG2(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
}
return buf;
}
/*
* "bufname(expr)" function
*/
@ -7999,6 +8029,85 @@ static void f_dictwatcherdel(typval_T *argvars, typval_T *rettv, FunPtr fptr)
callback_free(&callback);
}
/// "deletebufline()" function
static void f_deletebufline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
buf_T *buf;
linenr_T first, last;
linenr_T lnum;
long count;
int is_curbuf;
buf_T *curbuf_save = NULL;
win_T *curwin_save = NULL;
buf = tv_get_buf(&argvars[0], false);
if (buf == NULL) {
rettv->vval.v_number = 1; // FAIL
return;
}
is_curbuf = buf == curbuf;
first = tv_get_lnum_buf(&argvars[1], buf);
if (argvars[2].v_type != VAR_UNKNOWN) {
last = tv_get_lnum_buf(&argvars[2], buf);
} else {
last = first;
}
if (buf->b_ml.ml_mfp == NULL || first < 1
|| first > buf->b_ml.ml_line_count || last < first) {
rettv->vval.v_number = 1; // FAIL
return;
}
if (!is_curbuf) {
curbuf_save = curbuf;
curwin_save = curwin;
curbuf = buf;
find_win_for_curbuf();
}
if (last > curbuf->b_ml.ml_line_count) {
last = curbuf->b_ml.ml_line_count;
}
count = last - first + 1;
// When coming here from Insert mode, sync undo, so that this can be
// undone separately from what was previously inserted.
if (u_sync_once == 2) {
u_sync_once = 1; // notify that u_sync() was called
u_sync(true);
}
if (u_save(first - 1, last + 1) == FAIL) {
rettv->vval.v_number = 1; // FAIL
return;
}
for (lnum = first; lnum <= last; lnum++) {
ml_delete(first, true);
}
FOR_ALL_TAB_WINDOWS(tp, wp) {
if (wp->w_buffer == buf) {
if (wp->w_cursor.lnum > last) {
wp->w_cursor.lnum -= count;
} else if (wp->w_cursor.lnum> first) {
wp->w_cursor.lnum = first;
}
if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count) {
wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
}
}
}
check_cursor_col();
deleted_lines_mark(first, count);
if (!is_curbuf) {
curbuf = curbuf_save;
curwin = curwin_save;
}
}
/*
* "did_filetype()" function
*/
@ -9286,24 +9395,6 @@ static void f_get(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
/// Returns information about signs placed in a buffer as list of dicts.
static list_T *get_buffer_signs(buf_T *buf)
FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
list_T *const l = tv_list_alloc(kListLenMayKnow);
for (signlist_T *sign = buf->b_signlist; sign; sign = sign->next) {
dict_T *const d = tv_dict_alloc();
tv_dict_add_nr(d, S_LEN("id"), sign->id);
tv_dict_add_nr(d, S_LEN("lnum"), sign->lnum);
tv_dict_add_str(d, S_LEN("name"),
(const char *)sign_typenr2name(sign->typenr));
tv_list_append_dict(l, d);
}
return l;
}
/// Returns buffer options, variables and other attributes in a dictionary.
static dict_T *get_buffer_info(buf_T *buf)
{
@ -15438,6 +15529,347 @@ static void f_shiftwidth(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = get_sw_value(curbuf);
}
/// "sign_define()" function
static void f_sign_define(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
const char *name;
dict_T *dict;
char *icon = NULL;
char *linehl = NULL;
char *text = NULL;
char *texthl = NULL;
char *numhl = NULL;
rettv->vval.v_number = -1;
name = tv_get_string_chk(&argvars[0]);
if (name == NULL) {
return;
}
if (argvars[1].v_type != VAR_UNKNOWN) {
if (argvars[1].v_type != VAR_DICT) {
EMSG(_(e_dictreq));
return;
}
// sign attributes
dict = argvars[1].vval.v_dict;
if (tv_dict_find(dict, "icon", -1) != NULL) {
icon = tv_dict_get_string(dict, "icon", true);
}
if (tv_dict_find(dict, "linehl", -1) != NULL) {
linehl = tv_dict_get_string(dict, "linehl", true);
}
if (tv_dict_find(dict, "text", -1) != NULL) {
text = tv_dict_get_string(dict, "text", true);
}
if (tv_dict_find(dict, "texthl", -1) != NULL) {
texthl = tv_dict_get_string(dict, "texthl", true);
}
if (tv_dict_find(dict, "numhl", -1) != NULL) {
numhl = tv_dict_get_string(dict, "numhl", true);
}
}
if (sign_define_by_name((char_u *)name, (char_u *)icon, (char_u *)linehl,
(char_u *)text, (char_u *)texthl, (char_u *)numhl)
== OK) {
rettv->vval.v_number = 0;
}
xfree(icon);
xfree(linehl);
xfree(text);
xfree(texthl);
}
/// "sign_getdefined()" function
static void f_sign_getdefined(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
const char *name = NULL;
tv_list_alloc_ret(rettv, 0);
if (argvars[0].v_type != VAR_UNKNOWN) {
name = tv_get_string(&argvars[0]);
}
sign_getlist((const char_u *)name, rettv->vval.v_list);
}
/// "sign_getplaced()" function
static void f_sign_getplaced(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
buf_T *buf = NULL;
dict_T *dict;
dictitem_T *di;
linenr_T lnum = 0;
int sign_id = 0;
const char *group = NULL;
bool notanum = false;
tv_list_alloc_ret(rettv, 0);
if (argvars[0].v_type != VAR_UNKNOWN) {
// get signs placed in the specified buffer
buf = get_buf_arg(&argvars[0]);
if (buf == NULL) {
return;
}
if (argvars[1].v_type != VAR_UNKNOWN) {
if (argvars[1].v_type != VAR_DICT
|| ((dict = argvars[1].vval.v_dict) == NULL)) {
EMSG(_(e_dictreq));
return;
}
if ((di = tv_dict_find(dict, "lnum", -1)) != NULL) {
// get signs placed at this line
lnum = (linenr_T)tv_get_number_chk(&di->di_tv, &notanum);
if (notanum) {
return;
}
lnum = tv_get_lnum(&di->di_tv);
}
if ((di = tv_dict_find(dict, "id", -1)) != NULL) {
// get sign placed with this identifier
sign_id = (int)tv_get_number_chk(&di->di_tv, &notanum);
if (notanum) {
return;
}
}
if ((di = tv_dict_find(dict, "group", -1)) != NULL) {
group = tv_get_string_chk(&di->di_tv);
if (group == NULL) {
return;
}
if (*group == '\0') { // empty string means global group
group = NULL;
}
}
}
}
sign_get_placed(buf, lnum, sign_id, (const char_u *)group,
rettv->vval.v_list);
}
/// "sign_jump()" function
static void f_sign_jump(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
int sign_id;
char *sign_group = NULL;
buf_T *buf;
bool notanum = false;
rettv->vval.v_number = -1;
// Sign identifer
sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
if (notanum) {
return;
}
if (sign_id <= 0) {
EMSG(_(e_invarg));
return;
}
// Sign group
const char * sign_group_chk = tv_get_string_chk(&argvars[1]);
if (sign_group_chk == NULL) {
return;
}
if (sign_group_chk[0] == '\0') {
sign_group = NULL; // global sign group
} else {
sign_group = xstrdup(sign_group_chk);
if (sign_group == NULL) {
return;
}
}
// Buffer to place the sign
buf = get_buf_arg(&argvars[2]);
if (buf == NULL) {
goto cleanup;
}
rettv->vval.v_number = sign_jump(sign_id, (char_u *)sign_group, buf);
cleanup:
xfree(sign_group);
}
/// "sign_place()" function
static void f_sign_place(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
int sign_id;
char_u *group = NULL;
const char *sign_name;
buf_T *buf;
dict_T *dict;
dictitem_T *di;
linenr_T lnum = 0;
int prio = SIGN_DEF_PRIO;
bool notanum = false;
rettv->vval.v_number = -1;
// Sign identifer
sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
if (notanum) {
return;
}
if (sign_id < 0) {
EMSG(_(e_invarg));
return;
}
// Sign group
const char *group_chk = tv_get_string_chk(&argvars[1]);
if (group_chk == NULL) {
return;
}
if (group_chk[0] == '\0') {
group = NULL; // global sign group
} else {
group = vim_strsave((const char_u *)group_chk);
if (group == NULL) {
return;
}
}
// Sign name
sign_name = tv_get_string_chk(&argvars[2]);
if (sign_name == NULL) {
goto cleanup;
}
// Buffer to place the sign
buf = get_buf_arg(&argvars[3]);
if (buf == NULL) {
goto cleanup;
}
if (argvars[4].v_type != VAR_UNKNOWN) {
if (argvars[4].v_type != VAR_DICT
|| ((dict = argvars[4].vval.v_dict) == NULL)) {
EMSG(_(e_dictreq));
goto cleanup;
}
// Line number where the sign is to be placed
if ((di = tv_dict_find(dict, "lnum", -1)) != NULL) {
lnum = (linenr_T)tv_get_number_chk(&di->di_tv, &notanum);
if (notanum) {
goto cleanup;
}
lnum = tv_get_lnum(&di->di_tv);
}
if ((di = tv_dict_find(dict, "priority", -1)) != NULL) {
// Sign priority
prio = (int)tv_get_number_chk(&di->di_tv, &notanum);
if (notanum) {
goto cleanup;
}
}
}
if (sign_place(&sign_id, group, (const char_u *)sign_name, buf, lnum, prio)
== OK) {
rettv->vval.v_number = sign_id;
}
cleanup:
xfree(group);
}
/// "sign_undefine()" function
static void f_sign_undefine(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
const char *name;
rettv->vval.v_number = -1;
if (argvars[0].v_type == VAR_UNKNOWN) {
// Free all the signs
free_signs();
rettv->vval.v_number = 0;
} else {
// Free only the specified sign
name = tv_get_string_chk(&argvars[0]);
if (name == NULL) {
return;
}
if (sign_undefine_by_name((const char_u *)name) == OK) {
rettv->vval.v_number = 0;
}
}
}
/// "sign_unplace()" function
static void f_sign_unplace(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
dict_T *dict;
dictitem_T *di;
int sign_id = 0;
buf_T *buf = NULL;
char_u *group = NULL;
rettv->vval.v_number = -1;
if (argvars[0].v_type != VAR_STRING) {
EMSG(_(e_invarg));
return;
}
const char *group_chk = tv_get_string(&argvars[0]);
if (group_chk[0] == '\0') {
group = NULL; // global sign group
} else {
group = vim_strsave((const char_u *)group_chk);
if (group == NULL) {
return;
}
}
if (argvars[1].v_type != VAR_UNKNOWN) {
if (argvars[1].v_type != VAR_DICT) {
EMSG(_(e_dictreq));
goto cleanup;
}
dict = argvars[1].vval.v_dict;
if ((di = tv_dict_find(dict, "buffer", -1)) != NULL) {
buf = get_buf_arg(&di->di_tv);
if (buf == NULL) {
goto cleanup;
}
}
if (tv_dict_find(dict, "id", -1) != NULL) {
sign_id = tv_dict_get_number(dict, "id");
}
}
if (buf == NULL) {
// Delete the sign in all the buffers
FOR_ALL_BUFFERS(cbuf) {
if (sign_unplace(sign_id, group, cbuf, 0) == OK) {
rettv->vval.v_number = 0;
}
}
} else {
if (sign_unplace(sign_id, group, buf, 0) == OK) {
rettv->vval.v_number = 0;
}
}
cleanup:
xfree(group);
}
/*
* "simplify()" function
*/

View File

@ -75,6 +75,7 @@ return {
cursor={args={1, 3}},
deepcopy={args={1, 2}},
delete={args={1,2}},
deletebufline={args={2,3}},
dictwatcheradd={args=3},
dictwatcherdel={args=3},
did_filetype={},
@ -277,6 +278,13 @@ return {
sha256={args=1},
shellescape={args={1, 2}},
shiftwidth={},
sign_define={args={1, 2}},
sign_getdefined={args={0, 1}},
sign_getplaced={args={0, 2}},
sign_jump={args={3, 3}},
sign_place={args={4, 5}},
sign_undefine={args={0, 1}},
sign_unplace={args={1, 2}},
simplify={args=1},
sin={args=1, func="float_op_wrapper", data="&sin"},
sinh={args=1, func="float_op_wrapper", data="&sinh"},

View File

@ -67,10 +67,6 @@
#include "nvim/os/input.h"
#include "nvim/os/time.h"
/*
* Struct to hold the sign properties.
*/
typedef struct sign sign_T;
/// Case matching style to use for :substitute
typedef enum {
@ -5521,21 +5517,6 @@ void ex_helptags(exarg_T *eap)
}
}
struct sign
{
sign_T *sn_next; // next sign in list
int sn_typenr; // type number of sign
char_u *sn_name; // name of sign
char_u *sn_icon; // name of pixmap
char_u *sn_text; // text used instead of pixmap
int sn_line_hl; // highlight ID for line
int sn_text_hl; // highlight ID for text
int sn_num_hl; // highlight ID for line number
};
static sign_T *first_sign = NULL;
static int next_sign_typenr = 1;
/*
* ":helpclose": Close one help window
*/
@ -5549,681 +5530,6 @@ void ex_helpclose(exarg_T *eap)
}
}
static char *cmds[] = {
"define",
#define SIGNCMD_DEFINE 0
"undefine",
#define SIGNCMD_UNDEFINE 1
"list",
#define SIGNCMD_LIST 2
"place",
#define SIGNCMD_PLACE 3
"unplace",
#define SIGNCMD_UNPLACE 4
"jump",
#define SIGNCMD_JUMP 5
NULL
#define SIGNCMD_LAST 6
};
/*
* Find index of a ":sign" subcmd from its name.
* "*end_cmd" must be writable.
*/
static int sign_cmd_idx(
char_u *begin_cmd, /* begin of sign subcmd */
char_u *end_cmd /* just after sign subcmd */
)
{
int idx;
char save = *end_cmd;
*end_cmd = NUL;
for (idx = 0; ; ++idx) {
if (cmds[idx] == NULL || STRCMP(begin_cmd, cmds[idx]) == 0) {
break;
}
}
*end_cmd = save;
return idx;
}
/*
* ":sign" command
*/
void ex_sign(exarg_T *eap)
{
char_u *arg = eap->arg;
char_u *p;
int idx;
sign_T *sp;
sign_T *sp_prev;
// Parse the subcommand.
p = skiptowhite(arg);
idx = sign_cmd_idx(arg, p);
if (idx == SIGNCMD_LAST) {
EMSG2(_("E160: Unknown sign command: %s"), arg);
return;
}
arg = skipwhite(p);
if (idx <= SIGNCMD_LIST) {
// Define, undefine or list signs.
if (idx == SIGNCMD_LIST && *arg == NUL) {
// ":sign list": list all defined signs
for (sp = first_sign; sp != NULL && !got_int; sp = sp->sn_next) {
sign_list_defined(sp);
}
} else if (*arg == NUL) {
EMSG(_("E156: Missing sign name"));
} else {
// Isolate the sign name. If it's a number skip leading zeroes,
// so that "099" and "99" are the same sign. But keep "0".
p = skiptowhite(arg);
if (*p != NUL) {
*p++ = NUL;
}
while (arg[0] == '0' && arg[1] != NUL) {
arg++;
}
sp_prev = NULL;
for (sp = first_sign; sp != NULL; sp = sp->sn_next) {
if (STRCMP(sp->sn_name, arg) == 0) {
break;
}
sp_prev = sp;
}
if (idx == SIGNCMD_DEFINE) {
// ":sign define {name} ...": define a sign
if (sp == NULL) {
sign_T *lp;
int start = next_sign_typenr;
// Allocate a new sign.
sp = xcalloc(1, sizeof(sign_T));
// Check that next_sign_typenr is not already being used.
// This only happens after wrapping around. Hopefully
// another one got deleted and we can use its number.
for (lp = first_sign; lp != NULL; ) {
if (lp->sn_typenr == next_sign_typenr) {
next_sign_typenr++;
if (next_sign_typenr == MAX_TYPENR) {
next_sign_typenr = 1;
}
if (next_sign_typenr == start) {
xfree(sp);
EMSG(_("E612: Too many signs defined"));
return;
}
lp = first_sign; // start all over
continue;
}
lp = lp->sn_next;
}
sp->sn_typenr = next_sign_typenr;
if (++next_sign_typenr == MAX_TYPENR) {
next_sign_typenr = 1; // wrap around
}
sp->sn_name = vim_strsave(arg);
// add the new sign to the list of signs
if (sp_prev == NULL) {
first_sign = sp;
} else {
sp_prev->sn_next = sp;
}
}
// set values for a defined sign.
for (;;) {
arg = skipwhite(p);
if (*arg == NUL) {
break;
}
p = skiptowhite_esc(arg);
if (STRNCMP(arg, "icon=", 5) == 0) {
arg += 5;
xfree(sp->sn_icon);
sp->sn_icon = vim_strnsave(arg, (int)(p - arg));
backslash_halve(sp->sn_icon);
} else if (STRNCMP(arg, "text=", 5) == 0) {
char_u *s;
int cells;
int len;
arg += 5;
for (s = arg; s + 1 < p; s++) {
if (*s == '\\') {
// Remove a backslash, so that it is possible
// to use a space.
STRMOVE(s, s + 1);
p--;
}
}
// Count cells and check for non-printable chars
cells = 0;
for (s = arg; s < p; s += utfc_ptr2len(s)) {
if (!vim_isprintc(utf_ptr2char(s))) {
break;
}
cells += utf_ptr2cells(s);
}
// Currently must be one or two display cells
if (s != p || cells < 1 || cells > 2) {
*p = NUL;
EMSG2(_("E239: Invalid sign text: %s"), arg);
return;
}
xfree(sp->sn_text);
// Allocate one byte more if we need to pad up
// with a space.
len = (int)(p - arg + ((cells == 1) ? 1 : 0));
sp->sn_text = vim_strnsave(arg, len);
if (cells == 1) {
STRCPY(sp->sn_text + len - 1, " ");
}
} else if (STRNCMP(arg, "linehl=", 7) == 0) {
arg += 7;
sp->sn_line_hl = syn_check_group(arg, (int)(p - arg));
} else if (STRNCMP(arg, "texthl=", 7) == 0) {
arg += 7;
sp->sn_text_hl = syn_check_group(arg, (int)(p - arg));
} else if (STRNCMP(arg, "numhl=", 6) == 0) {
arg += 6;
sp->sn_num_hl = syn_check_group(arg, (int)(p - arg));
} else {
EMSG2(_(e_invarg2), arg);
return;
}
}
} else if (sp == NULL) {
EMSG2(_("E155: Unknown sign: %s"), arg);
} else if (idx == SIGNCMD_LIST) {
// ":sign list {name}"
sign_list_defined(sp);
} else {
// ":sign undefine {name}"
sign_undefine(sp, sp_prev);
}
}
} else {
int id = -1;
linenr_T lnum = -1;
char_u *sign_name = NULL;
char_u *arg1;
if (*arg == NUL) {
if (idx == SIGNCMD_PLACE) {
// ":sign place": list placed signs in all buffers
sign_list_placed(NULL);
} else if (idx == SIGNCMD_UNPLACE) {
// ":sign unplace": remove placed sign at cursor
id = buf_findsign_id(curwin->w_buffer, curwin->w_cursor.lnum);
if (id > 0) {
buf_delsign(curwin->w_buffer, id);
redraw_buf_line_later(curwin->w_buffer, curwin->w_cursor.lnum);
} else {
EMSG(_("E159: Missing sign number"));
}
} else {
EMSG(_(e_argreq));
}
return;
}
if (idx == SIGNCMD_UNPLACE && arg[0] == '*' && arg[1] == NUL) {
// ":sign unplace *": remove all placed signs
buf_delete_all_signs();
return;
}
// first arg could be placed sign id
arg1 = arg;
if (ascii_isdigit(*arg)) {
id = getdigits_int(&arg);
if (!ascii_iswhite(*arg) && *arg != NUL) {
id = -1;
arg = arg1;
} else {
arg = skipwhite(arg);
if (idx == SIGNCMD_UNPLACE && *arg == NUL) {
// ":sign unplace {id}": remove placed sign by number
FOR_ALL_BUFFERS(buf) {
if ((lnum = buf_delsign(buf, id)) != 0) {
redraw_buf_line_later(buf, lnum);
}
}
return;
}
}
}
// Check for line={lnum} name={name} and file={fname} or buffer={nr}.
// Leave "arg" pointing to {fname}.
buf_T *buf = NULL;
for (;;) {
if (STRNCMP(arg, "line=", 5) == 0) {
arg += 5;
lnum = atoi((char *)arg);
arg = skiptowhite(arg);
} else if (STRNCMP(arg, "*", 1) == 0 && idx == SIGNCMD_UNPLACE) {
if (id != -1) {
EMSG(_(e_invarg));
return;
}
id = -2;
arg = skiptowhite(arg + 1);
} else if (STRNCMP(arg, "name=", 5) == 0) {
arg += 5;
sign_name = arg;
arg = skiptowhite(arg);
if (*arg != NUL) {
*arg++ = NUL;
}
while (sign_name[0] == '0' && sign_name[1] != NUL) {
sign_name++;
}
} else if (STRNCMP(arg, "file=", 5) == 0) {
arg += 5;
buf = buflist_findname(arg);
break;
} else if (STRNCMP(arg, "buffer=", 7) == 0) {
arg += 7;
buf = buflist_findnr(getdigits_int(&arg));
if (*skipwhite(arg) != NUL) {
EMSG(_(e_trailing));
}
break;
} else {
EMSG(_(e_invarg));
return;
}
arg = skipwhite(arg);
}
if (buf == NULL) {
EMSG2(_("E158: Invalid buffer name: %s"), arg);
} else if (id <= 0 && !(idx == SIGNCMD_UNPLACE && id == -2)) {
if (lnum >= 0 || sign_name != NULL) {
EMSG(_(e_invarg));
} else {
// ":sign place file={fname}": list placed signs in one file
sign_list_placed(buf);
}
} else if (idx == SIGNCMD_JUMP) {
// ":sign jump {id} file={fname}"
if (lnum >= 0 || sign_name != NULL) {
EMSG(_(e_invarg));
} else if ((lnum = buf_findsign(buf, id)) > 0) {
// goto a sign ...
if (buf_jump_open_win(buf) != NULL) {
// ... in a current window
curwin->w_cursor.lnum = lnum;
check_cursor_lnum();
beginline(BL_WHITE);
} else {
// ... not currently in a window
if (buf->b_fname == NULL) {
EMSG(_("E934: Cannot jump to a buffer that does not have a name"));
return;
}
size_t cmdlen = STRLEN(buf->b_fname) + 24;
char *cmd = xmallocz(cmdlen);
snprintf(cmd, cmdlen, "e +%" PRId64 " %s",
(int64_t)lnum, buf->b_fname);
do_cmdline_cmd(cmd);
xfree(cmd);
}
foldOpenCursor();
} else {
EMSGN(_("E157: Invalid sign ID: %" PRId64), id);
}
} else if (idx == SIGNCMD_UNPLACE) {
if (lnum >= 0 || sign_name != NULL) {
EMSG(_(e_invarg));
} else if (id == -2) {
// ":sign unplace * file={fname}"
redraw_buf_later(buf, NOT_VALID);
buf_delete_signs(buf);
} else {
// ":sign unplace {id} file={fname}"
lnum = buf_delsign(buf, id);
redraw_buf_line_later(buf, lnum);
}
} else if (sign_name != NULL) {
// idx == SIGNCMD_PLACE
for (sp = first_sign; sp != NULL; sp = sp->sn_next) {
if (STRCMP(sp->sn_name, sign_name) == 0) {
break;
}
}
if (sp == NULL) {
EMSG2(_("E155: Unknown sign: %s"), sign_name);
return;
}
if (lnum > 0) {
// ":sign place {id} line={lnum} name={name} file={fname}":
// place a sign
buf_addsign(buf, id, lnum, sp->sn_typenr);
} else {
// ":sign place {id} file={fname}": change sign type
lnum = buf_change_sign_type(buf, id, sp->sn_typenr);
}
if (lnum > 0) {
redraw_buf_line_later(buf, lnum);
} else {
EMSG2(_("E885: Not possible to change sign %s"), sign_name);
}
} else {
EMSG(_(e_invarg));
}
}
}
/*
* List one sign.
*/
static void sign_list_defined(sign_T *sp)
{
smsg("sign %s", sp->sn_name);
if (sp->sn_icon != NULL) {
msg_puts(" icon=");
msg_outtrans(sp->sn_icon);
msg_puts(_(" (not supported)"));
}
if (sp->sn_text != NULL) {
msg_puts(" text=");
msg_outtrans(sp->sn_text);
}
if (sp->sn_line_hl > 0) {
msg_puts(" linehl=");
const char *const p = get_highlight_name_ext(NULL,
sp->sn_line_hl - 1, false);
if (p == NULL) {
msg_puts("NONE");
} else {
msg_puts(p);
}
}
if (sp->sn_text_hl > 0) {
msg_puts(" texthl=");
const char *const p = get_highlight_name_ext(NULL,
sp->sn_text_hl - 1, false);
if (p == NULL) {
msg_puts("NONE");
} else {
msg_puts(p);
}
}
if (sp->sn_num_hl > 0) {
msg_puts(" numhl=");
const char *const p = get_highlight_name_ext(NULL,
sp->sn_num_hl - 1, false);
if (p == NULL) {
msg_puts("NONE");
} else {
msg_puts(p);
}
}
}
/*
* Undefine a sign and free its memory.
*/
static void sign_undefine(sign_T *sp, sign_T *sp_prev)
{
xfree(sp->sn_name);
xfree(sp->sn_icon);
xfree(sp->sn_text);
if (sp_prev == NULL)
first_sign = sp->sn_next;
else
sp_prev->sn_next = sp->sn_next;
xfree(sp);
}
/// Gets highlighting attribute for sign "typenr" corresponding to "type".
int sign_get_attr(int typenr, SignType type)
{
sign_T *sp;
int sign_hl = 0;
for (sp = first_sign; sp != NULL; sp = sp->sn_next) {
if (sp->sn_typenr == typenr) {
switch (type) {
case SIGN_TEXT:
sign_hl = sp->sn_text_hl;
break;
case SIGN_LINEHL:
sign_hl = sp->sn_line_hl;
break;
case SIGN_NUMHL:
sign_hl = sp->sn_num_hl;
break;
default:
abort();
}
if (sign_hl > 0) {
return syn_id2attr(sign_hl);
}
break;
}
}
return 0;
}
/*
* Get text mark for sign "typenr".
* Returns NULL if there isn't one.
*/
char_u * sign_get_text(int typenr)
{
sign_T *sp;
for (sp = first_sign; sp != NULL; sp = sp->sn_next)
if (sp->sn_typenr == typenr)
return sp->sn_text;
return NULL;
}
/*
* Get the name of a sign by its typenr.
*/
char_u * sign_typenr2name(int typenr)
{
sign_T *sp;
for (sp = first_sign; sp != NULL; sp = sp->sn_next)
if (sp->sn_typenr == typenr)
return sp->sn_name;
return (char_u *)_("[Deleted]");
}
#if defined(EXITFREE)
/*
* Undefine/free all signs.
*/
void free_signs(void)
{
while (first_sign != NULL)
sign_undefine(first_sign, NULL);
}
#endif
static enum
{
EXP_SUBCMD, /* expand :sign sub-commands */
EXP_DEFINE, /* expand :sign define {name} args */
EXP_PLACE, /* expand :sign place {id} args */
EXP_UNPLACE, /* expand :sign unplace" */
EXP_SIGN_NAMES /* expand with name of placed signs */
} expand_what;
/// Function given to ExpandGeneric() to obtain the sign command
/// expansion.
char_u * get_sign_name(expand_T *xp, int idx)
{
switch (expand_what)
{
case EXP_SUBCMD:
return (char_u *)cmds[idx];
case EXP_DEFINE: {
char *define_arg[] = { "icon=", "linehl=", "text=", "texthl=", "numhl=",
NULL };
return (char_u *)define_arg[idx];
}
case EXP_PLACE: {
char *place_arg[] = { "line=", "name=", "file=", "buffer=", NULL };
return (char_u *)place_arg[idx];
}
case EXP_UNPLACE: {
char *unplace_arg[] = { "file=", "buffer=", NULL };
return (char_u *)unplace_arg[idx];
}
case EXP_SIGN_NAMES: {
// Complete with name of signs already defined
int current_idx = 0;
for (sign_T *sp = first_sign; sp != NULL; sp = sp->sn_next) {
if (current_idx++ == idx) {
return sp->sn_name;
}
}
}
return NULL;
default:
return NULL;
}
}
/*
* Handle command line completion for :sign command.
*/
void set_context_in_sign_cmd(expand_T *xp, char_u *arg)
{
char_u *p;
char_u *end_subcmd;
char_u *last;
int cmd_idx;
char_u *begin_subcmd_args;
/* Default: expand subcommands. */
xp->xp_context = EXPAND_SIGN;
expand_what = EXP_SUBCMD;
xp->xp_pattern = arg;
end_subcmd = skiptowhite(arg);
if (*end_subcmd == NUL)
/* expand subcmd name
* :sign {subcmd}<CTRL-D>*/
return;
cmd_idx = sign_cmd_idx(arg, end_subcmd);
// :sign {subcmd} {subcmd_args}
// |
// begin_subcmd_args
begin_subcmd_args = skipwhite(end_subcmd);
p = skiptowhite(begin_subcmd_args);
if (*p == NUL)
{
/*
* Expand first argument of subcmd when possible.
* For ":jump {id}" and ":unplace {id}", we could
* possibly expand the ids of all signs already placed.
*/
xp->xp_pattern = begin_subcmd_args;
switch (cmd_idx)
{
case SIGNCMD_LIST:
case SIGNCMD_UNDEFINE:
/* :sign list <CTRL-D>
* :sign undefine <CTRL-D> */
expand_what = EXP_SIGN_NAMES;
break;
default:
xp->xp_context = EXPAND_NOTHING;
}
return;
}
// Expand last argument of subcmd.
//
// :sign define {name} {args}...
// |
// p
// Loop until reaching last argument.
do
{
p = skipwhite(p);
last = p;
p = skiptowhite(p);
} while (*p != NUL);
p = vim_strchr(last, '=');
// :sign define {name} {args}... {last}=
// | |
// last p
if (p == NULL) {
// Expand last argument name (before equal sign).
xp->xp_pattern = last;
switch (cmd_idx)
{
case SIGNCMD_DEFINE:
expand_what = EXP_DEFINE;
break;
case SIGNCMD_PLACE:
expand_what = EXP_PLACE;
break;
case SIGNCMD_JUMP:
case SIGNCMD_UNPLACE:
expand_what = EXP_UNPLACE;
break;
default:
xp->xp_context = EXPAND_NOTHING;
}
}
else
{
/* Expand last argument value (after equal sign). */
xp->xp_pattern = p + 1;
switch (cmd_idx)
{
case SIGNCMD_DEFINE:
if (STRNCMP(last, "texthl", p - last) == 0
|| STRNCMP(last, "linehl", p - last) == 0
|| STRNCMP(last, "numhl", p - last) == 0) {
xp->xp_context = EXPAND_HIGHLIGHT;
} else if (STRNCMP(last, "icon", p - last) == 0) {
xp->xp_context = EXPAND_FILES;
} else {
xp->xp_context = EXPAND_NOTHING;
}
break;
case SIGNCMD_PLACE:
if (STRNCMP(last, "name", p - last) == 0)
expand_what = EXP_SIGN_NAMES;
else
xp->xp_context = EXPAND_NOTHING;
break;
default:
xp->xp_context = EXPAND_NOTHING;
}
}
}
/// Shows the effects of the :substitute command being typed ('inccommand').
/// If inccommand=split, shows a preview window and later restores the layout.
static buf_T *show_sub(exarg_T *eap, pos_T old_cusr,

View File

@ -53,6 +53,7 @@
#include "nvim/regexp.h"
#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/sign.h"
#include "nvim/spell.h"
#include "nvim/spellfile.h"
#include "nvim/strings.h"

View File

@ -54,6 +54,7 @@
#include "nvim/regexp.h"
#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/sign.h"
#include "nvim/strings.h"
#include "nvim/state.h"
#include "nvim/syntax.h"

View File

@ -2833,13 +2833,12 @@ buf_write (
//
XFREE_CLEAR(backup); // no backup file to delete
} else if (!p_bk) {
/*
* We are not going to keep the backup file, so don't
* delete an existing one, and try to use another name instead.
* Change one character, just before the extension.
*/
// We are not going to keep the backup file, so don't
// delete an existing one, and try to use another name instead.
// Change one character, just before the extension.
//
wp = backup + STRLEN(backup) - 1 - STRLEN(backup_ext);
if (wp < backup) { /* empty file name ??? */
if (wp < backup) { // empty file name ???
wp = backup;
}
*wp = 'z';
@ -2847,7 +2846,7 @@ buf_write (
&& os_fileinfo((char *)backup, &file_info_new)) {
--*wp;
}
/* They all exist??? Must be something wrong. */
// They all exist??? Must be something wrong.
if (*wp == 'a') {
XFREE_CLEAR(backup);
}
@ -2969,18 +2968,17 @@ nobackup:
}
}
if (backup != NULL) {
/*
* Delete any existing backup and move the current version
* to the backup. For safety, we don't remove the backup
* until the write has finished successfully. And if the
* 'backup' option is set, leave it around.
*/
/*
* If the renaming of the original file to the backup file
* works, quit here.
*/
if (vim_rename(fname, backup) == 0)
// Delete any existing backup and move the current version
// to the backup. For safety, we don't remove the backup
// until the write has finished successfully. And if the
// 'backup' option is set, leave it around.
// If the renaming of the original file to the backup file
// works, quit here.
///
if (vim_rename(fname, backup) == 0) {
break;
}
XFREE_CLEAR(backup); // don't do the rename below
}
@ -2993,7 +2991,7 @@ nobackup:
}
#if defined(UNIX)
/* When using ":w!" and the file was read-only: make it writable */
// When using ":w!" and the file was read-only: make it writable
if (forceit && perm >= 0 && !(perm & 0200)
&& file_info_old.stat.st_uid == getuid()
&& vim_strchr(p_cpo, CPO_FWRITE) == NULL) {
@ -3003,12 +3001,12 @@ nobackup:
}
#endif
/* When using ":w!" and writing to the current file, 'readonly' makes no
* sense, reset it, unless 'Z' appears in 'cpoptions'. */
// When using ":w!" and writing to the current file, 'readonly' makes no
// sense, reset it, unless 'Z' appears in 'cpoptions'.
if (forceit && overwriting && vim_strchr(p_cpo, CPO_KEEPRO) == NULL) {
buf->b_p_ro = FALSE;
need_maketitle = TRUE; /* set window title later */
status_redraw_all(); /* redraw status lines later */
buf->b_p_ro = false;
need_maketitle = true; // set window title later
status_redraw_all(); // redraw status lines later
}
if (end > buf->b_ml.ml_line_count)
@ -3016,13 +3014,11 @@ nobackup:
if (buf->b_ml.ml_flags & ML_EMPTY)
start = end + 1;
/*
* If the original file is being overwritten, there is a small chance that
* we crash in the middle of writing. Therefore the file is preserved now.
* This makes all block numbers positive so that recovery does not need
* the original file.
* Don't do this if there is a backup file and we are exiting.
*/
// If the original file is being overwritten, there is a small chance that
// we crash in the middle of writing. Therefore the file is preserved now.
// This makes all block numbers positive so that recovery does not need
// the original file.
// Don't do this if there is a backup file and we are exiting.
if (reset_changed && !newfile && overwriting
&& !(exiting && backup != NULL)) {
ml_preserve(buf, false, !!p_fs);
@ -3033,36 +3029,34 @@ nobackup:
}
/* Default: write the file directly. May write to a temp file for
* multi-byte conversion. */
// Default: write the file directly. May write to a temp file for
// multi-byte conversion.
wfname = fname;
/* Check for forced 'fileencoding' from "++opt=val" argument. */
// Check for forced 'fileencoding' from "++opt=val" argument.
if (eap != NULL && eap->force_enc != 0) {
fenc = eap->cmd + eap->force_enc;
fenc = enc_canonize(fenc);
fenc_tofree = fenc;
} else
} else {
fenc = buf->b_p_fenc;
}
/*
* Check if the file needs to be converted.
*/
// Check if the file needs to be converted.
converted = need_conversion(fenc);
/*
* Check if UTF-8 to UCS-2/4 or Latin1 conversion needs to be done. Or
* Latin1 to Unicode conversion. This is handled in buf_write_bytes().
* Prepare the flags for it and allocate bw_conv_buf when needed.
*/
// Check if UTF-8 to UCS-2/4 or Latin1 conversion needs to be done. Or
// Latin1 to Unicode conversion. This is handled in buf_write_bytes().
// Prepare the flags for it and allocate bw_conv_buf when needed.
if (converted && (enc_utf8 || STRCMP(p_enc, "latin1") == 0)) {
wb_flags = get_fio_flags(fenc);
if (wb_flags & (FIO_UCS2 | FIO_UCS4 | FIO_UTF16 | FIO_UTF8)) {
/* Need to allocate a buffer to translate into. */
if (wb_flags & (FIO_UCS2 | FIO_UTF16 | FIO_UTF8))
// Need to allocate a buffer to translate into.
if (wb_flags & (FIO_UCS2 | FIO_UTF16 | FIO_UTF8)) {
write_info.bw_conv_buflen = bufsize * 2;
else /* FIO_UCS4 */
} else { // FIO_UCS4
write_info.bw_conv_buflen = bufsize * 4;
}
write_info.bw_conv_buf = verbose_try_malloc(write_info.bw_conv_buflen);
if (!write_info.bw_conv_buf) {
end = 0;
@ -3074,10 +3068,8 @@ nobackup:
if (converted && wb_flags == 0) {
# ifdef USE_ICONV
/*
* Use iconv() conversion when conversion is needed and it's not done
* internally.
*/
// Use iconv() conversion when conversion is needed and it's not done
// internally.
write_info.bw_iconv_fd = (iconv_t)my_iconv_open(fenc,
enc_utf8 ? (char_u *)"utf-8" : p_enc);
if (write_info.bw_iconv_fd != (iconv_t)-1) {

View File

@ -484,6 +484,11 @@ EXTERN buf_T *curbuf INIT(= NULL); // currently active buffer
#define FOR_ALL_BUFFERS_BACKWARDS(buf) \
for (buf_T *buf = lastbuf; buf != NULL; buf = buf->b_prev)
// Iterate through all the signs placed in a buffer
#define FOR_ALL_SIGNS_IN_BUF(buf, sign) \
for (sign = buf->b_signlist; sign != NULL; sign = sign->next) // NOLINT
/*
* List of files being edited (global argument list). curwin->w_alist points
* to this when the window is using the global argument list.

View File

@ -1524,12 +1524,10 @@ static void cs_fill_results(char *tagstr, size_t totmatches, int *nummatches_a,
}
totsofar++;
} /* for all matches */
} // for all matches
(void)cs_read_prompt(i);
} /* for all cscope connections */
} // for all cscope connections
if (totsofar == 0) {
// No matches, free the arrays and return NULL in "*matches_p".
@ -1541,20 +1539,25 @@ static void cs_fill_results(char *tagstr, size_t totmatches, int *nummatches_a,
*cntxts_p = cntxts;
xfree(buf);
} /* cs_fill_results */
} // cs_fill_results
/* get the requested path components */
static char *cs_pathcomponents(char *path)
{
if (p_cspc == 0)
if (p_cspc == 0) {
return path;
}
char *s = path + strlen(path) - 1;
for (int i = 0; i < p_cspc; ++i)
while (s > path && *--s != '/') continue;
if ((s > path && *s == '/'))
++s;
for (int i = 0; i < p_cspc; i++) {
while (s > path && *--s != '/') {
continue;
}
}
if ((s > path && *s == '/')) {
s++;
}
return s;
}

View File

@ -49,6 +49,7 @@
#include "nvim/popupmnu.h"
#include "nvim/quickfix.h"
#include "nvim/screen.h"
#include "nvim/sign.h"
#include "nvim/state.h"
#include "nvim/strings.h"
#include "nvim/syntax.h"
@ -1337,6 +1338,8 @@ static void init_path(const char *exename)
// shipped with Windows package. This also mimics SearchPath().
os_setenv_append_path(exepath);
#endif
init_signs();
}
/// Get filename from command line, if any.

View File

@ -29,6 +29,7 @@
#include "nvim/path.h"
#include "nvim/quickfix.h"
#include "nvim/search.h"
#include "nvim/sign.h"
#include "nvim/strings.h"
#include "nvim/ui.h"
#include "nvim/os/os.h"

View File

@ -2085,31 +2085,31 @@ static char_u *iconv_string(const vimconv_T *const vcp, char_u *str,
to = (char *)result + done;
tolen = len - done - 2;
/* Avoid a warning for systems with a wrong iconv() prototype by
* casting the second argument to void *. */
// Avoid a warning for systems with a wrong iconv() prototype by
// casting the second argument to void *.
if (iconv(vcp->vc_fd, (void *)&from, &fromlen, &to, &tolen) != SIZE_MAX) {
/* Finished, append a NUL. */
// Finished, append a NUL.
*to = NUL;
break;
}
/* Check both ICONV_EINVAL and EINVAL, because the dynamically loaded
* iconv library may use one of them. */
// Check both ICONV_EINVAL and EINVAL, because the dynamically loaded
// iconv library may use one of them.
if (!vcp->vc_fail && unconvlenp != NULL
&& (ICONV_ERRNO == ICONV_EINVAL || ICONV_ERRNO == EINVAL)) {
/* Handle an incomplete sequence at the end. */
// Handle an incomplete sequence at the end.
*to = NUL;
*unconvlenp = fromlen;
break;
}
/* Check both ICONV_EILSEQ and EILSEQ, because the dynamically loaded
* iconv library may use one of them. */
else if (!vcp->vc_fail
&& (ICONV_ERRNO == ICONV_EILSEQ || ICONV_ERRNO == EILSEQ
|| ICONV_ERRNO == ICONV_EINVAL || ICONV_ERRNO == EINVAL)) {
/* Can't convert: insert a '?' and skip a character. This assumes
* conversion from 'encoding' to something else. In other
* situations we don't know what to skip anyway. */
} else if (!vcp->vc_fail
&& (ICONV_ERRNO == ICONV_EILSEQ || ICONV_ERRNO == EILSEQ
|| ICONV_ERRNO == ICONV_EINVAL || ICONV_ERRNO == EINVAL)) {
// Check both ICONV_EILSEQ and EILSEQ, because the dynamically loaded
// iconv library may use one of them.
// Can't convert: insert a '?' and skip a character. This assumes
// conversion from 'encoding' to something else. In other
// situations we don't know what to skip anyway.
*to++ = '?';
if (utf_ptr2cells((char_u *)from) > 1) {
*to++ = '?';
@ -2122,7 +2122,7 @@ static char_u *iconv_string(const vimconv_T *const vcp, char_u *str,
XFREE_CLEAR(result);
break;
}
/* Not enough room or skipping illegal sequence. */
// Not enough room or skipping illegal sequence.
done = to - (char *)result;
}
@ -2132,11 +2132,9 @@ static char_u *iconv_string(const vimconv_T *const vcp, char_u *str,
}
# if defined(DYNAMIC_ICONV)
/*
* Dynamically load the "iconv.dll" on Win32.
*/
// Dynamically load the "iconv.dll" on Win32.
#ifndef DYNAMIC_ICONV /* just generating prototypes */
#ifndef DYNAMIC_ICONV // just generating prototypes
# define HINSTANCE int
#endif
static HINSTANCE hIconvDLL = 0;

View File

@ -3356,47 +3356,38 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname,
break;
}
/*
* A file name equal to old_fname is OK to use.
*/
if (old_fname != NULL && fnamecmp(fname, old_fname) == 0)
// A file name equal to old_fname is OK to use.
if (old_fname != NULL && fnamecmp(fname, old_fname) == 0) {
break;
}
/*
* get here when file already exists
*/
if (fname[n - 2] == 'w' && fname[n - 1] == 'p') { /* first try */
/*
* If we get here the ".swp" file really exists.
* Give an error message, unless recovering, no file name, we are
* viewing a help file or when the path of the file is different
* (happens when all .swp files are in one directory).
*/
// get here when file already exists
if (fname[n - 2] == 'w' && fname[n - 1] == 'p') { // first try
// If we get here the ".swp" file really exists.
// Give an error message, unless recovering, no file name, we are
// viewing a help file or when the path of the file is different
// (happens when all .swp files are in one directory).
if (!recoverymode && buf_fname != NULL
&& !buf->b_help && !(buf->b_flags & BF_DUMMY)) {
int fd;
struct block0 b0;
int differ = FALSE;
/*
* Try to read block 0 from the swap file to get the original
* file name (and inode number).
*/
// Try to read block 0 from the swap file to get the original
// file name (and inode number).
fd = os_open(fname, O_RDONLY, 0);
if (fd >= 0) {
if (read_eintr(fd, &b0, sizeof(b0)) == sizeof(b0)) {
/*
* If the swapfile has the same directory as the
* buffer don't compare the directory names, they can
* have a different mountpoint.
*/
// If the swapfile has the same directory as the
// buffer don't compare the directory names, they can
// have a different mountpoint.
if (b0.b0_flags & B0_SAME_DIR) {
if (fnamecmp(path_tail(buf->b_ffname),
path_tail(b0.b0_fname)) != 0
|| !same_directory((char_u *) fname, buf->b_ffname)) {
/* Symlinks may point to the same file even
* when the name differs, need to check the
* inode too. */
|| !same_directory((char_u *)fname, buf->b_ffname)) {
// Symlinks may point to the same file even
// when the name differs, need to check the
// inode too.
expand_env(b0.b0_fname, NameBuff, MAXPATHL);
if (fnamecmp_ino(buf->b_ffname, NameBuff,
char_to_long(b0.b0_ino))) {
@ -3404,10 +3395,8 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname,
}
}
} else {
/*
* The name in the swap file may be
* "~user/path/file". Expand it first.
*/
// The name in the swap file may be
// "~user/path/file". Expand it first.
expand_env(b0.b0_fname, NameBuff, MAXPATHL);
if (fnamecmp_ino(buf->b_ffname, NameBuff,
char_to_long(b0.b0_ino))) {
@ -3418,9 +3407,9 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname,
close(fd);
}
/* give the ATTENTION message when there is an old swap file
* for the current file, and the buffer was not recovered. */
if (differ == FALSE && !(curbuf->b_flags & BF_RECOVERED)
// give the ATTENTION message when there is an old swap file
// for the current file, and the buffer was not recovered. */
if (differ == false && !(curbuf->b_flags & BF_RECOVERED)
&& vim_strchr(p_shm, SHM_ATTENTION) == NULL) {
int choice = 0;

View File

@ -16,6 +16,7 @@
#include "nvim/message.h"
#include "nvim/misc1.h"
#include "nvim/ui.h"
#include "nvim/sign.h"
#include "nvim/api/vim.h"
#ifdef UNIT_TESTING

View File

@ -1082,16 +1082,14 @@ void wait_return(int redraw)
/* Put the character back in the typeahead buffer. Don't use the
* stuff buffer, because lmaps wouldn't work. */
ins_char_typebuf(c);
do_redraw = TRUE; /* need a redraw even though there is
typeahead */
do_redraw = true; // need a redraw even though there is
// typeahead
}
}
redir_off = FALSE;
redir_off = false;
/*
* If the user hits ':', '?' or '/' we get a command line from the next
* line.
*/
// If the user hits ':', '?' or '/' we get a command line from the next
// line.
if (c == ':' || c == '?' || c == '/') {
if (!exmode_active)
cmdline_row = msg_row;
@ -1100,19 +1098,17 @@ void wait_return(int redraw)
msg_ext_keep_after_cmdline = true;
}
/*
* If the window size changed set_shellsize() will redraw the screen.
* Otherwise the screen is only redrawn if 'redraw' is set and no ':'
* typed.
*/
// If the window size changed set_shellsize() will redraw the screen.
// Otherwise the screen is only redrawn if 'redraw' is set and no ':'
// typed.
tmpState = State;
State = oldState; /* restore State before set_shellsize */
State = oldState; // restore State before set_shellsize
setmouse();
msg_check();
need_wait_return = FALSE;
did_wait_return = TRUE;
emsg_on_display = FALSE; /* can delete error message now */
lines_left = -1; /* reset lines_left at next msg_start() */
need_wait_return = false;
did_wait_return = true;
emsg_on_display = false; // can delete error message now
lines_left = -1; // reset lines_left at next msg_start()
reset_last_sourcing();
if (keep_msg != NULL && vim_strsize(keep_msg) >=
(Rows - cmdline_row - 1) * Columns + sc_col) {
@ -1183,25 +1179,25 @@ void msg_ext_set_kind(const char *msg_kind)
*/
void msg_start(void)
{
int did_return = FALSE;
int did_return = false;
if (!msg_silent) {
XFREE_CLEAR(keep_msg); // don't display old message now
}
if (need_clr_eos) {
/* Halfway an ":echo" command and getting an (error) message: clear
* any text from the command. */
need_clr_eos = FALSE;
// Halfway an ":echo" command and getting an (error) message: clear
// any text from the command.
need_clr_eos = false;
msg_clr_eos();
}
if (!msg_scroll && full_screen) { /* overwrite last message */
if (!msg_scroll && full_screen) { // overwrite last message
msg_row = cmdline_row;
msg_col =
cmdmsg_rl ? Columns - 1 :
0;
} else if (msg_didout) { /* start message on next line */
} else if (msg_didout) { // start message on next line
msg_putchar('\n');
did_return = TRUE;
if (exmode_active != EXMODE_NORMAL)
@ -1210,7 +1206,7 @@ void msg_start(void)
if (!msg_didany || lines_left < 0)
msg_starthere();
if (msg_silent == 0) {
msg_didout = FALSE; /* no output on current line yet */
msg_didout = false; // no output on current line yet
}
if (ui_has(kUIMessages)) {
@ -2992,12 +2988,13 @@ int verbose_open(void)
*/
void give_warning(char_u *message, bool hl) FUNC_ATTR_NONNULL_ARG(1)
{
/* Don't do this for ":silent". */
if (msg_silent != 0)
// Don't do this for ":silent".
if (msg_silent != 0) {
return;
}
/* Don't want a hit-enter prompt here. */
++no_wait_return;
// Don't want a hit-enter prompt here.
no_wait_return++;
set_vim_var_string(VV_WARNINGMSG, (char *)message, -1);
XFREE_CLEAR(keep_msg);
@ -3015,7 +3012,7 @@ void give_warning(char_u *message, bool hl) FUNC_ATTR_NONNULL_ARG(1)
msg_nowait = true; // Don't wait for this message.
msg_col = 0;
--no_wait_return;
no_wait_return--;
}
void give_warning2(char_u *const message, char_u *const a1, bool hl)

View File

@ -4213,10 +4213,10 @@ dozet:
set_fraction(curwin);
break;
/* "z^", "z-" and "zb": put cursor at bottom of screen */
case '^': /* Strange Vi behavior: <count>z^ finds line at top of window
* when <count> is at bottom of window, and puts that one at
* bottom of window. */
// "z^", "z-" and "zb": put cursor at bottom of screen
case '^': // Strange Vi behavior: <count>z^ finds line at top of window
// when <count> is at bottom of window, and puts that one at
// bottom of window.
if (cap->count0 != 0) {
scroll_cursor_bot(0, true);
curwin->w_cursor.lnum = curwin->w_topline;

View File

@ -103,6 +103,7 @@
#include "nvim/quickfix.h"
#include "nvim/regexp.h"
#include "nvim/search.h"
#include "nvim/sign.h"
#include "nvim/spell.h"
#include "nvim/state.h"
#include "nvim/strings.h"
@ -220,7 +221,8 @@ void redraw_buf_later(buf_T *buf, int type)
void redraw_buf_line_later(buf_T *buf, linenr_T line)
{
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp->w_buffer == buf) {
if (wp->w_buffer == buf
&& line >= wp->w_topline && line < wp->w_botline) {
redrawWinline(wp, line);
}
}

View File

@ -87,13 +87,13 @@ static struct spat spats[2] =
static int last_idx = 0; /* index in spats[] for RE_LAST */
static char_u lastc[2] = {NUL, NUL}; /* last character searched for */
static int lastcdir = FORWARD; /* last direction of character search */
static int last_t_cmd = TRUE; /* last search t_cmd */
static char_u lastc[2] = { NUL, NUL }; // last character searched for
static int lastcdir = FORWARD; // last direction of character search
static int last_t_cmd = true; // last search t_cmd
static char_u lastc_bytes[MB_MAXBYTES + 1];
static int lastc_bytelen = 1; /* >1 for multi-byte char */
static int lastc_bytelen = 1; // >1 for multi-byte char
/* copy of spats[], for keeping the search patterns while executing autocmds */
// copy of spats[], for keeping the search patterns while executing autocmds
static struct spat saved_spats[2];
// copy of spats[RE_SEARCH], for keeping the search patterns while incremental
// searching
@ -101,8 +101,8 @@ static struct spat saved_last_search_spat;
static int saved_last_idx = 0;
static int saved_no_hlsearch = 0;
static char_u *mr_pattern = NULL; /* pattern used by search_regcomp() */
static int mr_pattern_alloced = FALSE; /* mr_pattern was allocated */
static char_u *mr_pattern = NULL; // pattern used by search_regcomp()
static int mr_pattern_alloced = false; // mr_pattern was allocated
/*
* Type used by find_pattern_in_path() to remember which included files have

1746
src/nvim/sign.c Normal file

File diff suppressed because it is too large Load Diff

13
src/nvim/sign.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef NVIM_SIGN_H
#define NVIM_SIGN_H
#include <stdbool.h>
#include "nvim/buffer_defs.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/sign_defs.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "sign.h.generated.h"
#endif
#endif // NVIM_SIGN_H

View File

@ -2,20 +2,38 @@
#define NVIM_SIGN_DEFS_H
#include "nvim/pos.h"
#include "nvim/types.h"
// signs: line annotations
// Sign group
typedef struct signgroup_S
{
uint16_t refcount; // number of signs in this group
int next_sign_id; // next sign id for this group
char_u sg_name[1]; // sign group name
} signgroup_T;
// Macros to get the sign group structure from the group name
#define SGN_KEY_OFF offsetof(signgroup_T, sg_name)
#define HI2SG(hi) ((signgroup_T *)((hi)->hi_key - SGN_KEY_OFF))
typedef struct signlist signlist_T;
struct signlist
{
int id; // unique identifier for each placed sign
linenr_T lnum; // line number which has this sign
int typenr; // typenr of sign
signlist_T *next; // next signlist entry
signlist_T *prev; // previous entry -- for easy reordering
int id; // unique identifier for each placed sign
linenr_T lnum; // line number which has this sign
int typenr; // typenr of sign
signgroup_T *group; // sign group
int priority; // priority for highlighting
signlist_T *next; // next signlist entry
signlist_T *prev; // previous entry -- for easy reordering
};
// Default sign priority for highlighting
#define SIGN_DEF_PRIO 10
// type argument for buf_getsigntype() and sign_get_attr()
typedef enum {
SIGN_ANY,

View File

@ -38,6 +38,7 @@
#include "nvim/macros.h"
#include "nvim/regexp.h"
#include "nvim/screen.h"
#include "nvim/sign.h"
#include "nvim/strings.h"
#include "nvim/syntax_defs.h"
#include "nvim/terminal.h"

File diff suppressed because it is too large Load Diff

View File

@ -240,7 +240,7 @@ describe('Signs', function()
:sign place |
{9:--- Signs ---} |
{10:Signs for [NULL]:} |
line=1 id=100000 name=piet |
line=1 id=100000 name=piet priority=10 |
|
{11:Press ENTER or type command to continue}^ |
]])