从Emacs运行交互式Python脚本

8

我是一个相当熟练的vim用户,但我的朋友们告诉我关于emacs的很多好东西,所以我决定试一试--特别是在发现了名副其实的evil模式之后......

无论如何,我目前正在编写一个需要用户输入(cmd.Cmd的子类)的python脚本。在vim中,如果我想要尝试它,我可以简单地执行:!python %,然后就可以与我的脚本交互,直到它退出。在emacs中,我尝试了M-! python script.py,它确实会在一个单独的缓冲区中运行脚本,但是RETURN键似乎没有被发送回脚本,而是被emacs缓冲区捕获了。我还试图看看python-mode的C-c C-c,但这会在一些临时目录中运行脚本,而我只想在当前目录下运行它。

那么,有没有什么权威的方法来做到这一点呢?


1
你要找的术语是“次级进程”。Python模式包括一个次级Python shell,但我对此并不熟悉。 - tripleee
6个回答

4

我不确定关于canonical的内容,但如果需要与脚本交互,我会使用M-xshellRET并在那里运行脚本。

还有M-xterminal-emulator用于更严肃的终端仿真,而不仅仅是shell操作。


这对我来说几乎可以工作,因为<RET>被发送到进程中; 然而,<TAB>仍然被emacs捕获(显然)。有没有办法让emacs也传递<TAB>呢? - antony

3

我目前使用这些钩子来定义我的编译命令:

(defun convert-filename-to-executable (file)
  (if (eq system-type 'windows-nt)
      (concat (file-name-sans-extension file) ".exe")
    ;; linux
    (concat "./" (file-name-sans-extension file))))


(add-hook 'c++-mode-hook
          (lambda ()
            (unless (file-exists-p "Makefile")
              (set (make-local-variable 'compile-command)
                   (let* ((file (file-name-nondirectory buffer-    file-name))
                      (executable (convert-filename-to-executable file)))
                 (concat "g++ -g -Wall -o "
                         (file-name-sans-extension file)
                         " "
                         file
                         " && "
                         executable))))))

(add-hook 'c-mode-hook
      (lambda ()
        (unless (file-exists-p "Makefile")
          (set (make-local-variable 'compile-command)
               (let* ((file (file-name-nondirectory buffer-file-name))
                      (executable (convert-filename-to-executable file)))
                 (concat "gcc -g -ansi -Wall -Wpedantic -Wextra -Wc++-compat -Wconversion -o "
                         (file-name-sans-extension file)
                         " "
                         file
                         " && "
                         executable))))))    
(add-hook 'python-mode-hook
          (lambda ()
              (set (make-local-variable 'compile-command)
                   (concat "python " buffer-file-name))))

(add-hook 'perl-mode-hook
          (lambda ()
              (set (make-local-variable 'compile-command)
                   (concat "python " buffer-file-name))))

与此同时,将这个lambda设置为交互调用编译函数:
(global-set-key (kbd "<f4>") (lambda () (interactive) (setq current-prefix-arg '(4)) (call-interactively 'compile)))

一键搞定!

如果你按下F4(在我的情况下,你可以在global-set-key的lambda函数中自行设置按键),那么一个以C++或C模式打开的文件将被编译,而一个以python或perl模式打开的文件将被运行(交互式地)。


1
太棒了!我正在寻找这个。谢谢。 - slk500

3
我喜欢使用Emacs的"编译"命令来测试/运行我的Python脚本。M - X - compile - RET会弹出默认的"make -k",但是如果你删除它并输入你的脚本的命令行(包括选项),随后的"编译"将自动提供新的"编译"命令。你的脚本的所有输出都将显示在编译缓冲区中。(与shell相比,每次调用时这提供一个漂亮的干净的缓冲区。对于搜索等功能很好。如果你在运行之前忘记保存你的脚本,编译将询问你是否要保存文件。)
当你重新启动Emacs时,你将失去命令行。但是,通过在Python脚本底部加入以下代码(实际上是Python注释),你可以让Emacs为包含你的脚本的缓冲区设置编译命令:
 # Trigger emacs to run this script using the "compile" command
 # ;;; Local Variables: ***
 # ;;; compile-command: "my_cool_script.py --complicated_option some_filename.txt" ***
 # ;;; end: ***

这对于具有复杂调用的脚本非常方便。 注意:Python注释字符“#”可以保护该命令免受Python解释器的影响,而Emacs则知道在打开文件时查看每个文件底部以设置这些变量。

我希望能够像编译C代码时使用编译命令一样跳转到我的Python脚本中的“编译错误”,但我太懒了,不想创建Emacs正则表达式来实现这一点。也许这将是提问stack overflow的另一个好问题!


我无法与*compilation*窗口进行交互,因为它是只读的,所以对我没有用... - antony
很棒的观点!我的脚本中很少有交互式的,所以我错过了这一点。 - user1040087
尽管这显然对提问者没有帮助,但这对我非常有用! - sage
您可以通过使用以下lambda表达式中的call-interactively使其交互式:(lambda () (interactive) (setq current-prefix-arg '(4)) (call-interactively 'compile)) - MartenBE

1

我认为ansi-term拥有最忠实的终端仿真。但是我没有找到一种传递参数给进程的方法。当然,你可以在ansi-term缓冲区内部启动它。

但我认为最好的做法是不使用python-send-buffer,而是使用一个新的函数来“正确”地发送当前文件的路径,而不是创建一个临时文件。当然,这样做会有一些细微的差别,因为你必须先保存当前文件,但以下内容至少可以让你走上正确的轨道。

(defun python-send-file ()
  (interactive)
  (save-buffer)
  (python-send-string (concat "execfile('" (buffer-file-name) "')")))

;; This overwrites the `python-send-buffer' binding so you may want to pick another key
(eval-after-load "python" 
  (define-key python-mode-map "\C-c\C-c" 'python-send-file))

我检查了一下,这可以让你进行交互。要获取选项卡,你有几个选择。

  • C-qTAB 总是会给你一个字面上的制表符
  • 你可以在 inferior-python-mode-map 中重新绑定 tab 为字面上的制表符:

    (define-key inferior-python-mode-map "\C-i" 'self-insert-command)
    
  • 我相信还有其他我想不到的方法


1
如果你使用C-c C-c,会创建一个缓冲区(查找inferior-python)。尝试切换到那个缓冲区*,每次按下C-c C-c时结果都会在那里显示,你需要查看该缓冲区以获取结果。使用C-x 2可以同时查看两个缓冲区。 还要尝试使用C-c C-z(切换到shell)。
*我使用Ibuffer来管理缓冲区,非常好用。 (顺便说一句,这个http://tuhdo.github.io/index.html是学习emacs的绝佳资源)
编辑:你尝试过C-c C-p吗?

0

另一个选项:

使用C-c C-cfgallina的python.el很好地配合使用 - pwd将是缓冲区文件的位置。


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