Editing in Emacs from Terminal to GUI

Introduction

I often need to edit some text really quick while I am working in a terminal app. I tried to make the switch between iterm and gnome-terminal in favor of eshell but, it's difficult to launch services such as ssh and long run scripts.

Very often I found myself in terminal apps launching VIM to perform a very quick modification in my scripts. I felt "that must be wrong" feeling…

EDIT: The scripts below are from MJ Wall blog. Thanks to u/xiongtx from /r/emacs.d.

Workflow

After searching for a whole while I found several tips that help me to accomplish the desired workflow:

  1. Open Emacs only once
  2. Send files from terminal apps to be edit inside the Emacs GUI
  3. Open files directly in terminal apps using the same Emacs session
  4. Kill the Emacs session if you wish.

As you will see below, the scripts already starts the emacs daemon by default, however I like to have that on my init.el. Therefore, the first setting that I performed was:

(require 'server)
(add-hook 'after-init-hook (lambda ()
                             (unless (or (daemonp) (server-running-p))
                               (server-start)
                               (setq server-raise-frame t))))

Send files to Emacs GUI

#!/bin/bash

# This script starts emacs daemon if it is not running, opens whatever file
# you pass in and changes the focus to emacs.  Without any arguments, it just
# opens the current buffer or *scratch* if nothing else is open.  The following
# example will open ~/.bashrc

# ec ~/.bashrc

# You can also pass it multiple files, it will open them all.  Unbury-buffer
# will cycle through those files in order

# The compliment to the script is et, which opens emacs in the terminal
# attached to a daemon

# If you want to execute elisp, pass in -e whatever.
# You may also want to stop the output from returning to the terminal, like
# ec -e "(message \"Hello\")" > /dev/null

# emacsclient options for reference
# -a "" starts emacs daemon and reattaches
# -c creates a new frame
# -n returns control back to the terminal
# -e eval the script

# Number of current visible frames,
# Emacs daemon always has a visible frame called F1
visible_frames() {
  emacsclient -a "" -e '(length (visible-frame-list))'
}

change_focus() {
  emacsclient -n -e "(select-frame-set-input-focus (selected-frame))" > /dev/null
}

# try switching to the frame incase it is just minimized
# will start a server if not running
test "$(visible_frames)" -eq "1" && change_focus

if [ "$(visible_frames)" -lt  "2" ]; then # need to create a frame
  # -c $@ with no args just opens the scratch buffer
  emacsclient -n -c "$@" && change_focus
else # there is already a visible frame besides the daemon, so
  change_focus
  # -n $@ errors if there are no args
  test  "$#" -ne "0" && emacsclient -n "$@"
fi

Open files in Emacs terminal using the same session

#!/bin/bash

# Makes sure emacs daemon is running and opens the file in Emacs in
# the terminal.

# If you want to execute elisp, use -e whatever, like so

# et -e "(message \"Word up\")"

# You may want to redirect that to /dev/null if you don't want the
# return to printed on the terminal.  Also, just echoing a message
# may not be visible if Emacs then gives you a message about what
# to do when do with the frame

# The compliment to this script is ec

# Emacsclient option reference
# -a "" starts emacs daemon and reattaches
# -t starts in terminal, since I won't be using the gui
# can also pass in -n if you want to have the shell return right away

exec emacsclient -a "" -t "$@"

Stop Emacs Daemon

The second script is es which means "Emacs Stop".

#!/bin/bash

# simple script to shutdown the running Emacs daemon

# emacsclient options for reference
# -a Alternate editor, runs bin/false in this case
# -e eval the script

# If the server-process is bound and the server is in a good state, then kill
# the server

server_ok() {
  emacsclient -a "false" -e "(boundp 'server-process)"
}

if [ "t" == "$(server_ok)" ]; then
  echo "Shutting down Emacs server"
  # wasn't removing emacs from ALT-TAB on mac
  # emacsclient -e "(server-force-delete)"
  emacsclient -e '(kill-emacs)'
else
  echo "Emacs server not running"
fi

Conclusion

That is pretty much it. You just need to add all these three scripts to your $PATH variable and use it as you like.

One of the greatest benefits of this setup is that you will not need to wait emacs load any second after the first run.

On my work, I needed to add a subtle helper for me…

alias vim="et"
alias vi="et"
alias gvim="ec"

Check this video to see the desired behavior in action: editing in Emacs

Happy hacking folks!


Author | Wanderson Ferreira

Currently a MSc student in Universidade de São Paulo in the area of Deep Learning algorithms at the ICONE Research Group.