| config | ||
| .editorconfig | ||
| README.md | ||
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.
Links
- Kuratierte Plugin-Liste: https://github.com/rockerBOO/awesome-neovim
- Plugin-Datenbank: https://dotfyle.com/neovim/plugins/trending
- Konfigs zur Inspiration: https://dotfyle.com/neovim/configurations/top
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/nvimablegen. - 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
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
}