在迷你缓冲区中显示当前文件的完整路径的功能

123

我需要获取正在使用emacs编辑的文件的完整路径。

  • 是否有可以实现此功能的函数?
  • 如果没有,那么获取此路径的elisp函数是什么?
  • 如何将结果(路径名)复制到剪贴板以便重用?

我正在使用Mac OS X和Aqumacs。

(setq filepath (get-fullpath-current-file)) ???
(copy-to-clipboard 'filepath) ???

新增

(defun show-file-name ()
  "在 minibuffer 中显示完整路径的文件名。"
  (interactive)
  (message (buffer-file-name))
  (kill-new (file-truename buffer-file-name))
)
(global-set-key "\C-cz" 'show-file-name)

结合我所得到的两个答案,我可以得到我想要的内容。感谢这些答案。还有一些问题。

  • (file-truename) 是用来干什么的?
  • 我能否将路径名复制到操作系统剪贴板,而不是 kill ring,以便我可以在其他应用程序中使用此信息?

2
你试过 C-x C-f 吗?它本来不是用来这个的,但它可以工作(原本是用于这个 https://www.gnu.org/software/emacs/manual/html_node/emacs/Visiting.html) - Charlie Parker
请参见 https://dev59.com/DXE95IYBdhLWcg3wMbB1。 - Alan
请参考https://stackoverflow.com/questions/2416655/file-path-to-clipboard-in-emacs,其中有关于在Emacs中复制文件路径到剪贴板的问题的讨论。 - undefined
13个回答

111

使用内置函数buffer-file-name可以获取文件的完整路径。

最好的做法是让你的emacs窗口始终显示你的系统名称和你当前正在编辑的缓冲区的完整路径:

(setq frame-title-format
      (list (format "%s %%S: %%j " (system-name))
        '(buffer-file-name "%f" (dired-directory dired-directory "%b"))))

你还可以像这样做:

(defun show-file-name ()
  "Show the full path file name in the minibuffer."
  (interactive)
  (message (buffer-file-name)))

(global-set-key [C-f1] 'show-file-name) ; Or any other key you want

11
在 Emacs 24 中,buffer-file-name 是一个变量。 - barracel
6
但也仍然是一个功能。 - phils
21
如果它是一个函数,为什么它不出现在 M-x 中? - asmeurer
9
asmeurer - 因为它不是互动式的 - Ben Fitzgerald
3
是的,完全正确。Elisp是“lisp-2”,而不是“lisp-1”,这意味着有两个独立的命名空间(变量和函数)。因此,每个符号都有一个“函数槽”和一个“值槽”,哪个槽被访问取决于上下文。实践中有许多例子(例如任何次要模式名称都将是函数和变量)。这也是为什么您需要使用funcall之类的函数来调用存储为变量foo的值的函数,因为如果您使用(foo),您将使用foo的函数槽而不是值槽。 - phils
显示剩余6条评论

85

借鉴Jérôme Radix的回答,如果你只想快速查看当前缓冲区的文件路径,可以执行M-: buffer-file-name命令。

或者在缓冲区中的任何位置键入(buffer-file-name),然后在右括号上运行C-x C-e(不仅仅在lisp-mode模式中有效)。


3
谢谢,我之前把 buffer-file-name 当成了一个函数,但是它并没有在 M-x 中出现。不过在 M-: 中作为 emacs eval 出现了,所以我可以通过那里运行这个命令。感谢您的回答 :) - PeterZD
9
是的,M-x只会运行交互式函数,而M-:可以运行任何Elisp函数。 - asmeurer
1
C-h v 并输入 buffer-file-name 可以通过选项卡完成获得变量的值和描述。 - frogcoder

45

我的技巧是使用类似于C-x C-f的方式打开文件,它将在 minibuffer 中预填充当前文件路径,按下C-g退出。比M-: buffer-file-name更快,但比其他方法难看得多。


我也这样做。虽然不是非常专业的emacs,但如果我只关心当前文件的路径,它就能发挥作用。 - andrunix
如果您打开一个文件A,然后跳转到另一个文件B,例如使用插件的某些跳转到定义功能,该方法会显示A的路径,而不是B的路径!因此,这个答案并不总是提供OP所要求的内容。 - Abhishek Anand
7
C-x C-v 不仅会显示当前路径,还会显示当前文件的名称。 - kuzzooroo
@kuzzooroo,对于不使用ido-mode的用户来说是正确的(当您使用ido-mode时,名称将显示在C-x C-f中)。 - Julien Palard

16
你想要的直接实现方法是:

The direct implementation of what you want is:

(defun copy-full-path-to-kill-ring ()
  "copy buffer's full path to kill ring"
  (interactive)
  (when buffer-file-name
    (kill-new (file-truename buffer-file-name))))

话说,我发现能够获取minibuffer中完整路径非常有用,这是我使用的方法:

(define-key minibuffer-local-completion-map "\C-r" 'resolve-sym-link)
(defun resolve-sym-link ()
  "Try to resolve symbolic links into true paths."
  (interactive)
  (beginning-of-line)
  (let* ((file (buffer-substring (point)
                                 (save-excursion (end-of-line) (point))))
         (file-dir (file-name-directory file))
         (file-true-dir (file-truename file-dir))
         (file-name (file-name-nondirectory file)))
    (delete-region (point) (save-excursion (end-of-line) (point)))
    (insert (concat file-true-dir file-name))))

然后如果我想将其复制到剪贴板中,我只需要删除该行 (C-a C-k)。但是在上述命令中,我们可以轻松地将真实名称复制到剪贴板中,只需将最后一行更改为:

(insert (kill-new (concat file-true-dir file-name)))))

新的部分是调用'kill-new函数,将字符串放入kill环中。


你能详细说明如何使用这些设置吗? "\C-r"是什么意思? - modeller
没关系,我自己想出来了。我认为当我在ido模式下指向一个文件时,按下C-r即可获取该文件的完整路径,这非常有用。确实很有用。但是我仍然不知道为什么要使用\C而不是C。 - modeller

13

不需要额外的函数,只需

M-! pwd

1
虽然这种方法可能有效,但它无法在Windows系统上运行,并且没有考虑到emacs的当前工作目录可能与当前缓冲区文件的目录不同。您可以通过使用C-x C-f访问文件,运行M-! pwd,然后运行M-x cd并选择另一个目录,最后再次运行M-! pwd来自己验证这一点。 - josaphatv

5

C-x C-b 显示缓冲区列表,对于每个缓冲区显示文件路径(如果适用)。


5

C-x C-d,也可通过M-x list-directory调用,将显示当前文件的目录,您只需要按下“Enter”键即可清除minibuffer。 可以在此处获取更多详细信息。


我最喜欢的答案,简单、快速、易懂! - ticktock

4

我已经使用以下代码很长时间了。 当我在模式行上按下中间鼠标按钮时,它将完整的文件路径复制到kill-ring。当我在模式行上按下shift-mouse-2时,它只会将缓冲区名称复制到kill-ring。

(defun copy-buffer-file-name (event &optional bufName)
  "Copy buffer file name to kill ring.
If no file is associated with buffer just get buffer name.
"
  (interactive "eP")
  (save-selected-window
    (message "bufName: %S" bufName)
    (select-window (posn-window (event-start event)))
    (let ((name (or (unless bufName (buffer-file-name)) (buffer-name))))
      (message "Saved file name \"%s\" in killring." name)
      (kill-new name)
      name)))

(define-key mode-line-buffer-identification-keymap [mode-line mouse-2] 'copy-buffer-file-name)
(define-key mode-line-buffer-identification-keymap [mode-line S-mouse-2] '(lambda (e) (interactive "e") (copy-buffer-file-name e 't)))

4

C-u C-x C-b 列出当前正在访问文件的缓冲区。


2
最简单的方法是:
(buffer-name)<(C-x)(C-e)> for the file name to appear in the echo area

(buffer-name)<(C-u)(C-x)(C-e)> would print the location <here>

借鉴 Trey Jackson 的思路,我想出了这个:

(defun buffer-kill-path ()
  "copy buffer's full path to kill ring"
  (interactive)
  (kill-new (buffer-file-name)))

你可以在 site 找到更多关于编程的信息。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接