Sommaire

Aujourd’hui, je vous propose de parler de l’éditeur de fichiers vi. Parmi ceux qui le connaissent, il y a ceux qui l’adorent, et ceux qui en sont allergiques… Sûrement parce que sans un peu d’entraînement, c’est effectivement un enfer à utiliser. Mais une fois qu’on s’habitue aux commandes de base, et qu’on l’a suffisamment personnalisé, il devient un outil extrêmement productif ! 😎

Installation de la version Improved

Selon les distributions, la version Improved n’est pas forcément installée. Sur une distribution basée sur Debian :

sudo apt install vim

Une fois Vim installé, la commande vi devient un alias qui pointe vers ce dernier.

Les commandes de base

Voici un tableau contenant les commandes principales de Vi :

CommandeDescription
EscQuitter le mode édition et repasser en mode commande
iEntrer en mode insertion
aEntrer en mode insertion après le curseur
AEntrer en mode insertion à la fin de la ligne
DEffacer le reste de la ligne à partir du curseur
CEffacer le reste de la ligne et entrer en mode édition
cwEffacer le mot et entrer en mode édition
uAnnuler la dernière action
:wEnregistrer le fichier
:wqEnregistrer le fichier et quitter
:q!Quitter sans enregistrer les modifications
ddSupprimer/couper la ligne courante
yyCopier la ligne courante
pColler sous la ligne courante
PColler avant la ligne courante
wAller au mot suivant
bAller au mot précédent
$Aller à la fin de la ligne
0Aller au début de la ligne
ggAller au début du fichier
GAller à la fin du fichier
/Suivi d’une saisie d’une chaîne à rechercher
nRechercher l’occurrence suivante
NRechercher l’occurrence précédente
*Rechercher les occurrences d’une chaîne à la position du curseur. * pour suivant

La liste est loin d’être exhaustive, mais vous avez déjà une bonne base pour éditer efficacement.

La personnalisation

Vi est par défaut assez austère, mais il est possible de passer de cette interface :

A ceci :

La personnalisation de Vi se fait dans un fichier que l’on nommera vimrc à placer ici : /home/<user>/.vim/vimrc). Il est possible d’indiquer des configurations propres à Vi, mais aussi de mapper des touches du clavier à certaines fonctions personnalisées. A noter aussi que Vi a son propre langage de scripting, afin par exemple de lui indiquer des conditions.

Le plus simple, c’est que vous récupériez mon fichier vimrc :


""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Configuration de Vim

" Paramétrage de base
syntax on                       " Active la colorisation syntaxique
set hlsearch                    " Affiche en surbrillance les recherches
set background=dark             " Optimise l'affiche pour un terminal sombre
set laststatus=2                " Affiche en permanence la barre de statut
set smartindent                 " Indentation intelligente
set smarttab                    " Gestion des espaces en debut de ligne
set autoindent                  " Conserve l'indentation sur une nouvelle ligne
set ruler                       " Affiche la position du curseur
set tabstop=2                   " La largeur d'une tabulation est définie sur 2
set shiftwidth=2                " Les retraits auront une largeur de 2
set softtabstop=2               " Nombre de colonnes pour une tabulation
set expandtab                   " Remplace les tab par des espaces
set linebreak                   " Revient à la ligne sans couper les mots
set showcmd                     " Afficher la commande dans la ligne d’état
set showmatch                   " Afficher les parentheses correspondantes
set ignorecase                  " Ignorer la casse
set smartcase                   " Faire un appariement intelligent
set incsearch                   " Recherche incrémentielle
set hidden                      " Cacher les tampons lorsqu'ils sont abandonnés
set mouse=                      " Désactive la souris par défaut
set nobackup                    " Désactive les sauvegardes automatiques
set spelllang=fr,en             " Spécifie les langues du dictionnaire

" Permet l'indentation automatique : gg=G
filetype plugin indent on

" Definition des caractères invisibles
let &listchars = "eol:$,space:\u00B7"

" Changement automatique du curseur en fonction du mode
let &t_SI = "\e[6 q"
let &t_EI = "\e[2 q"

" Fermeture automatique des brackets
inoremap { {}<Esc>ha
inoremap [ []<Esc>ha

" Mémoriser la dernière position du curseur
autocmd BufReadPost * if (line("'\"") > 1) && (line("'\"") <= line("$")) | silent exe "silent! normal g'\"zO" | endif

" Modification de certaines syntaxes
autocmd BufNewFile,BufRead *.lpl set syntax=json

" Configuration pour tmux
if $TERM == 'tmux-256color'
  set clipboard=unnamedplus
  set mouse=a
endif


""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Explorateur de fichiers

" Configuration
let g:netrw_liststyle = 3         " Active le mode Treeview
let g:netrw_sizestyle = "H"       " Active le mode human-readable
let g:netrw_banner = 0            " Désactive la bannière
let g:netrw_browse_split = 4      " Ouvre le fichier choisi dans un panel
let g:netrw_winsize = 15          " Définit la taille de l'explorateur

" Ferme automatiquement l'explorateur
aug netrw_close
  au!
  au WinEnter * if winnr('$') == 1 && getbufvar(winbufnr(winnr()), "&filetype") == "netrw"|q|endif
aug END


""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Barre de statut

" Elements à afficher
set statusline+=%F
set statusline+=\ %m
set statusline+=%=
set statusline+=\ %{strlen(&fenc)?&fenc:'none'}
set statusline+=\ \|
set statusline+=\ %P
set statusline+=\ \|
set statusline+=\ %l
set statusline+=\:%c


""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Mapping

" Explorateur de fichiers
nnoremap <F1> :Vexplore<CR>

" Activation de la numérotation
nnoremap <F2> :set number!<CR>

" Correction orthographique (z= pour afficher les propositions)
map <F3> :set spell!<CR>

" Affichage des caractères invisibles
nnoremap <F4> :set list!<CR>

" Indentation automatique
nnoremap <F5> gg=G <CR>

" Souris
nnoremap <F6> :call ToggleMouse()<CR>
function! ToggleMouse()
  if &mouse == 'a'
    set mouse=
    echo "Souris désactivée"
  else
    set mouse=a
    echo "Souris activée"
  endif
endfunction

" Coloration syntaxique
nnoremap <F7> :call ToggleSyntax()<CR>
function! ToggleSyntax()
  if &syntax == ''
    syntax on
    echo "Coloration syntaxique activée"
  else
    syntax off
    set syntax=
    echo "Coloration syntaxique désactivée"
  endif
endfunction

" Changement de document
nnoremap <S-TAB> <C-W>w
nnoremap <TAB> :tabnext<CR>


""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Theme

" OneHalfDark
if filereadable("/etc/vim/colors/onehalfdark.vim")
  set cursorline
  set t_Co=256
  colorscheme onehalfdark
  set termguicolors
  set noshowmode
endif

Pour le mapping des touches, voici ce qui est en place grâce à ce fichier :

  • F1 : Affiche l’explorateur de fichiers intégré
  • F2 : Affiche ou non les numéros de ligne
  • F3 : Permet de mettre en couleurs les mots mal orthographiés. La première fois, Vi vous proposera de télécharger les fichiers de langue nécessaires
  • F4 : Affiche les caractères de fin de ligne. Pratique si un espace invisible s’est glissé quelque part dans un script
  • F5 : Permet d’effectuer une indentation automatique sur l’intégralité du fichier
  • F6 : Active / désactive la gestion de la souris. Je ne l’active pas par défaut car la gestion du copier / coller est assez particulière
  • F7 : Désactive / active la coloration syntaxique (pour ceux qui sont gênés par les couleurs)

Le thème OneHalfDark

Vi possède une quantité dingue de thèmes différents. Personnellement, j’utilise le thème OneHalfDark :

Il est disponible sur la plupart des outils d’édition, et sur les terminaux les plus utilisés, dont l’excellent Windows Terminal de Microsoft.

Pour ajouter vos thèmes, il suffit de les déposer ici : /home/votre_user/.vim/colors (mkdir -p $HOME/.vim/colors si le dossier n’existe pas).

Ayant apporté quelques modifications dessus, je vous partage ma version modifiée directement ici :


set background=dark
highlight clear
syntax reset

let g:colors_name="onehalfdark"
let colors_name="onehalfdark"


let s:black       = { "gui": "#282c34", "cterm": "236" }
let s:red         = { "gui": "#e06c75", "cterm": "168" }
let s:green       = { "gui": "#98c379", "cterm": "114" }
let s:yellow      = { "gui": "#e5c07b", "cterm": "180" }
let s:blue        = { "gui": "#61afef", "cterm": "75"  }
let s:purple      = { "gui": "#c678dd", "cterm": "176" }
let s:cyan        = { "gui": "#56b6c2", "cterm": "73"  }
let s:white       = { "gui": "#abb2bf", "cterm": "188" }

let s:fg          = s:white
let s:bg          = s:black

let s:comment_fg  = { "gui": "#636a78", "cterm": "241" }
let s:gutter_bg   = { "gui": "#282c34", "cterm": "236" }
let s:gutter_fg   = { "gui": "#919baa", "cterm": "247" }
let s:non_text    = { "gui": "#373C45", "cterm": "239" }

let s:cursor_line = { "gui": "#313640", "cterm": "237" }
let s:color_col   = { "gui": "#313640", "cterm": "237" }

let s:selection   = { "gui": "#474e5d", "cterm": "239" }
let s:vertsplit   = { "gui": "#313640", "cterm": "237" }


function! s:h(group, fg, bg, attr)
  if type(a:fg) == type({})
    exec "hi " . a:group . " guifg=" . a:fg.gui . " ctermfg=" . a:fg.cterm
  else
    exec "hi " . a:group . " guifg=NONE cterm=NONE"
  endif
  if type(a:bg) == type({})
    exec "hi " . a:group . " guibg=" . a:bg.gui . " ctermbg=" . a:bg.cterm
  else
    exec "hi " . a:group . " guibg=NONE ctermbg=NONE"
  endif
  if a:attr != ""
    exec "hi " . a:group . " gui=" . a:attr . " cterm=" . a:attr
  else
    exec "hi " . a:group . " gui=NONE cterm=NONE"
  endif
endfun


" User interface colors {
call s:h("Normal", s:fg, s:bg, "")

call s:h("Cursor", s:bg, s:blue, "")
call s:h("CursorColumn", "", s:cursor_line, "")
call s:h("CursorLine", "", s:cursor_line, "")

call s:h("LineNr", s:gutter_fg, s:gutter_bg, "")
call s:h("CursorLineNr", s:fg, "", "")

call s:h("DiffAdd", s:green, "", "")
call s:h("DiffChange", s:yellow, "", "")
call s:h("DiffDelete", s:red, "", "")
call s:h("DiffText", s:blue, "", "")

call s:h("IncSearch", s:bg, s:yellow, "")
call s:h("Search", s:bg, s:yellow, "")

call s:h("ErrorMsg", s:fg, "", "")
call s:h("ModeMsg", s:fg, "", "")
call s:h("MoreMsg", s:fg, "", "")
call s:h("WarningMsg", s:red, "", "")
call s:h("Question", s:purple, "", "")

call s:h("Pmenu", s:bg, s:fg, "")
call s:h("PmenuSel", s:fg, s:blue, "")
call s:h("PmenuSbar", "", s:selection, "")
call s:h("PmenuThumb", "", s:fg, "")

call s:h("SpellBad", s:red, "", "")
call s:h("SpellCap", s:yellow, "", "")
call s:h("SpellLocal", s:yellow, "", "")
call s:h("SpellRare", s:yellow, "", "")

call s:h("StatusLine", s:blue, s:cursor_line, "")
call s:h("StatusLineNC", s:comment_fg, s:cursor_line, "")
call s:h("TabLine", s:comment_fg, s:cursor_line, "")
call s:h("TabLineFill", s:comment_fg, s:cursor_line, "")
call s:h("TabLineSel", s:fg, s:bg, "")

call s:h("Visual", "", s:selection, "")
call s:h("VisualNOS", "", s:selection, "")

call s:h("ColorColumn", "", s:color_col, "")
call s:h("Conceal", s:fg, "", "")
call s:h("Directory", s:blue, "", "")
call s:h("VertSplit", s:vertsplit, s:vertsplit, "")
call s:h("Folded", s:fg, "", "")
call s:h("FoldColumn", s:fg, "", "")
call s:h("SignColumn", s:fg, "", "")

call s:h("MatchParen", s:blue, "", "underline")
call s:h("SpecialKey", s:fg, "", "")
call s:h("Title", s:green, "", "")
call s:h("WildMenu", s:fg, "", "")
" }


" Syntax colors {
" Whitespace is defined in Neovim, not Vim.
" See :help hl-Whitespace and :help hl-SpecialKey
call s:h("Whitespace", s:non_text, "", "")
call s:h("NonText", s:non_text, "", "")
call s:h("Comment", s:comment_fg, "", "")
call s:h("Constant", s:cyan, "", "")
call s:h("String", s:green, "", "")
call s:h("Character", s:green, "", "")
call s:h("Number", s:yellow, "", "")
call s:h("Boolean", s:yellow, "", "")
call s:h("Float", s:yellow, "", "")

call s:h("Identifier", s:red, "", "")
call s:h("Function", s:blue, "", "")
call s:h("Statement", s:purple, "", "")

call s:h("Conditional", s:purple, "", "")
call s:h("Repeat", s:purple, "", "")
call s:h("Label", s:purple, "", "")
call s:h("Operator", s:fg, "", "")
call s:h("Keyword", s:red, "", "")
call s:h("Exception", s:purple, "", "")

call s:h("PreProc", s:yellow, "", "")
call s:h("Include", s:purple, "", "")
call s:h("Define", s:purple, "", "")
call s:h("Macro", s:purple, "", "")
call s:h("PreCondit", s:yellow, "", "")

call s:h("Type", s:yellow, "", "")
call s:h("StorageClass", s:yellow, "", "")
call s:h("Structure", s:yellow, "", "")
call s:h("Typedef", s:yellow, "", "")

call s:h("Special", s:blue, "", "")
call s:h("SpecialChar", s:fg, "", "")
call s:h("Tag", s:fg, "", "")
call s:h("Delimiter", s:fg, "", "")
call s:h("SpecialComment", s:fg, "", "")
call s:h("Debug", s:fg, "", "")
call s:h("Underlined", s:fg, "", "")
call s:h("Ignore", s:fg, "", "")
call s:h("Error", s:red, s:gutter_bg, "")
call s:h("Todo", s:purple, "", "")
" }

Le fichier vimrc que j’ai mis à disposition plus haut chargera automatiquement ce thème si le fichier onehalfdark.vim est présent et que votre terminal est compatible.

Conclusion

Toutes ces modifications ne sont qu’une porte d’entrée à tout ce qu’il est possible de personnaliser dans Vi. Pour ceux qui souhaiteraient aller encore plus loin, il existe tout un tas de plugins supplémentaires. Mais par expérience, je trouve que cela finit par l’alourdir par rapport à mes besoins.

Si vous avez des questions particulières, vous savez où me trouver 😉