Composable Commands - improving upon the ideas of Vim


#1

See this article on Vim vs Atom

I’d like to hear what people think about composable commands in Atom, like Vim. I know there’s already atom/vim-mode, but that package seems to be focused more around implementing Vim’s command mode rather than improving upon the core ideas of Vi.

For those who haven’t used Vi or Vim, the article linked above does a good job of explaining Vim’s command mode. The gist is that Vim has commands like $ and ^ that move the cursor to the end or beginning of the line. There’s also commands like d that don’t do anything immediately; instead d waits for the next command and deletes the characters between where the cursor was and where the cursor ends up. So d$ deletes to the end of the line and d^ deletes to the beginning.

While Vim has a single, composable delete command, Atom has a separate command for each kind of delete. And if you want to extend that, you need to implement a whole new command. Vim’s way of doing commands, though, isn’t without its problems. The first of which is that the commands are oddly named and hard to remember. I think we can do better, so here’s my “proposal” for a new way to handle commands:

First, let’s say that commands can be composed by adding some sort of character as a separator, like ::. Using the example above, we could have commands delete and end-of-line and write into the command pallet or a keybinding something like delete::end-of-line. The delete command could then be implemented along these lines:

function delete(editor, next) {

    // Save the current cursor position
    var pos_start = editor.getCursorPos();
    var pos_end;

    // Synchronously call the next command to get the new position
    // Or default to forward-delete
    if (typeof next === 'function') {
        next();
        pos_end = editor.getCursorPos();
    } else {
        pos_end = pos_start.copy();
        pos_end.col += 1;
    }

    // Delete and restore the cursor
    editor.delete(pos_start, pos_end);
    editor.setCursorPos(pos_start);

}

The idea is that we execute the first command and pass a callback that executes the next command. In the example, delete is smart enough to work as a non-composed command as well.

Something like this could go a long way towards adding Vi-like features which haven’t seen much innovation since Vim’s introduction.


#2

I generally like the idea and the sample implementation is really great to see! What’s confusing me about your idea though is that the article says composability is better for the user of the editor. It seems you’re saying that composability will benefit us in writing all of these many commands and you seem to leave the user out of it. Or am I misunderstanding?