Content from 2013-08

Filtering org tasks

Published on:

I want to be able to easily see a list of tasks that are relevant to the currently loaded desktop file. As I use desktop.el as a kind of project system, this means I only want the tasks for the project I'm currently working on.

First I wrote the tagify function, because org-mode tags can't contain . or - characters (among others I'm sure, but these are the only ones that have caused me any trouble so far). It's a simple string replacement:

(defun tagify (str)
  "Remove dots, replace - with _ in STR."
  (replace-regexp-in-string
   "-" "_" (replace-regexp-in-string "\\." "" (downcase str))))

Then I wrote a function to filter the task list by not showing anything that wasn't tagged with the name of the currently loaded desktop, unless it isn't tagged at all or no desktop has been loaded. And set this function to be the value of org-agenda-before-sorting-filter-function.

(defun filter-by-desktop (entry)
  "Return ENTRY if it has no tags or a tag corresponding to the desktop."
  (require 'desktop)
  (let ((label (when desktop-dirname
                 (tagify (file-name-base
                          (directory-file-name
                           (expand-file-name desktop-dirname))))))
        (tags (get-text-property 0 'tags entry)))
    (when (or (null desktop-dirname) (null tags) (member label tags))
      entry)))

(setq org-agenda-before-sorting-filter-function #'filter-by-desktop)

This works fine. I keep untagged tasks in the list as well because they might be important at all times and I don't want them falling through the cracks. I also want a complete list if no desktop has been loaded so I can browse through my tasks and decide what I'm going to do next.

The downside of this solution is that I have to close my current project in order to see the whole list.

Then I discovered the / key in the agenda buffer. I can't believe I didn't notice this key before. Anyway, that changed my solution.

Instead of setting org-agenda-before-sorting-filter-function I add a hook to the org-agenda-finalize-hook. The filter-by-desktop function looks a little different now:

(defun org-init-filter-by-desktop ()
  "Filter agenda by current label."
  (when desktop-dirname
    (let ((label (tagify (file-name-base
                          (directory-file-name
                           (expand-file-name desktop-dirname))))))
      (org-agenda-filter-apply (cons label nil) 'tag))))

(add-hook 'org-agenda-finalize-hook 'org-init-filter-by-desktop)

I don't need to compare any tags now, and if I want to see my entire list of tasks I can easily just press / /. Since it is easier to get back to the overview of my tasks it also doesn't bother me so much that this way any untagged tasks don't show up in the filtered buffer.

I haven't stopped using / since I discovered it. Filtering in this way is one of the things I like about ibuffer as well, now for org-mode it works excellently as well.


C-d to close eshell

Published on:

One of the "tricks" that I have learned to use when working with terminals is using C-d to close them, or when working on a TTY logout. It somehow grew to the extent that if I can't use it, I get annoyed, like with eshell.

I have customized ansi-term to immediately close its buffer after the shell quits. This makes it very easy to start an ansi-term, which I've bound to C-c t, run a quick command (perhaps make, or similar), C-d, and I'm out. I want that for my eshell too.

There are a few conditions that I want met before the buffer is killed, though.

  1. Since eshell is an Emacs mode like any other, C-d is usually used to forward-kill characters, I don't want to lose this.
  2. I only want it to quit when the line of input is empty.

The following piece of code make sure these conditions are met.

  1. It interactively calls delete-char, which keeps keybindings like C-4 C-d to delete 4 characters working.
  2. It catches the error condition which is signaled whenever delete-char can't do it's job (like when there's nothing left to delete in the buffer).
  3. It checks to make sure that the signaled error is the end-of-buffer error. I don't want to kill the buffer if I try to delete more characters than are in the buffer because I feel that could cause irritating surprises.
  4. It checks of the cursor is at the eshell prompt. This, combined with only responding to the end-of-buffer error, makes sure we're on an empty line and not just at the end of the input. Sometimes keys are pressed at the wrong time and I don't want to have to re-type a command just because I was being an idiot.
  5. If the right conditions aren't met, signal the error again so I can see what's going on.
(defun eshell-C-d ()
  "Either call `delete-char' interactively or quit."
  (interactive)
  (condition-case err
      (call-interactively #'delete-char)
    (error (if (and (eq (car err) 'end-of-buffer)
                    (looking-back eshell-prompt-regexp))
               (kill-buffer)
             (signal (car err) (cdr err))))))

I then bind this to C-d in eshell.

(add-hook 'eshell-mode-hook
          (lambda () (local-set-key (kbd "C-d") #'eshell-C-d)))

Some quick git diff tips

Published on:

A couple of quick tips. As you possibly know you can specify some options to be used for diffs (and other things) per file type. The one I'm interested in is the function name.

For org-mode

The primary way of identifying which part of an org-mode document a change occurs in seems to me to be the heading. So, in your $HOME/.gitconfig put:

[diff "org"]
      xfuncname = "^\\*+.*"

Which should show any lines starting with one or more * characters. And then in $XDG_CONFIG_HOME/git/attributes or $HOME/.config/git/attributes put:

,*.org   diff=org

For lisp and lisp-like langauges

For anything that resembles lisp (so Common Lisp, Emacs Lisp, Hy, scheme, etc.) I would think that the easiest thing to do is just see the closes top-level form. So, in your $HOME/.gitconfig put:

[diff "lisp"]
      xfuncname = "^\\([^ ]+ [^ ]+"

Which should show the opening parenthesis and the first two words. For example:

(defun some-function-name
(defclass my-awesome-class
(define-route this-strange-route

And then put in your $XDG_CONFIG_HOME/git/attributes or $HOME/.config/git/attributes:

,*.lisp  diff=lisp
,*.el    diff=lisp
,*.hy    diff=lisp
,*.scm   diff=lisp

And possibly any other lisp-like language files you can think of.


This blog covers archlinux, avandu, avandu-lua, cask, ci, clark, common-lisp, config, conkeror, diff, dispass, dispass.el, editors, elisp, emacs, eshell, evil, exherbo, experiments, file-synchronization, games, git, github, gnus, hla, html, javascript, lisp, lua, markam, meta, mpd, notion, org-mode, ox-coleslaw, projects, rc, sbcl, small-recent-posts, software, stumpwm, systemd, tasks, tekuti, testing, tips, todo, ttrss, utility, vagrant, vc, vim, visual, wdocker docker docker-compose, wm, wordpress, yoshi-theme

View content from 2016-02, 2015-09, 2015-08, 2014-12, 2014-10, 2014-08, 2014-07, 2014-06, 2014-04, 2014-01, 2013-11, 2013-10, 2013-08, 2013-05, 2013-04, 2013-02, 2013-01