1   Getting help inside Nvim

List what is available by the vim. variable:

  • :help lua-stdlib
  • :help lua-vim
  • :help api-global

API functions are documented under: :help api-global

To get a list of functions in a given module, do, for example:

:lua print(vim.inspect(vim))
:lua print(vim.inspect(vim.api))

To get help on a specific function, do for example:

:h vim.pretty_print()
:h vim.api.nvim_buf_line_count()

The Nvim help (text) files are in: ~/a1/Source/Neovim/Git/neovim/runtime/doc/*.txt.

Some examples:

# print a range of lines (concatenated and separated by "::".
:lua print(table.concat(vim.api.nvim_buf_get_lines(0, 6, 9, true), '::'))
# print each of a range of lines from the current buffer.
:lua for i, v in ipairs(vim.api.nvim_buf_get_lines(0, 6, 9, true)) do print(i, v) end
# print the current line (line with the cursor)
:lua print(vim.api.nvim_get_current_line())
# replace the second and third lines of the current buffer with lines in table.
:lua vim.api.nvim_buf_set_lines(0, 1, 3, true, table01)
# to delete a range of lines, give an empty table as replacement parameter
:lua vim.api.nvim_buf_set_lines(0, 1, 3, true, {})
# get a range of lines from a different buffer, then display them.
# use `:ls` or `:buffers` to learn the buffer numbers.
:lua table02 = vim.api.nvim_buf_get_lines(3, 3, 8, true)
:lua for i, v in ipairs(table02) do print(i, v) end

2   How to apply a Lua expression to lines in a range

The command :luado evaluates a Lua expression and replaces each line with the result. Here are several simple examples:

:'<,'>luado return 'silly'
:'<,'>luado return string.upper(line)
:'<,'>luado return string.format('%3d. %s', linenr, line)


  • The Lua expression in a ":luado" has two variables of interest that are available to it: (1) line contains the value of the current line; (2) linenr contains the line number in the buffer of line.
  • Example 1, above, replaces each line in the selection with the word "silly".
  • Example 2 replaces each line in the selection with the line converted to upper case.
  • Example 3 prefixes each line in the selection with the line number of that line.
  • If no range is specified, then the range is the entire file, i.e. all the lines in the current buffer.

For more information and help use: :help :luado.

3   How to read lines from a text file

Here is the implementation of an iterator that returns, one by one, lines of text from a text file:

-- File iterator with line and count.
-- This iterator is "stateless" -- all state is passed in parameters.
-- And, that state is saved in the inner function/closure.
-- Use:
--     > test10 = require 'test10'
--     > for count, line in test10.make_lines_iterator('some_file.txt') do print(count, line) end
function M.make_lines_iterator(filename)
  print('*** test 11')
  local file = io.open(filename, 'r')
  local iter = function(filestate, countstate)
    new_count = countstate + 1
    local new_line = filestate:read()
    if new_line == nil then
      return nil
      return new_count, new_line
  return iter, file, 0

function M.test_iterator(filename)
  for count, line in M.make_lines_iterator(filename) do
    print(string.format('%3d. |%s|', count, line))


  • Function make_lines_iterator creates and returns an iterator function, the file (unchanging state), and the initial count (changing state).
  • Each time the iterator function is called, it returns the new (updated) count and the next line, until there are no more lines, when it returns nil to end the iteration.
  • Function test_iterator performs a test of that iterator. Notice the for statement: it iterates over and prints, one by one, the lines of text from a text file.

More information -- Here are links to help you learn how to implement iterators:

4   How to extract an Nvim selection

The following code expects that there is a character-wise or line-wise selection (marked with either the Nvim v or V commands). It does the following:

  1. Gets the locations of the begin-selection and the end-selection marks.
  2. Retrieves the selected text, i.e. the text between those two marks.
  3. If the first line or last line of the retrieved text is not a whole line (marked with V as opposed to v), then it trims off the characters that are not part of the selection.
  4. Displays the retrieved text.

Here is the code:

function M.show_region_marks_and_lines(buffer)
  buffer = buffer or 0  -- default: current buffer
  start_tbl = vim.api.nvim_buf_get_mark(buffer, '<')
  end_tbl = vim.api.nvim_buf_get_mark(buffer, '>')
  print('v. 08')
  print('start mark:')
  for i, v in ipairs(start_tbl) do
    print('    ', i, v)
  print('end mark:')
  for i, v in ipairs(end_tbl) do
    print('    ', i, v)
  start_line = start_tbl[1] - 1
  start_col = start_tbl[2]
  end_line = end_tbl[1]
  end_col = end_tbl[2]
  range_tbl = vim.api.nvim_buf_get_lines(buffer, start_line, end_line, true)
  -- If start_col > 0 or end_col < 100000, then it's a per character
  -- (character-wise) visual mode selection/range.
  -- So, adjust the first and last line.
  -- I do not know how to find out if it's a block-wise (rectangular) selection.
  if start_col > 0 then
    range_tbl[1] = string.sub(range_tbl[1], start_col + 1)
  if end_col < 100000 then
    range_tbl[#range_tbl] = string.sub(range_tbl[#range_tbl], 1, end_col)
  for i, v in ipairs(range_tbl) do
    print('    ', string.format('%2d |%s|', i, v))


  • The buffer parameter is optional; if it is omitted, we use 0 (zero), which is the current buffer.

  • Retrieves the location of the begin selection and end-selection marks (i.e. marks < and >). The result for each mark is a table (array) containing two values: the line and column of the mark. The following calls do that:

    start_tbl = vim.api.nvim_buf_get_mark(buffer, '<')
    end_tbl = vim.api.nvim_buf_get_mark(buffer, '>')
  • Use the line locations to retrieve the text in the selection/range. The result is a table (array) containing one element for each line. The following call to a Vim API function does that:

    range_tbl = vim.api.nvim_buf_get_lines(buffer, start_line, end_line, true)
  • If the first line or last line of the selection are only partial lines, we trim off the unselected part. We use the column number of the mark location of the first and last line to determine whether this is needed. If the column of the first line is greater than zero, then the first line needs trimming. And, if the column number of the last line is less than some really large number (2147483647 on my machine), then the last line needs trimming.

5   How to exit from a program/script with a message

To print a message, use one of the following:

print('\nusage: ./test11.lua <file-name>\n')
io.stdout:write('some message or other')
io.stderr:write('some message or other')


  • The first two statements above are roughly equivalent. They both write to stdout.
  • The next statement writes to stderr.

To terminate/exit a Lua program/script, use on of the following:



  • The first line above exits with an error exit status code.

  • The second line above exits with a success exit status.

  • On Linux, you can check the exit status code with, for example, the following:

    $ ./my_sample_script.lua
    $ echo $?