Stratus3D

Software Engineering, Web Development and 3D Design

Better Vi Mode in Zshell

Many Vim users don’t realize that their shell offers a Vi mode, but both Zshell and Bash do. I’ve been a big fan of Vim for many years now and use it exclusively for all editing work I do. In addition to using Vim for code I also write all my blog post in Vim with vim-pencil and goyo.vim. I only recently decided to switch to Vi mode in my Zsh and Bash shells. While I was happy to move away from Emacs mode, which is the default in Zsh and Bash, I was disappointed with the key mappings present in Zsh’s Vi mode. Many of the features I’d come to love from Zsh’s Emacs mode were gone. After some tinkering and reading several blog posts (links at the bottom of the page) I figured out how to add these features back into Vi mode.

I found that oh-my-zsh offers a Vi mode plugin but I gave up using it when I realized it didn’t offer many of the things I needed. It also made doing some of the customizations I cover in this blog post much harder to do.

Incremental Searching

One of the features I loved most in Zsh’s Emacs mode was the incremental searching. I could type out the start of a command, say tmu, hit the up arrow and scroll through all the tmux commands I had previously run. This feature came in very handy when I needed to frequently rerun a command. All I’d have to do would be to type out the start of the command and then hit the up arrow a couple times. It was much easier than typing out the full command each time or searching back through history with Ctrl-R. Adding this back into Vi mode is easy. Just add something like this to your .zshrc:

# Better searching in command mode
bindkey -M vicmd '?' history-incremental-search-backward
bindkey -M vicmd '/' history-incremental-search-forward

# Beginning search with arrow keys
bindkey "^[OA" up-line-or-beginning-search
bindkey "^[OB" down-line-or-beginning-search
bindkey -M vicmd "k" up-line-or-beginning-search
bindkey -M vicmd "j" down-line-or-beginning-search

First we map the ? and / characters to incremental search when in Vi command mode, so we can use the same key sequences we would use in Vim to find something. Note that these mappings are only in command mode. In insert mode we want to be able to literally type ? or /.

Next we map the up and down arrows (^[OA and ^[OB) to incremental searching when in either insert or command mode. This allows for searching based on a partially typed command like I described above. Since the arrow keys are normally not used in Vi I can safely have these mappings in both insert and command mode.

In addition to mapping the arrow keys to the incremental searching commands I also map k and j in Vi command mode to the same commands, so I can use more Vi like mappings for incremental searching.

Visual Mode Hack

In Vim we have visual mode which makes it easy to select text to yank or manipulate. In Zshell prior to version 5.0.8 there wasn’t a proper visual mode, so if you are using an older version of Zshell you won’t have a way to visualize selections. Instead you can map the v key to open the command in Vim itself for editing. Just add this to your .zshrc:

# Easier, more vim-like editor opening
bindkey -M vicmd v edit-command-line

If you are using Zshell 5.0.8 or newer and have visual mode available you may still want to be able to open Vim to edit a command. I found Ctrl-V to be a mapping that doesn’t interfere with any of the existing mappings.

# `v` is already mapped to visual mode, so we need to use a different key to
# open Vim
bindkey -M vicmd "^V" edit-command-line

Both of these mappings will open the command for editing in the editor you’ve specified in $EDITOR, and from there you can use visual mode to manipulate the command. If you are using Vim and don’t want to load your entire .vimrc just to edit this command you can set $EDITOR to Vim with no config:

export EDITOR='vim -u NONE'

Or you can specify another vim file configuration to use:

export EDITOR='vim -u alternate_profile.vim'

Faster Mode Switching

When you press ESC Zsh normally waits 0.4 seconds before switching to command mode. This is a really long time to wait when typing in a command sequence but we can make it shorter with the KEYTIMEOUT setting. Setting it to 1 makes the wait only 10 milliseconds, which is much more reasonable. Add the following to your .zshrc file:

# Make Vi mode transitions faster (KEYTIMEOUT is in hundredths of a second)
export KEYTIMEOUT=1

Mode Indicator

This isn’t something I use myself, but it is a nice enhancement. With this code the text [NORMAL] or [INSERT] will be shown on the right side of the prompt. The code that adds the mode to the prompt is a bit more involved:

# Updates editor information when the keymap changes.
function zle-keymap-select() {
  zle reset-prompt
  zle -R
}

zle -N zle-keymap-select

function vi_mode_prompt_info() {
  echo "${${KEYMAP/vicmd/[% NORMAL]%}/(main|viins)/[% INSERT]%}"
}

# define right prompt, regardless of whether the theme defined it
RPS1='$(vi_mode_prompt_info)'
RPS2=$RPS1

Basically we call the zle-keymap-select function whenever the input changes, and then vi_mode_prompt_info function determines what mode should be displayed based off of the output from the vicmd, main and viins functions. We assign the resulting string to RPS1 and RPS2 so it’s presented on the right side of the prompt.

Conclusion

With a few tweaks I’ve found Vi mode in Zsh to be very powerful. I’m very happy with my setup and I’m not going back to Emacs mode. I wish I had started using Vi mode earlier as I spent a lot of time learning the Emacs mappings prior to switching. If you’ve got any questions about my configuration you can always find my .zshrc and all my other config files in my dotfiles repository on Github or you can ask me directly.

11/5/2017 Update

Previous versions of this blog post incorrectly stated that the Zshell’s Vi mode lacked a visual mode. That is incorrect. Zshell versions 5.0.8 later have a visual mode that works almost identical to Vi’s actual visual mode. This means the custom v mapping isn’t necessary in versions 5.0.8 and later.

References

Asdf Tip: Global Programs

Every so often I install a program via gem, npm or some other language specific package manager and want it to be available globally on my system. Npm has the -g flag but this doesn’t help when I change Node versions. The same goes for Ruby. If I switch to a different version of Ruby I can’t use the command I installed in the earlier version.

A concrete example of this is the excellent Tmuxinator gem. The gem allows tmux sessions to be defined in yaml files. When a project is opened with the tmuxinator command it creates the session defined in the yaml file for the project automatically. Since Tmuxinator is a gem it’s only available under the version of Ruby it was installed in. If I change to a directory that’s set to use a different version of Ruby my tmuxinator command won’t be available. I really don’t want to have to install the same gem in every version of Ruby I use. It would be wasteful to have multiple installations of the same gem and upgrading all those installations would be a hassle.

Thankfully there is an easy way to handle this if you are using asdf. asdf reads environment variables that are in the format ASDF_<LANGUAGE>_VERSION. In our case this is a Ruby gem, so we need to set ASDF_RUBY_VERSION to the right version of Ruby before executing tmuxinator. To do this you can create a simple alias or shell script. Either will work and both have their advantages. Aliases are shorter and easier to create. Assuming you’ve installed Tmuxinator under Ruby 2.3.0 the alias should look like this:

alias tmuxinator="ASDF_RUBY_VERSION=2.3.0 tmuxinator"

Just add that line to your .bashrc or .zshrc and you should have have a tmuxinator alias that works in any directory, even directories that are set to use different versions of Ruby. You can name the alias anything you want. A different name may be useful if you want to differentiate this global tmuxinator alias from another instance of tmuxinator installed on your system.

A slightly more involved solution is to use a shell script. Even this isn’t that hard to do. All you need to do is create a file with the name you want the command to have (just like the name of the alias above). The file should be placed in a directory on you $PATH (I have $HOME/bin/ for scripts like this). Then run chmod +x <filename> to set the execution permission for the file. Finally open it up in your editor and enter in the following:

#!/usr/bin/env bash

export ASDF_RUBY_VERSION=2.3.0
exec tmuxinator

That’s it! This will work just like the alias, and if it’s on your $PATH it will be available from every directory. The exec line tells Bash to execute the actual tmuxinator program in the same process as the script, rather than spawning another process as it normally would. This makes it slightly more efficient than just calling tmuxinator directly.

References

Promises in Erlang

I recently took the University of Kent’s Concurrent Programming in Erlang course hoping that I would learn some new things about the Erlang VM. I have been programming in Erlang for 3 years so I was a little disappointed when the course only covered the more basic aspects of OTP and didn’t cover anything new to me. Overall the material in the course was a very well presented and it turned out to be a great way to refresh my knowledge of the Erlang concurrency primitives. There was a promise implementation that was briefly presented by Joe Armstrong that caught my attention, and that’s what I want to talk about here.

The code sample Joe presented stood out to me because it’s not the way things are normally done in Erlang. Promises are common in JavaScript, but with asynchronous message passing in Erlang there isn’t really a need for promises. If we have task that we want to run asynchronously in the background we can just spawn and link another process to do some work, and then wait for a message (or exit signal) in a receive block when we need the results. There are also things like Elixir’s Task module that can handle this and hide all the message passing. I was struck by how simple it is to implement simple promises in Erlang:

1
2
3
4
5
6
7
8
9
10
promise(Pid, Request) ->
    Tag = erlang:make_ref(),
    Pid ! {self(), Tag, Request},
    Tag.

yield(Tag) ->
    receive
        {Tag, Response} ->
            Response
    end.

Using these functions it’s easy to run a task in another process:

1
2
3
4
5
6
7
% Call the promise function with our function
Tag = promise(ExistingPid, fun() ->
        io:format("expensive task...", [])
    end).

% Receive the results when we need them
Result = yield(Tag).

All we need is the process ID of an existing worker function and we can pass the Pid and the function into the promise function. The promise function calls the erlang:make_ref/0 function returns a unique reference that we use in our response message. This ensures we don’t get things confused if a lot of promise messages are sent to the same process at the same time. Then the promise/2 function sends the function we provided to the worker process in a message, along with the reference. All we have to do is wait for a message back from the worker process in the yield/1 function. The yield/1 function blocks while waiting for a message back from the promise with the tag that is provided. The code running in the worker process isn’t show here, but it’s not hard to spawn a process that receives a function in a message, execute the function, and send a response message back to the caller Pid:

1
2
3
4
5
6
7
8
9
10
11
12
spawn_worker() ->
    spawn(fun worker_loop/0).

worker_loop() ->
    receive
      {Pid, Tag, RequestFun} ->
         % Do the work
         Result = RequestFun(),
         % Send the response back
         Pid ! {Tag, Result},
         worker_loop()
    end.

This all that is needed for the worker process. We just call spawn_worker/0 and that function spawns a process that executes worker_loop/0, which is a recursive function that will loop forever handling request messages by executing the function received and then sending the results back in a message. While this will work it isn’t ideal. In JavaScript we just pass the function into Promise object and get a promise back. We shouldn’t have to use an existing process to execute the function we passed in. The promise function should spawn a new process for us automatically. It’s easy to modify our promise function to do this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
promise(ExecutorFun) ->
    Tag = erlang:make_ref(),
    Self = self(),
    WorkerFun = fun() ->
        % Do the work

        Result = ExecutorFun(),

        % Send a message with the result back to the callers process
        Self ! {Tag, Result}
    end,
    spawn(WorkerFun),

    % Return the reference so we can use it in the yield function
    Tag.

All we have to do is spawn a new process inside the promise/1 function that executes the function we pass in and then sends the results back to the calling process in a message. Using the promise function is now even easier:

1
2
3
4
5
6
7
% Call the promise function with our function
Tag = promise(fun() ->
        io:format("expensive task...", [])
    end).

% Receive the results when we need them
Result = yield(Tag).

This is much better, but there is still room for improvement here. In JavaScript we have a catch function that we can add to our promise chains to handle exceptions that happen in the promise or previous then handlers. In Erlang there isn’t really a need for catch and then functions because we can pattern match on the result returned from the yield/1 function directly in the calling process. Currently if something goes wrong will our function is being executed by the promise the process will crash. We need to handle exceptions that may occur during the execution of the function so this doesn’t happen. We can do that by wrapping the function call in a try catch block and then sending a different message back to the calling process process based on the outcome:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
promise(ExecutorFun) ->
    Tag = erlang:make_ref(),
    Self = self(),
    WorkerFun = fun() ->
        % Do the work

        Response = try ExecutorFun() of
            Result ->
                % If everything goes as planned just return an `ok` tuple with the response
                {ok, Result}
            catch
                Error:Reason ->
                    % Otherwise return an error tuple with the exception type and reason
                    {error, Error, Reason}
        end,

        % Send a message with the result back to the callers process
        Self ! {Tag, Response}
    end,
    spawn(WorkerFun),

    % Return the reference so we can use it in the yield function
    Tag.

This is all that is needed. This promise function takes a function to execute just like the Promise object in JavaScript, spawns a process to run the function, and then sends a message back to the calling process after the function has returned or crashed. We’ve done all this in less than 30 lines of code. Using the new function that handles exceptions is easy. Here we create a promise that immediately crashes, and then we pattern match on the value returned from yield/1 in a case statement:

1
2
3
4
5
6
7
8
9
10
% Crash the promise process
Tag = promise(fun() -> exit(crash) end),
% Do some other things...
% Then get the results from the promise when we need it
case yield(Tag) of
    {ok, Result} ->
         io:format("Success!", []);
    {error, Error, Reason} ->
         io:format("Failed with ~p due to ~p", [Error, Reason])
end

We now have one block of code that is executed when things go as expected and another that is run when an exception occurs. As you can see there is no need to chain callback functions onto the promise because yield/1 blocks when we need to get the results and the current process will wait until the promise message has been received. There isn’t an equivalent in JavaScript for this. The closest we can get in JavaScript is chaining then and catch callbacks on a promise like this:

1
2
3
4
5
6
7
new Promise(function() {
           throw 'crash';
        }).then(function() {
            console.log("Success!");
        }).catch(function(reason) {
            console.log("Failed with " + reason);
        });

This is very different because the callbacks are executed asynchronously, whereas in the Erlang code above our yield function is synchronous. If we wanted asynchronous callbacks to be executed in the Erlang promise variation we would simply call them from inside the function we pass into the promise. Something like this:

1
2
3
4
5
6
ThenCallback = fun() -> io:format("Success!", []) end,

Tag = promise(fun() ->
        do_some_work(), % Do everything we need to
        ThenCallback() % Then execute our callback function
    end),

Conclusion

We’ve used spawn, ! (send), and receive to construct a promise function and a yield function in less than 30 lines of code. Our promise function handles executing the executor function in a another process, catching errors that may occur, and sending the appropriate message back to the calling process. The yield function handles receiving the response message and could also enforce a timeout if the promise took too long. This wouldn’t be possible without Erlang’s concurrency primitives. We don’t ever use promises in Erlang because of other things like gen_server and Elixir’s Task, but hopefully this blog post has shown some of the inherit flexible in Erlang’s concurrency primitives.

References