aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/api/vim.c33
-rw-r--r--src/nvim/buffer.c40
-rw-r--r--src/nvim/ex_docmd.c46
-rw-r--r--src/nvim/getchar.c4
-rw-r--r--src/nvim/highlight.c32
-rw-r--r--src/nvim/highlight_defs.h12
-rw-r--r--src/nvim/macros.h3
-rw-r--r--src/nvim/screen.c2
-rw-r--r--src/nvim/syntax.c84
-rw-r--r--src/nvim/testdir/test_feedkeys.vim12
-rw-r--r--src/nvim/testdir/test_statusline.vim15
11 files changed, 213 insertions, 70 deletions
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 7c194935ce..e9182fde7f 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -19,6 +19,7 @@
#include "nvim/ascii.h"
#include "nvim/buffer.h"
#include "nvim/buffer_defs.h"
+#include "nvim/charset.h"
#include "nvim/context.h"
#include "nvim/decoration.h"
#include "nvim/edit.h"
@@ -31,6 +32,7 @@
#include "nvim/fileio.h"
#include "nvim/getchar.h"
#include "nvim/highlight.h"
+#include "nvim/highlight_defs.h"
#include "nvim/lua/executor.h"
#include "nvim/mark.h"
#include "nvim/memline.h"
@@ -121,7 +123,9 @@ Dictionary nvim__get_hl_defs(Integer ns_id, Error *err)
/// Set a highlight group.
///
-/// @param ns_id number of namespace for this highlight
+/// @param ns_id number of namespace for this highlight. Use value 0
+/// to set a highlight group in the global (`:highlight`)
+/// namespace.
/// @param name highlight group name, like ErrorMsg
/// @param val highlight definition map, like |nvim_get_hl_by_name|.
/// in addition the following keys are also recognized:
@@ -135,18 +139,23 @@ Dictionary nvim__get_hl_defs(Integer ns_id, Error *err)
/// same as attributes of gui color
/// @param[out] err Error details, if any
///
-/// TODO: ns_id = 0, should modify :highlight namespace
-/// TODO val should take update vs reset flag
+// TODO(bfredl): val should take update vs reset flag
void nvim_set_hl(Integer ns_id, String name, Dictionary val, Error *err)
FUNC_API_SINCE(7)
{
int hl_id = syn_check_group(name.data, (int)name.size);
int link_id = -1;
- HlAttrs attrs = dict2hlattrs(val, true, &link_id, err);
+ HlAttrNames *names = NULL; // Only used when setting global namespace
+ if (ns_id == 0) {
+ names = xmalloc(sizeof(*names));
+ *names = HLATTRNAMES_INIT;
+ }
+ HlAttrs attrs = dict2hlattrs(val, true, &link_id, names, err);
if (!ERROR_SET(err)) {
- ns_hl_def((NS)ns_id, hl_id, attrs, link_id);
+ ns_hl_def((NS)ns_id, hl_id, attrs, link_id, names);
}
+ xfree(names);
}
/// Set active namespace for highlights.
@@ -2236,7 +2245,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
Dictionary result = ARRAY_DICT_INIT;
int maxwidth;
- char fillchar = 0;
+ int fillchar = 0;
Window window = 0;
bool use_tabline = false;
bool highlights = false;
@@ -2251,12 +2260,12 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
}
if (HAS_KEY(opts->fillchar)) {
- if (opts->fillchar.type != kObjectTypeString || opts->fillchar.data.string.size > 1) {
- api_set_error(err, kErrorTypeValidation, "fillchar must be an ASCII character");
+ if (opts->fillchar.type != kObjectTypeString || opts->fillchar.data.string.size == 0
+ || char2cells(fillchar = utf_ptr2char((char_u *)opts->fillchar.data.string.data)) != 1
+ || (size_t)utf_char2len(fillchar) != opts->fillchar.data.string.size) {
+ api_set_error(err, kErrorTypeValidation, "fillchar must be a single-width character");
return result;
}
-
- fillchar = opts->fillchar.data.string.data[0];
}
if (HAS_KEY(opts->highlights)) {
@@ -2292,7 +2301,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
if (fillchar == 0) {
int attr;
- fillchar = (char)fillchar_status(&attr, wp);
+ fillchar = fillchar_status(&attr, wp);
}
}
@@ -2320,7 +2329,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
sizeof(buf),
(char_u *)str.data,
false,
- (char_u)fillchar,
+ fillchar,
maxwidth,
hltab_ptr,
NULL);
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 52a7db3be2..bb8483f644 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -3419,7 +3419,7 @@ typedef enum {
///
/// @return The final width of the statusline
int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use_sandbox,
- char_u fillchar, int maxwidth, stl_hlrec_t **hltab, StlClickRecord **tabtab)
+ int fillchar, int maxwidth, stl_hlrec_t **hltab, StlClickRecord **tabtab)
{
static size_t stl_items_len = 20; // Initial value, grows as needed.
static stl_item_t *stl_items = NULL;
@@ -3462,9 +3462,6 @@ int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use
if (fillchar == 0) {
fillchar = ' ';
- } else if (utf_char2len(fillchar) > 1) {
- // Can't handle a multi-byte fill character yet.
- fillchar = '-';
}
// The cursor in windows other than the current one isn't always
@@ -3662,7 +3659,7 @@ int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use
out_p = out_p - n + 1;
// Fill up space left over by half a double-wide char.
while (++group_len < stl_items[stl_groupitems[groupdepth]].minwid) {
- *out_p++ = fillchar;
+ MB_CHAR2BYTES(fillchar, out_p);
}
// }
@@ -3685,14 +3682,14 @@ int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use
if (min_group_width < 0) {
min_group_width = 0 - min_group_width;
while (group_len++ < min_group_width && out_p < out_end_p) {
- *out_p++ = fillchar;
+ MB_CHAR2BYTES(fillchar, out_p);
}
// If the group is right-aligned, shift everything to the right and
// prepend with filler characters.
} else {
// { Move the group to the right
- memmove(t + min_group_width - group_len, t, (size_t)(out_p - t));
- group_len = min_group_width - group_len;
+ group_len = (min_group_width - group_len) * utf_char2len(fillchar);
+ memmove(t + group_len, t, (size_t)(out_p - t));
if (out_p + group_len >= (out_end_p + 1)) {
group_len = (long)(out_end_p - out_p);
}
@@ -3706,7 +3703,7 @@ int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use
// Prepend the fill characters
for (; group_len > 0; group_len--) {
- *t++ = fillchar;
+ MB_CHAR2BYTES(fillchar, t);
}
}
}
@@ -4231,7 +4228,7 @@ int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use
if (l + 1 == minwid && fillchar == '-' && ascii_isdigit(*t)) {
*out_p++ = ' ';
} else {
- *out_p++ = fillchar;
+ MB_CHAR2BYTES(fillchar, out_p);
}
}
minwid = 0;
@@ -4242,20 +4239,21 @@ int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use
}
// { Copy the string text into the output buffer
- while (*t && out_p < out_end_p) {
- *out_p++ = *t++;
+ for (; *t && out_p < out_end_p; t++) {
// Change a space by fillchar, unless fillchar is '-' and a
// digit follows.
- if (fillable && out_p[-1] == ' '
- && (!ascii_isdigit(*t) || fillchar != '-')) {
- out_p[-1] = fillchar;
+ if (fillable && *t == ' '
+ && (!ascii_isdigit(*(t + 1)) || fillchar != '-')) {
+ MB_CHAR2BYTES(fillchar, out_p);
+ } else {
+ *out_p++ = *t;
}
}
// }
// For left-aligned items, fill any remaining space with the fillchar
for (; l < minwid && out_p < out_end_p; l++) {
- *out_p++ = fillchar;
+ MB_CHAR2BYTES(fillchar, out_p);
}
// Otherwise if the item is a number, copy that to the output buffer.
@@ -4448,7 +4446,7 @@ int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use
// Fill up for half a double-wide character.
while (++width < maxwidth) {
- *trunc_p++ = fillchar;
+ MB_CHAR2BYTES(fillchar, trunc_p);
*trunc_p = NUL;
}
// }
@@ -4499,13 +4497,13 @@ int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use
standard_spaces * (num_separators - 1);
for (int i = 0; i < num_separators; i++) {
- int dislocation = (i == (num_separators - 1))
- ? final_spaces : standard_spaces;
+ int dislocation = (i == (num_separators - 1)) ? final_spaces : standard_spaces;
+ dislocation *= utf_char2len(fillchar);
char_u *start = stl_items[stl_separator_locations[i]].start;
char_u *seploc = start + dislocation;
STRMOVE(seploc, start);
- for (char_u *s = start; s < seploc; s++) {
- *s = fillchar;
+ for (char_u *s = start; s < seploc; ) {
+ MB_CHAR2BYTES(fillchar, s);
}
for (int item_idx = stl_separator_locations[i] + 1;
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 07fbf1c61a..b94fe47c17 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -7835,13 +7835,11 @@ void post_chdir(CdScope scope, bool trigger_dirchanged)
/// @return true if the directory is successfully changed.
bool changedir_func(char_u *new_dir, CdScope scope)
{
- char_u *pdir = NULL;
- bool retval = false;
-
if (new_dir == NULL || allbuf_locked()) {
return false;
}
+ char_u *pdir = NULL;
// ":cd -": Change to previous directory
if (STRCMP(new_dir, "-") == 0) {
pdir = get_prevdir(scope);
@@ -7870,32 +7868,30 @@ bool changedir_func(char_u *new_dir, CdScope scope)
new_dir = NameBuff;
}
- bool dir_differs = new_dir == NULL || pdir == NULL
- || pathcmp((char *)pdir, (char *)new_dir, -1) != 0;
- if (new_dir != NULL && (!dir_differs || vim_chdir(new_dir) == 0)) {
- char_u **pp;
-
- switch (scope) {
- case kCdScopeTabpage:
- pp = &curtab->tp_prevdir;
- break;
- case kCdScopeWindow:
- pp = &curwin->w_prevdir;
- break;
- default:
- pp = &prev_dir;
- }
- xfree(*pp);
- *pp = pdir;
-
- post_chdir(scope, dir_differs);
- retval = true;
- } else {
+ bool dir_differs = pdir == NULL || pathcmp((char *)pdir, (char *)new_dir, -1) != 0;
+ if (dir_differs && vim_chdir(new_dir) != 0) {
emsg(_(e_failed));
xfree(pdir);
+ return false;
}
- return retval;
+ char_u **pp;
+ switch (scope) {
+ case kCdScopeTabpage:
+ pp = &curtab->tp_prevdir;
+ break;
+ case kCdScopeWindow:
+ pp = &curwin->w_prevdir;
+ break;
+ default:
+ pp = &prev_dir;
+ }
+ xfree(*pp);
+ *pp = pdir;
+
+ post_chdir(scope, dir_differs);
+
+ return true;
}
/// ":cd", ":tcd", ":lcd", ":chdir", "tchdir" and ":lchdir".
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index d3641032ab..5d8a8ddbfe 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -2304,6 +2304,10 @@ static int vgetorpeek(bool advance)
c = ESC;
}
tc = c;
+
+ // no chars to block abbreviations for
+ typebuf.tb_no_abbr_cnt = 0;
+
break;
}
diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c
index 3050ca02de..83a6ccf38f 100644
--- a/src/nvim/highlight.c
+++ b/src/nvim/highlight.c
@@ -144,13 +144,19 @@ int hl_get_syn_attr(int ns_id, int idx, HlAttrs at_en)
}
}
-void ns_hl_def(NS ns_id, int hl_id, HlAttrs attrs, int link_id)
+void ns_hl_def(NS ns_id, int hl_id, HlAttrs attrs, int link_id, HlAttrNames *names)
{
- DecorProvider *p = get_decor_provider(ns_id, true);
if ((attrs.rgb_ae_attr & HL_DEFAULT)
&& map_has(ColorKey, ColorItem)(&ns_hl, ColorKey(ns_id, hl_id))) {
return;
}
+ if (ns_id == 0) {
+ assert(names);
+ // set in global (':highlight') namespace
+ set_hl_group(hl_id, attrs, names, link_id);
+ return;
+ }
+ DecorProvider *p = get_decor_provider(ns_id, true);
int attr_id = link_id > 0 ? -1 : hl_get_syn_attr(ns_id, hl_id, attrs);
ColorItem it = { .attr_id = attr_id,
.link_id = link_id,
@@ -194,7 +200,7 @@ int ns_get_hl(NS ns_id, int hl_id, bool link, bool nodefault)
if (ret.type == kObjectTypeDictionary) {
Dictionary dict = ret.data.dictionary;
fallback = false;
- attrs = dict2hlattrs(dict, true, &it.link_id, &err);
+ attrs = dict2hlattrs(dict, true, &it.link_id, NULL, &err);
for (size_t i = 0; i < dict.size; i++) {
char *key = dict.items[i].key.data;
Object val = dict.items[i].value;
@@ -796,7 +802,7 @@ Dictionary hlattrs2dict(HlAttrs ae, bool use_rgb)
return hl;
}
-HlAttrs dict2hlattrs(Dictionary dict, bool use_rgb, int *link_id, Error *err)
+HlAttrs dict2hlattrs(Dictionary dict, bool use_rgb, int *link_id, HlAttrNames *names, Error *err)
{
HlAttrs hlattrs = HLATTRS_INIT;
@@ -820,7 +826,7 @@ HlAttrs dict2hlattrs(Dictionary dict, bool use_rgb, int *link_id, Error *err)
{ "italic", HL_ITALIC },
{ "reverse", HL_INVERSE },
{ "default", HL_DEFAULT },
- { "global", HL_GLOBAL },
+ // { "global", HL_GLOBAL },
{ NULL, 0 },
};
@@ -857,13 +863,14 @@ HlAttrs dict2hlattrs(Dictionary dict, bool use_rgb, int *link_id, Error *err)
const char *name;
const char *shortname;
int *dest;
+ char **dest_name;
} colors[] = {
- { "foreground", "fg", &fg },
- { "background", "bg", &bg },
- { "ctermfg", NULL, &ctermfg },
- { "ctermbg", NULL, &ctermbg },
- { "special", "sp", &sp },
- { NULL, NULL, NULL },
+ { "foreground", "fg", &fg, names ? &names->fg_name : NULL },
+ { "background", "bg", &bg, names ? &names->bg_name : NULL },
+ { "ctermfg", NULL, &ctermfg, NULL },
+ { "ctermbg", NULL, &ctermbg, NULL },
+ { "special", "sp", &sp, names ? &names->sp_name : NULL },
+ { NULL, NULL, NULL, NULL },
};
int k;
@@ -876,6 +883,9 @@ HlAttrs dict2hlattrs(Dictionary dict, bool use_rgb, int *link_id, Error *err)
// TODO(bfredl): be more fancy with "bg", "fg" etc
if (str.size) {
*colors[k].dest = name_to_color(str.data);
+ if (colors[k].dest_name) {
+ *colors[k].dest_name = str.data;
+ }
}
} else {
api_set_error(err, kErrorTypeValidation,
diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h
index 50a03e0c02..65374782b6 100644
--- a/src/nvim/highlight_defs.h
+++ b/src/nvim/highlight_defs.h
@@ -46,6 +46,18 @@ typedef struct attr_entry {
.hl_blend = -1, \
}
+typedef struct {
+ char *bg_name;
+ char *fg_name;
+ char *sp_name;
+} HlAttrNames;
+
+#define HLATTRNAMES_INIT (HlAttrNames) { \
+ .bg_name = NULL, \
+ .fg_name = NULL, \
+ .sp_name = NULL, \
+}
+
/// Values for index in highlight_attr[].
/// When making changes, also update hlf_names below!
typedef enum {
diff --git a/src/nvim/macros.h b/src/nvim/macros.h
index c2b2c89abf..d5611f587b 100644
--- a/src/nvim/macros.h
+++ b/src/nvim/macros.h
@@ -105,6 +105,9 @@
#define MB_PTR_BACK(s, p) \
(p -= utf_head_off((char_u *)s, (char_u *)p - 1) + 1)
+// MB_CHAR2BYTES(): convert character to bytes and advance pointer to bytes
+#define MB_CHAR2BYTES(c, b) ((b) += utf_char2bytes((c), (b)))
+
#define RESET_BINDING(wp) \
do { \
(wp)->w_p_scb = false; \
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index af023d6785..56a658ec6d 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -1981,7 +1981,7 @@ static size_t fill_foldcolumn(char_u *p, win_T *wp, foldinfo_T foldinfo, linenr_
level = foldinfo.fi_level;
// If the column is too narrow, we start at the lowest level that
- // fits and use numbers to indicated the depth.
+ // fits and use numbers to indicate the depth.
first_level = level - fdc - closed + 1;
if (first_level < 1) {
first_level = 1;
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index a9447165c2..b383b290ba 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -6714,6 +6714,90 @@ int lookup_color(const int idx, const bool foreground, TriState *const boldp)
return color;
}
+void set_hl_group(int id, HlAttrs attrs, HlAttrNames *names, int link_id)
+{
+ int idx = id - 1; // Index is ID minus one.
+
+ bool is_default = attrs.rgb_ae_attr & HL_DEFAULT;
+
+ // Return if "default" was used and the group already has settings
+ if (is_default && hl_has_settings(idx, true)) {
+ return;
+ }
+
+ HlGroup *g = &HL_TABLE()[idx];
+
+ if (link_id > 0) {
+ g->sg_cleared = false;
+ g->sg_link = link_id;
+ g->sg_script_ctx = current_sctx;
+ g->sg_script_ctx.sc_lnum += sourcing_lnum;
+ g->sg_set |= SG_LINK;
+ if (is_default) {
+ g->sg_deflink = link_id;
+ g->sg_deflink_sctx = current_sctx;
+ g->sg_deflink_sctx.sc_lnum += sourcing_lnum;
+ }
+ return;
+ }
+
+ g->sg_cleared = false;
+ g->sg_link = 0;
+ g->sg_gui = attrs.rgb_ae_attr;
+
+ g->sg_rgb_fg = attrs.rgb_fg_color;
+ g->sg_rgb_bg = attrs.rgb_bg_color;
+ g->sg_rgb_sp = attrs.rgb_sp_color;
+
+ struct {
+ char **dest; RgbValue val; char *name;
+ } cattrs[] = {
+ { &g->sg_rgb_fg_name, g->sg_rgb_fg, names->fg_name },
+ { &g->sg_rgb_bg_name, g->sg_rgb_bg, names->bg_name },
+ { &g->sg_rgb_sp_name, g->sg_rgb_sp, names->sp_name },
+ { NULL, -1, NULL },
+ };
+
+ for (int j = 0; cattrs[j].dest; j++) {
+ if (cattrs[j].val != -1) {
+ xfree(*cattrs[j].dest);
+ if (cattrs[j].name) {
+ *cattrs[j].dest = xstrdup(cattrs[j].name);
+ } else {
+ char hex_name[8];
+ snprintf(hex_name, sizeof(hex_name), "#%06x", cattrs[j].val);
+ *cattrs[j].dest = xstrdup(hex_name);
+ }
+ }
+ }
+
+ g->sg_cterm = attrs.cterm_ae_attr;
+ g->sg_cterm_bg = attrs.cterm_bg_color;
+ g->sg_cterm_fg = attrs.cterm_fg_color;
+ g->sg_cterm_bold = g->sg_cterm & HL_BOLD;
+ g->sg_blend = attrs.hl_blend;
+
+ g->sg_script_ctx = current_sctx;
+ g->sg_script_ctx.sc_lnum += sourcing_lnum;
+
+ // 'Normal' is special
+ if (STRCMP(g->sg_name_u, "NORMAL") == 0) {
+ cterm_normal_fg_color = g->sg_cterm_fg;
+ cterm_normal_bg_color = g->sg_cterm_bg;
+ normal_fg = g->sg_rgb_fg;
+ normal_bg = g->sg_rgb_bg;
+ normal_sp = g->sg_rgb_sp;
+ ui_default_colors_set();
+ } else {
+ g->sg_attr = hl_get_syn_attr(0, id, attrs);
+
+ // a cursor style uses this syn_id, make sure its attribute is updated.
+ if (cursor_mode_uses_syn_id(id)) {
+ ui_mode_info_set();
+ }
+ }
+}
+
/// Handle ":highlight" command
///
diff --git a/src/nvim/testdir/test_feedkeys.vim b/src/nvim/testdir/test_feedkeys.vim
index 70500f2bb5..f343b0174c 100644
--- a/src/nvim/testdir/test_feedkeys.vim
+++ b/src/nvim/testdir/test_feedkeys.vim
@@ -12,3 +12,15 @@ func Test_feedkeys_x_with_empty_string()
call assert_equal('foo', getline('.'))
quit!
endfunc
+
+func Test_feedkeys_with_abbreviation()
+ new
+ inoreabbrev trigger value
+ call feedkeys("atrigger ", 'x')
+ call feedkeys("atrigger ", 'x')
+ call assert_equal('value value ', getline(1))
+ bwipe!
+ iunabbrev trigger
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_statusline.vim b/src/nvim/testdir/test_statusline.vim
index f40c9ae097..fad13e3340 100644
--- a/src/nvim/testdir/test_statusline.vim
+++ b/src/nvim/testdir/test_statusline.vim
@@ -507,5 +507,20 @@ func Test_statusline_after_split_vsplit()
set ls& stl&
endfunc
+" Test using a multibyte character for 'stl' and 'stlnc' items in 'fillchars'
+" with a custom 'statusline'
+func Test_statusline_mbyte_fillchar()
+ only
+ set laststatus=2
+ set fillchars=vert:\|,fold:-,stl:━,stlnc:═
+ set statusline=a%=b
+ call assert_match('^a\+━\+b$', s:get_statusline())
+ vnew
+ call assert_match('^a\+━\+b━a\+═\+b$', s:get_statusline())
+ wincmd w
+ call assert_match('^a\+═\+b═a\+━\+b$', s:get_statusline())
+ set statusline& fillchars& laststatus&
+ %bw!
+endfunc
" vim: shiftwidth=2 sts=2 expandtab