Combine duas funções interativas

Sep 19 2020

Por exemplo, desejo classificar um arquivo e remover as linhas duplicadas. Eu corro M-x sortseguido por M-x delete-duplicate-lines. Eu queria combiná-los em uma única função interativa. Aqui está uma tentativa de resolver isso.

(defun sort-and-dedup ()
 ""
 (interactive)
 (sort)
 (delete-duplicate-lines)
)

Isso dá um erro dizendo que as funções subjacentes não têm um número suficiente de argumentos. Eu meio que entendo por que esse é o caso (o argumento interativo versus não interativo, entre alguns outros), mas não sei o que fazer exatamente. Você pode me dizer como corrigir isso?

Editar 1:

O código acima está errado de várias maneiras. Veja a resposta aceita para obter informações. E obrigado pela ajuda.

Editar 2:

Isso é o que eu pretendia fazer.

(defun sort-and-dedup-region (beg end)
  (interactive "r")
  (sort-lines nil beg end)
  (delete-duplicate-lines beg end nil t))

(defun sort-and-dedup ()
  (interactive)
  (sort-and-dedup-region
   (point-min)
   (point-max)))

Respostas

4 NickD Sep 19 2020 at 01:48

[Acredito que você quis dizer sort-lines, não sort- essa é a única maneira pela qual a pergunta faz sentido, então vou supor.]

Ambos sort-linese delete-duplicate-linesoperam na região selecionada . Você deve selecionar uma região antes de chamá-los, caso contrário, eles reclamarão que não há região. Portanto, você terá que fazer a mesma coisa em sua função: assumir que você recebeu uma região e reclamar se não houver nenhuma.

Uma região é especificada por duas posições no buffer, convencionalmente denominadas BEGe `END. Portanto, sua função será semelhante a esta:

(defun sort-and-dedup (beg end)
   (interactive <mumble>)
   (sort-lines nil beg end)
   (delete-duplicate-lines beg end))

O primeiro argumento para classificar as linhas informa se deve classificar na ordem inversa.

Ao chamar a função interativamente, você especifica uma região definindo uma marca em uma extremidade e, em seguida, movendo o ponto para a outra extremidade (ou iniciando em uma extremidade e arrastando com o mouse até a outra extremidade). Então, como você comunica essas posições para a função? Ao fornecer um argumento para interactive: se você olhar para a string doc (com C-h f interactive RET), você descobrirá que ré o que você precisa para especificar uma região - o Emacs irá providenciar para traduzir a região que você escolheu (independentemente de como você escolheu) em um par de posições (BEG e END) que serão passadas para sua função.

Portanto, a função é semelhante a esta:

(defun sort-and-dedup (beg end)
   (interactive "r")
   (sort-lines nil beg end)
   (delete-duplicate-lines beg end))

Como alternativa, como @Dan sugere, você pode usar call-interactivelye deixar cada função descobrir o que precisa. Mas você ainda terá que especificar uma região com antecedência:

(defun sort-and-dedup ()
   (interactive)
   (call-interactively #'sort-lines)
   (call-interactively #'delete-duplicate-lines))

EDITAR: incorporando a sugestão de @phil (e agora vejo que você realmente implementou isso e adicionou à sua pergunta), você pode escrever uma função que chama (a primeira definição de) sort-and-dedupcom os argumentos necessários para operar em todo o buffer:

(defun sort-and-dedup-whole-buffer()
   (interactive)
   (sort-and-dedup (point-min) (point-max)))

Você pode vinculá-lo a uma sequência de teclas se for fazer isso com frequência:

(define-key global-map (kbd "M-S-<f10>" #'sort-and-dedup-whole-buffer)

embora eu pessoalmente não fizesse isso: as sequências-chave são uma mercadoria rara, então eu tentaria usá-las M-x sort-and-dedup-whole-buffer RETpor um tempo; se isso se tornar um incômodo, eu o vincularia a uma sequência chave.

Eu também revisito todos os meus principais defs a cada dois anos e recupero aqueles que não uso mais. Eu os mantenho em seus próprios arquivos, carregados explicitamente pelo meu arquivo init, para que possa localizá-los e revisá-los facilmente.