Compare commits

..

23 Commits

Author SHA1 Message Date
Martin Pander
d522dcd5ab Add lldb debug config 2025-07-25 11:15:01 +02:00
Martin Pander
c3bf8c8e49 Add copilot keymaps 2025-07-25 09:52:19 +02:00
Martin
5876cf4564 Add nvim copilot chat 2025-07-24 21:52:28 +02:00
Martin
af49129b2a Add nvim render markdown 2025-07-24 19:50:58 +02:00
Martin Pander
2021268b73 Nvim 2025-07-24 19:11:41 +02:00
Martin
b432d26028 Add relative line numbers 2025-07-22 20:32:50 +02:00
Martin
5e4e0050dd Merge work 2025-07-22 20:06:22 +02:00
Martin
206ca73ee5 Add luasnip instead of vsnip 2025-07-20 18:29:36 +02:00
Martin
1824ed760d Configure conform 2025-07-16 20:15:34 +02:00
Martin
c52452dbf4 Merge work 2025-07-16 19:08:18 +02:00
Martin
4321d6bba5 Add lsp keymaps 2025-07-16 19:05:30 +02:00
Martin
db7bba461a Fix lsp 2025-07-12 19:33:38 +02:00
Martin
966a3cea5c Sync changes from work 2025-07-11 14:42:26 +02:00
Martin
4d7caf0abe Sync config for all systems 2025-07-10 20:03:17 +02:00
Martin
2517fd0269 Configure nvim obsidian 2025-07-09 21:21:25 +02:00
Martin
1e9873bae4 Refactor filetypes 2025-06-30 22:29:01 +02:00
Martin
ff4743a0db Minor things 2025-06-26 19:27:56 +02:00
Martin
3e3941a9f3 Add cli tools 2025-06-24 20:59:47 +02:00
Martin
dd7709d9e4 Configure nvim debugging 2025-06-23 21:39:25 +02:00
Martin
c494611b05 Take steps to a more IDE experience with neovim 2025-06-22 19:58:50 +02:00
Martin
4e69d65a8a Update flake 2025-06-18 21:54:29 +02:00
Martin
35af981c83 Merge changes from work 2025-06-18 21:53:08 +02:00
Martin
85450dd973 Add rust zsh config 2025-06-18 21:47:19 +02:00
57 changed files with 951 additions and 3715 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
plugins/

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "vim/bundle/Vundle.vim"]
path = vim/bundle/Vundle.vim
url = https://github.com/gmarik/Vundle.vim.git

130
README.md
View File

@@ -1,130 +0,0 @@
# Unified Nix Configuration
This repository contains a modular, flake-based Nix configuration for multiple platforms and hosts. It provides a declarative and reproducible environment using NixOS, nix-darwin, and Home Manager.
## Quick Start Guide
### Daily Usage
```bash
# Apply changes (NixOS WSL)
nixos-rebuild switch --sudo --flake .#work --impure
# Apply changes (macOS)
darwin-rebuild switch --flake .#Martins-MacBook-Pro
# Update packages (weekly/monthly)
nix flake update
# ... then run the switch command for your host
```
## Structure
The configuration is organized into `hosts` and `modules`:
```
.
├── flake.nix # Entry point with all system configurations
├── flake.lock # Locked dependency versions
├── hosts/ # Machine-specific configurations
│ ├── home/
│ │ ├── darwin/ # Martins-MacBook-Pro
│ │ ├── nix/ # Standalone Home Manager for Home
│ │ └── nixos/ # Home NixOS Server
│ └── work/
│ ├── nix/ # Standalone Home Manager for Work
│ └── nixos/ # Work NixOS (WSL)
└── modules/ # Shared reusable modules
├── home/ # Home Manager modules (sh, nvim, tmux, etc.)
└── nixos/ # NixOS-specific modules
```
## Available Configurations
### NixOS
- **work**: WSL-based NixOS environment for work (User: `pan`).
- **home**: Server-based NixOS environment for home (User: `martin`).
### Darwin (macOS)
- **Martins-MacBook-Pro**: nix-darwin configuration for macOS.
### Standalone Home Manager
- **pan@work**: Home Manager for non-NixOS Linux at work.
- **martin@mac**: Home Manager for macOS (without nix-darwin).
## Installation & Usage
### 1. Apply Configuration
Navigate to the repository and run the appropriate command for your system:
**NixOS (Work/WSL):**
```bash
sudo nixos-rebuild switch --flake .#work --impure
```
**Darwin (macOS):**
```bash
darwin-rebuild switch --flake .#Martins-MacBook-Pro
```
**Standalone Home Manager:**
```bash
home-manager switch --flake .#pan@work
```
*Note: The `--impure` flag may be required for certain configurations (like NIX_LD).*
### 2. Updating System Packages
To update all packages to the latest versions from nixpkgs-unstable:
```bash
# Update flake inputs
nix flake update
# Apply the updates
sudo nixos-rebuild switch --flake .#work --impure
```
## Maintenance
### Rollback
If something breaks after an update, you can rollback to the previous generation:
- **NixOS**: `sudo nixos-rebuild switch --rollback`
- **Darwin**: `darwin-rebuild --rollback`
### Cleanup
Remove old generations to free up disk space:
```bash
# Delete generations older than 30 days
sudo nix-collect-garbage --delete-older-than 30d
# Or delete all old generations
sudo nix-collect-garbage -d
```
## Modules Detail
### Home Manager Modules (`modules/home/`)
- **sh.nix**: Zsh configuration with completions and aliases.
- **nvim.nix**: Personalized Neovim setup.
- **tmux.nix**: Terminal multiplexer configuration.
- **git.nix**: Git, Lazygit, and Jujutsu settings.
- **dev.nix**: Development tools, language runtimes, and LLM tool configurations.
- **task.nix**: Taskwarrior and productivity tools.
### NixOS Modules (`modules/nixos/`)
- **common.nix**: Shared system settings for all NixOS hosts.
## Create Convenience Alias
Add these to your shell configuration for faster updates:
```bash
# Quick rebuild (adjust to your host)
alias nr='sudo nixos-rebuild switch --flake .#work --impure'
# Update and rebuild
alias nu='nix flake update && sudo nixos-rebuild switch --flake .#work --impure'
```

98
TODO.md
View File

@@ -1,98 +0,0 @@
# TODO - NixOS Configuration
This file tracks remaining tasks and known issues for the NixOS configuration.
## High Priority
### Hardware Configuration
- [ ] Replace `hardware-configuration.nix` with actual generated configuration
- Run `sudo nixos-generate-config --show-hardware-config > hardware-configuration.nix`
- Verify file systems are correctly configured
- Verify boot partition is correct
- Adjust CPU microcode (Intel vs AMD)
### System Settings
- [ ] Choose boot loader (systemd-boot vs GRUB)
## Medium Priority
### Tmux Configuration
- [ ] Update note popup keybindings (C-n, C-p) with correct NixOS paths
- Current: Commented out (had WSL hard-coded paths)
- Action: Decide on note location and update paths
- Example: `~/Documents/notes/Work/quick_notes.md`
- [ ] Verify `~/bin/tmuxp_selector.sh` script exists
- Used by `C-s` keybinding
- May need to be created or path adjusted
## Low Priority
### Shell Configuration
- [ ] Consider adding additional shell aliases
- [ ] Review if any macOS-specific tools need Linux alternatives
### Documentation
- [ ] Document custom Neovim configuration (lua files)
- [ ] Create troubleshooting guide for common issues
### Optimizations
- [ ] Consider using `programs.zsh.shellInit` vs `initContent`
- [ ] Review if `nix-ld` is actually needed (check use cases)
- [ ] Consider splitting large modules into smaller files
## Features Not Yet Ported
These were not in the original Home Manager config but might be useful on NixOS:
- [ ] Docker / Podman
## Known Issues
## Testing Checklist
Before considering this configuration complete:
- [ ] LSP servers work in Neovim
## Future Enhancements
- [ ] Add backup/restore scripts
- [ ] Create CI/CD for testing configuration
- [ ] Consider using flake-parts for better organization
- [ ] Add system monitoring tools
- [ ] Configure automatic updates
- [ ] Add custom shell functions
- [ ] Integrate with cloud sync for dotfiles
## Notes
### Unified Structure Benefits
1. **Multi-platform support**: Added support for Darwin (macOS) and NixOS (WSL and native).
2. **Modular Home Manager**: Reusable modules shared across all platforms.
3. **Machine-specific configurations**: Separated into `hosts/` for better organization.
4. **Flexible deployment**: Support for both NixOS modules and standalone Home Manager.
### Migration Path
This configuration is designed to be the central point for all machines:
1. Clone to `~/dev/dot/newnix` (or preferred path).
2. Identify your host type (NixOS WSL, Darwin, etc.).
3. Apply the corresponding flake output as described in `README.md`.
4. Test and verify workflows.
## Questions to Resolve
- [ ] What are the custom packages used for?
- [ ] Are there any private/work-specific configurations to add?
- [ ] Should we add any of the "Features Not Yet Ported"?
- [ ] Is GPU acceleration needed (NVIDIA, AMD)?
- [ ] Are there any cron jobs or systemd timers to configure?
- [ ] Should we enable fish or keep only zsh?
- [ ] Do we need any container tools (Docker, Podman)?

614
flake.lock generated
View File

@@ -1,614 +0,0 @@
{
"nodes": {
"bun2nix": {
"inputs": {
"flake-parts": "flake-parts",
"import-tree": "import-tree",
"nixpkgs": [
"hunk",
"nixpkgs"
],
"systems": [
"hunk",
"systems"
],
"treefmt-nix": "treefmt-nix"
},
"locked": {
"lastModified": 1770895533,
"narHash": "sha256-v3QaK9ugy9bN9RXDnjw0i2OifKmz2NnKM82agtqm/UY=",
"owner": "nix-community",
"repo": "bun2nix",
"rev": "c843f477b15f51151f8c6bcc886954699440a6e1",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "bun2nix",
"type": "github"
}
},
"bun2nix_2": {
"inputs": {
"flake-parts": [
"llm-agents",
"flake-parts"
],
"nixpkgs": [
"llm-agents",
"nixpkgs"
],
"systems": [
"llm-agents",
"systems"
],
"treefmt-nix": [
"llm-agents",
"treefmt-nix"
]
},
"locked": {
"lastModified": 1784665499,
"narHash": "sha256-9BMxlTxCCDAeoNLtb1a/st7udtTIJep+wpUzquA29VU=",
"owner": "nix-community",
"repo": "bun2nix",
"rev": "0f2a1f0b6f42cebe3b149bf62d38754c5e0e9729",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "bun2nix",
"type": "github"
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1767039857,
"narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-parts": {
"inputs": {
"nixpkgs-lib": "nixpkgs-lib"
},
"locked": {
"lastModified": 1769996383,
"narHash": "sha256-AnYjnFWgS49RlqX7LrC4uA+sCCDBj0Ry/WOJ5XWAsa0=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "57928607ea566b5db3ad13af0e57e921e6b12381",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"flake-parts_2": {
"inputs": {
"nixpkgs-lib": [
"llm-agents",
"nixpkgs"
]
},
"locked": {
"lastModified": 1787559586,
"narHash": "sha256-onL0VLf9vPllmT0H/OlURIU5r5t5WIEl7t4tVNKT0Nw=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "9d0d87172c374f89da73c1cfe6d81ae62feac1f1",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"flake-parts_3": {
"inputs": {
"nixpkgs-lib": "nixpkgs-lib_2"
},
"locked": {
"lastModified": 1772408722,
"narHash": "sha256-rHuJtdcOjK7rAHpHphUb1iCvgkU3GpfvicLMwwnfMT0=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "f20dc5d9b8027381c474144ecabc9034d6a839a3",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"flake-parts_4": {
"inputs": {
"nixpkgs-lib": "nixpkgs-lib_3"
},
"locked": {
"lastModified": 1769996383,
"narHash": "sha256-AnYjnFWgS49RlqX7LrC4uA+sCCDBj0Ry/WOJ5XWAsa0=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "57928607ea566b5db3ad13af0e57e921e6b12381",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"home-manager": {
"inputs": {
"nixpkgs": [
"nixpkgs-stable"
]
},
"locked": {
"lastModified": 1787377438,
"narHash": "sha256-Sxu1NLTD/Ern6hFGLlZmtKCSct3YQXZI/lls8RE1XeM=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "65258d5c65a250189fde2e35f490d15e064c4c62",
"type": "github"
},
"original": {
"owner": "nix-community",
"ref": "release-26.05",
"repo": "home-manager",
"type": "github"
}
},
"home-manager-wsl": {
"inputs": {
"nixpkgs": [
"nixpkgs-wsl-stable"
]
},
"locked": {
"lastModified": 1787377438,
"narHash": "sha256-Sxu1NLTD/Ern6hFGLlZmtKCSct3YQXZI/lls8RE1XeM=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "65258d5c65a250189fde2e35f490d15e064c4c62",
"type": "github"
},
"original": {
"owner": "nix-community",
"ref": "release-26.05",
"repo": "home-manager",
"type": "github"
}
},
"hunk": {
"inputs": {
"bun2nix": "bun2nix",
"nixpkgs": "nixpkgs",
"systems": "systems"
},
"locked": {
"lastModified": 1788145797,
"narHash": "sha256-nZhuKSUtaUl+MvEkeIh15BvmInQEdAO9VMtepVIfmbs=",
"owner": "modem-dev",
"repo": "hunk",
"rev": "f28ad59f219c7c629b691a5682b49cecc8a07c35",
"type": "github"
},
"original": {
"owner": "modem-dev",
"repo": "hunk",
"type": "github"
}
},
"import-tree": {
"locked": {
"lastModified": 1763762820,
"narHash": "sha256-ZvYKbFib3AEwiNMLsejb/CWs/OL/srFQ8AogkebEPF0=",
"owner": "vic",
"repo": "import-tree",
"rev": "3c23749d8013ec6daa1d7255057590e9ca726646",
"type": "github"
},
"original": {
"owner": "vic",
"repo": "import-tree",
"type": "github"
}
},
"llm-agents": {
"inputs": {
"bun2nix": "bun2nix_2",
"flake-parts": "flake-parts_2",
"nixpkgs": "nixpkgs_2",
"systems": "systems_2",
"treefmt-nix": "treefmt-nix_2"
},
"locked": {
"lastModified": 1788151314,
"narHash": "sha256-uNWTTBhvj+tPqfDJUuMq9hkVYb69YFz4dEGlnfsCW8A=",
"owner": "numtide",
"repo": "llm-agents.nix",
"rev": "e0e1c45e2d609f4a206ead7a637c28801e36baab",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "llm-agents.nix",
"type": "github"
}
},
"nix-darwin": {
"inputs": {
"nixpkgs": "nixpkgs_3"
},
"locked": {
"lastModified": 1786845137,
"narHash": "sha256-oQFip+v0luP8NIxJzmiW4Wu8bILsbFWom5l0zonl8hQ=",
"owner": "nix-darwin",
"repo": "nix-darwin",
"rev": "4cff07de74b50e64bdd68cd4e722ab5b6b35ee48",
"type": "github"
},
"original": {
"id": "nix-darwin",
"type": "indirect"
}
},
"nixos-vscode-server": {
"inputs": {
"flake-parts": "flake-parts_3"
},
"locked": {
"lastModified": 1784312229,
"narHash": "sha256-2uHCSUw341o3my1R0U0YCfbnMEazylxb58evWsjGL50=",
"owner": "nix-community",
"repo": "nixos-vscode-server",
"rev": "2f984dfbe7e5271b5c413d3e734374cc1306c921",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nixos-vscode-server",
"type": "github"
}
},
"nixos-wsl": {
"inputs": {
"flake-compat": "flake-compat",
"nixpkgs": [
"nixpkgs-wsl-stable"
]
},
"locked": {
"lastModified": 1784058838,
"narHash": "sha256-499ZAnS4nWV2Wtgoi3WdbIVuZbNoN7KptltceQhZc38=",
"owner": "nix-community",
"repo": "nixos-wsl",
"rev": "787a4c128292010ad182eed66f879fa688592e4c",
"type": "github"
},
"original": {
"owner": "nix-community",
"ref": "release-26.05",
"repo": "nixos-wsl",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1777954456,
"narHash": "sha256-hGdgeU2Nk87RAuZyYjyDjFL6LK7dAZN5RE9+hrDTkDU=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "549bd84d6279f9852cae6225e372cc67fb91a4c1",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-lib": {
"locked": {
"lastModified": 1769909678,
"narHash": "sha256-cBEymOf4/o3FD5AZnzC3J9hLbiZ+QDT/KDuyHXVJOpM=",
"owner": "nix-community",
"repo": "nixpkgs.lib",
"rev": "72716169fe93074c333e8d0173151350670b824c",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nixpkgs.lib",
"type": "github"
}
},
"nixpkgs-lib_2": {
"locked": {
"lastModified": 1772328832,
"narHash": "sha256-e+/T/pmEkLP6BHhYjx6GmwP5ivonQQn0bJdH9YrRB+Q=",
"owner": "nix-community",
"repo": "nixpkgs.lib",
"rev": "c185c7a5e5dd8f9add5b2f8ebeff00888b070742",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nixpkgs.lib",
"type": "github"
}
},
"nixpkgs-lib_3": {
"locked": {
"lastModified": 1769909678,
"narHash": "sha256-cBEymOf4/o3FD5AZnzC3J9hLbiZ+QDT/KDuyHXVJOpM=",
"owner": "nix-community",
"repo": "nixpkgs.lib",
"rev": "72716169fe93074c333e8d0173151350670b824c",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nixpkgs.lib",
"type": "github"
}
},
"nixpkgs-stable": {
"locked": {
"lastModified": 1787962033,
"narHash": "sha256-u6z9VTZA4Kf3RkHQo9sQI7NI4Ei/uiU9vrMqOiwWP1Y=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "c5c4a43b0e8056328ec4529f735cabdb8f1942bb",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-26.05",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-wsl-stable": {
"locked": {
"lastModified": 1787962033,
"narHash": "sha256-u6z9VTZA4Kf3RkHQo9sQI7NI4Ei/uiU9vrMqOiwWP1Y=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "c5c4a43b0e8056328ec4529f735cabdb8f1942bb",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-26.05",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1787424095,
"narHash": "sha256-dWLO5AHhKaw6rdWCtTes8hnntT1r0/J5yhQGm0f0ZgU=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "174eb786fb68e3a13e4e535a3deea479a0c07a6a",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_3": {
"locked": {
"lastModified": 1783279667,
"narHash": "sha256-/NAkDSsve+GNM0Bt6tleJdCGfsTlK89nPjkVOzZMo0s=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "f205b5574fd0cb7da5b702a2da51507b7f4fdd1b",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_4": {
"locked": {
"lastModified": 1788039129,
"narHash": "sha256-pa4Q0qErvCvzCaaUph7Sm37RhR4xvPrYI8Lgz6k85+A=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "d2f67949798825fe853f7c5d0492b8bf016d3f88",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_5": {
"locked": {
"lastModified": 1782175435,
"narHash": "sha256-EMzXKmnOtBQ2MnvpiNOm7E+kOMvdPrIKaeg52Tip2Uk=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "89570f24e97e614aa34aa9ab1c927b6578a43775",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_6": {
"locked": {
"lastModified": 1771369470,
"narHash": "sha256-0NBlEBKkN3lufyvFegY4TYv5mCNHbi5OmBDrzihbBMQ=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "0182a361324364ae3f436a63005877674cf45efb",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"home-manager": "home-manager",
"home-manager-wsl": "home-manager-wsl",
"hunk": "hunk",
"llm-agents": "llm-agents",
"nix-darwin": "nix-darwin",
"nixos-vscode-server": "nixos-vscode-server",
"nixos-wsl": "nixos-wsl",
"nixpkgs": "nixpkgs_4",
"nixpkgs-stable": "nixpkgs-stable",
"nixpkgs-wsl-stable": "nixpkgs-wsl-stable",
"sops-nix": "sops-nix",
"tasksquire": "tasksquire"
}
},
"sops-nix": {
"inputs": {
"nixpkgs": "nixpkgs_5"
},
"locked": {
"lastModified": 1786629091,
"narHash": "sha256-gkig4nPi1CWc4Z50GBsjE4ygSE7hMpl/TwID2an2Cck=",
"owner": "Mic92",
"repo": "sops-nix",
"rev": "a8627b21b9107c5711c96b84f32a9a4b3d45295f",
"type": "github"
},
"original": {
"owner": "Mic92",
"repo": "sops-nix",
"type": "github"
}
},
"systems": {
"locked": {
"lastModified": 1776166891,
"narHash": "sha256-bI8yrEGjrohR5hkQox7UrxDH7XqrYMwI8SL/LrJ1+S8=",
"owner": "nix-systems",
"repo": "triplet",
"rev": "6de7bc09397911ce03636afbcf6118745ab2cda0",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "triplet",
"type": "github"
}
},
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"tasksquire": {
"inputs": {
"flake-parts": "flake-parts_4",
"nixpkgs": "nixpkgs_6"
},
"locked": {
"lastModified": 1771878653,
"narHash": "sha256-+OkJmYH+h5dgAbUtbGq8fZ90g5/rwiew5WPmbexD9kI=",
"ref": "dev",
"rev": "6b1418fc71be513ba5ebb718da29e3190c3fda58",
"revCount": 52,
"type": "git",
"url": "ssh://git@git.pander.me/martin/tasksquire.git"
},
"original": {
"ref": "dev",
"type": "git",
"url": "ssh://git@git.pander.me/martin/tasksquire.git"
}
},
"treefmt-nix": {
"inputs": {
"nixpkgs": [
"hunk",
"bun2nix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1770228511,
"narHash": "sha256-wQ6NJSuFqAEmIg2VMnLdCnUc0b7vslUohqqGGD+Fyxk=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "337a4fe074be1042a35086f15481d763b8ddc0e7",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "treefmt-nix",
"type": "github"
}
},
"treefmt-nix_2": {
"inputs": {
"nixpkgs": [
"llm-agents",
"nixpkgs"
]
},
"locked": {
"lastModified": 1786901030,
"narHash": "sha256-WSFCsDSE5ffgD2MqzkM2CYjeFiKhRF/dJUN8uedb6YE=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "27b3b12a8e6375f28ebe122f07d230ca5459bbfa",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "treefmt-nix",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

154
flake.nix
View File

@@ -1,154 +0,0 @@
{
description = "Unified Nix Configuration";
inputs = {
# Unstable for standalone configurations and overlays
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
nixpkgs-stable.url = "github:nixos/nixpkgs/nixos-26.05";
nixpkgs-wsl-stable.url = "github:nixos/nixpkgs/nixos-26.05";
nixos-wsl = {
url = "github:nix-community/nixos-wsl/release-26.05";
inputs.nixpkgs.follows = "nixpkgs-wsl-stable";
};
home-manager = {
url = "github:nix-community/home-manager/release-26.05";
inputs.nixpkgs.follows = "nixpkgs-stable";
};
home-manager-wsl = {
url = "github:nix-community/home-manager/release-26.05";
inputs.nixpkgs.follows = "nixpkgs-wsl-stable";
};
# nix-darwin = {
# url = "github:LnL7/nix-darwin";
# };
# individual packages
sops-nix = {
url = "github:Mic92/sops-nix";
};
nixos-vscode-server = {
url = "github:nix-community/nixos-vscode-server";
};
tasksquire = {
url = "git+ssh://git@git.pander.me/martin/tasksquire.git?ref=dev";
};
hunk = {
url = "github:modem-dev/hunk";
};
llm-agents.url = "github:numtide/llm-agents.nix";
};
outputs = { self, nixpkgs, nixpkgs-stable, nixpkgs-wsl-stable, nixos-wsl, home-manager, home-manager-wsl, nix-darwin, ... }@inputs:
let
linuxSystem = "x86_64-linux";
linuxAarchSystem = "aarch64-linux";
# darwinSystem = "aarch64-darwin";
pkgsLinux = nixpkgs.legacyPackages.${linuxSystem};
pkgsLinuxAarch = nixpkgs.legacyPackages.${linuxAarchSystem};
# pkgsDarwin = nixpkgs.legacyPackages.${darwinSystem};
in
{
# --- NixOS Systems ---
nixosConfigurations = {
# Work WSL
"nixos@work" = nixpkgs-wsl-stable.lib.nixosSystem {
specialArgs = { inherit self inputs; };
modules = [
nixos-wsl.nixosModules.wsl
./hosts/work/nixos/configuration.nix
home-manager.nixosModules.home-manager
{
nixpkgs.hostPlatform = linuxSystem;
nixpkgs.config.allowUnfree = true;
nixpkgs.overlays = [
(import ./modules/overlays/unstable.nix nixpkgs)
];
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.extraSpecialArgs = {
inherit self inputs;
};
home-manager.users.pan = import ./hosts/work/nixos/home.nix;
}
inputs.nixos-vscode-server.nixosModules.default
({ pkgs, ... }: {
services.vscode-server.enable = true;
})
];
};
# Home
"nixos@home" = nixpkgs-stable.lib.nixosSystem {
specialArgs = {
inherit self inputs;
};
modules = [
./hosts/home/nixos/configuration.nix
home-manager.nixosModules.home-manager
{
nixpkgs.hostPlatform = linuxAarchSystem;
nixpkgs.config.allowUnfree = true;
nixpkgs.overlays = [ (import ./modules/overlays/unstable.nix nixpkgs) ];
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.extraSpecialArgs = {
inherit self inputs;
};
home-manager.users.martin = import ./hosts/home/nixos/home.nix;
}
];
};
};
# # --- Darwin Systems (Mac) ---
# darwinConfigurations."Martins-MacBook-Pro" = nix-darwin.lib.darwinSystem {
# specialArgs = { inherit self inputs; };
# modules = [
# ./hosts/home/darwin/configuration.nix
# {
# nixpkgs.hostPlatform = darwinSystem;
# }
# ];
# };
#
# --- Standalone Home Manager ---
homeConfigurations = {
"nix@work" = home-manager.lib.homeManagerConfiguration {
pkgs = nixpkgs-stable.legacyPackages.${linuxSystem};
extraSpecialArgs = { inherit self inputs; };
modules = [
./hosts/work/nix/home.nix
{
nixpkgs.config.allowUnfree = true;
nixpkgs.overlays = [ (import ./modules/overlays/unstable.nix nixpkgs) ];
}
];
};
# "nix@home" = home-manager.lib.homeManagerConfiguration {
# pkgs = nixpkgs-stable.legacyPackages.${darwinSystem};
# extraSpecialArgs = { inherit self inputs; };
# modules = [
# ./hosts/home/nix/home.nix
# {
# nixpkgs.config.allowUnfree = true;
# nixpkgs.overlays = [ (import ./modules/overlays/unstable.nix nixpkgs) ];
# }
# ];
# };
};
};
}

View File

@@ -1,26 +0,0 @@
{ config, pkgs, ... }:
{
imports = [
../../modules/home/common.nix
];
programs.git.settings.user = {
name = "Martin Pander";
email = "git@pander-on.de";
};
programs.jujutsu.settings.user = {
name = "Martin Pander";
email = "git@pander-on.de";
};
dot.llm = {
enable = true;
pi.enable = true;
pi.enableConfig = true;
opencode.enable = true;
opencode.enableConfig = true;
# pi.enable = true;
};
}

View File

@@ -1,19 +0,0 @@
{ config, pkgs, self, ... }:
{
# Minimal system configuration
environment.systemPackages = [ pkgs.vim ];
services.nix-daemon.enable = true;
nix.settings.experimental-features = "nix-command flakes";
programs.zsh.enable = true;
# Set Git commit hash for darwin-version.
system.configurationRevision = self.rev or self.dirtyRev or null;
system.stateVersion = 4;
nixpkgs.hostPlatform = "aarch64-darwin";
}

View File

@@ -1,12 +0,0 @@
{ config, pkgs, ... }:
{
imports = [
../common.nix
];
home.username = "martin";
home.homeDirectory = "/Users/martin";
home.stateVersion = "24.05";
}

View File

@@ -1,32 +0,0 @@
{ config, lib, pkgs, ... }:
{
imports = [
../../../modules/nixos/common.nix
];
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
fileSystems."/" = {
device = "/dev/disk/by-label/nixos";
fsType = "ext4";
};
networking.hostName = "macnix";
users.users.martin = {
isNormalUser = true;
extraGroups = [ "networkmanager" "wheel" ];
uid = 1000;
shell = pkgs.zsh;
};
services.openssh.enable = true;
environment.systemPackages = [
pkgs.ghostty.terminfo
];
system.stateVersion = "25.11";
}

View File

@@ -1,13 +0,0 @@
{ config, pkgs, lib, ... }:
{
imports = [
../common.nix
];
# User details
home.username = "martin";
home.homeDirectory = "/home/martin";
home.stateVersion = "25.11";
}

View File

@@ -1,30 +0,0 @@
{ config, pkgs, ... }:
{
imports = [
../../modules/home/common.nix
];
programs.git.settings.user = {
name = "Martin Pander";
email = "martin.pander@knowtion.de";
};
programs.jujutsu.settings.user = {
name = "Martin Pander";
email = "martin.pander@knowtion.de";
};
dot.llm = {
enable = true;
opencode.enable = true;
opencode.enableConfig = true;
opencode.workMode = true;
pi.enable = true;
pi.enableConfig = true;
pi.workMode = true;
};
dot.tmux.workMode = true;
dot.nvim.workMode = true;
}

View File

@@ -1,19 +0,0 @@
{ config, pkgs, ... }:
{
imports = [
../common.nix
];
home.username = "pan";
home.homeDirectory = "/home/pan";
home.packages = with pkgs; [
nix-ld
];
home.stateVersion = "23.11";
dot.sh.sourceProfile = true;
}

View File

@@ -1,32 +0,0 @@
{ config, lib, pkgs, ... }:
{
imports = [
../../../modules/nixos/common.nix
];
# For sshfs
programs.fuse.userAllowOther = true;
wsl.enable = true;
wsl.defaultUser = "pan";
wsl.interop.register = true;
networking.hostName = "nix";
networking.firewall.enable = false;
users.users.pan = {
isNormalUser = true;
extraGroups = [ "networkmanager" "wheel" ];
uid = 1000;
shell = pkgs.zsh;
};
fileSystems."/home/pan/pro" = {
device = "/dev/disk/by-uuid/9a37862c-85db-4434-b06a-ec8c2713ecc9";
fsType = "ext4";
options = [ "defaults" "nofail" "x-systemd.automount" ];
};
system.stateVersion = "25.05";
}

View File

@@ -1,14 +0,0 @@
{ config, pkgs, lib, ... }:
{
imports = [
../common.nix
];
# User details
home.username = "pan";
home.homeDirectory = "/home/pan";
# Home Manager release version
home.stateVersion = "25.05";
}

View File

@@ -1,60 +0,0 @@
{ config, pkgs, lib, ... }:
{
options.dot = {
dotfilesPath = lib.mkOption {
type = lib.types.str;
default = "${config.home.homeDirectory}/dev/dot";
description = "Absolute path to the dotfiles repository on the local machine.";
};
};
imports = [
./secrets.nix
./sh.nix
./tmux.nix
./git.nix
./dev.nix
./nvim.nix
./task.nix
./llm.nix
];
config = {
home.packages = with pkgs; [
nerd-fonts.fira-code
nil # Nix LSP
# Language servers
yaml-language-server
marksman
pkgs.unstable.dockerfile-language-server # Use unstable for latest LSP features
# Secrets management
sops
age
];
programs.ssh = {
enable = true;
enableDefaultConfig = false;
includes = [ "config.local" ];
settings = {
"*" = {
addKeysToAgent = "yes";
};
"git.pander.me" = {
hostname = "git.pander.me";
user = "git";
identityFile = "~/.ssh/private_git";
port = 2222;
};
};
};
news.display = "silent";
programs.home-manager.enable = true;
};
}

View File

@@ -1,28 +0,0 @@
{ pkgs, ... }:
{
config = {
programs.direnv = {
enable = true;
enableZshIntegration = true;
nix-direnv.enable = true;
stdlib = ''
: ''${XDG_CACHE_HOME:=$HOME/.cache}
declare -A direnv_layout_dirs
direnv_layout_dir() {
echo "''${direnv_layout_dirs[$PWD]:=$(
echo -n "$XDG_CACHE_HOME"/direnv/layouts/
echo -n "$PWD" | sha1sum | cut -d ' ' -f 1
)}"
}
'';
};
home.packages = with pkgs; [
visidata
codespelunker
jq
unstable.tuicr
];
};
}

View File

@@ -1,124 +0,0 @@
{ config, pkgs, lib, inputs, ... }:
let
cfg = config.dot.llm;
piPath = "${config.dot.dotfilesPath}/modules/pi/agent";
opencodePath = "${config.dot.dotfilesPath}/modules/opencode";
in
{
options.dot.llm = {
enable = lib.mkEnableOption "LLM tools";
claude-code.enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Enable claude-code";
};
gemini-cli.enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Enable gemini-cli";
};
bubblewrap.enable = lib.mkOption {
type = lib.types.bool;
default = pkgs.stdenv.isLinux;
description = "Enable bubblewrap (Linux only)";
};
opencode = {
enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Enable opencode";
};
enableConfig = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Enable managed OpenCode configuration";
};
workMode = lib.mkEnableOption "work-specific opencode configuration";
};
pi = {
enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Enable pi";
};
enableConfig = lib.mkEnableOption "managed pi coding agent configuration" // {
default = true;
};
workMode = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Apply work machine (WSL NixOS) specific pi patches";
};
};
};
config = lib.mkMerge [
(lib.mkIf cfg.enable {
home.packages =
(lib.optional cfg.claude-code.enable pkgs.unstable.claude-code) ++
(lib.optional cfg.opencode.enable pkgs.unstable.opencode) ++
(lib.optional cfg.gemini-cli.enable pkgs.unstable.gemini-cli) ++
(lib.optional cfg.pi.enable (
let
pi = inputs.llm-agents.packages.${pkgs.stdenv.hostPlatform.system}.pi;
in
if cfg.pi.workMode then
# Work machine runs WSL NixOS, which needs the checks disabled and the
# Bun binary's ELF interpreter patched to the correct dynamic linker.
pi.overrideAttrs (oldAttrs: {
doInstallCheck = false;
# Run patchelf after the package is installed/fixed up by nix
postFixup = (oldAttrs.postFixup or "") + ''
# 1. Target the actual Bun binary inside libexec, not the shell wrapper in bin/
TARGET_BIN="$out/libexec/pi/pi"
if [ -f "$TARGET_BIN" ]; then
# 2. Make it writable in the build store so patchelf can edit it
chmod +w "$TARGET_BIN"
# 3. Running patchelf to set the interpreter forces it to rebuild the ELF headers
patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" "$TARGET_BIN"
fi
'';
})
else
pi
)) ++
(lib.optional (cfg.bubblewrap.enable && pkgs.stdenv.isLinux) pkgs.unstable.bubblewrap);
})
# pi coding agent configuration
(lib.mkIf cfg.pi.enableConfig {
home.file = {
".pi/agent/settings.json".source =
config.lib.file.mkOutOfStoreSymlink
"${piPath}/${if cfg.pi.workMode then "settings.work" else "settings.home"}.json";
".pi/agent/extensions".source =
config.lib.file.mkOutOfStoreSymlink "${piPath}/extensions-common";
} // lib.optionalAttrs cfg.pi.workMode {
".pi/agent/extensions-work".source =
config.lib.file.mkOutOfStoreSymlink "${piPath}/extensions-work";
".pi/agent/models.json".source =
config.lib.file.mkOutOfStoreSymlink "${piPath}/models.work.json";
};
})
# OpenCode configuration
(lib.mkIf cfg.opencode.enableConfig {
xdg.configFile."opencode/opencode.json".source =
config.lib.file.mkOutOfStoreSymlink
"${opencodePath}/opencode.${if cfg.opencode.workMode then "work" else "home"}.json";
})
];
}

View File

@@ -1,110 +0,0 @@
{ config, pkgs, lib, ... }:
let
cfg = config.dot.nvim;
in
{
options.dot.nvim = {
workMode = lib.mkEnableOption "work-specific neovim configuration";
};
config = {
programs.neovim = {
enable = true;
defaultEditor = true;
vimAlias = true;
plugins = with pkgs.vimPlugins; [
vscode-nvim
vim-repeat
vim-surround
ts-comments-nvim
vim-fugitive
gitsigns-nvim
nvim-tree-lua
targets-vim
mini-pairs
mini-align
mini-bracketed
mini-splitjoin
mini-move
mini-ai
mini-icons
flash-nvim
trouble-nvim
conform-nvim
nvim-lint
promise-async
nvim-ufo
vim-windowswap
plenary-nvim
telescope-nvim
telescope-fzf-native-nvim
telescope-ui-select-nvim
yanky-nvim
lualine-nvim
undotree
luasnip
nvim-cmp
cmp_luasnip
cmp-buffer
cmp-path
cmp-cmdline
cmp-nvim-lsp
cmp-nvim-lsp-signature-help
cmp_yanky
cmp-git
nvim-lspconfig
lspkind-nvim
# opencode-nvim
pi-nvim
bullets-vim
nvim-dap
nvim-nio
nvim-dap-view
nvim-dap-virtual-text
nvim-dap-go
nvim-dap-python
nvim-dap-lldb
todo-comments-nvim
vim-markdown
zen-mode-nvim
plantuml-syntax
obsidian-nvim
render-markdown-nvim
image-nvim
img-clip-nvim
vim-nix
indent-blankline-nvim
(nvim-treesitter.withPlugins (p: [ p.awk p.bash p.c p.c_sharp p.cpp p.css p.diff p.dockerfile p.doxygen p.git_config p.gitcommit p.go p.gomod p.gosum p.gotmpl p.helm p.haskell p.html p.http p.java p.javascript p.json p.latex p.lua p.markdown p.markdown_inline p.matlab p.nix p.printf p.python p.regex p.rust p.sql p.strace p.supercollider p.svelte p.swift p.terraform p.tmux p.toml p.typescript p.vim p.xml p.yaml p.zig ]))
nvim-treesitter-context
];
initLua = ''
_G.is_work = ${if cfg.workMode then "true" else "false"}
_G.is_mac = ${if pkgs.stdenv.isDarwin then "true" else "false"}
_G.is_private_nixos = ${if !cfg.workMode && pkgs.stdenv.isLinux then "true" else "false"}
require('base')
require('keymaps')
require('plugins')
require('filetype')
'';
withRuby = false;
withPython3 = false;
};
# Allow for editing the lua modules without a nix rebuild
xdg.configFile."nvim/lua".source = config.lib.file.mkOutOfStoreSymlink "${config.dot.dotfilesPath}/modules/nvim/lua";
home.sessionVariables = {
VISUAL = "nvim";
};
home.packages = with pkgs; [
nodejs-slim
];
};
}

View File

@@ -1,41 +0,0 @@
{ inputs, config, lib, ... }:
let
# Both pi and opencode talk to Langdock on work machines and expect the API
# key in the environment, so the secret is managed here rather than in the
# individual agent modules.
needsLangdock = config.dot.llm.pi.workMode || config.dot.llm.opencode.workMode;
in
{
imports = [
inputs.sops-nix.homeManagerModules.sops
];
sops = {
defaultSopsFile = ../../secrets/secrets.yaml;
defaultSopsFormat = "yaml";
age = {
keyFile = "${config.home.homeDirectory}/.config/sops/age/keys.txt";
};
secrets = lib.mkIf needsLangdock {
langdock_api_key = {
# Uses defaultSopsFile from secrets.nix
};
};
};
home.sessionVariables = {
SOPS_AGE_KEY_FILE = config.sops.age.keyFile;
};
# Export the decrypted langdock API key as an env var. The secret lives in a
# runtime file, so it is read at shell startup rather than baked into the Nix
# store via home.sessionVariables.
programs.zsh.initContent = lib.mkIf needsLangdock ''
if [ -r "${config.sops.secrets.langdock_api_key.path}" ]; then
export LANGDOCK_API_KEY="$(cat "${config.sops.secrets.langdock_api_key.path}")"
fi
'';
}

View File

@@ -1,128 +0,0 @@
{ config, pkgs, lib, ... }:
let
cfg = config.dot.sh;
in
{
options.dot.sh = {
sourceProfile = lib.mkEnableOption "sourcing of $HOME/.profile in zsh profileExtra";
};
config = {
programs.zsh = {
enable = true;
enableCompletion = true;
autosuggestion.enable = true;
syntaxHighlighting.enable = true;
history.size = 500000;
prezto = {
enable = true;
caseSensitive = true;
color = true;
editor = {
dotExpansion = true;
keymap = "vi";
};
pmodules = [
"environment"
"terminal"
"editor"
"history"
"directory"
"spectrum"
"utility"
"completion"
"ssh"
"syntax-highlighting"
"history-substring-search"
"prompt"
"git"
];
prompt.theme = "minimal";
syntaxHighlighting.highlighters = [
"main"
"brackets"
"pattern"
"line"
"cursor"
"root"
];
tmux = {
autoStartLocal = true;
itermIntegration = true;
};
};
initContent = ''
HISTCONTROL='erasedups:ignoreboth'
HISTIGNORE='&:[ ]*:exit:ls:bg:fg:history:clear'
unsetopt beep
prg() {
# ''${1} is the search term, ''${2} is the path (defaulting to . if empty)
local query="''${1:-}"
local search_path="''${2:-.}"
local selected=$(
fzf --ansi --disabled --query "$query" \
--bind "start:reload(rg --column --line-number --no-heading --color=always --smart-case {q} \"$search_path\")" \
--bind "change:reload:sleep 0.1; rg --column --line-number --no-heading --color=always --smart-case {q} \"$search_path\" || true" \
--bind "shift-up:preview-up,shift-down:preview-down" \
--delimiter : \
--preview 'bat --color=always --style=numbers --highlight-line {2} {1}' \
--preview-window 'right,45%,border-left,+{2}+3/3,~3'
)
# Extract file and line, then open in Neovim
[ -n "$selected" ] && nvim "$(echo "$selected" | cut -d: -f1)" +"$(echo "$selected" | cut -d: -f2)"
}
'';
};
programs.fzf = {
enable = true;
enableZshIntegration = true;
};
programs.lsd = {
enable = true;
enableZshIntegration = true;
};
programs.zoxide = {
enable = true;
enableZshIntegration = true;
options = [
"--cmd cd"
];
};
programs.bat.enable = true;
programs.ripgrep.enable = true;
programs.btop.enable = true;
programs.ranger.enable = true;
home.packages = with pkgs; [
fd
dust
glow
ripgrep-all
viddy
duf
lsof
rclone
sshfs
];
home.sessionVariables = {
BAT_THEME = "Coldark-Cold";
};
home.shellAliases = {
lst = "lsd --tree";
};
};
}

View File

@@ -1,297 +0,0 @@
{ config, pkgs, lib, ... }:
let
cfg = config.dot.tmux;
# tmuxp from nixpkgs-unstable (provided by modules/overlays/unstable.nix)
tmuxp = pkgs.unstable.tmuxp;
projectSelector = pkgs.writeScriptBin "projectSelector" ''
#!${pkgs.zsh}/bin/zsh
# Configuration
PRO_BASE_DIR="$HOME/pro"
PRO_BLACKLIST=("lost+found" ".git" "node_modules")
# 1. Build the list of projects
list="misc"
if [[ -d "$PRO_BASE_DIR" ]]; then
for dir in "$PRO_BASE_DIR"/*(/N); do
name=$(basename "$dir")
# Check against blacklist
if [[ ! ''${PRO_BLACKLIST[(r)''${name}]} == ''${name} ]]; then
list+="\n$name"
fi
done
fi
# 2. Open fzf (Multi-select: Tab to mark, Enter to confirm)
selected=$(echo -e "$list" | ${pkgs.fzf}/bin/fzf -m --header="Select projects" --reverse)
[[ -z "$selected" ]] && exit 0
# 3. Process selections
# Convert newline-separated string to array
selected_array=("''${(@f)selected}")
total=''${#selected_array[@]}
i=0
for arg in "''${selected_array[@]}"; do
((i++))
target=""
s_name=""
if [[ "$arg" == "misc" ]]; then
target="$HOME"
s_name="misc"
else
target="$PRO_BASE_DIR/$arg"
s_name=$(basename "$target" | tr '.' '_')
fi
# Background load all but the last selection
if [[ $i -lt $total ]]; then
if [[ -f "$target/.tmuxp.yaml" || -f "$target/.tmuxp.yml" ]]; then
${tmuxp}/bin/tmuxp load --yes -d "$target"
else
if ! ${pkgs.tmux}/bin/tmux has-session -t "$s_name" 2>/dev/null; then
${pkgs.tmux}/bin/tmux new-session -d -s "$s_name" -c "$target"
fi
fi
else
# Last item: Foreground switch/attach
if [[ -f "$target/.tmuxp.yaml" || -f "$target/.tmuxp.yml" ]]; then
${tmuxp}/bin/tmuxp load --yes "$target"
else
if ! ${pkgs.tmux}/bin/tmux has-session -t "$s_name" 2>/dev/null; then
${pkgs.tmux}/bin/tmux new-session -d -s "$s_name" -c "$target"
fi
if [[ -n "$TMUX" ]]; then
${pkgs.tmux}/bin/tmux switch-client -t "$s_name"
else
${pkgs.tmux}/bin/tmux attach-session -t "$s_name"
fi
fi
fi
done
'';
tmuxKiller = pkgs.writeScriptBin "tmuxKiller" ''
#!${pkgs.zsh}/bin/zsh
# 1. Build the list of active tmux sessions
sessions=$(${pkgs.tmux}/bin/tmux list-sessions -F "#S" 2>/dev/null)
# Always add the kill-server option
sessions_list="$sessions\n--- KILL TMUX SERVER ---"
# 2. Open fzf (Multi-select: Tab to mark multiple, Enter to confirm)
selected=$(echo -e "$sessions_list" | ${pkgs.fzf}/bin/fzf -m --header="Select tmux sessions to KILL (Tab to multi-select)" --reverse)
[[ -z "$selected" ]] && exit 0
# 3. Process selections
# Convert newline-separated string to array
selected_array=("''${(@f)selected}")
for s_name in "''${selected_array[@]}"; do
if [[ "$s_name" == "--- KILL TMUX SERVER ---" ]]; then
${pkgs.tmux}/bin/tmux kill-server
echo "Killed tmux server"
exit 0
fi
if ${pkgs.tmux}/bin/tmux has-session -t "$s_name" 2>/dev/null; then
${pkgs.tmux}/bin/tmux kill-session -t "$s_name"
echo "Killed session: $s_name"
fi
done
'';
in
{
options.dot.tmux = {
workMode = lib.mkEnableOption "work-specific tmux configuration";
};
config = {
programs.tmux = {
enable = true;
shortcut = "a";
mouse = true;
keyMode = "vi";
escapeTime = 10;
terminal = "xterm-256color";
# tmuxp is installed manually below to pin it to unstable
# (programs.tmux.tmuxp has no package option)
tmuxp.enable = false;
extraConfig = ''
set -g display-time 1500
set -s set-clipboard on
set -g extended-keys on
set -g extended-keys-format csi-u
set -g renumber-windows on
set -g base-index 1
set -g pane-base-index 1
unbind S
bind S command-prompt "switch -t %1"
bind-key , command-prompt -p "rename-window:" "rename-window '%%'"
# Check if we are in vim
is_vim="ps -o state= -o comm= -t '#{pane_tty}' | grep -iqE '^[^TXZ ]+ +(\\S+\\/)?g?(view|n?vim?x?)(diff)?$'"
bind-key -n C-M-h if-shell "$is_vim" { send-keys C-M-h } { if -F "#{pane_at_left}" "previous-window" "select-pane -L" }
bind-key -n C-M-j if-shell "$is_vim" { send-keys C-M-j } { if -F "#{pane_at_bottom}" "switch-client -n" "select-pane -D" }
bind-key -n C-M-k if-shell "$is_vim" { send-keys C-M-k } { if -F "#{pane_at_top}" "switch-client -p" "select-pane -U" }
bind-key -n C-M-l if-shell "$is_vim" { send-keys C-M-l } { if -F "#{pane_at_right}" "next-window" "select-pane -R" }
bind '"' split-window -c "#{pane_current_path}"
bind % split-window -h -c "#{pane_current_path}"
bind c new-window -a -c "#{pane_current_path}"
bind C-g display-popup -E -d "#{pane_current_path}" -xC -yC -w 95% -h 95% "lazygit"
bind C-t display-popup -E -xC -yC -w 95% -h 95% "tasksquire"
bind C-r display-popup -E "tmuxKiller"
${lib.optionalString cfg.workMode ''
bind C-s display-popup -E "projectSelector"
bind C-n display-popup -E -xC -yC -w 95% -h 95% -d "/mnt/c/Users/marti/Documents/notes/Work/" "vim -c 'nnoremap q :wqa<CR>' quick_notes.md"
bind C-q display-popup -E -xC -yC -w 95% -h 95% " \
SESSION_NAME=\$(tmux display-message -p '#S'); \
if [ \"\$SESSION_NAME\" = 'misc' ]; then \
cd '/mnt/c/Users/marti/Documents/notes/Work/' && vim -c 'nnoremap q :wqa<CR>' task_notes.md; \
else \
cd \"\$HOME/pro/\$SESSION_NAME\" && vim -c 'nnoremap q :wqa<CR>' task_notes.md; \
fi"
bind C-p display-popup -E -xC -yC -w 95% -h 95% -d "/mnt/c/Users/marti/Documents/notes/Work/development/" "vim -c 'nnoremap q :wqa<CR>' mbpr.md"
''}
#######################################
# status line
#######################################
set -g status-justify centre
set -g status-left "#[bg=#808080,fg=#ffffff,bold] #S #[default]#[bg=#BCBCBC] #{-30:pane_title} "
set -g status-left-length 40
set -g status-right "#[bg=#BCBCBC] %H:%M #[bg=#808080,fg=#ffffff] %d.%m.%y "
setw -g window-status-format "#W:#I "
setw -g window-status-current-format " #W:#I "
setw -g window-status-separator ""
#######################################
# colors, taken from vim-lucius
#######################################
set -g status-style "bg=#DADADA,fg=#000000"
setw -g window-status-style "bg=#BCBCBC,fg=#000000"
setw -g window-status-current-style "bg=#808080,fg=#ffffff"
setw -g window-status-activity-style "bg=#AFD7AF,fg=#000000"
setw -g window-status-bell-style "bg=#AFD7AF,fg=#000000"
#setw -g window-status-content-style "bg=#AFD7AF,fg=#000000"
set -g pane-active-border-style "bg=#eeeeee,fg=#006699"
set -g pane-border-style "bg=#eeeeee,fg=#999999"
'';
};
programs.zsh.initExtra = lib.optionalString cfg.workMode ''
# --- 1. Configuration ---
export PRO_BASE_DIR="$HOME/pro"
export PRO_BLACKLIST=("lost+found")
# --- 2. The 'pro' function ---
pro() {
local total_args=$#
local i=0
for arg in "$@"; do
((i++))
local target=""
local s_name=""
# Resolve the target directory and session name
if [[ "$arg" == "misc" ]]; then
target="$HOME"
s_name="misc"
elif [[ -d "$PRO_BASE_DIR/$arg" ]]; then
target="$PRO_BASE_DIR/$arg"
s_name=$(basename "$target" | tr '.' '_')
elif [[ -d "$HOME/$arg" ]]; then
target="$HOME/$arg"
s_name=$(basename "$target" | tr '.' '_')
else
echo "Error: Project '$arg' not found in $PRO_BASE_DIR or $HOME"
continue
fi
target=$(realpath "$target")
# logic: If this is NOT the last argument, load it in the background.
# If it IS the last argument, load/attach to it in the foreground.
if [[ "$i" -lt "$total_args" ]]; then
# BACKGROUND LOADING
if [[ -f "$target/.tmuxp.yaml" || -f "$target/.tmuxp.yml" ]]; then
tmuxp load --yes -d "$target"
else
if ! tmux has-session -t "$s_name" 2>/dev/null; then
tmux new-session -d -s "$s_name" -c "$target"
fi
fi
else
# FOREGROUND ATTACHING (The "Winner")
if [[ -f "$target/.tmuxp.yaml" || -f "$target/.tmuxp.yml" ]]; then
# tmuxp load handles switching/attaching automatically
tmuxp load --yes "$target"
else
if ! tmux has-session -t "$s_name" 2>/dev/null; then
tmux new-session -d -s "$s_name" -c "$target"
fi
if [[ -n "$TMUX" ]]; then
tmux switch-client -t "$s_name"
else
tmux attach-session -t "$s_name"
fi
fi
fi
done
}
# --- 3. Tab Completion ---
_pro_completion() {
local -a projects
# Manually add the 'misc' alias to completion
projects+=("misc")
# Add directories from ~/pro/
if [[ -d "$PRO_BASE_DIR" ]]; then
for dir in "$PRO_BASE_DIR"/*(/N); do
local name=$(basename "$dir")
# Nix escape for array check: if name not in blacklist
if [[ ! ''${PRO_BLACKLIST[(r)''${name}]} == ''${name} ]]; then
projects+=("''${name}")
fi
done
fi
_describe 'projects' projects
}
compdef _pro_completion pro
'';
home.packages = [
tmuxKiller
tmuxp
] ++ lib.optional cfg.workMode projectSelector;
home.shellAliases = {
"o" = "tmuxp";
"ol" = "tmuxp load";
};
};
}

View File

@@ -1,47 +0,0 @@
{ config, pkgs, lib, ... }:
{
imports = [
./secrets.nix
];
time.timeZone = "Europe/Berlin";
i18n.defaultLocale = "en_US.UTF-8";
i18n.extraLocaleSettings = {
LC_ADDRESS = "de_DE.UTF-8";
LC_IDENTIFICATION = "de_DE.UTF-8";
LC_MEASUREMENT = "de_DE.UTF-8";
LC_MONETARY = "de_DE.UTF-8";
LC_NAME = "de_DE.UTF-8";
LC_NUMERIC = "de_DE.UTF-8";
LC_PAPER = "de_DE.UTF-8";
LC_TELEPHONE = "de_DE.UTF-8";
LC_TIME = "de_DE.UTF-8";
};
programs.zsh.enable = true;
programs.ssh.startAgent = true;
programs.nix-ld.enable = true;
nix.settings = {
experimental-features = [ "nix-command" "flakes" ];
auto-optimise-store = true;
};
nixpkgs.config.allowUnfree = true;
nix.gc = {
automatic = true;
dates = "weekly";
options = "--delete-older-than 7d";
};
environment.systemPackages = with pkgs; [
git
git-lfs
wget
curl
vim
];
}

View File

@@ -1,18 +0,0 @@
{ inputs, config, ... }:
{
imports = [
inputs.sops-nix.nixosModules.sops
];
sops = {
defaultSopsFile = ../../secrets/secrets.yaml;
defaultSopsFormat = "yaml";
age = {
sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
# keyFile = "/var/lib/sops-nix/key.txt";
# generateKey = true;
};
};
}

View File

@@ -1,239 +0,0 @@
local capabilities = require('cmp_nvim_lsp').default_capabilities()
vim.lsp.config('gopls', {
cmd = { 'gopls' },
filetypes = { 'go', 'gomod', 'gowork', 'gotmpl' },
root_markers = { 'go.work', 'go.mod', '.git' },
settings = {
gopls = {
semanticTokens = true,
hints = {
assignVariableTypes = true,
compositeLiteralFields = true,
compositeLiteralTypes = true,
constantValues = true,
functionTypeParameters = true,
rangeVariableTypes = true,
parameterNames = true,
},
analyses = {
unusedparams = true,
},
staticcheck = true,
},
},
})
vim.lsp.config('clangd', {
cmd = { 'clangd',
'--compile-commands-dir=build',
'--background-index',
'--clang-tidy',
},
})
vim.lsp.config('basedpyright', {
settings = {
basedpyright = {
analysis = {
indexing = true,
typeCheckingMode = "standard",
autoImportCompletions = true,
diagnosticSeverityOverrides = {
reportAttributeAccessIssue = "none",
},
}
}
}
})
vim.lsp.config('buf_ls', {
cmd = { 'buf', 'lsp', 'serve' },
filetypes = { 'proto' },
root_markers = { 'buf.yaml', '.git' },
})
vim.lsp.enable('gopls')
vim.lsp.enable('clangd')
vim.lsp.enable('basedpyright')
-- vim.lsp.enable('ty')
vim.lsp.enable('buf_ls')
vim.lsp.enable('marksman')
vim.lsp.enable('sqls')
vim.lsp.enable('dockerls')
vim.lsp.enable('docker_compose_language_service')
vim.lsp.enable('rust_analyzer')
vim.lsp.enable('zls')
vim.lsp.enable('yamlls')
vim.lsp.enable('omnisharp')
vim.lsp.enable('bashls')
vim.api.nvim_create_augroup('FileTypeConfigs', { clear = true })
vim.api.nvim_create_autocmd('FileType', {
group = vim.api.nvim_create_augroup('FileTypeConfigs', { clear = true }),
pattern = 'python',
callback = function()
local status, dappython = pcall(require, "dap-python")
if status then
dappython.setup()
end
end,
})
vim.api.nvim_create_autocmd('FileType', {
group = vim.api.nvim_create_augroup('FileTypeConfigs', { clear = true }),
pattern = { 'go', 'gomod', 'gowork', 'gotmpl' },
callback = function(args)
local status, dapgo = pcall(require, "dap-go")
if status then
dapgo.setup()
end
end,
})
local function cycle_todo()
local line = vim.api.nvim_get_current_line()
-- 0. STRICT CHECK: If the line doesn't start with a list marker (-), fall back to normal Enter behavior
if not line:match("^%s*%-") then
-- This simulates a normal carriage return if mapped to <CR>
local keys = vim.api.nvim_replace_termcodes("<CR>", true, false, true)
vim.api.nvim_feedkeys(keys, "n", false)
return
end
-- The sequence of checkbox states we want to cycle through
local states = { " ", ">", "x", "!", "~", "c" }
-- 1. If it's a cancelled todo [c], strip the brackets but KEEP the list item (- )
if line:match("^%s*%-%s*%[c%]") then
local clean_line = line:gsub("(%s*%-%s*)%[c%]%s*", "%1")
vim.api.nvim_set_current_line(clean_line)
return
end
-- 2. If it's a standard list item without a checkbox, turn it into `- [ ]`
if not line:match("^%s*%-%s*%[.%]") then
-- Matches the list prefix (e.g., "- " or " - ") and appends "[ ] "
local new_line = line:gsub("^(%s*%-%s*)", "%1[ ] ")
vim.api.nvim_set_current_line(new_line)
return
end
-- 3. Cycle through the custom states natively
for i, state in ipairs(states) do
-- Escape special Lua magic characters like !, >, ~, c
local escaped_state = state:gsub("([^%w])", "%%%1")
local pattern = "^(%s*%-%s*%[)" .. escaped_state .. "(%])"
if line:match(pattern) then
local next_state = states[(i % #states) + 1]
local new_line = line:gsub(pattern, "%1" .. next_state .. "%2", 1)
vim.api.nvim_set_current_line(new_line)
return
end
end
end
vim.api.nvim_create_autocmd('FileType', {
group = vim.api.nvim_create_augroup('FileTypeConfigs', { clear = true }),
pattern = 'markdown',
once = true,
callback = function()
vim.keymap.set('n', '<CR>', cycle_todo, {
buffer = true,
desc = 'Cycle todo state'
})
end,
})
-- vim.api.nvim_create_autocmd('FileType', {
-- group = vim.api.nvim_create_augroup('FileTypeConfigs', { clear = true }),
-- pattern = 'proto',
-- once = true,
-- callback = function()
-- end,
-- })
--
--
-- vim.api.nvim_create_autocmd('FileType', {
-- group = vim.api.nvim_create_augroup('FileTypeConfigs', { clear = true }),
-- pattern = 'sql',
-- once = true,
-- callback = function()
-- end,
-- })
-- vim.api.nvim_create_autocmd('FileType', {
-- group = vim.api.nvim_create_augroup('FileTypeConfigs', { clear = true }),
-- pattern = { 'dockerfile', 'yaml.docker-compose' },
-- once = true,
-- callback = function()
-- end,
-- })
--
-- vim.api.nvim_create_autocmd('FileType', {
-- group = vim.api.nvim_create_augroup('FileTypeConfigs', { clear = true }),
-- pattern = 'rust',
-- once = true,
-- callback = function()
-- end,
-- })
--
-- vim.lsp.enable('clangd')
-- vim.api.nvim_create_autocmd('FileType', {
-- group = vim.api.nvim_create_augroup('FileTypeConfigs', { clear = true }),
-- pattern = { 'c', 'cpp' },
-- once = true,
-- callback = function()
-- end,
-- })
--
-- vim.api.nvim_create_autocmd('FileType', {
-- group = vim.api.nvim_create_augroup('FileTypeConfigs', { clear = true }),
-- pattern = { 'zig' },
-- pattern = 'sql',
-- once = true,
-- callback = function()
-- end,
-- })
-- vim.api.nvim_create_autocmd('FileType', {
-- group = vim.api.nvim_create_augroup('FileTypeConfigs', { clear = true }),
-- pattern = { 'yaml' },
-- pattern = 'sql',
-- once = true,
-- callback = function()
-- end,
-- })
--
-- vim.api.nvim_create_autocmd('FileType', {
-- group = vim.api.nvim_create_augroup('FileTypeConfigs', { clear = true }),
-- pattern = { 'cs' },
-- pattern = 'sql',
-- once = true,
-- callback = function()
-- end,
-- })
local get_datetime = function()
return os.date("%Y-%m-%d %H:%M")
end
local ls = require('luasnip')
ls.add_snippets("markdown", {
ls.snippet("mindful", {
-- Inserts the output of the get_datetime function as static text
ls.function_node(get_datetime, {}),
ls.text_node(" -- "),
ls.insert_node(1, "project"),
ls.text_node(" -- "),
ls.insert_node(2, "mode"),
ls.text_node(" -- "),
ls.insert_node(3, "description"),
}, {
descr = "Mindful of distractions",
}),
})

View File

@@ -1,12 +0,0 @@
{
"$schema": "https://opencode.ai/config.json",
"default_agent": "plan",
"plugin": [
"opencode-gemini-auth@latest"
],
"model": "google/gemini-3-pro-preview",
"small_model": "google/gemini-3-flash-preview",
"enabled_providers": [
"google"
]
}

View File

@@ -1,75 +0,0 @@
{
"$schema": "https://opencode.ai/config.json",
"default_agent": "plan",
"enabled_providers": [
"anthropic",
"langdock-openai",
"sparkr",
"sparkl"
],
"model": "anthropic/claude-opus-5-default",
"small_model": "anthropic/claude-sonnet-5-default",
"provider": {
"sparkr": {
"npm": "@ai-sdk/openai-compatible",
"name": "sparkr",
"options": {
"baseURL": "http://192.168.10.110:8000/v1",
"apiKey": "vllm"
},
"models": {
"Qwen/Qwen3-Coder-Next-FP8": {
"name": "Qwen3 Coder Next FP8 (local vLLM)",
"tool_call": true,
"reasoning": false,
"limit": { "context": 262144, "output": 8192 }
}
}
},
"sparkl": {
"npm": "@ai-sdk/openai-compatible",
"name": "sparkl",
"options": {
"baseURL": "http://192.168.10.111:8000/v1",
"apiKey": "vllm"
},
"models": {
"Qwen/Qwen3-30B-A3B": {
"name": "Qwen3 30B A3B (local vLLM)",
"tool_call": true,
"reasoning": true,
"limit": { "context": 16384, "output": 8192 }
}
}
},
"langdock-openai": {
"npm": "@ai-sdk/openai-compatible",
"name": "Langdock OpenAI",
"options": {
"baseURL": "https://api.langdock.com/openai/eu/v1",
"apiKey": "{env:LANGDOCK_API_KEY}"
},
"models": {
"gpt-5.6-sol": { "name": "GPT-5.6 Sol" },
"gpt-5.6-terra": { "name": "GPT-5.6 Terra" },
"gpt-5.6-luna": { "name": "GPT-5.6 Luna" }
}
},
"anthropic": {
"options": {
"baseURL": "https://api.langdock.com/anthropic/eu/v1",
"apiKey": "{env:LANGDOCK_API_KEY}"
},
"models": {
"claude-opus-5-default": { "name": "Opus 5" },
"claude-opus-4-8-default": { "name": "Opus 4.8" },
"claude-sonnet-5-default": { "name": "Sonnet 5" }
},
"whitelist": [
"claude-opus-4-8-default",
"claude-opus-5-default",
"claude-sonnet-5-default"
]
}
}
}

View File

@@ -1,13 +0,0 @@
# Overlay to provide unstable packages under pkgs.unstable.* namespace
# This allows using stable packages by default while selectively using
# unstable versions for specific packages (e.g., LLM development tools)
#
# Usage: Pass nixpkgs input when applying overlay:
# overlays = [ (import ./modules/overlays/unstable.nix nixpkgs) ];
nixpkgs: final: prev: {
unstable = import nixpkgs {
inherit (prev) system;
config.allowUnfree = true;
};
}

View File

@@ -1,42 +0,0 @@
# Plan Mode
Minimal read-only mode. Built iteratively — v1 does one thing only.
## v1: no writing
| Trigger | Effect |
| --- | --- |
| `/plan` | Toggle plan mode |
| `Ctrl+Alt+P` | Toggle plan mode |
| `pi --plan` | Start in plan mode |
While active:
- Built-in `write` and `edit` tools are removed from the active tool set
- A `plan` marker appears in the footer status
- The system prompt tells the model it cannot modify files
- State is persisted, so `/resume` keeps plan mode on
Toggling off restores the exact tool set captured when plan mode was enabled.
## v2: `/handover`
`/handover [focus]` distils the session into a standalone plan document.
- Runs a **side LLM call** over the current branch — no extra turn is added to the
conversation, and the transcript is not polluted
- Compaction-aware: uses the summary plus surviving entries if the branch was compacted
- Opens the result in the editor for review; saving writes the file, an empty buffer cancels
- Written to `.pi/plans/<YYYYMMDD-HHMM>-<slug>.md`, slug derived from the `#` heading
- Optional `focus` argument steers what the document centres on
Document structure: `Goal`, `Findings`, `Plan` (numbered, file-scoped steps),
`Risks & open questions`, `Files`.
Works whether or not plan mode is active.
## Not implemented (yet)
- Guarding `bash` against writes — `bash` is still fully available
- Reading a handover back in / resuming from one
- Approval and step-by-step execution flow

View File

@@ -1,196 +0,0 @@
/**
* Handover document generation for plan mode.
*
* Runs a side LLM call over the current branch (does NOT add a turn to the
* conversation), lets the user edit the result, then writes it to
* `.pi/plans/<slug>-<timestamp>.md`.
*/
import type { AgentMessage } from "@earendil-works/pi-agent-core";
import { type Message, uuidv7 } from "@earendil-works/pi-ai";
import {
BorderedLoader,
CONFIG_DIR_NAME,
convertToLlm,
type ExtensionCommandContext,
type SessionEntry,
serializeConversation,
} from "@earendil-works/pi-coding-agent";
import { mkdir, writeFile } from "node:fs/promises";
import { join } from "node:path";
export const PLANS_DIR = "plans";
const SYSTEM_PROMPT = `You write handover documents. Another engineer (or agent) will pick up
this work with NO access to the conversation you are summarizing. The document must stand alone.
Output GitHub-flavoured markdown with exactly these sections:
# <short imperative title, max 8 words>
## Goal
One paragraph: what we are trying to achieve and why.
## Findings
What was learned while investigating. Cite concrete file paths and, where useful, line numbers
or symbol names. Include things that were ruled out and why.
## Plan
A numbered list of concrete, actionable steps in execution order. Each step names the files it
touches. No vague steps like "improve error handling".
## Risks & open questions
Bullets. Anything unverified, any decision the user still needs to make. Omit the section if
genuinely empty.
## Files
Bullet list of \`path\` — one-line reason it matters.
Rules:
- No preamble, no "Here is the handover". Start with the \`#\` heading.
- Be specific over complete. Facts from the conversation only; never invent file paths.
- Do not describe the conversation itself ("the user asked..."). Describe the work.`;
function entryToMessage(entry: SessionEntry): AgentMessage | undefined {
if (entry.type === "message") return entry.message;
if (entry.type === "compaction") {
return {
role: "compactionSummary",
summary: entry.summary,
tokensBefore: entry.tokensBefore,
timestamp: new Date(entry.timestamp).getTime(),
};
}
return undefined;
}
/** Branch messages, respecting the most recent compaction boundary. */
function collectMessages(branch: SessionEntry[]): AgentMessage[] {
let compactionIndex = -1;
for (let i = branch.length - 1; i >= 0; i--) {
if (branch[i]?.type === "compaction") {
compactionIndex = i;
break;
}
}
if (compactionIndex < 0) {
return branch.map(entryToMessage).filter((m): m is AgentMessage => m !== undefined);
}
const compaction = branch[compactionIndex];
const firstKept =
compaction?.type === "compaction" ? branch.findIndex((e) => e.id === compaction.firstKeptEntryId) : -1;
return [
compaction,
...(firstKept >= 0 ? branch.slice(firstKept, compactionIndex) : []),
...branch.slice(compactionIndex + 1),
]
.map((e) => (e ? entryToMessage(e) : undefined))
.filter((m): m is AgentMessage => m !== undefined);
}
function slugify(text: string): string {
return (
text
.toLowerCase()
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-+|-+$/g, "")
.slice(0, 50)
.replace(/-+$/g, "") || "handover"
);
}
function timestamp(): string {
const d = new Date();
const p = (n: number) => String(n).padStart(2, "0");
return `${d.getFullYear()}${p(d.getMonth() + 1)}${p(d.getDate())}-${p(d.getHours())}${p(d.getMinutes())}`;
}
/** Derive a filename slug from the document's first `# heading`. */
function slugFromDocument(markdown: string): string {
const heading = markdown.match(/^#\s+(.+)$/m);
return slugify(heading?.[1] ?? "handover");
}
/**
* Generate a handover document and write it to `.pi/plans/`.
* Returns the written path, or undefined if cancelled or unavailable.
*/
export async function writeHandover(ctx: ExtensionCommandContext, focus: string): Promise<string | undefined> {
if (ctx.mode !== "tui") {
ctx.ui.notify("/handover requires interactive mode", "error");
return;
}
if (!ctx.model) {
ctx.ui.notify("No model selected", "error");
return;
}
const messages = collectMessages(ctx.sessionManager.getBranch());
if (messages.length === 0) {
ctx.ui.notify("Nothing to hand over yet", "warning");
return;
}
const conversation = serializeConversation(convertToLlm(messages));
const model = ctx.model;
const generated = await ctx.ui.custom<string | null>((tui, theme, _kb, done) => {
const loader = new BorderedLoader(tui, theme, "Writing handover document...");
loader.onAbort = () => done(null);
void (async () => {
const prompt = focus
? `## Conversation\n\n${conversation}\n\n## Focus\n\nThe handover should centre on: ${focus}`
: `## Conversation\n\n${conversation}`;
const userMessage: Message = {
role: "user",
content: [{ type: "text", text: prompt }],
timestamp: Date.now(),
};
const response = await ctx.modelRegistry.complete(
model,
{ systemPrompt: SYSTEM_PROMPT, messages: [userMessage] },
{ signal: loader.signal, cacheRetention: "none", sessionId: uuidv7() },
);
if (response.stopReason === "aborted") return null;
return response.content
.filter((c): c is { type: "text"; text: string } => c.type === "text")
.map((c) => c.text)
.join("\n")
.trim();
})()
.then(done)
.catch(() => done(null));
return loader;
});
if (!generated) {
ctx.ui.notify("Handover cancelled", "info");
return;
}
const edited = await ctx.ui.editor("Review handover (save to write, empty to cancel)", generated);
if (edited === undefined || !edited.trim()) {
ctx.ui.notify("Handover cancelled", "info");
return;
}
const dir = join(ctx.cwd, CONFIG_DIR_NAME, PLANS_DIR);
const path = join(dir, `${timestamp()}-${slugFromDocument(edited)}.md`);
try {
await mkdir(dir, { recursive: true });
await writeFile(path, `${edited.trimEnd()}\n`, "utf8");
} catch (err) {
ctx.ui.notify(`Failed to write handover: ${err instanceof Error ? err.message : String(err)}`, "error");
return;
}
ctx.ui.notify(`Handover written to ${path}`, "info");
return path;
}

View File

@@ -1,130 +0,0 @@
/**
* Plan Mode — v1
*
* Scope (deliberately minimal, grown iteratively):
* - Toggle a read-only "plan mode" via `/plan`, `Ctrl+Alt+P`, or `--plan`
* - While active: built-in write tools (`write`, `edit`) are disabled
* - Footer status shows when plan mode is active
* - The model is told it cannot make changes
* - State survives session resume
* - `/handover` distils the session into a plan document under `.pi/plans/`
*
* NOT handled yet (future iterations): bash write guarding, approval flow,
* execution tracking.
*/
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
import { Key } from "@earendil-works/pi-tui";
import { writeHandover } from "./handover.ts";
/** Built-in tools that can mutate the filesystem. */
const WRITE_TOOLS = new Set(["write", "edit"]);
const STATE_ENTRY = "plan-mode";
interface PlanModeState {
enabled: boolean;
/** Active tool list captured before plan mode narrowed it. */
savedTools?: string[];
}
const PLAN_MODE_PROMPT = `[PLAN MODE ACTIVE]
You are in plan mode. The built-in \`write\` and \`edit\` tools are disabled for
this turn, so you cannot modify files.
Investigate, read code, and answer. When the user asks for changes, describe
what you would do instead of attempting it. Do not try to route around the
restriction (for example by writing files through \`bash\`).`;
export default function planModeExtension(pi: ExtensionAPI): void {
let enabled = false;
let savedTools: string[] | undefined;
pi.registerFlag("plan", {
description: "Start in plan mode (read-only)",
type: "boolean",
default: false,
});
function persist(): void {
pi.appendEntry(STATE_ENTRY, { enabled, savedTools } satisfies PlanModeState);
}
function applyToolRestrictions(): void {
if (savedTools === undefined) {
savedTools = pi.getActiveTools();
}
pi.setActiveTools(savedTools.filter((name) => !WRITE_TOOLS.has(name)));
}
function restoreTools(): void {
if (savedTools !== undefined) {
pi.setActiveTools(savedTools);
savedTools = undefined;
return;
}
// No snapshot (e.g. resumed session): re-enable write tools additively.
pi.setActiveTools([...new Set([...pi.getActiveTools(), ...WRITE_TOOLS])]);
}
function updateStatus(ctx: ExtensionContext): void {
ctx.ui.setStatus("plan-mode", enabled ? ctx.ui.theme.fg("warning", "plan") : undefined);
}
function setEnabled(next: boolean, ctx: ExtensionContext): void {
if (next === enabled) return;
enabled = next;
if (enabled) {
applyToolRestrictions();
ctx.ui.notify("Plan mode on — write and edit disabled.", "info");
} else {
restoreTools();
ctx.ui.notify("Plan mode off — write access restored.", "info");
}
updateStatus(ctx);
persist();
}
pi.registerCommand("plan", {
description: "Toggle plan mode (read-only)",
handler: async (_args, ctx) => setEnabled(!enabled, ctx),
});
pi.registerCommand("handover", {
description: "Write a handover document for this session to .pi/plans/",
handler: async (args, ctx) => {
await writeHandover(ctx, args.trim());
},
});
pi.registerShortcut(Key.ctrlAlt("p"), {
description: "Toggle plan mode",
handler: async (ctx) => setEnabled(!enabled, ctx),
});
pi.on("before_agent_start", async (event) => {
if (!enabled) return;
return { systemPrompt: `${event.systemPrompt}\n\n${PLAN_MODE_PROMPT}` };
});
pi.on("session_start", async (_event, ctx) => {
const entries = ctx.sessionManager.getEntries();
const last = entries
.filter((e: { type: string; customType?: string }) => e.type === "custom" && e.customType === STATE_ENTRY)
.pop() as { data?: PlanModeState } | undefined;
if (last?.data) {
enabled = last.data.enabled;
savedTools = last.data.savedTools;
}
if (pi.getFlag("plan") === true) {
enabled = true;
}
if (enabled) applyToolRestrictions();
updateStatus(ctx);
});
}

View File

@@ -1,263 +0,0 @@
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
export default function (pi: ExtensionAPI) {
// ── Anthropic via Langdock ──────────────────────────────────────────────
pi.registerProvider("anthropic", {
baseUrl: "https://api.langdock.com/anthropic/eu",
apiKey: "$LANGDOCK_API_KEY",
api: "anthropic-messages",
models: [
{
id: "claude-opus-4-8-default",
name: "Opus 4.8",
reasoning: true,
input: ["text", "image"],
contextWindow: 200000,
maxTokens: 32000,
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
compat: { forceAdaptiveThinking: true },
},
{
id: "claude-opus-5-default",
name: "Opus 5",
reasoning: true,
input: ["text", "image"],
contextWindow: 200000,
maxTokens: 32000,
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
compat: { forceAdaptiveThinking: true },
},
{
id: "claude-sonnet-5-default",
name: "Sonnet 5",
reasoning: true,
input: ["text", "image"],
contextWindow: 200000,
maxTokens: 16384,
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
compat: { forceAdaptiveThinking: true },
},
],
});
// ── OpenAI via Langdock (Responses API) ─────────────────────────────────
// Chat Completions is unusable for agent work: Langdock rejects the combo pi
// needs with "400 Function tools with reasoning_effort are not supported for
// <model> in /v1/chat/completions. To use function tools, use /v1/responses
// or set reasoning_effort to 'none'."
// Docs: https://docs.langdock.com/en/developer/completion-api/openai-responses
//
// Verified against api.langdock.com/openai/eu/v1/responses:
// ✓ SSE streaming, strict function tools, parallel calls, tool-result replay
// ✓ image input, developer role, store:false (pi always sends it)
// ✗ reasoning effort "minimal" (upstream rejects it for these models)
// ✗ Lark/regex grammar tools → only `type: "function"` is allowed
// ✗ max_output_tokens above the per-model cap (silently clamped)
// • no encrypted reasoning is returned, but replaying reasoning items in
// `input` on follow-up turns is accepted
const openaiCompat = {
// strict JSON-schema function tools are accepted
supportsStrictMode: true,
// Langdock: 'Unsupported tool type "custom". Only function tools are allowed.'
supportsOpenAIGrammarTools: false,
// skip the underscore-containing `session_id` header (proxies drop it),
// keep x-client-request-id for session affinity
sessionAffinityFormat: "openai-nosession",
} as const;
// NOTE: provider-level `compat` is ignored for extension-registered models,
// so it has to be repeated on every model entry below.
// Langdock caps OpenAI models at 60k tokens/minute (Claude gets 200k), and a
// request larger than the budget is rejected outright — so the usable window
// is far below the model's real context size. 60k here makes pi auto-compact
// at ~44k (contextWindow - reserveTokens) and stay under the gate.
// Raise this if your workspace admin lifts the per-model TPM limit.
const openaiContextWindow = 60000;
pi.registerProvider("openai", {
baseUrl: "https://api.langdock.com/openai/eu/v1",
apiKey: "$LANGDOCK_API_KEY",
api: "openai-responses",
compat: openaiCompat,
models: [
{
id: "gpt-5.6-sol",
name: "GPT-5.6 Sol",
reasoning: true,
input: ["text", "image"],
contextWindow: openaiContextWindow,
maxTokens: 16000,
thinkingLevelMap: {
off: "none",
minimal: null,
low: "low",
medium: "medium",
high: "high",
xhigh: "xhigh",
max: "max",
},
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
compat: openaiCompat,
},
{
id: "gpt-5.6-terra",
name: "GPT-5.6 Terra",
reasoning: true,
input: ["text", "image"],
contextWindow: openaiContextWindow,
maxTokens: 16000,
thinkingLevelMap: {
off: "none",
minimal: null,
low: "low",
medium: "medium",
high: "high",
xhigh: "xhigh",
max: "max",
},
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
compat: openaiCompat,
},
{
id: "gpt-5.6-luna",
name: "GPT-5.6 Luna",
reasoning: true,
input: ["text", "image"],
contextWindow: openaiContextWindow,
maxTokens: 16000,
thinkingLevelMap: {
off: "none",
minimal: null,
low: "low",
medium: "medium",
high: "high",
xhigh: "xhigh",
max: "max",
},
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
compat: openaiCompat,
},
{
id: "gpt-5.5",
name: "GPT-5.5",
reasoning: true,
input: ["text", "image"],
contextWindow: openaiContextWindow,
maxTokens: 16000,
// "max" is rejected for this model
thinkingLevelMap: {
off: "none",
minimal: null,
low: "low",
medium: "medium",
high: "high",
xhigh: "xhigh",
max: null,
},
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
compat: openaiCompat,
},
{
id: "gpt-5.4-mini",
name: "GPT-5.4 Mini",
reasoning: true,
input: ["text", "image"],
contextWindow: openaiContextWindow,
maxTokens: 32000,
thinkingLevelMap: {
off: "none",
minimal: null,
low: "low",
medium: "medium",
high: "high",
xhigh: "xhigh",
max: null,
},
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
compat: openaiCompat,
},
],
});
// ── Google via Langdock ─────────────────────────────────────────────────
// pi.registerProvider("google", {
// baseUrl: "https://api.langdock.com/google/eu/v1beta",
// apiKey: "$LANGDOCK_API_KEY",
// api: "google-generative-ai",
// models: [
// {
// id: "models/gemini-3.5-flash",
// name: "Gemini 3.5 Flash",
// reasoning: true,
// input: ["text", "image"],
// contextWindow: 1048576,
// maxTokens: 8192,
// cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
// },
// {
// id: "models/gemini-2.5-flash",
// name: "Gemini 2.5 Flash",
// reasoning: true,
// input: ["text", "image"],
// contextWindow: 1048576,
// maxTokens: 8192,
// cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
// },
// {
// id: "models/gemini-2.5-pro",
// name: "Gemini 2.5 Pro",
// reasoning: true,
// input: ["text", "image"],
// contextWindow: 2097152,
// maxTokens: 65536,
// cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
// },
// ],
// });
// ── Hide unwanted built-in providers ────────────────────────────────────
const keep = new Set([
"openrouter",
]);
const hide = [
"ant-ling",
"azure-openai",
"azure-openai-responses",
"deepseek",
"nvidia-nim",
"google-vertex",
"amazon-bedrock",
"google",
"mistral",
"groq",
"cerebras",
"cloudflare-ai-gateway",
"cloudflare-workers-ai",
"xai",
"vercel-ai-gateway",
"zai-coding-plan-global",
"zai-coding-plan-china",
"opencode-zen",
"opencode-go",
"huggingface",
"fireworks",
"together-ai",
"kimi-for-coding",
"minimax",
"xiaomi-mimo",
"xiaomi-mimo-china",
"xiaomi-mimo-amsterdam",
"xiaomi-mimo-singapore",
];
for (const provider of hide) {
if (!keep.has(provider)) {
try {
pi.unregisterProvider(provider);
} catch {
// provider may not exist in this build
}
}
}
}

View File

@@ -1,209 +0,0 @@
{
"providers": {
"sparkl": {
"baseUrl": "http://192.168.10.111:8000/v1",
"api": "openai-completions",
"apiKey": "vllm",
"compat": {
"supportsDeveloperRole": false,
"supportsReasoningEffort": false
},
"models": [
{
"id": "Qwen/Qwen3.8-27B",
"name": "Qwen3.8 27B (local vLLM)",
"reasoning": true,
"input": ["text"],
"contextWindow": 16384,
"maxTokens": 16384,
"samplingParams": {
"temperature": 0.6,
"top_p": 0.95,
"top_k": 20
},
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 },
"compat": {
"thinkingFormat": "qwen-chat-template",
"maxTokensField": "max_tokens"
}
},
{
"id": "Qwen/Qwen3.8-27B-FP8",
"name": "Qwen3.8 27B FP8 (local vLLM)",
"reasoning": true,
"input": ["text"],
"contextWindow": 65536,
"maxTokens": 65536,
"samplingParams": {
"temperature": 0.6,
"top_p": 0.95,
"top_k": 20
},
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 },
"compat": {
"thinkingFormat": "qwen-chat-template",
"maxTokensField": "max_tokens"
}
},
{
"id": "deepseek-v4-flash",
"name": "DeepSeek v4 Flash (local vLLM)",
"reasoning": true,
"input": ["text"],
"contextWindow": 393216,
"maxTokens": 65536,
"samplingParams": {
"temperature": 1,
"top_p": 0.95
},
"thinkingLevelMap": {
"minimal": null,
"low": "low",
"medium": null,
"high": "high",
"xhigh": null,
"max": "max"
},
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 },
"compat": {
"thinkingFormat": "chat-template",
"supportsUsageInStreaming": true,
"requiresReasoningContentOnAssistantMessages": true,
"chatTemplateKwargs": {
"thinking": {
"$var": "thinking.enabled"
},
"reasoning_effort": {
"$var": "thinking.effort"
}
},
"maxTokensField": "max_tokens"
}
}
]
},
"sparkr": {
"baseUrl": "http://192.168.10.110:8000/v1",
"api": "openai-completions",
"apiKey": "vllm",
"compat": {
"supportsDeveloperRole": false,
"supportsReasoningEffort": false
},
"models": [
{
"id": "Qwen/Qwen3-Coder-Next-FP8",
"name": "Qwen3 Coder Next FP8 (local vLLM)",
"reasoning": false,
"input": ["text"],
"contextWindow": 262144,
"maxTokens": 8192,
"samplingParams": {
"temperature": 0.6,
"top_p": 0.95,
"top_k": 20
},
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 },
"compat": {
"maxTokensField": "max_tokens"
}
}
]
},
"bifrost": {
"baseUrl": "http://192.168.10.111:8080/v1",
"api": "openai-completions",
"apiKey": "vllm",
"headers": {
"x-bf-vk": "sk-bf-7efb6014-35ef-43c7-a361-c106709e1be5"
},
"compat": {
"supportsDeveloperRole": false,
"supportsReasoningEffort": false
},
"models": [
{
"id": "deepseek-v4-flash",
"name": "DeepSeek v4 Flash (local vLLM)",
"reasoning": true,
"input": ["text"],
"contextWindow": 393216,
"maxTokens": 65536,
"samplingParams": {
"temperature": 1,
"top_p": 0.95
},
"thinkingLevelMap": {
"minimal": null,
"low": "low",
"medium": null,
"high": "high",
"xhigh": null,
"max": "max"
},
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 },
"compat": {
"thinkingFormat": "chat-template",
"supportsUsageInStreaming": true,
"requiresReasoningContentOnAssistantMessages": true,
"chatTemplateKwargs": {
"thinking": {
"$var": "thinking.enabled"
},
"reasoning_effort": {
"$var": "thinking.effort"
}
},
"maxTokensField": "max_tokens"
}
}
]
},
"newapi": {
"baseUrl": "http://192.168.10.111:3000/v1",
"api": "openai-completions",
"apiKey": "sk-EeSqF8gbb1hEajBZhZzKuyqF4HJkA7RDsws0cQCSBQizJ3SW",
"compat": {
"supportsDeveloperRole": false,
"supportsReasoningEffort": false
},
"models": [
{
"id": "deepseek-v4-flash",
"name": "DeepSeek v4 Flash (local vLLM)",
"reasoning": true,
"input": ["text"],
"contextWindow": 393216,
"maxTokens": 65536,
"samplingParams": {
"temperature": 1,
"top_p": 0.95
},
"thinkingLevelMap": {
"minimal": null,
"low": "low",
"medium": null,
"high": "high",
"xhigh": null,
"max": "max"
},
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 },
"compat": {
"thinkingFormat": "chat-template",
"supportsUsageInStreaming": true,
"requiresReasoningContentOnAssistantMessages": true,
"chatTemplateKwargs": {
"thinking": {
"$var": "thinking.enabled"
},
"reasoning_effort": {
"$var": "thinking.effort"
}
},
"maxTokensField": "max_tokens"
}
}
]
}
}
}

View File

@@ -1,11 +0,0 @@
{
"lastChangelogVersion": "0.81.1",
"theme": "light",
"defaultProvider": "openrouter",
"defaultModel": "deepseek/deepseek-v4-pro",
"defaultThinkingLevel": "high",
"hideThinkingBlock": false,
"enableInstallTelemetry": false,
"doubleEscapeAction": "tree",
"treeFilterMode": "all"
}

View File

@@ -1,16 +0,0 @@
{
"lastChangelogVersion": "0.81.1",
"theme": "light",
"defaultProvider": "openrouter",
"defaultModel": "deepseek/deepseek-v4-flash",
"defaultThinkingLevel": "high",
"hideThinkingBlock": false,
"retry": {
"enabled": true,
"maxRetries": 4,
"baseDelayMs": 10000
},
"enableInstallTelemetry": false,
"doubleEscapeAction": "tree",
"treeFilterMode": "all"
}

View File

@@ -1,19 +0,0 @@
{
"lastChangelogVersion": "0.84.4",
"theme": "light",
"defaultProvider": "anthropic",
"defaultModel": "claude-opus-5-default",
"defaultThinkingLevel": "high",
"hideThinkingBlock": false,
"retry": {
"enabled": true,
"maxRetries": 4,
"baseDelayMs": 10000
},
"enableInstallTelemetry": false,
"doubleEscapeAction": "tree",
"treeFilterMode": "all",
"extensions": [
"~/.pi/agent/extensions-work"
]
}

61
nix/common.nix Normal file
View File

@@ -0,0 +1,61 @@
{ config, pkgs, ... }:
{
imports = [
./user/sh.nix
./user/tmux.nix
./user/git.nix
./user/dev.nix
./user/nvim.nix
];
home.packages = with pkgs; [
nil
# neovim
# (pkgs.nerdfonts.override { fonts = [ "FiraCode" ]; })
pkgs.nerd-fonts.fira-code
# (pkgs.writeShellScriptBin "my-hello" ''
# echo "Hello, ${config.home.username}!"
# '')
];
home.file = {
# ".screenrc".source = dotfiles/screenrc;
# ".gradle/gradle.properties".text = ''
# org.gradle.console=verbose
# org.gradle.daemon.idletimeout=3600000
# '';
};
# Home Manager can also manage your environment variables through
# 'home.sessionVariables'. If you don't want to manage your shell through Home
# Manager then you have to manually source 'hm-session-vars.sh' located at
# either
#
# ~/.nix-profile/etc/profile.d/hm-session-vars.sh
#
# or
#
# ~/.local/state/nix/profiles/profile/etc/profile.d/hm-session-vars.sh
#
# or
#
# /etc/profiles/per-user/moustachioed/etc/profile.d/hm-session-vars.sh
#
#home.sessionVariables = {
# EDITOR = "nvim";
#};
#home.shellAliases = {
# "ll" = "ls -la";
# "t" = "tmuxp";
# "tl" = "tmuxp load";
# };
news.display = "silent";
programs.home-manager.enable = true;
}

69
nix/flake.lock generated Normal file
View File

@@ -0,0 +1,69 @@
{
"nodes": {
"home-manager": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1750275572,
"narHash": "sha256-upC/GIlsIgtdtWRGd1obzdXWYQptNkfzZeyAFWgsgf0=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "0f355844e54e4c70906b1ef5cc35a0047d666c04",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "home-manager",
"type": "github"
}
},
"nix-darwin": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1749873626,
"narHash": "sha256-1Mc/D/1RwwmDKY59f4IpDBgcQttxffm+4o0m67lQ8hc=",
"owner": "LnL7",
"repo": "nix-darwin",
"rev": "2f140d6ac8840c6089163fb43ba95220c230f22b",
"type": "github"
},
"original": {
"owner": "LnL7",
"repo": "nix-darwin",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1750134718,
"narHash": "sha256-v263g4GbxXv87hMXMCpjkIxd/viIF7p3JpJrwgKdNiI=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "9e83b64f727c88a7711a2c463a7b16eedb69a84c",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"home-manager": "home-manager",
"nix-darwin": "nix-darwin",
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

83
nix/flake.nix Normal file
View File

@@ -0,0 +1,83 @@
{
description = "Home Manager configuration of moustachioed";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
nix-darwin.url = "github:LnL7/nix-darwin";
nix-darwin.inputs.nixpkgs.follows = "nixpkgs";
home-manager = {
url = "github:nix-community/home-manager";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = { self, nix-darwin, nixpkgs, home-manager, ... }:
let
system = "x86_64-darwin";
pkgs = nixpkgs.legacyPackages.${system};
configuration = { pkgs, ... }: {
environment.systemPackages =
[
pkgs.vim
];
# Auto upgrade nix package and the daemon service.
services.nix-daemon.enable = true;
# nix.package = pkgs.nix;
nix.settings.experimental-features = "nix-command flakes";
programs.zsh.enable = true; # default shell on catalina
# Set Git commit hash for darwin-version.
system.configurationRevision = self.rev or self.dirtyRev or null;
# Used for backwards compatibility, please read the changelog before changing.
# $ darwin-rebuild changelog
system.stateVersion = 4;
# The platform the configuration will be used on.
nixpkgs.hostPlatform = system;
};
in {
# Build darwin flake using:
# $ darwin-rebuild build --flake .#Martins-MacBook-Pro
darwinConfigurations."Martins-MacBook-Pro" = nix-darwin.lib.darwinSystem {
modules = [ configuration ];
};
# Expose the package set, including overlays, for convenience.
darwinPackages = self.darwinConfigurations."Martins-MacBook-Pro".pkgs;
homeConfigurations = {
"moustachioed" = home-manager.lib.homeManagerConfiguration {
inherit pkgs;
modules = [
./user/profiles/moustachioedBook.nix
./common.nix
./user/task_home.nix
];
};
"martin" = home-manager.lib.homeManagerConfiguration {
inherit pkgs;
modules = [
./user/profiles/martin.nix
./common.nix
./user/task_home.nix
];
};
"pan" = home-manager.lib.homeManagerConfiguration {
inherit pkgs;
modules = [
./user/profiles/work.nix
./common.nix
./user/task.nix
];
};
};
};
}

13
nix/user/dev.nix Normal file
View File

@@ -0,0 +1,13 @@
{ config, pkgs, ... }:
{
programs.direnv = {
enable = true;
enableZshIntegration = true;
nix-direnv.enable = true;
};
home.packages = with pkgs; [
visidata
];
}

View File

@@ -1,10 +1,10 @@
{ config, pkgs, lib, ... }: { config, pkgs, ... }:
{ {
programs.git = { programs.git = {
enable = true; enable = true;
settings = {
alias = { aliases = {
st = "status"; st = "status";
ci = "commit"; ci = "commit";
co = "checkout"; co = "checkout";
@@ -17,6 +17,9 @@
cleanup = "!git fetch --prune && git branch -vv | grep ': gone]' | awk '{print $1}' | xargs git branch -D"; cleanup = "!git fetch --prune && git branch -vv | grep ': gone]' | awk '{print $1}' | xargs git branch -D";
}; };
difftastic.enable = true;
extraConfig = {
column.ui = "auto"; column.ui = "auto";
branch.sort = "-committerdate"; branch.sort = "-committerdate";
tag.sort = "version:refname"; tag.sort = "version:refname";
@@ -56,16 +59,9 @@
ignores = [ ignores = [
".direnv/" ".direnv/"
".envrc" ".envrc"
".pi/"
]; ];
}; };
# Difftastic - modern diff tool
programs.difftastic = {
enable = true;
git.enable = true;
};
programs.lazygit = { programs.lazygit = {
enable = true; enable = true;
settings = { settings = {
@@ -79,28 +75,5 @@
}; };
}; };
programs.jujutsu = { programs.jujutsu.enable = true;
enable = true;
settings = {
aliases = {
tug = ["bookmark" "move" "--from" "heads(::@- & bookmarks())" "--to" "@-"];
lg = ["log"];
des = ["describe"];
sq = ["squash"];
gp = ["git" "push"];
nc = [
"util" "exec" "--" "bash" "-c"
''jj new --no-edit -B "''${2:-@}" -m "$1"''
""
];
};
ui = {
default-command = "log";
pager = "less -FRX";
diff-formatter = ":git";
merge-editor = "vimdiff";
};
};
};
} }

91
nix/user/nvim.nix Normal file
View File

@@ -0,0 +1,91 @@
{ config, pkgs, lib, ... }:
{
programs.neovim = {
enable = true;
defaultEditor = true;
vimAlias = true;
plugins = with pkgs.vimPlugins; [
vim-repeat
vim-surround
ts-comments-nvim
vim-fugitive
gitsigns-nvim
nvim-tree-lua
targets-vim
mini-pairs
mini-align
mini-bracketed
mini-splitjoin
mini-move
mini-ai
mini-icons
flash-nvim
trouble-nvim
conform-nvim
nvim-lint
promise-async
nvim-ufo
vim-windowswap
plenary-nvim
telescope-nvim
telescope-fzf-native-nvim
telescope-ui-select-nvim
yanky-nvim
lualine-nvim
undotree
luasnip
nvim-cmp
cmp_luasnip
cmp-buffer
cmp-path
cmp-cmdline
cmp-nvim-lsp
cmp-nvim-lsp-signature-help
cmp_yanky
cmp-git
nvim-lspconfig
lspkind-nvim
copilot-lua
copilot-cmp
CopilotChat-nvim
bullets-vim
nvim-dap
nvim-nio
nvim-dap-ui
nvim-dap-virtual-text
nvim-dap-go
nvim-dap-python
nvim-dap-lldb
todo-comments-nvim
vim-markdown
zen-mode-nvim
plantuml-syntax
obsidian-nvim
render-markdown-nvim
image-nvim
img-clip-nvim
vim-nix
(nvim-treesitter.withPlugins (p: [ p.awk p.bash p.c p.c_sharp p.cpp p.css p.diff p.dockerfile p.doxygen p.git_config p.gitcommit p.go p.gomod p.gosum p.gotmpl p.helm p.haskell p.html p.http p.java p.javascript p.json p.latex p.lua p.markdown p.markdown_inline p.matlab p.nix p.printf p.python p.regex p.rust p.sql p.strace p.supercollider p.svelte p.swift p.terraform p.tmux p.toml p.typescript p.vim p.xml p.yaml p.zig ]))
];
# extraConfig = ''
# set t_vb=
# '';
extraLuaConfig = builtins.concatStringsSep "\n" [
(lib.strings.fileContents ../../nvim/base.lua)
(lib.strings.fileContents ../../nvim/keymaps.lua)
(lib.strings.fileContents ../../nvim/plugins.lua)
(lib.strings.fileContents ../../nvim/filetype.lua)
];
};
home.packages = with pkgs; [
nodejs-slim
marksman
];
}

View File

@@ -0,0 +1,13 @@
{ config, pkgs, ... }:
{
home.username = "martin";
home.homeDirectory = "/Users/martin";
home.stateVersion = "24.05"; # Please read the comment before changing.
programs.git = {
userName = "Martin";
userEmail = "git@pander-on.de";
};
}

View File

@@ -0,0 +1,13 @@
{ config, pkgs, ... }:
{
home.username = "moustachioed";
home.homeDirectory = "/Users/moustachioed";
home.stateVersion = "23.11"; # Please read the comment before changing.
programs.git = {
userName = "Martin";
userEmail = "git@pander-on.de";
};
}

View File

@@ -0,0 +1,24 @@
{ config, pkgs, ... }:
{
home.username = "pan";
home.homeDirectory = "/home/pan";
home.stateVersion = "23.11"; # Please read the comment before changing.
programs.git = {
userName = "Martin Pander";
userEmail = "martin.pander@knowtion.de";
};
home.packages = with pkgs; [
yaml-language-server
marksman
dockerfile-language-server-nodejs
];
programs.zsh.profileExtra = ''
source $HOME/.profile
'';
}

117
nix/user/sh.nix Normal file
View File

@@ -0,0 +1,117 @@
{ config, pkgs, lib, ... }:
{
programs.zsh = {
enable = true;
enableCompletion = true;
autosuggestion.enable = true;
syntaxHighlighting.enable = true;
history.size = 500000;
#history.path = "${config.xdg.dataHome}/zsh/history";
prezto = {
enable = true;
caseSensitive = true;
color = true;
editor = {
dotExpansion = true;
keymap = "vi";
};
pmodules = [
"environment"
"terminal"
"editor"
"history"
"directory"
"spectrum"
"utility"
"completion"
"syntax-highlighting"
"history-substring-search"
"prompt"
"git"
];
prompt.theme = "minimal";
syntaxHighlighting.highlighters = [
"main"
"brackets"
"pattern"
"line"
"cursor"
"root"
];
tmux = {
autoStartLocal = true;
itermIntegration = true;
};
};
initContent = ''
HISTCONTROL='erasedups:ignoreboth'
HISTIGNORE='&:[ ]*:exit:ls:bg:fg:history:clear'
unsetopt beep
if [[ "$(uname -s)" == "Darwin" ]]; then
export RUSTUP_HOME="$HOME/.rustup"
export CARGO_HOME="$HOME/.cargo"
[ -f "$CARGO_HOME/env" ] && . "$CARGO_HOME/env"
fi;
if [[ "$(uname -r)" == *Microsoft* ]]; then
if command -v tmuxp &> /dev/null && [ -z "$TMUX" ]; then
tmuxp load --yes misc
fi
fi;
'';
};
programs.fzf = {
enable = true;
enableZshIntegration = true;
};
programs.lsd = {
enable = true;
enableZshIntegration = true;
};
programs.zoxide = {
enable = true;
enableZshIntegration = true;
options = [
"--cmd cd"
];
};
programs.bat.enable = true;
programs.ripgrep.enable = true;
programs.btop.enable = true;
programs.ranger.enable = true;
home.packages = with pkgs; [
fd
du-dust
glow
ripgrep-all
viddy
duf
(python3.withPackages(ps: [ ps.llm ps.llm-gemini ]))
#nerdfonts
];
home.sessionVariables = lib.mkMerge [ {
BAT_THEME = "Coldark-Cold";
}
];
home.shellAliases = lib.mkMerge [
{
lst = "lsd --tree";
}
# This is the correct way to use lib.mkIf within lib.mkMerge
# (lib.mkIf pkgs.stdenv.targetPlatform.isWindows {
(lib.mkIf (lib.strings.hasSuffix "windows" pkgs.system) {
open = "explorer.exe .";
})
];
}

View File

@@ -1,4 +1,4 @@
{config, pkgs, lib, inputs, ...}: {config, pkgs, lib, ...}:
{ {
programs.taskwarrior = { programs.taskwarrior = {
@@ -8,10 +8,8 @@
config = { config = {
weekstart = "monday"; weekstart = "monday";
uda.tasksquire.tags.default="code,comm,cust,del,doc,mngmnt,ops,rsrch,rvw,track"; context.today.read = "(prio:H or +next)";
context.today.write = "prio:H +next";
uda.parenttask.type="string";
uda.parenttask.label="Parent";
uda.energy.type="string"; uda.energy.type="string";
uda.energy.label="Energy"; uda.energy.label="Energy";
@@ -22,32 +20,25 @@
urgency.uda.priority.L.coefficient = -0.5; urgency.uda.priority.L.coefficient = -0.5;
urgency.user.tag.deferred.coefficient = -15.0; urgency.user.tag.deferred.coefficient = -15.0;
urgency.user.tag.cust.coefficient = 5.0; urgency.user.tag.cust.coefficient = 5.0;
urgency.user.tag.fixed.coefficient = -100.0;
report.next.columns="id,start.age,entry.age,depends,priority,energy,urgency,project,tags,recur,scheduled.countdown,due.relative,until.remaining,description"; report.next.columns="id,start.age,entry.age,depends,priority,energy,project,tags,recur,scheduled.countdown,due.relative,until.remaining,description,urgency";
report.next.labels="ID,Active,Age,Deps,P,E,Urg,Project,Tag,Recur,S,Due,Until,Description"; report.next.labels="ID,Active,Age,Deps,P,E,Project,Tag,Recur,S,Due,Until,Description,Urg";
report.next.filter="status:pending -WAITING -deferred -track"; report.next.filter="status:pending -WAITING -deferred";
report.time.columns="id,start.age,entry.age,depends,priority,energy,urgency,project,tags,recur,scheduled.countdown,due.relative,until.remaining,description"; report.deferred.columns="id,start.age,entry.age,depends,priority,energy,project,tags,recur,scheduled.countdown,due.relative,until.remaining,description,urgency";
report.time.labels="ID,Active,Age,Deps,P,E,Urg,Project,Tag,Recur,S,Due,Until,Description";
report.time.filter="status:pending -WAITING -deferred +fixed";
report.deferred.columns="id,start.age,entry.age,depends,priority,energy,urgency,project,tags,recur,scheduled.countdown,due.relative,until.remaining,description";
report.deferred.context="1"; report.deferred.context="1";
report.deferred.description="Deferred and waiting tasks"; report.deferred.description="Deferred and waiting tasks";
report.deferred.labels="ID,Active,Age,Deps,P,E,Urg,Project,Tag,Recur,S,Due,Until,Description"; report.deferred.labels="ID,Active,Age,Deps,P,E,Project,Tag,Recur,S,Due,Until,Description,Urg";
report.deferred.filter="status:pending +deferred"; report.deferred.filter="status:pending +deferred";
report.deferred.sort="urgency-"; report.deferred.sort="urgency-";
report.low.columns="id,start.age,entry.age,depends,priority,energy,urgency,project,tags,recur,scheduled.countdown,due.relative,until.remaining,description"; report.low.columns="id,start.age,entry.age,depends,priority,energy,project,tags,recur,scheduled.countdown,due.relative,until.remaining,description,urgency";
report.low.context="1"; report.low.context="1";
report.low.description="Low energy tasks"; report.low.description="Low energy tasks";
report.low.filter="status:pending -WAITING -deferred"; report.low.filter="status:pending -WAITING -deferred";
report.low.labels="ID,Active,Age,Deps,P,E,Urg,Project,Tag,Recur,S,Due,Until,Description"; report.low.labels="ID,Active,Age,Deps,P,E,Project,Tag,Recur,S,Due,Until,Description,Urg";
report.low.sort="energy+,urgency-"; report.low.sort="energy+,urgency-";
context.today.read = "(prio:H or +next)";
context.today.write = "prio:H +next";
context.deferred.read = "+deferred"; context.deferred.read = "+deferred";
context.deferred.write = "+deferred"; context.deferred.write = "+deferred";
context.customer.read = "+cust"; context.customer.read = "+cust";
@@ -62,8 +53,7 @@
home.packages = with pkgs; [ home.packages = with pkgs; [
taskwarrior-tui taskwarrior-tui
unstable.timewarrior timewarrior
inputs.tasksquire.packages.${pkgs.stdenv.hostPlatform.system}.default
]; ];
home.shellAliases = lib.mkMerge [ { home.shellAliases = lib.mkMerge [ {

37
nix/user/task_home.nix Normal file
View File

@@ -0,0 +1,37 @@
{config, pkgs, lib, ...}:
{
programs.taskwarrior = {
enable = true;
colorTheme = "light-256";
package = pkgs.taskwarrior3;
config = {
weekstart = "monday";
uda.priority.values = "H,M,,L";
urgency.uda.priority.L.coefficient = -0.5;
urgency.user.tag.deferred.coefficient = -15.0;
urgency.user.tag.cust.coefficient = 5.0;
context.today.read = "-deferred and (prio:H or +next)";
context.today.write = "prio:H or +next";
context.deferred.read = "+deferred";
context.deferred.write = "+deferred";
context.low_energy.read = "+low";
context.low_energy.write = "+low";
uda.taskwarrior-tui.task-report.show-info = false;
uda.taskwarrior-tui.selection.reverse = "yes";
};
};
home.packages = with pkgs; [
taskwarrior-tui
];
home.shellAliases = lib.mkMerge [ {
t = "task";
tt = "taskwarrior-tui";
}
];
}

72
nix/user/tmux.nix Normal file
View File

@@ -0,0 +1,72 @@
{ config, pkgs, lib, ... }:
{
programs.tmux = {
enable = true;
shortcut = "a";
mouse = true;
keyMode = "vi";
escapeTime = 0;
terminal = "screen-256color";
tmuxp.enable = true;
extraConfig = ''
set -g display-time 1500
unbind S
bind S command-prompt "switch -t %1"
bind-key -n M-K switch-client -p
bind-key -n M-J switch-client -n
bind-key -n M-L next-window
bind-key -n M-H previous-window
bind '"' split-window -c "#{pane_current_path}"
bind % split-window -h -c "#{pane_current_path}"
bind c new-window -a -c "#{pane_current_path}"
bind C-s display-popup -E "zsh ~/bin/tmuxp_selector.sh"
bind C-g display-popup -E -d "#{pane_current_path}" -xC -yC -w 95% -h 95% "lazygit"
bind C-t display-popup -E -xC -yC -w 95% -h 95% "tasksquire"
bind C-n display-popup -E -xC -yC -w 95% -h 95% "vim /mnt/c/Users/marti/Documents/notes/Work/quick_notes.md"
bind C-m display-popup -E -xC -yC -w 95% -h 95% "vim /mnt/c/Users/marti/Documents/notes/Work/mbpr.md"
#######################################
# status line
#######################################
set -g status-justify centre
set -g status-left "#[bg=#808080,fg=#ffffff,bold] #S #[default]#[bg=#BCBCBC] #{-30:pane_title} "
set -g status-left-length 40
set -g status-right "#[bg=#BCBCBC] %H:%M #[bg=#808080,fg=#ffffff] %d.%m.%y "
# setw -g window-status-format " #W#F "
# setw -g window-status-current-format " #W#F "
setw -g window-status-format " #W "
setw -g window-status-current-format " #W "
setw -g window-status-separator ""
#######################################
# colors, taken from vim-lucius
#######################################
set -g status-style "bg=#DADADA,fg=#000000"
setw -g window-status-style "bg=#BCBCBC,fg=#000000"
setw -g window-status-current-style "bg=#808080,fg=#ffffff"
setw -g window-status-activity-style "bg=#AFD7AF,fg=#000000"
setw -g window-status-bell-style "bg=#AFD7AF,fg=#000000"
#setw -g window-status-content-style "bg=#AFD7AF,fg=#000000"
set -g pane-active-border-style "bg=#eeeeee,fg=#006699"
set -g pane-border-style "bg=#eeeeee,fg=#999999"
'';
};
home.shellAliases = lib.mkMerge [ {
"o" = "tmuxp";
"ol" = "tmuxp load";
}
];
}

View File

@@ -26,6 +26,8 @@ vim.opt.smartcase = true
vim.opt.hidden = true vim.opt.hidden = true
vim.opt.splitright = true vim.opt.splitright = true
vim.opt.splitbelow = true vim.opt.splitbelow = true
vim.opt.swapfile = true
vim.opt.directory= '~/.cache/nvim/swap//,$TEMP//,/tmp//'
vim.opt.wildmode = 'longest,list' vim.opt.wildmode = 'longest,list'
vim.opt.wildignore = vim.opt.wildignore + 'main,*.o,*.d,*.aux,*.bbl,*.lof,*.loa,*.blg,*.fdb_latexmk,*.fls,*.tdo,*.pdf,*.pyc' vim.opt.wildignore = vim.opt.wildignore + 'main,*.o,*.d,*.aux,*.bbl,*.lof,*.loa,*.blg,*.fdb_latexmk,*.fls,*.tdo,*.pdf,*.pyc'
vim.opt.spell = false vim.opt.spell = false
@@ -34,6 +36,7 @@ vim.opt.foldopen = vim.opt.foldopen - 'block'
vim.opt.foldlevel = 99 vim.opt.foldlevel = 99
vim.opt.lazyredraw = true vim.opt.lazyredraw = true
vim.opt.listchars = 'eol:¬,tab:▸ ,trail:·' vim.opt.listchars = 'eol:¬,tab:▸ ,trail:·'
vim.opt.fillchars = 'vert:|,fold: '
vim.opt.list = true vim.opt.list = true
vim.opt.laststatus = 3 vim.opt.laststatus = 3
vim.opt.scrolloff = 8 vim.opt.scrolloff = 8
@@ -49,59 +52,15 @@ vim.opt.encoding = 'utf-8'
vim.opt.completeopt = 'menu,menuone,noselect' vim.opt.completeopt = 'menu,menuone,noselect'
vim.opt.termguicolors = true vim.opt.termguicolors = true
vim.opt.conceallevel = 1 vim.opt.conceallevel = 1
vim.opt.updatetime = 300
----------------------------
----------- SWAP -----------
----------------------------
local swapdir = vim.fn.expand("~/.cache/nvim/swap//")
if vim.fn.isdirectory(swapdir) == 0 then
vim.fn.mkdir(swapdir, "p")
end
local temp = (os.getenv("TEMP") or "/tmp") .. "//"
vim.opt.swapfile = true
vim.opt.directory = swapdir .. "," .. temp
---------------------------- ----------------------------
-------- CLIPBOARD --------- -------- CLIPBOARD ---------
---------------------------- ----------------------------
-- Force Neovim to use the OSC 52 provider explicitly
vim.g.clipboard = {
name = 'OSC 52',
copy = {
['+'] = require('vim.ui.clipboard.osc52').copy('+'),
['*'] = require('vim.ui.clipboard.osc52').copy('*'),
},
paste = {
['+'] = require('vim.ui.clipboard.osc52').paste('+'),
['*'] = require('vim.ui.clipboard.osc52').paste('*'),
},
}
if vim.fn.has("wsl") == 1 then if vim.fn.has("wsl") == 1 then
local function win32yank_works() vim.opt.clipboard = vim.opt.clipboard + 'unnamedplus'
return os.execute("win32yank.exe -o >/dev/null 2>&1") == 0
end end
if win32yank_works() then
vim.g.clipboard = {
name = 'WslClipboard',
copy = {
["+"] = 'win32yank.exe -i --crlf',
["*"] = 'win32yank.exe -i --crlf',
},
paste = {
["+"] = 'win32yank.exe -o --lf',
["*"] = 'win32yank.exe -o --lf',
},
cache_enabled = 0,
}
end
end
vim.opt.clipboard = 'unnamedplus'
---------------------------- ----------------------------
-------- COMMANDS ---------- -------- COMMANDS ----------
@@ -109,6 +68,9 @@ vim.opt.clipboard = 'unnamedplus'
vim.cmd('filetype plugin indent on') vim.cmd('filetype plugin indent on')
-- vim.cmd('colorscheme lucius')
-- vim.cmd('LuciusWhite')
---------------------------- ----------------------------
-------- AUTOGROUPS -------- -------- AUTOGROUPS --------
@@ -171,7 +133,7 @@ vim.api.nvim_create_user_command('TrimWhiteSpace', function()
vim.cmd('%s/\\s\\+$//e') vim.cmd('%s/\\s\\+$//e')
end, {}) end, {})
function ToggleDiagnostics() local function ToggleDiagnostics()
vim.diagnostic.enable(not vim.diagnostic.is_enabled()) vim.diagnostic.enable(not vim.diagnostic.is_enabled())
if vim.diagnostic.is_enabled() then if vim.diagnostic.is_enabled() then
print("Diagnostics enabled") print("Diagnostics enabled")
@@ -192,18 +154,24 @@ vim.diagnostic.config({
prefix = '', prefix = '',
current_line = false, current_line = false,
severity = { severity = {
min = vim.diagnostic.severity.HINT, -- min = vim.diagnostic.severity.INFO,
max = vim.diagnostic.severity.INFO,
},
},
virtual_lines = {
current_line = false,
severity = {
min = vim.diagnostic.severity.WARN,
-- max = vim.diagnostic.severity.WARN,
}, },
}, },
virtual_lines = false,
-- float = false,
float = { float = {
prefix = '', prefix = '',
scope = 'line', focusable = false,
style = 'minimal', style = "minimal",
border = 'rounded', border = "rounded",
source = 'always', source = "always",
header = '', header = "",
}, },
}) })
@@ -212,11 +180,3 @@ vim.cmd([[highlight DiagnosticUnderlineWarn gui=undercurl guifg=Yellow]])
vim.cmd([[highlight DiagnosticUnderlineInfo gui=undercurl guifg=Blue]]) vim.cmd([[highlight DiagnosticUnderlineInfo gui=undercurl guifg=Blue]])
vim.cmd([[highlight DiagnosticUnderlineHint gui=undercurl guifg=Cyan]]) vim.cmd([[highlight DiagnosticUnderlineHint gui=undercurl guifg=Cyan]])
local orig_util_open_floating_preview = vim.lsp.util.open_floating_preview
function vim.lsp.util.open_floating_preview(contents, syntax, opts, ...)
opts = opts or {}
opts.border = opts.border or "rounded"
return orig_util_open_floating_preview(contents, syntax, opts, ...)
end

153
nvim/filetype.lua Normal file
View File

@@ -0,0 +1,153 @@
local capabilities = require('cmp_nvim_lsp').default_capabilities()
local lspconfig = require("lspconfig")
vim.api.nvim_create_augroup('FileTypeConfigs', { clear = true })
vim.api.nvim_create_autocmd('FileType', {
group = 'FileTypeConfigs',
pattern = 'python',
callback = function()
require('dap-python').setup()
-- lspconfig.pyright.setup({ capabilities = capabilities })
-- require("conform").setup({
-- python = {"black"},
-- })
end,
})
-- vim.api.nvim_create_autocmd('FileType', {
-- group = 'FileTypeConfigs',
-- pattern = 'go',
-- callback = function()
-- require('dap-python').setup()
-- require('dap-go').setup()
lspconfig.ruff.setup({ capabilities = capabilities })
lspconfig.gopls.setup({ capabilities = capabilities })
lspconfig.marksman.setup({ capabilities = capabilities })
lspconfig.rust_analyzer.setup({
capabilities = capabilities,
settings = {
["rust-analyzer"] = {
checkOnSave = {
command = "clippy",
},
},
},
})
lspconfig.dockerls.setup({ capabilities = capabilities })
lspconfig.docker_compose_language_service.setup({ capabilities = capabilities })
lspconfig.clangd.setup({ capabilities = capabilities })
lspconfig.sqls.setup({ capabilities = capabilities })
lspconfig.zls.setup({ capabilities = capabilities })
lspconfig.omnisharp.setup({ capabilities = capabilities })
lspconfig.yamlls.setup({ capabilities = capabilities })
require("conform").setup({
go = {"gofmt"},
python = {"black"},
rust = {"rustfmt"},
})
-- end,
-- })
-- vim.api.nvim_create_autocmd('FileType', {
-- group = 'FileTypeConfigs',
-- pattern = 'rust',
-- callback = function()
-- require('dap-python').setup()
--
-- lspconfig.rust_analyzer.setup({
-- capabilities = capabilities,
-- settings = {
-- ["rust-analyzer"] = {
-- checkOnSave = {
-- command = "clippy",
-- },
-- },
-- },
-- })
--
-- require("conform").setup({
-- rust = {"rustfmt"},
-- })
-- end,
-- })
-- vim.api.nvim_create_autocmd('FileType', {
-- group = 'FileTypeConfigs',
-- pattern = 'markdown',
-- callback = function()
-- lspconfig.marksman.setup({ capabilities = capabilities })
-- end,
-- })
--
-- vim.api.nvim_create_autocmd('FileType', {
-- group = 'FileTypeConfigs',
-- pattern = 'dockerfile',
-- callback = function()
-- lspconfig.dockerls.setup({ capabilities = capabilities })
-- lspconfig.docker_compose_language_service.setup({ capabilities = capabilities })
-- end,
-- })
--
-- vim.api.nvim_create_autocmd('FileType', {
-- group = 'FileTypeConfigs',
-- pattern = 'cs',
-- callback = function()
-- lspconfig.omnisharp.setup({ capabilities = capabilities })
-- end,
-- })
--
-- vim.api.nvim_create_autocmd('FileType', {
-- group = 'FileTypeConfigs',
-- pattern = 'yaml',
-- callback = function()
-- lspconfig.yamlls.setup({ capabilities = capabilities })
-- lspconfig.docker_compose_language_service.setup({ capabilities = capabilities })
-- end,
-- })
-- vim.api.nvim_create_autocmd('FileType', {
-- group = 'FileTypeConfigs',
-- pattern = {'c', 'cpp', 'objc', 'objcpp'},
-- callback = function()
-- lspconfig.clangd.setup({ capabilities = capabilities })
-- end,
-- })
--
-- vim.api.nvim_create_autocmd('FileType', {
-- group = 'FileTypeConfigs',
-- pattern = 'sql',
-- callback = function()
-- lspconfig.sqls.setup({ capabilities = capabilities })
-- end,
-- })
--
-- vim.api.nvim_create_autocmd('FileType', {
-- group = 'FileTypeConfigs',
-- pattern = 'zig',
-- callback = function()
-- lspconfig.zls.setup({ capabilities = capabilities })
-- end,
-- })
--
local get_datetime = function()
return os.date("%Y-%m-%d %H:%M")
end
local ls = require('luasnip')
ls.add_snippets("markdown", {
ls.snippet("mindful", {
-- Inserts the output of the get_datetime function as static text
ls.function_node(get_datetime, {}),
ls.text_node(" -- "),
ls.insert_node(1, "project"),
ls.text_node(" -- "),
ls.insert_node(2, "mode"),
ls.text_node(" -- "),
ls.insert_node(3, "description"),
}, {
descr = "Mindful of distractions",
}),
})

View File

@@ -1,14 +1,17 @@
vim.g.mapleader = " " vim.g.mapleader = " "
-- Convenience
vim.keymap.set('n', '<leader>w', ':w<CR>', { silent = true })
vim.keymap.set('n', '<leader>F', ':NvimTreeToggle<CR>', { noremap = true, silent = true })
vim.keymap.set('n', 'Y', 'y$', {})
-- Navigation -- Navigation
vim.keymap.set({'n', 'v'}, 'j', 'gj', {}) vim.keymap.set({'n', 'v'}, 'j', 'gj', {})
vim.keymap.set({'n', 'v'}, 'k', 'gk', {}) vim.keymap.set({'n', 'v'}, 'k', 'gk', {})
vim.keymap.set('n', '<C-M-h>', '<C-w>h', {})
vim.keymap.set('n', '<C-M-j>', '<C-w>j', {})
vim.keymap.set('n', '<C-M-k>', '<C-w>k', {})
vim.keymap.set('n', '<C-M-l>', '<C-w>l', {})
vim.keymap.set('t', '<C-M-h>', '<C-\\><C-n><C-w>h', {})
vim.keymap.set('t', '<C-M-j>', '<C-\\><C-n><C-w>j', {})
vim.keymap.set('t', '<C-M-k>', '<C-\\><C-n><C-w>k', {})
vim.keymap.set('t', '<C-M-l>', '<C-\\><C-n><C-w>l', {})
vim.keymap.set('n', '<leader>zm', '<C-W>_<C-W>|', { noremap = true, silent = true }) vim.keymap.set('n', '<leader>zm', '<C-W>_<C-W>|', { noremap = true, silent = true })
vim.keymap.set('n', '<C-M-Y>', '<C-w>5<', {}) vim.keymap.set('n', '<C-M-Y>', '<C-w>5<', {})
vim.keymap.set('n', '<C-M-U>', '<C-w>5+', {}) vim.keymap.set('n', '<C-M-U>', '<C-w>5+', {})
@@ -21,44 +24,10 @@ vim.keymap.set('t', '<C-M-O>', '<C-\\><C-n><C-w>5>', {})
vim.keymap.set('n', '<leader>s', ':call WindowSwap#EasyWindowSwap()<CR>', {}) vim.keymap.set('n', '<leader>s', ':call WindowSwap#EasyWindowSwap()<CR>', {})
-- tmux navigation -- Convenience
vim.g.tmux_navigator_no_mappings = 1 vim.keymap.set('n', '<leader>w', ':w<CR>', { silent = true })
vim.keymap.set('n', '<leader>F', ':NvimTreeToggle<CR>', { noremap = true, silent = true })
local function tmux_navigate(direction) vim.keymap.set('n', 'Y', 'y$', {})
local old_win = vim.api.nvim_get_current_win()
vim.cmd('wincmd ' .. direction)
local new_win = vim.api.nvim_get_current_win()
if old_win == new_win then
local tmux_cmd = ""
if direction == 'h' then
tmux_cmd = 'if -F "#{pane_at_left}" "previous-window" "select-pane -L"'
elseif direction == 'j' then
tmux_cmd = 'if -F "#{pane_at_bottom}" "switch-client -n" "select-pane -D"'
elseif direction == 'k' then
tmux_cmd = 'if -F "#{pane_at_top}" "switch-client -p" "select-pane -U"'
elseif direction == 'l' then
tmux_cmd = 'if -F "#{pane_at_right}" "next-window" "select-pane -R"'
end
vim.fn.system('tmux ' .. tmux_cmd)
end
end
-- vim.api.nvim_create_autocmd("CursorHold", {
-- callback = function()
-- vim.diagnostic.open_float(nil, { focusable = false })
-- end,
-- })
vim.keymap.set('n', '<C-M-h>', function() tmux_navigate('h') end)
vim.keymap.set('n', '<C-M-j>', function() tmux_navigate('j') end)
vim.keymap.set('n', '<C-M-k>', function() tmux_navigate('k') end)
vim.keymap.set('n', '<C-M-l>', function() tmux_navigate('l') end)
vim.keymap.set('t', '<C-M-h>', function() vim.cmd('stopinsert') tmux_navigate('h') end, { remap = true })
vim.keymap.set('t', '<C-M-j>', function() vim.cmd('stopinsert') tmux_navigate('j') end, { remap = true })
vim.keymap.set('t', '<C-M-k>', function() vim.cmd('stopinsert') tmux_navigate('k') end, { remap = true })
vim.keymap.set('t', '<C-M-l>', function() vim.cmd('stopinsert') tmux_navigate('l') end, { remap = true })
-- Telescope -- Telescope
local telebuiltin = require('telescope.builtin') local telebuiltin = require('telescope.builtin')
@@ -77,7 +46,6 @@ vim.keymap.set('n', '<leader>cr', vim.lsp.buf.rename, { desc = 'LSP Rename' })
vim.keymap.set('n', '<leader>ct', vim.lsp.buf.type_definition, { desc = 'LSP Type Definition' }) vim.keymap.set('n', '<leader>ct', vim.lsp.buf.type_definition, { desc = 'LSP Type Definition' })
vim.keymap.set('n', '<leader>cF', require("conform").format, { desc = 'LSP Format' }) vim.keymap.set('n', '<leader>cF', require("conform").format, { desc = 'LSP Format' })
vim.keymap.set('n', '<leader>cgi', vim.lsp.buf.implementation, { desc = 'LSP Implementation' }) vim.keymap.set('n', '<leader>cgi', vim.lsp.buf.implementation, { desc = 'LSP Implementation' })
vim.keymap.set('n', '<leader>cgr', telebuiltin.lsp_references, { desc = 'LSP References' })
vim.keymap.set('n', '<leader>cgd', vim.lsp.buf.definition, { desc = 'LSP Definition' }) vim.keymap.set('n', '<leader>cgd', vim.lsp.buf.definition, { desc = 'LSP Definition' })
vim.keymap.set('n', '<leader>cgD', vim.lsp.buf.declaration, { desc = 'LSP Declaration' }) vim.keymap.set('n', '<leader>cgD', vim.lsp.buf.declaration, { desc = 'LSP Declaration' })
vim.keymap.set('n', '<leader>cwa', vim.lsp.buf.add_workspace_folder, { desc = 'LSP Add Workspace Folder' }) vim.keymap.set('n', '<leader>cwa', vim.lsp.buf.add_workspace_folder, { desc = 'LSP Add Workspace Folder' })
@@ -88,7 +56,6 @@ vim.keymap.set('n', '<leader>ch', vim.lsp.buf.hover, { desc = 'LSP Hover' })
vim.keymap.set('n', '<leader>cH', vim.lsp.buf.signature_help, { desc = 'LSP Signature Help' }) vim.keymap.set('n', '<leader>cH', vim.lsp.buf.signature_help, { desc = 'LSP Signature Help' })
vim.keymap.set({ 'n', 'v' }, '<leader>ca', vim.lsp.buf.code_action, { desc = 'LSP Code Action' }) vim.keymap.set({ 'n', 'v' }, '<leader>ca', vim.lsp.buf.code_action, { desc = 'LSP Code Action' })
vim.keymap.set('n', '<leader>cde', ToggleDiagnostics, { desc = 'Toggle Diagnostics' }) vim.keymap.set('n', '<leader>cde', ToggleDiagnostics, { desc = 'Toggle Diagnostics' })
vim.keymap.set('n', '<leader>cdh', vim.diagnostic.open_float, { desc = 'Toggle Diagnostics float' })
vim.keymap.set('n', '<leader>cf', vim.keymap.set('n', '<leader>cf',
function() function()
local word = vim.fn.expand("<cword>") local word = vim.fn.expand("<cword>")
@@ -103,10 +70,28 @@ vim.keymap.set('v', '<leader>cf',
end end
) )
vim.keymap.set("n", "<leader>ai", ":PiAsk<CR>", { desc = "Ask pi" }) -- Copilot
vim.keymap.set("v", "<leader>ai", ":PiAskSelection<CR>", { desc = "Ask pi (selection)" }) local cop = require('copilot.panel')
vim.keymap.set("n", "<leader>ac", ":PiCancel<CR>", { desc = "Cancel pi request" }) local cos = require('copilot.suggestion')
vim.keymap.set("n", "<leader>al", ":PiLog<CR>", { desc = "Show session log" })
vim.keymap.set('n', '<leader>ap', cop.toggle)
vim.keymap.set('n', '<leader>apn', cop.jump_next)
vim.keymap.set('n', '<leader>app', cop.jump_prev)
vim.keymap.set('n', '<leader>apr', cop.refresh)
-- vim.keymap.set('n', '<leader>as', cos.accept)
-- vim.keymap.set('n', '<leader>ast', cos.toggle_auto_trigger)
-- vim.keymap.set('n', '<leader>asl', cos.accept_word)
-- vim.keymap.set('n', '<leader>asw', cos.accept_line)
-- vim.keymap.set('n', '<leader>asn', cos.next)
-- vim.keymap.set('n', '<leader>asp', cos.prev)
-- vim.keymap.set('n', '<leader>asd', cos.dismiss)
vim.keymap.set('n', '<leader>ac', '<cmd>CopilotChatToggle<cr>')
vim.keymap.set('n', '<leader>acs', '<cmd>CopilotChatStop<cr>')
vim.keymap.set('n', '<leader>acr', '<cmd>CopilotChatReset<cr>')
vim.keymap.set('n', '<leader>acm', '<cmd>CopilotChatModels<cr>')
vim.keymap.set('n', '<leader>acp', '<cmd>CopilotChatPrompts<cr>')
-- Yanky -- Yanky
vim.keymap.set({"n","x"}, "p", "<Plug>(YankyPutAfter)") vim.keymap.set({"n","x"}, "p", "<Plug>(YankyPutAfter)")
@@ -138,13 +123,9 @@ vim.keymap.set('n', "<leader>dr", function() require("dap").repl.toggle() end)
vim.keymap.set('n', "<leader>ds", function() require("dap").session() end) vim.keymap.set('n', "<leader>ds", function() require("dap").session() end)
vim.keymap.set('n', "<leader>dt", function() require("dap").terminate() end) vim.keymap.set('n', "<leader>dt", function() require("dap").terminate() end)
vim.keymap.set('n', "<leader>dw", function() require("dap.ui.widgets").hover() end) vim.keymap.set('n', "<leader>dw", function() require("dap.ui.widgets").hover() end)
vim.keymap.set('n', "<leader>dv", function() require("dap-view").toggle() end)
vim.keymap.set('n', "<F5>", function() require("dap").continue() end, { desc = "Debug: Continue/Start" }) vim.keymap.set('n', "<F5>", function() require("dap").continue() end)
vim.keymap.set('n', "<S-F5>", function() require("dap").terminate() end, { desc = "Debug: Stop" }) vim.keymap.set('n', "<F11>", function() require("dap").step_into() end)
vim.keymap.set('n', "<F6>", function() require("dap").pause() end, { desc = "Debug: Pause" }) vim.keymap.set('n', "<F10>", function() require("dap").step_over() end)
vim.keymap.set('n', "<F9>", function() require("dap").toggle_breakpoint() end, { desc = "Debug: Toggle Breakpoint" }) vim.keymap.set('n', "<F12>", function() require("dap").step_out() end)
vim.keymap.set('n', "<F10>", function() require("dap").step_over() end, { desc = "Debug: Step Over" })
vim.keymap.set('n', "<F11>", function() require("dap").step_into() end, { desc = "Debug: Step Into" })
vim.keymap.set('n', "<S-F11>", function() require("dap").step_out() end, { desc = "Debug: Step Out" })

View File

@@ -6,49 +6,20 @@ require('mini.align').setup()
require('mini.bracketed').setup() require('mini.bracketed').setup()
require('mini.splitjoin').setup() require('mini.splitjoin').setup()
require('mini.move').setup() require('mini.move').setup()
require('mini.move').setup()
require('flash').setup() require('flash').setup()
require('ts-comments').setup() require('ts-comments').setup()
local function is_wsl_env()
return os.getenv("WSL_DISTRO_NAME") ~= nil or os.getenv("WSL_INTEROP") ~= nil
end
vim.g.tagbar_left=1 vim.g.tagbar_left=1
vim.g.tagbar_autoclose=1 vim.g.tagbar_autoclose=1
vim.g.tagbar_autofocus=1 vim.g.tagbar_autofocus=1
vim.g.windowswap_map_keys=0 vim.g.windowswap_map_keys=0
local c = require('vscode.colors').get_colors()
require('vscode').setup({
style = 'light',
-- Enable transparent background
transparent = true,
-- Enable italic comment
-- italic_comments = true,
-- Enable italic inlay type hints
-- italic_inlayhints = true,
-- Underline `@markup.link.*` variants
underline_links = true,
-- Disable nvim-tree background color
disable_nvimtree_bg = true,
-- Apply theme colors to terminal
terminal_colors = true,
-- Override colors (see ./lua/vscode/colors.lua)
color_overrides = {
vscLineNumber = '#AAAAAA',
},
-- Override highlight groups (see ./lua/vscode/theme.lua)
-- group_overrides = {
-- -- this supports the same val table as vim.api.nvim_set_hl
-- -- use colors from this colorscheme by requiring vscode.colors!
-- Cursor = { fg=c.vscDarkBlue, bg=c.vscLightGreen, bold=true },
-- }
group_overrides = {
NormalFloat = { fg = c.vscFront, bg = "NONE" },
FloatBorder = { fg = c.vscFront, bg = "NONE" },
HoverTarget = { bg = "NONE" },
}
})
vim.cmd.colorscheme "vscode"
local cmp = require('cmp') local cmp = require('cmp')
local lspkind = require('lspkind') local lspkind = require('lspkind')
local ls = require('luasnip') local ls = require('luasnip')
@@ -113,6 +84,7 @@ cmp.setup({
sources = cmp.config.sources({ sources = cmp.config.sources({
{ name = 'nvim_lsp', priority = 1000 }, { name = 'nvim_lsp', priority = 1000 },
{ name = 'buffer', priority = 800, keyword_length = 2 }, { name = 'buffer', priority = 800, keyword_length = 2 },
{ name = 'copilot', priority = 700 },
{ name = 'path', priority = 600 }, { name = 'path', priority = 600 },
{ name = 'cmp_yanky', priority = 500 }, { name = 'cmp_yanky', priority = 500 },
{ name = 'git', priority = 400 }, { name = 'git', priority = 400 },
@@ -122,6 +94,7 @@ cmp.setup({
formatting = { formatting = {
format = lspkind.cmp_format({ format = lspkind.cmp_format({
-- mode = "symbol_text",
mode = "symbol", mode = "symbol",
menu = ({ menu = ({
buffer = "[buf]", buffer = "[buf]",
@@ -131,11 +104,22 @@ cmp.setup({
latex_symbols = "[tex]", latex_symbols = "[tex]",
path = "[path]", path = "[path]",
cmp_yanky = "[yank]", cmp_yanky = "[yank]",
copilot = "[copilot]",
}), }),
symbol_map = { Copilot = "" }
}), }),
}, },
}) })
-- -- Set configuration for specific filetype.
-- cmp.setup.filetype('gitcommit', {
-- sources = cmp.config.sources({
-- { name = 'git' }, -- You can specify the `git` source if [you were installed it](https://github.com/petertriho/cmp-git).
-- }, {
-- { name = 'buffer' },
-- })
-- })
cmp.setup.cmdline({ '/', '?' }, { cmp.setup.cmdline({ '/', '?' }, {
mapping = cmp.mapping.preset.cmdline(), mapping = cmp.mapping.preset.cmdline(),
sources = { sources = {
@@ -154,6 +138,10 @@ cmp.setup.cmdline(':', {
}) })
local capabilities = require('cmp_nvim_lsp').default_capabilities() local capabilities = require('cmp_nvim_lsp').default_capabilities()
local lspconfig = require("lspconfig")
-- lspconfig.svelte.setup({ capabilities = capabilities })
-- lspconfig.flow.setup({ capabilities = capabilities })
-- lspconfig.nil_ls.setup({ capabilities = capabilities })
capabilities.textDocument.foldingRange = { capabilities.textDocument.foldingRange = {
dynamicRegistration = false, dynamicRegistration = false,
@@ -162,14 +150,11 @@ capabilities.textDocument.foldingRange = {
local language_servers = vim.lsp.get_clients() -- or list servers manually like {'gopls', 'clangd'} local language_servers = vim.lsp.get_clients() -- or list servers manually like {'gopls', 'clangd'}
for _, ls in ipairs(language_servers) do for _, ls in ipairs(language_servers) do
if ls ~= nil then require('lspconfig')[ls].setup({
vim.lsp.config(ls).setup({
capabilities = capabilities capabilities = capabilities
-- you can add other fields for setting up lsp server in this table -- you can add other fields for setting up lsp server in this table
}) })
end end
end
require('ufo').setup() require('ufo').setup()
require("yanky").setup({ require("yanky").setup({
@@ -198,6 +183,27 @@ require("telescope").setup {
require("telescope").load_extension("ui-select") require("telescope").load_extension("ui-select")
require("telescope").load_extension("yank_history") require("telescope").load_extension("yank_history")
require'nvim-treesitter.configs'.setup {
-- ensure_installed = { "lua", "vim", "help" },
ensure_installed = {},
sync_install = false,
auto_install = false,
highlight = {
enable = true,
disable = function(lang, buf)
local max_filesize = 100 * 1024 -- 100 KB
local ok, stats = pcall(vim.loop.fs_stat, vim.api.nvim_buf_get_name(buf))
if ok and stats and stats.size > max_filesize then
return true
end
end,
additional_vim_regex_highlighting = false,
},
}
require('lualine').setup({ require('lualine').setup({
options = { options = {
@@ -240,6 +246,16 @@ require('lualine').setup({
extensions = {} extensions = {}
}) })
require("copilot").setup({
suggestion = { enabled = false },
panel = { enabled = false },
})
require("copilot_cmp").setup()
require("CopilotChat").setup {
model = 'claude-3.7-sonnet',
}
vim.g.bullets_enabled_file_types = { vim.g.bullets_enabled_file_types = {
'markdown', 'markdown',
'text', 'text',
@@ -263,7 +279,6 @@ require("nvim-tree").setup({
-- }, -- },
}) })
require('gitsigns').setup { require('gitsigns').setup {
signs = { signs = {
add = { text = '' }, add = { text = '' },
@@ -320,48 +335,30 @@ require("conform").setup({
rust = {"rustfmt", lsp_format = "fallback"}, rust = {"rustfmt", lsp_format = "fallback"},
go = {"gofmt", "goimports", lsp_format = "fallback"}, go = {"gofmt", "goimports", lsp_format = "fallback"},
lua = { "stylua", lsp_format = "fallback"}, lua = { "stylua", lsp_format = "fallback"},
sh = {"shfmt"},
bash = {"shfmt"},
zsh = {"shfmt"},
c = {"clang-format"},
cpp = {"clang-format"},
},
format_on_save = {
timeout_ms = 500,
lsp_fallback = true,
}, },
}) })
require('lint').linters_by_ft = { require('lint').linters_by_ft = {
markdown = {'vale'}, markdown = {'vale'},
} }
require("trouble").setup() require("trouble").setup()
require("todo-comments").setup() require("todo-comments").setup()
require("dap-view").setup({ require("dapui").setup()
winbar = {
-- sections = { "console", "scopes", "watches", "repl", "threads", "exceptions", "breakpoints" },
-- default_section = "console",
sections = { "scopes", "watches", "repl", "threads", "exceptions", "breakpoints" },
default_section = "scopes",
},
auto_toggle = "keep_terminal",
})
require("nvim-dap-virtual-text").setup() require("nvim-dap-virtual-text").setup()
local dap, dapui = require("dap"), require("dap-view") local dap, dapui = require("dap"), require("dapui")
-- dap.listeners.before.attach.dapui_config = function() dap.listeners.before.attach.dapui_config = function()
-- dapui.open() dapui.open()
-- end end
-- dap.listeners.before.launch.dapui_config = function() dap.listeners.before.launch.dapui_config = function()
-- dapui.open() dapui.open()
-- end end
-- dap.listeners.before.event_terminated.dapui_config = function() dap.listeners.before.event_terminated.dapui_config = function()
-- dapui.close() dapui.close()
-- end end
-- dap.listeners.before.event_exited.dapui_config = function() dap.listeners.before.event_exited.dapui_config = function()
-- dapui.close() dapui.close()
-- end end
dap.adapters.codelldb = { dap.adapters.codelldb = {
type = 'server', type = 'server',
@@ -372,49 +369,21 @@ dap.adapters.codelldb = {
} }
} }
dap.adapters.cppdbg = { dap.configurations.zig = {
type = "executable", {
command = "gdb", name = "Launch Zig Program",
args = { "--interpreter=dap", -- Tells GDB to speak the DAP protocol type = "codelldb",
"--eval-command", "set print pretty on" } request = "launch",
program = function()
-- Prompts for the executable path when you start debugging
return vim.fn.input('Path to executable: ', vim.fn.getcwd() .. '/zig-out/bin/', 'file')
end,
cwd = "${workspaceFolder}",
stopOnEntry = false,
},
} }
dap.adapters.debugpy = function(cb, config) if vim.fn.has("mac") then
if config.request == 'attach' then
local port = (config.connect or config).port
local host = (config.connect or config).host or '127.0.0.1'
cb({
type = 'server',
port = assert(port, '`connect.port` is required for a python `attach` configuration'),
host = host,
options = { source_filetype = 'python' },
})
else
-- local system_python = vim.fn.exepath('python3') or vim.fn.exepath('python')
cb({
type = 'executable',
command = 'python',
args = { '-m', 'debugpy.adapter' },
options = { source_filetype = 'python' },
})
end
end
-- dap.configurations.zig = {
-- {
-- name = "Launch Zig Program",
-- type = "codelldb",
-- request = "launch",
-- program = function()
-- -- Prompts for the executable path when you start debugging
-- return vim.fn.input('Path to executable: ', vim.fn.getcwd() .. '/zig-out/bin/', 'file')
-- end,
-- cwd = "${workspaceFolder}",
-- stopOnEntry = false,
-- },
-- }
if _G.is_mac then
workspaces = { workspaces = {
{ {
name = "privat", name = "privat",
@@ -433,7 +402,7 @@ if _G.is_mac then
} }
end end
if _G.is_work then if is_wsl_env() then
workspaces = { workspaces = {
{ {
name = "work", name = "work",
@@ -447,16 +416,6 @@ if _G.is_work then
daily_notes = {} daily_notes = {}
end end
if _G.is_private_nixos then
workspaces = {
{
name = "tech",
path = "~/notes",
},
}
daily_notes = {}
end
require("obsidian").setup({ require("obsidian").setup({
workspaces = workspaces, workspaces = workspaces,
templates = { templates = {
@@ -464,12 +423,18 @@ require("obsidian").setup({
date_format = "%Y-%m-%d %a", date_format = "%Y-%m-%d %a",
time_format = "%H:%M", time_format = "%H:%M",
}, },
checkbox = { ui = {
order = { " ", ">", "x", "!", "~", "c", "" }, checkboxes = {
[" "] = { char = "󰄱", hl_group = "ObsidianTodo" },
[">"] = { char = "", hl_group = "ObsidianRightArrow" },
["x"] = { char = "", hl_group = "ObsidianDone" },
["~"] = { char = "󰰱", hl_group = "ObsidianTilde" },
["!"] = { char = "", hl_group = "ObsidianImportant" },
["?"] = { char = "?", hl_group = "ObsidianImportant" }
}, },
frontmatter = { },
enabled = true, disable_frontmatter = false,
func = function(note) note_frontmatter_func = function(note)
-- Add the title of the note as an alias. -- Add the title of the note as an alias.
if note.title then if note.title then
note:add_alias(note.title) note:add_alias(note.title)
@@ -485,13 +450,11 @@ require("obsidian").setup({
return out return out
end, end,
},
note_path_func = function(spec) note_path_func = function(spec)
local path = spec.dir / spec.title local path = spec.dir / spec.title
return path:with_suffix(".md") return path:with_suffix(".md")
end, end,
daily_notes = daily_notes, daily_notes = daily_notes,
legacy_commands = false,
}) })
require('render-markdown').setup({ require('render-markdown').setup({
@@ -499,36 +462,4 @@ require('render-markdown').setup({
file_types = { 'markdown'}, file_types = { 'markdown'},
completions = { lsp = { enabled = true } }, completions = { lsp = { enabled = true } },
render_modes = { 'n', 'c', 't' }, render_modes = { 'n', 'c', 't' },
checkbox = {
enabled = true,
render_modes = false,
bullet = false,
right_pad = 1,
unchecked = {
icon = '󰄱',
highlight = 'RenderMarkdownUnchecked',
scope_highlight = nil,
},
checked = {
icon = '󰱒',
highlight = 'RenderMarkdownChecked',
scope_highlight = nil,
},
custom = {
next = { raw = '[!]', rendered = '', highlight = 'RenderMarkdownNext', scope_highlight = nil },
in_progress = { raw = '[>]', rendered = '', highlight = 'RenderMarkdownOngoing', scope_highlight = nil },
waiting = { raw = '[~]', rendered = '󰥔', highlight = 'RenderMarkdownWaiting', scope_highlight = nil },
cancelled = { raw = '[c]', rendered = 'x', highlight = 'RenderMarkdownCancelled', scope_highlight = nil },
},
},
}) })
require('treesitter-context').setup{
multiwindow = true,
}
vim.api.nvim_set_hl(0, "TreesitterContextBottom", {
underline = true,
sp = "Grey"
})
require('ibl').setup()

View File

@@ -62,6 +62,10 @@ vim.opt.clipboard:append('unnamedplus')
vim.cmd('filetype plugin indent on') vim.cmd('filetype plugin indent on')
-- vim.cmd('colorscheme lucius')
-- vim.cmd('LuciusWhite')
------------------------------ ------------------------------
---------- AUTOGROUPS -------- ---------- AUTOGROUPS --------
------------------------------ ------------------------------

View File

@@ -1,12 +0,0 @@
keys:
- &macbook age1hmgy68ukugduef75ev72jnpu77ff3lajadpf7u0zv3ex4nt7f5qs5nxx2l
- &macnix age1yez9q5q94kt99d9q8eqgqrkz7djmk3kwsqdjp7ww7e0fquzjevpsjkk5x4
- &worknix age1wufdcd234uw69lcw6gtv9r5zfz7h5tvu0fzcg5d8tn67yx6pv47sary4q2
creation_rules:
- path_regex: secrets\.yaml$
key_groups:
- age:
- *macbook
- *macnix
- *worknix

View File

@@ -1,35 +0,0 @@
langdock_api_key: ENC[AES256_GCM,data:9CTt73dQowcjIdjQoPMjsmGeIgV0nyHZxePOwak/m09ePfu4Gb3gDC17wq9Hde5J9IqpEID73Kdo/DsGm9m765rPGQFxGwTo3MO5eZgXAQjFXQNNhYm+sug=,iv:TVuiMG/7HYjncK3oC8r5xYrnNGXFcrBrpq9OO+7plNY=,tag:EZqUOGYwTHcukDop8p/JBw==,type:str]
openrouter_api_key: ENC[AES256_GCM,data:TqzRCeWH6Ibn/0dAf3YVnXUnBS766S+fZOHG5S49wYtoLcfhmHXFMHeDBZAWFdkU2E7X4Hhyv5l+hDlH+bJH0NQNL3rHvqVlbA==,iv:VF8RfLls3vYcOPqKPPax60kh7ILM/Y5mABf/UAzTBgo=,tag:lRY8skfDT3F9u5a+I0JJ6Q==,type:str]
sops:
age:
- recipient: age1hmgy68ukugduef75ev72jnpu77ff3lajadpf7u0zv3ex4nt7f5qs5nxx2l
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJcTBpZ3BwNnVxVkFQQWgy
VWFsMFF0WGIzbTBFZ0htQ251dGlVdW5PckdNCmtldkZZL0Z3SER2OHZuUGdvNVpI
Vk1KS1ZYVzZXZGtUbTNtZnhPeStSTlUKLS0tICtXYTgxMHc0alBYUDAzcXVXcm9J
YjQrUGZaWmpaV2tGOXJmbGR5K3l1VFEK+bsmeV/PjYcSlsJz0ZQZ8U9EYSu8bTJM
BJ0T910cPudb/dkMrU9QSWUlBbOKk78ivKvDbwqPBfguSqU5GevLGg==
-----END AGE ENCRYPTED FILE-----
- recipient: age1yez9q5q94kt99d9q8eqgqrkz7djmk3kwsqdjp7ww7e0fquzjevpsjkk5x4
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA3WXdEM2RORG56N3hVRGx5
NVZnWHY4TG5sRmdyQnJqVm4waUpoNGc4eFQ0CkNoanF3ZFRNQzQ5dHBST1BkSko0
cDAwYlBKVUZ3amJrcDJHcTloaXIwcWsKLS0tIDlMa0dqNmJvMjZZSVBPWjJncGlK
Q3F3cHFoWC9Ga0Q4S3VqQ1psRjZZUmsK7+d9wMgC27xaOu1CLX8YbG8BbJdYhLLg
dc8RHujixqkvheiv9syzCNF0z6Oc2qT5Vw2v7gCZ1SPgomOf3oHNHQ==
-----END AGE ENCRYPTED FILE-----
- recipient: age1wufdcd234uw69lcw6gtv9r5zfz7h5tvu0fzcg5d8tn67yx6pv47sary4q2
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBpWjdzMWpCemJJR2FvUjJ2
b0hraEVBWDdJeG9JRFpLYm5XV1FDUDFMeFdnCktwRElvTmoyZmpPQ3VjbldXVHo4
SmpjQlRPK2o3YnNLMklyMnVwWERtb28KLS0tIDNjcGJhMkR1bCtBWUV1WU5TZjVR
YjBrekY4Y2JSczBEQ3BObjhKZkhYc3MKMrGlO/w7Hvp23rpL71/XDsJDcbc3t73C
iXdD2Oc9V5g5Jz3H7mkaAlNRg8u+LwGXYdwZiG7NWSyQnARPgeMBwQ==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2026-06-09T14:03:10Z"
mac: ENC[AES256_GCM,data:H87P4qqRKayz/x9MKK0a8IqL48UFFMVJHQ1tiuGAcUjDDQVmU3BJof6jM38Sixbe+wiCrNuIdYwFoSIvJKwUZ+Yk6vQqwmxPqfTwEiPArmXdAkbggRlncuyJF0aQ/Jkr0ntrH+Bbc+QSwRYdRmGVZP62gZae1DaOi3chvMLSrCg=,iv:kw67WeIAhsBlJaJhPc77xgX9yadMzu9022olqe4JtNA=,tag:1C523XJecI1DkywQlZHFgg==,type:str]
unencrypted_suffix: _unencrypted
version: 3.12.1

View File

@@ -1,35 +0,0 @@
#!/usr/bin/env python3
"""things.py - description here."""
import argparse
def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
parser = argparse.ArgumentParser(description="things.py - description here.")
parser.add_argument(
"input",
nargs="?",
help="input file or value to process",
)
parser.add_argument(
"-o",
"--output",
help="output file (defaults to stdout)",
)
parser.add_argument(
"-v",
"--verbose",
action="store_true",
help="enable verbose output",
)
return parser.parse_args(argv)
def main() -> None:
args = parse_args()
if args.verbose:
print(f"input={args.input!r} output={args.output!r}")
if __name__ == "__main__":
main()