Como posso mapear d [count] d?

18

NB Esta não é uma duplicata de Como funciona o comando "d3fg"? Leia antes de votar para fechar!

Cheguei a um impasse na minha busca para que pequenas exclusões funcionem como grandes . O problema que tenho é que não consigo descobrir como remapear comandos como esse d3d. De fato, nem consigo entender como eles funcionam, nem encontro nenhuma menção a eles na ajuda de Vim. *

d3jé direto: aplica o doperador ao 3jmovimento,

3ddtambém é simples: executa o ddcomando com uma "contagem" de 3.

d3d parece que deve ser simples, aplica o doperador ao… mas o que é 3d? Não é um movimento. Se você digitar 3dpor conta própria, o Vim a tratará como uma contagem seguida por um operador e aguardará pacientemente por mais informações.

E você não pode aplicar operadores a outros operadores. ddnão é descrito na ajuda como uma sequência de dois operadores. É um comando separado, com duas teclas. (cf. dc, que não faz nada.)

Também não parece ser o caso de o posicionamento da contagem ser flexível para comandos que exigem duas teclas: 2gjmove o cursor para baixo duas linhas da tela, mas g2jdescarta as duas primeiras teclas pressionadas inteiramente e move o cursor para baixo uma linha.

Então, como isso funciona? Este é apenas um caso especial no código interno do Vim? Existe alguma maneira de criar um d[count]dmapeamento?

EDIT : É um objeto de texto? :h text-objectsnão incluí-lo na lista de "texto comandos de seleção objeto", mas então ele não incluem dd em uma lista de exclusões "agrupados desde pequenas a grandes objetos". E d2awexclui a palavra sob o cursor e a seguinte. Por outro lado, c2dnão faz nada.

* Tenho certeza de que alguma menção a eles deve existir, mas não consigo encontrá-la. Eu li :help deleting, :help motion.txte tentou :helpgrep dNdpara todos os valores de N de 1-9 .

Rico
fonte
2
Eu acho que o último datua como uma confirmação; Então é o mesmo que d3<CR>. y3ye c3ctambém funciona da mesma forma ... Não consigo encontrar nenhum documento sobre isso no Vim: help, vi (1), nvi (1) ou na especificação POSIX ... Ele se comporta da mesma forma vie nvientre .
Martin Tournoij 13/03/2015
1
De certa forma, ddé idêntico a d_. _leva o cursor para o primeiro não-espaço em branco na ( [count]-1) ésima linha para baixo, mas é no sentido da linha; portanto, quando emparelhado com um operador, ele opera em linhas inteiras. Por esse motivo, faz sentido que uma contagem possa aparecer entre os dois ds.
Tommcdo

Respostas:

28

Modo pendente do operador

Entre digitando um operador (como d, cou gU) e um movimento (como w, i}ou /foo<CR>), Vim está no modo Operador-pendente. Você pode criar mapeamentos para isso usando :omape :onoremap.

Nos meus exemplos, vou mapear o Operador pendente dpara w. Esta é uma escolha aleatória, porque não sei para que você realmente deseja usá-lo.

Crie um omap

Vamos criar um mapeamento para dno modo pendente Operador. Eu vou assumir que estamos escrevendo VimScript aqui (como no seu .vimrc), então vou omitir os :s principais .

onoremap d w

Isso faz ddagir como dw. Também faz d[count]dagir como d[count]w. Mas aposto que você não queria afetar o comportamento de dd(ou seja, não [count]fornecido).

Mapeamentos de expressão

Os mapeamentos de expressão permitem avaliar uma expressão VimScript para produzir o lado direito do mapeamento. A expressão deve ser avaliada como uma sequência. Os mapeamentos de expressão são indicados pela <expr>palavra - chave.

O Vim também possui algumas variáveis ​​internas que são preenchidas em vários momentos e geralmente são úteis durante os mapeamentos. Um deles é o v:countque é [count]fornecido a um operador ou movimento.

Vamos juntar tudo isso. Se não [count]for fornecido, v:countserá 0. Podemos dizer ao nosso mapeamento para usar apenas dnesse caso.

onoremap <expr> d v:count == 0 ? 'd' : 'w'

Agora ddse comporta como o padrão (exclui uma linha), mas d[count]dse comporta como d[count]w. Legal!

Restrinja o uso após o doperador

Você pode notar algo, no entanto. Agora cdtambém se comporta como cw. Isso pode não ser um problema, mas, para ser completo, vamos restringi-lo para que funcione somente após o doperador.

O Vim tem outra variável, v:operatorque contém o operador usado mais recentemente. Vamos verificar isso também antes de fazer algo especial.

onoremap <expr> d (v:count == 0 \|\| v:operator != 'd') ? 'd' : 'w'

NOTA: Como os :mapcomandos podem ser encadeados |, precisamos escapar deles em nossa expressão aqui. Portanto, o operador OR lógico ||se torna \|\|.

Legal, então cde c[count]dvoltamos a não fazer nada, como costumavam fazer. Isso é bom para que outros plugins possam definir cd.

Eu não quero apenas excluir alguma outra moção

Se você deseja mapear d[count]dpara algo totalmente diferente, nada a ver com a exclusão de texto, também podemos fazer isso funcionar.

Quando você digita comandos no modo Normal e começa a digitar um comando por engano, pode pressionar <Esc>para cancelar esse comando. O mesmo se aplica aos seus mapeamentos.

Vamos d[count]dmudar a linha atual para o que [count]for.

onoremap <expr> d (v:count == 0 \|\| v:operator != 'd') ? 'd' : '<Esc>cc' . v:count . '<Esc>'

A última parte do mapeamento é uma expressão VimScript: <Esc>cc' . v:count . '<Esc>'. Isso é <Esc>para cancelar o dcomando pendente , ccalterar a linha atual, v:countdigitar o valor de [count](no modo Inserir) e <Esc>retornar ao modo Normal. Observe que estamos construindo uma string aqui usando o operador de concatenação do VimScript .,.


Seu caso de uso real provavelmente será diferente do que descrevi aqui, mas espero que isso ajude você a fazer a bola rolar.

Vimming feliz!

tommcdo
fonte
Ótima resposta! Votado. Fiz um link para o meu caso de uso (também no vi.SE) no início da pergunta, mas acho que você deve ter esquecido. Eu basicamente preciso fazer :omap d d(!), Mas infelizmente o modo de operador pendente nunca é realmente atingido devido ao meu mapeamento para d que define a função de operador personalizada. Espero que seja possível ajustar as coisas para fazer o d3dtrabalho como deveria, no entanto. (Deixe-me saber se você tem alguma idéia ou, se preferir, pode postar uma solução completa para a outra pergunta.) Se eu não conseguir descobrir isso em breve, vou aceitar isso e postar outra pergunta mais específica. Obrigado!
Rich
1
Na verdade, pensando bem, estou aceitando isso agora. Você explicou como criar esse mapeamento e também como ele funciona sob o capô, que foram as duas coisas que pedi.
Rich