Merge #5928 'New event: DirChanged'

This commit is contained in:
Marco Hinz
2017-01-16 13:36:16 +01:00
committed by GitHub
12 changed files with 204 additions and 46 deletions

View File

@@ -315,7 +315,7 @@ void nvim_set_current_dir(String dir, Error *err)
try_start();
if (vim_chdir((char_u *)string)) {
if (vim_chdir((char_u *)string, kCdScopeGlobal)) {
if (!try_end(err)) {
api_set_error(err, Exception, _("Failed to change directory"));
}

View File

@@ -28,6 +28,7 @@ return {
'CursorHoldI', -- idem, in Insert mode
'CursorMoved', -- cursor was moved
'CursorMovedI', -- cursor was moved in Insert mode
'DirChanged', -- directory changed
'EncodingChanged', -- after changing the 'encoding' option
'FileAppendCmd', -- append to a file using command
'FileAppendPost', -- after appending to a file
@@ -102,6 +103,7 @@ return {
-- List of neovim-specific events or aliases for the purpose of generating
-- syntax file
neovim_specific = {
DirChanged=true,
TabClosed=true,
TabNew=true,
TabNewEntered=true,

View File

@@ -6998,8 +6998,6 @@ void post_chdir(CdScope scope)
shorten_fnames(TRUE);
}
/// `:cd`, `:tcd`, `:lcd`, `:chdir`, `:tchdir` and `:lchdir`.
void ex_cd(exarg_T *eap)
{
@@ -7041,30 +7039,31 @@ void ex_cd(exarg_T *eap)
new_dir = NameBuff;
}
#endif
if (vim_chdir(new_dir)) {
CdScope scope = kCdScopeGlobal; // Depends on command invoked
switch (eap->cmdidx) {
case CMD_tcd:
case CMD_tchdir:
scope = kCdScopeTab;
break;
case CMD_lcd:
case CMD_lchdir:
scope = kCdScopeWindow;
break;
default:
break;
}
if (vim_chdir(new_dir, scope)) {
EMSG(_(e_failed));
} else {
CdScope scope = kCdScopeGlobal; // Depends on command invoked
switch (eap->cmdidx) {
case CMD_tcd:
case CMD_tchdir:
scope = kCdScopeTab;
break;
case CMD_lcd:
case CMD_lchdir:
scope = kCdScopeWindow;
break;
default:
break;
}
post_chdir(scope);
/* Echo the new current directory if the command was typed. */
if (KeyTyped || p_verbose >= 5)
// Echo the new current directory if the command was typed.
if (KeyTyped || p_verbose >= 5) {
ex_pwd(eap);
}
}
xfree(tofree);
}
}

View File

@@ -19,21 +19,6 @@
#define EXMODE_NORMAL 1
#define EXMODE_VIM 2
/// The scope of a working-directory command like `:cd`.
///
/// Scopes are enumerated from lowest to highest. When adding a scope make sure
/// to update all functions using scopes as well, such as the implementation of
/// `getcwd()`. When using scopes as limits (e.g. in loops) don't use the scopes
/// directly, use `MIN_CD_SCOPE` and `MAX_CD_SCOPE` instead.
typedef enum {
kCdScopeInvalid = -1,
kCdScopeWindow, ///< Affects one window.
kCdScopeTab, ///< Affects one tab page.
kCdScopeGlobal, ///< Affects the entire instance of Neovim.
} CdScope;
#define MIN_CD_SCOPE kCdScopeWindow
#define MAX_CD_SCOPE kCdScopeGlobal
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ex_docmd.h.generated.h"
#endif

View File

@@ -48,6 +48,7 @@
#include <limits.h>
#include "nvim/vim.h"
#include "nvim/eval.h"
#include "nvim/ascii.h"
#include "nvim/file_search.h"
#include "nvim/charset.h"
@@ -1522,6 +1523,47 @@ theend:
return file_name;
}
static void do_autocmd_dirchanged(char_u *new_dir, CdScope scope)
{
static bool recursive = false;
if (recursive || !has_event(EVENT_DIRCHANGED)) {
// No autocommand was defined or we changed
// the directory from this autocommand.
return;
}
recursive = true;
dict_T *dict = get_vim_var_dict(VV_EVENT);
char buf[8];
switch (scope) {
case kCdScopeGlobal:
snprintf(buf, sizeof(buf), "global");
break;
case kCdScopeTab:
snprintf(buf, sizeof(buf), "tab");
break;
case kCdScopeWindow:
snprintf(buf, sizeof(buf), "window");
break;
case kCdScopeInvalid:
// Should never happen.
assert(false);
}
dict_add_nr_str(dict, "scope", 0L, (char_u *)buf);
dict_add_nr_str(dict, "cwd", 0L, new_dir);
dict_set_keys_readonly(dict);
apply_autocmds(EVENT_DIRCHANGED, NULL, new_dir, false, NULL);
dict_clear(dict);
recursive = false;
}
/// Change to a file's directory.
/// Caller must call shorten_fnames()!
/// @return OK or FAIL
@@ -1531,18 +1573,28 @@ int vim_chdirfile(char_u *fname)
STRLCPY(dir, fname, MAXPATHL);
*path_tail_with_sep(dir) = NUL;
return os_chdir((char *)dir) == 0 ? OK : FAIL;
if (os_chdir((char *)dir) != 0) {
return FAIL;
}
do_autocmd_dirchanged(dir, kCdScopeWindow);
return OK;
}
/// Change directory to "new_dir". Search 'cdpath' for relative directory names.
int vim_chdir(char_u *new_dir)
int vim_chdir(char_u *new_dir, CdScope scope)
{
char_u *dir_name = find_directory_in_path(new_dir, STRLEN(new_dir),
FNAME_MESS, curbuf->b_ffname);
if (dir_name == NULL) {
return -1;
}
int r = os_chdir((char *)dir_name);
if (r == 0) {
do_autocmd_dirchanged(dir_name, scope);
}
xfree(dir_name);
return r;
}

View File

@@ -6765,8 +6765,9 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io,
fname = vim_strsave(fname); /* make a copy, so we can change it */
} else {
sfname = vim_strsave(fname);
// don't try expanding the following events
// Don't try expanding the following events.
if (event == EVENT_COLORSCHEME
|| event == EVENT_DIRCHANGED
|| event == EVENT_FILETYPE
|| event == EVENT_FUNCUNDEFINED
|| event == EVENT_OPTIONSET
@@ -6775,10 +6776,11 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io,
|| event == EVENT_REMOTEREPLY
|| event == EVENT_SPELLFILEMISSING
|| event == EVENT_SYNTAX
|| event == EVENT_TABCLOSED)
|| event == EVENT_TABCLOSED) {
fname = vim_strsave(fname);
else
fname = (char_u *)FullName_save((char *)fname, FALSE);
} else {
fname = (char_u *)FullName_save((char *)fname, false);
}
}
if (fname == NULL) { /* out of memory */
xfree(sfname);

View File

@@ -1249,4 +1249,20 @@ typedef enum {
kBroken
} WorkingStatus;
/// The scope of a working-directory command like `:cd`.
///
/// Scopes are enumerated from lowest to highest. When adding a scope make sure
/// to update all functions using scopes as well, such as the implementation of
/// `getcwd()`. When using scopes as limits (e.g. in loops) don't use the scopes
/// directly, use `MIN_CD_SCOPE` and `MAX_CD_SCOPE` instead.
typedef enum {
kCdScopeInvalid = -1,
kCdScopeWindow, ///< Affects one window.
kCdScopeTab, ///< Affects one tab page.
kCdScopeGlobal, ///< Affects the entire instance of Neovim.
} CdScope;
#define MIN_CD_SCOPE kCdScopeWindow
#define MAX_CD_SCOPE kCdScopeGlobal
#endif /* NVIM_GLOBALS_H */

View File

@@ -1404,7 +1404,7 @@ int op_delete(oparg_T *oap)
if (oap->regname == 0) {
set_clipboard(0, reg);
yank_do_autocmd(oap, reg);
do_autocmd_textyankpost(oap, reg);
}
}
@@ -2315,7 +2315,7 @@ bool op_yank(oparg_T *oap, bool message)
yankreg_T *reg = get_yank_register(oap->regname, YREG_YANK);
op_yank_reg(oap, message, reg, is_append_register(oap->regname));
set_clipboard(oap->regname, reg);
yank_do_autocmd(oap, reg);
do_autocmd_textyankpost(oap, reg);
return true;
}
@@ -2538,7 +2538,7 @@ static void yank_copy_line(yankreg_T *reg, struct block_def *bd, size_t y_idx)
///
/// @param oap Operator arguments.
/// @param reg The yank register used.
static void yank_do_autocmd(oparg_T *oap, yankreg_T *reg)
static void do_autocmd_textyankpost(oparg_T *oap, yankreg_T *reg)
FUNC_ATTR_NONNULL_ALL
{
static bool recursive = false;

View File

@@ -14,4 +14,5 @@ typedef unsigned char char_u;
typedef uint32_t u8char_T;
typedef struct expand expand_T;
#endif // NVIM_TYPES_H