Comment supprimer simplement les accolades

8

Un de mes amis m'a dit que je pouvais utiliser l'astuce ci-dessous pour retirer une paire de crochets.

Placez le curseur à l'intérieur de la paire de crochets que vous souhaitez supprimer.

y i {pour tirer le texte entre accolades, v a {puis collez p.

Cela fonctionne bien comme:

for(int i = 0; i < s.length(); i++) {
        int index = s[i] - c;
        if(root->next[index] == NULL)
            root->next[index] = new TrieNode;
        root = root->next[index];
}

Après avoir exécuté la commande:

for(int i = 0; i < s.length(); i++)
    int index = s[i] - c;
    if(root->next[index] == NULL)
        root->next[index] = new TrieNode;
    root = root->next[index];

jusqu'à ce que je rencontre cette situation (l'espace avant le premier crochet est manquant).

for(int i = 0; i < s.length(); i++){
        int index = s[i] - c;
        if(root->next[index] == NULL)
            root->next[index] = new TrieNode;
        root = root->next[index];
}

Après avoir exécuté ces commandes, le bloc de texte devient

for(int i = 0; i < s.length(); i++
        int index = s[i] - c;
        if(root->next[index] == NULL)
            root->next[index] = new TrieNode;
        root = root->next[index];
)

La zone que je sélectionne en mode visuel semble bonne, mais pourquoi les parenthèses diminuent-elles?

MrDwZ
la source
Êtes-vous sûr de l'exemple de code que vous avez publié? Je ne comprends pas comment ça return -1;vient. Pourriez-vous également préciser où vous placez votre curseur avant d'exécuter chaque séquence de touches?
statox
@statox Désolé à ce sujet ... J'ai corrigé ce dernier bloc et ajouté une description de l'endroit où j'ai placé le curseur. Merci pour votre recommandation :-)
MrDwZ
Je ne peux pas reproduire cela. yi{tire entre les accolades et vapsélectionne visuellement le paragraphe (le texte entier dans ce cas) mais je ne vois pas du tout comment cela change le texte. Êtes-vous sûr de ne pas faire yi{+ va{+ p?
jjaderberg
2
Je viens d'essayer yi{+ va{+ psur votre texte dans une session propre (pas de vimrc, -u NONE) et cela reproduit votre résultat. Je ne sais pas pourquoi, par exemple, pet les Pdeux donnent ce résultat, malgré i{et se a{déplaçant dans le sens des caractères. Il serait utile que vous puissiez a) donner un exemple de texte sur lequel votre technique fonctionne et b) confirmer où se produit le «changement» dans votre technique. @Ben indique une bonne solution de contournement dans sa réponse (j'utilise ce plugin) mais cela ne me dérangerait pas d'apprendre pourquoi cela se produit en premier lieu.
jjaderberg
Je suis comme @jjaderberg, je ne peux pas reproduire le comportement que vous décrivez. Donner les détails demandés dans ses commentaires serait une très bonne idée.
statox

Réponses:

6

Installez le plug - in « surround » . Ensuite, vous pouvez simplement faire d s B .

Depuis la page du projet:

Surround.vim est tout au sujet de "l'environnement": parenthèses, crochets, guillemets, balises XML, etc. Le plugin fournit des mappages pour supprimer, modifier et ajouter facilement de tels environnements par paires.

La commande dssuivie de tout objet texte ( Bdans ce cas, pour "Bloquer", comme dans l' objet texte aBou iB) supprimera les caractères environnants qui définissent l'objet texte. Ainsi, d s B dans votre cas, accomplit ce que vous vouliez.

D'autres commandes incluent c s B b, si vous souhaitez changer l'entourage {...}en (...), ou y s {tout mouvement de curseur ou objet texte} B pour ajouter un entourage {...}au texte sélectionné par le curseur.

Voir la page du plugin et la documentation pour plus de détails.

Ben
la source
Il s'agit d'une bonne solution de contournement. Envisageriez-vous d'ajouter une phrase ou deux expliquant comment ce plugin fonctionne et pourquoi le mappage particulier accomplit la tâche?
jjaderberg
Existe-t-il un moyen élégant de supprimer ces accolades sans plug-in? : (
MrDwZ
Peut être. Mais le surround est vraiment léger et l'un des plugins "essentiels". Autant l'installer ...
Ben
6

Sommaire

C'est un bug et il y a un patch (743). Le bogue affecte à la fois vos exemples, mais vous ne le voyez pas dans un cas parce que le personnage qui est déplacé vers le bas est un (espace blanc). La solution consiste à installer le correctif, mais il existe également de nombreuses solutions de contournement ou méthodes alternatives, non affectées par le bogue.

NB : {, }et Btous se réfèrent au même objet texte: Block ( :help aB, :help iB). Si cette ou d'autres réponses utilisent un signe différent de celui utilisé dans la question, c'est peut-être pourquoi.

L'insecte

Je ne le comprends pas entièrement, mais voici vers une explication, si quelqu'un est intéressé.

Le comportement que vous voyez est dû à un bogue mentionné par Yukihiro Nakadaira sur vim_dev et son correctif est publié en 7.4.743: "p" en mode visuel provoque un fractionnement de ligne inattendu .

Le mode visuel put ( :help v_p) est censé remplacer le texte sélectionné visuellement par le texte d'un registre. Le bogue se produit lorsque a) le registre est de type ligne ( :help linewise-register) mais la sélection visuelle est de type caractère et b) la sélection visuelle se termine à la dernière colonne d'une ligne. Dans votre cas, si vous tirez sur le bloc intérieur puis sélectionnez visuellement un bloc et collez, le registre tiré sera dans le sens des lignes et la sélection visuelle sera dans le sens des caractères. Nous pouvons extraire le bloc interne et un bloc aux registres nommés et inspecter:

Sur

for(int i = 0; i < s.length(); i++){  
    int index = s[i] - c;  
    if(root->next[index] == NULL)  
        root->next[index] = new TrieNode;  
    root = root->next[index];  
}

Nous faisons

"ayi{
"bya{
:registers ab

qui montre

--- Registers ---
"a       int index = s[i] - c;^J    if(root->next[index] == NULL)^J        root->next[index] = new TrieNode;^J    root = root->next[index];^J
"b   {^J    int index = s[i] - c;^J    if(root->next[index] == NULL)^J        root->next[index] = new TrieNode;^J    root = root->next[index];^J}

et

:echo getregtype('a') " displays 'V' for linewise
:echo getregtype('b') " displays 'v' for characterwise

Pour remplacer une sélection visuelle par caractère par un registre par ligne, les lignes qui contiennent le début et la fin de la sélection visuelle doivent être divisées en deux, afin que le texte puisse être inséré entre les deux. Cela fonctionne généralement très bien:

Exécuter vim as vim -u NONE -U NONEet taper
( a )

iaaa
bbb
ccc
ddd<Esc>ggYjlvp

résulte en

aaa
b
aaa
b
ccc

et ( b )

iaaa
bbb
ccc
ddd<Esc>ggYjvjp

dans

aaa

aaa
cc
ddd

Mais lorsque la sélection visuelle par caractère se termine à la dernière colonne d'une ligne (et n'inclut pas la nouvelle ligne /n/ ^J), quelque chose ne va pas. Cela a à voir avec la position du curseur, qui est soudainement décalée de -1 et doit être spécialement incrémentée, ce que fait le patch. Comparez ( a ) avec la commande <Esc>ggYjllvp, c'est-à-dire la même commande, sauf déplacez une colonne de plus vers la droite pour que le curseur se trouve sur le dernier "b" de la ligne. Le résultat est le même qu'avant!

Prenez maintenant le texte suivant:

if (TIRED){
    goto bed;
} else {
    goto work;
}

Avec le curseur sur la deuxième ligne, votre travail yi{va{pfonctionne très bien et donne

if (TIRED)
    goto bed;
 else {
    goto work;
}

Le registre yank est toujours en ligne et la sélection visuelle en caractères, mais la sélection visuelle ne se termine plus dans la dernière colonne, et tout va bien.

Exemples de textes de la question

Pour les deux exemples de texte, où la seule différence est un espace vide entre la fermeture des parenthèses et l'ouverture du crochet entre parenthèses dans la première ligne, il peut sembler que votre commande se comporte différemment, mais ce n'est vraiment pas le cas. Dans le premier cas, celui qui semble réussi, il devrait y avoir un espace de fin sur la première ligne une fois les crochets supprimés. Cet espace de fin est à la place sur la dernière ligne. Avecyi{va{p

for(int i = 0; i < s.length(); i++) {
    int index = s[i] - c;
    if(root->next[index] == NULL)
        root->next[index] = new TrieNode;
    root = root->next[index];
}

devient

for(int i = 0; i < s.length(); i++)
    int index = s[i] - c;
    if(root->next[index] == NULL)
        root->next[index] = new TrieNode;
    root = root->next[index];
␣

juste comme

for(int i = 0; i < s.length(); i++){
    int index = s[i] - c;
    if(root->next[index] == NULL)
        root->next[index] = new TrieNode;
    root = root->next[index];
}

devient

for(int i = 0; i < s.length(); i++
    int index = s[i] - c;
    if(root->next[index] == NULL)
        root->next[index] = new TrieNode;
    root = root->next[index];
)

Solutions

La solution serait d'installer le correctif, mais il existe de nombreuses autres façons de supprimer les supports environnants qui ne souffrent pas du bogue. La meilleure solution de contournement est la réponse @Gilles mais la plus simple peut être de sélectionner visuellement avant de tirer, pour garder le registre dans le sens des caractères.

Le plugin surround de Tim Pope est excellent, mais (au moins pour moi) il fait plus que supprimer les crochets: il joint la deuxième ligne à la première, il supprime l'indentation et il déplace le curseur au début de la première ligne. Cela laisse un nettoyage non trivial à faire. Ingo Karkat et Luc Hermitte ont des plugins qui traitent des registres et du collage (je suis sûr qu'il y en a beaucoup d'autres) et qui devraient pouvoir le faire. Je ne les connais pas très bien, mais je pense qu'avec les crochets lh, vous pouvez faire <M-b>xpour supprimer les crochets environnants et pour des mises plus puissantes (en particulier en mode visuel), vous pouvez regarder ReplaceWithRegister et UnconditionalPaste .

La meilleure façon est celle donnée dans la réponse @Gilles, [{x]}x. Il est rapide, gère bien les blocs imbriqués et ne joint pas les lignes de manière inappropriée ou ne joue pas avec l'indentation. S'il y a un espace blanc avant le crochet d'ouverture, vous pouvez facilement ajouter un xà la commande pour le supprimer:[{xx]}x

Autres commandes vanilla

Encore une fois, la commande la plus appropriée à laquelle je peux penser est celle de la réponse de @Gilles, [{x]}xou [{xx]}x, mais voici deux alternatives spécifiquement à la lumière de ce bogue.

Yank caractère

Étant donné que le bogue se produit uniquement pour le registre de mise en ligne visuel mis sur la sélection de caractère, et comme il n'est qu'accidentel de votre yank de bloc interne qu'il soit en ligne, vous pouvez choisir de le tirer à la place. Un moyen facile est de choisir visuellement le bloc interne avant le collant, et de vous assurer que la sélection visuelle est characterwise (utilisation vnon V): vi{yva{p. Cela peut être le moyen le plus simple car il est très similaire à la façon dont vous effectuez actuellement l'opération.

Ne pas utiliser de put visuel

D'autres commandes, comme changer et supprimer, ne sont pas affectées par ce bogue. Vous pouvez tirer comme auparavant, mais ensuite supprimer un bloc dans le registre de trou noir ( :help quote_) et le mettre, ou supprimer un bloc et le mettre du registre 0 ( :help quote0): yi{"_da{pouyi{da{"0p

Généralité

Enfin, il existe des moyens similaires à la réponse @Gilles - déplacer au début d'un bloc, supprimer le caractère, déplacer à la fin d'un bloc, supprimer le caractère - mais qui sont plus génériques. La seule raison de les utiliser serait si le "bloc" que vous supprimez est excentrique et n'a pas de mouvements associés qui fonctionnent aussi bien que [{pour un bloc délimité par des accolades. Il y a une chance que le plugin vim-surround puisse bien gérer ces blocs excentriques, mais deux façons vanille seraient

  1. Sélectionnez visuellement le bloc excentrique et quittez le mode visuel. Le curseur se trouve sur le dernier caractère de la sélection. Supprimez-le, puis allez au début de la dernière sélection ( :help `<) et supprimez le caractère.va{<Esc>x`<x
  2. Recherchez en arrière le début du bloc excentrique et supprimez le caractère, puis recherchez en avant la fin du bloc excentrique et supprimez le caractère. ?{<CR>x/}<CR>xCela peut ne pas fonctionner correctement avec des blocs imbriqués.

Nombre de caractères

+----+------------------------+----------------------------+------------+
|    | method                 |          command           | characters |
+----+------------------------+----------------------------+------------+
| 1. | vim-surround           | ds{                        |          3 |
| 2. | @Gilles answer         | [{x]}x                     |          6 |
| 3. | Characterwise yank     | vi{yva{p                   |          8 |
| 4. | Delete, not visual put | yi{"_da{p or yi{da{"0p     |          9 |
| 5. | Visual mark            | va{<Esc>x`<x               |          8 |
| 6. | Search                 | ?{<CR>x/}<CR>x             |          8 |
+----+------------------------+----------------------------+------------+
jjaderberg
la source
5

Puisque vous ne demandez pas que le curseur revienne à sa position d'origine, [{x]}xfait le travail. Il est long de 6 caractères avec deux pressions Shiftmais le principe est simple donc c'est facile à retenir.

Si vous souhaitez revenir à la position d'origine, vous pouvez utiliser [{x``]}x``

Gilles 'SO- arrête d'être méchant'
la source