16 KiB
Archduino — TUI-Only Arch Linux Arduino Development Environment
A keyboard-driven, mouse-free Arch Linux setup for Arduino development built on Zellij + Neovim + Arduino CLI, themed in Gruvbox, targeting both WSL2 and native Arch.
Architecture Overview
┌─────────────────────────────────────────────────┐
│ Zellij (multiplexer + workspace manager) │
│ ┌─────────────────────┬───────────────────────┐ │
│ │ Neovim (LazyVim) │ Serial Monitor │ │
│ │ - clangd LSP │ (arduino-cli monitor)│ │
│ │ - Arduino syntax │ │ │
│ │ - compile/upload │ │ │
│ │ keybinds │ │ │
│ ├─────────────────────┼───────────────────────┤ │
│ │ Terminal / Build │ lazygit │ │
│ │ output pane │ │ │
│ └─────────────────────┴───────────────────────┘ │
│ [zjstatus bar — board | port | project | git] │
└─────────────────────────────────────────────────┘
Table of Contents
- Base System
- Shell — Zsh + Starship
- Zellij
- Neovim + LazyVim
- Arduino CLI
- Serial Monitor
- Git + Lazygit
- Project Scaffolding
- Zellij Arduino Layout
- Neovim Arduino Keybinds
- WSL2-Specific Notes
- Quick Reference Card
1. Base System
Native Arch
sudo pacman -Syu
sudo pacman -S base-devel git curl unzip wget ripgrep fd bat eza tree jq
WSL2 Arch
If you hit SSL issues (common behind corporate proxies):
sed -i 's|https://|http://|g' /etc/pacman.d/mirrorlist
pacman -Syu ca-certificates archlinux-keyring --noconfirm
sed -i 's|http://|https://|g' /etc/pacman.d/mirrorlist
Create your user (if root-only)
pacman -S sudo
useradd -m -G wheel -s /bin/zsh myuser
passwd myuser
EDITOR=nano visudo # uncomment: %wheel ALL=(ALL) ALL
Add to /etc/wsl.conf:
[user]
default=myuser
2. Shell — Zsh + Starship
Install Zsh
sudo pacman -S zsh
chsh -s /bin/zsh
Oh My Zsh
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
Zsh Plugins
git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
git clone https://github.com/zsh-users/zsh-syntax-highlighting ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting
Edit ~/.zshrc:
plugins=(git zsh-autosuggestions zsh-syntax-highlighting)
Starship Prompt
sudo pacman -S starship
Add to ~/.zshrc:
eval "$(starship init zsh)"
Create ~/.config/starship.toml:
palette = "gruvbox_dark"
format = """
$directory$git_branch$git_status$character"""
[directory]
style = "bold fg:bright-yellow"
truncation_length = 3
[git_branch]
style = "bold fg:bright-green"
format = " [$branch]($style) "
[git_status]
style = "bold fg:bright-red"
[character]
success_symbol = "[❯](bold fg:bright-green)"
error_symbol = "[❯](bold fg:bright-red)"
[palettes.gruvbox_dark]
bright-yellow = "#fabd2f"
bright-green = "#b8bb26"
bright-red = "#fb4934"
bright-blue = "#83a598"
bright-purple = "#d3869b"
bright-aqua = "#8ec07c"
bright-orange = "#fe8019"
3. Zellij
Install
sudo pacman -S zellij
Or latest binary:
curl -kL https://github.com/zellij-org/zellij/releases/latest/download/zellij-x86_64-unknown-linux-musl.tar.gz | tar xz -C /tmp
sudo mv /tmp/zellij /usr/local/bin/
Gruvbox Theme Config
Create ~/.config/zellij/config.kdl:
theme "gruvbox-dark"
default_layout "default"
default_mode "normal"
pane_frames false
simplified_ui true
mouse_mode false
keybinds {
shared {
bind "Alt h" { MoveFocusOrTab "Left"; }
bind "Alt l" { MoveFocusOrTab "Right"; }
bind "Alt j" { MoveFocus "Down"; }
bind "Alt k" { MoveFocus "Up"; }
bind "Alt n" { NewPane "Down"; }
bind "Alt v" { NewPane "Right"; }
bind "Alt f" { ToggleFloatingPanes; }
bind "Alt t" { NewTab; }
}
}
themes {
gruvbox-dark {
fg "#ebdbb2"
bg "#282828"
black "#1d2021"
red "#cc241d"
green "#98971a"
yellow "#d79921"
blue "#458588"
magenta "#b16286"
cyan "#689d6a"
white "#a89984"
orange "#d65d0e"
}
}
Auto-start Zellij
Add to ~/.zshrc:
if [[ -z "$ZELLIJ" ]]; then
zellij attach --create archduino
fi
4. Neovim + LazyVim
Install latest Neovim
curl -kLO https://github.com/neovim/neovim/releases/latest/download/nvim-linux-x86_64.tar.gz
sudo tar -xzf nvim-linux-x86_64.tar.gz -C /opt
sudo ln -sf /opt/nvim-linux-x86_64/bin/nvim /usr/local/bin/nvim
rm nvim-linux-x86_64.tar.gz
Install LazyVim
mv ~/.config/nvim{,.bak} 2>/dev/null
mv ~/.local/share/nvim{,.bak} 2>/dev/null
mv ~/.local/state/nvim{,.bak} 2>/dev/null
mv ~/.cache/nvim{,.bak} 2>/dev/null
git clone https://github.com/LazyVim/starter ~/.config/nvim
rm -rf ~/.config/nvim/.git
LSP for Arduino (clangd)
sudo pacman -S clang
LazyVim Gruvbox + Arduino config
Create ~/.config/nvim/lua/plugins/gruvbox.lua:
return {
{
"ellisonleao/gruvbox.nvim",
priority = 1000,
config = function()
require("gruvbox").setup({
contrast = "hard",
})
end,
},
{
"LazyVim/LazyVim",
opts = {
colorscheme = "gruvbox",
},
},
}
Create ~/.config/nvim/lua/plugins/arduino.lua:
return {
-- Arduino filetype & syntax
{
"stevearc/vim-arduino",
ft = { "arduino", "cpp", "c" },
config = function()
vim.g.arduino_use_cli = 1
vim.g.arduino_cli_path = "arduino-cli"
end,
},
-- Better C/C++ treesitter support
{
"nvim-treesitter/nvim-treesitter",
opts = function(_, opts)
vim.list_extend(opts.ensure_installed, { "c", "cpp", "arduino" })
end,
},
}
Create ~/.config/nvim/lua/plugins/lsp.lua:
return {
{
"neovim/nvim-lspconfig",
opts = {
servers = {
clangd = {
cmd = {
"clangd",
"--background-index",
"--clang-tidy",
"--header-insertion=iwyu",
"--completion-style=detailed",
},
},
},
},
},
}
5. Arduino CLI
Install
curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | BINDIR=/usr/local/bin sh
If SSL issues:
curl -kfsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | BINDIR=/usr/local/bin sh
Initialize & install cores
arduino-cli config init
arduino-cli core update-index
# AVR boards (Uno, Mega, Nano)
arduino-cli core install arduino:avr
# ESP32
arduino-cli config add board_manager.additional_urls \
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
arduino-cli core update-index
arduino-cli core install esp32:esp32
# ESP8266
arduino-cli config add board_manager.additional_urls \
https://arduino.esp8266.com/stable/package_esp8266com_index.json
arduino-cli core update-index
arduino-cli core install esp8266:esp8266
Install common libraries
arduino-cli lib install "Servo"
arduino-cli lib install "WiFi"
arduino-cli lib install "ArduinoJson"
arduino-cli lib install "Adafruit Unified Sensor"
arduino-cli lib install "DHT sensor library"
6. Serial Monitor
TUI Serial Monitor — tio
sudo pacman -S tio
Usage:
tio /dev/ttyUSB0 -b 115200
tio auto-detects ports, supports timestamps, and is fully keyboard-driven. Quit with Ctrl+t q.
WSL2 serial passthrough
WSL2 doesn't natively see USB devices. You need usbipd-win on Windows:
# In Windows PowerShell (admin)
winget install usbipd
# List USB devices
usbipd list
# Bind and attach your Arduino
usbipd bind --busid <BUSID>
usbipd attach --wsl --busid <BUSID>
Then in WSL:
ls /dev/ttyUSB* # or /dev/ttyACM*
Add user to dialout group
sudo usermod -aG uucp $USER # Arch
sudo usermod -aG dialout $USER # if needed
7. Git + Lazygit
sudo pacman -S git lazygit
Git config
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
git config --global init.defaultBranch main
Lazygit Gruvbox
Create ~/.config/lazygit/config.yml:
gui:
theme:
activeBorderColor:
- "#fabd2f"
- bold
inactiveBorderColor:
- "#665c54"
selectedLineBgColor:
- "#3c3836"
cherryPickedCommitFgColor:
- "#b8bb26"
defaultFgColor:
- "#ebdbb2"
Neovim lazygit keybind
Already included in LazyVim — press <leader>gg to open lazygit in a floating terminal.
8. Project Scaffolding
Create the scaffolding script at ~/.local/bin/arduino-new:
#!/bin/bash
set -e
TEMPLATE_DIR="$HOME/.config/archduino/templates"
declare -A FQBN_MAP=(
["uno"]="arduino:avr:uno"
["mega"]="arduino:avr:mega"
["nano"]="arduino:avr:nano"
["esp32"]="esp32:esp32:esp32"
["esp32s3"]="esp32:esp32:esp32s3"
["esp8266"]="esp8266:esp8266:nodemcuv2"
)
usage() {
echo "Usage: arduino-new <project-name> <board>"
echo ""
echo "Available boards:"
for board in "${!FQBN_MAP[@]}"; do
printf " %-12s %s\n" "$board" "${FQBN_MAP[$board]}"
done
exit 1
}
[[ $# -lt 2 ]] && usage
PROJECT="$1"
BOARD="$2"
FQBN="${FQBN_MAP[$BOARD]}"
[[ -z "$FQBN" ]] && echo "Unknown board: $BOARD" && usage
mkdir -p "$PROJECT"
cd "$PROJECT"
# Copy board-specific template or default
if [[ -f "$TEMPLATE_DIR/$BOARD.ino" ]]; then
cp "$TEMPLATE_DIR/$BOARD.ino" "$PROJECT.ino"
else
cp "$TEMPLATE_DIR/default.ino" "$PROJECT.ino"
fi
# Project-local config
cat > sketch.yaml <<EOF
default_fqbn: $FQBN
default_port: auto
EOF
# clangd compile flags for LSP
cat > .clangd <<EOF
CompileFlags:
Add:
- -xc++
- -std=c++17
- -I$HOME/.arduino15/packages/arduino/hardware/avr/*/cores/arduino
- -I$HOME/.arduino15/packages/arduino/hardware/avr/*/variants/standard
- -I$HOME/.arduino15/packages/arduino/tools/avr-gcc/*/avr/include
EOF
# .gitignore
cat > .gitignore <<EOF
build/
.cache/
*.elf
*.hex
*.bin
EOF
git init -q
echo "✓ Created '$PROJECT' for $BOARD ($FQBN)"
echo " cd $PROJECT && nvim $PROJECT.ino"
Templates
mkdir -p ~/.config/archduino/templates
Create ~/.config/archduino/templates/default.ino:
void setup() {
Serial.begin(115200);
while (!Serial) { ; }
Serial.println("Hello from Arduino!");
}
void loop() {
// Your code here
}
Create ~/.config/archduino/templates/esp32.ino:
#include <WiFi.h>
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASS";
void setup() {
Serial.begin(115200);
delay(1000);
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
Serial.print("Connected! IP: ");
Serial.println(WiFi.localIP());
}
void loop() {
// Your code here
delay(1000);
}
Create ~/.config/archduino/templates/esp8266.ino:
#include <ESP8266WiFi.h>
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASS";
void setup() {
Serial.begin(115200);
delay(1000);
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
Serial.print("Connected! IP: ");
Serial.println(WiFi.localIP());
}
void loop() {
// Your code here
delay(1000);
}
Make it executable and on PATH:
chmod +x ~/.local/bin/arduino-new
# Ensure ~/.local/bin is in PATH (add to .zshrc if needed)
export PATH="$HOME/.local/bin:$PATH"
Usage
arduino-new blink-test uno
arduino-new wifi-scanner esp32
9. Zellij Arduino Layout
Create ~/.config/zellij/layouts/arduino.kdl:
layout {
tab name="code" focus=true {
pane split_direction="vertical" {
pane size="65%" {
command "nvim"
args "."
}
pane split_direction="horizontal" {
pane size="60%" name="terminal"
pane size="40%" name="serial" {
command "bash"
args "-c" "echo 'Run: tio /dev/ttyUSB0 -b 115200'"
}
}
}
}
tab name="git" {
pane {
command "lazygit"
}
}
tab name="monitor" {
pane {
command "bash"
args "-c" "echo 'Board monitor — run: arduino-cli monitor -p /dev/ttyUSB0 -c baudrate=115200'"
}
}
}
Launch with:
zellij --layout arduino
Or add a shell alias in ~/.zshrc:
alias adev="zellij --layout arduino"
10. Neovim Arduino Keybinds
Create ~/.config/nvim/lua/plugins/arduino-keys.lua:
return {
{
"folke/which-key.nvim",
opts = function(_, opts)
opts.spec = opts.spec or {}
table.insert(opts.spec, {
{ "<leader>a", group = "Arduino", icon = "⚡" },
})
end,
},
{
"stevearc/vim-arduino",
keys = {
{ "<leader>ac", "<cmd>ArduinoChooseBoard<cr>", desc = "Choose Board" },
{ "<leader>ap", "<cmd>ArduinoChoosePort<cr>", desc = "Choose Port" },
{ "<leader>av", "<cmd>ArduinoVerify<cr>", desc = "Verify (compile)" },
{ "<leader>au", "<cmd>ArduinoUpload<cr>", desc = "Upload" },
{ "<leader>as", "<cmd>ArduinoSerial<cr>", desc = "Serial Monitor" },
{ "<leader>ai", "<cmd>ArduinoInfo<cr>", desc = "Board Info" },
},
},
}
Quick reference:
<leader>av— compile/verify sketch<leader>au— upload to board<leader>ac— pick board<leader>ap— pick port<leader>as— open serial monitor<leader>gg— lazygit (built into LazyVim)
11. WSL2-Specific Notes
USB passthrough (required for uploading)
Install on Windows:
winget install usbipd
Create a helper script at ~/.local/bin/arduino-usb:
#!/bin/bash
# Quick attach Arduino USB in WSL2
# Run the Windows-side command via PowerShell interop
powershell.exe -Command "usbipd list"
echo ""
echo "To attach, run in Windows PowerShell:"
echo " usbipd attach --wsl --busid <BUSID>"
Git SSL workaround (corporate proxies)
git config --global http.sslVerify false
echo 'insecure' >> ~/.curlrc
Performance tip
Add to /etc/wsl.conf:
[interop]
appendWindowsPath = false
[network]
generateResolvConf = true
Disabling appendWindowsPath significantly speeds up shell startup.
12. Quick Reference Card
| Action | Keybind / Command |
|---|---|
| New project | arduino-new <name> <board> |
| Open dev workspace | adev |
| Compile | <leader>av |
| Upload | <leader>au |
| Choose board | <leader>ac |
| Choose port | <leader>ap |
| Serial monitor | <leader>as or tio |
| Lazygit | <leader>gg |
| New Zellij pane ↓ | Alt+n |
| New Zellij pane → | Alt+v |
| Navigate panes | Alt+h/j/k/l |
| Floating pane | Alt+f |
| New tab | Alt+t |