Over the years I have settled on emacs as my sole editor. I have even tried to plug it in various IDEs (such as Eclipse: without much luck, so I backed off). So the initial approach requires having it installed everywhere I log in. Cool, but it deprives me of the graphical environment because...
- X over the network is pitiably slow
- FreeNX is better, but not enough, and sometimes screws up on fonts, keyboard type, etc. Also you end up with a mess of emacsen frames, and copypasting is still not ideal.
as
/remote/server1/...
/remote/server2/...
I could then use my local emacs to edit remote files as if they were local. Not bad - and I still use this technique now and then, for different purposes - except:
- It's overkill
- You now have to remember to unmount
- You now have this wonderful opportunity of wiping out an entire server (or part thereof) by mistyping a command on your local machine (I know. It happened - shudder)
After that, I began using an emacs extension called TRAMP. It gives emacs the ability to edit remote files whose path is of the form:
//server:/my/nifty/file.txt
TRAMP does its thing by using a variety of transports, mostly ssh based. It also gives you access to countless emacs goodies, like diff'ing (via ediff) two buffers sitting on different machines, editing remote directories, remote VC (careful of C-c C-Q, though) and more. But I digress.
So this TRAMPish solution is much better except for the (not huge, really, but still) snag of having to remember to:
- Look up the path of the file (in the terminal)
- Restrain the habit of editing in the terminal window itself
- Move to my emacs window (maybe on a different desktop, hidden under a pile of junk; also, makes me pick up the mouse even if not strictly needed)
- Type again (or maybe paste) the file path, in tramp digestible format.
Because of this, and to my chagrin, I sometime ended up in - unwillingly - editing within the terminal. Would it not be supercool if I could type on the server:
server1:/# hed /my/nifty/file.txt
and have the file pop up in my local emacs window? Which brings us to my latest, greatest solution to this monumental problem of computer science.
Update: Andrew McGlashan alerted me to vim's capability of opening remote files from the CLI much like emacs does. Which means that suitably combining that and gvim's client-server capabilities, you can pull the same trick if you are a vi head. Which is good, because, as soon as I posted this, a number of dudes felt obliged to point out that vi is the editor. Which may well be the case, for them and for all I (want to) know. I will leave the development of the idea to vi users more gifted than I (not a hard feat to achieve).
(Caveat: I tried what follows with emacs 24.2.1, tramp 2.2.24-1 (which ships with emacs) on a Fedora Core 18 Linux. I suppose it may work with other combinations of versions, operating systems... even with windows, putty and some sort of ssh server on top of that. But I did not even venture to try.)
- Be sure to have the following in your local .emacs:
(server-start)
This make emacs listen to a local socket so you later on, can type
localhost:/# emacsclient file.txt
and have the (local) file pop up inside emacs. Man emacsclient explains this. - Have shared ssh keys between your desktop and your servers, and an operating ssh-agent so you don't have to type your password every time (if you don't know what I am talking about, man ssh, man ssh-agent, man ssh-add are your friends)
- Have a .ssh/config file containing stanzas like the following:
Host server1 HostName server1.foo.bar RemoteForward 8222 127.0.0.1:22 User luser
So you can typelocalhost:/ #ssh server1
and be connected to server1 as luser, passwordless, and tunneling the port 8222 (arbitrary number) on the local interface of server1 back to your sshd port on your local machine (this is quite a mouthful). - Now install the following thingy on all your servers, say in /usr/local/bin, and call it hed (don't forget to chmod 755 /usr/local/bin/hed):
#!/bin/bash PORT=8222 HOST=localhost LHOST=${HOSTNAME:-$(hostname -f) } RU=${HUSERNAME:-$USER} ver=0.1 author="Alessandro Forghieri
" usage () { name=`basename $0` echo "$name $ver $author" echo echo "Usage: $name [-p port] [-h host ] [-l lname] [-u user] [-v] file1 file2 ..." echo echo " -p port number (defaults to $PORT)" echo " -h host remote host (defaults to $HOST)" echo " -l lname name of this host " echo " (defaults to content of HOSTNAME or output or hostname -f command, currrently: $LHOST)" echo " -u user remote user " echo " (defaults to the contents of the HUSERNAME or USER environment variable, " echo " currently: $RU)" echo " file1 file2 localfiles to edit with remote editor" echo echo "See also: man boilerplate" echo } #http://stackoverflow.com/questions/3915040/bash-fish-command-to-print-absolute-path-to-a-file abspath() { curdir=$(pwd) if [[ -d "$1" ]]; then retval=$( cd "$1" ; pwd ) else retval=$( cd $( dirname "$1" ); pwd )/$(basename "$1") fi cd $curdir echo $retval } while getopts p:h:u:l:v opt ; do case "$opt" in p) PORT=$OPTARG ;; h) HOST="$OPTARG" ;; i) usage ; exit ;; v) set -x ;; ?) usage ; exit ;; esac done shift `expr $OPTIND - 1` while [[ x$1 != x ]]; do target=$(abspath $1) ssh -f -p $PORT ${RU}@${HOST} "emacsclient -n \"/${LHOST}:/${target}\"" shift # or some funky race condition screws everything up sleep 2 done -
Explanation: the script above formats a file path in a form digestible to tramp - that is/hostname:/blah/blah (I need two leading slashes within emacs, only one from a shell, I wonder why). It then sends the command emacsclient -n
, via ssh, to my local desktop, using the tunnel I just created - my machine, like 99.9% of modern enduser machines is behind a firewall with NAT o top - that explains the need of the firewall. Now emacs opens the file(s) via the regular forward ssh channel
No comments:
Post a Comment