在远程主机上评估Emacs Python模式中的缓冲区

5 投票
2 回答
2700 浏览
提问于 2025-04-16 08:39

我正在使用emacs23和tramp来修改远程主机上的python脚本。 我发现当我在emacs中启动python解释器时,它实际上是在远程主机上启动python。

我的问题是,当我尝试通过按C-c C-c来调用python-send-buffer时,出现了错误:

追踪信息(最近的调用在最前面): 文件 "", 第 1 行, 在 ? 导入错误:没有名为emacs的模块

追踪信息(最近的调用在最前面): 文件 "", 第 1 行, 在 ? 名称错误:'emacs'没有定义

老实说,我不太明白这里发生了什么。有没有办法让我配置emacs,以便我可以在远程主机上执行这个缓冲区的内容?

非常感谢。

编辑:我按照eichin的建议重新实现了python-send-region。请看我下面的回答。

2 个回答

3

我现在正在尝试把我未注册的问题和这个账户合并,合并后我就可以接受eichin的回答,并编辑我的帖子,把我的解决方案加进去。

我按照eichin的建议,把emacs2.py、emacs3.py和emacs.py这几个文件复制到了远程主机上,并把它们的目录添加到了tramp-remote-process-environment变量中的PYTHONPATH里。

接着,我在我的.emacs文件里重新实现了python-send-buffer这个功能。

(require 'python)

(defun python-send-region (start end)
  "Send the region to the inferior Python process."

  (interactive "r")

  (let* ((loc_name)
     (f (if (file-remote-p default-directory)
        (let* ((con (tramp-dissect-file-name default-directory)))
          (setq loc_name (tramp-make-tramp-temp-file con))
          (concat "/"
              (tramp-file-name-method con) ":"
              (tramp-file-name-user con) "@"
              (tramp-file-name-host con) ":"
              loc_name
              ))
          (setq loc_name (make-temp-file "py"))))
     (command (format "emacs.eexecfile(%S)" loc_name))
     (orig-start (copy-marker start)))
    (save-excursion
      (let ((curbuf (current-buffer))
        (tempbuf (get-buffer-create "*python_temp*")))
    (set-buffer tempbuf)
    (delete-region (point-min) (point-max))
    (insert-buffer-substring curbuf start end)
    (python-mode)
    (when (save-excursion 
        (goto-char (point-min))
        (/= 0 (current-indentation)))
      (python-shift-left (point-min) (point-max)))
    (write-region nil nil f nil 'nomsg))

    (python-send-command command)
    (with-current-buffer (process-buffer (python-proc))
      ;; Tell compile.el to redirect error locations in file `f' to
      ;; positions past marker `orig-start'.  It has to be done *after*
      ;; `python-send-command''s call to `compilation-forget-errors'.
      (compilation-fake-loc orig-start f)))
))

基本上,我是把选中的部分复制到一个新的缓冲区,调整一下缩进,然后把它写入一个临时文件,这个临时文件是用tramp-make-tramp-temp-file或者make-temp-file创建的,具体用哪个取决于访问的文件是远程的还是本地的。

我在使用tramp-handle-write-region的时候遇到了一些问题,它似乎不接受字符串作为第一个参数,所以我先在一个单独的缓冲区里完成了所有的格式调整。

如果代码还有其他问题,请告诉我,不过这是我第一次尝试elisp编程,所以请多多包涵。

2

简短回答:没有写一些缺失的elisp代码是做不到的。

详细说说:在 python.el 文件中,run-python 会把 data-directory(在我的Ubuntu 10.10系统上是 /usr/share/emacs/23.1/etc/)添加到 $PYTHONPATH 中,这样它就能找到 emacs.py(这是本地emacs版本提供的)。然后它会执行 (python-send-string "import emacs"),希望能正常工作……

看起来 tramp 使用的 defadvice 包装器实际上并没有传递 PYTHONPATH,所以即使你在远程系统上有匹配的emacs版本,这也不起作用。

如果你输入 M-x customize-variable RET tramp-remote-process-environment RET,然后点击其中一个 INS 按钮,添加 PYTHONPATH=/usr/share/emacs/23.1/etc,再点击 STATE 并设置为“当前会话”(只是为了测试,或者如果对你有效就选择“保存为未来会话”),那么它就 差不多 能工作了——抱怨消失了,因为远程的python现在可以找到远程的 emacs.py。如果你现在回到最初的问题,使用 python-send-buffer,你会遇到另一个错误:No such file or directory: '/tmp/py24574XdA',因为 python-mode 会把内容放到一个临时文件中,然后告诉python子进程去加载这个文件。

你需要修改 python-send-region(其他函数会调用它),特别是它使用 make-temp-file 的方式,让它能识别tramp——实际上还有一个 tramp-make-tramp-temp-file,你可以在这个基础上进行修改。(如果你做到了,请务必分享一下……)

撰写回答