7

my usecase

I'm currently running GNU Emacs version=24.3.1 graphically (i.e., under GNOME/X though started from a script invoked from a gnome-terminal running bash) on a Debian Linux. Just now I was using commandline abcde to rip audio CDs when its terminal suddenly opened an instance of The Editor Which Must Not Be Named (to resolve an MP3 tagging question). I realized that, when I setup the box I'm currently using, I failed to set either of the bash environment variables EDITOR or VISUAL in my .bashrc.

what I want

I nearly always have an graphical/X instance of Emacs running. If I'm not running Emacs, I probably have a good reason not to (e.g., a problem with my config files, or that I'm running in a tty). So I'm wondering, how to set EDITOR or VISUAL so that an application that wants to open an editor does one of the following, in descending order of preference:

  1. If I already have an instance of Emacs running (i.e., pgrep -l emacs | wc -l -> 1): open the thing to be edited in a new buffer in the running Emacs.
  2. If I do not have an instance of Emacs running (i.e., pgrep -l emacs | wc -l -> 0): start a new instance of emacs -nw -q in the terminal.

If I can't get both those preferences, or if there's a reason why I should deprecate one or both, feel free to recommend Something Completely Different.

solution

emacsclient is finicky about its arguments (TODO: put a bug on it!), but that can be worked-around:

  1. Per Francesco's suggestion I made ~/bin/emacs-nw-q.sh (and of course set mode=executable)

    ### Purely for use with `emacsclient`: see https://emacs.stackexchange.com/a/8089/5444
    emacs -nw -q $@
    
  2. Added a stanza to the end of my .bashrc:

    if [[ -z "${EDITOR}" ]] ; then
      export ALTERNATE_EDITOR="${HOME}/bin/emacs-nw-q.sh"
      export EDITOR='emacsclient'
    fi
    if [[ -n "${EDITOR}" && -z "${VISUAL}" ]] ; then
      export VISUAL="${EDITOR}"
    fi
    

With this, and

  • a running "emacs+server" (i.e., a previously-running graphical Emacs, in which I have done M-x server-start): an edit-seeking application successfully opens a buffer in the running emacs on the desired file, and killing that buffer unpauses the edit-seeking application.
  • no running emacs+server: an edit-seeking application opens a "bare-bones" Emacs in its same terminal, as desired, with a buffer open to the desired file, and killing that buffer returns control to the edit-seeking application.

how I failed

I'm putting a stanza at the end of my .bashrc: each of the stanzas I've tried is listed below, with the resulting error. To test each stanza, after I [edit, save] .bashrc (via emacs -nw -q ~/.bashrc in a separate gnome-terminal tab), I open a fresh gnome-terminal tab to exercise it.

  1. With a running emacs (and after M-x server-start), following fails with emacsclient: unrecognized option '-''

    if [[ -z "${EDITOR}" ]] ; then
      export EDITOR="emacsclient --alternate-editor='emacs -nw -q'"
    fi
    if [[ -n "${EDITOR}" && -z "${VISUAL}" ]] ; then
      export VISUAL="${EDITOR}"
    fi
    
  2. With a running emacs+server, following fails with emacsclient: unrecognized option '-"'

    if [[ -z "${EDITOR}" ]] ; then
      export EDITOR='emacsclient --alternate-editor="emacs -nw -q"'
    fi
    if [[ -n "${EDITOR}" && -z "${VISUAL}" ]] ; then
      export VISUAL="${EDITOR}"
    fi
    
  3. With no running emacs, following fails with emacsclient: error executing alternate editor ""emacs"". So I guess --alternate-editor just won't take a quoted argument?

    if [[ -z "${EDITOR}" ]] ; then
      export EDITOR='emacsclient --alternate-editor="emacs"'
    fi
    if [[ -n "${EDITOR}" && -z "${VISUAL}" ]] ; then
      export VISUAL="${EDITOR}"
    fi
    
  4. With no running emacs, following starts a brand-new graphical emacs with everything (including full desktop, which I don't want for this usecase) ... but it gets worse: after I save and kill the buffer opened by the caller app, that caller app just sits there!

    if [[ -z "${EDITOR}" ]] ; then
      export EDITOR='emacsclient --alternate-editor=emacs'
    fi
    if [[ -n "${EDITOR}" && -z "${VISUAL}" ]] ; then
      export VISUAL="${EDITOR}"
    fi
    
  5. With no running emacs, following fails with emacsclient: error executing alternate editor """"

    if [[ -z "${EDITOR}" ]] ; then
      export EDITOR='emacsclient --alternate-editor=""' # sorta suggested by erikstokes at above link
    fi
    if [[ -n "${EDITOR}" && -z "${VISUAL}" ]] ; then
      export VISUAL="${EDITOR}"
    fi
    
  6. With no running emacs, following fails with emacsclient: error executing alternate editor """" (i.e., same as previous)

    if [[ -z "${EDITOR}" ]] ; then
      export EDITOR='emacsclient -a""'
    fi
    if [[ -n "${EDITOR}" && -z "${VISUAL}" ]] ; then
      export VISUAL="${EDITOR}"
    fi
    
  7. With no running emacs, following fails with emacsclient: error executing alternate editor "''"

    if [[ -z "${EDITOR}" ]] ; then
      export EDITOR="emacsclient -a''"
    fi
    if [[ -n "${EDITOR}" && -z "${VISUAL}" ]] ; then
      export VISUAL="${EDITOR}"
    fi
    
  8. With no running emacs, following

    if [[ -z "${EDITOR}" ]] ; then
      export EDITOR='emacsclient'
    fi
    if [[ -n "${EDITOR}" && -z "${VISUAL}" ]] ; then
      export VISUAL="${EDITOR}"
    fi
    

    fails with

    emacsclient: No socket or alternate editor.  Please use:
    --socket-name
    --server-file      (or environment variable EMACS_SERVER_FILE)
    --alternate-editor (or environment variable ALTERNATE_EDITOR)
    
  9. With no running emacs, following fails with emacsclient: error executing alternate editor "emacs -nw -q"

    if [[ -z "${EDITOR}" ]] ; then
      export ALTERNATE_EDITOR='emacs -nw -q'
      export EDITOR='emacsclient'
    fi
    if [[ -n "${EDITOR}" && -z "${VISUAL}" ]] ; then
      export VISUAL="${EDITOR}"
    fi
    
  10. Per Francesco's suggestion I made ~/bin/emacs-nw-q.sh

    ### Purely for use with `emacsclient`: see https://emacs.stackexchange.com/a/8089/5444
    emacs -nw -q
    

    and changed my .bashrc stanza to

    if [[ -z "${EDITOR}" ]] ; then
      export ALTERNATE_EDITOR="${HOME}/bin/emacs-nw-q.sh"
      export EDITOR='emacsclient'
    fi
    if [[ -n "${EDITOR}" && -z "${VISUAL}" ]] ; then
      export VISUAL="${EDITOR}"
    fi
    

    Good news: with running emacs (and after M-x server-start), an edit-seeking application successfully opens a buffer in the running emacs on the desired file, and killing that buffer returns control to the edit-seeking application.

    More good news: with no running emacs+server, the edit-seeking application opens a "bare-bones" Emacs in its same terminal, as desired.

    Bad news: with no running emacs+server, the "bare-bones" Emacs does not open the needed file in a buffer. It does create the following buffers: *GNU Emacs*, *Messages*, *scratch* ... but not the needed buffer.

2 Answers 2

6

Although it is not clearly documented in its man page, emacsclient doesn't seem to accept a full command (i.e. program + arguments) as the alternate editor, only a program.

You could write a small shell script:

#!/bin/bash
exec emacs -q -nw "$@"

and use it as the alternate editor:

export EDITOR='emacsclient -a PATH_TO_YOUR_SCRIPT'
3
  • This is very close to what I want! See item#=10 above. What am I missing?
    – TomRoche
    Commented Feb 9, 2015 at 19:55
  • Sorry, I forgot to add a "$@" in the script to forward command line arguments to emacs. See my edit; it should work as expected now. Commented Feb 9, 2015 at 20:05
  • This is the right solution (works well on Linux and macOS, with both git and sudo -e), but on MSYS2 (Windows): emacsclient seems to open the alternate editor and quit immediately, instead of waiting for the process to exit. So applications that refer to $EDITOR (like Git) return immediately complaining about an empty file. Tried on Emacs version 26.1.
    – legends2k
    Commented Dec 31, 2019 at 11:28
3

emacsclient has a -a option which lets you specify an alternate editor to use if there is not an emacs process with a running server.

So emacsclient -a emacs may do what you want.

The alternate editor can also be specified to emacsclient via the ALTERNATE_EDITOR environment variable.

As for which of EDITOR or VISUAL to set: EDITOR was traditionally used for line oriented editors such as ed or ex while VISUAL was for screen oriented editors such as emacs or vi. Thus you probably do not have to set EDITOR. I would however suggest setting both as a "belt-and-suspenders" measure as which variable is used is up to the program that is launching your editor, check with its documentation to find out which it would use.

7
  • so set that in both EDITOR and VISUAL?
    – TomRoche
    Commented Feb 9, 2015 at 2:13
  • I would suggest doing so. VISUAL is intended to be used for "full screen" applications such as emacs and vi while EDITOR was intended for editors such as ed or ex. Thus some suggest that leaving EDITOR unset is fine. However it is at the discretion of the program that wants to launch your editor what environment variables it may or may not check for your preferences. By setting both you are covered on most of the cases.
    – verdammelt
    Commented Feb 9, 2015 at 2:50
  • You can also use emacsclient -a"" to start a new daemon (if one doesn't already exist) and connect to that.
    – erikstokes
    Commented Feb 9, 2015 at 3:02
  • @erikstokes: would a new daemon start in the current terminal (i.e., emacs -nw) or graphically?
    – TomRoche
    Commented Feb 9, 2015 at 3:29
  • The daemon runs in the background as a child of the current terminal. Once the daemon is started you can open a file in an existing frame (emacsclient file), make a new graphical frame (emacsclient -c file) or a new frame in the terminal (emacsclient -nw file). If no frame exists and you don't give any other options you get a graphical frame if possible and a terminal otherwise.
    – erikstokes
    Commented Feb 9, 2015 at 3:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.