From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Andreas Politz Newsgroups: gmane.emacs.help Subject: Re: elisp exercise: toggle-letter-case Date: Sat, 18 Oct 2008 01:29:36 +0200 Organization: FH-Trier Message-ID: <1224286525.260548@arno.fh-trier.de> References: <420ba543-19ba-4987-9f3a-a57878777c9d@n33g2000pri.googlegroups.com> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit X-Trace: ger.gmane.org 1224286846 17243 80.91.229.12 (17 Oct 2008 23:40:46 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Fri, 17 Oct 2008 23:40:46 +0000 (UTC) To: help-gnu-emacs@gnu.org Original-X-From: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Sat Oct 18 01:41:45 2008 connect(): Connection refused Return-path: Envelope-to: geh-help-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([199.232.76.165]) by lo.gmane.org with esmtp (Exim 4.50) id 1Kqywy-00081V-Ns for geh-help-gnu-emacs@m.gmane.org; Sat, 18 Oct 2008 01:41:45 +0200 Original-Received: from localhost ([127.0.0.1]:43455 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Kqyvu-0003Jr-00 for geh-help-gnu-emacs@m.gmane.org; Fri, 17 Oct 2008 19:40:38 -0400 Original-Path: news.stanford.edu!newsfeed.stanford.edu!newsserver.news.garr.it!kanaga.switch.ch!switch.ch!news.belwue.de!news.uni-kl.de!not-for-mail Original-Newsgroups: gnu.emacs.help Original-Lines: 90 Original-NNTP-Posting-Host: 143-93-54-11.arno.fh-trier.de Original-X-Trace: news.uni-kl.de 1224286548 1678 143.93.54.11 (17 Oct 2008 23:35:48 GMT) Original-X-Complaints-To: usenet@news.uni-kl.de Original-NNTP-Posting-Date: Fri, 17 Oct 2008 23:35:48 +0000 (UTC) User-Agent: Mozilla-Thunderbird 2.0.0.16 (X11/20080724) In-Reply-To: <420ba543-19ba-4987-9f3a-a57878777c9d@n33g2000pri.googlegroups.com> Cache-Post-Path: arno.fh-trier.de!unknown@dslb-084-059-222-204.pools.arcor-ip.net X-Cache: nntpcache 3.0.1 (see http://www.nntpcache.org/) Original-Xref: news.stanford.edu gnu.emacs.help:163545 X-BeenThere: help-gnu-emacs@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Users list for the GNU Emacs text editor List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Errors-To: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.help:58885 Archived-At: 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