aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/auevents.lua5
-rw-r--r--src/nvim/autocmd.c13
-rw-r--r--src/nvim/ex_docmd.c15
-rw-r--r--src/nvim/file_search.c21
-rw-r--r--src/nvim/getchar.c17
-rw-r--r--src/nvim/highlight.c45
-rw-r--r--src/nvim/syntax.c42
-rw-r--r--src/nvim/testdir/test_autocmd.vim20
-rw-r--r--src/nvim/testdir/test_filetype.vim1
-rw-r--r--src/nvim/window.c23
10 files changed, 131 insertions, 71 deletions
diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua
index 8fe623fc96..518d0b52b2 100644
--- a/src/nvim/auevents.lua
+++ b/src/nvim/auevents.lua
@@ -40,6 +40,7 @@ return {
'DiagnosticChanged', -- diagnostics in a buffer were modified
'DiffUpdated', -- diffs have been updated
'DirChanged', -- directory changed
+ 'DirChangedPre', -- directory is going to change
'EncodingChanged', -- after changing the 'encoding' option
'ExitPre', -- before exiting
'FileAppendCmd', -- append to a file using command
@@ -132,18 +133,14 @@ return {
nvim_specific = {
BufModifiedSet=true,
DiagnosticChanged=true,
- DirChanged=true,
RecordingEnter=true,
RecordingLeave=true,
Signal=true,
- TabClosed=true,
- TabNew=true,
TabNewEntered=true,
TermClose=true,
TermOpen=true,
UIEnter=true,
UILeave=true,
- WinClosed=true,
WinScrolled=true,
},
}
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c
index dfba18b11d..9117dde089 100644
--- a/src/nvim/autocmd.c
+++ b/src/nvim/autocmd.c
@@ -1517,12 +1517,13 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io,
|| event == EVENT_CMDLINELEAVE || event == EVENT_CMDWINENTER
|| event == EVENT_CMDWINLEAVE || event == EVENT_CMDUNDEFINED
|| event == EVENT_COLORSCHEME || event == EVENT_COLORSCHEMEPRE
- || event == EVENT_DIRCHANGED || event == EVENT_FILETYPE
- || event == EVENT_FUNCUNDEFINED || event == EVENT_MODECHANGED
- || event == EVENT_OPTIONSET || event == EVENT_QUICKFIXCMDPOST
- || event == EVENT_QUICKFIXCMDPRE || event == EVENT_REMOTEREPLY
- || event == EVENT_SPELLFILEMISSING || event == EVENT_SYNTAX
- || event == EVENT_SIGNAL || event == EVENT_TABCLOSED
+ || event == EVENT_DIRCHANGED || event == EVENT_DIRCHANGEDPRE
+ || event == EVENT_FILETYPE || event == EVENT_FUNCUNDEFINED
+ || event == EVENT_MODECHANGED || event == EVENT_OPTIONSET
+ || event == EVENT_QUICKFIXCMDPOST || event == EVENT_QUICKFIXCMDPRE
+ || event == EVENT_REMOTEREPLY || event == EVENT_SPELLFILEMISSING
+ || event == EVENT_SYNTAX || event == EVENT_SIGNAL
+ || event == EVENT_TABCLOSED || event == EVENT_USER
|| event == EVENT_WINCLOSED) {
fname = vim_strsave(fname);
} else {
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 87f8865133..9991584862 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -7797,7 +7797,7 @@ static char_u *get_prevdir(CdScope scope)
/// Deal with the side effects of changing the current directory.
///
/// @param scope Scope of the function call (global, tab or window).
-void post_chdir(CdScope scope, bool trigger_dirchanged)
+static void post_chdir(CdScope scope, bool trigger_dirchanged)
{
// Always overwrite the window-local CWD.
XFREE_CLEAR(curwin->w_localdir);
@@ -7838,7 +7838,7 @@ void post_chdir(CdScope scope, bool trigger_dirchanged)
shorten_fnames(true);
if (trigger_dirchanged) {
- do_autocmd_dirchanged(cwd, scope, kCdCauseManual);
+ do_autocmd_dirchanged(cwd, scope, kCdCauseManual, false);
}
}
@@ -7882,10 +7882,13 @@ bool changedir_func(char_u *new_dir, CdScope scope)
}
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;
+ if (dir_differs) {
+ do_autocmd_dirchanged((char *)new_dir, scope, kCdCauseManual, true);
+ if (vim_chdir(new_dir) != 0) {
+ emsg(_(e_failed));
+ xfree(pdir);
+ return false;
+ }
}
char_u **pp;
diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c
index 25dbf680de..d0f7a91d6c 100644
--- a/src/nvim/file_search.c
+++ b/src/nvim/file_search.c
@@ -1600,11 +1600,13 @@ theend:
return file_name;
}
-void do_autocmd_dirchanged(char *new_dir, CdScope scope, CdCause cause)
+void do_autocmd_dirchanged(char *new_dir, CdScope scope, CdCause cause, bool pre)
{
static bool recursive = false;
- if (recursive || !has_event(EVENT_DIRCHANGED)) {
+ event_T event = pre ? EVENT_DIRCHANGEDPRE : EVENT_DIRCHANGED;
+
+ if (recursive || !has_event(event)) {
// No autocommand was defined or we changed
// the directory from this autocommand.
return;
@@ -1638,8 +1640,12 @@ void do_autocmd_dirchanged(char *new_dir, CdScope scope, CdCause cause)
new_dir = new_dir_buf;
#endif
+ if (pre) {
+ tv_dict_add_str(dict, S_LEN("directory"), new_dir);
+ } else {
+ tv_dict_add_str(dict, S_LEN("cwd"), new_dir);
+ }
tv_dict_add_str(dict, S_LEN("scope"), buf); // -V614
- tv_dict_add_str(dict, S_LEN("cwd"), new_dir);
tv_dict_add_bool(dict, S_LEN("changed_window"), cause == kCdCauseWindow);
tv_dict_set_keys_readonly(dict);
@@ -1655,8 +1661,7 @@ void do_autocmd_dirchanged(char *new_dir, CdScope scope, CdCause cause)
abort();
}
- apply_autocmds(EVENT_DIRCHANGED, (char_u *)buf, (char_u *)new_dir, false,
- curbuf);
+ apply_autocmds(event, (char_u *)buf, (char_u *)new_dir, false, curbuf);
restore_v_event(dict, &save_v_event);
@@ -1682,12 +1687,16 @@ int vim_chdirfile(char_u *fname, CdCause cause)
return OK;
}
+ if (cause != kCdCauseOther) {
+ do_autocmd_dirchanged(dir, kCdScopeWindow, cause, true);
+ }
+
if (os_chdir(dir) != 0) {
return FAIL;
}
if (cause != kCdCauseOther) {
- do_autocmd_dirchanged(dir, kCdScopeWindow, cause);
+ do_autocmd_dirchanged(dir, kCdScopeWindow, cause, false);
}
return OK;
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 6978823f2b..741fc6d803 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -1004,20 +1004,9 @@ int ins_char_typebuf(int c, int modifier)
buf[len + 2] = (char_u)K_THIRD(c);
buf[len + 3] = NUL;
} else {
- char_u *p = buf + len;
- int char_len = utf_char2bytes(c, p);
- len += char_len;
- // If the character contains K_SPECIAL bytes they need escaping.
- for (int i = char_len; --i >= 0; p++) {
- if ((uint8_t)(*p) == K_SPECIAL) {
- memmove(p + 3, p + 1, (size_t)i);
- *p++ = K_SPECIAL;
- *p++ = KS_SPECIAL;
- *p = KE_FILLER;
- len += 2;
- }
- }
- *p = NUL;
+ char_u *end = add_char2buf(c, buf + len);
+ *end = NUL;
+ len = (int)(end - buf);
}
(void)ins_typebuf(buf, KeyNoremap, 0, !KeyTyped, cmd_silent);
return len;
diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c
index fcd91cdf16..8b998ff62e 100644
--- a/src/nvim/highlight.c
+++ b/src/nvim/highlight.c
@@ -821,27 +821,27 @@ HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *e
CHECK_FLAG(dict, mask, global, , HL_GLOBAL);
if (HAS_KEY(dict->fg)) {
- fg = object_to_color(dict->fg, "fg", err);
+ fg = object_to_color(dict->fg, "fg", true, err);
} else if (HAS_KEY(dict->foreground)) {
- fg = object_to_color(dict->foreground, "foreground", err);
+ fg = object_to_color(dict->foreground, "foreground", true, err);
}
if (ERROR_SET(err)) {
return hlattrs;
}
if (HAS_KEY(dict->bg)) {
- bg = object_to_color(dict->bg, "bg", err);
+ bg = object_to_color(dict->bg, "bg", true, err);
} else if (HAS_KEY(dict->background)) {
- bg = object_to_color(dict->background, "background", err);
+ bg = object_to_color(dict->background, "background", true, err);
}
if (ERROR_SET(err)) {
return hlattrs;
}
if (HAS_KEY(dict->sp)) {
- sp = object_to_color(dict->sp, "sp", err);
+ sp = object_to_color(dict->sp, "sp", true, err);
} else if (HAS_KEY(dict->special)) {
- sp = object_to_color(dict->special, "special", err);
+ sp = object_to_color(dict->special, "special", true, err);
}
if (ERROR_SET(err)) {
return hlattrs;
@@ -876,20 +876,24 @@ HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *e
CHECK_FLAG(cterm, cterm_mask, strikethrough, , HL_STRIKETHROUGH);
CHECK_FLAG(cterm, cterm_mask, nocombine, , HL_NOCOMBINE);
+ } else if (dict->cterm.type == kObjectTypeArray && dict->cterm.data.array.size == 0) {
+ // empty list from Lua API should clear all cterm attributes
+ // TODO(clason): handle via gen_api_dispatch
+ cterm_mask_provided = true;
} else if (HAS_KEY(dict->cterm)) {
api_set_error(err, kErrorTypeValidation, "'cterm' must be a Dictionary.");
}
#undef CHECK_FLAG
if (HAS_KEY(dict->ctermfg)) {
- ctermfg = object_to_color(dict->ctermfg, "ctermfg", err);
+ ctermfg = object_to_color(dict->ctermfg, "ctermfg", false, err);
if (ERROR_SET(err)) {
return hlattrs;
}
}
if (HAS_KEY(dict->ctermbg)) {
- ctermbg = object_to_color(dict->ctermbg, "ctermbg", err);
+ ctermbg = object_to_color(dict->ctermbg, "ctermbg", false, err);
if (ERROR_SET(err)) {
return hlattrs;
}
@@ -904,28 +908,37 @@ HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *e
hlattrs.rgb_bg_color = bg;
hlattrs.rgb_fg_color = fg;
hlattrs.rgb_sp_color = sp;
- hlattrs.cterm_bg_color =
- ctermbg == -1 ? cterm_normal_bg_color : ctermbg + 1;
- hlattrs.cterm_fg_color =
- ctermfg == -1 ? cterm_normal_fg_color : ctermfg + 1;
+ hlattrs.cterm_bg_color = ctermbg == -1 ? 0 : ctermbg + 1;
+ hlattrs.cterm_fg_color = ctermfg == -1 ? 0 : ctermfg + 1;
hlattrs.cterm_ae_attr = cterm_mask;
} else {
hlattrs.cterm_ae_attr = cterm_mask;
- hlattrs.cterm_bg_color = bg == -1 ? cterm_normal_bg_color : bg + 1;
- hlattrs.cterm_fg_color = fg == -1 ? cterm_normal_fg_color : fg + 1;
+ hlattrs.cterm_bg_color = bg == -1 ? 0 : bg + 1;
+ hlattrs.cterm_fg_color = fg == -1 ? 0 : fg + 1;
}
return hlattrs;
}
-int object_to_color(Object val, char *key, Error *err)
+int object_to_color(Object val, char *key, bool rgb, Error *err)
{
if (val.type == kObjectTypeInteger) {
return (int)val.data.integer;
} else if (val.type == kObjectTypeString) {
String str = val.data.string;
// TODO(bfredl): be more fancy with "bg", "fg" etc
- return str.size ? name_to_color(str.data) : 0;
+ int color;
+ if (!str.size) {
+ color = 0;
+ } else if (rgb) {
+ color = name_to_color(str.data);
+ } else {
+ color = name_to_ctermcolor(str.data);
+ }
+ if (color < 0) {
+ api_set_error(err, kErrorTypeValidation, "'%s' is not a valid color", str.data);
+ }
+ return color;
} else {
api_set_error(err, kErrorTypeValidation, "'%s' must be string or integer", key);
return 0;
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index 119f6e811f..2b74c45478 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -6758,16 +6758,26 @@ void set_hl_group(int id, HlAttrs attrs, Dict(highlight) *dict, int link_id)
{ NULL, -1, NIL },
};
+ char hex_name[8];
+ char *name;
+
for (int j = 0; cattrs[j].dest; j++) {
- if (cattrs[j].val != -1) {
+ if (cattrs[j].val < 0) {
+ XFREE_CLEAR(*cattrs[j].dest);
+ continue;
+ }
+
+ if (cattrs[j].name.type == kObjectTypeString && cattrs[j].name.data.string.size) {
+ name = cattrs[j].name.data.string.data;
+ } else {
+ snprintf(hex_name, sizeof(hex_name), "#%06x", cattrs[j].val);
+ name = hex_name;
+ }
+
+ if (!*cattrs[j].dest
+ || STRCMP(*cattrs[j].dest, name) != 0) {
xfree(*cattrs[j].dest);
- if (cattrs[j].name.type == kObjectTypeString && cattrs[j].name.data.string.size) {
- *cattrs[j].dest = xstrdup(cattrs[j].name.data.string.data);
- } else {
- char hex_name[8];
- snprintf(hex_name, sizeof(hex_name), "#%06x", cattrs[j].val);
- *cattrs[j].dest = xstrdup(hex_name);
- }
+ *cattrs[j].dest = xstrdup(name);
}
}
@@ -8849,6 +8859,22 @@ RgbValue name_to_color(const char *name)
return -1;
}
+int name_to_ctermcolor(const char *name)
+{
+ int i;
+ int off = TOUPPER_ASC(*name);
+ for (i = ARRAY_SIZE(color_names); --i >= 0;) {
+ if (off == color_names[i][0]
+ && STRICMP(name+1, color_names[i]+1) == 0) {
+ break;
+ }
+ }
+ if (i < 0) {
+ return -1;
+ }
+ TriState bold = kNone;
+ return lookup_color(i, false, &bold);
+}
/**************************************
* End of Highlighting stuff *
diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim
index a8d51ef598..0146c06109 100644
--- a/src/nvim/testdir/test_autocmd.vim
+++ b/src/nvim/testdir/test_autocmd.vim
@@ -1827,6 +1827,14 @@ func Test_autocommand_all_events()
call assert_fails('au * x bwipe', 'E1155:')
endfunc
+func Test_autocmd_user()
+ au User MyEvent let s:res = [expand("<afile>"), expand("<amatch>")]
+ doautocmd User MyEvent
+ call assert_equal(['MyEvent', 'MyEvent'], s:res)
+ au! User
+ unlet s:res
+endfunc
+
function s:Before_test_dirchanged()
augroup test_dirchanged
autocmd!
@@ -1850,14 +1858,16 @@ endfunc
function Test_dirchanged_global()
call s:Before_test_dirchanged()
+ autocmd test_dirchanged DirChangedPre global call add(s:li, expand("<amatch>") .. " pre cd " .. v:event.directory)
autocmd test_dirchanged DirChanged global call add(s:li, "cd:")
autocmd test_dirchanged DirChanged global call add(s:li, expand("<afile>"))
call chdir(s:dir_foo)
- call assert_equal(["cd:", s:dir_foo], s:li)
+ let expected = ["global pre cd " .. s:dir_foo, "cd:", s:dir_foo]
+ call assert_equal(expected, s:li)
call chdir(s:dir_foo)
- call assert_equal(["cd:", s:dir_foo], s:li)
+ call assert_equal(expected, s:li)
exe 'lcd ' .. fnameescape(s:dir_bar)
- call assert_equal(["cd:", s:dir_foo], s:li)
+ call assert_equal(expected, s:li)
call s:After_test_dirchanged()
endfunc
@@ -1879,6 +1889,7 @@ function Test_dirchanged_auto()
CheckOption autochdir
call s:Before_test_dirchanged()
call test_autochdir()
+ autocmd test_dirchanged DirChangedPre auto call add(s:li, "pre cd " .. v:event.directory)
autocmd test_dirchanged DirChanged auto call add(s:li, "auto:")
autocmd test_dirchanged DirChanged auto call add(s:li, expand("<afile>"))
set acd
@@ -1886,7 +1897,8 @@ function Test_dirchanged_auto()
call assert_equal([], s:li)
exe 'edit ' . s:dir_foo . '/Xfile'
call assert_equal(s:dir_foo, getcwd())
- call assert_equal(["auto:", s:dir_foo], s:li)
+ let expected = ["pre cd " .. s:dir_foo, "auto:", s:dir_foo]
+ call assert_equal(expected, s:li)
set noacd
bwipe!
call s:After_test_dirchanged()
diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim
index b663032c24..dd14aa3e6f 100644
--- a/src/nvim/testdir/test_filetype.vim
+++ b/src/nvim/testdir/test_filetype.vim
@@ -81,6 +81,7 @@ let s:filename_checks = {
\ 'bc': ['file.bc'],
\ 'bdf': ['file.bdf'],
\ 'bib': ['file.bib'],
+ \ 'bicep': ['file.bicep'],
\ 'beancount': ['file.beancount'],
\ 'bindzone': ['named.root', '/bind/db.file', '/named/db.file', 'any/bind/db.file', 'any/named/db.file'],
\ 'blank': ['file.bl'],
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 1e737d2083..43667377c5 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -4688,20 +4688,29 @@ void fix_current_dir(void)
globaldir = (char_u *)xstrdup(cwd);
}
}
+ bool dir_differs = pathcmp(new_dir, cwd, -1) != 0;
+ if (!p_acd && dir_differs) {
+ do_autocmd_dirchanged(new_dir, curwin->w_localdir ? kCdScopeWindow : kCdScopeTabpage,
+ kCdCauseWindow, true);
+ }
if (os_chdir(new_dir) == 0) {
- if (!p_acd && pathcmp(new_dir, cwd, -1) != 0) {
- do_autocmd_dirchanged(new_dir, curwin->w_localdir
- ? kCdScopeWindow : kCdScopeTabpage, kCdCauseWindow);
+ if (!p_acd && dir_differs) {
+ do_autocmd_dirchanged(new_dir, curwin->w_localdir ? kCdScopeWindow : kCdScopeTabpage,
+ kCdCauseWindow, false);
}
- last_chdir_reason = NULL;
- shorten_fnames(true);
}
+ last_chdir_reason = NULL;
+ shorten_fnames(true);
} else if (globaldir != NULL) {
// Window doesn't have a local directory and we are not in the global
// directory: Change to the global directory.
+ bool dir_differs = pathcmp((char *)globaldir, cwd, -1) != 0;
+ if (!p_acd && dir_differs) {
+ do_autocmd_dirchanged((char *)globaldir, kCdScopeGlobal, kCdCauseWindow, true);
+ }
if (os_chdir((char *)globaldir) == 0) {
- if (!p_acd && pathcmp((char *)globaldir, cwd, -1) != 0) {
- do_autocmd_dirchanged((char *)globaldir, kCdScopeGlobal, kCdCauseWindow);
+ if (!p_acd && dir_differs) {
+ do_autocmd_dirchanged((char *)globaldir, kCdScopeGlobal, kCdCauseWindow, false);
}
}
XFREE_CLEAR(globaldir);