Re: Factor

Factor: the language, the theory, and the practice.

Todo Lists

Saturday, January 22, 2011


It seems the thing to do these days is to write “a better todo list”. Probably there is at least one (maybe dozens) implemented in each programming language in existence. Factor even has its own todo web application.

When it comes to development, most developers keep lists of changes that need to be made or features that need to be implemented. Factor has its own todo list on the wiki. I know you are thinking what I’m thinking: wouldn’t it be great if we could keep the todo list alongside the code? In any event, it would make a nice demonstration of the vocabulary and help browser system.


First, some background. Every vocabulary supports various metadata associated with the code, including:

summary.txt a single line description of the vocabulary
authors.txt a list of vocabulary authors
resources.txt a list of files to include when deploying
tags.txt a list of vocabulary tags used for organization
platforms.txt a list of supported platforms if not cross-platform


We are going to add to this a todo.txt file containing a todo list of improvements or additions that could be made to the vocabulary. The format of the todo.txt file will be a list of text, each on its own line.

USING: arrays assocs formatting io io.pathnames kernel
sequences vocabs vocabs.loader vocabs.metadata ;

IN: todos

The path to the todo.txt file is relative to the directory containing the specified vocabulary:

: vocab-todo-path ( vocab -- string )
    vocab-dir "todo.txt" append-path ;

We can get and set the list of todo items using vocab-file-contents and set-vocab-file-contents, respectively.

: vocab-todo ( vocab -- todos )
    dup vocab-todo-path vocab-file-contents ;

: set-vocab-todo ( todos vocab -- )
    dup vocab-todo-path set-vocab-file-contents ;

We could add new todo items at runtime:

: add-vocab-todo ( todo vocab -- )
    [ vocab-todo swap suffix ] keep set-vocab-todo ;

Printing out the todo list for a specified vocabulary is pretty easy:

: todos. ( vocab -- )
    vocab-todo [ print ] each ;

Using the child-vocabs word, we can look through a vocabulary hierarchy for all todo files, returning a map of vocabulary to non-empty list of todo items.

: all-todos ( vocab -- assoc )
    child-vocabs [ dup vocab-todo 2array ] map
    [ second empty? not ] filter ;

And then print them out from the Listener:

: all-todos. ( vocab -- )
    all-todos [
        [ "%s:\n" printf ] [ [ "- %s\n" printf ] each ] bi*
    ] assoc-each ;

Try it

Although we could make the todo.txt files by hand, why not try using Factor?

IN: scratchpad USE: tools.scaffold

IN: scratchpad "foo" scaffold-work
Creating scaffolding for P" resource:work/foo/foo.factor"

IN: scratchpad "" scaffold-work
Creating scaffolding for P" resource:work/foo/bar/bar.factor"
Loading resource:work/foo/bar/bar.factor

IN: scratchpad "The first thing" "foo" add-vocab-todo

IN: scratchpad "The second thing" "foo" add-vocab-todo

IN: scratchpad "Another thing" "" add-vocab-todo

IN: scratchpad "foo" todos.
The first thing
The second thing

IN: scratchpad "foo" all-todos.
- The first thing
- The second thing
- Another thing

If you look in $FACTOR/work, you will now find the foo/todo.txt and foo/bar/todo.txt files that we just created.


We can use these words to make a dynamic help article containing all of the todo entries for loaded vocabularies:

USING: assocs help.markup help.syntax kernel todos ;

: $all-todos ( element -- )
    drop "" all-todos [
        [ $heading ] [ $list ] bi*
    ] assoc-each ;

ARTICLE: "vocab-todos" "Vocabulary todos"
{ $all-todos } ;

Once loaded, just run this to see the help article created by the previous example:

IN: scratchpad "vocab-todos" help

The code for this is on my GitHub.