musicmatzes blog

vim

I use vim for my everyday things. No, actually I use vim for everything.

And today I rewrote large parts of my vim configuration. Here's why.

Dead mappings

I removed a lot of mappings from my vimrc that I did not used. For example: I had a mapping in normal mode that'd fire up fzf for the complete filetree I was in. I didn't use it in months, maybe more, because I use netrw (the vim-builtin file manager).

I don't need plugins

Well, at least you don't need the most of them. First, I removed maybe three or four plugins I didn't use at all, for example the “linux-kernel-style” plugin or “Goyo” and “Limelight”. Not because I didn't like them (I do, believe me), but because I simply did not use them at all. I also removed everything with snippets, because I barely used them. So “UltiSnips” and all the snippet packages are gone now.

Then, for example, I had the vim plugin “vim-indent-guides” with a great snippet of viml I found online:

" Simple replacement for vim-indent-guides
"
" unicode characters explained:
" tab: \uBB == ">>"
" trail: \uB8 == "-" in red box
exec "set listchars=tab:\uBB\uBB,trail:\uB7,nbsp:~"
set list

This does the very same as indent-guides and even does more, because I can have a dot (unicode character \uB7) if there is trailing whitespace at the end of a line. I really like that!

vim as server

Because I'm running XFCE, as explained in another post for some time now (and I still like it), I figured that I could use gvim instead of commandline vim. But gvim startup time is not that great – so I figured that I could use the awesome vim server capability to have only one running vim instance.

So I re-configured my aliases to be

alias vim="vim -g --servername VIM --remote-tab-silent";

for example, so I automatically start in a running gvim instance (which has the name VIM by default). If no vim instance is running, this automatically starts a new gvim instance.

But because I'm a notorious :q-hitting vimmer, I remapped :q:

if has("gui_running")
  cnoremap <silent> wq<CR> w<bar>bd<CR>
  cnoremap <silent> q<CR>  bd<CR>
  cnoremap <silent> x<CR>  bd<CR>
  nmap <Leader>q :bd<CR>
endif

So when I hit :q it actually executes bd, which just closes the current buffer. If the current buffer is the last buffer, it enters an anonymous buffer instead. This is really awesome! To actually close my vim session, I have to :quit now, which is longer and therefor I have more time to stop myself from doing that.


Edit 2017-03-06:

The code above did not completely work as intended, so I changed it to the following:

if has("gui_running")
  fu! CloseWindowOrBuffer()
    if winnr('$') == 1
      if bufnr('$') == 1
        :echo "Closing last instance not allowed"
      else
        :bd
      endif
    else
      :close
    endif

  endf
  nmap <Leader>q :call CloseWindowOrBuffer()

  cnoremap <silent> wq<CR> w<CR>:call CloseWindowOrBuffer()<CR>
  cnoremap <silent> q<CR>  :call CloseWindowOrBuffer()<CR>
  cnoremap <silent> x<CR>  bd<CR>
else
  nmap <Leader>q :q
endif

I'm still not sure whether this is what I want.


env!

Finally, I set my $EDITOR and $GIT_EDITOR variables to

export EDITOR="vim -g --servername VIM --remote-tab-wait-silent"
export GIT_EDITOR="vim -g --servername VIM --remote-tab-wait-silent"

To get the best experience when calling vim through scripts or other programs like git.

What I want to get from this

Well, I made my vim installation a lot less bloated. By removing a bunch of plugins I made vim start up way faster, and by using only one vim instance for all the things, even more. Using gvim, I can have pretty fonts and so on.

I wonder how these things work out for me...

tags: #desktop #linux #vim

This post is about how to setup vim (vim_configurable) on NixOS with reusable parts and the possibility to replace vim with neovim without rewriting the whole setup.

configuration.nix

What we have in the configuration.nix file is simple:

environment.systemPackages = let
    vimPackages = import ./some/directory/vimPackages.nix pkgs;
    # neovimPackages = import ./some/directory/neovimPackages.nix pkgs;
in
    vimPackages ++ with pkgs; [ some other packages ];

You can see that we simply import some nix expressions and pass them the pkgs of from our configuration.nix file. Everything else is done in this file and some sub-files.

vimPackages.nix

So here starts the fun. We define a function which gets the pkgs variable and the lib variable from the outside scope (we don't pass the lib variable, though nix is smart enough to figure out what we mean). We already know that we need to return an array of packages, so we can return vim and some things we use in our vim scripts, like so:

# ...
[ vim pkgs.ctags ]

vim is not prefixed with a pkgs. here because we define it in the file itself. But first, we need to know what we want to override. vim_customize allows us to compile vim without GUI support, for example (there are a lot more options). We also want to build our vimrc and we want to put plugins into our vim setup, because this is the NixOS way of life.

customization = {
    vimrcConfig = (import ./customization.nix { pkgs = pkgs; });
} // { name = "vim"; };

Here we import our customization (vimrc, plugins, etc) and ensure that the executable is named "vim". We can now use this customization to customize vim_configurable:

custom_vim = pkgs.vim_configurable.customize customization;

and afterwards we override this derivation and set variables, what features should be compiled into vim:

vim = lib.overrideDerivation custom_vim (o: {
    ftNixSupport = true;
    gui          = false;
    luaSupport   = true;
    # some more
});

Now we put these parts together and into a function, so the whole file looks like this:

{ pkgs, lib, ... }:

let
  customization = {
    vimrcConfig = (import ./vim/customization.nix { pkgs = pkgs; });
  } // { name = "vim"; };

  custom_vim = pkgs.vim_configurable.customize customization;

  vim = lib.overrideDerivation custom_vim (o: {
    aclSupport              = false;
    cscopeSupport           = true;
    darwinSupport           = false;
    fontsetSupport          = true;
    ftNixSupport            = true;
    gpmSupport              = true;
    gui                     = false;
    hangulinputSupport      = false;
    luaSupport              = true;
    multibyteSupport        = true;
    mzschemeSupport         = true;
    netbeansSupport         = false;
    nlsSupport              = false;
    perlSupport             = false;
    pythonSupport           = true;
    rubySupport             = true;
    sniffSupport            = false;
    tclSupport              = false;
    ximSupport              = false;
    xsmpSupport             = false;
    xsmp_interactSupport    = false;
  });

in [
  vim
  pkgs.python
  pkgs.ctags
]

But that's not all to it. The customization.nix is where the real fun begins.

customization.nix

So this is the file where we define which plugins we want to use. There are some plugins which are not yet included in the nixpkgs repository, so we have to build these packages ourselves to be able to install them. Luckily, the nixpkgs provide some helper functions to build vim plugin packages rather easily.

Also, we build our vimrc file here, which consists of another bunch of script files.

vimrc.nix

The vimrc itself is written in viml of course. If you have a lot of vimrc configuration, you can split this file into several smaller ones. For example, I have split these files into the following structure:

./
├── colorschemes
│   ├── mm_neverness_share.vim
│   └── razorlight.vim
├── filetypes.vim
├── folding.vim
├── general.vim
├── gui.vim
├── insertmode.vim
├── mappings.vim
├── menuconf.vim
├── plugins
│   ├── # ... some things
│   └── ycm.vim
├── pluginconfigurations.nix
├── scripts.vim
├── searchnreplace.vim
├── statusline.vim
└── textediting.vim

So what we do in our vimrc.nix file (which later gets included in our customization.nix file) is: We include all these .vim files and put them into one giant string, which is then our vimrc file:

{ stdenv, writeText }:

let
    generic     = builtins.readFile ./vimrc/general.vim;
    textediting = builtins.readFile ./vimrc/textediting.vim;
    # ... more here

    plug = import ./vimrc/pluginconfigurations.nix;
in

''
    ${generic}

    ${textediting}

    # ... more here

    ${plug}
''

You might noticed the vimrc/pluginconfigurations.nix file. This one is just another layer of abstraction here and is basically the same as the vimrc.nix file:

let
    # some files
    ycm = builtins.readFile ./plugins/ycm.vim;
in

''
    # some variables
    ${ycm}
''

plugins.nix

Another file we need is the plugins.nix file. As said, not all vim plugins are in nixpkgs (yet). So we have to build some vim plugins ourselves (don't get scared here. This does not mean you have to run compilejobs yourself, most plugins don't contain any binaries so rebuilding the system with vim plugins installed is normally a matter of seconds).

So this one is also rather simple in the end. In the example below you can see how I build the vim-trailing-whitespace plugin. The version might be outdated, though.

{ pkgs, fetchgit }:

let
  buildVimPlugin = pkgs.vimUtils.buildVimPluginFrom2Nix;
in {

  "vim-trailing-whitespace" = buildVimPlugin {
    name = "vim-trailing-whitespace";
    src = fetchgit {
      url = "https://github.com/bronson/vim-trailing-whitespace";
      rev = "d4ad27de051848e544e360482bdf076b154de0c1";
      sha256 = "594769a6f901407609b635a5041966456bfd91b13437169a4562857544e1dca3";
    };
    dependencies = [];
  };

  # more?
}

Finally... put the parts together.

Now we can write down our customization.nix file, which imports the plugins.nix and vimrc.nix files and puts them in the right context, so the nixpkgs infrastructure understands how we want to have our vim package build:

{ pkgs }:

let
  # this is the vimrc.nix from above
  vimrc   = pkgs.callPackage ./vimrc.nix {};

  # and the plugins.nix from above
  plugins = pkgs.callPackage ./plugins.nix {};
in
{
  customRC = vimrc;
  vam = {
    knownPlugins = pkgs.vimPlugins // plugins;

    pluginDictionaries = [
      # from pkgs.vimPlugins
      { name = "youcompleteme"; }

      # from our own plugin package set
      { name = "vim-trailing-whitespace"; }
    ];
  };
}

Building

After putting these things together you can rebuild your system. The vim binary might be compiled from source, though this isn't that much of a problem because there are only few vim updates, so rebuilding vim will happen every four weeks or something, not on every system rebuild.

nixos-rebuild switch

neovim

As said, you can now use the infrastructure we just wrote to compile the very same configuration into neovim, including your vimrc, plugins and everything.

{ pkgs, lib, ... }:

let
  nvim = pkgs.neovim.override {
    # don't alias neovim to vim, yet.
    vimAlias = false;

    configure = (import ./vim/customization.nix { pkgs = pkgs; });
  };

in [
  nvim
  pkgs.python
  pkgs.ctags
]

Just make sure your vimrc settings don't mess with neovim. Some things are not supported by neovim, so you have to put them into if-else conditions like so:

if has("nvim")
  " we don't need this in nvim
else
  set clipboard=exclude:.*
endif

And that's it. tags: #nix #nixos #vim #neovim #programming

How do you do your Personal Information Management? Or, more specific: How do you organize your contacts over multiple devices, how do you organize your calendar, todo lists, notes, wiki, diary, browser bookmarks, shopping list, mails, news feeds,...

Do you use Google for all this? Maybe you do. Don't you want to uncouple from Google? Well, then... I have to tell you about the sad state of PIM for nerds.

If you want to organize your personal information without google and host everything on your own, you will soon meet tools like owncloud, emacs orgmode or similar tools. Sadly, all these things are not what I want. OwnCloud is getting more buggy with every release and it is already slow as hell. orgmode needs emacs, which is a huge tool itself and you have to learn a whole new ecosystem. If you are a vim user like me, you don't want to use emacs.

But I'm not talking about editors here. I'm talking about PIM tools. What I do right now: Owncloud with khard, khal, vdirsyncer for contacts and calendar organization. As said, OwnCloud is buggy and sometimes calendar entries cannot be synced to all my devices. On Android, I use Apps to sync my contacts and calendar as well, and they fail as well, sometimes.

I use taskwarrior, which has a sync server available. Sadly, it doesn't work yet on NixOS, but well, that's my issue and I'm working on a solution. Nevertheless, the Android client (Mirakel) is badly supported and does not work that good as well.

For news, I use ttrss, which works fine and the appropriate Android App works good, too, so no issue here. For a Wiki, I use Gollum, which works but is a bit annoying to use because it is not that customizable. I do not use note-taking tools at all, because they simply suck. There's no good note-taking tool available for commandline use which integrates with the other tools. Mails work fine with mutt, of course, but they cannot be integrated in the wiki, todolist tools or the other tools I just mentioned. I do not use browser bookmarks at all, because there is no CLI tool available for them. Same goes for shopping lists.

What I want

What I want is simple: One tool, which integrates

  • Personal wiki
  • Personal todolist
  • Personal notes
  • Personal mail indexing
  • Personal Calendars
  • Personal Contact management
  • Personal News Feeds (RSS/Atom mostly)
  • Personal Bookmarks
  • Personal Shopping list
  • Personal Diary

in the following ways:

  • I can use whatever
    • text editor
    • mail reader, sender, receiver
    • rss reader I want to use
  • I can synchronize everything to all devices, including Android smartphones or my Toaster
  • Everything is done with open standards. Means
    • vcard for contacts
    • ical for calendar
    • markdown for
    • wiki
    • notes
    • diary
    • shopping list
    • maybe YAML for todolist
    • mbox or Maildir for mails
    • normal Atom/RSS for news stuff
    • for bookmarks, YAML or JSON would be appropriate, I guess.
  • I can access all my data in the system with a text editor, if I have to
  • a clean and polished (+fast) Android Application to access and modify this data.
  • I can move/link data from one system to another. For example:
    • I can link an Email from my notes
    • I can link a entry from my RSS, notes, calendars to (for example) my Wiki
    • I can send a shopping list from my mail client to a contact and attach a calendar entry which links to the shopping list
    • ... and so on
  • All the things are encrypted (optionally)

As everything should be plain text, git would be fine for synchronization. The sync should be decentralized at least, so I don't have to host a server at home and cannot sync if I'm on the go. A web-hosted entity should be optional and so should be a web interface. Having a web-UI like owncloud has is nice, but not that critical for me. A full encryption of the content would be nice as well, but would be kinda hard for the Android devices, at least if the device gets lost. Anyways, my drives are encrypted and that should be enough for the first step.

It is, for me, really important that these tools interact well with eachother. The feature that I can send a mail to a contact and attach for example a shopping list, which itself has a calendar entry (which gets attached as well, if I want to), is a real point for me. Same goes for attaching a RSS entry to a wiki article or todo item.

Another requirement would be that the tool is fast and stable, of course. Open Source (and at best also free software) would be a crucial point to me as well. GPLv2 would be the thing.

Do it yourself, then!

Well, developing such a tool would be a monstrous huge amount of work. I'd love to have time for all this, especially as student. But I think I have not. I have a lot of opinions how such a tool should work and also a lot of ideas how to solve a certain problem which may arise, though I absolutely have no time to do this.

I, personally, would develop such a tool in Rust. Simply because it gives you so much power to your hands while remaining a really fast language in manner of execution speed (speaking of zero-cost abstractions here). Though, there would be the need for a lot of external libraries, for example for git, vcard, ical, yaml, json, markdown, configuration parsing, etc etc. While some of these things might be available already, others are clearly not.

Sadly, such a tool is not available. Maybe I can find time until I'm 35 years old to develop such a thing. Maybe someone else has done so until then. Maybe I just inspired you to develop it? Would be neat!

tags: #life #linux #mail #media #open source #programming #software #rust #tools #vim #wiki

Yes, I use chromium. And I just installed the “cvim” plugin, to be able to navigate with vim bindings in my chromium instances. And it just feels like it should! Out of the box!

Awesome!

For my daily browsing, I use dwb (but I want to switch to luakit, I just didn't find the time to do the actual switch, yet). For some pages I use firefox and lately also started using chromium for it. And, of course, I wanted chromium to behave like vim. So I installed “cvim”. I first thought “Yeah, another vim emulatro plugin, could be nice... but well... it is not really a vim” – But after installing it, I just continued with my normal workflow. It just felt right, right from the beginning. I started navigating web pages without thinking about it.

Awesome! I just wanted to share this, so if you're looking for a vim plugin for chromium, just use cvim. It is awesome.

tags: #software #vim

I just discovered that the a.vim plugin almost breaks my vim flow.

Here's why.

You might know the a.vim plugin. It was made to switch between source file and header file, including split-opening it and so on. It is really neat and I really like the idea. So I installed it. But unfortunately, it uses some insert-mode mappings which are mapped on <Leader> ... something. And as my Leader is space, it completely broke my vim flow, as everytime when I hit space, vim waits to complete my mapping... but I wasn't actually using a mapping, I was just typing.

This little offset broke everything for me... I could barely use vim. You might now say that I could set the timeout for vim to something small, like 300 or something. I tell you: No! It's just not the same.

So, I removed the a.vim plugin again. Sadly. Maybe there is an option to configure on what it is mapped, but I really don't care this much anymore!

tags: #programming #vim

Some of you might know my little project rate. It is a bash script to collect a database of things you want to rate.

What this means and why I started to reimplement in C++ – read it here!

So I started to write this application because I wanted to keep track of animes I already watched, Bands I like but do not listen to that often and so on and so forth. What the application does is really simple: You can enter notes about a certain thing (in your favourite text editor, which is vim for me) and attach tags to it and put it into a category. Then you can give it a rating. The rating can be everything, from simply numbers to text to whatever you like. But it is supposed to be a number between 1 and 10, of course. That's also the way I use it.

So how does it work? Well, that's really simple: The “rate” script creates a directory structure in ~/.rate/collections/, whereas a folder is a “collection” of things and a file is a rating. So, I have something like “movies/animes/” as collections (they are nested, of course) and then a file for each anime I watched. The filename is generated from the title I passed “rate” when creating the entry. The file also contains a “header”, which includes a unique ID (which you really should not change), a list of tags, the title (the filename is the title, too, but as on linux you shouldn't include whitespace in file names, it is not the title as you typed it) and a rating of course. Custom fields could be added to the header, but this feature is not implemented yet. After the header, you can put your description.

That's basically it. “rate” provides some features to search this database, for example you can grep for text in your entries, you can view your entries, you can list your entries and you can attach more text to your entries or edit them. As everything is git controlled in the ~/.rate directory, you can reset if you (or the script,...) messed up somehow.

There's no release by now, as it lacks of some features by now. For example I want to be able to search for entries with a certain rating or within a certain range of ratings. I also want to be able to search for entries with aspecial set of tags or within a certain collection (I can do this, though) special set of tags or within a certain collection (I can do this, already)! After these things are implemented, I will release my first version, which would be 1.0 then. And, of course, I will package it for NixOS!

So why C++

Well, I have to learn C++ for my praxis semester. That's basically it. I wanted to learn a new programming language for a relatively long time, and that's my approach on learning C++. I was able to implement some things, but not yet to run an application. My first step would be to parse my already existing entries. Hope that works. As I stated in the github repos README.md file, I do not want to use any frameworks for this. No Boost, no Qt, no other libraries. I just want to use plain C++11 (or maybe 14 in future, not sure about this, though).

Also, C++ gives me way more posibilities when it comes to features. I can refactor things really easy and maybe the C++ implementation will continue to live whereas the bash implementation will die at some point. Who knows? The point is, the bash implementation implements a file format which is

  1. really simple
  2. forward compatible

The file actually looks like this:

key = value
other = value
another = another
---

<text>

and that's basically it. The three dashes mark the end of the header and everything before the header is a <key> = <value> list, whereas each line is only allowed to contain one key-value-pair. The value can be a list of values, for example a list of Tags whereas tags are seperated by a whitespace character (space) or a string, such as the title is. The bash implementation “knows” which key has to be which value and the C++ implementation has to know this, too, of course. But that's it.

The commandline interface of the application needs some work, though. Maybe it will get some REPL-like interface later on, or maybe something more interactive. By now, it is simply an interface where you can do one thing per call. I have no problem with that and I'm planning to keep backward compatibility with the bash implementation even if this one is not even released! It is fun to write such a tool and I really like doing it.


Also, it is not a that complex thing to implement and that's a huge point to me. I don't want to spend months and months in implementing a thing which only one or two people on this planet actually use. For bigger projects, I contribute to open source projects. That's a better way to produce large-scale software, IMHO.

tags: #bash #programming #c++ #linux #shell #vim

I'm really happy at the moment. I recently started in contributing to neovim.

I've done three pull requests by now, one is already closed (without merge, though), the other two are still pending but one of them looks really good. Just wanted to share...

tags: #vim #programming #neovim

Sharing ones dotfiles has become more and more popular with the rise of github. Almost everyone has a dotfiles repository showing her or his dotfiles, including configuration for various programs. Also for vim – the vimrc – gets shared. Much too often as I think!

Why sharing dotfiles? And why don't?

I had a dotfiles repository, too. Long time ago. I will not share my dotfiles anymore. Here is why:

People share their dotfiles because they want to tell people how awesome they are. “Hey look, I have this awesome set of mappings in my vimrc, which enables me to be fast as light when doing X”. Sharing dotfiles has become some sort of race. Who is the best at manipulating tools to do their jobs more efficient? I don't want to take part in this race anymore.

Sharing the vimrc is also some kind of opening my own personal working style to everyone. From my vimrc, one can easily see how I work. So it's kind of an open window into my privacy. And that's a big no-go for me.

My vimrc has evolved over the last years. A lot of stuff got adapted to my workflow, and a lot of things got removed again. I would say that it is almost perfect by now. But only perfect for me. And this is why I consider my vimrc as big part of my privacy and something which is realy intimate for me. And I don't share intimate stuff. It's that easy!

But how do you contribute to the vim community?

Well, one can now argue that sharing the vimrc file is some kind of giving something back to the community and as I do not share it, I do not contribute to the community. That's true.

But I'm really fine with sharing my knowledge if someone actually asks me! No matter if it is via stackoverflow (I really like to answer questions on SO, if I can) or reddit or personally via email. Sharing experience and knowledge has nothing to do with sharing personal information, I think. And in this context, the “how do I do this” is experience or knowledge and the vimrc (or dotfiles) is personal information.

So, feel free to ask me things about vim, mutt, mpd, git or other tools – I will answer them, of course! But I will not show you my configuration of the tool!

tags: #vim

I always wanted to provide some vim tips for advanced vim users. I always feared the feedback, but I think I should do it now.

Use the leader!

Oh my god! Use it! You will get so much faster when using the leader on a regular basis. Of course you have to map it to your mostly used actions, but it can be such an performance win!

Here goes mine. Note that my leader is mapped to my space key:

let mapleader = ““ map w :w& map q :q nnoremap za onoremap za vnoremap zf map sc :SyntasticCheck map nt :NERDTreeToggle %:p:h map tb :TagbarToggle map ut :UndotreeToggle map vr :VimroomToggle map ig IndentGuidesToggle map ga :Git add %:p map gs :Gstatus& map gc :Gcommit -v -q map gd :Gdiff map gb :Gblame map gp :!git push map m :Make map h h map j j map k k map l l map s s map v v

You can find these mappings in my vimrc at github as well. Use it!

Don't use the arrow keys!

This is very critical for your speed when using vim. Never, ever use the arrow keys!

map map map map

You will get faster by lightyears!

This were two tips which are very critical when talking about speed when using vim. I don't know whether these match your idea of 'advanced vim tips', but they are very important to me. I got a performance increase by around 50% just by using hjkl instead of the arrow keys as well as I got faster by the same amount with the leader mappings.

Use them. Tell me what you think.

GPG: 20CA0F94

tags: #vim