M-g vs. goto-line

Just as many of you, I always missed the goto-line command in Emacs having no key assigned by default despite its usefulness, and one day (when I moved from XEmacs) I bound it to M-g. However, starting with Emacs 22, they decided to have it bound to M-g M-g, along with previous-error which was bound to M-g M-p and next-error to M-g M-n. The last part looked nice especially when I wasn’t happy with C-x ` at all, but it was just far from acceptable to me that I had to type M-g twice for jumping to a specific line number, so I insisted on my binding of M-g.

Time has passed, and now I have a bit of skills in elisp, and here it goes:

(defun goto-line-number ()
  (interactive)
  (goto-line (string-to-number
              (read-from-minibuffer
               "Goto line: "
               (char-to-string last-command-event)))))
(loop for n from 1 to 9 do
      (global-set-key (format "\M-g%d" n) 'goto-line-number))
(global-set-key "\M-g?" 'describe-prefix-bindings)

This snippet makes it as if M-g were a key for goto-line by tweaking the key bindings of M-g 1..9. For example, typing M-g 2 lets you enter the minibuffer with the first figure (2) input, and you are ready to type the rest of the figures of a line number, just as below:

-UUU:@----F13  init.el        Top (1,0)     [1]  (Emacs-Lisp FlyC:1/5 hs AC yas)
Goto line: 2 

This means you can just say M-g 2 0 0 RET to get to the line 200 while you can say M-g M-n to jump to the next error line. Cool.

For those who may wonder, the last line of the snippet helps you remember other key combinations of the M-g family by typing ? after M-g. Happy hacking!

knu-z v2.0 released – a fork of “z”, a better “cd”

I am happy to announce that my fork of “z”, which was originally developed by rupa deadwyler, has reached the functionality level I aimed, and here I present you the very first release, knu-z v2.0, available for both zsh and bash. (The original is now at v1.5, hence v2.0)

Here is a list of user-side improvements I’ve made over the original version:

  • Search method enhancements
    • Adopted simple substring match instead of regular expression match, for those who often go under directories with dots in the name.
    • While it’s basically substring match, there is special syntax for searching by prefix and/or suffix.
    • $HOME part is ignored in matching.  Otherwise, it often gets in your way if you like to take your project names from your handle, or just by annoying coincidence.
  • Shell completion enhancements
    • Rewrote bash completion that didn’t seem working.
    • Rewrote zsh completion that was old (compctl) with the new completion system (“compsys”) for far better UI.
    • Subdirectories of your home directory show up like ~/src/project1 instead of /home/user/src/project1. [bash] [zsh]
    • Completion candidates are sorted by the score. [zsh]
    • Glob patterns can be used to narrow down candidates. [bash] [zsh]
    • Enhances cd by powering its completion function to include matching directories in the z database.  This almost eliminates the need for learning and “using” z.  Once you install “z”, the normal cd simply gets smart, and it automatically learns as you use it normally.
  • Other enhancements
    • Added a way to manually remove a directory from the database: z --del directory
    • Nonexistent directories are not immediately eliminated from the database.  It is worth keeping a directory on a certain removable medium or a remote disk that you often but don’t always mount.

All you need is put “. /path/to/z.sh” in your ~/.zshrc or ~/.bashrc. Don’t forget to check out the README file.

Compatibility?  No worries.  The data file format and core algorithms are compatible with those of the original.  Enjoy!

Toggling “hairy” features in cperl-mode of Emacs

Emacs’s cperl-mode has many “electric” features, but how would you turn them all at once? Here’s my implementation of cperl-toggle-hairy.

(eval-after-load "cperl-mode"
  '(progn
     (defun cperl-toggle-hairy ()
       (interactive)
       (unless (boundp 'cperl-electric-prev-alist)
         (set (make-local-variable 'cperl-electric-prev-alist) nil))
       (cond (cperl-electric-prev-alist
              (dolist (pair cperl-electric-prev-alist)
                (set (car pair) (cdr pair)))
              (abbrev-mode (if abbrev-mode 1 0))
              (setq cperl-electric-prev-alist nil)
              (message "cperl-toggle-hairy: on.")
              t)
             (t
              (dolist (var '(abbrev-mode
                             cperl-auto-newline
                             cperl-electric-keywords
                             cperl-electric-lbrace-space
                             cperl-electric-linefeed
                             cperl-electric-parens
                             cperl-hairy
                             cperl-indent-region-fix-constructs
                             cperl-info-on-command-no-prompt
                             cperl-lazy-help-time))
                (setq cperl-electric-prev-alist
                      (cons (cons var (symbol-value var)) cperl-electric-prev-alist))
                (set var nil))
              (message "cperl-toggle-hairy: off.")
              nil)))
 
     (define-key cperl-mode-map "\C-c\C-l" 'cperl-toggle-hairy)
 
     (defun cperl-electric-quote (arg)
       (interactive "P")
       (self-insert-command (prefix-numeric-value arg))
       (and
        (cperl-val 'cperl-electric-parens)
        (let ((properties (text-properties-at (point))))
          (and (null (memq 'font-lock-string-face properties))
               (null (memq 'font-lock-comment-face properties))
               (save-excursion (insert last-command-event))))))
     (define-key cperl-mode-map "\"" 'cperl-electric-quote)
     (define-key cperl-mode-map "'"  'cperl-electric-quote)))

As you see, I put cperl-electric-quote as a New Year’s present.

Pasting a text literally to Emacs under terminal

A text editor is distinguished from "cat > file" where it greatly assists the user in writing a structured text by offering such features as auto-indentation, auto-correction, completion for programming, etc., not to mention basic editing features like search, mass replace, cut, copy and paste. These advanced features are quite nice especially in programming, but sometimes they bite.
Suppose you are under terminal editing a ruby program in Emacs with ruby-electric-mode turned on, feeling like pasting a text from outside the editor like clipboard, GNU screen or tmux. You could easily imagine what would happen. The pasted text would be messed up with superfluous closing parenthesis and quotations that are automatically inserted during the character-by-character pasting process. Of course ruby-electric-mode is a minor mode that can be easily turned off, but for example, in cperl-mode there are many individual flags for a variety of its “electric” features and they cannot be turned off all at once (see the following post for cperl-toggle-hairy). Anyway, changing the editing state back and forth is definitely not something you want just for a copy & paste. It is not supposed to be such a pain in the first place.

Here’s my quick answer.

(defun ins ()
  (interactive)
  (let* ((target (current-buffer))
         (buffer (generate-new-buffer (format "*Paste Buffer for <%s>*"
                                              (buffer-name target)))))
    (with-current-buffer buffer
      (make-local-variable 'ins-target-buffer)
      (setq ins-target-buffer target)
      (local-set-key "\C-c\C-c"
                     '(lambda ()
                        (interactive)
                        (let ((buffer (current-buffer)))
                          (switch-to-buffer ins-target-buffer)
                          (insert-buffer-substring buffer)
                          (kill-buffer buffer))))
      (local-set-key "\C-c\C-k"
                     '(lambda ()
                        (interactive)
                        (let ((buffer (current-buffer)))
                          (switch-to-buffer ins-target-buffer)
                          (kill-buffer buffer)))))
    (switch-to-buffer buffer)
    (message (format "Enter a text to paste.  Type C-c C-c when done. (C-c C-k to dismiss)"
                     (buffer-name target)))))

Whenever you feel like pasting a text from clipboard at point, type M-x ins, paste, type C-c C-c and it’s done. Simple.

git-cp: cp(1) + git-add(1)

I just wrote a quick but functionally decent implementation of git-cp(1), a missing subcommand that Subversion users would certainly get used to.  While I desperately wanted it I could imagine why it is not part of the Git core.  There are many forms of changeset that could make it difficult for SCM to trace history, and keeping track of file copies would only handle a small part of the problem.  For example, you could merge two files into one, move a portion from one file to another, or split a file into two, and recording a hint that a file copy is done would only serve its purpose in the last case.  The designers of Git had the insight to recognize that and instead of adding a feature to record a copy, they equipped git-log and git-diff with copy/move detection so that a copy can be found when they look back the history, making recorded hints unnecessary as the detection method gets mature enough to work effectively.
But, but. I had been tired of typing cp a b && git add b every time I feel like using an existing file as a template for making a new file, and thought it would feel great if you could just say git cp a b to start working on the new file quickly. Some may say the name git cp is misleading but it is just as evil as git mv that is too just a type saver. Plus, git-cp is made not to overwrite an existing file or copy a file to outside of the repository, so it is safe to use.
I also wrote git-touch(1) for a similar reason. Whenever I want to create a new empty directory, I can say git touch log/.gitignore instead of a lengthy sequence of mkdir log && touch log/.gitignore && git add log/.gitignore. There’s also git-untouch(1) to undo it when you have made a typo or changed your mind on the new file path.
These are all dedicated to those who joy in typing less.

bcbiff(1) – Boxcar based IMAP biff

There’s one big common frustration among Gmail users on iPhone that you cannot receive instant notification for coming mails.  On the other hand, you know that Boxcar is one of the must-haves for iPhone bringing you a fully customizable push notification method that is flexible and easy to use.

It may seem enabling push notification for Gmail is as easy as setting up your Gmail account to forward important mails to your Boxcar address, but it actually isn’t.  Suppose you want to be only notified of mails hitting Inbox because you receive tons of mails on mailing lists or mail magazines that are tagged and archived by filters. You’ll find it not easy to write a filter rule that matches mails that will be dropping in Inbox, because in Gmail all filters are evaluated in parallel and you cannot define a rule based on tags added by other filters.

Another concern is your privacy.  Even if you managed to make up a filter rule and successfully set up forwarding to Boxcar, every mail forwarded would be relayed through external servers and end up having a copy on Boxcar.  I’m not saying I don’t trust Boxcar or relay servers, but there’s no point for you (nor for them!) to carry a private mail content including sensitive headers outside of Gmail just for notifying that a mail has received.

Here’s why I wrote bcbiff(1).  Bcbiff is a tool that checks the Inbox folder (or any specified folders) on an IMAP server for unread mails and sends a notification via Boxcar for each.  Mail bodies and headers other than From, Date and Subject are stripped off, and the Message-Id’s of the latest 100 unread mails are cached so that you get just one notification per mail.  Bcbiff supports multiple mailboxes and Boxcar accounts.

To use it, you need a server on which you can periodically run bcbiff (Ruby 1.8.7+ or 1.9.2+ required) and send email via the sendmail(1) command.  See README for details.

Have fun with it!

These Days

Er, um, a Happy New Year! Last year was just fantastic. Having spent a lot of time with my wife and little baby, I’ve had quite a lot of new things to think, learn and realize. It is quite inspiring to watch a baby grow!

While there have been happy times, I had one sad moment. My grandma passed away in December at the age of 90, just before her 91st birthday. If there is any solace to be taken, it is that I could make it to take our boy to see her in her last moments. When I introduced her first and so far only great-grandson to her, even though she was only barely conscious, she forced her voice and cried out as if she was responding. A fantastic coincidence is that they share a birthday. I will tell this story at every opportunity to my son so our grandma lives forever in our hearts.

As for work, last year was the year I coded in Ruby the most out of five years at my current company. These days I use Rails3 most of the time and I feel good about it. As I come to use Ruby for work, my current interests are shifting toward enriching programming experience by enhancing user libraries rather than tweaking the core language and builtin libraries. It is simply fun allowing myself just to be a user concentrating on productivity and specific problems he faces everyday.

This could be a reaction to my bitter experience working hard for everybody just to be criticised by nobody, but next time I get in the ring I believe I can do a better job than the last time based on these experiences.

Life is fun. You can do whatever to make yours more colorful and enjoyable.  Now I’m getting excited as to what I would see this year!  Feel free to contact me if you are interested in me through my activities.

WP-Syntax Download Extension

Moving from tDiary, I’m kind of new to WordPress. I chose it because it was easy enough to run it on my server and had a lot of nifty, nice-looking plugins that would do me with everything that I needed.  As you may imagine, while using those plugins is fine and cool, looking into the code is hell. Through my journey of fixing problems I encountered and submitting a couple of patches to the plugin authors, I’ve seen full of code duplicates, unoptimized funtion call repetition, lack of look-up table pre-generation or even a simple memoization, parsing and substituting HTML with messy, awkward, terribly composed regexps, etc. etc. .  OK, life is short, let’s just turn a blind eye to them as long as the code works.
Well,  so much for digressions.  I just wanted to write a code blog like this.  In order to do that, there is no doubt you need a good code highlighting engine with download/view buttons.  I searched around for the best, but no combination of plugins appealed to my taste.  I decided to write a plugin to add what is lacking for me  to WP-Syntax and here it is.  WP-Syntax Download Extension renders a nice caption on each WP-Syntax highlighted code snippet as below.

(defun goto-next-window (&optional arg)
  (interactive "P")
  (cond ((one-window-p)
         (select-window (split-window-horizontally)))
        (arg (other-window -1))
        (t (other-window 1))))
(global-set-key "\C-o" 'goto-next-window)
(global-set-key "\M-\C-o" 'open-line)

I’ll probably add “print” and “copy to clipboard” buttons in the future. Try it out and feel free to leave a comment.

git-shift: Changing commit timestamps in Git

Git is known to be so flexible that one can even fix or delete old commits, but what would you do if you wanted to change the timestamp of a particular commit? This need can arise for various reasons, such as when a merged commit has picked the unwanted timestamp on squash, when a contributor’s (or your notebook’s) machine clock was obviously far out of sync, and so on.
git-shift (update: repository moved) is the tool I wrote to change dates (timestamps) of specified commits in a git repository.  The choice of the name sounds a bit too bold, so maybe I will rename it later—but anyway.
The usage is simple; specify the amount of time you want to shift timestamps by, and a list of commit IDs you want to change timestamps of. (Range notation is currently not supported)
e.g. to move timestamps of commits identified by the IDs f9e8d7c6 and 579acf two hours backwards:

$ git-shift -2h f9e8d7c6 579acf

Use it wisely and enjoy your life, night and day workers! :D

Making FriendFeed a perfect Twitter client

As you all know, FriendFeed is equipped with some features to cooperate with Twitter. FriendFeed gives you with automatic CC to Twitter for writing and realtime feed updates for reading, and helps you find your Twitter friends on FriendFeed. However, they are just not enough because you cannot expect everyone to join FriendFeed. For Twitter users who don’t or wouldn’t have their accounts on FriendFeed, you have to set up an “imaginary friend” for each one of them by hand to make their tweets come up on your FriendFeed timeline. Even after all these hard work, you are left with some friends who make their tweets private, which FriendFeed cannot import. What about @replies? You don’t even notice on FriendFeed that someone is talking @you when your friends on Twitter are enjoying spontaneous talk with others, including strangers.

Introducing tw2ff

Here’s my answer to all these inconveniences. I wrote a tool called tw2ff that makes your FriendFeed life much easier in terms of integration with Twitter. It consists of the following features:

  • Friend list synchronization: importing Twitter-only friends to FriendFeed as “imaginary friends”
  • @replies import: generating a custom RSS feed of @replies for importing to FriendFeed
  • Protected tweets import: generating a custom RSS feed of protected tweets for importing to FriendFeed
  • Favorites synchronization: synchronizing FriendFeed likes and Twitter favorites
  • .. and some more

Installation

tw2ff is bundled in my “friendfeed” ruby gem, so you can install it right away by just one command as follows:

gem install friendfeed

The first thing you do after the installation is run tw2ff config and set up credentials for your Twtter and FriendFeed accounts. It invokes a text editor with the following content, so fill in with your login information and save the file.

---
friendfeed:
  username: "username"
  password: "password"
twitter:
  username: "username"
  password: "password"

The file is located at ~/.tw2ff/config.yml, which directory is created with mode 700. Make sure it is never read by anyone else.

Friend list synchronization

You are now ready to run tw2ff friends to import your Twitter-only friends to FriendFeed as “imaginary friends”. It’s automatic, it compares your friend list on Twitter with subscriptions on FriendFeed and creates one imaginary friend for each Twitter friend missing in FriendFeed, where the screen name is enclosed with parentheses so you can easily see it is an imaginary friend. The tw2ff friends command does not change anything with existing imaginary friends, so you can safely rerun it at any time to keep your FriendFeed timeline in sync with that of Twitter. You will likely want to run it every time you follow a new person on Twitter, but it is also an idea to register this as a daily cron job and just leave the task to it.
One note about replying to imaginary friends. If you post a comment to an imaginary friend’s entry with the “Also send this comment as an @reply twitter from ” box checked, it will be visible in Twitter but not on FriendFeed because imaginary friends are private to you.
After a while, you may happen to visit Twitter or run a Twitter client and notice that some of your friends have changed their icons. That’s when you run tw2ff icons, a command that updates all imaginary friends icons with those of their Twitter accounts. Maybe a candidate for a monthly cron job or so.

Import of @replies and protected tweets

The only way to import private feeds to FriendFeed is put the feed in a secret place no one else would know and feed it to your own imaginary friend. (FriendFeed does not support any kind of authentication in feed crawling)
First off, create an imaginary friend named, say, “@replies”. This is where your secret @replies RSS is fed to. Then set up a cron job that invokes tw2ff replies replies.rss and upload the file replies.rss to a secret location, preferably only fetchable via HTTPS. Now you can add a service to the above said imaginary friend and set the secret location. There are a couple of options to choose what kind of replies should be included to the feed: --include-friends and --include-protected. The default is both off. Specify them as needed. In addition, by the way, I highly recommend adding your favstar feed to the imaginary friend so you can see more as to how others are reacting to you. Currently there is no support in tw2ff for your tweets RT’d, but I’ll implement it some way in near future.
Okay, you’re done with @replies and now, you can pull protected tweets into your FriendFeed timeline the same way by importing a feed produced by tw2ff protected. Please be doubly sure that you won’t leak the feed out to public.

Favorites synchronization

I much prefer FriendFeed likes to Twitter favorites because they are visible to others, naturally including the one whose post is favorited. That makes it easier to share topics not just with your friends but across the much wider friends-of-friends community. Recently Twitter introduced the RT feature to help people share their attentions, but I don’t think it would have been needed if favorites had been implemented and featured properly.
Let’s get back to the subject. I use “likes” a lot in FriendFeed and whenever I “like” a tweet I want to “favorite” it on Twitter at the same time, and vice versa. That’s exactly what tw2ff favorites does. It looks into the recently liked entries for tweets, and the ones not yet favorited are favorited on Twitter. Likewise, it searches the recent entries on your FriendFeed timeline for your favorited tweets, and the ones not yet liked are liked on FriendFeed. All you need to do it make it a cron job. Problem solved!

To-Do’s

  • Support for RT’s
  • Switching Twitter client access to OAuth
  • Utilizing Twitter’s streaming API and eliminate the time lag of @replies/protected tweet feeds
  • Switching FriendFeed client access to v2 API
  • (You add one)

Conclusion

With the help of tw2ff as described above, I can live just with FriendFeed without the need for always keeping another window for Twitter. FriendFeed quite shines when it stands as the one-stop portal for sharing what you and your friends are up to. Empower your FriendFeed life with tw2ff!