/home/ /about/
    2026-04-13

    Neovim, Rust e Il Bianconiglio

    Disclaimer: Il senso di questo post e' dimostrare come il gamedev (la programmazione grafica, in generale) in Rust, su terminale Linux, nonostante possa sembrare spaventoso e masochistico, sia un'esperienza estremamente gratificante. La riflessione si basa quasi esclusivamente sul processo creativo. Se l'obiettivo e' creare un sofisticato software nel minor tempo possibile, il consiglio condiviso e' quello di tenersi lontani da Rust e neovim e utilizzare engine dedicati (Godot, Unity, Unreal etc. etc.).

    Qualche giorno fa sulla homepage di hackernews e' apparso un post sulla procrastinazione produttiva. Io so pochissimo di psicologia e ogni volta che leggo di ricette per aumentare la produttivita' penso al turbocapitalismo e ho un brivido lungo la spina dorsale. Ma e' un mio problema, non sono un professionista e tendo a dare molta piu' importanza al processo che al risultato finale - ma visto che viviamo nell'epoca della AI generativa, forse il mio approccio non e' sbagliatissimo.

    Comunque, tornando alla procrastinazione, l'autore del post ne distingue due tipologie, tra le tante: una totalmente dannosa e una (forse) utile. La prima e' quella che ti siedi al cavalletto, impugni la matita, guardi il foglio e decidi che forse sarebbe il caso di lanciare una lavatrice. E poi l'aspirapolvere, una tisana perche' no?, oh santo cielo e' quasi ora di cena meglio procacciarsi del cibo! Su questo c'e' un episodio esemplare dei Simpsons in cui Lisa decide di scrivere un romanzo per giovani adulti, resa plastica di questa follia cerebrale. Lisa Simpson

    La seconda, la procrastinazione utile, include invece quello che l'autore del post definisce "Rewarding Novelty", novita' gratificante. Mi siedo al solito cavalletto e decido che non mi piace il taglio della luce che entra dalla finestra, decido di riorganizzare gli spazi, cambio posizione della seduta etc. etc. Mi ritrovo in un ambiente nuovo, personalizzato e stimolante. Nella mia esperienza, l'ambiente digitale segue la stessa logica.

    Perche' Neovim?

    E non un IDE? Ovviamente tutta la mia prolissa introduzione per dire che non c'e' risposta a queste domande, si parte banalmente dalla volonta' di creare un ambiente su misura e si finisce nelle profondita' della tana del Bianconiglio. Oltre al totale controllo dell'editor, l'aspetto piu' interessante di neovim e' la grammatica dei comandi (di derivazione vi) che, per semplificare, e' composta da 'verbo' e 'oggetto' (es. d2j: cancello due righe). Una volta sviluppata la memoria muscolare ci si dimentica del mouse, delle freccette, del file browser: l'editor diventa estensione naturale del cervello (++dopamina).

    Perche' NON Neovim?

    Le motivazioni per non usare neovim sono probabilmente piu' di quelle per utilizzarlo, alcune speculari: curva di apprendimento ripida, l'uso del terminale per sviluppare applicazioni grafiche puo' sembrare controintuitivo, batterie non incluse, troppa personalizzazione, repulsione verso Lua (ognuno ha le proprie idiosincrasie). Se si vuole utilizzare un debugger si soffre l'assenza di una GUI - no problem se il debugging arriva massimo a log::debug!("hey!"). Infine mentre sto scrivendo siamo alla versione 0.12, la 1.0 e' ancora lontana.

    Un approccio minimale

    Disclaimer 2: Da qui in poi scendo nel tecnico. Prendete il codice come riferimento, questo non vuole essere un tutorial, la configurazione e' estremamente personale, basata sul mio uso e in generale diffidate da The Best NeoVim Configuration in the World. Detto questo: Repo su Gitlab

    Ovviamente nessuno vieta di installare decine di plugin e ritrovarsi un clone di vscode (ma tanto vale usare un IDE?). Il mio approccio e' minimale e tendo a ridurre il numero di righe di configurazione. Su questo le ultime release mi vengono incontro introducendo un plugin manager (vim.pack, scritto tra l'altro dall'autore di mini, plugin di cui probabilmente abuso) e vim.lsp.

    Init.lua

    -- ...
    -- Plugins
    vim.pack.add({
      'https://github.com/nvim-mini/mini.nvim',
      'https://github.com/neovim/nvim-lspconfig',
      'https://github.com/saghen/blink.cmp',
      'https://github.com/nvim-lua/plenary.nvim',
      'https://github.com/sindrets/diffview.nvim',
      'https://github.com/NeogitOrg/neogit',
      'https://github.com/MeanderingProgrammer/render-markdown.nvim'
    })
    -- ...

    LSP

    Per chi programma l'utilizzo di un Language Server e' imprescindibile, per l'autocompletamento, le definizioni, i salti da implementazione a uso, per la formattazione, la diagnostica, etc. etc.. Per Rust la scelta semi-obbligata e' rust-analyzer e, sorpresona!, anche lui deve essere configurato attraverso il Language Server Protocol. Qui trovate tutte le sue impostazioni; rust-analyzer consuma molta ram, potreste voler abilitare/disabilitare alcune funzioni in caso lavoriate in un progetto con molte dipendenze.

    after/lsp/rust-analyzer.lua

    return {
      on_attach = function(client, buf_id)
        client.server_capabilities.completionProvider.triggerCharacters =
          { '.', ':', '#', '(' }
      end,
      settings = {
        ["rust-analyzer"] = {
          cargo = {
            allFeatures = true,
          },
          checkOnSave = true,
          inlayHints = {
            bindingModeHints = { enable = true },
            closureReturnTypeHints = { enable = true },
            lifetimeElisionHints = { enable = true },
            parameterHints = { enable = true },
            typeHints = { enable = true },
          },
          diagnostics = {
            enable = true,
            experimental = { enable = true },
          },
          procMacro = {
            enable = true,
          },
        },
      },
    }

    ~/.config/nvim/

    Alcune considerazioni: gestisco rust-analyzer da pacman, per lasciare neovim piu' snello possibile, in alternativa e' possibile utilizzare mason.nvim. Discorso simile per treesitter: e' possibile installare i parser direttamente dal repository extra di Arch Linux. In alternativa c'e' treesitter.nvim ma dovrete comunque installare separatamente tree-sitter-cli. Per l'autocompletamento uso blink.cmp, che secondo me e' ancora un passo avanti rispetto a quello built-in.

    plugin/30_plugins.lua

    -- Configuration of plugins installed in init.lua
    require('mini.basics').setup({
        options = { basic = false },
        mappings = {
          -- Create `<C-hjkl>` mappings for window navigation
          windows = true,
          -- Create `<M-hjkl>` mappings for navigation in Insert and Command modes
          move_with_alt = true,
        },
      }
    )
    
    require('mini.files').setup({ windows = { preview = false } })
    require('mini.surround').setup()
    require('mini.tabline').setup()
    require('mini.statusline').setup()
    require('mini.icons').setup()
    require('mini.bufremove').setup()
    require('mini.pick').setup()
    require('mini.sessions').setup()
    require('mini.notify').setup()
    require('mini.extra').setup()
    require('mini.ai').setup({
        -- 'mini.ai' can be extended with custom textobjects
        custom_textobjects = {
          -- Make `aB` / `iB` act on around/inside whole *b*uffer
          B = MiniExtra.gen_ai_spec.buffer(),
          -- For more complicated textobjects that require structural awareness,
         -- use tree-sitter. This example makes `aF`/`iF` mean around/inside function
          -- definition (not call). See `:h MiniAi.gen_spec.treesitter()` for details.
          F = require('mini.ai').gen_spec.treesitter({ a = '@function.outer', i = '@function.inner' }),
        },
    
        -- 'mini.ai' by default mostly mimics built-in search behavior: first try
        -- to find textobject covering cursor, then try to find to the right.
        -- Although this works in most cases, some are confusing. It is more robust to
        -- always try to search only covering textobject and explicitly ask to search
        -- for next (`an`/`in`) or last (`an`/`il`).
        -- Try this. If you don't like it - delete next line and this comment.
        search_method = 'cover',
      }
    )
    vim.lsp.enable({
      'lua_ls',
      'rust_analyzer',
    })
    
    require('blink.cmp').setup({
      keymap = { preset = 'default' },
      appearance = {
        nerd_font_variant = 'mono',
      },
      completion = {
        trigger = {
          show_on_trigger_character = true,
          show_on_blocked_trigger_characters = { ' ', '\n', '\t' }
        },
        ghost_text = {
          -- enabled = true
        },
        documentation = { auto_show = false },
        menu = {
          -- Delay before showing the completion menu while typing
          auto_show_delay_ms = 500,
          -- Disable auto menu
          -- auto_show = false,
        }
      },
      sources = {
        default = { 'lsp', 'path', 'buffer' },
      },
      signature = { enabled = true },
      fuzzy = {
        implementation = 'prefer_rust',
      },
    }

    Note sui colorscheme

    Qui e' facile impazzire e probabilmente ne faro' un post dedicato. Il consiglio che mi sono dato e' quello di evitare temi arlecchino, usare pochi colori ognuno dei quali con un significato preciso, non abusare di grassetto, corsivo, sottolineature e usare contrasto/temperatura per evidenziare/nascondere le diverse parti di codice. nvim screen

    Alacritty + Tmux

    In Neovim e' possibile dividere la finestra, aprirne una del terminale e usare tab, nativamente. Molti utenti, me compreso, preferiscono usare il terminale fuori dall'editor e lasciare a neovim quello che sa fare meglio: l'editor. Non apro il capitolo terminal emulator o questo post non vedra' mai la luce (c'e' una wave pazzesca intorno alle console, probabilmente anche grazie alle AI). Importante che sia reattivo, supporti il truecolor e permetta di passare da una tab all'altra con una facile combo di tasti.

    alacritty.toml:

    [terminal.shell]
    program = "tmux"
    
    [env]
    TERM = "xterm-256color"
    
    [window]
    decorations = "None"
    startup_mode = "Maximized"
    padding.x = 1
    # dynamic_padding = true
    
    [general]
    import = [
        "~/.config/alacritty/themes/themes/gruvbox_material_medium_dark.toml"
    ]
    
    [font]
    normal = { family = "JetBrains Mono Nerd Font", style = "Regular" }
    size = 14.5
    
    [cursor]
    style = { shape = "Beam", blinking = "On" }
    
    [keyboard]
    bindings = []

    tmux.conf:

    # Terminal settings
    set -g default-terminal "screen-256color"
    set -ga terminal-overrides ",xterm-256color:Tc"
    
    # Ensure mouse mode is actually on
    set -g mouse on
    
    # set -g mode-keys vi
    set -g prefix C-s
    bind : command
    bind C-s send-prefix
    bind C-r source-file ~/.config/tmux/tmux.conf;
    
    bind Space copy-mode
    
    bind -T copy-mode-vi Escape send-keys -X cancel
    
    # new tab
    bind C-w new-window
    bind C-a prev
    bind C-d next
    
    # STYLE
    
    set -g window-style 'fg=colour247,bg=red'
    set -g window-active-style 'fg=colour250,bg=black'
    
    # panes
    set -g pane-border-style 'fg=yellow, bg=black'
    set -g pane-active-border-style 'fg=brown, bg=black'
    
    # statusbar
    set -g status-position top
    set -g status-justify left
    set -g status-style 'fg=blue, bg=default'
    
    set -g status-left ''
    set -g status-left-length 10
    
    set -g status-right '#[fg=red,dim,bg=default]#(uptime | cut -f 4-5 -d " " | cut -f 1 -d ",") #[fg=white,bg=default]%a%l:%M:%S %p#[default]'
    
    setw -g window-status-current-style 'fg=white bg=black bold'
    
    setw -g window-status-current-format ' #I:#W#F '
    
    setw -g window-status-style 'fg=colour59 bg=default'
    setw -g window-status-format ' #I:#W#F '
    
    setw -g window-status-bell-style 'fg=black bg=green'
    
    # messages
    set -g message-style 'fg=black bg=yellow bold'

    Note finali

    Se siete a digiuno di neovim/vi ma lo state considerando da un po', il mio consiglio e' quello di prendere coraggio e partire da una distribuzione "chiavi in mano", sperimentando con le configurazioni e modellando il vostro ambiente agendo per sottrazione (es. LazyVim, MinMax etc. etc.). Per imparare invece i comandi principali, consiglio dei tutorial gamificati, come i leggendari VimAdventures o VimGolf.

    #home
    2026-04-07

    Hello, World!

    A meta' viaggio verso la Luna, l'equipaggio di Artemis 2 si volta e scatta una foto intera della terra, Hello, World.

    Gli Stati Uniti sono quel paese che elegge per due volte Donald Trump come suo presidente e contemporaneamente manda gente in orbita sulla luna.

    Il ritorno dell'homo sapiens sulla roccia grigia avviene dopo piu' di 50 anni, lo stesso progetto Artemis arriva con 20 anni di ritardo sulla tabella di marcia.

    Voto procrastinazione: 8.5. foto della terra Hello, World! e' anche il programma che per tradizione viene utilizzato come introduzione al lessico e alla grammatica di un linguaggio di programmazione. Qui ne elenco un po', in ordine sparso e mischiando linguaggi interpretati e compilati.

    "hello, world" (senza maiuscole e punto esclamativo) compare per la prima volta come esempio nel linaguaggio C. Suona come un Haiku dal sapore nostalgico e rassicurante (soprattutto quel return 0), ma anche contemporaneo:

    #include <stdio.h>
    
    int main() {
        printf("Hello, World!\n");
        return 0;
    }   

    Fortran 77 ha delle regole molto stringenti sulla composizione della riga. Il codice viene scritto dalla colonna 7 alla 72 e tutto in CAPS LOCK!!!:

    C      THIS IS A COMMENT
           PROGRAM HELLO
           PRINT *, 'HELLO, WORLD!'
           STOP
           END

    Se Shakespeare fosse stato un programmatore avrebbe scritto in Cobol, il linguaggio piu' prosaico della lista:

    IDENTIFICATION DIVISION.
           PROGRAM-ID. HELLO-WORLD.
           
           PROCEDURE DIVISION.
               DISPLAY 'Hello, World!'.
               STOP RUN.

    Il common-lisp e' solo uno dei dialetti di una famiglia molto larga. In Lisp (abbreviazione di "list processing") tutto e' una lista e quindi chiuso tra parentesi. format indica una funzione, t e' il corrispettivo di printf in C, i caratteri ~% indicano una nuova linea ("\n" in C). Hello World! entra in una riga di codice:

    (format t "Hello, World!~%")

    Il mio primo videogioco lo sviluppai a 10 anni, circa. In realta' era un guess the number in cli, non proprio videogioco, e copiai il codice da una rivista de l'epoca (TGM?). Comunque lo digitai in BASIC. In BASIC per Commodore64 i numeri sono obbligatori perche' all'epoca gli editor non avevano la possibilita' di muoversi su tutto lo schermo e per modificare il codice era necessario specificare la riga:

    10 PRINT "Hello, World!"
    20 END

    Nel 1980 arriva il qbasic, i numeri di riga diventano opzionali:

    PRINT "Hello, World!"

    Dieci anni dopo Microsoft rende la programmazione piu' accessibile inventando il Visual Basic. Hello, World! pero' diventa piu' prolisso:

    Module HelloWorld
        Sub Main()
            Console.WriteLine("Hello, World!")
        End Sub
    End Module

    Pascal, torniamo agli anni 70. Notevole il punto dopo end, indica la fine del codice sorgente:

    program HelloWorld;
    begin
      writeln('Hello, World!');
    end.

    Ada e' nipote di Pascal e utilizzato nella ISS, per rimanere in tema di esplorazione spaziale:

    with Ada.Text_IO; use Ada.Text_IO;
    procedure Hello is
    begin
    Put_Line ("Hello, world!");
    end;

    Larry Wall, personaggio molto cinematografico, e' linguista prima di essere pogrammatore. Non stupisce che la sua creazione, Perl, abbia come motto: "There's more than one way to do it" (TMTOWTDI):

    use IO::Handle;
    STDOUT->print("Hello, World!\n");

    o:

    use v5.10;
    say "Hello, World!";

    o:

    system("echo Hello, World!");

    o:

    print pack("H*", "48656c6c6f2c20576f726c64210a");

    In opposizione al TMTOWTDI c'e' il tredicesimo aforisma de The Zen of Python, che dice "There should be one—and preferably only one—obvious way to do it."

    print("Hello, World!")

    Tornando alla procrastinazione, tema centrale di questo blog, Non oggi dedichero' del serio tempo allo studio di Haskell, linguaggio puramente funzionale che negli anni '90 ha tamponato l'ascesa straripante della programmazione a oggetti. Questo codice, apparentemente semplice, nasconde un importante cambio di paradigma:

    main :: IO ()
    main = putStrLn "Hello, World!"

    A proposito di programmazione a oggetti, non posso non citare l'ubiquo C++, qui molto simile a suo nonno C:

    #include <iostream>
    
    int main() {
        std::cout << "Hello, World!" << std::endl;
        return 0;
    }

    E quell'abominio boilerplate di Java:

    public class HelloWorld {
        public static void main(String[] args) {
            System.out.println("Hello, World!");
        }
    }

    Secondo il sondaggio 2025 di StackOverflow, i linguaggi piu' utilizzati e quelli che si vorrebbero imparare:

    package main
    
    import "fmt"
    
    func main() {
        fmt.Println("Hello, World!")
    }
    fun main() {
        println("Hello, World!")
    }
    const std = @import("std");
    
    pub fn main() !void {
        const stdout = std.io.getStdOut().writer();
        try stdout.print("Hello, World!\n", .{});
    }
    fn main() {
        println!("Hello, World!");
    }

    Oltre ad astrarre problemi piu' complessi di Hello, World!, la spinta a creare nuovi linguaggi viene dala necessita' di rendere leggibile il codice che in ultima iterazione viene trasformato in codice binario. Leggibile sia da chi il codice non l'ha scritto, sia da chi l'ha scritto ma deve tornarci molto dopo, ovvero discostarsi il piu' possibile da Assembly, qui nella version x86 in tutto il suo ermetico splendore:

    .section  .data
    msg:
        .asciz "Hello, World!\n"
    msg_len = . - msg
    
    .section .text
    .globl _start
    _start:
        movl $4, %eax
        movl $1, %ebx
        movl $msg, %ecx
        movl $msg_len, %edx
        int $0x80
    
        movl $1, %eax
        xorl %ebx, %ebx
        int $0x80
    #home

Marco Piunti