Emacs for Windows; Crash on linum-mode

Steps to reproduce:

  • Download the emacs at Source alpha.gnu.org
  • After install, cd to the “bin” dir, start it like this ./emacs.exe -Q
  • Type 【Alt+x linum-mode Enter】. Emacs crashes.

Thanks to Jon Snader for discussion.

Time Magazine 2001 December 5, Covers

Time Mag 2001-12-05 cover
Time Mag 2001-12-05 covers


keyboards porn: Kineses freestyle, Goldtouch, Typematrix, ergo 4000

Spent about 10 hours keyboard geeking again. Several major updates in the following pages. Addition of some 15 glorious photos of keyboards and their layouts.

Emacs: Insert Brackets by Pair

Perm URL with updates: http://xahlee.org/emacs/emacs_insert_brackets_by_pair.html

Some emacs commands that lets you insert brackets in pairs always.

(defun insert-bracket-pair (leftBracket rightBracket)
  "Insert a matching bracket and place the cursor between them."
  (when (region-active-p)
    (delete-region (region-beginning) (region-end) ) )
  (insert leftBracket rightBracket)
  (backward-char 1) )

(defun insert-pair-paren () (interactive) (insert-bracket-pair "(" ")") )
(defun insert-pair-brace () (interactive) (insert-bracket-pair "{" "}") )
(defun insert-pair-bracket () (interactive) (insert-bracket-pair "[" "]") )
(defun insert-pair-single-angle-quote () (interactive) (insert-bracket-pair "‹" "›") )
(defun insert-pair-double-angle-quote () (interactive) (insert-bracket-pair "«" "»") )
(defun insert-pair-double-curly-quote () (interactive) (insert-bracket-pair "“" "”") )
(defun insert-pair-single-curly-quote () (interactive) (insert-bracket-pair "‘" "’") )
(defun insert-pair-double-straight-quote () (interactive) (insert-bracket-pair "\"" "\"") )
(defun insert-pair-single-straight-quote () (interactive) (insert-bracket-pair "'" "'") )

(defun insert-pair-corner-bracket () (interactive) (insert-bracket-pair "「" "」") )
(defun insert-pair-white-corner-bracket () (interactive) (insert-bracket-pair "『" "』") )
(defun insert-pair-angle-bracket () (interactive) (insert-bracket-pair "〈" "〉") )
(defun insert-pair-double-angle-bracket () (interactive) (insert-bracket-pair "《" "》") )
(defun insert-pair-white-lenticular-bracket () (interactive) (insert-bracket-pair "〖" "〗") )
(defun insert-pair-black-lenticular-bracket () (interactive) (insert-bracket-pair "【" "】") )
(defun insert-pair-tortoise-shell-bracket () (interactive) (insert-bracket-pair "〔" "〕") )

(defun insert-pair-fullwith-paren () (interactive) (insert-bracket-pair "(" ")") )
(defun insert-pair-fullwith-bracket () (interactive) (insert-bracket-pair "[" "]") )
(defun insert-pair-fullwith-brace () (interactive) (insert-bracket-pair "{" "}") )

(defun insert-pair-white-paren () (interactive) (insert-bracket-pair "⦅" "⦆") )
(defun insert-pair-white-bracket () (interactive) (insert-bracket-pair "〚" "〛") )
(defun insert-pair-white-brace () (interactive) (insert-bracket-pair "⦃" "⦄") )

Here's the key setup, using 【Hyper+‹letter›】:

(global-set-key (kbd "H-e") 'insert-pair-paren)              ;()
(global-set-key (kbd "H-u") 'insert-pair-brace)              ;{}
(global-set-key (kbd "H-o") 'insert-pair-bracket)            ;[]
(global-set-key (kbd "H-i") 'insert-pair-single-angle-quote) ;‹›
(global-set-key (kbd "H-I") 'insert-pair-double-angle-quote) ;«»
(global-set-key (kbd "H-a") 'insert-pair-double-curly-quote) ;“”
(global-set-key (kbd "H-A") 'insert-pair-single-curly-quote) ;‘’
(define-key key-translation-map (kbd "H-.") (kbd "=")) ; equal
(define-key key-translation-map (kbd "H-,") (kbd "+")) ; plus

(global-set-key (kbd "H-p") 'insert-pair-double-straight-quote)
(global-set-key (kbd "H-y") 'insert-pair-single-straight-quote)

(global-set-key (kbd "H-k") 'insert-pair-corner-bracket) ;「」
(global-set-key (kbd "H-K") 'insert-pair-white-corner-bracket) ;『』
(global-set-key (kbd "H-j") 'insert-pair-angle-bracket)        ;〈〉
(global-set-key (kbd "H-J") 'insert-pair-double-angle-bracket) ;《》
(global-set-key (kbd "H-q") 'insert-pair-black-lenticular-bracket) ;【】
(global-set-key (kbd "H-Q") 'insert-pair-white-lenticular-bracket) ;〖〗
(global-set-key (kbd "H-;") 'insert-pair-tortoise-shell-bracket)   ;〔〕

Here's the setup for Hyper. On Windows, the Menu key is set to it. On the Mac it's Option:

 ((string-equal system-type "windows-nt") ; Windows

  ;; setting the PC keyboard's various keys to
  ;; Super or Hyper, for emacs running on Windows.
   w32-pass-lwindow-to-system nil
   w32-pass-rwindow-to-system nil
   w32-pass-apps-to-system nil
   w32-lwindow-modifier 'super ; Left Windows key
   w32-rwindow-modifier 'hyper ; Right Windows key
   w32-apps-modifier 'hyper)   ; Menu key

 ((string-equal system-type "darwin") ; Mac
  ;; Carbon Emacs variables
  ;;    (setq mac-command-key-is-meta t)
  ;;    (setq mac-option-key-is-meta nil)

  ;; 2009-10-01, 2011-05-31 works for emacs 23.1 built for ns
  (setq mac-control-modifier 'control)
  (setq mac-command-modifier 'meta)
  (setq mac-option-modifier 'hyper)
  ;; (setq mac-option-modifier 'super)

  ;; Carbon emacs. disable the Mac shortcut convention of cmd-h to hide current application.
  (setq mac-pass-command-to-system nil)

 ((string-equal system-type "gnu/linux")
  nil ; do nothing. You should set Super and Hyper from your OS

You probably want to adjust the keys used above. This setup is for Dvorak Keyboard Layout, Windows, the 【Menu+‹letter›】 key. The letter key is chosen so that the most frequently needed are placed on the home row, based on my own usage patterns of the brackets. For example, the [](){} are all left hand home row while right thumb holds down the menu key.

Advantage of Using Your Own Commands

With these commands, you can type brackets without relying on special modes or settings, and you can type them while in minibuffer, and in any mode.

Also, the keys are more ergonomic than traditional positions. They are under the home row, and using thumb instead of pinky for Shift.

Dragon flags

Air Wales airplane tail
Air Wales airplane tail

Dragon Flags


gencdo 2011-11-25
gencdo (meaning: gentle cherishing doll)

2 persons i like to thank.


Gorean (sex slaves) in Real Life

post removed because it might violate Google's ad program policy. See here instead: http://xahlee.org/sex/gorean_in_real_life.html

the μTRON Keyboard

utron keyboard
“μTRON Keyboard” img src

for detail, see: http://xahlee.org/kbd/uTRON_keyboard.html

Emacs Lisp Example: wrap-html-tag

A little elisp command, useful if you do a lot HTML coding.

(defun wrap-html-tag (tagName &optional className ξid)
  "Add a HTML tag to beginning and ending of current word or text selection.

If tagName is empty or nil, use “span”.
If className is empty or nil, don't add any class attribute.
If ξid is empty or nil, don't add id attribute."
  (interactive "sEnter tag name:
sEnter class:
sEnter id:")
  (let (bds p1 p2 inputText outputText)
    (setq bds (get-selection-or-unit 'word))
    (setq inputText (elt bds 0) )
    (setq p1 (elt bds 1) )
    (setq p2 (elt bds 2) )

      (if (or (equal tagName nil) (string= tagName "")) "span" tagName)
      (if (or (equal ξid nil) (string= ξid "")) "" (concat " id=\"" ξid "\""))
      (if (or (equal className nil) (string-equal className "")) "" (concat " class=\"" className "\""))
      (if (or (equal tagName nil) (string= tagName "")) "span" tagName)
      ">" ) )

    (delete-region p1 p2)
    (goto-char p1)
    (insert outputText) ) )

Remember to bind it to a key.

I used some elisp utils i wrote. You'll need to get it at: code.google.com xeu_elisp_util.el. Or, replace the get-selection-or-unit part by thing-at-point. For tutorial, see: Emacs Lisp: Using thing-at-point.

by the way, you could define your own commands for all html tags, but you probably shouldn't. html-mode has keys to insert many basic html tags. (See: Emacs and HTML Tips) Also, yasnippet has a whole set of html templates. (See: Emacs Templates with YASnippet). Though, still sometimes they don't cover everything you need. That's when adding your own is helpful.


Cute Girls Singing Adele's Rolling in the Deep

Perm url with updates: http://xahlee.org/music/rolling_in_the_deep.html

A very cute young girl, singing Adele's Rolling In The Deep. Watch the ending 10 seconds. It's called precocious.

Vazquez Sounds, Adele - Rolling In The Deep (Cover)

Vazquez is a family group. Very nice.

Following is another cute girl, singing in a cappella style. (A cappella means: without instrumental accompaniment.) To be able to sing in a cappella style means you gotta have voice talent. She's also flirtatious.

Ariana Grande, sining Rolling in The Deep.

Following is a all-girl, family group (they are all sisters).

Cimorelli - Rolling in the Deep

There's one thing about all these girls. There's one thing in common: they all have a good, loving, supportive family. If you grew up in a fucked up family, you won't have such good natured smile or body languages.

Here's Adele singing it.

Adele - Rolling In The Deep

Lousy flat song. Mundane lyrics. Dull music video.

thank you from Xah Lee

I want to write a quick Thank You to those of you who read my emacs blog, and also to many who have donated.

Reminder: it's preferred that you post questions as comments to my blog or website, because it gets seen by many, also better for my blog because people can see interaction. My email is often flooded, though i try to reply to all.

Also thank you for those who have donated, or bought my emacs tutorial. I haven't had a chance to update my Donor List. There is one person, Aigerim, who bought my entire website (for offline reading) for $100. Thank you Aigerim so much!

Am writing this quickly, been wanting to write it for a couple of weeks now. Wanted to mention all names but big plan always results in no action.

I want to thank those who retweeted my emacs tutorials, linked to my site, those who commented on my articles, or exchanged emails, and also those on Facebook and g+. I'm not much a social person, not much into chitchat, and don't like to follow marketing strategies on “establishing communities” or such, but i appreciate many discussions and support. Lew Perin recently sent me a printed pamphlet “Emacs Quick Ref”, of 3 leaflets, that was from 1984 of MIT's Project Athena. Thank you Lew for such a treasure. I hope to take a photo of it and show it to all soon.

On last note, my annual income is about USD$2.5k for the past few years. (or ~$200/month.) So, your donation is appreciated, or, Buy Xah Emacs Tutorial. As far as i know, no emacs book covers elisp as much except GNU Emacs Lisp Reference Manual. With your donation, i'd be able to write a complete cookbook, covering topics such as full controlling GUI elements (windows, frames, menu), text highlighting, emacs input system, display system, IO system, etc, and always with a little practical application you can use right away.

Ergonomic Keyboards: Microsoft 4000 vs Natural Elite

Yesterday, people on Hacker News site are discussing ergonomic keyboards. (Source news.ycombinator.com) Seems all are recommending the Microsoft Natural Ergonomic Keyboard 4000 (review).

I also love that keyboard. Used it for 2 years. Unfortunately, the stiff Spacebar is causing me hand problems. I spend 2 days trying to fix the spacebar. First by trying to remove the metal bar underneath, then tried to bend the metal, then tried to put lubricant in the key hole, then tried lengthen the poke, then tried to break the metal bar holder, then tried to trim the cylinder-poke's sides, then file it, and eventually cutting it out altogether. Ends up with a broken spacebar and nothing worked. (by the way, there's a blog on the web trying to tell you how to fix it. They don't work. It should be fixable though, if you are a tinkerer and lots tools and odd spare parts for spontaneous invention.) So i've switched back to Microsoft's earlier ergonomic model.

ergonomic posture laptop ergonomic posture

By the way, i've read extensively on the web about anything RSI since 1990 (before the web, it's mostly books about typing in libraries). Sometimes i thought perhaps i can do a summary, but, it turns out, i can't. The situation is too diverse, too complex. Causes of RSI are different for everyone. The only summary i could give, is to follow the general ergonomic advices. Namely:

More tips from my experience.

Thanks to Jon Snader for the tip.

Gor on Kindle

The Gor fictions are now in Kindle. Raiders of Gor By John Norma. amazon


The Fantom Language, and a Scathing Review of Scala

There are endless languages. Just discovered Fantom (programming language).

Also, there's this scathing review of Scala by someone who seems to be a Java platform expert.

Scala feels like EJB 2, and other thoughts (2011-11-22) By Stephen Colebourne. @ Source blog.joda.org

Ι don't know Java platform well, not having worked in the industry for many years, but i tend to agree with him on his views.

should i split the blog?

I really like to split my blog here to programing and none-tech. The programing topics would be: emacs, web dev, computer language thoughts, keyboards, etc. The none-tech would be art, literature, politics, random, etc.

Last year i did a poll, many think i shouldn't. But i think that many none-tech friends get annoyed by the so many emacs posts, which they have little idea what it is, while many emacs fans would get annoyed by my random music videos, art pictures, etc.

So, what do you think? vote on the right.

2011-12-22 Poll Result

Should this blog be split into programing topics vs none-tech topics?

  • Yes. 17 (70%)
  • No 7 (29%)

Cute Chick Showing Fancy Linux Desktop

Incredibly cute chick, gives us a tour of fancy animated desktop on linux.

“Ubuntu Linux Themes” demo by a cute chick.

Emacs Lisp Command: curly-quotes-to-emacs-function-tag

Perm URL with updates: http://xahlee.org/emacs/elisp_curly-quotes-to-emacs-function-tag.html

In my emacs tutorial, i want to put HTML markup on elisp functions. For example, if i've written:

<p>Call “sort-lines” to sort.</p>

I want it to be like this:

<p>Call <var class="εf">sort-lines</var> to sort.</p>

This way, i can write a Javascript that pops up documentation when mouse hovers on the function name.

I already have 300 HTML files of emacs/lisp tutorial. How to fix them?

One way is to write a elisp script that go thru all files. Another way is to write a interactive command that can be used on a case-by-case basis. I experimented with both, and decided to use the latter approach.

Here's the command:

(defun curly-quotes-to-emacs-function-tag (p1 p2)
  "Replace “word” to HTML markup for elisp function in text selection or current buffer (respects `narrow-to-region').

For example, the text:
 <p>Call “sort-lines” to sort.</p>
 <p>Call <var class=\"εf\">sort-lines</var> to sort.</p>

Note: a word is changed only if all of the following are true:

① It is enclosed in <p> tag, or <ul>, <ol>, <table>, <figcaption>. (For example, not inside <h1> or <title>, <a>, or other tags.)
② It is enclosed in “double curly quotes”.
③ `fboundp' returns true.

This command assumes that all tags are closed in your HTML. e.g. <p> must be closed with </p>.

This command also makes a report of changed items.

Some issues:

• If the lisp functions name is less than 2 chars, it won't be tagged. e.g. + - 1+ ….

• Only words contaning lowercase a to z, 0-9, or hyphen, are checked, even though elisp identifier allows many other chars. e.g. “yas/reload-all”, “Info-copy-current-node-name” (note capital letter).

• Some words are common in other lang, e.g. “while”, “print”, “string”, unix's “find”, “grep”, HTML's “kbd” tag, etc. But they are also built-in elisp symbols. So, you may not want to tag them.

• Personal emacs functions will also be tagged. You may not want them to be because they are not standard functions.

• Some functions are from 3rd party libs, and some are not bundled with GNU emacs , e.g. 「'cl」, 「'htmlize」. They may or may not be tagged depending whether they've been loaded."
   (if (region-active-p)
       (list (region-beginning) (region-end))
     (list (point-min) (point-max)) ) )
  (require 'sgml-mode) ; from html-mode, needs sgml-skip-tag-forward
  (let (p3 p4 mStr (ξi 0) (case-fold-search nil) )
        (narrow-to-region p1 p2)
        (goto-char (point-min))
        (while (search-forward-regexp "<p>\\|<ul>\\|<ol>\\|<table\\|<figcaption>" nil t)
          (setq p3 (point) )
          (sgml-skip-tag-forward 1)
          (setq p4 (point) )

            (narrow-to-region p3 p4)
            (goto-char (point-min))
            (while (search-forward-regexp "“\\([-a-z0-9]+\\)”" (point-max) t)
              (setq mStr (match-string 1) )

              (when (and (fboundp (intern mStr))
                         (> (length mStr) 2))
                (replace-match (concat "<var class=\"εf\">" mStr "</var>") t t)
                (setq ξi (1+ ξi) )
                ) ) ) )
        (when (> ξi 0)
          (occur "<var class=\"εf\">[-a-z0-9]+</var>" )) ) ) ))

With this code, i can just press a button, and the whole buffer will be so marked. Or, i can select a region of text, press a button, and have that part marked, with a report of the changes (in a second pane).

This still means i have to manually go thru my 300 existing files. The thing is, a batch script that fix all 300 files would not be accurate. For example, many words are also other language's keywords. There is no way for the script to really know unless it has strong AI. For example, on this page: Emacs Lisp Idioms, i have this passage:

Note that, when the thing is a “symbol”, it usually means any alphanumeric sequence with dash “-” or underscore “_” characters. For example, if you are writing PHP reference lookup command, and the cursor is on p in print_r($y);, you want to grab the whole “print_r” not just “print”. The exact meaning of symbol depends on current major mode's Syntax Table.

Notice it contains the string “print” there. The print there refers to PHP's function “print”, and shouldn't be marked as a elisp function.

Still, there are many way to help fix all the 300 files. The good thing about emacs i love is that everything can be done in a incremental, interactive way. So, i start by having this command. This command basically is a semi-automatic way. With this command, in 20 minutes, i could have fixed 20 pages, and i would have learned any complexities of the task. (for example, i learned, that if the elisp function appears inside <title> or <h1> tags, then they shouldn't be marked.) So, i work and modify the command as i go. By the time the command is in good shape as it is now, i've already fixed some 100 pages. Then, if i want, i can modify this command into a batch script. (by now i've fixed basically all pages, maybe 30 left.)


Review of ErgoEmacs by Joseph Buchignani

Joseph Buchignani wrote a review of ErgoEmacs, at: Source www.cyborganize.org. Check it out!

Besides some praises, he also listed several items he believed to be bad. He made many excellent points. Some of his points are due to him being a experienced emacs user, but some are still good points. I think we will follow up about half of his points in next release. Here's a list that is now fixed:

  • math-symbol-input-mode (alias of xmsi-mode) will be off by default. Also, a menu will be added to toggle it.
  • Dired recursive load problem will be fixed as he described.

For org-mode, the only customization in ErgoEmacs is (add-hook 'org-mode-hook 'soft-wrap-lines). What the soft-wrap-lines function do is to set “truncate-lines” to false and “word-wrap” to true. Otherwise, long lines will disappear into the right window border. Am not sure this is a good thing. Has newer org-mode changed this behavior?

Also, emacs 24 beta is out, and people are saying it's pretty stable. So, next release will probably be based on emacs 24.

Thanks to Joseph. Check out his review linked above.

emacs command update: toggle-line-spacing

Updated a function “toggle-line-spacing” for emacs 24, at How to Set Emacs's User Interface to Modern Conventions. Thanks to Ivan Kozik for the tip.

Screen Size Comparison

Screen Size Comparison, see: http://xahlee.org/comp/relative_screen_size.html

emacs updates: insert-random-uuid, backward-close-bracket

Last week, we discussed how to write a elisp to generat UUID. Christopher Wellons provided a excellent implementation involving random info from emacs, then calling md5. See bottom at: Emacs Lisp Exercise: insert-random-uuid.

For those of you using backward-close-bracket and forward-close-bracket, there's a bug that's been fixed. The bug is this: it misses some brackets because there's some typo in the regex in the code, it contained extra space. Get updated code at: Emacs: Commands and Keys to Navigate Brackets.

Old Long “s”: ſ and etymology of the integral sign ∫

Old Variant Form of the Letter “s” ſ and etymology of the integral sign ∫. See http://wordy-english.blogspot.com/2011/11/lingustics-old-variant-form-of-letter-s.html


Inconsistency of Emacs Text-Searching Features

Few days ago, i wrote a tutorial on emacs text-searching commands. See: Emacs: Searching for Text in Files (grep, find). There are lots of them: {list-matching-lines, grep, rgrep, lgrep, grep-find, find-dired, dired-do-search, …}. However, they are inconsistent.

list-matching-lines (alias of occur) is implemented with elisp, while the others rely on unix utils {find, grep}.

The interface also isn't consistent. e.g. grep and grep-find (alias find-grep) both directly prompt you to enter unix command in one shot. But find-dired, rgrep, lgrep, do several prompts asking for: {search string, file extension, directory}. (though, they still require user to be familiar with the unix commands. e.g. When “find-dired” promps “Run find (with args):”, you have to give -name "*html" or -type f etc.)

People who are not unix sys admin or unix programer won't be able to search a folder. The unix find/grep parameters are quite complex, and emacs documentation doesn't try to explain them. You have to know about “man pages” to read its documentation, and even so it's pretty much incomprehensible.

Also, occur shows result with search term highlighted. Nice. But the grep command doesn't (at least not on emacs 23.2 for Windows).

It seems to me, they could all use elisp, with a single code engine, and with the same interface. The files to be searched can be from buffer list or dired marked files, or entered from prompt with emacs regex. The output can be a output like occur or can be dired list or buffer list. For example, you could have a command list-matching-lines, and then “list-matching-lines-directory” with options to do nested dirs, and options to use a pattern to filter files to search for, or options to get marked files in dired, and also options to show result as file list in dired.

Calling external util has lots problems, especially under Windows. First of all, on Windows, external util may not be installed. This is a show stopper. Searching text is a critical feature of emacs. Then, there's Cygwin, MinGW and other variety issues. Emacs has to go thru several layers to interface with them. On unix/linux including Mac OS X, there's also complex issues of identifying the version of grep/find used, which differ in options and behavior. I recall that rgrep didn't work on Mac OS X neither. Then, emacs has to process the output to make syntax coloring. Also, if your search string contains Unicode, then there's extremely complex problem about setting some emacs variables or shell environment variables related to character encoding.

On the other hand, these text searching task is what elisp is designed to do, is rather trivial to code. It would eliminate the whole external program problems.

The core are already in emacs. occur, dired-do-query-replace-regexp, dired-do-search, and probably something in eshell too. They are just scattered and not unified.

By the way, doing it inside elisp is not that slow. Slower than those written in C, but remeber that emacs has to parse their output and the communication overhead might just make it up. I've written a grep command in elisp (See: How to Write grep in Emacs Lisp.). My script is more or less equivalent to unix's grep -c. Just tested now, calling it on a dir with subdir with total of 1592 files. Using a search word that returns over a thousand files. Both my script and unix util are close to 3 seconds. (e.g. call shell in emacs, then give grep -c */*html) Calling grep -c */*html by shell-command is less than 1 second. Calling grep -c */*html by emacs's grep is about 3 seconds too.

I think am going to polish my elisp grep script so it's going to be a general emacs command for all things grep. To begin with, i shall improve it for my own use to the degree that i never need to call unix find/grep directly or indirectly when in emacs.

Has someone written other grep util in elisp other than the above mentioned? What do you think about making emacs not rely on unix find/grep?

comp.emacs discussion

FOSS Infighting: My License is Holier Than Yours

On www.emacswiki.org, there's this fact mentioned:

The [emacs lisp] manual has license GFDL and thus the DFSG (Debian Free Software Guidelines) don't consider it free.

Ain't it bizarre? FSF's GNU Emacs, the mothership of all Free Software, and Debian Linux, the mothership of hacker linux, originally with support of Richard Stallman, have come to this quarrel.

Such quarrel are quite severe and wide-spread among open source communities. BSD's antagonistic forks, GNU vs MIT/BSD/Unices, Emacs vs XEmacs, Free Software vs Open Source, the KDE vs Gnome, GNU vs Linux, Firefox logo vs Debian, the rise and fall and rise and fall of Java as “free” (aka the Java Trap), OpenOffice vs LibreOffice, Richard Stallman vs Linus Torvalds, Richard Stallman vs Eric Raymond, Richard Stallman vs everybody else, …

Ideologies, ideologies!

These tech geekers are supposed to be the ethics gods of humanity, peace, freedom, et al, in reality, they are just scumbags like most human animals on earth, when YOUR self-interest is involved.

Emacs Lisp Example: title-case-string-region-or-line

Perm URL with updates: http://xahlee.org/emacs/elisp_title_case_text.html

This page shows you how to write a emacs lisp command to change letter case by title convention.

In English writing, the title follows a particular convention of capitalization. For example, it should be “A Tale of Two Cities”, not “A Tale Of Two Cities”.

I think this is rather a silly convention. For a while, i experimented by simply following a logically simpler style, of capitalizing the first letter of all words. (➲ The Writing Style on XahLee.org) But after a while, i find it rather jarring.

Part of the reason is that it's new, thus it will get some used to. This i expected. However, the other thing that turns out is that, the capitalization has subtle function for emphasis. For example, “Kung Fu versus Karate” seems better than “Kung Fu Versus Karate”.

It's rather cumbersome to manually capitalize words following this convention. So, i wrote a emacs command. Here's the code:

(defun title-case-string-region-or-line (ξstring &optional ξregion-boundary)
  "Capitalize the current line or text selection, following title conventions.

Capitalize first letter of each word, except words like {to, of,
the, a, in, or, and, …}. If a word already contains cap letters
such as HTTP, URL, they are left as is.

When called in a elisp program, if ξREGION-BOUNDARY is nil,
returns the changed ξSTRING, else, work on the region.
ξREGION-BOUNDARY is a pair [from to], it can be a vector or
   (let ((bds (get-selection-or-unit 'line)))
     (list nil (vector (elt bds 1) (elt bds 2)) ) ) )

  (let ( replacePairs
         (workOnStringP (if ξregion-boundary nil t ) )
         (p1 (elt ξregion-boundary 0))
         (p2 (elt ξregion-boundary 1))

    (setq replacePairs '(
                         [" A " " a "]
                         [" And " " and "]
                         [" At " " at "]
                         [" As " " as "]
                         [" By " " by "]
                         [" Be " " be "]
                         [" Into " " into "]
                         [" In " " in "]
                         [" Is " " is "]
                         [" It " " it "]
                         [" For " " for "]
                         [" Of " " of "]
                         [" Or " " or "]
                         [" On " " on "]
                         [" The " " the "]
                         [" That " " that "]
                         [" To " " to "]
                         [" Vs " " vs "]
                         [" With " " with "]
                         [" From " " from "]

    (let ((case-fold-search nil))
      (if workOnStringP
            (replace-pairs-in-string-recursive (upcase-initials ξstring) replacePairs)
            (narrow-to-region p1 p2)
            (upcase-initials-region (point-min) (point-max) )
            (replace-regexp-pairs-region (point-min) (point-max) replacePairs t t)
            ) ) ) ) ) )

I used some elisp utils i wrote. You'll need to get it at: code.google.com xeu_elisp_util.el. This command is also bundled there.