首页 > Elisp, 中级 > 用elisp编译解释当前的buffer

用elisp编译解释当前的buffer

2010年3月5日 ahei 发表评论 阅读评论

作者: laihj

运行当前的buffer,就是说编译或解释当前的buferr。比如在编辑的是python文件”hello.py”,那么运行它的命令就是”python hello.py”,一般的python-mode用”C-c C-c”来处理这个问题,在编辑过程中可以调用这个快捷键来运行。当然你也可以使用”M-!”来打开shell command的mini buffer来输入命令。

诚然,很多语言的mode里面实际上都内置了这一功能,但我觉得,一方面不同的mode可能定义不同快捷键,造成了额外的记忆负担,另一方面并不能要求所有的mode都提供这一功能,在mode不完整的情况下你大概也需要自己定义的能力。

要做这事儿,当然是自定义一个函数。那么最直观的想法,就是在elisp里面写一行调用shell来执行命令的代码。是的,有这种东西,示例如下:

(shell-command "python hello.py")

这一行代码的相当于在终端中执行”python hello.py”。

我们的目的是执行当前buffer,所以下一步要做的是得到当前buffer所对应的文件名。在上一篇blog中介绍过相关方法,就是”buffer-file-name”。

于是代码就变成了这样。

(shell-command (concat "python " (buffer-file-name)))

用concat把”python “和当前buffer的文件名连起来作为要执行的命令。

至此,就完成了.py文件的执行函数,那推广之,需要对不同的文件进行编译/解释时,就需要扩展这个命令。

我们知道对.sh文件要用bash命令执行,对.py要用python,对.htm要调用firefox。现在要做的就是让机器知道这件事。很明显的,我们需要一个map,把它们对应地存下来。

完整的代码和注释如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(defun run-current-file ()
(interactive)
(let (ext-map file-name file-ext prog-name cmd-str
(setq ext-map
         '(
            ("py" . "python")
            ("sh" . "bash")
            ("htm" . "firefox")
            )
          );定义命令-文件类型映身表.
    (setq file-name (buffer-file-name));得到当前的buffer名
    (setq file-ext (file-name-extension file-name));得到后缀
    (setq prog-name (cdr (assoc file-ext ext-map)));根据后缀得到执行的命令,通过对ext-map的查找
    (setq cmd-str (concat prog-name " " file-name));拼出一个命令
    (shell-command cmd-str)));执行

完毕,为这个函数绑定一个键,在编辑相应文件的时候调用,就可以对其进行需要的操作了,不仅限于编译和解释,实际上很容易看出来,只要shell能支持的,你可以玩。当然,要有权限。

Have Fun!

分享家:Addthis中国
GD Star Rating
loading...
用elisp编译解释当前的buffer, 6.8 out of 10 based on 4 ratings 标签:buffer, Elisp, laihj, lisp, mode, python, 扩展, 编译, 配色

相关日志

分类: Elisp, 中级
  1. ann77
    2010年3月5日08:58 | #1

    以前和 ahei 讨论过高阶函数的东西。我重写你的例子如下

    (defvar run-current-file-alist
    ‘((“py” . “python”)
    (“sh” . “bash”)
    (“htm” . “firefox”)))
    (defun run-current-file ()
    (interactive)
    (funcall
    (\. #’shell-command
    ($ (wlflip ($ mapconcat #’identity)) ” “)
    ($ (wlflip list) buffer-file-name)
    cdr
    ($ (wlflip assoc) run-current-file-alist)
    file-name-extension
    ($ buffer-file-name)
    )))

    评论不能格式化代码,copy paste 之后 C-M-\ 吧
    关于 wlcompose.el 参考 http://www.emacswiki.org/emacs/Wang_ChunYe

    [回复]

    ahei 回复:

    @ann77, 好复杂阿,看来我要学习的东西还有很多阿

    [回复]

  2. filebat
    2010年4月3日15:24 | #2

    十分handy的功能,学习学习

    做了几个小的改进:
    - 当对于不预知的文件类型不做处理
    - 文件名的全路径中有可能有空格,使用”将文件名括起来
    - 通过cond做switch选择来简化代码

    ;; ————————– separator ————————–
    (defun run-current-file ()
    (interactive)
    (setq file_name (buffer-file-name))
    (setq file_ext (file-name-extension file_name))
    (setq prog_name
    (cond ((string= file_ext “py”) “python”)
    ((string= file_ext “sh”) “bash”)
    (t “”)))

    (unless (string= prog_name “”)
    (progn
    (setq cmd_str (format “%s ‘%s’” prog_name file_name))
    (message cmd_str)
    ;;(shell-command cmd_str)
    ))
    )

    [回复]

    ahei 回复:

    @filebat, good

    [回复]

    filebat 回复:

    @ahei, 你博文对emacs的介绍通俗易懂, 值得我们好好学习。

    [回复]

    ahei 回复:

    谢谢, 都是靠众作者的一起努力, 还要靠大家的支持.

    [回复]

    filebat 回复:

    @filebat,

    上面的代码貌似还是有些小问题

    如果打开的文件是tramp打开的,不知道全路径名是不是会带上”/root@10.32.189.13:/tmp/1.py”之类的。
    这样的话,貌似只能取短文件名才行。

    [回复]

    ahei 回复:

    @filebat, 感觉tramp操作远程文件还是有点卡的, 不如直接ssh上去用emacs, 而且即使不能ssh上去, 还不如直接down下来修改, 呵呵, 我一般都不用tramp

    [回复]

    filebat 回复:

    @ahei,
    远程ssh上的电脑一般没有我们配置好的emacs, 所以不太方便。 tramp貌似第一次比较卡,之后都还好。

    [回复]

    ahei 回复:

    @filebat, 呵呵, 我一般都把配置文件放到svn上, 直接在远程svn up就可以了.

    [回复]

    filebat 回复:

    @ahei,

    可能是我太吹毛求疵了, 关键是要登录的是客户或QA的机器。

    [回复]

    ahei 回复:

    @filebat, 哦, 那样是麻烦了点.

    [回复]

  3. xilbert
    2010年5月30日10:28 | #3

    确实是个很实用的设置,根据此修改了一下,将shell-command 修改为compile,这样当编译出问题时,就可以点击错误,跳转到发生错误的行。我将编译绑定到F5,只有按F5,就能编译c 、c++、python、perl、emacs-lisp等。
    ;;系统安装了cygwin,gcc 不能使用windows路径,要先装化为cygwin型路径。
    (defun change-to-cygwin-style-path (full-path)
    (let ((file-full-path nil) (disk nil) (left nil) (cygwin-style-file-path nil))

    (setq file-full-path full-path)
    (setq disk (substring file-full-path 0 1))
    (setq left (substring file-full-path 2 (length file-full-path)))
    (setq cygwin-style-file-path (concat “/cygdrive/” disk left))))

    (defun xilbert-compile ()
    (interactive)
    (let ((mode major-mode)
    (compstr nil))

    (cond ((eq mode ‘c-mode)
    (setq compstr (concat “gcc -std=\”c99\” ” (change-to-cygwin-style-path (buffer-file-name)))))
    ((eq mode ‘c++-mode)
    (setq compstr (concat “c++ ” (change-to-cygwin-style-path (buffer-file-name)))))
    ((eq mode ‘emacs-lisp-mode)
    (emacs-lisp-byte-compile))
    ((eq mode ‘python-mode)
    (setq compstr (concat “python ” (buffer-file-name)))
    )
    ((eq mode ‘cperl-mode)
    (setq compstr (concat “D:/Perl/bin/perl.exe ” (buffer-file-name))))
    )
    (save-buffer)
    (if compstr
    (compile compstr))))

    (global-set-key [(f5)] ‘xilbert-compile)

    初学emacs-lisp,写得不好,只是能用而已,希望高手指点!

    [回复]

    ahei 回复:

    @xilbert, 不错不错

    [回复]

    xilbert 回复:

    @ahei,
    站长好,看了你们这些作者这么用心地在写文章,我也有点想写点文章,虽然水平有限,但想到
    能让更多地人了解这么好的软件就管不了那么多了,而且通过写文章如果能让你们这些高手指点一二
    进步也会更快。不知在emacser上怎么发文章?

    [回复]

    ahei 回复:

    非常欢迎.你加我的msn/gtalk就是了,或者直接把文章发到我邮箱,我的联系方式在这里

    [回复]

    xilbert 回复:

    @ahei,
    哈哈,谢谢啦!

    [回复]

  4. onixie
    2010年8月23日08:38 | #4

    是不是还应该分析一下文件开头的#!。
    也许有些没有扩展名的文件也是可执行的脚本(例如configure)

    [回复]

  1. 本文目前尚无任何 trackbacks 和 pingbacks.
:wink: :-| :-x :twisted: :) 8-O :( :roll: :-P :oops: :-o :mrgreen: :lol: :idea: :-D :evil: :cry: 8) :arrow: :-? :?: :!: