Monday, January 21, 2008

Emacs Tip #11: uniquify

Do you dislike the buffer names Emacs generates when two files have the same name? e.g. "myfile.txt" and "myfile.txt<2>"

A package 'uniquify' changes the default naming of buffers to include parts of the file name (directory names) until the buffer names are unique.

For instance, buffers visiting the files:


/u/mernst/tmp/Makefile
/usr/projects/zaphod/Makefile

would be named

Makefile|tmp
Makefile|zaphod

respectively (instead of "Makefile" and "Makefile<2>").

There are other naming schemes possible.

I use this to my .emacs:

(require 'uniquify)
(setq uniquify-buffer-name-style 'reverse)
(setq uniquify-separator "/")
(setq uniquify-after-kill-buffer-p t) ; rename after killing uniquified
(setq uniquify-ignore-buffers-re "^\\*") ; don't muck with special buffers


For the *info* page,

C-h i m emacs RET s uniquify RET

Wednesday, January 16, 2008

Teach The Hard Stuff

I read the Coding Horror entry on how to teach Computer Science the other day...
Coding Horror: How Should We Teach Computer Science?: "If we aren't teaching fundamental software engineering skills like deployment and source control in college today, we're teaching computer science the wrong way. What good is learning to write code in the abstract if you can't work on that code as a team in a controlled environment, and you can't deploy the resulting software? As so many computer science graduates belatedly figure out after landing their first real programming job, it isn't any good at all."
I scanned the comments and most people talked about CS versus SE (Software Engineering), or what they think is most important to teach. I agree with the narrow point that computer science is different than software engineering - the former teaches the theory and fundamentals of computers, languages, and programming, while the latter focuses on how to engineer software for the real world.

To a large extent CS and SE are orthogonal. Knowing how to write code that can compile on 11 platforms, versus understanding why a regular expression cannot be used to match parenthesis are two completely different issues.

The difficulty with coming up with the "truly important" concepts that should be taught in school is that the software industry is too diverse to be able to put in a nutshell. Take, for example, Jeff's idea that "computer science students should develop software under conditions as close as possible to the real world" just doesn't make sense. What real world?

I've, thankfully, been gainfully employed as a software engineer for 12 years, and I've never had to worry about software distribution, and there are large numbers of people who have never had to think about that. Why? Because it was taken care of by other people - I simply abstract away that problem as not something I had to solve. So how would that lesson have helped me?

But even if you wanted to teach about software distribution, what kind of distribution? Should the students have to deal with a wide variety of PC builds (Windows2K, Vista, Me, XP)? What about Mac? And the ton of flavors of Unix and all their varieties? What about 32 versus 64 bit platforms? What would this really teach students? Distributing software is a pain. Fine, lesson taught, but why have to go through this for every class? Does everyone in your company know how to distribute the software you produce?

My point isn't for or against teaching about distribution of software. Almost any one topic under the umbrella of CS or SE fails to apply to all of the software industry. No matter what you are taught, you are going to learn things you never use, and you are not going to learn things you need to know to do your job.

So, what should be taught?

This reminds me of the time I asked a professor what I should study in my last year or two - as I only had a couple of slots free for non-mandatory courses. I was specifically asking about taking math versus computer science classes (I was a double major), and he advised math. Why? Because math is hard.

So we should teach math?

Um.... not quite the point.

I think that school is a good time to learn the fundamentally difficult concepts. Hopefully you'll always be surrounded by intelligent, inquisitive peers and knowledgeable mentors, but the chances are school is your best bet for being immersed in that kind of environment. Think of school as a petri dish, sure, mold can grow anywhere, but it grows really well in a petri dish.

So now software is mold?

University should teach fundamentals and fundamentally difficult concepts. So things like: data and procedural abstraction, algorithmic complexity, data structures, algorithms, and what makes up this computer (OS, hardware, compiler, network). Hmmm... sounds like the course requirements for my CS degree.

No software engineering basics?

That being said, it would have been a heck of a lot easier to do some of the course work had I known more about how to use a text editor, version control, a debugger, logging, unit testing, or (gasp) an IDE. I would definitely have appreciated some introduction to those early on. But early on the projects are so small that none of those are important and would just get in the way. It's the classic chicken-and-egg problem.

So you want both CS and CE taught?

What I really want from a new college graduate is someone who can think for himself, and has the intellectual curiosity to continually improve.

Version control, any build system, testing harness, language, or software distribution system is (IMO) much easier to learn than discerning algorithmic complexity. So, if one has to make a choice between the two, I'd choose the more difficult subject, algorithmic complexity. Some of the comments argued that people don't tend to ever learn version control, so it should be taught in school. To which I would respond, if they are the kind of person who only ever learned it superficially in the real world, they would have only learned it enough to pass the class.

Teach the hard stuff in school, and, where possible, teach software engineering skills to help the student thrive while in school.

Back to the idea of developing software at school in conditions that match the 'real world'. The real world is full of noise. I'd much rather learn the subject matter than be subjected to compiler bugs, platform differences, whiny customers, incomplete specifications, etc.

I guess it boils down to the first CS class I took in college. I loved the class, and I still think it the best introductory CS class available. Why? Because in one semester you go from knowing next to nothing about CS to learning data structures/algorithms/complexity analysis and writing a interpreter, a CPU simulator, and a compiler. One semester, and you're exposed to basically all of computer science - and not just superficially.

Scheme? You want to force me to (parse (all (the (parentheses))))?

Grow up, look past the language. Look at the concepts taught. If you want to rewrite the book using Ruby or whatever, be my guest. If the result is a class that can still fit into a semester, all the power to you. The point of using Scheme was that the language is taught in one lecture, and after that you get to learn the interesting things. Try teaching meta-programming to C++ novices (hell, try teaching it to 99% of the software community).

Yeah, but it's just a toy interpreter/compiler/CPU...

If you actually look at what is taught, you have a supremely flexible interpreter/compiler/CPU simulator, and you can vary the semantics of the language, compiler optimizations, and hardware configurations. You can explore the intricacies of each to whatever extent you desire.

I've never seen that much information packed into such a concise form that is accessible to first year students.

Whatever is taught to computer science students should be taught with a focus on that subject. Just like you should remove distractions that drag your developers down, you should remove distractions from the subjects taught in school. If you want to teach about developing software in the real world, then make a class or two that does that, or provide internships, or contribute to open source projects. If something doesn't help the student learn the subject, it gets in the way.

Monday, January 14, 2008

Emacs Tip #10: sig-quote (intelligent, random signatures)

Way back when I first started using Emacs, I read email with it. A friend had some script which modified his .signature file with a random quote every 30 seconds. I thought that was kind of neat, but I wanted every email to get its own, random, quote. At the time I didn't know how to get a random number in a simple shell script, so I started writing something using Emacs directly.

A random signature wasn't enough though, I then wanted to be able to have different categories of quotes and send different people quotes from those different categories. From the documentation:


;; This mode is designed to allow a user to have quotes appended to
;; their mail and news posts according to whom/where the mail is
;; being sent. For example, one might wish to have "insightful"
;; quotes sent to Prof. Apple, and "crude" quotes to your brother
;; Sam. With this mode, upon sending a piece of mail, the email
;; addresses are scanned (this includes the To:, CC:, and BCC:
;; headers), and an appropriate quote is inserted into the letter.


Thus began my Emacs fascination.

You can download the source here.

Thursday, January 10, 2008

Emacs Tip #9: Gnus/Gmail integration (using IMAP)

Like many folks, I use Google for more and more. When I noticed Google's announcement that Gmail supports IMAP, I knew I could read my Gmail from Emacs.

The question was, how do you set up the integration? The Emacs wiki had instructions on how to read email, which worked nicely. But I wanted to enable Gmail to gather the mail I sent from Emacs into its conversation groups (it's no Gnus threading, but it's a start). So how to enable that? At first I automatically Bcc'ed my Gmail account, but that was hacky. Then I noticed Gmail lets you use their SMTP server.

I found some documentation on how to use it, but it didn't work for me (wrong ports evidentially), and it was integrated differently than what I wanted.

So I used my favorite Emacs lisp feature, advice, and wrote the following snippet. It checks to see if the 'From:' address is a gmail address, in which case it uses Gmail's SMTP server.


(defadvice message-send-mail (around gmail-message-send-mail protect activate)
"Set up SMTP settings to use Gmail's server when mail is from a gmail.com address."
(interactive "P")
(if (save-restriction
(message-narrow-to-headers)
(string-match "gmail.com" (message-fetch-field "from")))

(let ((message-send-mail-function 'smtpmail-send-it)
;; gmail says use port 465 or 587, but 25 works and those don't, go figure
(smtpmail-starttls-credentials '(("smtp.gmail.com" 25 nil nil)))
(smtpmail-auth-credentials '(("smtp.gmail.com" 25 "username@gmail.com" nil)))
(smtpmail-default-smtp-server "smtp.gmail.com")
(smtpmail-smtp-server "smtp.gmail.com")
(smtpmail-smtp-service 25)
(smtpmail-local-domain "yourdomain.com"))
ad-do-it)
ad-do-it))

Note: You can also download the snippet directly.

And, as a good netizen, I updated the wiki appropriately.

Friday, January 4, 2008

Emacs Tip #8 : markdown

I saw a post for auto-generating HTML and thought, neat trick. My preferred email client is Gnus, which already mimics that (changing *text* into text and so forth).

But how cool would it be to have both my regular text show up, as well as an HTML version (when useful) - I already write using the syntax of markdown.

Mr. O'Connor happened to choose to do integration using Python (preferred programming language). Of course I don't grok Python, so getting it to work isn't quite as easy as running the Perl version.

So I coded up similar functionality, only I also tweaked things such that only the text before the signature line is converted into HTML.


(defun mimedown ()
(interactive)
(save-excursion
(message-goto-body)
(let* ((sig-point (save-excursion (message-goto-signature) (forward-line -1) (point)))
(orig-txt (buffer-substring-no-properties (point) sig-point)))
(shell-command-on-region (point) sig-point "Markdown.pl" nil t)
(insert "<#multipart type=alternative>\n")
(insert orig-txt)
(insert "<#part type=text/html>\n< html>\n< head>\n< title> HTML version of email</title>\n</head>\n< body>")
(exchange-point-and-mark)
(insert "\n</body>\n</html>\n<#/multipart>\n"))))

Wednesday, January 2, 2008

Emacs Tip #7: resolve-sym-link

It's often nice to find the true path to a file or directory. Since I work in Emacs, it's often easier to use find-file to discover the path, and then invoke this little diddy. I like having it bound to C-r

(defun resolve-sym-link ()
"Replace the string at the point with the true path."
(interactive)
(beginning-of-line)
(let* ((file (buffer-substring (point)
(save-excursion (end-of-line) (point))))
(file-dir (file-name-directory file))
(file-true-dir (file-truename file-dir))
(file-name (file-name-nondirectory file)))
(delete-region (point) (save-excursion (end-of-line) (point)))
(insert (concat file-true-dir file-name))))

(define-key minibuffer-local-completion-map (kbd "C-r") 'resolve-sym-link)