1

I am looking for ways to start emacs within shell-mode, and I want the client to connect to the enclosing emacs instance so I don't need to switch to the instance running the server to edit the file.

I sense it is doable because magit is already doing something like this: the commit message is edited by emacsclient, and always opened in the enclosing instance. I don't even need to start the server explicitly!

My primary usage is to do git commit from shell-mode. I can't rely on magit because I have to use some customized git version with special command. Anyway I think it would be cool thing to do.

UPDATE:

I found the magit function magit-with-emacsclient that does the trick here: https://github.com/magit/magit/blob/master/magit.el#L1979

Any help to turn the function into a shell script that can act as the default editor of git will be greatly appreciated! I will also try and post the code if I can make it work.

UPDATE 2:

Here is my solution. It requires start the server beforehand with pid in the socket name and then set your $EDITOR to be emacsclient connecting to that server.

Put this in your init.el

; start a server with a pid
(require 'server)
(defun server-start-pid ()
  (interactive)
  (when (server-running-p server-name)
    (setq server-name (format "server%s" (emacs-pid)))
    (when (server-running-p server-name)
      (server-force-delete server-name)))
  (server-start))

and run server-start-pid before you launch the editor in your shell-mode.

put this script emacsclient-pid in your PATH. It recursively find the parent process until it finds the emacs instance and invoke emacsclient on the right socket:

#! /usr/bin/python
import os, sys
import psutil

def get_pid(name):
    pid = os.getppid()
    while True:
        proc = psutil.Process(pid)
        if name in proc.name():
            break
        pid = proc.ppid()
    return pid

if __name__ == '__main__':
    pid = get_pid("emacs")
    # pass the argument to emacsclient
    args = ' '.join(sys.argv[1:])
    cmd = "emacsclient -s server{pid} {args}".format(**globals())
    print cmd
    os.system(cmd)

And put this in your .bashrc

if [[ $EMACS"x" == tx || $TERM"x" == dumbx ]]; then
    export PAGER=/bin/cat
    export EDITOR='emacsclient-pid'
else
    export PAGER=/usr/bin/less
    export EDITOR='emacs -q -nw'
fi
chtlp
  • 645
  • 1
  • 6
  • 16
  • Is your goal to have a mini-Emacs instance (emacsclient) running inside of an Emacs shell-mode buffer? – lawlist Jul 10 '14 at 19:00
  • 2
    Please clarify what you want to do. You could enter `emacsclient somefile` in `shell-mode`, but it's not clear why you would do that. You can't run `emacsclient -nw` in `shell-mode` but you can in `ansi-term`. – Dan Jul 10 '14 at 19:40
  • And why not just do `git commit ...` from `shell-mode`? Not clear why you need `emacsclient`. – Dan Jul 10 '14 at 19:47
  • FWIW, you could probably get magit to issue the correct command line for you. – phils Jul 10 '14 at 22:02
  • Hi @lawlist: yes, that's my goal. – chtlp Jul 10 '14 at 22:50
  • @Dan I can `emacsclient somefile`, but that would go to the instance running the server (I have multiple emacs instance running). running emacs in `ansi-term` seems to be painful last time I checked because you don't know what the common keyboard commands will be sent to. I need to editor complex commit messages so I can't `git commit -am ...`, is that what you are suggesting? – chtlp Jul 10 '14 at 22:51
  • @phils: Thanks for the suggestion. I found the code here: https://github.com/magit/magit/blob/master/magit.el#L1979 , but I lack the advanced emacs knowledge to wrap it into a script so I can just call it from command line and set it to be the editor that git uses. I will try later. – chtlp Jul 10 '14 at 23:04
  • Anyone emacs expert who can quickly write a shell script that I can call and set it to be the default editor of `git` – chtlp Jul 10 '14 at 23:06

1 Answers1

4

I have split the code responsible for client-server interaction into a separate library with-editor. It's part of git-modes' next branch. Magit will start using that once I merge its next branch into master. You should study that instead of the old implementation in magit itself, because it puts all things related to this in one place and because it is also improved in many ways. E.g. it also works when using tramp.

with-editors can be used by other packages besides magit. That's one of the reasons why I have split it into a separate library/package. But I have not yet implemented the parts not actually needed by magit. E.g. the functionality it provides could also be used with shell-command, see https://github.com/magit/git-modes/pull/96.

Something similar would probably work for shell-mode too. From a very quick look I think the function that would need to be advices in this case is comint-exec. I will probably not work on this soon, but eventually I will get back to this. Meanwhile have a look at that library yourself. Understanding what it does won't be easy without good knowledge of elisp and how emacs handles child processes, though. The only advice I can give you here is to also read the issues that concern with-editor in the magit/git-modes repository on github.

Ps. Translating this to a shell script won't work, because certain things have to happen in Emacs before the child process is started, like starting the server.

tarsius
  • 8,147
  • 5
  • 32
  • 46
  • Thanks for the detailed answer from the author of `magit`! I am OK with manually starting the server. Can the shell-script know the pid of the emacs instance and just connect to that server? This is not completely hassle-free, but would solve most of my issues. – chtlp Jul 14 '14 at 03:32
  • `lsof -U -a -p $(ps -p $$ -o ppid=) |awk '$1 == "Emacs" { print $8; exit; }'` on OS X 10.10 gets me the socket/server file. I plan on using that in conjunction with a test of whether `INSIDE_EMACS` is set to assign `EDITOR` appropriately. If I only set `EDITOR` when it's undefined then this should work with sub shells, otherwise `$$` won't be Emacs. Also my use case is with `ansi-term`/`multi-term`. –  May 12 '15 at 02:01