Drill 03: Neovim API

The vim global object: options, keymaps, autocommands, and buffer operations.

Run these code blocks inside Neovim with :lua

Run This Drill

bash ~/atelier/_bibliotheca/domus-captures/docs/modules/ROOT/examples/lua-drills/03-neovim-api.sh

Drill Script

#!/bin/bash
# LUA DRILL 03: NEOVIM API
# Run these commands in Neovim with :lua or in init.lua
# Topics: vim.api, vim.fn, vim.opt, vim.keymap

echo "=================================================================="
echo "             LUA DRILL 03: NEOVIM API                            "
echo "=================================================================="
echo ""
echo "These drills are meant to be run INSIDE Neovim."
echo "Copy each block and run with :lua or add to your init.lua"
echo ""

# ---------------------------------------------------------------------------
echo "------------------------------------------------------------------"
echo "DRILL 3.1: vim GLOBAL OBJECT"
echo "The gateway to all Neovim functionality"
echo "------------------------------------------------------------------"
echo ""
cat << 'NVIMEOF'
-- Run in Neovim: :lua <command>

-- vim.inspect - pretty print tables
:lua print(vim.inspect(vim.opt.number:get()))

-- vim.api - Neovim API functions
:lua print(vim.api.nvim_get_current_buf())
:lua print(vim.api.nvim_buf_get_name(0))

-- vim.fn - Vimscript functions
:lua print(vim.fn.expand('%'))      -- current filename
:lua print(vim.fn.getcwd())         -- current working dir
:lua print(vim.fn.has('nvim'))      -- 1 if Neovim

-- vim.cmd - Execute Vimscript
:lua vim.cmd('echo "Hello from Lua!"')
:lua vim.cmd('set number')

-- vim.v - Vim variables (v:count, v:register, etc)
:lua print(vim.v.count)
NVIMEOF
echo ""

# ---------------------------------------------------------------------------
echo "------------------------------------------------------------------"
echo "DRILL 3.2: OPTIONS (vim.opt)"
echo "Set Neovim options"
echo "------------------------------------------------------------------"
echo ""
cat << 'NVIMEOF'
-- Get option value
:lua print(vim.opt.number:get())
:lua print(vim.opt.tabstop:get())
:lua print(vim.inspect(vim.opt.completeopt:get()))

-- Set options
:lua vim.opt.number = true
:lua vim.opt.relativenumber = true
:lua vim.opt.tabstop = 4
:lua vim.opt.shiftwidth = 4

-- List/set options
:lua vim.opt.completeopt = {'menu', 'menuone', 'noselect'}

-- Append/prepend/remove from list options
:lua vim.opt.wildignore:append('*.pyc')
:lua vim.opt.wildignore:prepend('node_modules')
:lua vim.opt.wildignore:remove('*.pyc')

-- In init.lua, typical pattern:
local opt = vim.opt
opt.number = true
opt.relativenumber = true
opt.tabstop = 4
opt.shiftwidth = 4
opt.expandtab = true
opt.smartindent = true
opt.wrap = false
opt.cursorline = true
opt.termguicolors = true
opt.signcolumn = "yes"
opt.clipboard = "unnamedplus"
NVIMEOF
echo ""

# ---------------------------------------------------------------------------
echo "------------------------------------------------------------------"
echo "DRILL 3.3: KEYMAPS (vim.keymap)"
echo "Define keybindings"
echo "------------------------------------------------------------------"
echo ""
cat << 'NVIMEOF'
-- Basic keymap
:lua vim.keymap.set('n', '<leader>w', ':w<CR>')

-- With options
:lua vim.keymap.set('n', '<leader>q', ':q<CR>', {silent = true})

-- With description (for which-key)
:lua vim.keymap.set('n', '<leader>h', ':nohlsearch<CR>', {desc = 'Clear highlights'})

-- Multiple modes
:lua vim.keymap.set({'n', 'v'}, '<leader>y', '"+y', {desc = 'Yank to clipboard'})

-- Lua function as callback
:lua vim.keymap.set('n', '<leader>p', function() print('Hello!') end)

-- In init.lua, typical pattern:
local keymap = vim.keymap.set

-- Better navigation
keymap('n', '<C-h>', '<C-w>h', {desc = 'Move to left window'})
keymap('n', '<C-j>', '<C-w>j', {desc = 'Move to lower window'})
keymap('n', '<C-k>', '<C-w>k', {desc = 'Move to upper window'})
keymap('n', '<C-l>', '<C-w>l', {desc = 'Move to right window'})

-- Buffer navigation
keymap('n', '<S-l>', ':bnext<CR>', {desc = 'Next buffer'})
keymap('n', '<S-h>', ':bprev<CR>', {desc = 'Previous buffer'})

-- Stay in visual mode when indenting
keymap('v', '<', '<gv', {desc = 'Indent left'})
keymap('v', '>', '>gv', {desc = 'Indent right'})

-- Move lines up/down
keymap('v', 'J', ":m '>+1<CR>gv=gv", {desc = 'Move selection down'})
keymap('v', 'K', ":m '<-2<CR>gv=gv", {desc = 'Move selection up'})
NVIMEOF
echo ""

# ---------------------------------------------------------------------------
echo "------------------------------------------------------------------"
echo "DRILL 3.4: AUTOCOMMANDS (vim.api.nvim_create_autocmd)"
echo "React to events"
echo "------------------------------------------------------------------"
echo ""
cat << 'NVIMEOF'
-- Create autocommand group
:lua vim.api.nvim_create_augroup('MyGroup', {clear = true})

-- Single autocommand
:lua vim.api.nvim_create_autocmd('BufWritePre', {
  pattern = '*.lua',
  callback = function()
    print('About to save Lua file!')
  end
})

-- Typical init.lua patterns:
local augroup = vim.api.nvim_create_augroup
local autocmd = vim.api.nvim_create_autocmd

-- Highlight yanked text
augroup('YankHighlight', {clear = true})
autocmd('TextYankPost', {
    group = 'YankHighlight',
    callback = function()
        vim.highlight.on_yank({higroup = 'IncSearch', timeout = 200})
    end
})

-- Remove trailing whitespace on save
augroup('TrimWhitespace', {clear = true})
autocmd('BufWritePre', {
    group = 'TrimWhitespace',
    pattern = '*',
    command = [[%s/\s\+$//e]]
})

-- Set options for specific filetypes
augroup('FileTypeSettings', {clear = true})
autocmd('FileType', {
    group = 'FileTypeSettings',
    pattern = {'lua', 'python'},
    callback = function()
        vim.opt_local.tabstop = 4
        vim.opt_local.shiftwidth = 4
    end
})
NVIMEOF
echo ""

# ---------------------------------------------------------------------------
echo "------------------------------------------------------------------"
echo "DRILL 3.5: BUFFERS AND WINDOWS"
echo "Work with buffers, windows, tabs"
echo "------------------------------------------------------------------"
echo ""
cat << 'NVIMEOF'
-- Get current buffer/window
:lua print(vim.api.nvim_get_current_buf())
:lua print(vim.api.nvim_get_current_win())

-- Get buffer info
:lua print(vim.api.nvim_buf_get_name(0))  -- 0 = current buffer
:lua print(vim.api.nvim_buf_line_count(0))

-- Get buffer lines
:lua print(vim.inspect(vim.api.nvim_buf_get_lines(0, 0, 5, false)))

-- Set buffer lines
:lua vim.api.nvim_buf_set_lines(0, 0, 0, false, {'-- Header added by Lua'})

-- List all buffers
:lua for _, buf in ipairs(vim.api.nvim_list_bufs()) do print(buf, vim.api.nvim_buf_get_name(buf)) end

-- Create new buffer
:lua local buf = vim.api.nvim_create_buf(false, true)  -- not listed, scratch
:lua vim.api.nvim_buf_set_lines(buf, 0, -1, false, {'Line 1', 'Line 2'})

-- Window operations
:lua print(vim.api.nvim_win_get_cursor(0))  -- {line, col}
:lua vim.api.nvim_win_set_cursor(0, {1, 0})  -- go to line 1, col 0
NVIMEOF
echo ""

# ---------------------------------------------------------------------------
echo "------------------------------------------------------------------"
echo "DRILL 3.6: USER COMMANDS"
echo "Create custom :Commands"
echo "------------------------------------------------------------------"
echo ""
cat << 'NVIMEOF'
-- Simple command
:lua vim.api.nvim_create_user_command('Hello', function() print('Hello World!') end, {})

-- Command with arguments
:lua vim.api.nvim_create_user_command('Greet', function(opts)
  print('Hello, ' .. opts.args .. '!')
end, {nargs = 1})

-- Usage: :Greet Admin

-- In init.lua, typical patterns:
local cmd = vim.api.nvim_create_user_command

-- Toggle line numbers
cmd('ToggleNumbers', function()
    vim.opt.number = not vim.opt.number:get()
    vim.opt.relativenumber = not vim.opt.relativenumber:get()
end, {})

-- Copy current file path
cmd('CopyPath', function()
    local path = vim.fn.expand('%:p')
    vim.fn.setreg('+', path)
    print('Copied: ' .. path)
end, {})

-- Format JSON in buffer
cmd('FormatJSON', function()
    vim.cmd('%!jq .')
end, {})
NVIMEOF
echo ""

# ---------------------------------------------------------------------------
echo "------------------------------------------------------------------"
echo "YOUR TURN - RUN IN NEOVIM:"
echo "------------------------------------------------------------------"
echo ""
echo "1. Check if file is modified:"
echo "   :lua print(vim.bo.modified)"
echo ""
echo "2. Get filetype:"
echo "   :lua print(vim.bo.filetype)"
echo ""
echo "3. Simple keymap:"
echo "   :lua vim.keymap.set('n', '<leader>t', ':echo \"test\"<CR>')"
echo ""
echo "------------------------------------------------------------------"
echo "KEY TAKEAWAYS:"
echo "1. vim.opt for options, vim.keymap.set for maps"
echo "2. vim.api.nvim_* for Neovim API"
echo "3. vim.fn.* for Vimscript functions"
echo "4. vim.cmd for Vimscript commands"
echo "5. 0 means current buffer/window in API calls"
echo "------------------------------------------------------------------"