Changer le retrait de 2 espaces en 4 espaces dans vim

91

J'ai des codes copiés à partir d'Internet qui ont une indentation de 2 espaces et je veux les changer en indentation de 4 espaces. Je me demande s'il existe une courte routine vim pour accomplir la tâche sans avoir à écrire de script vim? Voici comment je le fais actuellement avec un fichier HTML:

  • Enregistrer une macro
  • Aller au début d'une ligne
  • Sélection visuelle de tous les espaces jusqu'à la première occurrence de "<"
  • Tirez et collez tous les espaces (essentiellement pour les doubler)
  • Relire la macro jusqu'à la fin du fichier

En bref qa0vt<yp<esc>jq

Pièges:

La macro échoue pour une ligne vide ou une ligne qui ne commence pas par "<". Et je ne sais pas comment étendre cette solution à un fichier non HTML.

Lim H.
la source

Réponses:

170

Une manière générale de modifier le retrait consiste à modifier le tabstop:

Collez votre fichier dans un tampon vide, puis:

:set ts=2 sts=2 noet
:retab!

Cela change tous les 2 espaces en un caractère TAB, puis:

:set ts=4 sts=4 et
:retab

Cela change chaque TAB à 4 espaces.

L'avantage de cette méthode est que vous pouvez également l'utiliser dans l'autre sens, pour convertir de 4 en 2 espaces par exemple.

Daan Bakker
la source
16
@ XavierT Je pense en fait que cette réponse est assez facile à comprendre. Et ce sera peut - être plus clair si le nom court de commande est remplacer par leur nom complet: ts: = tabstop, sts: = softtabstopet [no]et: = [no]expandtab.
YaOzI
Dans quelle situation retabl'argumentation serait-elle utile, et pourquoi ne pouvons-nous pas l'utiliser pour cette tâche?
joeytwiddle
@joeytwiddle Si je comprends bien, vous pouvez utiliser cela et obtenir le même effet que cette réponse en utilisant :set sts=2 noetet :retab! 2donc ce serait un peu plus court (bien que peut-être moins lisible) de cette façon.
Daan Bakker
Cette méthode modifie également 2 espaces en 4 espaces dans les littéraux de chaîne et à d'autres endroits, plutôt que juste le début de la ligne.
nacitar sevaht
2
Mettez-les tous ensemble: :set ts=2 sts=2 noet | retab! | set ts=4 sts=4 et | retab!puis utilisez @:dans différents fichiers pour appliquer rapidement la même action.
L__
58

Cela peut être possible avec :set shiftwidth=4et gg=G.

perréel
la source
Notez que si cela ne fonctionne pas, vous pouvez avoir un mode activé qui a une autre influence sur l'indentation.
Dav Clark
1
Bien que la question ne concerne pas une solution générale, veuillez noter que cela ne fonctionne pas toujours, spécialement avec le code python.
0xc0de
5
Que veut gg=Gdire exatly? Je comprends que cela ggsignifie «passer à 1,1» et G«passer à la dernière ligne».
Jonathon Reinhart
5
@JonathonReinhart =fait l'indentation, donc cela signifie simplement l'indentation du début à la fin du texte
alex
fonctionnait mieux que %retab, qui convertissait de manière incorrecte les espaces incorporés dans des chaînes littérales.
Alnitak
33

Ce que je fais est très similaire aux approches d'esneider et de cforbish, mais un peu plus rapide à taper:

:%s/^\s*/&&

Remplace simplement l'espace de début (espaces ou tabulations) par deux fois plus d'espace de début ( &est remplacé par l'expression correspondante).

spro
la source
2
C'est pratique car cela fonctionne avec la sélection visuelle (V), déposez simplement le fichier %.
Trevor Robinson
1
J'aime aussi celui-ci car il ne gâche aucun alignement manuel des tableaux que j'ai dans les commentaires, etc.
stephenmm
@TrevorRobinson Les deux premières réponses fonctionnent également sur les plages.
Brian McCutchon
Cela a également l'avantage supplémentaire que vous pouvez l'étendre pour l'utiliser sedet l'appliquer à tous les fichiers d'un répertoire superuser.com/a/159286/41494
icc97
3

C'est une question très ancienne, mais toutes les réponses sont ... fausses ... Vim a un moyen très simple de réindenter le fichier entier. J'ai appris cela après avoir écrit ma propre fonction pour le faire, donc je suis dans le même bateau de l'ignorance;)

type

gg=G

cela suppose que vous avez votre tabstop réglé sur ce que vous aimez, (donc pour l'OP, ce serait ts = 4)

J'ai appris cela sur http://vim.wikia.com/wiki/Fix_indentation , qui mentionne

En mode normal, taper gg = G réindentera le fichier entier. C'est un cas particulier; = est un opérateur. Tout comme d ou y, il agira sur tout texte sur lequel vous vous déplacez avec une commande de déplacement du curseur. Dans ce cas, gg positionne le curseur sur la première ligne, puis = G ré-indente de la position actuelle du curseur à la fin du tampon.

Chase Vasic
la source
2
1. Si vous faites défiler vers le bas jusqu'en bas, vous verrez une réponse mentionnant gg = G. 2. Cela ne fonctionne pas toujours.
Lim
2

J'ai utilisé cette expression régulière (elle double le nombre d'espaces de début):

%s;^\(\s\+\);\=repeat(' ', len(submatch(0))*2);g
cforbish
la source
ne fait pas %s/\s\+/&&/la même chose? Btw, je pense que le gdrapeau est inutile (pour un, il n'y aurait qu'un seul match avec ^patterndans chaque ligne, non?)
doubleDown
Merci d'avoir indiqué «&». J'ai une légère correction à la vôtre principalement parce que vous avez oublié que «^» %s/^\s\+/&&/gest plus proche.
cforbish le
Ceci est similaire à la réponse de spro mais j'apprécie la réponse car elle vous permet de la modifier plus facilement si vous avez besoin de faire quelque chose d'un peu plus compliqué.
stephenmm
1

Similaire (mais un peu plus simple) à la réponse de cforbish, cette regex dupliquera les espaces de début

:%s/^\( \+\)/\1\1

Ou vous pouvez utiliser cette autre expression régulière pour transformer 2 espaces en 4 espaces, en préservant les espaces simples (et les quantités impaires en général)

:%s/^\(\(  \)\+\)/\1\1

C'est,

  • 1 espace ⇢ 1 espace
  • 2 espaces ⇢ 4 espaces
  • 3 espaces ⇢ 5 espaces
  • 4 espaces ⇢ 8 espaces
esneider
la source
0

Ceci est une variante des réponses basées sur les regex.

J'ai un script bash dans mon répertoire bin local qui doublera la quantité d'espaces blancs au début d'une ligne. L'entrée peut être stdin ou un fichier:

$ cat ~/bin/dblsp
#!/bin/bash

file=${1--}

while IFS= read -r line; do
    echo "$line" | sed 's/\s*/&&/'
done < <(cat -- "$file")

J'utilise ceci dans vim en sélectionnant visuellement une ligne et en émettant la commande suivante:

:'<,'>!dblsp

Cela m'évite d'avoir à taper (ou à me souvenir) de l'expression régulière.

Je l'utilise également dans des cartes comme les suivantes:

nnoremap <leader>] `[V`]!dblsp<CR>

qui l'appliquera à un bloc de texte récemment collé. J'utilise généralement la carte suivante pour coller plutôt que:set paste

nnoremap <leader>p :r !xclip -o<CR>

Mon flux de travail habituel est:

  • sélectionnez l'extrait de code (par exemple, l' exemple de code sur cette page contient 2 espaces mais je veux 4)
  • coller un extrait de code (, p)
  • modifier l'espacement (,])

ou simplement changer le retrait sur les blocs copiés collés à partir d'un autre tampon.

htaccess
la source
0

En plus de la réponse de @ spro, je mets ceci dans mon .vimrc

command! -range=% Format :<line1>,<line2>s/^\s*/&&

Tapez simplement :Format.

Avec la sélection visuelle, cela ne formate que les lignes sélectionnées.

Sans sélection visuelle, cela formate le fichier entier.

Eli
la source