【问题标题】:Open a file at line with "filename:line" syntax使用 "filename:line" 语法打开文件
【发布时间】:2010-06-29 10:56:40
【问题描述】:

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

如果直接复制粘贴到右边的行打开文件就好了。

Emacs 已经有一些模式可以在缓冲区中处理这个问题(编译模式、iirc),但我希望从 shell 命令行中使用它,因为我大部分时间在 emacs 之外使用标准 shell。

知道如何调整 emacs 以学习 file:line 语法以在 line 行打开 file 吗? (显然,如果file:line确实存在于磁盘上,最好打开它)

【问题讨论】:

  • 我想看看一种打开文件的方法,通过 emacs 传递 PHP 错误。看起来像这样:警告:_drupal_schema_initialize() 中为 foreach() 提供的参数无效(/srv/work.electricgroups.com/dave/projects/htdocs/includes/common.inc 的第 6866 行)。

标签: bash emacs


【解决方案1】:

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

emacsclient +4:3 FILE

去掉:3,只需在第 4 行打开文件。

【讨论】:

  • “-c”标志表示创建一个新框架;你不必为了跳线工作而指定。
  • 好点——这是个人喜好/习惯的问题。
  • 虽然这是一个有趣的事实,但当您从错误消息中剪切和粘贴文件名时,Ivan 的解决方案更实用,就像原始问题所说的那样
  • 如何打开多个文件,每个文件都有特定的行号?
  • 其实很直观:emacsclient +x file +y anotherfile ...
【解决方案2】:

我的.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))))))

【讨论】:

  • 不错!知道如何在默认打开函数中挂钩吗?
  • 我不确定你的意思。 find-file 默认的打开函数。 C-h C-k C-x C-f 显示什么?
  • "defadvice" 修改下一个名称的定义(在本例中为 find-file,默认打开函数)。所以这个(defadvice find-file ...)实际上确实修改了 find-file 以使其行为。
  • 很好,这修复了(find-file)。但是还是不行emacsclient -c -n -a "" ~/src/file.cpp:14
  • @To1ne 我认为对于命令行参数,您应该像这样添加+n 参数:emacs +11 file.cpp 而不是将:n 附加到文件名。
【解决方案3】:

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

附:我希望我的回答不会太晚。

【讨论】:

  • 找到有用的答案永远不会太晚。
  • @phils +1,忠于 xkcd 979:古人的智慧。 xkcd.com/979
【解决方案4】:

这是我的尝试。调用原来的 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)))

【讨论】:

  • 我只需将 (find-file-at-point) 更改为 (find-file (ffap-guesser))。然后你不会得到提示:)
【解决方案5】:

您可以使用 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 行打开 Emacs 中的 file.cpp..

【讨论】:

  • 谢谢!,这对我有帮助!。我使用的是稍微修改过的版本:emacs --no-splash "+$line" --file "$file"
  • 如果使用sed 而不是awk (file=$(sed 's/:[0-9]*$//' &lt;&lt;&lt; "$1"); line=$(sed 's/^.*://' &lt;&lt;&lt; "$1")),代码会简单一些。
【解决方案6】:

另一个版本的 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 时,是否有任何方法可以使命令行中的第二个和更高版本的文件生效?
【解决方案7】:

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 (C-x C-f) 内部调用打开文件,则此方法有效,但从命令行不再有效,当您从命令行调用它时,似乎 emacs 25 未使用find-file,我不知道如何调试这种东西。

【讨论】:

    【解决方案8】:

    您谈论粘贴以打开文件(我假设您的意思是在 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 集成,请参阅 How to configure firefox to run emacsclientw on certain links? 了解更多说明。

    【讨论】:

    • 我可以从中得到一些想法,是的,虽然它过于依赖 shell (我可能会编写一个脚本来处理文件:也没有语法,这是一个想法)跨度>
    【解决方案9】:

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

    【讨论】:

    • 当所有其他答案都没有时,这对我有用。
    • 在 emacs 24.5.1 上为我工作,谢谢!
    【解决方案10】:

    我稍微重写了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
    

    【讨论】:

      【解决方案11】:

      这是一个 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一样使用

      【讨论】:

        【解决方案12】:

        我已经修改了 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)))))))
        

        【讨论】:

          【解决方案13】:

          我经常使用这个,我用 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)
          

          【讨论】:

            猜你喜欢
            • 2021-11-07
            • 2021-04-09
            • 1970-01-01
            • 2010-12-17
            • 2020-12-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多