No description
Find a file
2024-12-24 12:09:16 +01:00
config Entferne whichkey 2024-12-24 12:09:16 +01:00
.editorconfig Füge .editorconfig hinzu 2024-08-15 21:20:37 +02:00
README.md Benutze doch wieder cmp 2024-12-24 11:38:14 +01:00

NeoVim - Konfig-Bastelstunde

ℹ️ Falls du Probleme hast, schaue hier nach.

Einleitung

Im Workshop erstellst du deine erste NeoVim Konfig per Hand. Du kannst die Anleitung eigenständig Schritt für Schritt durcharbeiten.

Was du hier machen wirst:

  • Eine Grundstruktur anlegen
  • Einige praktische Konfig-Optionen kennenlernen
  • Erste Key Mappings erstellen
  • Ein paar Plugins installieren
  • Einen Language Server mit live Diagnostics und Autocompletion für Python oder TypeScript einrichten (andere Sprachen gehen auch)

Bei Fragen geb einfach Bescheid :)
(wenn du nicht live im Workshop sitzt, dann melde dich über den Issue Tracker hier).

Falls dir eine Einstellung nicht gefällt, kannst du sie natürlich weglassen oder ändern. Gleiches gilt für Plugins. Es gibt andere und viel mehr Plugins, als hier gezeigt werden. Alle Key Mappings sind Vorschläge! Benutze, was auch immer für dich intuitiv Sinn ergibt.

⚠️ Es gibt auch fertige NeoVim Konfigurationen und Distributionen. Trotzdem empfiehlt es sich den Workshop durchzugehen, um zu verstehen wie die NeoVim Konfiguration funktioniert. Beispiele für eine Starter-Konfig oder eine Distribution sind kickstart.nvim und LazyVim.

Voraussetzungen

  • NeoVim in einer neuen Version (>= 0.10.0).
  • Git für den Plugin-Manager
  • Als schnelle Lösung gibt es in den Release-Dateien ein AppImage. Das kannst du bei dir zum Beispiel unter ~/.local/bin/nvim ablegen.
  • Ein Nerd-Font für schicke Icons. Siehe dazu hier https://www.nerdfonts.com/ .

Grundstruktur

Es geht immer mit der init.lua los. Die Konfig liegt unter $XDG_CONFIG_HOME/nvim/init.lua. Das ist bei dir vermutlich ~/.config/nvim/init.lua. Weil deine Konfig im Laufe der Zeit viel komplexer wird legen wir eine Grundstruktur an:

$XDG_CONFIG_HOME/nvim/init.lua:

require("NAME.init")

Hiermit wird deine init-Datei geladen, die im nächsten Schritt angelegt wird:

$XDG_CONFIG_HOME/nvim/lua/NAME/init.lua:

require("NAME.settings")

Damit wird das Modul NAME.settings geladen. lua im Pfad ist wichtig. $XDG_CONFIG_HOME/nvim/lua ist ein Pfad für Lua-Module.

$XDG_CONFIG_HOME/nvim/lua/NAME/settings.lua:

print("Hallo aus den Settings")

Für den Benutzer weeman (Beispiel) sollten jetzt folgende Dateien existieren:

init.lua
lua/weeman/init.lua
lua/weeman/settings.lua

Starte NeoVim neu, nachdem du die Dateien angelegt hast. Unten sollte Nachricht „Hallo aus den Settings“ auftauchen.

Praktisches

-- Zeilennummern
vim.wo.number = true


-- Relative Zeilennummern
vim.wo.relativenumber = true


-- Leader Taste setzen
-- Leader = Präfix für eigene Tastenkürzel
vim.g.mapleader = ' '
vim.g.maplocalleader = ' '

Vim hat eine sehr gute Hilfe! Für die vim.keymap.set Funktion kannst du die Hilfe mit :help vim.keymap.set aufrufen. Damit die Navigation in der Hilfe auch per Enter klappt, kannst du das in deine Konfig einbauen:

-- Hilfe-Links mit Enter folgen
vim.api.nvim_create_autocmd({"FileType"}, {
  pattern = "help",
  callback = function ()
    vim.keymap.set("n", "<CR>", "<C-]>", {buffer = true})
  end
})
-- Beim Wiederöffnen einer Datei zur letzten Position springen
vim.api.nvim_command([[au BufReadPost * if line("'\"") > 0 && line("'\"") <= line("$") | exe "normal! g`\"" | endif]])


-- Einrückung mit 4 Spaces als Standard
vim.o.tabstop = 4
vim.o.softtabstop = 4
vim.o.shiftwidth = 4
vim.o.expandtab = true


-- Aktuelle Einrückung fortführen
vim.o.smartindent = true


-- Groß-/Kleinschreibung smarter machen
vim.o.ignorecase = true
vim.o.smartcase = true


-- Undo-Historie abspeichern
vim.opt.undofile = true


-- Automatisches Speichern
vim.api.nvim_create_autocmd({"FocusLost", "BufLeave"}, {
  pattern = "*",
  callback = function (args)
    -- only autosave in normal mode
    if vim.api.nvim_get_mode().mode ~= "n" then return end

    -- do not auto save an empty buffer
    if (vim.fn.bufname(args.buf)) == "" then return end

    -- do not auto save readonly buffers
    if (vim.api.nvim_buf_get_option(args.buf, 'readonly')) then return end

    -- do not auto save non-modified buffers
    if (not vim.api.nvim_buf_get_option(args.buf, 'modified')) then return end

    vim.api.nvim_command("w")
  end,
  nested = true,
})

System-Clipboard benutzen

Damit das funktioniert braucht es xclip, wl-copy oder ähnliches. Siehe :help clipboard.

Das kann sehr verwirrend sein, weil NeoVim per Standard gelöschte und ersetzte Texte kopiert. Dafür (bzw. dagegen) gibt es später ein Plugin.

settings.lua:

-- System-Clipboard verwenden
vim.o.clipboard = 'unnamedplus'

lazy.nvim als Plugin-Manager

lazy.nvim ist ein Plugin-Manager, der (unter anderem) die Installation und Konfiguration von Plugins vereinfacht. Um lazy.nvim zu installieren kannst du den folgenden Code in ~/.config/nvim/lua/NAME/lazy.lua packen:

-- Lazy Plugin Manager
-- https://github.com/folke/lazy.nvim
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not (vim.uv or vim.loop).fs_stat(lazypath) then
  vim.fn.system({
    "git",
    "clone",
    "--filter=blob:none",
    "https://github.com/folke/lazy.nvim.git",
    "--branch=stable", -- latest stable release
    lazypath,
  })
end
vim.opt.rtp:prepend(lazypath)

-- Plugin Dateien in ~/.config/nvim/lua/NAME/plugins legen
require("lazy").setup("NAME.plugins")

In deine init.lua muss noch das hier vor den Settings rein:

require("NAME.lazy")

Als erstes Plugin installieren wir lualine.nvim als schickere Statuszeile:

~/.config/nvim/lua/NAME/plugins/lualine.lua:

return {
  "nvim-lualine/lualine.nvim",
  dependencies = { "kyazdani42/nvim-web-devicons" },
  config = function()
    require("lualine").setup()
  end
}

Für die Darstellung der Icons brauchst du ein Nerd Font.

Nach einem Neustart von NeoVim sollte ein Fenster von Lazy aufgehen. Dort wird dir angezeigt, was der Lazy Plugin Manager macht. Mit „q“ kommst du da wieder heraus. Falls du das Fenster erneut öffnen möchtest, klappt das mit :Lazy.

Ein Farbschema als Plugin installieren

Wir installieren zuerst das onedarkpro.nvim Farbschema. Dazu füge den folgenden Code in ~/.config/nvim/lua/NAME/plugins/onedarkpro.lua ein:

return {
  "olimorris/onedarkpro.nvim",
  priority = 1000, -- Ensure it loads first
  config = function ()
      -- normal
      vim.cmd("colorscheme onedark")

      -- für light-mode
      -- vim.cmd("colorscheme onelight")

      -- für mehr Kontrast
      -- vim.cmd("colorscheme onedark_dark")
  end
}

Suche mit Telescope

telescope.nvim ist ein Universalwerkzeug zum Finden von allen möglichen Dingen.

Erstelle die Datei ~/.config/nvim/lua/NAME/plugins/telescope.lua:

return {
  'nvim-telescope/telescope.nvim',
  tag = '0.1.6',
  dependencies = { 'nvim-lua/plenary.nvim' },
  config = function ()
    -- Leader he für „help“ - oder was auch immer für dich Sinn ergibt.
    vim.keymap.set("n", "<leader>he", ":Telescope help_tags<CR>")

    -- In Datei suchen (fi - find)
    vim.keymap.set("n", "<leader>fi", ":Telescope current_buffer_fuzzy_find<CR>")

    -- Dateien finden (ff - find files)
    vim.keymap.set("n", "<leader>ff", ":Telescope find_files<CR>")

    -- Grep (fg - find grep)
    vim.keymap.set("n", "<leader>fg", ":Telescope live_grep<CR>")

    -- Was es sonst noch gibt
    -- https://github.com/nvim-telescope/telescope.nvim?tab=readme-ov-file#pickers
  end
}

Nach einem Neustart von NeoVim kannst du jetzt zum Beispiel mit „ff“ Dateien finden.

ℹ️ Mit fd und ripgrep funktioniert Telescope noch besser!

Datei-Browser

nvim-tree.lua ist ein Datei-Browser für NeoVim.

Zuerst füge das hier in deine settings.lua ein:

-- netrw ausschalten
vim.g.loaded_netrw = 1
vim.g.loaded_netrwPlugin = 1

Jetzt lege die Datei ~/.config/nvim/lua/NAME/plugins/nvim-tree.lua an:

return {
  'kyazdani42/nvim-tree.lua',
  dependencies = {
     -- für schönere Icons
    'kyazdani42/nvim-web-devicons',
  },
  config = function()
    require('nvim-tree').setup({
      view = {
        width = 40,
      },
    })

    -- Beispiel mit sf - show files
    vim.keymap.set("n", "<leader>sf", ":NvimTreeToggle<CR>")

    -- Zur Datei springen (jump file), danach zentrieren (zz)
    vim.keymap.set("n", "<leader>jf", ":NvimTreeFindFile<CR>zz")
  end
}

Löschen und ersetzen ohne durchzudrehen

Normalerweise kopiert NeoVim Texte, wenn sie gelöscht oder geändert werden. Das ist sehr unintuitiv und nervig. cutlass.nvim benutzt bei d, c und so weiter das „blackhole Register“ (Zwischenablage wird nicht überschrieben). Dafür gibt es dann einen zusätzliche Ausschneiden-Shortcut.

Im folgenden Beispiel wird x zum Ausschneiden verwendet. Benutze, was auch immer für dich Sinn ergibt!

Erstelle die Datei ~/.config/nvim/lua/NAME/plugins/cutlass.lua mit folgendem Inhalt:

return {
  "gbprod/cutlass.nvim",
  opts = {
    cut_key = "x",
  }
}

Jetzt wird bei cc, dd und so weiter die Zwischenablage nicht überschrieben. Zum Ausschneiden kannst du jetzt x… verwenden.

Ein Language Server und Autocompletion

In diesem Schritt richten wir einen Language Server für Lua mit dazugehöriger Autocompletion ein. Zur Installation und einfacheren Konfiguration des Language Server benutzen wir mason.nvim und nvim-lspconfig. Für die Autocompletion verwenden wir nvim-cmp.

Statt mason.nvim kannst du auch Pakete deiner Distribution benutzen.

Lege die Datei ~/.config/nvim/NAME/plugins/lsp.lua an und kommentiere einen Language Server deiner Wahl ein:

return {
  {
    "williamboman/mason-lspconfig.nvim",
    dependencies = {
      "neovim/nvim-lspconfig",
      "williamboman/mason.nvim",
    },
    config = function ()
      require("mason").setup()

      require("mason-lspconfig").setup({
        -- Liste der zu installierenden Language Server
        -- Siehe https://github.com/williamboman/mason-lspconfig.nvim?tab=readme-ov-file#available-lsp-servers
        ensure_installed = {
          -- Lua language server; für die NeoVim Konfig
          "lua_ls",

          -- JSON - braucht Node.JS!
          -- "jsonls",

          -- Python - braucht Python!
          -- "pylsp",

          -- TypeScript/JavaScript - braucht Node.JS
          -- "ts_ls",
        },
      })

      -- Language Server Konfiguration
      -- Weitere siehe https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md
      require("lspconfig").lua_ls.setup({
        capabilities = capabilities,

        on_init = function(client)
          if client.workspace_folders then
            local path = client.workspace_folders[1].name
            if vim.loop.fs_stat(path..'/.luarc.json') or vim.loop.fs_stat(path..'/.luarc.jsonc') then
              return
            end
          end

          client.config.settings.Lua = vim.tbl_deep_extend('force', client.config.settings.Lua, {
            runtime = {
              version = 'LuaJIT'
            },
            workspace = {
              checkThirdParty = false,
              library = {
                vim.env.VIMRUNTIME
              }
            }
          })
        end,
        settings = {
          Lua = {}
        }
      })

      -- require("lspconfig").jsonls.setup({})
      -- require("lspconfig").pylsp.setup({})

      -- TypeScript/JavaScript - siehe nächster Absatz!!
      -- require("typescript-tools").setup({})
    end
  }
}

Für TypeScript (und JavaScript) gibt es zusätzlich die typescript-tools, die besser als der Language Server funktionieren:

~/.config/nvim/NAME/plugins/typescript-tools.lus:

return {
  "pmizio/typescript-tools.nvim",
  dependencies = { "nvim-lua/plenary.nvim", "neovim/nvim-lspconfig" },
  opts = {},
}

Führe nach einem Neustart von NeoVim das Kommando :LspInfo aus, wenn du eine Konfig-Datei (Lua) offen hast. Es sollte angezeigt werden, dass ein Language Server läuft. Wenn du in der Datei tippst, solltest du eine direkte Rückmeldung bekommen, wenn der Code einen Fehler hat.

Jetzt folgt die Autocompletion. Erstelle dazu die Datei ~/.config/nvim/NAME/plugins/completion.lua:

return {
  "hrsh7th/nvim-cmp",
  dependencies = {
    -- Autocomplete Quellen
    -- Siehe https://github.com/hrsh7th/nvim-cmp/wiki/List-of-sources
    -- Buffer
    "hrsh7th/cmp-buffer",
    -- Pfade
    "hrsh7th/cmp-path",
    -- Language Server
    "hrsh7th/cmp-nvim-lsp",
    -- Command mode
    "hrsh7th/cmp-cmdline",
    -- Snippet completion
    "hrsh7th/vim-vsnip",
    "hrsh7th/cmp-vsnip",
  },
  config = function ()
    -- Set up nvim-cmp.
  local cmp = require'cmp'

  cmp.setup({
    snippet = {
      expand = function(args)
        vim.fn["vsnip#anonymous"](args.body)
      end,
    },
    mapping = cmp.mapping.preset.insert({
      ['<C-b>'] = cmp.mapping.scroll_docs(-4),
      ['<C-f>'] = cmp.mapping.scroll_docs(4),
      ['<C-Space>'] = cmp.mapping.complete(),
      ['<C-e>'] = cmp.mapping.abort(),
      ['<CR>'] = cmp.mapping.confirm({ select = true }), -- Accept currently selected item. Set `select` to `false` to only confirm explicitly selected items.
    }),
    sources = cmp.config.sources({
      { name = 'nvim_lsp' },
      { name = 'vsnip' },
      { name = 'buffer' },
      { name = 'path' },
    })
  })

  -- Use buffer source for `/` and `?` (if you enabled `native_menu`, this won't work anymore).
  cmp.setup.cmdline({ '/', '?' }, {
    mapping = cmp.mapping.preset.cmdline(),
    sources = {
      { name = 'buffer' }
    }
  })

  -- Use cmdline & path source for ':' (if you enabled `native_menu`, this won't work anymore).
  cmp.setup.cmdline(':', {
    mapping = cmp.mapping.preset.cmdline(),
    sources = cmp.config.sources({
      { name = 'path' }
    }, {
      { name = 'cmdline' }
    }),
    matching = { disallow_symbol_nonprefix_matching = false }
  })
  end
}

Ändere die lsp.lua folgendermaßen ab:

      -- ...
      local capabilities = require('cmp_nvim_lsp').default_capabilities()

      -- Language Server Konfiguration
      -- Weitere siehe https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md
      require("lspconfig").pylsp.setup({
        -- Pro Language Server einmal
        capabilities = capabilities,
      -- ...

Nach einem Neustart solltest du für deine NeoVim Konfig eine Autovervollständigung haben. Die Autovervollständigung kann mit CTRL+Space explizit gestartet werden. Mit CTRL+n und CTRL+p kannst du durch die Einträge wechseln. CTRL+y bestätigt eine Autocompletion. Das ist wichtig, um zum Beispiel Snippets zu aktivieren.

Language Server und Autocompletion bieten eine Vielfalt an Einstellungsmöglichkeiten. Lese dir die Dokumentation durch und baue es so, wie es für dich am besten funktioniert!

Git Integration

Mit gitsigns.nvim kannst du dir den Git Status anzeigen lassen. Außerdem bietet das Plugin stagen von Hunks und Git blame an. Lese die Doku und versuche es zum Laufen zu bringen!

Auch nett ist diffview.nvim. Es ermöglicht eine komfortable Anzeige von Diffs und dem Git Verlauf für Dateien.

Hier findest du eine Liste mit NeoVim Plugins, die irgendwas mit Git machen. Ein Klassiker ist außerdem vim-fugitive.

Mehr hier: Awesome NeoVim

Tastenkürzel anzeigen lassen

which-key.nvim

Problembehebung

Bei mir kommen irgend welche Fehlermeldungen

Schau zuerst nach, ob du NeoVim Version 0.10.1 oder neuer installiert hast.

https://github.com/neovim/neovim/blob/master/INSTALL.md

Die init.lua scheint nicht geladen zu werden

Schaue nach, ob es noch eine init.vim in ~/.config/nvim gibt. Falls ja, lösche sie und versuche es erneut.

Es kommt ein Fehler, dass der Lua Parser nicht geladen werden kann

Deine NeoVim Version ist vermutlich ohne Tree Sitter kompiliert.

Nachdem zu Lazy eingerichtet hast, füge die Datei ~/.config/nvim/lua/NAME/plugins/treesitter.lua hinzu:

return {
  "nvim-treesitter/nvim-treesitter",
  build = ':TSUpdate',
  config = function()
    require 'nvim-treesitter.configs'.setup {
      ensure_installed = {
        "lua",
      },
      highlight = {
        enable = false,
      },
    }
  end
}