Ho provato per vari anni i maggiori editor di testi disponibili sul mercato: da Sublime Text, Atom, il famosissimo VSCode, PHPStorm e altri marchiati JetBrains. Devo dire che i migliori per facilità d’utilizzo, comodi per funzionalità di base o con l’aggiunta di plugins sono quelli di JetBrains e VSCode. Quest’ultimo l’ho utilizzato negli ultimi anni accantonando i JetBrains solamente per via del loro costo. Ho impostato VSCode per un utilizzo con vari linguaggi di programmazione, ho imparato gli shortcodes per rendere la digitazione e il movimento all’interno del programma più veloce e fluido e mantenere le dita il più possibile sui tasti e non spostarli su frecce direzionali o mouse.
Devo dire che mi sono sempre trovato bene ma ho sempre usato vim in remoto sui server per modificare configurazioni, settaggi etc..

I PRIMI PASSI CON VIM E NEOVIM

Come dicevo in precedenza, vim l’ho scoperto anni e anni fa appena ho avuto la necessità di gestire server remoti, anche in altri stati: non avendo grafica, la gestione delle configurazioni avviene tutta tramite riga di comando e vim è un must da saper utilizzare. Selezionare, taglia-copia-incolla, modificare, inserire parole o paragrafi, ricercare stringhe e sostituirle; insomma, vim è un editor completo a cui non manca nulla rispetto a uno classico da desktop.
Non è complicato da usare, ci sono molti video su Youtube in cui si spiegano i 4 comandi essenziali per iniziare ad utilizzarlo.

Guardando video e leggendo reddit avevo visto che molti suggerivano di abbandonare i ‘classici’ editor e di passare a vim, più nello specifico NeoVim.

Neovim is a Vim-based text editor engineered for extensibility and usability, to encourage new applications and contributions.

Ho voluto provarlo con un progetto già iniziato con VSCode.
Mai scelta fu più azzeccata: dalla console si riesce a fare anche di più di quello che VSCode permette; personalizzare i comandi, combinazione dei tasti per effettuare anche movimenti all’interno della schermato di lavoro.

Metto a disposizione di chi voglia provare una nuova modalità di scrittura i miei dotfiles.

OCCORRENTE

Questo è un piccolo riassunto di quello che servirà per avere un sistema funzionante.

PREREQUISITI

Alacritty è la console che ho scelto di utilizzare. Per visualizzare i glifi sulla console utilizzo Nerd fonts.

Struttura delle directory

Neovim è conforme alla struttura delle directory XDG Base Directory. Neovim carica $HOME/.config/nvim/init.vim o ìnit.lua invece di $HOME/.vimrc.

É presente una guida con i primi passi per utilizzare Neovim.

INSTALLAZIONE

Spiegherò brevemente come installare i pacchetti necessari per un utilizzo basilare

Neovim

Come prima cosa deve essere installato NeoVim:

macOS / OS X

brew install neovim

Arch Linux

sudo pacman -S neovim

Debian / Ubuntu

sudo apt-get install neovim

Packer

Installare prima di tutto wbthomason/packer.nvim con il seguente comando per la gestione dei plugins di Neovim:

git clone --depth 1 https://github.com/wbthomason/packer.nvim \
 ~/.local/share/nvim/site/pack/packer/start/packer.nvim

Successivamente creare il file ./.config/nvim/lua/plugins.lua contenente il seguente codice:

local status, packer = pcall(require, "packer")
if (not status) then
  print("Packer is not installed")
  return
end

vim.cmd [[packadd packer.nvim]]

packer.startup(function(use)
  use 'wbthomason/packer.nvim'
  -- Your plugins go here
end)

e richiamarlo nel file init.lua:

  git config pull.rebase false

Neosolarized

Neosolarized colorscheme for neovim

Utilizzo svrana/neosolarized.nvim con qualche minima modifica:

local status, n = pcall(require, "neosolarized")
if (not status) then return end

n.setup({
  comment_italics = true,
})

local cb = require('colorbuddy.init')
local Color = cb.Color
local colors = cb.colors
local Group = cb.Group
local groups = cb.groups
local styles = cb.styles

Color.new('black', '#000000')
Group.new('CursorLine', colors.none, colors.base03, styles.NONE, colors.base1)
Group.new('CursorLineNr', colors.yellow, colors.black, styles.NONE, colors.base1)
Group.new('Visual', colors.none, colors.base03, styles.reverse)

local cError = groups.Error.fg
local cInfo = groups.Information.fg
local cWarn = groups.Warning.fg
local cHint = groups.Hint.fg

Group.new("DiagnosticVirtualTextError", cError, cError:dark():dark():dark():dark(), styles.NONE)
Group.new("DiagnosticVirtualTextInfo", cInfo, cInfo:dark():dark():dark(), styles.NONE)
Group.new("DiagnosticVirtualTextWarn", cWarn, cWarn:dark():dark():dark(), styles.NONE)
Group.new("DiagnosticVirtualTextHint", cHint, cHint:dark():dark():dark(), styles.NONE)
Group.new("DiagnosticUnderlineError", colors.none, colors.none, styles.undercurl, cError)
Group.new("DiagnosticUnderlineWarn", colors.none, colors.none, styles.undercurl, cWarn)
Group.new("DiagnosticUnderlineInfo", colors.none, colors.none, styles.undercurl, cInfo)
Group.new("DiagnosticUnderlineHint", colors.none, colors.none, styles.undercurl, cHint)

Status line: Lualine

Lualine status line for neovim

nvim-lualine/lualine.nvim è un plugin che permette di creare graziose status line con le informazioni più utili mentre si lavora.

local status, lualine = pcall(require, "lualine")
if (not status) then return end

lualine.setup {
  options = {
    icons_enabled = true,
    theme = 'solarized_dark',
    section_separators = { left = '', right = '' },
    component_separators = { left = '', right = '' },
    disabled_filetypes = {}
  },
  sections = {
    lualine_a = { 'mode' },
    lualine_b = { 'branch' },
    lualine_c = { {
      'filename',
      file_status = true, -- displays file status (readonly status, modified status)
      path = 0 -- 0 = just filename, 1 = relative path, 2 = absolute path
    } },
    lualine_x = {
      { 'diagnostics', sources = { "nvim_diagnostic" }, symbols = { error = ' ', warn = ' ', info = ' ',
        hint = ' ' } },
      'encoding',
      'filetype'
    },
    lualine_y = { 'progress' },
    lualine_z = { 'location' }
  },
  inactive_sections = {
    lualine_a = {},
    lualine_b = {},
    lualine_c = { {
      'filename',
      file_status = true, -- displays file status (readonly status, modified status)
      path = 1 -- 0 = just filename, 1 = relative path, 2 = absolute path
    } },
    lualine_x = { 'location' },
    lualine_y = {},
    lualine_z = {}
  },
  tabline = {},
  extensions = { 'fugitive' }
}

LSPConfig

Neovim ha all’interno del proprio codice il supporto a LSP. Con neovim/nvim-lspconfig lo si può configurare facilemente.

Per esempio, per attivare il supporto a typescript con neovim:

local status, nvim_lsp = pcall(require, "lspconfig")
if (not status) then return end

local protocol = require('vim.lsp.protocol')

local on_attach = function(client, bufnr)
  -- format on save
  if client.server_capabilities.documentFormattingProvider then
    vim.api.nvim_create_autocmd("BufWritePre", {
      group = vim.api.nvim_create_augroup("Format", { clear = true }),
      buffer = bufnr,
      callback = function() vim.lsp.buf.formatting_seq_sync() end
    })
  end
end

-- TypeScript
nvim_lsp.tsserver.setup {
  on_attach = on_attach,
  filetypes = { "typescript", "typescriptreact", "typescript.tsx" },
  cmd = { "typescript-language-server", "--stdio" }
}

e non dimentichiamoci di installare il server per typescript con il comando:

npm i -g typescript-language-server

Auto completion: Lspkind and cmp

auto completition for neovim

Per ottenere LSP con l’autocompletamento automatico con i pittogrammi ho usato i seguenti plugins:

E configurarlo come segue:

local status, cmp = pcall(require, "cmp")
if (not status) then return end
local lspkind = require 'lspkind'

cmp.setup({
  snippet = {
    expand = function(args)
      require('luasnip').lsp_expand(args.body)
    end,
  },
  mapping = cmp.mapping.preset.insert({
    ['<C-d>'] = cmp.mapping.scroll_docs(-4),
    ['<C-f>'] = cmp.mapping.scroll_docs(4),
    ['<C-Space>'] = cmp.mapping.complete(),
    ['<C-e>'] = cmp.mapping.close(),
    ['<CR>'] = cmp.mapping.confirm({
      behavior = cmp.ConfirmBehavior.Replace,
      select = true
    }),
  }),
  sources = cmp.config.sources({
    { name = 'nvim_lsp' },
    { name = 'buffer' },
  }),
  formatting = {
    format = lspkind.cmp_format({ with_text = false, maxwidth = 50 })
  }
})

vim.cmd [[
  set completeopt=menuone,noinsert,noselect
  highlight! default link CmpItemKind CmpItemMenuDefault
]]

Highlight syntax: TreeSitter

TreeSitter highlight plugin

TreeSitter è un linguaggio parser popolare per evidenziare e colorare il codice a schermo: installarlo con il seguente comando:

macOS / OS X

brew install tree-sitter

Arch Linux

sudo pacman -S tree-sitter

Debian / Ubuntu

sudo apt-get install tree-sitter

Passo successivo è installare il plugin nvim-treesitter/nvim-treesitter con Packer e configurarlo:

local status, ts = pcall(require, "nvim-treesitter.configs")
if (not status) then return end

ts.setup {
  highlight = {
    enable = true,
    disable = {},
  },
  indent = {
    enable = true,
    disable = {},
  },
  ensure_installed = {
    "tsx",
    "toml",
    "fish",
    "php",
    "json",
    "yaml",
    "swift",
    "css",
    "html",
    "lua"
  },
  autotag = {
    enable = true,
  },
}

local parser_config = require "nvim-treesitter.parsers".get_parser_configs()
parser_config.tsx.filetype_to_parsername = { "javascript", "typescript.tsx" }

Autotag e Autopair

Con React capita molto spesso di voler chiudere i tags nel modo più rapido ed efficiente possibile. windwp/nvim-ts-autotag ci viene in soccorso:

local status, autotag = pcall(require, "nvim-ts-autotag")
if (not status) then return end

autotag.setup({})

Mentre windwp/nvim-autopairs è per chiudere in automatico le parentesi.

local status, autopairs = pcall(require, "nvim-autopairs")
if (not status) then return end

autopairs.setup({
  disable_filetype = { "TelescopePrompt" , "vim" },
})

Telescope

Telescope finder plugin

nvim-telescope/telescope.nvim è un utilissimo plugin per la ricerca di files e stringhe, grazie al suo potente motore di ricerca, nella cartella di lavoro.

Telescope file browser

Con l’aggiunta di nvim-telescope/telescope-file-browser.nvim sarà possibile visualizzare anche un’anteprima del file senza la necessità di aprirlo.

Configurazione richiesta:

local status, telescope = pcall(require, "telescope")
if (not status) then return end
local actions = require('telescope.actions')
local builtin = require("telescope.builtin")

local function telescope_buffer_dir()
  return vim.fn.expand('%:p:h')
end

local fb_actions = require "telescope".extensions.file_browser.actions

telescope.setup {
  defaults = {
    mappings = {
      n = {
        ["q"] = actions.close
      },
    },
  },
  extensions = {
    file_browser = {
      theme = "dropdown",
      -- disables netrw and use telescope-file-browser in its place
      hijack_netrw = true,
      mappings = {
        -- your custom insert mode mappings
        ["i"] = {
          ["<C-w>"] = function() vim.cmd('normal vbd') end,
        },
        ["n"] = {
          -- your custom normal mode mappings
          ["N"] = fb_actions.create,
          ["h"] = fb_actions.goto_parent_dir,
          ["/"] = function()
            vim.cmd('startinsert')
          end
        },
      },
    },
  },
}
telescope.load_extension("file_browser")

-- keymaps
vim.keymap.set('n', ';f',
  function()
    builtin.find_files({
      no_ignore = false,
      hidden = true
    })
  end)
vim.keymap.set('n', ';r', function()
  builtin.live_grep()
end)
vim.keymap.set('n', '\\\\', function()
  builtin.buffers()
end)
vim.keymap.set('n', ';t', function()
  builtin.help_tags()
end)
vim.keymap.set('n', ';;', function()
  builtin.resume()
end)
vim.keymap.set('n', ';e', function()
  builtin.diagnostics()
end)
vim.keymap.set("n", "sf", function()
  telescope.extensions.file_browser.file_browser({
    path = "%:p:h",
    cwd = telescope_buffer_dir(),
    respect_gitignore = false,
    hidden = true,
    grouped = true,
    previewer = false,
    initial_mode = "normal",
    layout_config = { height = 40 }
  })
end)

Gestione tabs: Bufferline

Bufferline

Ho installato anche akinsho/nvim-bufferline.lua per una migliore gestione dei tabs.

Code Formatting: Prettier e null-ls

jose-elias-alvarez/null-ls.nvim

è un plugin per poter utilizzare Neovim come linter, formatter, code action e tanto altro con Lua.

Nella configurazione che segue è impostato la diagnostica con eslint_d e il formatting con prettierd

if (not status) then return end

local augroup_format = vim.api.nvim_create_augroup("Format", { clear = true })

null_ls.setup({
  sources = {
    -- diagnostics
    null_ls.builtins.diagnostics.eslint_d.with({
      diagnostics_format = '[eslint] #{m}\n(#{c})'
    }),
    null_ls.builtins.diagnostics.tidy,
    -- linters
    null_ls.builtins.formatting.prettierd,
    -- code action
  },
  on_attach = function(client, bufnr)
    if client.server_capabilities.documentFormattingProvider then
      vim.api.nvim_clear_autocmds { buffer = 0, group = augroup_format }
      vim.api.nvim_create_autocmd("BufWritePre", {
        group = augroup_format,
        buffer = 0,
        callback = function() vim.lsp.buf.formatting_seq_sync() end
      })
    end
  end,
})

Gitsigns

Gitsigns

lewis6991/gitsigns.nvim integra le decorazioni ai lati dello schermo delle modifiche per il buffer corrente. É un aiuto per sapere quali linee di codice sono state modificate.

Non c’è bisogno di grandi configurazioni:

require('gitsigns').setup {}

Mason

williamboman/mason.nvim e williamboman/mason-lspconfig.nvim sono utilizzati nel caso servono librerie addizionali per LSP: Mason tramite un popup mostra quali language server sono disponibili e li installa in automatico.

Commenti

Commenti

Capita spesso di dover commentare porzioni di codice e numToStr/Comment.nvim è il plugin perfetto. Supporta treesitter, commentstring ed è possibile inserire commenti su singola linea // o su blocco di più righe /* */.

Per creare il default mapping:

require('Comment').setup()

AutoSession

AutoSession

rmagatti/auto-session è un plugin per la gestione della sessione di Neovim. Si avvantaggia della già esistente gestione della sessione presente in Neovim e la automatizza.

La uso associata a tmux/tmux per riprendere il lavoro nello stesso punto lasciato prima di un riavvio del PC. Ci si ritrova il cursore esattamente nella stessa linea.


Questo è attualmente il mio setup per Neovim. Tutta la configurazione e dotfiles sono online nel mio repo.