This repository contains configuration files and installation scripts for a complete and efficient minimal UNIX-like work environment based on any Debian or Debian-based distribution.
The purpose of this project is to provide a vim-loving, neckbeard-like, barebone environment, fancy enough to be used as a daily driver but not too fancy to be bloated with unnecessary software and dependencies.
The only prerequisite you need to cover is a working Debian in any version or form. There are two installers at your disposal to ease the setup process: ulpe_base and ulpe_plug.
The installers do not symlink any file, they just copy the configurations in the right place, so they can be easily modified and eventually reset running the single installer again.
To full install ULPE, launch the two installers separately (as described below) or just run the install script, it will execute both installers for you.
This script installs the basic packages and configures Bash, Vim and Tmux for you: just run ./ulpe_base from the root of the repository, relaunch your terminal and you are good to go.
This one installs additional plugins for your Vim alongside a little vimscript configuration to glue them together: run ./ulpe_plug from the root of the repository, launch Vim and see the magic happen.
You need to have Vim 9.0 or higher installed for the script to work, but it won’t be an issue since you should have at least a working Debian 12 by now with the 9.1 release available.
If you don’t want to run any installer, you can just copy the main configuration files with the following command and you got yourself a minimal ULPE. Copy-pasta this in your terminal and hit enter 😎
sh -c '
BASE="https://raw.githubusercontent.com/matteogiorgi/ulpe/refs/heads/main/base"
FILES=".profile .bashrc .bash_logout .tmux.conf .vimrc"
command -v wget >/dev/null 2>&1 || { echo "ERROR: install wget"; exit 1; }
for FILE in $FILES; do
[ -f "$HOME/$FILE" ] && cp "$HOME/$FILE" "$HOME/$FILE.bak"
wget -qO "$HOME/$FILE" "$BASE/$FILE" && echo "$FILE copied"
done
echo "finish"
'
For predetermined filetypes, Vim can lookup-doc, format and execute, all wired together in .vimrc through three dispatcher scripts: kdoc.sh, kfmt.sh and krun.sh. To support any new language you simply add one handler to each script and one entry to .vimrc. As an example, here is what adding Julia and Octave looks like.
kdoc.shA doc_<lang> function that prints documentation for a symbol, piped through the page helper when the output can be long:
# JULIA HANDLER
doc_julia() {
command -v julia >/dev/null 2>&1 || {
nodoc "$1"
return 1
}
julia --startup-file=no -e '
using REPL, Markdown
b = Docs.Binding(Main, Symbol(ARGS[1]))
d = Docs.doc(b)
occursin("No documentation found", Markdown.plain(d)) ||
show(IOContext(stdout, :color => true), MIME("text/plain"), d)
' "$1" 2>/dev/null | page "$1"
}
# OCTAVE HANDLER
doc_octave() {
command -v octave >/dev/null 2>&1 || {
nodoc "$1"
return 1
}
octave --quiet --norc --eval "more off; help('$1');" 2>/dev/null | page "$1"
}
# OUTPUT
[ -n "$2" ] || exit 1
case "$1" in
...
julia) doc_julia "$2" ;;
matlab | octave) doc_octave "$2" ;;
*) exit 1 ;;
esac
kfmt.shSame pattern, a fmt_<lang> function that formats the file in place and exits non-zero if the formatter is missing.
For Julia you can use JuliaFormatter, Octave instead has no standard formatter, so this example uses octfmt, a formatter written in Go:
# JULIA HANDLER
fmt_julia() {
command -v julia >/dev/null 2>&1 || return 1
julia --startup-file=no -e '
using JuliaFormatter
format_file(ARGS[1]; indent = 4, margin = 120)
' "$1" >/dev/null 2>&1
}
# OCTAVE HANDLER
fmt_octave() {
command -v octfmt >/dev/null 2>&1 || return 1
octfmt -w "$1" 2>/dev/null
}
# OUTPUT
[ -n "$2" ] || exit 1
case "$1" in
...
julia) fmt_julia "$2" ;;
matlab | octave) fmt_octave "$2" ;;
*) exit 1 ;;
esac
krun.shAdd a run_<lang> function and a matching case, mirroring the existing handlers (exec so the terminal buffer is replaced by the child process):
# JULIA HANDLER
run_julia() {
command -v julia >/dev/null 2>&1 || return 1
exec julia "$1"
}
# OCTAVE HANDLER
run_octave() {
command -v octave >/dev/null 2>&1 || return 1
exec octave --quiet --norc "$1"
}
# OUTPUT
[ -n "$2" ] || exit 1
case "$1" in
...
julia) run_julia "$2" ;;
matlab | octave) run_octave "$2" ;;
*) exit 1 ;;
esac
.vimrcFinally, plug the Vim filetype into the language_env augroup so <localleader>k runs it, <localleader>j formats it and K looks up documentation via kdoc.sh:
for [ft, kw] in [
...
\ ['julia', '.'],
\ ['matlab,octave', '.'],
\ ]
execute 'autocmd FileType ' . ft
\ . ' nnoremap <buffer> <silent><localleader>k :call <SID>ExecScript(&filetype)<CR>|'
\ . ' nnoremap <buffer> <silent><localleader>j :call <SID>Formatter(&filetype)<CR>|'
\ . ' nnoremap <buffer> <silent>K :call <SID>DocScript()<CR>|'
\ . ' setlocal iskeyword+=' . kw
endfor
ULPE doesn’t rely on any plugin manager: Vim’s built-in package system is enough. Every plugin is a plain git repository living under ~/.vim/pack/plug/start/, sourced automatically at startup with no extra configuration. As an example, this is how you would add copilot.vim:
mkdir -p ~/.vim/pack/plug/start
git clone --depth 1 https://github.com/github/copilot.vim.git ~/.vim/pack/plug/start/copilot.vim
Once cloned, launch Vim and run :helptags ALL to index the plugin documentation, so that :help copilot works as expected.
Everything under
start/is loaded at startup. If you want a plugin loaded on demand instead, clone it into~/.vim/pack/plug/opt/and pull it in with:packadd <plugin>(or lazily from your configuration).
Whatever tuning the plugin needs goes into ~/.vim/plug/plugin.vim, next to the configuration of the other plugins, wrapped in a fold marker and guarded by a &rtp check so the block stays harmless when the plugin isn’t installed:
if &rtp =~ 'copilot'
imap <silent><C-s> <Plug>(copilot-suggest)
imap <silent><C-f> <Plug>(copilot-accept-word)
imap <silent><C-j> <Plug>(copilot-next)
imap <silent><C-k> <Plug>(copilot-previous)
imap <silent><C-l> <Plug>(copilot-accept-line)
endif
Updating is just a git pull away, either on a single plugin or on all of them at once. You can do it running ulpe_plug from the root of the repository, or with:
for DIR in "$HOME"/.vim/pack/plug/start/*/; do
git -C "$DIR" pull --ff-only
done
Removing a plugin is equally trivial, delete its directory and drop the related block from ~/.vim/plug/plugin.vim:
rm -rf ~/.vim/pack/plug/start/<plugin>
To keep the environment reproducible, add the
git cloneline toulpe_plugand the configuration block to the vimscript the installer copies over, so a fresh machine gets the same setup with a single run.