Installing NeoVim on Manjaro
Note: If you want it to be considerably simpler, but still don’t want to miss the Vim or Neovim feeling, then you can also use this Rust editor: Zed - Your last next editor - https://zed.dev/
Manjaro’s official repositories usually offer a current version of Neovim.
With pacman
sudo pacman -Syu
sudo pacman -S neovim lua51
After installation, you can check the version with the following command:
nvim --version
Installing Rust
What Is Rustup - Toolchain
Advantage of Rustup
Rustup is the official toolchain manager for Rust. Without Rustup, you install Rust once via your distribution’s package management and are tied to that one version. Rustup additionally offers the following advantages:
Multiple Toolchains in Parallel
You can install the stable, beta, and nightly versions of Rust at the same time and switch between them:
rustup install nightly
rustup install beta
rustup default stable
rustup override set nightly # only for the current project
This is particularly useful, since some crates (programs or libraries) only run on nightly, for example for experimental features.
Project-Specific Versions
With a rust-toolchain.toml file in the project folder, you define which Rust version the project uses:
[toolchain]
channel = "1.75.0"
components = ["rustfmt", "clippy"]
As soon as you switch into the folder, Rustup automatically activates the matching version. This ensures that all team members and CI systems use the same version.
Pinning to Exact Versions
You can specifically install a particular Rust version to ensure reproducible builds:
rustup install 1.75.0
rustup default 1.75.0
Installing Additional Components
Additional tools such as rustfmt, clippy, rust-analyzer, or rust-src can be added or removed at any time:
rustup component add clippy
rustup component remove rust-docs
Target Support
For cross-compilation, you can add targets for other platforms:
rustup target add aarch64-unknown-linux-gnu
rustup target add x86_64-pc-windows-gnu
Updates
Rustup updates the toolchains with one command:
rustup update
In contrast, with installation via pacman you depend on the distribution’s update cycles, which often lag months behind.
Advantage of a Toolchain
A toolchain is the actual complete Rust package and consists of several components:
rustc: the compilercargo: the build manager and package managerrust-std: the standard libraryrust-docs: the local documentation- optional components such as
rustfmtandclippy
Why This Is Important
The advantage lies in the fact that all components of a toolchain are coordinated with one another. The compiler, the standard library, and the tools come from the same version. This avoids version conflicts such as can occur with manually assembled installations.
Channel Instead of Version
A toolchain is referenced via a channel (stable, beta, nightly) or via an exact version (1.75.0). This allows you to either always use the latest stable features or to rely on a fixed version when your project requires it.
Comparison: Rustup vs. Package Manager
| Aspect | Rustup | pacman |
|---|---|---|
| Version | Current | Often outdated |
| Multiple versions | Yes | No |
| Channel switching | Yes | No |
| Project-specific versions | Yes | No |
| Installing additional components | Yes | Partially |
| Cross-compilation targets | Yes | Limited |
| Update cycle | Independent | Dependent on distribution |
When Is the Package Manager Enough?
If you only use Rust occasionally, do not need project-specific versions, and are satisfied with your distribution’s version, installation via pacman is sufficient. For professional development, however, Rustup is clearly the better choice.
Installing Rustup
Step 1: Install base-devel & Rustup from the repository
sudo pacman -S base-devel rustup
Step 2: Activate the toolchain
rustup default stable
Important: The rustup package from the Arch repositories does not install a toolchain by default. The binaries (rustc, cargo) are symbolic links to rustup, so the toolchain must be activated manually.
Step 3: Verify the installation
rustc --version
cargo --version
Development Tools
After installing Rustup, you can add additional components:
rustup component add rustfmt # Code formatting
rustup component add clippy # Static analysis
rustup component add rust-analyzer # Language server for IDEs
Testing the Rust Installation
cargo new hello_world
cd hello_world
cargo run
NeoVim 4 Rust
To program Rust in Neovim, you essentially need Rust itself (done), the language server rust-analyzer, and a Neovim LSP configuration.
LSP - Language Server rust-analyzer
- rust-analyzer (the LSP server): This is the heart of code completion, error checking, and navigation. The best way is to add it as a component via
rustup. rustup component add rust-analyzer
Because there are occasional problems with invoking rust-analyzer, the following adjustment should also be made.
If the invocation does not work
rust-analyzer --version
install explicitly and then call the above command again
sudo pacman -S rust-analyzer
All of this has to do with a broken symlink/proxy. Possibly more on that later. For now, it should just work!
Neovim Configuration
# Overview of the directories
~/.config/nvim/
├── init.lua # Entry point, loads config.lazy
└── lua/
├── config/
│ └── lazy.lua # Bootstrap & setup for lazy.nvim
└── plugins/
├── init.lua # Placeholder, prevents errors
├── rust.lua # rustaceanvim
└── completion.lua # blink.cmp
- Create the configuration directory
mkdir -p ~/.config/nvim
- Install the plugin manager lazy.vim
Before you begin, make sure that Neovim (>= 0.8.0) and Git (>= 2.19.0) are installed on your system.
nvim --version | head -n 1 && git --version
If Git is not yet installed:
sudo pacman -S git
- Create configuration files
First create the required folders and files in your Neovim configuration directory.
mkdir -p ~/.config/nvim/lua/config && mkdir -p ~/.config/nvim/lua/plugins
- Create or adjust
init.lua
Create the file ~/.config/nvim/init.lua (if it does not yet exist) and add this line:
nvim ~/.config/nvim/init.lua
require("config.lazy")
- Create bootstrap file for lazy.nvim
So that lazy.nvim does not return an error message, an empty init.lua must be created in ~/.config/nvim/lua/plugins/.
echo "return {}" > ~/.config/nvim/lua/plugins/init.lua
- Create the file
~/.config/nvim/lua/config/lazy.lua
nvim ~/.config/nvim/lua/config/lazy.lua
with the following content. This code in lazy.lua automatically downloads the plugin lazy.nvim if it is not yet present:
-- ~/.config/nvim/lua/config/lazy.lua
-- Bootstrap lazy.nvim
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not (vim.uv or vim.loop).fs_stat(lazypath) then
local lazyrepo = "https://github.com/folke/lazy.nvim.git"
local out = vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable", lazyrepo, lazypath })
if vim.v.shell_error ~= 0 then
vim.api.nvim_echo({
{ "Failed to clone lazy.nvim:\n", "ErrorMsg" },
{ out, "WarningMsg" },
{ "\nPress any key to exit..." },
}, true, {})
vim.fn.getchar()
os.exit(1)
end
end
vim.opt.rtp:prepend(lazypath)
-- Leader keys must be set before lazy.nvim
vim.g.mapleader = " "
vim.g.maplocalleader = "\\"
-- lazy.nvim setup
require("lazy").setup({
spec = {
{ import = "plugins" },
},
-- LuaRocks support with hererocks
rocks = {
enabled = true,
hererocks = true,
},
-- Colorscheme when installing
install = { colorscheme = { "habamax" } },
-- Automatic update check
checker = { enabled = true },
-- Performance
performance = {
rtp = {
disabled_plugins = {
"gzip",
"matchit",
"matchparen",
"netrwPlugin",
"tarPlugin",
"tohtml",
"tutor",
"zipPlugin",
},
},
},
})
- Verify the installation
After you have saved the configuration, restart Neovim. The plugin lazy.nvim should now install itself automatically.
Open lazy.nvim: Enter the command :Lazy to open the graphical interface.
Once lazy.nvim is running, you can proceed to the next step: setting up rustaceanvim in your plugin configuration.
- Install the plugin
rustaceanvim
There are two common ways to configure this. The simplest and most modern way is a special plugin for Rust.
This plugin is a kind of “all-inclusive package” for Rust in Neovim. It automatically connects to rust-analyzer and brings many useful functions without you having to configure the LSP server manually.
The rustaceanvim entry does not go into lazy.lua, but into a separate file in the plugins folder. The lazy.lua is only responsible for the bootstrap and global configuration of lazy.nvim. Your actual plugins belong in ~/.config/nvim/lua/plugins/.
Create a new file:
nvim ~/.config/nvim/lua/plugins/rust.lua
The file must return a table. The rustaceanvim entry is in this table:
-- ~/.config/nvim/lua/plugins/rust.lua
return {
{
"mrcjkb/rustaceanvim",
version = "^9", -- Version 9 for current Neovim versions
lazy = false, -- Important: Loads the plugin immediately
},
}
- Save the file.
- Restart Neovim.
- Enter
:Lazyand possiblyUto update lazy.nvimrecognizes the new file and installsrustaceanvimautomatically.- Open a
.rsfile.rustaceanvimthen startsrust-analyzer.
Plugin blink.cmp - autocompletion
Installation
Create the following file:
nvim ~/.config/nvim/lua/plugins/completion.lua
With the following content
return {
{
'saghen/blink.cmp',
-- Optional: Provides snippets for snippet completion
dependencies = { 'rafamadriz/friendly-snippets' },
-- Uses a release tag to download prebuilt binaries.
-- This is the recommended way for the best performance.
version = '1.*',
---@module 'blink.cmp'
---@type blink.cmp.Config
opts = {
-- 'default' uses key bindings similar to those of the built-in
-- completion (e.g., <C-y> to accept)
keymap = { preset = 'default' },
appearance = {
-- 'mono' for 'Nerd Font Mono' to align icons correctly
nerd_font_variant = 'mono'
},
-- By default, suggestions from LSP, file paths,
-- snippets, and the current buffer are used.
sources = {
default = { 'lsp', 'path', 'snippets', 'buffer' },
},
-- Uses the Rust implementation for the fuzzy matcher (faster),
-- but automatically falls back to the Lua implementation.
fuzzy = { implementation = "prefer_rust_with_warning" }
},
opts_extend = { "sources.default" }
}
}
Shortcuts
blink.cmp uses the default preset by default, which is based on the built-in Neovim completion. The most important key bindings in insert mode are:
<C-Space>: Open the menu or toggle documentation.<C-y>: Accept the selected suggestion.<C-e>: Close the menu (and undo the preview).<C-n>/<C-p>(or arrow down/up): Select the next or previous entry.<C-k>: Toggle signature help (if enabled).<C-b>/<C-f>: Scroll in the documentation preview.<Tab>/<S-Tab>: Jump between snippet placeholders.
If you want different behavior, you can simply choose a different preset in your blink.cmp configuration, e.g., keymap = { preset = 'super-tab' } for tab-to-accept.
In addition to the shortcuts I mentioned, blink.cmp has a few more that are available depending on the configuration and context (e.g., in the command line).
Presets
In blink.cmp, presets are pre-made keyboard layouts that determine how you operate the completion menu. They are, so to speak, “packages” of key bindings for specific ways of working.
The Most Important Presets at a Glance
You choose a preset via keymap = { preset = 'name' } in your configuration.
default: Based on the built-in Neovim completion. You confirm a suggestion with<C-y>(like “Yes”).super-tab: Based on VS Code. The Tab key accepts the selected suggestion.enter: Uses the Enter key (<CR>) to accept. The Tab key remains reserved for navigating between snippet placeholders.cmdline: Is specially optimized for the command line (:). The Tab key shows the menu, inserts the first entry, or selects the next one.
Common Keys in All Presets
Regardless of the chosen preset, some keys are always assigned the same way, for example:
<C-space>: Open the menu or toggle documentation.<C-n>/<C-p>(or arrow keys): Select the next or previous entry.<C-e>: Close the menu.
The Most Important Presets Compared
blink.cmp comes with various predefined keyboard layouts, the so-called presets. Your currently used shortcuts (<C-Space>, <C-y>, <C-e>, etc.) belong to the default preset. Other presets change the assignment fundamentally:
| Function | default | super-tab | enter | cmdline |
|---|---|---|---|---|
| Accept | <C-y> | <Tab> (smart) | <CR> (Enter) | <Tab> |
| Next | <C-n>, <Down> | <C-n>, <Down> | <C-n>, <Down> | <Tab>, <C-n> |
| Previous | <C-p>, <Up> | <C-p>, <Up> | <C-p>, <Up> | <S-Tab>, <C-p> |
| Snippet forward | <Tab> | <Tab> (smart) | <Tab> | — |
So if, for example, you want Tab to accept the suggestion (as in VS Code), you change keymap = { preset = 'super-tab' } in your configuration.
Other Useful Standard Shortcuts
Regardless of the preset, there are some commands that are found in most configurations:
<C-k>: Toggles signature help (if enabled).<C-b>/<C-f>: Scrolls up/down in the documentation preview.<C-l>: Shows the completion menu or the documentation.<C-e>: Closes the menu (and undoes an automatic preview).
Shortcuts in the Command Line (cmdline)
When you type in the Neovim command line (:), different rules often apply. The cmdline preset is specially optimized for this:
<Tab>: Shows the menu, inserts the first element, or selects the next one.<S-Tab>: Selects the previous element.<Right>/<Left>: Navigates through the suggestions as in normal completion.
Defining Your Own Shortcuts
You can adjust the assignment at any time. If, for example, you want to use <CR> (Enter) to accept, you change the keymap entry in your blink.cmp configuration:
keymap = { preset = 'enter' },
Or you define completely custom combinations by setting preset = 'none' and assigning the keys yourself.
Example:
-- ~/.config/nvim/lua/plugins/completion.lua
return {
{
'saghen/blink.cmp',
dependencies = { 'rafamadriz/friendly-snippets' },
version = '1.*',
opts = {
keymap = { preset = 'enter' }, -- Here the preset is chosen
-- ... remaining options such as appearance, sources, fuzzy
},
},
}
Installation Script for Neovim, Rust, and Plugins on Manjaro
For the impatient with a willingness to take risks: Here is a complete Bash script that automates all steps from your guide. It installs Neovim, Rust (via Rustup), the Rust components, and sets up the complete Neovim configuration with lazy.nvim, rustaceanvim, and blink.cmp.
#!/usr/bin/env bash
### ### install_neovim_rust.sh
### Installs Neovim, Rust (Rustup) and sets up the Neovim configuration
### with lazy.nvim, rustaceanvim, and blink.cmp on Manjaro.
### ### Author: hoergen (template), automated
### Date: 2026-09-22
###
set -euo pipefail
### ------------------------------------------------------------------
### Colors for output
### ------------------------------------------------------------------
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m' # No Color
info() { echo -e "${GREEN}[INFO]${NC} $*"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
### ------------------------------------------------------------------
### 0. Check prerequisites
### ------------------------------------------------------------------
if [[ $EUID -eq 0 ]]; then
error "Please do NOT run as root. The script uses sudo where necessary."
exit 1
fi
if ! command -v pacman &>/dev/null; then
error "pacman not found. This script is intended for Manjaro/Arch."
exit 1
fi
### ------------------------------------------------------------------
### 1. Update system and install Neovim + Lua
### ------------------------------------------------------------------
info "Updating package database and system ..."
sudo pacman -Syu --noconfirm
info "Installing Neovim, Lua 5.1, git, base-devel, and rustup ..."
sudo pacman -S --noconfirm --needed \
neovim \
lua51 \
git \
base-devel \
rustup
### ------------------------------------------------------------------
### 2. Activate Rust toolchain
### ------------------------------------------------------------------
info "Activating Rust stable toolchain ..."
if ! rustup toolchain list | grep -q '^stable'; then
rustup default stable
else
info "stable toolchain is already active."
fi
### ------------------------------------------------------------------
### 3. Install Rust components
### ------------------------------------------------------------------
info "Installing Rust components: rustfmt, clippy, rust-analyzer ..."
rustup component add rustfmt || warn "rustfmt could not be installed."
rustup component add clippy || warn "clippy could not be installed."
rustup component add rust-analyzer || warn "rust-analyzer (rustup) could not be installed."
### Fallback: rust-analyzer from the repos if the rustup call does not work.
if ! command -v rust-analyzer &>/dev/null; then
warn "rust-analyzer not found in PATH. Installing from the repos ..."
sudo pacman -S --noconfirm --needed rust-analyzer
fi
### ------------------------------------------------------------------
### 4. Check versions
### ------------------------------------------------------------------
info "Checking installations ..."
nvim --version | head -n 1
rustc --version
cargo --version
rust-analyzer --version 2>/dev/null || warn "rust-analyzer --version not available."
### ------------------------------------------------------------------
### 5. Create Neovim configuration directory
### ------------------------------------------------------------------
NVIM_CONFIG="$HOME/.config/nvim"
NVIM_LUA="$NVIM_CONFIG/lua"
NVIM_PLUGINS="$NVIM_LUA/plugins"
info "Creating Neovim configuration directories ..."
mkdir -p "$NVIM_CONFIG"
mkdir -p "$NVIM_LUA/config"
mkdir -p "$NVIM_PLUGINS"
### ------------------------------------------------------------------
### 6. Create init.lua
### ------------------------------------------------------------------
info "Creating $NVIM_CONFIG/init.lua ..."
cat > "$NVIM_CONFIG/init.lua" <<'EOF'
require("config.lazy")
EOF
### ------------------------------------------------------------------
### 7. Plugin init (empty so that lazy.nvim does not throw errors)
### ------------------------------------------------------------------
info "Creating $NVIM_PLUGINS/init.lua ..."
cat > "$NVIM_PLUGINS/init.lua" <<'EOF'
return {}
EOF
### ------------------------------------------------------------------
### 8. Create lazy.lua bootstrap file
### ------------------------------------------------------------------
info "Creating $NVIM_LUA/config/lazy.lua ..."
cat > "$NVIM_LUA/config/lazy.lua" <<'EOF'
-- ~/.config/nvim/lua/config/lazy.lua
-- Bootstrap lazy.nvim
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not (vim.uv or vim.loop).fs_stat(lazypath) then
local lazyrepo = "https://github.com/folke/lazy.nvim.git"
local out = vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable", lazyrepo, lazypath })
if vim.v.shell_error ~= 0 then
vim.api.nvim_echo({
{ "Failed to clone lazy.nvim:\n", "ErrorMsg" },
{ out, "WarningMsg" },
{ "\nPress any key to exit..." },
}, true, {})
vim.fn.getchar()
os.exit(1)
end
end
vim.opt.rtp:prepend(lazypath)
-- Leader keys must be set before lazy.nvim
vim.g.mapleader = " "
vim.g.maplocalleader = "\\"
-- lazy.nvim setup
require("lazy").setup({
spec = {
{ import = "plugins" },
},
-- LuaRocks support with hererocks
rocks = {
enabled = true,
hererocks = true,
},
-- Colorscheme when installing
install = { colorscheme = { "habamax" } },
-- Automatic update check
checker = { enabled = true },
-- Performance
performance = {
rtp = {
disabled_plugins = {
"gzip",
"matchit",
"matchparen",
"netrwPlugin",
"tarPlugin",
"tohtml",
"tutor",
"zipPlugin",
},
},
},
})
EOF
### ------------------------------------------------------------------
### 9. rustaceanvim plugin configuration
### ------------------------------------------------------------------
info "Creating $NVIM_PLUGINS/rust.lua ..."
cat > "$NVIM_PLUGINS/rust.lua" <<'EOF'
-- ~/.config/nvim/lua/plugins/rust.lua
return {
{
"mrcjkb/rustaceanvim",
version = "^9", -- Version 9 for current Neovim versions
lazy = false, -- Important: Loads the plugin immediately
},
}
EOF
### ------------------------------------------------------------------
### 10. blink.cmp plugin configuration
### ------------------------------------------------------------------
info "Creating $NVIM_PLUGINS/completion.lua ..."
cat > "$NVIM_PLUGINS/completion.lua" <<'EOF'
-- ~/.config/nvim/lua/plugins/completion.lua
return {
{
'saghen/blink.cmp',
-- Optional: Provides snippets for snippet completion
dependencies = { 'rafamadriz/friendly-snippets' },
-- Uses a release tag to download prebuilt binaries.
-- This is the recommended way for the best performance.
version = '1.*',
---@module 'blink.cmp'
---@type blink.cmp.Config
opts = {
-- 'default' uses key bindings similar to those of the built-in
-- completion (e.g., <C-y> to accept)
keymap = { preset = 'default' },
appearance = {
-- 'mono' for 'Nerd Font Mono' to align icons correctly
nerd_font_variant = 'mono'
},
-- By default, suggestions from LSP, file paths,
-- snippets, and the current buffer are used.
sources = {
default = { 'lsp', 'path', 'snippets', 'buffer' },
},
-- Uses the Rust implementation for the fuzzy matcher (faster),
-- but automatically falls back to the Lua implementation.
fuzzy = { implementation = "prefer_rust_with_warning" }
},
opts_extend = { "sources.default" }
}
}
EOF
### ------------------------------------------------------------------
### 11. Install plugins headless (lazy.nvim sync)
### ------------------------------------------------------------------
info "Installing plugins via lazy.nvim (headless) ..."
if nvim --headless "+Lazy! sync" +qa 2>/dev/null; then
info "Plugins successfully synchronized."
else
warn "Headless sync failed. Please start Neovim manually and run ':Lazy sync'."
fi
### ------------------------------------------------------------------
### 12. Done
### ------------------------------------------------------------------
info "Done! Summary:"
echo " - Neovim version: $(nvim --version | head -n 1)"
echo " - Rust version: $(rustc --version)"
echo " - Cargo version: $(cargo --version)"
echo " - rust-analyzer: $(rust-analyzer --version 2>/dev/null || echo 'not available')"
echo " - Neovim config: $NVIM_CONFIG"
echo
info "Start Neovim with 'nvim' and check with ':Lazy' whether all plugins are installed."
info "Open a .rs file to test rustaceanvim and rust-analyzer."
Usage
Save the file as e.g.,
install_neovim_rust.sh.Make it executable:
chmod +x install_neovim_rust.shStart it (not as root):
./install_neovim_rust.sh
What the Script Does
| Step | Action |
|---|---|
| 1 | System update via pacman -Syu |
| 2 | Installation of neovim, lua51, git, base-devel, rustup |
| 3 | Activation of the Rust stable toolchain |
| 4 | Adding rustfmt, clippy, rust-analyzer |
| 5 | Fallback: rust-analyzer from the repos if the rustup version is not in PATH |
| 6 | Creating the directories ~/.config/nvim/lua/{config,plugins} |
| 7 | Creating init.lua with require("config.lazy") |
| 8 | Creating the empty plugins/init.lua |
| 9 | Creating config/lazy.lua (bootstrap + setup) |
| 10 | Creating plugins/rust.lua (rustaceanvim) |
| 11 | Creating plugins/completion.lua (blink.cmp, preset default) |
| 12 | Headless installation of the plugins via nvim --headless "+Lazy! sync" +qa |
Notes
- The script deliberately uses the
defaultpreset forblink.cmp. The custom shortcuts (e.g.,super-taborenter) are not included – you can adjust them later in~/.config/nvim/lua/plugins/completion.lua. rust-analyzeris first installed viarustup. If that fails or the command does not end up in PATH, the package from the Manjaro repos is automatically installed afterwards.- The plugin installation runs headless. If that fails, you can simply start Neovim normally and run
:Lazy sync.