Votre problème avec Vim c'est que vous ne comprenez pas vi .
Vous parlez de couper avec yy
et se plaignent que vous ne voulez presque jamais couper des lignes entières. En fait, les programmeurs, en éditant le code source, veulent très souvent travailler sur des lignes entières, des plages de lignes et des blocs de code. Cependant, yy
n'est qu'un moyen parmi d'autres d'introduire du texte dans le tampon de copie anonyme (ou "registre" comme on l'appelle dans vi ).
Le "zen" de vi c'est que vous parlez une langue. L'initiale y
est un verbe. L'énoncé yy
est un synonyme de y_
. Le site y
est doublé pour faciliter la saisie, car il s'agit d'une opération très courante.
Cela peut également être exprimé comme suit dd
P
(supprimer la ligne courante et coller une copie à la place ; laisser une copie dans le registre anonyme comme effet secondaire). Le site y
y d
Les "verbes" prennent tout mouvement comme "sujet". Ainsi yW
est "tirez d'ici (le curseur) à la fin du (grand) mot actuel/suivant" et y'a
est "tirez d'ici jusqu'à la ligne contenant la marque nommée '". a '."
Si vous ne comprenez que les mouvements de base du curseur vers le haut, le bas, la gauche et la droite, alors vi ne sera pas plus productif qu'une copie de "notepad" pour vous. (D'accord, vous disposerez toujours de la coloration syntaxique et de la possibilité de gérer des fichiers d'une taille supérieure à ~45KB environ, mais travaillez avec moi).
vi comporte 26 "marques" et 26 "registres". Une marque est placée sur n'importe quel emplacement du curseur à l'aide de la touche m
commande. Chaque marque est désignée par une seule lettre minuscule. Ainsi, ma
définit l'option ' a ' à l'emplacement actuel, et mz
définit l'option ' z . Vous pouvez passer à la ligne contenant une marque en utilisant la touche '
(guillemets simples). Ainsi, 'a
se déplace au début de la ligne contenant le ' a . Vous pouvez vous déplacer à l'endroit précis de n'importe quelle marque à l'aide de la touche `
(rétro-citation). Ainsi, `z
se déplacera directement à l'emplacement exact de la ' z marque.
Comme il s'agit de "mouvements", ils peuvent également être utilisés comme sujets pour d'autres "déclarations".
Ainsi, une façon de couper une sélection arbitraire de texte serait de déposer une marque (j'utilise généralement ' a comme ma " première " marque, z ' comme prochaine marque, ' b comme un autre, et e comme une autre (je ne me souviens pas d'avoir jamais utilisé interactivement plus de quatre marques en 15 ans d'utilisation de l'outil vi ; on crée ses propres conventions concernant la façon dont les marques et les registres sont utilisés par les macros qui ne perturbent pas le contexte interactif de chacun). Ensuite, nous nous rendons à l'autre extrémité du texte souhaité ; nous pouvons commencer à l'une ou l'autre extrémité, cela n'a pas d'importance. Ensuite, nous pouvons simplement utiliser d`a
de couper ou y`a
à copier. Ainsi, l'ensemble du processus a une surcharge de 5 frappes (six si nous avons commencé en mode "insertion" et que nous devions Esc out en mode commande). Une fois que nous avons coupé ou copié, il suffit d'appuyer sur une touche pour coller une copie : p
.
Je dis que c'est une façon de couper ou de copier du texte. Cependant, ce n'est qu'un moyen parmi d'autres. Souvent, nous pouvons décrire plus succinctement l'étendue du texte sans déplacer notre curseur et déposer une marque. Par exemple, si je suis dans un paragraphe de texte, je peux utiliser {
y }
mouvements au début ou à la fin du paragraphe respectivement. Donc, pour déplacer un paragraphe de texte, je le coupe en utilisant {
d}
(3 frappes). (S'il se trouve que je suis déjà à la première ou à la dernière ligne du paragraphe, je peux alors simplement utiliser la touche d}
o d{
respectivement.
La notion de "paragraphe" est par défaut quelque chose qui est généralement intuitivement raisonnable. Elle fonctionne donc souvent aussi bien pour le code que pour la prose.
Souvent, nous connaissons un motif (expression régulière) qui marque une extrémité ou l'autre du texte qui nous intéresse. La recherche en avant ou en arrière sont des mouvements en vi . Ils peuvent donc aussi être utilisés comme "sujets" dans nos "déclarations". Je peux donc utiliser d/foo
pour couper de la ligne actuelle à la ligne suivante contenant la chaîne "foo" et y?bar
pour copier de la ligne actuelle à la ligne la plus récente (précédente) contenant "bar". Si je ne veux pas de lignes entières, je peux toujours utiliser les mouvements de recherche (comme des déclarations à part entière), laisser tomber ma ou mes marques et utiliser la commande `x
comme décrit précédemment.
En plus des "verbes" et des "sujets". vi a également des "objets" (au sens grammatical du terme). Jusqu'à présent, je n'ai décrit que l'utilisation du registre anonyme. Cependant, je peux utiliser n'importe lequel des 26 registres "nommés" en préfixe la référence "objet" avec "
(le modificateur de guillemets). Ainsi, si j'utilise "add
Je coupe la ligne actuelle dans le ' a et si j'utilise "by/foo
puis j'envoie une copie du texte d'ici à la prochaine ligne contenant "foo" dans le fichier ' b registre. Pour coller à partir d'un registre, il suffit de faire précéder le collage de la même séquence de modification : "ap
colle une copie du fichier ' a dans le texte qui se trouve après le curseur. "bP
colle une copie de ' b ' avant la ligne en cours.
Cette notion de "préfixes" ajoute également les analogues des "adjectifs" et "adverbes" grammaticaux à notre "langage" de manipulation de texte. La plupart des commandes (verbes) et des mouvements (verbes ou objets, selon le contexte) peuvent également prendre des préfixes numériques. Ainsi, 3J
signifie "joindre les trois lignes suivantes" et d5}
signifie "supprimer de la ligne actuelle jusqu'à la fin du cinquième paragraphe vers le bas à partir d'ici".
Tout ceci est de niveau intermédiaire vi . Rien de tout cela n'est Vim spécifiques et il existe des astuces bien plus avancées dans vi si tu es prêt à les apprendre. Si vous deviez maîtriser uniquement ces concepts intermédiaires, vous constateriez probablement que vous avez rarement besoin d'écrire des macros, car le langage de manipulation du texte est suffisamment concis et expressif pour faire la plupart des choses assez facilement en utilisant le langage "natif" de l'éditeur.
Un échantillon d'astuces plus avancées :
Il existe un certain nombre de :
notamment la commande :% s/foo/bar/g
technique de substitution globale. (Ce n'est pas très avancé mais d'autres :
les commandes peuvent l'être). L'ensemble :
L'ensemble des commandes a été historiquement hérité par vi Les précédentes incarnations de l'artiste en tant que ed (éditeur de ligne) et plus tard le ex (éditeur de ligne étendu). En effet vi est ainsi nommée parce qu'il s'agit de l'interface visuelle de l'application ex .
:
Les commandes fonctionnent normalement sur des lignes de texte. ed y ex ont été écrits à une époque où les écrans de terminaux étaient rares et où de nombreux terminaux étaient des appareils de type "télétype" (TTY). Il était donc courant de travailler à partir de copies imprimées du texte, en utilisant des commandes via une interface extrêmement laconique (les vitesses de connexion courantes étaient de 110 bauds, soit, en gros, 11 caractères par seconde - ce qui est plus lent qu'un dactylo rapide ; les décalages étaient courants dans les sessions interactives multi-utilisateurs ; de plus, il y avait souvent une certaine motivation pour conserver le papier).
Ainsi, la syntaxe de la plupart des :
Les commandes comprennent une adresse ou une plage d'adresses (numéro de ligne) suivie d'une commande. Naturellement, on peut utiliser des numéros de ligne littéraux : :127,215 s/foo/bar
pour changer la première occurrence de "foo" en "bar" sur chaque ligne entre 127 et 215. On peut également utiliser des abréviations telles que .
o $
pour la ligne actuelle et la dernière ligne respectivement. On peut également utiliser des préfixes relatifs +
y -
pour se référer aux décalages après ou avant la ligne courante, respectivement. Ainsi : :.,$j
signifiant "de la ligne actuelle à la dernière ligne, joignez-les toutes en une seule ligne". :%
est synonyme de :1,$
(toutes les lignes).
El :... g
y :... v
Les commandes nécessitent quelques explications car elles sont incroyablement puissantes. :... g
est un préfixe pour "globalement" appliquant une commande ultérieure à toutes les lignes qui correspondent à un modèle (expression régulière) tandis que :... v
applique une telle commande à toutes les lignes qui ne correspondent PAS au motif donné ("v" de "conVerse"). Comme pour les autres ex Ces commandes peuvent être préfixées par des références d'adressage/de gamme. Ainsi, :.,+21g/foo/d
signifie "supprimer toutes les lignes contenant la chaîne "foo" de la ligne actuelle jusqu'aux 21 lignes suivantes" tandis que :.,$v/bar/d
signifie "d'ici à la fin du fichier, supprimez toutes les lignes qui ne contiennent pas la chaîne "bar"".
Il est intéressant de noter que la commande Unix courante grep a été en fait inspiré par ce ex (et est nommé d'après la façon dont il a été documenté). Le site ex commande :g/re/p
(grep) était la façon dont ils documentaient comment "globalement" "imprimer" les lignes contenant une "expression régulière" (re). Lorsque ed y ex ont été utilisés, les :p
était l'une des premières que l'on apprenait et souvent la première utilisée lors de l'édition d'un fichier. Elle permettait d'imprimer le contenu actuel (généralement une seule page complète à la fois en utilisant la commande :.,+25p
ou autre).
Notez que :% g/.../d
ou (sa contrepartie reVerse/conVerse : :% v/.../d
sont les modèles d'utilisation les plus courants. Cependant, il existe quelques autres ex
des commandes qui méritent d'être rappelées :
Nous pouvons utiliser m
pour déplacer les lignes, et j
pour joindre les lignes. Par exemple, si vous avez une liste et que vous voulez séparer tous les éléments qui correspondent (ou au contraire qui ne correspondent pas) à un certain modèle sans les effacer, vous pouvez utiliser quelque chose comme : :% g/foo/m$
... et toutes les lignes "foo" auront été déplacées à la fin du fichier. (Notez l'autre astuce concernant l'utilisation de la fin de votre fichier comme espace scratch). Ceci aura préservé l'ordre relatif de toutes les lignes "foo" tout en les ayant extraites du reste de la liste. (Ceci serait équivalent à faire quelque chose comme : 1G!GGmap!Ggrep foo<ENTER>1G:1,'a g/foo'/d
(copier le fichier dans sa propre queue, filtrer la queue par le biais de grep
et supprimer tout ce qui se trouve dans la tête).
Pour joindre des lignes, je peux généralement trouver un modèle pour toutes les lignes qui doivent être jointes à leur prédécesseur (toutes les lignes qui commencent par "^ " au lieu de "^ * " dans une liste à puces, par exemple). Dans ce cas, j'utiliserais : :% g/^ /-1j
(pour chaque ligne correspondante, remonter d'une ligne et les joindre). (BTW : pour les listes à puces, essayer de rechercher les lignes de puces et de les joindre à la suivante ne fonctionne pas pour plusieurs raisons ... cela peut joindre une ligne de puces à une autre, et cela ne joindra aucune ligne de puces à une autre ligne de puces. tous de ses continuations ; il ne fonctionnera que par paire sur les correspondances).
Il est presque inutile de mentionner que vous pouvez utiliser notre vieil ami s
(substitut) avec le g
y v
(global/converse-global). En général, vous n'avez pas besoin de le faire. Cependant, considérez un cas où vous souhaitez effectuer une substitution uniquement sur les lignes correspondant à un autre motif. Vous pouvez souvent utiliser un modèle compliqué avec des captures et utiliser des références arrière pour préserver les portions de lignes que vous ne voulez pas changer. Cependant, il sera souvent plus facile de séparer la correspondance de la substitution : :% g/foo/s/bar/zzz/g
-- pour chaque ligne contenant "foo", remplacez tous les "bar" par "zzz". (Quelque chose comme :% s/\(.*foo.*\)bar\(.*\)/\1zzz\2/g
ne fonctionnerait que pour les cas où les instances de "bar" ont été précédées par "foo" sur la même ligne ; c'est déjà assez lourd, et il faudrait encore le modifier pour prendre en compte tous les cas où "bar" a précédé "foo")
Le fait est qu'il n'y a pas seulement p
, s
y d
lignes dans le ex
le jeu de commandes.
El :
Les adresses peuvent également faire référence aux marques. Ainsi, vous pouvez utiliser : :'a,'bg/foo/j
pour joindre toute ligne contenant la chaîne foo à sa ligne suivante, si elle se trouve entre les lignes situées entre les ' a et b marques. (Oui, tout ce qui précède ex
les exemples de commandes peuvent être limités à des sous-ensembles de lignes du fichier en les faisant précéder de ce genre d'expressions d'adressage).
C'est assez obscur (je n'ai utilisé quelque chose comme ça que quelques fois au cours des 15 dernières années). Cependant, j'admets volontiers que j'ai souvent fait des choses de manière itérative et interactive qui auraient probablement pu être faites plus efficacement si j'avais pris le temps de réfléchir à la bonne incantation.
Un autre très utile vi o ex La commande est :r
pour lire le contenu d'un autre fichier. Ainsi : :r foo
insère le contenu du fichier nommé "foo" à la ligne courante.
Plus puissant est le :r!
commande. Cela permet de lire les résultats d'une commande. C'est la même chose que de suspendre la vi en exécutant une commande, en redirigeant sa sortie vers un fichier temporaire, en reprenant votre vi et lire le contenu du fichier temporaire.
Encore plus puissants sont les !
(bang) et :... !
( ex bang) des commandes. Celles-ci exécutent également des commandes externes et lisent les résultats dans le texte actuel. Cependant, elles filtrent également des sélections de notre texte par le biais de la commande ! Ainsi, nous pouvons trier toutes les lignes de notre fichier à l'aide de la commande 1G!Gsort
( G
est le vi La commande "goto" ; elle va par défaut à la dernière ligne du fichier, mais peut être préfixée par un numéro de ligne, tel que 1, la première ligne). Ceci est équivalent à la commande ex variante :1,$!sort
. Les écrivains utilisent souvent !
avec le système Unix fmt o pliage des utilitaires permettant de reformater ou de "mettre en forme" des sélections de texte. Une macro très courante est {!}fmt
(reformater le paragraphe actuel). Les programmeurs l'utilisent parfois pour faire passer leur code, ou seulement des parties de celui-ci, par le logiciel indentation ou d'autres outils de reformatage de code.
Utilisation de la :r!
y !
signifie que tout utilitaire ou filtre externe peut être traité comme une extension de notre éditeur. J'ai parfois utilisé ces commandes avec des scripts qui extrayaient des données d'une base de données ou avec des commandes wget o lynx des commandes qui extraient des données d'un site web, ou ssh des commandes qui ont extrait des données de systèmes distants.
Une autre utilité ex La commande est :so
(abréviation de :source
). Elle lit le contenu d'un fichier sous la forme d'une série de commandes. Lorsque vous lancez vi il effectue normalement, implicitement, une :source
en ~/.exinitrc
(et Vim fait généralement cela le ~/.vimrc
naturellement). L'intérêt de ce système est que vous pouvez changer votre profil d'éditeur à la volée en introduisant simplement un nouvel ensemble de macros, d'abréviations et de paramètres d'éditeur. Si vous êtes sournois, vous pouvez même l'utiliser comme une astuce pour stocker des séquences de ex des commandes d'édition à appliquer aux fichiers à la demande.
Par exemple, j'ai un fichier de sept lignes (36 caractères) qui exécute un fichier par le biais de wc et insère un commentaire de style C en haut du fichier contenant les données de comptage de mots. Je peux appliquer cette "macro" à un fichier en utilisant une commande comme : vim +'so mymacro.ex' ./mytarget
(Le +
option de ligne de commande pour vi y Vim est normalement utilisé pour démarrer la session d'édition à un numéro de ligne donné. Cependant, il est peu connu que l'on peut suivre la ligne +
par toute personne valide ex comme une commande "source" comme je l'ai fait ici ; pour un exemple simple, j'ai des scripts qui invoquent : vi +'/foo/d|wq!' ~/.ssh/known_hosts
pour supprimer une entrée de mon fichier d'hôtes connus SSH de manière non interactive pendant que je réimplante un ensemble de serveurs).
En général, il est beaucoup plus facile d'écrire de telles "macros" en utilisant Perl ou AWK, sed (qui est, en fait, comme grep un utilitaire inspiré par le ed commande).
El @
est probablement la commande la plus obscure vi commande. En enseignant occasionnellement des cours d'administration de systèmes avancés pendant près de dix ans, j'ai rencontré très peu de personnes qui l'ont déjà utilisée. @
exécute le contenu d'un registre comme s'il s'agissait d'un vi o ex commandement.
Exemple : J'utilise souvent : :r!locate ...
pour trouver un fichier sur mon système et lire son nom dans mon document. À partir de là, je supprime toutes les occurrences superflues, ne laissant que le chemin d'accès complet au fichier qui m'intéresse. Plutôt que de laborieusement Tab -en passant par chaque composant du chemin (ou pire, si je suis coincé sur une machine sans support pour la complétion de Tab dans sa copie de vi ) J'utilise simplement :
-
0i:r
(pour transformer la ligne actuelle en une ligne valide :r commande),
-
"cdd
(pour supprimer la ligne dans le registre "c") et
-
@c
exécute cette commande.
Cela ne représente que 10 frappes (et l'expression "cdd
@c
est en fait une macro digitale pour moi, ce qui me permet de le taper presque aussi rapidement que n'importe quel mot de six lettres).
Une pensée qui donne à réfléchir
Je n'ai fait qu'effleurer la surface de vi et rien de ce que j'ai décrit ici ne fait même partie des "améliorations" pour lesquelles l'entreprise a été créée. vim est nommé ! Tout ce que j'ai décrit ici devrait fonctionner sur n'importe quelle vieille copie de vi d'il y a 20 ou 30 ans.
Il y a des gens qui ont utilisé beaucoup plus de vi que je ne le ferai jamais.