Como inverter a ordem das linhas selecionadas no Vim?

94

Por exemplo, se eu tiver quatro linhas da seguinte maneira:

a primeira linha
a segunda linha
a terceira linha
a quarta linha

Eu quero revertê-los para

a quarta linha
a terceira linha
a segunda linha
a primeira linha

Como eu pude fazer isso no Vim?

Jichao
fonte
1
:command! -bar -range=% Reverse <line1>,<line2>global/^/m<line1>-1 vi.stackexchange.com/a/2107/10254
qeatzy

Respostas:

86

Para reverter todas as linhas em um arquivo,

:g/^/m0

Para uma explicação, consulte

:help 12.4

que também mostra como reverter apenas um intervalo de linhas.

garyjohn
fonte
12
Ótima dica na seção de ajuda exata! Para resumir: 1. defina um marcador na última linha que você deseja inverter (eu nomeio o marcador 'a' usando ma), 2. mova o cursor para a primeira linha do bloco, 3. digite:'a,.g/^/m 'a
Brent Faust
68

Selecione as linhas desejadas, pressione !e, no prompt resultante, passe as linhas por tacla :'<,'>!tac. Veja man tacpara mais detalhes.

Rhys Ulerich
fonte
4
Para selecionar as linhas, use shift+vpara entrar no modo de linha visual e, em seguida, jadicionar linhas à seleção.
21814 wisbucky
Posso confirmar que isso funciona no Windows gvimtambém! Caso contrário, você precisará usar números de linha absolutos (talvez você possa usar parente, mas você deve ter cuidado) com o :g/^/m0(que também é realmente difícil de lembrar) ... Então, essencialmente, o tac deve estar com o vim, independentemente da plataforma você está, mas não é 100% vimscript, mas quem se importa: P
dylnmc
O tac não é um tratamento totalmente nativo do vim, mas o comando 'm'ove pega um número de linha e isso nem sempre é razoável. Costumo usar uma marca como parte de um intervalo, por isso :.,'a!tactrabalha com o mínimo esforço.
studog 26/09/18
Após o uso shift+v, você pode usar }para alcançar o próximo parágrafo ou esvaziar o espaço vertical. Além disso man tac: concatenate and print files in reverse,.
nilon 10/08
33

No Mac OS X, tacnão existe, mas você pode usar tail -ro mesmo efeito:

:%!tail -r

Isso também funciona muito bem no modo visual:

:'<,'>!tail -r

Trecho da página tail(1)de manual de:

A opção -r faz com que a entrada seja exibida na ordem inversa, por linha. Além disso, esta opção altera o significado das opções -b, -c e -n. Quando a opção -r é especificada, essas opções especificam o número de bytes, linhas ou blocos de 512 bytes a serem exibidos, em vez dos bytes, linhas ou blocos do início ou do final da entrada a partir da qual iniciar a exibição. O padrão para a opção -r é exibir todas as entradas.

Thomas Perl
fonte
3
Excelente! Portanto, para fornecer 'tac' no OS X:alias tac='tail -r'
Brent Faust
4
Você também pode brew install coreutilse usar gtac.
Andrew Marshall
1
Gênio. Nunca pensei em usar! comandos para esse tipo de manipulação visual de linha.
Charlie Dalsass
3

Para quem se sente mais confortável com o modo Visual:
1. Identifique o número da linha acima da seleção que você deseja inverter :set nu.
2. Shift-Vpara realçar a seleção que você deseja inverter (modo visual).
3 :g/^/m <Line number from step 1>.

Observe que, no modo visual, ele aparecerá automaticamente como :'<,'>g/^/m <Line number>quando você digita o comando de 3.

Esse comando funciona movendo a seleção uma linha de cada vez para o número da linha que você especificar. Quando o segundo item é empurrado para o número da linha fornecido, ele empurra o primeiro para o número da linha + 1. Em seguida, o terceiro empurra o primeiro e o segundo para baixo, e assim sucessivamente, até que toda a lista seja empurrada para o número de linha única, resultando em um lista ordenada reversa.

horta
fonte
4
Você pode usar o em '<vez de digitar o número da linha manualmente. Basta iniciar a seleção uma linha anteriormente e executar :'<,'>g/^/m'<.
Palec 15/09/16
3

Um comando :Rev[erse]e mapeamentos opcionais para você vimrc, para que você não precise se lembrar e executar as etapas não óbvias desta receita:

" Reverse the lines of the whole file or a visually highlighted block.
    " :Rev is a shorter prefix you can use.
    " Adapted from http://tech.groups.yahoo.com/group/vim/message/34305
command! -nargs=0 -bar -range=% Reverse
    \       let save_mark_t = getpos("'t")
    \<bar>      <line2>kt
    \<bar>      exe "<line1>,<line2>g/^/m't"
    \<bar>  call setpos("'t", save_mark_t)

nmap <Leader>r :Reverse<CR>
xmap <Leader>r :Reverse<CR>

( :xmapmapeia para o modo Visual, mas não para o Modo de seleção, conforme :help mapmode-xaconselha o mapeamento de caracteres imprimíveis.)

(Com base em: http://tech.groups.yahoo.com/group/vim/message/34305 )

Aaron Thoma
fonte
Esta deve ser a resposta aceita IMO. Mais geralmente útil e eu não tenho que lembrar :'<,'>g/^/m'<:)
Eliot
1
@ Eliot, obrigado! :) (Eu adicionei um pouco de 'conteúdo bônus.';))
Aaron Thoma
Como posso dizer que a seleção começa -1 neste caso? Porque a mudança começa neste momento.
SergioAraujo 17/02
@SergioAraujo: É algo parecido com o :-1,+1Revque você está procurando? Saiba que você pode selecionar visualmente o intervalo que deseja reverter, por exemplo: V7j:Rev. Se isso não responder à sua pergunta, eu não a entendi, então você precisará elaborá-la ou reformulá-la para mim.
Aaron Thoma
1

Digamos que você esteja na linha 3, portanto temos um intervalo de 3 a 6. Basta digitar.

:3,6g/^/m2
SergioAraujo
fonte
1
Você pode deixar implícito o número da linha atual: Com o cursor na primeira linha do seu intervalo, você pode reduzir para :,6g/^/m2; ou quando em última linha do intervalo: :3,g/^/m2; e :3,6g/^/m2funciona de qualquer lugar no arquivo.
Aaron Thoma