Ever since I started reading blogs, I always wanted to start writing one myself, but I could not get myself to do it. Reading about how it could help me improve and also seeing open source developers convincing people write one, I figured it could at least help me get better at writing, even if nobody ever reads it.
After making the decision to write a blog post, I had to pick a topic, so for my first blog post ever and I have decided to write about my open source project with the most reach so far, my Neovim plugin for devcontainers. I have initially hosted on GitHub, but later I have decided it's better to host it on a free and open source platform, like Codeberg or Sourcehut. I have still left a mirror on GitHub, since that's where most of Neovim plugins are and where most plugin managers expect to find plugins (even though most of them support other platforms too).
In 2021, I worked on projects that required me to use containers in my
workflow. Looking at available Neovim plugins, the only one I found was
which did not offer much besides starting containers
devcontainer.json file. Even though I did not really have a need
for such a plugin anymore, I had some extra time and wanted to try building a proper
Neovim plugin (I have made a small one before,
but it barely offered any functionality).
Looking back at the initial commit, I guess I just wanted to experiment with idea of embedding Neovim in a container and connecting to it from current Neovim instance.
Goal of this plugin is to provide functionality similar to
VSCode's [remote container development](https://code.visualstudio.com/docs/remote/containers)
plugin and other functionality that enables development in docker container.
This plugin is inspired by [jamestthompson3/nvim-remote-containers](https://github.com/jamestthompson3/nvim-remote-containers),
but aims to enable having neovim embedded in docker container.
A lot has changed since then and I have set other goals for the plugin, while the original one isn't yet completed the way I wanted it initially.
Two weeks after the initial commit, I had prepared the first release. It had reached the original goal, but in a hacky way, by attaching to the container in a terminal buffer and hiding statusline from host Neovim instance, to make it seem like it's connected directly to the Neovim instance in the container. That made that feature confusing, since it wasn't clear that there's an embedded Neovim running, but I hoped that new Neovim release would make it easy to implement my initial idea.
Starting containers defined in .devcontainer.json is probably the only useful feature of the first release
Next 2 releases came fast, after I realised that I haven't thought the whole plugin through and that it wasn't providing the main features in an obvious way. I have also realised almost nobody cares about releases when it comes to Neovim plugins, since most users just use main branch as the target, so after 0.2.0 I have stopped versioning the plugin, even though more commits have been made after that release, than since the initial commit.
Shortly after release, there was a request to enable more container tools to be
used (like Podman). Since I wasn't interested in making
the plugin even more complicated by using Engine API, I just patched in support
and that was the moment the plugin started diverging from the idea of mimicking
The initial release offered 14 different commands
out of which most would probably never be used (since there were combinations of build,
run and attach sub commands). The latest version offers only 8,
but offers more functionality compared to the original 14. This could probably
be further reduced, since some of these are still less used, but at least it's
not as confusing as the original set and it offers only a single way of starting
DevcontainerStart), compared to 5 in the first release.
Use of arguments for
DevcontainerExec made it
possible to run arbitrary commands on running devcontainer (or any other running
container) and also attach to them in an embedded terminal.
Later updates also started using
vim.ui to make it more clear what is
happening when certain commands are started (like
DevcontainerStart, or when
autocommands are used), which has also helped reduce the number of commands,
since the plugin would now prompt the user if they would like to proceed to the
next step, be it starting or attaching the container.
The plugin now asks before installing Neovim, since it's a long process
After 2 years of occasional development of the plugin, it now offers:
- support for
- attaching to any command (defaulting to
nvim) and any container (defaulting to container defined in
devcontainerin the command)
- enabling users to manually add support for installing neovim in any container, by defining commands to run based on which package manager is available in the container
- optional autocommands for starting devcontainers automatically, removing them
when exiting Neovim and restarting then
- caching images after adding Neovim, since it takes too long to install it
- custom mounts and mounting local neovim configuration
- small extras, like build progress for statusline, UI prompts for some of the features, autocommand events
Please note that demo above includes my full configuration, including plugins for different UI elements. The plugin does not add any UI itself, but it just uses default configured elements.
Future of the plugin
Ever since I have added
podman support to the plugin, I realised that my goal
shouldn't be reaching parity with VSCode's plugin, but providing utilities that
enable Neovim users easier time when working with containers. Following the spec
.devcontainer.json as close as possible is still a goal, since it's
important when working in teams, considering that different developers may
prefer different tools.
Lately I haven't been using the plugin much. It's still in my configuration and it's most often used to automatically start containers related to the project when starting Neovim, but that is pretty much it. That is one of the reasons that I am not motivated enough to tackle some of the more difficult issues, which have been around since the first version, like:
- integration with LSP
- proper implementation of Neovim remote UI
- netman.nvim integration
- integration with DAP
I hope that you liked my short introduction of this plugin. Give it a try and let me know your thoughts.