Como diminuir automaticamente a segunda letra de uma palavra?

13

Quando tenho que digitar muito texto, costumo manter o dedo pressionado shiftquando escrevo a primeira letra de uma frase que geralmente fornece:

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

Aqui o Ede NEwdeve estar em minúsculas. Estou, então, tentando criar uma função que detecte se a segunda letra da primeira palavra da frase que estou digitando está em maiúscula e em minúscula. A parte importante seria que a correção fosse feita automaticamente enquanto eu estiver digitando o final da minha frase.

Até agora, tentei jogar com o evento de comando automático InsertCharPreantes de perceber que o texto não pode ser modificado por uma função acionada por esse evento.

Qual seria uma boa solução?

Observe que até agora não preciso focar em maiúsculas ou minúsculas, como siglas, que devem estar em maiúsculas ou esse tipo de coisa.

EDIT Eu fiz isso, que é uma solução não-perfeita:

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

Ele tem um problema, já que o primeiro caractere inserido no modo de inserção é movido para o final da linha, mas acho que isso pode ser corrigido.

Acho que agora minha pergunta se torna uma questão de revisão de código :

  • Como posso me livrar do efeito colateral que move o primeiro caractere inserido?
  • É o melhor método possível?
  • Esse método parece desacelerar o Vim: como ele pode ser melhorado?
statox
fonte

Respostas:

6

Aqui está uma coisinha preparada muito rápido. Acho que é menos robusto, mas também muito mais leve. Talvez você possa incorporá-lo ao seu para torná-lo mais rápido? Provavelmente vou revisar isso um pouco quando tiver tempo.

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

Acho que não é uma solução completa, mas pensei em tentar uma abordagem diferente e ver se isso provocou algo para você. :)

Tumbler41
fonte
4
A idéia de remapear <Space>parece bastante interessante, pois reduz o número de invocações das funções. Vou tentar trabalhar dessa maneira também!
Statox
4

Não sei como é confiável, mas você pode tentar o seguinte:

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

Ele instala um autocmd que executa o seguinte comando antes de inserir um caractere:

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

O caractere que você está prestes a inserir é armazenado na variável interna v:chare, se o teste:

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

... for bem-sucedido, o autocmd atribui um novo valor a v:char, que é tolower(v:char).

O teste verifica se você estava prestes a inserir uma letra maiúscula ( v:char =~ '\u') e seu cursor está após o primeiro caractere da primeira palavra de uma frase:

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

Edit: Eu não sei se há uma diferença (em termos de desempenho) entre essas 2 sintaxes: :let myvar = test ? new_value : old_valuee :if test | let myvar = new_value | endif.

Certa vez, li que, quando você deseja otimizar seu código, precisa usar o mínimo de comandos Ex possível. Então, talvez a segunda sintaxe (que poderia ser contado como 3 comandos Ex: :if, :let, :endif) é mais lento do que o 1º um, eu não sei.

Mas se esse for o caso, você poderá substituir o autocmd por:

autocmd InsertCharPre * let v:char = (v:char =~ '\u' && getline('.') =~ '\v(\.\s+|^\s*)\u%' . col('.') . 'c') ? tolower(v:char) : v:char
user9433424
fonte
1
Agora essa é uma solução elegante! De acordo com meus primeiros testes, funciona bem. Vou ter que usá-lo por algum tempo para ter certeza de que é robusto. Gosto de como você modificou v:chara ideia que estava perdendo na minha primeira tentativa.
statox
1

Outra maneira de fazer isso (não tão automático e nem tão universal; apenas mais curto):

  • desde que você esteja escrevendo frases / prosa, não código, faça com que o Vim ative a verificação ortográfica em seus buffers de texto
  • crie uma tecla combinada de modo de inserção rápida que remonta aos últimos erros ortográficos, corrige-a e retoma a posição / estado; por exemplo:

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

Então agora, digamos que você comece a escrever

"THis is a mistake|"

... e você acaba de perceber o erro - o que fazer? - basta clicar <C-s>e continuar escrevendo sua frase.

VanLaser
fonte