0Pricing
Lua Academy · Lesson

Buffers and Windows

Manipulate the editor.

Buffers and Windows is a free Lua Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Lua Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Buffers, Windows, Tabs

Neovim separates content from display. A buffer holds text in memory; a window is a viewport onto a buffer; a tabpage is a layout of windows.

One buffer can appear in many windows. Plugins manipulate these handles, which are integers, through the nvim_buf_* and nvim_win_* API families.

local buf = vim.api.nvim_get_current_buf()
local win = vim.api.nvim_get_current_win()
print(buf, win)

Reading Buffer Lines

nvim_buf_get_lines(buf, start, end_, strict) returns lines as a list. Indices are zero-based and end-exclusive; pass -1 as the end to reach the last line.

Setting strict_indexing to false tolerates out-of-range indices instead of erroring.

local lines = vim.api.nvim_buf_get_lines(0, 0, -1, false)
print('line count: ' .. #lines)

Writing Buffer Lines

nvim_buf_set_lines replaces a range with new text. To append at the end, set both start and end to -1. To overwrite everything, use 0, -1.

The replacement is a Lua list of strings, one per line, with no trailing newline characters.

vim.api.nvim_buf_set_lines(0, -1, -1, false, {
  '-- appended line',
})

Scratch Buffers

Create an unlisted, throwaway buffer with nvim_create_buf(listed, scratch). Passing false, true makes a scratch buffer ideal for plugin UI.

Set bufhidden = 'wipe' so it vanishes when its window closes, avoiding leftover buffers.

local buf = vim.api.nvim_create_buf(false, true)
vim.bo[buf].bufhidden = 'wipe'
vim.api.nvim_buf_set_lines(buf, 0, -1, false, { 'Panel' })

Buffer-Local Options

Index vim.bo[buf] to set buffer-local options on a specific handle. Common plugin settings include modifiable = false and buftype = 'nofile'.

Making a display buffer non-modifiable prevents users from accidentally editing generated content.

vim.bo[buf].modifiable = false
vim.bo[buf].buftype = 'nofile'
vim.bo[buf].filetype = 'myplugin'

Opening Floating Windows

nvim_open_win(buf, enter, config) places a buffer in a floating window. The config sets relative, row, col, width, height, and border.

Floats are the basis of modern UI like hover docs, pickers, and notifications.

local win = vim.api.nvim_open_win(buf, true, {
  relative = 'editor', row = 5, col = 10,
  width = 40, height = 10, border = 'rounded',
})

Window Configuration

Adjust an open float with nvim_win_set_config, useful for resizing on VimResized. Read the current layout with nvim_win_get_config.

Set window-local options through vim.wo[win], for instance hiding the cursor line or disabling number columns in UI panels.

vim.wo[win].number = false
vim.wo[win].cursorline = true
vim.api.nvim_win_set_config(win, { width = 50 })

Cursor and Position

Move the cursor with nvim_win_set_cursor(win, {row, col}). Note row is one-based but col is zero-based, a frequent source of off-by-one bugs.

Read it back with nvim_win_get_cursor to remember and restore a user's position around an operation.

local pos = vim.api.nvim_win_get_cursor(0)
vim.api.nvim_win_set_cursor(0, { pos[1], 0 })

Validity and Cleanup

Handles can become stale. Guard with nvim_buf_is_valid and nvim_win_is_valid before acting on stored handles.

Close windows with nvim_win_close(win, force) and delete buffers via nvim_buf_delete(buf, { force = true }). Always validate first to avoid errors.

if vim.api.nvim_win_is_valid(win) then
  vim.api.nvim_win_close(win, true)
end

Extmarks and Namespaces

Extmarks anchor metadata to text that moves as edits happen. Create a namespace with nvim_create_namespace, then attach virtual text or highlights.

nvim_buf_set_extmark supports virt_text, sign columns, and inline highlights, the engine behind inlay hints and git blame plugins.

local ns = vim.api.nvim_create_namespace('myplugin')
vim.api.nvim_buf_set_extmark(0, ns, 0, 0, {
  virt_text = { { ' hint', 'Comment' } },
})

Listing and Iterating

nvim_list_bufs and nvim_list_wins return all current handles. Filter them with nvim_buf_is_loaded or by checking options.

Iterating lets a plugin act across the whole session, such as closing every floating window or refreshing each buffer of a given filetype.

for _, b in ipairs(vim.api.nvim_list_bufs()) do
  if vim.api.nvim_buf_is_loaded(b) then print(b) end
end

Quick Check

Verify what you learned about buffers and windows.

Recap: Buffers and Windows

Buffers hold text, windows display them, and handles are integers you validate before use. You can read and write lines, create scratch buffers, and set buffer-local options.

Floating windows via nvim_open_win, cursor control, extmarks, and listing APIs give you everything needed to build rich, stateful plugin UIs.

Frequently asked questions

Is the “Buffers and Windows” lesson free?

Yes — the full text of “Buffers and Windows” is free to read here on the web, and the Lua Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Lua Academy course, upgrade to CoddyKit PRO.

What will I learn in “Buffers and Windows”?

Manipulate the editor. You practise Lua Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Lua Academy?

No prior experience is required. Lua Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Buffers and Windows” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Lua Academy lesson?

Yes. Every Lua Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. The Neovim Lua API
  2. Commands and Keymaps
  3. Buffers and Windows
  4. Packaging a Plugin
← Back to Lua Academy