Compare commits
1
Commits
main
..
6ad4bbbe8c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ad4bbbe8c |
+2
-2
@@ -1,4 +1,4 @@
|
|||||||
eln-cache
|
/users/crumb/programs/emacs/eln-cache
|
||||||
auto-save-list
|
/users/crumb/programs/emacs/auto-save-list
|
||||||
.direnv
|
.direnv
|
||||||
result
|
result
|
||||||
|
|||||||
Generated
+204
-268
@@ -38,11 +38,11 @@
|
|||||||
"base16-helix": {
|
"base16-helix": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1776754714,
|
"lastModified": 1760703920,
|
||||||
"narHash": "sha256-E3OAK27smtATTmX45uoTSRsVD+Y+ZiVVfgM/tjpbtYg=",
|
"narHash": "sha256-m82fGUYns4uHd+ZTdoLX2vlHikzwzdu2s2rYM2bNwzw=",
|
||||||
"owner": "tinted-theming",
|
"owner": "tinted-theming",
|
||||||
"repo": "base16-helix",
|
"repo": "base16-helix",
|
||||||
"rev": "4d508123037e7851ad36ebf7d9c48b0e9e1eb581",
|
"rev": "d646af9b7d14bff08824538164af99d0c521b185",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -76,11 +76,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1787524125,
|
"lastModified": 1762095388,
|
||||||
"narHash": "sha256-P48TOQdIbB0PKMn4FTk6X0utbf0LemNlJ+bFcSbveGA=",
|
"narHash": "sha256-7Q8LtcvKWHbP8znARRTOY2tpU5WoV6FHwp5TZJOI8Us=",
|
||||||
"owner": "9001",
|
"owner": "9001",
|
||||||
"repo": "copyparty",
|
"repo": "copyparty",
|
||||||
"rev": "9de090265f8d063056320f41d984830839017a2f",
|
"rev": "ac085b8149ff50e03d260128596dd130ed1c7cae",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -94,11 +94,11 @@
|
|||||||
"nixpkgs": "nixpkgs"
|
"nixpkgs": "nixpkgs"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1781152676,
|
"lastModified": 1741786315,
|
||||||
"narHash": "sha256-RxWs5ND31KzTG7wvMM+PMfUjyNpmIEr999lqNARaM5o=",
|
"narHash": "sha256-VT65AE2syHVj6v/DGB496bqBnu1PXrrzwlw07/Zpllc=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "disko",
|
"repo": "disko",
|
||||||
"rev": "ff8702b4de27f72b4c78573dfb89ec74e36abdf1",
|
"rev": "0d8c6ad4a43906d14abd5c60e0ffe7b587b213de",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -107,39 +107,17 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dms": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-compat": "flake-compat",
|
|
||||||
"nixpkgs": [
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1785111455,
|
|
||||||
"narHash": "sha256-aTNuC9NDBnYAeEtFsleeUwmGX3AZlKOutbl+LQRPkmQ=",
|
|
||||||
"owner": "AvengeMedia",
|
|
||||||
"repo": "DankMaterialShell",
|
|
||||||
"rev": "069ddab041c738236a8910e4c39b65d9628d3018",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "AvengeMedia",
|
|
||||||
"ref": "stable",
|
|
||||||
"repo": "DankMaterialShell",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"emacs-overlay": {
|
"emacs-overlay": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": "nixpkgs_2",
|
"nixpkgs": "nixpkgs_2",
|
||||||
"nixpkgs-stable": "nixpkgs-stable"
|
"nixpkgs-stable": "nixpkgs-stable"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1787979720,
|
"lastModified": 1742838319,
|
||||||
"narHash": "sha256-HlZp8BnRkHxx7p7fcCeW67/VYzjJAzyFRmrvZqiISEU=",
|
"narHash": "sha256-daVj+uHpHvndui9DOxytAjVP7Kx8lG3/W3KPNR0EG/0=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "emacs-overlay",
|
"repo": "emacs-overlay",
|
||||||
"rev": "0f8471b870c51c3ed6dcd09c01e88bb0f790da01",
|
"rev": "cb257a1d672f75f2f3e375fe1080216131dd1fb0",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -151,11 +129,11 @@
|
|||||||
"firefox-gnome-theme": {
|
"firefox-gnome-theme": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1783570805,
|
"lastModified": 1764873433,
|
||||||
"narHash": "sha256-ptl5aRlCv9/uRSv2u8Hq8UFVFeZ6Q/bT049bpqNgc3w=",
|
"narHash": "sha256-1XPewtGMi+9wN9Ispoluxunw/RwozuTRVuuQOmxzt+A=",
|
||||||
"owner": "rafaelmardojai",
|
"owner": "rafaelmardojai",
|
||||||
"repo": "firefox-gnome-theme",
|
"repo": "firefox-gnome-theme",
|
||||||
"rev": "5602ed62d638142c1ab31dccd01dfbfb28841225",
|
"rev": "f7ffd917ac0d253dbd6a3bf3da06888f57c69f92",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -165,19 +143,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"flake-compat": {
|
"flake-compat": {
|
||||||
"flake": false,
|
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1767039857,
|
"lastModified": 1733328505,
|
||||||
"narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
|
"narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
|
||||||
"owner": "NixOS",
|
"rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
|
||||||
"repo": "flake-compat",
|
"revCount": 69,
|
||||||
"rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
|
"type": "tarball",
|
||||||
"type": "github"
|
"url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.1.0/01948eb7-9cba-704f-bbf3-3fa956735b52/source.tar.gz"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"type": "tarball",
|
||||||
"repo": "flake-compat",
|
"url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz"
|
||||||
"type": "github"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"flake-parts": {
|
"flake-parts": {
|
||||||
@@ -185,11 +161,11 @@
|
|||||||
"nixpkgs-lib": "nixpkgs-lib"
|
"nixpkgs-lib": "nixpkgs-lib"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1785627969,
|
"lastModified": 1777678872,
|
||||||
"narHash": "sha256-4dtXQk/NMePegK/nWp5NSeuZKLATItOq61lpEvmXqGw=",
|
"narHash": "sha256-EPIFsulyon7Z1vLQq5Fk64GR8L7cQsT+IPhcsukVbgk=",
|
||||||
"owner": "hercules-ci",
|
"owner": "hercules-ci",
|
||||||
"repo": "flake-parts",
|
"repo": "flake-parts",
|
||||||
"rev": "427bf4bd9435fdf21321c8cc628c24efc14c0f7a",
|
"rev": "5250617bffd85403b14dbf43c3870e7f255d2c16",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -227,11 +203,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1782949081,
|
"lastModified": 1767609335,
|
||||||
"narHash": "sha256-vp6Y/Grm98ESt6ceOkWiHWyZRDV3J1RID4w+6NWK9yA=",
|
"narHash": "sha256-feveD98mQpptwrAEggBQKJTYbvwwglSbOv53uCfH9PY=",
|
||||||
"owner": "hercules-ci",
|
"owner": "hercules-ci",
|
||||||
"repo": "flake-parts",
|
"repo": "flake-parts",
|
||||||
"rev": "17c9d6cdfc60c64f4ee8d306f9bc0b4ccb51481e",
|
"rev": "250481aafeb741edfe23d29195671c19b36b6dca",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -311,17 +287,17 @@
|
|||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"host": "gitlab.gnome.org",
|
"host": "gitlab.gnome.org",
|
||||||
"lastModified": 1776175984,
|
"lastModified": 1767737596,
|
||||||
"narHash": "sha256-RJFlFW8GiMei6oqUGrMkGEvVqOH8U7Q8abc1yK4VKD8=",
|
"narHash": "sha256-eFujfIUQDgWnSJBablOuG+32hCai192yRdrNHTv0a+s=",
|
||||||
"owner": "GNOME",
|
"owner": "GNOME",
|
||||||
"repo": "gnome-shell",
|
"repo": "gnome-shell",
|
||||||
"rev": "e0fdc4c13250e9a9b8ea9594c83925274f4a5dca",
|
"rev": "ef02db02bf0ff342734d525b5767814770d85b49",
|
||||||
"type": "gitlab"
|
"type": "gitlab"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"host": "gitlab.gnome.org",
|
"host": "gitlab.gnome.org",
|
||||||
"owner": "GNOME",
|
"owner": "GNOME",
|
||||||
"ref": "50.1",
|
"ref": "gnome-49",
|
||||||
"repo": "gnome-shell",
|
"repo": "gnome-shell",
|
||||||
"type": "gitlab"
|
"type": "gitlab"
|
||||||
}
|
}
|
||||||
@@ -331,32 +307,11 @@
|
|||||||
"nixpkgs": "nixpkgs_3"
|
"nixpkgs": "nixpkgs_3"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1787797243,
|
"lastModified": 1773608492,
|
||||||
"narHash": "sha256-8+Q7NOB7RPajRjA4pbCDLzqH+MTjnG9x6LUPLfL2joA=",
|
"narHash": "sha256-QZteyExJYSQzgxqdsesDPbQgjctGG7iKV/6ooyQPITk=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"rev": "99c9ec63390f1d8c14d95d9e8b17cc29cfbd4e11",
|
"rev": "9a40ec3b78fc688d0908485887d355caa5666d18",
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nix-community",
|
|
||||||
"repo": "home-manager",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"home-manager_2": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs": [
|
|
||||||
"impermanence",
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1768598210,
|
|
||||||
"narHash": "sha256-kkgA32s/f4jaa4UG+2f8C225Qvclxnqs76mf8zvTVPg=",
|
|
||||||
"owner": "nix-community",
|
|
||||||
"repo": "home-manager",
|
|
||||||
"rev": "c47b2cc64a629f8e075de52e4742de688f930dc6",
|
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -366,16 +321,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"impermanence": {
|
"impermanence": {
|
||||||
"inputs": {
|
|
||||||
"home-manager": "home-manager_2",
|
|
||||||
"nixpkgs": "nixpkgs_4"
|
|
||||||
},
|
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1769548169,
|
"lastModified": 1737831083,
|
||||||
"narHash": "sha256-03+JxvzmfwRu+5JafM0DLbxgHttOQZkUtDWBmeUkN8Y=",
|
"narHash": "sha256-LJggUHbpyeDvNagTUrdhe/pRVp4pnS6wVKALS782gRI=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "impermanence",
|
"repo": "impermanence",
|
||||||
"rev": "7b1d382faf603b6d264f58627330f9faa5cba149",
|
"rev": "4b3e914cdf97a5b536a889e939fb2fd2b043a170",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -388,21 +339,21 @@
|
|||||||
"inputs": {
|
"inputs": {
|
||||||
"niri-stable": "niri-stable",
|
"niri-stable": "niri-stable",
|
||||||
"niri-unstable": "niri-unstable",
|
"niri-unstable": "niri-unstable",
|
||||||
"nixpkgs": "nixpkgs_5",
|
"nixpkgs": "nixpkgs_4",
|
||||||
"nixpkgs-stable": "nixpkgs-stable_2",
|
"nixpkgs-stable": "nixpkgs-stable_2",
|
||||||
"xwayland-satellite-stable": "xwayland-satellite-stable",
|
"xwayland-satellite-stable": "xwayland-satellite-stable",
|
||||||
"xwayland-satellite-unstable": "xwayland-satellite-unstable"
|
"xwayland-satellite-unstable": "xwayland-satellite-unstable"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1787937511,
|
"lastModified": 1772698812,
|
||||||
"narHash": "sha256-y8G4daKwwkm28VIQ6esMN2qg5u66Kqb4TwMs90STnQc=",
|
"narHash": "sha256-7+K/VaZ7TXUeUGSYshg8wC3UsRZHB+M4x6r38Q1B79c=",
|
||||||
"owner": "epireyn",
|
"owner": "sodiboo",
|
||||||
"repo": "niri-flake",
|
"repo": "niri-flake",
|
||||||
"rev": "16c59792de64470ad162d0ff080e3b3318ffaa5c",
|
"rev": "5641625ef950f024e3e0e3f38bb91f876290c0be",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "epireyn",
|
"owner": "sodiboo",
|
||||||
"repo": "niri-flake",
|
"repo": "niri-flake",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
@@ -410,16 +361,16 @@
|
|||||||
"niri-stable": {
|
"niri-stable": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1777115961,
|
"lastModified": 1756556321,
|
||||||
"narHash": "sha256-ehSMsSpE+0k8r+2Vseu8kangsYxToZv3vinynsDp9zs=",
|
"narHash": "sha256-RLD89dfjN0RVO86C/Mot0T7aduCygPGaYbog566F0Qo=",
|
||||||
"owner": "niri-wm",
|
"owner": "YaLTeR",
|
||||||
"repo": "niri",
|
"repo": "niri",
|
||||||
"rev": "8ed0da44d974c32c6877d2f4630c314da0717ecb",
|
"rev": "01be0e65f4eb91a9cd624ac0b76aaeab765c7294",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "niri-wm",
|
"owner": "YaLTeR",
|
||||||
"ref": "v26.04",
|
"ref": "v25.08",
|
||||||
"repo": "niri",
|
"repo": "niri",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
@@ -427,15 +378,15 @@
|
|||||||
"niri-unstable": {
|
"niri-unstable": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1787337984,
|
"lastModified": 1772207631,
|
||||||
"narHash": "sha256-BNZUEVR2H96hCKENNKoLSSTFT8W4smp7v94hJc4Ehfc=",
|
"narHash": "sha256-Jkkg+KqshFO3CbTszVVpkKN2AOObYz+wMsM3ONo1z5g=",
|
||||||
"owner": "niri-wm",
|
"owner": "YaLTeR",
|
||||||
"repo": "niri",
|
"repo": "niri",
|
||||||
"rev": "dd75865f547f0eac0e9b6c4d86d2cd00c0744252",
|
"rev": "e708f546153f74acf33eb183b3b2992587a701e5",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "niri-wm",
|
"owner": "YaLTeR",
|
||||||
"repo": "niri",
|
"repo": "niri",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
@@ -467,17 +418,17 @@
|
|||||||
},
|
},
|
||||||
"nixcord": {
|
"nixcord": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
|
"flake-compat": "flake-compat",
|
||||||
"flake-parts": "flake-parts",
|
"flake-parts": "flake-parts",
|
||||||
"nixpkgs": "nixpkgs_6",
|
"nixpkgs": "nixpkgs_5",
|
||||||
"nixpkgs-nixcord": "nixpkgs-nixcord",
|
"nixpkgs-nixcord": "nixpkgs-nixcord"
|
||||||
"treefmt-nix": "treefmt-nix"
|
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1787932216,
|
"lastModified": 1778257733,
|
||||||
"narHash": "sha256-OPJDo+mIHErjQL/uaclMFvgSkQeInH2MFGxT93+VXps=",
|
"narHash": "sha256-FPKWRBfH2Zowz2Q+vRqL8GKNRZHaa6L450Ys2CQtLDQ=",
|
||||||
"owner": "KaylorBen",
|
"owner": "KaylorBen",
|
||||||
"repo": "nixcord",
|
"repo": "nixcord",
|
||||||
"rev": "5b36c9187cabf90cb1659045c354cd6a0dd349ff",
|
"rev": "1b1f027264ad08153b480d37f10007ee71048567",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -487,15 +438,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixos-hardware": {
|
"nixos-hardware": {
|
||||||
"inputs": {
|
|
||||||
"nixpkgs": "nixpkgs_7"
|
|
||||||
},
|
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1787144466,
|
"lastModified": 1773533765,
|
||||||
"narHash": "sha256-HHfv2/HkNSKbbSyU9iD/g8lbP6r4tl33sSw1W4rXCk0=",
|
"narHash": "sha256-qonGfS2lzCgCl59Zl63jF6dIRRpvW3AJooBGMaXjHiY=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixos-hardware",
|
"repo": "nixos-hardware",
|
||||||
"rev": "0471accf8d0a8210b31d947497d179ecc99e0021",
|
"rev": "f8e82243fd601afb9f59ad230958bd073795cbfe",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -506,11 +454,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1780930886,
|
"lastModified": 1741402956,
|
||||||
"narHash": "sha256-rppURzHviaQN131F+nLiLdGfcb0uCd9gGP0E5+iw9MI=",
|
"narHash": "sha256-y2hByvBM03s9T2fpeLjW6iprbxnhV9mJMmSwCHc41ZQ=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "8c3cede7ddc26bd659d2d383b5610efbd2c7a16e",
|
"rev": "ed0b1881565c1ffef490c10d663d4f542031dad3",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -522,11 +470,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs-lib": {
|
"nixpkgs-lib": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1785031560,
|
"lastModified": 1777168982,
|
||||||
"narHash": "sha256-OmshNvn2vupOFpYinLUu+1Dnpu4n7Q5N3ggGVNHpkUI=",
|
"narHash": "sha256-GOkGPcboWE9BmGCRMLX3worL4EMnsnG8MyKmXNeYuhQ=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "nixpkgs.lib",
|
"repo": "nixpkgs.lib",
|
||||||
"rev": "0e79af5e3d4dcfcd676ab5ba3f95d2e3352e078c",
|
"rev": "f5901329dade4a6ea039af1433fb087bd9c1fe14",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -537,85 +485,53 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs-nixcord": {
|
"nixpkgs-nixcord": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1786711500,
|
"lastModified": 1777428379,
|
||||||
"narHash": "sha256-QvnceIGTBeDvDd9oCn+GvdsnkquliuwbVgpiRH68qaQ=",
|
"narHash": "sha256-ypxFOeDz+CqADEQNL72haqGjvZQdBR5Vc7pyx2JDttI=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "02e08985a27c65ffd33d434eeb2e660a2e4dc84d",
|
"rev": "755f5aa91337890c432639c60b6064bb7fe67769",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"ref": "nixos-26.05",
|
"ref": "nixos-25.11",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs-stable": {
|
"nixpkgs-stable": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1787848966,
|
"lastModified": 1742751704,
|
||||||
"narHash": "sha256-7gDpu5hpq0rOYnYMcOWqSzquK4HA/xU8Xf3CjUBOOJA=",
|
"narHash": "sha256-rBfc+H1dDBUQ2mgVITMGBPI1PGuCznf9rcWX/XIULyE=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "d57af924f160a5084293c71c2043f058bd1cdb60",
|
"rev": "f0946fa5f1fb876a9dc2e1850d9d3a4e3f914092",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"ref": "nixos-26.05",
|
"ref": "nixos-24.11",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs-stable_2": {
|
"nixpkgs-stable_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1787848966,
|
"lastModified": 1772598333,
|
||||||
"narHash": "sha256-7gDpu5hpq0rOYnYMcOWqSzquK4HA/xU8Xf3CjUBOOJA=",
|
"narHash": "sha256-YaHht/C35INEX3DeJQNWjNaTcPjYmBwwjFJ2jdtr+5U=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "d57af924f160a5084293c71c2043f058bd1cdb60",
|
"rev": "fabb8c9deee281e50b1065002c9828f2cf7b2239",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"ref": "nixos-26.05",
|
"ref": "nixos-25.11",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs_10": {
|
"nixpkgs_10": {
|
||||||
"locked": {
|
|
||||||
"lastModified": 1785454630,
|
|
||||||
"narHash": "sha256-LQy14TZp77TwbQf40gg1V3jo8FwJG0jGDkAH+zRHqg8=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "1559d3daa3ecc813a650b79375ea61b6741b8746",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixos-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs_11": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1756819007,
|
|
||||||
"narHash": "sha256-12V64nKG/O/guxSYnr5/nq1EfqwJCdD2+cIGmhz3nrE=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "aaff8c16d7fc04991cac6245bee1baa31f72b1e1",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixpkgs-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs_12": {
|
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1743568003,
|
"lastModified": 1743568003,
|
||||||
"narHash": "sha256-ZID5T65E8ruHqWRcdvZLsczWDOAWIE7om+vQOREwiX0=",
|
"narHash": "sha256-ZID5T65E8ruHqWRcdvZLsczWDOAWIE7om+vQOREwiX0=",
|
||||||
@@ -633,11 +549,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs_2": {
|
"nixpkgs_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1787736819,
|
"lastModified": 1742669843,
|
||||||
"narHash": "sha256-cV5xEJJK3BvhU8rEd4mC9UsmDi5qscv/kzGPhBRC5WA=",
|
"narHash": "sha256-G5n+FOXLXcRx+3hCJ6Rt6ZQyF1zqQ0DL0sWAMn2Nk0w=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "9fbb54b33e91ee4ca368e35a78e0613c720600b3",
|
"rev": "1e5b653dff12029333a6546c11e108ede13052eb",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -649,31 +565,31 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs_3": {
|
"nixpkgs_3": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1787209939,
|
"lastModified": 1773389992,
|
||||||
"narHash": "sha256-WvvHR4kSQLAbtouMC/ruZ5UpLwlUcY3K4FAllMN+yGk=",
|
"narHash": "sha256-wvfdLLWJ2I9oEpDd9PfMA8osfIZicoQ5MT1jIwNs9Tk=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "391b592eb44808b3bd0cb80bb71b63a5a118b8bb",
|
"rev": "c06b4ae3d6599a672a6210b7021d699c351eebda",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"ref": "nixpkgs-unstable",
|
"ref": "nixos-unstable",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs_4": {
|
"nixpkgs_4": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1768564909,
|
"lastModified": 1772624091,
|
||||||
"narHash": "sha256-Kell/SpJYVkHWMvnhqJz/8DqQg2b6PguxVWOuadbHCc=",
|
"narHash": "sha256-QKyJ0QGWBn6r0invrMAK8dmJoBYWoOWy7lN+UHzW1jc=",
|
||||||
"owner": "nixos",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "e4bae1bd10c9c57b2cf517953ab70060a828ee6f",
|
"rev": "80bdc1e5ce51f56b19791b52b2901187931f5353",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "nixos",
|
"owner": "NixOS",
|
||||||
"ref": "nixos-unstable",
|
"ref": "nixos-unstable",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
@@ -681,56 +597,43 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs_5": {
|
"nixpkgs_5": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1787736819,
|
"lastModified": 1777428379,
|
||||||
"narHash": "sha256-cV5xEJJK3BvhU8rEd4mC9UsmDi5qscv/kzGPhBRC5WA=",
|
"narHash": "sha256-ypxFOeDz+CqADEQNL72haqGjvZQdBR5Vc7pyx2JDttI=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "9fbb54b33e91ee4ca368e35a78e0613c720600b3",
|
"rev": "755f5aa91337890c432639c60b6064bb7fe67769",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"ref": "nixos-unstable",
|
"ref": "nixos-25.11",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs_6": {
|
"nixpkgs_6": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1786711500,
|
"lastModified": 1773700673,
|
||||||
"narHash": "sha256-QvnceIGTBeDvDd9oCn+GvdsnkquliuwbVgpiRH68qaQ=",
|
"narHash": "sha256-RLidgpn3mN3cVkIiiYehcmM2ImBnPudwISFLy71zN0o=",
|
||||||
"owner": "NixOS",
|
"owner": "msyds",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "02e08985a27c65ffd33d434eeb2e660a2e4dc84d",
|
"rev": "2595b5f0592534492bce3cb61c2c9bf5ba03ffbe",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"owner": "msyds",
|
||||||
"ref": "nixos-26.05",
|
"ref": "fix-bepasty",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs_7": {
|
"nixpkgs_7": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1767892417,
|
"lastModified": 1742578646,
|
||||||
"narHash": "sha256-8bW3q88CEg2u4hSP66Vf4lpbLonHz7hqDNBMcCY7E9U=",
|
"narHash": "sha256-GiQ40ndXRnmmbDZvuv762vS+gew1uDpFwOfgJ8tLiEs=",
|
||||||
"rev": "3497aa5c9457a9d88d71fa93a4a8368816fbeeba",
|
|
||||||
"type": "tarball",
|
|
||||||
"url": "https://releases.nixos.org/nixos/unstable/nixos-26.05pre924538.3497aa5c9457/nixexprs.tar.xz"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"type": "tarball",
|
|
||||||
"url": "https://channels.nixos.org/nixos-unstable/nixexprs.tar.xz"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs_8": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1787814960,
|
|
||||||
"narHash": "sha256-PYZq1qzCJXC2zGI0mH07vrZBsw6DRBAOX0jN1pPtqOQ=",
|
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "c27cdad491a991b11ed731760aa2ef8db0cb0410",
|
"rev": "94c4dbe77c0740ebba36c173672ca15a7926c993",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -740,13 +643,29 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs_9": {
|
"nixpkgs_8": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1782175435,
|
"lastModified": 1767767207,
|
||||||
"narHash": "sha256-EMzXKmnOtBQ2MnvpiNOm7E+kOMvdPrIKaeg52Tip2Uk=",
|
"narHash": "sha256-Mj3d3PfwltLmukFal5i3fFt27L6NiKXdBezC1EBuZs4=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "89570f24e97e614aa34aa9ab1c927b6578a43775",
|
"rev": "5912c1772a44e31bf1c63c0390b90501e5026886",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs_9": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1756819007,
|
||||||
|
"narHash": "sha256-12V64nKG/O/guxSYnr5/nq1EfqwJCdD2+cIGmhz3nrE=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "aaff8c16d7fc04991cac6245bee1baa31f72b1e1",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -761,14 +680,15 @@
|
|||||||
"flake-parts": "flake-parts_2",
|
"flake-parts": "flake-parts_2",
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"nixpkgs"
|
"nixpkgs"
|
||||||
]
|
],
|
||||||
|
"treefmt-nix": "treefmt-nix"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1787983941,
|
"lastModified": 1742849190,
|
||||||
"narHash": "sha256-TIqbEHH98OGczjrCLo2BMvYaAWt+y2rFqebaYdf+NT4=",
|
"narHash": "sha256-Isnx5t+L/G7AxpUwNvFgPiYc4IcZjdBrg3MIVz1cfnk=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "NUR",
|
"repo": "NUR",
|
||||||
"rev": "a64b7515ac7560f52b056e76d607b88e7ebadfdb",
|
"rev": "797067d7e3601713a3b43f823248a6232486376c",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -789,11 +709,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1785549842,
|
"lastModified": 1767810917,
|
||||||
"narHash": "sha256-DCwBZmGsySF7oKGTRgEv2HvpxVXkHT+38VhTM76k0B4=",
|
"narHash": "sha256-ZKqhk772+v/bujjhla9VABwcvz+hB2IaRyeLT6CFnT0=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "NUR",
|
"repo": "NUR",
|
||||||
"rev": "a9f987b57594e845e3e5cdd423b9a70846d70308",
|
"rev": "dead29c804adc928d3a69dfe7f9f12d0eec1f1a4",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -806,7 +726,6 @@
|
|||||||
"inputs": {
|
"inputs": {
|
||||||
"copyparty": "copyparty",
|
"copyparty": "copyparty",
|
||||||
"disko": "disko",
|
"disko": "disko",
|
||||||
"dms": "dms",
|
|
||||||
"emacs-overlay": "emacs-overlay",
|
"emacs-overlay": "emacs-overlay",
|
||||||
"home-manager": "home-manager",
|
"home-manager": "home-manager",
|
||||||
"impermanence": "impermanence",
|
"impermanence": "impermanence",
|
||||||
@@ -814,7 +733,7 @@
|
|||||||
"nixarr": "nixarr",
|
"nixarr": "nixarr",
|
||||||
"nixcord": "nixcord",
|
"nixcord": "nixcord",
|
||||||
"nixos-hardware": "nixos-hardware",
|
"nixos-hardware": "nixos-hardware",
|
||||||
"nixpkgs": "nixpkgs_8",
|
"nixpkgs": "nixpkgs_6",
|
||||||
"nur": "nur",
|
"nur": "nur",
|
||||||
"sops-nix": "sops-nix",
|
"sops-nix": "sops-nix",
|
||||||
"stylix": "stylix",
|
"stylix": "stylix",
|
||||||
@@ -826,14 +745,14 @@
|
|||||||
},
|
},
|
||||||
"sops-nix": {
|
"sops-nix": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": "nixpkgs_9"
|
"nixpkgs": "nixpkgs_7"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1786629091,
|
"lastModified": 1742700801,
|
||||||
"narHash": "sha256-gkig4nPi1CWc4Z50GBsjE4ygSE7hMpl/TwID2an2Cck=",
|
"narHash": "sha256-ZGlpUDsuBdeZeTNgoMv+aw0ByXT2J3wkYw9kJwkAS4M=",
|
||||||
"owner": "Mic92",
|
"owner": "Mic92",
|
||||||
"repo": "sops-nix",
|
"repo": "sops-nix",
|
||||||
"rev": "a8627b21b9107c5711c96b84f32a9a4b3d45295f",
|
"rev": "67566fe68a8bed2a7b1175fdfb0697ed22ae8852",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -851,24 +770,25 @@
|
|||||||
"firefox-gnome-theme": "firefox-gnome-theme",
|
"firefox-gnome-theme": "firefox-gnome-theme",
|
||||||
"flake-parts": "flake-parts_3",
|
"flake-parts": "flake-parts_3",
|
||||||
"gnome-shell": "gnome-shell",
|
"gnome-shell": "gnome-shell",
|
||||||
"nixpkgs": "nixpkgs_10",
|
"nixpkgs": "nixpkgs_8",
|
||||||
"nur": "nur_2",
|
"nur": "nur_2",
|
||||||
"systems": "systems",
|
"systems": "systems",
|
||||||
|
"tinted-foot": "tinted-foot",
|
||||||
"tinted-kitty": "tinted-kitty",
|
"tinted-kitty": "tinted-kitty",
|
||||||
"tinted-schemes": "tinted-schemes",
|
"tinted-schemes": "tinted-schemes",
|
||||||
"tinted-tmux": "tinted-tmux",
|
"tinted-tmux": "tinted-tmux",
|
||||||
"tinted-zed": "tinted-zed"
|
"tinted-zed": "tinted-zed"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1787771653,
|
"lastModified": 1772296853,
|
||||||
"narHash": "sha256-DkkJSBOXWV/mja5Vy8az5g1KpZlsbUwlmH0BsQhowaQ=",
|
"narHash": "sha256-pAtzPsgHRKw/2Kv8HgAjSJg450FDldHPWsP3AKG/Xj0=",
|
||||||
"owner": "nix-community",
|
"owner": "danth",
|
||||||
"repo": "stylix",
|
"repo": "stylix",
|
||||||
"rev": "5e3809851f486e7fc7e84b40f174c74b60ecc784",
|
"rev": "c4b8e80a1020e09a1f081ad0f98ce804a6e85acf",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "nix-community",
|
"owner": "danth",
|
||||||
"repo": "stylix",
|
"repo": "stylix",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
@@ -876,14 +796,14 @@
|
|||||||
"syd-fcitx5-tables": {
|
"syd-fcitx5-tables": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-utils": "flake-utils_2",
|
"flake-utils": "flake-utils_2",
|
||||||
"nixpkgs": "nixpkgs_11"
|
"nixpkgs": "nixpkgs_9"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1771615497,
|
"lastModified": 1771615370,
|
||||||
"narHash": "sha256-kyh/P0W8Th+AWFFGzVH7fC1pnI/Q6XqQUZoOHbs1S9A=",
|
"narHash": "sha256-UD/9fs1GYuwDGqrpKunrwOPrvkahLQ/6eeRy/0ejHNA=",
|
||||||
"ref": "refs/heads/main",
|
"ref": "refs/heads/main",
|
||||||
"rev": "c515caad2fbbabdcd29b63db7fa11aa4e0400cce",
|
"rev": "41111bead687315ca1f55a826509234ca2f0e0ce",
|
||||||
"revCount": 9,
|
"revCount": 8,
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://git.deertopia.net/msyds/syd-fcitx5-tables"
|
"url": "https://git.deertopia.net/msyds/syd-fcitx5-tables"
|
||||||
},
|
},
|
||||||
@@ -899,11 +819,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1782095156,
|
"lastModified": 1776985528,
|
||||||
"narHash": "sha256-3iWp9s12wje+qV7trS/XhQZVfolXBpTPLdGfOHWkdBs=",
|
"narHash": "sha256-32WDZGOJBjq3Jr4DRtumqXoX5t25/T0cQ7CzAqT1OnE=",
|
||||||
"ref": "refs/heads/main",
|
"ref": "refs/heads/main",
|
||||||
"rev": "6450642be3ee1af3b64ff2129e0fa2488f3c2d0e",
|
"rev": "40de55454366e390e6972f5e9a9b1444df49ed18",
|
||||||
"revCount": 43,
|
"revCount": 40,
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://git.deertopia.net/msyds/sydpkgs"
|
"url": "https://git.deertopia.net/msyds/sydpkgs"
|
||||||
},
|
},
|
||||||
@@ -914,16 +834,15 @@
|
|||||||
},
|
},
|
||||||
"systems": {
|
"systems": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1774449309,
|
"lastModified": 1681028828,
|
||||||
"narHash": "sha256-brhZ8DmuGtzkCYHJg4HEd602amKm89Y9ytsFZ5uWD1w=",
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
"owner": "nix-systems",
|
"owner": "nix-systems",
|
||||||
"repo": "default",
|
"repo": "default",
|
||||||
"rev": "c29398b59d2048c4ab79345812849c9bd15e9150",
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "nix-systems",
|
"owner": "nix-systems",
|
||||||
"ref": "future-26.11",
|
|
||||||
"repo": "default",
|
"repo": "default",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
@@ -961,14 +880,14 @@
|
|||||||
"tf2-nix": {
|
"tf2-nix": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-utils": "flake-utils_3",
|
"flake-utils": "flake-utils_3",
|
||||||
"nixpkgs": "nixpkgs_12"
|
"nixpkgs": "nixpkgs_10"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1761857232,
|
"lastModified": 1761467191,
|
||||||
"narHash": "sha256-EvWDkMdmAx9IKYHuIa8bWMu9Fa7KylKNWWAQ57Dr7KA=",
|
"narHash": "sha256-0NHhZztMuw17Tp/HjsGhAtjI4k5Qhg0ZxIkgIA0hHOI=",
|
||||||
"owner": "msyds",
|
"owner": "msyds",
|
||||||
"repo": "tf2-nix",
|
"repo": "tf2-nix",
|
||||||
"rev": "3afc3e370bfe66d31ef0711dabc90a29fb55940e",
|
"rev": "98673e8d34fbe59e3c5e9f27068a46e6b61ccc60",
|
||||||
"type": "gitlab"
|
"type": "gitlab"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -977,6 +896,23 @@
|
|||||||
"type": "gitlab"
|
"type": "gitlab"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"tinted-foot": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1726913040,
|
||||||
|
"narHash": "sha256-+eDZPkw7efMNUf3/Pv0EmsidqdwNJ1TaOum6k7lngDQ=",
|
||||||
|
"owner": "tinted-theming",
|
||||||
|
"repo": "tinted-foot",
|
||||||
|
"rev": "fd1b924b6c45c3e4465e8a849e67ea82933fcbe4",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "tinted-theming",
|
||||||
|
"repo": "tinted-foot",
|
||||||
|
"rev": "fd1b924b6c45c3e4465e8a849e67ea82933fcbe4",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"tinted-kitty": {
|
"tinted-kitty": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
@@ -996,11 +932,11 @@
|
|||||||
"tinted-schemes": {
|
"tinted-schemes": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1785153830,
|
"lastModified": 1767710407,
|
||||||
"narHash": "sha256-fNdfCTeCXU3tZG3TMincd+u68qBHQgCr2Ljr/M1mWP0=",
|
"narHash": "sha256-+W1EB79Jl0/gm4JqmO0Nuc5C7hRdp4vfsV/VdzI+des=",
|
||||||
"owner": "tinted-theming",
|
"owner": "tinted-theming",
|
||||||
"repo": "schemes",
|
"repo": "schemes",
|
||||||
"rev": "9bd28ed313560db3c5b605c63bc4e309e78e3fc8",
|
"rev": "2800e2b8ac90f678d7e4acebe4fa253f602e05b2",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1012,11 +948,11 @@
|
|||||||
"tinted-tmux": {
|
"tinted-tmux": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1785031658,
|
"lastModified": 1767489635,
|
||||||
"narHash": "sha256-mZp9O2LjzdMzlqQF3l3fjqsuPBzXy+1qTfBEUGjTlpk=",
|
"narHash": "sha256-e6nnFnWXKBCJjCv4QG4bbcouJ6y3yeT70V9MofL32lU=",
|
||||||
"owner": "tinted-theming",
|
"owner": "tinted-theming",
|
||||||
"repo": "tinted-tmux",
|
"repo": "tinted-tmux",
|
||||||
"rev": "5d2c67f61ea7af36f16865ab6d541cdba41dc257",
|
"rev": "3c32729ccae99be44fe8a125d20be06f8d7d8184",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1028,11 +964,11 @@
|
|||||||
"tinted-zed": {
|
"tinted-zed": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1785030526,
|
"lastModified": 1767488740,
|
||||||
"narHash": "sha256-klZf8UviewRkxuu74Bhbq6tqy7oxebQC7UVRWbbtQxU=",
|
"narHash": "sha256-wVOj0qyil8m+ouSsVZcNjl5ZR+1GdOOAooAatQXHbuU=",
|
||||||
"owner": "tinted-theming",
|
"owner": "tinted-theming",
|
||||||
"repo": "base16-zed",
|
"repo": "base16-zed",
|
||||||
"rev": "16f5a8adf4a6b1310d0a61ab172de963e8f76a02",
|
"rev": "11abb0b282ad3786a2aae088d3a01c60916f2e40",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1044,16 +980,16 @@
|
|||||||
"treefmt-nix": {
|
"treefmt-nix": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"nixcord",
|
"nur",
|
||||||
"nixpkgs"
|
"nixpkgs"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1785945821,
|
"lastModified": 1733222881,
|
||||||
"narHash": "sha256-NLSyTCW4K4ofhNBllt3omPasm6QpralXH1DBZOc91Dw=",
|
"narHash": "sha256-JIPcz1PrpXUCbaccEnrcUS8jjEb/1vJbZz5KkobyFdM=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "treefmt-nix",
|
"repo": "treefmt-nix",
|
||||||
"rev": "ae7910970dddc408fe6ab1c8e4b277bb21d72dc0",
|
"rev": "49717b5af6f80172275d47a418c9719a31a78b53",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1064,11 +1000,11 @@
|
|||||||
},
|
},
|
||||||
"vpn-confinement": {
|
"vpn-confinement": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1785142579,
|
"lastModified": 1742138327,
|
||||||
"narHash": "sha256-WEPxDMiKt3uGVVu/aorHnIgYYW62mEq2Q+rlN3qH6bg=",
|
"narHash": "sha256-Y71Mjej98CjaUKa1ecAIOo0eJ1B3ZVQl2ng6xl7/s9Y=",
|
||||||
"owner": "Maroka-chan",
|
"owner": "Maroka-chan",
|
||||||
"repo": "VPN-Confinement",
|
"repo": "VPN-Confinement",
|
||||||
"rev": "b3aa71a7edfe6af748c23729d1bdec3b499741ff",
|
"rev": "38eeb3bc501900b48d1caf8c52a5b7f2fb7a52c5",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1101,16 +1037,16 @@
|
|||||||
"xwayland-satellite-stable": {
|
"xwayland-satellite-stable": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1784679892,
|
"lastModified": 1755491097,
|
||||||
"narHash": "sha256-Mb7jpqnrcYCfNSItIkkHpuR3YxWFxPuIBfcwNKlRBkk=",
|
"narHash": "sha256-m+9tUfsmBeF2Gn4HWa6vSITZ4Gz1eA1F5Kh62B0N4oE=",
|
||||||
"owner": "Supreeeme",
|
"owner": "Supreeeme",
|
||||||
"repo": "xwayland-satellite",
|
"repo": "xwayland-satellite",
|
||||||
"rev": "8d135d3b2854b30fd01ea6cd6c27e523dd50a839",
|
"rev": "388d291e82ffbc73be18169d39470f340707edaa",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "Supreeeme",
|
"owner": "Supreeeme",
|
||||||
"ref": "v0.8.2",
|
"ref": "v0.7",
|
||||||
"repo": "xwayland-satellite",
|
"repo": "xwayland-satellite",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
@@ -1118,11 +1054,11 @@
|
|||||||
"xwayland-satellite-unstable": {
|
"xwayland-satellite-unstable": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1786221058,
|
"lastModified": 1772429643,
|
||||||
"narHash": "sha256-hF2atQzapHBLX5NFqJMcKZAWHfGkKQeNu1eQr46+AGg=",
|
"narHash": "sha256-M+bAeCCcjBnVk6w/4dIVvXvpJwOKnXjwi/lDbaN6Yws=",
|
||||||
"owner": "Supreeeme",
|
"owner": "Supreeeme",
|
||||||
"repo": "xwayland-satellite",
|
"repo": "xwayland-satellite",
|
||||||
"rev": "3bc915f09dd62bb2651a715114f9d140344bc6c1",
|
"rev": "10f985b84cdbcc3bbf35b3e7e43d1b2a84fa9ce2",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
disko.url = "github:nix-community/disko";
|
disko.url = "github:nix-community/disko";
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
# nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||||
# Waiting on https://github.com/NixOS/nixpkgs/pull/500538
|
# Waiting on https://github.com/NixOS/nixpkgs/pull/500538
|
||||||
# nixpkgs.url = "github:msyds/nixpkgs/fix-bepasty";
|
nixpkgs.url = "github:msyds/nixpkgs/fix-bepasty";
|
||||||
impermanence.url = "github:nix-community/impermanence";
|
impermanence.url = "github:nix-community/impermanence";
|
||||||
home-manager.url = "github:nix-community/home-manager";
|
home-manager.url = "github:nix-community/home-manager";
|
||||||
sops-nix.url = "github:Mic92/sops-nix";
|
sops-nix.url = "github:Mic92/sops-nix";
|
||||||
@@ -14,9 +14,8 @@
|
|||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
emacs-overlay.url = "github:nix-community/emacs-overlay";
|
emacs-overlay.url = "github:nix-community/emacs-overlay";
|
||||||
# niri.url = "github:sodiboo/niri-flake";
|
niri.url = "github:sodiboo/niri-flake";
|
||||||
niri.url = "github:epireyn/niri-flake";
|
stylix.url = "github:danth/stylix";
|
||||||
stylix.url = "github:nix-community/stylix";
|
|
||||||
nixcord.url = "github:KaylorBen/nixcord";
|
nixcord.url = "github:KaylorBen/nixcord";
|
||||||
vpn-confinement.url = "github:Maroka-chan/VPN-Confinement";
|
vpn-confinement.url = "github:Maroka-chan/VPN-Confinement";
|
||||||
nixarr = {
|
nixarr = {
|
||||||
@@ -37,10 +36,6 @@
|
|||||||
url = "git+https://git.deertopia.net/msyds/sydpkgs";
|
url = "git+https://git.deertopia.net/msyds/sydpkgs";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
dms = {
|
|
||||||
url = "github:AvengeMedia/DankMaterialShell/stable";
|
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = { self, nixpkgs, ... }@inputs:
|
outputs = { self, nixpkgs, ... }@inputs:
|
||||||
@@ -80,24 +75,16 @@
|
|||||||
|
|
||||||
packages.x86_64-linux.live-minimal =
|
packages.x86_64-linux.live-minimal =
|
||||||
self.nixosConfigurations.live-minimal.config.system.build.isoImage;
|
self.nixosConfigurations.live-minimal.config.system.build.isoImage;
|
||||||
|
|
||||||
devShells.x86_64-linux.default =
|
|
||||||
let pkgs = import inputs.nixpkgs { system = "x86_64-linux"; };
|
|
||||||
in pkgs.mkShell {
|
|
||||||
packages = [ pkgs.nil ];
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
nixConfig = {
|
nixConfig = {
|
||||||
extra-substituters = [
|
extra-substituters = [
|
||||||
"https://nix-community.cachix.org"
|
"https://nix-community.cachix.org"
|
||||||
"https://niri.cachix.org"
|
"https://niri.cachix.org"
|
||||||
"https://niri-epireyn.cachix.org"
|
|
||||||
];
|
];
|
||||||
extra-trusted-public-keys = [
|
extra-trusted-public-keys = [
|
||||||
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
|
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
|
||||||
"niri.cachix.org-1:Wv0OmO7PsuocRKzfDoJ3mulSl7Z6oezYhGhR+3W2964="
|
"niri.cachix.org-1:Wv0OmO7PsuocRKzfDoJ3mulSl7Z6oezYhGhR+3W2964="
|
||||||
"niri-epireyn.cachix.org-1:tlVyFN7CtsDT+ZcLPS+ekFWeT1X6X4OqvWqbBMyIzFA="
|
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
deertopia = {
|
deertopia = {
|
||||||
authelia.enable = true;
|
authelia.enable = true;
|
||||||
gitea.enable = true;
|
gitea.enable = true;
|
||||||
# quiver.enable = true;
|
quiver.enable = true;
|
||||||
www.enable = true;
|
www.enable = true;
|
||||||
bepasty.enable = true;
|
bepasty.enable = true;
|
||||||
jellyfin.enable = false;
|
jellyfin.enable = false;
|
||||||
@@ -67,16 +67,16 @@
|
|||||||
murmur.enable = true;
|
murmur.enable = true;
|
||||||
anki-sync-server.enable = true;
|
anki-sync-server.enable = true;
|
||||||
vaultwarden.enable = true;
|
vaultwarden.enable = true;
|
||||||
beets.enable = true;
|
|
||||||
servarr = {
|
servarr = {
|
||||||
enable = true;
|
enable = true;
|
||||||
prowlarr.enable = true;
|
prowlarr.enable = true;
|
||||||
jellyfin.enable = true;
|
jellyfin.enable = true;
|
||||||
transmission.enable = true;
|
transmission.enable = true;
|
||||||
sonarr.enable = true;
|
sonarr.enable = true;
|
||||||
# lidarr.enable = true;
|
lidarr.enable = true;
|
||||||
radarr.enable = true;
|
radarr.enable = true;
|
||||||
# sabnzbd.enable = true;
|
# sabnzbd.enable = true;
|
||||||
|
# slskd.enable = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
upower.enable = true;
|
upower.enable = true;
|
||||||
|
|
||||||
users.users = [
|
users.users = [
|
||||||
|
# "crumb"
|
||||||
"msyds"
|
"msyds"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ in {
|
|||||||
"/nix" = subvol "nix";
|
"/nix" = subvol "nix";
|
||||||
"/boot" = {
|
"/boot" = {
|
||||||
device = "/dev/disk/by-id/ata-APPLE_SSD_SM0512G_S29ANYAH526520-part3";
|
device = "/dev/disk/by-id/ata-APPLE_SSD_SM0512G_S29ANYAH526520-part3";
|
||||||
fsType = "vfat";
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,6 @@
|
|||||||
./disks.nix
|
./disks.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
boot.kernelPackages = pkgs.linuxPackages_latest;
|
|
||||||
|
|
||||||
boot.extraModulePackages = with config.boot.kernelPackages; [
|
boot.extraModulePackages = with config.boot.kernelPackages; [
|
||||||
v4l2loopback
|
v4l2loopback
|
||||||
];
|
];
|
||||||
@@ -41,11 +39,13 @@
|
|||||||
steam = {
|
steam = {
|
||||||
enable = true;
|
enable = true;
|
||||||
impermanenceUsers = [
|
impermanenceUsers = [
|
||||||
|
# "crumb"
|
||||||
"msyds"
|
"msyds"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
users.users = [
|
users.users = [
|
||||||
|
# "crumb"
|
||||||
"msyds"
|
"msyds"
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -69,6 +69,7 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Make pressing the power button suspend the system.
|
||||||
services.logind.settings.Login = {
|
services.logind.settings.Login = {
|
||||||
HandlePowerKey = "suspend";
|
HandlePowerKey = "suspend";
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.sydnix.dank-material-shell;
|
||||||
|
json = pkgs.formats.json {};
|
||||||
|
in {
|
||||||
|
options.sydnix.dank-material-shell = {
|
||||||
|
enable = lib.mkEnableOption "DMS";
|
||||||
|
settings = lib.mkOption {
|
||||||
|
type = json.type;
|
||||||
|
default = { };
|
||||||
|
description = ''
|
||||||
|
DankMaterialShell configuration settings as an attribute set,
|
||||||
|
to be written to ~/.config/DankMaterialShell/settings.json.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
xdg.configFile = {
|
||||||
|
"DankMaterialShell/settings.json".source =
|
||||||
|
json.generate "settings.json" cfg.settings;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -31,7 +31,7 @@ let
|
|||||||
display = ["year" "album" "genres"];
|
display = ["year" "album" "genres"];
|
||||||
separator = "•";
|
separator = "•";
|
||||||
};
|
};
|
||||||
blacklist.media_types = [
|
blacklist.libraries = [
|
||||||
"episode"
|
"episode"
|
||||||
"movie"
|
"movie"
|
||||||
"book"
|
"book"
|
||||||
|
|||||||
@@ -171,14 +171,6 @@ in {
|
|||||||
client.enable = true;
|
client.enable = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
# Start Emacs after the graphical session so as to inherit
|
|
||||||
# expected envvars, but don't necessarily /depend/ on a
|
|
||||||
# graphical session.
|
|
||||||
systemd.user.services.emacs = {
|
|
||||||
Unit.After = [ "graphical-session.target" ];
|
|
||||||
Install.WantedBy = lib.mkForce [ "graphical-session.target" ];
|
|
||||||
};
|
|
||||||
|
|
||||||
# We do this ourselves.
|
# We do this ourselves.
|
||||||
stylix.targets.emacs.enable = false;
|
stylix.targets.emacs.enable = false;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
|
||||||
|
|
||||||
let cfg = config.sydnix.guile;
|
|
||||||
in {
|
|
||||||
options.sydnix.guile = {
|
|
||||||
enable = lib.mkEnableOption "Guile Scheme";
|
|
||||||
};
|
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
|
||||||
home.file.".guile".text = ''
|
|
||||||
(use-modules (ice-9 readline))
|
|
||||||
(activate-readline)
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -12,24 +12,8 @@ in {
|
|||||||
builtins.readFile ./haskell/ghc-with-packages.sh;
|
builtins.readFile ./haskell/ghc-with-packages.sh;
|
||||||
|
|
||||||
home.file.".ghc/ghci.conf".text = ''
|
home.file.".ghc/ghci.conf".text = ''
|
||||||
:{
|
:set prompt "\x1b[38;5;5mλ>\x1b[0m "
|
||||||
ghci_set_prompt :: IO String
|
:set prompt-cont "\x1b[38;5;5m|>\x1b[0m "
|
||||||
ghci_set_prompt = do
|
|
||||||
term <- System.Environment.Blank.getEnvDefault "TERM" ""
|
|
||||||
let (prompt,promptCont) =
|
|
||||||
if Data.List.isPrefixOf "xterm-" term
|
|
||||||
then ("\x1b[38;5;5mλ>\x1b[0m ", "\x1b[38;5;5m|>\x1b[0m ")
|
|
||||||
else ("λ> ", "|> ")
|
|
||||||
pure . unlines $
|
|
||||||
[ ":set prompt " ++ show prompt
|
|
||||||
, ":set prompt-cont " ++ show promptCont
|
|
||||||
]
|
|
||||||
:}
|
|
||||||
:cmd ghci_set_prompt
|
|
||||||
:set -interactive-print=Text.Pretty.Simple.pPrint
|
|
||||||
:m + Text.Show.Functions
|
|
||||||
:unset +r
|
|
||||||
:set +m
|
|
||||||
'';
|
'';
|
||||||
|
|
||||||
sydnix.impermanence.cache.directories =
|
sydnix.impermanence.cache.directories =
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ in {
|
|||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
home.persistence = {
|
home.persistence = {
|
||||||
"/persist" = {
|
"/persist/home/${config.home.username}" = {
|
||||||
# allowOther = true;
|
allowOther = true;
|
||||||
directories = cfg.directories ++ cfg.cache.directories;
|
directories = cfg.directories ++ cfg.cache.directories;
|
||||||
files = cfg.files ++ cfg.cache.files;
|
files = cfg.files ++ cfg.cache.files;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ in {
|
|||||||
# https://github.com/ValveSoftware/steam-for-linux/issues/10552
|
# https://github.com/ValveSoftware/steam-for-linux/issues/10552
|
||||||
# https://github.com/nix-community/impermanence/issues/165
|
# https://github.com/nix-community/impermanence/issues/165
|
||||||
# { directory = ".local/share/Steam"; method = "symlink"; }
|
# { directory = ".local/share/Steam"; method = "symlink"; }
|
||||||
{ directory = ".steam"; }
|
{ directory = ".steam"; method = "symlink"; }
|
||||||
];
|
];
|
||||||
|
|
||||||
home.packages = [
|
home.packages = [
|
||||||
|
|||||||
@@ -7,6 +7,6 @@ in {
|
|||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.overlay.enable {
|
config = lib.mkIf cfg.overlay.enable {
|
||||||
# nixpkgs.overlays = [ inputs.sydpkgs.overlays.default ];
|
nixpkgs.overlays = [ inputs.sydpkgs.overlays.default ];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,14 +7,13 @@ in {
|
|||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
# fcitx5-toki-pona is broken
|
i18n.inputMethod.fcitx5.addons = [
|
||||||
# i18n.inputMethod.fcitx5.addons = [
|
(pkgs.fcitx5-toki-pona.overrideAttrs (final: prev: {
|
||||||
# (pkgs.fcitx5-toki-pona.overrideAttrs (final: prev: {
|
patches = prev.patches or [] ++ [
|
||||||
# patches = prev.patches or [] ++ [
|
./toki-pona/punctuation.patch
|
||||||
# ./toki-pona/punctuation.patch
|
];
|
||||||
# ];
|
}))
|
||||||
# }))
|
];
|
||||||
# ];
|
|
||||||
|
|
||||||
programs.ghostty.settings.font-family = lib.mkAfter [
|
programs.ghostty.settings.font-family = lib.mkAfter [
|
||||||
"sitelen seli kiwen mono juniko"
|
"sitelen seli kiwen mono juniko"
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
let
|
let
|
||||||
mutableSymlink = config.lib.file.mkOutOfStoreSymlink;
|
mutableSymlink = config.lib.file.mkOutOfStoreSymlink;
|
||||||
cfg = config.sydnix.users.msyds.age;
|
cfg = config.sydnix.users.crumb.age;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.sydnix.users.msyds.age.enable = lib.mkEnableOption "Age, à la msyds";
|
options.sydnix.users.crumb.age.enable = lib.mkEnableOption "Age, à la crumb";
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
home.packages = [
|
home.packages = [
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
let cfg = config.sydnix.users.msyds.anki;
|
let cfg = config.sydnix.users.crumb.anki;
|
||||||
in {
|
in {
|
||||||
options.sydnix.users.msyds.anki = {
|
options.sydnix.users.crumb.anki = {
|
||||||
enable = lib.mkEnableOption "Anki desktop";
|
enable = lib.mkEnableOption "Anki desktop";
|
||||||
};
|
};
|
||||||
|
|
||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
let cfg = config.sydnix.users.msyds.default-applications;
|
let cfg = config.sydnix.users.crumb.default-applications;
|
||||||
in {
|
in {
|
||||||
options.sydnix.users.msyds.default-applications = {
|
options.sydnix.users.crumb.default-applications = {
|
||||||
enable = lib.mkEnableOption "Default mime-type applications";
|
enable = lib.mkEnableOption "Default mime-type applications";
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.sydnix.users.msyds.direnv;
|
cfg = config.sydnix.users.crumb.direnv;
|
||||||
in {
|
in {
|
||||||
options.sydnix.users.msyds.direnv.enable =
|
options.sydnix.users.crumb.direnv.enable =
|
||||||
lib.mkEnableOption "direnv, à la msyds";
|
lib.mkEnableOption "direnv, à la crumb";
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
programs.direnv = {
|
programs.direnv = {
|
||||||
enable = true;
|
enable = true;
|
||||||
@@ -0,0 +1,213 @@
|
|||||||
|
{ config, lib, pkgs, inputs, options, ... }@args:
|
||||||
|
|
||||||
|
let cfg = config.sydnix.users.crumb.emacs;
|
||||||
|
in {
|
||||||
|
options.sydnix.users.crumb.emacs.enable =
|
||||||
|
lib.mkEnableOption ''Emacs, à la crumb'';
|
||||||
|
config = lib.mkIf cfg.enable
|
||||||
|
(let
|
||||||
|
emacsBasePackage = pkgs.emacs-pgtk;
|
||||||
|
# Hard-coded path. }:\
|
||||||
|
emacsConfigDir =
|
||||||
|
"/persist/dots/modules/home/users/${config.home.username}/emacs";
|
||||||
|
|
||||||
|
# Create a new instance of nixpkgs with emacs-overlay applied. This is a
|
||||||
|
# little unorthodox, but we do it
|
||||||
|
# 1. for the sake of organisation — For pure aesthetics and a clean
|
||||||
|
# codebase, I want everything Emacs to stay in this file;
|
||||||
|
# 2. and, there's simply no need to leak emacs-overlay's packages into the
|
||||||
|
# global nixpkgs instance when nothing else is using it!
|
||||||
|
# pkgs' = import inputs.nixpkgs {
|
||||||
|
# system = args.system;
|
||||||
|
# overlays = [ inputs.emacs-overlay.overlays.emacs ];
|
||||||
|
# };
|
||||||
|
|
||||||
|
emacsDataDir = "${config.xdg.dataHome}/emacs";
|
||||||
|
emacsCacheDir = "${config.xdg.cacheHome}/emacs";
|
||||||
|
straightBaseDir = "${emacsDataDir}/straight";
|
||||||
|
|
||||||
|
fontPackages = [
|
||||||
|
pkgs.julia-mono
|
||||||
|
pkgs.nerd-fonts.victor-mono
|
||||||
|
pkgs.ibm-plex
|
||||||
|
];
|
||||||
|
|
||||||
|
my-aspell = pkgs.aspellWithDicts
|
||||||
|
(dicts: with dicts; [
|
||||||
|
en en-computers en-science
|
||||||
|
]);
|
||||||
|
|
||||||
|
my-tex = pkgs.texlive.combine {
|
||||||
|
diagrams = pkgs.stdenvNoCC.mkDerivation (final: {
|
||||||
|
pname = "diagrams-latex";
|
||||||
|
version = "0.8.0.6-r3";
|
||||||
|
src = pkgs.fetchFromGitHub {
|
||||||
|
owner = "diagrams";
|
||||||
|
repo = "diagrams-builder";
|
||||||
|
rev = "v${final.version}";
|
||||||
|
hash = "sha256-/6vAxVWcwsPHh2im12zAD08b9VnsvOUXz/5mYsY7pK0=";
|
||||||
|
};
|
||||||
|
nativeBuildInputs = [ pkgs.texlive.combined.scheme-small ];
|
||||||
|
passthru = {
|
||||||
|
pkgs = [ final.finalPackage ];
|
||||||
|
tlDeps = with pkgs.texlive; [
|
||||||
|
latex
|
||||||
|
moreverb
|
||||||
|
];
|
||||||
|
tlType = "run";
|
||||||
|
};
|
||||||
|
installPhase = ''
|
||||||
|
runHook preInstall
|
||||||
|
dir="$out/tex/latex/diagrams-latex"
|
||||||
|
mkdir -p "$dir"
|
||||||
|
mv latex/diagrams-latex.sty "$dir"
|
||||||
|
runHook postInstall
|
||||||
|
'';
|
||||||
|
});
|
||||||
|
inherit (pkgs.texlive)
|
||||||
|
scheme-basic # Set of common packages.
|
||||||
|
fontspec
|
||||||
|
dvisvgm dvipng wrapfig # For Org-mode previews/export.
|
||||||
|
amsmath # Essential for mathematics.
|
||||||
|
ulem hyperref
|
||||||
|
capt-of
|
||||||
|
pgf # Includes TikZ.
|
||||||
|
pgfplots
|
||||||
|
spath3 # TikZ dependency?
|
||||||
|
tikz-cd # Commutative diagrams w/ TikZ.
|
||||||
|
quiver # Commutative diagrams w/ TikZ & q.uiver.app.
|
||||||
|
metafont
|
||||||
|
preview # For new-gen org-latex-preview.
|
||||||
|
mylatexformat # For new-gen org-latex-preview.
|
||||||
|
collection-fontsrecommended # Essential fonts.
|
||||||
|
etoolbox # For Org-mode exports.
|
||||||
|
siunitx # Typesetting units.
|
||||||
|
moderncv
|
||||||
|
# Tufte-latex and its stupid fucking dependencies.
|
||||||
|
tufte-latex
|
||||||
|
xkeyval
|
||||||
|
changepage
|
||||||
|
fancyhdr
|
||||||
|
geometry
|
||||||
|
natbib
|
||||||
|
paralist
|
||||||
|
placeins
|
||||||
|
ragged2e
|
||||||
|
setspace
|
||||||
|
textcase
|
||||||
|
titlesec
|
||||||
|
xcolor
|
||||||
|
hardwrap
|
||||||
|
xifthen
|
||||||
|
catchfile
|
||||||
|
;
|
||||||
|
};
|
||||||
|
|
||||||
|
my-emacs =
|
||||||
|
let ewp = (pkgs.emacsPackagesFor emacsBasePackage).emacsWithPackages
|
||||||
|
(epkgs: with epkgs; [
|
||||||
|
jinx
|
||||||
|
pdf-tools
|
||||||
|
treesit-grammars.with-all-grammars
|
||||||
|
]);
|
||||||
|
in pkgs.symlinkJoin {
|
||||||
|
name = "sydmacs";
|
||||||
|
paths = [ ewp ];
|
||||||
|
nativeBuildInputs = [ pkgs.makeWrapper ];
|
||||||
|
postBuild =
|
||||||
|
let runtime-binaries = [
|
||||||
|
my-aspell
|
||||||
|
pkgs.git # Dependency of Straight.el.
|
||||||
|
pkgs.ghostscript # For TeX.
|
||||||
|
my-tex
|
||||||
|
pkgs.unzip # For jump-to-source.
|
||||||
|
];
|
||||||
|
in ''
|
||||||
|
find "$out/bin" -name emacs -or -name "emacs-*" \
|
||||||
|
| while IFS= read -r emacs; do
|
||||||
|
wrapProgram "$emacs" \
|
||||||
|
--add-flags "--init-directory \"${emacsConfigDir}\"" \
|
||||||
|
--set EMACS_STRAIGHT_BASE_DIR "${straightBaseDir}" \
|
||||||
|
--set EMACS_CACHE_DIR "${emacsCacheDir}" \
|
||||||
|
--set EMACS_DATA_DIR "${emacsDataDir}" \
|
||||||
|
--set ASPELL_CONF "dict-dir ${my-aspell}/lib/aspell" \
|
||||||
|
--prefix PATH : "${lib.makeBinPath runtime-binaries}"
|
||||||
|
done
|
||||||
|
'';
|
||||||
|
meta = emacsBasePackage.meta;
|
||||||
|
version = emacsBasePackage.version;
|
||||||
|
};
|
||||||
|
|
||||||
|
emacsclient-or-emacs = pkgs.writeShellScriptBin "emacsclient-or-emacs" ''
|
||||||
|
emacsclient --alternate-editor=${config.programs.emacs.finalPackage}/bin/emacs "$@"
|
||||||
|
'';
|
||||||
|
in {
|
||||||
|
programs.emacs = {
|
||||||
|
enable = true;
|
||||||
|
package = my-emacs;
|
||||||
|
};
|
||||||
|
|
||||||
|
sydnix.impermanence.cache.directories =
|
||||||
|
# Impermanence expects the path to be relative to ~.
|
||||||
|
map (lib.removePrefix config.home.homeDirectory) [
|
||||||
|
straightBaseDir
|
||||||
|
emacsCacheDir
|
||||||
|
emacsDataDir
|
||||||
|
];
|
||||||
|
|
||||||
|
# Set emacsclient as the default editor for the time being.
|
||||||
|
home.sessionVariables =
|
||||||
|
let e = "${emacsclient-or-emacs}/bin/emacsclient-or-emacs";
|
||||||
|
in {
|
||||||
|
"EDITOR" = e;
|
||||||
|
"VISUAL" = e;
|
||||||
|
};
|
||||||
|
|
||||||
|
home.file =
|
||||||
|
let default =
|
||||||
|
lib.removePrefix "${config.home.homeDirectory}/"
|
||||||
|
"${straightBaseDir}/straight/versions/default.el";
|
||||||
|
in {
|
||||||
|
${default}.source =
|
||||||
|
config.lib.file.mkOutOfStoreSymlink
|
||||||
|
"${emacsConfigDir}/straight-lockfile.el";
|
||||||
|
};
|
||||||
|
|
||||||
|
home.packages = [
|
||||||
|
emacsclient-or-emacs
|
||||||
|
(pkgs.writeShellScriptBin "emacs-fuckyou" ''
|
||||||
|
${my-emacs}/bin/emacs "$@"
|
||||||
|
'')
|
||||||
|
] ++ fontPackages;
|
||||||
|
|
||||||
|
# There's probably a better place to put this, but the current setup demands
|
||||||
|
# Fontconfig for Emacs to find my fonts.
|
||||||
|
fonts.fontconfig.enable = true;
|
||||||
|
|
||||||
|
# TODO: Make sure this is using the right package for Emacs...
|
||||||
|
services.emacs = {
|
||||||
|
enable = true;
|
||||||
|
# Generate a desktop entry for emacsclient.
|
||||||
|
client.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# We do this ourselves.
|
||||||
|
stylix.targets.emacs.enable =
|
||||||
|
lib.mkIf (lib.hasAttrByPath ["stylix" "targets" "emacs"] options)
|
||||||
|
false;
|
||||||
|
|
||||||
|
home.shellAliases = {
|
||||||
|
e = "emacsclient-or-emacs";
|
||||||
|
ec = "emacsclient";
|
||||||
|
em = "emacs";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Mark Emacs as a valid PDF reader.
|
||||||
|
xdg.mimeApps.associations.added = {
|
||||||
|
"application/pdf" = [
|
||||||
|
"emacsclient.desktop"
|
||||||
|
"emacs.desktop"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
[cool-deer goes here]
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
;;; early-init.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(add-to-list 'load-path (file-name-concat user-emacs-directory "lib"))
|
||||||
|
(require 'syd-constants)
|
||||||
|
|
||||||
|
;; Disable package.el; we use Straight.
|
||||||
|
(setq package-enable-at-startup nil)
|
||||||
|
|
||||||
|
;; Enable use-package statistics for the sake of start-up profiling.
|
||||||
|
(setq use-package-compute-statistics t)
|
||||||
|
|
||||||
|
(setq gc-cons-threshold
|
||||||
|
;; (8 gibibytes)
|
||||||
|
(* 8 (expt 1024 3)))
|
||||||
|
|
||||||
|
(set-frame-parameter nil 'drag-with-header-line t)
|
||||||
|
(set-frame-parameter nil 'undecorated t)
|
||||||
|
|
||||||
|
;; By default, Emacs will cache compilation artifacts in my personal config
|
||||||
|
;; directory — I'm not keen on that! Redirect it to a dedicated cache directory.
|
||||||
|
(startup-redirect-eln-cache (file-name-concat syd-cache-dir "eln-cache"))
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
alias ga git add $*
|
||||||
|
alias gb git branch $*
|
||||||
|
alias gc git commit $*
|
||||||
|
alias gcl git clone $*
|
||||||
|
alias gco git checkout $*
|
||||||
|
alias gd git diff $*
|
||||||
|
alias gl git log $*
|
||||||
|
alias glo git log --pretty=oneline $*
|
||||||
|
alias glol git log --graph --oneline --decorate $*
|
||||||
|
alias gp git push $*
|
||||||
|
alias gr git remote $*
|
||||||
|
alias grs git remote show $*
|
||||||
|
alias gs git status $*
|
||||||
|
alias gtd git tag --delete $*
|
||||||
|
|
||||||
|
alias jj jj --no-pager $*
|
||||||
|
alias jb jj bookmark $*
|
||||||
|
alias jd jj describe $*
|
||||||
|
alias jdi jj diff $*
|
||||||
|
alias je jj edit $*
|
||||||
|
alias jgcl jj git clone $*
|
||||||
|
alias jgp jj git push $*
|
||||||
|
alias jgr jj git remote $*
|
||||||
|
alias jl jj log $*
|
||||||
|
alias jn jj new $*
|
||||||
|
alias js jj status $*
|
||||||
|
alias jsp jj split $*
|
||||||
|
|
||||||
|
alias l ls -alh $*
|
||||||
|
alias ll ls -l $*
|
||||||
|
alias ls ls --color=tty $*
|
||||||
|
alias ff find-file $*
|
||||||
|
|
||||||
|
alias pass /nix/store/hqhi6dgl7p16v49ymg2hwkgl844092fb-passage-1.7.4a2/bin/passage $*
|
||||||
|
|
||||||
|
alias cdp syd-cd-project
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
;;; init-straight.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(defun syd-initialise-straight-options ()
|
||||||
|
(setq
|
||||||
|
;; Improves Straight's startup time. Instead of checking for modifications
|
||||||
|
;; on init, changes will only be detected when the file is saved from within
|
||||||
|
;; Emacs (with `save-buffer', specifically!).
|
||||||
|
straight-check-for-modifications '(check-on-save find-when-checking)))
|
||||||
|
|
||||||
|
;; Bootstrap Straight.el
|
||||||
|
(defun syd-initialise-straight ()
|
||||||
|
(defvar bootstrap-version)
|
||||||
|
|
||||||
|
(syd-initialise-straight-options)
|
||||||
|
|
||||||
|
(setq straight-base-dir
|
||||||
|
(or (getenv "EMACS_STRAIGHT_BASE_DIR")
|
||||||
|
(error "Cannot initialise straight: $EMACS_STRAIGHT_BASE_DIR is undefined!")))
|
||||||
|
|
||||||
|
(let ((bootstrap-file
|
||||||
|
(file-name-concat straight-base-dir
|
||||||
|
"straight/repos/straight.el/bootstrap.el"))
|
||||||
|
(bootstrap-version 7))
|
||||||
|
(unless (file-exists-p bootstrap-file)
|
||||||
|
(message "Could not find Straight's bootstrap file. Attempting to download it now.")
|
||||||
|
(let* ((url "https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el")
|
||||||
|
(url-buffer (url-retrieve-synchronously url 'silent 'inhibit-cookies)))
|
||||||
|
(with-current-buffer url-buffer
|
||||||
|
(goto-char (point-max))
|
||||||
|
(eval-print-last-sexp))))
|
||||||
|
(load bootstrap-file nil 'nomessage))
|
||||||
|
|
||||||
|
(setq straight-use-package-by-default t))
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
;; -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
;; Initialise Straight.el
|
||||||
|
|
||||||
|
(load (locate-user-emacs-file "init-straight"))
|
||||||
|
(syd-initialise-straight)
|
||||||
|
|
||||||
|
|
||||||
|
;; My friend Nova
|
||||||
|
|
||||||
|
;; This is my friend Nova. She has to have her own page to spread her spores
|
||||||
|
;; in. Y^,..,^Y
|
||||||
|
|
||||||
|
;;⠀⠀⣄⠀⠀⠀⠀⠀⠀⢠⠖⠒⠒⠒⢄⠀⠀⠀⠀⢀⢖⡆⠀⠀⠀
|
||||||
|
;;⠀⠀⡇⠑⣄⠀⠀⠀⠀⠯⣀⡀⠀⢀⣨⠆⠀⠀⢀⠎⢸⠀⠀⠀⠀
|
||||||
|
;;⠀⠀⢹⠀⠈⠓⢄⣀⡠⠤⠤⡇⠀⢸⠤⣄⡀⣠⠎⠀⢸⠀⠀⠀⠀
|
||||||
|
;;⠀⠀⠸⡀⢀⡔⠉⠹⠄⠀⠴⠧⠤⢼⣀⠀⠈⠳⡄⠀⢸⠀⠀⠀⠀
|
||||||
|
;;⠀⠀⠀⢣⡞⠀⠀⠀⣀⣀⡀⠀⠀⠀⢀⣄⡀⠀⠘⢦⢸⠀⠀⠀⠀
|
||||||
|
;;⠀⠀⠀⠀⡇⠀⠀⠐⠁⠀⠙⠀⠀⠀⠋⠀⠙⠀⠀⠈⣿⠄⠀⠀⠀
|
||||||
|
;;⠀⠀⠀⠀⢳⡀⠀⠀⠀⠀⠀⣠⣄⠀⠀⠀⠀⠀⠀⠈⢹⠀⠀⠀⠀
|
||||||
|
;;⠀⠀⠀⠀⠀⠱⣄⠀⠀⠀⠀⠻⠟⠀⠀⠀⠀⠀⢀⣠⠏⠀⠀⠀⠀
|
||||||
|
;;⠀⠀⠀⠀⠀⠀⢸⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⢺⡉⠀⠀⠀⠀⠀⠀
|
||||||
|
;;⠀⠀⠀⠀⠀⢠⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠳⡀⠀⠀⠀⠀⠀
|
||||||
|
;;⠀⠀⠀⠀⠀⡞⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢳⠀⠀⠀⠀
|
||||||
|
;;⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀
|
||||||
|
;;⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠞⠀⠀⠀⠀
|
||||||
|
|
||||||
|
|
||||||
|
;; Personal modules
|
||||||
|
|
||||||
|
(add-to-list 'load-path (file-name-concat user-emacs-directory "modules"))
|
||||||
|
|
||||||
|
;; Must come before the rest!
|
||||||
|
(require 'syd-use-package)
|
||||||
|
(require 'syd-general)
|
||||||
|
|
||||||
|
;; `on.el' provides a collection of utility hooks and functions ported
|
||||||
|
;; from Doom Emacs. The hooks make it easier to speed up Emacs
|
||||||
|
;; startup by providing finer-grained control of the timing at which
|
||||||
|
;; packages are loaded.
|
||||||
|
(use-package on
|
||||||
|
:straight (:type git
|
||||||
|
:host gitlab
|
||||||
|
:repo "crumbtoo/on.el"))
|
||||||
|
|
||||||
|
;; Used in many other modules, so it comes first.
|
||||||
|
(require 'syd-popups)
|
||||||
|
|
||||||
|
(require 'syd-age)
|
||||||
|
(require 'syd-autosave)
|
||||||
|
(require 'syd-completion)
|
||||||
|
(require 'syd-custom)
|
||||||
|
(require 'syd-dired)
|
||||||
|
(require 'syd-display-startup-time)
|
||||||
|
(require 'syd-ediff)
|
||||||
|
(require 'syd-editing)
|
||||||
|
(require 'syd-eshell)
|
||||||
|
(require 'syd-evil)
|
||||||
|
(require 'syd-keybinds)
|
||||||
|
(require 'syd-lang)
|
||||||
|
(require 'syd-org)
|
||||||
|
(require 'syd-pdfs)
|
||||||
|
(require 'syd-projects)
|
||||||
|
(require 'syd-scratch)
|
||||||
|
(require 'syd-smartparens)
|
||||||
|
(require 'syd-snippets)
|
||||||
|
(require 'syd-tabs)
|
||||||
|
(require 'syd-tooling)
|
||||||
|
(require 'syd-tramp)
|
||||||
|
(require 'syd-trust)
|
||||||
|
(require 'syd-ui)
|
||||||
|
(put 'narrow-to-region 'disabled nil)
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
;;; clj-lib.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(require 'dash)
|
||||||
|
|
||||||
|
(defmacro clj-condp (pred expr &rest clauses)
|
||||||
|
"TODO: Very unfinished."
|
||||||
|
(declare (indent defun))
|
||||||
|
(unless (symbolp pred)
|
||||||
|
(signal 'wrong-type-argument `(symbolp ,pred)))
|
||||||
|
(let ((expr* (gensym "expr")))
|
||||||
|
`(let ((,expr* ,expr))
|
||||||
|
(cond ,@(mapcar (lambda (x) `((,pred ,expr ,(car x)) ,(nth 1 x)))
|
||||||
|
clauses)))))
|
||||||
|
|
||||||
|
(provide 'clj-lib)
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
;;; syd-buffers.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(require 'syd-prelude)
|
||||||
|
|
||||||
|
(syd-define-stub
|
||||||
|
syd/kill-all-buffers
|
||||||
|
:desc "Kill all buffers. See `doom/kill-all-buffers'."
|
||||||
|
:interactive t)
|
||||||
|
|
||||||
|
(syd-define-stub
|
||||||
|
syd/kill-other-buffers
|
||||||
|
:desc "Kill other buffers. See `doom/kill-other-buffers'."
|
||||||
|
:interactive t)
|
||||||
|
|
||||||
|
(syd-define-stub
|
||||||
|
syd/kill-burried-buffers
|
||||||
|
:desc "Kill burried buffers. See `doom/kill-burried-buffers'."
|
||||||
|
:interactive t)
|
||||||
|
|
||||||
|
(syd-define-stub
|
||||||
|
syd/save-buffer-as-root
|
||||||
|
:desc "Sudo save buffer as root. See `doom/sudo-save-buffer'"
|
||||||
|
:interactive t)
|
||||||
|
|
||||||
|
(defvar syd-fallback-buffer-name "*scratch*"
|
||||||
|
"The name of the buffer to fall back to if no other buffers exist (will create
|
||||||
|
it if it doesn't exist).")
|
||||||
|
|
||||||
|
(defun syd-fallback-buffer ()
|
||||||
|
"Returns the fallback buffer, creating it if necessary. By default this is the
|
||||||
|
scratch buffer. See `syd-fallback-buffer-name' to change this."
|
||||||
|
(let (buffer-list-update-hook)
|
||||||
|
(get-buffer-create syd-fallback-buffer-name)))
|
||||||
|
|
||||||
|
(defvar-local syd-real-buffer-p nil
|
||||||
|
"If non-nil, this buffer should be considered real no matter what. See
|
||||||
|
`syd-real-buffer-p' for more information.")
|
||||||
|
|
||||||
|
(defun syd-special-buffer-p (buf)
|
||||||
|
"Returns non-nil if BUF's name starts and ends with an *."
|
||||||
|
(char-equal ?* (aref (buffer-name buf) 0)))
|
||||||
|
|
||||||
|
(defun syd-non-file-visiting-buffer-p (buf)
|
||||||
|
(with-current-buffer buf
|
||||||
|
(if buffer-file-name t nil)))
|
||||||
|
|
||||||
|
(defvar syd-unreal-buffer-functions
|
||||||
|
'(minibufferp syd-special-buffer-p syd-non-file-visiting-buffer-p)
|
||||||
|
"A list of predicate functions run to determine if a buffer is *not* real,
|
||||||
|
unlike `syd-real-buffer-functions'. They are passed one argument: the buffer to
|
||||||
|
be tested.
|
||||||
|
|
||||||
|
Should any of these functions return non-nil, the rest of the functions are
|
||||||
|
ignored and the buffer is considered unreal.
|
||||||
|
|
||||||
|
See `syd-real-buffer-p' for more information.")
|
||||||
|
|
||||||
|
(defun syd-dired-buffer-p (buf)
|
||||||
|
"Returns non-nil if BUF is a dired buffer."
|
||||||
|
(provided-mode-derived-p (buffer-local-value 'major-mode buf)
|
||||||
|
'dired-mode))
|
||||||
|
|
||||||
|
(defvar syd-real-buffer-functions
|
||||||
|
'(syd-dired-buffer-p)
|
||||||
|
"A list of predicate functions run to determine if a buffer is real, unlike
|
||||||
|
`syd-unreal-buffer-functions'. They are passed one argument: the buffer to be
|
||||||
|
tested.
|
||||||
|
|
||||||
|
Should any of its function returns non-nil, the rest of the functions are
|
||||||
|
ignored and the buffer is considered real.
|
||||||
|
|
||||||
|
See `syd-real-buffer-p' for more information.")
|
||||||
|
|
||||||
|
(defun syd-temp-buffer-p (buf)
|
||||||
|
"Returns non-nil if BUF is temporary."
|
||||||
|
(char-equal ?\s (aref (buffer-name buf) 0)))
|
||||||
|
|
||||||
|
(defun syd-real-buffer-p (buffer-or-name)
|
||||||
|
"Returns t if BUFFER-OR-NAME is a 'real' buffer.
|
||||||
|
|
||||||
|
A real buffer is a useful buffer; a first class citizen. Real ones should get
|
||||||
|
special treatment, because we will be spending most of our time in them. Unreal
|
||||||
|
ones should be low-profile and easy to cast aside, so we can focus on real ones.
|
||||||
|
|
||||||
|
The exact criteria for a real buffer is:
|
||||||
|
|
||||||
|
1. A non-nil value for the buffer-local value of the `syd-real-buffer-p'
|
||||||
|
variable OR
|
||||||
|
2. Any function in `syd-real-buffer-functions' returns non-nil OR
|
||||||
|
3. None of the functions in `syd-unreal-buffer-functions' must return
|
||||||
|
non-nil.
|
||||||
|
|
||||||
|
If BUFFER-OR-NAME is omitted or nil, the current buffer is tested."
|
||||||
|
(or (bufferp buffer-or-name)
|
||||||
|
(stringp buffer-or-name)
|
||||||
|
(signal 'wrong-type-argument (list '(bufferp stringp) buffer-or-name)))
|
||||||
|
(when-let (buf (get-buffer buffer-or-name))
|
||||||
|
(when-let (basebuf (buffer-base-buffer buf))
|
||||||
|
(setq buf basebuf))
|
||||||
|
(and (buffer-live-p buf)
|
||||||
|
(not (syd-temp-buffer-p buf))
|
||||||
|
(or (buffer-local-value 'syd-real-buffer-p buf)
|
||||||
|
(run-hook-with-args-until-success 'syd-real-buffer-functions buf)
|
||||||
|
(not (run-hook-with-args-until-success 'syd-unreal-buffer-functions buf))))))
|
||||||
|
|
||||||
|
(defun syd-unreal-buffer-p (buffer-or-name)
|
||||||
|
"Return t if BUFFER-OR-NAME is an 'unreal' buffer.
|
||||||
|
|
||||||
|
See `syd-real-buffer-p' for details on what that means."
|
||||||
|
(not (syd-real-buffer-p buffer-or-name)))
|
||||||
|
|
||||||
|
(defun syd-fixup-windows (windows)
|
||||||
|
"Ensure that each of WINDOWS is showing a real buffer or the fallback buffer."
|
||||||
|
(dolist (window windows)
|
||||||
|
(with-selected-window window
|
||||||
|
(when (syd-unreal-buffer-p (window-buffer))
|
||||||
|
(previous-buffer)
|
||||||
|
(when (syd-unreal-buffer-p (window-buffer))
|
||||||
|
(switch-to-buffer (syd-fallback-buffer)))))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun syd-set-buffer-realness (buffer realness)
|
||||||
|
(with-current-buffer buffer
|
||||||
|
(setq syd-real-buffer-p realness)))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun syd-mark-buffer-as-real ()
|
||||||
|
(syd-set-buffer-realness (current-buffer) t))
|
||||||
|
|
||||||
|
(defun syd-kill-buffer-fixup-windows (buffer)
|
||||||
|
"Kill the BUFFER and ensure all the windows it was displayed in have switched
|
||||||
|
to a real buffer or the fallback buffer."
|
||||||
|
(let ((windows (get-buffer-window-list buffer)))
|
||||||
|
(kill-buffer buffer)
|
||||||
|
(syd-fixup-windows (cl-remove-if-not #'window-live-p windows))))
|
||||||
|
|
||||||
|
(defun syd/kill-this-buffer-in-all-windows (buffer &optional dont-save)
|
||||||
|
"Kill BUFFER globally and ensure all windows previously showing this buffer
|
||||||
|
have switched to a real buffer or the fallback buffer.
|
||||||
|
|
||||||
|
If DONT-SAVE, don't prompt to save modified buffers (discarding their changes)."
|
||||||
|
(interactive
|
||||||
|
(list (current-buffer) current-prefix-arg))
|
||||||
|
(cl-assert (bufferp buffer) t)
|
||||||
|
(when (and (buffer-modified-p buffer) dont-save)
|
||||||
|
(with-current-buffer buffer
|
||||||
|
(set-buffer-modified-p nil)))
|
||||||
|
(syd-kill-buffer-fixup-windows buffer))
|
||||||
|
|
||||||
|
(provide 'syd-buffers)
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
;;; syd-constants.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(defvar syd-data-dir
|
||||||
|
(or (getenv "EMACS_DATA_DIR")
|
||||||
|
(error "Need $EMACS_DATA_DIR"))
|
||||||
|
"Directory analogous to XDG_DATA_HOME for miscellaneous Emacs things. Sydnix
|
||||||
|
will wipe this on boot!")
|
||||||
|
|
||||||
|
(defvar syd-cache-dir
|
||||||
|
(or (getenv "EMACS_CACHE_DIR")
|
||||||
|
(error "Need $EMACS_CACHE_DIR"))
|
||||||
|
"Directory analogous to XDG_CACHE_HOME for miscellaneous Emacs things. Sydnix
|
||||||
|
will not usually wipe this on boot; /however/ it is still free to clear this
|
||||||
|
directory at any time.")
|
||||||
|
|
||||||
|
(provide 'syd-constants)
|
||||||
|
;;; syd-constants.el ends here
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
;;; syd-file.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(require 'syd-prelude)
|
||||||
|
(require 'syd-buffers)
|
||||||
|
(require 'cl-lib)
|
||||||
|
(eval-when-compile (require 'cl-lib))
|
||||||
|
(eval-when-compile (require 'tramp))
|
||||||
|
|
||||||
|
(syd-define-stub
|
||||||
|
syd/copy-this-file
|
||||||
|
:desc "Copy current file. See `doom/copy-this-file'."
|
||||||
|
:interactive t)
|
||||||
|
|
||||||
|
(defun syd-files--update-refs (&rest files)
|
||||||
|
"Ensure FILES are updated in `recentf', `magit' and `save-place'."
|
||||||
|
(let (toplevels)
|
||||||
|
(dolist (file files)
|
||||||
|
(when (featurep 'vc)
|
||||||
|
(vc-file-clearprops file)
|
||||||
|
(when-let (buffer (get-file-buffer file))
|
||||||
|
(with-current-buffer buffer
|
||||||
|
(vc-refresh-state))))
|
||||||
|
(when (featurep 'magit)
|
||||||
|
(when-let (default-directory
|
||||||
|
(magit-toplevel (file-name-directory file)))
|
||||||
|
(cl-pushnew default-directory toplevels)))
|
||||||
|
(unless (file-readable-p file)
|
||||||
|
(when (bound-and-true-p recentf-mode)
|
||||||
|
(recentf-remove-if-non-kept file))
|
||||||
|
(dolist (default-directory toplevels)
|
||||||
|
(magit-refresh))
|
||||||
|
(when (bound-and-true-p save-place-mode)
|
||||||
|
(save-place-forget-unreadable-files))))))
|
||||||
|
|
||||||
|
(defun syd/delete-this-file (&optional path force-p)
|
||||||
|
"Delete PATH, kill its buffers and expunge it from vc/magit cache.
|
||||||
|
|
||||||
|
If PATH is not specified, default to the current buffer's file.
|
||||||
|
|
||||||
|
If FORCE-P, delete without confirmation."
|
||||||
|
(interactive (list (buffer-file-name (buffer-base-buffer))
|
||||||
|
current-prefix-arg))
|
||||||
|
(let* ((path (or path (buffer-file-name (buffer-base-buffer))))
|
||||||
|
(short-path (and path (abbreviate-file-name path))))
|
||||||
|
(unless path
|
||||||
|
(user-error "Buffer is not visiting any file"))
|
||||||
|
(unless (file-exists-p path)
|
||||||
|
(error "File doesn't exist: %s" path))
|
||||||
|
(unless (or force-p (y-or-n-p (format "Really delete %S?" short-path)))
|
||||||
|
(user-error "Aborted"))
|
||||||
|
(let ((buf (current-buffer)))
|
||||||
|
(unwind-protect
|
||||||
|
(progn (delete-file path t) t))
|
||||||
|
(if (file-exists-p path)
|
||||||
|
(error "Failed to delete %S" short-path)
|
||||||
|
;; Ensures that windows displaying this buffer will be switched to
|
||||||
|
;; real buffers (`doom-real-buffer-p')
|
||||||
|
(syd/kill-this-buffer-in-all-windows buf t)
|
||||||
|
(syd-files--update-refs path)
|
||||||
|
(message "Deleted %S" short-path)))))
|
||||||
|
|
||||||
|
(syd-define-stub
|
||||||
|
syd/move-this-file
|
||||||
|
:desc "Move current file. See `doom/move-this-file'."
|
||||||
|
:interactive t)
|
||||||
|
|
||||||
|
(defun syd-find-file-in (root)
|
||||||
|
(interactive (list (read-directory-name
|
||||||
|
"Find file in: " default-directory nil t)))
|
||||||
|
;; HACK: To avoid reimplementation, we pretend `root' is a project and
|
||||||
|
;; delegate the work to project.el.
|
||||||
|
(syd-with-project-root root
|
||||||
|
(project-find-file)))
|
||||||
|
|
||||||
|
(syd-define-stub
|
||||||
|
syd/yank-buffer-path
|
||||||
|
:desc "Yank buffer path."
|
||||||
|
:interactive t)
|
||||||
|
|
||||||
|
(defun syd/find-file-in-emacs-user-directory ()
|
||||||
|
(interactive)
|
||||||
|
(unless (file-directory-p user-emacs-directory)
|
||||||
|
(user-error "`user-emacs-directory' doesn't exist! (%s)"
|
||||||
|
(abbreviate-file-name user-emacs-directory)))
|
||||||
|
(let ((default-directory user-emacs-directory))
|
||||||
|
(call-interactively #'find-file)))
|
||||||
|
|
||||||
|
(defun syd-switch-to-emacs-user-directory ()
|
||||||
|
"Switch project to `user-emacs-directory' via `project-switch-project'."
|
||||||
|
(interactive)
|
||||||
|
(require 'syd-project)
|
||||||
|
(if (file-directory-p user-emacs-directory)
|
||||||
|
(syd-with-project-root user-emacs-directory
|
||||||
|
(project-switch-project user-emacs-directory))
|
||||||
|
(user-error "`user-emacs-directory' (%s) does not exist or is not a directory!"
|
||||||
|
(abbreviate-file-name user-emacs-directory))))
|
||||||
|
|
||||||
|
(syd-define-stub
|
||||||
|
syd/open-this-file-as-root
|
||||||
|
:desc "Open current file as root. See `doom/sudo-this-file'."
|
||||||
|
:interactive t)
|
||||||
|
|
||||||
|
(syd-define-stub
|
||||||
|
syd/find-file-as-root
|
||||||
|
:desc "Open current file as root. See `doom/sudo-this-file'."
|
||||||
|
:interactive t)
|
||||||
|
|
||||||
|
(defun syd--make-syncthing-merge-finalise-hook (file-name conflict-file-name)
|
||||||
|
(lambda ()
|
||||||
|
(let ((merge-result-file (read-file-name
|
||||||
|
(format "Write merge to (default: %s):"
|
||||||
|
file-name)
|
||||||
|
nil file-name))
|
||||||
|
(delete-conflict-p (yes-or-no-p (format "Delete conflict file? (%s)"
|
||||||
|
conflict-file-name)))))
|
||||||
|
(when merge-result-file
|
||||||
|
(with-current-buffer ediff-buffer-C
|
||||||
|
(set-visited-file-name merge-result-file)
|
||||||
|
(save-buffer))
|
||||||
|
(kill-buffer ediff-buffer-C))
|
||||||
|
(when delete-conflict-p
|
||||||
|
(kill-buffer (find-buffer-visiting conflict-file-name))
|
||||||
|
(delete-file conflict-file-name))))
|
||||||
|
|
||||||
|
(defun syd--read-syncthing-conflict-file (&optional directory)
|
||||||
|
(let ((conflict-files (directory-files-recursively
|
||||||
|
(or directory default-directory)
|
||||||
|
(rx ".sync-conflict-"))))
|
||||||
|
(completing-read "Conflict file: " conflict-files nil t)))
|
||||||
|
|
||||||
|
(defun syd--syncthing-conflict-file-base-name (conflict-file)
|
||||||
|
(replace-regexp-in-string (rx ".sync-conflict-" (* (not ?.)))
|
||||||
|
""
|
||||||
|
conflict-file))
|
||||||
|
|
||||||
|
(defun syd-resolve-syncthing-conflict (conflict-file)
|
||||||
|
(interactive (list (syd--read-syncthing-conflict-file)))
|
||||||
|
(require 'ediff)
|
||||||
|
(let* ((base-file (syd--syncthing-conflict-file-base-name conflict-file))
|
||||||
|
(ediff-after-quit-hook-internal
|
||||||
|
;; Override Ediff's "save and quit" hook with our own.
|
||||||
|
(cons (syd--make-syncthing-merge-finalise-hook base-file conflict-file)
|
||||||
|
(remq #'ediff-write-merge-buffer-and-maybe-kill
|
||||||
|
(ensure-list ediff-quit-merge-hook)))))
|
||||||
|
(ediff-merge-files
|
||||||
|
base-file
|
||||||
|
conflict-file)))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun syd-split-tramp-file-name (file-name)
|
||||||
|
"Split FILE-NAME into (TRAMP-PREFIX . LOCAL-NAME). Returns (nil . FILE-NAME)
|
||||||
|
if FILE-NAME has no TRAMP prefix."
|
||||||
|
(if (tramp-tramp-file-p file-name)
|
||||||
|
(let* ((dissected (tramp-dissect-file-name file-name t))
|
||||||
|
(localname (tramp-file-name-localname dissected)))
|
||||||
|
(setf (tramp-file-name-localname dissected) nil)
|
||||||
|
(cons (tramp-make-tramp-file-name dissected)
|
||||||
|
localname))
|
||||||
|
(cons nil file-name)))
|
||||||
|
|
||||||
|
(provide 'syd-file)
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
;;; syd-general.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(use-package general
|
||||||
|
:custom (general-use-package-emit-autoloads t))
|
||||||
|
|
||||||
|
(require 'general)
|
||||||
|
|
||||||
|
(defvar syd-leader-key "SPC"
|
||||||
|
"A prefix key akin to Vim's <Leader>.")
|
||||||
|
|
||||||
|
(defvar syd-localleader-key "SPC m"
|
||||||
|
"A prefix key akin to Vim's <LocalLeader>.")
|
||||||
|
|
||||||
|
(defvar syd-alt-leader-key "M-SPC"
|
||||||
|
"`syd-leader', but for the states specified in `syd-alt-leader-key-states'.
|
||||||
|
|
||||||
|
Often, your \"usual\" leader key will be something unavailable in the Insert
|
||||||
|
state. This key exists as a fallback for when you need your Leader, but must
|
||||||
|
remain in the Insert state. Substitute \"Insert state\" for your states of
|
||||||
|
choice with `syd-alt-leader-key-states'.")
|
||||||
|
|
||||||
|
(defvar syd-alt-localleader-key "M-SPC m"
|
||||||
|
"`syd-localleader', but for the states specified in `syd-alt-leader-key-states'.
|
||||||
|
|
||||||
|
See `syd-alt-leader-key' for rationale.")
|
||||||
|
|
||||||
|
(defvar syd-leader-key-states '(normal visual motion)
|
||||||
|
"States for which the Leader keys (`syd-leader-key', `syd-localleader-key')
|
||||||
|
are active.")
|
||||||
|
|
||||||
|
(defvar syd-alt-leader-key-states '(emacs insert)
|
||||||
|
"States for which the alternative Leader keys are active. See
|
||||||
|
`syd-alt-leader-key' and `syd-alt-localleader-key'.")
|
||||||
|
|
||||||
|
(defvar-keymap syd-leader-map
|
||||||
|
:doc "Leader-prefixed commands")
|
||||||
|
|
||||||
|
(defun syd-initialise-leader ()
|
||||||
|
"Set up the (empty) keymap associated with `syd-leader-key',
|
||||||
|
`syd-localleader-key', `syd-alt-leader-key', and `syd-alt-localleader-key'."
|
||||||
|
(require 'evil)
|
||||||
|
;; Define `syd/leader' as a command corresponding to the prefix map
|
||||||
|
;; `syd-leader-map'.
|
||||||
|
(define-prefix-command 'syd/leader 'syd-leader-map)
|
||||||
|
;; This should help make the Leader key close to universally available.
|
||||||
|
;; Ideally, *nothing* takes precedence over Leader — it's an incredibly
|
||||||
|
;; important key!
|
||||||
|
;; https://github.com/noctuid/evil-guide?tab=readme-ov-file#undoprevent-overridingintercept-maps
|
||||||
|
;; See `evil-make-overriding-map'.
|
||||||
|
(define-key syd-leader-map [override-state] 'all)
|
||||||
|
;; Finally, we shall bind the damned keys. }:)
|
||||||
|
(let ((map general-override-mode-map))
|
||||||
|
(evil-define-key* syd-leader-key-states map (kbd syd-leader-key) 'syd/leader)
|
||||||
|
(evil-define-key* syd-alt-leader-key-states map (kbd syd-alt-leader-key) 'syd/leader))
|
||||||
|
(general-override-mode 1))
|
||||||
|
|
||||||
|
(defvar syd-escape-hook nil
|
||||||
|
"A hook run when C-g is pressed (or ESC in Evil's normal state).
|
||||||
|
|
||||||
|
More specifically, when `syd/escape' is pressed. If any hook returns non-nil,
|
||||||
|
all hooks after it are ignored.")
|
||||||
|
|
||||||
|
;;
|
||||||
|
;;; Universal, non-nuclear escape
|
||||||
|
|
||||||
|
;; `keyboard-quit' is too much of a nuclear option. I want ESC/C-g to
|
||||||
|
;; do-what-I-mean. It serves four purposes (in order):
|
||||||
|
;;
|
||||||
|
;; 1. Quit active states; e.g. highlights, searches, snippets, iedit,
|
||||||
|
;; multiple-cursors, recording macros, etc.
|
||||||
|
;; 2. Close popup windows remotely (if it is allowed to)
|
||||||
|
;; 3. Refresh buffer indicators, like diff-hl and flycheck
|
||||||
|
;; 4. Or fall back to `keyboard-quit'
|
||||||
|
;;
|
||||||
|
;; And it should do these things incrementally, rather than all at once. And it
|
||||||
|
;; shouldn't interfere with recording macros or the minibuffer. This may
|
||||||
|
;; require you press ESC/C-g two or three times on some occasions to reach
|
||||||
|
;; `keyboard-quit', but this is much more intuitive.
|
||||||
|
|
||||||
|
(defun syd/escape (&optional interactive)
|
||||||
|
"Run `syd-escape-hook'."
|
||||||
|
(interactive (list 'interactive))
|
||||||
|
(let ((inhibit-quit t))
|
||||||
|
(cond ((minibuffer-window-active-p (minibuffer-window))
|
||||||
|
;; quit the minibuffer if open.
|
||||||
|
(when interactive
|
||||||
|
(setq this-command 'abort-recursive-edit))
|
||||||
|
(abort-recursive-edit))
|
||||||
|
;; Run all escape hooks. If any returns non-nil, then stop there.
|
||||||
|
((run-hook-with-args-until-success 'syd-escape-hook))
|
||||||
|
;; don't abort macros
|
||||||
|
((or defining-kbd-macro executing-kbd-macro) nil)
|
||||||
|
;; Back to the default
|
||||||
|
((unwind-protect (keyboard-quit)
|
||||||
|
(when interactive
|
||||||
|
(setq this-command 'keyboard-quit)))))))
|
||||||
|
|
||||||
|
(with-eval-after-load 'eldoc
|
||||||
|
(eldoc-add-command 'syd/escape))
|
||||||
|
|
||||||
|
;; In normal state, pressing escape should run `syd-escape-hook'.
|
||||||
|
(with-eval-after-load 'evil
|
||||||
|
(defun evil-syd/escape-a (&rest _)
|
||||||
|
"Call `syd/escape' if `evil-force-normal-state' is called interactively."
|
||||||
|
(when (called-interactively-p 'any)
|
||||||
|
(call-interactively #'syd/escape)))
|
||||||
|
(advice-add #'evil-force-normal-state
|
||||||
|
:after #'evil-syd/escape-a))
|
||||||
|
|
||||||
|
(provide 'syd-general)
|
||||||
@@ -0,0 +1,258 @@
|
|||||||
|
;;; syd-handle-eval.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(defvar syd-eval-runners '())
|
||||||
|
|
||||||
|
;; Remove ellipsis when printing sexps in message buffer.
|
||||||
|
(setq eval-expression-print-length nil
|
||||||
|
eval-expression-print-level nil)
|
||||||
|
|
||||||
|
(set-popup-rule!
|
||||||
|
"*eval*"
|
||||||
|
:size 0.2)
|
||||||
|
|
||||||
|
|
||||||
|
;; Packages
|
||||||
|
|
||||||
|
(use-package quickrun
|
||||||
|
:defer t)
|
||||||
|
|
||||||
|
(use-package eros
|
||||||
|
:hook (emacs-lisp-mode . eros-mode))
|
||||||
|
|
||||||
|
;; (with-eval-after-load quickrun
|
||||||
|
;; (setq quickrun-focus-p nil)
|
||||||
|
|
||||||
|
;; (set-popup-rule! "^\\*quickrun" :size 0.3 :ttl 0)
|
||||||
|
|
||||||
|
;; (defadvice! +eval--quickrun-fix-evil-visual-region-a ()
|
||||||
|
;; "Make `quickrun-replace-region' recognize evil visual selections."
|
||||||
|
;; :override #'quickrun--outputter-replace-region
|
||||||
|
;; (let ((output (buffer-substring-no-properties (point-min) (point-max))))
|
||||||
|
;; (with-current-buffer quickrun--original-buffer
|
||||||
|
;; (cl-destructuring-bind (beg . end)
|
||||||
|
;; ;; Because `deactivate-mark', the function, was used in
|
||||||
|
;; ;; `quickrun--region-command-common' instead of `deactivate-mark',
|
||||||
|
;; ;; the variable, the selection is disabled by this point.
|
||||||
|
;; (if (bound-and-true-p evil-local-mode)
|
||||||
|
;; (cons evil-visual-beginning evil-visual-end)
|
||||||
|
;; (cons (region-beginning) (region-end)))
|
||||||
|
;; (delete-region beg end)
|
||||||
|
;; (insert output))
|
||||||
|
;; (setq quickrun-option-outputter quickrun--original-outputter))))
|
||||||
|
|
||||||
|
;; (defadvice! +eval--quickrun-auto-close-a (&rest _)
|
||||||
|
;; "Silently re-create the quickrun popup when re-evaluating."
|
||||||
|
;; :before '(quickrun quickrun-region)
|
||||||
|
;; (when-let (win (get-buffer-window quickrun--buffer-name))
|
||||||
|
;; (let ((inhibit-message t))
|
||||||
|
;; (quickrun--kill-running-process)
|
||||||
|
;; (message ""))
|
||||||
|
;; (delete-window win)))
|
||||||
|
|
||||||
|
;; (add-hook! 'quickrun-after-run-hook
|
||||||
|
;; (defun +eval-quickrun-shrink-window-h ()
|
||||||
|
;; "Shrink the quickrun output window once code evaluation is complete."
|
||||||
|
;; (when-let (win (get-buffer-window quickrun--buffer-name))
|
||||||
|
;; (with-selected-window (get-buffer-window quickrun--buffer-name)
|
||||||
|
;; (let ((ignore-window-parameters t))
|
||||||
|
;; (shrink-window-if-larger-than-buffer)))))
|
||||||
|
;; (defun +eval-quickrun-scroll-to-bof-h ()
|
||||||
|
;; "Ensures window is scrolled to BOF on invocation."
|
||||||
|
;; (when-let (win (get-buffer-window quickrun--buffer-name))
|
||||||
|
;; (with-selected-window win
|
||||||
|
;; (goto-char (point-min))))))
|
||||||
|
|
||||||
|
;; ;; Display evaluation results in an overlay at the end of the current line. If
|
||||||
|
;; ;; the output is more than `+eval-popup-min-lines' (4) lines long, it is
|
||||||
|
;; ;; displayed in a popup.
|
||||||
|
;; (when (modulep! +overlay)
|
||||||
|
;; (defadvice! +eval--show-output-in-overlay-a (fn)
|
||||||
|
;; :filter-return #'quickrun--make-sentinel
|
||||||
|
;; (lambda (process event)
|
||||||
|
;; (funcall fn process event)
|
||||||
|
;; (with-current-buffer quickrun--buffer-name
|
||||||
|
;; (when (> (buffer-size) 0)
|
||||||
|
;; (+eval-display-results
|
||||||
|
;; (string-trim (buffer-string))
|
||||||
|
;; quickrun--original-buffer)))))
|
||||||
|
|
||||||
|
;; ;; Suppress quickrun's popup window because we're using an overlay instead.
|
||||||
|
;; (defadvice! +eval--inhibit-quickrun-popup-a (buf cb)
|
||||||
|
;; :override #'quickrun--pop-to-buffer
|
||||||
|
;; (setq quickrun--original-buffer (current-buffer))
|
||||||
|
;; (save-window-excursion
|
||||||
|
;; (with-current-buffer (pop-to-buffer buf)
|
||||||
|
;; (setq quickrun-option-outputter #'ignore)
|
||||||
|
;; (funcall cb))))
|
||||||
|
|
||||||
|
;; ;; HACK Without this, `+eval--inhibit-quickrun-popup-a' throws a
|
||||||
|
;; ;; window-live-p error because no window exists to be recentered!
|
||||||
|
;; (advice-add #'quickrun--recenter :override #'ignore)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(cl-defun syd-eval-region-as-major-mode
|
||||||
|
(beg end &key (runner-major-mode major-mode))
|
||||||
|
"Evaluate a region between BEG and END and display the output.
|
||||||
|
|
||||||
|
Evaluate as in RUNNER-MAJOR-MODE. If RUNNER-MAJOR-MODE is nil, use major-mode
|
||||||
|
of the buffer instead."
|
||||||
|
(if-let* ((runner (alist-get runner-major-mode syd-eval-runners)))
|
||||||
|
(funcall runner beg end)
|
||||||
|
(and (require 'quickrun nil t)
|
||||||
|
(let ((quickrun-option-cmdkey
|
||||||
|
(quickrun--command-key
|
||||||
|
(buffer-file-name (buffer-base-buffer)))))
|
||||||
|
(quickrun-region beg end)))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun syd-eval-region (beg end)
|
||||||
|
(interactive "r")
|
||||||
|
;; (message "syd: %s" (pp-to-string
|
||||||
|
;; (buffer-substring-no-properties (syd-region-beginning)
|
||||||
|
;; (syd-region-end))))
|
||||||
|
;; (message "r: %s" (pp-to-string (buffer-substring-no-properties beg end)))
|
||||||
|
(syd-eval-region-as-major-mode beg end))
|
||||||
|
|
||||||
|
(with-eval-after-load 'evil
|
||||||
|
(evil-define-operator syd-eval-operator (beg end)
|
||||||
|
"Evaluate selection."
|
||||||
|
:move-point nil
|
||||||
|
(interactive "<r>")
|
||||||
|
(syd-eval-region beg end))
|
||||||
|
|
||||||
|
(general-def
|
||||||
|
:states 'normal
|
||||||
|
"gR" #'syd-eval-buffer)
|
||||||
|
|
||||||
|
(general-def
|
||||||
|
:states '(normal visual)
|
||||||
|
"gr" #'syd-eval-operator))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun set-eval-handler! (modes command)
|
||||||
|
"Define a code evaluator for major mode MODES with `quickrun'.
|
||||||
|
|
||||||
|
MODES can be list of major mode symbols, or a single one.
|
||||||
|
|
||||||
|
1. If MODE is a string and COMMAND is the string, MODE is a file regexp and
|
||||||
|
COMMAND is a string key for an entry in `quickrun-file-alist'.
|
||||||
|
2. If MODE is not a string and COMMAND is a string, MODE is a major-mode symbol
|
||||||
|
and COMMAND is a key (for `quickrun--language-alist'), and will be registered
|
||||||
|
in `quickrun--major-mode-alist'.
|
||||||
|
3. If MODE is not a string and COMMAND is an alist, see `quickrun-add-command':
|
||||||
|
(quickrun-add-command MODE COMMAND :mode MODE).
|
||||||
|
4. If MODE is not a string and COMMANd is a symbol, add it to
|
||||||
|
`syd-eval-runners', which is used by `syd-eval-region'."
|
||||||
|
(declare (indent defun))
|
||||||
|
(dolist (mode (ensure-list modes))
|
||||||
|
(cond ((symbolp command)
|
||||||
|
(push (cons mode command) syd-eval-runners))
|
||||||
|
((stringp command)
|
||||||
|
(with-eval-after-load 'quickrun
|
||||||
|
(push (cons mode command)
|
||||||
|
(if (stringp mode)
|
||||||
|
quickrun-file-alist
|
||||||
|
quickrun--major-mode-alist))))
|
||||||
|
((listp command)
|
||||||
|
(with-eval-after-load 'quickrun
|
||||||
|
(quickrun-add-command
|
||||||
|
(or (cdr (assq mode quickrun--major-mode-alist))
|
||||||
|
(string-remove-suffix "-mode" (symbol-name mode)))
|
||||||
|
command :mode mode))))))
|
||||||
|
|
||||||
|
(defvar syd-eval-overlay-max-lines 4
|
||||||
|
"The maximum number of lines allowed to be displayed in an eval overlay; any
|
||||||
|
more and a popup buffer will be used instead.")
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun syd-eval-display-results-in-popup (output)
|
||||||
|
"Display OUTPUT in a popup buffer."
|
||||||
|
(let ((output-buffer (get-buffer-create "*eval*"))
|
||||||
|
(origin (selected-window)))
|
||||||
|
(with-current-buffer output-buffer
|
||||||
|
(setq-local scroll-margin 0)
|
||||||
|
(erase-buffer)
|
||||||
|
(insert output)
|
||||||
|
(goto-char (point-min))
|
||||||
|
;; (if (fboundp '+word-wrap-mode)
|
||||||
|
;; (+word-wrap-mode +1)
|
||||||
|
;; (visual-line-mode +1))
|
||||||
|
)
|
||||||
|
(when-let* ((win (display-buffer output-buffer)))
|
||||||
|
;; (fit-window-to-buffer
|
||||||
|
;; win (/ (frame-height) 2)
|
||||||
|
;; nil (/ (frame-width) 2))
|
||||||
|
)
|
||||||
|
(select-window origin)
|
||||||
|
output-buffer))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun syd-eval-buffer ()
|
||||||
|
"Evaluate the entire buffer."
|
||||||
|
(interactive)
|
||||||
|
(syd-eval-region (point-min) (point-max)))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun syd-eval-buffer-or-region ()
|
||||||
|
"Evaluate the region if it is active, or the entire buffer, or not."
|
||||||
|
(if (use-region-p)
|
||||||
|
(call-interactively #'syd-eval-region)
|
||||||
|
(call-interactively #'syd-eval-buffer)))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(cl-defun syd-eval-display-results-in-overlay (output &key source-buffer)
|
||||||
|
"Display OUTPUT in a floating overlay next to the cursor."
|
||||||
|
(require 'eros)
|
||||||
|
(with-current-buffer (or source-buffer (current-buffer))
|
||||||
|
(let* ((this-command #'syd-eval/buffer-or-region)
|
||||||
|
(prefix eros-eval-result-prefix)
|
||||||
|
(lines (split-string output "\n"))
|
||||||
|
(prefixlen (length prefix))
|
||||||
|
(len (+ (apply #'max (mapcar #'length lines))
|
||||||
|
prefixlen))
|
||||||
|
(next-line? (or (cdr lines)
|
||||||
|
(< (- (window-width)
|
||||||
|
(save-excursion (goto-char (line-end-position))
|
||||||
|
(- (current-column)
|
||||||
|
(window-hscroll))))
|
||||||
|
len)))
|
||||||
|
(pad (if next-line?
|
||||||
|
(+ (window-hscroll) prefixlen)
|
||||||
|
0))
|
||||||
|
eros-overlays-use-font-lock)
|
||||||
|
(eros--make-result-overlay
|
||||||
|
(concat (make-string (max 0 (- pad prefixlen)) ?\s)
|
||||||
|
prefix
|
||||||
|
(string-join lines (concat hard-newline (make-string pad ?\s))))
|
||||||
|
:where (if next-line?
|
||||||
|
(line-beginning-position 2)
|
||||||
|
(line-end-position))
|
||||||
|
:duration eros-eval-result-duration
|
||||||
|
:format "%s"))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(cl-defun syd-eval-display-results (output &key source-buffer force-popup)
|
||||||
|
"Display OUTPUT in an overlay, or if it's too long, a popup buffer."
|
||||||
|
(if (or force-popup
|
||||||
|
;; EROS is used to display overlays. Without it, just use a popup.
|
||||||
|
(not (require 'eros nil t))
|
||||||
|
(with-temp-buffer
|
||||||
|
(insert output)
|
||||||
|
(or
|
||||||
|
;; Too tall!
|
||||||
|
(<= syd-eval-overlay-max-lines
|
||||||
|
(count-lines (point-min) (point-max)))
|
||||||
|
;; Too wide!
|
||||||
|
(<= (window-width)
|
||||||
|
(string-width
|
||||||
|
(buffer-substring (point-min)
|
||||||
|
(save-excursion
|
||||||
|
(goto-char (point-min))
|
||||||
|
(line-end-position))))))))
|
||||||
|
(syd-eval-display-results-in-popup output)
|
||||||
|
(syd-eval-display-results-in-overlay output :source-buffer source-buffer))
|
||||||
|
output)
|
||||||
|
|
||||||
|
(provide 'syd-handle-eval)
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
;;; syd-handle-lookup.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(require 'syd-text)
|
||||||
|
|
||||||
|
(use-package better-jumper)
|
||||||
|
|
||||||
|
(require 'better-jumper)
|
||||||
|
|
||||||
|
(defvar syd-lookup-online-documentation-backends
|
||||||
|
`(("Kagi" . "https://kagi.com/search?q=%s")
|
||||||
|
("DuckDuckGo" . "https://duckduckgo.com/?q=%s")
|
||||||
|
("Nixpkgs" . "https://search.nixos.org/packages?query=%s")
|
||||||
|
("Hackage" . "https://hackage.haskell.org/packages/search?terms=%s")
|
||||||
|
("The Free Dictionary" . "https://www.thefreedictionary.com/%s")
|
||||||
|
("The Free Thesaurus" . "https://www.freethesaurus.com/%s"))
|
||||||
|
"A list of pairs (NAME . BACKEND) describing the various backends
|
||||||
|
`syd-lookup-online-documentation' may delegate to.
|
||||||
|
|
||||||
|
NAME is a string used when speaking to the user about BACKEND.
|
||||||
|
|
||||||
|
If BACKEND is an interactive command, it will be called interactively.
|
||||||
|
|
||||||
|
If BACKEND is a procedure, it will be called with the search string as the lone
|
||||||
|
argument.
|
||||||
|
|
||||||
|
If BACKEND is a string, the user's browser will be opened to the URL returned by
|
||||||
|
(format BACKEND QUERY), where QUERY is the appropriately-encoded search
|
||||||
|
string.")
|
||||||
|
|
||||||
|
(defvar syd-lookup-documentation-handlers '(syd-lookup-online-documentation)
|
||||||
|
"A list of lookup handlers used to find documentation. A lookup handler
|
||||||
|
receives an identifier, and is expected to return nil on failure, and non-nil on
|
||||||
|
success. When a handler returns a marker, the marker will be jumped to.")
|
||||||
|
|
||||||
|
(defun syd-lookup--prompt-for-online-backend ()
|
||||||
|
(assoc-string
|
||||||
|
(completing-read "Search with: "
|
||||||
|
(mapcar #'car syd-lookup-online-documentation-backends)
|
||||||
|
nil
|
||||||
|
t)
|
||||||
|
syd-lookup-online-documentation-backends))
|
||||||
|
|
||||||
|
(cl-defun syd-lookup--call-online-backend (backend &key query-string)
|
||||||
|
(pcase-let ((`(,name . ,backend-fn) backend))
|
||||||
|
(cond ((functionp backend-fn) (if (commandp backend-fn)
|
||||||
|
(call-interactively backend-fn)
|
||||||
|
(funcall backend-fn query-string)))
|
||||||
|
((stringp backend-fn)
|
||||||
|
(browse-url (format backend-fn
|
||||||
|
(url-encode-url
|
||||||
|
(read-string (format "Search %s for: "
|
||||||
|
name)
|
||||||
|
query-string)))))
|
||||||
|
(t (signal 'wrong-type-argument `("backend" ,backend-fn))))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(cl-defun syd-lookup-online-documentation (backend &key query-string)
|
||||||
|
(interactive (list (syd-lookup--prompt-for-online-backend)
|
||||||
|
:query-string (when (use-region-p)
|
||||||
|
(syd-thing-at-point-or-region))))
|
||||||
|
(syd-lookup--call-online-backend backend
|
||||||
|
:query-string query-string))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun syd-lookup-documentation (identifier)
|
||||||
|
"Try to find documentation on IDENTIFIER, and "
|
||||||
|
(interactive (list (syd-thing-at-point-or-region)))
|
||||||
|
(or (syd-lookup--jump-to 'documentation identifier
|
||||||
|
:display-fn #'display-buffer)
|
||||||
|
(user-error "Couldn't find documentation on %S"
|
||||||
|
(substring-no-properties identifier))))
|
||||||
|
|
||||||
|
(defvar syd-lookup--handlers-by-category
|
||||||
|
'((documentation . syd-lookup-documentation-handlers)))
|
||||||
|
|
||||||
|
(cl-defun syd-lookup--jump-to
|
||||||
|
(category identifier &key (display-fn #'switch-to-buffer))
|
||||||
|
(let* ((handlers (alist-get category syd-lookup--handlers-by-category))
|
||||||
|
(origin (point-marker))
|
||||||
|
;; TODO: If called with a prefix argument, prompt the user to select a
|
||||||
|
;; handler.
|
||||||
|
(result (run-hook-wrapped handlers #'syd-lookup--run-handler
|
||||||
|
identifier origin)))
|
||||||
|
(unwind-protect
|
||||||
|
(when (cond ((null result)
|
||||||
|
(message "No lookup handler could find %S" identifier)
|
||||||
|
nil)
|
||||||
|
((markerp result)
|
||||||
|
(let ((b (marker-buffer result)))
|
||||||
|
(funcall display-fn b)
|
||||||
|
(when (eq (current-buffer) b)
|
||||||
|
(goto-char result)))
|
||||||
|
result)
|
||||||
|
(result))
|
||||||
|
(with-current-buffer (marker-buffer origin)
|
||||||
|
(better-jumper-set-jump (marker-position origin)))
|
||||||
|
result))
|
||||||
|
(set-marker origin nil)))
|
||||||
|
|
||||||
|
(defun syd-lookup--run-handler (handler identifier origin)
|
||||||
|
(condition-case-unless-debug e
|
||||||
|
(let ((wconf (current-window-configuration))
|
||||||
|
(result (condition-case-unless-debug e
|
||||||
|
(if (commandp handler)
|
||||||
|
(call-interactively handler)
|
||||||
|
(funcall handler identifier))
|
||||||
|
(error
|
||||||
|
(message "Lookup handler %S threw an error: %s" handler e)
|
||||||
|
'fail))))
|
||||||
|
(cond ((eq result 'fail)
|
||||||
|
(set-window-configuration wconf)
|
||||||
|
nil)
|
||||||
|
((or (get handler 'syd-lookup-async)
|
||||||
|
(eq result 'deferred)))
|
||||||
|
((bufferp result)
|
||||||
|
(with-current-buffer result
|
||||||
|
(point-marker)))
|
||||||
|
((or result
|
||||||
|
(null origin)
|
||||||
|
(/= (point-marker) origin))
|
||||||
|
(prog1 (point-marker)
|
||||||
|
(set-window-configuration wconf)))))
|
||||||
|
((error user-error)
|
||||||
|
(message "Lookup handler %S: %s" handler e)
|
||||||
|
nil)))
|
||||||
|
|
||||||
|
(general-def
|
||||||
|
:states 'normal
|
||||||
|
"K" #'syd-lookup-documentation)
|
||||||
|
|
||||||
|
(provide 'syd-handle-lookup)
|
||||||
|
;;; syd-handle-lookup.el ends here
|
||||||
@@ -0,0 +1,267 @@
|
|||||||
|
;;; syd-handle-repl.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(eval-when-compile (require 'cl-lib))
|
||||||
|
(require 'syd-prelude)
|
||||||
|
(require 'syd-project)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(syd-add-hook 'on-init-ui-hook
|
||||||
|
(defun syd--set-popup-rules-for-repls-h ()
|
||||||
|
(require 'doom-popup)
|
||||||
|
(set-popup-rule!
|
||||||
|
(lambda (bufname _)
|
||||||
|
(when (boundp 'syd-repl-mode)
|
||||||
|
(buffer-local-value 'syd-repl-mode (get-buffer bufname))))
|
||||||
|
:ttl (lambda (buf)
|
||||||
|
(unless (plist-get syd-repl-plist :persist)
|
||||||
|
(when-let (process (get-buffer-process buf))
|
||||||
|
(set-process-query-on-exit-flag process nil)
|
||||||
|
(kill-process process)
|
||||||
|
(kill-buffer buf))))
|
||||||
|
:size 0.25
|
||||||
|
:quit nil)))
|
||||||
|
|
||||||
|
|
||||||
|
;;; State & settings
|
||||||
|
|
||||||
|
(defvar +syd-major-mode-repl-alist '()
|
||||||
|
"TODO: An alist pairing major-modes (symbols) with plists describing REPLs.")
|
||||||
|
|
||||||
|
(defvar +syd-repl-buffers (make-hash-table :test 'equal)
|
||||||
|
"A hashmap mapping pairs (MAJOR-MODE . PROJECT-ROOT) to their corresponding
|
||||||
|
buffers. Indeed, this implies a single REPL per language per project. Is this
|
||||||
|
limitation worth overcoming? I'm not sure! I've yet to butt heads with it.")
|
||||||
|
|
||||||
|
(defvar-local syd-repl-plist nil
|
||||||
|
"A plist describing the repl associated with the current buffer.
|
||||||
|
|
||||||
|
This is little more than a cache. Its value can almost always be equivalently
|
||||||
|
derived from `+syd-major-mode-repl-alist'.")
|
||||||
|
|
||||||
|
(defun set-repl-handler! (modes command &rest plist)
|
||||||
|
"Defines a REPL for MODES.
|
||||||
|
|
||||||
|
MODES is either a single major mode symbol or a list of them. COMMAND is a
|
||||||
|
function that creates and returns the REPL buffer.
|
||||||
|
|
||||||
|
COMMAND can either be a function that takes no arguments, or an interactive
|
||||||
|
command that will be called interactively. COMMANDS must return either the repl
|
||||||
|
buffer or a function that takes no arguments and returns the repl buffer.
|
||||||
|
|
||||||
|
PLIST is a property list that map special attributes to this repl. These are
|
||||||
|
recognized:
|
||||||
|
|
||||||
|
:persist BOOL
|
||||||
|
If non-nil, this REPL won't be killed when its window is closed.
|
||||||
|
:send-region FUNC
|
||||||
|
A function that accepts a BEG and END, and sends the contents of the region
|
||||||
|
to the REPL. Defaults to `+eval/send-region-to-repl'.
|
||||||
|
:send-buffer FUNC
|
||||||
|
A function of no arguments that sends the contents of the buffer to the REPL.
|
||||||
|
Defaults to `+eval/region', which will run the :send-region specified function
|
||||||
|
or `+eval/send-region-to-repl'."
|
||||||
|
(declare (indent defun))
|
||||||
|
(dolist (mode (ensure-list modes))
|
||||||
|
(setf (alist-get mode +syd-major-mode-repl-alist)
|
||||||
|
(cons command plist))))
|
||||||
|
|
||||||
|
|
||||||
|
;;; Repls
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(define-minor-mode syd-repl-mode
|
||||||
|
"A minor mode for repl buffers. One use is to universally customise the
|
||||||
|
display of all repl buffers."
|
||||||
|
:after-hook (format "syd-repl-mode after %s" (current-buffer)))
|
||||||
|
|
||||||
|
(defun syd--repl-from-major-mode ()
|
||||||
|
"TODO:"
|
||||||
|
(pcase-let ((`(_ ,fn . ,plist) (assq major-mode +syd-major-mode-repl-alist)))
|
||||||
|
(list fn plist)))
|
||||||
|
|
||||||
|
(defun syd--clean-repl-buffers ()
|
||||||
|
"Remove any key/value pairs from `+syd-repl-buffers' whose values involve a
|
||||||
|
not-alive buffer."
|
||||||
|
(maphash (lambda (repl-key buffer)
|
||||||
|
(unless (buffer-live-p buffer)
|
||||||
|
(remhash repl-key +syd-repl-buffers)))
|
||||||
|
+syd-repl-buffers))
|
||||||
|
|
||||||
|
(defun syd--get-repl-key ()
|
||||||
|
(cons major-mode (syd-project-root)))
|
||||||
|
|
||||||
|
(defun syd--goto-end-of-repl ()
|
||||||
|
"Try to move point to the last comint prompt or the end of the buffer."
|
||||||
|
(unless (or (derived-mode-p 'term-mode)
|
||||||
|
(eq (current-local-map) (bound-and-true-p term-raw-map)))
|
||||||
|
(goto-char (if (and (derived-mode-p 'comint-mode)
|
||||||
|
(cdr comint-last-prompt))
|
||||||
|
(cdr comint-last-prompt)
|
||||||
|
(point-max)))))
|
||||||
|
|
||||||
|
(cl-defun syd--call-repl-handler (repl-handler &key plist repl-key)
|
||||||
|
"Spawn a new repl buffer using REPL-HANDLER. REPL-HANDLER's return value will
|
||||||
|
be returned.
|
||||||
|
|
||||||
|
If REPL-HANDLER fails to return a buffer, this `syd--call-repl-handler' will
|
||||||
|
throw an error. `syd-repl-mode' will be enabled in the new buffer, and the
|
||||||
|
buffer will be cached in `+syd-repl-buffers'.
|
||||||
|
|
||||||
|
REPL-HANDLER will be called interactively if supported."
|
||||||
|
(let ((repl-buffer (save-window-excursion
|
||||||
|
(if (commandp repl-handler)
|
||||||
|
(call-interactively repl-handler)
|
||||||
|
(funcall repl-handler)))))
|
||||||
|
(unless repl-buffer
|
||||||
|
(error "REPL handler %S couldn't open the REPL buffer" fn))
|
||||||
|
(unless (bufferp repl-buffer)
|
||||||
|
(error "REPL handler %S failed to return a buffer" fn))
|
||||||
|
(with-current-buffer repl-buffer
|
||||||
|
;; It is important that `syd-repl-mode' is enabled before the buffer is
|
||||||
|
;; displayed by `display-fn'.
|
||||||
|
(syd-repl-mode 1)
|
||||||
|
(when plist
|
||||||
|
;; Cache the plist at `syd-repl-plist'.
|
||||||
|
(setq syd-repl-plist plist)))
|
||||||
|
(puthash repl-key repl-buffer +syd-repl-buffers)
|
||||||
|
repl-buffer))
|
||||||
|
|
||||||
|
;; #+begin_src dot :file /tmp/repl.svg :results file graphics
|
||||||
|
;; digraph {
|
||||||
|
;; bgcolor="transparent"
|
||||||
|
;;
|
||||||
|
;; node [
|
||||||
|
;; fillcolor=gray95
|
||||||
|
;; color=black
|
||||||
|
;; shape=record
|
||||||
|
;; ]
|
||||||
|
;;
|
||||||
|
;; "Start" [shape=diamond]
|
||||||
|
;; "Start" -> x1
|
||||||
|
;; x1 [label="Is the user currently in the repl buffer,\nOR has a repl handler NOT been provided?"]
|
||||||
|
;;
|
||||||
|
;; x1 -> x2 [label="Yes"]
|
||||||
|
;; x1 -> x3 [label="No"]
|
||||||
|
;; x2 [label="Find entry in +syd-repl-buffers;\nis it a live buffer?"]
|
||||||
|
;; x2 -> x4 [label="Yes"]
|
||||||
|
;; x4 [label="Call display-fn on the\n+syd-repl-buffers entry, and use the result"]
|
||||||
|
;; x2 -> x5 [label="No"]
|
||||||
|
;; x5 [label="Call the provided repl-handler. Ensure it returns\na valid buffer, and pass the resultto display-fn.\nSet the plist, enable repl mode, update\n+syd-repl-buffers. Use the buffer returned by display-fn"]
|
||||||
|
;; x3 [label="Use entry found in +syd-repl-buffers"]
|
||||||
|
;; }
|
||||||
|
;; #+end_src
|
||||||
|
|
||||||
|
(cl-defun syd--ensure-in-repl-buffer
|
||||||
|
(&key repl-handler plist (display-fn #'get-buffer-create))
|
||||||
|
"Display the repl buffer associated with the current major mode and project.
|
||||||
|
A repl buffer will be created (using REPL-HANDLER) if necessary.
|
||||||
|
|
||||||
|
If an active repl buffer is found in `+syd-repl-buffers', it will be displayed
|
||||||
|
by the given DISPLAY-FN.
|
||||||
|
|
||||||
|
PLIST is a plist of repl-specific options."
|
||||||
|
(syd--clean-repl-buffers)
|
||||||
|
(let* ((repl-key (syd--get-repl-key))
|
||||||
|
(maybe-repl-buffer (gethash repl-key +syd-repl-buffers)))
|
||||||
|
(cl-check-type maybe-repl-buffer (or buffer null))
|
||||||
|
(let ((repl-buffer
|
||||||
|
(if (or (eq maybe-repl-buffer (current-buffer))
|
||||||
|
(null repl-handler))
|
||||||
|
;; * If the current buffer is the repl buffer, we can be sure
|
||||||
|
;; that it is not nil and can be returned as-is.
|
||||||
|
;; * If we were not given a repl-handler, there's nothing else we
|
||||||
|
;; can do. Return what was found in `+syd-repl-buffers', and
|
||||||
|
;; hope it's the right thing.
|
||||||
|
maybe-repl-buffer
|
||||||
|
;; If the repl buffer found in `+syd-repl-buffers' is live and
|
||||||
|
;; well, we can return that. If not, we're going to have to spawn
|
||||||
|
;; a new repl buffer with `repl-handler' and `display-fn'.
|
||||||
|
(if (buffer-live-p maybe-repl-buffer)
|
||||||
|
(funcall display-fn maybe-repl-buffer)
|
||||||
|
(funcall display-fn
|
||||||
|
(syd--call-repl-handler repl-handler
|
||||||
|
:plist plist
|
||||||
|
:repl-key repl-key))))))
|
||||||
|
(when (bufferp repl-buffer)
|
||||||
|
(with-current-buffer repl-buffer
|
||||||
|
(syd--goto-end-of-repl))
|
||||||
|
repl-buffer))))
|
||||||
|
|
||||||
|
(defun syd--known-repls ()
|
||||||
|
"Return a list of all known mode-repl pairs, each as a two-element list.
|
||||||
|
|
||||||
|
More precisely, the return value is a list of mode-repl pairs, where each
|
||||||
|
mode-repl pair is a two-element list (MAJOR-MODE HANDLER) where MAJOR-MODE is a
|
||||||
|
symbol, and HANDLER is a (possibly interactive) procedure.
|
||||||
|
|
||||||
|
See also: `+syd-major-mode-repl-alist'."
|
||||||
|
(mapcar (lambda (xs) (list (car xs) (cadr xs)))
|
||||||
|
+syd-major-mode-repl-alist))
|
||||||
|
|
||||||
|
(defun syd--pretty-mode-name (mode)
|
||||||
|
"Convert MODE (a symbol or string) into a string appropriate for human
|
||||||
|
presentation."
|
||||||
|
(let ((mode* (if (symbolp mode) (symbol-name mode) mode)))
|
||||||
|
(if (not (string-match "^\\([a-z-]+\\)-mode$" mode*))
|
||||||
|
(error "Given string/symbol is not a major mode: %s" mode*)
|
||||||
|
(string-join (split-string
|
||||||
|
(capitalize (match-string-no-properties 1 mode*))
|
||||||
|
"-")
|
||||||
|
" "))))
|
||||||
|
|
||||||
|
(defun syd-prompt-for-repl ()
|
||||||
|
"Prompt the user for a repl to open. Returns the chosen repl-handler
|
||||||
|
function."
|
||||||
|
;; REVIEW: Doom scans all interned symbols for anything that looks like
|
||||||
|
;; "open-XXXX-repl." Is this worth doing?
|
||||||
|
(let* ((repls (mapcar (lambda (xs)
|
||||||
|
(pcase-let ((`(,mode ,fn) xs))
|
||||||
|
(list (syd--pretty-mode-name mode) fn)))
|
||||||
|
(syd--known-repls)))
|
||||||
|
(choice (or (completing-read "Open a REPL for: "
|
||||||
|
(mapcar #'car repls))
|
||||||
|
(user-error "Aborting"))))
|
||||||
|
(cadr (assoc choice repls))))
|
||||||
|
|
||||||
|
(defun syd-send-region-to-repl (beg end)
|
||||||
|
(interactive "r")
|
||||||
|
(let ((selection (buffer-substring-no-properties beg end))
|
||||||
|
(buffer (syd--ensure-in-repl-buffer)))))
|
||||||
|
|
||||||
|
(cl-defun +syd-open-repl (&key prompt-p display-fn)
|
||||||
|
"TODO: Open a repl via DISPLAY-FN. When PROMPT-P, the user will be
|
||||||
|
unconditionally prompted for a repl choice.
|
||||||
|
|
||||||
|
If Evil-mode is active, insert state will be enabled."
|
||||||
|
(pcase-let* ((`(,major-mode-fn ,plist) (syd--repl-from-major-mode))
|
||||||
|
(repl-handler (if (or prompt-p (not major-mode-fn))
|
||||||
|
(syd-prompt-for-repl)
|
||||||
|
major-mode-fn))
|
||||||
|
(region (when (use-region-p)
|
||||||
|
(buffer-substring-no-properties (region-beginning)
|
||||||
|
(region-end)))))
|
||||||
|
(unless (commandp repl-handler)
|
||||||
|
(error "Couldn't find a REPL for %s" major-mode))
|
||||||
|
(with-current-buffer (syd--ensure-in-repl-buffer :repl-handler repl-handler
|
||||||
|
:plist plist
|
||||||
|
:display-fn display-fn)
|
||||||
|
;; Start the user in insert mode at the end of the input line.
|
||||||
|
(when (bound-and-true-p evil-mode)
|
||||||
|
(call-interactively #'evil-append-line))
|
||||||
|
(when region
|
||||||
|
(insert region))
|
||||||
|
t)))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun +syd/open-repl-other-window (prompt-p)
|
||||||
|
"Like `+syd-open-repl', but opens in a different window. The repl
|
||||||
|
corresponding to the current major mode and project will be opened, unless a
|
||||||
|
prefix argument is given, in which case the user will be prompted for a repl."
|
||||||
|
(interactive "P")
|
||||||
|
(+syd-open-repl :prompt-p prompt-p
|
||||||
|
:display-fn #'pop-to-buffer))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(provide 'syd-handle-repl)
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
;;; syd-kanagawa.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
;;; Rationale: I need direct access to the Kanagawa palette, which kanagawa.el
|
||||||
|
;;; does not provide.
|
||||||
|
|
||||||
|
(defvar syd-kanagawa-palette (make-hash-table :test 'eq
|
||||||
|
:size 130))
|
||||||
|
|
||||||
|
(defvar syd-kanagawa-palette-list
|
||||||
|
'((sumi-ink-0 "#16161D")
|
||||||
|
(sumi-ink-1 "#181820")
|
||||||
|
(sumi-ink-2 "#1a1a22")
|
||||||
|
(sumi-ink-3 "#1F1F28")
|
||||||
|
(sumi-ink-4 "#2A2A37")
|
||||||
|
(sumi-ink-5 "#363646")
|
||||||
|
(sumi-ink-6 "#54546D") ; fg
|
||||||
|
|
||||||
|
;; Popup and Floats
|
||||||
|
(wave-blue-1 "#223249")
|
||||||
|
(wave-blue-2 "#2D4F67")
|
||||||
|
|
||||||
|
;; Diff and Git
|
||||||
|
(winter-green "#2B3328")
|
||||||
|
(winter-yellow "#49443C")
|
||||||
|
(winter-red "#43242B")
|
||||||
|
(winter-blue "#252535")
|
||||||
|
(autumn-green "#76946A")
|
||||||
|
(autumn-red "#C34043")
|
||||||
|
(autumn-yellow "#DCA561")
|
||||||
|
|
||||||
|
;; Diag
|
||||||
|
(samurai-red "#E82424")
|
||||||
|
(ronin-yellow "#FF9E3B")
|
||||||
|
(wave-aqua-1 "#6A9589")
|
||||||
|
(dragon-blue "#658594")
|
||||||
|
|
||||||
|
;; Fg and Comments
|
||||||
|
(old-white "#C8C093")
|
||||||
|
(fuji-white "#DCD7BA")
|
||||||
|
(fuji-gray "#727169")
|
||||||
|
|
||||||
|
(oni-violet "#957FB8")
|
||||||
|
(oni-violet-2 "#b8b4d0")
|
||||||
|
(crystal-blue "#7E9CD8")
|
||||||
|
(spring-violet-1 "#938AA9")
|
||||||
|
(spring-violet-2 "#9CABCA")
|
||||||
|
(spring-blue "#7FB4CA")
|
||||||
|
(light-blue "#A3D4D5")
|
||||||
|
(wave-aqua-2 "#7AA89F") ;; improve lightness: desaturated greenish Aqua
|
||||||
|
|
||||||
|
(spring-green "#98BB6C")
|
||||||
|
(boat-yellow-1 "#938056")
|
||||||
|
(boat-yellow-2 "#C0A36E")
|
||||||
|
(carp-yellow "#E6C384")
|
||||||
|
|
||||||
|
(sakura-pink "#D27E99")
|
||||||
|
(wave-red "#E46876")
|
||||||
|
(peach-red "#FF5D62")
|
||||||
|
(surimi-orange "#FFA066")
|
||||||
|
(katana-gray "#717C7C")
|
||||||
|
|
||||||
|
(dragon-black-0 "#0d0c0c")
|
||||||
|
(dragon-black-1 "#12120f")
|
||||||
|
(dragon-black-2 "#1D1C19")
|
||||||
|
(dragon-black-3 "#181616")
|
||||||
|
(dragon-black-4 "#282727")
|
||||||
|
(dragon-black-5 "#393836")
|
||||||
|
(dragon-black-6 "#625e5a")
|
||||||
|
|
||||||
|
(dragon-white "#c5c9c5")
|
||||||
|
(dragon-green "#87a987")
|
||||||
|
(dragon-green-2 "#8a9a7b")
|
||||||
|
(dragon-pink "#a292a3")
|
||||||
|
(dragon-orange "#b6927b")
|
||||||
|
(dragon-orange-2 "#b98d7b")
|
||||||
|
(dragon-gray "#a6a69c")
|
||||||
|
(dragon-gray1 "#9e9b93")
|
||||||
|
(dragon-gray-3 "#7a8382")
|
||||||
|
(dragon-blue-2 "#8ba4b0")
|
||||||
|
(dragon-violet "#8992a7")
|
||||||
|
(dragon-red "#c4746e")
|
||||||
|
(dragon-aqua "#8ea4a2")
|
||||||
|
(dragon-ash "#737c73")
|
||||||
|
(dragon-teal "#949fb5")
|
||||||
|
(dragon-yellow "#c4b28a")
|
||||||
|
|
||||||
|
(lotus-ink-1 "#545464")
|
||||||
|
(lotus-ink-2 "#43436c")
|
||||||
|
(lotus-gray "#dcd7ba")
|
||||||
|
(lotus-gray-2 "#716e61")
|
||||||
|
(lotus-gray-3 "#8a8980")
|
||||||
|
(lotus-white-0 "#d5cea3")
|
||||||
|
(lotus-white-1 "#dcd5ac")
|
||||||
|
(lotus-white-2 "#e5ddb0")
|
||||||
|
(lotus-white-3 "#f2ecbc")
|
||||||
|
(lotus-white-4 "#e7dba0")
|
||||||
|
(lotus-white-5 "#e4d794")
|
||||||
|
(lotus-violet-1 "#a09cac")
|
||||||
|
(lotus-violet-2 "#766b90")
|
||||||
|
(lotus-violet-3 "#c9cbd1")
|
||||||
|
(lotus-violet-4 "#624c83")
|
||||||
|
(lotus-blue-1 "#c7d7e0")
|
||||||
|
(lotus-blue-2 "#b5cbd2")
|
||||||
|
(lotus-blue-3 "#9fb5c9")
|
||||||
|
(lotus-blue-4 "#4d699b")
|
||||||
|
(lotus-blue-5 "#5d57a3")
|
||||||
|
(lotus-green "#6f894e")
|
||||||
|
(lotus-green-2 "#6e915f")
|
||||||
|
(lotus-green-3 "#b7d0ae")
|
||||||
|
(lotus-pink "#b35b79")
|
||||||
|
(lotus-orange "#cc6d00")
|
||||||
|
(lotus-orange2 "#e98a00")
|
||||||
|
(lotus-yellow "#77713f")
|
||||||
|
(lotus-yellow-2 "#836f4a")
|
||||||
|
(lotus-yellow-3 "#de9800")
|
||||||
|
(lotus-yellow-4 "#f9d791")
|
||||||
|
(lotus-red "#c84053")
|
||||||
|
(lotus-red-2 "#d7474b")
|
||||||
|
(lotus-red-3 "#e82424")
|
||||||
|
(lotus-red-4 "#d9a594")
|
||||||
|
(lotus-aqua "#597b75")
|
||||||
|
(lotus-aqua-2 "#5e857a")
|
||||||
|
(lotus-teal-1 "#4e8ca2")
|
||||||
|
(lotus-teal-2 "#6693bf")
|
||||||
|
(lotus-teal-3 "#5a7785")
|
||||||
|
(lotus-cyan "#d7e3d8")))
|
||||||
|
|
||||||
|
(cl-loop for (k v) in syd-kanagawa-palette-list
|
||||||
|
do (puthash k v syd-kanagawa-palette))
|
||||||
|
|
||||||
|
(defun syd-kanagawa-get (k)
|
||||||
|
(gethash k syd-kanagawa-palette nil))
|
||||||
|
|
||||||
|
(provide 'syd-kanagawa)
|
||||||
@@ -0,0 +1,512 @@
|
|||||||
|
;;; syd-lisp-lib.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(require 'general)
|
||||||
|
(require 'clj-lib)
|
||||||
|
|
||||||
|
(use-package smartparens
|
||||||
|
:defer t)
|
||||||
|
|
||||||
|
(use-package evil-surround
|
||||||
|
:defer t)
|
||||||
|
|
||||||
|
;; Include various lispy symbols as word constituents.
|
||||||
|
(dolist (c '(?- ?_ ?? ?! ?+ ?* ?/ ?: ?> ?< ?= ?&))
|
||||||
|
(modify-syntax-entry c "w" lisp-data-mode-syntax-table))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defvar-keymap syd-lisp-mode-map
|
||||||
|
:doc "Keymap for `syd-lisp-mode'.")
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(define-minor-mode syd-lisp-mode
|
||||||
|
"A minor mode for editing lispy languages."
|
||||||
|
:keymap syd-lisp-mode-map)
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun syd-wrap-sexp (char)
|
||||||
|
"Wrap the sexp at point (using `smartparens') with the pair corresponding to
|
||||||
|
CHAR (using `evil-surround'). Unlike other `evil-surround' operations, the
|
||||||
|
point will be preserved and the wrapped region will be re-indented."
|
||||||
|
(interactive (evil-surround-input-char))
|
||||||
|
(sp-get (sp-get-thing)
|
||||||
|
(save-excursion
|
||||||
|
(evil-surround-region :beg :end 'inclusive char)
|
||||||
|
(indent-region :beg :end))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(evil-define-motion syd-get-enclosing-sexp ()
|
||||||
|
"Like `sp-get-enclosing-sexp', but with a slightly different meaning of
|
||||||
|
\"enclosing sexp\" that matches Vim-sexp's"
|
||||||
|
(or (let ((sexp-at-point (sp-get-sexp)))
|
||||||
|
(sp-get sexp-at-point
|
||||||
|
(when (or (and :beg (= (point) :beg))
|
||||||
|
(and :end (= (point) (- :end 1))))
|
||||||
|
sexp-at-point)))
|
||||||
|
(let ((sp-enclosing-sexp (sp-get-enclosing-sexp)))
|
||||||
|
(sp-get sp-enclosing-sexp
|
||||||
|
(when :beg
|
||||||
|
sp-enclosing-sexp)))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(evil-define-motion syd-backward-up-sexp (count)
|
||||||
|
"Move point to the opening bracket of the enclosing sexp. The precise meaning
|
||||||
|
of \"enclosing sexp\" differs slightly from that used by Smartparens for the
|
||||||
|
sake of a more Vim-like feel inspired by vim-sexp."
|
||||||
|
:type exclusive
|
||||||
|
(dotimes (_ (or count 1))
|
||||||
|
;; REVIEW: Is there a better way to do this? I'm slightly uncomfortable
|
||||||
|
;; calling two different `sp-get-*' functions.
|
||||||
|
(or (sp-get (sp-get-sexp)
|
||||||
|
(when (and :end (= (point) (- :end 1)))
|
||||||
|
(goto-char :beg)))
|
||||||
|
(sp-get (sp-get-enclosing-sexp)
|
||||||
|
(when :beg
|
||||||
|
(goto-char :beg))))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(evil-define-motion syd-forward-up-sexp (&optional count)
|
||||||
|
"Move point to the closing bracket of the enclosing sexp. See
|
||||||
|
`syd-backward-up-sexp'."
|
||||||
|
:type exclusive
|
||||||
|
(dotimes (_ (or count 1))
|
||||||
|
(or (sp-get (sp-get-sexp)
|
||||||
|
(when (and :beg (= (point) :beg))
|
||||||
|
(goto-char (- :end 1))))
|
||||||
|
(sp-get (sp-get-enclosing-sexp)
|
||||||
|
(when :end
|
||||||
|
(if (= (point) (- :end 1))
|
||||||
|
(sp-get (save-excursion (forward-char)
|
||||||
|
(sp-get-enclosing-sexp))
|
||||||
|
(when :end
|
||||||
|
(goto-char (- :end 1))))
|
||||||
|
(goto-char (- :end 1))))))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun syd-get-top-level-sexp ()
|
||||||
|
"Get the top-level sexp enclosing point. Destructure with `sp-get'.'"
|
||||||
|
;; The end position returned by `bounds-of-thing-at-point' includes an
|
||||||
|
;; unpredictable amount of trailing whitespace, so we discard it and compute
|
||||||
|
;; our own figure.
|
||||||
|
(let ((original-point (point)))
|
||||||
|
(-when-let ((beg . _) (bounds-of-thing-at-point 'defun))
|
||||||
|
(save-excursion
|
||||||
|
(goto-char beg)
|
||||||
|
;; We can trust Smarparents to get the desired end position.
|
||||||
|
(-let* ((top-level-sexp (sp-get-sexp))
|
||||||
|
((_ . end) (sp-get top-level-sexp (cons :beg :end))))
|
||||||
|
;; If the sexp is behind point, we aren't interested in it; find one
|
||||||
|
;; /ahead/ of point.
|
||||||
|
(if (< original-point end)
|
||||||
|
top-level-sexp
|
||||||
|
(goto-char end)
|
||||||
|
(sp-next-sexp)
|
||||||
|
(sp-get-sexp)))))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun syd-get-top-level-sexp-and-attached-comment-bounds ()
|
||||||
|
"Get the bounds of top-level sexp enclosing point and the \"attached\"
|
||||||
|
comment, if there is one. Returns nil or a pair (BEG . END)."
|
||||||
|
(-when-let ((beg . end) (sp-get (syd-get-top-level-sexp) (cons :beg :end)))
|
||||||
|
(let ((attached-comment-beg (save-excursion
|
||||||
|
(goto-char beg)
|
||||||
|
(syd-sexp--backward-attached-comment))))
|
||||||
|
(cons (or attached-comment-beg beg)
|
||||||
|
end))))
|
||||||
|
|
||||||
|
(evil-define-motion syd-forward-defun (count)
|
||||||
|
:jump t
|
||||||
|
(sp-get (syd-get-top-level-sexp)
|
||||||
|
(goto-char :beg)
|
||||||
|
(dotimes (_ (or count 1))
|
||||||
|
(sp-next-sexp))))
|
||||||
|
|
||||||
|
(defvar syd-sexp-cleanup-operators '(evil-delete)
|
||||||
|
"When `syd-evil-a-defun' is used in combination with one of these operators,
|
||||||
|
some cleanup will be performed.")
|
||||||
|
|
||||||
|
;; FIXME(#12): Comments should only attach to the *immediately* following sexp.
|
||||||
|
;; Consider the following snippet:
|
||||||
|
;;
|
||||||
|
;; ;; Call the continuation if non-nil. Wraps the return value in a singleton
|
||||||
|
;; ;; list for "affine" use with unquote-splicing.
|
||||||
|
;; (let ((call-cont (lambda (cont arg)
|
||||||
|
;; (if cont
|
||||||
|
;; (list (funcall cont arg))
|
||||||
|
;; nil)))
|
||||||
|
;; names)
|
||||||
|
;; ...)
|
||||||
|
;;
|
||||||
|
;; The curreny behaviour of `syd-sexp--backward-attached-comment' considers the
|
||||||
|
;; comment to be attached to both the (let ...) form, as well as the ((call-cont
|
||||||
|
;; ...)) form and the (call-cont ...) form. Not good!
|
||||||
|
(defun syd-sexp--backward-attached-comment ()
|
||||||
|
"Assuming point is on the opening delimiter of a sexp, move point backward to
|
||||||
|
the beginning of the \"attached\" comment."
|
||||||
|
(let ((sexp-line (line-number-at-pos))
|
||||||
|
(sexp-column (current-column)))
|
||||||
|
(-when-let ((beg . _end) (save-excursion
|
||||||
|
(goto-line (- sexp-line 1))
|
||||||
|
(evil-forward-char sexp-column t)
|
||||||
|
(sp-get-comment-bounds)))
|
||||||
|
(goto-char beg))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(evil-define-text-object syd-evil-a-defun (count _beg _end _type)
|
||||||
|
"Selects the enclosing top-level sexp. With a COUNT of N, that many
|
||||||
|
consequtive top-level sexps will be selected. TODO: Special care will be taken
|
||||||
|
to clean up whitespace following certain operators."
|
||||||
|
:type inclusive
|
||||||
|
(when (< count 0)
|
||||||
|
(user-error "TODO: Negative count"))
|
||||||
|
(-let ((cleanup-p (memq evil-this-operator syd-sexp-cleanup-operators))
|
||||||
|
((beg-0 . end-0)
|
||||||
|
(syd-get-top-level-sexp-and-attached-comment-bounds)))
|
||||||
|
(if (or (null count) (= count 1))
|
||||||
|
(list beg-0 end-0)
|
||||||
|
(goto-char end-0)
|
||||||
|
(dotimes (_ (- count 1))
|
||||||
|
(sp-next-sexp))
|
||||||
|
(sp-get (sp-get-sexp)
|
||||||
|
(list beg-0 :end)))))
|
||||||
|
|
||||||
|
;; IDEA: How about the inner-defun text object selects the defun /without/ the
|
||||||
|
;; comment? Is that more useful, or less? I can't think of the last time Ive
|
||||||
|
;; needed the top-level sexp without the brackets.
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(evil-define-text-object syd-evil-inner-defun (_count _beg _end _type)
|
||||||
|
"Select the *content* of the enclosing top-level sexp, i.e. without the
|
||||||
|
delimiters."
|
||||||
|
:type inclusive
|
||||||
|
(sp-get (syd-get-top-level-sexp)
|
||||||
|
(list (+ :beg 1)
|
||||||
|
(- :end 1))))
|
||||||
|
|
||||||
|
(defun syd-sexp--forward-trailing-whitespace (sexp)
|
||||||
|
"Move point to the end of the whitespace trailing after SEXP."
|
||||||
|
(goto-char (sp-get sexp :end))
|
||||||
|
(skip-chars-forward "[:blank:]")
|
||||||
|
(when (= (char-after) ?\n)
|
||||||
|
(forward-char)
|
||||||
|
(skip-chars-forward "[:blank:]")))
|
||||||
|
|
||||||
|
(defun syd-sexp--backward-leading-whitespace (sexp)
|
||||||
|
"Move point to the beginning of the whitespace preceding SEXP."
|
||||||
|
(goto-char (sp-get sexp :beg))
|
||||||
|
(skip-chars-backward "[:blank:]")
|
||||||
|
(when (= (char-before) ?\n)
|
||||||
|
(backward-char)
|
||||||
|
(skip-chars-backward "[:blank:]")))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(evil-define-text-object syd-evil-a-form (count _beg _end _type)
|
||||||
|
(let* ((cleanup-p (memq evil-this-operator syd-sexp-cleanup-operators))
|
||||||
|
(sexp (syd-get-enclosing-sexp)))
|
||||||
|
(if cleanup-p
|
||||||
|
(save-excursion
|
||||||
|
(goto-char (sp-get sexp :beg))
|
||||||
|
(if (syd-sexp--looking-at-last-p)
|
||||||
|
(progn (syd-sexp--backward-leading-whitespace sexp)
|
||||||
|
(list (point) (sp-get sexp :end)))
|
||||||
|
(syd-sexp--forward-trailing-whitespace sexp)
|
||||||
|
(list (sp-get sexp :beg) (point))))
|
||||||
|
(sp-get sexp (list :beg :end)))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(evil-define-text-object syd-evil-inner-form (count _beg _end _type)
|
||||||
|
(sp-get (syd-get-enclosing-sexp)
|
||||||
|
(list (+ :beg 1) (- :end 1))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(evil-define-command syd-open-sexp-below ()
|
||||||
|
"Insert a newline with appropriate indentation after the enclosing sexp. A
|
||||||
|
sexp-wise analogue to Evil's line-wise `evil-open-below'."
|
||||||
|
:suppress-operator t
|
||||||
|
(evil-with-single-undo
|
||||||
|
;; We want to add an additional blank line when operating at the top level.
|
||||||
|
;; Instead of parsing upward until we can no longer find an enclosing sexp,
|
||||||
|
;; we simply check if the opening bracket is on the first column. This is
|
||||||
|
;; not very correct, but it's way less work (for myself and the CPU). If we
|
||||||
|
;; switch to a tree-sitter–based parser, I'd love to switch to the correct
|
||||||
|
;; algorithm.
|
||||||
|
(-let* (((beg . end) (sp-get (syd-get-enclosing-sexp) (cons :beg :end)))
|
||||||
|
(col (save-excursion (goto-char beg) (current-column))))
|
||||||
|
(goto-char end)
|
||||||
|
(if (= col 0)
|
||||||
|
(newline 2)
|
||||||
|
(newline-and-indent))))
|
||||||
|
(evil-insert-state 1))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(evil-define-command syd-open-sexp-above ()
|
||||||
|
"Insert a newline with appropriate indentation above the enclosing sexp. A
|
||||||
|
sexp-wise analogue to Evil's line-wise `evil-open-above'."
|
||||||
|
:suppress-operator t
|
||||||
|
(evil-with-single-undo
|
||||||
|
(let ((beg (sp-get (syd-get-enclosing-sexp) :beg)))
|
||||||
|
(goto-char beg)
|
||||||
|
(syd-sexp--backward-attached-comment)
|
||||||
|
(let ((col (current-column)))
|
||||||
|
(save-excursion
|
||||||
|
;; We want to add an additional blank line when operating at the top
|
||||||
|
;; level. Instead of parsing upward until we can no longer find an
|
||||||
|
;; enclosing sexp, we simply check if the opening bracket is on the
|
||||||
|
;; first column. This is not very correct, but it's way less work (for
|
||||||
|
;; myself and the CPU). If we switch to a tree-sitter–based parser, I'd
|
||||||
|
;; love to switch to the correct algorithm.
|
||||||
|
(if (= col 0)
|
||||||
|
(newline 2)
|
||||||
|
(newline-and-indent)))
|
||||||
|
(indent-to col)
|
||||||
|
(evil-insert-state 1)))))
|
||||||
|
|
||||||
|
(defun syd-sexp-get-last-thing ()
|
||||||
|
(-let (((enclosing-beg . enclosing-end)
|
||||||
|
(sp-get (syd-get-enclosing-sexp) (cons :beg :end))))
|
||||||
|
(save-excursion
|
||||||
|
;; Imperative andy. }:\
|
||||||
|
(let (thing)
|
||||||
|
(while (sp-get (syd-get-thing)
|
||||||
|
(and (< enclosing-beg :beg enclosing-end)
|
||||||
|
(< enclosing-beg :end enclosing-end))))))))
|
||||||
|
|
||||||
|
(defun syd-sexp--looking-at-last-p ()
|
||||||
|
"Return non-nil if the sexp beginning at point is the last element of its
|
||||||
|
enclosing sexp."
|
||||||
|
(save-excursion
|
||||||
|
(let ((point-0 (point))
|
||||||
|
(sexp (sp-get-enclosing-sexp)))
|
||||||
|
(sp-next-sexp)
|
||||||
|
(if sexp
|
||||||
|
(or
|
||||||
|
;; If `sp-next-sexp' moved backwards, `point-0' was the last
|
||||||
|
;; element.
|
||||||
|
(<= (point) point-0)
|
||||||
|
;; If `sp-next-sexp' moved outside of the previously-enclosing
|
||||||
|
;; sexp, `point-0' was final.
|
||||||
|
(<= (sp-get sexp :end) (point)))
|
||||||
|
;; No enclosing sexp — we're looking at a top-level sexp.
|
||||||
|
(= (point) point-0)))))
|
||||||
|
|
||||||
|
(defun syd-sexp--next-thing ()
|
||||||
|
"Helper for `syd-sexo->'. Find the next thing relative to the sexp assumed to
|
||||||
|
begin at point, and the region covering the closing delimiters."
|
||||||
|
(save-excursion
|
||||||
|
(condition-case err
|
||||||
|
(cl-loop for relative-height from 0
|
||||||
|
while (syd-sexp--looking-at-last-p)
|
||||||
|
do (or (sp-backward-up-sexp)
|
||||||
|
;; Nothing to slurp!
|
||||||
|
(signal 'top))
|
||||||
|
finally return (cons (sp-next-sexp) relative-height))
|
||||||
|
(top nil))))
|
||||||
|
|
||||||
|
(defun syd-sexp--slurp-forward ()
|
||||||
|
"Slurp forward. Do not call this function directly; see `syd-sexp->'."
|
||||||
|
;; REVIEW: This is rather unoptimised when used with a count.
|
||||||
|
(when-let* ((consumer (sp-get-sexp)))
|
||||||
|
(goto-char (sp-get consumer :beg))
|
||||||
|
(-if-let ((next-thing . relative-height) (syd-sexp--next-thing))
|
||||||
|
(progn (goto-char (sp-get consumer :beg-in))
|
||||||
|
(sp-forward-slurp-sexp (+ 1 relative-height))
|
||||||
|
(sp-get (sp-get-enclosing-sexp)
|
||||||
|
(goto-char (- :end 1))))
|
||||||
|
(user-error "ra"))))
|
||||||
|
|
||||||
|
(defun syd-sexp--barf-forward ()
|
||||||
|
"Barf forward. Do not call this function directly; see `syd-sexp-<'."
|
||||||
|
(sp-forward-barf-sexp))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(evil-define-command syd-sexp-> (&optional count)
|
||||||
|
(interactive "<c>")
|
||||||
|
(evil-with-single-undo
|
||||||
|
(when-let* ((sexp (sp-get-sexp)))
|
||||||
|
(let ((fn (cond ((= (point) (sp-get sexp (- :end 1)))
|
||||||
|
#'syd-sexp--slurp-forward))))
|
||||||
|
(dotimes (_ (or count 1))
|
||||||
|
(funcall fn))))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(evil-define-command syd-sexp-< (&optional count)
|
||||||
|
(interactive "<c>")
|
||||||
|
(evil-with-single-undo
|
||||||
|
(when-let* ((sexp (sp-get-sexp)))
|
||||||
|
(let ((fn (cond ((= (point) (sp-get sexp (- :end 1)))
|
||||||
|
#'syd-sexp--barf-forward))))
|
||||||
|
(dotimes (_ (or count 1))
|
||||||
|
(funcall fn))))))
|
||||||
|
|
||||||
|
(defun syd-sexp--looking-at-delimiter-p ()
|
||||||
|
(sp-get (sp-get-sexp)
|
||||||
|
(and (not (sp-point-in-string-or-comment))
|
||||||
|
(or (= (point) :beg)
|
||||||
|
(= (point) (- :end 1))))))
|
||||||
|
|
||||||
|
;; REVIEW: It might be neat to, iff the point is already in a comment/string,
|
||||||
|
;; goto delimiters that are also in comments/strings. For now, let's just
|
||||||
|
;; ignore comments.
|
||||||
|
(defun syd-sexp--goto-delimiter (delimiter-type direction count)
|
||||||
|
(let* ((point-0 (point))
|
||||||
|
(delimiters (mapcar (clj-condp eq delimiter-type
|
||||||
|
('opening #'car)
|
||||||
|
('closing #'cdr))
|
||||||
|
sp-pair-list))
|
||||||
|
(delimiter-regexp (rx-to-string `(or ,@delimiters)))
|
||||||
|
(forward-p (clj-condp eq direction
|
||||||
|
('forward t)
|
||||||
|
('backward nil)
|
||||||
|
(t (error "todo errrrare"))))
|
||||||
|
(move (lambda ()
|
||||||
|
;; `forward-p' never changes between calls to `move'; we are
|
||||||
|
;; doing many more checks than we need to.
|
||||||
|
(and (condition-case er
|
||||||
|
(prog1 t (when forward-p
|
||||||
|
(forward-char)))
|
||||||
|
(end-of-buffer (throw 'no-move 'no-move)))
|
||||||
|
(if (if forward-p
|
||||||
|
(re-search-forward delimiter-regexp nil t)
|
||||||
|
(re-search-backward delimiter-regexp nil t))
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(throw 'no-move 'no-move))))))
|
||||||
|
;; If `syd-sexp--looking-at-delimiter-p' returns nil, we may be looking at
|
||||||
|
;; the right string of characters, but we are likely inside of a string,
|
||||||
|
;; or a comment, or something. If we aren't at a "real" delimiter, move
|
||||||
|
;; again.
|
||||||
|
(let ((r (catch 'no-move
|
||||||
|
(dotimes (_ count)
|
||||||
|
(while (and (funcall move)
|
||||||
|
(not (syd-sexp--looking-at-delimiter-p))))))))
|
||||||
|
(if (eq r 'no-move)
|
||||||
|
(progn (goto-char point-0)
|
||||||
|
(user-error "Nowhere to go"))
|
||||||
|
r))))
|
||||||
|
|
||||||
|
(evil-define-motion syd-sexp-forward-opening (count)
|
||||||
|
(syd-sexp--goto-delimiter 'opening 'forward (or count 1)))
|
||||||
|
|
||||||
|
(evil-define-motion syd-sexp-backward-opening (count)
|
||||||
|
(syd-sexp--goto-delimiter 'opening 'backward (or count 1)))
|
||||||
|
|
||||||
|
(evil-define-motion syd-sexp-forward-closing (count)
|
||||||
|
(syd-sexp--goto-delimiter 'closing 'forward (or count 1)))
|
||||||
|
|
||||||
|
(evil-define-motion syd-sexp-backward-closing (count)
|
||||||
|
(syd-sexp--goto-delimiter 'closing 'backward (or count 1)))
|
||||||
|
|
||||||
|
(defun syd-sexp-get-sexp-with-prefix ()
|
||||||
|
(-when-let* ((thing (sp-get-thing))
|
||||||
|
;; TODO: Rewrite using :beg-prf
|
||||||
|
((beg . prefix) (sp-get thing (cons :beg :prefix)))
|
||||||
|
(prefix-beg (- beg (length prefix))))
|
||||||
|
;; HACK: Relies on Smartparen's internal representation, which
|
||||||
|
;; they explicitly recommend against. This could break at any
|
||||||
|
;; time!
|
||||||
|
;; Reminder that `plist-put' is an in-place update. }:)
|
||||||
|
(plist-put thing :beg prefix-beg)
|
||||||
|
(plist-put thing :prefix "")
|
||||||
|
(goto-char prefix-beg)
|
||||||
|
thing))
|
||||||
|
|
||||||
|
(evil-define-motion syd-sexp-next (count)
|
||||||
|
"Like `sp-next-sexp', but prefixes will be considered as part of the sexp."
|
||||||
|
;; If point is resting on a prefix when `syd-sexp-next' is called,
|
||||||
|
;; `sp-next-sexp' will move to the beginning of the prefixed form. This is
|
||||||
|
;; undesirable, as `syd-sexp-next' considers the prefix and the prefixed form
|
||||||
|
;; to be a single thing. To get around this, we make sure to move point past
|
||||||
|
;; the prefixed sexp.
|
||||||
|
(let ((count* (or count 1)))
|
||||||
|
(when-let* ((_ (<= 0 count*))
|
||||||
|
(first-prefixed-sexp (syd-sexp-get-sexp-with-prefix)))
|
||||||
|
(sp-get first-prefixed-sexp
|
||||||
|
(when (<= :beg (point) :end)
|
||||||
|
(goto-char :end))))
|
||||||
|
(let ((current-prefix-arg count*))
|
||||||
|
(call-interactively #'sp-next-sexp)))
|
||||||
|
(syd-sexp-get-sexp-with-prefix))
|
||||||
|
|
||||||
|
(evil-define-motion syd-sexp-previous (count)
|
||||||
|
"Like `sp-next-sexp' (as if called with a negative count), but prefixes will
|
||||||
|
be considered as part of the sexp."
|
||||||
|
(syd-sexp-next (- (or count 1))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(evil-define-command syd-sexp-insert ()
|
||||||
|
(evil-with-single-undo
|
||||||
|
(sp-get (syd-get-enclosing-sexp)
|
||||||
|
(goto-char (+ 1 :beg))
|
||||||
|
(save-excursion (insert-char ?\s))
|
||||||
|
(evil-insert-state 1))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(evil-define-command syd-sexp-append ()
|
||||||
|
(evil-with-single-undo
|
||||||
|
(sp-get (syd-get-enclosing-sexp)
|
||||||
|
(goto-char (- :end 1))
|
||||||
|
(evil-insert-state 1))))
|
||||||
|
|
||||||
|
;; Text objects.
|
||||||
|
(general-def
|
||||||
|
:keymaps 'syd-lisp-mode-map
|
||||||
|
:states '(visual operator)
|
||||||
|
"ad" #'syd-evil-a-defun
|
||||||
|
"id" #'syd-evil-inner-defun
|
||||||
|
"af" #'syd-evil-a-form
|
||||||
|
"if" #'syd-evil-inner-form)
|
||||||
|
|
||||||
|
(general-def
|
||||||
|
:keymaps 'syd-lisp-mode-map
|
||||||
|
:states 'insert
|
||||||
|
";" #'sp-comment)
|
||||||
|
|
||||||
|
;; Bind editing commands in normal node, and motion commands in motion
|
||||||
|
;; mode.
|
||||||
|
(general-def
|
||||||
|
:keymaps 'syd-lisp-mode-map
|
||||||
|
:states 'normal
|
||||||
|
">" #'syd-sexp->
|
||||||
|
"<" #'syd-sexp-<
|
||||||
|
"M-w" #'syd-wrap-sexp
|
||||||
|
"M-r" #'sp-raise-sexp
|
||||||
|
"M-c" #'sp-clone-sexp
|
||||||
|
"M-S" #'sp-split-sexp
|
||||||
|
"M-J" #'sp-join-sexp
|
||||||
|
"M-u" #'sp-splice-sexp-killing-backward
|
||||||
|
"M-U" #'sp-splice-sexp-killing-around
|
||||||
|
"M-v" #'sp-convolute-sexp
|
||||||
|
"M-o" #'syd-open-sexp-below
|
||||||
|
"M-O" #'syd-open-sexp-above
|
||||||
|
"M-i" #'syd-sexp-insert
|
||||||
|
"M-a" #'syd-sexp-append)
|
||||||
|
|
||||||
|
;; Bind editing commands in normal node, and motion commands in motion
|
||||||
|
;; mode.
|
||||||
|
(general-def
|
||||||
|
:keymaps 'syd-lisp-mode-map
|
||||||
|
:states 'motion
|
||||||
|
"C-h" #'sp-backward-up-sexp ; Probably deprecated.
|
||||||
|
"C-j" #'syd-sexp-next ; Probably deprecated.
|
||||||
|
"C-k" #'syd-sexp-previous ; Probably deprecated.
|
||||||
|
"C-l" #'sp-down-sexp ; Probably deprecated.
|
||||||
|
|
||||||
|
"M-h" #'sp-backward-up-sexp
|
||||||
|
"M-j" #'syd-sexp-next
|
||||||
|
"M-k" #'syd-sexp-previous
|
||||||
|
"M-l" #'sp-down-sexp
|
||||||
|
|
||||||
|
"(" #'syd-backward-up-sexp
|
||||||
|
")" #'syd-forward-up-sexp
|
||||||
|
"{" #'syd-sexp-backward-opening
|
||||||
|
"}" #'syd-sexp-forward-opening
|
||||||
|
"M-{" #'syd-sexp-backward-closing
|
||||||
|
"M-}" #'syd-sexp-forward-closing)
|
||||||
|
|
||||||
|
(with-eval-after-load 'smartparens
|
||||||
|
(setq
|
||||||
|
;; By default, Smartparens will move backwards to the initial character of
|
||||||
|
;; the enclosing expression, and only move forwards when the point is already
|
||||||
|
;; on that initial character. This is not expected behaviour for an ex-Vim
|
||||||
|
;; user.
|
||||||
|
sp-navigate-interactive-always-progress-point t))
|
||||||
|
|
||||||
|
(provide 'syd-lisp-lib)
|
||||||
@@ -0,0 +1,183 @@
|
|||||||
|
;;; syd-prelude.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(eval-when-compile (require 'cl-lib))
|
||||||
|
|
||||||
|
(require 'syd-constants)
|
||||||
|
|
||||||
|
(use-package dash)
|
||||||
|
|
||||||
|
(require 'dash)
|
||||||
|
|
||||||
|
(cl-defmacro syd-define-stub
|
||||||
|
(name &key (desc "implement me!") interactive)
|
||||||
|
(let ((todo (format "%s: TODO: %s" name desc)))
|
||||||
|
`(defun ,name (&rest _)
|
||||||
|
,@(if interactive (list '(interactive)) nil)
|
||||||
|
,todo
|
||||||
|
(error ,todo))))
|
||||||
|
|
||||||
|
;; FIXME: When `arg-list' contains nils, things break.
|
||||||
|
(cl-defun syd-parse-rest-and-keys (arg-list)
|
||||||
|
"The default behaviour of `cl-defun' makes combining &rest with &keys pretty
|
||||||
|
useless. This function will partition ARG-LIST by returning a pair (REST
|
||||||
|
. KEYS), where REST is the list of ARGS that belong to no key-value pair, and
|
||||||
|
KEYS is an alist of the parsed keywords."
|
||||||
|
;; Ugh.
|
||||||
|
(let (parsed-rest parsed-keys)
|
||||||
|
(cl-loop for (lead lag) on arg-list by (lambda (x) (-drop 2 x))
|
||||||
|
do (if (keywordp lead)
|
||||||
|
(push (cons lead lag) parsed-keys)
|
||||||
|
;; Push in reverse order; we reverse the whole list as a
|
||||||
|
;; post-processing step.
|
||||||
|
(push lead parsed-rest)
|
||||||
|
(when lag
|
||||||
|
(push lag parsed-rest))))
|
||||||
|
(cons (reverse parsed-rest) parsed-keys)))
|
||||||
|
|
||||||
|
(cl-defun syd-lift-lambdas (&key with-each with-all forms)
|
||||||
|
;; Call the continuation if non-nil. Wraps the return value in a singleton
|
||||||
|
;; list for "affine" use with unquote-splicing.
|
||||||
|
(-let ((call-cont (lambda (cont arg)
|
||||||
|
(if cont
|
||||||
|
(list (funcall cont arg))
|
||||||
|
nil)))
|
||||||
|
names)
|
||||||
|
`(progn
|
||||||
|
,@(cl-loop
|
||||||
|
for form in forms
|
||||||
|
appending (cond ((syd-hform-symbol form)
|
||||||
|
(let ((name (nth 1 form)))
|
||||||
|
(push name names)
|
||||||
|
(funcall call-cont with-each name)))
|
||||||
|
((syd-hform-defun form)
|
||||||
|
(let ((name (nth 1 form)))
|
||||||
|
(push name names)
|
||||||
|
`(,form
|
||||||
|
,@(funcall call-cont with-each name))))
|
||||||
|
((syd-hform-lambda form)
|
||||||
|
(let ((name (gensym "lifted-lambda")))
|
||||||
|
(push name names)
|
||||||
|
`((defun ,name (&rest args)
|
||||||
|
(,form args))
|
||||||
|
,@(funcall call-cont with-each name))))
|
||||||
|
(t (error "IDK!"))))
|
||||||
|
,@(funcall call-cont with-all names))))
|
||||||
|
|
||||||
|
(defun syd-hform-symbol (hform)
|
||||||
|
(and (listp hform)
|
||||||
|
(= 2 (length hform))
|
||||||
|
(symbolp (nth 1 hform))
|
||||||
|
(memq (nth 0 hform) '(quote function))))
|
||||||
|
|
||||||
|
(defun syd-hform-defun (hform)
|
||||||
|
"If HFORM is a defun form, return the defun's name. Otherwise, return nil"
|
||||||
|
(when-let* ((sym (car-safe hform)))
|
||||||
|
(and (symbolp sym)
|
||||||
|
(eq sym 'defun)
|
||||||
|
(nth 1 hform))))
|
||||||
|
|
||||||
|
(defun syd-hform-lambda (hform)
|
||||||
|
"If HFORM is a lambda, return non-nil."
|
||||||
|
(when-let* ((sym (car-safe hform)))
|
||||||
|
(and (symbolp sym)
|
||||||
|
(eq sym 'lambda))))
|
||||||
|
|
||||||
|
(defmacro comment (&rest _)
|
||||||
|
"Ignore each argument, and expand to nil."
|
||||||
|
nil)
|
||||||
|
|
||||||
|
(defmacro with-transient-after (hook-or-function &rest forms)
|
||||||
|
(declare (indent defun))
|
||||||
|
(let ((hook-name (gensym "transient-hook"))
|
||||||
|
(hook-or-function* (gensym "hook-or-function")))
|
||||||
|
`(let* ((,hook-or-function* ,hook-or-function))
|
||||||
|
(defun ,hook-name (&rest _)
|
||||||
|
"Transient hook defined by `with-transient-after'."
|
||||||
|
(cond ((functionp ,hook-or-function*)
|
||||||
|
(advice-remove ,hook-or-function* #',hook-name))
|
||||||
|
((symbolp ,hook-or-function*)
|
||||||
|
(remove-hook ,hook-or-function* #',hook-name)))
|
||||||
|
,@forms)
|
||||||
|
(cond ((functionp ,hook-or-function*)
|
||||||
|
(advice-add ,hook-or-function* :before #',hook-name))
|
||||||
|
((symbolp ,hook-or-function*)
|
||||||
|
;; https://www.gnu.org/software/emacs/manual/html_node/elisp/Setting-Hooks.html#Setting-Hooks-1
|
||||||
|
(put ',hook-name 'permanent-local-hook t)
|
||||||
|
(add-hook ,hook-or-function* #',hook-name))))))
|
||||||
|
|
||||||
|
(defun syd-plist-put (plist prop new-val)
|
||||||
|
"Immutably update a single property of PLIST. Like `plist-put', but PLIST is
|
||||||
|
not mutated; a new plist is returned."
|
||||||
|
(cl-loop for (prop* old-val) on plist by #'cddr
|
||||||
|
appending (if (eq prop prop*)
|
||||||
|
(list prop* new-val)
|
||||||
|
(list prop* old-val))))
|
||||||
|
|
||||||
|
(defmacro syd-add-hook (hooks &rest hforms)
|
||||||
|
(declare (indent defun))
|
||||||
|
(syd-lift-lambdas
|
||||||
|
:forms hforms
|
||||||
|
:with-all (lambda (fns)
|
||||||
|
(let ((fn* (gensym "fn"))
|
||||||
|
(fns* (gensym "fns"))
|
||||||
|
(hook* (gensym "hook")))
|
||||||
|
`(let ((,fns* (list ,@(--map `(function ,it)
|
||||||
|
fns))))
|
||||||
|
(dolist (,hook* (ensure-list ,hooks))
|
||||||
|
(dolist (,fn* ,fns*)
|
||||||
|
(add-hook ,hook* ,fn*))))))))
|
||||||
|
|
||||||
|
(defmacro syd-silently (&rest body)
|
||||||
|
`(error "TODO: syd-silently"))
|
||||||
|
|
||||||
|
(defmacro syd-quietly (&rest body)
|
||||||
|
"Evaluate BODY without generating any output.
|
||||||
|
|
||||||
|
This silences calls to `message', `load', `write-region' and anything that
|
||||||
|
writes to `standard-output'. In interactive sessions this inhibits output to
|
||||||
|
the echo-area, but not to *Messages*. Return value is that of BODY's final
|
||||||
|
form."
|
||||||
|
`(if init-file-debug
|
||||||
|
(progn ,@body)
|
||||||
|
,(if noninteractive
|
||||||
|
`(syd-silently ,@body)
|
||||||
|
`(let ((inhibit-message t)
|
||||||
|
(save-silently t))
|
||||||
|
(prog1 (progn ,@body)
|
||||||
|
(message ""))))))
|
||||||
|
|
||||||
|
(defun syd--parse-defadvice-args (arg-list)
|
||||||
|
"Parses the docstring and keywords provided to `syd-defadvice'."
|
||||||
|
(let (docstring
|
||||||
|
advice)
|
||||||
|
(when (stringp (car-safe arg-list))
|
||||||
|
(setq docstring (pop arg-list)))
|
||||||
|
(while (and (length> arg-list 2)
|
||||||
|
(keywordp (car arg-list)))
|
||||||
|
(let ((how (pop arg-list))
|
||||||
|
(sym (pop arg-list)))
|
||||||
|
(push (cons how sym) advice)))
|
||||||
|
;; What's left of `arg-list' is the body of the defun.
|
||||||
|
(list docstring advice arg-list)))
|
||||||
|
|
||||||
|
(defmacro syd-defadvice (name params &rest args)
|
||||||
|
"Define a function and add it as advice."
|
||||||
|
(declare (indent defun))
|
||||||
|
(-let (((docstring advice body) (syd--parse-defadvice-args args)))
|
||||||
|
`(progn (defun ,name ,params
|
||||||
|
,@(-some-> docstring list)
|
||||||
|
,@body)
|
||||||
|
,@(-map (lambda (arg)
|
||||||
|
(-let (((how . sym) arg))
|
||||||
|
`(advice-add ,sym ,how #',name)))
|
||||||
|
advice))))
|
||||||
|
|
||||||
|
(syd-defadvice syd-lsp-install-server-a ()
|
||||||
|
:override #'lsp-install-server
|
||||||
|
(user-error (concat "Ignoring a call to `lsp-install-server'"
|
||||||
|
" — tell the caller to use Nix!")))
|
||||||
|
|
||||||
|
(defun syd-str (sep &rest strs)
|
||||||
|
(mapconcat #'identity strs sep))
|
||||||
|
|
||||||
|
(provide 'syd-prelude)
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
;;; syd-project.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(eval-when-compile (require 'cl-lib))
|
||||||
|
(require 'project)
|
||||||
|
|
||||||
|
(cl-defun syd-project-root (&key (dir default-directory))
|
||||||
|
"Return the project root of DIR, or nil if DIR belongs to no project."
|
||||||
|
(when-let* ((project (project-current nil dir)))
|
||||||
|
(project-root project)))
|
||||||
|
|
||||||
|
(defun syd-project-cd ()
|
||||||
|
"Change the working directory to the root of the current project."
|
||||||
|
(cd (syd-project-root)))
|
||||||
|
|
||||||
|
(define-obsolete-function-alias 'syd-cd-project 'syd-project-cd
|
||||||
|
"2025-02-20")
|
||||||
|
|
||||||
|
(defmacro syd-with-project-root (root &rest body)
|
||||||
|
"Execute BODY with ROOT recognised as what project.el calls a \"transient
|
||||||
|
project\"."
|
||||||
|
(declare (indent defun))
|
||||||
|
(let ((root* (gensym "root"))
|
||||||
|
(forget-after-p (gensym "forget-after-p")))
|
||||||
|
`(let* ((,root* ,root)
|
||||||
|
(,forget-after-p
|
||||||
|
(not (member ,root* (project-known-project-roots)))))
|
||||||
|
(let ((project-find-functions (lambda (_) (cons 'transient ,root*))))
|
||||||
|
,@body)
|
||||||
|
(when ,forget-after-p
|
||||||
|
(project-forget-project ,root*)))))
|
||||||
|
|
||||||
|
(defun syd-project-search ()
|
||||||
|
(interactive)
|
||||||
|
;; TODO: Prompt for path project root is not found.
|
||||||
|
;; TODO: Respect gitignore.
|
||||||
|
(syd-search-directory (syd-project-root)))
|
||||||
|
|
||||||
|
(defun syd-project-root-find-file (file-name)
|
||||||
|
"Just like `project-root-find-file', but allowing you to select the root
|
||||||
|
directory itself."
|
||||||
|
(declare (interactive-only find-file))
|
||||||
|
(interactive
|
||||||
|
(list (let ((root (project-root (project-current t))))
|
||||||
|
(read-file-name
|
||||||
|
"Find file in root: "
|
||||||
|
root root (confirm-nonexistent-file-or-buffer)))))
|
||||||
|
(find-file file-name t))
|
||||||
|
|
||||||
|
(provide 'syd-project)
|
||||||
|
;;; syd-project.el ends here
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
;;; syd-prose.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
;; Soft-wrap text to not the window edge, but a constant width. Also allows for
|
||||||
|
;; centering buffer text.
|
||||||
|
(use-package visual-fill-column
|
||||||
|
:defer t)
|
||||||
|
|
||||||
|
(defun syd-prose-disable-display-line-numbers-mode-h ()
|
||||||
|
"Disable `display-line-numbers-mode'."
|
||||||
|
(display-line-numbers-mode -1))
|
||||||
|
|
||||||
|
(defun syd-prose-set-visual-fill-column-center ()
|
||||||
|
"Sets the buffer-local value for `visual-fill-column-center-text'."
|
||||||
|
(setq-local visual-fill-column-center-text t))
|
||||||
|
|
||||||
|
;; Jinx is a fast just-in-time spell-checker for Emacs. Jinx highlights
|
||||||
|
;; misspelled words in the text of the visible portion of the buffer. For
|
||||||
|
;; efficiency, Jinx highlights misspellings lazily, recognizes window boundaries
|
||||||
|
;; and text folding, if any. For example, when unfolding or scrolling, only the
|
||||||
|
;; newly visible part of the text is checked if it has not been checked
|
||||||
|
;; before. Each misspelling can be corrected from a list of dictionary words
|
||||||
|
;; presented as a completion menu.
|
||||||
|
(use-package jinx
|
||||||
|
;; Managed by Nix: libenchant dependency.
|
||||||
|
:straight nil
|
||||||
|
:commands (jinx-mode jinx-correct jinx-correct-word)
|
||||||
|
:init
|
||||||
|
(defun syd-jinx--jinx-or-ispell ()
|
||||||
|
(interactive)
|
||||||
|
(if (bound-and-true-p jinx-mode)
|
||||||
|
(call-interactively #'jinx-correct-word)
|
||||||
|
(call-interactively #'ispell-word)))
|
||||||
|
:general (:states '(normal visual)
|
||||||
|
"z =" #'syd-jinx--jinx-or-ispell)
|
||||||
|
:config
|
||||||
|
;; Default is "en_US"; fuck that!
|
||||||
|
(jinx-languages "en" t))
|
||||||
|
|
||||||
|
(defvar syd-prose-mode-hook
|
||||||
|
(list #'syd-prose-set-visual-fill-column-center
|
||||||
|
#'visual-fill-column-mode
|
||||||
|
#'visual-line-mode
|
||||||
|
#'variable-pitch-mode
|
||||||
|
#'syd-prose-disable-display-line-numbers-mode-h
|
||||||
|
#'jinx-mode)
|
||||||
|
"Hooks run for `syd-prose-mode'.")
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(define-minor-mode syd-prose-mode
|
||||||
|
"A minor mode for writing prose."
|
||||||
|
:lighter nil)
|
||||||
|
|
||||||
|
(provide 'syd-prose)
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
;;; syd-search.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(cl-defun syd-search-region (beg end &key initial)
|
||||||
|
(save-restriction
|
||||||
|
(narrow-to-region beg end)
|
||||||
|
(consult-line initial)))
|
||||||
|
|
||||||
|
(defun syd-search--escape-regexp (str)
|
||||||
|
(require 'syd-text)
|
||||||
|
(replace-regexp-in-string " " "\\\\ "
|
||||||
|
(syd-pcre-quote str)))
|
||||||
|
|
||||||
|
(defun syd-search-buffer (buffer)
|
||||||
|
"Conduct a text search on BUFFER.
|
||||||
|
|
||||||
|
If a selection is active and multi-line, perform a search restricted to that
|
||||||
|
region.
|
||||||
|
|
||||||
|
If a selection is active and not multi-line, use the selection as the initial
|
||||||
|
input and search the whole buffer for it."
|
||||||
|
(interactive (list (current-buffer)))
|
||||||
|
(save-restriction
|
||||||
|
(let* ((beg (region-beginning))
|
||||||
|
(end (region-end))
|
||||||
|
(multiline-p (/= (line-number-at-pos beg)
|
||||||
|
(line-number-at-pos end))))
|
||||||
|
(if (and beg end (region-active-p))
|
||||||
|
(progn (deactivate-mark)
|
||||||
|
(if multiline-p
|
||||||
|
(syd-search-region beg end)
|
||||||
|
;; Treat as a single pattern, not several
|
||||||
|
;; space-separated patterns.
|
||||||
|
(consult-line (syd-search--escape-regexp
|
||||||
|
(buffer-substring-no-properties beg end)))))
|
||||||
|
(consult-line)))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun syd-search-directory (dir)
|
||||||
|
(interactive (list (read-directory-name
|
||||||
|
"Search directory: "
|
||||||
|
default-directory nil t)))
|
||||||
|
(cond ((executable-find "rg")
|
||||||
|
(consult-ripgrep dir))
|
||||||
|
((executable-find "grep")
|
||||||
|
(message "Couldn't find ripgrep; using grep")
|
||||||
|
(consult-grep dir))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun syd-search-current-directory ()
|
||||||
|
(interactive)
|
||||||
|
(syd-search-directory default-directory))
|
||||||
|
|
||||||
|
|
||||||
|
(provide 'syd-search)
|
||||||
|
;;; syd-search.el ends here
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
;; syd-strategies-lookup.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(require 'syd-strategies)
|
||||||
|
(use-package better-jumper)
|
||||||
|
(require 'better-jumper)
|
||||||
|
|
||||||
|
(defun syd-strat--run-lookup-strategy (strategy identifier origin)
|
||||||
|
"Safely call a lookup STRATEGY. A lookup strategy, if it is not an
|
||||||
|
interactive command, will be called with the lone argument IDENTIFIER.
|
||||||
|
Interactive or not, the procedure is expected to return nil on failure. Returns
|
||||||
|
a marker if STRATEGY returns a buffer or marker, or nil on failure.
|
||||||
|
Modifications to the window configuration will be discarded if STRATEGY fails to
|
||||||
|
return a buffer or marker."
|
||||||
|
(condition-case-unless-debug e
|
||||||
|
(let ((wconf (current-window-configuration))
|
||||||
|
(result (condition-case-unless-debug e
|
||||||
|
(if (commandp strategy)
|
||||||
|
(call-interactively strategy)
|
||||||
|
(funcall strategy identifier))
|
||||||
|
(error
|
||||||
|
(message "Lookup strategy %S threw an error: %s" strategy e)
|
||||||
|
'fail))))
|
||||||
|
(cond ((eq result 'fail)
|
||||||
|
(set-window-configuration wconf)
|
||||||
|
nil)
|
||||||
|
((bufferp result)
|
||||||
|
(with-current-buffer result
|
||||||
|
(point-marker)))
|
||||||
|
((or result
|
||||||
|
(null origin)
|
||||||
|
(/= (point-marker) origin))
|
||||||
|
(prog1 (point-marker)
|
||||||
|
(set-window-configuration wconf)))))
|
||||||
|
((error user-error)
|
||||||
|
(message "Lookup strategy %S: %s" strategy e)
|
||||||
|
nil)))
|
||||||
|
|
||||||
|
(cl-defun syd-strat--lookup-and-jump-to
|
||||||
|
(strategy-category identifier &key (display-fn #'switch-to-buffer))
|
||||||
|
(let* ((origin (point-marker))
|
||||||
|
(strategies (alist-get strategy-category syd-strat--strategies))
|
||||||
|
;; TODO: If called with a prefix argument, prompt the user to select a
|
||||||
|
;; strategy.
|
||||||
|
(result (syd-strat-try-functions-wrapped
|
||||||
|
#'syd-strat--run-lookup-strategy
|
||||||
|
strategies identifier origin)))
|
||||||
|
(unwind-protect
|
||||||
|
(when (cond ((null result)
|
||||||
|
(message "No lookup strategy could find %S" identifier)
|
||||||
|
nil)
|
||||||
|
((markerp result)
|
||||||
|
(funcall display-fn (marker-buffer result))
|
||||||
|
(goto-char result)
|
||||||
|
result)
|
||||||
|
(result))
|
||||||
|
(with-current-buffer (marker-buffer origin)
|
||||||
|
(better-jumper-set-jump (marker-position origin)))
|
||||||
|
result))
|
||||||
|
(set-marker origin nil)))
|
||||||
|
|
||||||
|
(defun syd-strat-lookup-documentation (identifier)
|
||||||
|
(interactive (list (syd-thing-at-point-or-region)))
|
||||||
|
(syd-strat--lookup-and-jump-to :documentation identifier
|
||||||
|
:display-fn #'pop-to-buffer))
|
||||||
|
|
||||||
|
(defun syd-strat-lookup-definition (identifier)
|
||||||
|
(interactive (list (syd-thing-at-point-or-region)))
|
||||||
|
(syd-strat--lookup-and-jump-to :definition identifier))
|
||||||
|
|
||||||
|
(provide 'syd-strategies-lookup)
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
;; syd-strategies.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(require 'syd-text)
|
||||||
|
|
||||||
|
(comment
|
||||||
|
"For demonstration:"
|
||||||
|
(setq syd-strat--strategies
|
||||||
|
'((:documentation syd-emacs-lisp-lookup-documentation)
|
||||||
|
(:definition evil-goto-definition))))
|
||||||
|
|
||||||
|
;; :documentation : Identifier -> Marker
|
||||||
|
(defvar-local syd-strat--strategies nil)
|
||||||
|
|
||||||
|
(defun syd-strat-try-functions-wrapped (wrapper fns &rest args)
|
||||||
|
"For each FN in FNS, call WRAPPER with the arguments FN followed by ARGS,
|
||||||
|
until a FN returns non-nil."
|
||||||
|
(cl-loop for fn in fns
|
||||||
|
with r = nil
|
||||||
|
do (setq r (apply wrapper fn args))
|
||||||
|
until r
|
||||||
|
finally return r))
|
||||||
|
|
||||||
|
(defun syd-strat--set-strategies (category strategies)
|
||||||
|
(cl-loop for ref in-ref syd-strat--strategies
|
||||||
|
until (eq category (car ref))
|
||||||
|
finally do (pp ref)))
|
||||||
|
|
||||||
|
(defun syd-set-strategies (modes &rest args)
|
||||||
|
(dolist (mode (ensure-list modes))
|
||||||
|
(let ((hook (intern (format "%s-hook" mode)))
|
||||||
|
(fn-name (intern (format "syd-strat--init-for-%s-h" mode))))
|
||||||
|
(unless (cl-evenp (length args))
|
||||||
|
(signal 'wrong-number-of-arguments args))
|
||||||
|
;; We use this `defalias' incantation instead of a raw `fset' because the
|
||||||
|
;; former will properly associate a source location to the definition.
|
||||||
|
(defalias fn-name
|
||||||
|
(function
|
||||||
|
(lambda ()
|
||||||
|
(cl-loop for (category strategies) on args by (lambda (x) (-drop 2 x))
|
||||||
|
do (syd-strat--set-strategies category strategies)))))
|
||||||
|
(add-hook hook fn-name))))
|
||||||
|
|
||||||
|
(provide 'syd-strategies)
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
;;; syd-text.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun syd-region-active-p ()
|
||||||
|
"Return non-nil if selection is active.
|
||||||
|
Detects evil visual mode as well."
|
||||||
|
(declare (side-effect-free t))
|
||||||
|
(or (use-region-p)
|
||||||
|
(and (bound-and-true-p evil-local-mode)
|
||||||
|
(evil-visual-state-p))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun syd-region-beginning ()
|
||||||
|
"Return beginning position of selection.
|
||||||
|
Uses `evil-visual-beginning' if available."
|
||||||
|
(declare (side-effect-free t))
|
||||||
|
(or (and (bound-and-true-p evil-local-mode)
|
||||||
|
(evil-visual-state-p)
|
||||||
|
(markerp evil-visual-beginning)
|
||||||
|
(marker-position evil-visual-beginning))
|
||||||
|
(region-beginning)))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun syd-region-end ()
|
||||||
|
"Return end position of selection.
|
||||||
|
Uses `evil-visual-end' if available."
|
||||||
|
(declare (side-effect-free t))
|
||||||
|
(or (and (bound-and-true-p evil-local-mode)
|
||||||
|
(evil-visual-state-p)
|
||||||
|
(markerp evil-visual-end)
|
||||||
|
(marker-position evil-visual-end))
|
||||||
|
(region-end)))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(cl-defun syd-thing-at-point-or-region (&optional thing &key prompt)
|
||||||
|
"Grab the current selection, THING at point, or xref identifier at point.
|
||||||
|
|
||||||
|
Returns THING if it is a string. Otherwise, if nothing is found at point and
|
||||||
|
PROMPT is non-nil, prompt for a string (if PROMPT is a string it'll be used as
|
||||||
|
the prompting string). Returns nil if all else fails.
|
||||||
|
|
||||||
|
NOTE: Don't use THING for grabbing symbol-at-point. The xref fallback is smarter
|
||||||
|
in some cases."
|
||||||
|
(declare (side-effect-free t))
|
||||||
|
(cond ((stringp thing)
|
||||||
|
thing)
|
||||||
|
((syd-region-active-p)
|
||||||
|
(buffer-substring-no-properties
|
||||||
|
(syd-region-beginning)
|
||||||
|
(syd-region-end)))
|
||||||
|
(thing
|
||||||
|
(thing-at-point thing t))
|
||||||
|
((require 'xref nil t)
|
||||||
|
;; Eglot, nox (a fork of eglot), and elpy implementations for
|
||||||
|
;; `xref-backend-identifier-at-point' betray the documented purpose of
|
||||||
|
;; the interface. Eglot/nox return a hardcoded string and elpy
|
||||||
|
;; prepends the line number to the symbol.
|
||||||
|
(let ((backend (xref-find-backend)))
|
||||||
|
(if (memq backend '(eglot elpy nox))
|
||||||
|
(thing-at-point 'symbol t)
|
||||||
|
;; A little smarter than using `symbol-at-point', though in most
|
||||||
|
;; cases, xref ends up using `symbol-at-point' anyway.
|
||||||
|
(if-let ((ident (xref-backend-identifier-at-point backend)))
|
||||||
|
;; REVIEW: `xref-backend-identifier' seems to have some special
|
||||||
|
;; uses of text properties. Are we sure we want to remove
|
||||||
|
;; them?
|
||||||
|
(substring-no-properties ident)))))
|
||||||
|
(prompt
|
||||||
|
(read-string (if (stringp prompt) prompt "")))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun syd-insert-newline-above (count)
|
||||||
|
"Insert a blank line below the current line."
|
||||||
|
(interactive "p")
|
||||||
|
(dotimes (_ count)
|
||||||
|
(let ((point-was-at-bol-p (= (current-column) 0)))
|
||||||
|
(save-excursion
|
||||||
|
(evil-insert-newline-above))
|
||||||
|
;; Special case: with `syd-insert-newline-above' is called with point at
|
||||||
|
;; BOL, the point unexpectedly fails to "stick" to its original position.
|
||||||
|
(when point-was-at-bol-p
|
||||||
|
(next-line)))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun syd-insert-newline-below (count)
|
||||||
|
"Insert a blank line below the current line."
|
||||||
|
(interactive "p")
|
||||||
|
(dotimes (_ count)
|
||||||
|
(save-excursion (evil-insert-newline-below))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun syd-render-ansi-escape-codes (beg end)
|
||||||
|
(interactive "r")
|
||||||
|
(require 'ansi-color)
|
||||||
|
(if (region-active-p)
|
||||||
|
(ansi-color-apply-on-region beg end)
|
||||||
|
(ansi-color-apply-on-region (point-min) (point-max))))
|
||||||
|
|
||||||
|
(defun syd-evil-paste (before-p arg &optional register yank-handler)
|
||||||
|
"Like `evil-paste-after', but a 'C-u' prefix argument will instead act like
|
||||||
|
':put' (i.e. the register will be pasted onto a new line)."
|
||||||
|
(if (consp arg)
|
||||||
|
(evil-ex-put (syd-region-beginning) (syd-region-end)
|
||||||
|
;; `evil-ex-put' wants a string, but it is immediately
|
||||||
|
;; converted back to a char. }xP
|
||||||
|
(and register (string register))
|
||||||
|
before-p)
|
||||||
|
(funcall (if before-p #'evil-paste-before #'evil-paste-after)
|
||||||
|
arg register yank-handler)))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(evil-define-command syd-evil-paste-after (arg &optional register yank-handler)
|
||||||
|
"See `syd-evil-paste'.'"
|
||||||
|
(interactive "P<x><y>")
|
||||||
|
(syd-evil-paste nil arg register yank-handler))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(evil-define-command syd-evil-paste-before (arg &optional register yank-handler)
|
||||||
|
"See `syd-evil-paste'.'"
|
||||||
|
(interactive "P<x><y>")
|
||||||
|
(syd-evil-paste t arg register yank-handler))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun syd-pcre-quote (str)
|
||||||
|
"Like `reqexp-quote', but for PCREs."
|
||||||
|
(let ((special '(?. ?^ ?$ ?* ?+ ?? ?{ ?\\ ?\[ ?\| ?\())
|
||||||
|
(quoted nil))
|
||||||
|
(mapc (lambda (c)
|
||||||
|
(when (memq c special)
|
||||||
|
(push ?\\ quoted))
|
||||||
|
(push c quoted))
|
||||||
|
str)
|
||||||
|
(concat (nreverse quoted))))
|
||||||
|
|
||||||
|
(provide 'syd-text)
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
;;; syd-window.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(syd-define-stub
|
||||||
|
syd/window-swap-left
|
||||||
|
:desc "Select left window."
|
||||||
|
:interactive t)
|
||||||
|
|
||||||
|
(syd-define-stub
|
||||||
|
syd/window-swap-down
|
||||||
|
:desc "Select down window."
|
||||||
|
:interactive t)
|
||||||
|
|
||||||
|
(syd-define-stub
|
||||||
|
syd/window-swap-up
|
||||||
|
:desc "Select up window."
|
||||||
|
:interactive t)
|
||||||
|
|
||||||
|
(syd-define-stub
|
||||||
|
syd/window-swap-right
|
||||||
|
:desc "Select right window."
|
||||||
|
:interactive t)
|
||||||
|
|
||||||
|
(syd-define-stub
|
||||||
|
syd/window-maximise
|
||||||
|
:desc "Maximise window"
|
||||||
|
:interactive t)
|
||||||
|
|
||||||
|
(provide 'syd-window)
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
;;; syd-lang-agda.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(with-eval-after-load 'agda2
|
||||||
|
(general-define-key
|
||||||
|
:keymaps 'agda2-mode-map
|
||||||
|
:states '(normal visual motion emacs insert)
|
||||||
|
:major-modes t
|
||||||
|
:prefix syd-localleader-key
|
||||||
|
:non-normal-prefix syd-alt-localleader-key
|
||||||
|
"?" #'agda2-show-goals
|
||||||
|
"." #'agda2-goal-and-context-and-inferred
|
||||||
|
"," #'agda2-goal-and-context
|
||||||
|
"=" #'agda2-show-constraints
|
||||||
|
"g" #'agda2-give
|
||||||
|
"a" #'agda2-mimer-maybe-all
|
||||||
|
"[" #'agda2-previous-goal
|
||||||
|
"c" #'agda2-make-case
|
||||||
|
"d" #'agda2-infer-type-maybe-toplevel
|
||||||
|
"e" #'agda2-show-context
|
||||||
|
"]" #'agda2-next-goal
|
||||||
|
"h" #'agda2-helper-function-type
|
||||||
|
"l" #'agda2-load
|
||||||
|
"n" #'agda2-compute-normalised-maybe-toplevel
|
||||||
|
"p" #'agda2-module-contents-maybe-toplevel
|
||||||
|
"r" #'agda2-refine
|
||||||
|
"s" #'agda2-solveAll
|
||||||
|
"t" #'agda2-goal-type
|
||||||
|
"w" #'agda2-why-in-scope-maybe-toplevel
|
||||||
|
"x c" #'agda2-compile
|
||||||
|
"x d" #'agda2-remove-annotations
|
||||||
|
"x h" #'agda2-display-implicit-arguments
|
||||||
|
"x q" #'agda2-quit
|
||||||
|
"x r" #'agda2-restart)
|
||||||
|
(general-def
|
||||||
|
:keymaps 'agda2-mode-map
|
||||||
|
:states '(motion normal)
|
||||||
|
"[ n" #'agda2-previous-goal
|
||||||
|
"] n" #'agda2-next-goal)
|
||||||
|
(setq agda2-fontset-name "JuliaMono")
|
||||||
|
|
||||||
|
;; Inform Smartparens and Evil-surround of some extra brackets.
|
||||||
|
(with-eval-after-load 'smartparens
|
||||||
|
(sp-local-pair 'agda2-mode "⟨" "⟩"))
|
||||||
|
(syd-add-hook 'agda2-mode-hook
|
||||||
|
(defun syd-agda--configure-evil-surround-h ()
|
||||||
|
(with-eval-after-load 'evil-surround
|
||||||
|
(push '(?z . ("⟨" . "⟩"))
|
||||||
|
evil-surround-pairs-alist))))
|
||||||
|
|
||||||
|
(defun syd-agda-lookup-documentation ()
|
||||||
|
(interactive)
|
||||||
|
(call-interactively #'agda2-goal-and-context)
|
||||||
|
agda2-info-buffer)
|
||||||
|
|
||||||
|
;; DEPRECATED: Remove once syd-strategies is working.
|
||||||
|
(syd-add-hook 'agda2-mode-hook
|
||||||
|
(defun syd-agda-set-handlers-h ()
|
||||||
|
(setq-local syd-lookup-documentation-handlers
|
||||||
|
(list #'syd-agda-lookup-documentation)))))
|
||||||
|
|
||||||
|
(provide 'syd-lang-agda)
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
;;; syd-lang-c.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(with-eval-after-load 'cc-mode
|
||||||
|
(dolist (c '(?_))
|
||||||
|
(modify-syntax-entry c "w" c-mode-syntax-table)))
|
||||||
|
|
||||||
|
(provide 'syd-lang-c)
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
;;; syd-lang-clojure.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(use-package clojure-mode
|
||||||
|
:mode (("\\.\\(clj\\|cljd\\|dtm\\|edn\\|lpy\\)\\'" . clojure-mode)
|
||||||
|
("\\.cljc\\'" . clojurec-mode)
|
||||||
|
("\\.cljs\\'" . clojurescript-mode)
|
||||||
|
("\\(?:build\\|profile\\)\\.boot\\'" . clojure-mode))
|
||||||
|
:interpreter (("bb" . clojure-mode)
|
||||||
|
("nbb" . clojurescript-mode))
|
||||||
|
:config
|
||||||
|
(add-hook 'clojure-mode-hook #'syd-lisp-mode)
|
||||||
|
(dolist (c '(?- ?_ ?? ?! ?+ ?* ?/ ?: ?> ?< ?= ?&))
|
||||||
|
(modify-syntax-entry c "w" clojure-mode-syntax-table)))
|
||||||
|
|
||||||
|
(use-package cider
|
||||||
|
:after clojure-mode)
|
||||||
|
|
||||||
|
(defun syd-clojure-open-repl (&optional arg type)
|
||||||
|
"Open a Cider REPL for clojure and return the buffer."
|
||||||
|
(interactive "P")
|
||||||
|
;; TODO: Better error handling
|
||||||
|
;; type is `clj' for clojure and `cljs' for clojurescript
|
||||||
|
;; ... with no type specified, assume `clj'.
|
||||||
|
(let ((type (or type 'clj)))
|
||||||
|
(if-let* ((buffer (cider-current-repl type)))
|
||||||
|
(pop-to-buffer buffer)
|
||||||
|
(let ((process (cond ((eq type 'clj) (cider-jack-in-clj arg))
|
||||||
|
((eq type 'cljs) (cider-jack-in-cljs arg)))))
|
||||||
|
(message "Starting CIDER server for the first time...")
|
||||||
|
(while (and (process-live-p process)
|
||||||
|
(not (cider-current-repl type)))
|
||||||
|
(sit-for 1))
|
||||||
|
(message "Starting CIDER server for the first time...done")
|
||||||
|
(pop-to-buffer (cider-current-repl type))))))
|
||||||
|
|
||||||
|
(defun syd-clojure-open-cljs-repl (&optional arg)
|
||||||
|
(interactive "P")
|
||||||
|
(syd-clojure-open-repl arg 'cljs))
|
||||||
|
|
||||||
|
(use-package cider-mode
|
||||||
|
:straight nil
|
||||||
|
;; :after clojure-mode
|
||||||
|
:hook (clojure-mode-local-vars . cider-mode)
|
||||||
|
:init
|
||||||
|
(with-eval-after-load 'clojure-mode
|
||||||
|
(set-repl-handler! '(clojure-mode clojurec-mode)
|
||||||
|
#'syd-clojure-open-repl :persist t)
|
||||||
|
(set-repl-handler! 'clojurescript-mode
|
||||||
|
#'syd-clojure-open-cljs-repl :persist t)
|
||||||
|
(set-eval-handler! '(clojure-mode
|
||||||
|
cider-clojure-interaction-mode
|
||||||
|
clojurec-mode clojurescript-mode)
|
||||||
|
#'cider-eval-region))
|
||||||
|
:custom ((cider-show-error-buffer nil)
|
||||||
|
;; Download Java source archives for local Javadoc and jump-to-def
|
||||||
|
;; functionality.
|
||||||
|
(cider-download-java-sources t))
|
||||||
|
:general
|
||||||
|
;; DEPRECATED: Remove once a `map!' equivalent is implemented.
|
||||||
|
(:keymaps 'cider-repl-mode-map
|
||||||
|
:states '(normal insert)
|
||||||
|
"C-k" #'cider-repl-backward-input
|
||||||
|
"C-j" #'cider-repl-forward-input
|
||||||
|
"C-s" #'consult-history)
|
||||||
|
;; DEPRECATED: Remove once a `map!' equivalent is implemented.
|
||||||
|
(:keymaps '(cider-repl-mode-map clojure-mode-map)
|
||||||
|
:states '(normal visual motion emacs insert)
|
||||||
|
:major-modes t
|
||||||
|
:prefix syd-localleader-key
|
||||||
|
:non-normal-prefix syd-alt-localleader-key
|
||||||
|
"\"" #'cider-jack-in-cljs
|
||||||
|
"'" #'cider-jack-in-clj
|
||||||
|
"c" #'cider-connect-clj
|
||||||
|
"C" #'cider-connect-cljs
|
||||||
|
"r l" #'cider-load-buffer
|
||||||
|
"r n" #'cider-repl-set-ns
|
||||||
|
"r r" #'cider-ns-refresh
|
||||||
|
"r R" #'cider-restart
|
||||||
|
"r q" #'cider-quit
|
||||||
|
"d d" #'cider-debug-defun-at-point
|
||||||
|
"M-:" #'cider-read-and-eval
|
||||||
|
"h d" #'cider-doc
|
||||||
|
"h c" #'cider-cheatsheet
|
||||||
|
"h j" #'cider-javadoc
|
||||||
|
"h n" #'cider-browse-ns
|
||||||
|
"T n" #'cider-test-run-ns-tests
|
||||||
|
"T r" #'cider-test-rerun-failed-tests
|
||||||
|
"T R" #'cider-test-rerun-test
|
||||||
|
"x" #'cider-scratch)
|
||||||
|
(:keymaps 'cider-repl-mode-map
|
||||||
|
:states 'insert
|
||||||
|
"S-<return>" #'cider-repl-newline-and-indent)
|
||||||
|
:config
|
||||||
|
(add-hook 'cider-mode-hook #'eldoc-mode)
|
||||||
|
(add-hook 'cider-repl-mode-hook #'syd-lisp-mode)
|
||||||
|
(set-popup-rules!
|
||||||
|
`(("^\\*cider-error\\*" :ignore t)
|
||||||
|
("^\\*cider-repl" :quit nil :ttl nil)
|
||||||
|
("^\\*cider-repl-history" :vslot 2 :ttl nil)
|
||||||
|
(,(rx bol "*cider-nrepl-middleware") :slot 3 :quit t :ttl 0)
|
||||||
|
(,(rx bol "*cider-test-report") :vslot 3 :quit t :ttl 0 :height 0.4)
|
||||||
|
(,(rx bol "*cider-cheatsheet*")
|
||||||
|
:width ,(lambda (win)
|
||||||
|
(with-selected-window win
|
||||||
|
(enlarge-window (- (min 45 (* 0.2 (frame-width)))
|
||||||
|
(window-width))
|
||||||
|
t)))
|
||||||
|
:side right :vslot -8 :quit t :select t)
|
||||||
|
(,(rx bol "*cider-ns-browser")
|
||||||
|
:side right :vslot -8 :quit t :select t)
|
||||||
|
(,(rx bol "*cider-doc*")
|
||||||
|
:slot 2 :vslot -8 :quit t :select t)))
|
||||||
|
(with-eval-after-load 'cider-scratch
|
||||||
|
(add-to-list 'display-buffer-alist
|
||||||
|
`(,(regexp-quote cider-scratch-buffer-name)
|
||||||
|
(,#'display-buffer-same-window))))
|
||||||
|
;; DEPRECATED: Remove once syd-strategies is working.
|
||||||
|
(syd-add-hook '(clojure-mode-hook
|
||||||
|
clojurescript-mode-hook
|
||||||
|
cider-repl-mode-hook
|
||||||
|
cider-clojure-interaction-mode-hook)
|
||||||
|
(defun syd-clojure-set-handlers-h ()
|
||||||
|
(setq-local syd-lookup-documentation-handlers
|
||||||
|
(list #'cider-doc))))
|
||||||
|
|
||||||
|
;; Correctly indent some common macros.
|
||||||
|
(put-clojure-indent 'match 1)
|
||||||
|
|
||||||
|
(with-eval-after-load 'consult
|
||||||
|
(add-to-list 'consult-mode-histories
|
||||||
|
'(cider-repl-mode cider-repl-input-history nil cider-repl-bol-mark))))
|
||||||
|
|
||||||
|
;; Give different pairs of delimiters different colours.
|
||||||
|
(use-package rainbow-delimiters
|
||||||
|
:hook (clojure-mode . rainbow-delimiters-mode))
|
||||||
|
|
||||||
|
(provide 'syd-lang-clojure)
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
;;; emacs-lisp.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(require 'syd-handle-repl)
|
||||||
|
(require 'syd-handle-lookup)
|
||||||
|
(require 'syd-handle-eval)
|
||||||
|
(require 'syd-lisp-lib)
|
||||||
|
;; (require 'handle)
|
||||||
|
|
||||||
|
;; Don't `use-package' `ielm', since it's loaded by Emacs. You'll get weird
|
||||||
|
;; autoload errors if you do.
|
||||||
|
;; https://www.reddit.com/r/emacs/comments/q7fjbi/comment/lml127d
|
||||||
|
(use-package emacs
|
||||||
|
:custom ((ielm-history-file-name ; Stay out of my config dir!
|
||||||
|
(file-name-concat syd-cache-dir "ielm-history.eld"))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun syd/open-emacs-lisp-repl ()
|
||||||
|
(interactive)
|
||||||
|
(pop-to-buffer
|
||||||
|
(or (get-buffer "*ielm*")
|
||||||
|
(progn (ielm) ; Creates the *ielm* buffer.
|
||||||
|
(let ((b (get-buffer "*ielm*")))
|
||||||
|
;; We leave it to the enclosing `pop-to-buffer' to display the
|
||||||
|
;; buffer.
|
||||||
|
(bury-buffer b)
|
||||||
|
b)))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun syd-emacs-lisp-lookup-documentation (identifier)
|
||||||
|
"Lookup IDENTIFIER with `describe-symbol'"
|
||||||
|
;; HACK: Much to my frustration, `describe-symbol' has no defined return
|
||||||
|
;; value. To test if the call was successful or not, we check if any window
|
||||||
|
;; is displaying the help buffer. This breaks if
|
||||||
|
;; `syd-emacs-lisp-lookup-documentation' is called while the help buffer is
|
||||||
|
;; already open.
|
||||||
|
(describe-symbol (intern identifier))
|
||||||
|
(let ((buffer (get-buffer (help-buffer))))
|
||||||
|
(and (get-buffer-window-list buffer)
|
||||||
|
buffer)))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun syd-emacs-lisp-eval (beg end)
|
||||||
|
"Evaluate a region and print it to the echo area (if one line long), otherwise
|
||||||
|
to a pop up buffer."
|
||||||
|
(syd-eval-display-results
|
||||||
|
(string-trim-right
|
||||||
|
(let ((buffer (generate-new-buffer " *eval-output*"))
|
||||||
|
(debug-on-error t))
|
||||||
|
(unwind-protect
|
||||||
|
(condition-case-unless-debug e
|
||||||
|
(progn (eval-region beg end buffer load-read-function)
|
||||||
|
(with-current-buffer buffer
|
||||||
|
(let ((pp-max-width nil))
|
||||||
|
(require 'pp)
|
||||||
|
(pp-buffer)
|
||||||
|
(replace-regexp-in-string
|
||||||
|
"\\\\n" "\n" (string-trim-left (buffer-string))))))
|
||||||
|
(error (format "ERROR: %s" e)))
|
||||||
|
(kill-buffer buffer))))
|
||||||
|
:source-buffer (current-buffer)
|
||||||
|
:force-popup current-prefix-arg))
|
||||||
|
|
||||||
|
(dolist (m '(emacs-lisp-mode lisp-data-mode))
|
||||||
|
(set-repl-handler! m
|
||||||
|
#'syd/open-emacs-lisp-repl)
|
||||||
|
(set-eval-handler! m
|
||||||
|
#'syd-emacs-lisp-eval))
|
||||||
|
|
||||||
|
(syd-add-hook '(emacs-lisp-mode-hook lisp-data-mode-hook)
|
||||||
|
#'syd-lisp-mode)
|
||||||
|
|
||||||
|
;; DEPRECATED: Remove once syd-strategies is working.
|
||||||
|
(syd-add-hook '(emacs-lisp-mode-hook help-mode-hook lisp-data-mode-hook)
|
||||||
|
(defun syd-emacs-set-handlers-h ()
|
||||||
|
(setq-local syd-lookup-documentation-handlers
|
||||||
|
(list #'syd-emacs-lisp-lookup-documentation))))
|
||||||
|
|
||||||
|
;; Semantic highlighting for Elisp.
|
||||||
|
(use-package highlight-defined
|
||||||
|
:hook (emacs-lisp-mode-hook . highlight-defined-mode))
|
||||||
|
|
||||||
|
;; Automatically and inteligently expand abbreviations. E.g. `wcb` will be
|
||||||
|
;; expanded to `(with-current-buffer)`, but only where it makes sense for a
|
||||||
|
;; function/macro call to be.
|
||||||
|
(use-package sotlisp
|
||||||
|
:straight (:host github
|
||||||
|
:repo "Malabarba/speed-of-thought-lisp")
|
||||||
|
:hook (emacs-lisp-mode . speed-of-thought-mode))
|
||||||
|
|
||||||
|
;; Give different pairs of delimiters different colours.
|
||||||
|
(use-package rainbow-delimiters
|
||||||
|
:hook (emacs-lisp-mode . rainbow-delimiters-mode))
|
||||||
|
|
||||||
|
(use-package macrostep
|
||||||
|
:commands (macrostep-expand)
|
||||||
|
:init
|
||||||
|
(general-define-key
|
||||||
|
:keymaps 'emacs-lisp-mode-map
|
||||||
|
:states '(normal visual motion emacs insert)
|
||||||
|
:major-modes t
|
||||||
|
:prefix syd-localleader-key
|
||||||
|
:non-normal-prefix syd-alt-localleader-key
|
||||||
|
"m" #'macrostep-expand))
|
||||||
|
|
||||||
|
(provide 'syd-lang-emacs-lisp)
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
;;; syd-lang-haskell.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(require 'syd-handle-repl)
|
||||||
|
(require 'syd-handle-lookup)
|
||||||
|
|
||||||
|
(defun syd-haskell-open-repl ()
|
||||||
|
"Open a Haskell REPL."
|
||||||
|
(interactive)
|
||||||
|
(require 'inf-haskell)
|
||||||
|
(run-haskell))
|
||||||
|
|
||||||
|
(defun syd-haskell-evil-open-above ()
|
||||||
|
"Opens a line above the current, following Haskell-mode's indentation"
|
||||||
|
(interactive)
|
||||||
|
(evil-beginning-of-line)
|
||||||
|
(haskell-indentation-newline-and-indent)
|
||||||
|
(evil-previous-line)
|
||||||
|
(haskell-indentation-indent-line)
|
||||||
|
(evil-append-line nil))
|
||||||
|
|
||||||
|
(defun syd-haskell-evil-open-below ()
|
||||||
|
"Opens a line below the current, following Haskell-mode's indentation"
|
||||||
|
(interactive)
|
||||||
|
(evil-append-line nil)
|
||||||
|
(haskell-indentation-newline-and-indent))
|
||||||
|
|
||||||
|
(defun syd-haskell-hoogle-start-server ()
|
||||||
|
(interactive)
|
||||||
|
(haskell-hoogle-start-server)
|
||||||
|
(message "Hoogle started on localhost:%d" haskell-hoogle-port-number))
|
||||||
|
|
||||||
|
(use-package haskell-mode
|
||||||
|
:mode (("\\.l?hs'" . haskell-literate-mode)
|
||||||
|
("\\.hs'" . haskell-mode))
|
||||||
|
:custom (; Show errors in REPL, not popup buffers.
|
||||||
|
(haskell-interactive-popup-errors nil)
|
||||||
|
(haskell-process-suggest-remove-import-line t)
|
||||||
|
(haskell-process-auto-import-loaded-modules t))
|
||||||
|
:general
|
||||||
|
;; DEPRECATED: Remove once a `map!' equivalent is implemented.
|
||||||
|
(:keymaps 'haskell-mode-map
|
||||||
|
:states '(normal visual motion emacs insert)
|
||||||
|
:major-modes t
|
||||||
|
:prefix syd-localleader-key
|
||||||
|
:non-normal-prefix syd-alt-localleader-key
|
||||||
|
"c" #'haskell-cabal-visit-file
|
||||||
|
"h s" #'syd-haskell-hoogle-start-server
|
||||||
|
"h q" #'haskell-hoogle-kill-server)
|
||||||
|
(:keymaps 'interactive-haskell-mode-map
|
||||||
|
:states '(normal insert)
|
||||||
|
"C-j" #'haskell-interactive-mode-history-next
|
||||||
|
"C-k" #'haskell-interactive-mode-history-previous)
|
||||||
|
(:keymaps 'haskell-mode-map
|
||||||
|
:states 'normal
|
||||||
|
[remap evil-open-above] #'syd-haskell-evil-open-above
|
||||||
|
[remap evil-open-below] #'syd-haskell-evil-open-below)
|
||||||
|
:config
|
||||||
|
(set-repl-handler! '(haskell-mode haskell-cabal-mode literate-haskell-mode)
|
||||||
|
#'syd-haskell-open-repl
|
||||||
|
;; Haskell-mode provides IDE features by communicating with a persistent
|
||||||
|
;; REPL process à la Lisp.
|
||||||
|
:persist t)
|
||||||
|
(add-to-list 'completion-ignored-extensions ".hi")
|
||||||
|
|
||||||
|
;; Don't kill REPL popup on ESC/C-g
|
||||||
|
(set-popup-rule! "^\\*haskell\\*" :quit nil)
|
||||||
|
(syd-add-hook 'haskell-mode-local-vars-hook
|
||||||
|
;; Folding of Haskell sections.
|
||||||
|
#'haskell-collapse-mode
|
||||||
|
#'interactive-haskell-mode)
|
||||||
|
(dolist (c '(?' ?_))
|
||||||
|
(modify-syntax-entry c "w" haskell-mode-syntax-table)))
|
||||||
|
|
||||||
|
(use-package lsp-haskell
|
||||||
|
:defer t
|
||||||
|
:init
|
||||||
|
(add-hook 'haskell-mode-hook #'lsp 'append)
|
||||||
|
(add-hook 'haskell-literate-mode-hook #'lsp 'append))
|
||||||
|
|
||||||
|
(provide 'syd-lang-haskell)
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
;;; syd-lang-idris2.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(require 'syd-handle-repl)
|
||||||
|
(require 'syd-handle-lookup)
|
||||||
|
|
||||||
|
(defun syd-idris2-open-repl ()
|
||||||
|
(interactive)
|
||||||
|
(idris2-repl-buffer))
|
||||||
|
|
||||||
|
(use-package idris2-mode
|
||||||
|
:mode "\\.idr\\'"
|
||||||
|
:straight (:type git
|
||||||
|
:host github
|
||||||
|
:repo "idris-community/idris2-mode")
|
||||||
|
:config
|
||||||
|
;; Fixes lag when editing idris code with Evil. See
|
||||||
|
;; https://github.com/idris-community/idris2-mode?tab=readme-ov-file#doom-emacs
|
||||||
|
(syd-defadvice syd-idris2--fix-evil-motion-range (fn &rest args)
|
||||||
|
"Like `evil-motion-range', but override field-beginning for performance.
|
||||||
|
See `https://github.com/ProofGeneral/PG/issues/427'."
|
||||||
|
:around #'evil-motion-range
|
||||||
|
(cl-letf (((symbol-function 'field-beginning)
|
||||||
|
(lambda (&rest args) 1)))
|
||||||
|
(apply fn args)))
|
||||||
|
|
||||||
|
(add-hook 'idris2-mode-hook #'lsp)
|
||||||
|
|
||||||
|
(general-define-key
|
||||||
|
:keymaps 'idris2-mode-map
|
||||||
|
:states '(normal visual motion emacs insert)
|
||||||
|
:major-modes t
|
||||||
|
:prefix syd-localleader-key
|
||||||
|
:non-normal-prefix syd-alt-localleader-key
|
||||||
|
"l" #'idris2-load-file)
|
||||||
|
|
||||||
|
(set-repl-handler! 'idris2-mode
|
||||||
|
#'syd-idris2-open-repl)
|
||||||
|
|
||||||
|
(set-popup-rules!
|
||||||
|
`((,(rx bol "*idris2-notes*" eol)
|
||||||
|
:ttl nil)
|
||||||
|
(,(rx bol "*idris2-holes*" eol)
|
||||||
|
:ttl nil :quit t :vslot -5 :height 7)))
|
||||||
|
(dolist (c '(?_ ??))
|
||||||
|
(modify-syntax-entry c "w" idris2-syntax-table)))
|
||||||
|
|
||||||
|
(provide 'syd-lang-idris2)
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
;;; syd-lang-kdl.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(use-package kdl-ts-mode
|
||||||
|
:mode "\\.kdl\\'"
|
||||||
|
:straight (:type git
|
||||||
|
:host github
|
||||||
|
:repo "dataphract/kdl-ts-mode"))
|
||||||
|
|
||||||
|
(provide 'syd-lang-kdl)
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
;;; syd-lang-lean4.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(use-package lean4-mode
|
||||||
|
:straight (:type git
|
||||||
|
:host github
|
||||||
|
:repo "leanprover-community/lean4-mode"
|
||||||
|
:files ("*.el" "data")))
|
||||||
|
|
||||||
|
(provide 'syd-lang-lean4)
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
;;; syd-lang-nix.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(require 'syd-handle-repl)
|
||||||
|
(require 'syd-handle-lookup)
|
||||||
|
|
||||||
|
(defun syd-nix-open-nix-repl ()
|
||||||
|
(interactive)
|
||||||
|
;; If possible, cd to the project root. Flakes force you to use relative
|
||||||
|
;; paths, which can be annoying in combination with
|
||||||
|
;;
|
||||||
|
;; REVIEW: Should this be something handled by `syd--call-repl-handler'?
|
||||||
|
(-some-> (syd-project-root) cd)
|
||||||
|
(nix-repl)
|
||||||
|
(current-buffer))
|
||||||
|
|
||||||
|
(evil-define-text-object syd-nix-obj-outer-binding (count _beg _end _type)
|
||||||
|
"TODO"
|
||||||
|
:type 'inclusive
|
||||||
|
(let* ((cleanup-p (memq evil-this-operator '(evil-delete)))
|
||||||
|
(node (treesit-thing-at-point "binding" "nested")))
|
||||||
|
(list (treesit-node-start node)
|
||||||
|
(treesit-node-end node))))
|
||||||
|
|
||||||
|
(use-package nix-mode
|
||||||
|
;; :mode "\\.nix\\'"
|
||||||
|
:init
|
||||||
|
(add-to-list 'auto-mode-alist
|
||||||
|
(cons (rx "/flake.lock'")
|
||||||
|
(if (fboundp 'json-mode)
|
||||||
|
'json-mode
|
||||||
|
'js-mode)))
|
||||||
|
:config
|
||||||
|
(add-hook 'nix-mode-hook #'lsp)
|
||||||
|
(set-popup-rule! (rx bol "*nixos-options-doc*" eol) :ttl 0 :quit t)
|
||||||
|
(set-repl-handler! '(nix-mode nix-ts-mode) #'syd-nix-open-nix-repl)
|
||||||
|
(dolist (c '(?- ?_))
|
||||||
|
(modify-syntax-entry c "w" nix-mode-syntax-table))
|
||||||
|
|
||||||
|
;; Inform Smartparens and Evil-surround of Nix's alternative string syntax.
|
||||||
|
(with-eval-after-load 'smartparens
|
||||||
|
(sp-local-pair '(nix-mode nix-ts-mode) "''" "''"))
|
||||||
|
(syd-add-hook '(nix-mode-hook nix-ts-mode-hook)
|
||||||
|
(defun syd-nix--configure-evil-surround-h ()
|
||||||
|
(with-eval-after-load 'evil-surround
|
||||||
|
(push '(?Q . ("''" . "''"))
|
||||||
|
evil-surround-pairs-alist)))))
|
||||||
|
|
||||||
|
(use-package nix-ts-mode
|
||||||
|
:mode "\\.nix\\'"
|
||||||
|
:config
|
||||||
|
(require 'nix-mode)
|
||||||
|
(general-def
|
||||||
|
:keymaps 'nix-ts-mode-map
|
||||||
|
:states '(visual operator)
|
||||||
|
"ad" #'syd-nix-obj-outer-binding)
|
||||||
|
(syd-add-hook 'nix-ts-mode-hook
|
||||||
|
(defun syd-nix-set-syntax-table-h ()
|
||||||
|
"Set the syntax table in `nix-ts-mode' buffers to `nix-mode-syntax-table'."
|
||||||
|
(set-syntax-table nix-mode-syntax-table))))
|
||||||
|
|
||||||
|
(provide 'syd-lang-nix)
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
;;; syd-lang-sql.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(with-eval-after-load 'sql
|
||||||
|
(add-hook 'sql-interactive-mode-hook #'syd-repl-mode))
|
||||||
|
|
||||||
|
(provide 'syd-lang-sql)
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
;;; syd-age.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(use-package age
|
||||||
|
:hook (on-first-file . age-file-enable)
|
||||||
|
:custom
|
||||||
|
;; We use rage over age, as the former supports pinentry.
|
||||||
|
((age-program "rage")
|
||||||
|
(age-default-identity (expand-file-name "~/private-keys/age/crumb.age"))
|
||||||
|
(age-default-recipient (expand-file-name "~/public-keys/age/crumb.pub"))))
|
||||||
|
|
||||||
|
(provide 'syd-age)
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
;;; syd-autosave.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(require 'syd-prelude)
|
||||||
|
|
||||||
|
(setq backup-directory-alist
|
||||||
|
`(("." . ,(file-name-concat syd-data-dir "backup")))
|
||||||
|
auto-save-list-file-prefix (let ((dir (file-name-concat syd-cache-dir
|
||||||
|
"autosave/")))
|
||||||
|
(make-directory dir t)
|
||||||
|
dir)
|
||||||
|
;; Nil means untracked files under VC won't get backed up.
|
||||||
|
vc-make-backup-files t
|
||||||
|
;; Nil will clobber symlinks.
|
||||||
|
backup-by-copying t
|
||||||
|
;; Use versioned backups.
|
||||||
|
version-control t
|
||||||
|
;; Don't create ugly lockfiles. See
|
||||||
|
;; https://www.gnu.org/software/emacs/manual/html_node/emacs/Interlocking.html#Interlocking
|
||||||
|
;; This is a good feature, but not very relevant to a single-user system.
|
||||||
|
create-lockfiles nil
|
||||||
|
auto-save-file-name-transforms
|
||||||
|
;; Good grief, girl...
|
||||||
|
`(("\\`/[^/]*:\\([^/]*/\\)*\\([^/]*\\)\\'"
|
||||||
|
,(concat auto-save-list-file-prefix "tramp-\\2") t)
|
||||||
|
(".*"
|
||||||
|
,(file-name-concat syd-cache-dir "autosave") t))
|
||||||
|
kept-new-versions 5
|
||||||
|
delete-old-versions t)
|
||||||
|
|
||||||
|
;; Save your cursor position in recently-opened files.
|
||||||
|
(use-package saveplace
|
||||||
|
:hook (on-first-file-hook . save-place-mode)
|
||||||
|
:custom (save-place-file (file-name-concat syd-cache-dir "places")))
|
||||||
|
|
||||||
|
;; Keep track of recently-visited files.
|
||||||
|
(use-package recentf
|
||||||
|
:hook ((on-first-file-hook . recentf-mode)
|
||||||
|
(find-file-hook . recentf-save-list))
|
||||||
|
:custom (recentf-save-file (file-name-concat syd-data-dir "recentf")))
|
||||||
|
|
||||||
|
(use-package savehist
|
||||||
|
:defer-incrementally custom
|
||||||
|
:hook (on-first-input-hook . savehist-mode)
|
||||||
|
:custom (savehist-file (file-name-concat syd-cache-dir "savehist"))
|
||||||
|
:config
|
||||||
|
(setq savehist-save-minibuffer-history t
|
||||||
|
savehist-autosave-interval nil ; save on kill only
|
||||||
|
savehist-additional-variables
|
||||||
|
'(kill-ring ; persist clipboard
|
||||||
|
register-alist ; persist macros
|
||||||
|
mark-ring global-mark-ring ; persist marks
|
||||||
|
search-ring regexp-search-ring)) ; persist searches
|
||||||
|
(syd-add-hook 'savehist-save-hook
|
||||||
|
(defun syd--savehist-unpropertize-variables-h ()
|
||||||
|
"Remove text properties from `kill-ring' to reduce savehist cache size."
|
||||||
|
(setq kill-ring
|
||||||
|
(mapcar #'substring-no-properties
|
||||||
|
(cl-remove-if-not #'stringp kill-ring))
|
||||||
|
register-alist
|
||||||
|
(cl-loop for (reg . item) in register-alist
|
||||||
|
if (stringp item)
|
||||||
|
collect (cons reg (substring-no-properties item))
|
||||||
|
else collect (cons reg item))))
|
||||||
|
(defun syd--savehist-remove-unprintable-registers-h ()
|
||||||
|
"Remove unwriteable registers (e.g. containing window configurations).
|
||||||
|
Otherwise, `savehist' would discard `register-alist' entirely if we don't omit
|
||||||
|
the unwritable tidbits."
|
||||||
|
;; Save new value in the temp buffer savehist is running
|
||||||
|
;; `savehist-save-hook' in. We don't want to actually remove the
|
||||||
|
;; unserializable registers in the current session!
|
||||||
|
(setq-local register-alist
|
||||||
|
(cl-remove-if-not #'savehist-printable register-alist)))))
|
||||||
|
|
||||||
|
;; Stay out of my config dir!
|
||||||
|
(setq bookmark-default-file
|
||||||
|
(file-name-concat syd-data-dir "bookmarks")
|
||||||
|
transient-history-file
|
||||||
|
(file-name-concat syd-data-dir "transient/history.el"))
|
||||||
|
|
||||||
|
|
||||||
|
(provide 'syd-autosave)
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
;;; syd-completion.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(use-package emacs
|
||||||
|
:custom
|
||||||
|
;; Allow the opening of new minibuffers from inside existing minibuffers.
|
||||||
|
((enable-recursive-minibuffers t)
|
||||||
|
;; Hide commands in M-x which do not work in the current mode.
|
||||||
|
(read-extended-command-predicate #'command-completion-default-include-p))
|
||||||
|
:config
|
||||||
|
;; Disable blinking cursor. Aesthetically, I personally don't fancy it;
|
||||||
|
;; technically, it doesn't play well with `evil-terminal-cursor-changer'.
|
||||||
|
(blink-cursor-mode -1))
|
||||||
|
|
||||||
|
;; Consult adds various search and navigation tools using Emacs' completing-read
|
||||||
|
;; function; i.e., in our case, Vertico.
|
||||||
|
(use-package consult
|
||||||
|
:defer t
|
||||||
|
:config
|
||||||
|
(advice-add #'consult-recent-file
|
||||||
|
:before #'syd-enable-recentf-mode-a))
|
||||||
|
|
||||||
|
(use-package embark-consult
|
||||||
|
:after (embark consult))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun syd-vertico-embark-preview ()
|
||||||
|
"Previews candidate in vertico buffer, unless it's a consult command"
|
||||||
|
(interactive)
|
||||||
|
(unless (bound-and-true-p consult--preview-function)
|
||||||
|
(if (fboundp 'embark-dwim)
|
||||||
|
(save-selected-window
|
||||||
|
(let (embark-quit-after-action)
|
||||||
|
(embark-dwim)))
|
||||||
|
(user-error "Embark not installed, aborting..."))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun syd-enable-recentf-mode-a ()
|
||||||
|
"Used as :before advice for `consult-recent-file' to ensure recentf mode is
|
||||||
|
enabled."
|
||||||
|
;; REVIEW: Shall we take any extra precautions to only enable `recentf-mode'
|
||||||
|
;; if it was going to be enabled anyway?
|
||||||
|
(recentf-mode 1))
|
||||||
|
|
||||||
|
;; Vertico is a simple completion engine that replaces Emacs' built-in
|
||||||
|
;; completion engine, achieving Just Works™ compatibility. This is in contrast
|
||||||
|
;; to e.g. Helm and Ivy, which spawn ecosystems orthogonal to Emacs, and
|
||||||
|
;; diametrically-opposed to each other.
|
||||||
|
(use-package vertico
|
||||||
|
:hook (on-first-input . vertico-mode)
|
||||||
|
:general
|
||||||
|
(:keymaps 'vertico-map
|
||||||
|
"DEL" #'vertico-directory-delete-char
|
||||||
|
"C-SPC" #'syd-vertico-embark-preview
|
||||||
|
"C-j" #'vertico-next
|
||||||
|
"C-k" #'vertico-previous
|
||||||
|
"C-M-j" #'vertico-next-group
|
||||||
|
"C-M-k" #'vertico-previous-group)
|
||||||
|
(:keymaps 'vertico-map
|
||||||
|
:states 'normal
|
||||||
|
"j" #'vertico-next
|
||||||
|
"k" #'vertico-previous
|
||||||
|
"RET" #'vertico-exit)
|
||||||
|
:custom ((vertico-resize nil)
|
||||||
|
(vertico-count 17)
|
||||||
|
(vertico-cycle t))
|
||||||
|
:config
|
||||||
|
(setq-default completion-in-region-function #'consult-completion-in-region)
|
||||||
|
;; Cleans up path when moving directories with shadowed paths syntax, e.g.
|
||||||
|
;; cleans ~/foo/bar/// to /, and ~/foo/bar/~/ to ~/.
|
||||||
|
(add-hook 'rfn-eshadow-update-overlay-hook #'vertico-directory-tidy))
|
||||||
|
|
||||||
|
(defun syd-vertico-orderless-dispatch (pattern _index _total)
|
||||||
|
"Like `orderless-affix-dispatch', but allows affixes to be escaped.
|
||||||
|
|
||||||
|
Shamelessly stolen from Doom. }:3"
|
||||||
|
(let ((len (length pattern))
|
||||||
|
(alist orderless-affix-dispatch-alist))
|
||||||
|
(when (> len 0)
|
||||||
|
(cond
|
||||||
|
;; Ignore single dispatcher character
|
||||||
|
((and (= len 1) (alist-get (aref pattern 0) alist)) #'ignore)
|
||||||
|
;; Prefix
|
||||||
|
((when-let ((style (alist-get (aref pattern 0) alist))
|
||||||
|
((not (char-equal (aref pattern (max (1- len) 1)) ?\\))))
|
||||||
|
(cons style (substring pattern 1))))
|
||||||
|
;; Suffix
|
||||||
|
((when-let ((style (alist-get (aref pattern (1- len)) alist))
|
||||||
|
((not (char-equal (aref pattern (max 0 (- len 2))) ?\\))))
|
||||||
|
(cons style (substring pattern 0 -1))))))))
|
||||||
|
|
||||||
|
;; Orderless provides a completion style that divides the pattern into
|
||||||
|
;; space-separated components, and matches candidates that match all of the
|
||||||
|
;; components in any order. Each component can match in any one of several
|
||||||
|
;; ways: literally, as a regexp, as an initialism, in the flex style, or as
|
||||||
|
;; multiple word prefixes. By default, regexp and literal matches are enabled.
|
||||||
|
(use-package orderless
|
||||||
|
:after vertico
|
||||||
|
:custom ((completion-styles '(orderless basic))
|
||||||
|
(completion-category-overrides
|
||||||
|
'((file
|
||||||
|
(styles ;basic-remote
|
||||||
|
orderless partial-completion))))
|
||||||
|
(orderless-style-dispatchers '(syd-vertico-orderless-dispatch))
|
||||||
|
;; TODO: See Doom's `+vertico-orderless-dispatch'.
|
||||||
|
(orderless-affix-dispatch-alist
|
||||||
|
'((?! . orderless-without-literal)
|
||||||
|
(?& . orderless-annotation)
|
||||||
|
;; %1 -> {1, ₁, ꘡, ⒈, ...}
|
||||||
|
(?% . char-fold-to-regexp)
|
||||||
|
;; ,wcb -> {with-current-buffer, widget-convert-button, ...}
|
||||||
|
(?, . orderless-initialism)
|
||||||
|
(?= . orderless-literal)
|
||||||
|
(?^ . orderless-literal-prefix)
|
||||||
|
(?~ . orderless-flex)))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun embark-which-key-indicator ()
|
||||||
|
"An embark indicator that displays keymaps using which-key. The which-key
|
||||||
|
help message will show the type and value of the current target followed by an
|
||||||
|
ellipsis if there are further targets."
|
||||||
|
(lambda (&optional keymap targets prefix)
|
||||||
|
(if (null keymap)
|
||||||
|
(which-key--hide-popup-ignore-command)
|
||||||
|
(which-key--show-keymap
|
||||||
|
(if (eq (plist-get (car targets) :type) 'embark-become)
|
||||||
|
"Become"
|
||||||
|
(format "Act on %s '%s'%s"
|
||||||
|
(plist-get (car targets) :type)
|
||||||
|
(embark--truncate-target (plist-get (car targets) :target))
|
||||||
|
(if (cdr targets) "…" "")))
|
||||||
|
(if prefix
|
||||||
|
(pcase (lookup-key keymap prefix 'accept-default)
|
||||||
|
((and (pred keymapp) km) km)
|
||||||
|
(_ (key-binding prefix 'accept-default)))
|
||||||
|
keymap)
|
||||||
|
nil nil t (lambda (binding)
|
||||||
|
(not (string-suffix-p "-argument" (cdr binding))))))))
|
||||||
|
|
||||||
|
;; TODO: Mark the Embark export buffer as a popup.
|
||||||
|
(use-package embark
|
||||||
|
:after vertico
|
||||||
|
:defer t
|
||||||
|
:custom ((which-key-use-C-h-commands nil)
|
||||||
|
(prefix-help-command #'embark-prefix-help-command)
|
||||||
|
;; Embark uses their own custom interface that is essentially
|
||||||
|
;; equivalent to which-key; just use which-key. }:)
|
||||||
|
(embark-indicators '(embark-which-key-indicator)))
|
||||||
|
:general
|
||||||
|
(:keymaps 'minibuffer-local-map
|
||||||
|
"C-;" `("Actions" . ,#'embark-act))
|
||||||
|
(:keymaps 'syd-leader-map
|
||||||
|
"a" `("Actions" . ,#'embark-act)))
|
||||||
|
|
||||||
|
(provide 'syd-completion)
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
;;; syd-custom.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
;; To discourage use of the custom file, we store it somewhere will
|
||||||
|
;; Impermanence will wipe it.
|
||||||
|
(use-package emacs
|
||||||
|
;; TODO: I'd like to allow /some/ custom variables. E.g., the trusted
|
||||||
|
;; dir-locals files. See `hack-dir-local-variables'. It has some hooks that
|
||||||
|
;; should make this accomplishable.
|
||||||
|
:custom (custom-file (file-name-concat syd-data-dir "custom.el"))
|
||||||
|
:config
|
||||||
|
(when (file-readable-p custom-file)
|
||||||
|
(load custom-file)))
|
||||||
|
|
||||||
|
(provide 'syd-custom)
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
;;; syd-dired.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(defun syd-dired-here ()
|
||||||
|
(interactive)
|
||||||
|
(dired default-directory))
|
||||||
|
|
||||||
|
(defun syd-dired-goto-file (file)
|
||||||
|
"Like `dired-goto-file', but will act as `find-file' if FILE is inside another
|
||||||
|
directory."
|
||||||
|
(interactive
|
||||||
|
(prog1 (let ((dir (dired-current-directory)))
|
||||||
|
(list (directory-file-name
|
||||||
|
(file-relative-name
|
||||||
|
(read-file-name "Goto file: " dir)
|
||||||
|
dir))))
|
||||||
|
;; let push-mark display its message
|
||||||
|
(push-mark))
|
||||||
|
dired-mode)
|
||||||
|
(if (file-name-directory file)
|
||||||
|
(find-file file)
|
||||||
|
(dired-goto-file (expand-file-name file))))
|
||||||
|
|
||||||
|
(use-package dired
|
||||||
|
;; Built-in to Emacs.
|
||||||
|
:straight nil
|
||||||
|
:general
|
||||||
|
(:keymaps 'syd-leader-open-map
|
||||||
|
"-" #'syd-dired-here)
|
||||||
|
(:keymaps 'syd-leader-project-map
|
||||||
|
"-" #'project-dired)
|
||||||
|
(:keymaps 'dired-mode-map
|
||||||
|
:states '(normal motion)
|
||||||
|
"g r" #'revert-buffer)
|
||||||
|
(:keymaps 'dired-mode-map
|
||||||
|
[remap dired-goto-file] #'syd-dired-goto-file)
|
||||||
|
:commands dired-jump
|
||||||
|
:custom (;; When there are other Dired windows open, suggest them as targets
|
||||||
|
;; for renaming/copying.
|
||||||
|
(dired-dwim-target t)
|
||||||
|
;; Don't prompt to revert, just do it.
|
||||||
|
(dired-auto-revert-buffer #'dired-buffer-stale-p)
|
||||||
|
(dired-listing-switches
|
||||||
|
(mapconcat
|
||||||
|
#'identity
|
||||||
|
'("-l" ; Mandatory!
|
||||||
|
"--almost-all" ; Show hidden files; omit '.' and '..'.
|
||||||
|
"--human-readable" ; Display sizes in human-readable units.
|
||||||
|
"--time-style=+") ; Omit times/dates.
|
||||||
|
" "))
|
||||||
|
;; Always copy recursively
|
||||||
|
(dired-recursive-copies 'always)
|
||||||
|
;; Prompt for confirmation for each top-level directory being
|
||||||
|
;; deleted.
|
||||||
|
(dired-recursive-deletes 'top)
|
||||||
|
(dired-create-destination-dirs 'ask)
|
||||||
|
(dired-create-destination-dirs-on-trailing-dirsep t)
|
||||||
|
;; Where to store image caches
|
||||||
|
(image-dired-dir (concat syd-cache-dir "image-dired/"))
|
||||||
|
(image-dired-db-file (concat image-dired-dir "db.el"))
|
||||||
|
(image-dired-gallery-dir (concat image-dired-dir "gallery/"))
|
||||||
|
(image-dired-temp-image-file (concat image-dired-dir "temp-image"))
|
||||||
|
(image-dired-temp-rotate-image-file (concat image-dired-dir "temp-rotate-image"))
|
||||||
|
;; Increase thumbnail sizes.
|
||||||
|
(image-dired-thumb-size 150))
|
||||||
|
:config
|
||||||
|
(set-popup-rule! "^\\*image-dired"
|
||||||
|
:slot 20 :size 0.8 :select t :quit nil :ttl 0)
|
||||||
|
|
||||||
|
;; On ESC, abort `wdired-mode' (will prompt)
|
||||||
|
(syd-add-hook 'syd-escape-hook
|
||||||
|
(defun syd-dired--wdired-exit-h ()
|
||||||
|
(when (eq major-mode 'wdired-mode)
|
||||||
|
(wdired-exit)
|
||||||
|
t))))
|
||||||
|
|
||||||
|
(use-package diredfl
|
||||||
|
:hook ((dired-mode . diredfl-mode)
|
||||||
|
(dirvish-directory-view-mode . diredfl-mode)))
|
||||||
|
|
||||||
|
(use-package dirvish
|
||||||
|
:custom ((dirvish-cache-dir (file-name-concat syd-cache-dir "dirvish/"))
|
||||||
|
(dirvish-reuse-session 'open)
|
||||||
|
(dirvish-default-layout '(0 0.4 0.6))
|
||||||
|
(dirvish-hide-details '(dirvish dirvish-fd dirvish-side)))
|
||||||
|
:general
|
||||||
|
(:keymaps 'dired-mode-map
|
||||||
|
"<tab>" #'dirvish-subtree-toggle
|
||||||
|
"TAB" #'dirvish-subtree-toggle)
|
||||||
|
:init
|
||||||
|
;; Ugh… I'm fairly certain this leads to eager loading of the entire package.
|
||||||
|
(dirvish-override-dired-mode 1)
|
||||||
|
:config
|
||||||
|
;; Fix random void-variable errors.
|
||||||
|
(require 'autorevert))
|
||||||
|
|
||||||
|
(provide 'syd-dired)
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
;;; syd-display-startup-time.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(defun syd-display-startup-time ()
|
||||||
|
(message "Emacs loaded in %s with %d garbage collections."
|
||||||
|
(format "%.3f seconds"
|
||||||
|
(float-time
|
||||||
|
(time-subtract after-init-time before-init-time)))
|
||||||
|
gcs-done))
|
||||||
|
|
||||||
|
(use-package emacs
|
||||||
|
:hook
|
||||||
|
(emacs-startup-hook . syd-display-startup-time))
|
||||||
|
|
||||||
|
(provide 'syd-display-startup-time)
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
;;; syd-ediff.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(require 'syd-prelude)
|
||||||
|
|
||||||
|
(with-eval-after-load 'ediff
|
||||||
|
(setq ediff-diff-options "-w" ; Ignore whitespace
|
||||||
|
ediff-window-setup-function #'ediff-setup-windows-plain)
|
||||||
|
(defvar syd--ediff-saved-wconf nil)
|
||||||
|
|
||||||
|
;; Restore window config after quitting Ediff.
|
||||||
|
(syd-add-hook 'ediff-before-setup-hook
|
||||||
|
(defun syd--ediff-save-wconf-h ()
|
||||||
|
(setq syd--ediff-saved-wconf (current-window-configuration))))
|
||||||
|
(syd-add-hook '(ediff-quit-hook ediff-suspend-hook)
|
||||||
|
(defun syd--ediff-restore-wconf-h ()
|
||||||
|
(when (window-configuration-p syd--ediff-saved-wconf)
|
||||||
|
(set-window-configuration syd--ediff-saved-wconf)))))
|
||||||
|
|
||||||
|
(provide 'syd-ediff)
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
;;; syd-editing.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(use-package emacs
|
||||||
|
:hook ((on-init-ui-hook . whitespace-mode))
|
||||||
|
:custom ((fill-column 80)
|
||||||
|
(indent-tabs-mode nil)
|
||||||
|
(whitespace-style '(face tabs tab-mark))
|
||||||
|
;; Disable synchronization between the kill ring and clipboard.
|
||||||
|
(select-enable-clipboard nil)))
|
||||||
|
|
||||||
|
(provide 'syd-editing)
|
||||||
@@ -0,0 +1,418 @@
|
|||||||
|
;;; syd-eshell.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(require 'ring)
|
||||||
|
(require 'cl-lib)
|
||||||
|
|
||||||
|
(defvar eshell-buffer-name "*eshell*")
|
||||||
|
|
||||||
|
(defvar syd-eshell-buffers (make-ring 25)
|
||||||
|
"List of open eshell buffers.")
|
||||||
|
|
||||||
|
(defun syd-eshell-buffers ()
|
||||||
|
"TODO"
|
||||||
|
(ring-elements syd-eshell-buffers))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun syd-eshell-run-command (command &optional buffer)
|
||||||
|
"TODO"
|
||||||
|
(let ((buffer
|
||||||
|
(or buffer
|
||||||
|
(if (eq major-mode 'eshell-mode)
|
||||||
|
(current-buffer)
|
||||||
|
(cl-find-if #'buffer-live-p (syd-eshell-buffers))))))
|
||||||
|
(unless buffer
|
||||||
|
(user-error "No living eshell buffers available"))
|
||||||
|
(unless (buffer-live-p buffer)
|
||||||
|
(user-error "Cannot operate on a dead buffer"))
|
||||||
|
(with-current-buffer buffer
|
||||||
|
(goto-char eshell-last-output-end)
|
||||||
|
(goto-char (line-end-position))
|
||||||
|
(insert command)
|
||||||
|
(eshell-send-input nil t))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun syd-eshell/toggle (arg &optional command)
|
||||||
|
"Toggle eshell popup window."
|
||||||
|
(interactive "P")
|
||||||
|
(let ((eshell-buffer
|
||||||
|
(get-buffer-create
|
||||||
|
(format "*eshell-popup:%s*"
|
||||||
|
(if (bound-and-true-p persp-mode)
|
||||||
|
(safe-persp-name (get-current-persp))
|
||||||
|
"main"))))
|
||||||
|
confirm-kill-processes
|
||||||
|
current-prefix-arg)
|
||||||
|
(when arg
|
||||||
|
(when-let* ((win (get-buffer-window eshell-buffer)))
|
||||||
|
(delete-window win))
|
||||||
|
(when (buffer-live-p eshell-buffer)
|
||||||
|
(with-current-buffer eshell-buffer
|
||||||
|
(fundamental-mode)
|
||||||
|
(erase-buffer))))
|
||||||
|
(if-let* ((win (get-buffer-window eshell-buffer)))
|
||||||
|
(let (confirm-kill-processes)
|
||||||
|
(delete-window win)
|
||||||
|
(ignore-errors (kill-buffer eshell-buffer)))
|
||||||
|
(with-current-buffer eshell-buffer
|
||||||
|
(syd-mark-buffer-as-real)
|
||||||
|
(if (eq major-mode 'eshell-mode)
|
||||||
|
(run-hooks 'eshell-mode-hook)
|
||||||
|
(eshell-mode))
|
||||||
|
(when command
|
||||||
|
(syd-eshell-run-command command eshell-buffer)))
|
||||||
|
(pop-to-buffer eshell-buffer)
|
||||||
|
(when (bound-and-true-p evil-mode)
|
||||||
|
(call-interactively #'evil-append-line)))))
|
||||||
|
|
||||||
|
(defun syd-eshell-adapt-bash-aliases ()
|
||||||
|
"Very sloppily convert aliases defined in Bash to an Eshell alias file."
|
||||||
|
(interactive)
|
||||||
|
(save-window-excursion
|
||||||
|
(let ((err-buf (generate-new-buffer "*adapt-bash-aliases-err*"))
|
||||||
|
(result-buf (generate-new-buffer "*adapted-bash-aliases*")))
|
||||||
|
(with-current-buffer result-buf
|
||||||
|
(insert "# Automatically generated by syd-eshell-adapt-bash-aliases\n"))
|
||||||
|
(with-temp-buffer
|
||||||
|
;; Aliases are only loaded when bash is in interactive mode.
|
||||||
|
(shell-command "bash -ic alias" (current-buffer) err-buf)
|
||||||
|
(goto-char (point-min))
|
||||||
|
(while (re-search-forward
|
||||||
|
(rx bol "alias " (group (+ alphanumeric)) "='"
|
||||||
|
(group (* (not ?\'))) "'")
|
||||||
|
nil t)
|
||||||
|
(let ((eshell-alias (format "alias %s %s $*\n"
|
||||||
|
(match-string 1)
|
||||||
|
(match-string 2))))
|
||||||
|
(with-current-buffer result-buf
|
||||||
|
(insert eshell-alias)))))
|
||||||
|
(unless (= 0 (buffer-size err-buf))
|
||||||
|
(message "Some errors occured whilst fetching Bash's aliases:")
|
||||||
|
(message (with-current-buffer err-buf (buffer-string))))
|
||||||
|
(kill-buffer err-buf)
|
||||||
|
result-buf)))
|
||||||
|
|
||||||
|
(defun syd-eshell-C-d ()
|
||||||
|
"Imitate the typical 'C-d' behaviour in other shells. Quits Eshell when the input is empty."
|
||||||
|
(interactive)
|
||||||
|
(when (and (eolp) (looking-back eshell-prompt-regexp nil))
|
||||||
|
(eshell-life-is-too-much)))
|
||||||
|
|
||||||
|
(defun syd-eshell--init-ui-hacks ()
|
||||||
|
(defun syd-eshell-remove-fringes-h ()
|
||||||
|
(set-window-fringes nil 0 0)
|
||||||
|
(set-window-margins nil 1 nil))
|
||||||
|
(defun syd-eshell-enable-text-wrapping-h ()
|
||||||
|
(visual-line-mode +1)
|
||||||
|
(set-display-table-slot standard-display-table 0 ?\ ))
|
||||||
|
(add-hook 'eshell-mode-hook #'syd-eshell-remove-fringes-h)
|
||||||
|
(add-hook 'eshell-mode-hook #'syd-eshell-enable-text-wrapping-h)
|
||||||
|
|
||||||
|
(with-eval-after-load 'hide-mode-line
|
||||||
|
(add-hook 'eshell-mode-hook #'hide-mode-line-mode))
|
||||||
|
|
||||||
|
;; Remove hscroll-margin in shells, otherwise you get jumpiness when the
|
||||||
|
;; cursor comes close to the left/right edges of the window.
|
||||||
|
(defun syd-eshell-disable-hscroll-margin ()
|
||||||
|
(setq hscroll-margin 0))
|
||||||
|
(add-hook 'eshell-mode-hook #'syd-eshell-disable-hscroll-margin))
|
||||||
|
|
||||||
|
(use-package shrink-path
|
||||||
|
:defer t)
|
||||||
|
|
||||||
|
(defface syd-eshell-local-name '((t (:inherit font-lock-constant-face)))
|
||||||
|
"Face used by the Eshell prompt for the CWD's non-TRAMP part. See
|
||||||
|
`syd-eshell--prompt-fn'"
|
||||||
|
:group 'eshell)
|
||||||
|
|
||||||
|
(defface syd-eshell-tramp-prefix '((t (:inherit font-lock-comment-face)))
|
||||||
|
"Face used by the Eshell prompt for the CWD's TRAMP prefix. See
|
||||||
|
`syd-eshell--prompt-fn'."
|
||||||
|
:group 'eshell)
|
||||||
|
|
||||||
|
(defun syd-eshell--prompt-fn ()
|
||||||
|
"See `eshell-prompt-function'."
|
||||||
|
(require 'shrink-path)
|
||||||
|
(require 'syd-file)
|
||||||
|
(-let (((tramp-prefix . local-name) (syd-split-tramp-file-name (eshell/pwd))))
|
||||||
|
(concat (unless (bobp) "\n")
|
||||||
|
(when tramp-prefix
|
||||||
|
(propertize tramp-prefix 'face 'syd-eshell-tramp-prefix))
|
||||||
|
(propertize (if (equal local-name "~")
|
||||||
|
local-name
|
||||||
|
(abbreviate-file-name (shrink-path-file local-name)))
|
||||||
|
'face 'syd-eshell-local-name)
|
||||||
|
(propertize " $"
|
||||||
|
'face (if (zerop eshell-last-command-status)
|
||||||
|
'success
|
||||||
|
'error))
|
||||||
|
" ")))
|
||||||
|
|
||||||
|
(defvar syd-eshell--prompt-regexp (rx bol (* (not (any "\n$"))) " $ "))
|
||||||
|
|
||||||
|
(set-popup-rule! "^\\*eshell-popup"
|
||||||
|
:vslot -5 :size 13 :select t :modeline nil :quit nil :ttl nil)
|
||||||
|
|
||||||
|
(use-package eshell
|
||||||
|
:init
|
||||||
|
(defvar syd-eshell-data-dir (file-name-concat syd-data-dir
|
||||||
|
"eshell"))
|
||||||
|
(make-directory syd-eshell-data-dir t)
|
||||||
|
:custom
|
||||||
|
((eshell-banner-message
|
||||||
|
'(format "🦌 %s %s }:3\n"
|
||||||
|
(propertize (format " %s " (string-trim (buffer-name)))
|
||||||
|
'face 'mode-line-highlight)
|
||||||
|
(propertize (current-time-string)
|
||||||
|
'face 'font-lock-keyword-face)))
|
||||||
|
(eshell-scroll-to-bottom-on-input 'all)
|
||||||
|
(eshell-scroll-to-bottom-on-output nil)
|
||||||
|
(eshell-kill-processes-on-exit t)
|
||||||
|
(eshell-hist-ignoredups t)
|
||||||
|
(eshell-glob-case-insensitive t)
|
||||||
|
(eshell-error-if-no-glob t)
|
||||||
|
(eshell-history-file-name (file-name-concat
|
||||||
|
syd-eshell-data-dir "history"))
|
||||||
|
(eshell-last-dir-ring-file-name (file-name-concat
|
||||||
|
syd-eshell-data-dir "lastdir"))
|
||||||
|
(eshell-prompt-function #'syd-eshell--prompt-fn)
|
||||||
|
(eshell-prompt-regexp syd-eshell--prompt-regexp))
|
||||||
|
:general
|
||||||
|
(:keymaps 'syd-leader-open-map
|
||||||
|
"e" #'syd-eshell/toggle)
|
||||||
|
(:keymaps 'eshell-mode-map
|
||||||
|
:states 'insert
|
||||||
|
"C-d" #'syd-eshell-C-d)
|
||||||
|
(:keymaps 'eshell-mode-map
|
||||||
|
:states 'motion
|
||||||
|
"[ [" #'eshell-previous-prompt
|
||||||
|
"] ]" #'eshell-next-prompt)
|
||||||
|
(:keymaps 'eshell-mode-map
|
||||||
|
:states '(normal insert)
|
||||||
|
"C-j" #'eshell-next-matching-input-from-input
|
||||||
|
"C-k" #'eshell-previous-matching-input-from-input
|
||||||
|
"C-s" #'consult-history)
|
||||||
|
:config
|
||||||
|
;; When cd'd into a TRAMP remote, automatically expand '/' to the TRAMP
|
||||||
|
;; notation referring to the remote's root.
|
||||||
|
(add-to-list 'eshell-modules-list 'eshell-elecslash)
|
||||||
|
|
||||||
|
(require 'syd-buffers)
|
||||||
|
|
||||||
|
(add-hook 'eshell-mode-hook #'syd-mark-buffer-as-real)
|
||||||
|
|
||||||
|
;; UI enhancements.
|
||||||
|
(syd-eshell--init-ui-hacks))
|
||||||
|
|
||||||
|
(provide 'syd-eshell)
|
||||||
|
;;; syd-eshell.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(require 'ring)
|
||||||
|
(require 'cl-lib)
|
||||||
|
|
||||||
|
(defvar eshell-buffer-name "*eshell*")
|
||||||
|
|
||||||
|
(defvar syd-eshell-buffers (make-ring 25)
|
||||||
|
"List of open eshell buffers.")
|
||||||
|
|
||||||
|
(defun syd-eshell-buffers ()
|
||||||
|
"TODO"
|
||||||
|
(ring-elements syd-eshell-buffers))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun syd-eshell-run-command (command &optional buffer)
|
||||||
|
"TODO"
|
||||||
|
(let ((buffer
|
||||||
|
(or buffer
|
||||||
|
(if (eq major-mode 'eshell-mode)
|
||||||
|
(current-buffer)
|
||||||
|
(cl-find-if #'buffer-live-p (syd-eshell-buffers))))))
|
||||||
|
(unless buffer
|
||||||
|
(user-error "No living eshell buffers available"))
|
||||||
|
(unless (buffer-live-p buffer)
|
||||||
|
(user-error "Cannot operate on a dead buffer"))
|
||||||
|
(with-current-buffer buffer
|
||||||
|
(goto-char eshell-last-output-end)
|
||||||
|
(goto-char (line-end-position))
|
||||||
|
(insert command)
|
||||||
|
(eshell-send-input nil t))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun syd-eshell/toggle (arg &optional command)
|
||||||
|
"Toggle eshell popup window."
|
||||||
|
(interactive "P")
|
||||||
|
(let ((eshell-buffer
|
||||||
|
(get-buffer-create
|
||||||
|
(format "*eshell-popup:%s*"
|
||||||
|
(if (bound-and-true-p persp-mode)
|
||||||
|
(safe-persp-name (get-current-persp))
|
||||||
|
"main"))))
|
||||||
|
confirm-kill-processes
|
||||||
|
current-prefix-arg)
|
||||||
|
(when arg
|
||||||
|
(when-let* ((win (get-buffer-window eshell-buffer)))
|
||||||
|
(delete-window win))
|
||||||
|
(when (buffer-live-p eshell-buffer)
|
||||||
|
(with-current-buffer eshell-buffer
|
||||||
|
(fundamental-mode)
|
||||||
|
(erase-buffer))))
|
||||||
|
(if-let* ((win (get-buffer-window eshell-buffer)))
|
||||||
|
(let (confirm-kill-processes)
|
||||||
|
(delete-window win)
|
||||||
|
(ignore-errors (kill-buffer eshell-buffer)))
|
||||||
|
(with-current-buffer eshell-buffer
|
||||||
|
(syd-mark-buffer-as-real)
|
||||||
|
(if (eq major-mode 'eshell-mode)
|
||||||
|
(run-hooks 'eshell-mode-hook)
|
||||||
|
(eshell-mode))
|
||||||
|
(when command
|
||||||
|
(syd-eshell-run-command command eshell-buffer)))
|
||||||
|
(pop-to-buffer eshell-buffer)
|
||||||
|
(when (bound-and-true-p evil-mode)
|
||||||
|
(call-interactively #'evil-append-line)))))
|
||||||
|
|
||||||
|
(defun syd-eshell (&optional arg)
|
||||||
|
(interactive "P")
|
||||||
|
(eshell (or arg t)))
|
||||||
|
|
||||||
|
(defun syd-eshell-adapt-bash-aliases ()
|
||||||
|
"Very sloppily convert aliases defined in Bash to an Eshell alias file."
|
||||||
|
(interactive)
|
||||||
|
(save-window-excursion
|
||||||
|
(let ((err-buf (generate-new-buffer "*adapt-bash-aliases-err*"))
|
||||||
|
(result-buf (generate-new-buffer "*adapted-bash-aliases*")))
|
||||||
|
(with-current-buffer result-buf
|
||||||
|
(insert "# Automatically generated by syd-eshell-adapt-bash-aliases\n"))
|
||||||
|
(with-temp-buffer
|
||||||
|
;; Aliases are only loaded when bash is in interactive mode.
|
||||||
|
(shell-command "bash -ic alias" (current-buffer) err-buf)
|
||||||
|
(goto-char (point-min))
|
||||||
|
(while (re-search-forward
|
||||||
|
(rx bol "alias " (group (+ alphanumeric)) "='"
|
||||||
|
(group (* (not ?\'))) "'")
|
||||||
|
nil t)
|
||||||
|
(let ((eshell-alias (format "alias %s %s $*\n"
|
||||||
|
(match-string 1)
|
||||||
|
(match-string 2))))
|
||||||
|
(with-current-buffer result-buf
|
||||||
|
(insert eshell-alias)))))
|
||||||
|
(unless (= 0 (buffer-size err-buf))
|
||||||
|
(message "Some errors occured whilst fetching Bash's aliases:")
|
||||||
|
(message (with-current-buffer err-buf (buffer-string))))
|
||||||
|
(kill-buffer err-buf)
|
||||||
|
result-buf)))
|
||||||
|
|
||||||
|
(defun syd-eshell-C-d ()
|
||||||
|
"Imitate the typical 'C-d' behaviour in other shells. Quits Eshell when the input is empty."
|
||||||
|
(interactive)
|
||||||
|
(when (and (eolp) (looking-back eshell-prompt-regexp nil))
|
||||||
|
(eshell-life-is-too-much)))
|
||||||
|
|
||||||
|
(defun syd-eshell--init-ui-hacks ()
|
||||||
|
(defun syd-eshell-remove-fringes-h ()
|
||||||
|
(set-window-fringes nil 0 0)
|
||||||
|
(set-window-margins nil 1 nil))
|
||||||
|
(defun syd-eshell-enable-text-wrapping-h ()
|
||||||
|
(visual-line-mode +1)
|
||||||
|
(set-display-table-slot standard-display-table 0 ?\ ))
|
||||||
|
(add-hook 'eshell-mode-hook #'syd-eshell-remove-fringes-h)
|
||||||
|
(add-hook 'eshell-mode-hook #'syd-eshell-enable-text-wrapping-h)
|
||||||
|
|
||||||
|
(with-eval-after-load 'hide-mode-line
|
||||||
|
(add-hook 'eshell-mode-hook #'hide-mode-line-mode))
|
||||||
|
|
||||||
|
;; Remove hscroll-margin in shells, otherwise you get jumpiness when the
|
||||||
|
;; cursor comes close to the left/right edges of the window.
|
||||||
|
(defun syd-eshell-disable-hscroll-margin ()
|
||||||
|
(setq hscroll-margin 0))
|
||||||
|
(add-hook 'eshell-mode-hook #'syd-eshell-disable-hscroll-margin))
|
||||||
|
|
||||||
|
(use-package shrink-path
|
||||||
|
:defer t)
|
||||||
|
|
||||||
|
(defface syd-eshell-local-name '((t (:inherit font-lock-constant-face)))
|
||||||
|
"Face used by the Eshell prompt for the CWD's non-TRAMP part. See
|
||||||
|
`syd-eshell--prompt-fn'"
|
||||||
|
:group 'eshell)
|
||||||
|
|
||||||
|
(defface syd-eshell-tramp-prefix '((t (:inherit font-lock-comment-face)))
|
||||||
|
"Face used by the Eshell prompt for the CWD's TRAMP prefix. See
|
||||||
|
`syd-eshell--prompt-fn'."
|
||||||
|
:group 'eshell)
|
||||||
|
|
||||||
|
(defun syd-eshell--prompt-fn ()
|
||||||
|
"See `eshell-prompt-function'."
|
||||||
|
(require 'shrink-path)
|
||||||
|
(require 'syd-file)
|
||||||
|
(-let (((tramp-prefix . local-name) (syd-split-tramp-file-name (eshell/pwd))))
|
||||||
|
(concat (unless (bobp) "\n")
|
||||||
|
(when tramp-prefix
|
||||||
|
(propertize tramp-prefix 'face 'syd-eshell-tramp-prefix))
|
||||||
|
(propertize (if (equal local-name "~")
|
||||||
|
local-name
|
||||||
|
(abbreviate-file-name (shrink-path-file local-name)))
|
||||||
|
'face 'syd-eshell-local-name)
|
||||||
|
(propertize " $"
|
||||||
|
'face (if (zerop eshell-last-command-status)
|
||||||
|
'success
|
||||||
|
'error))
|
||||||
|
" ")))
|
||||||
|
|
||||||
|
(defvar syd-eshell--prompt-regexp (rx bol (* (not (any "\n$"))) " $ "))
|
||||||
|
|
||||||
|
(set-popup-rule! "^\\*eshell-popup"
|
||||||
|
:vslot -5 :size 13 :select t :modeline nil :quit nil :ttl nil)
|
||||||
|
|
||||||
|
(use-package eshell
|
||||||
|
:init
|
||||||
|
(defvar syd-eshell-data-dir (file-name-concat syd-data-dir
|
||||||
|
"eshell"))
|
||||||
|
(make-directory syd-eshell-data-dir t)
|
||||||
|
:custom
|
||||||
|
((eshell-banner-message
|
||||||
|
'(format "🦌 %s %s }:3\n"
|
||||||
|
(propertize (format " %s " (string-trim (buffer-name)))
|
||||||
|
'face 'mode-line-highlight)
|
||||||
|
(propertize (current-time-string)
|
||||||
|
'face 'font-lock-keyword-face)))
|
||||||
|
(eshell-scroll-to-bottom-on-input 'all)
|
||||||
|
(eshell-scroll-to-bottom-on-output nil)
|
||||||
|
(eshell-kill-processes-on-exit t)
|
||||||
|
(eshell-hist-ignoredups t)
|
||||||
|
(eshell-glob-case-insensitive t)
|
||||||
|
(eshell-error-if-no-glob t)
|
||||||
|
(eshell-history-file-name (file-name-concat
|
||||||
|
syd-eshell-data-dir "history"))
|
||||||
|
(eshell-last-dir-ring-file-name (file-name-concat
|
||||||
|
syd-eshell-data-dir "lastdir"))
|
||||||
|
(eshell-prompt-function #'syd-eshell--prompt-fn)
|
||||||
|
(eshell-prompt-regexp syd-eshell--prompt-regexp))
|
||||||
|
:general
|
||||||
|
(:keymaps 'syd-leader-open-map
|
||||||
|
"e" #'syd-eshell/toggle
|
||||||
|
"E" #'syd-eshell)
|
||||||
|
(:keymaps 'eshell-mode-map
|
||||||
|
:states 'insert
|
||||||
|
"C-d" #'syd-eshell-C-d)
|
||||||
|
(:keymaps 'eshell-mode-map
|
||||||
|
:states 'motion
|
||||||
|
"[ [" #'eshell-previous-prompt
|
||||||
|
"] ]" #'eshell-next-prompt)
|
||||||
|
(:keymaps 'eshell-mode-map
|
||||||
|
:states '(normal insert)
|
||||||
|
"C-j" #'eshell-next-matching-input-from-input
|
||||||
|
"C-k" #'eshell-previous-matching-input-from-input
|
||||||
|
"C-s" #'consult-history)
|
||||||
|
:config
|
||||||
|
;; When cd'd into a TRAMP remote, automatically expand '/' to the TRAMP
|
||||||
|
;; notation referring to the remote's root.
|
||||||
|
(add-to-list 'eshell-modules-list 'eshell-elecslash)
|
||||||
|
|
||||||
|
(require 'syd-buffers)
|
||||||
|
|
||||||
|
(add-hook 'eshell-mode-hook #'syd-mark-buffer-as-real)
|
||||||
|
|
||||||
|
;; UI enhancements.
|
||||||
|
(syd-eshell--init-ui-hacks))
|
||||||
|
|
||||||
|
(provide 'syd-eshell)
|
||||||
|
|
||||||
@@ -0,0 +1,365 @@
|
|||||||
|
;;; syd-evil.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
;; More sensible undo functionality. Emacs' default is very weird, not
|
||||||
|
;; maintaining a proper history.
|
||||||
|
(use-package undo-fu)
|
||||||
|
|
||||||
|
;; Vim emulation.
|
||||||
|
(use-package evil
|
||||||
|
:preface
|
||||||
|
(setq evil-want-minibuffer t
|
||||||
|
evil-move-beyond-eol t
|
||||||
|
evil-respect-visual-line-mode t
|
||||||
|
evil-vsplit-window-right t
|
||||||
|
evil-ex-search-vim-style-regexp t
|
||||||
|
evil-want-Y-yank-to-eol t
|
||||||
|
evil-want-C-u-scroll t
|
||||||
|
evil-want-C-w-in-emacs-state t
|
||||||
|
;; - If non-nil: When using ex commands on a visual selection, pass the
|
||||||
|
;; precise region selected to the command.
|
||||||
|
;; - If nil: Pass the region of /lines/ spanned by the visual selection.
|
||||||
|
evil-ex-visual-char-range t
|
||||||
|
evil-v$-excludes-newline t
|
||||||
|
;; Don't display the state in the mode line.
|
||||||
|
evil-mode-line-format nil
|
||||||
|
evil-normal-state-cursor 'box
|
||||||
|
evil-emacs-state-cursor 'hbar
|
||||||
|
evil-operator-state-cursor 'evil-half-cursor
|
||||||
|
evil-insert-state-cursor 'bar
|
||||||
|
evil-visual-state-cursor 'hollow
|
||||||
|
;; Only do highlighting in selected window so that Emacs has less work
|
||||||
|
;; to do highlighting them all.
|
||||||
|
evil-ex-interactive-search-highlight 'selected-window
|
||||||
|
;; It's infuriating that innocuous "beginning of line" or "end of line"
|
||||||
|
;; errors will abort macros, so we suppress them:
|
||||||
|
evil-kbd-macro-suppress-motion-error t
|
||||||
|
evil-undo-system (cond ((featurep 'undo-tree) 'undo-tree)
|
||||||
|
((featurep 'undo-fu) 'undo-fu)))
|
||||||
|
;; These two are required for evil-collection.
|
||||||
|
(setq evil-want-keybinding nil
|
||||||
|
evil-want-integration t)
|
||||||
|
|
||||||
|
:config
|
||||||
|
;; 'M-:' starts off in insert mode, yet the normal mode cursor lingers until a
|
||||||
|
;; refresh is forced. Quick fix! }:P
|
||||||
|
(add-hook 'minibuffer-setup-hook #'evil-refresh-cursor)
|
||||||
|
|
||||||
|
;; Unbind 'C-k'. Normally, it inserts digraphs; I have a compose key, and
|
||||||
|
;; it's strictly less useful than Emacs' native input methods. It often gets
|
||||||
|
;; in the way of buffers with navigation, e.g. scrolling through shell/REPL
|
||||||
|
;; history, navigating Vertico completions, etc.
|
||||||
|
(keymap-set evil-insert-state-map "C-k" nil)
|
||||||
|
|
||||||
|
;; In imitation of Vim's :mes[sages] command, define an Evil analogue to show
|
||||||
|
;; the echo area.
|
||||||
|
(defun syd-evil-messages ()
|
||||||
|
(interactive)
|
||||||
|
(view-echo-area-messages)
|
||||||
|
(with-current-buffer messages-buffer-name
|
||||||
|
(evil-motion-state 1)))
|
||||||
|
(evil-ex-define-cmd "mes[sages]" #'syd-evil-messages)
|
||||||
|
|
||||||
|
;; On ESC, remove highlighted search results.
|
||||||
|
(defun syd-evil-nohl-h ()
|
||||||
|
"If any Evil Ex search highlightings are active, remove them and return t.
|
||||||
|
Otherwise, nil."
|
||||||
|
(let ((names '(evil-ex-substitute evil-ex-search)))
|
||||||
|
(when (-any #'evil-ex-hl-active-p names)
|
||||||
|
(prog1 t (evil-ex-nohighlight)))))
|
||||||
|
(add-hook 'syd-escape-hook #'syd-evil-nohl-h)
|
||||||
|
|
||||||
|
(general-def
|
||||||
|
:states 'motion
|
||||||
|
"/" #'evil-ex-search-forward
|
||||||
|
"?" #'evil-ex-search-backward
|
||||||
|
"n" #'evil-ex-search-next
|
||||||
|
"N" #'evil-ex-search-previous
|
||||||
|
"*" #'evil-ex-search-word-forward)
|
||||||
|
|
||||||
|
(evil-mode 1))
|
||||||
|
|
||||||
|
;; A large, community-sourced collection of preconfigured Evil-mode
|
||||||
|
;; integrations.
|
||||||
|
(use-package evil-collection
|
||||||
|
;; :after evil
|
||||||
|
;; :defer t
|
||||||
|
:custom (evil-collection-setup-minibuffer t)
|
||||||
|
:preface
|
||||||
|
(defvar evil-collection-key-blacklist)
|
||||||
|
(unless noninteractive
|
||||||
|
(defvar syd-evil-collection-disabled-list
|
||||||
|
'(anaconda-mode buff-menu calc comint company custom eldoc elisp-mode ert
|
||||||
|
free-keys helm help image indent kmacro kotlin-mode lispy outline
|
||||||
|
replace shortdoc simple slime tab-bar)
|
||||||
|
"A list of `evil-collection' modules to ignore. See
|
||||||
|
`evil-collection-mode-list' for a list of available options.")
|
||||||
|
|
||||||
|
;; We do this ourselves.
|
||||||
|
(defvar evil-collection-want-unimpaired-p nil)
|
||||||
|
;; We binds goto-reference on gD and goto-assignments on gA ourselves
|
||||||
|
(defvar evil-collection-want-find-usages-bindings-p nil)
|
||||||
|
;; Reduces keybind conflicts between outline-mode and org-mode (which is
|
||||||
|
;; derived from outline-mode).
|
||||||
|
(defvar evil-collection-outline-enable-in-minor-mode-p nil)
|
||||||
|
;; We handle loading evil-collection ourselves
|
||||||
|
(defvar evil-collection--supported-modes nil)
|
||||||
|
;; This has to be defined here since evil-collection doesn't autoload its own.
|
||||||
|
;; It must be updated whenever evil-collection updates theirs.
|
||||||
|
(defvar evil-collection-mode-list
|
||||||
|
`(2048-game ag alchemist anaconda-mode apropos arc-mode atomic-chrome
|
||||||
|
auto-package-update beginend bluetooth bm bookmark
|
||||||
|
(buff-menu "buff-menu") bufler calc calendar cider citre cmake-mode
|
||||||
|
color-rg comint company compile consult corfu crdt (csv "csv-mode")
|
||||||
|
(custom cus-edit) cus-theme dape dashboard daemons deadgrep debbugs
|
||||||
|
debug devdocs dictionary diff-hl diff-mode dired dired-sidebar
|
||||||
|
disk-usage distel doc-view docker eat ebib ebuku edbi edebug ediff eglot
|
||||||
|
elpaca ement explain-pause-mode eldoc elfeed elisp-mode elisp-refs
|
||||||
|
elisp-slime-nav embark emms ,@(if (> emacs-major-version 28) '(emoji))
|
||||||
|
epa ert eshell eval-sexp-fu evil-mc eww fanyi finder flycheck flymake
|
||||||
|
forge free-keys geiser ggtags git-timemachine gited gnus go-mode gptel
|
||||||
|
grep guix hackernews helm help helpful hg-histedit hungry-delete hyrolo
|
||||||
|
ibuffer (image image-mode) image-dired image+ imenu imenu-list
|
||||||
|
(indent "indent") indium info ivy js2-mode
|
||||||
|
,@(if (>= emacs-major-version 30) '(kmacro)) leetcode lispy lms log-edit
|
||||||
|
log-view lsp-ui-imenu lua-mode kotlin-mode macrostep man
|
||||||
|
(magit magit-repos magit-submodule) magit-repos magit-section
|
||||||
|
magit-todos markdown-mode monky mpc mpdel mu4e mu4e-conversation neotree
|
||||||
|
newsticker notmuch nov omnisharp org org-present org-roam osx-dictionary
|
||||||
|
outline p4 (package-menu package) pass (pdf pdf-tools) popup proced
|
||||||
|
prodigy profiler p-search python quickrun racer racket-describe realgud
|
||||||
|
reftex replace restclient rg ripgrep rjsx-mode robe rtags ruby-mode
|
||||||
|
scheme scroll-lock selectrum sh-script
|
||||||
|
,@(if (> emacs-major-version 27) '(shortdoc)) simple simple-mpc slime
|
||||||
|
sly smerge-mode snake so-long speedbar tab-bar tablist tar-mode telega
|
||||||
|
(term term ansi-term multi-term) tetris thread tide timer-list
|
||||||
|
transmission trashed tuareg typescript-mode vc-annotate vc-dir vc-git
|
||||||
|
vdiff vertico view vlf vterm vundo w3m wdired wgrep which-key
|
||||||
|
with-editor woman xref xwidget yaml-mode youtube-dl zmusic
|
||||||
|
(ztree ztree-diff)))
|
||||||
|
|
||||||
|
(cl-defun syd-evil-collection-init (module &key disabled-modules)
|
||||||
|
"Initialise evil-collection-MODULE.
|
||||||
|
|
||||||
|
A wrapper for `evil-collection-init' that respects a given list of disabled
|
||||||
|
modules."
|
||||||
|
(let ((module* (or (car-safe module) module)))
|
||||||
|
(unless (memq module* disabled-modules)
|
||||||
|
(message "Loading evil-collection-%s%s"
|
||||||
|
module*
|
||||||
|
(if after-init-time "" " too early! }:("))
|
||||||
|
(with-demoted-errors "error loading evil-collection: %s"
|
||||||
|
(evil-collection-init (list module))))))
|
||||||
|
|
||||||
|
;; Allow binding to ESC.
|
||||||
|
(syd-defadvice syd-evil-collection-disable-blacklist-a (fn)
|
||||||
|
:around #'evil-collection-vterm-toggle-send-escape
|
||||||
|
(let (evil-collection-key-blacklist)
|
||||||
|
(funcall-interactively fn)))
|
||||||
|
|
||||||
|
;; These modes belong to packages that Emacs always loads at startup, causing
|
||||||
|
;; evil-collection and it's co-packages to all load immediately. We avoid
|
||||||
|
;; this by loading them after evil-collection has first loaded...
|
||||||
|
(with-eval-after-load 'evil-collection
|
||||||
|
(require 'syd-prelude)
|
||||||
|
(require 'syd-keybinds)
|
||||||
|
;; Don't let evil-collection interfere with certain keys
|
||||||
|
(setq evil-collection-key-blacklist
|
||||||
|
(append (list syd-leader-key syd-localleader-key
|
||||||
|
syd-alt-leader-key)
|
||||||
|
evil-collection-key-blacklist
|
||||||
|
;; Reserved for goto definition; lookup docs; eval; eval
|
||||||
|
;; buffer; movement prefix; movement prefix; escaping };).
|
||||||
|
'("gd" "K" "gr" "gR" "[" "]" "<escape>")))
|
||||||
|
|
||||||
|
(mapc #'syd-evil-collection-init '(comint custom))
|
||||||
|
|
||||||
|
(with-eval-after-load 'evil
|
||||||
|
;; Emacs loads these two packages immediately, at startup, which needlessly
|
||||||
|
;; convolutes load order for evil-collection-help.
|
||||||
|
(with-transient-after 'help-mode
|
||||||
|
(syd-evil-collection-init 'help))
|
||||||
|
(with-transient-after 'Buffer-menu-mode
|
||||||
|
(syd-evil-collection-init '(buff-menu "buff-menu")))
|
||||||
|
(with-transient-after 'calc-mode
|
||||||
|
(syd-evil-collection-init 'calc))
|
||||||
|
(with-transient-after 'image-mode
|
||||||
|
(syd-evil-collection-init 'image))
|
||||||
|
(with-transient-after 'emacs-lisp-mode
|
||||||
|
(syd-evil-collection-init 'elisp-mode))
|
||||||
|
(with-transient-after 'occur-mode
|
||||||
|
(syd-evil-collection-init 'replace))
|
||||||
|
(with-transient-after 'indent-rigidly
|
||||||
|
(syd-evil-collection-init '(indent "indent")))
|
||||||
|
(when (>= emacs-major-version 30)
|
||||||
|
(with-transient-after 'kmacro-menu-mode
|
||||||
|
(syd-evil-collection-init 'kmacro)))
|
||||||
|
(with-transient-after 'minibuffer-setup-hook
|
||||||
|
(when evil-collection-setup-minibuffer
|
||||||
|
(syd-evil-collection-init 'minibuffer)
|
||||||
|
(evil-collection-minibuffer-insert)))
|
||||||
|
(with-transient-after 'process-menu-mode
|
||||||
|
(syd-evil-collection-init '(process-menu simple)))
|
||||||
|
(with-transient-after 'shortdoc-mode
|
||||||
|
(syd-evil-collection-init 'shortdoc))
|
||||||
|
(with-transient-after 'tabulated-list-mode
|
||||||
|
(syd-evil-collection-init 'tabulated-list))
|
||||||
|
(with-transient-after 'tab-bar-mode
|
||||||
|
(syd-evil-collection-init 'tab-bar))
|
||||||
|
|
||||||
|
;; HACK: Do this ourselves because evil-collection break's
|
||||||
|
;; `eval-after-load' load order by loading their target plugin before
|
||||||
|
;; applying keys. This makes it hard for end-users to overwrite these
|
||||||
|
;; keybinds with a simple `after!' or `with-eval-after-load'.
|
||||||
|
(dolist (mode evil-collection-mode-list)
|
||||||
|
(dolist (req (or (cdr-safe mode) (list mode)))
|
||||||
|
(with-eval-after-load req
|
||||||
|
(syd-evil-collection-init
|
||||||
|
mode
|
||||||
|
:disabled-modules syd-evil-collection-disabled-list))))))))
|
||||||
|
|
||||||
|
;; Tim Pope's famous `surround.vim' for Evil.
|
||||||
|
(use-package evil-surround
|
||||||
|
:commands (global-evil-surround-mode
|
||||||
|
evil-surround-edit
|
||||||
|
evil-Surround-edit
|
||||||
|
evil-surround-region)
|
||||||
|
:hook (on-first-input . global-evil-surround-mode)
|
||||||
|
:config
|
||||||
|
;; In `emacs-lisp-mode', `' is a much more common pair than ``.
|
||||||
|
(add-hook 'emacs-lisp-mode-hook
|
||||||
|
(lambda ()
|
||||||
|
(push '(?` . ("`" . "'")) evil-surround-pairs-alist))))
|
||||||
|
|
||||||
|
;; TODO: I'd like JK to escape visual state. evil-escape only allows defining a
|
||||||
|
;; single key sequence. Perhaps key-chord is capable of this?
|
||||||
|
(use-package evil-escape
|
||||||
|
:hook (on-first-input . evil-escape-mode)
|
||||||
|
:custom ((evil-escape-key-sequence "jk")
|
||||||
|
(evil-escape-excluded-states '(normal visual multiedit emacs motion))
|
||||||
|
(evil-escape-delay 0.15)))
|
||||||
|
|
||||||
|
;; `evil-nerd-commenter' has a bunch of cool functions[1]. Here, only the Evil
|
||||||
|
;; operator is used. }:3
|
||||||
|
;; [1]: https://github.com/redguardtoo/evil-nerd-commenter?tab=readme-ov-file#commands-and-hotkeys
|
||||||
|
(use-package evil-nerd-commenter
|
||||||
|
:commands (evilnc-comment-operator
|
||||||
|
evilnc-inner-comment
|
||||||
|
evilnc-outer-commenter)
|
||||||
|
:defer t
|
||||||
|
:bind (:map evil-normal-state-map ("#" . evilnc-comment-operator)
|
||||||
|
:map evil-visual-state-map ("#" . evilnc-comment-operator)
|
||||||
|
:map evil-inner-text-objects-map ("c" . evilnc-inner-comment)
|
||||||
|
:map evil-outer-text-objects-map ("c" . evilnc-outer-comment)))
|
||||||
|
|
||||||
|
;; Enhance `evil-surround' with integration with `embrace'.
|
||||||
|
(use-package evil-embrace
|
||||||
|
:disabled
|
||||||
|
:after evil-surround
|
||||||
|
:config
|
||||||
|
(evil-embrace-enable-evil-surround-integration))
|
||||||
|
|
||||||
|
;; Provides an Evil operator to swap two spans of text.
|
||||||
|
(use-package evil-exchange
|
||||||
|
:bind (:map evil-normal-state-map ("gX" . evil-exchange)
|
||||||
|
:map evil-visual-state-map ("gX" . evil-exchange)))
|
||||||
|
|
||||||
|
;; Evil doesn't ship with support for Vim's 'g-'/'g+'. `evil-numbers'
|
||||||
|
;; implements this.
|
||||||
|
(use-package evil-numbers
|
||||||
|
;; 'g=' is a bit more comfortable than 'g+', whilst preserving the analogy.
|
||||||
|
;; ('=' is '+' modulo shift)
|
||||||
|
:bind (:map evil-normal-state-map ("g=" . 'evil-numbers/inc-at-pt)
|
||||||
|
:map evil-normal-state-map ("g-" . 'evil-numbers/dec-at-pt))
|
||||||
|
:defer t)
|
||||||
|
|
||||||
|
;; Tree-sitter queries → Evil text objects.
|
||||||
|
(use-package evil-textobj-tree-sitter
|
||||||
|
:defer t)
|
||||||
|
|
||||||
|
;; Visually "flash" the region acted upon by Evil-mode operations.
|
||||||
|
(use-package evil-goggles
|
||||||
|
:hook (on-first-input . evil-goggles-mode)
|
||||||
|
;; The flash animation will delay actions, which can be very annoying for some
|
||||||
|
;; operations. Disable `evil-goggles' for those ones.
|
||||||
|
:custom
|
||||||
|
((evil-goggles-enable-delete nil)
|
||||||
|
(evil-goggles-enable-change nil)
|
||||||
|
(evil-goggles-duration 0.1)))
|
||||||
|
|
||||||
|
;; Change cursor shape and color by evil state in terminal.
|
||||||
|
(use-package evil-terminal-cursor-changer
|
||||||
|
;; This package is only useful in the terminal.
|
||||||
|
:if (not (display-graphic-p))
|
||||||
|
:defer t
|
||||||
|
:hook (on-first-input . evil-terminal-cursor-changer-activate))
|
||||||
|
|
||||||
|
;; Automatic alignment in region, by regexp.
|
||||||
|
(use-package evil-lion
|
||||||
|
:hook (on-first-input . evil-lion-mode))
|
||||||
|
|
||||||
|
;; 'g' text object selecting the entire buffer.
|
||||||
|
(with-eval-after-load 'evil
|
||||||
|
(evil-define-text-object
|
||||||
|
evil-entire-buffer (count &optional beg end type)
|
||||||
|
"Select entire buffer"
|
||||||
|
(evil-range (point-min) (point-max) type))
|
||||||
|
(define-key evil-inner-text-objects-map "g" #'evil-entire-buffer)
|
||||||
|
(define-key evil-outer-text-objects-map "g" #'evil-entire-buffer))
|
||||||
|
|
||||||
|
;; 2-character search.
|
||||||
|
(use-package evil-snipe
|
||||||
|
:commands (evil-snipe-local-mode evil-snipe-override-local-mode)
|
||||||
|
:hook ((on-first-input . evil-snipe-override-mode)
|
||||||
|
;; (on-first-input . evil-snipe-mode)
|
||||||
|
)
|
||||||
|
:custom ((evil-snipe-smart-case t)
|
||||||
|
(evil-snipe-scope 'visible)
|
||||||
|
(evil-snipe-repeat-scope 'visible)
|
||||||
|
(evil-snipe-char-fold t)))
|
||||||
|
|
||||||
|
;; Evil's default behaviour for '#'/'*' in visual state will remain in visual
|
||||||
|
;; mode, and jump to the next occurence of the symbol under point. That is, the
|
||||||
|
;; movement is exactly the same as it is in normal state; if the region is over
|
||||||
|
;; the text `two words`, but the point is over `two`, Evil will search for
|
||||||
|
;; `two`. `evil-visualstar' will instead search for `two words`.
|
||||||
|
(use-package evil-visualstar
|
||||||
|
:defer t
|
||||||
|
:bind (:map evil-visual-state-map
|
||||||
|
("*" . evil-visualstar/begin-search-forward)))
|
||||||
|
|
||||||
|
(defvar syd-evil-last-eval-expression-register ?e
|
||||||
|
"An Evil-mode register in which the last expression evaluated with an
|
||||||
|
interactive call to `eval-expression' is stored.")
|
||||||
|
|
||||||
|
(with-eval-after-load 'evil
|
||||||
|
(defun syd-set-eval-expression-register-a (expr &rest _)
|
||||||
|
"If called interactively, set the register
|
||||||
|
`syd-evil-last-eval-expression-register' to a printed form of EXPR."
|
||||||
|
(when (called-interactively-p 'interactive)
|
||||||
|
(->> (pp-to-string expr)
|
||||||
|
(string-remove-suffix "\n")
|
||||||
|
(evil-set-register syd-evil-last-eval-expression-register))))
|
||||||
|
(advice-add #'eval-expression
|
||||||
|
:after #'syd-set-eval-expression-register-a))
|
||||||
|
|
||||||
|
;; HACK: '=' unpredictably moves the cursor when it really doesn't need to.
|
||||||
|
(defun syd-evil-dont-move-point-a (fn &rest args)
|
||||||
|
"Used as :around advice on Evil operators to avoid moving the point."
|
||||||
|
;; We don't use `save-excursion', as we /only/ want to restore the point.
|
||||||
|
(save-excursion (apply fn args)))
|
||||||
|
|
||||||
|
(with-eval-after-load 'evil
|
||||||
|
(advice-add #'evil-indent
|
||||||
|
:around #'syd-evil-dont-move-point-a))
|
||||||
|
|
||||||
|
;(use-package evil-leap
|
||||||
|
; :hook (on-first-input . evil-leap-mode)
|
||||||
|
; :load-path "/home/crumb/src/evil-leap"
|
||||||
|
; :straight nil
|
||||||
|
; ;; :straight (:type git
|
||||||
|
; ;; :host gitlab
|
||||||
|
; ;; :repo "msyds/evil-leap")
|
||||||
|
; :config
|
||||||
|
; (evil-leap-install-default-keybindings))
|
||||||
|
|
||||||
|
(provide 'syd-evil)
|
||||||
@@ -0,0 +1,176 @@
|
|||||||
|
;;; syd-keybinds.el -*- lexical-binding: t; -*-
|
||||||
|
;;; Universal keybindings, not /too/ tied to any particular packages.
|
||||||
|
|
||||||
|
(require 'syd-general)
|
||||||
|
|
||||||
|
(defun syd-keybinds-initialise ()
|
||||||
|
(syd-initialise-leader)
|
||||||
|
|
||||||
|
(global-set-key [remap keyboard-quit] #'syd/escape)
|
||||||
|
|
||||||
|
;; Buffer
|
||||||
|
(require 'syd-buffers)
|
||||||
|
(general-def
|
||||||
|
:prefix-map 'syd-leader-buffer-map
|
||||||
|
"k" `("Kill buffer" . ,#'kill-current-buffer)
|
||||||
|
"K" `("Kill all buffers" . ,#'syd/kill-all-buffers)
|
||||||
|
"O" `("Kill other buffers" . ,#'syd/kill-other-buffers)
|
||||||
|
"i" `("IBuffer" . ,#'ibuffer)
|
||||||
|
"Z" `("Kill burried buffers" . ,#'syd/kill-burried-buffers)
|
||||||
|
"C" `("Clone (indirect) buffer O/W" . ,#'clone-indirect-buffer-other-window)
|
||||||
|
"c" `("Clone (indirect) buffer" . ,#'clone-indirect-buffer)
|
||||||
|
"u" `("Save buffer as root" . ,#'syd/save-buffer-as-root)
|
||||||
|
"r" `("Revert buffer" . ,#'revert-buffer))
|
||||||
|
|
||||||
|
;; Search
|
||||||
|
(require 'syd-search)
|
||||||
|
(general-def
|
||||||
|
:prefix-map 'syd-leader-search-map
|
||||||
|
"i" `("IMenu" . ,#'consult-imenu)
|
||||||
|
"b" `("Search buffer" . ,#'syd-search-buffer)
|
||||||
|
"d" `("Search directory" . ,#'syd-search-directory))
|
||||||
|
|
||||||
|
;; File
|
||||||
|
(require 'syd-file)
|
||||||
|
(general-def
|
||||||
|
:prefix-map 'syd-leader-file-map
|
||||||
|
"D" `("Delete file" . ,#'syd/delete-this-file)
|
||||||
|
"R" `("Move file" . ,#'syd/move-this-file)
|
||||||
|
"C" `("Copy file" . ,#'syd/copy-this-file)
|
||||||
|
"F" `("Find file in" . ,#'syd-find-file-in)
|
||||||
|
"P" `("Browse Emacs config" . ,#'syd-switch-to-emacs-user-directory)
|
||||||
|
"u" `("Find file as root" . ,#'syd/find-file-as-root)
|
||||||
|
"U" `("Open this file as root" . ,#'syd/open-this-file-as-root)
|
||||||
|
"y" `("Yank buffer path" . ,#'syd/yank-buffer-path)
|
||||||
|
"r" `("Browse recent file" . ,#'consult-recent-file))
|
||||||
|
|
||||||
|
;; Window
|
||||||
|
(require 'syd-window)
|
||||||
|
(general-def
|
||||||
|
:prefix-map 'syd-leader-window-maximise-map
|
||||||
|
"m" `("Maximise" . ,#'syd/window-maximise))
|
||||||
|
(general-def
|
||||||
|
:prefix-map 'syd-leader-window-map
|
||||||
|
"h" `("Select window left" . ,#'evil-window-left)
|
||||||
|
"j" `("Select window below" . ,#'evil-window-down)
|
||||||
|
"k" `("Select window above" . ,#'evil-window-up)
|
||||||
|
"l" `("Select window right" . ,#'evil-window-right)
|
||||||
|
"H" `("Swap window left" . ,#'syd/window-swap-left)
|
||||||
|
"J" `("Swap window below" . ,#'syd/window-swap-down)
|
||||||
|
"K" `("Swap window above" . ,#'syd/window-swap-up)
|
||||||
|
"L" `("Swap window right" . ,#'syd/window-swap-right)
|
||||||
|
"T" `("Tear off window" . ,#'tear-off-window)
|
||||||
|
"=" `("Balance windows" . ,#'balance-windows)
|
||||||
|
"v" `("Vertical split" . ,#'evil-window-vsplit)
|
||||||
|
"s" `("Horizontal split" . ,#'evil-window-split)
|
||||||
|
"F" `("Fit window to contents" . ,#'fit-window-to-buffer)
|
||||||
|
"r" `("Rotate window downwards" . ,#'evil-window-rotate-downwards)
|
||||||
|
"R" `("Rotate window upwards" . ,#'evil-window-rotate-upwards)
|
||||||
|
"u" `("Undo window change" . ,#'winner-undo)
|
||||||
|
"C-r" `("Redo window change" . ,#'winner-redo)
|
||||||
|
"m" `("Maximise" . ,syd-leader-window-maximise-map))
|
||||||
|
|
||||||
|
;; Open
|
||||||
|
(require 'syd-handle-repl)
|
||||||
|
(general-def
|
||||||
|
:prefix-map 'syd-leader-open-map
|
||||||
|
"r" `("Repl o/w" . ,#'+syd/open-repl-other-window))
|
||||||
|
|
||||||
|
;; Project
|
||||||
|
(general-def
|
||||||
|
:prefix-map 'syd-leader-project-map
|
||||||
|
"C" `("Compile project" . ,#'project-compile)
|
||||||
|
"&" `("Async cmd in project root" . ,#'project-async-shell-command)
|
||||||
|
"p" `("Switch project" . ,#'project-switch-project)
|
||||||
|
"." `("Browse project from root" . ,#'syd-project-root-find-file))
|
||||||
|
|
||||||
|
(general-def
|
||||||
|
:prefix-map 'syd-leader-help-package-map
|
||||||
|
"u" `("Temporarily install package" . ,#'straight-use-package)
|
||||||
|
"v" `("Browse package repo" . ,#'straight-visit-package))
|
||||||
|
|
||||||
|
;; Help
|
||||||
|
(general-def
|
||||||
|
:prefix-map 'help-map
|
||||||
|
"F" #'describe-face
|
||||||
|
"'" #'describe-char
|
||||||
|
"T" #'consult-theme
|
||||||
|
"p" `("Packages" . ,syd-leader-help-package-map))
|
||||||
|
|
||||||
|
(general-def
|
||||||
|
:prefix-map 'syd-leader-notes-map)
|
||||||
|
|
||||||
|
(general-def
|
||||||
|
:keymaps '(evil-ex-completion-map minibuffer-local-map minibuffer-mode-map
|
||||||
|
read--expression-map)
|
||||||
|
"C-k" #'previous-history-element
|
||||||
|
"C-j" #'next-history-element)
|
||||||
|
|
||||||
|
;; Motion
|
||||||
|
(general-def
|
||||||
|
:states 'motion
|
||||||
|
"[ b" #'previous-buffer
|
||||||
|
"] b" #'next-buffer
|
||||||
|
"] SPC" #'syd-insert-newline-below
|
||||||
|
"[ SPC" #'syd-insert-newline-above)
|
||||||
|
|
||||||
|
(general-def
|
||||||
|
:keymaps 'global-map
|
||||||
|
:states 'motion
|
||||||
|
"M-:" #'eval-expression
|
||||||
|
"M-x" #'execute-extended-command)
|
||||||
|
|
||||||
|
(general-def
|
||||||
|
:maps 'help-mode-map
|
||||||
|
"<escape>" #'syd/escape)
|
||||||
|
|
||||||
|
;; Insert
|
||||||
|
(general-def
|
||||||
|
:prefix-map 'syd-leader-insert-map
|
||||||
|
"u" #'insert-char)
|
||||||
|
|
||||||
|
;; Code
|
||||||
|
(general-def
|
||||||
|
:prefix-map 'syd-leader-code-map)
|
||||||
|
|
||||||
|
;; This is necessary to properly rebind `universal-argument'.
|
||||||
|
;; `universal-argument-more' is a command that provides additional prefixes
|
||||||
|
;; after the first. Without it, the first 'C-u' will be interpreted as a
|
||||||
|
;; prefix argument for the second 'C-u'.
|
||||||
|
(general-def
|
||||||
|
:keymaps 'universal-argument-map
|
||||||
|
"SPC u" #'universal-argument-more
|
||||||
|
"u" #'universal-argument-more)
|
||||||
|
|
||||||
|
;; Leader
|
||||||
|
(general-def
|
||||||
|
:keymaps 'syd-leader-map
|
||||||
|
"." #'find-file
|
||||||
|
"SPC" `("Find file in project" . ,#'project-find-file)
|
||||||
|
"x" `("Open scratch buffer" . ,#'scratch-buffer)
|
||||||
|
"u" `("Universal argument" . ,#'universal-argument)
|
||||||
|
"b" `("Buffer" . ,syd-leader-buffer-map)
|
||||||
|
"o" `("Open" . ,syd-leader-open-map)
|
||||||
|
"p" `("Project" . ,syd-leader-project-map)
|
||||||
|
"w" `("Window" . ,syd-leader-window-map)
|
||||||
|
"f" `("File" . ,syd-leader-file-map)
|
||||||
|
"s" `("Search" . ,syd-leader-search-map)
|
||||||
|
"h" `("Help" . ,help-map)
|
||||||
|
"n" `("Notes" . ,syd-leader-notes-map)
|
||||||
|
"i" `("Insert" . ,syd-leader-insert-map)
|
||||||
|
"c" `("Code" . ,syd-leader-code-map)
|
||||||
|
"," `("Switch buffer in project" . ,#'consult-project-buffer)
|
||||||
|
"<" `("Switch buffer" . ,#'consult-buffer)
|
||||||
|
"/" `("Search project" . ,#'syd-project-search)))
|
||||||
|
|
||||||
|
(syd-keybinds-initialise)
|
||||||
|
|
||||||
|
;; Show possible completions for a partially-entered key sequence.
|
||||||
|
(use-package which-key
|
||||||
|
;; BUG: (#4) If the first input is a prefix key, `which-key-mode' won't be
|
||||||
|
;; activated in time.
|
||||||
|
:hook (on-first-input . which-key-mode)
|
||||||
|
:custom ((which-key-allow-evil-operators t)
|
||||||
|
(which-key-show-operator-state-maps t)))
|
||||||
|
|
||||||
|
(provide 'syd-keybinds)
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
(add-to-list 'load-path
|
||||||
|
(file-name-concat user-emacs-directory "modules" "lang"))
|
||||||
|
|
||||||
|
(require 'syd-lang-agda)
|
||||||
|
(require 'syd-lang-clojure)
|
||||||
|
(require 'syd-lang-emacs-lisp)
|
||||||
|
(require 'syd-lang-haskell)
|
||||||
|
(require 'syd-lang-idris2)
|
||||||
|
(require 'syd-lang-kdl)
|
||||||
|
(require 'syd-lang-lean4)
|
||||||
|
(require 'syd-lang-nix)
|
||||||
|
(require 'syd-lang-sql)
|
||||||
|
|
||||||
|
(use-package tf2-conf-mode)
|
||||||
|
|
||||||
|
(provide 'syd-lang)
|
||||||
@@ -0,0 +1,617 @@
|
|||||||
|
;;; syd-org.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
;; Optional Org-mode dependency used for highlighting source code in HTML
|
||||||
|
;; exports.
|
||||||
|
(use-package htmlize)
|
||||||
|
|
||||||
|
(with-eval-after-load 'org
|
||||||
|
(syd-add-hook 'org-tab-first-hook
|
||||||
|
(defun syd-org-cycle-only-current-subtree-h (&optional arg)
|
||||||
|
"Toggle the local fold at the point, and no deeper.
|
||||||
|
`org-cycle's standard behavior is to cycle between three levels: collapsed,
|
||||||
|
subtree and whole document. This is slow, especially in larger org buffer. Most
|
||||||
|
of the time I just want to peek into the current subtree -- at most, expand
|
||||||
|
*only* the current subtree.
|
||||||
|
|
||||||
|
All my (performant) foldings needs are met between this and `org-show-subtree'
|
||||||
|
(on zO for evil users), and `org-cycle' on shift-TAB if I need it."
|
||||||
|
(interactive "P")
|
||||||
|
(unless (or (eq this-command 'org-shifttab)
|
||||||
|
(and (bound-and-true-p org-cdlatex-mode)
|
||||||
|
(or (org-inside-LaTeX-fragment-p)
|
||||||
|
(org-inside-latex-macro-p))))
|
||||||
|
(save-excursion
|
||||||
|
(org-beginning-of-line)
|
||||||
|
(let (invisible-p)
|
||||||
|
(when (and (org-at-heading-p)
|
||||||
|
(or org-cycle-open-archived-trees
|
||||||
|
(not (member org-archive-tag (org-get-tags))))
|
||||||
|
(or (not arg)
|
||||||
|
(setq invisible-p
|
||||||
|
(memq (get-char-property (line-end-position)
|
||||||
|
'invisible)
|
||||||
|
'(outline org-fold-outline)))))
|
||||||
|
(unless invisible-p
|
||||||
|
(setq org-cycle-subtree-status 'subtree))
|
||||||
|
(org-cycle-internal-local)
|
||||||
|
t)))))))
|
||||||
|
|
||||||
|
(defun syd-org--init-hacks-h ()
|
||||||
|
;; Open file links in current window, rather than new ones
|
||||||
|
(setf (alist-get 'file org-link-frame-setup) #'find-file)
|
||||||
|
;; Open directory links in dired
|
||||||
|
(add-to-list 'org-file-apps '(directory . emacs))
|
||||||
|
(add-to-list 'org-file-apps '(remote . emacs))
|
||||||
|
|
||||||
|
(defun syd-org--restart-mode-h ()
|
||||||
|
"Restart `org-mode', but only once."
|
||||||
|
(syd-quietly (org-mode-restart))
|
||||||
|
(setq org-agenda-new-buffers
|
||||||
|
(delq (current-buffer)
|
||||||
|
org-agenda-new-buffers))
|
||||||
|
(run-hooks 'find-file-hook))
|
||||||
|
|
||||||
|
(syd-add-hook 'org-agenda-finalize-hook
|
||||||
|
(defun syd-org-exclude-agenda-buffers-from-workspace-h ()
|
||||||
|
"Don't associate temporary agenda buffers with current workspace."
|
||||||
|
(when (and org-agenda-new-buffers
|
||||||
|
(bound-and-true-p persp-mode)
|
||||||
|
(not org-agenda-sticky))
|
||||||
|
(let (persp-autokill-buffer-on-remove)
|
||||||
|
(persp-remove-buffer org-agenda-new-buffers
|
||||||
|
(get-current-persp)
|
||||||
|
nil)))))
|
||||||
|
|
||||||
|
(syd-defadvice syd-org--restart-mode-before-indirect-buffer-a (&optional buffer _)
|
||||||
|
"Restart `org-mode' in buffers in which the mode has been deferred (see
|
||||||
|
`syd-org-defer-mode-in-agenda-buffers-h') before they become the base buffer for an
|
||||||
|
indirect org-cpature buffer. This ensures that the buffer is fully functional
|
||||||
|
not only when the *user* visits it, but also when org-capture interacts with it
|
||||||
|
via an indirect buffer."
|
||||||
|
:before #'org-capture-get-indirect-buffer
|
||||||
|
(with-current-buffer (or buffer (current-buffer))
|
||||||
|
(when (memq #'syd-org--restart-mode-h on-switch-buffer-hook)
|
||||||
|
(syd-org--restart-mode-h))))
|
||||||
|
|
||||||
|
(defvar recentf-exclude)
|
||||||
|
|
||||||
|
(syd-defadvice syd-org--optimise-backgrounded-agenda-buffers-a (fn file)
|
||||||
|
"Disable `org-mode's startup processes for temporary agenda buffers.
|
||||||
|
|
||||||
|
Prevents recentf pollution as well. However, if the user tries to visit one of
|
||||||
|
these buffers they'll see a gimped, half-broken org buffer, so to avoid that,
|
||||||
|
install a hook to restart `org-mode' when they're switched to so they can grow
|
||||||
|
up to be fully-fledged org-mode buffers."
|
||||||
|
:around #'org-get-agenda-file-buffer
|
||||||
|
(if-let* ((buf (org-find-base-buffer-visiting file)))
|
||||||
|
buf
|
||||||
|
(let ((recentf-exclude '(always))
|
||||||
|
;; (doom-inhibit-large-file-detection t)
|
||||||
|
;; (doom-inhibit-local-var-hooks t)
|
||||||
|
(org-inhibit-startup t)
|
||||||
|
vc-handled-backends
|
||||||
|
enable-local-variables
|
||||||
|
find-file-hook)
|
||||||
|
(when-let ((buf (delay-mode-hooks (funcall fn file))))
|
||||||
|
(with-current-buffer buf
|
||||||
|
(add-hook 'on-switch-buffer-hook #'syd-org--restart-mode-h
|
||||||
|
nil 'local))
|
||||||
|
buf))))
|
||||||
|
|
||||||
|
(syd-defadvice syd-org--fix-inconsistent-uuidgen-case-a (uuid)
|
||||||
|
"Ensure uuidgen is always lowercase (consistent) regardless of system.
|
||||||
|
See https://lists.gnu.org/archive/html/emacs-orgmode/2019-07/msg00081.html."
|
||||||
|
:filter-return #'org-id-new
|
||||||
|
(if (eq org-id-method 'uuid)
|
||||||
|
(downcase uuid)
|
||||||
|
uuid)))
|
||||||
|
|
||||||
|
(defun syd-org-init-theme ()
|
||||||
|
(require 'syd-kanagawa)
|
||||||
|
(let* ((hl `(:weight bold))
|
||||||
|
(fg (lambda (c) `(:foreground ,(syd-kanagawa-get c))))
|
||||||
|
(bg (lambda (c) `(:background ,(syd-kanagawa-get c))))
|
||||||
|
(block-delim `(:foreground unspecified
|
||||||
|
:inherit font-lock-comment-face
|
||||||
|
:extend t
|
||||||
|
,@(funcall bg 'sumi-ink-0)
|
||||||
|
:height 0.75))
|
||||||
|
(keyword '(:background unspecified :foreground unspecified
|
||||||
|
:inherit (fixed-pitch font-lock-comment-face)
|
||||||
|
:height 0.9)))
|
||||||
|
(setq org-src-block-faces
|
||||||
|
`(("jupyter-apl" syd-apl)))
|
||||||
|
(custom-theme-set-faces
|
||||||
|
'user
|
||||||
|
`(org-document-title ((t (,@hl :height 1.60))))
|
||||||
|
`(org-document-info ((t (,@hl :height 1.0))))
|
||||||
|
`(org-document-info-keyword ((t ,keyword)))
|
||||||
|
`(org-meta-line ((t ,keyword)))
|
||||||
|
`(org-table ((t (:inherit fixed-pitch))))
|
||||||
|
`(org-level-1 ((t (,@hl :height 1.40 ,@(funcall fg 'oni-violet)))))
|
||||||
|
`(org-level-2 ((t (,@hl :height 1.35 ,@(funcall fg 'crystal-blue)))))
|
||||||
|
`(org-level-3 ((t (,@hl :height 1.30 ,@(funcall fg 'spring-violet-2)))))
|
||||||
|
`(org-level-4 ((t (,@hl :height 1.25 ,@(funcall fg 'light-blue)))))
|
||||||
|
`(org-level-5 ((t (,@hl :height 1.20 ,@(funcall fg 'wave-aqua-2)))))
|
||||||
|
`(org-level-6 ((t (,@hl :height 1.15 ,@(funcall fg 'spring-green)))))
|
||||||
|
`(org-level-7 ((t (,@hl :height 1.10 ,@(funcall fg 'boat-yellow-1)))))
|
||||||
|
`(org-level-8 ((t (,@hl :height 1.05 ,@(funcall fg 'boat-yellow-2)))))
|
||||||
|
`(org-block-begin-line ((t ,block-delim)))
|
||||||
|
`(org-block-end-line ((t ,block-delim)))
|
||||||
|
'(org-ellipsis ((t (:height 1.0))))
|
||||||
|
;; It is important that the `org-indent' face uses a fixed-pitch font, lest
|
||||||
|
;; e.g. multi-line bullets appear misaligned.
|
||||||
|
'(org-indent ((t (:inherit (org-hide syd-alt-fixed-pitch)))))
|
||||||
|
;; Must be fixed-pitch; `[ ]` and `[X]' should be the same width.
|
||||||
|
'(org-checkbox ((t (:inherit fixed-pitch))))
|
||||||
|
`(org-drawer ((t ,block-delim)))
|
||||||
|
'(org-property-value ((t (:inherit fixed-pitch))))
|
||||||
|
'(org-special-keyword ((t (:inherit (font-lock-comment-face fixed-pitch)))))
|
||||||
|
`(org-block ((t (:inherit fixed-pitch
|
||||||
|
,@(funcall bg 'sumi-ink-2)))))
|
||||||
|
`(org-quote ((t (:inherit (variable-pitch org-block)))))
|
||||||
|
'(org-code ((t (:inherit (shadow fixed-pitch))))))))
|
||||||
|
|
||||||
|
(evil-define-command syd-org-yank-link (register)
|
||||||
|
(interactive "<x>")
|
||||||
|
(if-let* ((url (thing-at-point 'url)))
|
||||||
|
(progn (evil-set-register (or register ?\") url)
|
||||||
|
(message "Yanked link: %s" url))
|
||||||
|
(message "No URL at point")))
|
||||||
|
|
||||||
|
(defun syd-org-latex-preview-recompile-preamble ()
|
||||||
|
(interactive)
|
||||||
|
(setq org-latex-preview-process-precompiled nil)
|
||||||
|
(org-latex-preview-clear-cache)
|
||||||
|
(org-latex-preview 'buffer))
|
||||||
|
|
||||||
|
(defun syd-org-latex-preview-buffer ()
|
||||||
|
(interactive)
|
||||||
|
(org-latex-preview 'buffer))
|
||||||
|
|
||||||
|
(defun syd-org-init-keybinds ()
|
||||||
|
(general-def
|
||||||
|
:keymaps 'org-mode-map
|
||||||
|
:states '(insert emacs)
|
||||||
|
[C-M-return] #'org-insert-subheading
|
||||||
|
"TAB" nil
|
||||||
|
"<tab>" nil)
|
||||||
|
(general-def
|
||||||
|
:prefix-map 'syd-org-mode-links-map
|
||||||
|
"l" #'org-insert-link
|
||||||
|
"y" #'syd-org-yank-link)
|
||||||
|
(general-define-key
|
||||||
|
:keymaps 'org-mode-map
|
||||||
|
:states '(normal visual motion emacs insert)
|
||||||
|
:major-modes t
|
||||||
|
:prefix syd-localleader-key
|
||||||
|
:non-normal-prefix syd-alt-localleader-key
|
||||||
|
"." #'consult-org-heading
|
||||||
|
"/" #'consult-org-agenda
|
||||||
|
"@" #'org-cite-insert
|
||||||
|
"e" #'org-export-dispatch
|
||||||
|
"f" #'org-footnote-action
|
||||||
|
"h" #'org-toggle-heading
|
||||||
|
"i" #'org-toggle-item
|
||||||
|
"I" #'org-id-get-create
|
||||||
|
"k" #'org-babel-remove-result
|
||||||
|
"l" `("Links" . ,syd-org-mode-links-map)
|
||||||
|
"t" #'org-todo
|
||||||
|
"L L" #'syd-org-latex-preview-buffer
|
||||||
|
"L r" #'syd-org-latex-preview-recompile-preamble
|
||||||
|
"L c" #'org-latex-preview-clear-cache
|
||||||
|
"s t" #'org-set-tags-command
|
||||||
|
"s p" #'org-set-property
|
||||||
|
"s d" #'org-deadline
|
||||||
|
"s s" #'org-schedule
|
||||||
|
"d t" #'org-timestamp
|
||||||
|
"d T" #'org-timestamp-inactive
|
||||||
|
"x" #'org-toggle-checkbox)
|
||||||
|
(general-define-key
|
||||||
|
:keymaps 'org-agenda-mode-map
|
||||||
|
:states '(normal visual motion emacs insert)
|
||||||
|
:major-modes t
|
||||||
|
:prefix syd-localleader-key
|
||||||
|
:non-normal-prefix syd-alt-localleader-key
|
||||||
|
"t" #'org-agenda-todo
|
||||||
|
"r" #'org-agenda-refile
|
||||||
|
"q" #'org-agenda-set-tags
|
||||||
|
"p p" #'org-agenda-priority
|
||||||
|
"p u" #'org-agenda-priority-up
|
||||||
|
"p d" #'org-agenda-priority-down
|
||||||
|
"p k" #'org-agenda-priority-up
|
||||||
|
"p j" #'org-agenda-priority-down
|
||||||
|
"d d" #'org-agenda-deadline
|
||||||
|
"d s" #'org-agenda-schedule))
|
||||||
|
|
||||||
|
(defun syd-org-init-popup-rules-h ()
|
||||||
|
(set-popup-rules!
|
||||||
|
'(("^\\*Org Links" :slot -1 :vslot -1 :size 2 :ttl 0)
|
||||||
|
("^ ?\\*\\(?:Agenda Com\\|Calendar\\|Org Export Dispatcher\\)"
|
||||||
|
:slot -1 :vslot -1 :size #'+popup-shrink-to-fit :ttl 0)
|
||||||
|
("^\\*Org \\(?:Select\\|Attach\\|Table Edit\\)" :slot -1 :vslot -2 :ttl 0 :size 0.25)
|
||||||
|
("^\\*Edit Formulas\\*$" :slot -1 :vslot -2 :ttl 0 :size 0.25)
|
||||||
|
("^\\*Org Agenda" :ignore t)
|
||||||
|
("^\\*Org Src" :size 0.42 :quit nil :select t :autosave t :modeline t :ttl nil)
|
||||||
|
("^\\*Org-Babel")
|
||||||
|
("^\\*Capture\\*$\\|CAPTURE-.*$" :size 0.42 :quit nil :select t :autosave ignore))))
|
||||||
|
|
||||||
|
(defun syd-org-init-appearance-h ()
|
||||||
|
;; Larger LaTeX previews.
|
||||||
|
(plist-put org-format-latex-options :scale 1.4))
|
||||||
|
|
||||||
|
(defun syd-org-init-agenda-h ()
|
||||||
|
(setq
|
||||||
|
;; The lengths of these leaders take account for our added
|
||||||
|
;; `syd-org--agenda-repeater'.
|
||||||
|
org-agenda-scheduled-leaders '("Sched" "S.%2dx")
|
||||||
|
org-agenda-deadline-leaders '("Deadl" "In%2dd" "D.%2dx")
|
||||||
|
org-agenda-timerange-leaders '("" ; Range within a single day.
|
||||||
|
"%2d/%2d") ; Range spanning many days.
|
||||||
|
;; Hide "upcoming deadlines" until the scheduled date.
|
||||||
|
org-agenda-skip-deadline-prewarning-if-scheduled 'pre-scheduled
|
||||||
|
;; Hide completed tasks.
|
||||||
|
org-agenda-skip-scheduled-if-done t)
|
||||||
|
|
||||||
|
;; Show the repeater (the repeat interval, e.g. +1d) in repeating agenda
|
||||||
|
;; entries.
|
||||||
|
(defun syd-org--agenda-repeater ()
|
||||||
|
"The repeater information (e.g. +1w) in the agenda."
|
||||||
|
(let ((pom (org-get-at-bol 'org-marker)))
|
||||||
|
(if (or (org-get-scheduled-time pom) (org-get-deadline-time pom))
|
||||||
|
(format "%5s: " (or (org-get-repeat) ""))
|
||||||
|
"┄┄┄┄┄┄┄┄┄┄┄┄")))
|
||||||
|
|
||||||
|
;; Add `syd-org--agenda-repeater' to the agenda prefix.
|
||||||
|
(setcdr (assoc 'agenda org-agenda-prefix-format)
|
||||||
|
" %i %-12:c%?-12t%s%(syd-org--agenda-repeater)")
|
||||||
|
|
||||||
|
(setq org-agenda-custom-commands
|
||||||
|
'(("k" "My agenda for today"
|
||||||
|
((agenda
|
||||||
|
""
|
||||||
|
((org-agenda-span 1)
|
||||||
|
(org-deadline-warning-days 0)))
|
||||||
|
(agenda
|
||||||
|
""
|
||||||
|
((org-agenda-span 7)
|
||||||
|
(org-agenda-start-day "+1d")
|
||||||
|
(org-deadline-warning-days 0)
|
||||||
|
(org-agenda-time-grid nil)
|
||||||
|
(org-agenda-entry-types '(:deadline))
|
||||||
|
(org-agenda-overriding-header "Upcoming deadlines"))))))))
|
||||||
|
|
||||||
|
(defvar syd-org-default-css "
|
||||||
|
<style>
|
||||||
|
html
|
||||||
|
{ height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body
|
||||||
|
{ height: 100%
|
||||||
|
; padding: 0 10px
|
||||||
|
; line-height: 1.6
|
||||||
|
; font-size: 18px
|
||||||
|
; margin: 40px auto
|
||||||
|
; max-width: 650px
|
||||||
|
; color: #444
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, h3
|
||||||
|
{ line-height: 1.2
|
||||||
|
}
|
||||||
|
|
||||||
|
pre
|
||||||
|
{ line-height: normal
|
||||||
|
}
|
||||||
|
|
||||||
|
.org-svg
|
||||||
|
{ max-height: 100%
|
||||||
|
; max-width: 100%
|
||||||
|
}
|
||||||
|
|
||||||
|
.figure img
|
||||||
|
{ max-height: 100%
|
||||||
|
; max-width: 100%
|
||||||
|
}
|
||||||
|
</style>"
|
||||||
|
"A default style for Org HTML exports.")
|
||||||
|
|
||||||
|
(use-package org
|
||||||
|
:defer-incrementally
|
||||||
|
calendar find-func format-spec org-macs org-compat org-faces org-entities
|
||||||
|
org-list org-pcomplete org-src org-footnote org-macro ob org org-agenda
|
||||||
|
org-capture
|
||||||
|
;; We are using Tecosaur's shiny new async LaTeX preview engine. Learn more
|
||||||
|
;; here: https://abode.karthinks.com/org-latex-preview/#org9054eb6
|
||||||
|
:straight `(org
|
||||||
|
:fork (:host nil
|
||||||
|
:repo "https://git.tecosaur.net/tec/org-mode.git"
|
||||||
|
:branch "dev"
|
||||||
|
:remote "tecosaur")
|
||||||
|
:files (:defaults "etc")
|
||||||
|
:build t
|
||||||
|
:pre-build
|
||||||
|
(with-temp-file "org-version.el"
|
||||||
|
(require 'lisp-mnt)
|
||||||
|
(let ((version
|
||||||
|
(with-temp-buffer
|
||||||
|
(insert-file-contents "lisp/org.el")
|
||||||
|
(lm-header "version")))
|
||||||
|
(git-version
|
||||||
|
(string-trim
|
||||||
|
(with-temp-buffer
|
||||||
|
(call-process "git" nil t nil "rev-parse" "--short" "HEAD")
|
||||||
|
(buffer-string)))))
|
||||||
|
(insert
|
||||||
|
(format "(defun org-release () \"The release version of Org.\" %S)\n" version)
|
||||||
|
(format "(defun org-git-version () \"The truncate git commit hash of Org mode.\" %S)\n" git-version)
|
||||||
|
"(provide 'org-version)\n")))
|
||||||
|
:pin nil)
|
||||||
|
:init
|
||||||
|
;; HACK: Face specs fed directly to `org-todo-keyword-faces' don't respect
|
||||||
|
;; underlying faces like the `org-todo' face does, so we define our own
|
||||||
|
;; intermediary faces that extend from org-todo.
|
||||||
|
(with-no-warnings
|
||||||
|
(custom-declare-face 'syd-org-todo-active
|
||||||
|
'((t (:inherit (bold font-lock-constant-face org-todo)))) "")
|
||||||
|
(custom-declare-face 'syd-org-todo-project
|
||||||
|
'((t (:inherit (bold font-lock-doc-face org-todo)))) "")
|
||||||
|
(custom-declare-face 'syd-org-todo-onhold
|
||||||
|
'((t (:inherit (bold warning org-todo)))) "")
|
||||||
|
(custom-declare-face 'syd-org-todo-cancel
|
||||||
|
'((t (:inherit (bold error org-todo)))) ""))
|
||||||
|
:custom ((org-startup-folded 'content)
|
||||||
|
(org-directory "~/org")
|
||||||
|
(org-agenda-files (list org-directory))
|
||||||
|
(org-agenda-deadline-faces '((1.001 . error)
|
||||||
|
(1.0 . org-warning)
|
||||||
|
(0.5 . org-upcoming-deadline)
|
||||||
|
(0.0 . org-upcoming-distant-deadline)))
|
||||||
|
(org-agenda-window-setup 'current-window)
|
||||||
|
(org-refile-use-outline-path t)
|
||||||
|
(org-tag-persistent-alist `(("orgmode" . ?o)
|
||||||
|
("hrt" . ?h)))
|
||||||
|
(org-agenda-skip-unavailable-files t)
|
||||||
|
;; Shift the agenda to show the previous 3 days and the next 7 days
|
||||||
|
;; for better context on your week. The past is less important than
|
||||||
|
;; the future.
|
||||||
|
(org-agenda-span 10)
|
||||||
|
(org-agenda-start-on-weekday nil)
|
||||||
|
(org-agenda-start-day "-3d")
|
||||||
|
;; Optimize `org-agenda' by inhibiting extra work while opening
|
||||||
|
;; agenda buffers in the background. They'll be "restarted" if the
|
||||||
|
;; user switches to them anyway (see
|
||||||
|
;; `syd-org-exclude-agenda-buffers-from-workspace-h')
|
||||||
|
(org-agenda-inhibit-startup t)
|
||||||
|
;; Upon finishing a task, leave a timestamp.
|
||||||
|
(org-log-done 'time)
|
||||||
|
(org-indirect-buffer-display 'current-window)
|
||||||
|
;; Force a TeX-like syntax for {sub,super}-scripts. x^{blah blah}
|
||||||
|
(org-use-sub-superscripts '{})
|
||||||
|
(org-fontify-quote-and-verse-blocks t)
|
||||||
|
(org-enforce-todo-dependencies t)
|
||||||
|
(org-image-actual-width nil)
|
||||||
|
(org-imenu-depth 6)
|
||||||
|
;; Include some sane default CSS declarations when exporting to HTML.
|
||||||
|
(org-html-head syd-org-default-css)
|
||||||
|
;; Don't right-align tags.
|
||||||
|
(org-tags-column 0)
|
||||||
|
(org-priority-faces '((?A . error)
|
||||||
|
(?B . warning)
|
||||||
|
(?C . success)))
|
||||||
|
;; Stay out of my config dir!
|
||||||
|
(org-id-locations-file (file-name-concat syd-cache-dir
|
||||||
|
"org-id-locations"))
|
||||||
|
(org-cite-global-bibliography
|
||||||
|
(list (expand-file-name "~/etc/liography.bib")))
|
||||||
|
;; New headings should be inserted /after/ the heading's contents.
|
||||||
|
(org-insert-heading-respect-content t)
|
||||||
|
;; Hide markup syntax and leave the markup.
|
||||||
|
(org-hide-emphasis-markers t)
|
||||||
|
(org-ellipsis " […]")
|
||||||
|
(org-todo-keywords
|
||||||
|
'((sequence
|
||||||
|
"TODO(t)" ; A task that needs doing & is ready to do
|
||||||
|
"PROJ(p)" ; A project, which usually contains other tasks
|
||||||
|
"STRT(s)" ; A task that is in progress
|
||||||
|
"WAIT(w)" ; Something external is holding up this task
|
||||||
|
"HOLD(h)" ; This task is paused/on hold because of me
|
||||||
|
"IDEA(i)" ; An unconfirmed and unapproved task or notion
|
||||||
|
"|"
|
||||||
|
"DONE(d)" ; Task successfully completed
|
||||||
|
"KILL(k)"))) ; Task was cancelled, aborted, or is no longer
|
||||||
|
; applicable
|
||||||
|
(org-todo-keyword-faces
|
||||||
|
'(("[-]" . syd-org-todo-active)
|
||||||
|
("STRT" . syd-org-todo-active)
|
||||||
|
("WAIT" . syd-org-todo-onhold)
|
||||||
|
("HOLD" . syd-org-todo-onhold)
|
||||||
|
("PROJ" . syd-org-todo-project)
|
||||||
|
("KILL" . syd-org-todo-cancel)))
|
||||||
|
(org-startup-with-latex-preview t)
|
||||||
|
(org-pretty-entities t))
|
||||||
|
:preface
|
||||||
|
;; Speed up initialisation by disabling modules we don't need.
|
||||||
|
(defvar org-modules
|
||||||
|
'(;; ol-w3m
|
||||||
|
;; ol-bbdb
|
||||||
|
ol-bibtex
|
||||||
|
;; ol-docview
|
||||||
|
;; ol-gnus
|
||||||
|
;; ol-info
|
||||||
|
;; ol-irc
|
||||||
|
;; ol-mhe
|
||||||
|
;; ol-rmail
|
||||||
|
;; ol-eww
|
||||||
|
))
|
||||||
|
(syd-add-hook 'org-load-hook
|
||||||
|
#'syd-org-init-popup-rules-h
|
||||||
|
#'syd-org-init-appearance-h)
|
||||||
|
(with-eval-after-load 'org-agenda
|
||||||
|
(syd-org-init-agenda-h))
|
||||||
|
:config
|
||||||
|
(require 'syd-prose)
|
||||||
|
(syd-add-hook 'org-mode-hook
|
||||||
|
#'org-indent-mode
|
||||||
|
#'syd-prose-mode)
|
||||||
|
(syd-org-init-theme)
|
||||||
|
(syd-org-init-keybinds))
|
||||||
|
|
||||||
|
(use-package org-latex-preview
|
||||||
|
:defer t
|
||||||
|
:straight nil
|
||||||
|
:custom (;; Generate previews whilst editing.
|
||||||
|
(org-latex-preview-live t)
|
||||||
|
;; Default behaviour waits one second before generating the live
|
||||||
|
;; preview.
|
||||||
|
(org-latex-preview-live-debounce 0.25)
|
||||||
|
;; Increase size of previews.
|
||||||
|
(org-latex-preview-appearance-options
|
||||||
|
(plist-put org-latex-preview-appearance-options :zoom 1.4)))
|
||||||
|
:hook (org-mode . org-latex-preview-mode))
|
||||||
|
|
||||||
|
(use-package org-appear
|
||||||
|
:hook (org-mode . org-appear-mode)
|
||||||
|
:custom ((org-appear-autoemphasis t)
|
||||||
|
(org-appear-auto-submarkers t)))
|
||||||
|
|
||||||
|
;; Unlike those appearing in `syd-org--init-roam-keybinds', these should be
|
||||||
|
;; available even outside of Org-mode.
|
||||||
|
(general-def
|
||||||
|
:prefix-map 'syd-leader-notes-roam-map
|
||||||
|
"f" #'org-roam-node-find
|
||||||
|
"d t" #'org-roam-dailies-capture-today
|
||||||
|
"d T" #'org-roam-dailies-goto-today)
|
||||||
|
|
||||||
|
(general-def
|
||||||
|
:keymaps 'syd-leader-open-map
|
||||||
|
"A" #'org-agenda)
|
||||||
|
|
||||||
|
(defun syd-org--init-roam-keybinds ()
|
||||||
|
(general-def
|
||||||
|
:prefix-map 'syd-org-roam-mode-map)
|
||||||
|
(general-def
|
||||||
|
:prefix-map 'syd-leader-notes-map
|
||||||
|
"r" `("Org-roam" . ,syd-leader-notes-roam-map))
|
||||||
|
;; Rebind Imenu keybind to `consult-org-heading'. It's similar enough in
|
||||||
|
;; appearance and functionality, but more reliable and "correct."
|
||||||
|
;; REVIEW: Perhaps it would be best to implement `imenu-create-index-function'
|
||||||
|
;; using `consult-org-heading'?
|
||||||
|
(general-def
|
||||||
|
:keymaps 'org-mode-map
|
||||||
|
[remap consult-imenu] #'consult-org-heading
|
||||||
|
[remap imenu] #'consult-org-heading)
|
||||||
|
(general-define-key
|
||||||
|
:keymaps 'org-mode-map
|
||||||
|
:states '(normal visual motion emacs insert)
|
||||||
|
:major-modes t
|
||||||
|
:prefix syd-localleader-key
|
||||||
|
:non-normal-prefix syd-alt-localleader-key
|
||||||
|
"m" `("Org-roam" . ,syd-org-roam-mode-map)))
|
||||||
|
|
||||||
|
(use-package org-roam
|
||||||
|
:hook (org-load . syd-org-init-roam-h)
|
||||||
|
:commands (org-roam-buffer-toggle-display
|
||||||
|
org-roam-dailies-capture-today
|
||||||
|
org-roam-dailies-goto-date
|
||||||
|
org-roam-dailies-goto-today
|
||||||
|
org-roam-dailies-goto-tomorrow
|
||||||
|
org-roam-dailies-goto-yesterday)
|
||||||
|
:init (progn (syd-org--init-roam-keybinds)
|
||||||
|
(syd-load-packages-incrementally
|
||||||
|
'(ansi-color dash f rx seq magit-section emacsql)))
|
||||||
|
:custom ((org-roam-directory org-directory)
|
||||||
|
(org-roam-db-location (file-name-concat syd-cache-dir
|
||||||
|
"org-roam.db"))
|
||||||
|
;; Make org-roam buffer sticky; i.e. don't replace it when opening a
|
||||||
|
;; file with an *-other-window command.
|
||||||
|
(org-roam-buffer-window-parameters '((no-delete-other-windows . t)))
|
||||||
|
(org-roam-completion-everywhere t)
|
||||||
|
(org-roam-dailies-capture-templates
|
||||||
|
`(("d" "default" entry "* %?\n%U"
|
||||||
|
:target (file+head "%<%Y-%m-%d>.org" "#+title: %<%Y-%m-%d>")
|
||||||
|
:empty-lines 1))))
|
||||||
|
:config
|
||||||
|
(add-to-list 'org-agenda-files org-roam-directory)
|
||||||
|
(with-eval-after-load 'org-roam-dailies
|
||||||
|
(add-to-list 'org-agenda-files
|
||||||
|
(file-name-concat org-roam-directory
|
||||||
|
org-roam-dailies-directory)))
|
||||||
|
(defun syd-org-init-roam-h ()
|
||||||
|
"Setup `org-roam' but don't immediately initialize its database. Instead,
|
||||||
|
initialize it when it will be actually needed."
|
||||||
|
(cl-letf (((symbol-function #'org-roam-db-sync) #'ignore))
|
||||||
|
(org-roam-db-autosync-enable)))
|
||||||
|
|
||||||
|
(syd-org--init-roam-keybinds)
|
||||||
|
|
||||||
|
(syd-defadvice syd-org-roam-try-init-db-a (&rest _)
|
||||||
|
"Try to initialize org-roam database at the last possible safe moment.
|
||||||
|
In case of failure, fail gracefully."
|
||||||
|
:before #'org-roam-db-query
|
||||||
|
(message "Initializing org-roam database...")
|
||||||
|
(advice-remove 'org-roam-db-query #'syd-org-roam-try-init-db-a)
|
||||||
|
(org-roam-db-sync)))
|
||||||
|
|
||||||
|
(use-package evil-org
|
||||||
|
:hook ((org-mode . evil-org-mode)
|
||||||
|
(org-capture-mode . evil-insert-state))
|
||||||
|
:straight (:type git :host github :repo "doomelpa/evil-org-mode")
|
||||||
|
:init
|
||||||
|
(defvar evil-org-retain-visual-state-on-shift t)
|
||||||
|
(defvar evil-org-special-o/O '(table-row))
|
||||||
|
(defvar evil-org-use-additional-insert t)
|
||||||
|
:config
|
||||||
|
(add-hook 'evil-org-mode-hook #'evil-normalize-keymaps)
|
||||||
|
(evil-org-set-key-theme))
|
||||||
|
|
||||||
|
(use-package evil-org-agenda
|
||||||
|
:hook (org-agenda-mode . evil-org-agenda-mode)
|
||||||
|
:straight nil
|
||||||
|
:config
|
||||||
|
(evil-org-agenda-set-keys)
|
||||||
|
;; Stay away from my leader key!
|
||||||
|
(evil-define-key* 'motion evil-org-agenda-mode-map
|
||||||
|
(kbd syd-leader-key) nil))
|
||||||
|
|
||||||
|
(use-package hide-mode-line
|
||||||
|
:hook (org-mode . hide-mode-line-mode))
|
||||||
|
|
||||||
|
(use-package org-superstar
|
||||||
|
:hook (org-mode . org-superstar-mode)
|
||||||
|
:custom ((org-superstar-headline-bullets-list '(9675))
|
||||||
|
(org-superstar-item-bullet-alist '((?- . ?•)
|
||||||
|
(?+ . ?➤)
|
||||||
|
(?* . ?⋆))))
|
||||||
|
:config
|
||||||
|
;; Stars should use fixed-pitch font to align w/ `org-indent'.
|
||||||
|
(custom-theme-set-faces
|
||||||
|
'user
|
||||||
|
`(org-superstar-header-bullet ((t (:font ,syd-alt-fixed-pitch-font))))
|
||||||
|
`(org-superstar-item ((t (:font ,syd-alt-fixed-pitch-font))))))
|
||||||
|
|
||||||
|
(use-package org-noter
|
||||||
|
:commands org-noter)
|
||||||
|
|
||||||
|
(use-package org-contrib)
|
||||||
|
|
||||||
|
(use-package ox-extra
|
||||||
|
:after org-contrib
|
||||||
|
:config
|
||||||
|
(ox-extras-activate '(latex-header-blocks ignore-headlines)))
|
||||||
|
|
||||||
|
(with-eval-after-load 'org
|
||||||
|
(org-link-set-parameters "wiktionary"
|
||||||
|
:follow #'syd-org-wiktionary-open
|
||||||
|
;; :export #'syd-org-wiktionary-export
|
||||||
|
)
|
||||||
|
(defun syd-org-wiktionary-open (path _)
|
||||||
|
(browse-url (format "https://en.wiktionary.org/wiki/%s"
|
||||||
|
(browse-url-encode-url path))))
|
||||||
|
;; (defun syd-org-wiktionary-export (link description format _)
|
||||||
|
;; (org-export-transcoder))
|
||||||
|
)
|
||||||
|
|
||||||
|
(provide 'syd-org)
|
||||||
|
;;; syd-org.el ends here
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
;;; syd-pdfs.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
;; A better PDF reader for Emacs.
|
||||||
|
(use-package pdf-tools
|
||||||
|
;; Managed by Nix: pdf-tools depends on a standalone compiled binary.
|
||||||
|
:straight nil
|
||||||
|
:mode ("\\.pdf\\'" . pdf-view-mode)
|
||||||
|
:magic ("%PDF" . pdf-view-mode)
|
||||||
|
:general (:keymaps 'pdf-view-mode-map
|
||||||
|
:states 'motion
|
||||||
|
"q" #'kill-current-buffer
|
||||||
|
"d" #'pdf-view-scroll-up-or-next-page
|
||||||
|
"u" #'pdf-view-scroll-down-or-previous-page)
|
||||||
|
:custom ((pdf-view-display-size 'fit-page))
|
||||||
|
:config
|
||||||
|
;; HACK: Fix "Symbol's function definition is void:
|
||||||
|
;; pdf-occur-global-minor-mode" errors on load.
|
||||||
|
;; https://github.com/politza/pdf-tools/issues/206#issuecomment-614885793
|
||||||
|
(use-package pdf-occur
|
||||||
|
:straight nil
|
||||||
|
:commands (pdf-occur-global-minor-mode))
|
||||||
|
(use-package pdf-history
|
||||||
|
:straight nil
|
||||||
|
:commands (pdf-history-minor-mode))
|
||||||
|
(use-package pdf-links
|
||||||
|
:straight nil
|
||||||
|
:commands (pdf-links-minor-mode))
|
||||||
|
(use-package pdf-outline
|
||||||
|
:straight nil
|
||||||
|
:commands (pdf-outline-minor-mode))
|
||||||
|
(use-package pdf-annot
|
||||||
|
:straight nil
|
||||||
|
:commands (pdf-annot-minor-mode))
|
||||||
|
(use-package pdf-sync
|
||||||
|
:straight nil
|
||||||
|
:commands (pdf-sync-minor-mode))
|
||||||
|
;; Despite its namesake, this does not call `pdf-tools-install', it only sets
|
||||||
|
;; up hooks, auto-mode-alist/magic-mode-alist entries, global modes, and
|
||||||
|
;; refreshes pdf-view-mode buffers, if any.
|
||||||
|
;;
|
||||||
|
;; I avoid calling `pdf-tools-install' directly because `pdf-tools' is easy to
|
||||||
|
;; prematurely load in the background (e.g. when exporting an org file or by
|
||||||
|
;; packages like org-pdftools). And I don't want pdf-tools to suddenly block
|
||||||
|
;; Emacs and spew out compiler output for a few minutes in those cases. It's
|
||||||
|
;; abysmal UX. The `pdf-view-mode' advice above works around this with a less
|
||||||
|
;; cryptic failure message, at least.
|
||||||
|
(pdf-tools-install-noverify)
|
||||||
|
(syd-add-hook 'pdf-view-mode-hook
|
||||||
|
#'pdf-view-themed-minor-mode
|
||||||
|
#'hide-mode-line-mode
|
||||||
|
#'pdf-view-auto-slice-minor-mode
|
||||||
|
(defun syd-pdf--init-ui-h ()
|
||||||
|
;; HACK: Flickering pdfs when evil-mode is enabled.
|
||||||
|
(setq-local evil-normal-state-cursor (list nil))))
|
||||||
|
(set-popup-rules!
|
||||||
|
'(("^\\*Outline*" :side right :size 40 :select nil)
|
||||||
|
("^\\*Edit Annotation " :quit nil)
|
||||||
|
("\\(?:^\\*Contents\\|'s annots\\*$\\)" :ignore t)))
|
||||||
|
;; Silence "File *.pdf is large (X MiB), really open?" prompts for PDFs.
|
||||||
|
(syd-defadvice syd-pdf--suppress-large-file-prompts-a
|
||||||
|
(fn size op-type filename &optional offer-raw)
|
||||||
|
:around #'abort-if-file-too-large
|
||||||
|
(unless (string-match-p "\\.pdf\\'" filename)
|
||||||
|
(funcall fn size op-type filename offer-raw))))
|
||||||
|
|
||||||
|
(use-package saveplace-pdf-view
|
||||||
|
:after pdf-view)
|
||||||
|
|
||||||
|
(provide 'syd-pdfs)
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
;; syd-popups.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(use-package popper
|
||||||
|
:hook (on-init-ui-hook)
|
||||||
|
:init
|
||||||
|
(setq popper-display-control nil
|
||||||
|
popper-reference-buffers
|
||||||
|
(list (lambda (buf)
|
||||||
|
(with-current-buffer buf
|
||||||
|
(bound-and-true-p doom-popup-buffer-mode)))))
|
||||||
|
:config
|
||||||
|
(popper-mode 1))
|
||||||
|
|
||||||
|
;; An optional dependency of `doom-popup'. As the name suggests, it provides a
|
||||||
|
;; minor mode that hides the mode-line. `doom-popup' will automatically enable
|
||||||
|
;; it in popup windowss.
|
||||||
|
(use-package hide-mode-line
|
||||||
|
:commands hide-mode-line-mode
|
||||||
|
:preface
|
||||||
|
;; `doom-popup' tests (boundp 'hide-mode-line-mode) before it tries enabling
|
||||||
|
;; or disabling the mode. We must define this because `hide-mode-line' does
|
||||||
|
;; not autoload it.
|
||||||
|
(defvar hide-mode-line-mode nil))
|
||||||
|
|
||||||
|
(use-package doom-popup
|
||||||
|
:straight (:type git
|
||||||
|
:host gitlab
|
||||||
|
:repo "crumbtoo/doom-popup"))
|
||||||
|
|
||||||
|
(provide 'syd-popups)
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
;;; syd-projects.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(require 'syd-constants)
|
||||||
|
|
||||||
|
(with-eval-after-load 'project ; Built-in
|
||||||
|
;; Stay out of my config directory!
|
||||||
|
(setq project-list-file (file-name-concat syd-cache-dir "known-projects"))
|
||||||
|
;; For each command in `project-switch-commands' will assign it the key found
|
||||||
|
;; in `project-prefix-map'. We emulate that behaviour but for our own
|
||||||
|
;; `syd-leader-project-map'.
|
||||||
|
(let* ((project-key
|
||||||
|
(lambda (f)
|
||||||
|
(key-description
|
||||||
|
(where-is-internal
|
||||||
|
f
|
||||||
|
;; If the keymap is not wrapped in a list,
|
||||||
|
;; `where-is-internal' will also search the
|
||||||
|
;; global ;; keymaps
|
||||||
|
(list syd-leader-project-map)
|
||||||
|
;; First result only.
|
||||||
|
t))))
|
||||||
|
(switch-cmd (lambda (command name &optional key)
|
||||||
|
(append (list command name)
|
||||||
|
(list (or key (funcall project-key command)))))))
|
||||||
|
(add-to-list 'project-switch-commands
|
||||||
|
(funcall switch-cmd #'syd-project-root-find-file "Browse"))))
|
||||||
|
|
||||||
|
(defun syd-project-checkout (repo-uri)
|
||||||
|
(interactive (list (read-string "Repo: ")))
|
||||||
|
(let* ((repo-name
|
||||||
|
(when (string-match (rx "/" (group-n 1 (+ (any alphanumeric "-_")))
|
||||||
|
(? ".git") eol)
|
||||||
|
repo-uri)
|
||||||
|
(match-string 1 repo-uri)))
|
||||||
|
(dest (file-name-concat (expand-file-name "~/git") repo-name)))
|
||||||
|
(shell-command (format "git clone %s %s" repo-uri dest))
|
||||||
|
(find-file dest)))
|
||||||
|
|
||||||
|
;; Projection provides a Projectile-like project management library atop
|
||||||
|
;; Emacs built-in project.el. It's more lightweight, while still featureful.
|
||||||
|
(use-package projection
|
||||||
|
:straight (:type git
|
||||||
|
:host github
|
||||||
|
:repo "msyds/projection"
|
||||||
|
:files (:defaults "src/*.el"))
|
||||||
|
;; Enable the `projection-hook' feature.
|
||||||
|
:hook (after-init . global-projection-hook-mode)
|
||||||
|
:general (:keymaps 'syd-leader-project-map
|
||||||
|
"R" #'projection-commands-run-project
|
||||||
|
"M" #'projection-multi-compile
|
||||||
|
"T" #'projection-commands-test-project))
|
||||||
|
|
||||||
|
;; Allow interactively selecting available compilation targets from the
|
||||||
|
;; current project type.
|
||||||
|
(use-package projection-multi
|
||||||
|
:straight (:type git
|
||||||
|
:host github
|
||||||
|
:repo "msyds/projection"
|
||||||
|
:files ("src/projection-multi/*.el"))
|
||||||
|
:general (:keymaps 'syd-leader-project-map
|
||||||
|
"M" #'projection-multi-compile)
|
||||||
|
:after projection
|
||||||
|
:config
|
||||||
|
(require 'projection-multi-bb))
|
||||||
|
|
||||||
|
;; ;; Embark integration for projection-multi.
|
||||||
|
;; (use-package projection-multi-embark
|
||||||
|
;; :after (embark projection-multi)
|
||||||
|
;; ;; Add the projection set-command bindings to
|
||||||
|
;; ;; `compile-multi-embark-command-map'.
|
||||||
|
;; :config (projection-multi-embark-setup-command-map))
|
||||||
|
|
||||||
|
(use-package skeletor
|
||||||
|
:commands (skeletor-create-project-at skeletor-create-project)
|
||||||
|
:custom ((skeletor-project-directory (expand-file-name "~/src"))
|
||||||
|
(skeletor-completing-read-function #'completing-read))
|
||||||
|
:general (:keymaps 'syd-leader-project-map
|
||||||
|
"n" #'skeletor-create-project
|
||||||
|
"N" #'skeletor-create-project-at)
|
||||||
|
:config
|
||||||
|
;; TODO: Fix the `ns' form in Clojure files.
|
||||||
|
(defun syd-fix-clojure-file-name! (file-name)
|
||||||
|
(let ((new-file-name (->> file-name
|
||||||
|
(string-replace "-" "_")
|
||||||
|
;; NOTE: Will cause fuckiness if file-name starts
|
||||||
|
;; with a dot.
|
||||||
|
(string-replace "." "/"))))
|
||||||
|
(make-directory (file-name-directory new-file-name) t)
|
||||||
|
(rename-file file-name new-file-name)))
|
||||||
|
(defun syd-fix-clojure-file-names! (directory)
|
||||||
|
(let ((default-directory (file-name-concat directory "src")))
|
||||||
|
(dolist (file-name (directory-files "." nil "-" t))
|
||||||
|
(syd-fix-clojure-file-name! file-name))))
|
||||||
|
(skeletor-define-template "clj-nix"
|
||||||
|
:substitutions
|
||||||
|
'(("__PROJECT-OWNER__" . (lambda ()
|
||||||
|
(read-no-blanks-input "Project owner: "))))
|
||||||
|
:before-git
|
||||||
|
(lambda (dir)
|
||||||
|
;; Use underscores instead of hyphens in clj file names.
|
||||||
|
(syd-fix-clojure-file-names! dir)
|
||||||
|
;; REVIEW: Is it safe to make this be async? We require that the command
|
||||||
|
;; has finished before Git initialises.
|
||||||
|
(skeletor-shell-command "nix run github:jlesquembre/clj-nix#deps-lock"
|
||||||
|
dir)))
|
||||||
|
(skeletor-define-template "haskell-flake"
|
||||||
|
:title "Haskell (Flake)"
|
||||||
|
:license-file-name "LICENSE"))
|
||||||
|
|
||||||
|
(provide 'syd-projects)
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
;;; syd-scratch.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(require 'syd-prelude)
|
||||||
|
|
||||||
|
;; Persist the scratch buffer between sessions. Note that it is not persisted
|
||||||
|
;; between boots.
|
||||||
|
;; TODO: This could be better deferred.
|
||||||
|
(use-package persistent-scratch
|
||||||
|
:hook (after-init)
|
||||||
|
:custom (persistent-scratch-save-file
|
||||||
|
(file-name-concat syd-data-dir "scratch"))
|
||||||
|
:config
|
||||||
|
;; The default warning message is a bit too error-looking for my tastes. This
|
||||||
|
;; is the same function, but with a tamer warning message.
|
||||||
|
(defun syd--persistent-scratch--auto-restore-a ()
|
||||||
|
"Automatically restore the scratch buffer once per session."
|
||||||
|
(unless persistent-scratch--auto-restored
|
||||||
|
(condition-case err
|
||||||
|
(persistent-scratch-restore)
|
||||||
|
(error
|
||||||
|
(message "No previous scratch buffer to restore")))
|
||||||
|
(setq persistent-scratch--auto-restored t)))
|
||||||
|
(advice-add #'persistent-scratch--auto-restore
|
||||||
|
:override #'syd--persistent-scratch--auto-restore-a)
|
||||||
|
|
||||||
|
;; Arrange the activation of autosave and auto-restore (if applicable) on
|
||||||
|
;; Emacs start.
|
||||||
|
(persistent-scratch-setup-default))
|
||||||
|
|
||||||
|
(use-package emacs
|
||||||
|
:custom ((initial-scratch-message
|
||||||
|
(with-temp-buffer
|
||||||
|
(insert-file-contents (file-name-concat user-emacs-directory
|
||||||
|
"cool-deer.org"))
|
||||||
|
(buffer-string)))
|
||||||
|
;; Initial major mode for scratch buffer.
|
||||||
|
(initial-major-mode 'fundamental-mode)
|
||||||
|
;; Disable the initial "help" screen, in favour of starting off in
|
||||||
|
;; the scratch buffer.
|
||||||
|
(inhibit-splash-screen t)
|
||||||
|
(inhibit-startup-screen t)
|
||||||
|
(inhibit-startup-message t)))
|
||||||
|
|
||||||
|
(provide 'syd-scratch)
|
||||||
|
;;; syd-scratch.el ends here
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
;;; syd-smartparens.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
;; Smartparens, most importantly to me, automatically closes opened delimiters.
|
||||||
|
;; It additionally offers a lot of Paredit-like functionality, but we do not yet
|
||||||
|
;; use any of it.
|
||||||
|
;; FIXME: If the first buffer visited is the eval minibuffer, smartparens is not
|
||||||
|
;; activated.
|
||||||
|
(use-package smartparens
|
||||||
|
:hook (on-first-buffer . smartparens-global-mode)
|
||||||
|
:commands (sp-pair sp-local-pair sp-with-modes sp-point-in-comment
|
||||||
|
sp-point-in-string)
|
||||||
|
:custom
|
||||||
|
;; Overlays are too distracting and not terribly helpful. show-parens does
|
||||||
|
;; this for us already (and is faster), so...
|
||||||
|
((sp-highlight-pair-overlay nil)
|
||||||
|
(sp-highlight-wrap-overlay nil)
|
||||||
|
(sp-highlight-wrap-tag-overlay nil)
|
||||||
|
|
||||||
|
;; The default is 100. because smartparen's scans are relatively expensive
|
||||||
|
;; (especially with large pair lists for some modes), we reduce it, as a
|
||||||
|
;; better compromise between performance and accuracy.
|
||||||
|
(sp-max-prefix-length 25)
|
||||||
|
|
||||||
|
;; No pair has any business being longer than 4 characters; if they must, set
|
||||||
|
;; it buffer-locally. It's less work for smartparens.
|
||||||
|
(sp-max-pair-length 4))
|
||||||
|
:config
|
||||||
|
;; Load default config.
|
||||||
|
(require 'smartparens-config)
|
||||||
|
;; Silence some harmless but annoying echo-area spam
|
||||||
|
(dolist (key '(:unmatched-expression :no-matching-tag))
|
||||||
|
(setf (alist-get key sp-message-alist) nil))
|
||||||
|
|
||||||
|
(syd-add-hook 'eval-expression-minibuffer-setup-hook
|
||||||
|
(defun syd-init-smartparens-in-eval-expression-h ()
|
||||||
|
"Enable `smartparens-mode' in the minibuffer for `eval-expression'. This
|
||||||
|
includes everything that calls `read--expression', e.g. `edebug-eval-expression'
|
||||||
|
It is only enabled it if `smartparens-global-mode' is on."
|
||||||
|
(when smartparens-global-mode
|
||||||
|
(smartparens-mode 1))))
|
||||||
|
|
||||||
|
(syd-add-hook 'minibuffer-setup-hook
|
||||||
|
(defun syd-init-smartparens-in-minibuffer-maybe-h ()
|
||||||
|
"Enable `smartparens' for non-`eval-expression' commands. Only enable
|
||||||
|
`smartparens-mode' if `smartparens-global-mode' is on."
|
||||||
|
(when (and smartparens-global-mode (memq this-command '(evil-ex)))
|
||||||
|
(smartparens-mode 1))))
|
||||||
|
|
||||||
|
;; You're likely writing lisp in the minibuffer, therefore, disable these
|
||||||
|
;; quote pairs, which lisps doesn't use for strings:
|
||||||
|
(sp-local-pair '(minibuffer-mode minibuffer-inactive-mode) "'" nil :actions nil)
|
||||||
|
(sp-local-pair '(minibuffer-mode minibuffer-inactive-mode) "`" nil :actions nil))
|
||||||
|
|
||||||
|
(provide 'syd-smartparens)
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
;;; syd-snippets.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(use-package yasnippet
|
||||||
|
:hook (on-first-input . yas-global-mode)
|
||||||
|
:bind (:map syd-leader-insert-map ("s" . yas-insert-snippet)))
|
||||||
|
|
||||||
|
(use-package yasnippet-snippets
|
||||||
|
:after yasnippet)
|
||||||
|
|
||||||
|
(provide 'syd-snippets)
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
;;; syd-tabs.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
;; Many themes neglect tab-bar customisation, leaving it completely unstyled.
|
||||||
|
;; `vim-tab-bar' will style it to look like Vim's tab-bar, but more importantly,
|
||||||
|
;; it will colour it to match the current theme.
|
||||||
|
(use-package vim-tab-bar
|
||||||
|
:commands vim-tab-bar-mode)
|
||||||
|
|
||||||
|
(with-eval-after-load 'tab-bar
|
||||||
|
(setq tab-bar-new-tab-to 'rightmost)
|
||||||
|
|
||||||
|
(defun syd-tab-bar-make-free-name ()
|
||||||
|
(cl-loop for i from 1
|
||||||
|
with candidate = nil
|
||||||
|
do (setq candidate (format "#%d" i))
|
||||||
|
while (tab-bar--tab-index-by-name candidate)
|
||||||
|
finally return candidate))
|
||||||
|
|
||||||
|
(defun syd-tab-bar-rename-tab (tab new-name)
|
||||||
|
;; HACK: Using `tab-bar-rename-tab' doesn't work, for some reason. This
|
||||||
|
;; relies on the internal representation of tabs.
|
||||||
|
(setf (alist-get 'name tab) new-name
|
||||||
|
(alist-get 'explicit-name tab) t))
|
||||||
|
|
||||||
|
(defvar syd-tab-bar-name-function #'syd-tab-bar-make-free-name
|
||||||
|
"Nullary function expected to return the name for a new tab.")
|
||||||
|
|
||||||
|
(defvar syd-tab-bar-default-buffer-function #'scratch-buffer)
|
||||||
|
|
||||||
|
(syd-add-hook 'tab-bar-tab-post-open-functions
|
||||||
|
(defun syd-tab-bar--name-new-tab-h (tab)
|
||||||
|
"Hooks to `tab-bar-tab-post-open-functions' such that new tabs will be
|
||||||
|
given \"explicit names\" that are static."
|
||||||
|
(syd-tab-bar-rename-tab tab (funcall syd-tab-bar-name-function))))
|
||||||
|
|
||||||
|
(defun syd-tab-bar--show-tab-bar-h (_tab)
|
||||||
|
"Show the tab-bar if it is not already visible. See
|
||||||
|
`syd-tab-bar-hide-tab-bar-h'."
|
||||||
|
(unless vim-tab-bar-mode
|
||||||
|
(vim-tab-bar-mode 1)))
|
||||||
|
|
||||||
|
(defun syd-tab-bar-new-tab ()
|
||||||
|
(interactive)
|
||||||
|
(let ((tab-bar-tab-post-open-functions
|
||||||
|
(-cons* (lambda (_tab)
|
||||||
|
(switch-to-buffer
|
||||||
|
(funcall syd-tab-bar-default-buffer-function)))
|
||||||
|
#'syd-tab-bar--show-tab-bar-h
|
||||||
|
tab-bar-tab-post-open-functions)))
|
||||||
|
(tab-bar-new-tab)))
|
||||||
|
|
||||||
|
(syd-add-hook 'tab-bar-tab-pre-close-functions
|
||||||
|
(defun syd-tab-bar-hide-tab-bar-h (_tab _final-tab-p)
|
||||||
|
"Hide the tab-bar when there is only a single tab to show. See
|
||||||
|
`syd-tab-bar--show-tab-bar-h'."
|
||||||
|
(when (<= (length (tab-bar-tabs)) 2) ; The tab hasn't yet been removed.
|
||||||
|
(tab-bar-mode -1))))
|
||||||
|
|
||||||
|
(defun syd-tab-bar-new-named-tab (name)
|
||||||
|
(interactive (list (read-string "Tab name: ")))
|
||||||
|
;; Relies on `syd-tab-bar--name-new-tab-h'.
|
||||||
|
(let ((syd-tab-bar-name-function (lambda () name)))
|
||||||
|
(syd-tab-bar-new-tab)))
|
||||||
|
|
||||||
|
(general-def
|
||||||
|
:prefix-map 'syd-leader-tab-map
|
||||||
|
"[" #'tab-previous
|
||||||
|
"]" #'tab-next
|
||||||
|
"r" #'tab-rename
|
||||||
|
"R" #'tab-rename
|
||||||
|
"n" #'syd-tab-bar-new-tab
|
||||||
|
"N" #'syd-tab-bar-new-named-tab
|
||||||
|
"d" #'tab-close)
|
||||||
|
(general-def
|
||||||
|
:keymaps 'syd-leader-map
|
||||||
|
"TAB" `("Tabs" . ,syd-leader-tab-map)
|
||||||
|
"<tab>" `("Tabs" . ,syd-leader-tab-map)))
|
||||||
|
|
||||||
|
(provide 'syd-tabs)
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
;;; syd-tooling.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(defun syd-lsp-lookup-documentation ()
|
||||||
|
(interactive)
|
||||||
|
(when-let* ((buf (get-buffer "*lsp-help*")))
|
||||||
|
(kill-buffer buf))
|
||||||
|
(call-interactively #'lsp-describe-thing-at-point)
|
||||||
|
(when-let* ((buf (get-buffer "*lsp-help*")))
|
||||||
|
(when (get-buffer-window-list buf)
|
||||||
|
;; Bury the buffer so the popup system has full control over how it's
|
||||||
|
;; selected.
|
||||||
|
(bury-buffer buf)
|
||||||
|
buf)))
|
||||||
|
|
||||||
|
(use-package lsp-mode
|
||||||
|
:init
|
||||||
|
;; We'll bind things ourselves.
|
||||||
|
(setq lsp-keymap-prefix nil)
|
||||||
|
;; Keep state out of my config dir.
|
||||||
|
(setq lsp-session-file (file-name-concat syd-data-dir "lsp-session")
|
||||||
|
;; We disable `lsp-install-server', but I don't want this to be nil.
|
||||||
|
lsp-server-install-dir (file-name-concat syd-data-dir "lsp"))
|
||||||
|
;; Disable features that have great potential to be slow. LSPs tend to be
|
||||||
|
;; quite slow compared to non-LSP equivalents.
|
||||||
|
(setq lsp-enable-folding nil
|
||||||
|
lsp-enable-text-document-color nil)
|
||||||
|
;; Reduce unexpected modifications to code
|
||||||
|
(setq lsp-enable-on-type-formatting nil)
|
||||||
|
;; Make breadcrumbs opt-in; they're redundant with the modeline and imenu
|
||||||
|
(setq lsp-headerline-breadcrumb-enable nil)
|
||||||
|
:hook (lsp-mode . lsp-enable-which-key-integration)
|
||||||
|
:commands lsp
|
||||||
|
:general (:keymaps 'syd-leader-code-map
|
||||||
|
"a" #'lsp-execute-code-action
|
||||||
|
"r" #'lsp-rename)
|
||||||
|
:custom (; Fixes type error when using rename.
|
||||||
|
(lsp-rename-use-prepare nil))
|
||||||
|
:config
|
||||||
|
(syd-defadvice syd-lsp-install-server-a ()
|
||||||
|
"Override and disbale `lsp-install-server'"
|
||||||
|
:override #'lsp-install-server
|
||||||
|
(user-error (concat "Ignoring a call to `lsp-install-server'"
|
||||||
|
" — tell the caller to use Nix!")))
|
||||||
|
(set-popup-rule! (rx line-start "*lsp-" (or "help" "install"))
|
||||||
|
:size 13 :quit t :select nil)
|
||||||
|
|
||||||
|
;; DEPRECATED: Remove once syd-strategies is working.
|
||||||
|
(syd-add-hook 'lsp-mode-hook
|
||||||
|
(defun syd-lsp-set-handlers-h ()
|
||||||
|
(setq-local syd-lookup-documentation-handlers
|
||||||
|
(list #'syd-lsp-lookup-documentation)))))
|
||||||
|
|
||||||
|
(use-package envrc
|
||||||
|
;; REVIEW: Can we load this any later/better?
|
||||||
|
:hook (on-first-file . envrc-global-mode)
|
||||||
|
:general
|
||||||
|
(:prefix-map 'syd-leader-file-env-map
|
||||||
|
"a" #'envrc-allow
|
||||||
|
"r" #'envrc-reload)
|
||||||
|
(:keymaps 'syd-leader-file-map
|
||||||
|
"e" `("Environment" . ,syd-leader-file-env-map))
|
||||||
|
:config
|
||||||
|
(set-popup-rule! (rx "*envrc*")
|
||||||
|
:quit t :ttl 0))
|
||||||
|
|
||||||
|
(provide 'syd-tooling)
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
;;; syd-tramp.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(with-eval-after-load 'tramp
|
||||||
|
(setq tramp-persistency-file-name
|
||||||
|
(file-name-concat syd-cache-dir "tramp"))
|
||||||
|
(setq tramp-auto-save-directory
|
||||||
|
(file-name-concat syd-cache-dir "tramp-autosave/"))
|
||||||
|
;; TRAMP's default settings try to disable Readline, *rc files, profiles, etc.
|
||||||
|
;; This is all very important and prevents unexpected behaviour and various
|
||||||
|
;; hangs/crashes. However, the default settings (`tramp-sh-extra-args') can
|
||||||
|
;; only kick in when the shell is accurately identified — on my NixOS system,
|
||||||
|
;; /bin/sh links to Bash. Thus, the appropriate flags are never applied,
|
||||||
|
;; unless we make the Bash of the matter explicit.
|
||||||
|
(setq tramp-encoding-shell (executable-find "bash"))
|
||||||
|
(add-to-list 'tramp-remote-path 'tramp-own-remote-path))
|
||||||
|
|
||||||
|
(provide 'syd-tramp)
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
;;; syd-trust.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(setq safe-local-variable-directories
|
||||||
|
(list "/persist/dots"
|
||||||
|
(expand-file-name "~/org")))
|
||||||
|
|
||||||
|
(provide 'syd-trust)
|
||||||
@@ -0,0 +1,200 @@
|
|||||||
|
;;; syd-ui.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(require 'syd-prelude)
|
||||||
|
|
||||||
|
(defvar syd-fixed-pitch-font
|
||||||
|
(font-spec :family "VictorMono Nerd Font" :size 13)
|
||||||
|
"Default fixed-pitch (monospace) font.")
|
||||||
|
|
||||||
|
(defvar syd-variable-pitch-font
|
||||||
|
(font-spec :family "IBM Plex Serif" :size 15)
|
||||||
|
"Default variable-pitch font.")
|
||||||
|
|
||||||
|
(defvar syd-alt-fixed-pitch-font
|
||||||
|
(font-spec :family "JuliaMono" :size 16)
|
||||||
|
"A monospace font secondary to `syd-fixed-pitch-font'.")
|
||||||
|
|
||||||
|
(defface syd-alt-fixed-pitch
|
||||||
|
`((t (:inherit fixed-pitch :font ,syd-alt-fixed-pitch-font)))
|
||||||
|
"TODO")
|
||||||
|
|
||||||
|
(defface syd-apl
|
||||||
|
`((t (:inherit syd-alt-fixed-pitch)))
|
||||||
|
"Face for APL code")
|
||||||
|
|
||||||
|
;; Beautiful theme in dark and light.
|
||||||
|
(use-package kanagawa-themes
|
||||||
|
:config
|
||||||
|
(load-theme 'kanagawa-wave t))
|
||||||
|
|
||||||
|
(defun syd-init-fonts-h ()
|
||||||
|
"Loads `syd-fixed-pitch-font' and `syd-variable-pitch-font'."
|
||||||
|
(dolist (map `((default . ,syd-fixed-pitch-font)
|
||||||
|
(fixed-pitch . ,syd-fixed-pitch-font)
|
||||||
|
(variable-pitch . ,syd-variable-pitch-font)))
|
||||||
|
(pcase-let ((`(,face . ,font) map))
|
||||||
|
(set-face-attribute face nil
|
||||||
|
:width 'normal :weight 'normal
|
||||||
|
:slant 'normal :font font))))
|
||||||
|
|
||||||
|
(defun syd-configure-default-frame-h ()
|
||||||
|
"Customise the default frame, primarily by adding to `default-frame-alist'."
|
||||||
|
;; Maximise the frame.
|
||||||
|
;; (add-to-list 'default-frame-alist '(fullscreen . maximized))
|
||||||
|
;; Disable the titlebar and borders (decorations).
|
||||||
|
(add-to-list 'default-frame-alist '(undecorated . t)))
|
||||||
|
|
||||||
|
(let ((hook (if (daemonp)
|
||||||
|
'server-after-make-frame-hook
|
||||||
|
'after-init-hook)))
|
||||||
|
(add-hook hook #'syd-init-fonts-h)
|
||||||
|
(add-hook hook #'syd-configure-default-frame-h))
|
||||||
|
|
||||||
|
;; Use JuliaMono as a fallback for some glyphs that VictorMono does not cover.
|
||||||
|
(dolist (char-range '((#x0250 . #x02af) ; IPA extensions
|
||||||
|
(#x2200 . #x22FF))) ; Mathematical operators
|
||||||
|
(set-fontset-font "fontset-default" char-range "JuliaMono"))
|
||||||
|
|
||||||
|
(use-package emacs
|
||||||
|
;; Display (relative) line numbers only in prog-mode derivatives.
|
||||||
|
:hook ((prog-mode-hook . display-line-numbers-mode)
|
||||||
|
;; (on-init-ui-hook . syd-configure-default-frame-h)
|
||||||
|
;; (on-init-ui-hook . syd-init-fonts-h)
|
||||||
|
)
|
||||||
|
:custom ((display-line-numbers-type 'relative)
|
||||||
|
;; Always ask "y/n"; never "yes/no".
|
||||||
|
(use-short-answers t)
|
||||||
|
;; Scroll compilation buffer to follow output.
|
||||||
|
(compilation-scroll-output t)
|
||||||
|
;; Allow `fit-window-to-buffer' to make horizontal adjustments.
|
||||||
|
(fit-window-to-buffer-horizontally t)
|
||||||
|
;; I don't like that `grep' asks me to save unsaved files. It makes
|
||||||
|
;; me think it's about to kill my buffers.
|
||||||
|
(grep-save-buffers nil)
|
||||||
|
;; The default value is `ask', meaning that Emacs will ask for
|
||||||
|
;; confirmation any time you follow a symlink to a file under version
|
||||||
|
;; control. The documentation claims this is "dangerous, and
|
||||||
|
;; probably not what you want;" I personally don't see it, and it's
|
||||||
|
;; usually what I want.
|
||||||
|
(vc-follow-symlinks t)
|
||||||
|
;; Log native-compiler warnings, but don't display the
|
||||||
|
;; buffer. Most of the warnings are "`X' is not known to
|
||||||
|
;; be defined" which are typically nothing worth concerning.
|
||||||
|
(native-comp-async-report-warnings-errors 'silent)
|
||||||
|
;; Don't recenter the view unless >10 lines are scrolled off-screen
|
||||||
|
;; in a single movement.
|
||||||
|
(scroll-conservatively 10)
|
||||||
|
;; In modes making use of `recenter-top-bottom' (e.g. Comint,
|
||||||
|
;; Eshell), this will make the command behave more like a plain old
|
||||||
|
;; `clear` invocation.
|
||||||
|
(recenter-positions '(top)))
|
||||||
|
:config
|
||||||
|
;; Disable the menu bar, scroll bar, and tool bar.
|
||||||
|
(menu-bar-mode -1)
|
||||||
|
(scroll-bar-mode -1)
|
||||||
|
(tool-bar-mode -1)
|
||||||
|
;; Remember allowed risky variabled.
|
||||||
|
(advice-add 'risky-local-variable-p :override #'ignore))
|
||||||
|
|
||||||
|
(defun syd-init-kill-process-buffer-on-exit ()
|
||||||
|
(defun syd-comint--kill-buffer-sentinel (process _output)
|
||||||
|
"Process sentinel to auto kill associated buffer once PROCESS dies."
|
||||||
|
;; Note that `process-exit-status' returns zero when the process has not yet
|
||||||
|
;; died.
|
||||||
|
(unless (and process (zerop (process-exit-status process)))
|
||||||
|
(let ((buffer (process-buffer process)))
|
||||||
|
(with-current-buffer buffer
|
||||||
|
(goto-char (point-max))
|
||||||
|
(insert (format "\n[Process exited with exit status %d]"
|
||||||
|
(process-exit-status process))))
|
||||||
|
(kill-buffer (process-buffer process)))))
|
||||||
|
|
||||||
|
(defun syd-comint--add-kill-on-exit-sentinel ()
|
||||||
|
"Replace current process sentinel with a new sentinel composed of the
|
||||||
|
current one and `syd-comint--kill-buffer-sentinel'."
|
||||||
|
(let* ((process (get-buffer-process (current-buffer)))
|
||||||
|
(original-sentinel (process-sentinel process))
|
||||||
|
(sentinel-list
|
||||||
|
(-remove #'null
|
||||||
|
(list original-sentinel #'syd-comint--kill-buffer-sentinel)))
|
||||||
|
(combined-sentinel
|
||||||
|
(lambda (process line)
|
||||||
|
(--each sentinel-list
|
||||||
|
(funcall it process line)))))
|
||||||
|
(setf (process-sentinel process) combined-sentinel)))
|
||||||
|
|
||||||
|
(defvar syd-comint--kill-on-exit-h-has-run nil
|
||||||
|
"Whether or not `syd-comint--kill-on-exit-h' has run or not. We need this
|
||||||
|
buffer-local var to prevent the hook from running several times, as can happen
|
||||||
|
for example when calling `shell'.")
|
||||||
|
|
||||||
|
(defun syd-comint--async-funcall (fn &optional buffer args delay)
|
||||||
|
"Run FUNCTION with ARGS in the buffer after a short DELAY."
|
||||||
|
(run-at-time (or delay 0.2) nil
|
||||||
|
`(lambda ()
|
||||||
|
(with-current-buffer ,buffer ,(cons fn args)))))
|
||||||
|
|
||||||
|
(syd-add-hook 'comint-mode-hook
|
||||||
|
(defun syd-comint--kill-on-exit-h ()
|
||||||
|
(unless syd-comint--kill-on-exit-h-has-run
|
||||||
|
(setq-local syd-comint--kill-on-exit-h-has-run t)
|
||||||
|
(syd-comint--async-funcall
|
||||||
|
#'syd-comint--add-kill-on-exit-sentinel
|
||||||
|
(current-buffer))))))
|
||||||
|
|
||||||
|
(with-eval-after-load 'comint
|
||||||
|
(require 'syd-kanagawa)
|
||||||
|
(custom-theme-set-faces
|
||||||
|
'user
|
||||||
|
;; Default prompt face is very ugly. Give it a more subtle look.
|
||||||
|
`(comint-highlight-prompt
|
||||||
|
((t :foreground ,(syd-kanagawa-get 'old-white)
|
||||||
|
:background unspecified
|
||||||
|
:weight bold))))
|
||||||
|
|
||||||
|
(general-def
|
||||||
|
:keymaps 'comint-mode-map
|
||||||
|
:states '(normal insert)
|
||||||
|
"C-k" #'comint-previous-input
|
||||||
|
"C-j" #'comint-next-input
|
||||||
|
"C-s" #'consult-history)
|
||||||
|
(general-def
|
||||||
|
:keymaps 'comint-mode-map
|
||||||
|
:states 'insert
|
||||||
|
"C-d" #'comint-delchar-or-maybe-eof))
|
||||||
|
|
||||||
|
(syd-add-hook 'on-init-ui-hook
|
||||||
|
(defun syd-init-ui-hacks ()
|
||||||
|
(set-popup-rule! "*Backtrace*"
|
||||||
|
:size #'doom-popup-shrink-to-fit)
|
||||||
|
(set-popup-rule! "*Messages*"
|
||||||
|
:ttl nil
|
||||||
|
:quit t)
|
||||||
|
(syd-init-kill-process-buffer-on-exit)
|
||||||
|
;; Required for :quit t to do anything.
|
||||||
|
(evil-set-initial-state 'messages-buffer-mode 'motion)
|
||||||
|
(evil-set-initial-state 'debugger-mode 'normal)
|
||||||
|
(set-popup-rule! shell-command-buffer-name-async
|
||||||
|
:slot -2
|
||||||
|
:modeline nil
|
||||||
|
:ttl nil)))
|
||||||
|
|
||||||
|
;; Display form-feed characters as horizontal lines.
|
||||||
|
(use-package form-feed-st
|
||||||
|
:config
|
||||||
|
;; Set the colour of the horizontal lines to be the same as comments.
|
||||||
|
(custom-theme-set-faces
|
||||||
|
'user
|
||||||
|
`(form-feed-st-line
|
||||||
|
((t :strike-through
|
||||||
|
,(plist-get (custom-face-attributes-get font-lock-comment-face
|
||||||
|
(selected-frame))
|
||||||
|
:foreground)))))
|
||||||
|
(global-form-feed-st-mode))
|
||||||
|
|
||||||
|
(use-package fcitx
|
||||||
|
:hook (on-first-input . fcitx-aggressive-setup)
|
||||||
|
:custom ((fcitx-use-dbus 'fcitx5)
|
||||||
|
(fcitx-remote-command "fcitx5-remote")))
|
||||||
|
|
||||||
|
(provide 'syd-ui)
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
;;; syd-use-package.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(defvar syd-incremental-idle-timer 0.75
|
||||||
|
"How long (in idle seconds) in between incrementally loading packages.")
|
||||||
|
|
||||||
|
(defvar syd-incremental-first-idle-timer (if (daemonp) 0 2.0)
|
||||||
|
"How long (in idle seconds) until incremental loading starts.
|
||||||
|
|
||||||
|
Set this to nil to disable incremental loading at startup.
|
||||||
|
Set this to 0 to load all incrementally deferred packages immediately at
|
||||||
|
`after-init-hook'.")
|
||||||
|
|
||||||
|
(defvar syd-incremental-packages '(t)
|
||||||
|
"A list of packages to load incrementally after startup. Any large packages
|
||||||
|
here may cause noticeable pauses, so it's recommended you break them up into
|
||||||
|
sub-packages. For example, `org' is comprised of many packages, and might be
|
||||||
|
broken up into:
|
||||||
|
|
||||||
|
(syd-load-packages-incrementally
|
||||||
|
'(calendar find-func format-spec org-macs org-compat
|
||||||
|
org-faces org-entities org-list org-pcomplete org-src
|
||||||
|
org-footnote org-macro ob org org-clock org-agenda
|
||||||
|
org-capture))
|
||||||
|
|
||||||
|
This is already done by the lang/org module, however.
|
||||||
|
|
||||||
|
If you want to disable incremental loading altogether, either remove
|
||||||
|
`syd-load-packages-incrementally-h' from `after-init-hook' or set
|
||||||
|
`syd-incremental-first-idle-timer' to nil. Incremental loading does not occur
|
||||||
|
in daemon sessions (they are loaded immediately at startup).")
|
||||||
|
|
||||||
|
(defun syd-load-packages-incrementally (packages &optional now)
|
||||||
|
"Registers PACKAGES to be loaded incrementally.
|
||||||
|
|
||||||
|
If NOW is non-nil, PACKAGES will be marked for incremental loading next time
|
||||||
|
Emacs is idle for `syd-incremental-first-idle-timer' seconds (falls back to
|
||||||
|
`syd-incremental-idle-timer'), then in `syd-incremental-idle-timer' intervals
|
||||||
|
afterwards."
|
||||||
|
(let* ((gc-cons-threshold most-positive-fixnum)
|
||||||
|
(first-idle-timer (or syd-incremental-first-idle-timer
|
||||||
|
syd-incremental-idle-timer)))
|
||||||
|
(if (not now)
|
||||||
|
(cl-callf append syd-incremental-packages packages)
|
||||||
|
(while packages
|
||||||
|
(let ((req (pop packages))
|
||||||
|
idle-time)
|
||||||
|
(unless (featurep req)
|
||||||
|
(condition-case-unless-debug e
|
||||||
|
(and
|
||||||
|
(or (null (setq idle-time (current-idle-time)))
|
||||||
|
(< (float-time idle-time) first-idle-timer)
|
||||||
|
(not
|
||||||
|
(while-no-input
|
||||||
|
;; If `default-directory' doesn't exist or is
|
||||||
|
;; unreadable, Emacs throws file errors.
|
||||||
|
(let ((default-directory user-emacs-directory)
|
||||||
|
(inhibit-message t)
|
||||||
|
(file-name-handler-alist
|
||||||
|
(list (rassq 'jka-compr-handler file-name-handler-alist))))
|
||||||
|
(message "loading %s" req)
|
||||||
|
(require req nil t)
|
||||||
|
t))))
|
||||||
|
(push req packages))
|
||||||
|
(error
|
||||||
|
(message "Error: failed to incrementally load %S because: %s" req e)
|
||||||
|
(setq packages nil)))
|
||||||
|
(unless (null packages)
|
||||||
|
(run-at-time (if idle-time
|
||||||
|
syd-incremental-idle-timer
|
||||||
|
first-idle-timer)
|
||||||
|
nil #'syd-load-packages-incrementally
|
||||||
|
packages t)
|
||||||
|
(setq packages nil))))))))
|
||||||
|
|
||||||
|
(defun syd-load-packages-incrementally-h ()
|
||||||
|
"Begin incrementally loading packages in `syd-incremental-packages'.
|
||||||
|
|
||||||
|
If this is a daemon session, load them all immediately instead."
|
||||||
|
(when (numberp syd-incremental-first-idle-timer)
|
||||||
|
(if (zerop syd-incremental-first-idle-timer)
|
||||||
|
(mapc #'require (cdr syd-incremental-packages))
|
||||||
|
(run-with-idle-timer syd-incremental-first-idle-timer
|
||||||
|
nil #'syd-load-packages-incrementally
|
||||||
|
(cdr syd-incremental-packages) t))))
|
||||||
|
|
||||||
|
(unless noninteractive
|
||||||
|
(add-hook 'after-init-hook #'syd-load-packages-incrementally-h 100))
|
||||||
|
|
||||||
|
(with-eval-after-load 'use-package-core
|
||||||
|
(push :defer-incrementally use-package-deferring-keywords)
|
||||||
|
(setq use-package-keywords (use-package-list-insert
|
||||||
|
:defer-incrementally use-package-keywords :after))
|
||||||
|
(defalias 'use-package-normalize/:defer-incrementally
|
||||||
|
#'use-package-normalize-symlist)
|
||||||
|
(defun use-package-handler/:defer-incrementally
|
||||||
|
(name _keyword targets rest state)
|
||||||
|
(use-package-concat
|
||||||
|
`((syd-load-packages-incrementally
|
||||||
|
',(if (equal targets '(t))
|
||||||
|
(list name)
|
||||||
|
(append targets (list name)))))
|
||||||
|
(use-package-process-keywords name rest state))))
|
||||||
|
|
||||||
|
(provide 'syd-use-package)
|
||||||
|
;;; syd-use-package.el ends here
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
result
|
||||||
|
.nrepl
|
||||||
|
.nrepl-port
|
||||||
|
.cpcache/
|
||||||
|
.cache/
|
||||||
|
.lsp/
|
||||||
|
.clj-kondo
|
||||||
|
.cpcache
|
||||||
|
.lsp
|
||||||
|
.nrepl
|
||||||
|
.direnv/
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{:tasks
|
||||||
|
{:requires ([babashka.process :as p])
|
||||||
|
update-lockfile
|
||||||
|
{:doc "Update the clj-nix lockfile"
|
||||||
|
:task (let [r (p/sh {:out :inherit :err :inherit}
|
||||||
|
"nix run github:jlesquembre/clj-nix#deps-lock")]
|
||||||
|
(System/exit (:exit r)))}}}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{:deps {org.clojure/clojure {:mvn/version "1.12.0"}}
|
||||||
|
:paths ["src"]
|
||||||
|
:aliases
|
||||||
|
{:cider
|
||||||
|
{:extra-deps {cider/cider-nrepl {:mvn/version "0.50.2"}}
|
||||||
|
:main-opts ["-m" "nrepl.cmdline"
|
||||||
|
"--middleware" "[cider.nrepl/cider-middleware]"]}
|
||||||
|
:run
|
||||||
|
{:main-opts ["-m" "__PROJECT-NAME__.main"]}}}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
{
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
|
clj-nix.url = "github:jlesquembre/clj-nix";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { self, ... }@inputs:
|
||||||
|
inputs.flake-utils.lib.eachDefaultSystem (system:
|
||||||
|
let pkgs = import inputs.nixpkgs {
|
||||||
|
inherit system;
|
||||||
|
overlays = [
|
||||||
|
inputs.clj-nix.overlays.default
|
||||||
|
];
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
packages = rec {
|
||||||
|
__PROJECT-NAME__ = inputs.clj-nix.lib.mkCljApp {
|
||||||
|
pkgs = inputs.nixpkgs.legacyPackages.${system};
|
||||||
|
modules = [
|
||||||
|
{
|
||||||
|
name = "__PROJECT-OWNER__/__PROJECT-NAME__";
|
||||||
|
version = "1.0.0";
|
||||||
|
main-ns = "__PROJECT-NAME__.main";
|
||||||
|
projectSrc = ./.;
|
||||||
|
|
||||||
|
nativeImage = {
|
||||||
|
# Disable for faster build times.
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
default = __PROJECT-NAME__;
|
||||||
|
};
|
||||||
|
|
||||||
|
devShells.default = pkgs.mkShell {
|
||||||
|
packages = with pkgs; [
|
||||||
|
clojure-lsp
|
||||||
|
cljfmt
|
||||||
|
clojure
|
||||||
|
babashka
|
||||||
|
];
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
(ns __PROJECT-NAME__.main
|
||||||
|
(:gen-class))
|
||||||
|
|
||||||
|
(defn -main [& args]
|
||||||
|
(println "🦭!"))
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
;;; Directory Local Variables -*- no-byte-compile: t -*-
|
||||||
|
;;; For more information see (info "(emacs) Directory Variables")
|
||||||
|
|
||||||
|
((nil . ((projection-commands-run-command . "cabal run"))))
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
use flake
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
.direnv/
|
||||||
|
result
|
||||||
|
dist-newstyle/
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
cabal-version: 3.0
|
||||||
|
name: __PROJECT-NAME__
|
||||||
|
version: 0.1.0.0
|
||||||
|
synopsis: __PROJECT-NAME__
|
||||||
|
description: __PROJECT-NAME__
|
||||||
|
license: GPL-3.0-only
|
||||||
|
license-file: LICENSE
|
||||||
|
author: __USER-NAME__
|
||||||
|
maintainer: __USER-EMAIL__
|
||||||
|
category: Application
|
||||||
|
build-type: Simple
|
||||||
|
extra-doc-files:
|
||||||
|
|
||||||
|
common common
|
||||||
|
ghc-options: -Wno-typed-holes -fdefer-typed-holes -threaded -fdefer-type-errors
|
||||||
|
|
||||||
|
default-extensions:
|
||||||
|
BlockArguments
|
||||||
|
DataKinds
|
||||||
|
DuplicateRecordFields
|
||||||
|
DeriveDataTypeable
|
||||||
|
DeriveGeneric
|
||||||
|
DeriveTraversable
|
||||||
|
DerivingVia
|
||||||
|
FlexibleContexts
|
||||||
|
GADTs
|
||||||
|
GeneralisedNewtypeDeriving
|
||||||
|
LambdaCase
|
||||||
|
MultiWayIf
|
||||||
|
NoFieldSelectors
|
||||||
|
OverloadedLabels
|
||||||
|
OverloadedRecordDot
|
||||||
|
OverloadedStrings
|
||||||
|
PartialTypeSignatures
|
||||||
|
PatternSynonyms
|
||||||
|
StandaloneDeriving
|
||||||
|
TypeApplications
|
||||||
|
TypeFamilies
|
||||||
|
|
||||||
|
default-language: GHC2021
|
||||||
|
|
||||||
|
library
|
||||||
|
import: common
|
||||||
|
|
||||||
|
ghc-options: -fplugin=Effectful.Plugin
|
||||||
|
|
||||||
|
-- cabal-fmt: expand src/ -Main
|
||||||
|
exposed-modules:
|
||||||
|
__PROJECT-NAME__
|
||||||
|
|
||||||
|
default-language: GHC2021
|
||||||
|
|
||||||
|
build-depends:
|
||||||
|
, base ^>=4.19.1.0
|
||||||
|
, containers
|
||||||
|
, hashable
|
||||||
|
, mtl
|
||||||
|
, transformers
|
||||||
|
, lens
|
||||||
|
, generic-lens
|
||||||
|
, pretty-simple
|
||||||
|
, text >=2.0 && <2.2
|
||||||
|
, unordered-containers
|
||||||
|
, effectful
|
||||||
|
, effectful-plugin
|
||||||
|
|
||||||
|
hs-source-dirs: src
|
||||||
|
|
||||||
|
-- executable __PROJECT-NAME__
|
||||||
|
-- import: common
|
||||||
|
-- main-is: Main.hs
|
||||||
|
-- default-language: GHC2021
|
||||||
|
-- hs-source-dirs: app
|
||||||
|
-- build-depends:
|
||||||
|
-- , base ^>=4.19.1.0
|
||||||
|
-- , __PROJECT-NAME__
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||||
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs, ... }@inputs:
|
||||||
|
inputs.flake-utils.lib.eachDefaultSystem (system:
|
||||||
|
let
|
||||||
|
pkgs = import nixpkgs { inherit system; };
|
||||||
|
hlib = pkgs.haskell.lib.compose;
|
||||||
|
hpkgs = pkgs.haskell.packages.ghc98.extend (final: prev: {
|
||||||
|
__PROJECT-NAME__ =
|
||||||
|
hlib.dontCheck (final.callCabal2nix "__PROJECT-NAME__" ./. {});
|
||||||
|
});
|
||||||
|
in {
|
||||||
|
packages = rec {
|
||||||
|
__PROJECT-NAME__ = hpkgs.__PROJECT-NAME__;
|
||||||
|
default = __PROJECT-NAME__;
|
||||||
|
};
|
||||||
|
|
||||||
|
devShells.default = hpkgs.shellFor {
|
||||||
|
packages = p: [
|
||||||
|
p.__PROJECT-NAME__
|
||||||
|
];
|
||||||
|
nativeBuildInputs = [
|
||||||
|
hpkgs.cabal-fmt
|
||||||
|
hpkgs.fourmolu
|
||||||
|
hpkgs.haskell-language-server
|
||||||
|
hpkgs.cabal-install
|
||||||
|
];
|
||||||
|
withHoogle = true;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
module __PROJECT-NAME__ where
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
;;; -*- lisp-data -*-
|
||||||
|
(("/persist/dots/")
|
||||||
|
("/persist/dots/modules/home/users/crumb/emacs/elpa/org-mode/"))
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# -*- mode: snippet -*-
|
||||||
|
# name: __cubical
|
||||||
|
# key: __cubical
|
||||||
|
# --
|
||||||
|
{-# OPTIONS --safe --guardedness --cubical --without-K #-}
|
||||||
|
|
||||||
|
module ${1:Module} where
|
||||||
|
|
||||||
|
open import Cubical.Foundations.Prelude
|
||||||
|
-- open import Cubical.Data.Sigma
|
||||||
|
-- open import Cubical.HITs.PropositionalTruncation
|
||||||
|
-- open import Cubical.Foundations.Function
|
||||||
|
-- open import Cubical.Foundations.Function
|
||||||
|
|
||||||
|
|
||||||
|
private variable
|
||||||
|
ℓ ℓ' ℓ'' : Level
|
||||||
|
|
||||||
|
$2
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
;;; .yas-setup.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(require 'dash)
|
||||||
|
(require 's)
|
||||||
|
|
||||||
|
(defun snippet-bibtex--make-id ()
|
||||||
|
(let ((surname (--> (or (yas-field-value 2)
|
||||||
|
"surname")
|
||||||
|
(s-downcase it)
|
||||||
|
(string-to-list it)
|
||||||
|
(-take-while (lambda (x) (/= x ?,)) it)
|
||||||
|
(-filter (lambda (x) (not (memq x '(?- ?\s)))) it)
|
||||||
|
(apply #'string it)))
|
||||||
|
(year (--> (or (yas-field-value 3)
|
||||||
|
"1234")
|
||||||
|
(string-to-list it)
|
||||||
|
(-take-while (lambda (x) (<= ?0 x ?9)) it)
|
||||||
|
(apply #'string it)))
|
||||||
|
(keyword (or (-some--> (or (yas-field-value 1)
|
||||||
|
"keyword")
|
||||||
|
(s-downcase it)
|
||||||
|
(s-split-words it)
|
||||||
|
(-find (lambda (x)
|
||||||
|
(not (member x '("the" "on" "of" "a" "when"))))
|
||||||
|
it))
|
||||||
|
"keyword")))
|
||||||
|
(concat surname year keyword)))
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# -*- mode: snippet -*-
|
||||||
|
# name: Article
|
||||||
|
# uuid:
|
||||||
|
# key: @art
|
||||||
|
# condition: t
|
||||||
|
# --
|
||||||
|
@article{${1:$(snippet-bibtex--make-id)}
|
||||||
|
, title = {${1:Principia Mathematica}}
|
||||||
|
, author = {${2:of Sinope, Diogenes}}
|
||||||
|
, year = {${3:1992}}
|
||||||
|
, url = {${4:https://example.com/}}
|
||||||
|
, urldate = {${5:`(format-time-string "%Y-%m-%d")`}}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# -*- mode: snippet -*-
|
||||||
|
# name: Minimal Elisp file
|
||||||
|
# uuid:
|
||||||
|
# key: __
|
||||||
|
# condition: t
|
||||||
|
# expand-env: ((yas-indent-line 'fixed) (yas-wrap-around-region 'nil) (this-current-file-name (file-name-base (buffer-file-name (current-buffer)))))
|
||||||
|
# --
|
||||||
|
;;; ${1:`this-current-file-name`}.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
$2
|
||||||
|
|
||||||
|
(provide '$1)
|
||||||
|
;;; $1.el ends here
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# -*- mode: snippet -*-
|
||||||
|
# name: foreign
|
||||||
|
# uuid: haskell-foreign
|
||||||
|
# key: foreign
|
||||||
|
# condition: t
|
||||||
|
# --
|
||||||
|
|
||||||
|
foreign import ccall unsafe "src/bridge.c $1"
|
||||||
|
$1 :: $2
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# -*- mode: snippet -*-
|
||||||
|
# name: Nix module
|
||||||
|
# uuid:
|
||||||
|
# key: __module
|
||||||
|
# condition: t
|
||||||
|
# expand-env: ((yas-indent-line 'fixed) (yas-wrap-around-region 'nil) (this-current-file-name (file-name-base (buffer-file-name (current-buffer)))))
|
||||||
|
# --
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
let cfg = config.${1:`this-current-file-name`};
|
||||||
|
in {
|
||||||
|
options.$1 = {
|
||||||
|
enable = lib.mkEnableOption "$2";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
$3
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
# -*- mode: snippet -*-
|
||||||
|
# name: shell
|
||||||
|
# key: __shell
|
||||||
|
# --
|
||||||
|
{ pkgs ? import <nixpkgs> {}, ... }:
|
||||||
|
|
||||||
|
pkgs.mkShell {
|
||||||
|
packages = with pkgs; [
|
||||||
|
$1
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# -*- mode: snippet -*-
|
||||||
|
# name: enable
|
||||||
|
# uuid:
|
||||||
|
# key: enable
|
||||||
|
# condition: t
|
||||||
|
# --
|
||||||
|
enable = lib.mkEnableOption "$1";
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user