aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjörn Linse <bjorn.linse@gmail.com>2018-08-02 13:28:36 +0200
committerGitHub <noreply@github.com>2018-08-02 13:28:36 +0200
commit2b9fc9a13f1404260448c129762a2679ac688372 (patch)
treed252343457668ef7b5998f831669baf842f60cde
parenta2253744c9bcd9229be9533540075e977f0be2cd (diff)
parentea2e8f4f107fb50cbb261d4377922ce3814cce32 (diff)
downloadrneovim-2b9fc9a13f1404260448c129762a2679ac688372.tar.gz
rneovim-2b9fc9a13f1404260448c129762a2679ac688372.tar.bz2
rneovim-2b9fc9a13f1404260448c129762a2679ac688372.zip
Merge pull request #8660 from phodge/7688-nvim-buf-lines-should-return-empty-list-for-unloaded-buffer
handle unloaded buffers in nvim_buf_*() functions
-rw-r--r--CMakeLists.txt4
-rw-r--r--runtime/doc/api.txt40
-rwxr-xr-xscripts/gen_api_vimdoc.py21
-rw-r--r--src/nvim/api/buffer.c52
-rw-r--r--test/functional/api/buffer_spec.lua57
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')