aboutsummaryrefslogtreecommitdiff
path: root/emacs/init.el
blob: b321e1b8453edea4947674c17b2218c4137428b1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
;;; init.el --- Emacs configuration  -*- lexical-binding: t; -*-

(require 'package)
(add-to-list 'package-archives
             '("melpa" . "https://melpa.org/packages/") t)
(package-initialize)

(unless package-archive-contents
  (package-refresh-contents))

(require 'use-package)
(setq use-package-always-ensure t)

(scroll-bar-mode -1)
(setq display-line-numbers-type 'relative)
(global-display-line-numbers-mode 1)
(setq-default indent-tabs-mode nil)

(setq custom-file
      (make-temp-file "emacs-custom-"))

;; move temp files out of the cwd
(let ((auto-save-dir (concat user-emacs-directory "auto-save/"))
      (backup-dir (concat user-emacs-directory "backups/")))
  (make-directory auto-save-dir t)
  (make-directory backup-dir t)
  (setq auto-save-file-name-transforms
        `((".*" ,auto-save-dir t)))
  (setq backup-directory-alist
        `(("." . ,backup-dir))))

(use-package evil
  :init
  (setq evil-want-keybinding nil)
  (setq evil-want-C-u-scroll t)
  :config
  (evil-mode 1))

(use-package evil-collection
  :after evil
  :config
  (evil-collection-init))

(add-hook 'eshell-mode-hook (lambda () (evil-insert-state)))

(use-package vs-dark-theme
  :config
  (load-theme 'vs-dark t))

(use-package apheleia
  :config
  (add-to-list 'apheleia-mode-alist '(scheme-mode . lisp-indent))
  (apheleia-global-mode +1))

(use-package geiser-guile)

(use-package markdown-mode
  :ensure t
  :mode ("\\.md\\'" . gfm-mode)
  :hook (markdown-mode . flyspell-mode))

(use-package nix-ts-mode
  :mode "\\.nix\\'")

(use-package rainbow-delimiters
  :hook (scheme-mode . rainbow-delimiters-mode))

(add-hook 'scheme-mode-hook #'electric-pair-local-mode)

(setq ispell-program-name "aspell"
      ispell-dictionary "en_US")
(add-hook 'markdown-mode-hook #'flyspell-mode)

(use-package magit
  :bind ("C-x g" . magit-status))

(use-package agent-shell
  ;; Talks to LLM coding agents over the Agent Client Protocol (ACP).
  ;; Pi needs the external `pi-acp` adapter on PATH (provided via nixos-config).
  ;; Pi authenticates via OAuth -- run `/login` inside the shell once; no API key.
  :bind ("C-c a p" . agent-shell-pi-start-agent)
  :config
  (setq agent-shell-pi-acp-command '("pi-acp"))
  ;; Start ready to type instead of in evil normal state.
  (add-hook 'agent-shell-mode-hook #'evil-insert-state)
  ;; Same GUI-Enter gotcha as mpdel: shell-maker binds submit via a
  ;; comint-send-input remap on RET/C-m, but a GUI frame's Enter sends
  ;; <return> -- which evil-collection shadows -- so input never gets sent.
  ;; Point <return> (and keypad Enter) straight at submit in insert state.
  (defun my/agent-shell-restore-ret ()
    (evil-local-set-key 'insert (kbd "<return>") #'shell-maker-submit)
    (evil-local-set-key 'insert (kbd "<kp-enter>") #'shell-maker-submit))
  (add-hook 'agent-shell-mode-hook #'my/agent-shell-restore-ret))

(use-package mpdel
  :after evil
  :config
  (mpdel-mode)
  ;; In a GUI frame the Enter key sends <return>, which evil-collection binds to
  ;; play/pause -- shadowing tablist's "descend into entry" command (that command
  ;; only sits on RET / C-m).  Point <return> (and the keypad Enter) at descend
  ;; in all mpdel list buffers (browser, playlists, ...).
  (defun my/mpdel-restore-ret ()
    (evil-local-set-key 'normal (kbd "<return>") #'tablist-find-entry)
    (evil-local-set-key 'normal (kbd "<kp-enter>") #'tablist-find-entry))
  (add-hook 'mpdel-tablist-mode-hook #'my/mpdel-restore-ret)

  ;; "Recently added" view.  MPD has no such entity, so subclass mpdel's filter
  ;; (which already renders a browsable, addable song list) and issue a search
  ;; sorted by modification time, newest first.
  (require 'cl-lib)
  (defvar my/mpdel-recent-count 50
    "How many recently added songs `my/mpdel-recent' lists.")
  (cl-defstruct (my/mpdel-recent-entity (:include libmpdel-filter)))
  (cl-defmethod libmpdel-entity-name ((_e my/mpdel-recent-entity))
    "Recently added")
  (cl-defmethod libmpdel-list-songs ((_e my/mpdel-recent-entity) function)
    (libmpdel-send-command
     (format "search \"(file != \\\"\\\")\" sort -Last-Modified window 0:%d"
             my/mpdel-recent-count)
     (lambda (data)
       (funcall function (libmpdel--create-songs-from-data data)))))
  (defun my/mpdel-recent ()
    "Browse the most recently added songs, newest first."
    (interactive)
    (mpdel-core-open (make-my/mpdel-recent-entity :text "recently added")))
  (defun my/mpdel-recent-replace ()
    "Replace the current playlist with the recently added songs."
    (interactive)
    (libmpdel-list-songs
     (make-my/mpdel-recent-entity :text "recently added")
     (lambda (songs) (libmpdel-current-playlist-replace songs))))
  (global-set-key (kbd "C-c m r") #'my/mpdel-recent)
  (global-set-key (kbd "C-c m R") #'my/mpdel-recent-replace))