diff options
-rw-r--r-- | CMakeLists.txt | 4 | ||||
-rw-r--r-- | runtime/doc/api.txt | 40 | ||||
-rwxr-xr-x | scripts/gen_api_vimdoc.py | 21 | ||||
-rw-r--r-- | src/nvim/api/buffer.c | 52 | ||||
-rw-r--r-- | test/functional/api/buffer_spec.lua | 57 |
5 files changed, 162 insertions, 12 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c2e40ab8b..02b555d540 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -113,9 +113,9 @@ set(NVIM_VERSION_PATCH 2) set(NVIM_VERSION_PRERELEASE "-dev") # for package maintainers # API level -set(NVIM_API_LEVEL 4) # Bump this after any API change. +set(NVIM_API_LEVEL 5) # Bump this after any API change. set(NVIM_API_LEVEL_COMPAT 0) # Adjust this after a _breaking_ API change. -set(NVIM_API_PRERELEASE false) +set(NVIM_API_PRERELEASE true) file(TO_CMAKE_PATH ${CMAKE_CURRENT_LIST_DIR}/.git FORCED_GIT_DIR) include(GetGitRevisionDescription) diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index 21f818cb8d..c260101e92 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -836,10 +836,26 @@ nvim_get_proc({pid}) *nvim_get_proc()* Return: ~ Map of process properties, or NIL if process not found. +nvim__inspect_cell({row}, {col}) *nvim__inspect_cell()* + TODO: Documentation + ============================================================================== Buffer Functions *api-buffer* +Unloaded Buffers:~ + +Buffers may be unloaded by the |:bunload| command or the +buffer's |'bufhidden'| option. When a buffer is unloaded its +file contents are freed from memory and vim cannot operate on +the buffer lines until it is reloaded (usually by opening the +buffer again in a new window). API methods such as +|nvim_buf_get_lines()| and |nvim_buf_line_count()| will be +affected. + +You can use |nvim_buf_is_loaded()| or |nvim_buf_line_count()| +to check whether a buffer is loaded. + nvim_buf_line_count({buffer}) *nvim_buf_line_count()* Gets the buffer line count @@ -847,7 +863,8 @@ nvim_buf_line_count({buffer}) *nvim_buf_line_count()* {buffer} Buffer handle Return: ~ - Line count + Line count, or `0` if the buffer has been unloaded (see + |api-buffer|). nvim_buf_attach({buffer}, {send_buffer}, {opts}) *nvim_buf_attach()* Activate updates from this buffer to the current channel. @@ -896,7 +913,8 @@ nvim_buf_get_lines({buffer}, {start}, {end}, {strict_indexing}) error. Return: ~ - Array of lines + Array of lines. If the buffer has been unloaded then an + empty array will be returned instead. (See |api-buffer|.) *nvim_buf_set_lines()* nvim_buf_set_lines({buffer}, {start}, {end}, {strict_indexing}, @@ -1013,14 +1031,28 @@ nvim_buf_set_name({buffer}, {name}) *nvim_buf_set_name()* {buffer} Buffer handle {name} Buffer name +nvim_buf_is_loaded({buffer}) *nvim_buf_is_loaded()* + Checks if a buffer is valid and loaded. See |api-buffer| for + more info about unloaded buffers. + + Parameters: ~ + {buffer} Buffer handle + + Return: ~ + true if the buffer is valid and loaded, false otherwise. + nvim_buf_is_valid({buffer}) *nvim_buf_is_valid()* - Checks if a buffer is valid + Checks if a buffer is valid. + + Note: + Even if a buffer is valid it may have been unloaded. See + |api-buffer| for more info about unloaded buffers. Parameters: ~ {buffer} Buffer handle Return: ~ - true if the buffer is valid, false otherwise + true if the buffer is valid, false otherwise. nvim_buf_get_mark({buffer}, {name}) *nvim_buf_get_mark()* Return a tuple (row,col) representing the position of the diff --git a/scripts/gen_api_vimdoc.py b/scripts/gen_api_vimdoc.py index 0bbc3706c6..4e86f15b37 100755 --- a/scripts/gen_api_vimdoc.py +++ b/scripts/gen_api_vimdoc.py @@ -413,10 +413,26 @@ def gen_docs(config): sys.exit(p.returncode) sections = {} + intros = {} sep = '=' * text_width base = os.path.join(out_dir, 'xml') dom = minidom.parse(os.path.join(base, 'index.xml')) + + # generate docs for section intros + for compound in dom.getElementsByTagName('compound'): + if compound.getAttribute('kind') != 'group': + continue + + groupname = get_text(find_first(compound, 'name')) + groupxml = os.path.join(base, '%s.xml' % compound.getAttribute('refid')) + + desc = find_first(minidom.parse(groupxml), 'detaileddescription') + if desc: + doc = parse_parblock(desc) + if doc: + intros[groupname] = doc + for compound in dom.getElementsByTagName('compound'): if compound.getAttribute('kind') != 'file': continue @@ -437,6 +453,11 @@ def gen_docs(config): name = name.title() doc = '' + + intro = intros.get('api-%s' % name.lower()) + if intro: + doc += '\n\n' + intro + if functions: doc += '\n\n' + functions diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 8ff24b877e..67a4b70c9e 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -31,11 +31,27 @@ # include "api/buffer.c.generated.h" #endif + +/// \defgroup api-buffer +/// +/// Unloaded Buffers:~ +/// +/// Buffers may be unloaded by the |:bunload| command or the buffer's +/// |'bufhidden'| option. When a buffer is unloaded its file contents are freed +/// from memory and vim cannot operate on the buffer lines until it is reloaded +/// (usually by opening the buffer again in a new window). API methods such as +/// |nvim_buf_get_lines()| and |nvim_buf_line_count()| will be affected. +/// +/// You can use |nvim_buf_is_loaded()| or |nvim_buf_line_count()| to check +/// whether a buffer is loaded. + + /// Gets the buffer line count /// /// @param buffer Buffer handle /// @param[out] err Error details, if any -/// @return Line count +/// @return Line count, or \`0` if the buffer has been unloaded (see +/// |api-buffer|). Integer nvim_buf_line_count(Buffer buffer, Error *err) FUNC_API_SINCE(1) { @@ -45,6 +61,11 @@ Integer nvim_buf_line_count(Buffer buffer, Error *err) return 0; } + // return sentinel value if the buffer isn't loaded + if (buf->b_ml.ml_mfp == NULL) { + return 0; + } + return buf->b_ml.ml_line_count; } @@ -205,7 +226,8 @@ ArrayOf(String) buffer_get_line_slice(Buffer buffer, /// @param end Last line index (exclusive) /// @param strict_indexing Whether out-of-bounds should be an error. /// @param[out] err Error details, if any -/// @return Array of lines +/// @return Array of lines. If the buffer has been unloaded then an empty array +/// will be returned instead. (See |api-buffer|.) ArrayOf(String) nvim_buf_get_lines(uint64_t channel_id, Buffer buffer, Integer start, @@ -221,6 +243,11 @@ ArrayOf(String) nvim_buf_get_lines(uint64_t channel_id, return rv; } + // return sentinel value if the buffer isn't loaded + if (buf->b_ml.ml_mfp == NULL) { + return rv; + } + bool oob = false; start = normalize_index(buf, start, &oob); end = normalize_index(buf, end, &oob); @@ -745,10 +772,27 @@ void nvim_buf_set_name(Buffer buffer, String name, Error *err) } } -/// Checks if a buffer is valid +/// Checks if a buffer is valid and loaded. See |api-buffer| for more info +/// about unloaded buffers. +/// +/// @param buffer Buffer handle +/// @return true if the buffer is valid and loaded, false otherwise. +Boolean nvim_buf_is_loaded(Buffer buffer) + FUNC_API_SINCE(5) +{ + Error stub = ERROR_INIT; + buf_T *buf = find_buffer_by_handle(buffer, &stub); + api_clear_error(&stub); + return buf && buf->b_ml.ml_mfp != NULL; +} + +/// Checks if a buffer is valid. +/// +/// @note Even if a buffer is valid it may have been unloaded. See |api-buffer| +/// for more info about unloaded buffers. /// /// @param buffer Buffer handle -/// @return true if the buffer is valid, false otherwise +/// @return true if the buffer is valid, false otherwise. Boolean nvim_buf_is_valid(Buffer buffer) FUNC_API_SINCE(1) { diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua index 823c134ebd..958e2f68fc 100644 --- a/test/functional/api/buffer_spec.lua +++ b/test/functional/api/buffer_spec.lua @@ -35,8 +35,37 @@ describe('api/buf', function() -- There's always at least one line eq(1, curbuf_depr('line_count')) end) - end) + it('line_count has defined behaviour for unloaded buffers', function() + -- we'll need to know our bufnr for when it gets unloaded + local bufnr = curbuf('get_number') + -- replace the buffer contents with these three lines + request('nvim_buf_set_lines', bufnr, 0, -1, 1, {"line1", "line2", "line3", "line4"}) + -- check the line count is correct + eq(4, request('nvim_buf_line_count', bufnr)) + -- force unload the buffer (this will discard changes) + command('new') + command('bunload! '..bufnr) + -- line count for an unloaded buffer should always be 0 + eq(0, request('nvim_buf_line_count', bufnr)) + end) + + it('get_lines has defined behaviour for unloaded buffers', function() + -- we'll need to know our bufnr for when it gets unloaded + local bufnr = curbuf('get_number') + -- replace the buffer contents with these three lines + buffer('set_lines', bufnr, 0, -1, 1, {"line1", "line2", "line3", "line4"}) + -- confirm that getting lines works + eq({"line2", "line3"}, buffer('get_lines', bufnr, 1, 3, 1)) + -- force unload the buffer (this will discard changes) + command('new') + command('bunload! '..bufnr) + -- attempting to get lines now always gives empty list + eq({}, buffer('get_lines', bufnr, 1, 3, 1)) + -- it's impossible to get out-of-bounds errors for an unloaded buffer + eq({}, buffer('get_lines', bufnr, 8888, 9999, 1)) + end) + end) describe('{get,set,del}_line', function() it('works', function() @@ -70,7 +99,6 @@ describe('api/buf', function() end) end) - describe('{get,set}_line_slice', function() it('get_line_slice: out-of-bounds returns empty array', function() curbuf_depr('set_line_slice', 0, 0, true, true, {'a', 'b', 'c'}) @@ -345,6 +373,31 @@ describe('api/buf', function() end) end) + describe('is_loaded', function() + it('works', function() + -- record our buffer number for when we unload it + local bufnr = curbuf('get_number') + -- api should report that the buffer is loaded + ok(buffer('is_loaded', bufnr)) + -- hide the current buffer by switching to a new empty buffer + -- Careful! we need to modify the buffer first or vim will just reuse it + buffer('set_lines', bufnr, 0, -1, 1, {'line1'}) + command('hide enew') + -- confirm the buffer is hidden, but still loaded + local infolist = nvim('eval', 'getbufinfo('..bufnr..')') + eq(1, #infolist) + eq(1, infolist[1].hidden) + eq(1, infolist[1].loaded) + -- now force unload the buffer + command('bunload! '..bufnr) + -- confirm the buffer is unloaded + infolist = nvim('eval', 'getbufinfo('..bufnr..')') + eq(0, infolist[1].loaded) + -- nvim_buf_is_loaded() should also report the buffer as unloaded + eq(false, buffer('is_loaded', bufnr)) + end) + end) + describe('is_valid', function() it('works', function() nvim('command', 'new') |