como obter buffers (não apenas arquivos) para honrar o modo automático alist?

13

P: como posso obter novos buffers para honrar o mapeamento auto-mode-alist?

Ao encontrar um arquivo , o Emacs compara a extensão do arquivo com a auto-mode-alistpara determinar qual modo principal usar para o buffer do arquivo. Existe uma maneira de usar as informações auto-mode-alistpara determinar o modo de um buffer que ainda não possui um arquivo associado a ele?

Ou seja: se eu abrir um novo buffer cujo nome tem algo parecido com uma extensão de arquivo, posso fazê-lo abrir automaticamente no modo esperado? Por exemplo, se eu abrir um novo buffer a-new-buffer.elque ainda não esteja associado a um arquivo, quero que ele seja aberto no emacs-lisp-modemodo padrão.

Dan
fonte
2
Apenas curioso: qual é o caso de uso? IOW, por que / quando / em que contexto você deseja fazer isso? Normalmente, se você deseja que um buffer seja associado a um arquivo e, portanto, escolhe seu modo auto-mode-alist, faça com que o buffer " visite " o arquivo (e isso cuida de tudo).
Drew
5
Exemplos de casos de uso típicos para mim são: a) um orgbuffer temporário para testar novas funções nas quais estou escrevendo para uso org-mode; b) um Rbuffer temporário para fazer algumas manipulações estatísticas rápidas e descartáveis; c) um buffer de texto temporário para compor um email. Em cada caso, não quero criar um arquivo para visitar, apenas quero um buffer descartável que, no entanto, seja aberto no modo apropriado.
Dan
2
Visitar arquivo comandos como C-x C-fse não " criar um arquivo de visita ". Esse é um mal-entendido fundamental. Eles simplesmente fazem exatamente o que você está procurando. É somente se e quando você tenta salvar o buffer que um arquivo é criado. Se você não tentar salvar o buffer, nenhum arquivo será criado. O que você quer, pelo que entendi até agora, é "visitar um arquivo" (o que realmente significa abrir um buffer no modo adequado).
Drew
8
Como Dan, eu crio buffers temporários o tempo todo que não quero associar a um caminho de arquivo real. Visitar um caminho de arquivo falso funcionaria, mas há pelo menos uma pequena quantidade de atrito na escolha de um diretório (ou na aceitação do diretório atual). Pode haver outros efeitos colaterais, dependendo do restante da sua configuração: Comportamento de salvamento automático? Grupos Ibuffer ou projetos de projéteis determinados pelo caminho? A confirmação do Ido solicita? Como os buffers precisam ter um nome de qualquer maneira, usar o nome para definir o modo automaticamente para um buffer temporário faz sentido para mim.
glucas
@ Drew, sim, isso faz sentido e seria a resposta mais simples para essa pergunta - você poderia publicá-la como resposta, por favor? Merece uma atualização.
Dan

Respostas:

8

Comandos de visita a arquivos, como C-x C-f não criar um arquivo para visitar. Eles fazem o que você está procurando.

É somente se e quando você tenta salvar o buffer que um arquivo é criado .

Se você não tentar salvar o buffer, nenhum arquivo será criado. O que você quer, pelo que entendi até agora, é " visitar um arquivo " (o que realmente significa abrir um buffer no modo adequado).

Desenhou
fonte
4
E se você tiver um dedo hiperativo que salve constantemente o arquivo atual a cada 3 segundos, independentemente do que você deseja?
Malabarba 23/10
1
@ Malabarba: Na verdade, eu tenho esse dedo! ;-) Talvez a maioria de nós peidos velhos - um hábito recuperado quando as coisas caíam o tempo todo. De qualquer forma, faço exatamente o que sugeri: edite em um buffer de arquivo visitado descartável. Se minha memória muscular hiperativa atrapalhar e tentar salvar, assim seja: ou eu bato npara não salvar ou (frequentemente) eu apenas salvo o buffer. E depois eu jogue o arquivo criado ... ou não).
de Drew
1
@ Malabarba É exatamente para evitar a confusão de arquivos temporários, que comecei a usar buffers específicos do modo principal. Se o arranhão merece um arquivo, você sempre pode salvá-lo como um posteriormente.
precisa
1
@kaushalmodi: Nada contra os buffers específicos do modo, mas um " monte de arquivos temporários " é tão facilmente limpo quanto um monte de buffers . ;-) E o dedo hiperativo em um buffer temporário específico do modo apresenta o mesmo problema, presumivelmente - o mesmo de *scratch*: você é solicitado a salvar quando esse dedo bate automaticamente C-x C-s.
Drew
9

Se estiver usando a solução de Juri Linkov há anos.

Eu crio buffers temporários com algo parecido C-x b test.org C-j. O major-modeé determinado pela extensão do arquivo via auto-mode-alist.

;; http://thread.gmane.org/gmane.emacs.devel/115520/focus=115794
(setq-default major-mode
              (lambda () (if buffer-file-name
                          (fundamental-mode)
                            (let ((buffer-file-name (buffer-name)))
                          (set-auto-mode)))))

Para testar o efeito, você pode tentar (prog1 (and (switch-to-buffer "my-new.org") major-mode) (kill-buffer "my-new.org")) => org-mode. Em uma limpeza, emacs -qo teste retornaria fundamental-mode.

rasmus
fonte
1
Isso é muito inteligente! Também é mais arrumado do que a adviceopção que eu estava usando. Não tenho certeza se estou seguindo para que (prog1...)serve a parte, mas a (setq-default major-mode ...)parte é bastante agradável.
Dan
1
Sinta-se livre para verificar o site Emacs de Juri . O prog1teste apenas mostra que você obtém o esperado major-modeao alternar para um buffer. Avalie a setq-defaultpeça e execute o teste. Voltará org-mode Sem o setq-defaultretorno fundamental-mode.
Rasmus
Isso é muito mais elegante que meu gancho de lista de atualizações de buffer. Obrigado!
glucas
esta deve ser a resposta aceita, uma vez que realmente responde à pergunta em vez de dizer-nos porque estamos errados por perguntar isso :)
Shlomi
6

Descobri uma maneira baseada em conselhos usando idéias que vieram dos comentários de @ Drew e da resposta de @ glucas, que gravarei aqui caso sejam úteis para qualquer pessoa.

A versão curta: use afterconselhos para consultar se o buffer tem um nome de arquivo associado, defina um temporariamente, se não tiver, e deixe o restante do set-auto-modemaquinário cuidar dos detalhes. Após um pouco de teste (não extenso), parece estar funcionando bem.

Para ido-switch-buffere baunilha switch-to-buffer, os dois conselhos seriam:

(defadvice ido-switch-buffer (after set-mode activate)
  (unless buffer-file-name
    (let ((buffer-file-name (buffer-name)))
      (set-auto-mode t))))

(defadvice switch-to-buffer (after set-mode activate)
  (unless buffer-file-name
    (let ((buffer-file-name (buffer-name)))
      (set-auto-mode t))))

Acho essa opção útil, além do find-fileponto em que @Drew levantou, porque meus dedos podem ficar à frente do meu cérebro: a memória muscular geralmente me leva ao território de troca para buffer antes que me ocorra completamente que find-filefaria o que eu precisava. Agora, as duas opções estão disponíveis.

UPDATE: bug pequeno, mas potencialmente irritante no código acima: ele executará novamente o gancho de modo no buffer sempre que você mudar para ele. A seguir, é fornecido um nome de arquivo real fora do /tmpdiretório e evita esse problema:

(defadvice ido-switch-buffer (after set-mode activate)
  (unless buffer-file-name
    (setq buffer-file-name (concat "/tmp/" (buffer-name)))
    (set-auto-mode t)))
Dan
fonte
Parece bom e limpa o lixo que minha resposta acumulou em algumas iterações. :-) Vou repetir aqui que, se você não quiser definir um caminho de arquivo real por algum motivo, poderá usar uma variável buffer-local para evitar definir o modo várias vezes.
glucas
5

A set-auto-modefunção define o modo com base no arquivo associado a um buffer. Aqui está uma função que define temporariamente a buffer-file-namepartir do nome do buffer para definir o modo:

(defun my/set-buffer-mode (buffer &optional again)
  "Set the mode for BUFFER from the name.  
When called repeatedly for the same buffer only set the mode the first
time, unless the optional argument AGAIN is specified.
Does nothing if the buffer is associated with a file."

  (with-current-buffer buffer
    (when again (kill-local-variable 'my/buffer-mode-set))
    (unless (or buffer-file-name 
            (local-variable-p 'my/buffer-mode-set))
      (let ((buffer-file-name (buffer-name)))
        (set-auto-mode t)
        (setq-local my/buffer-mode-set t)))))

Você pode executar isso quando um buffer for renomeado usando o conselho:

(defadvice rename-buffer (after my/rename-update-mode activate)
  (my/set-buffer-mode (current-buffer) 'again))

Não tenho certeza sobre o melhor lugar para conectar isso e afetar novos buffers. Aqui estou usando o buffer-list-update-hook, mas que é chamado em mais casos do que precisamos.

(add-hook 'buffer-list-update-hook
      '(lambda ()
         (my/set-buffer-mode (car (buffer-list)))))
glucas
fonte
A resposta acima foi revisada para lidar com alguns problemas. Em particular, voltei a usar o buffer-list-update-hookporque o change-major-mode-hooknão estava sendo chamado com o buffer atual esperado. Para o registro, provavelmente faz mais sentido aconselhar sua função switch-buffer como o @Dan faz em sua resposta.
glucas
3

Você pode usar os buffers * scratch * com a finalidade de criar buffers temporários com o mesmo modo principal que o arquivo em que você pode estar trabalhando.

Aqui está uma resposta do emacs SE que pode resolver seu problema:

Como alternar rapidamente entre um arquivo e um buffer * scratch * com o mesmo modo principal?

A pergunta e resposta referenciadas foram postadas por mim. A resposta na função faz o seguinte:

  • Se você estiver trabalhando no modo principal X em um arquivo, chamar essa função criará um novo buffer temporário chamado *scratch-X-mode*se ainda não existir, e alterna para esse buffer recém-criado.
  • Se *scratch-X-mode*já existir, ele simplesmente alterna para esse buffer.
  • Chamar essa função novamente enquanto estiver no buffer temporário o levará de volta ao buffer do arquivo em que estava trabalhando originalmente.
Kaushal Modi
fonte
0

Há algumas boas respostas aqui, mas eu queria acrescentar mais uma coisa. O Emacs tem muitos recursos e muitas vezes existem várias maneiras de fazer algo. Você pode adicionar tags na parte superior de qualquer arquivo que diga ao emacs qual o seu tipo, independentemente da extensão. Por exemplo, adicionando isso:

# -*-Python-*-

No topo de um arquivo, o emacs saberá que é um arquivo Python, mesmo sem a .pyextensão. Observe que o #início da linha é um comentário no estilo Python. Para diferentes tipos de arquivo, você pode usar comentários diferentes. Por exemplo, para especificar um arquivo Lisp que você usa ;para iniciar uma linha de comentário e definir o modo no emacs assim:

; -*- mode: Lisp;-*-

Consulte Especificando variáveis ​​de arquivo e escolhendo modos de arquivo .

jcoffland
fonte
Sim, mas a pergunta aqui é especificamente sobre a criação de um novo buffer temporário (por exemplo, com switch-buffer) e a configuração automática do modo para algo diferente de fundamental-mode.
glucas