help-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: elisp exercise: toggle-letter-case


From: Andreas Politz
Subject: Re: elisp exercise: toggle-letter-case
Date: Sat, 18 Oct 2008 01:29:36 +0200
User-agent: Mozilla-Thunderbird 2.0.0.16 (X11/20080724)

Xah wrote:
here's a little interesting exercise.

I'm writing a toggle-letter-case function below. However, it has some
problems. (see the doc string). After thinking on this for a while,
the problem seems a bit complex. It'll take perhaps few hours to fix
these, in particular, if it is to cover chars like éÉ èÈ üÜ. Also, it
seems a good solution will require this function to have a state, but
i'm reluctant to introduce a global variable for it.

I'm wondering, if anyone have a better solution?

(defun toggle-letter-case ()
  "Toggle the letter case of current word or text selection.
Toggles from 3 cases: upper case, lower case, title case,
in that order.
Title case means upcase first letter of each word.

Todo:
• this command only consider English alphabets. For example, it may
not work properly if you have éÉ èÈ üÜ.
• It may not work when the first or second letter is a number, e.g.
“1time”.
• It may not work when you only have a single letter. e.g. “A
teapot”."
(interactive)

(save-excursion
(let (pt pos1 pos2 cap1p cap2p (deactivate-mark nil) (case-fold-search
nil)
         )
  (setq pt (point))
  (if (and transient-mark-mode mark-active)
      (setq pos1 (region-beginning)
            pos2 (region-end))
    (setq pos1 (car (bounds-of-thing-at-point 'word))
          pos2 (cdr (bounds-of-thing-at-point 'word))))

;; check 1th and 2th letters cases
  (goto-char pos1)
  (setq cap1p (looking-at "[A-Z]"))
  (goto-char (1+ pos1))
  (setq cap2p (looking-at "[A-Z]"))

  (cond
   ((and (not cap1p) (not cap2p)) (upcase-initials-region pos1 pos2))
   ((and cap1p (not cap2p)) (upcase-region pos1 pos2) )
   ((and cap1p cap2p) (downcase-region pos1 pos2) )
   (t (downcase-region pos1 pos2) )
   )
  )
)
)

PS the above assumes you have transient-mode on.

  Xah
∑ http://xahlee.org/


Giving the command a state makes it so much easier, because you
don't have to look at the text at all.  Unless you want it to
consider the current textstate.
Anyway, here is how I would do it:
                                        
(defun up/down/camel-case (&optional start end)
  (interactive (if (and transient-mark-mode mark-active)
                   (list (region-beginning)
                         (region-end))))

  (if (not (eq last-command this-command))
      (put this-command 'call-count 0))
  (let* ((mark (and transient-mark-mode mark-active))
        (call-count (get this-command 'call-count))
        deactivate-mark
        (action
         (nth call-count
              (if mark
                  '(downcase-region upcase-region capitalize-region)
                '(downcase-word upcase-word capitalize-word)))))
    (if mark
        (apply action (list start end))
      (funcall action 1)
      (backward-word))
    (put this-command 'call-count (% (1+ call-count) 3))))

-ap



reply via email to

[Prev in Thread] Current Thread [Next in Thread]