Mon, 15 Dec 2008
If you happen to be using Windows Emacs and Cygwin Python there's an annoying interaction where “M-x run-python” hangs. The easiest way to fix it is to mount the directory where you have your emacs installation into the Cygwin file name structure. For instance, I have my emacs installation in C:\emacs\emacs-22.2, and in a cygwin shell I did mount -b ‘C:\emacs' /emacs, and now running the Cygwin python works.
The emacs function run-python adds the emacs data-directory to the PYTHONPATH in the emacs process-environment before running python; unfortunately, since this is the MS Windows emacs, its data-directory starts with a drive letter and a colon. When the Cygwin python initializes sys.path it splits PYTHONPATH at the colons, which means sys.path ends up with the drive letter as one component (usually interpreted as a relative path) and everything after the colon as another component. It that's a valid Cygwin pathname for the Emacs data directory (which is what the above mount command did), things work (accidentally).
Thu, 11 Dec 2008
It turns out that if you execute the command xterm-mouse-mode (or evaluate (xterm-mouse-mode 1) in your initialization file) when running Emacs under Screen it allows “non-modified single clicks” to work. Normal mouse functionality is still available by holding the Shift key while clicking. I use the PuTTY ssh client for remote access to various servers, and this works well Emacs in Screen under PuTTY, too.
Sat, 16 Aug 2008
Fri, 15 Aug 2008
Ok, suppose you want to evaluate a particular bit of code after emacs loads a particular emacs-lisp file, but you want to pass values of local variables into that code. The function eval-after-load makes you quote the expression and doesn't allow passing values into the expression. How about this?
(require 'cl)
(defmacro* eval-after-load* (file varlist &rest body)
"Like `eval-after-load', but bind variables according to VARLIST in
the current environment of the `eval-after-load' expression, not the
environment when BODY is evaluated. This allows easy passing of values
into BODY.
Each element of VARLIST is a symbol (which is bound to the current value
of that symbol) or a list (SYMBOL VALUEFORM) (which binds SYMBOL to the
value of VALUEFORM in the environment of the `eval-after-load' expression."
`(eval-after-load ,file
'(let ,(loop for v in varlist
collect (if (symbolp v)
`(,v ,(eval v))
`(,(car v) ,(eval (cadr v))))
into new-varlist
finally return new-varlist) ,@body)))
(put 'eval-after-load* 'lisp-indent-function
(1+ (get 'eval-after-load 'lisp-indent-function)))
Here's a contrived example which demonstrates when things happen.
(let ((f (make-temp-file "tkb-madness" nil ".el"))
(x 1))
(unwind-protect
(progn
(save-excursion
(let ((buf (find-file f)))
(insert (format "(y-or-n-p \"In the file '%s'! \")" f))
(save-buffer)
(kill-buffer buf)))
(y-or-n-p "This happens before the eval-after-load*")
(eval-after-load* f
(x
(y (y-or-n-p "This happens when the eval-after-load* is executed?"))
(z 2))
(y-or-n-p (format "x: %d y: %S z: %d" x y z))
(y-or-n-p "This happends during the delayed expressions"))
(y-or-n-p "This happens after the eval-after-load* expression")
(load f))
(when (file-exists-p f) (delete-file f))))
You should see something like:
Wrote /tmp/tkb-madness88647vuE.el This happens before the eval-after-load*(y or n) This happens when the eval-after-load* is executed?(y or n) This happens after the eval-after-load* expression(y or n) Loading /tmp/tkb-madness88647vuE.el (source)... In the file '/tmp/tkb-madness88647vuE.el'! (y or n) x: 1 y: t z: 2(y or n) This happends during the delayed expressions(y or n) Loading /tmp/tkb-madness88647vuE.el (source)...done
(y-or-n-p is used instead of message so you see each message when it happens.)
Does the eval-after-load* macro make sense?
Ever use the emacs command describe-char? It's even more fun with proper unicode lookup data!
;; First, we'll bind it to a key.
(global-set-key "\C-cD" #'describe-char)
;; Now we'll download it if necessary.
(let ((udf-url "http://www.unicode.org/Public/UNIDATA/UnicodeData.txt")
(udf-dest "~/tmp/UnicodeData.txt"))
(if (file-readable-p udf-dest)
;; Let describe-char know it exists.
(setq describe-char-unicodedata-file udf-dest)
;; It doesn't exist, and we need to download it!
(when (y-or-n-p (format "You need to download %s ! Do it? " udf-url))
;; Really weird: wget -O 'file' complains that file doesn't exist.
(let* ((cmd (format "cd ~/tmp/ && wget -O %s --progress=dot '%s'"
udf-dest udf-url))
(buf (get-buffer-create (format " *wget '%s'*" udf-url)))
(proc (start-process-shell-command "wget-unicode-Data"
buf cmd)))
(display-buffer buf)
(set-process-sentinel
proc
`(lambda (proc event)
(unless (string-match "^finished" event)
(error "unexpected status '%s' getting '%s'" ,udf-url event))
(setq describe-char-unicodedata-file ,udf-dest)
(message "Try describe-char now! ☣☥☸▧◉✘✽☮⅙▧⚅☑☢☹☺♠♥♦♣♨♻⚔")))
(message "Downloading... check describe-char later")
nil))))
Once this is run and it tells you to try describe-char you can position your cursor over one of the Unicode characters in the message (“C-h e” to display the “*Messages*” buffer) and press “C-cD” and look for the “Name:” line. You'll see something like this:
character: ♻ (299515, #o1110773, #x491fb, U+267B)
charset: mule-unicode-2500-33ff (Unicode characters of the range U+2500..U+33FF.)
code point: #x23 #x7B
syntax: w which means: word
buffer code: #x9C #xF2 #xA3 #xFB
file code: #xE2 #x99 #xBB (encoded by coding system mule-utf-8)
display: terminal code #xE2 #x99 #xBB
Unicode data:
Name: BLACK UNIVERSAL RECYCLING SYMBOL
Category: other symbol
Combining class: Spacing
Bidi category: Other Neutrals