Comment mettre automatiquement en minuscule la deuxième lettre d'un mot?

13

Quand je dois taper beaucoup de texte, j'ai souvent tendance à garder le doigt appuyé shiftlorsque j'écris la première lettre d'une phrase qui donne souvent:

[...]end of sentence. NEw sentence[...]

Ici , le Ede NEwdevrait être en minuscules. J'essaie alors de créer une fonction qui détecterait si la deuxième lettre du premier mot de la phrase que je tape est en majuscule et qui la minuscule. L'important serait que la correction soit effectuée automatiquement pendant que je tape la fin de ma phrase.

Jusqu'à présent, j'ai essayé de jouer avec l'événement de la commande automatique InsertCharPreavant de réaliser que le texte ne peut pas être modifié par une fonction déclenchée par cet événement.

Quelle serait une bonne solution?

Notez que jusqu'à présent, je n'ai pas besoin de me concentrer sur les cas marginaux comme les acronymes qui devraient être en majuscules ou ce genre de choses.

EDIT J'ai fait ceci, ce qui n'est pas une solution de contournement parfaite:

autocmd CursorMovedI * call RemoveUnwantedUpper()

function! RemoveUnwantedUpper()
    " Get the current sentence
    " Based on http://stackoverflow.com/a/23315227/4194289
    let l:save_clipboard = &clipboard
    set clipboard= " Avoid clobbering the selection and clipboard registers.
    let l:save_reg = getreg('"')
    let l:save_regmode = getregtype('"')

    normal! y(
    normal! ``

    let l:sentence =getreg('"') 

    call setreg('"', l:save_reg, l:save_regmode)
    let &clipboard = l:save_clipboard

    " Check that we entered a new word (space inserted)
    if l:sentence[len(l:sentence)-1] != " "
       return
    endif 

    " Check if the word is the first one of the sentence
    let l:size = len(split(l:sentence, " "))
    if l:size > 1 
        return
    endif

    " If the last char entered is a space (new word) remove the unwanted Upper case
   normal! bl
   normal! vu
   normal! ``

endfunction

Il y a un problème puisque le premier caractère que j'entre en mode insertion est déplacé à la fin de la ligne, mais je pense que cela peut être corrigé.

Je suppose que maintenant ma question devient une question de révision de code :

  • Comment puis-je me débarrasser de l'effet secondaire qui déplace le premier caractère inséré?
  • Est-ce la meilleure méthode possible?
  • Cette méthode semble ralentir Vim: comment pourrait-elle être améliorée?
statox
la source

Réponses:

6

Voici un petit quelque chose qui est préparé très rapidement. C'est moins robuste je pense, mais c'est aussi beaucoup plus léger. Peut-être pourriez-vous l'intégrer dans le vôtre pour le rendre plus rapide? Je vais probablement revoir cela un peu quand j'aurai le temps.

inoremap <Space> <C-o>:call CheckCase()<CR><Space>

function! CheckCase()
   normal! may2b
   let l:words = getreg('"')
   if l:words[0] == '.'
      normal! wlvu
   endif
   normal! `a
endfunction

Pas une solution complète, je pense, mais j'ai pensé que j'essaierais une approche différente et voir si cela vous a déclenché quelque chose. :)

Tumbler41
la source
4
L'idée de remappage <Space>semble assez intéressante car elle réduit le nombre d'appels des fonctions. J'essaierai de travailler de cette façon aussi!
statox
4

Je ne sais pas à quel point c'est fiable, mais vous pouvez essayer ceci:

augroup FixDoubleUppercase
    autocmd!
    autocmd InsertCharPre * if v:char =~ '\u' && getline('.') =~ '\v(\.\s+|^\s*)\u%' . col('.') . 'c' | let v:char = tolower(v:char) | endif
augroup END

Il installe un autocmd qui exécute la commande suivante avant d'insérer un caractère:

if v:char =~ '\u' && getline('.') =~ '\v(\.\s+|^\s*)\u%' . col('.') . 'c' | let v:char = tolower(v:char) | endif

Le caractère que vous êtes sur le point d'insérer est stocké dans la variable interne v:char, et si le test:

v:char =~ '\u' && getline('.') =~ '\v(\.\s+|^\s*)\u%' . col('.') . 'c'

... réussit, puis l'autocmd attribue une nouvelle valeur à v:char, qui est tolower(v:char).

Le test vérifie si vous étiez sur le point d'insérer une lettre majuscule ( v:char =~ '\u') et votre curseur se trouve après le premier caractère du premier mot d'une phrase:

getline('.') =~ '\v(\.\s+|^\s*)\u%' . col('.') . 'c'

Edit: je ne sais pas s'il y a une différence (en termes de performances) entre ces 2 syntaxes: :let myvar = test ? new_value : old_valueet :if test | let myvar = new_value | endif.

J'ai lu une fois que lorsque vous voulez optimiser votre code, vous devez utiliser le moins de commandes Ex possible. Alors peut - être la 2ème syntaxe (qui peut être compté comme 3 commandes Ex: :if, :let, :endif) est plus lent que la 1ère, je ne sais pas.

Mais si c'est le cas, vous pouvez remplacer l'autocmd par:

autocmd InsertCharPre * let v:char = (v:char =~ '\u' && getline('.') =~ '\v(\.\s+|^\s*)\u%' . col('.') . 'c') ? tolower(v:char) : v:char
user9433424
la source
1
Voilà une solution élégante! D'après mes premiers tests ça marche bien. Je vais devoir l'utiliser pendant un certain temps pour être sûr qu'il est robuste. J'aime la façon dont vous avez modifié v:charl'idée qui me manquait lors de mon premier essai.
statox
1

Une autre façon de le faire (pas si automatique et pas si universelle; juste plus courte):

  • puisque vous écrivez des phrases / prose, pas du code, demandez à Vim d'activer la vérification orthographique dans vos tampons de texte
  • créer une touche combinée en mode d'insertion rapide qui remonte aux dernières fautes d'orthographe, la corrige, puis reprend la position / l'état; par exemple:

    inoremap <C-s> <Esc>[s1z=gi
    

Alors maintenant, dis que tu commences à écrire

"THis is a mistake|"

... et vous vous rendez compte de l'erreur - que faire? - appuyez simplement <C-s>et continuez à écrire votre phrase.

VanLaser
la source