151 Commits

Author SHA1 Message Date
Patrick Stevens
f413ff7918 Format 2024-11-29 09:38:23 +00:00
Patrick Stevens
7de8ba96f8 Get sway working 2024-11-29 09:37:28 +00:00
Patrick Stevens
ab4af6d488 Merge branch 'main' into more-earthworm 2024-11-28 22:55:29 +00:00
Patrick Stevens
02f757bf57 Fix pavucontrol (#96) 2024-11-24 12:47:27 +00:00
Patrick Stevens
6d3804a5ee Start tmux automatically (#95) 2024-11-20 18:29:59 +00:00
Patrick Stevens
6c3bdcc4b2 AMD GPU on capybara (#94) 2024-11-20 18:23:01 +00:00
Patrick Stevens
f9172d159b Stash pop 2024-11-15 00:10:47 +00:00
Patrick Stevens
233771f07d Merge main 2024-11-15 00:10:10 +00:00
Patrick Stevens
2123c53980 Bump flake again (#93) 2024-11-14 23:40:40 +00:00
Patrick Stevens
7f712faf2c Bump flake (#92) 2024-11-14 23:31:22 +00:00
Patrick Stevens
5b8b64b0a2 Keepassxc broken on aarch64-darwin (#91) 2024-11-14 23:26:55 +00:00
Patrick Stevens
73efe7a18c Add golang (#90) 2024-10-26 08:25:43 +00:00
Patrick Stevens
f6dd2e686a Add gopls (#89) 2024-10-26 08:20:48 +00:00
Patrick Stevens
df071387b2 Pipewire on Capybara (#88) 2024-10-23 21:00:06 +00:00
Patrick Stevens
f83285dec2 Use Waybar (#87) 2024-10-21 23:23:29 +00:00
Patrick Stevens
9fbcd75842 Use pinentry-curses (#86) 2024-10-21 23:28:21 +01:00
Patrick Stevens
52c08e4183 Fix Earthworm key (#84) 2024-10-21 23:23:37 +01:00
Patrick Stevens
d7221c2af1 Resolve borked merge 2024-10-21 23:20:40 +01:00
Patrick Stevens
8969b0c347 Merge main 2024-10-21 23:06:40 +01:00
Patrick Stevens
a40777c034 Add waybar 2024-10-21 23:05:37 +01:00
Patrick Stevens
dbe797cf03 WIP 2024-10-21 22:41:31 +01:00
Patrick Stevens
e60a954838 Fix Earthworm key 2024-10-21 22:41:10 +01:00
Patrick Stevens
0e00b6250f Merge main 2024-10-20 10:33:21 +01:00
Patrick Stevens
fd1452cc8f Fix tmux after macOS upgrade (#83) 2024-10-20 10:05:03 +01:00
Patrick Stevens
8ef0e6ef37 Merge main 2024-10-19 22:30:32 +01:00
dependabot[bot]
8e7abf90c2 Bump cachix/install-nix-action from 29 to 30 (#82)
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 29 to 30.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Commits](https://github.com/cachix/install-nix-action/compare/v29...v30)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-07 09:14:14 +01:00
dependabot[bot]
8d888029bd Bump cachix/install-nix-action from V28 to 29 (#81) 2024-09-30 08:36:19 +01:00
Patrick Stevens
d891582dfe Add regular Nix store optimisation (#80) 2024-09-20 21:37:30 +00:00
Patrick Stevens
fa88755137 Fix mail and Git repo syncing on darwin (#79) 2024-09-20 21:42:08 +01:00
Patrick Stevens
544fc635eb Install pip (#78) 2024-09-20 20:36:06 +00:00
Patrick Stevens
6a493ab214 Delete ltex, it sticks around consuming loads of CPU (#77) 2024-09-20 20:32:54 +00:00
Patrick Stevens
86b6269229 Disable auto-optimise on Darwin (#76) 2024-09-20 18:37:42 +00:00
dependabot[bot]
89e1aa4d7e Bump cachix/install-nix-action from V27 to 28 (#75)
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from V27 to 28. This release includes the previously tagged commit.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Commits](https://github.com/cachix/install-nix-action/compare/V27...V28)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-16 10:26:24 +01:00
Patrick Stevens
76dbd82446 Add Rider and nvidia drivers (#73) 2024-09-08 21:25:33 +01:00
Patrick Stevens
ceaead9b63 Some Linux fixes (#72) 2024-09-08 16:45:20 +00:00
Patrick Stevens
88f4111744 Move Capybara to AMD (#71) 2024-09-08 17:31:33 +01:00
Patrick Stevens
3ae9cebd58 Bump nixpkgs and fix some nvim stuff (#70) 2024-08-28 20:00:31 +01:00
Patrick Stevens
5c872e2c4a Add some more stuff (#69) 2024-08-19 22:38:06 +00:00
Patrick Stevens
ede76d2bc2 Update flake (breaks ;; in which-key) (#67) 2024-08-06 20:14:01 +01:00
Patrick Stevens
19e8024a13 Add NuGet upgrade shortcut in neovim (#66) 2024-07-23 17:27:55 +01:00
Patrick Stevens
43c7842fac Fix required checks (#65) 2024-07-14 11:11:32 +01:00
Patrick Stevens
df22898e58 Add clangd (#64) 2024-07-14 11:08:36 +01:00
Patrick Stevens
ad9621acd3 Bump Nixpkgs (#63) 2024-06-29 19:53:49 +01:00
Patrick Stevens
dec7aff312 Bump Nixpkgs (#62) 2024-06-29 10:08:48 +01:00
Patrick Stevens
def75585dd Fix merge 2024-06-14 22:08:39 +01:00
Patrick Stevens
8c67cd2e0a Merge main 2024-06-14 21:58:47 +01:00
Patrick Stevens
9649e2e37b Add .NET project filetypes in nvim (#61) 2024-05-31 20:33:33 +00:00
Patrick Stevens
162b58abc4 Difftastic as Git diff tool (#60) 2024-05-27 17:03:47 +00:00
Patrick Stevens
29d80dec16 Neovim non nightly (#59) 2024-05-27 16:55:10 +00:00
dependabot[bot]
1fc72d0288 Bump cachix/install-nix-action from 26 to 27 (#58)
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 26 to 27.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Commits](https://github.com/cachix/install-nix-action/compare/v26...V27)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 08:24:50 +01:00
Patrick Stevens
8752e0a720 Update Ionide (#57) 2024-05-03 23:10:38 +00:00
Patrick Stevens
cde0abe5d9 Add calendar backup job (#56) 2024-04-28 21:42:54 +00:00
Patrick Stevens
5536c97493 Qualify path to cat (#55) 2024-04-28 21:40:55 +00:00
Patrick Stevens
ad6a4548c6 Capybara Steam and syncthing (#54) 2024-04-19 13:18:22 +00:00
Patrick Stevens
b361bbcbcb Syncthing (#53) 2024-04-19 10:48:11 +00:00
Patrick Stevens
02ceae3e22 Start signing Git commits (#52) 2024-04-15 20:42:29 +00:00
Patrick Stevens
e7f68f24a3 Add gnupg (#51) 2024-04-15 20:11:22 +00:00
Patrick Stevens
3208bf16c5 Split into modules (#50) 2024-04-12 20:33:50 +01:00
Patrick Stevens
ccaa90d392 Delete dead file (#49) 2024-04-06 13:29:21 +00:00
Patrick Stevens
fd71527762 Delete Python workaround (#48) 2024-04-06 11:30:05 +00:00
Patrick Stevens
a210ee4301 Add mail config (#47) 2024-04-06 12:24:52 +01:00
Patrick Stevens
d3ec6b02c3 Ripgrep config from store (#46) 2024-04-06 00:25:15 +01:00
Smaug123
aa3d08745a Everything except the actual mail config 2024-04-05 23:56:57 +01:00
Smaug123
bf1dfe3d6d Rename some vim bindings 2024-04-05 22:16:39 +01:00
Smaug123
d867348640 Move mailcap 2024-04-05 22:14:26 +01:00
Smaug123
7fb26eb707 Add prerequisites for a mail setup 2024-04-05 22:12:12 +01:00
Smaug123
f723b64486 Add more debugger-related commands in Python 2024-04-03 21:21:46 +01:00
Smaug123
7b94e76589 Always enable gutter 2024-04-02 21:08:55 +01:00
Patrick Stevens
68d57ea7cb Add capybara config (#45) 2024-03-30 18:07:17 +00:00
Smaug123
c6879ac254 Delete unnecessary overlay 2024-03-29 12:24:50 +00:00
Smaug123
59e1e8637c More python stuff 2024-03-29 11:58:52 +00:00
Smaug123
6256ad908f Add licence 2024-03-28 15:29:29 +00:00
Smaug123
d783fe475e Don't allow CHADtree to change what it points to 2024-03-28 15:26:19 +00:00
Patrick Stevens
77d7d402c3 More languages, clean up keybinds (#44) 2024-03-27 23:41:43 +00:00
Patrick Stevens
b69b9248f9 More F# and .NET stuff (#43) 2024-03-27 20:30:31 +00:00
Patrick Stevens
e91fb514fe More language servers (#42) 2024-03-26 21:33:10 +00:00
Patrick Stevens
07b3034bc0 Commonise floating-window logic (#41) 2024-03-26 09:31:39 +00:00
Patrick Stevens
a734e7f73f Fix up neovim deprecations (#40) 2024-03-26 00:27:53 +00:00
Patrick Stevens
010498edce Also style-check Lua (#39) 2024-03-26 00:15:10 +00:00
Smaug123
348d913a49 Merge branch 'main' into more-earthworm 2024-03-26 00:04:11 +00:00
Patrick Stevens
87492c2abe Big neovim overhaul (#38) 2024-03-26 00:04:01 +00:00
Smaug123
e668501cad Merge main 2024-03-26 00:01:04 +00:00
Patrick Stevens
15e603063a Remove sops (#37) 2024-03-26 00:00:04 +00:00
Smaug123
e160ff5704 Merge main 2024-03-25 23:58:23 +00:00
Patrick Stevens
028817765e Evil-mode (#36) 2024-03-25 23:55:45 +00:00
Smaug123
7a1e5eb445 Merge branch 'main' into more-earthworm 2024-03-25 23:54:14 +00:00
Patrick Stevens
7b14690664 Remove vscode-lldb, it doesn't actually work (#35) 2024-03-25 23:51:12 +00:00
Patrick Stevens
5647f009fb Reduce dependence on oh-my-zsh (#34) 2024-03-25 23:49:39 +00:00
Smaug123
47fc4dfd39 Use roslyn-nvim, fix some prefixes 2024-03-25 23:44:29 +00:00
Smaug123
ae0713074f Add C# language server 2024-03-25 21:29:19 +00:00
Smaug123
db633836f1 Attempt at venv creation thing 2024-03-25 09:39:47 +00:00
Smaug123
4554ea1a90 Fix buffer-specific binds 2024-03-24 23:30:52 +00:00
Smaug123
75cebeaa7a Stop for today 2024-03-24 21:08:06 +00:00
Smaug123
b94098e5af Fix 2024-03-24 18:18:02 +00:00
Smaug123
371af97527 Fix misalignment 2024-03-24 17:15:54 +00:00
Smaug123
742a708c0c Tidy up 2024-03-24 17:14:24 +00:00
Smaug123
ddbd6718b5 Upgrade nixpkgs 2024-03-24 16:53:46 +00:00
Smaug123
824e35351d Move entirely to Lua 2024-03-24 11:24:35 +00:00
Smaug123
8336993820 Document more 2024-03-23 19:07:25 +00:00
Smaug123
49f2b9be5c Much better 2024-03-23 18:46:18 +00:00
Smaug123
289e430d52 It works 2024-03-23 17:44:00 +00:00
Smaug123
d54f38cf68 Move more stuff to Lua 2024-03-23 14:12:42 +00:00
Smaug123
14981d3401 More 2024-03-23 11:11:27 +00:00
Smaug123
3e9b26c093 More 2024-03-23 11:07:02 +00:00
Smaug123
47b5993422 Nearly working 2024-03-23 01:06:01 +00:00
Smaug123
93b5fc92e9 Rustaceanvim 2024-03-22 21:24:48 +00:00
Smaug123
e493cdbcdd And F# 2024-03-22 21:17:19 +00:00
Smaug123
78b2d62ce2 Python setup 2024-03-22 21:01:26 +00:00
Smaug123
1e4c4c525f More 2024-03-22 19:38:21 +00:00
dependabot[bot]
31e8d08da3 Bump cachix/install-nix-action from 25 to 26 (#33) 2024-03-11 07:30:57 +00:00
Smaug123
21bb1ebd3d Fix autoloads 2024-02-26 18:32:35 +00:00
Smaug123
b111a9509d Fix config 2024-02-25 20:01:12 +00:00
Smaug123
ef64007cc9 Couple of fixes 2024-02-25 17:24:04 +00:00
Smaug123
b9bb4c49fa Merge branch 'main' into more-earthworm 2024-02-23 22:47:53 +00:00
Patrick Stevens
75c77e99c0 Rem oh-my-zsh (#32) 2024-02-23 22:47:37 +00:00
Smaug123
d2718febf8 Rem oh-my-zsh 2024-02-23 22:44:39 +00:00
Patrick Stevens
ef6d3d4445 FiraCode (#31) 2024-02-23 14:18:18 +00:00
Smaug123
b3eb9adb9f Format 2024-02-23 14:16:04 +00:00
Smaug123
ada02e558b FiraCode 2024-02-23 14:11:48 +00:00
Smaug123
ae96250101 Delete unused keybinds 2024-02-23 11:15:36 +00:00
Smaug123
5e3f257ce6 Merge branch 'main' into more-earthworm 2024-02-23 11:11:39 +00:00
Patrick Stevens
a3a8a5598a Add some extensions (#30) 2024-02-23 11:11:31 +00:00
Smaug123
134b0dc8a7 CHADdeps and coq_nvim 2024-02-23 11:06:57 +00:00
Smaug123
a290279914 Relegate to Linux 2024-02-04 23:39:41 +00:00
Patrick Stevens
bea4ca1220 More earthworm 2024-02-04 20:15:15 +00:00
Patrick Stevens
6af765d032 Update (#29) 2024-01-29 00:42:13 +00:00
dependabot[bot]
02c87e8ea4 Bump cachix/install-nix-action from 24 to 25 (#28)
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 24 to 25.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Commits](https://github.com/cachix/install-nix-action/compare/v24...v25)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-15 01:58:46 +00:00
dependabot[bot]
0339c1f051 Bump cachix/install-nix-action from 23 to 24 (#27)
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 23 to 24.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Commits](https://github.com/cachix/install-nix-action/compare/v23...v24)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-04 09:11:42 +00:00
Patrick Stevens
3743aead94 Mailcap and flake check (#26) 2023-10-04 14:25:52 +00:00
Patrick Stevens
8f956b631c Add mailcap (#25) 2023-10-04 15:11:10 +01:00
Patrick Stevens
142e7f2244 Improve Git config, add lynx, add F# Vim config (#24) 2023-10-04 15:04:44 +01:00
dependabot[bot]
166ef06a35 Bump actions/checkout from 3 to 4 (#22)
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-11 09:09:19 +01:00
dependabot[bot]
b07f725d3d Bump cachix/install-nix-action from 22 to 23 (#23)
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 22 to 23.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Commits](https://github.com/cachix/install-nix-action/compare/v22...v23)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-11 09:07:16 +01:00
dependabot[bot]
4b3f3f886b Bump cachix/install-nix-action from 17 to 22 (#21)
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 17 to 22.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Commits](https://github.com/cachix/install-nix-action/compare/v17...v22)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-04 08:40:18 +01:00
Patrick Stevens
028225eca7 Add more linting (#20) 2023-08-28 20:25:01 +01:00
Patrick Stevens
b343f6bb01 Add config for Earthworm (#19) 2023-08-28 19:52:17 +01:00
Patrick Stevens
2cd767ae5b Add rg, poetry, woodpecker-agent, stable Emacs, upstreamed VSCode plugins (#18) 2023-08-28 11:18:05 +01:00
Patrick Stevens
44856ee782 Many updates (#16) 2023-04-01 09:00:45 +01:00
Patrick Stevens
36171014c8 Split into multiple configs (#10) 2022-11-24 20:07:50 +00:00
Patrick Stevens
df297beff1 Add VSCode pull-requests extension, add more libraries to Rust flags (#15) 2022-11-24 19:42:41 +00:00
Patrick Stevens
4e6c9b03af Add PR checks (#14) 2022-11-24 19:30:04 +00:00
Patrick Stevens
460af9d007 Flake update (#13) 2022-11-24 19:24:38 +00:00
Patrick Stevens
b72a716083 Better gitignore for darwin (#12) 2022-11-24 19:15:06 +00:00
Patrick Stevens
f1d917d4ec Add JSON reformat to init.vim (#11) 2022-11-24 19:13:39 +00:00
Patrick Stevens
f4678f910f General faff (#9) 2022-08-20 21:45:49 +01:00
Smaug123
cf0dbe7f44 Merge branch 'main' of ssh://ssh.github.com:443/Smaug123/nix-dotfiles 2022-03-17 22:13:20 +00:00
Patrick Stevens
c45a0d9df6 Add yt-dlp config and fix up git diff style (#8)
* Update git diff method

* Bump flake

* Add yt-dlp
2022-03-17 22:13:13 +00:00
Smaug123
d22ad837a0 Bump flake 2022-03-06 15:33:19 +00:00
Smaug123
005de0c62a Update git diff method 2022-03-02 19:14:46 +00:00
Smaug123
c9dd6b03ec Merge branch 'update-extensions' 2022-02-20 10:23:04 +00:00
Smaug123
5fda4e0165 Add config for LaTeX 2022-02-20 10:22:33 +00:00
66 changed files with 4556 additions and 833 deletions

8
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,8 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"

28
.github/workflows/lint.yaml vendored Normal file
View File

@@ -0,0 +1,28 @@
name: Lint
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
flake-check:
runs-on: "ubuntu-latest"
steps:
- name: "Checkout"
uses: "actions/checkout@v4"
- name: "Install Nix"
uses: "cachix/install-nix-action@v30"
with: { "extra_nix_config": "access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}" }
- name: "Check flake"
run: "nix flake check --all-systems"
all-required-checks-complete:
if: ${{ always() }}
runs-on: "ubuntu-latest"
steps:
- uses: Smaug123/all-required-checks-complete-action@05b40a8c47ef0b175ea326e9abb09802cb67b44e
with:
needs-context: ${{ toJSON(needs) }}
needs: [ "flake-check" ]

1
.gitignore vendored
View File

@@ -2,3 +2,4 @@ result
.idea/
bin/
obj/
.DS_Store

View File

@@ -1,9 +1,6 @@
This repository currently has no licence applied to it, except for the NeoVim configuration.
That configuration is in large part derived from https://github.com/amix/vimrc and is therefore provided under the following licence.
The MIT License (MIT)
Copyright (c) 2016 Amir Salihefendic
Copyright (c) 2024 Patrick Stevens
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -81,14 +81,14 @@ type NixFile =
static member Parse (s : string) : NixFile =
let pre, post =
s.Split "\n] ++ pkgs.vscode-utils.extensionsFromVscodeMarketplace [\n"
s.Split "++ pkgs.vscode-utils.extensionsFromVscodeMarketplace ["
|> function
| [| pre ; post |] -> pre, post
| _ -> failwith "Unexpected number of '++'"
let verbatim, skipped =
match pre.Split "\n" |> List.ofArray with
| "{ pkgs }:" :: "" :: "with pkgs.vscode-extensions; [" :: rest ->
match pre.Split "\n" |> Seq.filter (fun s -> s <> "") |> List.ofSeq with
| pkgsStr :: "with pkgs.vscode-extensions; [" :: rest when pkgsStr.Replace(" ", "") = "{pkgs}:" ->
rest
|> List.map (fun s ->
if s.StartsWith '#' then Choice2Of2 (s.[2..].Trim()) else Choice1Of2 (s.Trim())
@@ -146,7 +146,9 @@ let upgradeExtension (client : HttpClient) (e : Extension) : Extension Async =
|> sprintf "[%s]"
|> fun s -> JsonSerializer.Deserialize<Version array> (s, options)
|> Seq.head
return { e with Version = latestVersion.Version }
if latestVersion.Version <> e.Version then
return { e with Version = latestVersion.Version ; Sha256 = "sha256-/000+cQBqzb6QB5+AizlyIcjqNpZ86o2at885hOcro0=" }
else return e
}
let upgrade (nixFile : NixFile) : NixFile =
@@ -170,7 +172,7 @@ module Program =
File.ReadAllText sourceFile
|> NixFile.Parse
|> upgrade
|> sprintf "%O"
|> string<NixFile>
|> fun s -> File.WriteAllText (sourceFile, s)
0

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>
<ItemGroup>

View File

@@ -1,13 +1,13 @@
#!/bin/sh
install_nix () {
install_nix() {
echo "Installing Nix..."
diskutil list > /dev/null || export PATH=/usr/sbin:$PATH
diskutil list >/dev/null || export PATH="/usr/sbin:$PATH"
curl -L https://nixos.org/nix/install | sh -s -- --darwin-use-unencrypted-nix-store-volume --daemon || exit 1
echo "Nix installed."
}
install_darwin_build () {
install_darwin_build() {
echo "Installing nix-darwin..."
nix-build https://github.com/LnL7/nix-darwin/archive/master.tar.gz -A installer || exit 1
./result/bin/darwin-installer || exit 1
@@ -23,4 +23,4 @@ nix-channel --update || exit 1
darwin-rebuild changelog || install_darwin_build || exit 1
NIX_PATH="darwin-config=$HOME/.nixpkgs/darwin-configuration.nix:/nix/var/nix/profiles/per-user/Patrick/channels:$NIX_PATH" darwin-rebuild switch || exit 1
NIX_PATH="darwin-config=$HOME/.nixpkgs/darwin-configuration.nix:/nix/var/nix/profiles/per-user/patrick/channels:$NIX_PATH" darwin-rebuild switch || exit 1

View File

@@ -1,43 +1,131 @@
{ pkgs, ... }:
let python = import ./python.nix { inherit pkgs; }; in
{
{pkgs, ...}: let
mbsync = import ./mbsync.nix {inherit pkgs;};
in {
nix.useDaemon = true;
# List packages installed in system profile. To search by name, run:
# $ nix-env -qaP | grep wget
environment.systemPackages =
[
pkgs.alacritty
pkgs.rustup
pkgs.libiconv
pkgs.clang
#pkgs.keepassxc
python
];
environment.systemPackages = [
pkgs.alacritty
pkgs.rustup
pkgs.libiconv
pkgs.clang
pkgs.python3
];
users.users.patrick = {
home = "/Users/patrick";
name = "patrick";
};
# This line is required; otherwise, on shell startup, you won't have Nix stuff in the PATH.
programs.zsh.enable = true;
programs.gnupg.agent.enable = true;
# Use a custom configuration.nix location.
# $ darwin-rebuild switch -I darwin-config=$HOME/.config/nixpkgs/darwin/configuration.nix
environment.darwinConfig = "$HOME/.nixpkgs/darwin-configuration.nix";
launchd.agents = {
mbsync-btinternet = {
command = "${mbsync}/bin/mbsync BTInternet > /tmp/mbsync.btinternet.log 2>/tmp/mbsync.btinternet.2.log";
serviceConfig = {
KeepAlive = false;
UserName = "patrick";
StartInterval = 60;
RunAtLoad = true;
};
};
mbsync-proton = {
command = "${mbsync}/bin/mbsync Proton > /tmp/mbsync.proton.1.log 2>/tmp/mbsync.proton.2.log";
serviceConfig = {
KeepAlive = false;
UserName = "patrick";
StartInterval = 60;
RunAtLoad = true;
};
};
mbsync-gmail = {
command = "${mbsync}/bin/mbsync Gmail > /tmp/mbsync.gmail.1.log 2>/tmp/mbsync.gmail.2.log";
serviceConfig = {
KeepAlive = false;
UserName = "patrick";
# Refresh token is 60min long, so do this more often than that!
StartInterval = 30;
RunAtLoad = true;
};
};
backup-calendar = {
command = ''${pkgs.bash}/bin/bash -c "mkdir -p '/Users/patrick/Library/Application Support/RadicaleBackups' && if [ ! -d '/Users/patrick/Library/Application Support/RadicaleBackups/.git' ] ; then ${pkgs.git}/bin/git clone root@patrickstevens.co.uk:/preserve/radicale/data/.git '/Users/patrick/Library/Application Support/RadicaleBackups' >/tmp/radicale.out.log 2>/tmp/radicale.err.log; fi && ${pkgs.git}/bin/git --git-dir '/Users/patrick/Library/Application Support/RadicaleBackups/.git' --work-tree '/Users/patrick/Library/Application Support/RadicaleBackups/' pull 2>>/tmp/radicale.err.log"'';
serviceConfig = {
KeepAlive = false;
UserName = "patrick";
StartInterval = 3600;
RunAtLoad = true;
};
};
sync-nixpkgs = {
command = ''${pkgs.bash}/bin/bash -c "if [ -d /Users/patrick/Documents/GitHub/nixpkgs ] ; then ${pkgs.git}/bin/git --git-dir /Users/patrick/Documents/GitHub/nixpkgs/.git --work-tree '/Users/patrick/Documents/GitHub/nixpkgs/' fetch origin ; fi"'';
serviceConfig = {
KeepAlive = false;
UserName = "patrick";
StartInterval = 36000;
RunAtLoad = true;
};
};
sync-dotnet-api-docs = {
command = ''${pkgs.bash}/bin/bash -c "if [ -d /Users/patrick/Documents/GitHub/dotnet-api-docs ] ; then ${pkgs.git}/bin/git --git-dir /Users/patrick/Documents/GitHub/dotnet-api-docs/.git --work-tree '/Users/patrick/Documents/GitHub/dotnet-api-docs' fetch origin ; fi"'';
serviceConfig = {
KeepAlive = false;
UserName = "patrick";
StartInterval = 36000;
RunAtLoad = true;
};
};
sync-dotnet-docs = {
command = ''${pkgs.bash}/bin/bash -c "if [ -d /Users/patrick/Documents/GitHub/dotnet-docs ] ; then ${pkgs.git}/bin/git --git-dir /Users/patrick/Documents/GitHub/dotnet-docs/.git --work-tree '/Users/patrick/Documents/GitHub/dotnet-docs' fetch origin ; fi"'';
serviceConfig = {
KeepAlive = false;
UserName = "patrick";
StartInterval = 36000;
RunAtLoad = true;
};
};
nix-store-optimise = {
command = ''${pkgs.nix}/bin/nix store optimise'';
serviceConfig = {
KeepAlive = false;
UserName = "patrick";
StartInterval = 72000;
RunAtLoad = true;
};
};
};
# Auto upgrade nix package and the daemon service.
services.nix-daemon.enable = true;
nix.package = pkgs.nixFlakes;
nix.package = pkgs.nixVersions.stable;
nix.gc.automatic = true;
# Sandbox causes failure: https://github.com/NixOS/nix/issues/4119
nix.useSandbox = false;
nix.settings.sandbox = false;
# Optimising store leads to transient build failures https://github.com/NixOS/nix/issues/7273
nix.extraOptions = ''
auto-optimise-store = true
auto-optimise-store = false
experimental-features = nix-command flakes
extra-experimental-features = ca-derivations
max-jobs = auto # Allow building multiple derivations in parallel
keep-outputs = true # Do not garbage-collect build time-only dependencies (e.g. clang)
keep-derivations = true
# Allow fetching build results from the Lean Cachix cache
trusted-substituters = https://lean4.cachix.org/
trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= lean4.cachix.org-1:mawtxSxcaiWE24xCXXgh3qnvlTkyU7evRRnGeAhD4Wk=

View File

198
flake.lock generated
View File

@@ -1,5 +1,25 @@
{
"nodes": {
"apple-silicon": {
"inputs": {
"flake-compat": "flake-compat",
"nixpkgs": "nixpkgs",
"rust-overlay": "rust-overlay"
},
"locked": {
"lastModified": 1731473366,
"narHash": "sha256-sE2WfD3YyNrCROfRZKqMDR77g3KV4FXUaJ7NWe+A7ro=",
"owner": "tpwrules",
"repo": "nixos-apple-silicon",
"rev": "3eee753e4b074790342fadb1c4e7183d037ddac4",
"type": "github"
},
"original": {
"owner": "tpwrules",
"repo": "nixos-apple-silicon",
"type": "github"
}
},
"darwin": {
"inputs": {
"nixpkgs": [
@@ -7,11 +27,11 @@
]
},
"locked": {
"lastModified": 1645007752,
"narHash": "sha256-FQZMiVP/1vgR7x+TWonMf0NZczrZ4ZjhSTj3rM+kglY=",
"lastModified": 1731454423,
"narHash": "sha256-TtwvgFxUa0wyptLhQbKaixgNW1UXf3+TDqfX3Kp63oM=",
"owner": "lnl7",
"repo": "nix-darwin",
"rev": "c944b5ee82a829ddf7fa6bd9300bc2fe3d005fa1",
"rev": "6c71c49e2448e51ad830ed211024e6d0edc50116",
"type": "github"
},
"original": {
@@ -22,12 +42,18 @@
}
},
"emacs": {
"inputs": {
"nixpkgs": [
"nixpkgs"
],
"nixpkgs-stable": "nixpkgs-stable"
},
"locked": {
"lastModified": 1644143491,
"narHash": "sha256-ld5MzYesjOE8Ml5uvjFUFaxAozJEl48svwWQ3i7oggc=",
"lastModified": 1731604406,
"narHash": "sha256-CUkO4CXaDcGyUqQ+/ArvekL3hlfgass7LjrnG6m2+g8=",
"owner": "nix-community",
"repo": "emacs-overlay",
"rev": "4c7e0980a5f23684ca3ea772d4f62b0da4f55e3c",
"rev": "f6c94b95f529cfbd29848c12816111a2471a5293",
"type": "github"
},
"original": {
@@ -36,6 +62,39 @@
"type": "github"
}
},
"flake-compat": {
"locked": {
"lastModified": 1688025799,
"narHash": "sha256-ktpB4dRtnksm9F5WawoIkEneh1nrEvuxb5lJFt1iOyw=",
"owner": "nix-community",
"repo": "flake-compat",
"rev": "8bf105319d44f6b9f0d764efa4fdef9f1cc9ba1c",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "flake-compat",
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1701680307,
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"home-manager": {
"inputs": {
"nixpkgs": [
@@ -43,11 +102,11 @@
]
},
"locked": {
"lastModified": 1645140957,
"narHash": "sha256-WTJzLSCDLBI537o2L/3kRyqEV5YRT7+1QSGryeKReHE=",
"lastModified": 1731604581,
"narHash": "sha256-Qq2YZZaDTB3FZLWU/Hgh1uuWlUBl3cMLGB99bm7rFUM=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "4f4165a8b9108818ab0193bbd1a252106870b2a2",
"rev": "1d0862ee2d7c6f6cd720d6f32213fa425004be10",
"type": "github"
},
"original": {
@@ -56,28 +115,141 @@
"type": "github"
}
},
"model": {
"flake": false,
"locked": {
"narHash": "sha256-aMuDhcvEaioTWn+LUcnxfAgs2VFbM8xBVVfdzx2Cu8I=",
"type": "file",
"url": "https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-large-v3.bin?download=true"
},
"original": {
"type": "file",
"url": "https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-large-v3.bin?download=true"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1644972330,
"narHash": "sha256-hEDWZcTDopnz4jRDhCmnH9VztdKSfR6mrudSM8+Jfco",
"lastModified": 1731139594,
"narHash": "sha256-IigrKK3vYRpUu+HEjPL/phrfh7Ox881er1UEsZvw9Q4=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "1a5ff5ea0297dc8ec5a33b87dfb4fc78687068e6",
"rev": "76612b17c0ce71689921ca12d9ffdc9c23ce40b2",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-stable": {
"locked": {
"lastModified": 1731386116,
"narHash": "sha256-lKA770aUmjPHdTaJWnP3yQ9OI1TigenUqVC3wweqZuI=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "689fed12a013f56d4c4d3f612489634267d86529",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-24.05",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1731531548,
"narHash": "sha256-sz8/v17enkYmfpgeeuyzniGJU0QQBfmAjlemAUYhfy8=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "24f0d4acd634792badd6470134c387a3b039dace",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_3": {
"locked": {
"lastModified": 1695033101,
"narHash": "sha256-RQ4m+ycjdLdass7Hr4+Lzwnjw7wGhcUkKqWiJS3YxPM=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "d941d9491804e0ca01e03468dbf6f8d3a7919a16",
"type": "github"
},
"original": {
"owner": "nixos",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"apple-silicon": "apple-silicon",
"darwin": "darwin",
"emacs": "emacs",
"home-manager": "home-manager",
"nixpkgs": "nixpkgs"
"nixpkgs": "nixpkgs_2",
"whisper": "whisper"
}
},
"rust-overlay": {
"flake": false,
"locked": {
"lastModified": 1686795910,
"narHash": "sha256-jDa40qRZ0GRQtP9EMZdf+uCbvzuLnJglTUI2JoHfWDc=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "5c2b97c0a9bc5217fc3dfb1555aae0fb756d99f9",
"type": "github"
},
"original": {
"owner": "oxalica",
"repo": "rust-overlay",
"type": "github"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"whisper": {
"inputs": {
"flake-utils": "flake-utils",
"model": "model",
"nixpkgs": "nixpkgs_3"
},
"locked": {
"lastModified": 1704121968,
"narHash": "sha256-N8FJb+ohJ4Qt/m5RoAbwm3RP4VRjl+hA6PUCfjPhZo8=",
"owner": "Smaug123",
"repo": "whisper.cpp",
"rev": "04f8e0cdc73abe7c593b2c9405f0f590c51de95a",
"type": "github"
},
"original": {
"owner": "Smaug123",
"ref": "nix",
"repo": "whisper.cpp",
"type": "github"
}
}
},

179
flake.nix
View File

@@ -2,45 +2,186 @@
description = "Patrick's Darwin Nix setup";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
nixpkgs = {
url = "github:NixOS/nixpkgs/nixpkgs-unstable";
};
home-manager = {
url = "github:nix-community/home-manager";
inputs.nixpkgs.follows = "nixpkgs";
};
darwin = {
url = "github:lnl7/nix-darwin/master";
# url = "github:Smaug123/nix-darwin/extract";
inputs.nixpkgs.follows = "nixpkgs";
};
emacs = {
url = "github:nix-community/emacs-overlay";
inputs.nixpkgs.follows = "nixpkgs";
};
apple-silicon = {
url = "github:tpwrules/nixos-apple-silicon";
};
whisper = {
url = "github:Smaug123/whisper.cpp/nix";
};
};
outputs = { self, darwin, emacs, nixpkgs, home-manager, ... }@inputs:
let system = "aarch64-darwin"; in
let config = {
allowUnfreePredicate = pkg: builtins.elem (nixpkgs.lib.getName pkg) [
"vscode"
];
}; in
let overlays = [ emacs.overlay ] ++ import ./overlays.nix; in
let pkgs = (import nixpkgs { inherit system config overlays; }); in
{
darwinConfigurations = {
nixpkgs = pkgs;
patrick = darwin.lib.darwinSystem {
system = system;
modules = [
./darwin-configuration.nix
home-manager.darwinModules.home-manager
outputs = {
darwin,
emacs,
nixpkgs,
home-manager,
apple-silicon,
whisper,
...
}: let
config = {
# contentAddressedByDefault = true;
allowUnfree = true;
};
systems = ["aarch64-darwin" "aarch64-linux" "x86_64-linux"];
in let
overlays = [emacs.overlay];
recursiveMerge = attrList: let
f = attrPath:
builtins.zipAttrsWith (n: values:
if builtins.tail values == []
then builtins.head values
else if builtins.all builtins.isList values
then nixpkgs.lib.unique (builtins.concatLists values)
else if builtins.all builtins.isAttrs values
then f (attrPath ++ [n]) values
else builtins.last values);
in
f [] attrList;
in {
nixosConfigurations = {
capybara = let
system = "x86_64-linux";
in let
pkgs = import nixpkgs {inherit system config overlays;};
in
nixpkgs.lib.nixosSystem {
inherit system;
specialArgs = {
username = "patrick";
dotnet = pkgs.dotnet-sdk_8;
};
modules = let
args = {
nixpkgs = pkgs;
username = "patrick";
dotnet = pkgs.dotnet-sdk_8;
mbsync = import ./mbsync.nix {inherit pkgs;};
secretsPath = "/home/patrick/.secrets/";
machinename = "capybara";
};
in [
./home-manager/capybara-config.nix
home-manager.nixosModules.home-manager
{
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.users.Patrick = import ./home.nix { nixpkgs = pkgs; };
home-manager.users.patrick = recursiveMerge [(import ./home-manager/linux.nix args) (import ./home-manager/home.nix args)];
}
];
};
earthworm = let
system = "aarch64-linux";
in let
pkgs = import nixpkgs {inherit system config overlays;};
in
nixpkgs.lib.nixosSystem {
inherit system;
modules = let
args = {
nixpkgs = pkgs;
username = "patrick";
dotnet = pkgs.dotnet-sdk_8;
mbsync = import ./mbsync.nix {inherit pkgs;};
secretsPath = "/home/patrick/.secrets/";
machinename = "earthworm";
};
in [
./home-manager/earthworm-config.nix
apple-silicon.nixosModules.default
home-manager.nixosModules.home-manager
{
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.users.patrick = recursiveMerge [(import ./home-manager/linux.nix args) (import ./home-manager/home.nix args)];
}
];
};
};
darwinConfigurations = let
system = "aarch64-darwin";
in let
pkgs = import nixpkgs {inherit system config overlays;};
in {
nixpkgs = pkgs;
patrick = darwin.lib.darwinSystem {
system = system;
modules = let
args = {
nixpkgs = pkgs;
username = "patrick";
dotnet = pkgs.dotnet-sdk_8;
whisper = whisper.packages.${system};
mbsync = import ./mbsync.nix {inherit pkgs;};
secretsPath = "/Users/patrick/.secrets/";
machinename = "darwin";
};
in [
./darwin-configuration.nix
home-manager.darwinModules.home-manager
{
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.users.patrick = recursiveMerge [(import ./home-manager/darwin.nix args) (import ./home-manager/home.nix args)];
}
];
};
};
checks = let
fmt-check = system: let
pkgs = import nixpkgs {inherit config system;};
in
pkgs.stdenvNoCC.mkDerivation {
name = "fmt-check";
src = ./.;
nativeBuildInputs = [pkgs.alejandra pkgs.shellcheck pkgs.shfmt pkgs.stylua];
checkPhase = ''
find . -type f -name '*.sh' | xargs shfmt -d -s -i 2 -ci
alejandra -c .
find . -type f -name '*.sh' -exec shellcheck -x {} \;
find . -type f -name '*.lua' -exec stylua --check {} \;
'';
installPhase = "mkdir $out";
dontBuild = true;
doCheck = true;
};
in
builtins.listToAttrs (builtins.map (system: {
name = system;
value = {fmt-check = fmt-check system;};
})
systems);
devShells = let
devShell = system: (
let
pkgs = import nixpkgs {inherit config system;};
in {
default = pkgs.mkShell {
buildInputs = [pkgs.alejandra pkgs.shellcheck pkgs.stylua];
};
}
);
in
builtins.listToAttrs (builtins.map (system: {
name = system;
value = devShell system;
})
systems);
};
}

43
hardware/capybara.nix Normal file
View File

@@ -0,0 +1,43 @@
# Do not modify this file! It was generated by nixos-generate-config
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{
config,
lib,
pkgs,
modulesPath,
...
}: {
imports = [
(modulesPath + "/installer/scan/not-detected.nix")
];
boot.initrd.availableKernelModules = ["nvme" "xhci_pci" "ahci" "usb_storage" "usbhid" "sd_mod"];
boot.initrd.kernelModules = [];
boot.kernelModules = ["kvm-amd"];
boot.extraModulePackages = [];
fileSystems."/" = {
device = "/dev/disk/by-uuid/63c5394d-55ce-48a9-8d7c-2b68f3b5f834";
fsType = "ext4";
};
fileSystems."/boot" = {
device = "/dev/disk/by-uuid/9248-31C6";
fsType = "vfat";
options = ["fmask=0022" "dmask=0022"];
};
swapDevices = [];
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
# (the default) this is the recommended approach. When using systemd-networkd it's
# still possible to use this option, but it's recommended to use it in conjunction
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
networking.useDHCP = lib.mkDefault true;
# networking.interfaces.eno1.useDHCP = lib.mkDefault true;
# networking.interfaces.wlp9s0.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}

41
hardware/earthworm.nix Normal file
View File

@@ -0,0 +1,41 @@
# Do not modify this file! It was generated by nixos-generate-config
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{
config,
lib,
pkgs,
modulesPath,
...
}: {
imports = [
(modulesPath + "/installer/scan/not-detected.nix")
];
boot.initrd.availableKernelModules = ["usb_storage" "sdhci_pci"];
boot.initrd.kernelModules = [];
boot.kernelModules = [];
boot.extraModulePackages = [];
fileSystems."/" = {
device = "/dev/disk/by-uuid/49068d2d-13e6-43b5-a740-f23db6fbd6b2";
fsType = "ext4";
};
fileSystems."/boot" = {
device = "/dev/disk/by-uuid/43ED-0FE7";
fsType = "vfat";
};
swapDevices = [];
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
# (the default) this is the recommended approach. When using systemd-networkd it's
# still possible to use this option, but it's recommended to use it in conjunction
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
networking.useDHCP = lib.mkDefault true;
# networking.interfaces.wlan0.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "aarch64-linux";
powerManagement.cpuFreqGovernor = lib.mkDefault "ondemand";
}

View File

@@ -0,0 +1,88 @@
{
pkgs,
config,
...
}: {
nixpkgs.config.allowUnfree = true;
imports = [
../hardware/capybara.nix
];
hardware.graphics = {
enable = true;
enable32Bit = true;
};
security.rtkit.enable = true;
services.pipewire = {
enable = true;
alsa.enable = true;
alsa.support32Bit = true;
pulse.enable = true;
};
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
boot.loader.grub.useOSProber = true;
boot.kernelParams = [
"video=DP-1:2560x1440@144"
"video=HDMI-A-1:1920x1080@144"
];
boot.extraModulePackages = [config.boot.kernelPackages.rtl8821au];
networking = {
hostName = "capybara";
networkmanager.enable = true;
};
time.timeZone = "Europe/London";
programs.sway.enable = true;
programs.zsh.enable = true;
# TODO: work out secrets management for password, then set mutableUsers to false
users.mutableUsers = true;
users.users.patrick = {
isNormalUser = true;
extraGroups = ["wheel" "networkManager"];
};
services.syncthing = {
enable = true;
user = "patrick";
dataDir = "/home/patrick/syncthing";
};
environment.systemPackages = [
pkgs.git
pkgs.vim
pkgs.wget
pkgs.tmux
pkgs.home-manager
pkgs.firefox
];
environment.loginShellInit = ''
[[ "$(tty)" == /dev/tty1 ]] && sway --unsupported-gpu
'';
services.openssh.enable = true;
system.stateVersion = "23.11";
nix.settings.experimental-features = ["nix-command" "flakes" "ca-derivations"];
nix.gc.automatic = true;
nix.extraOptions = ''
auto-optimise-store = true
max-jobs = auto
keep-outputs = true
keep-derivations = true
'';
programs.steam = {
enable = true;
remotePlay.openFirewall = true;
};
}

43
home-manager/darwin.nix Normal file
View File

@@ -0,0 +1,43 @@
{
nixpkgs,
username,
dotnet,
whisper,
...
}: {
imports = [./rider];
rider = {
enable = true;
username = username;
dotnet = dotnet;
};
home.packages = [
whisper.default
whisper.normalize
# "Damaged and can't be opened"
#nixpkgs.bcompare
#nixpkgs.gdb
#nixpkgs.handbrake
];
programs.vscode = {
userSettings = {
"lean.leanpkgPath" = "/Users/${username}/.elan/toolchains/stable/bin/leanpkg";
"lean.executablePath" = "/Users/${username}/.elan/toolchains/stable/bin/lean";
"lean.memoryLimit" = 16384;
"latex-workshop.view.pdf.viewer" = "tab";
"lean4.toolchainPath" = "/Users/${username}/.elan/toolchains/leanprover--lean4---nightly-2022-12-16";
};
};
programs.zsh = {
shellAliases = {
cmake = "cmake -DCMAKE_MAKE_PROGRAM=${nixpkgs.gnumake}/bin/make -DCMAKE_AR=${nixpkgs.darwin.cctools}/bin/ar -DCMAKE_RANLIB=${nixpkgs.darwin.cctools}/bin/ranlib -DGMP_INCLUDE_DIR=${nixpkgs.gmp.dev}/include/ -DGMP_LIBRARIES=${nixpkgs.gmp}/lib/libgmp.10.dylib";
ar = "${nixpkgs.darwin.cctools}/bin/ar";
};
};
home.file.".ssh/config".source = ./ssh.config;
}

View File

@@ -0,0 +1,81 @@
{pkgs, ...}: {
imports = [
../hardware/earthworm.nix
];
hardware.asahi.peripheralFirmwareDirectory = ./../firmware;
hardware.asahi = {
useExperimentalGPUDriver = true;
experimentalGPUInstallMode = "overlay";
setupAsahiSound = true;
withRust = true;
};
hardware.graphics.enable = true;
programs.light.enable = true;
services.actkbd = {
enable = true;
bindings = [
{
keys = [225];
events = ["key"];
command = "${pkgs.light}/bin/light -A 10";
}
{
keys = [224];
events = ["key"];
command = "${pkgs.light}/bin/light -U 10";
}
];
};
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = false;
boot.extraModprobeConfig = ''
options hid_apple iso_layout=0
'';
networking = {
hostName = "earthworm";
networkmanager.enable = true;
wireless.iwd = {
enable = true;
settings.General.EnableNetworkConfiguration = true;
};
};
time.timeZone = "Europe/London";
programs.sway.enable = true;
programs.zsh.enable = true;
# TODO: work out secrets management for password, then set mutableUsers to false
users.mutableUsers = true;
users.users.patrick = {
isNormalUser = true;
extraGroups = ["wheel" "networkManager"];
};
environment.systemPackages = [
pkgs.vim
pkgs.wget
pkgs.mesa-asahi-edge
];
environment.loginShellInit = ''
[[ "$(tty)" == /dev/tty1 ]] && export WLR_RENDER_NO_EXPLICIT_SYNC=1 && sway
'';
services.openssh.enable = true;
system.stateVersion = "23.11";
nix.settings.experimental-features = ["nix-command" "flakes" "ca-derivations"];
nix.gc.automatic = true;
nix.extraOptions = ''
auto-optimise-store = true
max-jobs = auto
keep-outputs = true
keep-derivations = true
'';
}

425
home-manager/home.nix Normal file
View File

@@ -0,0 +1,425 @@
{
nixpkgs,
machinename,
username,
mbsync,
dotnet,
secretsPath,
...
}: {
# Let Home Manager install and manage itself.
programs.home-manager.enable = true;
# Home Manager needs a bit of information about you and the
# paths it should manage.
home.username = username;
# This value determines the Home Manager release that your
# configuration is compatible with. This helps avoid breakage
# when a new Home Manager release introduces backwards
# incompatible changes.
#
# You can update Home Manager without changing this value. See
# the Home Manager release notes for a list of state version
# changes in each release.
home.stateVersion = "22.05";
fonts.fontconfig.enable = true;
imports = [
# ./modules/agda.nix
# ./modules/emacs.nix
./modules/direnv.nix
./modules/tmux.nix
./modules/zsh.nix
./modules/ripgrep.nix
./modules/alacritty.nix
./modules/rust.nix
(import ./modules/mail.nix
{
inherit mbsync secretsPath;
pkgs = nixpkgs;
})
];
programs.fzf = {
enable = true;
};
programs.git = {
package = nixpkgs.gitAndTools.gitFull;
enable = true;
userName = "Smaug123";
userEmail = "3138005+Smaug123@users.noreply.github.com";
aliases = {
co = "checkout";
st = "status";
};
difftastic.enable = true;
extraConfig = {
commit.gpgsign = true;
gpg.program = "${nixpkgs.gnupg}/bin/gpg";
user.signingkey =
if machinename == "darwin"
then "7C97D679CF3BC4F9"
else if machinename == "earthworm"
then "6E8B1BA1148AD7C9"
else if machinename == "capybara"
then "AE90453E879DBCFA"
else throw "unrecognised machine name!";
core = {
autocrlf = "input";
};
rerere = {
enabled = true;
};
push = {
default = "current";
autoSetupRemote = true;
};
pull = {
rebase = false;
};
init = {
defaultBranch = "main";
};
advice = {
addIgnoredFile = false;
};
"filter \"lfs\"" = {
clean = "${nixpkgs.git-lfs} clean -- %f";
smudge = "${nixpkgs.git-lfs}/bin/git-lfs smudge --skip -- %f";
process = "${nixpkgs.git-lfs}/bin/git-lfs filter-process";
required = true;
};
pull = {
twohead = "ort";
};
merge = {
conflictStyle = "diff3";
};
diff = {
colorMoved = "default";
};
"protocol.file" = {
allow = "always";
};
};
};
programs.vscode = {
enable = true;
enableExtensionUpdateCheck = true;
enableUpdateCheck = true;
package = nixpkgs.vscode;
extensions = import ./vscode-extensions.nix {pkgs = nixpkgs;};
userSettings = {
workbench.colorTheme = "Default";
"files.Exclude" = {
"**/.git" = true;
"**/.DS_Store" = true;
"**/Thumbs.db" = true;
"**/*.olean" = true;
"**/result" = true;
};
"git.path" = "${nixpkgs.git}/bin/git";
"update.mode" = "none";
"explorer.confirmDelete" = false;
};
};
services.syncthing = {
enable = true;
};
programs.neovim = let
debugPyEnv = nixpkgs.python3.withPackages (ps: [ps.debugpy]);
in {
enable = true;
plugins = [
{
plugin = nixpkgs.vimPlugins.nvim-web-devicons;
}
{
plugin = nixpkgs.vimPlugins.mini-nvim;
}
{
plugin = nixpkgs.vimPlugins.satellite-nvim;
}
{
plugin = nixpkgs.vimPlugins.nvim-lightbulb;
type = "lua";
config = builtins.readFile ./nvim/nvim-lightbulb.lua;
}
{
plugin = nixpkgs.vimPlugins.lean-nvim;
type = "lua";
config = builtins.readFile ./nvim/lean.lua;
}
{
plugin = nixpkgs.vimPlugins.which-key-nvim;
type = "lua";
config = builtins.readFile ./nvim/which-key.lua;
}
{
plugin = nixpkgs.vimPlugins.tokyonight-nvim;
config = builtins.readFile ./nvim/tokyonight.lua;
type = "lua";
}
{
plugin = nixpkgs.vimPlugins.nvim-treesitter.withAllGrammars;
config = builtins.readFile ./nvim/treesitter.lua;
type = "lua";
}
{
plugin = nixpkgs.vimPlugins.nvim-lspconfig;
config = builtins.readFile ./nvim/lspconfig.lua;
type = "lua";
}
nixpkgs.vimPlugins.telescope-nvim
nixpkgs.vimPlugins.tagbar
nixpkgs.vimPlugins.fzf-vim
{
plugin = nixpkgs.vimPlugins.roslyn-nvim;
config = builtins.readFile ./nvim/roslyn-nvim.lua;
type = "lua";
}
{
plugin = let
name = "coq.artifacts";
rev = "9c5067a471322c6bb866545e88e5b28c82511865";
in
nixpkgs.vimUtils.buildVimPlugin {
name = name;
src = nixpkgs.fetchFromGitHub {
owner = "ms-jpq";
repo = name;
rev = rev;
hash = "sha256-BHm7U3pINtYamY7m26I4lQee7ccJ6AcHmYx7j1MRFDA=";
};
};
}
{
plugin = let
name = "venv-selector.nvim";
rev = "2ad34f36d498ff5193ea10f79c87688bd5284172";
in
nixpkgs.vimUtils.buildVimPlugin {
name = name;
src = nixpkgs.fetchFromGitHub {
owner = "linux-cultist";
repo = name;
rev = rev;
hash = "sha256-aOga7kJ1y3T2vDyYFl/XHOwk35ZqeUcfPUk+Pr1mIeo=";
};
};
config = builtins.readFile ./nvim/venv-selector.lua;
type = "lua";
}
{
plugin = nixpkgs.vimPlugins.Ionide-vim;
type = "lua";
config = builtins.readFile ./nvim/ionide-vim.lua;
}
{
plugin = nixpkgs.vimPlugins.chadtree;
config = builtins.readFile ./nvim/chadtree.lua;
type = "lua";
}
{
plugin = nixpkgs.vimPlugins.coq_nvim;
config = ''let g:coq_settings = { 'auto_start': 'shut-up', 'xdg': v:true }'';
}
{
plugin = nixpkgs.vimPlugins.rustaceanvim;
}
{
plugin = nixpkgs.vimPlugins.LanguageClient-neovim;
}
{
plugin = nixpkgs.vimPlugins.nvim-dap;
config = builtins.readFile ./nvim/nvim-dap.lua;
type = "lua";
}
{
plugin = nixpkgs.vimPlugins.nvim-dap-python;
config = builtins.replaceStrings ["%PYTHONENV%"] ["${debugPyEnv}"] (builtins.readFile ./nvim/nvim-dap-python.lua);
type = "lua";
}
];
viAlias = true;
vimAlias = true;
vimdiffAlias = true;
withPython3 = true;
extraPython3Packages = ps: [
ps.pip
ps.pynvim
ps.pynvim-pp
ps.pyyaml
ps.std2
];
withRuby = true;
extraLuaConfig = builtins.readFile ./nvim/build-utils.lua + "\n" + (builtins.replaceStrings ["_CURL_"] ["${nixpkgs.curl}/bin/curl"] (builtins.readFile ./nvim/dotnet.lua)) + "\n" + builtins.readFile ./nvim/init.lua + "\n" + builtins.readFile ./nvim/python.lua;
};
home.packages =
[
nixpkgs.jq
nixpkgs.difftastic
nixpkgs.syncthing
nixpkgs.nodePackages_latest.dockerfile-language-server-nodejs
nixpkgs.nodePackages_latest.bash-language-server
nixpkgs.nodePackages_latest.vscode-json-languageserver
nixpkgs.nodePackages_latest.vscode-langservers-extracted
nixpkgs.hadolint
nixpkgs.yaml-language-server
nixpkgs.csharp-ls
nixpkgs.netcoredbg
nixpkgs.nil
nixpkgs.fsautocomplete
nixpkgs.wget
nixpkgs.yt-dlp
nixpkgs.cmake
nixpkgs.gnumake
nixpkgs.gcc
nixpkgs.lldb
nixpkgs.hledger
nixpkgs.hledger-web
dotnet
nixpkgs.elan
nixpkgs.coreutils-prefixed
nixpkgs.shellcheck
nixpkgs.universal-ctags
nixpkgs.asciinema
nixpkgs.git-lfs
nixpkgs.imagemagick
nixpkgs.nixpkgs-fmt
nixpkgs.lnav
nixpkgs.age
nixpkgs.nodejs
nixpkgs.pyright
nixpkgs.woodpecker-agent
nixpkgs.lynx
nixpkgs.alejandra
nixpkgs.ffmpeg
nixpkgs.bat
nixpkgs.pandoc
nixpkgs.fd
nixpkgs.sumneko-lua-language-server
nixpkgs.gnupg
nixpkgs.gh
nixpkgs.clang-tools
nixpkgs.deno
nixpkgs.yazi
nixpkgs.font-awesome
nixpkgs.gopls
nixpkgs.go
]
++ (
if nixpkgs.stdenv.isLinux
then [
nixpkgs.protonmail-bridge
nixpkgs.pinentry
nixpkgs.signal-desktop
nixpkgs.keepassxc
]
else []
)
++ (
if machinename == "capybara"
then [
nixpkgs.steam-run
nixpkgs.discord
nixpkgs.anki-bin
]
else []
);
home.file.".ideavimrc".source = ./ideavimrc;
home.file.".config/yt-dlp/config".source = ./youtube-dl.conf;
programs.firefox = {
enable = true;
package = nixpkgs.firefox-wayland;
profiles = {
patrick = {
isDefault = true;
name = "patrick";
search = {
default = "Google";
force = true;
};
settings = {
# see https://github.com/TLATER/dotfiles/blob/b39af91fbd13d338559a05d69f56c5a97f8c905d/home-config/config/graphical-applications/firefox.nix
# see https://www.ghacks.net/2015/08/18/a-comprehensive-list-of-firefox-privacy-and-security-settings/
"browser.search.isUS" = false;
"browser.search.region" = "GB";
"gfx.webrender.all" = true; # enable GPU acceleration
"media.ffmpeg.vaapi.enabled" = true;
"widget.dmabuf.force-enabled" = true;
"privacy.webrtc.legacyGlobalIndicator" = false;
"app.shield.optoutstudies.enabled" = false;
"app.update.enabled" = false;
"app.update.auto" = false;
"app.update.silent" = false;
"app.update.service.enabled" = false;
"app.update.staging.enabled" = false;
"browser.discovery.enabled" = false;
"browser.laterrun.enabled" = false;
"browser.shell.checkDefaultBrowser" = false;
"browser.rights.3.shown" = true;
"browser.search.update" = false;
"extensions.update.enabled" = false;
"extensions.update.autoUpdateDefault" = false;
"extensions.getAddons.cache.enabled" = false;
"dom.ipc.plugins.reportCrashURL" = false;
"extensions.webservice.discoverURL" = "http://127.0.0.1";
"toolkit.telemetry.unified" = false;
"toolkit.telemetry.unifiedIsOptIn" = true;
"toolkit.telemetry.enabled" = false;
"toolkit.telemetry.server" = "";
"toolkit.telemetry.archive.enabled" = false;
"lightweightThemes.update.enabled" = false;
"startup.homepage_welcome_url" = "";
"startup.homepage_welcome_url.additional" = "";
"startup.homepage_override_url" = "";
"datareporting.healthreport.uploadEnabled" = false;
"datareporting.healthreport.documentServerURI" = "";
"datareporting.healthreport.service.enabled" = false;
"datareporting.healthreport.about.reportUrl" = "data:text/plain,";
"toolkit.telemetry.cachedClientID" = "";
"browser.selfsupport.url" = "";
"browser.selfsupport.enabled" = false;
"experiments.enabled" = false;
"experiments.supported" = false;
"experiments.activeExperiment" = false;
"experiments.manifest.uri" = "";
"network.allow-experiments" = false;
"breakpad.reportURL" = "";
"browser.tabs.crashReporting.sendReport" = false;
"browser.newtab.preload" = false;
"browser.newtabpage.directory.ping" = "data:text/plain,";
"browser.newtabpage.directory.source" = "data:text/plain,";
"browser.newtabpage.enabled" = false;
"browser.newtabpage.enhanced" = false;
"browser.newtabpage.introShown" = true;
"browser.aboutHomeSnippets.updateUrl" = "https://127.0.0.1";
"extensions.pocket.enabled" = false;
"extensions.pocket.api" = "";
"extensions.pocket.site" = "";
"extensions.pocket.oAuthConsumerKey" = "";
"social.whitelist" = "";
"social.toast-notifications.enabled" = false;
"social.shareDirectory" = "";
"social.remote-install.enabled" = false;
"social.directories" = "";
"social.share.activationPanelEnabled" = false;
"social.enabled" = false;
"dom.flyweb.enabled" = false;
"services.sync.enabled" = false;
};
};
};
};
}

211
home-manager/linux.nix Normal file
View File

@@ -0,0 +1,211 @@
{
nixpkgs,
username,
dotnet,
...
}: {
home.packages = [nixpkgs.wl-clipboard nixpkgs.jetbrains.rider];
nixpkgs.config.firefox = {
speechSynthesisSupport = true;
};
wayland.windowManager.sway = {
enable = true;
config = {
focus = {followMouse = false;};
modifier = "Mod4";
terminal = "alacritty";
window = {border = 5;};
bars = [
{command = "${nixpkgs.waybar}/bin/waybar";}
];
};
extraConfig = builtins.readFile ./sway.conf;
};
programs.waybar = {
enable = true;
settings = {
"bar-0" = {
position = "bottom";
layer = "top";
height = 34;
spacing = 8;
modules-left = ["sway/workspaces" "sway/mode" "sway/scratchpad" "custom/media"];
modules-center = ["sway/window"];
modules-right = ["mpd" "idle_inhibitor" "pulseaudio" "network" "power-profiles-daemon" "cpu" "memory" "temperature" "backlight" "keyboard-state" "sway/language" "battery" "battery#bat2" "clock" "tray" "custom/power"];
"keyboard-state" = {
"numlock" = true;
"capslock" = true;
"format" = "{name} {icon}";
"format-icons" = {
"locked" = "";
"unlocked" = "";
};
};
"sway/mode" = {
"format" = "<span style=\"italic\">{}</span>";
};
"sway/scratchpad" = {
"format" = "{icon} {count}";
"show-empty" = false;
"format-icons" = ["" ""];
"tooltip" = true;
"tooltip-format" = "{app}: {title}";
};
"mpd" = {
"format" = "{stateIcon} {consumeIcon}{randomIcon}{repeatIcon}{singleIcon}{artist} - {album} - {title} ({elapsedTime:%M:%S}/{totalTime:%M:%S}) {songPosition}|{queueLength} {volume}% ";
"format-disconnected" = "Disconnected ";
"format-stopped" = "{consumeIcon}{randomIcon}{repeatIcon}{singleIcon}Stopped ";
"unknown-tag" = "N/A";
"interval" = 5;
"consume-icons" = {
"on" = " ";
};
"random-icons" = {
"off" = "<span color=\"#f53c3c\"></span> ";
"on" = " ";
};
"repeat-icons" = {
"on" = " ";
};
"single-icons" = {
"on" = "1 ";
};
"state-icons" = {
"paused" = "";
"playing" = "";
};
"tooltip-format" = "MPD (connected)";
"tooltip-format-disconnected" = "MPD (disconnected)";
};
"idle_inhibitor" = {
"format" = "{icon}";
"format-icons" = {
"activated" = "";
"deactivated" = "";
};
};
"tray" = {
"spacing" = 20;
};
"clock" = {
"tooltip-format" = "<big>{:%Y %B}</big>\n<tt><small>{calendar}</small></tt>";
"format" = "{:%Y-%m-%d %H:%M:%S}";
"interval" = 1;
};
"cpu" = {
"format" = "{usage}% ";
"tooltip" = false;
};
"memory" = {
"format" = "{}% ";
};
"temperature" = {
"critical-threshold" = 80;
"format" = "{temperatureC}°C {icon}";
"format-icons" = ["" "" ""];
};
"backlight" = {
"format" = "{percent}% {icon}";
"format-icons" = ["" "" "" "" "" "" "" "" ""];
};
"battery" = {
"states" = {
"warning" = 30;
"critical" = 15;
};
"format" = "{capacity}% {icon}";
"format-full" = "{capacity}% {icon}";
"format-charging" = "{capacity}% ";
"format-plugged" = "{capacity}% ";
"format-alt" = "{time} {icon}";
"format-icons" = ["" "" "" "" ""];
};
"battery#bat2" = {
"bat" = "BAT2";
};
"power-profiles-daemon" = {
"format" = "{icon}";
"tooltip-format" = "Power profile: {profile}\nDriver: {driver}";
"tooltip" = true;
"format-icons" = {
"default" = "";
"performance" = "";
"balanced" = "";
"power-saver" = "";
};
};
"network" = {
"format-wifi" = "{essid} ({signalStrength}%) ";
"format-ethernet" = "{bandwidthDownBytes}/{bandwidthUpBytes} ";
"interval" = 5;
"tooltip-format" = "{ifname} via {gwaddr} ";
"format-linked" = "{ifname} (No IP) ";
"format-disconnected" = "Disconnected ";
"format-alt" = "{ifname}: {ipaddr}/{cidr}";
};
"pulseaudio" = {
"format" = "{volume}% {icon} {format_source}";
"format-bluetooth" = "{volume}% {icon} {format_source}";
"format-bluetooth-muted" = " {icon} {format_source}";
"format-muted" = " {format_source}";
"format-source" = "{volume}% ";
"format-source-muted" = "";
"format-icons" = {
"headphone" = "";
"hands-free" = "";
"headset" = "";
"phone" = "";
"portable" = "";
"car" = "";
"default" = ["" "" ""];
};
"on-click" = "${nixpkgs.pavucontrol}/bin/pavucontrol";
};
"custom/media" = {
"format" = "{icon} {text}";
"return-type" = "json";
"max-length" = 40;
"format-icons" = {
"spotify" = "";
"default" = "🎜";
};
"escape" = true;
"exec" = let
python = nixpkgs.python312.withPackages (ppkgs: [ppkgs.pygobject3]);
in "${python}/bin/python ${./modules/waybar/mediaplayer.py} 2> /dev/null";
};
"custom/power" = {
"format" = " ";
"tooltip" = false;
"menu" = "on-click";
"menu-file" = ./modules/waybar/power_menu.xml;
"menu-actions" = {
"shutdown" = "shutdown";
"reboot" = "reboot";
"suspend" = "systemctl suspend";
"hibernate" = "systemctl hibernate";
};
};
};
};
style = ''
* {
font-family: FontAwesome, Roboto, Helvetica, Arial, sans-serif;
font-size: 13px;
}
'';
};
services.gpg-agent = {
enable = nixpkgs.stdenv.isLinux;
pinentryPackage = nixpkgs.pinentry-curses;
};
services.swayidle = {enable = true;};
}

View File

@@ -0,0 +1,7 @@
{pkgs, ...}: {
imports = [./emacs.nix];
home.packages = [
pkgs.agda
];
}

View File

@@ -0,0 +1,18 @@
{pkgs, ...}: {
programs.alacritty = {
enable = true;
settings = {
font = {
normal = {
family = "FiraCode Nerd Font Mono";
};
};
terminal = {shell = "${pkgs.zsh}/bin/zsh";};
};
};
home.packages = [
pkgs.alacritty
(pkgs.nerdfonts.override {fonts = ["FiraCode" "DroidSansMono"];})
];
}

View File

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

View File

@@ -0,0 +1,14 @@
{pkgs, ...}: {
programs.emacs = {
enable = true;
package = pkgs.emacs;
extraPackages = epkgs: [epkgs.evil];
extraConfig = ''
(load-file (let ((coding-system-for-read 'utf-8))
(shell-command-to-string "agda-mode locate")))
(require 'evil)
(evil-mode 1)
(evil-set-undo-system 'undo-redo)
'';
};
}

View File

@@ -0,0 +1,182 @@
{
pkgs,
mbsync,
secretsPath,
...
}: let
deobfuscate = str: let
lib = pkgs.lib;
base64Table =
builtins.listToAttrs
(lib.imap0 (i: c: lib.nameValuePair c i)
(lib.stringToCharacters "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"));
# Generated using python3:
# print(''.join([ chr(n) for n in range(1, 256) ]), file=open('ascii', 'w'))
ascii = builtins.readFile ./mail/ascii;
# List of base-64 numbers
numbers64 = map (c: base64Table.${c}) (lib.lists.reverseList (lib.stringToCharacters str));
# List of base-256 numbers
numbers256 = lib.concatLists (lib.genList (
i: let
v =
lib.foldl'
(acc: el: acc * 64 + el)
0
(lib.sublist (i * 4) 4 numbers64);
in [
(lib.mod (v / 256 / 256) 256)
(lib.mod (v / 256) 256)
(lib.mod v 256)
]
) (lib.length numbers64 / 4));
in
# Converts base-256 numbers to ascii
lib.concatMapStrings (
n:
# Can't represent the null byte in Nix..
let
result = lib.substring (n - 1) 1 ascii;
in
if result == " "
then ""
else result
)
numbers256;
in {
accounts.email.accounts."Gmail" = let
address = (deobfuscate "AFTN0cWdh12c") + "gmail.com";
in {
notmuch.enable = true;
neomutt = {
enable = true;
};
address = address;
flavor = "gmail.com";
mbsync = {
enable = true;
create = "maildir";
extraConfig.account = {
AuthMechs = "XOAUTH2";
};
};
userName = address;
# This is accompanied by a developer application at Google:
# https://console.cloud.google.com/apis/credentials
# Create an OAuth 2.0 Client ID with type `Desktop`.
# The Google application needs the https://mail.google.com scope; mine has
# an authorized domain `google.com` but I don't know if that's required.
# Enter the client ID and client secret into a two-line text file
# named gmail-client-app.txt immediately next to the intended destination
# secret file (the arg to mutt-oauth2.py in the invocation):
# so here it would be /path/to/gmail-client-app.txt .
# Run `./mail/mutt-oauth2.py /path/to/secret --authorize --verbose` once manually,
# and that will populate /path/to/secret.
# I've left it unencrypted here; the original uses GPG to store it encrypted at rest.
passwordCommand = ''${pkgs.python3}/bin/python ${./mail/mutt-oauth2.py} ${secretsPath}/gmail.txt 2>/tmp/gmail-passcmd.2.txt'';
realName = "Patrick Stevens";
};
accounts.email.accounts."BTInternet" = let
address = (deobfuscate "z5WZ2VGdz5yajlmc0FGc") + "@btinternet.com";
in {
notmuch.enable = true;
neomutt = {
enable = true;
};
address = address;
imap = {
host = "mail.btinternet.com";
port = 993;
tls = {
enable = true;
useStartTls = false;
};
};
mbsync = {
enable = true;
create = "maildir";
};
realName = "Patrick Stevens";
passwordCommand = "${pkgs.coreutils}/bin/cat ${secretsPath}/btinternet.txt";
smtp = {
host = "mail.btinternet.com";
port = 465;
tls = {
enable = true;
useStartTls = false;
};
};
userName = address;
primary = true;
};
accounts.email.accounts."Proton" = let
address = deobfuscate "gAya15ybj5ycuVmdlR3crNWayRXYwB0ajlmc0FGc";
in {
notmuch.enable = true;
neomutt = {
enable = true;
};
address = address;
# I use the ProtonMail bridge, which sits at localhost.
imap = {
host = "127.0.0.1";
port = 1143; # 8125; if using hydroxide
tls = {
enable = false;
useStartTls = true;
};
};
mbsync = {
enable = true;
create = "maildir";
extraConfig.account = {
# Because ProtonMail Bridge is localhost, we don't
# care that we can only auth to it in plain text.
AuthMechs = "LOGIN";
};
};
realName = "Patrick Stevens";
passwordCommand =
# I store the ProtonMail Bridge password here.
# Extracting it from a keychain would be better.
"${pkgs.coreutils}/bin/cat ${secretsPath}/proton.txt";
smtp = {
host = "127.0.0.1";
port = 1025; # 8126; if using hydroxide
tls = {enable = false;};
};
userName =
if pkgs.stdenv.isLinux
then builtins.head (pkgs.lib.strings.splitString "@" address)
else address;
};
programs.mbsync = {
enable = true;
extraConfig = ''
CopyArrivalDate yes
'';
package = mbsync;
};
programs.neomutt = {
enable = true;
extraConfig = ''
set use_threads=threads sort=last-date sort_aux=date
'';
sidebar.enable = true;
vimKeys = true;
};
programs.notmuch.enable = true;
home.file.".mailcap".source = ./mail/mailcap;
home.packages = [
pkgs.notmuch
pkgs.lynx
];
}

View File

@@ -0,0 +1,2 @@


View File

@@ -0,0 +1,3 @@
text/html; lynx -force_html %s; needsterminal
image/png; qlmanage -p %s
image/jpeg; qlmanage -p %s

View File

@@ -0,0 +1,402 @@
#!/usr/bin/env python3
#
# Mutt OAuth2 token management script, version 2020-08-07
# Written against python 3.7.3, not tried with earlier python versions.
#
# Copyright (C) 2020 Alexander Perlis
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
# Subsequently adapted by Patrick Stevens, who hacked it up to read gmail
# client app configuration from a file called gmail-client-app.txt that
# lives next to the secret file.
'''Mutt OAuth2 token management'''
import sys
import json
import argparse
import urllib.error
import urllib.parse
import urllib.request
import imaplib
import poplib
import smtplib
import base64
import secrets
import hashlib
import time
from datetime import timedelta, datetime
from pathlib import Path
import socket
import http.server
import subprocess
ap = argparse.ArgumentParser(epilog='''
This script obtains and prints a valid OAuth2 access token. State is maintained in an
encrypted TOKENFILE. Run with "--verbose --authorize" to get started or whenever all
tokens have expired, optionally with "--authflow" to override the default authorization
flow. To truly start over from scratch, first delete TOKENFILE. Use "--verbose --test"
to test the IMAP/POP/SMTP endpoints.
''')
ap.add_argument('-v', '--verbose', action='store_true', help='increase verbosity')
ap.add_argument('-d', '--debug', action='store_true', help='enable debug output')
ap.add_argument('tokenfile', help='persistent token storage')
ap.add_argument('-a', '--authorize', action='store_true', help='manually authorize new tokens')
ap.add_argument('--authflow', help='authcode | localhostauthcode | devicecode')
ap.add_argument('-t', '--test', action='store_true', help='test IMAP/POP/SMTP endpoints')
args = ap.parse_args()
token = {}
path = Path(args.tokenfile)
if path.exists():
if 0o777 & path.stat().st_mode != 0o600:
sys.exit('Token file has unsafe mode. Suggest deleting and starting over.')
try:
token = json.loads(path.read_bytes())
except subprocess.CalledProcessError:
sys.exit('Difficulty decrypting token file. Is your decryption agent primed for '
'non-interactive usage, or an appropriate environment variable such as '
'GPG_TTY set to allow interactive agent usage from inside a pipe?')
client_id, client_secret = (path.parent / "gmail-client-app.txt").read_text().strip().split('\n')
registrations = {
'google': {
'authorize_endpoint': 'https://accounts.google.com/o/oauth2/auth',
'devicecode_endpoint': 'https://oauth2.googleapis.com/device/code',
'token_endpoint': 'https://accounts.google.com/o/oauth2/token',
'redirect_uri': 'urn:ietf:wg:oauth:2.0:oob',
'imap_endpoint': 'imap.gmail.com',
'pop_endpoint': 'pop.gmail.com',
'smtp_endpoint': 'smtp.gmail.com',
'sasl_method': 'OAUTHBEARER',
'scope': 'https://mail.google.com/',
'client_id': client_id,
'client_secret': client_secret,
},
}
def writetokenfile():
'''Writes global token dictionary into token file.'''
if not path.exists():
path.touch(mode=0o600)
if 0o777 & path.stat().st_mode != 0o600:
sys.exit('Token file has unsafe mode. Suggest deleting and starting over.')
path.write_bytes(json.dumps(token).encode('utf-8'))
if args.debug:
print('Obtained from token file:', json.dumps(token))
if not token:
if not args.authorize:
sys.exit('You must run script with "--authorize" at least once.')
print('Available app and endpoint registrations:', *registrations)
token['registration'] = input('OAuth2 registration: ')
token['authflow'] = input('Preferred OAuth2 flow ("authcode" or "localhostauthcode" '
'or "devicecode"): ')
token['email'] = input('Account e-mail address: ')
token['access_token'] = ''
token['access_token_expiration'] = ''
token['refresh_token'] = ''
writetokenfile()
if token['registration'] not in registrations:
sys.exit(f'ERROR: Unknown registration "{token["registration"]}". Delete token file '
f'and start over.')
registration = registrations[token['registration']]
authflow = token['authflow']
if args.authflow:
authflow = args.authflow
baseparams = {'client_id': registration['client_id']}
# Microsoft uses 'tenant' but Google does not
if 'tenant' in registration:
baseparams['tenant'] = registration['tenant']
def access_token_valid():
'''Returns True when stored access token exists and is still valid at this time.'''
token_exp = token['access_token_expiration']
return token_exp and datetime.now() < datetime.fromisoformat(token_exp)
def update_tokens(r):
'''Takes a response dictionary, extracts tokens out of it, and updates token file.'''
token['access_token'] = r['access_token']
token['access_token_expiration'] = (datetime.now() +
timedelta(seconds=int(r['expires_in']))).isoformat()
if 'refresh_token' in r:
token['refresh_token'] = r['refresh_token']
writetokenfile()
if args.verbose:
print(f'NOTICE: Obtained new access token, expires {token["access_token_expiration"]}.')
if args.authorize:
p = baseparams.copy()
p['scope'] = registration['scope']
if authflow in ('authcode', 'localhostauthcode'):
verifier = secrets.token_urlsafe(90)
challenge = base64.urlsafe_b64encode(hashlib.sha256(verifier.encode()).digest())[:-1]
redirect_uri = registration['redirect_uri']
listen_port = 0
if authflow == 'localhostauthcode':
# Find an available port to listen on
s = socket.socket()
s.bind(('127.0.0.1', 0))
listen_port = s.getsockname()[1]
s.close()
redirect_uri = 'http://localhost:'+str(listen_port)+'/'
# Probably should edit the port number into the actual redirect URL.
p.update({'login_hint': token['email'],
'response_type': 'code',
'redirect_uri': redirect_uri,
'code_challenge': challenge,
'code_challenge_method': 'S256'})
print(registration["authorize_endpoint"] + '?' +
urllib.parse.urlencode(p, quote_via=urllib.parse.quote))
authcode = ''
if authflow == 'authcode':
authcode = input('Visit displayed URL to retrieve authorization code. Enter '
'code from server (might be in browser address bar): ')
else:
print('Visit displayed URL to authorize this application. Waiting...',
end='', flush=True)
class MyHandler(http.server.BaseHTTPRequestHandler):
'''Handles the browser query resulting from redirect to redirect_uri.'''
# pylint: disable=C0103
def do_HEAD(self):
'''Response to a HEAD requests.'''
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
def do_GET(self):
'''For GET request, extract code parameter from URL.'''
# pylint: disable=W0603
global authcode
querystring = urllib.parse.urlparse(self.path).query
querydict = urllib.parse.parse_qs(querystring)
if 'code' in querydict:
authcode = querydict['code'][0]
self.do_HEAD()
self.wfile.write(b'<html><head><title>Authorizaton result</title></head>')
self.wfile.write(b'<body><p>Authorization redirect completed. You may '
b'close this window.</p></body></html>')
with http.server.HTTPServer(('127.0.0.1', listen_port), MyHandler) as httpd:
try:
httpd.handle_request()
except KeyboardInterrupt:
pass
if not authcode:
sys.exit('Did not obtain an authcode.')
for k in 'response_type', 'login_hint', 'code_challenge', 'code_challenge_method':
del p[k]
p.update({'grant_type': 'authorization_code',
'code': authcode,
'client_secret': registration['client_secret'],
'code_verifier': verifier})
print('Exchanging the authorization code for an access token')
try:
response = urllib.request.urlopen(registration['token_endpoint'],
urllib.parse.urlencode(p).encode())
except urllib.error.HTTPError as err:
print(err.code, err.reason)
response = err
response = response.read()
if args.debug:
print(response)
response = json.loads(response)
if 'error' in response:
print(response['error'])
if 'error_description' in response:
print(response['error_description'])
sys.exit(1)
elif authflow == 'devicecode':
try:
response = urllib.request.urlopen(registration['devicecode_endpoint'],
urllib.parse.urlencode(p).encode())
except urllib.error.HTTPError as err:
print(err.code, err.reason)
response = err
response = response.read()
if args.debug:
print(response)
response = json.loads(response)
if 'error' in response:
print(response['error'])
if 'error_description' in response:
print(response['error_description'])
sys.exit(1)
print(response['message'])
del p['scope']
p.update({'grant_type': 'urn:ietf:params:oauth:grant-type:device_code',
'client_secret': registration['client_secret'],
'device_code': response['device_code']})
interval = int(response['interval'])
print('Polling...', end='', flush=True)
while True:
time.sleep(interval)
print('.', end='', flush=True)
try:
response = urllib.request.urlopen(registration['token_endpoint'],
urllib.parse.urlencode(p).encode())
except urllib.error.HTTPError as err:
# Not actually always an error, might just mean "keep trying..."
response = err
response = response.read()
if args.debug:
print(response)
response = json.loads(response)
if 'error' not in response:
break
if response['error'] == 'authorization_declined':
print(' user declined authorization.')
sys.exit(1)
if response['error'] == 'expired_token':
print(' too much time has elapsed.')
sys.exit(1)
if response['error'] != 'authorization_pending':
print(response['error'])
if 'error_description' in response:
print(response['error_description'])
sys.exit(1)
print()
else:
sys.exit(f'ERROR: Unknown OAuth2 flow "{token["authflow"]}. Delete token file and '
f'start over.')
update_tokens(response)
if not access_token_valid():
if args.verbose:
print('NOTICE: Invalid or expired access token; using refresh token '
'to obtain new access token.')
if not token['refresh_token']:
sys.exit('ERROR: No refresh token. Run script with "--authorize".')
p = baseparams.copy()
p.update({'client_secret': registration['client_secret'],
'refresh_token': token['refresh_token'],
'grant_type': 'refresh_token'})
try:
response = urllib.request.urlopen(registration['token_endpoint'],
urllib.parse.urlencode(p).encode())
except urllib.error.HTTPError as err:
print(err.code, err.reason)
response = err
response = response.read()
if args.debug:
print(response)
response = json.loads(response)
if 'error' in response:
print(response['error'])
if 'error_description' in response:
print(response['error_description'])
print('Perhaps refresh token invalid. Try running once with "--authorize"')
sys.exit(1)
update_tokens(response)
if not access_token_valid():
sys.exit('ERROR: No valid access token. This should not be able to happen.')
if args.verbose:
print('Access Token: ', end='')
print(token['access_token'])
def build_sasl_string(user, host, port, bearer_token):
'''Build appropriate SASL string, which depends on cloud server's supported SASL method.'''
if registration['sasl_method'] == 'OAUTHBEARER':
return f'n,a={user},\1host={host}\1port={port}\1auth=Bearer {bearer_token}\1\1'
if registration['sasl_method'] == 'XOAUTH2':
return f'user={user}\1auth=Bearer {bearer_token}\1\1'
sys.exit(f'Unknown SASL method {registration["sasl_method"]}.')
if args.test:
errors = False
imap_conn = imaplib.IMAP4_SSL(registration['imap_endpoint'])
sasl_string = build_sasl_string(token['email'], registration['imap_endpoint'], 993,
token['access_token'])
if args.debug:
imap_conn.debug = 4
try:
imap_conn.authenticate(registration['sasl_method'], lambda _: sasl_string.encode())
# Microsoft has a bug wherein a mismatch between username and token can still report a
# successful login... (Try a consumer login with the token from a work/school account.)
# Fortunately subsequent commands fail with an error. Thus we follow AUTH with another
# IMAP command before reporting success.
imap_conn.list()
if args.verbose:
print('IMAP authentication succeeded')
except imaplib.IMAP4.error as e:
print('IMAP authentication FAILED (does your account allow IMAP?):', e)
errors = True
pop_conn = poplib.POP3_SSL(registration['pop_endpoint'])
sasl_string = build_sasl_string(token['email'], registration['pop_endpoint'], 995,
token['access_token'])
if args.debug:
pop_conn.set_debuglevel(2)
try:
# poplib doesn't have an auth command taking an authenticator object
# Microsoft requires a two-line SASL for POP
# pylint: disable=W0212
pop_conn._shortcmd('AUTH ' + registration['sasl_method'])
pop_conn._shortcmd(base64.standard_b64encode(sasl_string.encode()).decode())
if args.verbose:
print('POP authentication succeeded')
except poplib.error_proto as e:
print('POP authentication FAILED (does your account allow POP?):', e.args[0].decode())
errors = True
# SMTP_SSL would be simpler but Microsoft does not answer on port 465.
smtp_conn = smtplib.SMTP(registration['smtp_endpoint'], 587)
sasl_string = build_sasl_string(token['email'], registration['smtp_endpoint'], 587,
token['access_token'])
smtp_conn.ehlo('test')
smtp_conn.starttls()
smtp_conn.ehlo('test')
if args.debug:
smtp_conn.set_debuglevel(2)
try:
smtp_conn.auth(registration['sasl_method'], lambda _=None: sasl_string)
if args.verbose:
print('SMTP authentication succeeded')
except smtplib.SMTPAuthenticationError as e:
print('SMTP authentication FAILED:', e)
errors = True
if errors:
sys.exit(1)

View File

@@ -0,0 +1,7 @@
{pkgs, ...}: {
home.packages = [
pkgs.ripgrep
];
home.file.".config/ripgrep/config".source = ./ripgrep/ripgrep.conf;
}

View File

@@ -0,0 +1,6 @@
# Don't let ripgrep vomit really long lines to my terminal, and show a preview.
--max-columns=150
--max-columns-preview
# Ignore contents of .git
--glob=!.git/*

View File

@@ -0,0 +1,10 @@
{pkgs, ...}: {
programs.zsh.sessionVariables = {
RUSTFLAGS = "-L ${pkgs.libiconv}/lib -L ${pkgs.libcxx}/lib";
RUST_BACKTRACE = "full";
};
home.file.".cargo/config.toml".source = ./rust/cargo-config.toml;
home.packages = [
pkgs.rust-analyzer
];
}

View File

@@ -0,0 +1,2 @@
[registries.crates-io]
protocol = "sparse"

View File

@@ -0,0 +1,19 @@
{pkgs, ...}: {
imports = [./zsh.nix];
home.packages = [
pkgs.tmux
];
programs.tmux = {
shell = "${pkgs.zsh}/bin/zsh";
escapeTime = 50;
mouse = false;
prefix = "C-b";
enable = true;
terminal = "screen-256color";
extraConfig = ''
set-option -sa terminal-features ',xterm-256color:RGB'
set -g default-command "exec ${pkgs.zsh}/bin/zsh"
'';
};
}

View File

@@ -0,0 +1,199 @@
#!/usr/bin/env python3
# MIT licenced, https://github.com/Alexays/Waybar/blob/dacecb9b265c1c7c36ee43d17526fa95f4e6596f/resources/custom_modules/mediaplayer.py
# See licence in power_menu.xml
import gi
gi.require_version("Playerctl", "2.0")
from gi.repository import Playerctl, GLib
from gi.repository.Playerctl import Player
import argparse
import logging
import sys
import signal
import gi
import json
import os
from typing import List
logger = logging.getLogger(__name__)
def signal_handler(sig, frame):
logger.info("Received signal to stop, exiting")
sys.stdout.write("\n")
sys.stdout.flush()
# loop.quit()
sys.exit(0)
class PlayerManager:
def __init__(self, selected_player=None, excluded_player=[]):
self.manager = Playerctl.PlayerManager()
self.loop = GLib.MainLoop()
self.manager.connect(
"name-appeared", lambda *args: self.on_player_appeared(*args))
self.manager.connect(
"player-vanished", lambda *args: self.on_player_vanished(*args))
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
self.selected_player = selected_player
self.excluded_player = excluded_player.split(',') if excluded_player else []
self.init_players()
def init_players(self):
for player in self.manager.props.player_names:
if player.name in self.excluded_player:
continue
if self.selected_player is not None and self.selected_player != player.name:
logger.debug(f"{player.name} is not the filtered player, skipping it")
continue
self.init_player(player)
def run(self):
logger.info("Starting main loop")
self.loop.run()
def init_player(self, player):
logger.info(f"Initialize new player: {player.name}")
player = Playerctl.Player.new_from_name(player)
player.connect("playback-status",
self.on_playback_status_changed, None)
player.connect("metadata", self.on_metadata_changed, None)
self.manager.manage_player(player)
self.on_metadata_changed(player, player.props.metadata)
def get_players(self) -> List[Player]:
return self.manager.props.players
def write_output(self, text, player):
logger.debug(f"Writing output: {text}")
output = {"text": text,
"class": "custom-" + player.props.player_name,
"alt": player.props.player_name}
sys.stdout.write(json.dumps(output) + "\n")
sys.stdout.flush()
def clear_output(self):
sys.stdout.write("\n")
sys.stdout.flush()
def on_playback_status_changed(self, player, status, _=None):
logger.debug(f"Playback status changed for player {player.props.player_name}: {status}")
self.on_metadata_changed(player, player.props.metadata)
def get_first_playing_player(self):
players = self.get_players()
logger.debug(f"Getting first playing player from {len(players)} players")
if len(players) > 0:
# if any are playing, show the first one that is playing
# reverse order, so that the most recently added ones are preferred
for player in players[::-1]:
if player.props.status == "Playing":
return player
# if none are playing, show the first one
return players[0]
else:
logger.debug("No players found")
return None
def show_most_important_player(self):
logger.debug("Showing most important player")
# show the currently playing player
# or else show the first paused player
# or else show nothing
current_player = self.get_first_playing_player()
if current_player is not None:
self.on_metadata_changed(current_player, current_player.props.metadata)
else:
self.clear_output()
def on_metadata_changed(self, player, metadata, _=None):
logger.debug(f"Metadata changed for player {player.props.player_name}")
player_name = player.props.player_name
artist = player.get_artist()
title = player.get_title()
title = title.replace("&", "&amp;")
track_info = ""
if player_name == "spotify" and "mpris:trackid" in metadata.keys() and ":ad:" in player.props.metadata["mpris:trackid"]:
track_info = "Advertisement"
elif artist is not None and title is not None:
track_info = f"{artist} - {title}"
else:
track_info = title
if track_info:
if player.props.status == "Playing":
track_info = "" + track_info
else:
track_info = "" + track_info
# only print output if no other player is playing
current_playing = self.get_first_playing_player()
if current_playing is None or current_playing.props.player_name == player.props.player_name:
self.write_output(track_info, player)
else:
logger.debug(f"Other player {current_playing.props.player_name} is playing, skipping")
def on_player_appeared(self, _, player):
logger.info(f"Player has appeared: {player.name}")
if player.name in self.excluded_player:
logger.debug(
"New player appeared, but it's in exclude player list, skipping")
return
if player is not None and (self.selected_player is None or player.name == self.selected_player):
self.init_player(player)
else:
logger.debug(
"New player appeared, but it's not the selected player, skipping")
def on_player_vanished(self, _, player):
logger.info(f"Player {player.props.player_name} has vanished")
self.show_most_important_player()
def parse_arguments():
parser = argparse.ArgumentParser()
# Increase verbosity with every occurrence of -v
parser.add_argument("-v", "--verbose", action="count", default=0)
parser.add_argument("-x", "--exclude", "- Comma-separated list of excluded player")
# Define for which player we"re listening
parser.add_argument("--player")
parser.add_argument("--enable-logging", action="store_true")
return parser.parse_args()
def main():
arguments = parse_arguments()
# Initialize logging
if arguments.enable_logging:
logfile = os.path.join(os.path.dirname(
os.path.realpath(__file__)), "media-player.log")
logging.basicConfig(filename=logfile, level=logging.DEBUG,
format="%(asctime)s %(name)s %(levelname)s:%(lineno)d %(message)s")
# Logging is set by default to WARN and higher.
# With every occurrence of -v it's lowered by one
logger.setLevel(max((3 - arguments.verbose) * 10, 0))
logger.info("Creating player manager")
if arguments.player:
logger.info(f"Filtering for player: {arguments.player}")
if arguments.exclude:
logger.info(f"Exclude player {arguments.exclude}")
player = PlayerManager(arguments.player, arguments.exclude)
player.run()
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Source: https://github.com/Alexays/Waybar/blob/dacecb9b265c1c7c36ee43d17526fa95f4e6596f/resources/custom_modules/power_menu.xml -->
<!-- MIT licence available at https://github.com/Alexays/Waybar/blob/dacecb9b265c1c7c36ee43d17526fa95f4e6596f/LICENSE
MIT License
Copyright (c) 2018 Alex
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-->
<interface>
<object class="GtkMenu" id="menu">
<child>
<object class="GtkMenuItem" id="suspend">
<property name="label">Suspend</property>
</object>
</child>
<child>
<object class="GtkMenuItem" id="hibernate">
<property name="label">Hibernate</property>
</object>
</child>
<child>
<object class="GtkMenuItem" id="shutdown">
<property name="label">Shutdown</property>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="delimiter1"/>
</child>
<child>
<object class="GtkMenuItem" id="reboot">
<property name="label">Reboot</property>
</object>
</child>
</object>
</interface>

View File

@@ -0,0 +1,23 @@
{pkgs, ...}: {
programs.zsh = {
enable = true;
autocd = true;
autosuggestion.enable = true;
enableCompletion = true;
history = {
expireDuplicatesFirst = true;
};
sessionVariables = {
EDITOR = "vim";
LC_ALL = "en_US.UTF-8";
LC_CTYPE = "en_US.UTF-8";
};
shellAliases = {
vim = "nvim";
view = "vim -R";
};
initExtra = builtins.readFile ./zsh/zshrc;
};
programs.fzf.enableZshIntegration = true;
}

View File

@@ -0,0 +1,36 @@
prompt_custom() {
local cyan='%F{cyan}'
local red='%F{red}'
local blue='%F{blue}'
local reset_color='%f'
local git_info=$(git symbolic-ref --short HEAD 2> /dev/null || git describe --tags --exact-match 2> /dev/null || git rev-parse --short HEAD 2> /dev/null)
if [[ -n "$git_info" ]]; then
# escape the percent character, which is the only zsh prompt metacharacter
git_info=$git_info:s/%/%%/
git_info=" ${blue}git:${reset_color}${red}(${git_info})${reset_color}"
else
git_info=""
fi
# %1 is the name of cwd
PROMPT="${cyan}%1~${reset_color}${git_info} > "
}
# Full path to cwd, with `~` for any initial home component, in light green,
RPROMPT='%F{155}%~%f'
precmd_functions+=(prompt_custom)
export WORDCHARS=''
autoload edit-command-line
zle -N edit-command-line
bindkey '^X^E' edit-command-line
bindkey -e
PATH="$PATH:$HOME/.cargo/bin"
if [[ -z "$TMUX" ]]; then
tmux new-session -A -s default
fi

View File

@@ -0,0 +1,110 @@
BuildUtils = {}
-- Create a new buffer and a new floating window to hold that buffer.
local function create_floating_window()
-- Create a new buffer for build output
local buf = vim.api.nvim_create_buf(false, true) -- No listed, scratch buffer
-- Calculate window size and position here (example: full width, 10 lines high at the bottom)
local width = vim.api.nvim_get_option_value("columns", {})
local height = vim.api.nvim_get_option_value("lines", {})
local win_height = math.min(10, math.floor(height * 0.2)) -- 20% of total height or 10 lines
local win_opts = {
relative = "editor",
width = width,
height = win_height,
col = 0,
row = height - win_height,
style = "minimal",
border = "single",
}
local win = vim.api.nvim_open_win(buf, false, win_opts)
return { window = win, buffer = buf }
end
local function _on_output(context, is_stdout, err, data, on_line)
local prefix
if is_stdout then
prefix = "OUT"
else
prefix = "ERR"
end
if err or data then
vim.schedule(function()
if err then
-- Append the error message to the buffer
local count = vim.api.nvim_buf_line_count(context.buffer)
vim.api.nvim_buf_set_lines(context.buffer, count, count, false, { "error " .. prefix .. ": " .. err })
end
if data then
-- Append the data to the buffer
local count = vim.api.nvim_buf_line_count(context.buffer)
vim.api.nvim_buf_set_lines(
context.buffer,
count,
count,
false,
vim.tbl_map(function(line)
return prefix .. ": " .. line
end, vim.split(data, "\n"))
)
end
if vim.api.nvim_win_is_valid(context.window) then
local cur_win = vim.api.nvim_get_current_win()
local cur_buf = vim.api.nvim_win_get_buf(cur_win)
if cur_buf ~= context.buffer then
local new_line_count = vim.api.nvim_buf_line_count(context.buffer)
vim.api.nvim_win_set_cursor(context.window, { new_line_count, 0 })
end
end
on_line(data, is_stdout, context)
end)
end
end
-- Arguments:
-- * exe, a string (no need to escape this)
-- * args, a table like { "-m", "venv", vim.fn.shellescape(some_path) }
-- * description of this process, visible to the user, e.g. "venv creation"
-- * context, the result of `create_floating_window`
-- * on_line, a function which takes "the string written", (true if stdout else false), and the context table; should return nothing. We'll call that on every line of stdout and stderr.
-- * on_complete, takes `context`, `code` (exit code) and `signal` ("documented" with neovim's uv.spawn, hah)
local function run_external(exe, args, description, context, on_line, on_complete)
local handle
local stdout = vim.uv.new_pipe(false)
local stderr = vim.uv.new_pipe(false)
handle, _ = vim.uv.spawn(
exe,
{
args = args,
stdio = { nil, stdout, stderr },
},
vim.schedule_wrap(function(code, signal)
stdout:read_stop()
stderr:read_stop()
stdout:close()
stderr:close()
handle:close()
print("External process " .. description .. " completed, exit code " .. code .. " and signal " .. signal)
on_complete(context, code, signal)
end)
)
if not handle then
print("Failed to start " .. description .. " process.")
return
end
vim.uv.read_start(stdout, function(err, data)
_on_output(context, true, err, data, on_line)
end)
vim.uv.read_start(stderr, function(err, data)
_on_output(context, false, err, data, on_line)
end)
end
BuildUtils.create_window = create_floating_window
BuildUtils.run = run_external

View File

@@ -0,0 +1,57 @@
vim.g.chadtree_settings = { xdg = true }
vim.api.nvim_create_autocmd("VimEnter", {
pattern = "*",
command = "CHADopen --nofocus",
})
vim.api.nvim_create_autocmd("BufEnter", {
pattern = "*",
callback = function()
if vim.fn.winnr("$") == 1 and vim.bo.filetype == "CHADTree" then
vim.cmd("quit")
end
end,
})
-- Variable to store the CHADtree window ID
local chadtree_winid_and_buf = nil
-- Function to check if a window is displaying CHADtree
local function is_chadtree_window(winid)
local bufnr = vim.api.nvim_win_get_buf(winid)
local filetype = vim.api.nvim_get_option_value("filetype", { buf = bufnr })
return filetype == "CHADTree"
end
-- Function to find and store the CHADtree window ID
local function find_chadtree_window()
for _, winid in ipairs(vim.api.nvim_list_wins()) do
if is_chadtree_window(winid) then
chadtree_winid_and_buf = { winid, vim.api.nvim_win_get_buf(winid) }
break
end
end
end
-- Function to switch to CHADtree buffer in the CHADtree window
local function switch_to_chadtree()
if chadtree_winid_and_buf and vim.api.nvim_win_is_valid(chadtree_winid_and_buf[1]) then
local current_winid = vim.api.nvim_get_current_win()
if current_winid == chadtree_winid_and_buf[1] and not is_chadtree_window(current_winid) then
print("CHADtree window may only point to CHADtree")
vim.api.nvim_win_set_buf(chadtree_winid_and_buf[1], chadtree_winid_and_buf[2])
end
end
end
-- Autocommand to find the CHADtree window after startup
vim.api.nvim_create_autocmd("VimEnter", {
callback = function()
vim.defer_fn(find_chadtree_window, 500)
end,
})
vim.api.nvim_create_autocmd("BufEnter", {
callback = switch_to_chadtree,
})

View File

@@ -0,0 +1,765 @@
local dotnet_has_set_status_line
function DetachSolution()
vim.g.current_sln_path = nil
-- TODO: unregister key bindings again
end
local function on_line(data, _, context)
-- Keep the window alive if there were warnings
if string.match(data, "%s[1-9]%d* Warning%(s%)") then
context.warn = context.warn + 1
end
end
local function on_complete(context, code, _)
if code ~= 0 then
print("Exit code " .. code)
context.errs = context.errs + 1
end
if context.errs == 0 and context.warn == 0 then
-- Close the temporary floating window (but keep it alive if the
-- cursor is in it)
local cur_win = vim.api.nvim_get_current_win()
local cur_buf = vim.api.nvim_win_get_buf(cur_win)
if cur_buf ~= context.buffer then
vim.api.nvim_win_close(context.window, true)
end
print("All builds successful")
end
end
function GetCurrentSln()
if vim.g.current_sln_path then
return vim.g.current_sln_path
else
return nil
end
end
function BuildDotNetSolution()
if vim.g.current_sln_path then
local context = BuildUtils.create_window()
context.errs = 0
context.warn = 0
BuildUtils.run("dotnet", { "build", vim.g.current_sln_path }, "dotnet build", context, on_line, on_complete)
end
end
function TestDotNetSolution()
if vim.g.current_sln_path then
local context = BuildUtils.create_window()
context.warn = 0
context.errs = 0
BuildUtils.run("dotnet", { "test", vim.g.current_sln_path }, "dotnet test", context, on_line, on_complete)
end
end
function CurrentSlnOrEmpty()
local sln = GetCurrentSln()
if sln then
return sln
else
return ""
end
end
function RegisterSolution(sln_path)
vim.g.current_sln_path = sln_path
if not dotnet_has_set_status_line then
dotnet_has_set_status_line = true
vim.o.statusline = vim.o.statusline .. " %{v:lua.CurrentSlnOrEmpty()}"
end
local whichkey = require("which-key")
whichkey.add({
{
"<localleader>s",
desc = ".NET solution",
},
{ "<localleader>sb", BuildDotNetSolution, desc = "Build .NET solution" },
{ "<localleader>st", TestDotNetSolution, desc = "Test .NET solution" },
}, { buffer = vim.api.nvim_get_current_buf() })
end
local function find_nearest_slns()
local path = vim.fn.expand("%:p:h") -- Get the full path of the current buffer's directory
while path and path ~= "/" do
local sln_paths = vim.fn.glob(path .. "/*.sln", nil, true)
if #sln_paths > 0 then
return sln_paths
end
path = vim.fn.fnamemodify(path, ":h") -- Move up one directory
end
return {}
end
local function FindAndRegisterSolution(should_override)
if not should_override and GetCurrentSln() ~= nil then
RegisterSolution(GetCurrentSln())
end
local solutions = find_nearest_slns()
if not solutions or #solutions == 0 then
print("No .sln file found in any parent directory.")
return
elseif #solutions == 1 then
-- Exactly one solution found; register it directly
RegisterSolution(solutions[1])
elseif #solutions > 1 then
-- Multiple solutions found; use Telescope to pick one
local pickers = require("telescope.pickers")
local finders = require("telescope.finders")
local actions = require("telescope.actions")
local action_state = require("telescope.actions.state")
local conf = require("telescope.config").values
pickers
.new({}, {
prompt_title = "Select a Solution File",
finder = finders.new_table({
results = solutions,
entry_maker = function(entry)
return {
value = entry,
display = entry,
ordinal = entry,
}
end,
}),
sorter = conf.generic_sorter({}),
attach_mappings = function(prompt_bufnr, _)
actions.select_default:replace(function()
local selection = action_state.get_selected_entry()
actions.close(prompt_bufnr)
RegisterSolution(selection.value)
end)
return true
end,
})
:find()
end
end
vim.api.nvim_create_autocmd({ "BufReadPost", "BufNewFile" }, {
pattern = "*.sln",
callback = function()
if GetCurrentSln() == nil then
RegisterSolution(vim.fn.expand("%:p"))
end
end,
})
vim.api.nvim_create_autocmd("FileType", {
pattern = { "fsharp", "cs", "fsharp_project" },
callback = function()
FindAndRegisterSolution(false)
end,
})
-- For what I'm sure are reasons, Lua appears to have nothing in its standard library
---@generic K
---@generic V1
---@generic V2
---@param tbl table<K, V1>
---@param f fun(V1): V2
---@return table<K, V2>
local function map(tbl, f)
local t = {}
for k, v in pairs(tbl) do
t[k] = f(v)
end
return t
end
---@generic K
---@generic V
---@param tbl table<K, V>
---@param f fun(V1): nil
local function iter(tbl, f)
for _, v in pairs(tbl) do
f(v)
end
end
---@generic K
---@generic V
---@param tbl table<K, V>
---@param predicate fun(V): boolean
---@return boolean, V
local function find(tbl, predicate)
for _, v in pairs(tbl) do
if predicate(v) then
return true, v
end
end
return false, nil
end
---@class (exact) NuGetVersion
---@field major number
---@field minor number
---@field patch number
---@field suffix? string
local NuGetVersion = {}
---@param v NuGetVersion
---@nodiscard
---@return string
local function nuGetVersionToString(v)
local s = tostring(v.major) .. "." .. tostring(v.minor) .. "." .. tostring(v.patch)
if v.suffix then
return s .. v.suffix
else
return s
end
end
local function get_all_variables()
local variables = {}
local lines = vim.api.nvim_buf_get_lines(0, 0, -1, false)
for _, line in ipairs(lines) do
local var_name, var_value = line:match("<(%w+)>([^<]+)</(%w+)>")
if var_name and var_value then
variables[var_name] = var_value
end
end
return variables
end
local function resolve_variable(version, variables)
if version:match("^%$%((.+)%)$") then
local var_name = version:match("^%$%((.+)%)$")
return variables[var_name] or nil
end
return nil
end
---@param v string
---@nodiscard
---@return NuGetVersion
local function parse_version(v)
local variables = get_all_variables()
local major, minor, patch, pre = v:match("(%d+)%.(%d+)%.(%d+)(.*)$")
if major == nil then
local resolved = resolve_variable(v, variables)
if resolved ~= nil then
return parse_version(resolved)
end
end
-- TODO: why does this type-check if you remove the field names?
return {
major = tonumber(major) or 0,
minor = tonumber(minor) or 0,
patch = tonumber(patch) or 0,
suffix = pre or nil,
}
end
---@param a NuGetVersion
---@param b NuGetVersion
---@nodiscard
---@return boolean
local function compare_versions(a, b)
if a.major ~= b.major then
return a.major < b.major
elseif a.minor ~= b.minor then
return a.minor < b.minor
elseif a.patch ~= b.patch then
return a.patch < b.patch
elseif a.suffix and not b.suffix then
return false
elseif not a.suffix and b.suffix then
return true
else
return a.suffix < b.suffix
end
end
---@param url string
---@nodiscard
local function curl_sync(url)
local command = string.format("_CURL_ --silent --compressed --fail '%s'", url)
local response = vim.fn.system(command)
if vim.v.shell_error ~= 0 then
print("Failed to fetch " .. url)
return nil
end
local success, decoded = pcall(vim.fn.json_decode, response)
if not success then
print("Failed to decode JSON from curl at " .. url)
return nil
end
return decoded
end
---@param url string
---@param callback fun(table): nil
---@return nil
local function curl(url, callback)
local stdout = vim.uv.new_pipe(false)
local stdout_text = ""
local handle
handle, _ = vim.uv.spawn(
"_CURL_",
{ args = { "--silent", "--compressed", "--fail", url }, stdio = { nil, stdout, nil } },
vim.schedule_wrap(function(code, _)
stdout:read_stop()
stdout:close()
if handle and not handle:is_closing() then
handle:close()
end
if code ~= 0 then
print("Failed to fetch " .. url)
end
local success, decoded = pcall(vim.fn.json_decode, stdout_text)
if not success then
print("Failed to decode JSON from curl at " .. url .. "\n" .. stdout_text)
end
callback(decoded)
end)
)
vim.uv.read_start(stdout, function(err, data)
assert(not err, err)
if data then
stdout_text = stdout_text .. data
end
end)
end
local _nugetIndex
local _packageBaseAddress
---@param callback fun(): nil
local function populate_nuget_api(callback)
if _nugetIndex ~= nil then
callback()
end
local url = string.format("https://api.nuget.org/v3/index.json")
local function handle(decoded)
local default_nuget_reg = "https://api.nuget.org/v3/registration5-semver1/"
local default_base_address = "https://api.nuget.org/v3-flatcontainer/"
if not decoded then
print("Failed to fetch NuGet index; falling back to default")
_nugetIndex = default_nuget_reg
_packageBaseAddress = default_base_address
else
local resources = decoded["resources"]
if resources == nil then
print("Failed to parse: " .. decoded .. tostring(decoded))
for k, v in pairs(decoded) do
print(k .. ": " .. tostring(v))
end
callback()
return
end
local resourceSuccess, regUrl = find(resources, function(o)
return o["@type"] == "RegistrationsBaseUrl/3.6.0"
end)
if not resourceSuccess then
print("Failed to find endpoint in NuGet index; falling back to default")
_nugetIndex = default_nuget_reg
else
_nugetIndex = regUrl["@id"]
end
local baseAddrSuccess, baseAddrUrl = find(resources, function(o)
return o["@type"] == "PackageBaseAddress/3.0.0"
end)
if not baseAddrSuccess then
print("Failed to find endpoint in NuGet index; falling back to default")
_packageBaseAddress = default_base_address
else
_packageBaseAddress = baseAddrUrl["@id"]
end
end
callback()
end
curl(url, handle)
end
---@return nil
local function populate_nuget_api_sync()
if _nugetIndex ~= nil then
return
end
local url = string.format("https://api.nuget.org/v3/index.json")
local decoded = curl_sync(url)
local default_nuget_reg = "https://api.nuget.org/v3/registration5-semver1/"
local default_base_address = "https://api.nuget.org/v3-flatcontainer/"
if not decoded then
print("Failed to fetch NuGet index; falling back to default")
_nugetIndex = default_nuget_reg
_packageBaseAddress = default_base_address
else
local resources = decoded["resources"]
local resourceSuccess, regUrl = find(resources, function(o)
return o["@type"] == "RegistrationsBaseUrl/3.6.0"
end)
if not resourceSuccess then
print("Failed to find endpoint in NuGet index; falling back to default")
_nugetIndex = default_nuget_reg
else
_nugetIndex = regUrl["@id"]
end
local baseAddrSuccess, baseAddrUrl = find(resources, function(o)
return o["@type"] == "PackageBaseAddress/3.0.0"
end)
if not baseAddrSuccess then
print("Failed to find endpoint in NuGet index; falling back to default")
_packageBaseAddress = default_base_address
else
_packageBaseAddress = baseAddrUrl["@id"]
end
end
end
---@return nil
---@param callback fun(nugetIndex: string): nil
local function get_nuget_index(callback)
populate_nuget_api(function()
callback(_nugetIndex)
end)
end
---@return nil
---@param callback fun(packageBaseIndex: string): nil
local function get_package_base_addr(callback)
populate_nuget_api(function()
callback(_packageBaseAddress)
end)
end
---@return string
local function get_package_base_addr_sync()
populate_nuget_api_sync()
return _packageBaseAddress
end
local _package_versions_cache = {}
---@param package_name string
---@return NuGetVersion[]
local function get_package_versions_sync(package_name)
if _package_versions_cache[package_name] ~= nil then
return _package_versions_cache[package_name]
end
local base = get_package_base_addr_sync()
local url = base .. string.format("%s/index.json", package_name:lower())
local decoded = curl_sync(url)
if not decoded then
print("Failed to fetch package versions")
return {}
end
local versions = map(decoded.versions, parse_version)
table.sort(versions, function(a, b)
return compare_versions(b, a)
end)
_package_versions_cache[package_name] = versions
return versions
end
---@param package_name string
---@param callback fun(v: NuGetVersion[]): nil
---@return nil
local function get_package_versions(package_name, callback)
if _package_versions_cache[package_name] ~= nil then
callback(_package_versions_cache[package_name])
end
local function handle(base)
local url = base .. string.format("%s/index.json", package_name:lower())
local function handle2(decoded)
if not decoded then
print("Failed to fetch package versions")
callback({})
end
local versions = map(decoded.versions, parse_version)
table.sort(versions, function(a, b)
return compare_versions(b, a)
end)
_package_versions_cache[package_name] = versions
callback(versions)
end
curl(url, handle2)
end
get_package_base_addr(handle)
end
---@param version NuGetVersion
---@return nil
local function update_package_version(version)
local line = vim.api.nvim_get_current_line()
local new_line = line:gsub('Version="[^"]+"', string.format('Version="%s"', nuGetVersionToString(version)))
vim.api.nvim_set_current_line(new_line)
end
-- A map from package to { packageWeDependOn: version }.
--- @type table<string, table<string, string>>
local _package_dependency_cache = {}
---@param package_name string
---@param version NuGetVersion
---@param callback fun(result: table<string, string>): nil
---@return nil
local function get_package_dependencies(package_name, version, callback)
local key = package_name .. "@" .. nuGetVersionToString(version)
local cache_hit = _package_dependency_cache[key]
if cache_hit ~= nil then
callback(cache_hit)
return
end
local function handle1(index)
local url = index .. string.format("%s/%s.json", package_name:lower(), nuGetVersionToString(version):lower())
local function handle(response)
if not response then
print(
"Failed to get dependencies of "
.. package_name
.. " at version "
.. version
.. " : unsuccessful response to "
.. url
)
return
end
local entry_url = response["catalogEntry"]
local function handle2(catalog_entry)
if not catalog_entry then
print(
"Failed to get dependencies of "
.. package_name
.. " at version "
.. version
.. " : unsuccessful response to "
.. entry_url
)
return
end
local result = {}
if catalog_entry["dependencyGroups"] then
iter(catalog_entry["dependencyGroups"], function(grp)
if grp["dependencies"] then
for _, dep in pairs(grp["dependencies"]) do
result[dep["id"]] = dep["range"]
end
end
end)
end
_package_dependency_cache[key] = result
callback(result)
end
curl(entry_url, handle2)
end
curl(url, handle)
end
get_nuget_index(handle1)
end
---@return table<string, NuGetVersion>
---@nodiscard
local function get_all_package_references()
local packages = {}
local lines = vim.api.nvim_buf_get_lines(0, 0, -1, false)
for _, line in ipairs(lines) do
local package_name = line:match('PackageReference Include="([^"]+)"')
or line:match('PackageReference Update="([^"]+)"')
local version = line:match('Version="([^"]+)"')
if package_name and version then
if not packages[package_name] then
packages[package_name] = {}
end
table.insert(packages[package_name], parse_version(version))
end
end
return packages
end
function ClearNuGetDependencyCache()
for k, _ in pairs(_package_dependency_cache) do
_package_dependency_cache[k] = nil
end
end
vim.api.nvim_create_user_command("ClearNuGetDependencyCache", ClearNuGetDependencyCache, {})
function PrintNuGetDependencyCache()
for k, v in pairs(_package_dependency_cache) do
print(k .. ":")
for dep, ver in pairs(v) do
print(" " .. dep .. ": " .. ver)
end
end
end
vim.api.nvim_create_user_command("PrintNuGetDependencyCache", PrintNuGetDependencyCache, {})
local function prefetch_dependencies()
local packages = get_all_package_references()
local function process_package(package_name, versions, callback)
local count = #versions
for _, version in ipairs(versions) do
vim.schedule(function()
get_package_dependencies(package_name, version, function(_)
count = count - 1
if count == 0 then
callback()
end
end)
end)
end
end
local total_packages = 0
for _ in pairs(packages) do
total_packages = total_packages + 1
end
local processed_packages = 0
for package_name, versions in pairs(packages) do
process_package(package_name, versions, function()
local function handle(package_versions)
if package_versions then
process_package(package_name, package_versions, function()
processed_packages = processed_packages + 1
if processed_packages == total_packages then
print("All dependencies prefetched")
end
end)
else
processed_packages = processed_packages + 1
if processed_packages == total_packages then
print("All dependencies prefetched")
end
end
end
get_package_versions(package_name, handle)
end)
end
end
---@param v1 NuGetVersion
---@param v2 NuGetVersion
---@return boolean
---@nodiscard
local function nuget_versions_equal(v1, v2)
return v1.major == v2.major and v1.minor == v2.minor and v1.patch == v2.patch and v1.suffix == v2.suffix
end
vim.api.nvim_create_autocmd("FileType", {
pattern = { "fsharp_project", "csharp_project", "xml" },
callback = function()
function UpdateNuGetVersion()
local line = vim.api.nvim_get_current_line()
local package_name = line:match('PackageReference Include="([^"]+)"')
or line:match('PackageReference Update="([^"]+)"')
if not package_name then
print("No package reference found on the current line")
return
end
local current_version = parse_version(line:match('Version="([^"]+)"'))
if not current_version then
print("oh no!")
end
local package_versions = get_package_versions_sync(package_name)
if #package_versions == 0 then
print("No versions found for the package")
return
end
local pickers = require("telescope.pickers")
local finders = require("telescope.finders")
local previewers = require("telescope.previewers")
pickers
.new({}, {
prompt_title = string.format("Select version for %s", package_name),
finder = finders.new_table({
results = package_versions,
entry_maker = function(entry)
local val = nuGetVersionToString(entry)
local display_value = val
if current_version and nuget_versions_equal(entry, current_version) then
display_value = "[CURRENT] " .. val
end
return {
value = entry,
display = display_value,
ordinal = entry,
}
end,
}),
previewer = previewers.new_buffer_previewer({
define_preview = function(self, entry, _)
local bufnr = self.state.bufnr
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { "Loading..." })
get_package_dependencies(package_name, entry.value, function(package_dependencies)
if not package_dependencies then
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { "No dependencies found" })
return
end
local display = {}
table.insert(
display,
"Dependencies for "
.. package_name
.. " at version "
.. nuGetVersionToString(entry.value)
.. ":"
)
for dep, range in pairs(package_dependencies) do
table.insert(display, dep .. ": " .. range)
end
local ok, err = pcall(vim.api.nvim_buf_set_lines, bufnr, 0, -1, false, display)
if not ok then
-- If we can't set lines, the window's probably gone. Ignore.
return
end
end)
end,
}),
attach_mappings = function(_, mapping)
mapping("i", "<CR>", function(prompt_bufnr)
local selection = require("telescope.actions.state").get_selected_entry()
require("telescope.actions").close(prompt_bufnr)
update_package_version(selection.value)
end)
return true
end,
})
:find()
end
local whichkey = require("which-key")
whichkey.add({
{ "<localleader>n", desc = "NuGet" },
{ "<localleader>nu", UpdateNuGetVersion, desc = "Upgrade NuGet versions" },
}, { buffer = vim.api.nvim_get_current_buf() })
vim.schedule(prefetch_dependencies)
end,
})

290
home-manager/nvim/init.lua Normal file
View File

@@ -0,0 +1,290 @@
vim.opt.mouse = ""
vim.opt.history = 500
vim.opt.background = "dark"
vim.opt.signcolumn = "yes"
vim.opt.wildmenu = true
vim.opt.wildignore = vim.opt.wildignore + { "*/.git/*", "*/.hg/*", "*/.svn/*", "*/.DS_Store" }
vim.opt.ignorecase = true
vim.opt.smartcase = true
vim.opt.incsearch = true
vim.opt.magic = true
vim.opt.hlsearch = true
vim.opt.autoindent = true
vim.opt.smartindent = true
vim.opt.wrap = true
vim.opt.linebreak = true
vim.opt.textwidth = 500
vim.opt.switchbuf = "useopen"
vim.opt.laststatus = 2
-- I don't use tabs, but one day I might!
vim.opt.showtabline = 2
vim.opt.langmenu = "en"
vim.opt.ffs = "unix"
vim.opt.encoding = "utf8"
-- Always show current position
vim.opt.ruler = true
vim.opt.number = true
-- A bit of extra margin to the left
vim.opt.foldcolumn = "1"
vim.opt.autoread = true
vim.opt.backup = false
vim.opt.writebackup = true
vim.opt.swapfile = false
vim.opt.cmdheight = 2
-- Use spaces instead of tabs
vim.opt.expandtab = true
vim.opt.smarttab = true
vim.opt.shiftwidth = 4
vim.opt.tabstop = 4
vim.opt.lazyredraw = true
-- Show matching brackets when text indicator is on one of them
vim.opt.showmatch = true
vim.opt.mat = 2
-- Turn off sound
vim.opt.errorbells = false
vim.opt.visualbell = false
vim.opt.timeoutlen = 500
vim.opt.scrolloff = 2
-- Return to last edit position when opening files
vim.api.nvim_create_autocmd("BufReadPost", {
pattern = "*",
callback = function()
local line = vim.fn.line
local last_pos = line("'\"")
if last_pos > 1 and last_pos <= line("$") then
vim.cmd("normal! g'\"")
end
end,
})
-- Trim trailing whitespace on save
function CleanExtraSpaces()
local save_cursor = vim.api.nvim_win_get_cursor(0)
local old_query = vim.fn.getreg("/")
vim.cmd("%s/\\s\\+$//e")
vim.api.nvim_win_set_cursor(0, save_cursor)
vim.fn.setreg("/", old_query)
end
vim.api.nvim_create_autocmd("BufWritePre", {
pattern = { "*.fs", "*.fsi", "*.txt", "*.js", "*.py", "*.wiki", "*.sh", "*.coffee" },
callback = CleanExtraSpaces,
})
-- Status line
-- Returns true if paste mode is enabled
function HasPaste()
if vim.opt.paste:get() then
return "PASTE MODE "
end
return ""
end
vim.o.statusline = vim.o.statusline .. "%{v:lua.HasPaste()}%F%m%r%h %w Line: %l Column: %c"
--------------------------------------------------------------
vim.api.nvim_set_keymap("n", ";", "<Nop>", { noremap = true })
vim.api.nvim_set_var("maplocalleader", ";")
vim.api.nvim_set_var("mapleader", " ")
function MarkdownPreview()
local temp_file = vim.fn.tempname() .. ".md"
local file_name = vim.fn.substitute(vim.fn.tolower(vim.fn.expand("%:t")), "\\W", "_", "g")
local temp_html = "/tmp/" .. file_name .. "_tmp.html"
-- Write the current buffer to the temp file
vim.cmd("write! " .. temp_file)
local pandoc_cmd = "pandoc " .. temp_file .. " -o " .. temp_html
-- Execute the pandoc command
vim.fn.system(pandoc_cmd)
-- Use tmux and lynx to preview the HTML file
local lynx_cmd = "tmux split-window -h lynx " .. temp_html
vim.fn.jobstart(vim.split(lynx_cmd, " "), { silent = true })
-- Delete the temp markdown file
vim.fn.delete(temp_file, "rf")
end
function RemoveCarriageReturn()
vim.cmd("mark m")
vim.cmd("normal! Hmt")
vim.cmd("%s/\r//ge")
vim.cmd("normal! 'tzt'm")
end
function FormatJson()
vim.cmd("%!python -m json.tool")
end
function ChangeToCurrentDirectory()
vim.cmd(":cd %:p:h")
vim.cmd(":pwd")
end
local function close_loclist_if_orphaned()
local win = vim.fn.expand("<afile>")
vim.fn.win_execute(win, "lclose")
end
-- Set up an autocmd using the nvim_create_autocmd API
vim.api.nvim_create_autocmd("WinClosed", {
pattern = "*",
callback = close_loclist_if_orphaned,
})
local whichkey = require("which-key")
local pickers = require("telescope.pickers")
local action_state = require("telescope.actions.state")
local actions = require("telescope.actions")
local finders = require("telescope.finders")
local conf = require("telescope.config").values
function DisplayAllMappingsWithTelescope()
local mappings = {}
local commands = {} -- Store commands keyed by the display string
local function accumulate(tree)
tree:walk(function(node)
if node.mapping then
local mapping = node.mapping
if not mapping.group then
local description = mapping.desc or mapping.label or mapping.cmd
-- Some actions are just there for which-key to hook into to display prefixes; they don't have a description.
if description then
local displayString = description .. " | " .. mapping.prefix
commands[displayString] = mapping.prefix
mappings[#mappings + 1] = displayString
else
for k, v in pairs(mapping) do
print("Nothing: " .. k .. " : " .. tostring(v) .. " (type: " .. type(v) .. ")")
end
print("-----")
end
end
end
end)
end
local cur_buf = vim.api.nvim_win_get_buf(0)
accumulate(require("which-key.keys").get_tree("n").tree)
accumulate(require("which-key.keys").get_tree("n", cur_buf).tree)
pickers
.new({}, {
prompt_title = "Actions",
finder = finders.new_table({
results = mappings,
}),
sorter = conf.generic_sorter({}),
attach_mappings = function(_, map)
map("i", "<CR>", function(bufnr)
local selection = action_state.get_selected_entry()
actions.close(bufnr)
local cmd = commands[selection.value]
if cmd then
vim.api.nvim_command(":normal " .. vim.api.nvim_replace_termcodes(cmd, true, true, true))
else
print("no command found")
end
end)
return true
end,
})
:find()
end
function ToggleSpell()
vim.cmd("setlocal spell!")
end
whichkey.add({
{
"<localleader><localleader>",
function()
require("which-key").show({ global = false })
end,
desc = "View all mappings",
},
{ "<localleader>mp", MarkdownPreview, desc = "Preview Markdown in Lynx" },
{ "<localleader>md", RemoveCarriageReturn, desc = "Delete carriage returns from file" },
{ "<localleader>j", FormatJson, desc = "Auto-format JSON" },
})
whichkey.add({
{
"<leader>g",
function()
require("telescope.builtin").grep_string()
end,
desc = "Find instances of text under cursor",
},
{ "<leader>h", desc = "Find historical..." },
{
"<leader>hf",
function()
require("telescope.builtin").oldfiles()
end,
desc = "List previously open files",
},
{
"<leader>hc",
function()
require("telescope.builtin").command_history()
end,
desc = "List previously run commands",
},
{
"<leader>hs",
function()
require("telescope.builtin").search_history()
end,
desc = "List previously run searches",
},
{
"<leader>m",
function()
require("telescope.builtin").marks()
end,
desc = "List marks",
},
{ "<leader>cd", ChangeToCurrentDirectory, desc = "Switch CWD to the directory of the open buffer" },
{ "<leader>ss", ToggleSpell, desc = "Toggle spell-checker on or off" },
{
"<leader><leader>",
function()
require("telescope.builtin").find_files()
end,
desc = "Find files by name",
},
})
vim.api.nvim_create_autocmd({ "BufRead", "BufNewFile" }, {
pattern = { "Directory.Build.props", "*.fsproj", "*.csproj" },
callback = function()
vim.bo.filetype = "xml"
end,
})

View File

@@ -0,0 +1,230 @@
vim.g["fsharp#fsautocomplete_command"] = { "fsautocomplete" }
vim.g["fsharp#show_signature_on_cursor_move"] = 1
vim.g["fsharp#fsi_keymap"] = "none"
-- Supply nil to get all loaded F# projects and build them.
local function BuildFSharpProjects(projects)
local function on_line(data, _, context)
-- Keep the window alive if there were warnings
if string.match(data, "%s[1-9]%d* Warning%(s%)") then
context.warn = context.warn + 1
end
end
local on_complete
local function spawn_next(context)
BuildUtils.run(
"dotnet",
{ "build", context.projects[context.completed + 1] },
"dotnet build",
context,
on_line,
on_complete
)
end
on_complete = function(context, code, signal)
print("Build process exited with code " .. code .. " and signal " .. signal)
if code ~= 0 then
context.errs = context.errs + 1
end
context.completed = context.completed + 1
print(
"Completed: "
.. context.completed
.. " out of "
.. context.expected
.. " (errors: "
.. context.errs
.. ", warnings: "
.. context.warn
.. ")"
)
if context.completed == context.expected then
if context.errs == 0 and context.warn == 0 then
-- Close the temporary floating window (but keep it alive if the
-- cursor is in it)
local cur_win = vim.api.nvim_get_current_win()
local cur_buf = vim.api.nvim_win_get_buf(cur_win)
if cur_buf ~= context.buffer then
vim.api.nvim_win_close(context.window, true)
end
print("All builds successful")
end
else
spawn_next(context)
end
end
if not projects then
projects = vim.fn["fsharp#getLoadedProjects"]()
end
if projects then
local total_projects = 0
for _, _ in ipairs(projects) do
total_projects = total_projects + 1
end
local context = BuildUtils.create_window()
context.warn = 0
context.errs = 0
context.completed = 0
context.expected = total_projects
context.projects = projects
spawn_next(context)
end
end
vim.api.nvim_create_user_command("BuildFSharpProject", function(opts)
if opts.fargs and opts.fargs[1] then
BuildFSharpProjects(opts.fargs)
else
local pickers = require("telescope.pickers")
local finders = require("telescope.finders")
local conf = require("telescope.config").values
local action_state = require("telescope.actions.state")
local actions = require("telescope.actions")
pickers
.new({}, {
prompt_title = "Projects",
finder = finders.new_table({
results = vim.fn["fsharp#getLoadedProjects"](),
}),
sorter = conf.generic_sorter({}),
attach_mappings = function(prompt_buf, _)
actions.select_default:replace(function()
actions.close(prompt_buf)
local selection = action_state.get_selected_entry()
BuildFSharpProjects({ selection.value })
end)
return true
end,
})
:find()
end
end, { nargs = "?", complete = "file" })
local function TableConcat(tables)
local result = {}
for _, tab in ipairs(tables) do
for _, v in ipairs(tab) do
table.insert(result, v)
end
end
return result
end
-- args is a table that will be splatted into the command line and will be immediately
-- followed by the project.
local function RunDotnet(command, args, project, configuration)
local function on_line(data, _, context) end
local function on_complete(context, code, signal) end
local context = BuildUtils.create_window()
BuildUtils.run(
"dotnet",
TableConcat({ { command }, args, { project, "--configuration", configuration } }),
"dotnet",
context,
on_line,
on_complete
)
end
-- Call this as:
-- RunFSharpProject path/to/fsproj
-- RunFSharpProject Debug path/to/fsproj
vim.api.nvim_create_user_command("RunFSharpProject", function(opts)
local configuration = "Release"
if opts.fargs and opts.fargs[1] and opts.fargs[1]:match("sproj$") then
RunDotnet("run", { "--project" }, opts.fargs[1], configuration)
elseif opts.fargs and opts.fargs[1] and opts.fargs[2] then
configuration = opts.fargs[1]
RunDotnet("run", { "--project" }, opts.fargs[2], configuration)
else
configuration = opts.fargs[1]
local pickers = require("telescope.pickers")
local finders = require("telescope.finders")
local conf = require("telescope.config").values
local action_state = require("telescope.actions.state")
local actions = require("telescope.actions")
pickers
.new({}, {
prompt_title = "Projects",
finder = finders.new_table({
results = vim.fn["fsharp#getLoadedProjects"](),
}),
sorter = conf.generic_sorter({}),
attach_mappings = function(prompt_buf, _)
actions.select_default:replace(function()
actions.close(prompt_buf)
local selection = action_state.get_selected_entry()
RunDotnet("run", { "--project" }, selection.value, configuration)
end)
return true
end,
})
:find()
end
end, { nargs = "*", complete = "file" })
vim.api.nvim_create_user_command("PublishFSharpProject", function(opts)
if opts.fargs and opts.fargs[1] then
RunDotnet("publish", {}, opts.fargs[1], "Release")
else
local pickers = require("telescope.pickers")
local finders = require("telescope.finders")
local conf = require("telescope.config").values
local action_state = require("telescope.actions.state")
local actions = require("telescope.actions")
pickers
.new({}, {
prompt_title = "Projects",
finder = finders.new_table({
results = vim.fn["fsharp#getLoadedProjects"](),
}),
sorter = conf.generic_sorter({}),
attach_mappings = function(prompt_buf, _)
actions.select_default:replace(function()
actions.close(prompt_buf)
local selection = action_state.get_selected_entry()
RunDotnet("publish", {}, selection.value, "Release")
end)
return true
end,
})
:find()
end
end, { nargs = "*", complete = "file" })
vim.api.nvim_create_autocmd("FileType", {
pattern = "fsharp",
callback = function()
local status, whichkey = pcall(require, "which-key")
if status then
whichkey.add({
{ "<localleader>f", desc = "F#" },
{ "<localleader>ft", ":call fsharp#showTooltip()<CR>", desc = "Show F# Tooltip" },
{ "<localleader>fsi", ":call fsharp#toggleFsi()<CR>", desc = "Toggle FSI (F# Interactive)" },
{ "<localleader>fsl", ":call fsharp#sendLineToFsi()<cr>", desc = "Send line to FSI (F# Interactive)" },
{ "<localleader>fr", desc = "Run F# project" },
{ "<localleader>frd", ":RunFSharpProject Debug", desc = "Run F# project in debug configuration" },
{ "<localleader>frr", ":RunFSharpProject Release", desc = "Run F# project in release configuration" },
{ "<localleader>fp", ":PublishFSharpProject", desc = "Publish F# project" },
{ "<localleader>fb", desc = "Build F# project" },
{ "<localleader>fba", BuildFSharpProjects, desc = "Build all projects" },
{ "<localleader>fbs", ":BuildFSharpProject", desc = "Build specified project" },
}, { buffer = vim.api.nvim_get_current_buf() })
else
vim.api.nvim_set_keymap("n", "<localleader>ft", ":call fsharp#showTooltip()<CR>", { noremap = true })
vim.api.nvim_set_keymap("n", "<localleader>fsi", ":call fsharp#toggleFsi()<CR>", { noremap = true })
vim.api.nvim_set_keymap("n", "<localleader>fsl", ":call fsharp#sendLineToFsi()<CR>", { noremap = true })
vim.api.nvim_set_keymap("n", "<localleader>bpa", ":lua BuildFSharpProjects()", { noremap = true })
vim.api.nvim_set_keymap("n", "<localleader>bps", ":BuildFSharpProject", { noremap = true })
end
end,
})

View File

@@ -0,0 +1,17 @@
require("lspconfig")["leanls"].setup({})
require("lean").setup({})
require("which-key").add({
{ "<localleader>l", desc = "Lean" },
{ "<localleader>li", "<Cmd>LeanInfoviewToggle<CR>", desc = "Toggle Lean info view" },
{ "<localleader>lp", "<Cmd>LeanInfoviewPinTogglePause<CR>", desc = "Pause Lean info view" },
{ "<localleader>ls", "<Cmd>LeanSorryFill<CR>", desc = "Fill open goals with sorry" },
{ "<localleader>lw", "<Cmd>LeanInfoviewEnableWidgets<CR>", desc = "Enable Lean widgets" },
{ "<localleader>lW", "<Cmd>LeanInfoviewDisableWidgets<CR>", desc = "Disable Lean widgets" },
{
"<localleader>l?",
"<Cmd>LeanAbbreviationsReverseLookup<CR>",
desc = "Show what Lean abbreviation produces the symbol under the cursor",
},
})

View File

@@ -0,0 +1,192 @@
local coq = require("coq")
-- Using rustaceanvim means we shouldn't set up the LSP for Rust manually.
-- Similarly csharp_ls is unnecessary given roslyn.nvim
-- require("lspconfig")["csharp_ls"].setup({})
local schemas = {
["https://raw.githubusercontent.com/docker/compose/master/compose/config/compose_spec.json"] = "docker-compose*.{yml,yaml}",
["https://json.schemastore.org/github-workflow.json"] = ".github/**/*.{yml,yaml}",
["https://json.schemastore.org/package.json"] = "package.json",
["https://json.schemastore.org/global.json"] = "global.json",
["https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json"] = "version.json",
["https://json-schema.org/draft/2020-12/schema"] = "*.schema.json",
["https://json.schemastore.org/dotnet-tools.json"] = "dotnet-tools.json",
}
require("lspconfig")["clangd"].setup({})
require("lspconfig")["gopls"].setup({})
require("lspconfig")["yamlls"].setup({
settings = {
yaml = {
validate = true,
-- disable the schema store
schemaStore = {
enable = false,
url = "",
},
-- manually select schemas
schemas = schemas,
},
},
filetypes = { "yaml", "json", "jsonc" },
})
local capabilities = vim.lsp.protocol.make_client_capabilities()
capabilities.textDocument.completion.completionItem.snippetSupport = true
require("lspconfig")["jsonls"].setup({
capabilities = capabilities,
cmd = { "vscode-json-languageserver", "--stdio" },
settings = {
json = {
validate = { enable = true },
},
},
})
require("lspconfig")["denols"].setup({})
require("lspconfig")["bashls"].setup({})
require("lspconfig")["dockerls"].setup({})
require("lspconfig")["html"].setup({
capabilities = capabilities,
})
require("lspconfig")["lua_ls"].setup({
on_init = function(client)
if not client.workspace_folders then
return
end
local path = client.workspace_folders[1].name
if vim.uv.fs_stat(path .. "/.luarc.json") or vim.loop.fs_stat(path .. "/.luarc.jsonc") then
return
end
client.config.settings.Lua = vim.tbl_deep_extend("force", client.config.settings.Lua, {
runtime = {
-- Tell the language server which version of Lua you're using
-- (most likely LuaJIT in the case of Neovim)
version = "LuaJIT",
},
-- Make the server aware of Neovim runtime files
workspace = {
checkThirdParty = false,
library = {
vim.env.VIMRUNTIME,
-- Depending on the usage, you might want to add additional paths here.
-- "${3rd}/luv/library"
-- "${3rd}/busted/library",
},
-- or pull in all of 'runtimepath'. NOTE: this is a lot slower
-- library = vim.api.nvim_get_runtime_file("", true)
},
})
end,
settings = {
Lua = {},
},
})
require("lspconfig").pyright.setup(coq.lsp_ensure_capabilities({
handlers = {
["textDocument/publishDiagnostics"] = function(...)
vim.lsp.diagnostic.on_publish_diagnostics(...)
local window = vim.api.nvim_get_current_win()
vim.diagnostic.setloclist({ open_loclist = true })
vim.api.nvim_set_current_win(window)
end,
},
}))
require("lspconfig").nil_ls.setup(coq.lsp_ensure_capabilities({
settings = {
nix = {
flake = {
autoArchive = true,
},
},
},
}))
function ToggleLocList()
local winid = vim.fn.getloclist(0, { winid = 0 }).winid
if winid == 0 then
local window = vim.api.nvim_get_current_win()
vim.cmd.lopen()
vim.api.nvim_set_current_win(window)
else
vim.cmd.lclose()
end
end
do
local whichkey_status, whichkey = pcall(require, "which-key")
if whichkey_status then
whichkey.add({
{ "<leader>l", desc = "loclist-related commands" },
{ "<leader>lp", vim.diagnostic.goto_prev, desc = "Go to previous entry in loclist" },
{ "<leader>ln", vim.diagnostic.goto_next, desc = "Go to next entry in loclist" },
{ "<leader>ll", ToggleLocList, desc = "Toggle loclist" },
{ "<leader>lf", vim.diagnostic.open_float, desc = "Open current loclist entry in floating window" },
})
else
vim.keymap.set("n", "<leader>lp", vim.diagnostic.goto_prev)
vim.keymap.set("n", "<leader>ln", vim.diagnostic.goto_next)
vim.keymap.set("n", "<leader>ll", ToggleLocList)
vim.keymap.set("n", "<leader>lf", vim.diagnostic.open_float)
end
end
-- Use LspAttach autocommand to only map the following keys
-- after the language server attaches to the current buffer
vim.api.nvim_create_autocmd("LspAttach", {
group = vim.api.nvim_create_augroup("UserLspConfig", {}),
callback = function(ev)
local whichkey = require("which-key")
-- Enable completion triggered by <c-x><c-o>
vim.bo[ev.buf].omnifunc = "v:lua.vim.lsp.omnifunc"
-- Buffer local mappings.
-- See `:help vim.lsp.*` for documentation on any of the below functions
whichkey.add({
{ "g", desc = "Go-to related commands" },
{ "gD", vim.lsp.buf.declaration, desc = "Go to declaration" },
{ "gd", vim.lsp.buf.definition, desc = "Go to definition" },
{ "gi", vim.lsp.buf.implementation, desc = "Go to implementation" },
{
"gr",
function()
require("telescope.builtin").lsp_references()
end,
desc = "Find references",
},
{ "gK", vim.lsp.buf.hover, desc = "Display information about symbol under cursor" },
})
whichkey.add({
{ "<C-k>", vim.lsp.buf.signature_help, desc = "Display signature information about symbol under cursor" },
})
whichkey.add({
{ "<leader>w", desc = "Workspace-related commands" },
{ "<leader>wa", vim.lsp.buf.add_workspace_folder, desc = "Add a path to the workspace folders list" },
{ "<leader>wr", vim.lsp.buf.add_workspace_folder, desc = "Remove a path from the workspace folders list" },
{
"<leader>wl",
function()
print(vim.inspect(vim.lsp.buf.list_workspace_folders()))
end,
desc = "Show the workspace folders list",
},
{
"<leader>f",
function()
vim.lsp.buf.format({ async = true })
end,
desc = "Autoformat",
},
{ "<leader>ca", vim.lsp.buf.code_action, desc = "Select a code action" },
{ "<leader>rn", vim.lsp.buf.rename, desc = "Rename variable" },
{ "<leader>D", vim.lsp.buf.type_definition, desc = "Go to type definition" },
})
end,
})

View File

@@ -0,0 +1,11 @@
require("dap-python").setup("%PYTHONENV%/bin/python")
do
local whichkey = require("which-key")
whichkey.add({
{ "<localleader>pd", desc = "Debugger-related commands" },
{ "<localleader>pdt", desc = "Tests" },
{ "<localleader>pdtf", require("dap-python").test_class, desc = "Run Python tests in the current file" },
{ "<localleader>pdtc", require("dap-python").test_method, desc = "Run the Python test under the cursor" },
})
end

View File

@@ -0,0 +1,65 @@
local dap = require("dap")
local dap_ui = require("dap.ui.widgets")
dap.adapters.coreclr = {
type = "executable",
command = "netcoredbg",
args = { "--interpreter=vscode" },
}
dap.configurations.fsharp = {
{
type = "coreclr",
name = "launch - netcoredbg",
request = "launch",
program = function()
return vim.fn.input("Path to dll: ", vim.fn.getcwd() .. "/bin/Debug/", "file")
end,
},
}
dap.configurations.cs = {
{
type = "coreclr",
name = "launch - netcoredbg",
request = "launch",
program = function()
return vim.fn.input("Path to dll: ", vim.fn.getcwd() .. "/bin/Debug/", "file")
end,
},
}
do
local whichkey = require("which-key")
whichkey.add({
{ "<localleader>d", desc = "Debugger-related commands" },
{ "<localleader>do", dap.step_over, desc = "Step over" },
{ "<localleader>di", dap.step_into, desc = "Step into" },
{ "<localleader>dc", dap.continue, desc = "Continue" },
{ "<localleader>dC", dap.run_last, desc = "Run with last debug configuration" },
{ "<localleader>db", dap.toggle_breakpoint, desc = "Toggle breakpoint" },
{ "<localleader>dr", dap.repl.open, desc = "Open debug repl" },
{ "<localleader>dv", desc = "Commands to view debugger state" },
{
"<localleader>dvv",
function()
dap_ui.hover()
end,
desc = "View value of expression under cursor",
},
{
"<localleader>dvs",
function()
dap_ui.sidebar(dap_ui.scopes).open()
end,
desc = "View values of all variables in all scopes",
},
{
"<localleader>dvf",
function()
dap_ui.sidebar(dap_ui.frames).open()
end,
desc = "View stack frames",
},
{ "<localleader>dt", dap.terminate, desc = "Terminate/stop/end debug session" },
})
end

View File

@@ -0,0 +1,9 @@
require("nvim-lightbulb").setup({
autocmd = { enabled = true },
ignore = {
clients = {
-- This one is really noisy
"lua_ls",
},
},
})

View File

@@ -0,0 +1,64 @@
local function pytest_on_line(_, _, _) end
local function pytest_on_complete(_, code, _)
if code ~= 0 then
print("Exit code " .. code)
end
end
function RunPythonTestAtCursor()
local api = vim.api
-- Get the current buffer and cursor position
local bufnr = api.nvim_get_current_buf()
local line_nr = api.nvim_win_get_cursor(0)[1]
local filename = api.nvim_buf_get_name(bufnr)
-- Read the file content
local lines = api.nvim_buf_get_lines(bufnr, 0, -1, false)
-- Find the test function
local test_name = nil
for i = line_nr, 1, -1 do
local line = lines[i]
if line:match("^def test_") then
test_name = line:match("^def (%S+)%(")
break
end
end
if test_name then
-- Run pytest for the found test function
local context = BuildUtils.create_window()
BuildUtils.run(
"pytest",
{ filename .. "::" .. test_name },
"Run PyTest (" .. test_name .. ")",
context,
pytest_on_line,
pytest_on_complete
)
else
print("No test function found at or above line " .. line_nr)
end
end
function RunPythonTestsInFile()
local file_path = vim.fn.expand("%:p")
local context = BuildUtils.create_window()
BuildUtils.run("pytest", { file_path }, "Run PyTest", context, pytest_on_line, pytest_on_complete)
end
function RunAllPythonTests()
local context = BuildUtils.create_window()
BuildUtils.run("pytest", {}, "Run PyTest", context, pytest_on_line, pytest_on_complete)
end
do
local whichkey = require("which-key")
whichkey.add({
{ "<localleader>pt", desc = "Run Python tests" },
{ "<localleader>ptf", RunPythonTestsInFile, desc = "Run Python tests in the current file" },
{ "<localleader>pta", RunAllPythonTests, desc = "Run all Python tests" },
{ "<localleader>ptc", RunPythonTestAtCursor, desc = "Run the Python test under the cursor" },
})
end

View File

@@ -0,0 +1,4 @@
require("roslyn").setup({
on_attach = function(_, _) end,
capabilities = vim.lsp.protocol.make_client_capabilities(),
})

View File

@@ -0,0 +1,8 @@
require("tokyonight").setup({
style = "night",
on_colors = function(colors)
colors.border = "#565f89"
end,
})
vim.cmd([[colorscheme tokyonight]])

View File

@@ -0,0 +1,9 @@
require("nvim-treesitter.configs").setup({
-- Automatically install missing parsers when entering buffer
-- Recommendation: set to false if you don't have `tree-sitter` CLI installed locally
auto_install = false,
highlight = {
enable = true,
},
})

View File

@@ -0,0 +1,99 @@
local venv_selector = require("venv-selector")
venv_selector.setup({
changed_venv_hooks = { venv_selector.hooks.pyright },
name = { "venv", ".venv" },
search_venv_managers = true,
})
vim.api.nvim_create_autocmd("VimEnter", {
desc = "Auto select virtualenv Nvim open",
pattern = "*",
callback = function()
-- Mystery: this seems to be being called twice whenever we open nvim
local venv = vim.fn.findfile("pyproject.toml", vim.fn.getcwd() .. ";")
if venv ~= "" then
require("venv-selector").retrieve_from_cache()
end
end,
once = true,
})
function SelectVenv()
local old_path = vim.fn.getenv("PATH")
vim.cmd("VenvSelectCached")
local new_path = vim.fn.getenv("PATH")
if old_path == new_path then
-- Failed to source venv. Get the user to choose one.
vim.cmd("VenvSelect")
end
end
local function find_requirements_txt(start_path)
local path = vim.fn.fnamemodify(start_path, ":p")
while path and #path > 1 do
local req_path = path .. "requirements.txt"
if vim.fn.filereadable(req_path) ~= 0 then
return req_path
end
path = vim.fn.fnamemodify(path, ":h")
end
return nil
end
-- TODO: make this one work
local function load_venv(venv_dir)
require("venv-selector.venv").load()
require("venv-selector.venv").set_venv_and_system_paths(venv_dir)
require("venv-selector.venv").cache_venv(venv_dir)
end
function CreateVenv()
local requirements_path = find_requirements_txt(vim.fn.getcwd())
local venv_dir
if not requirements_path then
print("requirements.txt not found; creating fresh venv in current working directory.")
venv_dir = vim.fn.getcwd() .. "/.venv"
else
venv_dir = vim.fn.fnamemodify(requirements_path, ":h") .. "/.venv"
end
print("Creating virtual environment in " .. venv_dir)
-- Create virtual environment
vim.fn.system("python -m venv " .. vim.fn.shellescape(venv_dir))
-- Install requirements
if requirements_path then
print("Installing requirements from " .. requirements_path)
local context = BuildUtils.create_window()
BuildUtils.run(
venv_dir .. "/bin/python",
{ "-m", "pip", "install", "-r", requirements_path },
"venv creation",
context,
function(_, _, _) end,
function(_, _, _)
load_venv(venv_dir)
end
)
else
load_venv(venv_dir)
end
end
do
local whichkey = require("which-key")
whichkey.add({
{ "<localleader>pv", desc = "Python virtual environment-related commands" },
{ "<localleader>pvc", CreateVenv, desc = "Create virtual environment" },
{ "<localleader>pvl", SelectVenv, desc = "Load virtual environment" },
{
"<localleader>pvo",
function()
vim.cmd("VenvSelect")
end,
desc = "Choose (override) new virtual environment",
},
})
end

View File

@@ -0,0 +1,40 @@
require("which-key").setup({
plugins = {
marks = true, -- shows a list of your marks on ' and `
registers = true, -- shows your registers on " in NORMAL or <C-r> in INSERT mode
-- the presets plugin, adds help for a bunch of default keybindings in Neovim
-- No actual key bindings are created
spelling = {
enabled = true, -- enabling this will show WhichKey when pressing z= to select spelling suggestions
suggestions = 20, -- how many suggestions should be shown in the list?
},
presets = {
operators = true, -- adds help for operators like d, y, ...
motions = true, -- adds help for motions
text_objects = true, -- help for text objects triggered after entering an operator
windows = true, -- default bindings on <c-w>
nav = true, -- misc bindings to work with windows
z = true, -- bindings for folds, spelling and others prefixed with z
g = true, -- bindings for prefixed with g
},
},
icons = {
breadcrumb = "»", -- symbol used in the command line area that shows your active key combo
separator = "", -- symbol used between a key and it's label
group = "+", -- symbol prepended to a group
},
layout = {
height = { min = 4, max = 25 }, -- min and max height of the columns
width = { min = 20, max = 50 }, -- min and max width of the columns
spacing = 3, -- spacing between columns
align = "left", -- align columns left, center or right
},
show_help = true, -- show a help message in the command line for using WhichKey
show_keys = true, -- show the currently pressed key and its label as a message in the command line
-- disable the WhichKey popup for certain buf types and file types.
-- Disabled by default for Telescope
disable = {
buftypes = {},
filetypes = {},
},
})

View File

@@ -1,6 +1,6 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/Environment/Hierarchy/NuGetOptions/IncludePrerelease/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/AppBrowserSnapshotsStoreSettings/CurrentStore/@EntryValue">/Users/Patrick/Library/Preferences/Rider2019.3/resharper-host/Sessions</s:String>
<s:String x:Key="/Default/AppBrowserSnapshotsStoreSettings/CurrentStore/@EntryValue">/Users/patrick/Library/Preferences/Rider2019.3/resharper-host/Sessions</s:String>
<s:Boolean x:Key="/Default/CodeEditing/Intellisense/CodeCompletion/CacheImportCompletion/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/Roslyn/LegacySeveritiesMigrated/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/ExternalSources/Decompiler/DecompilerLegalNoticeAccepted/@EntryValue">True</s:Boolean>
@@ -34,7 +34,7 @@
<s:String x:Key="/Default/Profilers/Common/ConfigurationsStore/SelectedProfileConfigurationId/=NotSupported/@EntryIndexedValue">00000000-0000-0000-0000-000000000000</s:String>
<s:String x:Key="/Default/Profilers/Common/ConfigurationsStore/SelectedProfileTestsConfigurationId/=Any/@EntryIndexedValue">2704f639-7a6d-4dc0-8931-351a3f933333</s:String>
<s:Boolean x:Key="/Default/RiderDebugger/RiderRestoreDecompile/RestoreDecompileSetting/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/SnapshotsStore/CurrentStore/@EntryValue">/Users/Patrick/Library/Preferences/Rider2019.3/resharper-host/Sessions</s:String>
<s:String x:Key="/Default/SnapshotsStore/CurrentStore/@EntryValue">/Users/patrick/Library/Preferences/Rider2019.3/resharper-host/Sessions</s:String>
<s:Boolean x:Key="/Default/SymbolServers/RestoreDecompileSetting/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Leet/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=nums/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
<s:Boolean x:Key="/Default/UserDictionary/Words/=nums/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@@ -0,0 +1,49 @@
{
pkgs,
config,
lib,
...
}: let
src = ./GlobalSettingsStorage.DotSettings;
in let
link = ./link.sh;
in let
riderconfig = pkgs.stdenv.mkDerivation {
name = "rider-config";
version = "2023.1";
__contentAddressed = true;
src = src;
phases = ["unpackPhase"];
unpackPhase = ''
mkdir -p "$out"
cp ${src} "$out/GlobalSettingsStorage.DotSettings"
cp ${link} "$out/link.sh"
chmod u+x "$out/link.sh"
sed -i 's_NIX-DOTNET-SDK_${config.rider.dotnet}_' "$out/GlobalSettingsStorage.DotSettings"
sed -i "s!NIX-RIDER-CONFIG!$out!" "$out/link.sh"
'';
installPhase = ''
'';
};
in {
options = {
rider.enable = lib.mkOption {default = false;};
rider.username = lib.mkOption {
type = lib.types.str;
example = "Patrick";
};
rider.dotnet = lib.mkOption {default = pkgs.dotnet-sdk;};
};
config = lib.mkIf config.rider.enable {
home.activation.jetbrains-rider-settings = lib.hm.dag.entryAfter ["writeBoundary"] ''
dest="/Users/${config.rider.username}/Library/Application Support/JetBrains"
if [ -e "$dest" ]; then
find "$dest" -maxdepth 1 -type d -name 'Rider*' -exec sh -c '${riderconfig}/link.sh "$0"' {} \;
fi
'';
};
}

View File

@@ -3,17 +3,19 @@
outfile="$1/resharper-host/GlobalSettingsStorage.DotSettings"
if [ -e "$outfile" ]; then
existing=$(readlink "$outfile")
if [ $? -eq 1 ] ; then
if [ $? -eq 1 ]; then
echo "Backing up existing settings file $outfile"
mv "$outfile" "$outfile.bak"
ln -s "NIX-RIDER-CONFIG/GlobalSettingsStorage.DotSettings" "$outfile"
else
case "$existing" in
"/nix/store/"*)
ln -fs "NIX-RIDER-CONFIG/GlobalSettingsStorage.DotSettings" "$outfile" ;;
ln -fs "NIX-RIDER-CONFIG/GlobalSettingsStorage.DotSettings" "$outfile"
;;
*)
echo "Refusing to overwrite existing symlink to $existing" && \
exit 1 ;;
echo "Refusing to overwrite existing symlink to $existing" &&
exit 1
;;
esac
fi
else

View File

@@ -4,4 +4,4 @@ Host *
AddKeysToAgent yes
IgnoreUnknown UseKeychain
UseKeychain yes
IdentityFile ~/.ssh/id_rsa
IdentityFile ~/.ssh/id_ed25519

4
home-manager/sway.conf Normal file
View File

@@ -0,0 +1,4 @@
output Unknown-1 scale 2
input * {
xkb_layout "gb"
}

View File

@@ -0,0 +1,87 @@
{pkgs}:
with pkgs.vscode-extensions;
[
bbenoist.nix
haskell.haskell
yzhang.markdown-all-in-one
james-yu.latex-workshop
vscodevim.vim
ms-dotnettools.csharp
ms-vscode-remote.remote-ssh
justusadam.language-haskell
rust-lang.rust-analyzer
github.vscode-pull-request-github
shardulm94.trailing-spaces
nvarner.typst-lsp
arrterian.nix-env-selector
# Doesn't build on arm64
# vadimcn.vscode-lldb
]
++ pkgs.vscode-utils.extensionsFromVscodeMarketplace [
{
name = "remote-containers";
publisher = "ms-vscode-remote";
version = "0.285.0";
sha256 = "sha256-UHp6Ewx0bUvPjgaO0A5k77SGj8ovPFLl/WvxyLcZ4y0=";
}
{
name = "vscode-hsx";
publisher = "s0kil";
version = "0.4.0";
sha256 = "sha256-/WRy+cQBqzb6QB5+AizlyIcjqNpZ86o2at885hOcroM=";
}
{
name = "vscode-docker";
publisher = "ms-azuretools";
version = "1.24.0";
sha256 = "sha256-zZ34KQrRPqVbfGdpYACuLMiMj4ZIWSnJIPac1yXD87k=";
}
{
name = "toml";
publisher = "be5invis";
version = "0.6.0";
sha256 = "yk7buEyQIw6aiUizAm+sgalWxUibIuP9crhyBaOjC2E=";
}
{
name = "ionide-fsharp";
publisher = "ionide";
version = "7.18.1";
sha256 = "sha256-6NPMQncoZhZYtx5c+qzarjuSzUXMb5HdKCzcHPCFUhU=";
}
{
name = "lean4";
publisher = "leanprover";
version = "0.0.128";
sha256 = "sha256-odRDOrlDFahweLzoQtpufY8UUwAutPFunqg7atTxnPo=";
}
{
name = "vscode-clang";
publisher = "mitaki28";
version = "0.2.4";
sha256 = "0sys2h4jvnannlk2q02lprc2ss9nkgh0f0kwa188i7viaprpnx23";
}
{
name = "dotnet-interactive-vscode";
publisher = "ms-dotnettools";
version = "1.0.4165021";
sha256 = "sha256-P5EHc5t4UyKEfxIGNTg+SyQPFlrbwaNIaprPY63iJ/k=";
}
{
name = "mono-debug";
publisher = "ms-vscode";
version = "0.16.3";
sha256 = "sha256-6IU8aP4FQVbEMZAgssGiyqM+PAbwipxou5Wk3Q2mjZg=";
}
{
name = "Theme-MarkdownKit";
publisher = "ms-vscode";
version = "0.1.4";
sha256 = "1im78k2gaj6cri2jcvy727qdy25667v0f7vv3p3hv13apzxgzl0l";
}
{
name = "debug";
publisher = "webfreak";
version = "0.26.1";
sha256 = "sha256-lLLa8SN+Sf9Tbi7HeWYWa2KhPQFJyQWrf9l3EUljwYo=";
}
]

209
home.nix
View File

@@ -1,209 +0,0 @@
{
nixpkgs,
...
}:
let
username = "Patrick";
in let
dotnet = nixpkgs.dotnet-sdk_6;
in {
imports = [./rider];
rider = {
enable = true;
username = username;
dotnet = dotnet;
};
# Let Home Manager install and manage itself.
programs.home-manager.enable = true;
# Home Manager needs a bit of information about you and the
# paths it should manage.
home.username = username;
# This value determines the Home Manager release that your
# configuration is compatible with. This helps avoid breakage
# when a new Home Manager release introduces backwards
# incompatible changes.
#
# You can update Home Manager without changing this value. See
# the Home Manager release notes for a list of state version
# changes in each release.
home.stateVersion = "22.05";
home.packages =
[
nixpkgs.rust-analyzer
nixpkgs.tmux
nixpkgs.wget
nixpkgs.youtube-dl
nixpkgs.cmake
nixpkgs.gnumake
nixpkgs.gcc
nixpkgs.gdb
nixpkgs.hledger
nixpkgs.hledger-web
dotnet
nixpkgs.docker
nixpkgs.jitsi-meet
#nixpkgs.handbrake
nixpkgs.ripgrep
nixpkgs.elan
nixpkgs.coreutils-prefixed
nixpkgs.shellcheck
nixpkgs.html-tidy
nixpkgs.hugo
#nixpkgs.agda
nixpkgs.pijul
nixpkgs.universal-ctags
nixpkgs.asciinema
nixpkgs.git-lfs
nixpkgs.imagemagick
nixpkgs.nixpkgs-fmt
nixpkgs.rnix-lsp
];
programs.vscode = {
enable = true;
package = nixpkgs.vscode;
extensions = import ./vscode-extensions.nix { pkgs = nixpkgs; };
userSettings = {
workbench.colorTheme = "Default High Contrast";
"files.Exclude" = {
"**/.git" = true;
"**/.DS_Store" = true;
"**/Thumbs.db" = true;
"**/*.olean" = true;
"**/result" = true;
};
"git.path" = "${nixpkgs.git}/bin/git";
"update.mode" = "none";
"docker.dockerPath" = "${nixpkgs.docker}/bin/docker";
#"lean.leanpkgPath" = "/Users/${username}/.elan/toolchains/stable/bin/leanpkg";
"lean.executablePath" = "/Users/${username}/.elan/toolchains/lean4/bin/lean";
"lean.memoryLimit" = 8092;
};
};
programs.tmux = {
shell = "\${nixpkgs.zsh}/bin/zsh";
};
programs.zsh = {
enable = true;
autocd = true;
enableAutosuggestions = true;
enableCompletion = true;
history = {
expireDuplicatesFirst = true;
};
oh-my-zsh = {
enable = true;
plugins = ["git" "macos" "dircycle" "timer"];
theme = "robbyrussell";
};
sessionVariables = {
EDITOR = "vim";
LC_ALL = "en_US.UTF-8";
LC_CTYPE = "en_US.UTF-8";
RUSTFLAGS = "-L ${nixpkgs.libiconv}/lib";
RUST_BACKTRACE = "full";
};
shellAliases = {
vim = "nvim";
view = "vim -R";
nix-upgrade = "sudo -i sh -c 'nix-channel --update && nix-env -iA nixpkgs.nix && launchctl remove org.nixos.nix-daemon && launchctl load /Library/LaunchDaemons/org.nixos.nix-daemon.plist'";
cmake = "cmake -DCMAKE_MAKE_PROGRAM=${nixpkgs.gnumake}/bin/make -DCMAKE_AR=${nixpkgs.darwin.cctools}/bin/ar -DCMAKE_RANLIB=${nixpkgs.darwin.cctools}/bin/ranlib -DGMP_INCLUDE_DIR=${nixpkgs.gmp.dev}/include/ -DGMP_LIBRARIES=${nixpkgs.gmp}/lib/libgmp.10.dylib";
ar = "${nixpkgs.darwin.cctools}/bin/ar";
};
};
programs.fzf = {
enable = true;
enableZshIntegration = true;
};
programs.git = {
package = nixpkgs.gitAndTools.gitFull;
enable = true;
userName = "Smaug123";
userEmail = "patrick+github@patrickstevens.co.uk";
aliases = {
co = "checkout";
st = "status";
};
extraConfig = {
rerere = {
enabled = true;
};
push = {
default = "current";
};
pull = {
rebase = false;
};
init = {
defaultBranch = "main";
};
advice = {
addIgnoredFile = false;
};
"filter \"lfs\"" = {
clean = "${nixpkgs.git-lfs} clean -- %f";
smudge = "${nixpkgs.git-lfs}/bin/git-lfs smudge --skip -- %f";
process = "${nixpkgs.git-lfs}/bin/git-lfs filter-process";
required = true;
};
pull = {
twohead = "ort";
};
};
};
programs.neovim.enable = true;
programs.neovim.plugins = with nixpkgs.vimPlugins; [
molokai
tagbar
{
plugin = rust-vim;
config = "let g:rustfmt_autosave = 1";
}
{
plugin = LanguageClient-neovim;
config = "let g:LanguageClient_serverCommands = { 'nix': ['rnix-lsp'] }";
}
{
plugin = syntastic;
config = '' let g:syntastic_rust_checkers = ['cargo']
let g:syntastic_always_populate_loc_list = 1
let g:syntastic_auto_loc_list = 1
let g:syntastic_check_on_open = 1
let g:syntastic_check_on_wq = 0'';
}
YouCompleteMe
tagbar
];
programs.neovim.viAlias = true;
programs.neovim.vimAlias = true;
programs.neovim.vimdiffAlias = true;
programs.neovim.withPython3 = true;
programs.neovim.extraConfig = builtins.readFile ./init.vim;
home.file.".ssh/config".source = ./ssh.config;
home.file.".ideavimrc".source = ./ideavimrc;
home.file.".config/youtube-dl/config".source = ./youtube-dl.conf;
programs.emacs = {
enable = true;
package = nixpkgs.emacsGcc;
extraPackages = (epkgs: []);
extraConfig = ''
(load-file (let ((coding-system-for-read 'utf-8))
(shell-command-to-string "agda-mode locate")))
'';
};
}

368
init.vim
View File

@@ -1,368 +0,0 @@
set nu
colorscheme molokai
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Maintainer:
" Amir Salihefendic — @amix3k
"
" Awesome_version:
" Get this config, nice color schemes and lots of plugins!
"
" Install the awesome version from:
"
" https://github.com/amix/vimrc
"
" Sections:
" -> General
" -> VIM user interface
" -> Colors and Fonts
" -> Files and backups
" -> Text, tab and indent related
" -> Visual mode related
" -> Moving around, tabs and buffers
" -> Status line
" -> Editing mappings
" -> vimgrep searching and cope displaying
" -> Spell checking
" -> Misc
" -> Helper functions
"
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => General
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Sets how many lines of history VIM has to remember
set history=500
" Enable filetype plugins
filetype plugin on
filetype indent on
" Set to auto read when a file is changed from the outside
set autoread
" With a map leader it's possible to do extra key combinations
" like <leader>w saves the current file
let mapleader = "`"
" :W sudo saves the file
" (useful for handling the permission-denied error)
command W w !sudo tee % > /dev/null
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => VIM user interface
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Set 7 lines to the cursor - when moving vertically using j/k
set so=7
" Avoid garbled characters in Chinese language windows OS
let $LANG='en'
set langmenu=en
source $VIMRUNTIME/delmenu.vim
source $VIMRUNTIME/menu.vim
" Turn on the Wild menu
set wildmenu
" Ignore compiled files
set wildignore=*.o,*~,*.pyc
if has("win16") || has("win32")
set wildignore+=.git\*,.hg\*,.svn\*
else
set wildignore+=*/.git/*,*/.hg/*,*/.svn/*,*/.DS_Store
endif
"Always show current position
set ruler
" Height of the command bar
set cmdheight=2
" A buffer becomes hidden when it is abandoned
set hid
" Ignore case when searching
set ignorecase
" When searching try to be smart about cases
set smartcase
" Highlight search results
set hlsearch
" Makes search act like search in modern browsers
set incsearch
" Don't redraw while executing macros (good performance config)
set lazyredraw
" For regular expressions turn magic on
set magic
" Show matching brackets when text indicator is over them
set showmatch
" How many tenths of a second to blink when matching brackets
set mat=2
" No annoying sound on errors
set noerrorbells
set novisualbell
set t_vb=
set tm=500
" Properly disable sound on errors on MacVim
if has("gui_macvim")
autocmd GUIEnter * set vb t_vb=
endif
" Add a bit extra margin to the left
set foldcolumn=1
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => Colors and Fonts
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Enable syntax highlighting
syntax enable
" Enable 256 colors palette in Gnome Terminal
if $COLORTERM == 'gnome-terminal'
set t_Co=256
endif
set background=dark
" Set extra options when running in GUI mode
if has("gui_running")
set guioptions-=T
set guioptions-=e
set t_Co=256
set guitablabel=%M\ %t
endif
" Set utf8 as standard encoding and en_US as the standard language
set encoding=utf8
" Use Unix as the standard file type
set ffs=unix,dos,mac
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => Files, backups and undo
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Turn backup off, since most stuff is in SVN, git et.c anyway...
set nobackup
set nowb
set noswapfile
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => Text, tab and indent related
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Use spaces instead of tabs
set expandtab
" Be smart when using tabs ;)
set smarttab
" 1 tab == 4 spaces
set shiftwidth=4
set tabstop=4
" Linebreak on 500 characters
set lbr
set tw=500
set ai "Auto indent
set si "Smart indent
set wrap "Wrap lines
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => Moving around, tabs, windows and buffers
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Map <Space> to / (search) and Ctrl-<Space> to ? (backwards search)
map <space> /
map <c-space> ?
" Disable highlight when <leader><cr> is pressed
map <silent> <leader><cr> :noh<cr>
" Smart way to move between windows
map <C-j> <C-W>j
map <C-k> <C-W>k
map <C-h> <C-W>h
map <C-l> <C-W>l
" Close the current buffer
map <leader>bd :Bclose<cr>:tabclose<cr>gT
" Close all the buffers
map <leader>ba :bufdo bd<cr>
map <leader>l :bnext<cr>
map <leader>h :bprevious<cr>
" Useful mappings for managing tabs
map <leader>tn :tabnew<cr>
map <leader>to :tabonly<cr>
map <leader>tc :tabclose<cr>
map <leader>tm :tabmove
map <leader>t<leader> :tabnext
" Let 'tl' toggle between this and the last accessed tab
let g:lasttab = 1
nmap <Leader>tl :exe "tabn ".g:lasttab<CR>
au TabLeave * let g:lasttab = tabpagenr()
" Opens a new tab with the current buffer's path
" Super useful when editing files in the same directory
map <leader>te :tabedit <c-r>=expand("%:p:h")<cr>/
" Switch CWD to the directory of the open buffer
map <leader>cd :cd %:p:h<cr>:pwd<cr>
" Specify the behavior when switching between buffers
try
set switchbuf=useopen,usetab,newtab
set stal=2
catch
endtry
" Return to last edit position when opening files (You want this!)
au BufReadPost * if line("'\"") > 1 && line("'\"") <= line("$") | exe "normal! g'\"" | endif
""""""""""""""""""""""""""""""
" => Status line
""""""""""""""""""""""""""""""
" Always show the status line
set laststatus=2
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => Editing mappings
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Move a line of text using ALT+[jk] or Command+[jk] on mac
nmap <M-j> mz:m+<cr>`z
nmap <M-k> mz:m-2<cr>`z
vmap <M-j> :m'>+<cr>`<my`>mzgv`yo`z
vmap <M-k> :m'<-2<cr>`>my`<mzgv`yo`z
if has("mac") || has("macunix")
nmap <D-j> <M-j>
nmap <D-k> <M-k>
vmap <D-j> <M-j>
vmap <D-k> <M-k>
endif
" Delete trailing white space on save, useful for some filetypes ;)
fun! CleanExtraSpaces()
let save_cursor = getpos(".")
let old_query = getreg('/')
silent! %s/\s\+$//e
call setpos('.', save_cursor)
call setreg('/', old_query)
endfun
if has("autocmd")
autocmd BufWritePre *.fs,*.fsi,*.txt,*.js,*.py,*.wiki,*.sh,*.coffee :call CleanExtraSpaces()
endif
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => Spell checking
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Pressing ,ss will toggle and untoggle spell checking
map <leader>ss :setlocal spell!<cr>
" Shortcuts using <leader>
map <leader>sn ]s
map <leader>sp [s
map <leader>sa zg
map <leader>s? z=
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => Misc
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Remove the Windows ^M - when the encodings gets messed up
noremap <Leader>m mmHmt:%s/<C-V><cr>//ge<cr>'tzt'm
" Quickly open a buffer for scribble
map <leader>q :e ~/buffer<cr>
" Quickly open a markdown buffer for scribble
map <leader>x :e ~/buffer.md<cr>
" Toggle paste mode on and off
map <leader>pp :setlocal paste!<cr>
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => Helper functions
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Returns true if paste mode is enabled
function! HasPaste()
if &paste
return 'PASTE MODE '
endif
return ''
endfunction
" Don't close window, when deleting a buffer
command! Bclose call <SID>BufcloseCloseIt()
function! <SID>BufcloseCloseIt()
let l:currentBufNum = bufnr("%")
let l:alternateBufNum = bufnr("#")
if buflisted(l:alternateBufNum)
buffer #
else
bnext
endif
if bufnr("%") == l:currentBufNum
new
endif
if buflisted(l:currentBufNum)
execute("bdelete! ".l:currentBufNum)
endif
endfunction
function! CmdLine(str)
call feedkeys(":" . a:str)
endfunction
function! VisualSelection(direction, extra_filter) range
let l:saved_reg = @"
execute "normal! vgvy"
let l:pattern = escape(@", "\\/.*'$^~[]")
let l:pattern = substitute(l:pattern, "\n$", "", "")
if a:direction == 'gv'
call CmdLine("Ack '" . l:pattern . "' " )
elseif a:direction == 'replace'
call CmdLine("%s" . '/'. l:pattern . '/')
endif
let @/ = l:pattern
let @" = l:saved_reg
endfunction
nnoremap <leader>c :!cargo clippy
set statusline+=%#warningmsg#
set statusline+=%{SyntasticStatuslineFlag()}
set statusline+=%*
" Format the status line
set statusline=\ %{HasPaste()}%F%m%r%h\ %w\ \ CWD:\ %r%{getcwd()}%h\ \ \ Line:\ %l\ \ Column:\ %c

11
mbsync.nix Normal file
View File

@@ -0,0 +1,11 @@
{pkgs}:
pkgs.buildEnv {
name = "isync-oauth2";
paths = [pkgs.isync];
pathsToLink = ["/bin"];
nativeBuildInputs = [pkgs.makeWrapper];
postBuild = ''
wrapProgram "$out/bin/mbsync" \
--prefix SASL_PATH : "${pkgs.cyrus_sasl}/lib/sasl2:${pkgs.cyrus-sasl-xoauth2}/lib/sasl2"
'';
}

View File

@@ -1,10 +0,0 @@
[
(self: super: {
# https://github.com/NixOS/nixpkgs/issues/153304
alacritty = super.alacritty.overrideAttrs (
o: rec {
doCheck = false;
}
);
})
]

View File

@@ -1,16 +0,0 @@
{ pkgs }:
let my-python-packages = python-packages: with python-packages; [
pip
mathlibtools
];
in
let packageOverrides = self: super: {
# Test failures on darwin ("windows-1252"); just skip pytest
# (required for elan)
beautifulsoup4 = super.beautifulsoup4.overridePythonAttrs (old: { pytestCheckPhase = "true"; });
};
in
(pkgs.python3.override { inherit packageOverrides; }).withPackages my-python-packages

View File

@@ -1,44 +0,0 @@
{ pkgs, config, lib, ... }:
let src = ./GlobalSettingsStorage.DotSettings; in
let link = ./link.sh; in
let riderconfig =
pkgs.stdenv.mkDerivation {
name = "rider-config";
version = "2021.2";
src = src;
phases = [ "unpackPhase" ];
unpackPhase = ''
mkdir -p "$out"
cp ${src} "$out/GlobalSettingsStorage.DotSettings"
cp ${link} "$out/link.sh"
chmod u+x "$out/link.sh"
sed -i 's_NIX-DOTNET-SDK_${config.rider.dotnet}_' "$out/GlobalSettingsStorage.DotSettings"
sed -i "s!NIX-RIDER-CONFIG!$out!" "$out/link.sh"
'';
installPhase = ''
'';
};
in
{
options = {
rider.enable = lib.mkOption { default = false; };
rider.username = lib.mkOption { type = lib.types.str; example = "Patrick"; };
rider.dotnet = lib.mkOption { default = pkgs.dotnet-sdk; };
};
config = lib.mkIf config.rider.enable {
home.activation.jetbrains-rider-settings = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
dest="/Users/${config.rider.username}/Library/Application Support/JetBrains"
if [ -e "$dest" ]; then
find "$dest" -maxdepth 1 -type d -name 'Rider*' -exec sh -c '${riderconfig}/link.sh "$0"' {} \;
fi
'';
};
}

View File

@@ -1,115 +0,0 @@
{pkgs}:
with pkgs.vscode-extensions;
[
bbenoist.nix
haskell.haskell
yzhang.markdown-all-in-one
james-yu.latex-workshop
vscodevim.vim
# Not supported on Darwin, apparently
# ms-dotnettools.csharp
]
++ pkgs.vscode-utils.extensionsFromVscodeMarketplace [
{
name = "remote-containers";
publisher = "ms-vscode-remote";
version = "0.222.0";
sha256 = "4Li0sYfHOsJMn5FJtvDTGKoGPcRmoosD9tZ7q9H9DfQ=";
}
{
name = "remote-ssh";
publisher = "ms-vscode-remote";
version = "0.75.2022021903";
sha256 = "hTRfoUHKrIOSV8eZ/62ewaII5291huXjOZ++dRUmKoI=";
}
{
name = "vscode-docker";
publisher = "ms-azuretools";
version = "1.19.0";
sha256 = "UPUfTOc5xJhI5ACm2oyWqtZ4zNxZjy16D6Mf30eHFEI=";
}
{
name = "code-gnu-global";
publisher = "austin";
version = "0.2.2";
sha256 = "1fz89m6ja25aif6wszg9h2fh5vajk6bj3lp1mh0l2b04nw2mzhd5";
}
{
name = "rust-analyzer";
publisher = "matklad";
version = "0.3.939";
sha256 = "t5CCUdFCiSYrMsBHG5eOfg3sXMacFWiR0hmVa7S1i8Y=";
}
{
name = "vscode-lldb";
publisher = "vadimcn";
version = "1.6.10";
sha256 = "CGVVs//jIZM8uX7Wc9gM4aQGwECi88eIpfPqU2hKbeA=";
}
{
name = "toml";
publisher = "be5invis";
version = "0.6.0";
sha256 = "yk7buEyQIw6aiUizAm+sgalWxUibIuP9crhyBaOjC2E=";
}
{
name = "Ionide-Paket";
publisher = "Ionide";
version = "2.0.0";
sha256 = "1455zx5p0d30b1agdi1zw22hj0d3zqqglw98ga8lj1l1d757gv6v";
}
{
name = "lean";
publisher = "jroesch";
version = "0.16.46";
sha256 = "hjflz5JHVr1YWq6QI9DpdNPY1uL7lAuQTMAdwCtLEfY=";
}
{
name = "language-haskell";
publisher = "justusadam";
version = "3.4.0";
sha256 = "0ab7m5jzxakjxaiwmg0jcck53vnn183589bbxh3iiylkpicrv67y";
}
{
name = "vscode-clang";
publisher = "mitaki28";
version = "0.2.4";
sha256 = "0sys2h4jvnannlk2q02lprc2ss9nkgh0f0kwa188i7viaprpnx23";
}
{
name = "dotnet-interactive-vscode";
publisher = "ms-dotnettools";
version = "1.0.3103011";
sha256 = "a3u9NKsqHZKhZkKqJqo+LgJFTL2yhehBepTOFOXE+jY=";
}
{
name = "python";
publisher = "ms-python";
version = "2022.0.1814523869";
sha256 = "hXTVZ7gbu234zyAg0ZrZPUo6oULB98apxe79U2yQHD4=";
}
{
name = "mono-debug";
publisher = "ms-vscode";
version = "0.16.2";
sha256 = "10hixqkw5r3cg52xkbky395lv72sb9d9wrngdvmrwx62hkbk5465";
}
{
name = "Theme-MarkdownKit";
publisher = "ms-vscode";
version = "0.1.4";
sha256 = "1im78k2gaj6cri2jcvy727qdy25667v0f7vv3p3hv13apzxgzl0l";
}
{
name = "trailing-spaces";
publisher = "shardulm94";
version = "0.3.1";
sha256 = "0h30zmg5rq7cv7kjdr5yzqkkc1bs20d72yz9rjqag32gwf46s8b8";
}
{
name = "debug";
publisher = "webfreak";
version = "0.25.1";
sha256 = "1l01sv6kwh8dlv3kygkkd0z9m37hahflzd5bx1wwij5p61jg7np9";
}
]