Come verificare se un buffer sta visitando un file?


9

Vorrei verificare se alcuni buffer (diciamo, correnti) stanno visitando un file o no. Potrei dire:

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

ma sembra non essere molto elegante - ciò che mi interessa è solo il valore booleano, non il nome effettivo del buffer in questione. Se la buffer-file-namefunzione fosse scritta in Elisp, potrei cercare nella sua fonte per scoprire cosa usa - ma è scritta in C, e mentre potrei installare le fonti di Emacs, temo di non trovare un nome elisp per la funzione che controlla comunque quello che sto cercando lì.

Quello di cui ho bisogno è che voglio creare una directory in base al nome del file del buffer corrente, e attualmente sto facendo più o meno questo:

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

Quindi, quale sarebbe il modo Elisp-idiomatico di farlo?


2
Non sono sicuro del motivo per cui ti opponi all'utilizzo buffer-file-namedavvero, è il modo giusto per farlo (se lo vuoi davvero t, fallo (and (buffer-file-name) t)ma è IMO più brutto). La sua implementazione sta leggendo il filenamecampo del buffer C struct, che non è comunque accessibile direttamente da Elisp. Alla fine, è solo un puntatore che è nullo o no.
Sigma,

Bene, se questo è il modo giusto, va bene per me. Come ho detto, non conoscevo l'implementazione in C, e il buon senso dice che chiedere il nome del file quando voglio solo sapere se ce ne sono potrebbe essere ridondante.
mbork,

E sono d'accordo che (and (buffer-file-name) t)sembra strano.
mbork,

Se non pensi che (if (buffer-file-name) ... )sia elegante, allora non hai programmato elisp per molto tempo. Diventa solo più brutto da qui.
nispio,

Risposte:


12

Direi che il tuo utilizzo è elis idiomatico, poiché il nome del buffer è un valore booleano perfettamente appropriato a sé stante. Citando dal manuale :

C'è un aspetto importante nel test di verità in un'espressione if. Finora abbiamo parlato di "vero" e "falso" come valori di predicati come se fossero nuovi tipi di oggetti Emacs Lisp. In realtà, "falso" è solo il nostro vecchio amico nil. Qualcos'altro, qualunque cosa, è "vero".

Per approfondire il punto, controlla il codice per clone-buffer. Mi aspetto che vedrai quanto segue:

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

Si noti che questo sta testando l'associazione variabile buffer-file-nameinvece di chiamare la funzione senza argomento (buffer-file-name), ma i due dovrebbero sempre comportarsi allo stesso modo.


8

È possibile utilizzare (buffer-file-name)(con argomento buffer facoltativo) o la buffer-file-namevariabile buffer-local . Entrambi valutano lo stesso valore per un determinato buffer.

Questo è il modo idiomatico per farlo in Elisp, tuttavia, quindi il tuo codice va bene. Se lo desideri disperatamente, puoi sempre fare una buffer-has-file-pfunzione wrapper.


Grazie. C'è qualche differenza significativa nella scelta della funzione o della variabile?
mbork,

1
Io non la penso così. Se hai bisogno di indicare l'argomento buffer, allora (buffer-file-name BUFFER)è sicuramente più bello di (with-current-buffer BUFFER buffer-file-name), ma per il resto non penso sia importante quale usi (e poiché la funzione è scritta in C, dubito che ci sia anche molta differenza nelle prestazioni).
phils,

3

Basta usare buffer-file-name. In Lisp usiamo spesso un non nilvalore per significare vero .

Le uniche volte che potresti voler evitare è se la funzione è costosa o ha effetti collaterali indesiderati.


Vedo. So che qualsiasi cosa non nilsia vera, ho solo pensato di afferrare il nome quando volevo solo sapere se un nome esiste è "costoso" - ma a quanto pare non lo è.
mbork,

1

Dal capitolo "Elenco buffer" della documentazione:

L'elenco restituito da buffer-list è costruito specificamente; non è una struttura di dati Emacs interna e la modifica non ha alcun effetto sull'ordine dei buffer.

Quindi devi trovare un modo per cercare nell'elenco dei buffer live. Eccone uno:

  (if (string-match-p (regexp-quote "My buffer name") (format "%s" (buffer-list)))
      (message "Open")
    (message "Not open"))
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.