How to run NTEmacs and Cygwin Emacs on the same box

I've decided to switch to Cygwin Emacs from NTEmacs lately. As I had previously seen that the Cygwin X server may refuse to work at times, I wasn't ready to deinstall NTEmacs altogether (the X problems were certainly caused by my lack of understanding, or lack of maintenance, or both. Cygwin X in general is said to run smoothly). I rather figured it should be possible to run both Emacsen in parallel, without duplicating all efforts which go into maintaining your hand-crafted .emacs file. So I tried to come up with a way to share my existing .emacs with both versions. The major problem is that NTEmacs requires quite a lot of tweaks to make it cooperate with Cygwin bash, which is a far superior shell compared to Windows "cmd", whereas Cygwin Emacs requires at least as many tweaks to make it cooperate with native Windows tools like web browser or proprietary Windows programs. This is how I solved the problem.

The first question is how to reliably tell apart which version of Emacs is trying to load our .emacs. I settled for checking the value of "window-system". This is "w32" for NTEmacs, whereas it is nil for Cygwin Emacs running in a console window and "x" for the same program running as a GUI app under X. Therefore you get away with checking for "w32" to handle NTEmacs in the if body and to handle Cygwin Emacs in the else body.

I have maintained an "emacsen" directory for lisp code outside of my NTEmacs installation directory. This considerably simplifies upgrading, and it also comes in handy if you want to run two different versions of Emacs. The following (simplified) example code includes some of these lisp directories into the load path, taking care of the different path notations of NTEmacs and Cygwin Emacs:

(if (equal window-system 'w32)
(setq load-path
(nconc load-path (list "C:/Programme/emacsen/site-lisp"
"C:/Programme/emacsen/site-lisp/planner-latest"
"C:/Programme/emacsen/site-lisp/muse-latest/lisp"
)))
(setq load-path
(nconc load-path (list "/cygdrive/c/Programme/emacsen/site-lisp"
"/cygdrive/c/Programme/emacsen/site-lisp/planner-latest"
"/cygdrive/c/Programme/emacsen/site-lisp/muse-latest/lisp"
))))

Similar checks are required whenever paths are part of the code.

The next problem is to improve browse-url support for local files on Cygwin Emacs. My planner-mode based project management makes extensive use of links to local OpenOffice, SigmaPlot, SigmaStat, or Acrobat files. This is extremely convenient as your data or graphs or statistics are just a mouseclick away while you read the experimental protocol. This worked out of the box on NTEmacs. Cygwin Emacs requires a replacement for w32-shell-execute, which I borrowed from Ken Brown, and another helper function for browse-url:

(if (not (equal window-system 'w32))
(progn
;; Minimal replacement for w32-shell-execute under Cygwin.
(defun w32-shell-execute (operation document &optional parameters show-flag)
(if (string-equal operation "open")
(shell-command (concat "cygstart " (shell-quote-argument document)))))

;; This is a helper to open arbitrary files specified by a file:// kind of URL via browse-url in their default Win32 app
(defun w32-display-file (document)
(w32-shell-execute "open" document))
))

Now we need to customize (Options->Customize Emacs) browse-url. The variable "muse-url-protocols" should use our function "w32-display-file" whenever browse-url is called with an URL containing the "file://" protocol. The URL is essentially handed to the cygstart utility by our custom functions. cygstart uses conventional Windows magic to open files with their associated application.

One problem remains to be solved: If customizations involve paths, we need to use separate "custom-set-variables" blocks for NTEmacs and Cygwin Emacs.
;; save customizations into separate files depending on the Emacs version we're running. The custom file needs to be loaded manually
(if (equal window-system 'w32)
(setq custom-file "~/.emacs-nt-custom.el")
(setq custom-file "~/.emacs-cygwin-custom.el"))

(load custom-file)

This is all it takes to run both flavours of Emacs on Windows (and it could certainly be extended to cover XEmacs as well).

Kommentare

mhoenicka meint:

I've had to upgrade my work box to Windows 7 lately. This time I set up Cygwin to mount a folder of my roaming directory as /home/[username], exposing a flaw in the code presented above. As M$ figured it'd be a nice idea to include spaces in folder names, the URLs in muse files will no longer be recognized in full length - unless you properly encode them. Use either a "+" or a "%20" to encode spaces in an URL. As the cygstart utility which ultimately has to deal with the URL can't seem to handle encoded URLs directly, we need to add some code to decode the spaces again. This is my current version of the w32-shell-execute function introduced above:

(defun w32-shell-execute (operation document &optional parameters show-flag)
(if (string-equal operation "open")
(shell-command (concat "cygstart " (shell-quote-argument (url-unhex-string document))))))
Dienstag 25 März 15:28

min meint:

hello
i am nomal user ,nowaday i run emacs
i have problem emacs + cygwin
i want firefox open buffer file
.)buffer file dir: d:/documents/test.html | work good
.)buffer file dir: d:/documents/my notes/test.html | not work

firefox error browser address
file:///:/Documents/My/

i think bash is missing dir path " "
here my dotemacs

;; open in browser(Firefox)
(defun open-in-browser()
"open buffer in browser, unless it is not a file. Then fail silently (ouch)."
(interactive)
(if (buffer-file-name)
(let ((filename (buffer-file-name)))
(shell-command (concat "cygstart d:/program/waterfox/core/waterfox \"file://" filename "\"")))))
(global-set-key (kbd "C-c C-o") 'open-in-browser)

i changed to
(shell-command (concat...filename
filename to this > (shell-quote-argument filename)
but not work
how i fix it help me :D
Dienstag 30 September 09:32

Mein Kommentar

Dieser Artikel ist geschlossen. Keine Kommentare mehr möglich.