很多时候,编译错误会以
file:line
语法显示。
直接复制粘贴以在右行打开文件就好了。
Emacs 已经有一些模式可以在缓冲区中处理这个问题(编译模式、iirc),但我希望可以从 shell 命令行获得此功能,因为我在 emacs 之外的大部分时间都使用标准 shell。
知道如何调整 emacs 来学习
file:line
语法以在 file
行打开 line
吗? (显然,如果磁盘上确实存在file:line
,最好打开它)
您可以使用 emacsclient 来完成此操作。例如在新框架中打开第 4 行第 3 列的 FILE:
emacsclient +4:3 FILE
省略
:3
即可在第 4 行打开文件。
我的
.emacs
中有以下内容,但我没有发现它像我想象的那样有用。
;; Open files and goto lines like we see from g++ etc. i.e. file:line#
;; (to-do "make `find-file-line-number' check if the file exists")
(defun find-file-noselect--advice-around-with-line-number (orig-fun filename &rest args)
(save-match-data
(let* ((matched (string-match "^\\(.*\\):\\([0-9]+\\):?$" filename))
(line-number (and matched
(match-string 2 filename)
(string-to-number (match-string 2 filename))))
(filename (if matched (match-string 1 filename) filename))
;; Call the underlying function
(buf (apply orig-fun filename args)))
(when line-number
(with-current-buffer buf
;; goto-line is for interactive use
(goto-char (point-min))
(forward-line (1- line-number))))
;; Always need to return the buffer for other things to use
buf)))
;; By advising find-file-noselect instead of find-file we also get this
;; behaviour in lots of other places, e.g. opening files from emacsclient.
(advice-add #'find-file-noselect :around #'find-file-noselect--advice-around-with-line-number)
我建议在你的 emacs 配置中添加以下代码:
(defadvice server-visit-files (before parse-numbers-in-lines (files proc &optional nowait) activate)
"looks for filenames like file:line or file:line:position and reparses name in such manner that position in file"
(ad-set-arg 0
(mapcar (lambda (fn)
(let ((name (car fn)))
(if (string-match "^\\(.*?\\):\\([0-9]+\\)\\(?::\\([0-9]+\\)\\)?$" name)
(cons
(match-string 1 name)
(cons (string-to-number (match-string 2 name))
(string-to-number (or (match-string 3 name) "")))
)
fn))) files))
)
现在您可以直接从命令行打开带有行号的文件,如下所示:
emacsclient filename:linenumber:position
附注我希望我的回答还不算太晚。
这是我的尝试。调用原始的 find-file-at-point
(defun find-file-at-point-with-line()
"if file has an attached line num goto that line, ie boom.rb:12"
(interactive)
(setq line-num 0)
(save-excursion
(search-forward-regexp "[^ ]:" (point-max) t)
(if (looking-at "[0-9]+")
(setq line-num (string-to-number (buffer-substring (match-beginning 0) (match-end 0))))))
(find-file-at-point)
(if (not (equal line-num 0))
(goto-line line-num)))
您可以使用 bash 脚本:
#! /bin/bash
file=$(awk '{sub(/:[0-9]*$/,"")}1' <<< "$1")
line=$(awk '{sub(/^.*:/,"")}1' <<< "$1")
emacs --no-splash "+$line" "$file" &
如果您为
openline
调用此脚本,并且收到错误消息,例如
Error: file.cpp:1046
你可以做
openline file.cpp:1046
打开第 1046 行
file.cpp
中的 Emacs
..
Ivan Andrus 不错的查找文件建议的另一个版本,它同时执行行号和可选列号,正如您在节点和咖啡脚本错误中看到的那样:
;; Open files and go places like we see from error messages, i e: path:line:col
;; (to-do "make `find-file-line-number' work for emacsclient as well")
;; (to-do "make `find-file-line-number' check if the file exists")
(defadvice find-file (around find-file-line-number
(path &optional wildcards)
activate)
"Turn files like file.js:14:10 into file.js and going to line 14, col 10."
(save-match-data
(let* ((match (string-match "^\\(.*?\\):\\([0-9]+\\):?\\([0-9]*\\)$" path))
(line-no (and match
(match-string 2 path)
(string-to-number (match-string 2 path))))
(col-no (and match
(match-string 3 path)
(string-to-number (match-string 3 path))))
(path (if match (match-string 1 path) path)))
ad-do-it
(when line-no
;; goto-line is for interactive use
(goto-char (point-min))
(forward-line (1- line-no))
(when (> col-no 0)
(forward-char (1- col-no)))))))
Emacs 25 不再使用
defadvice
。 参考。
所以这是更新为新语法的版本:
(defun find-file--line-number (orig-fun filename &optional wildcards)
"Turn files like file.cpp:14 into file.cpp and going to the 14-th line."
(save-match-data
(let* ((matched (string-match "^\\(.*\\):\\([0-9]+\\):?$" filename))
(line-number (and matched
(match-string 2 filename)
(string-to-number (match-string 2 filename))))
(filename (if matched (match-string 1 filename) filename)))
(apply orig-fun (list filename wildcards))
(when line-number
;; goto-line is for interactive use
(goto-char (point-min))
(forward-line (1- line-number))))))
(advice-add 'find-file :around #'find-file--line-number)
如果您从 emacs 内部调用打开文件(C-x C-f),这可以工作,但从命令行不再工作,当您从命令行调用它时,emacs 25 似乎不使用
find-file
,我不知道如何调试这种事情。
您谈论了粘贴以打开文件(我假设您的意思是在 emacs 内的查找文件提示符下)以及从命令行执行某些操作。如果您想复制和粘贴,那么您需要执行类似 Ivan 在 defadvice 中展示的操作。如果您想从命令行执行某些操作,可以执行以下操作。我根据一年前使用 emacs:// URI 处理程序(在 Firefox 中使用)所做的事情进行了改编:
将其放入您的 .emacs 文件中:
(defun emacs-uri-handler (uri)
"Handles emacs URIs in the form: emacs:///path/to/file/LINENUM"
(save-match-data
(if (string-match "emacs://\\(.*\\)/\\([0-9]+\\)$" uri)
(let ((filename (match-string 1 uri))
(linenum (match-string 2 uri)))
(while (string-match "\\(%20\\)" filename)
(setq filename (replace-match " " nil t filename 1)))
(with-current-buffer (find-file filename)
(goto-line (string-to-number linenum))))
(beep)
(message "Unable to parse the URI <%s>" uri))))
然后在您的路径中创建一个 shell 脚本(我将其称为“emacsat”):
#!/bin/bash
emacsclient --no-wait -e "(emacs-uri-handler \"emacs://$1/${2:-1}\")"
DOS 批处理脚本看起来类似,但我不知道如何设置默认值(尽管我很确定你可以做到)。
如果您也想与 Firefox 集成,请参阅如何配置 Firefox 以在某些链接上运行 emacsclientw? 以获取更多说明。
为了返回42的代码,添加了列号支持,并清理了存在列号和查找行号的情况。
;; find file at point, jump to line no.
;; ====================================
(require 'ffap)
(defun find-file-at-point-with-line (&optional filename)
"Opens file at point and moves point to line specified next to file name."
(interactive)
(let* ((filename (or filename (if current-prefix-arg (ffap-prompter) (ffap-guesser))))
(line-number
(and (or (looking-at ".* line \\(\[0-9\]+\\)")
(looking-at "[^:]*:\\(\[0-9\]+\\)"))
(string-to-number (match-string-no-properties 1))))
(column-number
(or
(and (looking-at "[^:]*:\[0-9\]+:\\(\[0-9\]+\\)")
(string-to-number (match-string-no-properties 1)))
(let 'column-number 0))))
(message "%s --> %s:%s" filename line-number column-number)
(cond ((ffap-url-p filename)
(let (current-prefix-arg)
(funcall ffap-url-fetcher filename)))
((and line-number
(file-exists-p filename))
(progn (find-file-other-window filename)
;; goto-line is for interactive use
(goto-char (point-min))
(forward-line (1- line-number))
(forward-char column-number)))
((and ffap-pass-wildcards-to-dired
ffap-dired-wildcards
(string-match ffap-dired-wildcards filename))
(funcall ffap-directory-finder filename))
((and ffap-dired-wildcards
(string-match ffap-dired-wildcards filename)
find-file-wildcards
;; Check if it's find-file that supports wildcards arg
(memq ffap-file-finder '(find-file find-alternate-file)))
(funcall ffap-file-finder (expand-file-name filename) t))
((or (not ffap-newfile-prompt)
(file-exists-p filename)
(y-or-n-p "File does not exist, create buffer? "))
(funcall ffap-file-finder
;; expand-file-name fixes "~/~/.emacs" bug sent by CHUCKR.
(expand-file-name filename)))
;; User does not want to find a non-existent file:
((signal 'file-error (list "Opening file buffer"
"no such file or directory"
filename))))))
我对
find-file-at-point
函数进行了一些重写。
如果行号匹配,文件将在另一个窗口中打开,并且课程器将放置在该行中。如果没有行号匹配,则执行 ffap 通常执行的操作...
;; find file at point, jump to line no.
;; ====================================
(require 'ffap)
(defun find-file-at-point-with-line (&optional filename)
"Opens file at point and moves point to line specified next to file name."
(interactive)
(let* ((filename (or filename (ffap-prompter)))
(line-number
(and (or (looking-at ".* line \\(\[0-9\]+\\)")
(looking-at ".*:\\(\[0-9\]+\\):"))
(string-to-number (match-string-no-properties 1)))))
(message "%s --> %s" filename line-number)
(cond ((ffap-url-p filename)
(let (current-prefix-arg)
(funcall ffap-url-fetcher filename)))
((and line-number
(file-exists-p filename))
(progn (find-file-other-window filename)
(goto-line line-number)))
((and ffap-pass-wildcards-to-dired
ffap-dired-wildcards
(string-match ffap-dired-wildcards filename))
(funcall ffap-directory-finder filename))
((and ffap-dired-wildcards
(string-match ffap-dired-wildcards filename)
find-file-wildcards
;; Check if it's find-file that supports wildcards arg
(memq ffap-file-finder '(find-file find-alternate-file)))
(funcall ffap-file-finder (expand-file-name filename) t))
((or (not ffap-newfile-prompt)
(file-exists-p filename)
(y-or-n-p "File does not exist, create buffer? "))
(funcall ffap-file-finder
;; expand-file-name fixes "~/~/.emacs" bug sent by CHUCKR.
(expand-file-name filename)))
;; User does not want to find a non-existent file:
((signal 'file-error (list "Opening file buffer"
"no such file or directory"
filename))))))
如果您有旧版本的 ffap (2008),您应该更新您的 emacs 或应用 另一个小补丁...
--- Emacs/lisp/ffap.el
+++ Emacs/lisp/ffap.el
@@ -1170,7 +1170,7 @@ which may actually result in an url rather than a filename."
;; remote, you probably already have a connection.
((and (not abs) (ffap-file-exists-string name)))
;; Try stripping off line numbers; good for compilation/grep output.
- ((and (not abs) (string-match ":[0-9]" name)
+ ((and (string-match ":[0-9]" name)
(ffap-file-exists-string (substring name 0 (match-beginning 0)))))
;; Try stripping off prominent (non-root - #) shell prompts
这是一个 zsh 函数,如果您将其放入您的
.zshrc
文件中,它就可以工作。
因为我通常在 zsh 中运行代码,这就是我看到错误的地方。感谢 @sanityinc 的 emacs 部分。只是觉得这应该在谷歌上。
emn () {
blah=$1
filen=(${(s.:.)blah})
/Applications/Emacs.app/Contents/MacOS/Emacs +$filen[2] $filen[1] &
}
像
emn /long/stack/error.rb:123
一样使用
我修改了 ivan-andrus
defadvice
,因此它可以与 emacsclient 一起使用:
(defadvice find-file-noselect (around find-file-noselect-at-line
(filename &optional nowarn rawfile wildcards)
activate)
"Turn files like file.cpp:14 into file.cpp and going to the 14-th line."
(save-match-data
(let* ((matched (string-match "^\\(.*\\):\\([0-9]+\\):?$" filename))
(line-number (and matched
(match-string 2 filename)
(string-to-number (match-string 2 filename))))
(filename (if matched (match-string 1 filename) filename))
(buffer-name ad-do-it))
(when line-number
(with-current-buffer buffer-name
(goto-char (point-min))
(forward-line (1- line-number)))))))
我经常使用这个,我用 command-line-1 制作的:
;;;; Open files and goto lines like we see from g++ etc. i.e. file:line#
(defun command-line-1--line-number (orig-fun args)
(setq new-args ())
(dolist (f args)
(setq new-args
(append new-args
(if (string-match "^\\(.*\\):\\([0-9]+\\):?$" f)
(list (concat "+" (match-string 2 f))
(match-string 1 f))
(list f)))))
(apply orig-fun (list new-args)))
(advice-add 'command-line-1 :around #'command-line-1--line-number)
失败时出现错误消息的另一种解决方案
(defun find-file-at-point-with-line ()
"Like `find-file-at-point' but use line num, if any, to go to that line
Example: boom.rb:12"
(interactive)
(let ((filename (thing-at-point 'filename))
(line nil))
(unless filename
(error "Cannot find file at point"))
;; Extract line number
(let ((line-str-pos (string-match ":\\([0-9]+\\)$" filename)))
(when line-str-pos
(setq line (string-to-number (match-string 1 filename)))
(setq filename (substring filename 0 line-str-pos))))
;; Open file and jump to line (if any)
(unless (file-exists-p filename)
(error "File does not exist: %s" filename))
(find-file filename)
(when line
(goto-line line))))