Category Archives: emacs

On this page:

Emacs: beginner, intermediate, advanced

In a recent Emacs Chat, Bozhidar Batsov mentioned the need for more intermediate to advanced resources, not just tutorials covering the same introductory ground. It got me thinking about different levels of Emacs use, and what kinds of things would help people move upwards.

I think of Emacs beginners as people who are getting the hang of using Emacs. They might even use Emacs regularly. They might have installed and configured a number of packages with lots of help from StackOverflow, coworkers, IRC, and so on. They are not yet comfortable with customization, so they find workflow descriptions and code snippets helpful.

Intermediate users are those who have figured out workflows that fit them well. They may have installed and configured a number of packages. They’re comfortable reading the documentation to figure out how to customize variables, and may even have written a few custom functions and keybindings. They’ve dived into the Emacs Lisp Reference Manual a few times, and know where to go to find examples and common idioms. Some have written tutorials to help beginners get started with useful packages or tips.

Advanced users are those who can imagine a new use for Emacs and make it happen. Here’s where you’ll find people with complex workflows built around combinations of packages, people who write custom modes and other tools, and people for whom hacking Emacs has become a recreational activity. They’re comfortable digging through the source and creating their own versions. They might even package the new code in order to share those features with others. Their code feels like Emacs code, following conventions and idioms.

What have I learned from Emacs Chats about how people move from one stage to the other?

Beginner to intermediate: “Oh, neat, Emacs can do that! I wonder how I can…”

Many people find it inspiring to see how other people have tweaked Emacs. Demos, examples, IRC conversations, and peeking over people’s shoulders are all great ways to find out that Emacs can do more than you think it does, which is an important motivator for moving from the beginner stage to the intermediate stage.

Useful resources could include:

  • Demos of interesting features that require some configuration, with notes on other things you might tweak along the way (exercises for the reader?)
  • Walkthroughs of advanced users’ workflows, since people pick up little tips that advanced users may forget to mention
  • Tips on how to read and modify code

Intermediate to advanced: “I’m in Emacs all the time anyway, so I might as well…”

Going from intermediate to advanced tends to involve a lot of practice in creating little tools, much rereading of the Emacs Lisp Reference and well-written package source code, and participation in the community (through mailing lists, IRC, StackOverflow, Github, etc). It can involve a commitment to use Emacs for way more than you might expect, possibly pushing it to be equivalent or superior to other tools.

People who maintain packages with active communities or who answer questions on mailing lists/newsgroups StackOverflow/Quora/IRC tend to grow a lot, too, since they actively learn from other people’s questions.

Useful resources could include:

  • Practical applications of concepts from the Emacs Lisp Reference
  • Tweaks using internal or obscure code
  • Posts that new features or “What if…” and walk through the code (and possibly the thought process as well)

Emacs is so big, so people probably have different levels of competence for different things. For example, one can be a beginner at Smartparens (memorized the keybindings for some common operations), while being an intermediate/advanced user of completions (have defined a custom completion backend).

What kinds of resources have helped you move from stage to stage? What would you like to see more of?

Emacs Chat: Oh no, my chat with Bodil Stokke didn’t get recorded!

Camtasia said it was recording the whole thing, and then when I went to edit it, I found that I only had the first 9 minutes. Extracting the .camrec didn’t get me any additional data. Nooooooooooooooooooooooooo! That’s what I get for doing an interview without two recording systems. Normally I use Google Hangout On Air’s built-in recording and Camtasia Studio as a backup, but since I was using appear.in, I only had Camtasia Studio running.

And it was a cool demo/discussion of Flycheck with Haskell (including better ways to do things), Tern, js2-mode, smartparens, tagedit, the XWidgets branch and running Reveal.js presentations inside Emacs, styling tips (Powerline, Nyancat, font-locking), the Emacs Lisp Reference…

We might be able to reschedule after I crawl out from under a rock and also hammer a solid backup screen recording strategy in place, although Bodil mentioned she’s open to using Google Hangout on Air even though it uses some proprietary plugins.

In the meantime:

http://twitter.com/bodil

https://gitlab.com/bodil/emacs-d/tree/master

Argh. Bodil, I’m so sorry!

Emacs Chat: Christopher Wellons

Christopher Wellons (nullprogram.com, github.com/skeeto/) started using Emacs nine years ago and has built all sorts of nifty customizations since, including something that plays Tetris for you. He demonstrates the benefits of having an HTTP server running inside Emacs by using Skewer to interact with a web browser and Impatient-mode to share his syntax-highlighted buffer through the Web. In addition, he covers foreign function interfaces, packages, and other good things. Check it out!

Links: 

Download the MP3

Playing around with Clojure, Cider, and 4Clojure

4Clojure has a lovely series of exercises to help you practice Clojure. I don’t know much Clojure yet. I’ve basically been taking what I know of Emacs Lisp and trying to cram it into Clojure syntax. (compose is pretty cool!) I should probably read through a Clojure tutorial and some kind of syntax reference. (Hyperpolyglot is neat!) But hey, I’ve gotten through 21 problems so far.

Tom Marble and I were chatting about Clojure, Emacs, and Org Babel. As it turns out, there are lots of ways to interact with 4clojure problems from within Emacs. Tom told me about the 4clojure package by Joshua Hoff, which is probably slightly improved with the following code:

(require 'clojure-mode)
(defun my/4clojure-check-and-proceed ()
  "Check the answer and show the next question if it worked."
  (interactive)
  (let ((result (4clojure-check-answers)))
    (unless (string-match "failed." result)
       (4clojure-next-question))))
(define-key clojure-mode-map (kbd "C-c C-c") 'my/4clojure-check-and-proceed)

That one doesn’t track your progress on the website, though, so you’ll still want to copy and paste the solution yourself.

I like working within Org Mode so that I can easily take notes along the way. Here are the notes I took while figuring out how to get Clojure and Org to work together. http://www.braveclojure.com/basic-emacs/ is nice. http://bzg.fr/emacs-org-babel-overtone-intro.html has a good introduction. Here’s what I used from those:

Install Java (at least version 6), Clojure and Leiningen.

Install the clojure-mode and cider Emacs packages

Evaluate this by moving the point to the #+begin_src line and running C-c C-c

(add-to-list 'package-archives '("melpa" . "http://melpa.milkbox.net/packages/") t)
(package-refresh-contents)
(package-install 'clojure-mode)
(package-install 'cider)

And then evaluate this afterwards:

(add-to-list 'org-babel-load-languages '(emacs-lisp . t))
(add-to-list 'org-babel-load-languages '(clojure . t))
(org-babel-do-load-languages 'org-babel-load-languages org-babel-load-languages)
(setq nrepl-hide-special-buffers t
      cider-repl-pop-to-buffer-on-connect nil
      cider-popup-stacktraces nil
      cider-repl-popup-stacktraces t)
(cider-jack-in)

That should let you evaluate this:

(list? '(1 2 3 4))

—————–
And that let me do stuff like this for #27: Palindrome Detector:

(defn __ [x] (= (seq x) (reverse x)))
(list
  (false? (__ '(1 2 3 4 5)))
  (true? (__ "racecar"))
  (true? (__ [:foo :bar :foo]))
  (true? (__ '(1 1 3 3 1 1)))
  (false? (__ '(:a :b :c))))
true true true true true

If all the results are true, then I’ve passed. Yay! In the web interface, __ is where your answers go. Fortunately, it’s also a valid Lisp name, so I can defn a function to replace it when testing locally. The proper answer would probably be something like (fn [x] (= (seq x) (reverse x))) when submitted through the web interface, which is close enough.

it would be great to have something like 4clojure for Emacs Lisp – a site where you can practise solving small, well-defined problems. =) Has someone already written one?

Cobbling together a semi-auto-responder using Emacs, Gnus, and org-contacts

It turns out that lots of people are interested in an e-mail-based course for learning Emacs Lisp. Yay! =) Maybe it’s the idea of bite-size chunks. Maybe it’s the ease of asking questions. Maybe it’s the regular reminders to work on something. Who knows? Whatever the reason, it’s awesome to see so many people willing to join me on this experiment.

Since this is my first time to venture into the world of teaching people online, I wanted to see how far I could push actually doing all the mails myself, instead of just signing up for an Aweber account and handing everyone off to an impersonal autoresponder. I dusted off Gnus, offlineimap, and org-contacts, and started figuring out my workflow. I’ll share how that workflow’s evolving so that you can get a sense of how someone might write little bits of Emacs Lisp to make something repetitive easier.

For the first little while, I got by with using C-x r s (copy-to-register) and C-x r i (insert-register) to store the text that I needed.
Sometimes I needed to paste in the welcome message and checklist, and sometimes I needed to paste in the first lesson. By using registers, I could insert whatever I wanted instead of going through the kill ring. I also had another bit of templated code in yet another register so that I could easily create an org-contacts entry for the person whose mail I was replying to. In the beginning, I used tasks under each person’s heading to indicate that I had sent them the checklist or that I had sent them the first lesson. Eventually, I changed my org-contacts notes so that the TODO state of each person showed which lesson I was going to send them next, or CHECKLIST if I was waiting for their reply to the checklist. I also set up Org so that it would automatically log when the TODO state was changed.

#+TODO: TODO | DONE
#+TODO: CHECKLIST(c!) BEGINNER1(1!) BEGINNER2(2!) BEGINNER3(3!) BEGINNER4(4!) FULL(f!) | FINISHED(x!)
#+TODO: | CANCELLED

* Who
** CHECKLIST Jane Smith ...
** BEGINNER1 John Smith
   SCHEDULED: <2014-05-28 Wed>
   :PROPERTIES:
   :EMAIL: [email protected]
   :END:
(notes from the messages, etc.)

I wrote some code to make it easier to send someone a checklist and create a note for them in my org-contacts file. I bound it to C-c e c for convenience.
(The bind-key function is defined by a package.)

(setq sacha/elisp-course-checklist-body "... really long text here...")
(defun sacha/elisp-course-checklist ()
  "Copy this message and put it at the end as a checklist item. 
Start a message with the checklist."
  (interactive)
  (gnus-summary-scroll-up 1)
  (with-current-buffer gnus-article-buffer
    (let ((message (buffer-substring-no-properties (point-min) (point-max)))
          (email (cadr (org-contacts-gnus-get-name-email))))
      (with-current-buffer "elisp-course.org"
        (save-excursion
          (goto-char (point-max))
          (save-excursion
            (insert "\n** " message)
            (org-set-property "EMAIL" email)
            (org-todo "CHECKLIST"))))))
  (gnus-summary-followup-with-original nil)
  (goto-char (point-max))
  (insert sacha/elisp-course-checklist-body))
(bind-key "C-c e c" 'sacha/elisp-course-checklist)

This made it easier for me to read the starred messages from my inbox and use C-c e c to get a head start on processing people’s introductory messages.
Yay! I used the register trick to help me reply to people who were ready for the first lesson. After the first few replies, I noticed that the attachment code was fine even if I put that in the register too, so I added it as well.

Things got more complicated when I started processing lesson 2. I didn’t want to have to set up and remember lots of different registers, and I didn’t want to manually update the TODO states either. So I started defining functions that I could call with keyboard shortcuts:

(defun sacha/elisp-course-1 ()
  (interactive)
  (let ((marker (org-contacts-gnus-article-from-get-marker)))
    (if marker
        (org-with-point-at marker
          (org-todo "BEGINNER2"))))
  ;; Find the person's contact record
  (gnus-summary-scroll-up 1)
  (gnus-summary-followup-with-original nil)
  (message-goto-subject)
  (message-delete-line)
  (insert (concat "Subject: " sacha/elisp-course-1-subject "\n"))
  (goto-char (point-max))
  (insert sacha/elisp-course-1-body))
(bind-key "C-c e 1" 'sacha/elisp-course-1)
(defun sacha/elisp-course-2 ()
  (interactive)
  (let ((marker (org-contacts-gnus-article-from-get-marker)))
    (if marker
        (org-with-point-at marker
          (org-todo "BEGINNER3"))))
  ;; Find the person's contact record
  (gnus-summary-scroll-up)
  (gnus-summary-followup-with-original nil)
  (goto-char (point-max))
  (insert sacha/elisp-course-2-body))
(bind-key "C-c e 2" 'sacha/elisp-course-2)

Really, though, it doesn’t make sense to have a lot of duplicated code. So I wrote some code that would use the person’s TODO keyword to look up the message to send them, and then move them to the next keyword. Now I don’t need sacha/elisp-course-1 or sacha/elisp-course-2 any more.

(setq sacha/elisp-course-info
      `(("CHECKLIST" nil ,sacha/elisp-course-checklist-body)
        ("BEGINNER1" ,sacha/elisp-course-1-subject ,sacha/elisp-course-1-body)
        ("BEGINNER2" ,sacha/elisp-course-2-subject ,sacha/elisp-course-2-body)))

(defun sacha/elisp-course-process (subject body &optional state)
  "Process this course entry."
  (if (derived-mode-p 'org-mode)
      (progn
        ;; Move this node to the next state and compose a message
        (if state (org-todo state))
        (org-todo 'right)
        (message-mail (org-entry-get (point) "EMAIL") subject)
        (goto-char (point-max))
        (insert body))
    ;; Doing this from Gnus; find the person's info
    (let ((marker (org-contacts-gnus-article-from-get-marker)))
      (if marker (org-with-point-at marker
                   (if state (org-todo state))
                   (org-todo 'right)))
      ;; Compose a reply
      (gnus-summary-scroll-up 1)
      (gnus-summary-followup-with-original nil)
      (message-goto-subject)
      (message-delete-line)
      (insert (concat "Subject: " subject "\n"))
      (goto-char (point-max))
      (insert body))))

(defun sacha/elisp-course-guess-and-process (&optional state)
  (interactive (list (if current-prefix-arg (read-string "State: "))))
  (let ((current-state
         (or state (elt
                    (if (derived-mode-p 'org-mode)
                        (org-heading-components) 
                      (let ((marker (org-contacts-gnus-article-from-get-marker)))
                        (if marker (org-with-point-at marker (org-heading-components)))))
                    2))))
    (sacha/elisp-course-process
     (elt (assoc current-state sacha/elisp-course-info) 1)
     (elt (assoc current-state sacha/elisp-course-info) 2)
     state)))
(bind-key "C-c e e" 'sacha/elisp-course-guess-and-process)

Come to think of it, I should totally have it schedule the next update for the next Wednesday, too. ;) That’s just (org-schedule "+wed"). Neat, huh?
And I’m sure there are all sorts of ways the code can be simpler, but it works for me at the moment, so hooray!

I really like this approach. It lets me pull in standard information while also letting me customize the messages and how it fits into my task tracking. I can’t get that with Gmail (even with canned responses), and I’m not sure any CRM is going to be quite as awesome as this. I can’t wait to see how else we’ll tweak this as we go through more conversations. I’d like to get better at:

  • having a consistent place where I can process all the messages and make sure nothing falls through the cracks; I currently star messages to make sure I process them, since the Gmail label folder in IMAP seems to be missing some messages
  • seeing all Gnus conversations related to an org-contacts entry
  • reaching out to people proactively with the next lesson, even if they haven’t e-mailed me (or maybe I should wait for them?)

Anyway, that’s an example of writing a little bit of Emacs Lisp in order to connect different packages. Gnus handles mail, Org handles notes, org-contacts links the two together, and with a little bit of custom code, I can make the combination fit what I want to do. I read the source code of org-contacts to find out how I could look up the appropriate note, and I looked at org-shiftright to find out how to move things to the next TODO state. If you know something that works roughly like what you want it to work, you can find out how it does things and then copy that.

As for the course itself: I’ve been sending people links to the HTML output, attached .txt files (with -*- mode: org -*-) so they can open it in Emacs if they want, and inline text so that they can skim it briefly in their e-mail client if they want to. I’m not perfectly happy with the plain-text formats, but it seems to be a reasonable compromise, and so far people have been able to deal with it. I’ve been improving pieces of it based on feedback on clarity, suggestions for good examples, and so on. I didn’t take all the feedback; after thinking about some of the suggestions, I still preferred it my way. It’s shaping up quite nicely, though!

If you’re curious about the beginner’s course on reading Emacs Lisp, e-mail me at [email protected] and we’ll see how this works out. I’m certainly learning a lot. =)

Emacs Chat: Bozhidar Batsov

UPDATE 2014-06-13: The transcript is now available.

Bozhidar Batsov (emacsredux.com) shares how he got into Emacs and Emacs Lisp. He also demonstrates cool features from Prelude and Projectile, which are great if you do a lot of programming. Check it out!

Quick Links: https://twitter.com/bbatsov , https://twitter.com/emacs_knight , http://emacsredux.com , https://github.com/bbatsov/prelude , https://github.com/bbatsov/projectile . If you like his work, there’s https://www.gittip.com/bbatsov/

Guest: Bozhidar Batsov

For the event page, you may click here.

Want just the audio? Get it from archive.org: MP3

Transcript here!

Check out Emacs Chat for more interviews like this. Got a story to tell about how you learned about or how you use Emacs? Get in touch!