Blog

Blog

Emacs Corner

Posted at 23:01 on 14 Nov 2008

I seem to be making a habit of posting random snippets of Emacs Lisp code. Well today is no exception so I've got a little function to share which helps search and replace symbols in glib-style C code. For example, if you want to rename MyCleverWidget, MY_CLEVER_WIDGET and my_clever_widget to MyDumbMess, MY_DUMB_MESS and my_dumb_mess respectively then this function can do it for you in one step. You just type in the symbol with words separated by underscores and it replaces with the right version. It asks about each match like query-replace does.

(defun renamespace-get-replacement (repl-data replace-count)
  (cond ((match-string 1)
         (car repl-data))
        ((match-string 2)
         (cadr repl-data))
        ((match-string 3)
         (caddr repl-data))))

(defun renamespace (full-symbol old-namespace new-namespace)
  "Interactively replace one glib-style symbol with another.
OLD-NAMESPACE should be a symbol with words separated by
underscores (like gtk_widget). A search will then be done for
three different variants of that symbol: gtk_widget, GTK_WIDGET
and GtkWidget. Each match will be replaced with NEW-NAMESPACE
which will be converted to the right format for that match.

If FULL-SYMBOL is non-nil (prefix arg if interactive) then the
search will be anchored to a complete symbol, otherwise it can
match part of a symbol.

The replacement is done interactively the same way
`query-replace' would."
  (interactive "P\nsOld namespace, (like gtk_widget): \nsNew namespace: ")
  (let* ((parts (split-string old-namespace "_"))
         (class (mapconcat 'capitalize parts ""))
         (const (mapconcat 'upcase parts "_"))
         (func (mapconcat 'downcase parts "_"))
         (re (concat "\\(" (regexp-quote class) "\\)"
                     "\\|\\(" (regexp-quote const) "\\)"
                     "\\|\\(" (regexp-quote func) "\\)"))
         (nparts (split-string new-namespace "_"))
         (nclass (mapconcat 'capitalize nparts ""))
         (nconst (mapconcat 'upcase nparts "_"))
         (nfunc (mapconcat 'downcase nparts "_"))
         (case-fold-search nil))
    (if full-symbol
        (setq re (concat "\\_<\\(?:" re "\\)\\_>")))
    (perform-replace re ; from-string
                     (list 'renamespace-get-replacement nclass nconst nfunc)
                     t ; query-flag
                     t ; regexp-flag
                     nil ; delimited flag
                     )))

I also made a little script to export Emacs' syntax highlighting to HTML which is how I got the purdy colours above. Maybe if I tidy that up I will blog that too.