Minimalistic development environment

Stack used

shell

I used zsh, mostly because of ohmyzsh, but I could change that. I use the following alias


# If you come from bash you might have to change your $PATH.
# export PATH=$HOME/bin:$HOME/.local/bin:/usr/local/bin:$PATH

# Path to your Oh My Zsh installation.
export ZSH="$HOME/.oh-my-zsh"
ZSH_THEME="clean"
plugins=(git)
source $ZSH/oh-my-zsh.sh

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion

# blog
alias blog='cd ~/Projects/personal-site/org'

ff() {
  local sel file line
  sel=$(rg -n . | fzf --multi) || return
  file=${sel%%:*}
  line=${sel#*:}
  line=${line%%:*}
  vim +"$line" "$file"
}

nn() {
  cd ~/Projects/personal-site/org
  fzf --print-query | head -1 | xargs -o -I{} vi $(date +%Y%m%d-%H%M)-{}.md
}

gdf() {
  local base=${1:-origin/main}
    git diff --name-only "$base"...HEAD | \
            fzf --multi --preview "git diff $base..HEAD -- {}" \
    --bind 'enter:execute(less -R {+}),ctrl-e:become(vim {+})'
}


. "$HOME/.atuin/bin/env"
# -------------------------------
# ZSH: Vim mode
# -------------------------------
bindkey -v

# Better cursor shape (optional, works in most terminals)
function zle-keymap-select {
  if [[ $KEYMAP == vicmd ]] || [[ $1 = 'block' ]]; then
    printf '\e[2 q'  # block cursor
  else
    printf '\e[6 q'  # beam cursor
  fi
}
zle -N zle-keymap-select

# -------------------------------
# Enable Ctrl-S (disable flow control)
# -------------------------------
stty -ixon

# -------------------------------
# Atuin init
# -------------------------------
eval "$(atuin init zsh)"

# Replace default reverse search
bindkey '^R' atuin-search

# Forward search (Ctrl-S)
atuin-forward-search() {
  BUFFER=$(atuin search --shell-up-key-binding --interactive)
  CURSOR=${#BUFFER}
}
zle -N atuin-forward-search
bindkey '^S' atuin-forward-search

# -------------------------------
# Project (cwd) scoped search
# Alt-h
# -------------------------------
atuin-cwd-search() {
  BUFFER=$(atuin search --cwd --interactive)
  CURSOR=${#BUFFER}
}
zle -N atuin-cwd-search
bindkey '^[h' atuin-cwd-search

# -------------------------------
# Session scoped search
# Alt-s
# -------------------------------
atuin-session-search() {
  BUFFER=$(atuin search --session --interactive)
  CURSOR=${#BUFFER}
}
zle -N atuin-session-search
bindkey '^[s' atuin-session-search


# =====================================================
# ZSH PAPER MODE CONFIG
# Minimal. Calm. Book-like.
# =====================================================

# -----------------------------------------------------
# Basics
# -----------------------------------------------------
export TERM="xterm-256color"
setopt AUTO_CD
setopt INTERACTIVE_COMMENTS
setopt HIST_IGNORE_DUPS
setopt HIST_REDUCE_BLANKS
setopt SHARE_HISTORY
setopt EXTENDED_HISTORY

HISTSIZE=50000
SAVEHIST=50000
HISTFILE=~/.zsh_history

# -----------------------------------------------------
# Completion (quiet + clean)
# -----------------------------------------------------
autoload -Uz compinit
compinit

zstyle ':completion:*' menu no
zstyle ':completion:*' matcher-list 'm:{a-z}={A-Za-z}'
zstyle ':completion:*' list-colors ''

# -----------------------------------------------------
# Paper Color Palette (Grayscale 256)
# -----------------------------------------------------
autoload -U colors && colors
setopt PROMPT_SUBST

GRAY_DARKEST="%F{236}"
GRAY_DARK="%F{238}"
GRAY_MED="%F{242}"
GRAY_LIGHT="%F{245}"
RESET="%f"

# -----------------------------------------------------
# Git branch (subtle, soft)
# -----------------------------------------------------
git_branch() {
  local branch
  branch=$(git symbolic-ref --short HEAD 2>/dev/null)
  if [[ -n $branch ]]; then
    echo " ${GRAY_LIGHT}($branch)${RESET}"
  fi
}

# -----------------------------------------------------
# Exit status (only if non-zero)
# -----------------------------------------------------
exit_status() {
  local code=$?
  if [[ $code -ne 0 ]]; then
    echo " ${GRAY_DARK}[exit:$code]${RESET}"
  fi
}

# -----------------------------------------------------
# Prompt (Two-line, Book Layout)
# -----------------------------------------------------
PROMPT='${GRAY_MED}%~${RESET}$(git_branch)$(exit_status)
${GRAY_DARK}%# ${RESET}'

# -----------------------------------------------------
# No visual noise
# -----------------------------------------------------
unsetopt PROMPT_CR
unsetopt PROMPT_SP

# No bold in completions
zstyle ':completion:*' format "${GRAY_MED}%d${RESET}"

# -----------------------------------------------------
# Vi Mode (optional but calm)
# -----------------------------------------------------
bindkey -v
KEYTIMEOUT=1

# -----------------------------------------------------
# No terminal title changes
# -----------------------------------------------------
DISABLE_AUTO_TITLE="true"

# -----------------------------------------------------
# Aliases (clean and minimal)
# -----------------------------------------------------
alias ll='ls -lh'
alias la='ls -lha'
alias l='ls -lh'
alias g='git'
alias v='vim'
alias e='emacs'

# -----------------------------------------------------
# Silence greeting
# -----------------------------------------------------
unsetopt BEEP

ff uses fzf to select files and then opens vim nn is to create new notes in markdown gdf to see what files were changed and review them.

.vimrc

Here is my .vimrc

let mapleader = " "
set nocompatible                  " Must come first because it changes other options.
syntax enable                     " Turn on syntax highlighting.
filetype plugin on                " Turn on file type detection.
set showcmd                       " Display incomplete commands.
set showmode                      " Display the mode you're in.
set backspace=indent,eol,start    " Intuitive backspacing.
set hidden                        " Handle multiple buffers better.
set wildmenu                      " Enhanced command line completion.
set wildmode=list:longest         " Complete files like a shell.
set incsearch                     " Highlight matches as you type.
set hlsearch                      " Highlight matches.
set wrap                          " Turn on line wrapping.
set modeline                      " Allow per file config
set autoindent
set noexpandtab
set tabstop=4
set shiftwidth=4
au FileType cpp silent! cs add cscope.out
au FileType js silent! cs add cscope.out
set clipboard=unnamed
set ruler
"set colorcolumn=80
syntax off
"highlight ColorColumn ctermbg=000 guibg=lightgrey
set laststatus=2
set statusline=%f\ %m\ [%{&filetype}]\ %l:%c
set guicursor=n-v-c:block,i-ci-ve:ver25
set grepprg=rg\ --vimgrep\ --smart-case
set grepformat=%f:%l:%c:%m
set nowrap
set sidescroll=5
set sidescrolloff=8

nnoremap <Leader>cs :cs find s <C-R>=expand("<cword>")<CR><CR>
nnoremap <Leader>cg :cs find g <C-R>=expand("<cword>")<CR><CR>
nnoremap <Leader>cc :cs find c <C-R>=expand("<cword>")<CR><CR>
nnoremap <Leader>ct :cs find t <C-R>=expand("<cword>")<CR><CR>
nnoremap <Leader>ce :cs find e <C-R>=expand("<cword>")<CR><CR>
nnoremap <Leader>cf :cs find f <C-R>=expand("<cword>")<CR><CR>
nnoremap <Leader>ci :cs find i <C-R>=expand("<cword>")<CR><CR>
nnoremap <Leader>cd :cs find d <C-R>=expand("<cword>")<CR><CR>
nnoremap <Leader>ca :cs find a <C-R>=expand("<cword>")<CR><CR>

nnoremap <leader>f :!vi "$(fzf)"<CR>
nnoremap <Leader>r :source ~/.vimrc<CR>

nnoremap <C-h> <C-w>h
nnoremap <C-j> <C-w>j
nnoremap <C-k> <C-w>k
nnoremap <C-l> <C-w>l

" --- fzf + ripgrep: jump to definition / references for word under cursor ---

function! s:rg_fzf_jump(pattern)
  " Uses: rg --vimgrep -> file:line:col:match
  let l:cmd = 'rg --vimgrep --smart-case ' . shellescape(a:pattern) . ' . | fzf'
  let l:out = system(l:cmd)

  if v:shell_error != 0 || empty(l:out)
    return
  endif

  let l:parts = split(l:out, ':', 4)
  if len(l:parts) < 3
    return
  endif

  execute 'edit ' . fnameescape(l:parts[0])
  call cursor(str2nr(l:parts[1]), str2nr(l:parts[2]))
  normal! zz
endfunction

function! FzfReferencesCword()
  let l:w = expand('<cword>')
  " word-boundary-ish: avoid partial matches
  call s:rg_fzf_jump('\b' . l:w . '\b')
endfunction

function! FzfDefinitionsCword()
  let l:w = expand('<cword>')

  " Heuristic definition patterns (works across many languages)
  " - anchored near line start, allows indentation
  " - tries common constructs: function/type/class/struct/enum/interface/const/var/let
  " - plus Go: func/type
  " - plus Rust: fn/struct/enum/trait/impl
  " - plus TS/JS: function/class/interface/type/const/let
  let l:pat =
        \ '(^\s*(export\s+)?(async\s+)?(function|class|interface|type|struct|enum|trait|impl|const|let|var)\s+'
        \ . l:w . '(\b|\s|<|\(|\{|:)'
        \ . '|^\s*(def|fn)\s+' . l:w . '\b'
        \ . '|^\s*func\s+(\([^)]+\)\s*)?' . l:w . '\b'
        \ . '|^\s*type\s+' . l:w . '\b'

  call s:rg_fzf_jump(l:pat)
endfunction

" Mappings:
nnoremap <silent> <leader>r :call FzfReferencesCword()<CR>
nnoremap <silent> <leader>d :call FzfDefinitionsCword()<CR>


" ---------- Reading / Book mode (no plugins) ----------
let g:book_mode = 0

function! ToggleBookMode()
  if g:book_mode
    " OFF: restore normal coding UI
    let g:book_mode = 0
    set nowrap
    set nocursorline
    set colorcolumn=
    set laststatus=2
    set showmode
    set ruler
    set signcolumn=auto
  else
    " ON: reading-friendly UI
    let g:book_mode = 1
    set wrap
    set linebreak
    set breakindent
    set showbreak=↳\
    set cursorline
    set laststatus=0
    set noshowmode
    set noruler
    set signcolumn=no

    " Pick your "page width" target:
    set textwidth=88

    " Visual guide at textwidth (subtle)
    execute "set colorcolumn=" . ( &textwidth + 1 )

    " Keep line numbers if you want; for pure reading, you can turn them off:
    set nonumber
    set norelativenumber
  endif
endfunction

nnoremap <silent> <leader>b :call ToggleBookMode()<CR>

" Make the colorcolumn subtle (paper-like)
highlight ColorColumn ctermbg=NONE cterm=NONE guibg=#d8caa6


" ========== Writing setup ==========

" Enable spell automatically for writing
augroup writing
  autocmd!
  autocmd FileType markdown,gitcommit,text setlocal spell spelllang=en_us
augroup END

" Toggle spell manually
nnoremap <leader>s :setlocal spell!<CR>

" ---------- LanguageTool (grammar) ----------

function! LT_Check()
  write
  setlocal errorformat=%f:%l:%c:\ %m
  cexpr system('languagetool --language en-US ' . shellescape(expand('%')))
  if len(getqflist()) > 0
    copen
  else
    cclose
    echo "LanguageTool: clean."
  endif
endfunction

command! Grammar call LT_Check()
nnoremap <leader>g :Grammar<CR>

" ========= Vale runner into quickfix =========
function! Vale_Check() abort
  write
  " Parse: file:line:col:message (Vale --output=line)
  setlocal errorformat=%f:%l:%c:%m
  cexpr system('vale --config /Users/carlosneira/.vale.ini --output=line ' . shellescape(expand('%')))
  if len(getqflist()) > 0
    copen
  else
    cclose
    call s:ValeClearHighlights()
    echo "Vale: clean."
  endif
endfunction

command! Style call Vale_Check()
nnoremap <leader>v :Style<CR>



" ---------- Vale (style) ----------
function! Vale_Check()
  write
  setlocal errorformat=%f:%l:%c:%m
  cexpr system('vale --config /Users/carlosneira/.vale.ini --output=line ' . shellescape(expand('%')))
  if len(getqflist()) > 0
    copen
  else
    cclose
    echo "Vale: clean."
  endif
endfunction

command! Style call Vale_Check()
nnoremap <leader>v :Style<CR>

magit diff-range

I used a lot magit diff-range, but this is just enough for me

:!git diff main..somebranch -- %

spottify ?

I just use

mpv --no-audio-display  ~/Music 

.wezterm.lua

local wezterm = require("wezterm")
local act = wezterm.action
local is_reader = false

local function is_night()
    local hour = tonumber(os.date("%H"))
    return hour >= 21 or hour < 10
end

local function appearance_mode()
    if wezterm.gui then
        local appearance = wezterm.gui.get_appearance()
        if appearance:find("Dark") then
            return "dark"
        end
    end
    return "light"
end


wezterm.on("update-right-status", function(window, pane)
  local tab = window:active_tab()
  local tab_index = tab.tab_index + 1
  local tab_count = #window:mux_window():tabs()
  local title = tab.active_pane.title

  window:set_right_status(
    wezterm.format({
      { Foreground = { Color = "#a89f91" } },
      { Text = "  " .. tab_index .. "/" .. tab_count .. "  " .. title .. "  " },
    })
  )
end)


wezterm.on("toggle-reader-mode", function(window, pane)
    is_reader = not is_reader
    local overrides = window:get_config_overrides() or {}
    if is_reader then
        -- Reader / “book page” mode
        overrides.window_padding = { left = 140, right = 140, top = 32, bottom = 32 }
        overrides.initial_cols = 84
        overrides.line_height = 1.30
        overrides.cell_width = 1.02
        -- Optional: hide tab bar for maximum “page” vibe
        overrides.enable_tab_bar = false
    else
        -- Normal mode (your defaults)
        overrides.window_padding = nil
        overrides.initial_cols = nil
        overrides.line_height = nil
        overrides.cell_width = nil
        overrides.enable_tab_bar = nil
    end

    window:set_config_overrides(overrides)
end)

local function paper_palette(mode)
    if mode == "dark" then
        return {
            --foreground = "#c8c1b6",
            --background = "#1e1b18",
            background =   "#23201c",
            foreground =  "#ddd6c8",

            cursor_bg = "#c8c1b6",
            cursor_fg = "#1e1b18",
            cursor_border = "#c8c1b6",

            selection_bg = "#3a332d",
            selection_fg = "#c8c1b6",

            ansi = {
                "#3b3a36",
                "#b85450",
                "#6a9955",
                "#b58900",
                "#4f6fad",
                "#875f9a",
                "#3a7f7a",
                "#c8c1b6",
            },

            brights = {
                "#5c5b57",
                "#c06060",
                "#7aa65a",
                "#c59f2f",
                "#5f7fbe",
                "#9a6fbf",
                "#4a9f9a",
                "#e0d8cc",
            },
        }
    else
        return {
            foreground = "#3a352a", -- slightly softer than #2f2e2a for “paper”
            -- background = "#f4ecd8",
            background = "#fbf7ed",

            cursor_bg = "#3a352a",
            cursor_fg = "#f4ecd8",
            cursor_border = "#3a352a",

            selection_bg = "#d8caa6",
            selection_fg = "#3a352a",

            ansi = {
                "#3b3a36",
                "#b85450",
                "#6a9955",
                "#b58900",
                "#4f6fad",
                "#875f9a",
                "#3a7f7a",
                "#5c5b57",
            },

            brights = {
                "#5c5b57",
                "#c06060",
                "#7aa65a",
                "#c59f2f",
                "#5f7fbe",
                "#9a6fbf",
                "#4a9f9a",
                "#3a352a",
            },
        }
    end
end

-- -----------------------------------------------------
-- Main
-- -----------------------------------------------------

local mode = appearance_mode()
local colors = paper_palette(mode)

return {
    ---------------------------------------------------------
    -- Kindle feel / typography
    ---------------------------------------------------------
    bold_brightens_ansi_colors = false,
    font = wezterm.font("Iosevka Term", { weight = "Regular" }),
    font_size = is_night() and 16.3 or 16.0,
    line_height = 1.28, -- slightly more “book”
    cell_width = 1.02, -- subtle breathing room for code

    ---------------------------------------------------------
    -- Rendering (Smooth Text)
    ---------------------------------------------------------
    freetype_load_target = "Light",
    freetype_render_target = "HorizontalLcd",
    front_end = "WebGpu",

    ---------------------------------------------------------
    -- Window
    ---------------------------------------------------------
    window_decorations = "RESIZE",
    native_macos_fullscreen_mode = true,

    -- keep layout stable when toggling font sizes
    adjust_window_size_when_changing_font_size = false,

    -- Paper / softness (removed duplicate opacity line)
    window_background_opacity = is_night() and 0.96 or 1.0,
    text_background_opacity = 1.0,
    macos_window_background_blur = is_night() and 18 or 0,

    colors = colors,

    ---------------------------------------------------------
    -- Padding (Like Margins in a Book)
    ---------------------------------------------------------
    window_padding = {
        left = 60,
        right = 60,
        top = 28,
        bottom = 28,
    },

    initial_cols = 88,
    initial_rows = 42,

    ---------------------------------------------------------
    -- Tabs (kept, but calmer)
    ---------------------------------------------------------
    enable_tab_bar = true,
    tab_bar_at_bottom = true,
    use_fancy_tab_bar = false,
    hide_tab_bar_if_only_one_tab = true,

    ---------------------------------------------------------
    -- Scrolling / cursor / misc
    ---------------------------------------------------------
    enable_scroll_bar = false,
    scrollback_lines = 10000,
    cursor_blink_rate = 0,
    --  default_cursor_style = "SteadyBar",
    animation_fps = 1,
    pane_select_font_size = 36,

    keys = {
        -- book like mode
        {
            key = "b",
            mods = "CMD|SHIFT",
            action = act.EmitEvent("toggle-reader-mode"),
        },
        -- Increase density for fonts
        {
            key = "d",
            mods = "CMD",
            action = wezterm.action_callback(function(window, pane)
                local overrides = window:get_config_overrides() or {}
                if not overrides.font_size then
                    overrides.font_size = 15.5
                    overrides.line_height = 1.18
                    overrides.cell_width = 1.0
                else
                    overrides.font_size = nil
                    overrides.line_height = nil
                    overrides.cell_width = nil
                end
                window:set_config_overrides(overrides)
            end),
        },

        -- Pane resize key
        {
            key = "8",
            mods = "CTRL|SHIFT",
            action = wezterm.action.AdjustPaneSize({ "Left", 15 }),
        },

        -- Rename tab prompt
        {
            key = "E",
            mods = "CTRL|SHIFT",
            action = act.PromptInputLine({
                description = "Enter new name for tab",
                action = wezterm.action_callback(function(window, pane, line)
                    if line then
                        window:active_tab():set_title(line)
                    end
                end),
            }),
        },
        -- Emit event
        { key = "m", mods = "CTRL|SHIFT", action = wezterm.action({ EmitEvent = "update-right-status" }) },
    },
    mouse_bindings = {
        -- ctrl-click link open
        {
            event = { Up = { streak = 1, button = "Left" } },
            mods = "CTRL",
            action = wezterm.action.OpenLinkAtMouseCursor,
        },
    },
}

Atuin config.toml

keymap_mode = "vim"
enter_accept = false
style = "compact"
inline_height = 20

git log colors

git config --global color.ui auto

# Branches
git config --global color.branch.current "bold black"
git config --global color.branch.local "black"
git config --global color.branch.remote "bold blue"

# Log
git config --global color.log.commit "bold black"
git config --global color.log.author "blue"
git config --global color.log.date "dim black"
git config --global color.log.decorate "bold black"

# Diff
git config --global color.diff.meta "black"
git config --global color.diff.frag "magenta"
git config --global color.diff.old "red"
git config --global color.diff.new "green"
git config --global color.diff.commit "bold black"

# Status
git config --global color.status.added "green"
git config --global color.status.changed "blue"
git config --global color.status.untracked "red"
git config --global color.status.branch "bold black"

Vale

I have rules to check my grammar using William Zinsser “How to write well” book, they are included in my dotfiles repo.

Haystacks at dusk by Unknown artist