Como verificar se um buffer está visitando um arquivo?

9

Gostaria de verificar se algum buffer (digamos, atual) está visitando um arquivo ou não. Eu poderia dizer:

(if (buffer-file-name) ...)

mas parece não ser muito elegante - o que me interessa é apenas o valor booleano, não o nome real do buffer em questão. Se a buffer-file-namefunção fosse escrita no Elisp, eu poderia procurar na fonte para descobrir o que ela usa - mas está escrita em C e, embora eu possa instalar as fontes do Emacs, tenho medo de não encontrar um nome para o elisp para a função que verifica o que eu estou procurando lá de qualquer maneira.

O que eu preciso é que eu quero criar um diretório com base no nome do arquivo do buffer atual e atualmente estou fazendo mais ou menos isso:

(make-directory (if (buffer-file-name) (file-name-base) "default-dir"))

Então, qual seria a maneira idiomática do Elisp de fazer isso?

mbork
fonte
2
Não sei por que você se opõe a usá- buffer-file-namelo realmente, é a maneira certa de fazê-lo (se você realmente quer t, (and (buffer-file-name) t)mas o IMO é mais feio). Sua implementação está lendo o filenamecampo do buffer C struct, que de qualquer maneira não é acessível diretamente do Elisp. No final, é apenas um ponteiro que é nulo ou não.
Sigma
Bem, se esse é o caminho certo, tudo bem para mim. Como eu disse - eu não conhecia a implementação C, e o bom senso diz que pedir o nome do arquivo quando eu só quero saber se existe algum pode ser redundante.
mbork
E eu concordo que isso (and (buffer-file-name) t)parece estranho.
mbork
Se você não acha que isso (if (buffer-file-name) ... )é elegante, você não está codificando no elisp há muito tempo. Só fica mais feio daqui.
Nispio 8/10

Respostas:

12

Eu diria que seu uso é elisp idiomático, já que o nome do buffer é um valor booleano perfeitamente apropriado. Citando o manual :

Há um aspecto importante no teste da verdade em uma expressão if. Até agora, falamos de `true 'e' false 'como valores de predicados, como se fossem novos tipos de objetos Emacs Lisp. De fato, 'false' é apenas nosso velho amigo nil. Qualquer outra coisa - qualquer coisa - é "verdadeira".

Para aprofundar o assunto, confira o código para clone-buffer. Espero que você veja o seguinte:

(interactive
 (progn
   (if buffer-file-name
       (error "Cannot clone a file-visiting buffer"))
...

Observe que isso está testando a ligação da variável em buffer-file-namevez de chamar a função sem argumento (buffer-file-name), mas os dois sempre devem se comportar da mesma maneira.

purple_arrows
fonte
8

Você pode usar (buffer-file-name)(com argumento de buffer opcional) ou a buffer-file-namevariável buffer-local . Ambos são avaliados com o mesmo valor para um determinado buffer.

Essa é a maneira idiomática de fazer isso no Elisp, portanto, seu código está correto. Se você quisesse desesperadamente, sempre poderia fazer uma buffer-has-file-pfunção de invólucro.

phils
fonte
Obrigado. Existe alguma diferença significativa para escolher a função ou a variável?
mbork
11
Acho que não. Se você precisar indicar o argumento do buffer, (buffer-file-name BUFFER)certamente será melhor do que isso (with-current-buffer BUFFER buffer-file-name), mas, caso contrário, acho que não importa qual deles você use (e como a função está escrita em C, duvido que exista muita diferença no desempenho).
phils
3

Basta usar buffer-file-name. No Lisp, geralmente usamos um não- nilvalor para significar verdadeiro .

As únicas vezes em que você pode evitar isso são se a função for cara ou tiver efeitos colaterais indesejados.

Desenhou
fonte
Eu vejo. Eu sei que qualquer coisa que não nilseja verdadeira, só pensei em pegar o nome quando só quero saber se existe algum nome que seja "caro" - mas aparentemente não é.
mbork
1

No capítulo "Buffer List" da documentação:

A lista retornada pela lista de buffers é construída especificamente; não é uma estrutura de dados interna do Emacs e sua modificação não afeta a ordem dos buffers.

Então você tem que encontrar uma maneira de pesquisar na lista de buffers ao vivo. Aqui está um:

  (if (string-match-p (regexp-quote "My buffer name") (format "%s" (buffer-list)))
      (message "Open")
    (message "Not open"))
yPhil
fonte