tags:

views:

454

answers:

7

There are a bunch of applications out there that integrate Emacs with external processes. GDB is one that comes to mind. I can control GDB from emacs and then get feedback on the screen.

I'd like to do something in that direction with my application.

Here's what I want:

  • establish a connection between me and emacs. I'd probably start a new emacs process and slurp it into my GUI
  • tell emacs to display a file. (easy with emacsclient)
  • tell emacs to scroll to center on a particular line number and hilite or just move the cursor there.
    • Probably the real question is how do I send arbitrary elisp code from my external app for emacs to execute.
    • I don't speak elisp, but this would be a great excuse to learn
  • provide some clickable areas in the emacs buffer that, when triggered, will send a message back to my app.
    • Even short of clickability, a key-binding that sends the message would be a start. (but I know the clickable thing is possible, so I'm asking)

I know that this is all possible (what isn't possible in emacs?), but I just don't know where to start googling.

+1  A: 

In general, you should look around in the emacs manual.

For your third bullet, take a look at emacs' command line options. In particular, --eval and -f.

T.E.D.
A: 

to make emacs execute lisp code just create a function that is interactive and then you can call it using M-x function-name. Following is a basic function that will reopen file.

    (defun na-reopen-file ()
  "Reopen file in buffer."
  (interactive)
  (let ((p (point)))
    (progn
      (find-alternate-file buffer-file-name)
      (goto-char p) ) ) )

For interacting with your application you can run a async process and comunicate with it using a buffer. check the start-process function in the manual.

For creating click able links you can use the following functions

  (make-button beg end 'action 'nmap-clear-buffer 'follow-link t)
  ;;for color
  (put-text-property beg end 'face nmap-active-button )
Hamza Yerlikaya
for executing abritrary elisp, I meant that I want to send that code from outside of emacs. I made a small edit to the question to clarify. I will try the other part of your answer
mmccoo
+3  A: 

You want an asynchronous process that talks to Emacs. Look in the Emacs manual in the section on processes. A good place to start might be with the start-process or start-process-shell-command functions.

For example code you could look at the source for the man command distributed with emacs, or the source for vc-do-command. (To see source code, type C-h f then the function name and then click on the name of the function in the help window.)

Norman Ramsey
+5  A: 

You might want to look at Distel (an integration of Emacs with Erlang's message system) and SLIME (an interface between Emacs and Common Lisp). These are two Emacs modes that involve a quite impressive integration of another system by talking to it asynchronously. In particular, there is a paper on how Distel was implemented, along with some other good information on how it works here.

Brian Campbell
+4  A: 

It kind of depends on how you want to set things up. Definitely the portion of the manual on processes is worth reading. Reading the code for 'comint package is a good place to start.

You've listed a pretty limited set of functionality you'd like to expose, which could be solved by a direct connection. You can find helpful utility functions by looking at what is provided in 'net-utils (M-x find-library net-utils RET).

If the application you're trying to connect to has an interpreted language, I'd connect to that, as opposed to writing a custom parser on the app side.

Launching Emacs From App

Since you're launching Emacs from the app (as opposed to the other way (which might have made this job easier)), this is what I'd probably do:

  • write little perl script to open a socket and read/write to it
  • set up '(read (eval (print))) loop in the interpreter (or write a custom one) and connect it to a socket/port
  • launch Emacs with function call (--eval or --execute) specifying the socket
  • start the perl script as a subprocess and the port (see how inferior-lisp or inferior-tcl do it)

At that point, anything from Emacs could be sent to the perl subprocess ('comint-send-string), and be passed on to your REPL and have the desired effect there. Likewise, you can send commands back to emacs by just sending over strings, and have them parsed by functions you've stuck in 'comint-output-filter-functions.

You'd then write two little libraries, one in your APP interpreted language, and one in Emacs, to do whatever functionality makes sense. The emacs library should probably be packaged as a major (or minor) mode depending on what the files are like. If they're solely to be used with the app, a major mode, if they're (for example) C++ files, a minor mode would be better given that you'd probably want to leverage the c++-mode.

I'd write the little perl script in perl, as opposed to elisp, simply b/c I know how to interact with 'comint. If the little perl script could be replaced with a chunk of elisp, and still have the benefit using comint, that'd be an added bonus.

I've got pretty much the same setup for Tcl/Tk, only the connection stuff is handled by Tk's send command. It works really well.

Launching App From Emacs

Now, if you could, instead, launch the app from Emacs, the above still applies, only you can get rid of the little perl script and just interact through the 'comint interface. No sockets needed.

  • You'd still need the 'repl loop (if the app can't leave stdin/stdout tied to the interpreter
  • The libraries would remain the same

That'd be much easier, but only works if the user flow enables you to go that direction. (I've a hunch you're writing this for more than just your use.)

That being said, it might be easier to develop/test this way (launching from Emacs). You could add on the socket communication later as an enhancement. Whichever is more motivating...

Trey Jackson
A: 

I'm not sure how much it will help, but you might want to have a look at the implementation of SLIME which, while lisp oriented, has some very nice features. You can set it up to attach to a running process easily, for example. Not exactly what you want, but it's got all the pieces and is pretty slick.

simon
+3  A: 

Clickable Areas

The widget library would let you make parts of your buffer into buttons (also radio boxes, check boxes, lists), which will execute elisp when you click them. For example:

    (require 'widget)

(defun simple-widget-example ()
   (interactive)
  (switch-to-buffer "*Simple widget example*")

  (let ((inhibit-read-only t))
    (erase-buffer))

  (let ((all (overlay-lists)))
    ;; Delete all the overlays.
    (mapcar 'delete-overlay (car all))
    (mapcar 'delete-overlay (cdr all)))

  (widget-insert "Sample button\n")
  (widget-create 'push-button
      :notify (lambda (&rest ignore) 
         (message "Poop! Ha Ha!"))
      "Press Me")

  (use-local-map widget-keymap)

  (widget-setup))

See Emacs Widget Library

justinhj