Votre problème avec Vim est que vous ne grok vi .
Vous mentionnez couper avec yy
et vous plaignez que vous ne voulez presque jamais couper des lignes entières. En fait, les programmeurs, éditant du code source, veulent très souvent travailler sur des lignes entières, des plages de lignes et des blocs de code. Cependant, ce yy
n'est qu'une des nombreuses façons d'extraire du texte dans le tampon de copie anonyme (ou "s'inscrire" comme on l'appelle dans vi ).
Le "Zen" de vi est que vous parlez une langue. L'initiale y
est un verbe. La déclaration yy
est synonyme de y_
. Le y
est doublé pour le rendre plus facile à taper, car il s'agit d'une telle opération courante.
Cela peut également être exprimé par dd
P
(supprimer la ligne actuelle et coller une copie en place; laisser une copie dans le registre anonyme comme effet secondaire). Les y
et d
« verbes » prennent tout mouvement comme leur « sujet ». Ainsi, yW
"tirez d'ici (le curseur) jusqu'à la fin du mot courant / suivant (gros)" et y'a
"tirez d'ici jusqu'à la ligne contenant la marque nommée" a "".
Si vous ne comprenez que les mouvements basiques du curseur vers le haut, le bas, la gauche et la droite, vi ne sera pas plus productif qu'une copie du "bloc-notes" pour vous. (D'accord, vous aurez toujours la mise en évidence de la syntaxe et la capacité de gérer des fichiers plus volumineux qu'un ~ 45 Ko environ; mais travaillez avec moi ici).
vi a 26 "marques" et 26 "registres". Une marque est définie à n'importe quel emplacement du curseur à l'aide de la m
commande. Chaque marque est désignée par une seule lettre minuscule. ma
Définit ainsi la marque « a » à l'emplacement actuel et mz
définit la marque « z ». Vous pouvez passer à la ligne contenant une marque à l'aide de la commande '
(guillemet simple). Se 'a
déplace ainsi au début de la ligne contenant la marque « a ». Vous pouvez vous déplacer vers l'emplacement précis de n'importe quelle marque à l'aide de la `
commande (backquote). Ainsi `z
, vous vous déplacerez directement à l'emplacement exact de la marque « z ».
Parce que ce sont des «mouvements», ils peuvent également être utilisés comme sujets pour d'autres «déclarations».
Donc, une façon de couper une sélection arbitraire de texte serait de déposer une marque (j'utilise habituellement ' a ' comme ma "première" marque, ' z ' comme ma prochaine marque, ' b ' comme une autre et ' e ' comme encore une autre (je ne me souviens pas avoir utilisé interactivement plus de quatre marques en 15 ans d'utilisation de 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). Ensuite, nous allons à l'autre extrémité de notre texte souhaité; nous pouvons commencer à chaque extrémité, peu importe. Ensuite, nous pouvons simplement utiliser d`a
pour couper ou y`a
copier. Ainsi, l'ensemble du processus a une surcharge de 5 touches (six si nous avons commencé dans "insérer "mode et nécessaire pourEscen mode commande). Une fois que nous avons copié ou coupé puis coller dans une copie est une simple pression de touche: p
.
Je dis que c'est une façon de couper ou de copier du texte. Cependant, ce n'est qu'un parmi tant d'autres. Fréquemment, nous pouvons décrire plus succinctement la plage de texte sans déplacer notre curseur et laisser tomber une marque. Par exemple , si je suis dans un paragraphe de texte que je peux utiliser {
et }
mouvements au début ou à la fin du paragraphe respectivement. Donc, pour déplacer un paragraphe de texte, je le coupe à l'aide de {
d}
(3 touches). (S'il m'arrive d'être déjà sur la première ou la dernière ligne du paragraphe, je peux alors simplement utiliser d}
ou d{
respectivement.
La notion de "paragraphe" par défaut est quelque chose qui est généralement intuitivement raisonnable. Ainsi, cela fonctionne souvent pour le code ainsi que pour la prose.
Nous connaissons fréquemment un modèle (expression régulière) qui marque l'une ou l'autre extrémité du texte qui nous intéresse. La recherche en avant ou en arrière sont des mouvements dans vi . Ainsi, ils peuvent également ê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
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 leurs propres déclarations), déposez mes marques et utilisez les `x
commandes 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éfixant la référence "objet" avec "
(le modificateur de guillemet double). Ainsi, si j'utilise, "add
je coupe la ligne actuelle dans le registre « a » et si j'utilise "by/foo
alors je tire une copie du texte d'ici à la ligne suivante contenant «foo» dans le registre « b ». Pour coller à partir d' un préfixe simplement j'enregistrer la pâte avec la même séquence de modification: "ap
colle une copie du « un » registre »"bP
colle une copie de ' b ' à avant la ligne courante.
Cette notion de «préfixes» ajoute également les analogues des «adjectifs» et des «adverbes» grammaticaux à notre langage de manipulation de texte. «La plupart des commandes (verbes) et du mouvement (verbes ou objets, selon le contexte) peuvent également prendre des préfixes numériques. 3J
signifie «joindre les trois lignes suivantes» et d5}
signifie «supprimer de la ligne actuelle jusqu'à la fin du cinquième paragraphe d'ici».
Tout cela est de niveau intermédiaire vi . Rien de tout cela n'est spécifique à Vim et il existe des astuces bien plus avancées dans vi si vous êtes 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 parce que le langage de manipulation de texte est suffisamment concis et expressif pour faire la plupart des choses assez facilement en utilisant la langue "native" de l'éditeur.
Un échantillon d'astuces plus avancées:
Il existe un certain nombre de :
commandes, notamment la :% s/foo/bar/g
technique de substitution globale. (Ce n'est pas avancé mais d'autres :
commandes peuvent l'être). L'ensemble :
des commandes a été historiquement hérité des incarnations précédentes de vi en tant qu'utilitaires ed (éditeur de ligne) et plus tard ex (éditeur de ligne étendu). En fait, vi est nommé ainsi parce que c'est l'interface visuelle de ex .
:
les commandes fonctionnent normalement sur des lignes de texte. ed et ex ont été écrits à une époque où les écrans de terminaux étaient rares et de nombreux terminaux étaient des appareils "téléscripteurs" (ATS). 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, ou, en gros, 11 caractères par seconde - ce qui est plus lent qu'une dactylographie rapide; les décalages étaient courants sur sessions interactives multi-utilisateurs; en outre, il y avait souvent une certaine motivation pour économiser le papier).
Ainsi, la syntaxe de la plupart des :
commandes comprend une adresse ou une plage d'adresses (numéro de ligne) suivie d'une commande. Naturellement, on pourrait 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 pourrait également utiliser des abréviations telles que .
ou $
pour les lignes actuelles et dernières respectivement. On pourrait également utiliser des préfixes relatifs +
et -
faire référence aux décalages après ou avant la ligne actuelle, respectivement. Ainsi: :.,$j
signifiant "de la ligne actuelle à la dernière ligne, joignez-les tous en une seule ligne". :%
est synonyme de :1,$
(toutes les lignes).
Les commandes :... g
et :... v
portent une explication car elles sont incroyablement puissantes. :... g
est un préfixe pour "globalement" appliquer une commande ultérieure à toutes les lignes qui correspondent à un modèle (expression régulière) tandis :... v
qu'applique une telle commande à toutes les lignes qui ne correspondent pas au modèle donné ("v" de "conVerse"). Comme pour les autres commandes ex, celles-ci peuvent être préfixées par des références d'adressage / plage. Ainsi :.,+21g/foo/d
signifie "supprimer toutes les lignes contenant la chaîne" foo "de la ligne actuelle 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 commune Unix grep a en fait été inspirée par cette commande ex (et est nommée d'après la façon dont elle a été documentée). L' ex commande :g/re/p
(grep) était la façon dont ils ont documenté comment "globalement" "imprimer" les lignes contenant une "expression régulière" (re). Lorsque ed et ex étaient utilisés, la :p
commande était l'une des premières que quiconque apprenait et souvent la première utilisée lors de la modification d'un fichier. C'est ainsi que vous avez imprimé le contenu actuel (généralement une seule page à la fois en utilisant :.,+25p
ou quelque chose comme ça ).
Notez que :% g/.../d
or (son homologue reVerse / conVerse: :% v/.../d
sont les modèles d'utilisation les plus courants. Cependant, il existe quelques autres ex
commandes qui méritent d'être rappelées:
Nous pouvons utiliser m
pour déplacer des lignes et j
pour joindre des lignes. Par exemple, si vous avez une liste et que vous souhaitez séparer tous les éléments correspondant (ou inversement ne correspondant pas à un modèle) sans les supprimer, vous pouvez utiliser quelque chose comme: :% g/foo/m$
... et toutes les lignes "foo" auront été déplacées vers la fin du fichier. (Notez l'autre astuce sur l'utilisation de la fin de votre fichier comme espace de travail). Cela aura conservé l'ordre relatif de toutes les lignes "foo" tout en les ayant extraites du reste de la liste. (Cela équivaudrait à 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 à travers grep
et supprimer toutes les choses de 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 "^" plutôt que "^ *" dans une liste à puces, par exemple). Pour ce cas, j'utiliserais: :% g/^ /-1j
(pour chaque ligne correspondante, remontez d'une ligne et joignez-les). (BTW: pour les listes de balles en essayant de rechercher les lignes de balles et rejoindre à l'autre ne fonctionne pas pour plusieurs raisons ... il peut se joindre à une ligne de balle à l' autre, et il ne sera pas adhérer à une ligne de balle à tous de ses suites; cela ne fonctionnera que par paires sur les matchs).
Il est presque inutile de mentionner que vous pouvez utiliser notre vieil ami s
(substitut) avec les commandes g
et v
(global / converse-global). Vous n'avez généralement pas besoin de le faire. Cependant, considérez un cas où vous souhaitez effectuer une substitution uniquement sur les lignes correspondant à un autre modèle. Souvent, vous pouvez utiliser un modèle compliqué avec des captures et utiliser des références arrières pour conserver les parties des lignes que vous ne voulez PAS modifier. Cependant, il sera souvent plus facile de séparer le match de la substitution: :% g/foo/s/bar/zzz/g
- pour chaque ligne contenant "foo" remplacer tous "bar" par "zzz". (Quelque chose comme:% s/\(.*foo.*\)bar\(.*\)/\1zzz\2/g
ne fonctionnerait que pour les cas où "bar" a été PRÉCÉDÉ par "foo" sur la même ligne; il est déjà assez disgracieux, et devrait être encore modifié pour attraper tous les cas où "bar" a précédé "foo")
Le point est qu'il ya plus que p
, s
et les d
lignes du ex
jeu de commandes.
Les :
adresses peuvent également faire référence à des marques. Ainsi, vous pouvez utiliser: :'a,'bg/foo/j
pour joindre n'importe quelle ligne contenant la chaîne foo à sa ligne suivante, si elle se situe entre les lignes entre les marques « a » et « b ». (Oui, tous les ex
exemples de commandes précédents peuvent être limités à des sous-ensembles des lignes du fichier en préfixant ces sortes 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, je dois admettre 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.
Une autre commande vi ou ex très utile consiste :r
à lire le contenu d'un autre fichier. Ainsi: :r foo
insère le contenu du fichier nommé "foo" à la ligne courante.
La :r!
commande est plus puissante . Ceci lit les résultats d'une commande. Cela revient à suspendre la session vi , à exécuter une commande, à rediriger sa sortie vers un fichier temporaire, à reprendre votre session vi et à lire le contenu de temp. fichier.
Les commandes !
(bang) et :... !
( ex bang) sont encore plus puissantes . Ceux-ci exécutent également des commandes externes et lisent les résultats dans le texte actuel. Cependant, ils filtrent également les sélections de notre texte via la commande! Ceci, nous pouvons trier toutes les lignes de notre fichier à l'aide de 1G!Gsort
( G
est la commande vi "goto"; elle revient 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). C'est équivalent à la variante ex:1,$!sort
. Les rédacteurs utilisent souvent !
avec les utilitaires fmt ou fold d' Unix pour reformater ou "encapsuler" des sélections de texte. Une macro très courante est{!}fmt
(reformater le paragraphe actuel). Les programmeurs l'utilisent parfois pour exécuter leur code, ou seulement des parties de celui-ci, via le retrait ou d'autres outils de reformatage de code.
L'utilisation des commandes :r!
et !
signifie que tout utilitaire ou filtre externe peut être traité comme une extension de notre éditeur. Je les ai parfois utilisés avec des scripts qui tiraient des données d'une base de données, ou avec des commandes wget ou lynx qui tiraient des données d'un site Web, ou des commandes ssh qui tiraient des données de systèmes distants.
Une autre commande ex utile est :so
(abréviation de :source
). Cela lit le contenu d'un fichier comme une série de commandes. Lorsque vous démarrez vi normalement, implicitement, effectue une :source
sur le ~/.exinitrc
fichier (et Vim fait généralement sur ~/.vimrc
, assez naturellement). L'utilisation de ceci est que vous pouvez changer votre profil d'éditeur à la volée simplement en vous approvisionnant dans 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 d' ex 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 via wc et insère un commentaire de style C en haut du fichier contenant ces données de comptage de mots. Je peux appliquer cette "macro" à un fichier en utilisant une commande comme:vim +'so mymacro.ex' ./mytarget
(L' +
option de ligne de commande pour vi et Vim est normalement utilisée pour démarrer la session d'édition à un numéro de ligne donné. Cependant, c'est un fait peu connu que l'on peut suivre le +
par n'importe quelle commande / expression ex valide , telle qu'une commande "source" comme J'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éimagine un ensemble de serveurs).
Habituellement, il est beaucoup plus facile d'écrire de telles "macros" en utilisant Perl, AWK, sed (qui est, en fait, comme grep un utilitaire inspiré de la commande ed ).
La @
commande est probablement la commande vi la plus obscure . En enseignant occasionnellement des cours avancés d'administration de systèmes pendant près d'une décennie, j'ai rencontré très peu de gens qui l'ont utilisé. @
exécute le contenu d'un registre comme s'il s'agissait d'une commande vi ou ex .
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 tous les hits superflus, ne laissant que le chemin d'accès complet au fichier qui m'intéresse. Plutôt que de Tabparcourir laborieusement chaque composant du chemin (ou pire, s'il se trouve que je suis bloqué sur une machine sans prise en charge de la tabulation) dans sa copie de vi ) j'utilise juste:
0i:r
(pour transformer la ligne courante en une commande valide : r ),
"cdd
(pour supprimer la ligne dans le registre "c") et
@c
exécutez cette commande.
Cela ne représente que 10 frappes (et l'expression "cdd
@c
est en fait une macro de doigt pour moi, donc je peux la saisir 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 puissance de vi et rien de ce que j'ai décrit ici ne fait même partie des "améliorations" pour lesquelles vim est nommé! Tout ce que j'ai décrit ici devrait fonctionner sur n'importe quelle ancienne copie de vi d'il y a 20 ou 30 ans.
Il y a des gens qui ont utilisé beaucoup plus de pouvoir de vi que jamais.