Bloerg
       

Beamer is an awesome way to make slides with LaTeX. But I always felt that the stock themes do not necessarily look particularly nice and the custom themes often scream “Beamer” at first sight.

So, I sat down and made the mtheme …

2014-09-20/mtheme.png

In the spirit of Jan Tschichold and Matthew Butterick, the theme tries to minimize visual noise and maximize space for content. Thus an ordinary slide is free of superfluous elements such as a navigation bar, progress indicators and heavy block elements. What’s left is all the necessary information: the frame titles, a frame number to refer to the slide and the actual content.

Colors

Yes, teal and orange is an annoying fad in movie productions but it is a refreshing choice for a presentation theme. Rather than using both colors all the time, a dark teal tone is used for the majority of the Beamer elements while orange is used to highlight bits and pieces such as \alert{} commands. Instead of going for an all-white background, I toned it down a tiny notch to reduce eye strain but keep the contrast high enough to easily discern individual letters.

Fonts

Fira Sans is gorgeous typeface commissioned by Mozilla and designed by Carrois. It comes with an enormous amount of styles and features that cover even the most adventurous presentations. In the mtheme I used Fira Sans Light as the main font and the regular Fira Sans Book typeface for any heavier uses such as \textbf{}. Fira Sans Mono is a perfect match for lstlistings or minted environments.

Titles tend to be difficult to get right because of capitalization which almost always looks weird. I avoid this problem by lowercasing frame titles and set them in small capitals of Fira Sans Book.

Sections

In a presentation it can sometimes be difficult to go from one sub-topic to another. An elegant solution is to insert a slide whenever a new section starts. As a little gimmick, the mtheme features a tiny progress bar drawn with TikZ below the section title.

Conclusion

Even though this theme might give your presentation a somewhat “professional” look, you should focus on content first. Because the comments are not back yet, you can leave any feedback in this reddit thread.

There haven’t been in any posts for a while and I sincerely have to apologize that this will continue for at least two months. This will also affect the comment section, which I will deactivate to reduce the amount of moderation.

I knew, Google was scanning my mail to present personalized ads to me but I never saw them though because of AdblockPlus. I got back to reality, when Gmail offered me to track the delivery of an Amazon order …

2014-04-29/amazon-gmail.png

I use git-annex to distribute and synchronize fairly large and mostly static files across different machines. However, being based on Git makes it pretty uncomfortable to use from the command line. So, why not integrating it into our favorite command line file manager, ranger? Because I struggled a bit with ranger’s internals, I will outline how I wrote the plugin.

Initialization

First of all, we need a place for our plugin. By default ranger imports every Python module from $XDG_CONFIG_HOME/ranger/plugins in lexicographic order. If $XDG_CONFIG_HOME is not set, ~/.config is used as the default alternative.

To use the plugin from within ranger, you need to provide code that hooks into one of the two methods provided by the ranger API. hook_init is called before the UI is ready, which means you can dump output on stdout, whereas the UI can be used in hook_ready. The suggested way is not to replace the original function but chaining up like this:

import ranger.api

old_hook_init = ranger.api.hook_init

def hook_init(fm):
    # setup
    return old_hook_init(fm)

ranger.api.hook_init = hook_init

Adding new commands

In the introductory post, I briefly explained how to write custom commands which you add to your commands.py file: You simply subclass from ranger.api.commands.Command and write code in the execute method. However, commands defined in a plugin are not automatically added to the global command list. For this you need to extend the commands dictionary of the file manager instance, i.e.

def hook_init(fm):
    fm.commands.commands['annex_copy'] = copy

When using the annex_copy command, tab-completion should cycle through all available remotes. This is done by returning an iterable in the tab method. In the execute method you can access arguments, by calls to the arg method:

class copy(ranger.api.commands.Command):
    def tab(self):
        return ('annex_copy {}'.format(r) for r in remotes)

    def execute(self):
        remote = self.arg(1)

Asynchronous calls

The git-annex plugin works on the current or currently selected list of files, which you can get via fm.env.get_selection(). To avoid blocking the UI while fetching large files, I use the CommandLoader to run the git annex commands in the background (thanks @hut). The loader emits a signal when the action is finished to which we subscribe in order to refresh the directory content:

class copy(ranger.api.commands.Command):
    def execute(self):
        remote = self.arg(1)

        def reload_dir():
            self.fm.thisdir.unload()
            self.fm.thisdir.load_content()

        for path in (str(p) for p in self.fm.env.get_selection()):
            fname = os.path.basename(path)
            cmd = ['git', 'annex', 'copy', '-t', remote, fname]
            loader = CommandLoader(cmd, "annex_copy to remote")
            loader.signal_bind('after', reload_dir)
            fm.loader.add(loader)

Long running actions can be cancelled by the user, so if you need to clean up you should add that extra code to the cancel method.

Wrap up

That’s it, a plugin that registers new commands for interacting with git-annex an asynchronous way. Bug reports and pull requests are welcome.