Quel est le moyen le plus simple de supprimer les espaces finaux de toutes les lignes d'un fichier?

140

Il est assez courant, lors de la programmation ou de l’ouverture de fichiers texte, de rencontrer des fichiers avec des espaces en fin de ligne. vim a un moyen de le montrer en définissant l' trailoption dans l' listcharsoption puis en l'activant list.

Cependant, quel est le moyen le plus simple d’éliminer globalement l’espace caché dans l’ensemble du fichier (idéalement sans plugin)?

Andrew Ferrier
la source
Voici une entrée de doc sur le sujet.
Filipp W.
Si vous avez installé vim-faq , vous pouvez obtenir une réponse hors ligne à cet endroit: :h vim-faqet effectuer une recherche /trailing. Le tag difficile à mémoriser est :h faq-12.1.
Hotschke le

Réponses:

73

Utilisez un raccourci clavier pour effacer tous les espaces finaux

Étant donné que certaines pages que je modifie ont réellement besoin d'espaces de fin (par exemple, de markdown) et d'autres non, j'ai configuré une liaison de clé pour F5qu'il soit facile de le faire sans être automatique. Pour ce faire, ajoutez le code ci-dessous (de vim.wikia) ou une variante de celui-ci à votre .vimrc:

"Remove all trailing whitespace by pressing F5
nnoremap <F5> :let _s=@/<Bar>:%s/\s\+$//e<Bar>:let @/=_s<Bar><CR>
  • nnoremap <F5>effectue un mappage non récursif sur la clé F5en mode normal
  • :let _s=@/stocke le dernier terme de recherche (de la macro @/) dans la variable_s
  • <Bar>Fonctionne comme un symbole de canal |pour séparer les commandes, mais |mettrait fin à une commande dans ce contexte, elle <Bar>doit donc être utilisée à la place.
  • :%s/\s\+$//erecherche les espaces de fin et les supprime partout dans le tampon (voir la réponse de CarpetSmoker pour une analyse détaillée de cette expression)
  • let @/=_srestaure votre dernier terme de recherche dans la macro @/, afin qu'il soit disponible lors de votre prochain contact n.
  • <CR> termine la cartographie

... ou être plus sélectif

Si vous avez des cas dans lesquels vous ne souhaitez pas effacer tous les espaces finaux, vous pouvez utiliser un modèle pour être plus sélectif. Par exemple, le code suivant montre comment je supprime les espaces en fin de champ uniquement s'ils sont placés après un point-virgule (ici, ils sont liés F8).

nnoremap <F8> :let _s=@/<Bar>:%s/;\s\+$/;/e<Bar>:let @/=_s<Bar><CR>

Ceci est utile si, comme moi, vous avez des fichiers avec des heredocs de type markdown, intercalés entre des instructions de programmation terminées par des points-virgules.

Christopher Bottoms
la source
6
Essayez :keeppatternsd'éviter de passer outre @/. Et aussi jeter un oeil à :keepjumps.
Bohr
@ Bohr Quelle version de vim utilisez-vous? J'ai essayé :help keeppatternet je n'ai rien eu.
Christopher Bottoms
@ChristopherBottoms Au moins la version 7.4.155 .
Bohr
@ Bohr. Merci! Venez découvrir que j'utilisais encore 7.4.0. J'ai installé la dernière version et elle est disponible.
Christopher Bottoms
2
Vous pouvez obtenir le même effet en enveloppant cette commande dans une fonction, depuis lors , le dernier terme de recherche est automatiquement restauré :-) De cette façon , vous ne devez pas perdre son temps avec :nohlsoit, si si vous surlignant quelque chose, il gardera mettre en évidence le (voir ma réponse mise à jour).
Martin Tournoij
176

Le "plus simple" consiste simplement à utiliser :substitute:

:%s/\s\+$//e
  • :%spour exécuter :substitutesur la plage %, qui est la totalité du tampon.
  • \s Ne correspond pas à tous les caractères blancs.
  • \+ pour les répéter 1 fois ou plus.
  • $ jeter l'ancre au bout de la ligne.
  • L' eindicateur pour ne pas donner d'erreur s'il n'y a pas de correspondance (c'est-à-dire que le fichier est déjà sans espaces de fin).

Cependant, ce n’est probablement pas le "meilleur" moyen car il a deux effets secondaires:

  1. il déplace le curseur sur le dernier match;
  2. il ajoute la commande à l'historique et à l'historique de recherche;
  3. il réinitialise le dernier terme de recherche.

Vous pouvez corriger les deux éléments en les transformant en une fonction:

fun! TrimWhitespace()
    let l:save = winsaveview()
    keeppatterns %s/\s\+$//e
    call winrestview(l:save)
endfun

Et puis l'utiliser comme:

:call TrimWhitespace()
  1. La winsaveview()sauvegarde enregistrera la "vue" actuelle, qui comprend la position du curseur, les replis, les sauts, etc. La dernière winrestview()la restaurera à partir de la variable enregistrée.
  2. L' :keeppatternsempêche le \s\+$motif d'être ajouté à l'historique de recherche.
  3. Le dernier terme de recherche utilisé est automatiquement restauré après avoir quitté une fonction. Nous n'avons donc rien d'autre à faire pour cela.

Comme il est un peu ennuyeux de taper :calltout le temps, vous pouvez définir une commande:

command! TrimWhitespace call TrimWhitespace()

Qui peut être utilisé sans le :call:

:TrimWitespace

Et vous pouvez bien sûr le lier à une clé:

:noremap <Leader>w :call TrimWhitespace()<CR>

Certaines personnes aiment le faire automatiquement avant d’écrire un fichier sur le disque, comme ceci:

autocmd BufWritePre * :call TrimWhitespace()

Je n'aime pas ça, car certains formats nécessitent des espaces de fin (tels que Markdown) et, à d'autres occasions, vous souhaitez même des espaces de fin dans votre code (tels que le formatage d'un e-mail et l'utilisation du --<Space>marqueur pour indiquer le début d'une signature.) ).


Mode plug éhonté: il y a quelque temps, j'ai écrit un petit script Python pour nettoyer les espaces d'un projet entier à la fois.

Martin Tournoij
la source
1
Si vous ne souhaitez pas créer de fonction pour passer à la position précédente, vous pouvez appuyer ​`​deux fois sur cette option une fois le remplacement terminé. Cela ouvre la possibilité de créer un oneliner comme celui-ci:%s/\s\+$//e | exe "normal ``"
Neaţu Ovidiu Gabriel
1
@ NeaţuOvidiuGabriel, bien entendu, le double backtick ne fonctionnera pas de la même manière après l'exécution de l'unique doublure ;)
Wildcard
Similaire: stackoverflow.com/a/1618401 . Mais j'aime plus le code de Martin.
john cj
11

Pour supprimer tous les espaces finaux (à la fin de chaque ligne), vous pouvez utiliser la commande suivante:

:%s/ \+$//

Pour inclure des onglets, utilisez \splutôt que l'espace.


A partir de la ligne de commande:

$ ex +'%s/\s\+$//e' -cwq file.c

Tous les fichiers du répertoire en cours (à utiliser de manière récursive **/*.*):

$ ex +'bufdo!%s/\s\+$//e' -cxa *.*

Façon Python:

:py import vim
:pydo vim.current.buffer[linenr - 1] = vim.current.buffer[linenr - 1].strip()

ou:

:py import vim
:py for i, l in enumerate(vim.current.buffer): vim.current.buffer[i] = l.rstrip()

Utilisez-le lstrip()pour la bande gauche (tirée), rstrip()pour la bande droite (avant) ou strip()pour la retirer des deux côtés.


Voici une fonction utile qui supprime les blancs superflus de la fin d'une ligne que vous pouvez ajouter à votre .vimrc:

" Removes superfluous white space from the end of a line
function! RemoveWhiteSpace()
   :%s/\s*$//g
    :'^
    "`.
endfunction

Il existe également un plugin DeleteTrailingWhitespace pour cela.


Mise en évidence des espaces blancs

Pour vérifier si tous les espaces de fin ont disparu, utilisez:

  1. Tapez / $pour les trouver. S'il y en a, vim les mettra en évidence pour vous.

  2. Utilisez des couleurs pour les mettre en évidence:

    :highlight ws ctermbg=red guibg=red
    :match ws /\s\+$/
    
  3. Utilisez des caractères visibles ( source ):

    :set encoding=utf-8
    :set listchars=trail:·
    :set list
    

Voir aussi: Mettre en évidence les espaces non désirés

Pour mettre en évidence les espaces finaux par défaut, vous pouvez configurer votre .vimrccomme suit:

highlight ws ctermbg=red guibg=red
match ws /\s\+$/
autocmd BufWinEnter * match ws / \+$/

Supprimer les espaces blancs par défaut

Si vous souhaitez vous assurer que tous les espaces finaux d'un fichier sont automatiquement supprimés lors de l'enregistrement, vous pouvez ajouter la commande suivante dans votre .vimrc:

autocmd BufWritePre *.c,*.php :%s/ \+$//ge

ce qui n'est pas recommandé, car il supprimera les espaces finaux de chaque fichier enregistré par l'utilisateur (même lorsque des espaces peuvent être souhaités).


Voir également:

Kenorb
la source
5

En réponse à la réponse de Christopher Bottoms : Jonathan Palardy a écrit un bon article à ce sujet . Il y écrit une fonction Preserve(command)qui préserve l’état de l’éditeur (principalement la position du curseur et le dernier motif de recherche) lors de l’exécution d’une commande quelconque:

function! Preserve(command)
  " Preparation: save window state
  let l:saved_winview = winsaveview()
  " Run the command:
  execute a:command
  " Clean up: restore previous window position
  call winrestview(l:saved_winview)
endfunction

Cela a l’avantage d’être polyvalent. Par exemple, vous pouvez l’utiliser pour remplacer tous les espaces finaux (comme le fait Jonathan) en les mappant sur:

nnoremap <F5> :call Preserve("%s/\\s\\+$//e")<CR>

Vous pouvez également l'utiliser pour un mappage en mode visuel afin de simplement supprimer les espaces de fin sur les lignes sélectionnées visuellement:

xnoremap <F5> :call Preserve("'<,'>s/\\s\\+$//e")<CR>

Et vous pouvez l’utiliser pour d’autres appels, tels que le formatage de l’ensemble du document =tout en conservant votre emplacement (utilisez une autre clé pour éviter tout conflit):

nnoremap <F6> :call Preserve("normal gg=G")<CR>

Dans l’ensemble, j’ai trouvé la Preserve(command)fonction très utile.

Alex
la source
2
Le dernier terme de recherche utilisé doit être automatiquement conservé lorsque vous quittez une fonction. si déblayage environ avec @/ne devrait pas être nécessaire (dans ce cas, de toute façon).
Martin Tournoij
3
winsaveview()et winrestview()sont de loin supérieurs.
dash-tom-bang
Tout à fait raison! Mis à jour en fonction de vos commentaires.
Alex
0

Une autre version de la fonction StripTrailingSpaces:

if !exists('*StripTrailingWhitespace')
    function! StripTrailingWhitespace() range
        if !&binary && &filetype != 'diff'
            call Preserve(":" . a:firstline . "," . a:lastline . "s/\\s\\+$//e")
        endif
    endfunction
endif

ACTUELLEMENT, IL Y A UN BUG DANS CETTE FONCTION (celle-ci): l’option n’est pas conservée à cause de l’option "range". si elle est supprimée, cela fonctionne très bien, mais je partage le code pour recevoir de l’aide.

Comme vous pouvez le constater, il utilise également la fonction Préserver décrite ci-dessus, mais d'une manière légèrement différente.

La différence ici est que je peux sélectionner une plage de lignes ou un paragraphe avec vip, puis la plage :'<,'>apparaîtra automatiquement à l'invite de commande.

L'idée est venue du message de Bez Hermoso .

SergioAraujo
la source