Introduction

Welcome to Learn Neovim The Hard Way, a book for those who believe in the power of persistence and repetition. Inspired by Steve Losh’s excellent Learn Vimscript the Hard Way, this book follows the same philosophy: there are no shortcuts to MASTERY. Learning Neovim requires focus, patience, and a commitment to practice.

The method is straightforward:

  • learn one thing
  • practice until you can do it without thinking
  • repeat once
  • repeat twice
  • repeat thrice
  • still not enough?
  • repeat repeat repeat
  • well... you get the point

Each chapter presents a new skill, but the key is to not rush. Take at least a few days to repeat the exercises, letting the actions become automatic to the point where your finger moves without thinking about it before moving to the next skill. Mastery isn’t achieved by speeding through content, but by building strong, lasting habits through repetition, more repetition, and yes, even more repetition.

This approach emphasizes the importance of slow but steady learning. By taking your time, practicing consistently, and committing each skill to muscle memory, you'll gradually transition into using Neovim as your daily tool without even realizing it. If you’ve ever gone through tutorials that left you overwhelmed with information and didn’t change your workflow at all, this book is your friend. No more consuming endless tutorials without real progress—Learn Neovim The Hard Way forces you to slow down, focus, and truly learn.

Remember, there’s no fast track to MASTERY. Just focused effort, one small step at a time. You’ll need to repeat the same tasks over and over, and there’s no way around that. PERIOD. This may seem like a slow process, but the long-term rewards are immense. Why? Because once you master Neovim, you’ll be spending so much of your time using it. As a programmer—or someone aspiring to be one—you’ll be writing code for the rest of your career. So, why not invest a little time now to master the tool that will shape your entire workflow?

Even if it takes a year (just for argument’s sake), what is that compared to the decades you’ll spend writing code? Neovim enhances the joy of coding and keeps improving every year. It’s a small investment if you plan to code for life. Plus, let’s be honest—using Neovim puts you in the ranks of the programmer's elite. (People really do get impressed when they hear you're using Neovim 😎.)

So buckle up because this journey will take time...

Opening and Closing Neovim

First we have to be able to open Neovim before we can use it. To start Neovim, simply open a terminal and type:

nvim

Info

Notice that it is nvim and not neovim

You should see a welcome screen like the picture below:

img

To close Neovim, press ZZ. It should exit Neovim and take you back to the shell. There are many other ways to close Neovim but I think this is the simplest. Just need to know one anyway. If you are cusious Google can give you more than enough materials to read. Let's keep our lesson short and sweet.

Summary

  • nvim
  • ZZ

Moving The Cursor with hjkl

In Neovim, the most basic way to move around is by using the hjkl keys.

Here’s what each key does with the finger to press:

⬅️ h: index finger
⬇️ j: index finger
⬆️ k: middle finger
➡️ l: ring finger

img

Make sure that your index finger is always on the letter j. So even after you move the finger to the left to press h, it should go back to the letter j immediately after.

Spend at least a few days getting used to moving around with hjkl with the exercise below. Your fingers need to build muscle memory, so repetition is essential. You’ll know you’ve mastered this when your fingers press the right keys without consciously thinking about it.

Remember: mastery is built through steady, consistent effort.

  1. Learn one thing
  2. Practice until you can do it without thinking
  3. Repeat Repeat Repeat

Exercise

  1. Install Vimium Extension
  2. Use jk to scroll whenver you are viewing a web page
  3. Keep doing it
  4. Do not go to the next page until it becomes automatic

Cursor

General

Cursor Highlighting and Behavior

  • How do I highlight the cursor line in Neovim using the API?
  • How do I customize the cursor shape (e.g., block, underline, beam) in Neovim?
  • How do I ensure the cursor position is visible in the current viewport?
  • How can I highlight or visually mark the current cursor position?
  • How do I prevent the cursor from moving to the wrong position when switching modes?

Visual Mode and Text Objects

  • How do I get the current cursor range in visual mode using the API?
  • How do I determine the text object under the cursor?
  • How can I programmatically adjust the visual selection based on the cursor position?
  • How do I programmatically extend a visual selection using the cursor?

Multicursor

  • Does Neovim support multiple cursors natively through the API?
  • How can I simulate multiple cursors programmatically in Neovim?
  • How do plugins like vim-visual-multi implement multiple cursors?

Cursor and Windows

  • How do I move the cursor between windows programmatically?
  • How do I ensure the cursor position is maintained when switching between splits?
  • How can I scroll a window to center the cursor programmatically?
  • How do I move the cursor in a floating window using the Neovim API?

Cursor and Buffers

  • How do I get the cursor position in a specific buffer?
  • How do I set the cursor position in a different buffer?
  • How can I programmatically restore the cursor position in a buffer after reopening it?

Cursor Events

  • How do I detect when the cursor moves using autocommands or the API?
  • How can I execute a function every time the cursor moves?
  • How do I handle CursorHold and CursorMoved events programmatically?
  • How do I trigger custom actions based on the cursor's position?

Cursor Styling

  • How do I customize the cursor style in Neovim?
  • How can I make the cursor blink programmatically?
  • How do I change the cursor style for different modes (e.g., insert, normal, visual)?
  • How do I create a cursor trail or animation using the API?

Cursor and Searching

  • How do I move the cursor to the next search match programmatically?
  • How can I highlight all occurrences of a word under the cursor?
  • How do I programmatically search for a word and place the cursor at the first match?
  • How do I move the cursor to the previous search result?

Troubleshooting

  • Why does the cursor position change unexpectedly in some cases?
  • How do I handle cursor jumps caused by plugins or custom configurations?
  • Why does the cursor move out of the visible viewport during execution?
  • How do I reset the cursor to its previous position after executing a function?
  • How can I fix issues where the cursor position is incorrect after resizing the window?

Miscellaneous

  • How do I center the cursor in the viewport programmatically?
  • How do I detect if the cursor is at the end of the file?
  • How do I retrieve the character under the cursor using the Neovim API?
  • How do I prevent the cursor from moving during a specific operation?
  • How do I move the cursor relative to a specific mark or location in the buffer?

How to Get the Current Cursor Position using Neovim's Lua API

Learn how to retrieve and display the current cursor position using Neovim Api. This guide provides step-by-step instructions with a code example, making it easy to use this code in your Neovim Plugin.

What is vim.api.nvim_win_get_cursor?

The vim.api.nvim_win_get_cursor function in Neovim retrieves the current cursor position in a specified window.

Function Signature

  • vim.api.nvim_win_get_cursor(win_id) -> { line, column }

Parameters:

  • win_id: The ID of the window to query. Use 0 for the current window.

Returns:

  • { line, column }
    • The line number (1-based).
    • The column number (0-based).

Example

-- Function to retrieve and display the current cursor position
local function print_cursor_position()

  -- Get the current cursor position in the current window
  local cursor_pos = vim.api.nvim_win_get_cursor(0)
  local line = cursor_pos[1] -- 1-based line number
  local col = cursor_pos[2] -- 0-based column number

  -- Display the cursor position in the command line
  print("Cursor Position: Line " .. line .. ", Column " .. col)
end

-- Map the function to a key
vim.keymap.set('n', ',,', print_cursor_position, { desc = "Print cursor position" })

-- Or execute it inside the function
vim.keymap.set('n', ',,', function()
    print_cursor_position()
end, { desc = "Print cursor position" })

How to Set the Cursor Position Using Neovim's Lua API

Learn how to programmatically set the cursor position in a Neovim buffer using its Lua API. This guide provides step-by-step instructions with a code example, making it easy to integrate into your Neovim configuration or plugin.

What is vim.api.nvim_win_set_cursor?

The vim.api.nvim_win_set_cursor function in Neovim allows you to set the cursor position in a specified window.

Function Signature

  • vim.api.nvim_win_set_cursor(win_id, { line, column }) -> nil

Parameters:

  • win_id: The ID of the window to manipulate. Use 0 for the current window.
  • { line, column }
    • The line number (1-based).
    • The column number (0-based).

Returns:

  • nil

Example

-- Example usage: Jump to line 10, column 5
local function jump()
  vim.api.nvim_win_set_cursor(0, { 10, 5 }) -- 0 is the ID of the current window
end

-- Map the function to a key
vim.keymap.set('n', ',,', jump, { desc = "Set cursor position" })

-- Or execute it inside the function
vim.keymap.set('n', ',,', function()
    jump()
end, { desc = "Set cursor position" })

How to Move the Cursor to a Specific Line using Neovim's Lua API

Learn how to programmatically move the cursor to a specific line in a file using Neovim API. This guide provides detailed instructions with a code example to help you integrate it into your Neovim configuration or plugin.

What is vim.api.nvim_win_set_cursor?

The vim.api.nvim_win_set_cursor function allows you to set the cursor's position in a specified window programmatically.

Function Signature

  • vim.api.nvim_win_set_cursor(win_id, { line, column }) -> nil

Parameters:

  • win_id: The ID of the window where the cursor will be moved. Use 0 for the current window.
  • { line, column }: A table containing:
    • line (1-based): The target line number.
    • column (0-based): The target column number.

Returns:

  • nil

Example

-- Function to move the cursor to Line 10
local function move_to_line_10()
  vim.api.nvim_win_set_cursor(0, { 10, 0 }) -- 0 is the ID of the current window
end

-- Map the function to a key
vim.keymap.set('n', ',,', move_to_line_10, { desc = "Move cursor to line 10" })

-- Or execute it inside the function
vim.keymap.set('n', ',,', function()
    move_to_line_10()
end, { desc = "Move cursor to Line 10" })

How to Move the Cursor Up or Down Using Neovim's Lua API

There are two ways to move the cursor up or down using Neovim's Lua API:

How to Move the Cursor Up or Down Using vim.api

Learn how to programmatically move the cursor up or down using vim.api.nvim_win_get_cursor and vim.api.nvim_win_set_cursor. This guide includes a code example to make it easy to integrate into your Neovim configuration or plugin.

APIs Required:

To move the cursor, you'll need to combine the vim.api.nvim_win_get_cursor function (to get the current cursor position) with the vim.api.nvim_win_set_cursor function (to set the new cursor position).

1. vim.api.nvim_win_get_cursor

Retrieves the current cursor position in a specified window.

  • Signature: vim.api.nvim_win_get_cursor(win_id) -> { line, column }
  • Parameters:
    • win_id: Use 0 for the current window.
  • Returns:
    • { line, column }: the position of the cursor as a table with the line number (1-based) and column number (0-based).

2. vim.api.nvim_win_set_cursor

Sets the cursor position in a specified window.

  • Signature: vim.api.nvim_win_set_cursor(win_id, { line, column }) -> nil
  • Parameters:
    • win_id: Use 0 for the current window.
    • { line, column }: the new position of the cursor as a table with the line number (1-based) and column number (0-based).

Example: Move the Cursor Up or Down

-- Function to move the cursor by a specified number of lines
local function move_cursor(offset)

  -- Get the current cursor position
  local cursor_pos = vim.api.nvim_win_get_cursor(0)
  local current_line = cursor_pos[1] -- 1-based line number
  local current_col = cursor_pos[2] -- 0-based column number

  -- Calculate the new line position
  local new_line = current_line + offset

  -- Update the cursor position
  vim.api.nvim_win_set_cursor(0, { new_line, current_col })
end

-- Example: Move the cursor 5 lines down
vim.keymap.set('n', '<leader>j', function() 
  move_cursor(5)
end, { desc = "Move cursor down by 5 lines" })

-- Example: Move the cursor 5 lines up
vim.keymap.set('n', '<leader>k', function()
  move_cursor(-5)
end, { desc = "Move cursor up by 5 lines" })

How to Move the Cursor Up or Down Using feedkeys

Learn how to programmatically move the cursor up and down using Neovim's feedkeys function. This guide provides an example for invoking normal mode commands through Lua, enabling you to manipulate the cursor efficiently.

What is vim.api.nvim_feedkeys?

The vim.api.nvim_feedkeys function allows you to simulate key presses in Neovim, making it a versatile tool for programmatically invoking commands.

Function Signature

  • vim.api.nvim_feedkeys(keys, mode, escape_ks)

Parameters:

  • keys: A string representing the key sequence to simulate.
  • mode: A string indicating the mode to execute the keys (e.g., "n" for normal mode).
  • escape_ks: A boolean or string determining whether the key sequences should escape special characters.

Example: Moving the Cursor Up or Down

-- Function to move the cursor up by a specified number of lines
local function move_cursor_up(lines)
  vim.api.nvim_feedkeys(tostring(lines) .. "k", "n", false)
end

-- Function to move the cursor down by a specified number of lines
local function move_cursor_down(lines)
  vim.api.nvim_feedkeys(tostring(lines) .. "j", "n", false)
end

-- Example usage: Move the cursor up by 5 lines
vim.keymap.set('n', '<leader>k', function()
  move_cursor_up(5)
end, { desc = "Move cursor up by 5 lines" })

-- Example usage: Move the cursor down by 5 lines
vim.keymap.set('n', '<leader>j', function()
  move_cursor_down(5)
end, { desc = "Move cursor down by 5 lines" })

Keymap

How to Map a Key to a Lua Function in Neovim

Learn how to set a keymap to invoke a Lua function in Neovim. This guide provides step-by-step instructions with a code example, making it easy to integrate Lua functions into your Neovim Plugin.

What is vim.keymap.set?

The vim.keymap.set function in Neovim is a modern and flexible way to create key mappings. It allows you to map a key directly to a Lua function, providing seamless integration with Lua scripting.

Function Signature

  • vim.keymap.set(mode, lhs, rhs, opts) -> nil

Parameters:

  • mode: The mode(s) in which the key mapping applies (e.g., 'n' for normal mode, 'i' for insert mode).
  • lhs: The key sequence to trigger the mapping (left-hand side).
  • rhs: The Lua function to execute or a string representing a command (right-hand side).
  • opts (optional): A table of options to customize the mapping.

Common Options

  • desc: A description of the mapping (useful for documentation in :map output).
  • silent: Suppress command echo (default false).
  • noremap: Prevent remapping (default true).

Example

-- Define a Lua function
local function greet_user()
  print("Hello, welcome to Neovim!")
end

-- Map the function to the key
vim.keymap.set('n', ',,', greet_user, { desc = "Greet the user" })

-- Or execute it inside the function
vim.keymap.set('n', ',,', function()
  greet_user()
end, { desc = "Greet the user" })

Text

How to Get the Current Line Content using Neovim's Lua API

Learn how to retrieve the content of the current line in a Neovim buffer using its Lua API. This guide provides a simple code example for seamless integration into your Neovim configurations or plugins.

What is vim.api.nvim_get_current_line?

The vim.api.nvim_get_current_line function retrieves the content of the current line where the cursor is positioned.

Function Signature

  • vim.api.nvim_get_current_line() -> string

Returns:

  • string
    • The content of the current line as a string.

Example

-- Function to retrieve and display the current line content
local function print_current_line_content()

  -- Get the content of the current line
  local line_content = vim.api.nvim_get_current_line()

  -- Display the current line content in the command line
  print("Current Line Content: " .. line_content)
end

-- Map the function to a key
vim.keymap.set('n', ',,', print_current_line_content, { desc = "Print current line content" })

-- Or execute it inside the function
vim.keymap.set('n', ',,', function()
    print_current_line_content()
end, { desc = "Print current line content" })

Lua

Meta Methods

How to Handle Missing Keys in Lua Tables Using __index

Learn how to define custom behavior for missing keys in Lua tables using the __index metamethod. This guide provides step-by-step instructions with a code example, making it easy to implement in your Lua scripts.

What is the __index Metamethod?

The __index metamethod in Lua allows you to customize what happens when a missing key is accessed in a table. By setting it to a function, you can define dynamic or default behavior.

Function Signature

  • function(tbl, key) -> value

Parameters:

  • tbl: The table being accessed.
  • key: The key that is missing in the table.

Returns:

  • value
    • The result that Lua returns when the missing key is accessed.

Example

-- Table representing a basic inventory
inventory = {
  apple = 5,
  banana = 10,
}

-- Define a metatable with an __index function
setmetatable(inventory, {
  -- when the key does not exist in inventory table, invoke this function
  -- tbl is the inventory table
  -- key is the missing key eg. mango or orange
  __index = function(tbl, key)
    print("Item '" .. key .. "' is not in the inventory.")
    -- return a default value
    return 0
  end
})

-- Example usage
print(inventory.apple)   -- Exists, prints 5
print(inventory.banana)  -- Exists, prints 10
print(inventory.mango)   -- Missing, calls __index
print(inventory.orange)  -- Missing, calls __index

Lazy Loading in Lua with Plenary.nvim

Plenary.nvim, a popular Lua library for Neovim, uses the __index metamethod to implement lazy loading. Lazy loading allows you to defer loading a module or resource until it is accessed, optimizing performance and reducing initial load times.

How Does Plenary Use __index for Lazy Loading?

Plenary utilizes the __index metamethod to dynamically load modules when they are accessed for the first time. The loaded modules are cached to avoid repeated lookups.

Function Signature for __index

  • function(tbl, key) -> value

Parameters:

  • tbl: The table being accessed.
  • key: The key that is missing in the table.

Returns:

  • value
    • The dynamically loaded module or resource.

Simplified Example: Lazy Loading with __index

For this example, we create a dummy plenary plugin.

-- plenary/lua/plenary/init.lua
local M = {}

return M

It also has an empty submodule.

-- plenary/lua/plenary/a.lua
local M = {}

return M

This is init.lua calling the dummy plenary plugin.

local plenary = require("plenary") -- assuming plenary is an empty table

setmetatable(plenary, {
  __index = function(tbl, key)
    -- load the submodule
    local module = require("plenary." .. key)

    -- store the submodule in the plenary table
    rawset(tbl, key, module)
    return module
  end
})

-- plenary table starts with just a metatable
vim.print(plenary)
-- {
--   <metatable> = {
--     __index = <function>,
--   }
-- }

-- Triggers __index, require "plenary.a" and insert it into plenary table
vim.print(plenary.a) -- {}

-- now plenary table has "a" with the loaded submodule
vim.print(plenary)
-- {
--   <metatable> = {
--     __index = <function>,
--   }
--   a = <submodule returned by require "plenary.a">
-- }

-- From the second time onwards, it does not trigger __index
-- because the submodule is already in the table
vim.print(plenary.a) -- {}

Providing Default User Config with __index

Using Lua's __index metamethod, you can provide default values for user configurations in your Neovim plugins or scripts. This pattern is particularly useful for maintaining flexibility while ensuring that critical configurations are always available.

Why Use __index for Default Configs?

When creating a plugin or script, you often need to handle user-defined configurations. However, not every user will define all the options you expect. With __index, you can set default values for missing configurations while allowing users to override them.

Function Signature for __index

  • function(tbl, key) -> value

Parameters:

  • tbl: The table being accessed.
  • key: The key that is missing in the table.

Returns:

  • value
    • The default value for the missing key.

Example: Providing Default Configurations

Here’s an example of using __index to provide default values for user configurations:

-- Default configuration table
local defaults = {
  theme = "dark",
  auto_save = false,
  max_tabs = 10,
}

-- User configuration table (can be partially filled)
local user_config = {
  auto_save = true, -- User overrides this setting
}

-- Set up a metatable to use defaults for missing keys
setmetatable(user_config, {
  __index = function(tbl, key)
    -- lookup the missing key from the defaults table
    return defaults[key]
  end
})

-- Example usage
print(user_config.theme)     -- theme is missing, use the default -> "dark"
print(user_config.max_tabs)  -- max_tabs is missing, use the default -> 10

print(user_config.auto_save) -- auto_save is in the user config -> true

How to Use __call Metamethod in Lua

Learn how to define custom behavior for tables so they can be called like functions using the __call metamethod. This guide provides step-by-step instructions with a code example, making it easy to implement in your Lua scripts.

What is the __call Metamethod?

The __call metamethod in Lua allows you to customize what happens when a table is used as a function. By setting it in a table's metatable, you can define dynamic behavior when the table is invoked as a callable object.

Function Signature

  • function(tbl, ...) -> value

Parameters:

  • tbl: The table being accessed.
  • ...: Any arguments passed to the function.

Returns:

  • value
    • The result that Lua returns when the table is invoked as a function.

Example

-- Define a table with a metatable implementing __call
local CallableTable = {}

-- Set the metatable
setmetatable(CallableTable, {
  __call = function(self, ...)
    return "Called with " .. table.concat({...}, ", ")
  end
})

-- Use the table as a function
print(CallableTable("Lua", "arg1", "arg2"))  -- Output: Called with Lua, arg1, arg2

Eliminates Explicit Function Calls with __call

When using __call, you no longer need to explicitly reference a method or function name. This reduces verbosity and results in a cleaner syntax, particularly in scenarios where repeated calls are necessary.

Function Signature

  • function(tbl, ...) -> value

Parameters:

  • tbl: The table being accessed.
  • ...: Any arguments passed to the function.

Returns:

  • value
    • The result that Lua returns when the table is invoked as a function.

Example Without Using __call:

local Logger = {}

function Logger.log(message, level)
  level = level or "INFO"
  print("[" .. level .. "]: " .. message)
end

-- Use the Logger via a method call
Logger.log("System initialized.")         -- Output: [INFO]: System initialized.
Logger.log("Disk space low.", "WARNING")  -- Output: [WARNING]: Disk space low.

Example Using __call:

local Logger = {}

setmetatable(Logger, {
  __call = function(self, message, level)
    level = level or "INFO"
    print("[" .. level .. "]: " .. message)
  end
})

-- Use the Logger directly
Logger("System initialized.")         -- Output: [INFO]: System initialized.
Logger("Disk space low.", "WARNING")  -- Output: [WARNING]: Disk space low.

Using __call for Matrix Operations in Lua

Let's see how we can use __call to make retrieving the elements of a matrix look more intuitive.

Implementation Without __call:

Normally it would look something like this:

-- Define a Matrix table
local M = {}

-- Initialize the matrix
M.data = {
  {1, 2, 3},
  {4, 5, 6},
  {7, 8, 9}
}

-- Function to access matrix elements
function M.get(row, col)
  return M.data[row][col]
end

-- We have to call get function
print(M.get(0, 1))  -- Output: 2
print(M.get(1, 2))  -- Output: 6

However scientists would probably expect something like this:

print(M(0, 1))  -- Output: 2
print(M(1, 2))  -- Output: 6

Implementation With __call:

-- Matrix metatable implementing __call
setmetatable(Matrix, {
  __call = function(self, row, col)
    return self.data[row][col]
  end
})

-- Access matrix elements using __call
print(M(0, 1))  -- Output: 2
print(M(1, 2))  -- Output: 6

Cursor

Cómo Obtener la Posición Actual del Cursor Usando la API de Lua de Neovim

Aprende a recuperar y mostrar la posición actual del cursor usando la API de Neovim. Esta guía proporciona instrucciones paso a paso con un ejemplo de código, facilitando el uso de este código en tu plugin de Neovim.

¿Qué es vim.api.nvim_win_get_cursor?

La función vim.api.nvim_win_get_cursor en Neovim recupera la posición actual del cursor en una ventana especificada.

Firma de la Función

  • vim.api.nvim_win_get_cursor(win_id) -> { línea, columna }

Parámetros:

  • win_id: El ID de la ventana a consultar. Usa 0 para la ventana actual.

Retorno:

  • { línea, columna }
    • El número de línea (comienza en 1).
    • El número de columna (comienza en 0).

Ejemplo

-- Función para obtener y mostrar la posición actual del cursor
local function print_cursor_position()

  -- Obtiene la posición actual del cursor en la ventana actual
  local cursor_pos = vim.api.nvim_win_get_cursor(0)
  local line = cursor_pos[1] -- Número de línea basado en 1
  local col = cursor_pos[2] -- Número de columna basado en 0

  -- Muestra la posición del cursor en la línea de comandos
  print("Posición del cursor: Línea " .. line .. ", Columna " .. col)
end

-- Asigna la función a una tecla
vim.keymap.set('n', ',,', print_cursor_position, { desc = "Imprimir posición del cursor" })

-- O ejecútala dentro de la función
vim.keymap.set('n', ',,', function()
    print_cursor_position()
end, { desc = "Imprimir posición del cursor" })

Cómo Establecer la Posición del Cursor Usando la API de Lua de Neovim

Aprende a establecer programáticamente la posición del cursor en un buffer de Neovim utilizando su API de Lua. Esta guía proporciona instrucciones paso a paso con un ejemplo de código, haciéndolo fácil de integrar en tu configuración o plugin de Neovim.

¿Qué es vim.api.nvim_win_set_cursor?

La función vim.api.nvim_win_set_cursor en Neovim permite establecer la posición del cursor en una ventana específica.

Firma de la Función

  • vim.api.nvim_win_set_cursor(win_id, { line, column }) -> nil

Parámetros:

  • win_id: El ID de la ventana a manipular. Usa 0 para la ventana actual.
  • { line, column }
    • El número de línea (base 1).
    • El número de columna (base 0).

Retorna:

  • nil

Ejemplo

-- Ejemplo de uso: Saltar a la línea 10, columna 5
local function jump()
  vim.api.nvim_win_set_cursor(0, { 10, 5 }) -- 0 es el ID de la ventana actual
end

-- Asigna la función a una tecla
vim.keymap.set('n', ',,', jump, { desc = "Establecer posición del cursor" })

-- O ejecútala dentro de la función
vim.keymap.set('n', ',,', function()
    jump()
end, { desc = "Establecer posición del cursor" })

Cómo Mover el Cursor a una Línea Específica Usando el API de Lua de Neovim

Aprende cómo mover el cursor a una línea específica en un buffer de Neovim usando su API de Lua. Este tutorial te guía paso a paso con un ejemplo de código, lo que facilita integrar este código en tu configuración o plugin de Neovim.

¿Qué es vim.api.nvim_win_set_cursor?

La función vim.api.nvim_win_set_cursor en Neovim permite establecer la posición del cursor en una ventana específica.

Firma de la Función

  • vim.api.nvim_win_set_cursor(win_id, { line, column }) -> nil

Parámetros:

  • win_id: El ID de la ventana que deseas manipular. Usa 0 para la ventana actual.
  • { line, column }
    • El número de línea (base 1).
    • El número de columna (base 0).

Devuelve:

  • nil

Ejemplo

-- Función para mover el cursor a la línea 10
local function move_to_line_10()
  vim.api.nvim_win_set_cursor(0, { 10, 0 }) -- 0 es el ID de la ventana actual
end

-- Asigna la función a una tecla
vim.keymap.set('n', ',,', move_to_line_10, { desc = "Mover el cursor a la línea 10" })

-- O ejecútala dentro de la función
vim.keymap.set('n', ',,', function()
    move_to_line_10()
end, { desc = "Mover el cursor a la línea 10" })

Cómo Mover el Cursor Hacia Arriba o Abajo Usando la API de Lua de Neovim

Aprende cómo mover programáticamente el cursor hacia arriba o abajo un número especificado de líneas usando la API de Lua de Neovim. Esta guía incluye un ejemplo de código para facilitar su integración en tu configuración de Neovim o en un plugin.

APIs Necesarias:

Para mover el cursor, necesitas combinar la función vim.api.nvim_win_get_cursor (para obtener la posición actual del cursor) con la función vim.api.nvim_win_set_cursor (para establecer la nueva posición del cursor).

1. vim.api.nvim_win_get_cursor

Obtiene la posición actual del cursor en una ventana especificada.

  • Firma: vim.api.nvim_win_get_cursor(win_id) -> { line, column }
  • Parámetros:
    • win_id: Usa 0 para la ventana actual.
  • Devuelve:
    • { line, column }: la posición del cursor como una tabla con el número de línea (basado en 1) y el número de columna (basado en 0).

2. vim.api.nvim_win_set_cursor

Establece la posición del cursor en una ventana especificada.

  • Firma: vim.api.nvim_win_set_cursor(win_id, { line, column }) -> nil
  • Parámetros:
    • win_id: Usa 0 para la ventana actual.
    • { line, column }: la nueva posición del cursor como una tabla con el número de línea (basado en 1) y el número de columna (basado en 0).

Ejemplo: Mover el Cursor Hacia Arriba o Abajo

-- Función para mover el cursor un número especificado de líneas
local function move_cursor(offset)

  -- Obtiene la posición actual del cursor
  local cursor_pos = vim.api.nvim_win_get_cursor(0)
  local current_line = cursor_pos[1] -- Número de línea basado en 1
  local current_col = cursor_pos[2] -- Número de columna basado en 0

  -- Calcula la nueva posición de línea
  local new_line = current_line + offset

  -- Actualiza la posición del cursor
  vim.api.nvim_win_set_cursor(0, { new_line, current_col })
end

-- Ejemplo: Mover el cursor 5 líneas hacia abajo
vim.keymap.set('n', '<leader>j', function() 
  move_cursor(5)
end, { desc = "Mover el cursor hacia abajo 5 líneas" })

-- Ejemplo: Mover el cursor 5 líneas hacia arriba
vim.keymap.set('n', '<leader>k', function()
  move_cursor(-5)
end, { desc = "Mover el cursor hacia arriba 5 líneas" })

Cómo Mover el Cursor Arriba y Abajo Usando feedkeys en la API de Lua de Neovim

Aprende cómo mover el cursor programáticamente hacia arriba y abajo utilizando la función feedkeys de Neovim. Esta guía proporciona un ejemplo de cómo invocar comandos en modo normal a través de Lua, permitiéndote manipular el cursor de manera eficiente.

¿Qué es vim.api.nvim_feedkeys?

La función vim.api.nvim_feedkeys te permite simular pulsaciones de teclas en Neovim, convirtiéndola en una herramienta versátil para invocar comandos de forma programada.

Firma de la función

  • vim.api.nvim_feedkeys(keys, mode, escape_ks)

Parámetros:

  • keys: Una cadena que representa la secuencia de teclas a simular.
  • mode: Una cadena que indica el modo en el que se ejecutarán las teclas (por ejemplo, "n" para modo normal).
  • escape_ks: Un booleano o cadena que determina si las secuencias de teclas deben escapar caracteres especiales.

Ejemplo: Mover el Cursor Arriba y Abajo

-- Función para mover el cursor hacia arriba un número específico de líneas
local function move_cursor_up(lines)
  vim.api.nvim_feedkeys(tostring(lines) .. "k", "n", false)
end

-- Función para mover el cursor hacia abajo un número específico de líneas
local function move_cursor_down(lines)
  vim.api.nvim_feedkeys(tostring(lines) .. "j", "n", false)
end

-- Ejemplo de uso: Mover el cursor hacia arriba 5 líneas
vim.keymap.set('n', '<leader>k', function()
  move_cursor_up(5)
end, { desc = "Mover cursor hacia arriba 5 líneas" })

-- Ejemplo de uso: Mover el cursor hacia abajo 5 líneas
vim.keymap.set('n', '<leader>j', function()
  move_cursor_down(5)
end, { desc = "Mover cursor hacia abajo 5 líneas" })