From 6aefd03d0da963a374d757a274bcdf6f079220eb Mon Sep 17 00:00:00 2001 From: Alexander Heldt Date: Sat, 9 Sep 2023 10:06:44 +0200 Subject: [PATCH] pinwheel: Add `emacs` --- flake.lock | 72 +++++ flake.nix | 6 + hosts/pinwheel/configuration.nix | 1 + hosts/pinwheel/modules/emacs/config.nix | 10 + hosts/pinwheel/modules/emacs/config.org | 387 +++++++++++++++++++++++ hosts/pinwheel/modules/emacs/default.nix | 20 ++ 6 files changed, 496 insertions(+) create mode 100644 hosts/pinwheel/modules/emacs/config.nix create mode 100644 hosts/pinwheel/modules/emacs/config.org create mode 100644 hosts/pinwheel/modules/emacs/default.nix diff --git a/flake.lock b/flake.lock index d420c58..870418f 100644 --- a/flake.lock +++ b/flake.lock @@ -44,6 +44,46 @@ "type": "github" } }, + "emacs-overlay": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": [ + "nixpkgs" + ], + "nixpkgs-stable": "nixpkgs-stable" + }, + "locked": { + "lastModified": 1693220267, + "narHash": "sha256-/F1GUutDzX2o+JhK9JpL4IfytXJ8Gw9ABhYvh2Rnnz8=", + "owner": "nix-community", + "repo": "emacs-overlay", + "rev": "7c239d6ec798caba895588ee98e42d6a3df318e0", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "emacs-overlay", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1692799911, + "narHash": "sha256-3eihraek4qL744EvQXsK1Ha6C3CR7nnT8X2qWap4RNk=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "f9e7cf818399d17d347f847525c5a5a8032e4e44", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, "home-manager": { "inputs": { "nixpkgs": [ @@ -117,6 +157,22 @@ "type": "github" } }, + "nixpkgs-stable": { + "locked": { + "lastModified": 1693087214, + "narHash": "sha256-Kn1SSqRfPpqcI1MDy82JXrPT1WI8c03TA2F0xu6kS+4=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "f155f0cf4ea43c4e3c8918d2d327d44777b6cad4", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-23.05", + "repo": "nixpkgs", + "type": "github" + } + }, "nixpkgs2211": { "locked": { "lastModified": 1688392541, @@ -136,11 +192,27 @@ "root": { "inputs": { "agenix": "agenix", + "emacs-overlay": "emacs-overlay", "home-manager": "home-manager_2", "nixos-hardware": "nixos-hardware", "nixpkgs": "nixpkgs", "nixpkgs2211": "nixpkgs2211" } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 7e44636..a393d43 100644 --- a/flake.nix +++ b/flake.nix @@ -16,6 +16,11 @@ url = "github:ryantm/agenix"; inputs.nixpkgs.follows = "nixpkgs"; }; + + emacs-overlay = { + url = "github:nix-community/emacs-overlay"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; outputs = { self, ... } @inputs : { @@ -30,6 +35,7 @@ inputs.nixos-hardware.nixosModules.lenovo-thinkpad-x1-10th-gen inputs.home-manager.nixosModules.home-manager ./hosts/pinwheel/home.nix + { nixpkgs.overlays = [ inputs.emacs-overlay.overlay ]; } ]; }; diff --git a/hosts/pinwheel/configuration.nix b/hosts/pinwheel/configuration.nix index b80f41e..e87fda5 100644 --- a/hosts/pinwheel/configuration.nix +++ b/hosts/pinwheel/configuration.nix @@ -16,6 +16,7 @@ ./modules/zsh ./modules/tmux ./modules/vim + ./modules/emacs ./modules/foot ./modules/hyprland ./modules/waybar diff --git a/hosts/pinwheel/modules/emacs/config.nix b/hosts/pinwheel/modules/emacs/config.nix new file mode 100644 index 0000000..eacab8e --- /dev/null +++ b/hosts/pinwheel/modules/emacs/config.nix @@ -0,0 +1,10 @@ +{ emacs, runCommand, ... }: +runCommand "default.el" {} '' + cp ${./config.org} $TMPDIR/config.org + cd $TMPDIR + ${emacs}/bin/emacs --batch -Q \ + -l org config.org \ + -f org-babel-tangle + + mv config.el $out + '' diff --git a/hosts/pinwheel/modules/emacs/config.org b/hosts/pinwheel/modules/emacs/config.org new file mode 100644 index 0000000..5ca8b59 --- /dev/null +++ b/hosts/pinwheel/modules/emacs/config.org @@ -0,0 +1,387 @@ +#+PROPERTY: header-args :emacs-lisp :tangle yes + +* Initialization +** Package handling (by Nix) +#+BEGIN_SRC emacs-lisp + (when (featurep 'nativecomp) + (setq comp-deferred-compilation nil)) +#+END_SRC +*** Use package autoloads provided by Nix +#+BEGIN_SRC emacs-lisp + (defvar package-quickstart t) + #+END_SRC +*** Disable impure packages (as in not already fetched by Nix) +#+BEGIN_SRC emacs-lisp + (setq package-archives nil) + #+END_SRC +*** Initialize `use-package` +`bind-key` is required by `use-package` +#+BEGIN_SRC emacs-lisp + (use-package bind-key + :config + (add-to-list 'same-window-buffer-names "*Personal Keybindings*")) + + ;; (eval-when-compile + ;; (require 'use-package)) + ;; (use-package quelpa-use-package) +#+END_SRC +** Optimization +*** Time startup +#+BEGIN_SRC emacs-lisp + (add-hook 'emacs-startup-hook + (lambda () + (message "Started emacs in %.03fs" + (float-time (time-subtract after-init-time before-init-time))))) +#+END_SRC +*** Keep a reference to the actual file-name-handler. +#+BEGIN_SRC emacs-lisp + (defvar file-name-handler-alist-actual file-name-handler-alist) +#+END_SRC +*** Set the file-name-handler to nil (because regexing is cpu intensive) +#+BEGIN_SRC emacs-lisp + (setq file-name-handler-alist nil) +#+END_SRC +*** Increase the gc threshold significantly for faster startup +#+BEGIN_SRC emacs-lisp + (setq gc-cons-threshold most-positive-fixnum) + (add-hook 'emacs-startup-hook + (lambda () + (setq gc-cons-threshold 16777216 ; 16mb + gc-cons-percentage 0.1))) +#+END_SRC +*** The default is very low - 4k, lsp server responses are easily much larger +#+BEGIN_SRC emacs-lisp + (setq read-process-output-max (* 1024 1024)) ;; 1mb +#+END_SRC +*** Reset file-name-handler-alist after initialization +#+BEGIN_SRC emacs-lisp + (add-hook 'after-init-hook + (lambda () + (garbage-collect) + (setq file-name-handler-alist file-name-handler-alist-actual)) t) +#+END_SRC +*** This makes emacsclient startup faster in TUI-mode + #+BEGIN_SRC emacs-lisp + (setq-default xterm-query-timeout nil) + #+END_SRC +*** Disable startup messages +#+BEGIN_SRC emacs-lisp + (setq inhibit-startup-message t) + (setq initial-buffer-choice t) + (setq initial-scratch-message nil) +#+END_SRC +*** Don't resize gui when setting new font +... it affecs startup time +#+BEGIN_SRC emacs-lisp + (setq frame-inhibit-implied-resize t) +#+END_SRC +*** Skip loading default lib, use fundamental-mode +#+BEGIN_SRC emacs-lisp + (setq inhibit-default-init t + initial-major-mode 'fundamental-mode) +#+END_SRC + +* Setup +#+BEGIN_SRC emacs-lisp +(setq confirm-kill-processes nil) +#+END_SRC +** Use wl-clipboard for interprocess copy/paste +#+BEGIN_SRC emacs-lisp + (setq wl-copy-process nil) + + (defun wl-copy (text) + (setq wl-copy-process (make-process :name "wl-copy" + :buffer nil + :command '("wl-copy" "-f" "-n") + :connection-type 'pipe)) + (process-send-string wl-copy-process text) + (process-send-eof wl-copy-process)) + + (defun wl-paste () + (if (and wl-copy-process (process-live-p wl-copy-process)) + nil ; should return nil if we're the current paste owner + (shell-command-to-string "wl-paste -n | tr -d \r"))) + + (when (display-graphic-p) + (setq interprogram-cut-function 'wl-copy) + (setq interprogram-paste-function 'wl-paste) + ) +#+END_SRC +** Don't create backup files, don't create #autosave# files + #+BEGIN_SRC emacs-lisp + (setq temporary-file-directory "~/.emacs.d/tmp/") + (unless (file-exists-p "~/.emacs.d/tmp") + (make-directory "~/.emacs.d/tmp")) + + (setq backup-inhibited t + make-backup-files nil ; don't create backup~ files + create-lockfiles nil + auto-save-default nil) ; don't create #autosave# files + #+END_SRC +** Don't store custom settings +#+BEGIN_SRC emacs-lisp + (setq custom-file null-device) +#+END_SRC + +* Look and feel +** Font +#+BEGIN_SRC emacs-lisp + (set-face-attribute 'default nil :font "DejaVuSansM Nerd Font Mono" :height 160) +#+END_SRC +** Icons +#+BEGIN_SRC emacs-lisp + (use-package all-the-icons) +#+END_SRC +** Modeline +#+BEGIN_SRC emacs-lisp + (use-package doom-modeline + :init (doom-modeline-mode 1) + :custom ((doom-modeline-height 15))) +#+END_SRC +** Theme +#+BEGIN_SRC emacs-lisp + (use-package doom-themes + :init (load-theme 'doom-dracula t)) +#+END_SRC +** Disable the menu bar +#+BEGIN_SRC emacs-lisp + (menu-bar-mode -1) +#+END_SRC +** Disable the tool bar +#+BEGIN_SRC emacs-lisp + (tool-bar-mode -1) +#+END_SRC +** Disable the scroll bar +#+BEGIN_SRC emacs-lisp + (scroll-bar-mode -1) +#+END_SRC +** Disable tool tips +#+BEGIN_SRC emacs-lisp + (tooltip-mode -1) +#+END_SRC +** Add margin left of buffers +#+BEGIN_SRC emacs-lisp + (set-fringe-mode 10) +#+END_SRC +** Faster "confirm kill" +#+BEGIN_SRC emacs-lisp + (setq confirm-kill-emacs 'y-or-n-p) +#+END_SRC +** Use ESC to quit prompts +#+BEGIN_SRC emacs-lisp + (global-set-key (kbd "") 'keyboard-escape-quit) +#+END_SRC +** Enable column numbers +#+BEGIN_SRC emacs-lisp + (column-number-mode) +#+END_SRC +** Enable line numbers +#+BEGIN_SRC emacs-lisp + (global-display-line-numbers-mode t) + (setq display-line-numbers-width-start t) +#+END_SRC +** Show trailing whitespace (when programming and in org-mode) +#+BEGIN_SRC emacs-lisp + (add-hook 'prog-mode-hook + (lambda () + (setq show-trailing-whitespace t))) + + (add-hook 'org-mode-hook + (lambda () + (setq show-trailing-whitespace t))) +#+END_SRC +** Auto-insert matching parenthesis (when programming) +#+BEGIN_SRC emacs-lisp + (add-hook 'prog-mode-hook 'electric-pair-mode) +#+END_SRC +** Hilight parethesis (when programming) +#+BEGIN_SRC emacs-lisp + (defun my-show-paren-mode () + "Enables show-paren-mode." + (setq show-paren-delay 0) + (set-face-background 'show-paren-match (face-background 'default)) + (set-face-foreground 'show-paren-match "#def") + (set-face-attribute 'show-paren-match nil :weight 'extra-bold) + (show-paren-mode 1)) + + (add-hook 'prog-mode-hook 'my-show-paren-mode) +#+END_SRC +** Calendar +*** Show week numbers +#+BEGIN_SRC emacs-lisp + (setq calendar-intermonth-text + '(propertize + (format "%2d" + (car + (calendar-iso-from-absolute + (calendar-absolute-from-gregorian (list month day year))))) + 'font-lock-face 'calendar-iso-week-face)) + + (setq calendar-intermonth-header + (propertize "Wk" 'font-lock-face 'font-lock-keyword-face)) +#+END_SRC +*** Begin week with monday +#+BEGIN_SRC emacs-lisp + (setq calendar-week-start-day 1) +#+END_SRC +** Tabs +*** Enable tabs +#+BEGIN_SRC emacs-lisp + (tab-bar-mode 1) +#+END_SRC +*** Remove tab buttons +#+BEGIN_SRC emacs-lisp + (setq tab-bar-close-button-show nil) + (setq tab-bar-new-button-show nil) +#+END_SRC +*** Close tabs with :q +#+BEGIN_SRC emacs-lisp + (defun alex/close-tab (orig-fun &rest args) + "Close tab instead of calling ORIG-FUN if there is more than a single tab." + (if (cdr (tab-bar-tabs)) + (tab-bar-close-tab) + (apply orig-fun args))) + + (advice-add #'evil-quit :around #'alex/close-tab) +#+END_SRC + +* Completion +** Consult +Consult provides search and navigation commands based on the Emacs completion function completing-read. +https://github.com/minad/consult +#+BEGIN_SRC emacs-lisp +(use-package consult + :bind + ("C-x b" . 'consult-buffer)) +#+END_SRC +** Orderless completion +Allow orderless completion, e.g. `org mode` and `mode org` return same result +https://github.com/oantolin/orderless +#+BEGIN_SRC emacs-lisp + (use-package orderless + :custom (completion-styles '(orderless))) +#+END_SRC +** Helpful +https://github.com/Wilfred/helpful +#+BEGIN_SRC emacs-lisp + (use-package helpful + ;; :custom + ;; (counsel-describe-function-function #'helpful-callable) + ;; (counsel-describe-variable-function #'helpful-variable) + :bind + ;; ([remap describe-function] . counsel-describe-function) + ([remap describe-command] . helpful-command) + ;; ([remap describe-variable] . counsel-describe-variable) + ([remap describe-key] . helpful-key)) +#+END_SRC +** Company +https://company-mode.github.io/ +#+BEGIN_SRC emacs-lisp +(use-package company + :init + (setq company-idle-delay 0 + company-echo-delay 0 + company-minimum-prefix-length 1) + :config + (global-company-mode)) +#+END_SRC +** Which key +`which-key` is a minor mode for Emacs that displays the key bindings following your currently entered incomplete command (a prefix) in a popup. +https://github.com/justbur/emacs-which-key +#+BEGIN_SRC emacs-lisp +(use-package which-key + :config + (which-key-mode) + (which-key-setup-side-window-bottom) + (setq which-key-sort-order 'which-key-key-order-alpha + which-key-side-window-max-width 0.33 + which-key-idle-delay 0.05) + ) +#+END_SRC +** Buffer history +`savehist` saves buffer history +#+BEGIN_SRC emacs-lisp + (use-package savehist + :init + (savehist-mode)) +#+END_SRC +** Vertico +#+BEGIN_SRC emacs-lisp +(use-package vertico + :init + (vertico-mode)) +#+END_SRC +** Marginalia +#+BEGIN_SRC emacs-lisp +(use-package marginalia + :after vertico + :init + (marginalia-mode)) +#+END_SRC + +* Evil +#+BEGIN_SRC emacs-lisp + (use-package evil + :init + (setq evil-undo-system 'undo-tree) + (setq evil-want-integration t) + (setq evil-want-keybinding nil) + (setq evil-want-C-u-scroll t) + (setq evil-want-C-i-jump nil) + :config + (evil-mode 1) + + ;; Use visual line motions even outside of visual-line-mode buffers + (evil-global-set-key 'motion "j" 'evil-next-visual-line) + (evil-global-set-key 'motion "k" 'evil-previous-visual-line) + + (evil-set-initial-state 'messages-buffer-mode 'normal) + (evil-set-initial-state 'dashboard-mode 'normal)) + + (use-package evil-surround + :config (global-evil-surround-mode)) + + (use-package evil-collection + :after evil + :config + (evil-collection-init)) +#+END_SRC +* Undo tree +#+BEGIN_SRC emacs-lisp + (use-package undo-tree + :init + (setq undo-tree-auto-save-history nil) + (global-undo-tree-mode 1)) +#+END_SRC +* Org-mode +#+BEGIN_SRC emacs-lisp + (use-package org + :hook (org-mode . visual-line-mode) ;; wrap lines + :config + (setq org-ellipsis " ▾") + (setq org-agenda-start-with-log-mode t) + (setq org-log-done 'time) + (setq org-cycle-separator-lines 1) + (setq org-startup-folded 'content) + (setq org-startup-indented t) + (setq org-agenda-files '("~/sync/org")) +#+END_SRC +** Org-habit +#+BEGIN_SRC emacs-lisp + (require 'org-habit) + (add-to-list 'org-modules 'org-habit) + (setq org-habit-graph-column 60)) +#+END_SRC +* Magit +#+BEGIN_SRC emacs-lisp + (use-package magit + :custom + (magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1)) +#+END_SRC +* Diff-hl (git diff in margin) +#+BEGIN_SRC emacs-lisp + (use-package diff-hl + :config + (setq diff-hl-side 'right) + (global-diff-hl-mode t)) +#+END_SRC diff --git a/hosts/pinwheel/modules/emacs/default.nix b/hosts/pinwheel/modules/emacs/default.nix new file mode 100644 index 0000000..8603adc --- /dev/null +++ b/hosts/pinwheel/modules/emacs/default.nix @@ -0,0 +1,20 @@ +{home-manager, pkgs, ... }: +let + emacs = pkgs.emacsWithPackagesFromUsePackage { + package = pkgs.emacs-unstable; + config = ./config.org; + defaultInitFile = pkgs.callPackage ./config.nix {}; + + alwaysEnsure = true; + alwaysTangle = true; + #extraEmacsPackages = epkgs: with epkgs; [ use-package ]; + }; +in +{ + home-manager.users.alex = { + home.packages = [ + emacs + pkgs.wl-clipboard + ]; + }; +}