diff options
-rw-r--r-- | src/nvim/buffer.h | 56 | ||||
-rw-r--r-- | src/nvim/ex_cmds.c | 18 | ||||
-rw-r--r-- | src/nvim/globals.h | 22 | ||||
-rw-r--r-- | src/nvim/main.c | 20 | ||||
-rw-r--r-- | src/nvim/memory.c | 2 | ||||
-rw-r--r-- | src/nvim/quickfix.c | 6 | ||||
-rw-r--r-- | src/nvim/tempfile.c | 6 | ||||
-rw-r--r-- | src/nvim/vim.h | 12 | ||||
-rw-r--r-- | test/unit/buffer_spec.lua | 216 | ||||
-rw-r--r-- | test/unit/fileio_spec.lua | 83 | ||||
-rw-r--r-- | test/unit/tempfile_spec.lua | 5 |
11 files changed, 375 insertions, 71 deletions
diff --git a/src/nvim/buffer.h b/src/nvim/buffer.h index a8220c65a0..a7f4feb342 100644 --- a/src/nvim/buffer.h +++ b/src/nvim/buffer.h @@ -4,33 +4,43 @@ #include "nvim/pos.h" // for linenr_T #include "nvim/ex_cmds_defs.h" // for exarg_T -/* Values for buflist_getfile() */ -#define GETF_SETMARK 0x01 /* set pcmark before jumping */ -#define GETF_ALT 0x02 /* jumping to alternate file (not buf num) */ -#define GETF_SWITCH 0x04 /* respect 'switchbuf' settings when jumping */ +// Values for buflist_getfile() +enum getf_values { + GETF_SETMARK = 0x01, // set pcmark before jumping + GETF_ALT = 0x02, // jumping to alternate file (not buf num) + GETF_SWITCH = 0x04, // respect 'switchbuf' settings when jumping +}; -/* Values for buflist_new() flags */ -#define BLN_CURBUF 1 /* May re-use curbuf for new buffer */ -#define BLN_LISTED 2 /* Put new buffer in buffer list */ -#define BLN_DUMMY 4 /* Allocating dummy buffer */ +// Values for buflist_new() flags +enum bln_values { + BLN_CURBUF = 1, // May re-use curbuf for new buffer + BLN_LISTED = 2, // Put new buffer in buffer list + BLN_DUMMY = 4, // Allocating dummy buffer +}; -/* Values for action argument for do_buffer() */ -#define DOBUF_GOTO 0 /* go to specified buffer */ -#define DOBUF_SPLIT 1 /* split window and go to specified buffer */ -#define DOBUF_UNLOAD 2 /* unload specified buffer(s) */ -#define DOBUF_DEL 3 /* delete specified buffer(s) from buflist */ -#define DOBUF_WIPE 4 /* delete specified buffer(s) really */ +// Values for action argument for do_buffer() +enum dobuf_action_values { + DOBUF_GOTO = 0, // go to specified buffer + DOBUF_SPLIT = 1, // split window and go to specified buffer + DOBUF_UNLOAD = 2, // unload specified buffer(s) + DOBUF_DEL = 3, // delete specified buffer(s) from buflist + DOBUF_WIPE = 4, // delete specified buffer(s) really +}; -/* Values for start argument for do_buffer() */ -#define DOBUF_CURRENT 0 /* "count" buffer from current buffer */ -#define DOBUF_FIRST 1 /* "count" buffer from first buffer */ -#define DOBUF_LAST 2 /* "count" buffer from last buffer */ -#define DOBUF_MOD 3 /* "count" mod. buffer from current buffer */ +// Values for start argument for do_buffer() +enum dobuf_start_values { + DOBUF_CURRENT = 0, // "count" buffer from current buffer + DOBUF_FIRST = 1, // "count" buffer from first buffer + DOBUF_LAST = 2, // "count" buffer from last buffer + DOBUF_MOD = 3, // "count" mod. buffer from current buffer +}; -/* flags for buf_freeall() */ -#define BFA_DEL 1 /* buffer is going to be deleted */ -#define BFA_WIPE 2 /* buffer is going to be wiped out */ -#define BFA_KEEP_UNDO 4 /* do not free undo information */ +// flags for buf_freeall() +enum bfa_values { + BFA_DEL = 1, // buffer is going to be deleted + BFA_WIPE = 2, // buffer is going to be wiped out + BFA_KEEP_UNDO = 4, // do not free undo information +}; #ifdef INCLUDE_GENERATED_DECLARATIONS # include "buffer.h.generated.h" diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 384eebe556..c516b24236 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -5156,7 +5156,11 @@ void fix_help_buffer(void) /* Find all "doc/ *.txt" files in this directory. */ add_pathsep(NameBuff); STRCAT(NameBuff, "doc/*.??[tx]"); - if (gen_expand_wildcards(1, &NameBuff, &fcount, + + // Note: We cannot just do `&NameBuff` because it is a statically sized array + // so `NameBuff == &NameBuff` according to C semantics. + char_u *buff_list[1] = {(char_u*) NameBuff}; + if (gen_expand_wildcards(1, buff_list, &fcount, &fnames, EW_FILE|EW_SILENT) == OK && fcount > 0) { int i1; @@ -5324,7 +5328,11 @@ void ex_helptags(exarg_T *eap) STRCPY(NameBuff, dirname); add_pathsep(NameBuff); STRCAT(NameBuff, "**"); - if (gen_expand_wildcards(1, &NameBuff, &filecount, &files, + + // Note: We cannot just do `&NameBuff` because it is a statically sized array + // so `NameBuff == &NameBuff` according to C semantics. + char_u *buff_list[1] = {(char_u*) NameBuff}; + if (gen_expand_wildcards(1, buff_list, &filecount, &files, EW_FILE|EW_SILENT) == FAIL || filecount == 0) { EMSG2("E151: No match: %s", NameBuff); @@ -5422,7 +5430,11 @@ helptags_one ( STRCPY(NameBuff, dir); STRCAT(NameBuff, "/**/*"); STRCAT(NameBuff, ext); - if (gen_expand_wildcards(1, &NameBuff, &filecount, &files, + + // Note: We cannot just do `&NameBuff` because it is a statically sized array + // so `NameBuff == &NameBuff` according to C semantics. + char_u *buff_list[1] = {(char_u*) NameBuff}; + if (gen_expand_wildcards(1, buff_list, &filecount, &files, EW_FILE|EW_SILENT) == FAIL || filecount == 0) { if (!got_int) diff --git a/src/nvim/globals.h b/src/nvim/globals.h index f9d5a766c8..c0122ae189 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -40,6 +40,20 @@ # define MSG_BUF_CLEN (MSG_BUF_LEN / 6) // cell length (worst case: utf-8 // takes 6 bytes for one cell) +/* + * Maximum length of a path (for non-unix systems) Make it a bit long, to stay + * on the safe side. But not too long to put on the stack. + * TODO(metrix78): Move this to os_defs.h + */ +#ifndef MAXPATHL +# ifdef MAXPATHLEN +# define MAXPATHL MAXPATHLEN +# else +# define MAXPATHL 256 +# endif +#endif + + /* Values for "starting" */ #define NO_SCREEN 2 /* no screen updating yet */ #define NO_BUFFERS 1 /* not all buffers loaded yet */ @@ -841,11 +855,9 @@ EXTERN int swap_exists_action INIT(= SEA_NONE); EXTERN int swap_exists_did_quit INIT(= FALSE); /* Selected "quit" at the dialog. */ -EXTERN char_u IObuff[IOSIZE]; /* sprintf's are done in this buffer, - size is IOSIZE */ -EXTERN char_u *NameBuff; /* file names are expanded in this - * buffer, size is MAXPATHL */ -EXTERN char_u msg_buf[MSG_BUF_LEN]; /* small buffer for messages */ +EXTERN char_u IObuff[IOSIZE]; /* sprintf's are done in this buffer */ +EXTERN char_u NameBuff[MAXPATHL]; /* buffer for expanding file names */ +EXTERN char_u msg_buf[MSG_BUF_LEN]; /* small buffer for messages */ /* When non-zero, postpone redrawing. */ EXTERN int RedrawingDisabled INIT(= 0); diff --git a/src/nvim/main.c b/src/nvim/main.c index ac1366bfd9..6b8c2f4d4d 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -144,10 +144,6 @@ int main(int argc, char **argv) char_u *fname = NULL; /* file name from command line */ mparm_T params; /* various parameters passed between * main() and other functions. */ - /* - * Do any system-specific initialisations. These can NOT use IObuff or - * NameBuff. Thus emsg2() cannot be called! - */ mch_early_init(); /* Many variables are in "params" so that we can pass them to invoked @@ -167,12 +163,6 @@ int main(int argc, char **argv) /* Init the table of Normal mode commands. */ init_normal_cmds(); - /* - * Allocate space for the generic buffers (needed for set_init_1() and - * EMSG2()). - */ - allocate_generic_buffers(); - #if defined(HAVE_LOCALE_H) || defined(X_LOCALE) /* * Setup to use the current locale (for ctype() and many other things). @@ -1477,16 +1467,6 @@ static void init_startuptime(mparm_T *paramp) } /* - * Allocate space for the generic buffers (needed for set_init_1() and - * EMSG2()). - */ -static void allocate_generic_buffers(void) -{ - NameBuff = xmalloc(MAXPATHL); - TIME_MSG("Allocated generic buffers"); -} - -/* * Check if we have an interactive window. * On the Amiga: If there is no window, we open one with a newcli command * (needed for :! to * work). mch_check_win() will also handle the -d or diff --git a/src/nvim/memory.c b/src/nvim/memory.c index 9f68b6066b..50dcca3c84 100644 --- a/src/nvim/memory.c +++ b/src/nvim/memory.c @@ -510,8 +510,6 @@ void free_all_mem(void) free_screenlines(); clear_hl_tables(); - - free(NameBuff); } #endif diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index ff2123bac1..2415858e0f 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -3540,7 +3540,11 @@ void ex_helpgrep(exarg_T *eap) /* Find all "*.txt" and "*.??x" files in the "doc" directory. */ add_pathsep(NameBuff); STRCAT(NameBuff, "doc/*.\\(txt\\|??x\\)"); - if (gen_expand_wildcards(1, &NameBuff, &fcount, + + // Note: We cannot just do `&NameBuff` because it is a statically sized array + // so `NameBuff == &NameBuff` according to C semantics. + char_u *buff_list[1] = {(char_u*) NameBuff}; + if (gen_expand_wildcards(1, buff_list, &fcount, &fnames, EW_FILE|EW_SILENT) == OK && fcount > 0) { for (fi = 0; fi < fcount && !got_int; ++fi) { diff --git a/src/nvim/tempfile.c b/src/nvim/tempfile.c index 41fc163936..c25da77717 100644 --- a/src/nvim/tempfile.c +++ b/src/nvim/tempfile.c @@ -60,7 +60,11 @@ void vim_deltempdir(void) char_u **files; int file_count; - if (gen_expand_wildcards(1, &NameBuff, &file_count, &files, + + // Note: We cannot just do `&NameBuff` because it is a statically + // sized array so `NameBuff == &NameBuff` according to C semantics. + char_u *buff_list[1] = {(char_u*) NameBuff}; + if (gen_expand_wildcards(1, buff_list, &file_count, &files, EW_DIR|EW_FILE|EW_SILENT) == OK) { for (int i = 0; i < file_count; ++i) { os_remove((char *)files[i]); diff --git a/src/nvim/vim.h b/src/nvim/vim.h index 5d903633e4..6479aeaafb 100644 --- a/src/nvim/vim.h +++ b/src/nvim/vim.h @@ -45,18 +45,6 @@ Error: configure did not run properly.Check auto/config.log. #include "nvim/os_unix_defs.h" /* bring lots of system header files */ -/* - * Maximum length of a path (for non-unix systems) Make it a bit long, to stay - * on the safe side. But not too long to put on the stack. - */ -#ifndef MAXPATHL -# ifdef MAXPATHLEN -# define MAXPATHL MAXPATHLEN -# else -# define MAXPATHL 256 -# endif -#endif - #define NUMBUFLEN 30 /* length of a buffer to store a number in ASCII */ # define MAX_TYPENR 65535 diff --git a/test/unit/buffer_spec.lua b/test/unit/buffer_spec.lua new file mode 100644 index 0000000000..11d99a7bcb --- /dev/null +++ b/test/unit/buffer_spec.lua @@ -0,0 +1,216 @@ +local helpers = require("test.unit.helpers") + +local to_cstr = helpers.to_cstr +local eq = helpers.eq + +helpers.vim_init() + +local buffer = helpers.cimport("./src/nvim/buffer.h") +local window = helpers.cimport("./src/nvim/window.h") +local option = helpers.cimport("./src/nvim/option.h") + +--{ Initialize the options needed for interacting with buffers +window.win_alloc_first() +option.set_init_1() +--} + +describe('buffer functions', function() + + local buflist_new = function(file, flags) + local c_file = to_cstr(file) + return buffer.buflist_new(c_file, c_file, 1, flags) + end + + local close_buffer = function(win, buf, action, abort_if_last) + return buffer.close_buffer(win, buf, action, abort_if_last) + end + + local path1 = 'test_file_path' + local path2 = 'file_path_test' + local path3 = 'path_test_file' + + before_each(function() + -- create the files + io.open(path1, 'w').close() + io.open(path2, 'w').close() + io.open(path3, 'w').close() + end) + + after_each(function() + os.remove(path1) + os.remove(path2) + os.remove(path3) + end) + + describe('buf_valid', function() + + it('should view NULL as an invalid buffer', function() + eq(0, buffer.buf_valid(NULL)) + end) + + it('should view an open buffer as valid', function() + local buf = buflist_new(path1, buffer.BLN_LISTED) + + eq(1, buffer.buf_valid(buf)) + end) + + it('should view a closed and hidden buffer as valid', function() + local buf = buflist_new(path1, buffer.BLN_LISTED) + + close_buffer(NULL, buf, 0, 0) + + eq(1, buffer.buf_valid(buf)) + end) + + it('should view a closed and unloaded buffer as valid', function() + local buf = buflist_new(path1, buffer.BLN_LISTED) + + close_buffer(NULL, buf, buffer.DOBUF_UNLOAD, 0) + + eq(1, buffer.buf_valid(buf)) + end) + + it('should view a closed and wiped buffer as invalid', function() + local buf = buflist_new(path1, buffer.BLN_LISTED) + + close_buffer(NULL, buf, buffer.DOBUF_WIPE, 0) + + eq(0, buffer.buf_valid(buf)) + end) + end) + + + describe('buflist_findpat', function() + + local ALLOW_UNLISTED = 1 + local ONLY_LISTED = 0 + + local buflist_findpat = function(pat, allow_unlisted) + return buffer.buflist_findpat(to_cstr(pat), NULL, allow_unlisted, 0, 0) + end + + it('should find exact matches', function() + local buf = buflist_new(path1, buffer.BLN_LISTED) + + eq(buf.b_fnum, buflist_findpat(path1, ONLY_LISTED)) + + close_buffer(NULL, buf, buffer.DOBUF_WIPE, 0) + end) + + it('should prefer to match the start of a file path', function() + local buf1 = buflist_new(path1, buffer.BLN_LISTED) + local buf2 = buflist_new(path2, buffer.BLN_LISTED) + local buf3 = buflist_new(path3, buffer.BLN_LISTED) + + eq(buf1.b_fnum, buflist_findpat("test", ONLY_LISTED)) + eq(buf2.b_fnum, buflist_findpat("file", ONLY_LISTED)) + eq(buf3.b_fnum, buflist_findpat("path", ONLY_LISTED)) + + close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0) + close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0) + close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0) + end) + + it('should prefer to match the end of a file over the middle', function() + --{ Given: Two buffers, where 'test' appears in both + -- And: 'test' appears at the end of buf3 but in the middle of buf2 + local buf2 = buflist_new(path2, buffer.BLN_LISTED) + local buf3 = buflist_new(path3, buffer.BLN_LISTED) + + -- Then: buf2 is the buffer that is found + eq(buf2.b_fnum, buflist_findpat("test", ONLY_LISTED)) + --} + + --{ When: We close buf2 + close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0) + + -- And: Open buf1, which has 'file' in the middle of its name + local buf1 = buflist_new(path1, buffer.BLN_LISTED) + + -- Then: buf3 is found since 'file' appears at the end of the name + eq(buf3.b_fnum, buflist_findpat("file", ONLY_LISTED)) + --} + + close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0) + close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0) + end) + + it('should match a unique fragment of a file path', function() + local buf1 = buflist_new(path1, buffer.BLN_LISTED) + local buf2 = buflist_new(path2, buffer.BLN_LISTED) + local buf3 = buflist_new(path3, buffer.BLN_LISTED) + + eq(buf3.b_fnum, buflist_findpat("_test_", ONLY_LISTED)) + + close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0) + close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0) + close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0) + end) + + it('should include / ignore unlisted buffers based on the flag.', function() + --{ Given: A buffer + local buf3 = buflist_new(path3, buffer.BLN_LISTED) + + -- Then: We should find the buffer when it is given a unique pattern + eq(buf3.b_fnum, buflist_findpat("_test_", ONLY_LISTED)) + --} + + --{ When: We unlist the buffer + close_buffer(NULL, buf3, buffer.DOBUF_DEL, 0) + + -- Then: It should not find the buffer when searching only listed buffers + eq(-1, buflist_findpat("_test_", ONLY_LISTED)) + + -- And: It should find the buffer when including unlisted buffers + eq(buf3.b_fnum, buflist_findpat("_test_", ALLOW_UNLISTED)) + --} + + --{ When: We wipe the buffer + close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0) + + -- Then: It should not find the buffer at all + eq(-1, buflist_findpat("_test_", ONLY_LISTED)) + eq(-1, buflist_findpat("_test_", ALLOW_UNLISTED)) + --} + end) + + it('should prefer listed buffers to unlisted buffers.', function() + --{ Given: Two buffers that match a pattern + local buf1 = buflist_new(path1, buffer.BLN_LISTED) + local buf2 = buflist_new(path2, buffer.BLN_LISTED) + + -- Then: The first buffer is preferred when both are listed + eq(buf1.b_fnum, buflist_findpat("test", ONLY_LISTED)) + --} + + --{ When: The first buffer is unlisted + close_buffer(NULL, buf1, buffer.DOBUF_DEL, 0) + + -- Then: The second buffer is preferred because + -- unlisted buffers are not allowed + eq(buf2.b_fnum, buflist_findpat("test", ONLY_LISTED)) + --} + + --{ When: We allow unlisted buffers + -- Then: The second buffer is still preferred + -- because listed buffers are preferred to unlisted + eq(buf2.b_fnum, buflist_findpat("test", ALLOW_UNLISTED)) + --} + + --{ When: We unlist the second buffer + close_buffer(NULL, buf2, buffer.DOBUF_DEL, 0) + + -- Then: The first buffer is preferred again + -- because buf1 matches better which takes precedence + -- when both buffers have the same listing status. + eq(buf1.b_fnum, buflist_findpat("test", ALLOW_UNLISTED)) + + -- And: Neither buffer is returned when ignoring unlisted + eq(-1, buflist_findpat("test", ONLY_LISTED)) + --} + + close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0) + close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0) + end) + end) +end) diff --git a/test/unit/fileio_spec.lua b/test/unit/fileio_spec.lua new file mode 100644 index 0000000000..180fc3c184 --- /dev/null +++ b/test/unit/fileio_spec.lua @@ -0,0 +1,83 @@ +local helpers = require("test.unit.helpers") +--{:cimport, :internalize, :eq, :neq, :ffi, :lib, :cstr, :to_cstr} = require 'test.unit.helpers' + +local eq = helpers.eq +local ffi = helpers.ffi +local to_cstr = helpers.to_cstr + +local fileio = helpers.cimport("./src/nvim/fileio.h") + +describe('file_pat functions', function() + describe('file_pat_to_reg_pat', function() + + local file_pat_to_reg_pat = function(pat) + local res = fileio.file_pat_to_reg_pat(to_cstr(pat), NULL, NULL, 0) + return ffi.string(res) + end + + it('returns ^path$ regex for literal path input', function() + eq( '^path$', file_pat_to_reg_pat('path')) + end) + + it('does not prepend ^ when there is a starting glob (*)', function() + eq('path$', file_pat_to_reg_pat('*path')) + end) + + it('does not append $ when there is an ending glob (*)', function() + eq('^path', file_pat_to_reg_pat('path*')) + end) + + it('does not include ^ or $ when surrounded by globs (*)', function() + eq('path', file_pat_to_reg_pat('*path*')) + end) + + it('replaces the bash any character (?) with the regex any character (.)', function() + eq('^foo.bar$', file_pat_to_reg_pat('foo?bar')) + end) + + it('replaces a glob (*) in the middle of a path with regex multiple any character (.*)', + function() + eq('^foo.*bar$', file_pat_to_reg_pat('foo*bar')) + end) + + it([[unescapes \? to ?]], function() + eq('^foo?bar$', file_pat_to_reg_pat([[foo\?bar]])) + end) + + it([[unescapes \% to %]], function() + eq('^foo%bar$', file_pat_to_reg_pat([[foo\%bar]])) + end) + + it([[unescapes \, to ,]], function() + eq('^foo,bar$', file_pat_to_reg_pat([[foo\,bar]])) + end) + + it([[unescapes '\ ' to ' ']], function() + eq('^foo bar$', file_pat_to_reg_pat([[foo\ bar]])) + end) + + it([[escapes . to \.]], function() + eq([[^foo\.bar$]], file_pat_to_reg_pat('foo.bar')) + end) + + it('Converts bash brace expansion {a,b} to regex options (a|b)', function() + eq([[^foo\(bar\|baz\)$]], file_pat_to_reg_pat('foo{bar,baz}')) + end) + + it('Collapses multiple consecutive * into a single character', function() + eq([[^foo.*bar$]], file_pat_to_reg_pat('foo*******bar')) + eq([[foobar$]], file_pat_to_reg_pat('********foobar')) + eq([[^foobar]], file_pat_to_reg_pat('foobar********')) + end) + + it('Does not escape ^', function() + eq([[^^blah$]], file_pat_to_reg_pat('^blah')) + eq([[^foo^bar$]], file_pat_to_reg_pat('foo^bar')) + end) + + it('Does not escape $', function() + eq([[^blah$$]], file_pat_to_reg_pat('blah$')) + eq([[^foo$bar$]], file_pat_to_reg_pat('foo$bar')) + end) + end) +end) diff --git a/test/unit/tempfile_spec.lua b/test/unit/tempfile_spec.lua index adc52b9a8f..e558ff04c8 100644 --- a/test/unit/tempfile_spec.lua +++ b/test/unit/tempfile_spec.lua @@ -6,10 +6,7 @@ local tempfile = helpers.cimport './src/nvim/tempfile.h' describe('tempfile related functions', function() after_each(function() - -- This won't work because vim_deltempdir() uses global buffer - -- that is initialized in main() and main() is not called for unit tests. - -- But it is not a big problem: all tests can work with or without it. - -- tempfile.vim_deltempdir() + tempfile.vim_deltempdir() end) local vim_gettempdir = function() |