Nathan's Lucubrations; on computers, music and the outdoors

04 01 2013

Fri, 04 Jan 2013

Man Page a Day

Reading Hacker News, I came across someone's goal of reading a man page a day. The discussion around that post quickly turned to how to pick manual pages, and I decided to try to come up with a way to automatically load a random one in Emacs. Here's the result:

;; Taken from http://emacswiki.org/emacs/ElispCookbook#toc57
(defun directory-dirs (dir)
  "Find all directories in DIR."
  (unless (file-directory-p dir)
    (error "Not a directory `%s'" dir))
  (let ((dir (directory-file-name dir))
        (dirs '())
        (files (directory-files dir nil nil t)))
    (dolist (file files)
      (unless (member file '("." ".."))
        (let ((file (concat dir "/" file)))
          (when (file-directory-p file)
            (setq dirs (append (cons file
                                     (directory-dirs file))
                               dirs))))))
    dirs))

;; Taken from
;; http://stackoverflow.com/questions/3815467/stripping-duplicate-elements-in-a-list-of-strings-in-elisp
(defun strip-duplicates (list)
  (let ((new-list nil))
    (while list
      (when (and (car list) (not (member (car list) new-list)))
        (setq new-list (cons (car list) new-list)))
      (setq list (cdr list)))
    (nreverse new-list)))

;; Display a random manual page
(defun open-random-man-page ()
  (interactive)
  ;; Get manual page paths from the environment.
  (setq man-paths (parse-colon-path (getenv "MANPATH")))
  ;; What if MANPATH isn't set or is empty? We'll take a guess:
  (if (eq man-paths nil)
      (setq man-paths (list "/usr/share/man")))
  (setq man-dirs ())
  (dolist (man-path man-paths)
    (setq man-dirs (append man-dirs (directory-dirs man-path))))

  ;; Get a list of files in manual page paths.
  (setq files ())
  (dolist (man-dir man-dirs)
    (setq files (append files (directory-files man-dir nil "^[^\.].*"))))

  ;; Fixup the files to be a list of man pages.
  (setq man-pages ())
  (dolist (file files)
    (setq man-pages (cons (car (split-string file "\\." t)) man-pages)))

  (setq man-pages (strip-duplicates man-pages))

  (random t)
  (princ "Selecting random manual page from " t)
  (princ (length man-pages) t)
  (princ " possibilities." t)
  (manual-entry (nth (random (length man-pages)) man-pages)))


syntax highlighted by Code2HTML, v. 0.9.1

I'm sure there's a more elegant way of doing this, but it works, mostly. It doesn't filter out subdirectories (such as man1), and only gives you the default manpage if there is more than one (such as read). Some other things caught my eye though: on my main home machine, this code finds roughly 20k manual pages, which would take over 50 years to read if you only read one a day. Of course, you could read more than one a day, or focus on things you are using or interested in. Another way to use this code is as a starting point: fire up a random manual page, then research more from there, or at least after reading it you are aware of "the tip of the iceberg" (especially in the case of many libraries with man pages).

posted at: 10:43 | path: | permanent link to this entry

powered by blosxom