Ein Parser für meinen Code

Code zu Lesen ist fast genauso schwierig wie Code zu Schreiben. Das betrifft nicht nur fremden Code, sondern auch den eigenen Code von vor zwei Monaten. Den man jetzt refactoren darf. Oder möchte.
Damit das Ganze sich ein wenig einfacher gestaltet, ist ein kluger Kopf auf die Idee gekommen, die einzelnen Teile des Codes nach seiner Bestimmung einzufärben. So dass man Funktionen, Variablen und Konstrukte auf den ersten Blick voneinander unterscheiden kann.

Natürlich möchte man diese Teile nicht selber einfärben und da kommen dann Plugins wie tree-sitter bzw. nvim-treesitter ins Spiel, die den Code selbst mit Syntax-Fehlern parsen können, damit sie entsprechend gehighlighted werden. Dazu habe ich mir in meiner Konfiguration unter lua/kaffdaddy/plugins eine Datei mit folgendem Inhalt erstellt:

return {
  {
    "nvim-treesitter/nvim-treesitter",
    event = { "BufReadPre", "BufNewFile" },
    build = ":TSUpdate",
    dependencies = {
      "nvim-treesitter/nvim-treesitter-textobjects",
      "windwp/nvim-ts-autotag",
    },
    config = function()
      local treesitter = require("nvim-treesitter.configs")
      treesitter.setup({
        highlight = {
          enable = true,
        },
        indent = { enable = true },
        autotag = {
          enable = true,
        },
        ensure_installed = {
          "json",
          "javascript",
          "typescript",
          "yaml",
          "html",
          "css",
          "bash",
          "lua",
          "vim",
          "dockerfile",
          "gitignore",
          "php",
          "scss",
          "gitattributes",
          "gitignore",
          "json",
          "json5",
          "regex",
          "typoscript",
        },
        incremental_selection = {
          enable = true,
          keymaps = {
            init_selection = "",
            node_incremental = "",
            scope_incremental = false,
            node_decremental = "",
          },
        },
        context_commentstring = {
          enable = true,
          enable_autocmd = false,
        },
      })
    end,
  },
}

Wie man sieht, ist dort sogar ein Parser für TypoScript enthalten, auf den mich dankenswerterweise Dragan (melde dich, wenn ich hier etwas verlinken soll!) aufmerksam gemacht hat: Teddytrombone/tree-sitter-typoscript
Weil neovim natürlich nicht alle Dateitypen aufgrund ihrer Dateiendung erkennt, habe ich ein wenig mit nathom/filetype.nvim nachgeholfen:

return {
  "nathom/filetype.nvim",
  config = function()
    local filetype = require("filetype")
    filetype.setup({
      overrides = {
        extensions = {
            html = "html",
            tsconfig = "typoscript",
            typoscript = "typoscript",
        }
      }
    })
  end,
}

Den aktuellen Stand meiner Konfiguration kann man sich hier anschauen.

Doom

Vor genau 30 Jahren ist Doom erschienen und hat in den nächsten Monaten und eigentlich Jahren mein Computerspielen beeinflusst. Zwar haben wir auch schon ein Jahr vorher mit Wolfenstein 3D Egoshooter gespielt, aber Doom war dann doch ein Meilenstein mit richtiger 3D-Grafik, der unsere Rechner zum Glühen brachte.

Auch die hervorragende Soundkulisse und vor allem die Geräusche von sich in der Nähe befindlichen Imps lassen auch heute noch meinen Puls in die Höhe schnellen. Selbst auf einem Game Boy Advance habe ich das Spiel komplett durchgespielt. Und wahrscheinlich meine Augen ruiniert.

Ein Fuzzy-Finder für neovim

Eine der wichtigsten Funktionen in einer IDE ist für mich das Suchen nach Code. Oder Dateien. Ich habe keine Lust, auch wenn ich das Projekt vielleicht in- und auswendig kenne, mich durch die Dateiansicht zu klicken, um eine Datei zu finden.
Für sowas sind sogenannte Fuzzy-Suchen zuständig und mit telescope gibt es sowas in wunderbarer Umsetzung auch für neovim.

Im Verzeichnis lua/kaffdaddy/plugins lege ich die Datei telescope.lua mit folgendem Inhalt an:

return {
  "nvim-telescope/telescope.nvim",
  branch = "0.1.x",
  dependencies = {
    "nvim-lua/plenary.nvim",
    { "nvim-telescope/telescope-fzf-native.nvim", build = "make" },
    "nvim-tree/nvim-web-devicons",
  },
  config = function()
    local telescope = require("telescope")
    local actions = require("telescope.actions")

    telescope.setup({
      defaults = {
        path_display = { "truncate " },
        mappings = {
          i = {
            ["<C-k>"] = actions.move_selection_previous,
            ["<C-j>"] = actions.move_selection_next,
            ["<C-q>"] = actions.send_selected_to_qflist + actions.open_qflist,
          },
        },
      },
    })

    telescope.load_extension("fzf")

    -- set keymaps
    local keymap = vim.keymap

    keymap.set("n", "<leader>ff", "<cmd>Telescope find_files<cr>", { desc = "Fuzzy find files in cwd" })
    keymap.set("n", "<leader>fr", "<cmd>Telescope oldfiles<cr>", { desc = "Fuzzy find recent files" })
    keymap.set("n", "<leader>fs", "<cmd>Telescope live_grep<cr>", { desc = "Find string in cwd" })
    keymap.set("n", "<leader>fc", "<cmd>Telescope grep_string<cr>", { desc = "Find string under cursor in cwd" })
  end,
}

Mit den definierten Kommandos kann ich dann nach Dateien und sogar nach Strings im aktuellen Projektverzeichnis suchen. Und das atemberaubend schnell und mit einer Vorschau der Datei und Position, wenn man nach einem String gesucht hat.
Den aktuellen Stand der Konfiguration bis hierher findet man dann hier: https://github.com/KaffDaddy/nvim-config/tree/0.5.0

Ein Universum voller Plugins

Ich habe am Anfang meiner Reise mit neovim sehr schnell gemerkt, dass es für den Editor zigtausend Plugins und noch viel mehr Wege gibt, selbige zu integrieren. Es gibt wirklich mehr Möglichkeiten, seine eigene Editor-Konfiguration zu schreiben, als mit TYPO3 eine Website zu erstellen. Und das finde ich bemerkenswert.

Mein Ziel ist es ja, dass ich mit neovim zu 95% meine Bedürfnisse abdecke, die ich beim Programmieren von PHP/HTML/JavaScript/SCSS habe. Das ich nicht alles erschlagen werde, war mir im Vorfeld bewusst. Plugins wie Fluid- oder TypoScript-Linter gibt es einfach nicht. Aber den Rest, den ich benötige... das ist alles da. Es gibt wirklich alles, was das Herz begehrt.

Nur habe ich gemerkt, dass ich zwar ein Grundverständnis entwickelt habe, wie man mit Lazy als Paket-/Plugin-Manager eine Konfiguration erstellt, aber ich stoße bei der Konfiguration der ganzen Plugins an sich sehr schnell an Grenzen.
Ich habe mir zwar mittlerweile eine für mich funktionierende Konfiguration erstellt, in der ich sogar mittels Xdebug in einem Docker-Container debuggen kann, aber so richtig verstehen und erklären, was jetzt welches Plugin wie macht, kann ich nicht. Da brauche ich noch ein wenig Zeit und muss mich eingehender mit der Materie beschäftigen.

Daher habe ich auch noch nicht weiter in meinem Repository für meine Konfiguration weitergemacht, obwohl ich schon viel weiter bin und nächste Woche auch das erste Mal produktiv entwickeln werde. Da freue ich mich schon drauf wie Bolle.
Und ich werde bestimmt noch das ein oder andere Plugin entdecken, was das Ganze noch mehr zu einer besseren und auf mich abgestimmteren Programmierumgebung machen wird.

Gerechtes Feuer

Nachdem ich nun vor einigen Wochen endlich mal Privateer durchgespielt hatte, konnte ich es mir natürlich nicht nehmen, auch das Add-On “Righteous fire” durchzuspielen. Das fügt dem Hauptspiel einen Geschichtsstrang nach dem Hauptspiel hinzu und bringt einem noch ein paar weitere Stunden Spaß. Einschneidende Änderungen am bekannten Spiel gibt es nicht, ein paar Erweiterungen für sein Raumschiff, die aber kaum der Rede wert sind. Ansonsten findet die Handlung in den schon bekannten Weltraum-Sektoren statt, was ein wenig schade ist. Hier hätte man das Spiel vielleicht noch ein wenig erweitern können.

Aber hey, Spaß hatte ich. Mal sehen, was ich als nächstes vom Pile of shame nehme. Baldurs Gate 3 muss glaube ich noch ein wenig warten.

vim in PhpStorm

In der letzten Woche habe ich wenig Zeit gefunden, an meiner vim-Erfahrung zu schrauben. Mein kurzer Exkurs, LazyVimals Kickstarter zu verwenden, habe ich direkt wieder verworfen. Zu umständlich erscheint es mir, wieder Plugins zu deaktivieren und Konfigurationen umzuschreiben. Da kann ich meine Konfiguration auch gleich direkt schreiben. Und habe gefühlt mehr Einfluss darauf, wie es werden soll.

Aber ich habe mir das IdeaVim-Plugin in PhpStorm aktiviert. Das sorgt dafür, dass sich der Editor und auch ein wenig der Projektbaum sich wie vim verhält. Und das großartige ist, dass man seine vim-Konfiguration integrieren kann. Ich habe zwar noch nicht viel konfiguriert, aber mit dem bißchen hier

set number relativenumber
set idearefactormode=keep
set ideajoin
set surround
set easymotion

let mapleader = " "
nmap <leader>h <action>(PreviousTab) nmap <leader>l <action>(NextTab) nmap <leader>i <action>(Generate) nmap <leader>s <action>(ShowErrorDescription) nmap <leader>n <action>(GotoNextError) nmap <leader>p <action>(GoToPreviousError) nnoremap <leader><leader> <C-Tab>
set NERDTree nnoremap <Leader>nj :NERDTreeFind<CR> nnoremap <Leader>nn :NERDTreeFocus<CR> nnoremap <Leader>tn :NERDTreeToggle<CR> let g:NERDTreeMapActivateNode='l' let g:NERDTreeMapJumpParent='h'

konnte ich schon für ein wenig vim-Feeling sorgen.

Kleine Verbesserungen und Annehmlichkeiten

Da vim von Hause aus geöffnete Dateien und somit auch die Navigations-Sidebar in sogenannten Buffer hält, muss man natürlich zwischen diesen wechseln können. Das kann man selber anhand von Keymaps versuchen abzubilden oder man installiert sich tmux und das Plugin christoomey/vim-tmux-navigator, mit dem man dann per STRG/Control und HJKL-Tasten zwischen der Navigation und der geöffneten Datei wechseln kann. Es hat also doch etwas gebracht, Nethack zu spielen.

In der Datei lua/kaffdaddy/core/options.lua habe ich ein paar grundsätzliche Konfigurationen hinterlegt, die das Einrückungsverhalten und das Aussehen von nvim regeln. Nichts spannendes, kann man sich mal anschauen und sollte selbsterklärend sein.

Aktueller Stand der Konfiguration ist hier zu finden, als nächstes kommt dann auch schon die Integration von LSP dran, um dann die ersten Schritte beim täglichen Entwickeln gehen zu können. Yeah!

Ein anderer Datei-Explorer muss her

Mit `:Explore` kommt man ja schon weit, aber wenn man seine Verzeichnisse und Dateien schön in einer Sidebar zur Verfügung hat, macht es einem den Umzug schon leichter. Also: ein neuer Datei-Explorer muss her. Und zwar in Form von nvim-tree.

In der Datei lua/kaffdaddy/plugins/nvim-tree.lua lege ich eine grundlegende Konfiguration ab:

return {
 "nvim-tree/nvim-tree.lua",
 dependencies = {
   “nvim-tree/nvim-web-devicons”
 },
 config = function()
   -- disable netrw at the very start of your init.lua
   vim.g.loaded_netrw = 1
   vim.g.loaded_netrwPlugin = 1
-- set termguicolors to enable highlight groups vim.opt.termguicolors = true
require("nvim-tree").setup({ sort_by = "case_sensitive", view = { width = 30, }, renderer = { group_empty = true, }, filters = { dotfiles = true, }, })
local keymap = vim.keymap keymap.set("n", "<leader>eo", "<cmd>NvimTreeOpen<CR>", { desc = "Opens up file explorer" }) keymap.set("n", "<leader>et", "<cmd>NvimTreeToggle<CR>", { desc = "Toggle file explorer" }) keymap.set("n", "<leader>ecf", "<cmd>NvimTreeFindFile<CR>", { desc = "Toggle file explorer on current file" }) end, }

Ich merke jetzt schon, dass das Projekt neovim sehr komplex wird. Da die Steuerung komplett über Keyboard-Shortcuts funktioniert und man diese selber definieren kann, werde ich im nächsten Schritt Shortcuts definieren und in der Readme dokumentieren.

Als erstes habe ich den sogenannten Leader-Key von Backslash auf ein Komma geändert, was in der Datei lua/kaffdaddy/core/keymaps.lua geschieht. Auf einem deutschen Tastatur-Layout ist der Backslash etwas umständlich zu erreichen. Ich ahne schon, dass, wenn ich irgendwie mit dem Switch auf neovim Erfolg haben werde, der Umzug auf ein QWERTY-Keyboard-Layout folgen wird.

Die geänderten Keymaps für nvim-tree sind nicht in diese globale Konfiguration gerutscht, da sie nur erfolgen sollen, wenn nvim-tree geladen wurde. Da weiß ich aber noch nicht, ob das so eine gute Idee ist. Wenn ich das für jedes Plugin so machen werde, muss ich selber den Überblick behalten, in welcher Datei Keymaps-Bindings stehen, um mir nicht selber in die Quere zu kommen und eventuell schon bestehende Konfigurationen zu überschreiben.

Der aktuelle Stand der Konfiguration mit nvim-tree als Datei-Explorer ist hier zu finden.

Colors, colors, colors

Frei nach Ice-T brauche ich auch andere Farben. Eine Übersicht über die sogenannten colorschemes kann man sich hier verschaffen.
Für die Integration erstelle ich eine Datei colorscheme.lua unterhalb von lua/kaffdaddy/plugins mit folgendem Inhalt

return {
{
"bluz71/vim-nightfly-guicolors",
priority = 1000,
config = function()
vim.cmd([[colorscheme nightfly]])
end,
}
}

Hier kommt auch zum ersten Mal eine Funktion von Lazy ins Spiel und zwar kann man die Ladereihenfolge von Plugins über den Parameter priority steuern. Plugins, die bei Bedarf nachgeladen werden sollen, bekommen den Parameter lazy verpasst.

In der Datei lua/kaffdaddy/lazy.lua ändert man dann noch die Setup-Methode von Lazy folgendermaßen um:

require("lazy").setup(
{ import = "kaffdaddy.plugins" },
{
install = {
colorscheme = { "nightfly" }
}
}
)

Und schon sieht alles gar nicht mehr ganz so schlimm aus. Aktueller Stand des Repos: https://github.com/KaffDaddy/nvim-config/tree/0.2.0

Meine Reise mit neovim

Wenn man doch mal gezwungen wird, sich auf fremden Servern herumzutreiben und dort in irgendwelchen Konfigurationsdateien herumzustöbern kommt man um den Editor vi nicht herum. Und irgendwie bin ich darauf gestoßen, dass es Entwickler gibt, die die weiterentwickelte Version vim beziehungsweise dessen Fork neovim als eine Art IDE verwenden. Und das möchte ich auch. Weil man es kann. Mehr gibt es dazu einfach nicht zu sagen.

Und ich will mal schauen, ob ich soweit komme. Denn ein vorgefertigtes Paket dafür gibt es nicht. Das gesamte Ökosystem um vim/neovim besteht aus einer unüberschaubaren Zahl an Erweiterungen und einer noch viel größeren Anzahl an Wegen, sein Ziel zu erreichen. Also so ähnlich wie mit TYPO3, wenn man "nur" eine Website umsetzen möchte.

Man mag mir verzeihen, wenn ich neovim und seine ganzen Plugins und Erweiterungen noch falsch bezeichne. Ich werde auf dem bestimmt sehr steinigen Weg eine Menge Fehler machen, aber wenn ihr das Kopfschütteln beendet habt: helft mir! Wirklich, ich will den ganzen Kram lernen und für mich hier und in einem Repository dokumentieren. Vielleicht hilft es dem ein oder anderen, seine Konfiguration für neovim zu finden.

Zur Zeit verwende ich PhpStorm zum Entwickeln von PHP, der Integration von TYPO3-Extensions und ab und zu immer noch ein wenig Frontend in Form von Vanilla-JavaScript und SCSS. Bis auf ein paar Begebenheiten benutze ich PhpStorm aber wie einen Texteditor und genau deshalb möchte ich versuchen, alles in und mit neovim zu ersetzen.

Meine Anforderungen sind folgende:

  • Komplette Unterstützung von PHP, HTML, JavaScript, SCSS, Fluid und TypoScript
  • Auto-Vervollständigung
  • Debugging mit xDebug
  • Code-Qualitätstools wie PHP-CodeSniffer, CS-Fixer, Psalm und PHPStan
  • Integration von Test-Frameworks wie PHPUnit und Codeception
  • Konfiguration mittels editorconfig usw.

Die letzten Tage habe ich damit verbracht, mich in die Materie einzulesen, was sich erst einmal als sehr schwierig erwiesen hat. Eine Anlaufstelle für verzweifelte Menschen wie mich scheint es nicht zu geben. Zwar scheint sich die Community um vim/neovim und seine Plugins sehr anständig zu verhalten und ein nettes Klima zu pflegen, aber die Einstiegshürde ist phänomenal. Ich glaube, das letzte Mal, das ich vor so einem Berg stand, war damals, als ich mit TYPO3 angefangen habe (FC BigFeet anyone?).

Fangen wir also an und als erstes steht die Auswahl eines Plugin-Managers an. Und ich habe mich für Lazy entschieden, da Plugins, wie der Name schon vermuten lässt, nachgeladen werden und nicht alle beim Systemstart zur Verfügung stehen müssen.
Was ich auch bei vielen Konfigurationen gesehen habe und was ich dreist kopieren werde, ist die Aufteilung der Konfigurationen in einzelne Dateien.

Fangen wir also im Verzeichnis

~/.config/nvim

an, denn da gehört unter macOS oder Linux die Konfiguration hinein. Darunter erstelle ich mir das Unterverzeichnis lua und darunter noch das Verzeichnis kaffdaddy. Das kann ja jeder nennen, wie er möchte. In diesem untersten Verzeichnis kommt in die Datei lazy.lua der Bootstrap-Code für Lazy herein, wie er hier zu finden ist. Dann nur noch unter

~/.config/nvim/init.lua

per

require("kaffdaddy.lazy")

diese Datei laden und nach einem beherzten Schließen und Öffnen von neovim kann per

:Lazy

die wunderschöne Oberfläche von Lazy angeschaut werden.

Ich glaube, der nächste Schritt wird sein, dem Ganzen ein paar schönere Farben zu verpassen. Meine Konfiguration kann man jedenfalls hier Schritt für Schritt nachvollziehen.
Der aktuelle Stand für diesen Blogpost ist hier und alle Blogposts zu meiner Reise werden in der Kategorie neovim erscheinen. Muss man halt rückwärts lesen.