tags:

views:

152

answers:

2

I'm trying to write simple Emacs function to convert ids between C style ones and camelCase ones (i.e. c_style <-> cStyle). But for some reason, Emacs built in downcase function leaves the word intact. M-x downcase-word works fine so I completely lost. Any ideas are welcome.

(defun toggle-id-style ()
  "Toggle between C-style ids and camel Case ones (i.e. c_style_id -> cStyleId and  back)."
  (interactive)
    (save-excursion
      (progn
        (re-search-forward "[^A-Za-z0-9_]" nil t)
          (let ((end (point))
         (case-fold-search nil))
            (progn
              (re-search-backward "[^A-Za-z0-9_]" nil t)
              (let* ((cstyle (if (string-match "_" (buffer-substring-no-properties (point) end)) t nil))
                     (regexp (if cstyle "_\\(\\w+\\)" "\\([A-Z][a-z0-9]+\\)") )
                     (func (if cstyle 'capitalize (lambda (s) (concat "_" (downcase s) ) ))))
             (progn
                   (while (re-search-forward regexp end t)
                     (replace-match (funcall func (match-string 1)) nil nil)))))))))

;;M-x replace-regexp _\(\w+\) -> \,(capitalize \1) ;; c_style -> cStyle
;;M-x replace-regexp \([A-Z][a-z0-9]+\) -> _\,(downcase \1) ;;cStyle -> c_style

It works fine if I convert c_style but when I'm trying to convert cStyle I got c_Style as result. Yes, I've checked that this is due to downcase behaviour.

+1  A: 

I think you need the second arg of replace-match to be t instead of nil.

scottfrazer
+3  A: 

Your problem is the second argument to replace-match. From the documentation:

If second arg fixedcase is non-nil, do not alter case of replacement text.
Otherwise maybe capitalize the whole text, or maybe just word initials,
based on the replaced text.
If the replaced text has only capital letters
and has at least one multiletter word, convert newtext to all caps.
Otherwise if all words are capitalized in the replaced text,
capitalize each word in newtext.

You're passing nil for the fixedcase argument, which causes replace-match to capitalize the replacement when the text being replaced is capitalized. Pass t instead and this bit of the code will work.

I have two general comments about your code.

  1. All of your uses of progn are unnecessary. The body of save-excursion is an implicit progn and so are the bodies of let and let*.

  2. You search forwards and then backwards to try to find the bounds of the symbol underneath point. Emacs already has a thingatpt library to find things at or near the point. In your case you can just call (bounds-of-thing-at-point 'symbol) which returns a cons cell (START . END) giving the start and end positions of the symbol that was found.

Gareth Rees