Como configurar o Vim para trabalhar com uma frase por linha?

17

Atualmente, estou escrevendo muito texto sem formatação (e LaTeX com formatação mínima em parágrafos), e seria bom se eu pudesse configurar o vim para manter cada frase (por simplicidade, texto terminado com um '.', '!' , ou '?', ou seja, uma pontuação final seguida por um espaço para evitar a quebra de números decimais) em sua própria linha, para que as diferenças de VCS sejam mais úteis.

No mínimo, gostaria gqde formatar o texto de:

He lay flat on the brown, pine-needled floor of the forest, his chin on his
folded arms, and high overhead the wind blew in the tops of the pine trees.
The mountainside sloped gently where he lay; but below it was steep and he
could see the dark of the oiled road winding through the pass. There was a
stream alongside the road and far down the pass he saw a mill beside the
stream and the falling water of the dam, white in the summer sunlight. 

Para:

He lay flat on the brown, pine-needled floor of the forest, his chin on his folded arms, and high overhead the wind blew in the tops of the pine trees.
The mountainside sloped gently where he lay; but below it was steep and he could see the dark of the oiled road winding through the pass.
There was a stream alongside the road and far down the pass he saw a mill beside the stream and the falling water of the dam, white in the summer sunlight.

Mas seria bom se o vim também executasse essa formatação enquanto digito (como acontece com o reflow da largura do texto). Isso é possível?

Minha solução atual é juntar um parágrafo Je executar o :'<,'>s/\. /.\r/gque é muito bom, pois há poucos pontos de exclamação e interrogação, mas seria muito melhor se eu pudesse tornar o gq um pouco mais inteligente.

Alex
fonte

Respostas:

23

A 'formatexpr'opção

Você pode conseguir isso usando a 'formatexpr'opção Da ajuda:

Expressão avaliada para formatar um intervalo de linhas para o operador gq ou formatação automática (consulte 'formatação'). Quando esta opção está vazia, 'formatprg' é usado.

A configuração 'formatexpr'correta funcionará ao usar gqe ao inserir texto.

Um exemplo simples

Aqui está uma função simples do VimScript e o 'formatexpr'valor correspondente que deve fazer o trabalho. Não testei em todos os casos extremos, mas funcionou muito bem para meus testes simples.

function! MyFormatExpr(start, end)
    silent execute a:start.','.a:end.'s/[.!?]\zs /\r/g'
endfunction

set formatexpr=MyFormatExpr(v:lnum,v:lnum+v:count-1)

Explicação

A expressão é uma chamada para a função MyFormatExpr(), passando nas linhas inicial e final sobre as quais a formatação será aplicada. Essas linhas são calculadas usando as variáveis ​​preenchidas automaticamente v:lnum(a primeira linha a ser formatada) e v:count(o número de linhas a serem formatadas).

A MyFormatExpr()função constrói um :substitutecomando com o passado na gama, e substitui um espaço em branco na sequência de um sinal de pontuação final de frase ( ., !, ou ?) com uma nova linha ( \r).

Ressalvas

  • A MyFormatExpr()função não preserva o recuo principal. Alguma lógica mais sofisticada seria necessária para consertar isso.
  • Pode haver outros casos extremos onde isso se desfaz. Faça um test drive e ajuste conforme necessário!
tommcdo
fonte
Ah, sim, esse é o caminho, ignore minha resposta.
Sukima
Isso é incrível! O que eu gostaria de poder fazer é que a função execute uma macro, como "avançar para a próxima frase )e inserir uma nova linha; repita até chegar ao final do intervalo". Presumivelmente, aplicaria qualquer regra de indentação. Mas meu Vim-fu é muito fraco para isso. :)
Nathan Long
Isso se divide, por exemplo e.g. blah, e Blah et al. 2018é um pouco chato. Você pode cancelar a correspondência de padrões como esse com algo parecido 's/\(e\.g\|\<al\)\@<![.!?]\zs /\r/g'. Basta adicionar mais padrões ao primeiro grupo para evitar outras coisas que você não deseja dividir. Caso contrário, isso é super útil, obrigado. Eu não havia me encontrado gqantes e gqipé super útil para formatar o texto que os editores de co-autor confundiram.
naught101
Existe uma maneira de adicionar esse comportamento ao comportamento padrão? Eu gostaria de ser capaz de quebrar em uma determinada largura de texto, bem como dividir no final das frases ..
naught101 15/01
1

Bem, você pode configurar alguns mapas e comandos automáticos:

function! AddSentenceMaps()
  imap .<Space> .<CR>
  imap !<Space> !<CR>
  imap ?<Space> ?<CR>
  exec "nmap gq vipJ:s/\\([.!?]\\)\\s\\+/\\1\\r/g<CR>"
endfunction

autocmd Filetype customtxt call AddSentenceMaps()

Em seguida, basta definir o tipo de arquivo como mphxt ou chamar a AddSentenceMapsfunção manualmente.

Sukima
fonte
0

Quero adicionar meus pensamentos sobre esse problema. Geralmente, as pessoas desejam esse tipo de recurso por causa de pular linhas quebradas quando navegam pelo código com je kcomandos, que é o comportamento padrão do Vim. Para a navegação através de linhas quebradas, eu uso gj- mover para baixo e gk- mover para cima. Também existe a possibilidade de remapear o padrão je o kcomando nas contrapartes com prefixo g, mas IMHO seria um exagero.

Alexander Myshov
fonte
ou tem uma chave para fazer o remapeamento de je kpara gje gkquando você quiser ;-)
anthony
0

Ele não responde sua pergunta específica sobre reformatação, mas 'set wrap' junto com 'set linebreak' podem tornar a edição de linhas longas muito mais agradável. Combine isso com gj e gk para navegar dentro de linhas quebradas. Mapeio as setas para cima e para baixo para gj e gk, respectivamente, para que eu possa escolher entre mover para cima e para baixo linhas reais ou linhas visuais. Como sábio para Início / Fim para g0 / g $.

Desenhou
fonte