Emacs Bugfixes: Dirtrack Errors, Python Highlighting, and VC-Revert Window Clobbering

I’ve recently gotten involved in the emacs development community. I’m not a commiter or anything, but I’m working on improving Java support for cc-mode, have a lrage patch(that is unfortunately currently in limbo), and have been submitting bugfixes for problems I’ve been running into. This post describes the fixes for a few of these bugs that you can add to your emacs configuration and fix right now.

The first patch is to dirtrack. If you have a somewhat incorrectly-specified regexp for your shell, dirtrack will sometimes eat output from your shell buffer and error out. Specifically, this happens when a non-existent directory is matched. This is clearly not what you want; instead, in most cases I want dirtrack to just ignore this, not switch the buffer, and proceed as normal. The following function does this, although it still messages you about an incorrect match:

(defun dirtrack (input)
  "Determine the current directory by scanning the process output for a prompt.
The prompt to look for is the first item in `dirtrack-list'.
 
You can toggle directory tracking by using the function `dirtrack-mode'.
 
If directory tracking does not seem to be working, you can use the
function `dirtrack-debug-mode' to turn on debugging output."
  (unless (or (null dirtrack-mode)
              (eq (point) (point-min)))     ; no output?
    (let (prompt-path
          (current-dir default-directory)
          (dirtrack-regexp    (nth 0 dirtrack-list))
          (match-num	      (nth 1 dirtrack-list))
          ;; Currently unimplemented, it seems.  --Stef
          (multi-line	      (nth 2 dirtrack-list)))
      (save-excursion
        ;; No match
        (if (not (string-match dirtrack-regexp input))
            (dirtrack-debug-message
             (format "Input `%s' failed to match `dirtrack-list'" input))
          (setq prompt-path (match-string match-num input))
          ;; Empty string
          (if (not (> (length prompt-path) 0))
              (dirtrack-debug-message "Match is empty string")
            ;; Transform prompts into canonical forms
            (setq prompt-path (funcall dirtrack-directory-function
                                       prompt-path)
                  current-dir (funcall dirtrack-canonicalize-function
                                       current-dir))
            (dirtrack-debug-message
             (format "Prompt is %s\nCurrent directory is %s"
                     prompt-path current-dir))
            ;; Compare them
            (if (or (string= current-dir prompt-path)
                    (string= current-dir (abbreviate-file-name prompt-path)))
                (dirtrack-debug-message (format "Not changing directory"))
              ;; It's possible that Emacs will think the directory
              ;; won't exist (eg, rlogin buffers)
              (if (file-accessible-directory-p prompt-path)
                  ;; Change directory
                  (and (shell-process-cd prompt-path)
                       (run-hooks 'dirtrack-directory-change-hook)
                       (dirtrack-debug-message
                        (format "Changing directory to %s" prompt-path)))
                (progn (message "Directory %s does not exist" prompt-path) input)))
            )))))
  input)

Another small patch is to python.el’s syntax highlighting. In the current form, def and class are only highlighted as keywords when the function/class name is started. This is clearly wrong, and led to me spending a few minutes looking up python method declaration syntax, as it looked like ‘def’ wasn’t a keyword. To fix this, put this in your .emacs file:

 
    (,(rx symbol-start "None" symbol-end)	; see � Keywords in 2.5 manual
     . font-lock-constant-face)
    ;; Definitions
    (,(rx symbol-start (group "class") (? (1+ space) (group (1+ (or word ?_)))))
     (1 font-lock-keyword-face) (2 font-lock-type-face))
    (,(rx symbol-start (group "def") (? (1+ space) (group (1+ (or word ?_)))))
     (1 font-lock-keyword-face) (2 font-lock-function-name-face))
    ;; Top-level assignments are worth highlighting.
    (,(rx line-start (group (1+ (or word ?_))) (0+ space) "=")
     (1 font-lock-variable-name-face))
    ;; decorators
    (,(rx line-start (* (any " \t")) (group "@" (1+ (or word ?_ ?.))))
     (1 font-lock-type-face))
    ;; Built-ins.  (The next three blocks are from
    ;; `__builtin__.__dict__.keys()' in Python 2.5.1.  Now modified
    ;; for Python 2/3 compatibility.)  These patterns are debateable,
    ;; but they at least help to spot possible shadowing of builtins.
    (,(rx symbol-start (or
                        ;; exceptions
                        "ArithmeticError" "AssertionError" "AttributeError"
                        "BaseException" "DeprecationWarning" "EOFError"
                        "EnvironmentError" "Exception" "FloatingPointError"
                        "FutureWarning" "GeneratorExit" "IOError" "ImportError"
                        "ImportWarning" "IndentationError" "IndexError" "KeyError"
                        "KeyboardInterrupt" "LookupError" "MemoryError" "NameError"
                        "NotImplemented" "NotImplementedError" "OSError"
                        "OverflowError" "PendingDeprecationWarning" "ReferenceError"
                        "RuntimeError" "RuntimeWarning" "StandardError"
                        "StopIteration" "SyntaxError" "SyntaxWarning" "SystemError"
                        "SystemExit" "TabError" "TypeError" "UnboundLocalError"
                        "UnicodeDecodeError" "UnicodeEncodeError" "UnicodeError"
                        "UnicodeTranslateError" "UnicodeWarning" "UserWarning"
                        "ValueError" "Warning" "ZeroDivisionError") symbol-end)
     . font-lock-type-face)
    (,(rx (or line-start (not (any ". \t"))) (* (any " \t")) symbol-start
          (group (or
                  ;; callable built-ins, fontified when not appearing as
                  ;; object attributes
                  "abs" "all" "any" "bool"
                  "chr" "classmethod" "cmp" "compile" "complex"
                  "copyright" "credits" "delattr" "dict" "dir" "divmod"
                  "enumerate" "eval" "exit" "filter" "float"
                  "frozenset" "getattr" "globals" "hasattr" "hash" "help"
                  "hex" "id" "input" "int" "isinstance" "issubclass"
                  "iter" "len" "license" "list" "locals" "map" "max"
                  "min" "object" "oct" "open" "ord" "pow" "property" "quit"
                  "range" "repr" "reversed"
                  "round" "set" "setattr" "slice" "sorted" "staticmethod"
                  "str" "sum" "super" "tuple" "type" "vars"
                  "xrange" "zip")) symbol-end)
     (1 font-lock-builtin-face))
    (,(rx symbol-start (or
                        ;; other built-ins
                        "True" "False" "Ellipsis"
                        "_" "__debug__" "__doc__" "__import__" "__name__") symbol-end)
     . font-lock-builtin-face)))

The last small patch is a fix for vc-revert-file. Right now, if you have a split window and call vc-revert-file, your other window will be closed in the process of reverting the file. This is clearly wrong; the following function replaces vc-revert-file to leave your window configuration alone after reverting the file.

(defun vc-revert () "This asks for confirmation if the buffer contents are not identical to the working revision (except for keyword expansion)." (interactive) (save-window-excursion (let* ((vc-fileset (vc-deduce-fileset)) (files (cadr vc-fileset))) ;; If any of the files is visited by the current buffer, make ;; sure buffer is saved. If the user says `no', abort since ;; we cannot show the changes and ask for confirmation to ;; discard them. (when (or (not files) (memq (buffer-file-name) files)) (vc-buffer-sync nil)) (dolist (file files) (let ((buf (get-file-buffer file))) (when (and buf (buffer-modified-p buf)) (error "Please kill or save all modified buffers before reverting"))) (when (vc-up-to-date-p file) (unless (yes-or-no-p (format "%s seems up-to-date. Revert anyway? " file)) (error "Revert canceled")))) (when (vc-diff-internal vc-allow-async-revert vc-fileset nil nil) (unless (yes-or-no-p (format "Discard changes in %s? " (let ((str (vc-delistify files)) (nfiles (length files))) (if (< (length str) 50) str (format "%d file%s" nfiles (if (= nfiles 1) "" "s")))))) (error "Revert canceled")) (delete-windows-on "*vc-diff*") (kill-buffer "*vc-diff*")) (dolist (file files) (message "Reverting %s..." (vc-delistify files)) (vc-revert-file file) (message "Reverting %s...done" (vc-delistify files))))))

One Response to “Emacs Bugfixes: Dirtrack Errors, Python Highlighting, and VC-Revert Window Clobbering”

  1. Cool Thanks for your post. I am new at development and this will help a lot.

Leave a Reply