Bookmarks em Neovim

Eu percorro muitos arquivos quando trabalho, principalmente ao resolver bugs ou rastrear comportamentos. Eu criei um sistema de marcadores (bookmarks) no Neovim para navegar mais rápido entre arquivos. Esse sistema difere do sistema padrão do Neovim, pois foca em marcar arquivos e linhas, não apenas posições dentro do mesmo arquivo.

Funcionamento

O sistema registra o caminho do arquivo e a linha atual em um arquivo texto. Eu uso a tecla <leader>o para abrir todos os arquivos marcados. Eu uso a tecla <leader>m para marcar um arquivo. Eu também uso o comando :Clearmarks para limpar todos os marcadores quando termino um trabalho ou inicio outro.

Implementação

A função Mark_point grava o caminho do arquivo e a linha atual no final de um arquivo texto. Ela cria esse arquivo, se ele não existir.

function Mark_point()
  local home = os.getenv("HOME")
  local file_marks = home .. "/marks.txt"

  local file = vim.fn.expand('%:p') -- caminho completo
  local line = vim.fn.line('.')     -- número da linha atual

  local mark = file .. " +" .. line

  local file_handle = io.open(file_marks, "a")
  if file_handle then
    file_handle:write(mark .. "\n")
    file_handle:close()
    print("Marked: " .. mark)
    return
  end
  print("Erro ao abrir o arquivo de marcação: " .. file_marks)
end

A função Open_mark lê o arquivo de marcação, abre o arquivo e salta para a linha marcada. Ela primeiro salta para o início do arquivo com gg e depois para a linha desejada com G.

function Open_mark(marks_file)
  local file = io.open(marks_file, "r")
  if not file then
    -- print("Erro ao abrir o arquivo de marcação: " .. marks_file)
    return
  end

  for line in file:lines() do
    local file_path, line_number = string.match(
        line, "^(.-)%s+%+(%d+)$")
    vim.cmd('edit ' .. file_path)
    vim.cmd('normal gg')
    vim.cmd('normal ' .. line_number .. 'G')
  end
  file:close()
end

Criei a função Open_marks para abrir arquivos marcados no diretório do usuário e no diretório atual.

function Open_marks()
  local path = os.getenv("HOME")
  local marks_file = path .. "/marks.txt"
  Open_mark(marks_file)

  path = vim.fn.getcwd()
  marks_file = path .. "/marks.txt"
  Open_mark(marks_file)
end

A função Clear_marks remove os arquivos de marcação do diretório do usuário e do diretório atual.

function Clear_marks()
  local path = os.getenv("HOME")
  local marks_file = path .. "/marks.txt"
  os.remove(marks_file)

  path = vim.fn.getcwd()
  marks_file = path .. "/marks.txt"
  os.remove(marks_file)
end

Configurei teclas de atalho e um comando do Neovim para chamar as funções.

vim.api.nvim_set_keymap(
  'n', '<leader>o', ':lua Open_marks()<CR>',
  { noremap = true, silent = true }
)
vim.api.nvim_set_keymap(
  'n', '<leader>m', ':lua Mark_point()<CR>',
  { noremap = true, silent = true }
)
vim.api.nvim_command(
  'command! Clearmarks lua Clear_marks()'
)

Código fonte completo

Arquivo de Marcação

Guardo as marcações em um arquivo texto simples. Dessa forma é simples criar scripts para interagir com esses marcadores, sem precisar abrir o Neovim. Segue um exemplo em Bash:

#!/usr/bin/env bash

INITIAL_QUERY="${*:-}"

MARKS_FILES=("$HOME/marks.txt")
[ -f "./marks.txt" ] && \
    MARKS_FILES+=("./marks.txt")

IFS='+' read -r file_path line_number <<< "$(
    cat "${MARKS_FILES[@]}" | \
    fzf --ansi \
        --delimiter '+' \
        --preview 'bat --color=always {1} --highlight-line {2}' \
        --preview-window 'up,60%,border-bottom,+{2}+3/3,~3' \
        --query "$INITIAL_QUERY"
)"

[ -n "$file_path" ] && {
    file_path=$(echo "$file_path" | xargs)
    line_number=$(echo "$line_number" | xargs)
    "$EDITOR" "$file_path" "+$line_number"
    echo "$file_path" "+$line_number"
}

Código fonte

Esse script lê o arquivo de bookmarks, permite a seleção de um arquivo e o abre no Neovim na linha marcada. Ele usa o fzf para interagir com o usuário e o bat para visualizar o arquivo.

Conclusão

Eu prefiro pequenas ferramentas que executam tarefas específicas de forma eficiente. Elas são fáceis de combinar ou modificar, deixando meu dia a dia mais produtivo e agradável.

Até a próxima!

Referências

Cesar Gimenes

Última modificação