No description
  • Lua 91.1%
  • Dockerfile 4.6%
  • Shell 4.3%
Find a file
Szwendacz 9ee49e70fc
All checks were successful
Build mc-devbox image / build-mc-devbox-amd64 (push) Successful in 11m15s
Build mc-devbox image / build-mc-devbox-arm64 (push) Successful in 1h1m4s
Build mc-devbox image / update-images-manifest (push) Successful in 6s
Merge pull request 'keymaps organizing' (#2) from wip into main
Reviewed-on: #2
2026-03-19 15:24:31 +00:00
.forgejo/workflows mc-devbox init 2026-03-17 19:45:10 +01:00
nvim keymaps organizing 2026-03-19 16:16:51 +01:00
.dockerignore mc-devbox init 2026-03-17 19:45:10 +01:00
AGENTS.md readme 2026-03-19 12:17:38 +01:00
build_stage.sh fixing lua ls build 2026-01-04 19:12:56 +01:00
Containerfile mc-devbox init 2026-03-17 19:45:10 +01:00
LICENSE Initial commit 2022-10-05 19:20:32 +00:00
README.md readme 2026-03-19 12:17:38 +01:00

My personal neovim as container configuration

I made this public so I can easily clone without authentication, but since I treat this as a personal use only stuff, there can be some (read "a lot of") messy stuff.

Much of this might have been selectively copy pasted from plugin repos. Those repos are obviously listed in plugin setup part.

Tested only with rootless podman, docker might require additional setup, or proper in-container user setup

Table of Contents

Host System Setup

Installing host system stuff, currently just fonts (Fedora example):

sudo dnf install -y \
    dejavu-fonts-all \
    gnu-free-mono-fonts

Image Management

Building the Image

git clone https://github.com/Szwendacz99/nvim && \
podman build -t neovim ./nvim && \
podman tag localhost/neovim:latest localhost/neovim:$(date +"%Y-%m-%dT%H-%M")

Exporting/Importing the Image

Pack to file with high compression:

podman save localhost/neovim:latest -o /dev/stdout | \
    xz -z -T 8 -c > neovim$(date +"%Y-%m-%dT%H-%M").tar.xz

Import file back to local registry:

podman load -i ./neovim.tar.xz

Usage Examples

Basic startup for editing current folder:

podman run --privileged -it --rm \
    -e XDG_RUNTIME_DIR=/runtime_dir \
    -e WAYLAND_DISPLAY=$WAYLAND_DISPLAY \
    -v $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY:/runtime_dir/$WAYLAND_DISPLAY \
    -v ~/.local/share/nvim/sessions:/root/.local/share/nvim/sessions \
    --workdir /data \
    -v "$(pwd):/data:rw" \
        neovim:latest

Custom Neovim Container Helper Functions

Temporary Container Function

Function for opening current dir or some files/folders in temporary container:

function nvim() {
    # Mount current folder OR folders/files given as parameters, then
    # open neovim. Container will be removed on neovim exit.
    # Mount wayland for clipboard sync.
    # Also pass all parameters to neovim as its arguments.

    for arg in "$@"; do
        if [ -f "$arg" ] || [ -d "$arg" ]; then
            local MOUNT_FILE=("${MOUNT_FILE[@]}" -v "$arg:$arg:rw")
            echo "Mounting $arg"
        fi
    done
    if [ -z "$MOUNT_FILE" ]; then
        # mount current workdir if no arguments with path
        # mount on base_path to make sessions saving work
        local base_path="$(pwd)"

        # use list as a trick to allow paths with spaces
        local MOUNT_FILE=(--workdir "/data$base_path" -v "$base_path:/data$base_path:rw")
    fi

    if [ -f "$HOME/.gitconfig" ]; then
        local MOUNT_FILE=("${MOUNT_FILE[@]}" -v "$HOME/.gitconfig:/root/.gitconfig:ro")
    fi

    if [ -f "$HOME/.ssh/known_hosts" ]; then
        local MOUNT_FILE=("${MOUNT_FILE[@]}" -v "$HOME/.ssh/known_hosts:/root/.ssh/known_hosts:ro")
    fi

    if [ -d "$XDG_RUNTIME_DIR" ]; then
        local MOUNT_FILE=("${MOUNT_FILE[@]}" -v "$XDG_RUNTIME_DIR:/runtime_dir:rw")
    else
        local MOUNT_FILE=("${MOUNT_FILE[@]}" --tmpfs "/runtime_dir")
    fi

    if [ -S "$SSH_AUTH_SOCK" ]; then
        local MOUNT_FILE=("${MOUNT_FILE[@]}" -v "$SSH_AUTH_SOCK:/runtime_dir/ssh-agent.socket:rw")
    fi

    # make sure there is a folder for sessions on default path
    mkdir -p ~/.local/share/nvim/sessions ~/.local/state/nvim/shada

    echo "Files mount options: ${MOUNT_FILE[*]}"
    podman run --privileged -it --rm \
        --shm-size=0 \
        --init \
        --network host \
        -e XDG_RUNTIME_DIR=/runtime_dir \
        -e SSH_AUTH_SOCK=/runtime_dir/ssh-agent.socket \
        -e WAYLAND_DISPLAY="$WAYLAND_DISPLAY" \
        -v ~/.local/share/nvim/sessions:/root/.local/share/nvim/sessions:rw \
        -v ~/.local/state/nvim/shada/:/root/.local/state/nvim/shada/:rw \
        "${MOUNT_FILE[@]}" \
        neovim:latest "$@"
}

Persistent Container Function

If there is need to make more persistent container that will also start with bash so you can install project dependencies and stuff:

function nvim_project() {
    # Mount current folder to a container that will not be removed on exit.
    # If you specify some paths as latter parameters, then these paths will
    # be mounted instead of current folder.
    # Also mounts wayland for clipboard sync.

    read -p "Enter container name: " container_name
    for arg in "$@"; do
        if [ -f "$arg" ] || [ -d "$arg" ]; then
            local MOUNT_FILE=("${MOUNT_FILE[@]}" -v "$arg:$arg:rw")
            echo "Mounting $arg"
        fi
    done
    if [ -z "$MOUNT_FILE" ]; then
        # mount current workdir if no arguments with path
        # mount on base_path to make sessions saving work
        local base_path
        base_path="$(pwd)"
        local MOUNT_FILE=(--workdir "/data$base_path" -v "$base_path:/data$base_path:rw")
    fi

    if [ -f "$HOME/.gitconfig" ]; then
        local MOUNT_FILE=("${MOUNT_FILE[@]}" -v "$HOME/.gitconfig:/root/.gitconfig:ro")
    fi

    if [ -f "$HOME/.ssh/known_hosts" ]; then
        local MOUNT_FILE=("${MOUNT_FILE[@]}" -v "$HOME/.ssh/known_hosts:/root/.ssh/known_hosts:ro")
    fi

    if [ -d "$XDG_RUNTIME_DIR" ]; then
        local MOUNT_FILE=("${MOUNT_FILE[@]}" -v "$XDG_RUNTIME_DIR:/runtime_dir:rw")
    else
        local MOUNT_FILE=("${MOUNT_FILE[@]}" --tmpfs "/runtime_dir")
    fi

    if [ -S "$SSH_AUTH_SOCK" ]; then
        local MOUNT_FILE=("${MOUNT_FILE[@]}" -v "$SSH_AUTH_SOCK:/runtime_dir/ssh-agent.socket:rw")
    fi

    # make sure there is a folder for sessions on default path
    mkdir -p ~/.local/share/nvim/sessions ~/.local/state/nvim/shada

    echo "Files mount options: ${MOUNT_FILE[*]}"
    podman run --privileged -it \
        --shm-size=0 \
        --init \
        --network host \
        -e XDG_RUNTIME_DIR=/runtime_dir \
        -e SSH_AUTH_SOCK=/runtime_dir/ssh-agent.socket \
        -e WAYLAND_DISPLAY="$WAYLAND_DISPLAY" \
        -v "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY:/runtime_dir/$WAYLAND_DISPLAY:rw" \
        -v ~/.local/share/nvim/sessions:/root/.local/share/nvim/sessions:rw \
        -v ~/.local/state/nvim/shada/:/root/.local/state/nvim/shada/:rw \
        "${MOUNT_FILE[@]}" \
        --entrypoint bash \
        "$@" \
        --name "nvim-$container_name" \
        neovim:latest
}

This container will not be removed on exit, you can reenter later with:

podman start -ai {project/container name}

Custom Functions

Opencode Function

Function for running opencode in a container with proper mounts:

opencode() {
    local image="mc-devbox"
    local mounts=()
    local filtered_args=()

    local opencode_data_dir="$HOME/.local/share/opencode"
    mkdir -p "$opencode_data_dir"

    local cwd="$(pwd)"
    local data_root="/data$cwd"

    # Track if we mounted anything explicitly
    local has_mounts=false

    for arg in "$@"; do
        if [ -e "$arg" ]; then
            has_mounts=true

            local abs="$(realpath "$arg")"
            local rel

            # Compute path relative to cwd
            rel="${abs#$cwd/}"

            # If outside cwd, just use basename fallback
            if [[ "$abs" == "$cwd" ]]; then
                rel="."
            elif [[ "$abs" != "$cwd"* ]]; then
                rel="$(basename "$abs")"
            fi

            mounts+=(-v "$abs:/data/$cwd/$rel:rw")
            echo "Mounting: $abs -> /data/$cwd/$rel"
        else
            filtered_args+=("$arg")
        fi
    done

    # If nothing mounted → mount current dir
    if [ "$has_mounts" = false ]; then
        mounts+=(-v "$cwd:$data_root:rw")
        echo "Mounting current directory: $cwd -> $data_root"
    fi

    # Always mount opencode data dir
    mounts+=(-v "$opencode_data_dir:/root/.local/share/opencode:rw")

    # Set correct workdir
    local workdir="$data_root"

    echo "Workdir: $workdir"
    echo "Mounts: ${mounts[*]}"
    echo "Args: ${filtered_args[*]}"

    podman run --privileged -it --rm $PODMAN_FLAGS \
        --entrypoint opencode \
        --log-driver none \
        --shm-size=0 \
        --init \
        --network host \
        --workdir "$workdir" \
        "${mounts[@]}" \
        "$image" \
        -c \
        "${filtered_args[@]}"
}

Custom Neovim Commands

Vim functions for activating different modes

  • MCModeAnsible - Sets filetype to yaml.ansible for .yml and .yaml files and starts ansible-ls LSP
  • MCModeHelm - Sets filetype to helm for .yml and .yaml files, starts helm_ls LSP, and stops yamlls

Key Bindings Reference

For a complete list of key bindings and commands available in this Neovim configuration, see the sections below.

Inside Neovim

Plugin Management

# manage plugins:
:Lazy

Unicode Support

There is a need to make sure your system can display (almost) any unicode character. Hacked fonts may be needed for filetype icons but there is also need for a dedicated package with unicode fonts (like unifont-fonts.noarch) that will have every character missing from default font used in Neovim editor.

Link to hacked fonts: https://www.nerdfonts.com/font-downloads

General Information

Commands and Keys

Vim functions for activating different modes
  • MCModeAnsible
  • MCModeHelm
General
keys action
<leader>l disable (search) highlighting
<leader>cb Close all buffers (:bufdo bd)
Opened files navigation
keys action
Ctrl w w Move to next splitted frame
Ctrl w <arrow> moving throught splitted frame
Ctrl w c close split
Ctrl w v split vertically
Ctrl w s split horizontally
Ctrl w x swap places of two splits
gt next tab
gT previous tab
:tabnew Create new tab
Ctrl+g Ctrl+t (when in file tree) open selected file in new tab
:bd close buffer
:bnext next buffer
:b3 switch to buffer 3
:buffers list buffers and their numbers
File explorer
keys action
Ctrl+t Toggle file explorer when not focused on it
f Toggle filtering when focused on explorer
<leader> n Move focus to explorer
d Delete selected file
rn Rename file
c add file to clipboard
p paste (file) from clipboard
File searching / Telescope
keys action
<leader>ff Find files
<leader>fg Live grep
<leader>fb Buffers
<leader>fh Help tags
Ctrl+/ Show mappings for picker actions (insert mode)
Ctrl+q Open search result list as a dedicated split (quickfix list) (will overwrite previous one created this way in current tab)
Ctrl+u Scroll preview up
Ctrl+d Scroll preview down
Ctrl+f Scroll left in preview window
Ctrl+k Scroll right in preview window
Ctrl+x Open selection as a split
Ctrl+v Open selection as a vsplit
Ctrl+t Open selection in new tab
Usefull Telescope commands

Find files including hidden

Telescope find_files hidden=true
Markdown Preview

Markdown plugin commands:

:RenderMarkdown*
Git stuff
Neogit

Just run :Neogit (shortcut: <leader>ng) to launch it, ? for help, changing parameters is done usually by adding - before letter assigned to specific option.

Diffview

Diff log / file history:

:DiffviewFileHistory

Diff log of single file (or dir):

:DiffviewFileHistory <filename/dirname>
Telescope git stuff

Commands: :Telescope git_*

Bindings:

keys action
gs git_status
gc git_commits
gb git_branches
GitSings provides some commands for displaying git stuff:
:Gitsigns *

#examples:
:Gitsigns toggle_word_diff
:Gitsigns toggle_linehl
:Gitsigns toggle_numhl
:Gitsigns toggle_signs
Code editing stuff
w jump forward by one word
b jump backward by one word
:%s/^original.\*/replacement/gc regex replacing (c is for choice prompt, its optional)
Ctrl+q Visual block select mode
LSP usage
<space>q open list with diagnostics postions
<space>e open diagnostics floating window
[d next diagnostic
] previous diagnostic
<leader>k open hoover box and enter it
<leader>rn rename element (function name, etc)
<leader>f format file
gd go to definition
gD go to declaration
<space>D go to type definition
gi go to implementation
gr go to references
Ctrl+f scroll down popup with docstring
Ctrl+b scroll up popup with docstring
<leader>wa add workspace folder
<leader>wr remove workspace folder
<leader>wl list workspace folders
LSP diagnostics (custom and trouble.nvim)
<leader>vt switch display of virtual text
<leader>xx Open diagnostics window
gR lsp references
<space>ca code action menu
Sessions

To save new session on specific path, just use :SaveSession, then when opening nvim there, without arguments, the session will be restored.

Notifications
:Notifications show recent notifications
:Telescope notify show recent notifications in telescope gui