← Назад к обзору

Treesitter и LSP

Treesitter

Tree-sitter обеспечивает инкрементальный парсинг исходного кода. Это даёт:

  • Точную подсветку синтаксиса
  • Текстовые объекты на основе структуры кода (функции, классы и т.д.)
  • Сворачивание кода
  • Автоматические отступы
{
  "nvim-treesitter/nvim-treesitter",
  build = ":TSUpdate",
  config = function()
    require("nvim-treesitter.configs").setup({
      ensure_installed = {
        "lua", "python", "javascript", "typescript",
        "go", "rust", "c", "cpp", "bash", "json", "yaml",
      },
      highlight = { enable = true },
      indent = { enable = true },
      incremental_selection = {
        enable = true,
        keymaps = {
          init_selection = "<C-space>",
          node_incremental = "<C-space>",
          scope_incremental = false,
          node_decremental = "<bs>",
        },
      },
    })
  end,
}

LSP (Language Server Protocol)

Neovim имеет встроенный LSP-клиент. Вы настраиваете языковые серверы и привязки клавиш.

Mason (менеджер LSP-серверов)

{
  "williamboman/mason.nvim",
  config = function()
    require("mason").setup()
  end,
},
{
  "williamboman/mason-lspconfig.nvim",
  config = function()
    require("mason-lspconfig").setup({
      ensure_installed = { "lua_ls", "pyright", "gopls", "rust_analyzer" },
    })
  end,
},
{
  "neovim/nvim-lspconfig",
  config = function()
    local lspconfig = require("lspconfig")
    local capabilities = require("cmp_nvim_lsp").default_capabilities()

    -- Настройка каждого установленного сервера
    require("mason-lspconfig").setup_handlers({
      function(server_name)
        lspconfig[server_name].setup({
          capabilities = capabilities,
        })
      end,
      -- Отдельная конфигурация для конкретных серверов
      ["lua_ls"] = function()
        lspconfig.lua_ls.setup({
          capabilities = capabilities,
          settings = {
            Lua = {
              diagnostics = { globals = { "vim" } },
            },
          },
        })
      end,
    })

    -- Глобальные привязки LSP (активны при подключении LSP)
    vim.api.nvim_create_autocmd("LspAttach", {
      callback = function(event)
        local opts = { buffer = event.buf }
        vim.keymap.set("n", "gd", vim.lsp.buf.definition, opts)
        vim.keymap.set("n", "gD", vim.lsp.buf.declaration, opts)
        vim.keymap.set("n", "gr", vim.lsp.buf.references, opts)
        vim.keymap.set("n", "gi", vim.lsp.buf.implementation, opts)
        vim.keymap.set("n", "K", vim.lsp.buf.hover, opts)
        vim.keymap.set("n", "<leader>rn", vim.lsp.buf.rename, opts)
        vim.keymap.set("n", "<leader>ca", vim.lsp.buf.code_action, opts)
        vim.keymap.set("n", "<leader>f", function()
          vim.lsp.buf.format({ async = true })
        end, opts)
        vim.keymap.set("n", "[d", vim.diagnostic.goto_prev, opts)
        vim.keymap.set("n", "]d", vim.diagnostic.goto_next, opts)
      end,
    })
  end,
}

Автодополнение с nvim-cmp

{
  "hrsh7th/nvim-cmp",
  dependencies = {
    "hrsh7th/cmp-nvim-lsp",    -- Дополнения от LSP
    "hrsh7th/cmp-buffer",       -- Дополнения из слов буфера
    "hrsh7th/cmp-path",         -- Дополнения путей
    "L3MON4D3/LuaSnip",         -- Движок сниппетов
    "saadparwaiz1/cmp_luasnip", -- Дополнения из сниппетов
  },
  config = function()
    local cmp = require("cmp")
    local luasnip = require("luasnip")

    cmp.setup({
      snippet = {
        expand = function(args)
          luasnip.lsp_expand(args.body)
        end,
      },
      mapping = cmp.mapping.preset.insert({
        ["<C-Space>"] = cmp.mapping.complete(),
        ["<C-e>"] = cmp.mapping.abort(),
        ["<CR>"] = cmp.mapping.confirm({ select = true }),
        ["<Tab>"] = cmp.mapping(function(fallback)
          if cmp.visible() then
            cmp.select_next_item()
          elseif luasnip.expand_or_jumpable() then
            luasnip.expand_or_jump()
          else
            fallback()
          end
        end, { "i", "s" }),
        ["<S-Tab>"] = cmp.mapping(function(fallback)
          if cmp.visible() then
            cmp.select_prev_item()
          elseif luasnip.jumpable(-1) then
            luasnip.jump(-1)
          else
            fallback()
          end
        end, { "i", "s" }),
      }),
      sources = cmp.config.sources({
        { name = "nvim_lsp" },
        { name = "luasnip" },
        { name = "path" },
      }, {
        { name = "buffer" },
      }),
    })
  end,
}

Нечёткий поиск и навигация по файлам

Telescope

Telescope — стандартный нечёткий поисковик.

{
  "nvim-telescope/telescope.nvim",
  branch = "0.1.x",
  dependencies = {
    "nvim-lua/plenary.nvim",
    { "nvim-telescope/telescope-fzf-native.nvim", build = "make" },
  },
  keys = {
    { "<leader>ff", "<cmd>Telescope find_files<cr>", desc = "Найти файлы" },
    { "<leader>fg", "<cmd>Telescope live_grep<cr>", desc = "Поиск по тексту" },
    { "<leader>fb", "<cmd>Telescope buffers<cr>", desc = "Найти буферы" },
    { "<leader>fh", "<cmd>Telescope help_tags<cr>", desc = "Документация" },
    { "<leader>fs", "<cmd>Telescope lsp_document_symbols<cr>", desc = "Символы документа" },
    { "<leader>fw", "<cmd>Telescope grep_string<cr>", desc = "Найти слово под курсором" },
  },
  config = function()
    local telescope = require("telescope")
    telescope.setup()
    telescope.load_extension("fzf")
  end,
}

Основные «пикеры» Telescope

ПикерОписание
find_filesНечёткий поиск файлов в проекте
live_grepПоиск текста по всем файлам проекта
buffersСписок и переключение между открытыми буферами
help_tagsПоиск по документации Neovim
grep_stringПоиск слова под курсором
oldfilesСписок недавно открытых файлов
diagnosticsПоказать диагностику LSP
git_filesСписок файлов, отслеживаемых git