vim não se move para a linha esperada

0

Meu objetivo final é dividir um texto em delimitadores de frase. No entanto, não deve ser dividido em frases, mas em pedaços ca. 1000 linhas e mais o resto da frase atual. Mas no experimento abaixo eu uso apenas 2 linhas para simplificar.

Considere o seguinte texto em um buffer VIM:

line 1. line 1. line 1.
line 2. line 2. line 2.
line 3. line 3. line 3.
line 4. line 4. line 4.
line 5. line 5. line 5.

Após a execução de:

:2 | exec 'normal! )hvgg' | exec "'<,'>w /tmp/part1.txt" | exec 'normal! gvd'

O resultado é o esperado. O buffer contém:

line 2. line 2.
line 3. line 3. line 3.
line 4. line 4. line 4.
line 5. line 5. line 5.

Mas depois da próxima corrida

:2 | exec 'normal! )hvgg' | exec "'<,'>w /tmp/part2.txt" | exec 'normal! gvd'

o buffer contém:

line 2.
line 3. line 3. line 3.
line 4. line 4. line 4.
line 5. line 5. line 5.

O que está acontecendo aqui? Por que ele não passa para a segunda linha, que é line 3. line 3. line 3. ?

Mas eu esperaria que o texto a seguir permanecesse no buffer

line 3. line 3.
line 4. line 4. line 4.
line 5. line 5. line 5.
    
por ka3ak 17.02.2018 / 14:16

2 respostas

-1

Eu finalmente cheguei à solução aceita. Agradecemos a @B Layer pela cooperação (por exemplo, mencionar que o comando w apenas grava linhas inteiras em um arquivo). Eu inventei sua resposta.

:let i=1
:1000 | exec 'normal! )hvggd' | exec 'if i<10 | let num="0" . i | else | let num=i | endif' | call writefile(split(@@, "\n", 1), '/tmp/test' . num . '.txt') | let i=i+1

Depois disso, repita o comando pressionando @: se o último bloco for menor que 1000 linhas e você receberá um erro. Apenas salve o resto manualmente.

Após 5 execuções, tive como esperado:

$ wc -l /tmp/test*.txt
  1001 /tmp/test01.txt
  1000 /tmp/test02.txt
  1001 /tmp/test03.txt
  1006 /tmp/test04.txt
  1001 /tmp/test05.txt

Para aqueles que querem usá-lo, explicarei em breve os principais passos:

:1000

Mover para a linha 1000 (os pedaços devem ter pelo menos 1000 linhas de comprimento)

exec 'normal! )hvggd'

Mude para o início da próxima frase e um caractere de volta para que o primeiro caractere da próxima sentença não seja excluído posteriormente. Para funcionar corretamente em frases que estão espalhadas em várias linhas whichwrap=h,l deve ser definido, o que não é padrão, tanto quanto eu sei. Selecione tudo, desde a posição atual do cursor até o início e exclua-o. O conteúdo excluído será salvo no registro.

call writefile(split(@@, "\n", 1), '/tmp/test' . num . '.txt')

Escreva o conteúdo do registro (o pedaço) em um arquivo

Eu parti da suposição de que não haveria mais de 99 partes. Se precisar de mais, ajuste a parte relacionada ao preenchimento conforme necessário.

    
por 18.02.2018 / 08:21
4

A raiz do problema é o gv no final. É desnecessário, pois a seleção visual persiste da parte anterior do comando. Pior, não é inofensivo porque quando você faz gv quando você já está no modo Visual a área visual atual e anterior são trocados . Significando que a seleção anterior é selecionada novamente!

Embora a seleção anterior tenha sido excluída, a seleção é aplicada à mesma área ... ou pelo menos ao que resta dela. Nesse caso, essa seria a primeira das sentenças line 2. restantes.

Para demonstrar, observe o que acontece quando você insere isso duas vezes: 2G)hvgggvd . Isso é exatamente o que está acontecendo na linha de comando, menos a gravação no disco, mas com 100% dos comandos do modo normal.

Portanto, só precisamos perder o gv e isso funcionará:

:2 | exec 'normal! )hvgg' | exec "'<,'>w! /tmp/part1.txt" | exec 'normal! d'

Além disso, há muito ruído neste comando que pode ser limpo. Dois dos exec s e citações acompanhantes não são necessários:

:2 | exec 'norm! )hvgg' | '<,'>w! /tmp/part1.txt | norm! d

Atualização: Em resposta a um de seus comentários, isso ...

'<,'>

é uma operação linear que seleciona da primeira linha da última área visual selecionada até a última linha da mesma área. Para obter intervalos de caracteres sábios você precisa usar back-tics como este:

'<,'>

No entanto, isso não funcionará com :w ... é apenas uma operação linear.

Eu gostaria de salientar que isso está fora do escopo da sua pergunta, que pergunta por que determinado texto está sendo excluído .... então você pode querer fazer uma pergunta separada para escrever no arquivo.

Atualização 2: Veja uma abordagem totalmente diferente para o seu problema ...

Crie uma macro com o seguinte comando

:let @q = ")hs\<CR>\<ESC>k:let @a=@a+1\<CR>:1,.w /tmp/part\<C-R>a.txt\<CR>dgg"
  • Execute este comando: :let @a = 0 .
  • Coloque o cursor em uma frase e, no modo normal, execute a macro com @q

Isso se comportará da maneira que você descreve: a sentença e tudo o que estiver acima dela será gravado em um arquivo chamado /tmp/part1.txt e o texto salvo será excluído. Agora mova para qualquer outra frase e faça @q novamente e desta vez a mesma coisa acontecerá, mas irá gravar em /tmp/part2.txt . Sempre que você executar a macro, o nome do arquivo será incrementado automaticamente. Você pode redefinir o índice novamente com :let @a = 0 .

Como na atualização anterior, isso não está respondendo à pergunta atual, mas, como sou bom, estou oferecendo ajuda extra. (E o OP ainda não aceite minha resposta.)

    
por 17.02.2018 / 16:23

Tags