使用“filename:line”语法打开一个文件

时间:2010-06-29 10:56:41

标签: bash emacs

通常,编译错误会以file:line语法显示。

将它直接复制粘贴以打开右侧的文件会很不错。

Emacs已经有一些模式可以在缓冲区(compile-mode,iirc)中处理这个问题,但是我想从shell命令行中获取它,因为我在emacs之外的大部分时间都使用标准shell。 / p>

知道如何调整emacs以了解file:line语法,以便在file行打开line吗? (显然,如果file:line确实存在于磁盘上,则应该优先打开它)

13 个答案:

答案 0 :(得分:42)

您可以使用emacsclient执行此操作。例如在第4行第3列打开FILE:

emacsclient +4:3 FILE

取消:3只需在第4行打开文件。

答案 1 :(得分:15)

我的.emacs中有以下内容,但我发现它并没有像我想象的那样有用。

;; Open files and goto lines like we see from g++ etc. i.e. file:line#
;; (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
                             (filename &optional 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)))
      ad-do-it
      (when line-number
        ;; goto-line is for interactive use
        (goto-char (point-min))
        (forward-line (1- line-number))))))

答案 2 :(得分:9)

这是我的理由。调用原始的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)))

答案 3 :(得分:8)

您可以使用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 ..

答案 4 :(得分:8)

我建议在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

P.S。我希望我的回答不会太迟。

答案 5 :(得分:7)

另一个版本的Ivan Andrus'很好的查找文件建议,可以同时执行行+可选列号,正如您在节点和coffeescript错误中看到的那样:

;; 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)))))))

答案 6 :(得分:5)

Emacs 25不再使用defadviceRefs

所以这里是更新为新语法的版本:

(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(Cx Cf)内部调用打开文件,但是从命令行不再工作,这是有效的,当你从命令行调用它时,似乎emacs 25没有使用find-file而且我没有&# 39;我知道如何调试这种事情。

答案 7 :(得分:3)

您谈到粘贴打开文件(我假设您的意思是在emacs内的查找文件提示符下)并且还从命令行执行某些操作。如果你想复制&amp;粘贴,然后你需要做一些像伊万与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集成,请参阅How to configure firefox to run emacsclientw on certain links?以获取更多说明。

答案 8 :(得分:1)

我稍微重写了find-file-at-point函数。

如果行号匹配,则该文件将在另一个窗口中打开,并且courser将被放置在该行中。如果没有行号匹配,请执行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

答案 9 :(得分:1)

要返回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))))))

答案 10 :(得分:1)

如果将zsh函数放入.zshrc文件中,则可以使用zsh函数。

由于我通常在zsh中运行我的代码,这就是我看到错误的地方。感谢@sanityinc的emacs部分。只是认为这应该在google上。


emn () {
blah=$1
filen=(${(s.:.)blah})
/Applications/Emacs.app/Contents/MacOS/Emacs +$filen[2] $filen[1] &
}

emn /long/stack/error.rb:123

一样使用

答案 11 :(得分:1)

我修改了ivan-andrus package org.wso2.carbon.um.ws.service; import java.net.MalformedURLException; import java.net.URL; import javax.xml.namespace.QName; import javax.xml.ws.Service; import javax.xml.ws.WebEndpoint; import javax.xml.ws.WebServiceClient; import javax.xml.ws.WebServiceException; import javax.xml.ws.WebServiceFeature; /** * This class was generated by the JAX-WS RI. * JAX-WS RI 2.2.9-b130926.1035 * Generated source version: 2.2 * */ @WebServiceClient(name = "RemoteUserStoreManagerService", targetNamespace = "http://service.ws.um.carbon.wso2.org", wsdlLocation = "https://svn.wso2.org/repos/wso2/people/asela/user-mgt/jaxws/RemoteUserStoreManagerService.wsdl") public class RemoteUserStoreManagerService extends Service { private final static URL REMOTEUSERSTOREMANAGERSERVICE_WSDL_LOCATION; private final static WebServiceException REMOTEUSERSTOREMANAGERSERVICE_EXCEPTION; private final static QName REMOTEUSERSTOREMANAGERSERVICE_QNAME = new QName("http://service.ws.um.carbon.wso2.org", "RemoteUserStoreManagerService"); static { URL url = null; WebServiceException e = null; try { url = new URL("https://svn.wso2.org/repos/wso2/people/asela/user-mgt/jaxws/RemoteUserStoreManagerService.wsdl"); } catch (MalformedURLException ex) { e = new WebServiceException(ex); } REMOTEUSERSTOREMANAGERSERVICE_WSDL_LOCATION = url; REMOTEUSERSTOREMANAGERSERVICE_EXCEPTION = e; } public RemoteUserStoreManagerService() { super(__getWsdlLocation(), REMOTEUSERSTOREMANAGERSERVICE_QNAME); } public RemoteUserStoreManagerService(WebServiceFeature... features) { super(__getWsdlLocation(), REMOTEUSERSTOREMANAGERSERVICE_QNAME, features); } public RemoteUserStoreManagerService(URL wsdlLocation) { super(wsdlLocation, REMOTEUSERSTOREMANAGERSERVICE_QNAME); } public RemoteUserStoreManagerService(URL wsdlLocation, WebServiceFeature... features) { super(wsdlLocation, REMOTEUSERSTOREMANAGERSERVICE_QNAME, features); } public RemoteUserStoreManagerService(URL wsdlLocation, QName serviceName) { super(wsdlLocation, serviceName); } public RemoteUserStoreManagerService(URL wsdlLocation, QName serviceName, WebServiceFeature... features) { super(wsdlLocation, serviceName, features); } /** * * @return * returns RemoteUserStoreManagerServicePortType */ @WebEndpoint(name = "RemoteUserStoreManagerServiceHttpSoap11Endpoint") public RemoteUserStoreManagerServicePortType getRemoteUserStoreManagerServiceHttpSoap11Endpoint() { return super.getPort(new QName("http://service.ws.um.carbon.wso2.org", "RemoteUserStoreManagerServiceHttpsSoap11Endpoint"), RemoteUserStoreManagerServicePortType.class); } /** * * @param features * A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy. Supported features not in the <code>features</code> parameter will have their default values. * @return * returns RemoteUserStoreManagerServicePortType */ @WebEndpoint(name = "RemoteUserStoreManagerServiceHttpSoap11Endpoint") public RemoteUserStoreManagerServicePortType getRemoteUserStoreManagerServiceHttpSoap11Endpoint(WebServiceFeature... features) { return super.getPort(new QName("http://service.ws.um.carbon.wso2.org", "RemoteUserStoreManagerServiceHttpSoap11Endpoint"), RemoteUserStoreManagerServicePortType.class, features); } private static URL __getWsdlLocation() { if (REMOTEUSERSTOREMANAGERSERVICE_EXCEPTION!= null) { throw REMOTEUSERSTOREMANAGERSERVICE_EXCEPTION; } return REMOTEUSERSTOREMANAGERSERVICE_WSDL_LOCATION; } } ,因此它适用于emacsclient:

defadvice

答案 12 :(得分:0)

我经常使用它,我是用命令行 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)