From: Xah Lee
Subject: Elisp Lesson: Execute/Compile Current File
Date: 
Message-ID: <1194491509.711822.42980@v23g2000prn.googlegroups.com>
Elisp Lesson: Execute/Compile Current File

Xah Lee, 2007-10-09

This page shows a example of writing a emacs lisp function that
execute or compile the file associated with the current buffer. If you
don't know elisp, first take a gander at Emacs Lisp Basics.

( a HTML version of this article with colors and links is at
 http://xahlee.org/emacs/elisp_run_current_file.html
)

---------------------------------------------
THE PROBLEM

--------------------
Summary

I want to be able to press a button, and have the current buffer's
file executed or compiled. The file may be a perl, python, bash, php
script, or java.

--------------------
Detail

I work in Perl, Python, PHP, bash a lot. For example, suppose i'm
currently editing “process_log.pl”. Once i'm done, i'd like to run
this in a command line call: “perl process_log.pl”. In emacs, to call
a shell command, press the key “Alt+!”, then type “perl
process_log.pl”. This is convenient, but if one writes a lot different
scripts in various languages, the typing gets tedious.

For example, when i program in perl, i may often create a temp file
test.pl that tests some snippet of construct or function before i
actually put it into a program i'm working on. It is common to do the
edit-then-run cycle some 5 or 10 times. Typing out “Alt+Shift+! perl
test.pl RET” tens of times is no fun. Emacs's promp provides a history
feature, so that once i've run it once, i can just press the up-arrow
to get the previous command i typed in the promp. The full keystrokes
to type now is: “Alt+Shift+! ↑ RET”. But then, sometimes while working
on a function in “test.pl”, i want to branch out into alternatives. So
i may have “test2.pl” and “test3.pl”. To execute these different
files, i'll either have to type their full commands again, or use the
up-arrow and eyeball.

It would be better, if i can just press a button such as F7, then have
emacs automatically execute the current file in shell using the proper
program (e.g. perl, python, bash, java). We proceed to write this.

---------------------------------------------
Solution

Here's the solution:

(defun run-current-file ()
  "Execute or compile the current file.
For example, if the current buffer is the file x.pl,
then it'll call “perl x.pl” in a shell.
The file can be php, perl, python, bash, java.
File suffix is used to determine what program to run."
(interactive)
  (let (ext-map file-name fext prog-name cmd-str)
; get the file name
; get the program name
; run it
    (setq ext-map
          '(
            ("php" . "php")
            ("pl" . "perl")
            ("py" . "python")
            ("sh" . "bash")
            ("java" . "javac")
            )
          )
    (setq file-name (buffer-file-name))
    (setq fext (file-name-extension file-name))
    (setq prog-name (cdr (assoc fext ext-map)))
    (setq cmd-str (concat prog-name " " file-name))
    (shell-command cmd-str)))

This is really just a simple program. The program does a very few
things. It gets the current file's name, current file's suffix, and
use the suffix to determine which shell command to run. Then, it
generate the shell command string, then run it in a shell.

First, it defines a “extmap” which is basically a list of pairs, with
first element being the file suffix and the last element being the
command line tool name. Such a list of pairs is called “association
list” in lisp. (a similar concept is hash table. But we don't need it
here since our list only have a handful of elements.)

Reference: Elisp Manual: Association-Lists.

The rest of the program is rather simple:

    * “buffer-file-name” returns the full path of the file name of the
curretn buffer.
    * “file-name-extension” returns the file extension of a given file
path/name.
    * “(concat prog-name " " file-name)” is the string we want to
execute in shell.
    * “(shell-command cmd-str)” executes our cmdstr in a shell.

Reference: Elisp Manual: Buffer-File-Name.

Reference: Elisp Manual: File-Name-Components.

Now, we can define a keyboard shortcut for this:

(global-set-key (kbd "<f7>") 'run-current-file)

So now, doesn't matter we are writting in perl, python, php, bash, or
even Java, we can just press a button and have the file executed or
compiled.

WOOT! Emacs is beautiful!

  Xah
  ···@xahlee.org
∑ http://xahlee.org/

From: namekuseijin
Subject: Re: Elisp Lesson: Execute/Compile Current File
Date: 
Message-ID: <1194498509.755394.194130@o3g2000hsb.googlegroups.com>
On 8 nov, 01:11, Xah Lee <····@xahlee.org> wrote:
> So now, doesn't matter we are writting in perl, python, php, bash, or
> even Java, we can just press a button and have the file executed or
> compiled.
>
> WOOT! Emacs is beautiful!

you know, I gave up having to deal with emacs and elisp idiosyncrasies
and maintain my own elisp extensions to emacs a long time ago.  It's
so much simpler and easier to simply call the interpreter/compiler
from the shell...

besides, I'd never want to press a button, but simply to press some
keystroke... ;)
From: Brian Palmer
Subject: Re: Elisp Lesson: Execute/Compile Current File
Date: 
Message-ID: <0wh4pfwsl02.fsf@rescomp.stanford.edu>
namekuseijin <············@gmail.com> writes:

> besides, I'd never want to press a button, but simply to press some
> keystroke... ;)

You're just using a 101-button mouse with really bad tracking.
-- 
I'm awfully glad I'm a Beta, because I don't work so hard.
From: David Rod
Subject: Re: Elisp Lesson: Execute/Compile Current File
Date: 
Message-ID: <ufxzbtbf8.fsf@tiscali.co.uk>
To Xah Lee

Thankyou for these postings.  Very useful

-- 
From: ·············@gmail.com
Subject: Re: Elisp Lesson: Execute/Compile Current File
Date: 
Message-ID: <1195072464.235103.215830@50g2000hsm.googlegroups.com>
On Nov 12, 4:13 pm, David Rod <··············@tiscali.co.uk> wrote:
> To Xah Lee
>
> Thankyou for these postings.  Very useful
>
> --

I concur.  What do you think about this form to use let* instead of
all the setq's?

(defun run-current-file ()
  "Execute or compile the current file.
For example, if the current buffer is the file x.pl,
then it'll call "perl x.pl" in a shell.
The file can be php, perl, python, bash, java.
File suffix is used to determine what program to run."
  (interactive)
  (let* ((ext-map
	  '(("php" . "php")
	    ("pl" . "perl")
	    ("py" . "python")
	    ("sh" . "bash")
	    ("java" . "javac")))
	 (file-name (buffer-file-name))
	 (fext (file-name-extension file-name))
	 (prog-name (cdr (assoc fext ext-map)))
	 (cmd-str (concat prog-name " " file-name)))
    (shell-command cmd-str)))

Mirko
From: Tim X
Subject: Re: Elisp Lesson: Execute/Compile Current File
Date: 
Message-ID: <87sl384ibf.fsf@lion.rapttech.com.au>
·············@gmail.com writes:

> On Nov 12, 4:13 pm, David Rod <··············@tiscali.co.uk> wrote:
>> To Xah Lee
>>
>> Thankyou for these postings.  Very useful
>>
>> --
>
> I concur.  What do you think about this form to use let* instead of
> all the setq's?
>

I'm a bit confused by why this is needed? Most of the emacs modes I use
seem to already have this functionality and it would seem we are
re-inventing the wheel somewhat. for example, unless its changed, jde,
cperl, ruby, python, cc-mode, auctex and probably others all have the
functionality to compile/run the program according to the mode the file is
in. Most of them also incorporate support for interactively jumping to
errors (in the case of compiling or syntax checking). 

Also, while I've never been required to do any php, does it make any sense
to call the php interpreter outside of a web server environment? (or is it
like executing perl cgi on the command line?)

Tim



> (defun run-current-file ()
>   "Execute or compile the current file.
> For example, if the current buffer is the file x.pl,
> then it'll call "perl x.pl" in a shell.
> The file can be php, perl, python, bash, java.
> File suffix is used to determine what program to run."
>   (interactive)
>   (let* ((ext-map
> 	  '(("php" . "php")
> 	    ("pl" . "perl")
> 	    ("py" . "python")
> 	    ("sh" . "bash")
> 	    ("java" . "javac")))
> 	 (file-name (buffer-file-name))
> 	 (fext (file-name-extension file-name))
> 	 (prog-name (cdr (assoc fext ext-map)))
> 	 (cmd-str (concat prog-name " " file-name)))
>     (shell-command cmd-str)))
>
> Mirko
>

-- 
tcross (at) rapttech dot com dot au
From: Raymond Wiker
Subject: Re: Elisp Lesson: Execute/Compile Current File
Date: 
Message-ID: <m2d4ucjy4u.fsf@Macintosh-2.local>
Tim X <····@nospam.dev.null> writes:

> ·············@gmail.com writes:
>
>> On Nov 12, 4:13 pm, David Rod <··············@tiscali.co.uk> wrote:
>>> To Xah Lee
>>>
>>> Thankyou for these postings.  Very useful
>>>
>>> --
>>
>> I concur.  What do you think about this form to use let* instead of
>> all the setq's?
>>
>
> I'm a bit confused by why this is needed? Most of the emacs modes I use
> seem to already have this functionality and it would seem we are
> re-inventing the wheel somewhat. for example, unless its changed, jde,
> cperl, ruby, python, cc-mode, auctex and probably others all have the
> functionality to compile/run the program according to the mode the file is
> in. Most of them also incorporate support for interactively jumping to
> errors (in the case of compiling or syntax checking). 

	Hint: Xah does not know emacs or emacs-lisp very well, so ends
up reimplementing, badly, existing functionality.
From: David Rod
Subject: Re: Elisp Lesson: Execute/Compile Current File
Date: 
Message-ID: <uk5odoylc.fsf@tiscali.co.uk>
I think it may be useful if you are reading a newsgroup and want to test a little bit of code and don't want to enter any major mode for something which is 10 lines long, and you switch between several newsgroups in a day
-- 
From: Xah Lee
Subject: Re: Elisp Lesson: Execute/Compile Current File
Date: 
Message-ID: <6f892248-5dcc-412c-8819-71a1a61884ae@s6g2000prc.googlegroups.com>
Xah wrote:
 Execute/Compile Current File
 http://xahlee.org/emacs/elisp_run_current_file.html

David Rod wrote:
<<I think it may be useful if you are reading a newsgroup and want to
test a little bit of code and don't want to enter any major mode for
something which is 10 lines long, and you switch between several
newsgroups in a day>>

As far as i know, cperl-mode, php-mode, python-mode, java-mode, do not
have a command to execute/compile the current file. The only mode i
know of that has a command to run/compile current buffer's file is
something like jde mode for java (it's default on Xemacs, which i used
some 6 years ago)

  Xah
  ···@xahlee.org
$B-t(B http://xahlee.org/