Pourquoi un saut de ligne est-il converti en caractère nul dans le registre de recherche et en retour chariot sur la ligne de commande?

12

Si j'ai le texte suivant:

foo
bar

Je le sélectionne visuellement et le copie.
Le texte est maintenant stocké dans le registre sans nom "et voici son contenu (sortie de :reg "):

""   foo^Jbar^J

Selon ce graphique , il semble que ce ^Jsoit la notation caret pour un saut de ligne.

Si je veux dupliquer le registre sans nom dans le aregistre en tapant: :let @a = @"
Voici son contenu (sortie de :reg a):

"a   foo^Jbar^J

Cela n'a pas changé.

Si je le copie maintenant dans le registre de recherche en tapant :let @/ = @", voici son contenu (sortie de :reg /):

"/   foo^@bar^@

Selon le tableau précédent, il semble que ce ^@soit la notation caret pour un caractère nul.
Pourquoi un saut de ligne est-il automatiquement converti en caractère nul dans le registre de recherche (mais pas dans le aregistre)?

Si j'insère le registre sans nom sur la ligne de commande (ou dans une recherche après /), en tapant :<C-R>", voici ce qui est inséré:

:foo^Mbar^M

Encore une fois, selon le dernier tableau, ^Msemble être la notation caret pour un retour chariot.
Pourquoi un saut de ligne est-il automatiquement converti en retour chariot sur la ligne de commande?

Modifier :

Habituellement, vous pouvez insérer un caractère de contrôle littéral en tapant:
<C-V><C-{character in caret notation}>

Par exemple, vous pouvez insérer un littéral <C-R>en tapant <C-V><C-R>.
Vous pouvez le faire pour apparemment n'importe quel personnage de contrôle.
Cependant, j'ai remarqué que je ne peux pas insérer un LF littéral dans un tampon ou sur la ligne de commande, car si je tape: <C-V><C-J>il insère ^@, un caractère nul, au lieu de ^J.
Est-ce pour la même raison qu'un LF est converti en NUL dans le registre de recherche?

Modifier 2 :

Dans :h key-notation, nous pouvons lire ceci:

<Nul>       zero            CTRL-@    0 (stored as 10) <Nul>
<NL>        linefeed        CTRL-J   10 (used for <Nul>)

La stored as 10partie sur la première ligne et used for <Nul>sur la deuxième ligne pourrait indiquer qu'il y a une sorte de chevauchement entre un LF et un NUL, et qu'ils pourraient être interprétés comme la même chose. Mais ils ne peuvent pas être la même chose, car après avoir exécuté la commande précédente :let @/ = @", si je tape nen mode normal pour arriver à la prochaine occurrence des 2 lignes fooet bar, au lieu d'obtenir une correspondance positive, j'ai le message d'erreur suivant:

E486: Pattern not found: foo^@bar^@

En outre, ce lien semble expliquer qu'un NUL désigne la fin d'une chaîne, tandis qu'un LF désigne la fin d'une ligne dans un fichier texte.

Et si un NUL est stored as 10comme l'indique l'aide, qui est le même code que pour un LF, comment Vim est-il capable de faire la différence entre les 2?

Modifier 3 :

Peut-être qu'un LF et un NUL sont codés avec le même code décimal 10, comme le dit l'aide. Et Vim fait la différence entre les 2 grâce au contexte. S'il rencontre un caractère dont le code décimal est 10dans un tampon ou n'importe quel registre, à l'exception des registres de recherche et de commande, il l'interprète comme un LF.
Mais dans le registre de recherche ( :reg /) il l'interprète comme un NUL car dans le contexte d'une recherche, Vim ne recherche qu'une chaîne où le concept de end of line in a filen'a pas de sens car une chaîne n'est pas un fichier (ce qui est bizarre puisque vous pouvez utilise toujours l'atome \ndans un motif recherché, mais ce n'est peut-être qu'une caractéristique du moteur d'expression régulière?). Il est donc automatiquement interprété 10comme un NUL car c'est le concept le plus proche ( end of stringend of line).

Et de la même manière, sur la ligne de commande / registre de commande ( :reg :), il interprète le code 10comme un CR, car le concept de end of line in a filen'a pas de sens ici. Le concept le plus proche est end of commandque Vim interprète 10comme un CR, car frapper Enterest le moyen de terminer / exécuter une commande et un CR est le même que frapper Enter, car lorsque vous insérez un littéral avec <C-V><Enter>, ^Ms'affiche.

Peut-être que l'interprétation du caractère dont le code est 10change en fonction du contexte:

  • fin de ligne dans un buffer ( ^J)
  • fin de chaîne dans une recherche ( ^@)
  • fin de commande sur la ligne de commande ( ^M)
saginaw
la source
2
Parfois, l'occurrence de NULL caractères inattendus est provoquée par la fonction C sous-jacente qui gère les chaînes. Cette explication de la façon dont C traite les chaînes auxquelles vous avez lié explique qu'en C interne délimite les chaînes avec a NULL. NULLs apparaissent assez rarement dans le texte pour en faire un bon caractère à cet effet. Une conséquence de cela est que si le programme C (vim) essayait de passer une chaîne "vide" dans une fonction C interne
the_velour_fog
2
par exemple, someFunction(arg1, "")où arg 2 était "" ie "l'élément entre les guillemets, qui est littéralement rien - un" vide ". un NULL peut apparaître, car il a été" ajouté "par l'implémentation C sous-jacente car il délimitait la chaîne. Je ne sais pas comment vous vérifieriez cela - mais cela vient à l'esprit comme une cause possible
the_velour_fog
1
Voir également la discussion \ret la \ndifférence:substitute .
jamessan

Réponses:

4

Tout d'abord, merci pour ce message très complet et réfléchi.

Après quelques tests, je suis arrivé à cette conclusion:

  1. Les caractères de contrôle sont affichés en utilisant la notation caret: ^Mpour <CR>(retour chariot) et ^Jpour <LF>(saut de ligne). Dans les tampons, <EOL>(fin de ligne) sont affichés en tant que nouvelles lignes d'écran et sont saisis avec la touche Entrée. <EOL>dépendent du format de fichier du tampon: <EOL> = <CR>|<LF>|<CR><LF>pour mac|unix|dosrespectivement.

  2. Lors de l'édition d'un tampon, le format de fichier est toujours défini. Pour modifier le format de fichier d'un tampon ouvert, vous pouvez utiliser la commande suivante qui convertit <EOL>:

    :set f[ile]f[ormat]=mac|unix|dos
    

    Outre la conversion <EOL>, cette commande est convertie <LF>en <CR>lors du changement de format de fichier de macen unix|dos, et inversement <CR>en <LF>lors de la modification du format de fichier de unix|dosen mac. Pour voir les octets réels du tampon, vous pouvez utiliser la commande suivante qui transforme la représentation textuelle du tampon en sa représentation hexadécimale à l'aide de l'éditeur hexadécimal pratique xxd:

    :%!xxd
    
  3. Dans les registres (avec la commande montraient :reg[isters]ou :di[splay]), <EOL>sont toujours affichés comme ^J(mais tous ne ^Jsont <EOL>), quel que soit le format de fichier du tampon. Cependant <EOL>sont stockés comme ils le devraient. Pour pouvoir distinguer visuellement réel ^J(c'est-à-dire <LF>) des autres ^J(c'est-à-dire <EOL>) dans les registres, vous pouvez utiliser la commande suivante qui affiche les valeurs hexadécimales au lieu de la notation caret des caractères de contrôle différents de <EOL>:

    :set d[ispla]y=uhex
    
  4. Dans les modèles de recherche et les chaînes de substitution:

    \r = newline different from <EOL> (<CR> if <EOL> = <CR><LF>|<LF>, <LF> if <EOL> = <CR>)
    \n = <EOL>
    
  5. Partout:

    <C-V><C-M>|<C-V><EOL> = newline different from <EOL>
    <C-V><C-J> = <NUL>
    

    Cela montre que lorsque le format de fichier est dos, il est impossible de saisir <LF>, puisque <EOL> = <CR><LF>et <C-V><C-M>|<C-V><EOL> = <CR>.

  6. Dans les chaînes de substitution:

    • les retours à la ligne différents de <EOL>sont interprétés comme <EOL>;

    • <EOL>sont interprétés comme <NUL>.

    Ainsi, selon 4., :%s[ubstitute]/\r/\r/gremplace chaque nouvelle ligne différente de <EOL>dans le tampon avec <EOL>, tandis que :%s[ubstitute]/\n/\n/gremplace chaque <EOL>dans le tampon avec <NUL>.

  7. Dans le registre de recherche /et le registre de commande :, <EOL>sont convertis en

    • nouvelle ligne différente de celle <EOL>insérée à partir d'un registre avec /<C-R>{register}ou :<C-R>{register}respectivement;

    • <NUL>lorsqu'ils sont insérés à partir d'un registre avec :let @/=@{register}ou :let @:=@{register}respectivement.

  8. Dans les tampons, les sauts de ligne différents de <EOL>sont convertis en <EOL>lorsqu'ils sont insérés à partir d'un registre en utilisant i<C-R>{register}.

Pourquoi un saut de ligne est-il converti en caractère nul dans le registre de recherche et en retour chariot sur la ligne de commande?

Avant de copier <LF>du registre sans nom "vers d'autres registres, vous devez le saisir <LF>et le mettre dans le registre ". Si le format de fichier est unix, vous pouvez le faire en utilisant yysur une ligne vide; si le format de fichier est mac, vous pouvez le faire en utilisant i<C-V><C-M><Esc>yl; si le format de fichier est dos, vous ne pouvez pas saisir <LF>(cf. 5.).

Maintenant, votre déclaration est partiellement fausse, car

  • vous n'utilisez pas la même méthode pour copier <LF>du registre "dans le registre de recherche /et le registre de commande :. Vous utilisez :let @/=@"pour copier dans le registre /et :<C-R>"pour copier dans le registre :. Utiliser /<C-R>"et :<C-R>"respectivement vous donnera le même résultat ( <CR>) dans les deux cas;

  • les conversions <LF>ont lieu avec vos deux méthodes de copie différentes uniquement lorsque le format de fichier est unix. Si c'est le cas mac, <LF>n'est pas converti lors de la copie dans le registre /ou le registre :, et si c'est le cas, dosvous ne pouvez même pas entrer <LF>.

La bonne déclaration est donnée par 7. Mais je n'en connais vraiment pas les raisons.

Maggyero
la source
Pourquoi est-ce si difficile à comprendre ... J'ai fait des recherches à travers plusieurs articles sur SO et vim-SE et l'aide de vim, mais pas complètement cohérent et toujours confus.
Violapterin