75 Commits

Author SHA1 Message Date
Smaug123
2a962e928b Mail on Linux 2024-04-19 15:55:00 +01: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
Patrick Stevens
87492c2abe Big neovim overhaul (#38) 2024-03-26 00:04:01 +00:00
Patrick Stevens
15e603063a Remove sops (#37) 2024-03-26 00:00:04 +00:00
Patrick Stevens
028817765e Evil-mode (#36) 2024-03-25 23:55:45 +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
dependabot[bot]
31e8d08da3 Bump cachix/install-nix-action from 25 to 26 (#33) 2024-03-11 07:30:57 +00:00
Patrick Stevens
75c77e99c0 Rem oh-my-zsh (#32) 2024-02-23 22:47:37 +00:00
Patrick Stevens
ef6d3d4445 FiraCode (#31) 2024-02-23 14:18:18 +00:00
Patrick Stevens
a3a8a5598a Add some extensions (#30) 2024-02-23 11:11:31 +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
Smaug123
e603de3347 Update VSCode extensions 2022-02-20 09:54:34 +00:00
Smaug123
fc0987c71e Merge branch 'main' of github.com:Smaug123/nix-dotfiles 2022-02-20 09:46:44 +00:00
Patrick Stevens
76b0a99899 Update Nixpkgs (#7) 2022-02-20 09:46:28 +00:00
Smaug123
9071035ba2 Format 2022-02-18 20:02:50 +00:00
Patrick Stevens
2463b3275b Use flakes (#6) 2022-02-06 14:40:14 +00:00
Smaug123
278ef5278d Remove ca-derivations again 2022-02-06 13:06:46 +00:00
Smaug123
cf971dbbb9 Lean 4 2022-02-05 10:21:46 +00:00
Smaug123
73539bc753 Fix up some config 2022-02-04 19:58:13 +00:00
Smaug123
4cdf00f879 A few bits and bobs 2022-01-26 20:17:50 +00:00
Smaug123
49b4432235 Upgrade extensions 2022-01-16 22:59:35 +00:00
Smaug123
135a036dd8 Add imagemagick 2022-01-16 22:56:38 +00:00
Smaug123
4e0ed30fbf Upgrade VS Code 2021-12-20 21:35:49 +00:00
Smaug123
40c8093b49 Remove custom GMP setup entirely 2021-12-12 19:10:12 +00:00
66 changed files with 3866 additions and 826 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"

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

@@ -0,0 +1,26 @@
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@v26"
with: { "extra_nix_config": "access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}" }
- name: "Check flake"
run: "nix flake check --all-systems"
all-required-checks-complete:
runs-on: "ubuntu-latest"
steps:
- run: "echo \"All required checks complete.\""
needs:
- "flake-check"

6
.gitignore vendored
View File

@@ -1 +1,5 @@
result/
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

16
VsCodeExtensions.sln Normal file
View File

@@ -0,0 +1,16 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "VsCodeExtensions", "VsCodeExtensions\VsCodeExtensions.fsproj", "{5BD60C47-954A-42E3-9863-9B6ED29AC112}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5BD60C47-954A-42E3-9863-9B6ED29AC112}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5BD60C47-954A-42E3-9863-9B6ED29AC112}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5BD60C47-954A-42E3-9863-9B6ED29AC112}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5BD60C47-954A-42E3-9863-9B6ED29AC112}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

178
VsCodeExtensions/Program.fs Normal file
View File

@@ -0,0 +1,178 @@
open System.IO
open System.Net.Http
open System.Text.Json
type Extension =
{
Name : string
Publisher : string
Version : string
Sha256 : string
}
override this.ToString () =
[
"{"
$" name = \"{this.Name}\";"
$" publisher = \"{this.Publisher}\";"
$" version = \"{this.Version}\";"
$" sha256 = \"{this.Sha256}\";"
"}"
]
|> String.concat "\n"
static member Parse (s : string list) : Extension =
let collection =
s
|> List.fold (fun fields s ->
match s.Split "=" |> List.ofArray with
| field :: rest when not <| rest.IsEmpty ->
Map.add (field.Trim ()) ((String.concat "=" rest).Split('"').[1].TrimEnd(';')) fields
| _ -> fields
) Map.empty
{
Name = collection.["name"]
Publisher = collection.["publisher"]
Version = collection.["version"]
Sha256 = collection.["sha256"]
}
type Skipped =
{
NixpkgsRef : string
Reason : string
}
override this.ToString () =
[
$"# {this.Reason}"
$"# {this.NixpkgsRef}"
]
|> String.concat "\n"
let bimap f g (x, y) = (f x, g y)
let partition<'a, 'b> (l : List<Choice<'a, 'b>>) : 'a list * 'b list =
l
|> List.fold (fun (aEntries, bEntries) next ->
match next with
| Choice1Of2 a -> (a :: aEntries, bEntries)
| Choice2Of2 b -> (aEntries, b :: bEntries)
) ([], [])
|> bimap List.rev List.rev
type NixFile =
{
NixpkgsRefs : string list
Skipped : Skipped list
SpecificVersions : Extension list
}
override this.ToString () =
[
yield "{ pkgs }:"
yield ""
yield "with pkgs.vscode-extensions; ["
yield! this.NixpkgsRefs |> List.map (sprintf " %s")
yield! this.Skipped |> List.map (sprintf "%O")
yield "] ++ pkgs.vscode-utils.extensionsFromVscodeMarketplace ["
yield! this.SpecificVersions |> List.map (sprintf "%O")
yield "]"
]
|> String.concat "\n"
static member Parse (s : string) : NixFile =
let pre, post =
s.Split "++ pkgs.vscode-utils.extensionsFromVscodeMarketplace ["
|> function
| [| pre ; post |] -> pre, post
| _ -> failwith "Unexpected number of '++'"
let verbatim, skipped =
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())
)
|> partition
| _ -> failwith $"Unexpected pre:\n{pre}"
let pairs (l : 'a list) : ('a * 'a) list =
let rec go acc l =
match l with
| [] -> acc
| [singleton] -> failwith $"Expected pair, got {singleton}"
| x :: y :: rest -> go ((x, y) :: acc) rest
go [] l
|> List.rev
let skipped =
skipped
|> pairs
|> List.map (fun (comment, link) -> { NixpkgsRef = link ; Reason = comment })
let specificVersions =
post.TrimEnd([| '\n' ; ']'|]).Split "}"
|> Array.choose (fun contents ->
match contents.Trim([|'\n' ; ' '|]).Split "\n" |> List.ofArray with
| "{" :: rest ->
Some (Extension.Parse rest)
| [] ->
failwith $"Expected extension, got:\n{contents}"
| [""] -> None
| fst :: rest ->
failwith $"Expected bracket, got '{fst}'\n {rest}"
)
|> Array.toList
{
Skipped = skipped
NixpkgsRefs = verbatim
SpecificVersions = specificVersions
}
type Version =
{
Version : string
TargetPlatform : string
}
let upgradeExtension (client : HttpClient) (e : Extension) : Extension Async =
let uri = System.Uri $"https://marketplace.visualstudio.com/items?itemName={e.Publisher}.{e.Name}"
async {
let! response = client.GetAsync uri |> Async.AwaitTask
let! content = response.Content.ReadAsStringAsync () |> Async.AwaitTask
let options = JsonSerializerOptions ()
options.PropertyNameCaseInsensitive <- true
let latestVersion =
content.Split("\"Versions\":[").[1].Split("]").[0]
|> sprintf "[%s]"
|> fun s -> JsonSerializer.Deserialize<Version array> (s, options)
|> Seq.head
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 =
use client = new HttpClient ()
{ nixFile with
SpecificVersions =
nixFile.SpecificVersions
|> List.map (upgradeExtension client)
|> Async.Parallel
|> Async.RunSynchronously
|> List.ofArray
}
module Program =
[<EntryPoint>]
let main args =
let sourceFile =
if args.Length = 0 then "vscode-extensions.nix" else args.[0]
File.ReadAllText sourceFile
|> NixFile.Parse
|> upgrade
|> string<NixFile>
|> fun s -> File.WriteAllText (sourceFile, s)
0

View File

@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Compile Include="Program.fs"/>
</ItemGroup>
</Project>

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,55 +1,82 @@
{ config, lib, pkgs, ... }:
let python = import ./python.nix { inherit pkgs; }; in
{
{pkgs, ...}: let
mbsync = import ./mbsync.nix {inherit pkgs;};
in {
nix.useDaemon = true;
imports = [ <home-manager/nix-darwin> ];
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.users.Patrick = import ./home.nix;
# 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";
nixpkgs.overlays = [
(import (builtins.fetchTarball {
url = https://github.com/nix-community/emacs-overlay/archive/25dd5297f613fd13971e4847e82d1097077eeb53.tar.gz;
}))
];
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;
};
};
nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [
"vscode"
];
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";
StartInterval = 60;
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;
nix.useSandbox = true;
# Sandbox causes failure: https://github.com/NixOS/nix/issues/4119
nix.settings.sandbox = false;
nix.extraOptions = ''
auto-optimise-store = true
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=
'';
# Used for backwards compatibility, please read the changelog before changing.

View File

454
flake.lock generated Normal file
View File

@@ -0,0 +1,454 @@
{
"nodes": {
"apple-silicon": {
"inputs": {
"flake-compat": "flake-compat",
"nixpkgs": "nixpkgs",
"rust-overlay": "rust-overlay"
},
"locked": {
"lastModified": 1712279577,
"narHash": "sha256-Bwn4rmQi2L2iX6g3ycQMA4baE3zgPHAO0xPBpr2T4/k=",
"owner": "tpwrules",
"repo": "nixos-apple-silicon",
"rev": "d47afc3f0f8b3078c818da8609c41340af61a2ec",
"type": "github"
},
"original": {
"owner": "tpwrules",
"repo": "nixos-apple-silicon",
"type": "github"
}
},
"darwin": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1711763326,
"narHash": "sha256-sXcesZWKXFlEQ8oyGHnfk4xc9f2Ip0X/+YZOq3sKviI=",
"owner": "lnl7",
"repo": "nix-darwin",
"rev": "36524adc31566655f2f4d55ad6b875fb5c1a4083",
"type": "github"
},
"original": {
"owner": "lnl7",
"ref": "master",
"repo": "nix-darwin",
"type": "github"
}
},
"emacs": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": [
"nixpkgs"
],
"nixpkgs-stable": "nixpkgs-stable"
},
"locked": {
"lastModified": 1712941527,
"narHash": "sha256-wD9XQFGW0qzRW1YHj6oklCHzgKNxjwS0tZ/hFGgiHX4=",
"owner": "nix-community",
"repo": "emacs-overlay",
"rev": "9f4406718ada7af83892e17355ef7fd202c20897",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "emacs-overlay",
"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-compat_2": {
"flake": false,
"locked": {
"lastModified": 1696426674,
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-parts": {
"inputs": {
"nixpkgs-lib": [
"neovim-nightly",
"nixpkgs"
]
},
"locked": {
"lastModified": 1712014858,
"narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "9126214d0a59633752a136528f5f3b9aa8565b7d",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"flake-parts_2": {
"inputs": {
"nixpkgs-lib": [
"neovim-nightly",
"hercules-ci-effects",
"nixpkgs"
]
},
"locked": {
"lastModified": 1709336216,
"narHash": "sha256-Dt/wOWeW6Sqm11Yh+2+t0dfEWxoMxGBvv3JpIocFl9E=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "f7b3c975cf067e56e7cda6cb098ebe3fb4d74ca2",
"type": "github"
},
"original": {
"id": "flake-parts",
"type": "indirect"
}
},
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1710146030,
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_2": {
"inputs": {
"systems": "systems_2"
},
"locked": {
"lastModified": 1701680307,
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_3": {
"inputs": {
"systems": "systems_3"
},
"locked": {
"lastModified": 1701680307,
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"hercules-ci-effects": {
"inputs": {
"flake-parts": "flake-parts_2",
"nixpkgs": [
"neovim-nightly",
"nixpkgs"
]
},
"locked": {
"lastModified": 1710478346,
"narHash": "sha256-Xjf8BdnQG0tLhPMlqQdwCIjOp7Teox0DP3N/jjyiGM4=",
"owner": "hercules-ci",
"repo": "hercules-ci-effects",
"rev": "64e7763d72c1e4c1e5e6472640615b6ae2d40fbf",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "hercules-ci-effects",
"type": "github"
}
},
"home-manager": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1712759992,
"narHash": "sha256-2APpO3ZW4idlgtlb8hB04u/rmIcKA8O7pYqxF66xbNY=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "31357486b0ef6f4e161e002b6893eeb4fafc3ca9",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "home-manager",
"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"
}
},
"neovim-flake": {
"inputs": {
"flake-utils": "flake-utils_2",
"nixpkgs": [
"neovim-nightly",
"nixpkgs"
]
},
"locked": {
"dir": "contrib",
"lastModified": 1712877603,
"narHash": "sha256-8JesAgnsv1bD+xHNoqefz0Gv243wSiCKnzh4rhZLopU=",
"owner": "neovim",
"repo": "neovim",
"rev": "18ee9f9e7dbbc9709ee9c1572870b4ad31443569",
"type": "github"
},
"original": {
"dir": "contrib",
"owner": "neovim",
"repo": "neovim",
"type": "github"
}
},
"neovim-nightly": {
"inputs": {
"flake-compat": "flake-compat_2",
"flake-parts": "flake-parts",
"hercules-ci-effects": "hercules-ci-effects",
"neovim-flake": "neovim-flake",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1712880226,
"narHash": "sha256-2CGLzsFft8zF/gEY4qDN0uAjRCWUqvNJ9yV118NlzTg=",
"owner": "nix-community",
"repo": "neovim-nightly-overlay",
"rev": "58d367a1924bf0d02bcc5bd2c5af8ac97f178381",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "neovim-nightly-overlay",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1712163089,
"narHash": "sha256-Um+8kTIrC19vD4/lUCN9/cU9kcOsD1O1m+axJqQPyMM=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "fd281bd6b7d3e32ddfa399853946f782553163b5",
"type": "github"
},
"original": {
"owner": "nixos",
"repo": "nixpkgs",
"rev": "fd281bd6b7d3e32ddfa399853946f782553163b5",
"type": "github"
}
},
"nixpkgs-stable": {
"locked": {
"lastModified": 1712741485,
"narHash": "sha256-bCs0+MSTra80oXAsnM6Oq62WsirOIaijQ/BbUY59tR4=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "b2cf36f43f9ef2ded5711b30b1f393ac423d8f72",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-23.11",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1712849433,
"narHash": "sha256-flQtf/ZPJgkLY/So3Fd+dGilw2DKIsiwgMEn7BbBHL0=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "f173d0881eff3b21ebb29a2ef8bedbc106c86ea5",
"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",
"neovim-nightly": "neovim-nightly",
"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"
}
},
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"systems_3": {
"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_3",
"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"
}
}
},
"root": "root",
"version": 7
}

185
flake.nix Normal file
View File

@@ -0,0 +1,185 @@
{
description = "Patrick's Darwin Nix setup";
inputs = {
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";
};
neovim-nightly = {
url = "github:nix-community/neovim-nightly-overlay";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = {
neovim-nightly,
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 neovim-nightly.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;
modules = let
args = {
nixpkgs = pkgs;
username = "patrick";
dotnet = pkgs.dotnet-sdk_8;
mbsync = import ./mbsync.nix {inherit pkgs;};
secretsPath = "/home/patrick/.secrets/";
};
in [
./home-manager/capybara-config.nix
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)];
}
];
};
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/";
};
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/";
};
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);
};
}

View File

@@ -1,36 +0,0 @@
{ pkgs, config, lib, ... }:
let link = ./link.sh; in
let gmp-symlink =
pkgs.stdenv.mkDerivation {
name = "gmp-symlink";
src = ./link.sh;
phases = [ "unpackPhase" ];
unpackPhase = ''
mkdir -p "$out"
cp ${link} "$out/link.sh"
chmod u+x "$out/link.sh"
sed -i 's_NIX-GMP_${config.gmp-symlink.gmp}_' "$out/link.sh"
'';
installPhase = ''
'';
};
in
{
options = {
gmp-symlink.enable = lib.mkOption { default = false; };
gmp-symlink.gmp = lib.mkOption { default = pkgs.gmp; };
};
config = lib.mkIf config.gmp-symlink.enable {
home.activation.gmp-symlink = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
${gmp-symlink}/link.sh
'';
};
}

View File

@@ -1,15 +0,0 @@
#!/bin/bash
dest="/usr/local/opt/gmp/lib/libgmp.10.dylib"
sudo mkdir -p "$(dirname "$dest")"
existing=$(readlink "$dest")
if [ $? -eq 1 ]; then
sudo ln -s "NIX-GMP/lib/libgmp.10.dylib" "$dest"
else
if [[ "$existing" == /nix/store/* ]]; then
sudo ln -fs "NIX-GMP/lib/libgmp.10.dylib" "$dest"
else
echo "Existing symlink is $existing, refusing to overwrite"
exit 1
fi
fi

34
hardware/capybara.nix Normal file
View File

@@ -0,0 +1,34 @@
# 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 = ["xhci_pci" "ahci" "nvme" "usb_storage" "usbhid" "sd_mod"];
boot.initrd.kernelModules = [];
boot.kernelModules = ["kvm-intel"];
boot.extraModulePackages = [];
fileSystems."/" = {
device = "/dev/disk/by-uuid/63c5394d-55ce-48a9-8d7c-2b68f3b5f834";
fsType = "ext4";
};
fileSystems."/boot" = {
device = "/dev/nvme0n1p2";
fsType = "vfat";
};
swapDevices = [];
powerManagement.cpuFreqGovernor = lib.mkDefault "powersave";
hardware.cpu.intel.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,70 @@
{
pkgs,
config,
...
}: {
nixpkgs.config.allowUnfree = true;
imports = [
../hardware/capybara.nix
];
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
boot.loader.grub.useOSProber = true;
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.vim
pkgs.wget
pkgs.tmux
pkgs.home-manager
pkgs.firefox
pkgs.steam-run
];
environment.loginShellInit = ''
[[ "$(tty)" == /dev/tty1 ]] && 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
'';
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,52 @@
{pkgs, ...}: {
imports = [
../hardware/earthworm.nix
];
hardware.asahi.peripheralFirmwareDirectory = ../firmware;
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;
};
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
];
environment.loginShellInit = ''
[[ "$(tty)" == /dev/tty1 ]] && 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
'';
}

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

@@ -0,0 +1,316 @@
{
nixpkgs,
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";
};
delta = {enable = true;};
extraConfig = {
commit.gpgsign = true;
gpg.program = "${nixpkgs.gnupg}/bin/gpg";
user.signingkey = "7C97D679CF3BC4F9";
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
pynvimpp = nixpkgs.python3.pkgs.buildPythonPackage {
pname = "pynvim-pp";
version = "unstable-2024-03-24";
pyproject = true;
src = nixpkgs.fetchFromGitHub {
owner = "ms-jpq";
repo = "pynvim_pp";
rev = "34e3a027c595981886d7efd1c91071f3eaa4715d";
hash = "sha256-2+jDRJXlg9q4MN9vOhmeq4cWVJ0wp5r5xAh3G8lqgOg=";
};
nativeBuildInputs = [nixpkgs.python3.pkgs.setuptools];
propagatedBuildInputs = [nixpkgs.python3.pkgs.pynvim];
};
in let
pythonEnv = nixpkgs.python3.withPackages (ps: [
ps.pynvim
pynvimpp
ps.pyyaml
ps.std2
]);
debugPyEnv = nixpkgs.python3.withPackages (ps: [ps.debugpy]);
in {
enable = true;
plugins = [
{
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;
withRuby = true;
extraLuaConfig = builtins.readFile ./nvim/build-utils.lua + "\n" + builtins.readFile ./nvim/dotnet.lua + "\n" + builtins.replaceStrings ["%PYTHONENV%"] ["${pythonEnv}"] (builtins.readFile ./nvim/init.lua) + "\n" + builtins.readFile ./nvim/python.lua;
package = nixpkgs.neovim-nightly;
};
home.packages = [
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.ltex-ls
nixpkgs.yaml-language-server
nixpkgs.csharp-ls
nixpkgs.netcoredbg
nixpkgs.nil
nixpkgs.fsautocomplete
nixpkgs.keepassxc
nixpkgs.wget
nixpkgs.yt-dlp
nixpkgs.cmake
nixpkgs.gnumake
nixpkgs.gcc
nixpkgs.lldb
nixpkgs.hledger
nixpkgs.hledger-web
dotnet
nixpkgs.jitsi-meet
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.nodePackages.pyright
nixpkgs.woodpecker-agent
nixpkgs.lynx
nixpkgs.alejandra
nixpkgs.ffmpeg
nixpkgs.bat
nixpkgs.pandoc
nixpkgs.fd
nixpkgs.sumneko-lua-language-server
nixpkgs.gnupg
];
home.file.".ideavimrc".source = ./ideavimrc;
home.file.".config/yt-dlp/config".source = ./youtube-dl.conf;
}

3
home-manager/ideavimrc Normal file
View File

@@ -0,0 +1,3 @@
set ideajoin
set visualbell
set noerrorbells

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

@@ -0,0 +1,24 @@
{nixpkgs, ...}: {
home.packages = [nixpkgs.firefox-wayland];
nixpkgs.config.firefox.speechSynthesisSupport = true;
wayland.windowManager.sway = {
enable = true;
config = {
focus = {followMouse = false;};
modifier = "Mod4";
terminal = "alacritty";
window = {border = 5;};
};
extraConfig = ''
output Unknown-1 scale 2
'';
};
services.swayidle = {enable = true;};
services.cbatticon = {
lowLevelPercent = 20;
iconType = "standard";
enable = true;
};
}

View File

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

View File

@@ -0,0 +1,17 @@
{pkgs, ...}: {
programs.alacritty = {
enable = true;
settings = {
font = {
normal = {
family = "FiraCode Nerd Font Mono";
};
};
};
};
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,184 @@
{
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'';
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 = "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.
"cat ${secretsPath}/proton.txt";
smtp = {
host = "127.0.0.1";
port = 1025; # 8126; if using hydroxide
tls = {enable = false;};
};
userName = address;
};
services.mbsync = {
enable = pkgs.stdenv.isLinux;
package = mbsync;
};
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,18 @@
{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'
'';
};
}

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,32 @@
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"

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,160 @@
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.register({
s = {
name = ".NET solution",
b = { BuildDotNetSolution, "Build .NET solution" },
t = { TestDotNetSolution, "Test .NET solution" },
},
}, { prefix = vim.api.nvim_get_var("maplocalleader"), 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" },
callback = function()
FindAndRegisterSolution(false)
end,
})

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

@@ -0,0 +1,290 @@
vim.g.python3_host_prog = "%PYTHONENV%/bin/python"
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)
-- Note: we could (if desired) view all groups, because the `node.mapping` table looks like this:
-- { prefix = "g", group = true, keys = {...}}
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.register({
[vim.api.nvim_get_var("maplocalleader")] = {
DisplayAllMappingsWithTelescope,
"View all mappings",
},
m = {
p = { MarkdownPreview, "Preview Markdown in Lynx" },
d = { RemoveCarriageReturn, "Delete carriage returns from file" },
},
["j"] = {
FormatJson,
"Auto-format JSON",
},
}, { prefix = vim.api.nvim_get_var("maplocalleader") })
whichkey.register({
g = {
function()
require("telescope.builtin").grep_string()
end,
"Find instances of text under cursor",
},
h = {
name = "Find historical...",
f = {
function()
require("telescope.builtin").oldfiles()
end,
"List previously open files",
},
c = {
function()
require("telescope.builtin").command_history()
end,
"List previously run commands",
},
s = {
function()
require("telescope.builtin").search_history()
end,
"List previously run searches",
},
},
m = {
function()
require("telescope.builtin").marks()
end,
"List marks",
},
["cd"] = {
ChangeToCurrentDirectory,
"Switch CWD to the directory of the open buffer",
},
["ss"] = {
ToggleSpell,
"Toggle spell-checker on or off",
},
[vim.api.nvim_get_var("mapleader")] = {
function()
require("telescope.builtin").find_files()
end,
"Find files by name",
},
}, { prefix = vim.api.nvim_get_var("mapleader") })

View File

@@ -0,0 +1,256 @@
vim.g["fsharp#fsautocomplete_command"] = { "fsautocomplete" }
vim.g["fsharp#show_signature_on_cursor_move"] = 1
vim.g["fsharp#fsi_keymap"] = "none"
-- MASSIVE HACK - raised https://github.com/ionide/Ionide-vim/pull/78
local function captureLoadedProjects()
vim.fn.execute("redir => g:massive_hack_patrick_capture")
vim.fn.execute("call fsharp#showLoadedProjects()")
vim.fn.execute("redir END")
local output = vim.fn.eval("g:massive_hack_patrick_capture")
local projects = {}
for line in output:gmatch("[^\r\n]+") do
local project = line:gsub("^%s*-%s*", "")
table.insert(projects, project)
end
return projects
end
-- 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 = captureLoadedProjects()
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 = captureLoadedProjects(),
}),
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 = captureLoadedProjects(),
}),
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 = captureLoadedProjects(),
}),
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.register({
f = {
name = "F#",
t = { ":call fsharp#showTooltip()<CR>", "Show F# Tooltip" },
["si"] = { ":call fsharp#toggleFsi()<CR>", "Toggle FSI (F# Interactive)" },
["sl"] = { ":call fsharp#sendLineToFsi()<cr>", "Send line to FSI (F# Interactive)" },
r = {
name = "Run F# project",
d = { ":RunFSharpProject Debug", "Run F# project in debug configuration" },
r = { ":RunFSharpProject Release", "Run F# project in release configuration" },
},
p = {
":PublishFSharpProject",
"Publish F# project",
},
b = {
"Build F# project",
a = { BuildFSharpProjects, "Build all projects" },
s = { ":BuildFSharpProject", "Build specified project" },
},
},
}, { prefix = vim.api.nvim_get_var("maplocalleader"), 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").register({
l = {
i = { "<Cmd>LeanInfoviewToggle<CR>", "Toggle Lean info view" },
p = { "<Cmd>LeanInfoviewPinTogglePause<CR>", "Pause Lean info view" },
s = { "<Cmd>LeanSorryFill<CR>", "Fill open goals with sorry" },
w = { "<Cmd>LeanInfoviewEnableWidgets<CR>", "Enable Lean widgets" },
W = { "<Cmd>LeanInfoviewDisableWidgets<CR>", "Disable Lean widgets" },
["?"] = {
"<Cmd>LeanAbbreviationsReverseLookup<CR>",
"Show what Lean abbreviation produces the symbol under the cursor",
},
},
}, { prefix = vim.api.nvim_get_var("maplocalleader") })

View File

@@ -0,0 +1,191 @@
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")["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")["bashls"].setup({})
require("lspconfig")["dockerls"].setup({})
require("lspconfig")["html"].setup({
capabilities = capabilities,
})
require("lspconfig")["ltex"].setup({})
require("lspconfig")["lua_ls"].setup({
on_init = function(client)
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.register({
l = {
name = "loclist-related commands",
p = { vim.diagnostic.goto_prev, "Go to previous entry in loclist" },
n = { vim.diagnostic.goto_next, "Go to next entry in loclist" },
l = { ToggleLocList, "Toggle loclist" },
f = { vim.diagnostic.open_float, "Open current loclist entry in floating window" },
},
}, { prefix = vim.api.nvim_get_var("mapleader") })
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.register({
g = {
name = "Go-to related commands",
D = { vim.lsp.buf.declaration, "Go to declaration" },
d = { vim.lsp.buf.definition, "Go to definition" },
i = { vim.lsp.buf.implementation, "Go to implementation" },
r = {
function()
require("telescope.builtin").lsp_references()
end,
"Find references",
},
},
K = { vim.lsp.buf.hover, "Display information about symbol under cursor" },
})
whichkey.register({
["<C-k>"] = { vim.lsp.buf.signature_help, "Display signature information about symbol under cursor" },
})
whichkey.register({
w = {
a = { vim.lsp.buf.add_workspace_folder, "Add a path to the workspace folders list" },
r = { vim.lsp.buf.add_workspace_folder, "Remove a path from the workspace folders list" },
l = {
function()
print(vim.inspect(vim.lsp.buf.list_workspace_folders()))
end,
"Show the workspace folders list",
},
},
f = {
function()
vim.lsp.buf.format({ async = true })
end,
"Autoformat",
},
c = {
a = { vim.lsp.buf.code_action, "Select a code action" },
},
r = {
n = { vim.lsp.buf.rename, "Rename variable" },
},
D = { vim.lsp.buf.type_definition, "Go to type definition" },
}, { prefix = vim.api.nvim_get_var("mapleader") })
end,
})

View File

@@ -0,0 +1,15 @@
require("dap-python").setup("%PYTHONENV%/bin/python")
do
local whichkey = require("which-key")
whichkey.register({
['pd'] = {
"Debugger-related commands",
t = {
"Tests",
f = { require("dap-python").test_class, "Run Python tests in the current file" },
c = { require("dap-python").test_method, "Run the Python test under the cursor" },
},
},
}, { prefix = vim.api.nvim_get_var("maplocalleader") })
end

View File

@@ -0,0 +1,66 @@
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.register({
d = {
name = "Debugger-related commands",
o = { dap.step_over, "Step over" },
i = { dap.step_into, "Step into" },
c = { dap.continue, "Continue" },
C = { dap.run_last, "Run with last debug configuration" },
b = { dap.toggle_breakpoint, "Toggle breakpoint" },
r = { dap.repl.open, "Open debug repl" },
v = {
name = "Commands to view debugger state",
v = {
function()
dap_ui.hover()
end,
"View value of expression under cursor",
},
s = {
function()
dap_ui.sidebar(dap_ui.scopes).open()
end,
"View values of all variables in all scopes",
},
f = {
function()
dap_ui.sidebar(dap_ui.frames).open()
end,
"View stack frames",
},
},
t = { dap.terminate, "Terminate/stop/end debug session" },
},
}, { prefix = vim.api.nvim_get_var("maplocalleader") })
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,66 @@
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.register({
['pt'] = {
"Run Python tests",
f = { RunPythonTestsInFile, "Run Python tests in the current file" },
a = { RunAllPythonTests, "Run all Python tests" },
c = { RunPythonTestAtCursor, "Run the Python test under the cursor" },
},
}, { prefix = vim.api.nvim_get_var("maplocalleader") })
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,5 @@
require("tokyonight").setup({
style = "night",
})
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,100 @@
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.register({
['pv'] = {
name = "Python virtual environment-related commands",
c = { CreateVenv, "Create virtual environment" },
l = { SelectVenv, "Load virtual environment" },
o = {
function()
vim.cmd("VenvSelect")
end,
"Choose (override) new virtual environment",
},
},
}, { prefix = vim.api.nvim_get_var("maplocalleader") })
end

View File

@@ -0,0 +1,88 @@
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
},
},
-- add operators that will trigger motion and text object completion
-- to enable all native operators, set the preset / operators plugin above
operators = { gc = "Comments" },
key_labels = {
-- override the label used to display some keys. It doesn't effect WK in any other way.
-- For example:
-- ["<space>"] = "SPC",
-- ["<cr>"] = "RET",
-- ["<tab>"] = "TAB",
},
motions = {
count = true,
},
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
},
popup_mappings = {
scroll_down = "<c-d>", -- binding to scroll down inside the popup
scroll_up = "<c-u>", -- binding to scroll up inside the popup
},
window = {
border = "none", -- none, single, double, shadow
position = "bottom", -- bottom, top
margin = { 1, 0, 1, 0 }, -- extra window margin [top, right, bottom, left]. When between 0 and 1, will be treated as a percentage of the screen size.
padding = { 1, 2, 1, 2 }, -- extra window padding [top, right, bottom, left]
winblend = 0, -- value between 0-100 0 for fully opaque and 100 for fully transparent
zindex = 1000, -- positive value to position WhichKey above other floating windows.
},
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
},
ignore_missing = false, -- enable this to hide mappings for which you didn't specify a label
hidden = { "<silent>", "<cmd>", "<Cmd>", "<CR>", "^:", "^ ", "^call ", "^lua " }, -- hide mapping boilerplate
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
triggers = "auto", -- automatically setup triggers
-- triggers = {"<leader>"} -- or specifiy a list manually
-- list of triggers, where WhichKey should not wait for timeoutlen and show immediately
triggers_nowait = {
-- marks
"`",
"'",
"g`",
"g'",
-- registers
'"',
"<c-r>",
-- spelling
"z=",
},
triggers_blacklist = {
-- list of mode / prefixes that should never be hooked by WhichKey
-- this is mostly relevant for keymaps that start with a native binding
i = { "j", "k" },
v = { "j", "k" },
},
-- 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

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=";
}
]

189
home.nix
View File

@@ -1,189 +0,0 @@
{ config, pkgs, ... }:
let username = "Patrick"; in
let dotnet = pkgs.dotnet-sdk_6; in
{
imports = [ ./rider ./gmp ];
rider = { enable = true; username = username; dotnet = dotnet; };
gmp-symlink = { enable = true; };
# 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 = "21.11";
home.packages =
[
pkgs.rust-analyzer
pkgs.tmux
pkgs.wget
pkgs.youtube-dl
pkgs.cmake
pkgs.gnumake
pkgs.gcc
pkgs.gdb
pkgs.hledger
pkgs.hledger-web
dotnet
pkgs.docker
pkgs.jitsi-meet
#pkgs.handbrake
pkgs.ripgrep
pkgs.elan
pkgs.coreutils-prefixed
pkgs.shellcheck
pkgs.html-tidy
pkgs.hugo
#pkgs.agda
pkgs.pijul
pkgs.universal-ctags
pkgs.asciinema
pkgs.git-lfs
];
programs.vscode = {
enable = true;
package = pkgs.vscode;
extensions = import ./vscode-extensions.nix { inherit pkgs; };
userSettings = {
workbench.colorTheme = "Default High Contrast";
"files.Exclude" = {
"**/.git" = true;
"**/.DS_Store" = true;
"**/Thumbs.db" = true;
"**/*.olean" = true;
};
"git.path" = "${pkgs.git}/bin/git";
"update.mode" = "none";
"docker.dockerPath" = "${pkgs.docker}/bin/docker";
"lean.leanpkgPath" = "/Users/${username}/.elan/toolchains/stable/bin/leanpkg";
"lean.executablePath" = "/Users/${username}/.elan/toolchains/stable/bin/lean";
"lean.memoryLimit" = 8092;
};
};
programs.tmux = {
shell = "\${pkgs.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 ${pkgs.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=${pkgs.gnumake}/bin/make -DCMAKE_AR=${pkgs.darwin.cctools}/bin/ar -DCMAKE_RANLIB=${pkgs.darwin.cctools}/bin/ranlib -DGMP_INCLUDE_DIR=${pkgs.gmp.dev}/include/ -DGMP_LIBRARIES=${pkgs.gmp}/lib/libgmp.10.dylib";
ar = "${pkgs.darwin.cctools}/bin/ar";
};
};
programs.fzf = {
enable = true;
enableZshIntegration = true;
};
programs.git = {
package = pkgs.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 = "${pkgs.git-lfs} clean -- %f";
smudge = "${pkgs.git-lfs}/bin/git-lfs smudge --skip -- %f";
process = "${pkgs.git-lfs}/bin/git-lfs filter-process";
required = true;
};
};
};
programs.neovim.enable = true;
programs.neovim.plugins = with pkgs.vimPlugins; [
molokai
tagbar
{ plugin = rust-vim;
config = "let g:rustfmt_autosave = 1"; }
{ 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 = pkgs.emacsGcc;
extraPackages = (epkgs: []);
extraConfig = ''
(load-file (let ((coding-system-for-read 'utf-8))
(shell-command-to-string "agda-mode locate")))
'';
};
}

View File

@@ -1 +0,0 @@
set ideajoin

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,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" -type d -maxdepth 1 -name 'Rider*' -exec sh -c '${riderconfig}/link.sh "$0"' {} \;
fi
'';
};
}

View File

@@ -1,110 +0,0 @@
{ pkgs }:
with pkgs.vscode-extensions; [
bbenoist.nix
haskell.haskell
yzhang.markdown-all-in-one
james-yu.latex-workshop
vscodevim.vim
# Doesn't work with vscodium, and unfree
# ms-vscode-remote.remote-ssh
# Not supported on Darwin, apparently
# ms-dotnettools.csharp
] ++ pkgs.vscode-utils.extensionsFromVscodeMarketplace [
{
name = "vscode-docker";
publisher = "ms-azuretools";
version = "1.14.0";
sha256 = "0wc0k3hf9yfjcx7cw9vm528v5f4bk968bgc98h8fwmlx14vhapzp";
}
{
name = "code-gnu-global";
publisher = "austin";
version = "0.2.2";
sha256 = "1fz89m6ja25aif6wszg9h2fh5vajk6bj3lp1mh0l2b04nw2mzhd5";
}
{
name = "rust-analyzer";
publisher = "matklad";
version = "0.2.792";
sha256 = "1m4g6nf5yhfjrjja0x8pfp79v04lxp5lfm6z91y0iilmqbb9kx1q";
}
{
name = "vscode-lldb";
publisher = "vadimcn";
version = "1.6.8";
sha256 = "1c81hs2lbcxshw3fnpajc9hzkpykc76a6hgs7wl5xji57782bckl";
}
{
name = "toml";
publisher = "be5invis";
version = "0.5.1";
sha256 = "1r1y6krqw5rrdhia9xbs3bx9gibd1ky4bm709231m9zvbqqwwq2j";
}
{
name = "Ionide-Paket";
publisher = "Ionide";
version = "2.0.0";
sha256 = "1455zx5p0d30b1agdi1zw22hj0d3zqqglw98ga8lj1l1d757gv6v";
}
{
name = "lean";
publisher = "jroesch";
version = "0.16.39";
sha256 = "0v1w0rmx2z7q6lfrl430fl6aq6n70y14s2fqsp734igdkdhdnvmk";
}
{
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.2309031";
sha256 = "0vqlspq3696yyfsv17rpcbsaqs7nm7yvggv700sl1bia817cak10";
}
{
name = "python";
publisher = "ms-python";
version = "2021.5.926500501";
sha256 = "0hpb1z10ykg1sz0840qnas5ddbys9inqnjf749lvakj9spk1syk3";
}
{
name = "remote-containers";
publisher = "ms-vscode-remote";
version = "0.183.0";
sha256 = "12v7037rn46svv6ff2g824hdkk7l95g4gbzrp5zdddwxs0a62jlg";
}
{
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";
}
]