" org-mode-map)
20 |
21 | ;; Update [/] cookies after a selection of commands
22 | (--each '(org-yank
23 | org-kill-line
24 | kill-whole-line
25 | duplicate-current-line-or-region)
26 | (advice-add it :after 'my/org-update-parent-cookie)))
27 |
28 | (defun my/org-update-parent-cookie (&rest _)
29 | (when (equal major-mode 'org-mode)
30 | (save-excursion
31 | (ignore-errors
32 | (forward-char 1)
33 | (org-back-to-heading)
34 | (org-update-parent-todo-statistics)))
35 | (save-excursion
36 | (ignore-errors
37 | (forward-char -1)
38 | (org-back-to-heading)
39 | (org-update-parent-todo-statistics)))))
40 |
41 | (provide 'setup-org-mode)
42 |
--------------------------------------------------------------------------------
/packages/setup-projectile.el:
--------------------------------------------------------------------------------
1 | ;; Projectile
2 | ;;
3 | ;; A project interaction library. It provides a nice set of features operating
4 | ;; on a project level without introducing external dependencies
5 |
6 | (use-package projectile
7 | :diminish projectile-mode
8 | :commands (projectile-switch-project-by-name)
9 |
10 | :bind-keymap
11 | (("s-p" . projectile-command-map))
12 |
13 | :bind
14 | ("C-x p p" . projectile-switch-project)
15 | ("C-x p e" . my/projectile-switch-project-to-emacs)
16 |
17 | :config
18 | (projectile-mode +1)
19 | (define-key projectile-command-map (kbd "s-p") #'projectile-switch-project)
20 |
21 | (setq projectile-ignored-project-function 'my/ignore-project?)
22 |
23 | (require 'setup-perspective)
24 | (setq projectile-switch-project-action 'switch-perspective+find-file))
25 |
26 | (defun current-project-name ()
27 | (cadr (reverse (split-string (projectile-project-root) "/"))))
28 |
29 | (defun switch-perspective+find-file ()
30 | (with-perspective (current-project-name)
31 | (projectile-find-file)))
32 |
33 | (defun my/ignore-project? (file-name)
34 | (s-contains? ".gitlibs" file-name))
35 |
36 | (defun my/projectile-switch-project-to-emacs ()
37 | (interactive)
38 | (projectile-switch-project-by-name "~/.emacs.d/"))
39 |
40 | (provide 'setup-projectile)
41 |
--------------------------------------------------------------------------------
/packages/setup-consult.el:
--------------------------------------------------------------------------------
1 | ;; Consult
2 | ;;
3 | ;; Provides search and navigation commands based on the Emacs completion
4 | ;; function completing-read. Completion allows you to quickly select an item
5 | ;; from a list of candidates.
6 |
7 | (use-package consult
8 | :bind (("C-x f" . consult-recent-file)
9 | ("C-x C-i" . consult-imenu)
10 | ("C-x M-i" . consult-imenu-multi)
11 | ("C-x i" . consult-outline)
12 | ("C-x C-y" . consult-yank-from-kill-ring)
13 | ("C-v" . consult-line)
14 | ("M-v" . consult-line-multi)
15 | ("M-g g" . consult-goto-line)
16 | ("M-g M-g" . consult-goto-line)
17 | ("M-y" . consult-yank-pop)
18 | ("M-s k" . consult-keep-lines))
19 |
20 | :after (perspective)
21 |
22 | :config
23 | ;; Show only perspective-buffers with consult-buffer
24 | (consult-customize consult--source-buffer :hidden t :default nil)
25 | (add-to-list 'consult-buffer-sources persp-consult-source))
26 |
27 | (use-package consult-flycheck
28 | :bind (("M-g f" . consult-flycheck)))
29 |
30 | (setq completion-in-region-function
31 | (lambda (&rest args)
32 | (apply (if vertico-mode
33 | #'consult-completion-in-region
34 | #'completion--in-region)
35 | args)))
36 |
37 | (provide 'setup-consult)
38 |
--------------------------------------------------------------------------------
/init.el:
--------------------------------------------------------------------------------
1 | ;; Add settings to load-path
2 | (add-to-list 'load-path (expand-file-name "settings" user-emacs-directory))
3 |
4 | ;; Optimize startup of Emacs
5 | (require 'fast-startup)
6 |
7 | ;; Keep emacs Custom-settings in separate file, not appended to init.el
8 | (setq custom-file (expand-file-name "custom.el" user-emacs-directory))
9 | (load custom-file)
10 |
11 | ;; Set up appearance early
12 | (require 'appearance)
13 |
14 | ;; Configure the package manager
15 | (require 'packages)
16 |
17 | ;; Configure Emacs for Norwegian OSX, lol
18 | (when (string= "darwin" system-type)
19 | (require 'norwegian-mac))
20 |
21 | ;; Lets start with a smattering of sanity
22 | (require 'sane-defaults)
23 |
24 | ;; Set up tooling for the rest of the configuration
25 | (require 'tooling)
26 |
27 | ;; Add utilities
28 | (require 'navigation)
29 | (require 'editing)
30 | (require 'buffers)
31 | (require 'windows)
32 | (require 'extra-keybindings)
33 | (require 'indented-yank)
34 |
35 | ;; Set up Straight (for packages on github)
36 | (require 'setup-straight)
37 |
38 | ;; Load all packages
39 | (dolist (file (directory-files packages-dir t "^[^#].*el$"))
40 | (when (file-regular-p file)
41 | (load file)))
42 |
43 | ;; Project-specific settings
44 | (require 'matnyttig)
45 |
46 | ;; Conclude init by setting up specifics for the current user
47 | (require 'user-specific-settings)
48 |
--------------------------------------------------------------------------------
/settings/norwegian-mac.el:
--------------------------------------------------------------------------------
1 | ;; change command to meta, and ignore option to use weird Norwegian keyboard
2 | (setq mac-option-modifier 'super)
3 | (setq mac-command-modifier 'meta)
4 | (setq ns-function-modifier 'hyper)
5 | (setq mac-right-option-modifier nil)
6 |
7 | ;; Norwegian mac-keyboard alt-keys
8 | (define-key key-translation-map (kbd "s-8") (kbd "["))
9 | (define-key key-translation-map (kbd "s-(") (kbd "{"))
10 | (define-key key-translation-map (kbd "s-9") (kbd "]"))
11 | (define-key key-translation-map (kbd "s-)") (kbd "}"))
12 | (define-key key-translation-map (kbd "s-7") (kbd "|"))
13 | (define-key key-translation-map (kbd "s-/") (kbd "\\"))
14 | (define-key key-translation-map (kbd "M-s-7") (kbd "M-|"))
15 |
16 | (defun insert-backslash ()
17 | (interactive)
18 | (insert "\\"))
19 |
20 | ;; Insert backslash, no questions asked
21 | (global-set-key (kbd "H-7") 'insert-backslash)
22 |
23 | ;; Move to OSX trash folder when deleting stuff
24 | (setq trash-directory "~/.Trash/emacs")
25 |
26 | ;; Use aspell for spell checking: brew install aspell --lang=en
27 | (setq ispell-program-name "/opt/homebrew/bin/aspell")
28 |
29 | ;; Use GNU ls - install with: brew install xz coreutils
30 | (setq insert-directory-program "gls")
31 |
32 | ;; Setup environment variables from the user's shell.
33 | (use-package exec-path-from-shell
34 | :init
35 | (exec-path-from-shell-initialize))
36 |
37 | (provide 'norwegian-mac)
38 |
--------------------------------------------------------------------------------
/custom.el:
--------------------------------------------------------------------------------
1 | (custom-set-variables
2 | ;; custom-set-variables was added by Custom.
3 | ;; If you edit it by hand, you could mess it up, so be careful.
4 | ;; Your init file should contain only one such instance.
5 | ;; If there is more than one, they won't work right.
6 | '(custom-safe-themes
7 | '("05692bda554c178fafe15cc3e6ab09539e7db4846eb9bb6272b97068c055a903" default))
8 | '(package-selected-packages
9 | '(diff-hl exec-path-from-shell whitespace-cleanup-mode clj-refactor kaocha-runner marginalia which-key cider diminish move-text undo-fu-session vundo undo-fu consult-flycheck orderless consult flycheck datomic-snippets yasnippet projectile wgrep-deadgrep wgrep deadgrep vertico-directory vertico lsp-mode clojure-mode s multiple-cursors expand-region paredit magit))
10 | '(safe-local-variable-values
11 | '((cider-clojure-cli-aliases . "-A:dev")
12 | (cider-figwheel-main-default-options . ":ui")
13 | (cider-preferred-build-tool . clojure-cli)
14 | (cider-default-cljs-repl . figwheel-main)
15 | (cider-clojure-cli-aliases . "-A:ui")
16 | (flycheck-disabled-checkers emacs-lisp-checkdoc))))
17 | (custom-set-faces
18 | ;; custom-set-faces was added by Custom.
19 | ;; If you edit it by hand, you could mess it up, so be careful.
20 | ;; Your init file should contain only one such instance.
21 | ;; If there is more than one, they won't work right.
22 | '(highlight ((t (:background "dark magenta")))))
23 |
--------------------------------------------------------------------------------
/settings/significant-other.el:
--------------------------------------------------------------------------------
1 | ;; Significant Other
2 | ;;
3 | ;; Many files come in pairs, like tests and source files, header files and
4 | ;; implementations, components and their devcards.
5 | ;;
6 | ;; This impromptu package-to-be helps set up functions to jump between
7 | ;; significant other files.
8 | ;;
9 | ;; See setup-clojure-mode for example usage.
10 |
11 | (require 'dash)
12 |
13 | (setq significant-other-find-fn
14 | (lambda ()
15 | (message "Significant other not configured for this mode.")
16 | nil))
17 |
18 | (defun significant-other-find-existing ()
19 | (-first 'file-exists-p (funcall significant-other-find-fn)))
20 |
21 | (defun significant-other-jump (arg)
22 | (interactive "P")
23 | (if-let (file (significant-other-find-existing))
24 | (find-file file)
25 | (when-let (file (car (funcall significant-other-find-fn)))
26 | (if arg
27 | (progn (find-file file) (save-buffer))
28 | (ido-find-file-in-dir (file-name-directory file))))))
29 |
30 | (defmacro with-significant-others (binding &rest mappings)
31 | (declare (indent 1))
32 | `(setq-local
33 | significant-other-find-fn
34 | (lambda ()
35 | (let ((,binding (buffer-file-name)))
36 | (cond
37 | ,@(--map
38 | `((string-match-p ,(car it) ,binding)
39 | ,(cadr it))
40 | mappings))))))
41 |
42 | (global-set-key (kbd "s-j") 'significant-other-jump)
43 |
44 | (provide 'significant-other)
45 |
--------------------------------------------------------------------------------
/users/sigmund/jetbrains-mono.el:
--------------------------------------------------------------------------------
1 | ;; Configure JetBrains Mono
2 | (set-face-attribute 'default nil :family "JetBrains Mono")
3 | (use-package ligature
4 | :config
5 | (ligature-set-ligatures 'prog-mode '("--" "---" "==" "===" "!=" "!==" "=!="
6 | "=:=" "=/=" "<=" ">=" "&&" "&&&" "&=" "++" "+++" "***" ";;" "!!"
7 | "??" "???" "?:" "?." "?=" "<:" ":<" ":>" ">:" "<:<" "<>" "<<<" ">>>"
8 | "<<" ">>" "||" "-|" "_|_" "|-" "||-" "|=" "||=" "##" "###" "####"
9 | "#{" "#[" "]#" "#(" "#?" "#_" "#_(" "#:" "#!" "#=" "^=" "<$>" "<$"
10 | "$>" "<+>" "<+" "+>" "<*>" "<*" "*>" "" ">" "/>" "" "->" "->>" "<<-" "<-" "<=<" "=<<" "<<=" "<==" "<=>" "<==>"
12 | "==>" "=>" "=>>" ">=>" ">>=" ">>-" ">-" "-<" "-<<" ">->" "<-<" "<-|"
13 | "<=|" "|=>" "|->" "<->" "<~~" "<~" "<~>" "~~" "~~>" "~>" "~-" "-~"
14 | "~@" "[||]" "|]" "[|" "|}" "{|" "[<" ">]" "|>" "<|" "||>" "<||"
15 | "|||>" "<|||" "<|>" "..." ".." ".=" "..<" ".?" "::" ":::" ":=" "::="
16 | ":?" ":?>" "//" "///" "/*" "*/" "/=" "//=" "/==" "@_" "__" "???"
17 | "<:<" ";;;"))
18 | (global-ligature-mode t))
19 |
20 | (provide 'jetbrains-mono)
21 |
--------------------------------------------------------------------------------
/settings/indented-yank.el:
--------------------------------------------------------------------------------
1 | ;; Make indenting yanked text the default for programming modes.
2 | ;; Use C-S-y to yank unindented.
3 |
4 | (require 'dash)
5 |
6 | (global-set-key (kbd "C-S-y") 'yank-unindented)
7 |
8 | (defvar yank-indent-modes '(prog-mode
9 | sgml-mode
10 | js2-mode)
11 | "Modes in which to indent regions that are yanked (or yank-popped)")
12 |
13 | (defvar yank-advised-indent-threshold 1000
14 | "Threshold (# chars) over which indentation does not automatically occur.")
15 |
16 | (defun yank-advised-indent-function (beg end)
17 | "Do indentation, as long as the region isn't too large."
18 | (if (<= (- end beg) yank-advised-indent-threshold)
19 | (indent-region beg end nil)))
20 |
21 | (defadvice yank (after yank-indent activate)
22 | "If current mode is one of 'yank-indent-modes, indent yanked text (with prefix arg don't indent)."
23 | (if (and (not (ad-get-arg 0))
24 | (--any? (derived-mode-p it) yank-indent-modes))
25 | (let ((transient-mark-mode nil))
26 | (yank-advised-indent-function (region-beginning) (region-end)))))
27 |
28 | (defadvice yank-pop (after yank-pop-indent activate)
29 | "If current mode is one of 'yank-indent-modes, indent yanked text (with prefix arg don't indent)."
30 | (if (and (not (ad-get-arg 0))
31 | (member major-mode yank-indent-modes))
32 | (let ((transient-mark-mode nil))
33 | (yank-advised-indent-function (region-beginning) (region-end)))))
34 |
35 | (defun yank-unindented ()
36 | (interactive)
37 | (yank 1))
38 |
39 | (provide 'indented-yank)
40 |
--------------------------------------------------------------------------------
/packages/setup-kaocha-runner.el:
--------------------------------------------------------------------------------
1 | ;; Kaocha Runner
2 | ;;
3 | ;; An emacs package for running Kaocha tests via CIDER.
4 |
5 | (use-package kaocha-runner
6 | :after (cider-mode)
7 | :commands (kaocha-runner--run-tests)
8 | :bind (:map clojure-mode-map
9 | ("C-c k t" . kaocha-runner-run-test-at-point)
10 | ("C-c k r" . kaocha-runner-run-tests)
11 | ("C-c k a" . kaocha-runner-run-all-tests)
12 | ("C-c k w" . kaocha-runner-show-warnings)
13 | ("C-c k h" . kaocha-runner-hide-windows)))
14 |
15 | (defun kaocha-runner--is-test? (s)
16 | (string-match-p "/test/.+\.clj" s))
17 |
18 | (defun kaocha-runner--significant-other-find-existing-test ()
19 | (--first
20 | (and (file-exists-p it)
21 | (kaocha-runner--is-test? it))
22 | (funcall significant-other-find-fn)))
23 |
24 | (defun kaocha-runner-run-relevant-tests ()
25 | (interactive)
26 | (when (cljr--project-depends-on-p "kaocha")
27 | (if (kaocha-runner--is-test? (buffer-file-name))
28 | (kaocha-runner--run-tests
29 | (kaocha-runner--testable-sym (cider-current-ns) nil nil)
30 | nil t)
31 | (let ((original-buffer (current-buffer)))
32 | (save-window-excursion
33 | (when-let ((file (kaocha-runner--significant-other-find-existing-test)))
34 | (find-file file)
35 | (kaocha-runner--run-tests
36 | (kaocha-runner--testable-sym (cider-current-ns) nil nil)
37 | nil t original-buffer)))))))
38 |
39 | (add-hook 'cider-file-loaded-hook #'kaocha-runner-run-relevant-tests)
40 |
41 | (provide 'setup-kaocha-runner)
42 |
--------------------------------------------------------------------------------
/settings/mattilsynet.el:
--------------------------------------------------------------------------------
1 | (with-eval-after-load 'lsp-mode
2 | (add-to-list 'lsp-file-watch-ignored-directories "[/\\\\]docker/build"))
3 |
4 | (prodigy-define-service
5 | :name "Datomic transactor"
6 | :tags '(matnyttig datomic)
7 | :command "make"
8 | :args '("start-transactor")
9 | :cwd "~/work/matnyttig"
10 | :stop-signal 'sigkill
11 | :kill-process-buffer-on-stop t)
12 |
13 | (prodigy-define-service
14 | :name "NATS server"
15 | :tags '(matnyttig nats)
16 | :command "nats-server"
17 | :args '("--jetstream" "-sd=data/matnyttig-nats")
18 | :cwd "~/"
19 | :stop-signal 'sigkill
20 | :kill-process-buffer-on-stop t)
21 |
22 | (prodigy-define-service
23 | :name "Shadow-CLJS watcher"
24 | :tags '(matnyttig cljs)
25 | :command "npx"
26 | :args '("shadow-cljs" "watch" "client")
27 | :cwd "~/work/matnyttig"
28 | :stop-signal 'sigkill
29 | :kill-process-buffer-on-stop t)
30 |
31 | (prodigy-define-service
32 | :name "Launchpad"
33 | :tags '(matnyttig)
34 | :command "make"
35 | :args '("launch")
36 | :cwd "~/work/matnyttig"
37 | :stop-signal 'sigkill
38 | :kill-process-buffer-on-stop t)
39 |
40 | (prodigy-define-service
41 | :name "Jaeger"
42 | :tags '(matnyttig otel)
43 | :command "docker"
44 | :args (list "run" "--rm"
45 | "-e" "SPAN_STORAGE_TYPE=badger"
46 | "-e" "BADGER_EPHEMERAL=false"
47 | "-e" "BADGER_DIRECTORY_VALUE=/badger/data"
48 | "-e" "BADGER_DIRECTORY_KEY=/badger/key"
49 | "-v" (concat (expand-file-name "~/data/badger") ":/badger")
50 | "-p" "16686:16686"
51 | "-p" "4318:4318"
52 | "-p" "4317:4317"
53 | "jaegertracing/all-in-one"
54 | "--collector.otlp.enabled=true")
55 | :cwd "~/"
56 | :stop-signal 'sigkill
57 | :kill-process-buffer-on-stop t)
58 |
59 | (provide 'mattilsynet)
60 |
--------------------------------------------------------------------------------
/users/magnars/what-the-emacs-d.el:
--------------------------------------------------------------------------------
1 | (use-package htmlize :defer t)
2 |
3 | (defun wte--unique-filename (stub &optional index)
4 | (setq index (or index 1))
5 | (let ((filename (concat "~/stuff/what-the-emacsd/resources/posts/"
6 | stub
7 | ".el"
8 | (if (< index 10) "-0" "-")
9 | (number-to-string index)
10 | ".html")))
11 | (if (file-exists-p filename)
12 | (wte--unique-filename stub (1+ index))
13 | filename)))
14 |
15 | (defun what-the-emacsd-post (beg end)
16 | (interactive "r")
17 | (let ((example (with-current-buffer (htmlize-region beg end)
18 | (search-forward "")
19 | (setq beg (point))
20 | (search-forward "
")
21 | (forward-char -7)
22 | (buffer-substring beg (point))))
23 | (filename (wte--unique-filename (buffer-file-name-body)))
24 | (timestamp (floor (time-to-seconds (current-time)))))
25 | (find-file filename)
26 | (insert (format "
27 |
28 |
29 |
30 |
31 |
32 | %s
33 |
34 |
35 |
36 |
37 | " timestamp example))
38 | (goto-char 25)
39 | (local-set-key (kbd "C-c C-c") 'what-the-emacsd-publish)
40 | (local-set-key (kbd "C-c C-q") 'what-the-emacsd-done)))
41 |
42 | (defun what-the-emacsd-publish ()
43 | (interactive)
44 | (let ((filename (file-name-nondirectory (buffer-file-name))))
45 | (save-buffer)
46 | (compile
47 | (format "git add %s && git commit -m %S && git push && curl -i http://whattheemacsd.com/site/build"
48 | filename
49 | filename) t)))
50 |
51 | (defun what-the-emacsd-done ()
52 | (interactive)
53 | (when-let ((prev my/previous-window-configuration))
54 | (when prev (register-val-jump-to prev nil))))
55 |
56 | (wrap-fullscreen what-the-emacsd-post)
57 |
58 | (provide 'what-the-emacs-d)
59 |
--------------------------------------------------------------------------------
/packages/setup-lsp-mode.el:
--------------------------------------------------------------------------------
1 | (use-package lsp-mode
2 | :hook ((clojure-mode . lsp)
3 | (clojurescript-mode . lsp)
4 | (clojurec-mode . lsp)
5 | (lsp-mode . lsp-enable-which-key-integration))
6 | :diminish " lsp"
7 |
8 | :bind ((:map lsp-mode-map
9 | ("s-l w l" . lsp-workspace-show-log)))
10 |
11 | :init
12 | (setq lsp-headerline-breadcrumb-enable nil) ;; Don't need file path in my buffer
13 | (setq lsp-lens-enable nil) ;; Hide clutter (reference and test counts)
14 | (setq lsp-enable-indentation nil) ;; use clojure-mode indentation
15 | (setq lsp-eldoc-enable-hover nil) ;; use CIDER eldoc
16 | (setq lsp-modeline-code-actions-enable nil) ;; Don't clutter modeline
17 | (setq lsp-modeline-diagnostics-enable nil) ;; Don't clutter modeline, jeez
18 | (setq lsp-completion-provider :none) ;; Skip company-mode
19 | (setq lsp-enable-symbol-highlighting nil) ;; Don't highlight current symbol
20 |
21 | (setq lsp-apply-edits-after-file-operations nil) ;; Disable broken lsp feature: https://github.com/clojure-lsp/clojure-lsp/issues/1813
22 |
23 | ;; To consider
24 | ;;
25 | ;; (setq lsp-enable-completion-at-point nil) ;; CIDER vs LSP?
26 | ;; (remove-hook 'completion-at-point-functions #'cider-complete-at-point t)
27 |
28 | :config
29 | (advice-add 'lsp--info :around #'my/silence-some-lsp-info-messages)
30 | (add-hook 'lsp-completion-mode-hook 'my/use-lsp-completion-only-as-fallback))
31 |
32 | (defun my/use-lsp-completion-only-as-fallback ()
33 | (when (-contains? completion-at-point-functions #'lsp-completion-at-point)
34 | (remove-hook 'completion-at-point-functions #'tags-completion-at-point-function t)
35 | (remove-hook 'completion-at-point-functions #'lsp-completion-at-point t)
36 | (remove-hook 'completion-at-point-functions t t)
37 | (add-to-list 'completion-at-point-functions #'lsp-completion-at-point t)
38 | (add-to-list 'completion-at-point-functions t t)))
39 |
40 | (defun my/silence-some-lsp-info-messages (orig-fn &rest args)
41 | (unless (or (string-equal (car args) "Connected to %s.")
42 | (string-equal (car args) "Disconnected"))
43 | (apply orig-fn args)))
44 |
45 | (provide 'setup-lsp-mode)
46 |
--------------------------------------------------------------------------------
/packages/setup-yasnippet.el:
--------------------------------------------------------------------------------
1 | (use-package yasnippet
2 | :diminish yas-minor-mode
3 | :defer t
4 |
5 | :bind ((:map yas-keymap
6 | ("" . yas-exit-all-snippets)
7 | ("C-e" . yas/goto-end-of-active-field)
8 | ("C-a" . yas/goto-start-of-active-field)))
9 |
10 | :config
11 | ;; Use only own snippets, do not use bundled ones
12 | (setq yas-snippet-dirs '("~/.emacs.d/snippets"))
13 |
14 | ;; No dropdowns please, yas
15 | (setq yas-prompt-functions '(yas-ido-prompt yas-completing-prompt))
16 |
17 | ;; No need to be so verbose
18 | (setq yas-verbosity 1)
19 |
20 | ;; Wrap around region
21 | (setq yas-wrap-around-region t)
22 |
23 | ;; Use yasnippet everywhere
24 | (yas-global-mode 1))
25 |
26 | (use-package datomic-snippets
27 | :config
28 | (datomic-snippets-initialize))
29 |
30 | ;; Inter-field navigation
31 | (defun yas/goto-end-of-active-field ()
32 | (interactive)
33 | (let* ((snippet (car (yas--snippets-at-point)))
34 | (position (yas--field-end (yas--snippet-active-field snippet))))
35 | (if (= (point) position)
36 | (move-end-of-line 1)
37 | (goto-char position))))
38 |
39 | (defun yas/goto-start-of-active-field ()
40 | (interactive)
41 | (let* ((snippet (car (yas--snippets-at-point)))
42 | (position (yas--field-start (yas--snippet-active-field snippet))))
43 | (if (= (point) position)
44 | (move-beginning-of-line 1)
45 | (goto-char position))))
46 |
47 | ;; Snippet helpers
48 | (defun buffer-file-name-body ()
49 | "Buffer file name stripped of directory and extension"
50 | (if (buffer-file-name)
51 | (file-name-nondirectory (file-name-sans-extension (buffer-file-name)))
52 | (cadr (reverse (split-string (dired-current-directory) "/")))))
53 |
54 | ;;; Snippet helpers: javascript
55 | (defun js-method-p ()
56 | (save-excursion
57 | (word-search-backward "function")
58 | (looking-back ": ")))
59 |
60 | (defun js-function-declaration-p ()
61 | (save-excursion
62 | (word-search-backward "function")
63 | (looking-back "^\\s *")))
64 |
65 | (defun snippet--function-punctuation ()
66 | (if (js-method-p)
67 | (when (not (looking-at "[ \n\t\r]*[},]"))
68 | (insert ","))
69 | (unless (js-function-declaration-p)
70 | (if (looking-at "$") (insert ";")))))
71 |
72 | (defun snippet--function-name ()
73 | (if (js-function-declaration-p) "name" ""))
74 |
75 |
76 | (provide 'setup-yasnippet)
77 |
--------------------------------------------------------------------------------
/packages/setup-vertico.el:
--------------------------------------------------------------------------------
1 | ;; Vertico
2 | ;;
3 | ;; Provides a performant and minimalistic vertical completion UI based on the
4 | ;; default completion system.
5 |
6 | (use-package vertico
7 | :bind (:map vertico-map
8 | ("M-" . vertico-exit-input))
9 |
10 | :init
11 | (vertico-mode))
12 |
13 | (use-package vertico-directory
14 | :after vertico
15 | :ensure nil ;; comes with vertico
16 | ;; More convenient directory navigation commands
17 | :bind (:map vertico-map
18 | ("RET" . vertico-directory-enter)
19 | ("C-d" . vertico-directory-enter)
20 | ("DEL" . vertico-directory-delete-char)
21 | ("M-DEL" . vertico-directory-delete-word))
22 |
23 | ;; Cleans up path when moving directories with shadowed paths syntax, e.g.
24 | ;; cleans ~/foo/bar/// to /, and ~/foo/bar/~/ to ~/.
25 | :hook (rfn-eshadow-update-overlay . vertico-directory-tidy))
26 |
27 | ;; Camel Case
28 |
29 | (defun orderless-camel-case (component)
30 | (orderless--separated-by '(zero-or-more nonl)
31 | (--map
32 | `(or (seq word-boundary ,it)
33 | ,(s-capitalize it))
34 | (split-string component " "))))
35 |
36 | ;; Use + to join parts of same long word
37 |
38 | (defun orderless-long-words-plus (component)
39 | (orderless--separated-by '(one-or-more word)
40 | (split-string component "+")))
41 |
42 | ;; Use the `orderless' completion style.
43 | (use-package orderless
44 | :init
45 | ;; Configure a custom style dispatcher (see the Consult wiki)
46 | ;; (setq orderless-style-dispatchers '(+orderless-consult-dispatch orderless-affix-dispatch)
47 | ;; orderless-component-separator #'orderless-escapable-split-on-space)
48 | (setq completion-styles '(orderless basic)
49 | completion-category-defaults nil
50 | completion-category-overrides '((file (styles partial-completion)))
51 | orderless-matching-styles '(orderless-prefixes orderless-initialism orderless-camel-case orderless-long-words-plus)))
52 |
53 | ;; Persist minibuffer history over Emacs restarts. Vertico sorts from history.
54 | (use-package savehist
55 | :init
56 | (savehist-mode))
57 |
58 | ;; Enable rich annotations using the Marginalia package
59 | (use-package marginalia
60 | :bind (:map minibuffer-local-map
61 | ("M-A" . marginalia-cycle))
62 |
63 | :init (marginalia-mode)
64 |
65 | :config
66 | ;; No need for rich annotations when just switching buffers
67 | (setcdr (assq 'buffer marginalia-annotator-registry)
68 | '(none marginalia-annotate-buffer builtin)))
69 |
70 | (provide 'setup-vertico)
71 |
--------------------------------------------------------------------------------
/settings/windows.el:
--------------------------------------------------------------------------------
1 | ;; Manipulating windows, ie. the squares with buffers in them
2 |
3 | (global-set-key (kbd "C-x -") 'toggle-window-split)
4 | (global-set-key (kbd "C-c -") 'rotate-windows)
5 |
6 | (defun toggle-window-split ()
7 | (interactive)
8 | (if (= (count-windows) 2)
9 | (let* ((this-win-buffer (window-buffer))
10 | (next-win-buffer (window-buffer (next-window)))
11 | (this-win-edges (window-edges (selected-window)))
12 | (next-win-edges (window-edges (next-window)))
13 | (this-win-2nd (not (and (<= (car this-win-edges)
14 | (car next-win-edges))
15 | (<= (cadr this-win-edges)
16 | (cadr next-win-edges)))))
17 | (splitter
18 | (if (= (car this-win-edges)
19 | (car (window-edges (next-window))))
20 | 'split-window-horizontally
21 | 'split-window-vertically)))
22 | (delete-other-windows)
23 | (let ((first-win (selected-window)))
24 | (funcall splitter)
25 | (if this-win-2nd (other-window 1))
26 | (set-window-buffer (selected-window) this-win-buffer)
27 | (set-window-buffer (next-window) next-win-buffer)
28 | (select-window first-win)
29 | (if this-win-2nd (other-window 1))))))
30 |
31 | (defun rotate-windows (count)
32 | "Rotate your windows.
33 | Dedicated windows are left untouched. Giving a negative prefix
34 | argument makes the windows rotate backwards."
35 | (interactive "p")
36 | (let* ((non-dedicated-windows (cl-remove-if 'window-dedicated-p (window-list)))
37 | (num-windows (length non-dedicated-windows))
38 | (i 0)
39 | (step (+ num-windows count)))
40 | (cond ((not (> num-windows 1))
41 | (message "You can't rotate a single window!"))
42 | (t
43 | (dotimes (counter (- num-windows 1))
44 | (let* ((next-i (% (+ step i) num-windows))
45 |
46 | (w1 (elt non-dedicated-windows i))
47 | (w2 (elt non-dedicated-windows next-i))
48 |
49 | (b1 (window-buffer w1))
50 | (b2 (window-buffer w2))
51 |
52 | (s1 (window-start w1))
53 | (s2 (window-start w2)))
54 | (set-window-buffer w1 b2)
55 | (set-window-buffer w2 b1)
56 | (set-window-start w1 s2)
57 | (set-window-start w2 s1)
58 | (setq i next-i)))))))
59 |
60 | (provide 'windows)
61 |
--------------------------------------------------------------------------------
/packages/setup-rgrep.el:
--------------------------------------------------------------------------------
1 | (require 'grep)
2 |
3 | (global-set-key (kbd "M-s M-s") 'rgrep-fullscreen)
4 |
5 | (defvar rgrep-default-search-patterns
6 | '("*.el" "*.clj" "*.cljs" "*.clj*" "*.edn" "*.md" "*.css"))
7 |
8 | (defun rgrep-fullscreen (regexp &optional files dir confirm)
9 | "Open grep in full screen, saving windows."
10 | (interactive
11 | (progn
12 | (grep-compute-defaults)
13 | (cond
14 | ((and grep-find-command (equal current-prefix-arg '(16)))
15 | (list (read-from-minibuffer "Run: " grep-find-command
16 | nil nil 'grep-find-history)))
17 | ((not grep-find-template)
18 | (error "grep.el: No `grep-find-template' available"))
19 | (t (let* ((regexp (grep-read-regexp))
20 | (my-extension (when (buffer-file-name)
21 | (when-let ((my-extension (file-name-extension (buffer-file-name))))
22 | (concat "*." my-extension))))
23 | (files (completing-read (format "Search for %s in files matching: " regexp)
24 | (if my-extension
25 | (cons my-extension (--remove (equal it my-extension) rgrep-default-search-patterns))
26 | rgrep-default-search-patterns)
27 | nil nil nil nil my-extension))
28 | (dir (ido-read-directory-name "Base directory: "
29 | nil default-directory t))
30 | (confirm (equal current-prefix-arg '(4))))
31 | (list regexp files dir confirm))))))
32 | (window-configuration-to-register ?$)
33 | (rgrep regexp files dir confirm)
34 | (switch-to-buffer "*grep*")
35 | (delete-other-windows)
36 | (goto-char (point-min)))
37 |
38 | (defun rgrep-quit-window ()
39 | (interactive)
40 | (kill-buffer)
41 | (jump-to-register ?$))
42 |
43 | (defun rgrep-goto-file-and-close-rgrep ()
44 | (interactive)
45 | (compile-goto-error)
46 | (kill-buffer "*grep*")
47 | (delete-other-windows)
48 | (message "Type C-x r j $ to return to pre-rgrep windows."))
49 |
50 | ;; Don't recurse into some directories
51 | (add-to-list 'grep-find-ignored-directories "target")
52 | (add-to-list 'grep-find-ignored-directories "node_modules")
53 | (add-to-list 'grep-find-ignored-directories "vendor")
54 |
55 | ;; Add custom keybindings
56 | (define-key grep-mode-map "q" 'rgrep-quit-window)
57 | (define-key grep-mode-map (kbd "C-") 'rgrep-goto-file-and-close-rgrep)
58 | (define-key grep-mode-map (kbd "C-x C-s") 'wgrep-save-all-buffers)
59 |
60 | ;; Use same keybinding as occur
61 | (setq wgrep-enable-key "e")
62 |
63 | (provide 'rgrep)
64 |
--------------------------------------------------------------------------------
/settings/buffers.el:
--------------------------------------------------------------------------------
1 | ;; manipulating buffers and the files that are in them
2 |
3 | ;; Rename or delete current buffer file
4 | (global-set-key (kbd "C-x C-r") 'rename-current-buffer-file)
5 | (global-set-key (kbd "C-x C-k") 'delete-current-buffer-file)
6 |
7 | ;; Copy the file path for the current buffer
8 | (global-set-key (kbd "C-x M-w") 'copy-current-file-path)
9 |
10 | ;; Touch the buffer (save without changing)
11 | (global-set-key (kbd "C-x t") 'touch-buffer-file)
12 |
13 | ;; Create new frame
14 | (define-key global-map (kbd "C-x C-n") 'make-frame-command)
15 |
16 | ;; Bury buffer
17 | (global-set-key (kbd "s-y") 'bury-buffer)
18 |
19 | ;; Toggle two most recent buffers
20 | (global-set-key (kbd "s-b") 'mode-line-other-buffer)
21 |
22 | ;; Eval buffer
23 | (global-set-key (kbd "C-c C-k") 'eval-buffer)
24 |
25 | ;; Create scratch buffer
26 | (global-set-key (kbd "C-c b") 'create-scratch-buffer)
27 |
28 | ;;;; Implementations
29 |
30 | (defun rename-current-buffer-file ()
31 | "Renames current buffer and file it is visiting."
32 | (interactive)
33 | (let ((name (buffer-name))
34 | (filename (buffer-file-name)))
35 | (if (not (and filename (file-exists-p filename)))
36 | (error "Buffer '%s' is not visiting a file!" name)
37 | (let ((new-name (read-file-name "New name: " filename)))
38 | (if (get-buffer new-name)
39 | (error "A buffer named '%s' already exists!" new-name)
40 | (rename-file filename new-name 1)
41 | (rename-buffer new-name)
42 | (set-visited-file-name new-name)
43 | (set-buffer-modified-p nil)
44 | (message "File '%s' successfully renamed to '%s'"
45 | name (file-name-nondirectory new-name)))))))
46 |
47 | (defun delete-current-buffer-file ()
48 | "Removes file connected to current buffer and kills buffer."
49 | (interactive)
50 | (let ((filename (buffer-file-name))
51 | (buffer (current-buffer))
52 | (name (buffer-name)))
53 | (if (not (and filename (file-exists-p filename)))
54 | (ido-kill-buffer)
55 | (when (yes-or-no-p "Are you sure you want to remove this file? ")
56 | (delete-file filename)
57 | (kill-buffer buffer)
58 | (message "File '%s' successfully removed" filename)))))
59 |
60 | (defun copy-current-file-path ()
61 | "Add current file path to kill ring.
62 | Limits the filename to project root if possible."
63 | (interactive)
64 | (let ((filename (buffer-file-name)))
65 | (kill-new filename)
66 | (message "Copied file path %s" filename)))
67 |
68 | (defun create-scratch-buffer ()
69 | "Create a new scratch buffer to work in. (could be *scratch* - *scratchX*)"
70 | (interactive)
71 | (let ((n 0)
72 | bufname)
73 | (while (progn
74 | (setq bufname (concat "*scratch"
75 | (if (= n 0) "" (int-to-string n))
76 | "*"))
77 | (setq n (1+ n))
78 | (get-buffer bufname)))
79 | (switch-to-buffer (get-buffer-create bufname))
80 | (emacs-lisp-mode)))
81 |
82 | (defun touch-buffer-file ()
83 | (interactive)
84 | (insert " ")
85 | (backward-delete-char 1)
86 | (save-buffer))
87 |
88 | (provide 'buffers)
89 |
--------------------------------------------------------------------------------
/packages/setup-paredit.el:
--------------------------------------------------------------------------------
1 | (use-package paredit
2 | :hook ((clojure-mode . paredit-mode)
3 | (cider-repl-mode . paredit-mode)
4 | (emacs-lisp-mode . paredit-mode)
5 | (lisp-data-mode . paredit-mode))
6 | :diminish " ()"
7 |
8 | :config
9 | ;; Rebind nasty paredit keys
10 | (--each '(("M-s" "s-s" paredit-splice-sexp)
11 | ("M-" "s-" paredit-splice-sexp-killing-backward)
12 | ("M-" "s-" paredit-splice-sexp-killing-forward)
13 | ("C-" "s-" paredit-forward-slurp-sexp)
14 | ("C-" "s-" paredit-forward-barf-sexp)
15 | ("C-M-" "s-S-" paredit-backward-slurp-sexp)
16 | ("C-M-" "s-S-" paredit-backward-barf-sexp))
17 | (-let [(original replacement command) it]
18 | (define-key paredit-mode-map (read-kbd-macro original) nil)
19 | (define-key paredit-mode-map (read-kbd-macro replacement) command)))
20 |
21 | ;; Make paredit work with delete-selection-mode
22 | (put 'paredit-forward-delete 'delete-selection 'supersede)
23 | (put 'paredit-backward-delete 'delete-selection 'supersede)
24 | (put 'paredit-newline 'delete-selection t)
25 |
26 | ;; Enable `paredit-mode' in the minibuffer, during `eval-expression'.
27 | (add-hook 'minibuffer-setup-hook 'conditionally-enable-paredit-mode)
28 |
29 | :bind ((:map paredit-mode-map
30 | ("C-w" . paredit-kill-region-or-backward-word)
31 | ("M-C-" . backward-kill-sexp)
32 | ("C-d" . paredit-forward-delete)
33 | ("M-(" . paredit-wrap-round)
34 | ("M-)" . paredit-wrap-round-from-behind)
35 | ("M-s-8" . paredit-wrap-square)
36 | ("M-s-9" . paredit-wrap-square-from-behind)
37 | ("M-s-(" . paredit-wrap-curly)
38 | ("M-s-)" . paredit-wrap-curly-from-behind))))
39 |
40 | (defun paredit-wrap-round-from-behind ()
41 | (interactive)
42 | (forward-sexp -1)
43 | (paredit-wrap-round)
44 | (insert " ")
45 | (forward-char -1))
46 |
47 | (defun paredit-wrap-square-from-behind ()
48 | (interactive)
49 | (forward-sexp -1)
50 | (paredit-wrap-square))
51 |
52 | (defun paredit-wrap-curly-from-behind ()
53 | (interactive)
54 | (forward-sexp -1)
55 | (paredit-wrap-curly))
56 |
57 | (defun paredit-kill-region-or-backward-word ()
58 | (interactive)
59 | (if (region-active-p)
60 | (kill-region (region-beginning) (region-end))
61 | (paredit-backward-kill-word)))
62 |
63 | (defun conditionally-enable-paredit-mode ()
64 | (when (or (eq this-command 'eval-expression)
65 | (eq this-command 'cider-run-in-dev-namespace))
66 | (paredit-mode 1)
67 | (disable-inconvenient-paredit-keybindings-in-minor-mode)))
68 |
69 | (defun disable-inconvenient-paredit-keybindings-in-minor-mode ()
70 | (let ((oldmap (cdr (assoc 'paredit-mode minor-mode-map-alist)))
71 | (newmap (make-sparse-keymap)))
72 | (set-keymap-parent newmap oldmap)
73 | (define-key newmap (kbd "RET") nil)
74 | (make-local-variable 'minor-mode-overriding-map-alist)
75 | (push `(paredit-mode . ,newmap) minor-mode-overriding-map-alist)))
76 |
77 | (provide 'setup-paredit)
78 |
--------------------------------------------------------------------------------
/settings/navigation.el:
--------------------------------------------------------------------------------
1 | ;; Moving the cursor around
2 |
3 | ;; Like isearch, but adds region (if any) to history and deactivates mark
4 | (global-set-key (kbd "C-s") 'isearch-forward-use-region)
5 | (global-set-key (kbd "C-r") 'isearch-backward-use-region)
6 |
7 | ;; Navigate between windows using shift + arrow key
8 | (global-set-key (kbd "S-") 'windmove-right)
9 | (global-set-key (kbd "S-") 'windmove-left)
10 | (global-set-key (kbd "S-") 'windmove-up)
11 | (global-set-key (kbd "S-") 'windmove-down)
12 |
13 | ;: Keep them windows nice and balanced
14 | (global-set-key (kbd "C-x 0") 'my/delete-window)
15 | (global-set-key (kbd "C-x 3") 'my/split-window-right)
16 |
17 | ;; Move cursor back to indentation
18 | (global-set-key (kbd "M-i") 'back-to-indentation)
19 |
20 | ;; Navigate paragraphs
21 | (global-set-key (kbd "M-p") 'backward-paragraph)
22 | (global-set-key (kbd "M-n") 'forward-paragraph)
23 |
24 | ;; Move more quickly
25 | (global-set-key (kbd "C-S-n") (λ (ignore-errors (forward-line 5) (recenter))))
26 | (global-set-key (kbd "C-S-p") (λ (ignore-errors (forward-line -5) (recenter))))
27 | (global-set-key (kbd "C-S-f") (λ (ignore-errors (forward-char 5) (recenter))))
28 | (global-set-key (kbd "C-S-b") (λ (ignore-errors (backward-char 5) (recenter))))
29 |
30 | ;; Readily navigate in modes with significant whitespace
31 | (global-set-key (kbd "H-n") 'goto-next-line-with-same-indentation)
32 | (global-set-key (kbd "H-p") 'goto-prev-line-with-same-indentation)
33 |
34 | ;; Where was I again?
35 | (global-set-key (kbd "M-B") 'goto-last-modification)
36 |
37 | ;; No more scrolling surprises
38 | (global-unset-key (kbd "C-v"))
39 | (global-unset-key (kbd "M-v"))
40 |
41 | ;; Implementations
42 |
43 | (use-package windmove)
44 |
45 | (defun isearch-forward-use-region ()
46 | (interactive)
47 | (when (region-active-p)
48 | (add-to-history 'search-ring (buffer-substring (region-beginning)
49 | (region-end)))
50 | (deactivate-mark))
51 | (call-interactively 'isearch-forward))
52 |
53 | (defun isearch-backward-use-region ()
54 | (interactive)
55 | (when (region-active-p)
56 | (add-to-history 'search-ring (buffer-substring (region-beginning)
57 | (region-end)))
58 | (deactivate-mark))
59 | (call-interactively 'isearch-backward))
60 |
61 | (defun goto-next-line-with-same-indentation ()
62 | (interactive)
63 | (back-to-indentation)
64 | (re-search-forward (s-concat "^" (s-repeat (current-column) " ") "[^ \t\r\n\v\f]")
65 | nil nil (if (= 0 (current-column)) 2 1))
66 | (back-to-indentation))
67 |
68 | (defun goto-prev-line-with-same-indentation ()
69 | (interactive)
70 | (back-to-indentation)
71 | (re-search-backward (s-concat "^" (s-repeat (current-column) " ") "[^ \t\r\n\v\f]"))
72 | (back-to-indentation))
73 |
74 | (defun goto-last-modification ()
75 | (interactive)
76 | (undo-fu-only-undo)
77 | (undo-fu-only-redo))
78 |
79 | (defun my/delete-window ()
80 | (interactive)
81 | (delete-window)
82 | (balance-windows))
83 |
84 | (defun my/split-window-right ()
85 | (interactive)
86 | (split-window-right)
87 | (windmove-right)
88 | (balance-windows))
89 |
90 | (provide 'navigation)
91 |
--------------------------------------------------------------------------------
/settings/i18n-edn.el:
--------------------------------------------------------------------------------
1 | ;; Edit multiple i18n.edn files at once with multifile.el
2 |
3 | (require 'multifiles)
4 | (require 'tooling)
5 | (require 's)
6 |
7 | (defun i18n-edn--find-current-i18n-header ()
8 | (save-excursion
9 | (unless (looking-at "#:")
10 | (unless (search-backward "#:" nil t)
11 | (when (search-forward "#:" nil t)
12 | (forward-char -2))))
13 | (when (looking-at "#:")
14 | (let* ((beg (point))
15 | (end (progn (paredit-forward) (point))))
16 | (buffer-substring-no-properties beg end)))))
17 |
18 | (defun i18n-edn--find-files-with-same-extension ()
19 | "Find all files in the current directory with the same extension as the current file."
20 | (let* ((current-file (buffer-file-name))
21 | (current-dir (file-name-directory current-file))
22 | (extension (file-name-extension current-file))
23 | (search-pattern (concat "\\." extension "$")))
24 | (directory-files current-dir nil search-pattern)))
25 |
26 | (defun i18n-edn--cleanup ()
27 | (when (get-buffer "*i18n-multifile*")
28 | (with-current-buffer "*i18n-multifile*"
29 | (delete-region (point-min) (point-max)))
30 | (kill-buffer "*i18n-multifile*")))
31 |
32 | (defvar i18n-heading
33 | ";; Editing files in %s
34 | ;;
35 | ;; C-x C-s to save all buffers, but keep this open.
36 | ;; C-c C-c to save all buffers and close this.
37 | ;; C-c C-q to just close this (changes will not be saved or undone)
38 |
39 | ")
40 |
41 | (defun i18n-edn-edit-in-multifile ()
42 | (interactive)
43 | (if-let ((header (i18n-edn--find-current-i18n-header)))
44 | (progn
45 | (i18n-edn--cleanup)
46 | (let ((root-dir (s-chop-prefix
47 | (projectile-project-root)
48 | (file-name-directory (buffer-file-name)))))
49 | (save-excursion
50 | (switch-to-buffer-other-window "*i18n-multifile*")
51 | (insert (format i18n-heading root-dir))))
52 | (--each (i18n-edn--find-files-with-same-extension)
53 | (with-current-buffer (find-file-noselect it)
54 | (save-excursion
55 | (goto-char (point-min))
56 | (when (search-forward header nil t)
57 | (paredit-backward)
58 | (let* ((beg (point))
59 | (end (progn (paredit-forward 2) (point))))
60 | (with-current-buffer "*i18n-multifile*"
61 | (insert (format ";; %s\n" it)))
62 | (mf/mirror-region-in-multifile beg end "*i18n-multifile*"))))))
63 | (switch-to-buffer-other-window "*i18n-multifile*")
64 | (goto-line 6)
65 | (define-key multifiles-minor-mode-map (kbd "C-c C-c") 'i18n-edn-save-and-close)
66 | (define-key multifiles-minor-mode-map (kbd "C-c C-q") 'i18n-edn-close))
67 | (message "No i18n header found. i18n-edn expects to find namespaced maps.")))
68 |
69 | (wrap-fullscreen i18n-edn-edit-in-multifile)
70 |
71 | (defun i18n-edn-close ()
72 | (interactive)
73 | (let ((prev my/previous-window-configuration))
74 | (i18n-edn--cleanup)
75 | (when prev (register-val-jump-to prev nil))))
76 |
77 | (defun i18n-edn-save-and-close ()
78 | (interactive)
79 | (mf/save-original-buffers)
80 | (i18n-edn-close))
81 |
82 | (provide 'i18n-edn)
83 |
--------------------------------------------------------------------------------
/.mc-lists.el:
--------------------------------------------------------------------------------
1 | ;; This file is automatically generated by the multiple-cursors extension.
2 | ;; It keeps track of your preferences for running commands with multiple cursors.
3 |
4 | (setq mc/cmds-to-run-for-all
5 | '(
6 | backward-kill-sexp
7 | backward-sexp
8 | change-number-at-point
9 | changes
10 | cider-eval-last-sexp
11 | cider-load-buffer
12 | clj-hippie-expand-no-case-fold
13 | cljr-raise-sexp
14 | cljr-slash
15 | cljr-splice-sexp-killing-backward
16 | clojure-backward-logical-sexp
17 | clojure-convert-collection-to-list
18 | clojure-convert-collection-to-set
19 | clojure-convert-collection-to-vector
20 | clojure-forward-logical-sexp
21 | clojure-thread-first-all
22 | clojure-toggle-keyword-string
23 | clojure-unwind
24 | comment-dwim
25 | completion-at-point
26 | copy-region-or-current-line
27 | cycle-spacing
28 | duplicate-current-line-or-region
29 | electric-newline-and-maybe-indent
30 | fill-paragraph
31 | forward-sexp
32 | inc-number-at-point
33 | indent-for-tab-command
34 | isearch-forward-use-region
35 | kill-region-or-backward-word
36 | kill-sentence
37 | kill-sexp
38 | kmacro-start-macro-or-insert-counter
39 | markdown-beginning-of-line
40 | markdown-end-of-line
41 | markdown-outdent-or-delete
42 | move-text-up
43 | open-line-and-indent
44 | open-line-below
45 | org-beginning-of-line
46 | org-delete-char
47 | org-end-of-line
48 | org-self-insert-command
49 | org-shiftright
50 | org-yank
51 | paredit-C-j
52 | paredit-C-j
53 | paredit-backward-down
54 | paredit-backward-kill-word
55 | paredit-backward-slurp-sexp
56 | paredit-backward-up
57 | paredit-close-curly
58 | paredit-close-round
59 | paredit-close-square
60 | paredit-comment-dwim
61 | paredit-doublequote
62 | paredit-forward
63 | paredit-forward-barf-sexp
64 | paredit-forward-delete
65 | paredit-forward-down
66 | paredit-forward-kill-word
67 | paredit-forward-slurp-sexp
68 | paredit-forward-up
69 | paredit-join-sexps
70 | paredit-kill
71 | paredit-kill-region-or-backward-word
72 | paredit-open-curly
73 | paredit-open-round
74 | paredit-open-square
75 | paredit-raise-sexp
76 | paredit-semicolon
77 | paredit-splice-sexp
78 | paredit-splice-sexp-killing-backward
79 | paredit-split-sexp
80 | paredit-wrap-round
81 | paredit-wrap-square
82 | reposition-window
83 | sort-lines
84 | subtract-number-at-point
85 | tagedit-insert-quote
86 | transpose-sexps
87 | upstream
88 | wdired--self-insert
89 | wgrep-mark-deletion
90 | yas-expand
91 | ))
92 |
93 | (setq mc/cmds-to-run-once
94 | '(
95 | beginning-of-buffer
96 | cleanup-buffer
97 | end-of-buffer
98 | find-file
99 | magit-status
100 | mouse-set-region
101 | persp-switch-to-buffer*
102 | wgrep-change-to-wgrep-mode
103 | xref-find-definitions
104 | ))
105 |
--------------------------------------------------------------------------------
/users/teodorlu/tplay.el:
--------------------------------------------------------------------------------
1 | ;; A light Emacs interface for https://github.com/teodorlu/play.teod.eu
2 |
3 | ;; This code is based on older, messier code.
4 | ;;
5 | ;; Approach this time around: move in smaller steps. Don't copy the whole thing,
6 | ;; just the parts that are needed.
7 |
8 | (require 's)
9 |
10 | (defun tplay-clean ()
11 | (interactive)
12 | (let ((default-directory "~/repo/teodorlu/play.teod.eu"))
13 | (shell-command-to-string "./play.clj makefile && make clean && make")
14 | (shell-command-to-string "./play.clj reindex")))
15 |
16 | (defun tplay-create* (page-slug title form lang body)
17 | "Low-level function for creating pages.
18 |
19 | PAGE-SLUG: eg \"rudyard-kipling\"
20 | TITLE: eg \"Rudyard Kipling\"
21 | FORM: eg \":remote-reference\" or \"nil\"
22 | LANG: eg \":en\" or \":no\"
23 | BODY: nil, or the content of the document to create"
24 | (let ((default-directory "~/repo/teodorlu/play.teod.eu"))
25 | (shell-command-to-string (s-concat "./play.clj create-page"
26 | " :slug " page-slug
27 | " :title " (shell-quote-argument title)
28 | " :form " (shell-quote-argument form)
29 | " :lang " (shell-quote-argument lang)
30 | (when body
31 | (s-concat " :body " (shell-quote-argument body)))))))
32 |
33 | (defmacro comment (&rest body) nil)
34 |
35 | (comment
36 | (teod-play-create* "the-lollercoasters" "The Lollercoasters" "nil" ":en" "hello there")
37 | )
38 |
39 | (defun tplay-create ()
40 | (interactive)
41 | (let* ((page-slug (read-string "Page slug: "))
42 | (title (read-string "Page title: "))
43 | (form (completing-read ":form? > " '(":remote-reference" "nil")))
44 | (lang (completing-read ":lang? > " '(":en" ":no")))
45 | (default-directory "~/repo/teodorlu/play.teod.eu"))
46 | (tplay-create* page-slug title form lang nil)
47 | (tplay-clean)
48 | (switch-to-buffer (find-file-noselect page-slug))))
49 |
50 | (defun tplay-youtube-embed ()
51 | "Embed a youtube-video from its ID."
52 | (interactive)
53 | (let* ((youtube-video-id (read-string "Youtube video ID (like SxdOUGdseq4): ")))
54 | (cond ((eq major-mode 'org-mode) (insert (s-concat
55 | "#+begin_export html"
56 | "\n"
57 | ""
60 | "\n"
61 | "#+end_export"
62 | "\n")))
63 | (t (message (s-concat "sorry: youtube links for " (symbol-name major-mode) " is not yet supported."))))))
64 |
65 | (defun tplay-link ()
66 | "Insert page link"
67 | (interactive)
68 | (let* ((default-directory "~/repo/teodorlu/play.teod.eu")
69 | (pages (s-with "bb -x tplay.linkui/page-titles"
70 | shell-command-to-string
71 | s-trim
72 | s-lines))
73 | (page-title (completing-read "Select link> " pages))
74 | (link (s-with (concat "bb -x tplay.linkui/title-to-link" " :title " (shell-quote-argument page-title))
75 | shell-command-to-string
76 | s-trim)))
77 | (insert link)))
78 |
79 | (require 'parseedn)
80 |
81 | (parseedn-read-str ":select")
82 | (parseedn-read-str "{:select 1}")
83 |
--------------------------------------------------------------------------------
/settings/clj-auto-refer-mode.el:
--------------------------------------------------------------------------------
1 | ;; clj-auto-refer-mode.el
2 | ;;
3 | ;; Requires and refers well-known functions and macros for you.
4 |
5 | (require 'dash)
6 | (require 'cider)
7 | (require 'clj-refactor)
8 | (require 'clj-clean-namespace)
9 |
10 | (defvar auto-refer-packages nil)
11 | ;; see setup-clj-refactor.el for usage (for now)
12 |
13 | (defun auto-refer--in-comment? ()
14 | (nth 4 (syntax-ppss)))
15 |
16 | (defun auto-refer--in-string? ()
17 | (nth 3 (syntax-ppss)))
18 |
19 | (defun auto-refer--find-usages (package)
20 | (let ((symbols-re (concat (regexp-opt '("(" "["))
21 | (regexp-opt (-concat (plist-get package :functions)
22 | (plist-get package :macros))
23 | 'symbols)))
24 | result)
25 | (save-excursion
26 | (goto-char (point-min))
27 | (while (re-search-forward symbols-re nil t)
28 | (unless (or (auto-refer--in-comment?)
29 | (auto-refer--in-string?))
30 | (!cons (cider-symbol-at-point) result))))
31 | (-distinct result)))
32 |
33 | (defun auto-refer--remove-from-ns (type s)
34 | (cljr--goto-ns)
35 | (when (cljr--search-forward-within-sexp (concat "(" type))
36 | (skip-syntax-forward " >")
37 | (while (not (looking-at ")"))
38 | (if (looking-at (regexp-quote (concat "[" s)))
39 | (cljr--delete-sexp)
40 | (paredit-forward))
41 | (skip-syntax-forward " >"))))
42 |
43 | (defun auto-refer--update-clj-namespace (package)
44 | (let ((ns (plist-get package :ns)))
45 | (save-excursion
46 | (cljr--goto-ns)
47 | (unless (cljr--search-forward-within-sexp (concat ns " :as"))
48 | (let ((usages (auto-refer--find-usages package)))
49 | (auto-refer--remove-from-ns ":require" ns)
50 | (when usages
51 | (cljr--insert-in-ns ":require")
52 | (insert (concat "[" ns " :refer ["))
53 | (apply 'insert (->> usages
54 | (-sort 'string<)
55 | (-interpose " ")))
56 | (insert "]]"))))
57 | (clj-cn-sort-ns))))
58 |
59 | (defun auto-refer--update-cljs-namespace (package)
60 | (let* ((ns (or (plist-get package :cljs-ns)
61 | (plist-get package :ns)))
62 | (macro-ns (or (plist-get package :cljs-macro-ns)
63 | ns))
64 | (functions (plist-get package :functions))
65 | (macros (plist-get package :macros)))
66 | (save-excursion
67 | (cljr--goto-ns)
68 | (unless (cljr--search-forward-within-sexp (concat ns " :as"))
69 | (let* ((usages (auto-refer--find-usages package))
70 | (used-fns (--filter (member it functions) usages))
71 | (used-macros (--filter (member it macros) usages)))
72 | (auto-refer--remove-from-ns ":require" ns)
73 | (auto-refer--remove-from-ns ":require-macros" macro-ns)
74 | (when used-fns
75 | (cljr--insert-in-ns ":require")
76 | (just-one-space)
77 | (insert (concat "[" ns " :refer ["))
78 | (apply 'insert (->> used-fns
79 | (-sort 'string<)
80 | (-interpose " ")))
81 | (insert "]]"))
82 | (when used-macros
83 | (cljr--insert-in-ns ":require-macros")
84 | (just-one-space)
85 | (insert (concat "[" macro-ns " :refer ["))
86 | (apply 'insert (->> used-macros
87 | (-sort 'string<)
88 | (-interpose " ")))
89 | (insert "]]"))
90 | (clj-cn-sort-ns))))))
91 |
92 | (defun auto-refer-update-namespace ()
93 | (interactive)
94 | (cond ((s-ends-with? ".clj" (buffer-file-name))
95 | (--each auto-refer-packages
96 | (auto-refer--update-clj-namespace it)))
97 |
98 | ((s-ends-with? ".cljs" (buffer-file-name))
99 | (--each auto-refer-packages
100 | (auto-refer--update-cljs-namespace it)))))
101 |
102 | (define-minor-mode auto-refer-mode
103 | "Auto refer mode"
104 | :lighter ""
105 | (if auto-refer-mode
106 | (add-hook 'before-save-hook 'auto-refer-update-namespace t t)
107 | (remove-hook 'before-save-hook 'auto-refer-update-namespace t)))
108 |
109 | (provide 'clj-auto-refer-mode)
110 |
--------------------------------------------------------------------------------
/settings/cider-run.el:
--------------------------------------------------------------------------------
1 | ;;; cider-run.el --- A package for running commands via CIDER. -*- lexical-binding: t; -*-
2 |
3 | (require 'kaocha-runner)
4 | (require 'projectile)
5 |
6 | (defvar cider-run--out-buffer "*cider-run-output*")
7 | (defvar ns-regex "^(ns \\([^\s]+\\)")
8 |
9 | (defun cider-run--find-comment-forms ()
10 | (when (re-search-forward "^(comment ;; s-:" nil t)
11 | (let (forms beg end)
12 | (while (ignore-errors
13 | (forward-sexp) (setq end (point))
14 | (backward-sexp) (setq beg (point))
15 | (!cons (buffer-substring-no-properties beg end) forms)
16 | (forward-sexp)
17 | t))
18 | forms)))
19 |
20 | (defun cider-run--find-dev-namespace-and-comment-forms ()
21 | "Find and return the first Clojure namespace in dev.clj files under dev/ and its subdirectories."
22 | (let ((project-root (projectile-project-root)))
23 | (when project-root
24 | (let ((find-cmd (format "find %sdev -type f -name dev.clj" project-root))
25 | ns
26 | forms)
27 | (with-temp-buffer
28 | (call-process-shell-command find-cmd nil t)
29 | (goto-char (point-min))
30 | (while (and (not ns) (not (eobp)))
31 | (let ((file (buffer-substring (line-beginning-position) (line-end-position))))
32 | (with-temp-buffer
33 | (insert-file-contents file)
34 | (goto-char (point-min))
35 | (when (re-search-forward ns-regex nil t)
36 | (setq ns (match-string 1))
37 | (setq forms (cider-run--find-comment-forms)))))
38 | (forward-line 1)))
39 | (cons (s-trim ns)
40 | forms)))))
41 |
42 | (defun cider-run--run-in-repl (ns invocation)
43 | (interactive)
44 | (kaocha-runner--clear-buffer cider-run--out-buffer)
45 | (let ((buffer (cider-current-repl 'clj 'ensure)))
46 | (cider-nrepl-request:eval
47 | invocation
48 | (let ((original-buffer (current-buffer))
49 | (any-errors? nil)
50 | (done? nil))
51 | (lambda (response)
52 | (let ((showing? (get-buffer cider-run--out-buffer)))
53 | (nrepl-dbind-response response (value out err status)
54 | (unless done?
55 | (when (and (or out err) showing?)
56 | (with-current-buffer cider-run--out-buffer
57 | (insert (propertize (or out err) 'face
58 | (if out
59 | 'cider-repl-stdout-face
60 | 'cider-repl-stderr-face))))
61 | (kaocha-runner--with-window cider-run--out-buffer original-buffer
62 | (window-resize nil (- (max 6
63 | (min 15 (1+ (line-number-at-pos (point-max)))))
64 | (window-height)))
65 | (goto-char (point-max))
66 | (recenter (- -1 (min (max 0 scroll-margin)
67 | (truncate (/ (window-body-height) 4.0)))) t)))
68 | (when out
69 | (ignore-errors
70 | (cider-repl-emit-stdout buffer out)))
71 | (when err
72 | (setq any-errors? t)
73 | (ignore-errors
74 | (cider-repl-emit-stderr buffer err)))
75 | (when value
76 | (message "%s" value))
77 | (when (and status (member "done" status))
78 | (setq done? t)
79 | (when (and (not any-errors?) showing?)
80 | (run-with-timer 1 nil 'cider-run--kill-out-buffer))))))))
81 | ns nil nil nil buffer)))
82 |
83 | (defun cider-run--kill-out-buffer ()
84 | (kaocha-runner--hide-window cider-run--out-buffer)
85 | (kill-buffer cider-run--out-buffer))
86 |
87 | (defun cider-run-in-dev-namespace ()
88 | (interactive)
89 | (if-let ((ns+forms (cider-run--find-dev-namespace-and-comment-forms)))
90 | (cider-run--run-in-repl (car ns+forms)
91 | (completing-read (format "Eval in %s: " (car ns+forms))
92 | (or (cdr ns+forms)
93 | cider-run-in-dev-namespace-default-suggestions)))
94 | (message "No dev namespace found")))
95 |
96 | (defvar cider-run-in-dev-namespace-default-suggestions
97 | '("(start)" "(reset)"))
98 |
99 | (provide 'cider-run)
100 |
--------------------------------------------------------------------------------
/settings/sane-defaults.el:
--------------------------------------------------------------------------------
1 | ;; Auto refresh buffers
2 | (use-package autorevert
3 | :defer 2
4 | :config (global-auto-revert-mode 1))
5 |
6 | ;; Also auto refresh dired, but be quiet about it
7 | (setq global-auto-revert-non-file-buffers t)
8 | (setq auto-revert-verbose nil)
9 |
10 | ;; Show keybinding prefixes faster
11 | (setq echo-keystrokes 0.1)
12 |
13 | ;; Move files to trash when deleting
14 | (setq delete-by-moving-to-trash t)
15 |
16 | ;; Shift is more useful as a modifier
17 | (setq shift-select-mode nil)
18 |
19 | ;; Transparently open compressed files
20 | (auto-compression-mode t)
21 |
22 | ;; Answering just 'y' or 'n' will do
23 | (defalias 'yes-or-no-p 'y-or-n-p)
24 |
25 | ;; UTF-8 please
26 | (setq locale-coding-system 'utf-8) ; pretty
27 | (set-terminal-coding-system 'utf-8) ; pretty
28 | (set-keyboard-coding-system 'utf-8) ; pretty
29 | (set-selection-coding-system 'utf-8) ; please
30 | (prefer-coding-system 'utf-8) ; with sugar on top
31 |
32 | ;; Remove text in active region if inserting text
33 | (use-package delsel
34 | :defer 1
35 | :config (delete-selection-mode 1))
36 |
37 | ;; Always display column numbers
38 | (setq column-number-mode t)
39 |
40 | ;; 80 chars is a good width.
41 | (set-default 'fill-column 80)
42 |
43 | ;; Save a list of recent files visited. (open recent file with C-x f)
44 | (use-package recentf
45 | :defer 1 ;; Loads after 1 second of idle time.
46 | :config (recentf-mode 1)
47 | :custom (recentf-max-saved-items 100)) ;; just 20 is too recent
48 |
49 | ;; Undo/redo window configuration with C-c /
50 | (use-package winner
51 | :defer 1
52 | :config (winner-mode 1))
53 |
54 | ;; Never insert tabs
55 | (set-default 'indent-tabs-mode nil)
56 |
57 | ;; Show me empty lines after buffer end
58 | (set-default 'indicate-empty-lines t)
59 |
60 | ;; Easily navigate sillycased words
61 | (use-package subword
62 | :defer 1
63 | :config (global-subword-mode 1)
64 | :diminish subword-mode)
65 |
66 | ;; Don't visually break lines for me, please
67 | (setq-default truncate-lines t)
68 |
69 | ;; Sentences do not need double spaces to end. Period.
70 | (set-default 'sentence-end-double-space nil)
71 |
72 | ;; Add parts of each file's directory to the buffer name if not unique
73 | (use-package uniquify
74 | :ensure nil
75 | :defer 2 ;; Loads after 2 seconds of idle time.
76 | :custom (uniquify-buffer-name-style 'forward))
77 |
78 | ;; Start Emacs server for emacsclient
79 | (use-package server
80 | :defer 2
81 | :config (unless (server-running-p)
82 | (server-start)))
83 |
84 | ;; Show more than 4 levels when evaling expressions
85 | (setq eval-expression-print-level 100)
86 |
87 | ;; Offer to create parent directories if they do not exist
88 | ;; http://iqbalansari.github.io/blog/2014/12/07/automatically-create-parent-directories-on-visiting-a-new-file-in-emacs/
89 | (defun my-create-non-existent-directory ()
90 | (let ((parent-directory (file-name-directory buffer-file-name)))
91 | (when (and (not (file-exists-p parent-directory))
92 | (y-or-n-p (format "Directory `%s' does not exist! Create it?" parent-directory)))
93 | (make-directory parent-directory t))))
94 |
95 | (add-to-list 'find-file-not-found-functions 'my-create-non-existent-directory)
96 |
97 | ;; Don't zoom individual buffers
98 | (global-unset-key (kbd "C-x C-+"))
99 |
100 | ;; Disable zooming with pinch / mouse wheel
101 | ;;
102 | ;; In addition to zooming with `C-x C-+` and `C-x C--`, there's a different,
103 | ;; buffer specific zoom that zooms insanel fast.
104 | (global-set-key (kbd "") 'ignore)
105 | (global-set-key (kbd "C-") 'mwheel-scroll)
106 | (global-set-key (kbd "C-") 'mwheel-scroll)
107 |
108 | ;; Write backup files to own directory
109 | (setq backup-directory-alist
110 | `(("." . ,(expand-file-name
111 | (concat user-emacs-directory "backups")))))
112 |
113 | ;; Make backups of files, even when they're in version control
114 | (setq vc-make-backup-files t)
115 |
116 | ;; We use git. Don't try all the other VC systems in existence first.
117 | (setq vc-handled-backends '(Git))
118 |
119 | ;; Don't write lock-files, I'm the only one here
120 | (setq create-lockfiles nil)
121 |
122 | ;; Write all autosave files in the tmp dir
123 | (setq auto-save-file-name-transforms
124 | `((".*" ,temporary-file-directory t)))
125 |
126 | ;; No electric indent
127 | (setq electric-indent-mode nil)
128 |
129 | ;; Automatically prompt for sudo in write protected files
130 | (use-package auto-sudoedit
131 | :defer 1
132 | :config (auto-sudoedit-mode 1))
133 |
134 | (provide 'sane-defaults)
135 |
--------------------------------------------------------------------------------
/packages/setup-clj-refactor.el:
--------------------------------------------------------------------------------
1 | (use-package clj-refactor
2 | :diminish clj-refactor-mode
3 |
4 | :custom
5 | (cljr-favor-prefix-notation nil)
6 | (cljr-favor-private-functions nil)
7 | (cljr-insert-newline-after-require nil)
8 | (cljr-assume-language-context "clj")
9 |
10 | :config
11 | (cljr-add-keybindings-with-modifier "C-s-")
12 | (define-key clojure-mode-map (kbd "C-S-M-u") (λ (cljr--goto-toplevel)))
13 | (define-key clojure-mode-map (kbd "C->") 'cljr-thread)
14 | (define-key clojure-mode-map (kbd "C-<") 'cljr-unwind)
15 |
16 | (setq cljr-clojure-test-declaration "[clojure.test :refer [deftest is testing]]")
17 | (setq cljr-cljs-clojure-test-declaration cljr-clojure-test-declaration)
18 | (setq cljr-cljc-clojure-test-declaration cljr-clojure-test-declaration)
19 |
20 | (add-hook 'clojure-mode-hook 'clj-refactor-mode)
21 |
22 | (require 'clj-auto-refer-mode)
23 | (setq auto-refer-packages
24 | '((:ns "clojure.core.async"
25 | :functions ("!" ">!!" "admix" "alt!" "alt!!" "alts!" "alts!!" "buffer"
26 | "chan" "close!" "do-alts" "dropping-buffer" "mix" "mult" "offer!"
27 | "onto-chan" "pipe" "pipeline" "pipeline-async" "pipeline-blocking"
28 | "poll!" "pub" "put!" "sliding-buffer" "solo-mode" "sub" "take!"
29 | "tap" "thread" "thread-call" "timeout" "to-chan" "unblocking-buffer?"
30 | "unmix" "unmix-all" "unsub" "unsub-all" "untap" "untap-all")
31 | :macros ("go" "go-loop")
32 | :cljs-ns "cljs.core.async"
33 | :cljs-macro-ns "cljs.core.async.macros")
34 |
35 | (:ns "clojure.test"
36 | :macros ("deftest" "testing" "is" "are"))))
37 | (add-hook 'clojure-mode-hook 'auto-refer-mode)
38 |
39 | (advice-add 'cljr-update-project-dependency :around #'my/cljr-handle-git-sha-deps))
40 |
41 | (require 'json)
42 |
43 | (defun my/fetch-latest-github-commits (user repo num)
44 | (let* ((url (format "https://api.github.com/repos/%s/%s/commits?per_page=%s" user repo num))
45 | (buffer (url-retrieve-synchronously url))
46 | (json-array-type 'list))
47 | (with-current-buffer buffer
48 | (goto-char (point-min))
49 | (re-search-forward "^$")
50 | (delete-region (point) (point-min))
51 | (let ((data (json-read)))
52 | (kill-buffer)
53 | (mapcar (lambda (commit)
54 | (let ((sha (cdr (assoc 'sha commit)))
55 | (message (cdr (assoc 'message (assoc 'commit commit))))
56 | (timestamp (cdr (assoc 'date (assoc 'committer (assoc 'commit commit))))))
57 | (list :sha sha :message message :timestamp timestamp)))
58 | data)))))
59 |
60 | (defun my/clj-refactor-upgrade-git-sha-dep ()
61 | (interactive)
62 | (when (cljr--looking-at-dependency-p)
63 | (save-excursion
64 | (let ((kind (match-string-no-properties 2))
65 | (url (match-string-no-properties 4)))
66 | (when (and (s-equals? ":git" kind)
67 | (s-contains? "github.com" url))
68 | (-let [(_ user repo) (s-match "github.com/\\([^/]+\\)/\\([^/.]+\\).git" url)]
69 | (let ((commit (car (my/fetch-latest-github-commits user repo 1))))
70 | (when (search-forward ":sha \"")
71 | (let ((old-sha (progn (looking-at "[a-z0-9]+")
72 | (match-string-no-properties 0))))
73 | (if (s-equals? old-sha (plist-get commit :sha))
74 | (message "Already at newest revision")
75 | (progn
76 | (delete-char (length old-sha))
77 | (insert (plist-get commit :sha))
78 | (message "Bumped to revision from %s\n%s"
79 | (plist-get commit :timestamp)
80 | (plist-get commit :message)))))))))))))
81 |
82 | (defun my/cljr-handle-git-sha-deps (orig-fn &rest args)
83 | (unless (my/clj-refactor-upgrade-git-sha-dep)
84 | (apply orig-fn args)))
85 |
86 | (defun cljr--add-test-declarations ()
87 | (save-excursion
88 | (let* ((ns (clojure-find-ns))
89 | (source-ns (cljr--find-source-ns-of-test-ns ns (buffer-file-name))))
90 | (cljr--insert-in-ns ":require")
91 | (when source-ns
92 | (insert "[" source-ns " :as "
93 | (car (last (s-split "\\." source-ns))) "]"))
94 | (cljr--insert-in-ns ":require")
95 | (insert (cond
96 | ((cljr--project-depends-on-p "midje")
97 | cljr-midje-test-declaration)
98 | ((cljr--project-depends-on-p "expectations")
99 | cljr-expectations-test-declaration)
100 | ((cljr--cljs-file-p)
101 | cljr-cljs-clojure-test-declaration)
102 | ((cljr--cljc-file-p)
103 | cljr-cljc-clojure-test-declaration)
104 | (t cljr-clojure-test-declaration))))
105 | (indent-region (point-min) (point-max))))
106 |
107 | (provide 'setup-clj-refactor)
108 |
--------------------------------------------------------------------------------
/packages/setup-makefile-mode.el:
--------------------------------------------------------------------------------
1 | ;;; Inject some Emacs into makefile-mode.
2 |
3 | (defun my/tab-indent (n)
4 | (back-to-indentation)
5 | (delete-horizontal-space)
6 | (--dotimes n
7 | (insert "\t")))
8 |
9 | (defun my/in-process-of-adding-commands-to-rule? ()
10 | "This will indicate indentation of the current line if we are
11 | working on a rule, but only if there is a blank line below.
12 | Otherwise we would add a TAB to all the blank lines between rules
13 | when cleaning the buffer."
14 | (interactive)
15 | (save-excursion
16 | (let ((current-line (thing-at-point 'line t))
17 | (above-line nil)
18 | (below-line nil))
19 | (forward-line -1)
20 | (setq above-line (thing-at-point 'line t))
21 | (forward-line 2)
22 | (setq below-line (thing-at-point 'line t))
23 | (and (equal "\n" current-line) ;; Current line is blank
24 | (or (string-match-p "^\t" above-line) ;; Above line is indented with a tab
25 | (string-match-p "^[^ \t\n#]+:" above-line)) ;; or is a rule definition
26 | (equal "\n" below-line))))) ;; Below line is blank
27 |
28 | (defun my/makefile-indent-line ()
29 | "Indent current line as Makefile code."
30 | (interactive)
31 | (let* ((savep (point))
32 | (indent-col
33 | (save-excursion
34 | (back-to-indentation)
35 | (when (>= (point) savep) (setq savep nil))
36 | (beginning-of-line)
37 | (cond
38 | ((my/in-process-of-adding-commands-to-rule?) 1)
39 |
40 | ((or (looking-at "^[ \t]*$") ;; Blank line
41 | (looking-at "^[ \t]*#") ;; Comment line
42 | (looking-at "^[^ \t\n#]+ ?=") ;; Variable definition
43 | (looking-at "^[A-Z_]+$") ;; Variable definition in progress
44 | (looking-at "^[^ \t\n#]+:")) ;; Rule definition
45 | 0)
46 | (t 1)))))
47 | (if (null indent-col)
48 | 'noindent
49 | (if savep
50 | (save-excursion (my/tab-indent indent-col))
51 | (my/tab-indent indent-col)))))
52 |
53 | (add-hook 'makefile-mode-hook
54 | (lambda ()
55 | (setq-local indent-line-function 'my/makefile-indent-line)))
56 |
57 | (defun makefile-find-targets ()
58 | "Find all targets in a Makefile."
59 | (let (targets)
60 | (save-excursion
61 | (goto-char (point-min))
62 | (while (re-search-forward "^\\([^:#\t\n]+?\\):" nil t)
63 | (let ((target (match-string-no-properties 1)))
64 | (unless (s-equals? target ".PHONY")
65 | (setq targets (cons (string-trim target) targets))))))
66 | (reverse targets)))
67 |
68 | (defun shorten-path (path)
69 | "Shortens the file PATH by replacing the home directory with ~."
70 | (let ((home (expand-file-name "~")))
71 | (if (string-prefix-p home path)
72 | (concat "~" (substring path (length home)))
73 | path)))
74 |
75 | (defvar makefile--previous-window-configuration nil)
76 | (defvar makefile--previous-target nil)
77 |
78 | (defun makefile-invoke-target (&optional repeat?)
79 | (interactive)
80 | (let* ((file (concat (projectile-project-root) "Makefile"))
81 | (short-dir (shorten-path (projectile-project-root)))
82 | (default-directory (projectile-project-root))
83 | (make-buffer-name (concat "*Make " (projectile-project-name) "*"))
84 | (prev (if (get-buffer make-buffer-name)
85 | (with-current-buffer make-buffer-name
86 | makefile--previous-window-configuration)
87 | (list (current-window-configuration) (point-marker))))
88 | (target (or (and repeat? (with-current-buffer make-buffer-name
89 | makefile--previous-target))
90 | (completing-read (format "Make in %s: " short-dir)
91 | (--map
92 | (concat "make " it)
93 | (with-temp-buffer
94 | (insert-file-contents file)
95 | (makefile-find-targets)))))))
96 | (if (file-exists-p file)
97 | (progn
98 | (async-shell-command target make-buffer-name)
99 | (unless (s-equals? (buffer-name) make-buffer-name)
100 | (switch-to-buffer-other-window make-buffer-name))
101 | (setq-local makefile--previous-window-configuration prev)
102 | (setq-local makefile--previous-target target)
103 | (read-only-mode)
104 | (local-set-key (kbd "m") 'makefile-invoke-target)
105 | (local-set-key (kbd "g") (λ (makefile-invoke-target t)))
106 | (local-set-key (kbd "q") (λ (let ((conf makefile--previous-window-configuration))
107 | (kill-buffer)
108 | (when conf (register-val-jump-to conf nil))))))
109 | (message "No Makefile found in %s" short-dir))))
110 |
111 | (global-set-key (kbd "s-m") 'makefile-invoke-target)
112 |
113 | (provide 'setup-makefile-mode)
114 |
--------------------------------------------------------------------------------
/settings/css-completions.el:
--------------------------------------------------------------------------------
1 | (require 'cider)
2 | (require 'dash)
3 | (require 's)
4 | (require 'projectile)
5 |
6 | (defun cssc/find-css-files-in-project ()
7 | (let ((root (projectile-project-root)))
8 | (->> (projectile-dir-files root)
9 | (--filter (s-ends-with? ".css" it))
10 | (--map (concat root it)))))
11 |
12 | (defun cssc/read-file-into-string (filename)
13 | (with-temp-buffer
14 | (insert-file-contents filename)
15 | (buffer-string)))
16 |
17 | (defun cssc/read-project-css-file-contents ()
18 | (apply #'concat
19 | (-map #'cssc/read-file-into-string
20 | (cssc/find-css-files-in-project))))
21 |
22 | (setq cssc/well-known-file-endings
23 | '("jpg" "jpeg" "png" "svg"))
24 |
25 | (defun cssc/extract-css-class-names (string)
26 | "Extract all CSS class names from STRING."
27 | (let ((pattern "\\.[a-zA-Z][a-zA-Z0-9_-]+\\b")
28 | (pos 0)
29 | (hash (make-hash-table :test 'equal)))
30 | (while (string-match pattern string pos)
31 | (setq pos (match-end 0))
32 | (puthash (substring (match-string 0 string) 1) t hash))
33 | (--each cssc/well-known-file-endings
34 | (remhash it hash))
35 | (hash-table-keys hash)))
36 |
37 | (defun cssc/inside-clojure-class-structure? ()
38 | (or
39 | ;; matches {:class :bar}
40 | (save-excursion (ignore-errors (paredit-backward 2)
41 | (looking-at ":class")))
42 | ;; matches {:class [:bar]}
43 | (save-excursion (ignore-errors (paredit-backward-up)
44 | (paredit-backward)
45 | (looking-at ":class")))
46 | ;; matches (into class [:bar])
47 | (save-excursion (ignore-errors (paredit-backward-up 2)
48 | (paredit-backward)
49 | (looking-at ":class")))))
50 |
51 | (defun cssc/find-hiccup-class-name-position ()
52 | "Are we completing a Clojure keyword with dots in it, like :div.foo.bar ?"
53 | (when-let ((bounds (bounds-of-thing-at-point 'symbol)))
54 | (when (not (or (cider-in-string-p)
55 | (cider-in-comment-p)))
56 | (let ((s (buffer-substring-no-properties (car bounds)
57 | (cdr bounds))))
58 | (when (s-starts-with? ":" s)
59 | (when-let ((last-dot-index (string-match-p "\\.[^\\.]+$" s)))
60 | (list
61 | (+ last-dot-index (car bounds))
62 | (cdr bounds)
63 | ".")))))))
64 |
65 | (defun cssc/find-keyword-class-name-position ()
66 | "Are we completing a Clojure keyword inside some structure assigning to :class?"
67 | (when-let ((bounds (bounds-of-thing-at-point 'symbol)))
68 | (when (not (or (cider-in-string-p)
69 | (cider-in-comment-p)))
70 | (let ((s (buffer-substring-no-properties (car bounds)
71 | (cdr bounds))))
72 | (when (and (s-starts-with? ":" s)
73 | (cssc/inside-clojure-class-structure?))
74 | (list
75 | (car bounds)
76 | (cdr bounds)
77 | ":"))))))
78 |
79 | (defun cssc/find-string-class-name-position ()
80 | "Are we completing a symbol in a string inside some structure assigning to :class?"
81 | (when-let ((bounds (bounds-of-thing-at-point 'symbol)))
82 | (when (and (cider-in-string-p)
83 | (cssc/inside-clojure-class-structure?))
84 | (list
85 | (car bounds)
86 | (cdr bounds)
87 | ""))))
88 |
89 | (defun cssc/find-html-class-name-position ()
90 | (when-let ((bounds (bounds-of-thing-at-point 'symbol)))
91 | (when (and (nth 3 (syntax-ppss))
92 | (save-excursion
93 | (goto-char (nth 8 (syntax-ppss)))
94 | (looking-back "class=" (- (point) 10))))
95 | (list
96 | (car bounds)
97 | (cdr bounds)
98 | ""))))
99 |
100 | (defvar cssc/find-class-name-position-fns ())
101 | (make-variable-buffer-local 'cssc/find-class-name-position-fns)
102 |
103 | (defun cssc/css-classes-completion-at-point ()
104 | (when-let ((res (--some (funcall it) cssc/find-class-name-position-fns)))
105 | (-let [(beg end prefix) res]
106 | (list beg end
107 | (--map (concat prefix it)
108 | (cssc/extract-css-class-names
109 | (cssc/read-project-css-file-contents)))))))
110 |
111 | (defun cssc/enable-for-clojure ()
112 | "Sets up current buffer for clojure css completions. Run in a hook."
113 | (add-to-list 'completion-at-point-functions
114 | #'cssc/css-classes-completion-at-point)
115 | (setq cssc/find-class-name-position-fns
116 | (list #'cssc/find-hiccup-class-name-position
117 | #'cssc/find-keyword-class-name-position
118 | #'cssc/find-string-class-name-position)))
119 |
120 | (defun cssc/enable-for-html ()
121 | (add-to-list 'completion-at-point-functions
122 | #'cssc/css-classes-completion-at-point)
123 | (setq cssc/find-class-name-position-fns
124 | (list #'cssc/find-html-class-name-position)))
125 |
126 | (defun cssc/skip-in-front-of-the-completion-chain ()
127 | (when (-contains? completion-at-point-functions
128 | #'cssc/css-classes-completion-at-point)
129 | (remove-hook 'completion-at-point-functions
130 | #'cssc/css-classes-completion-at-point
131 | t)
132 | (add-to-list 'completion-at-point-functions
133 | #'cssc/css-classes-completion-at-point)))
134 |
135 | (add-hook 'lsp-completion-mode-hook 'cssc/skip-in-front-of-the-completion-chain)
136 | (add-hook 'cider-mode-hook 'cssc/skip-in-front-of-the-completion-chain)
137 |
138 | (provide 'css-completions)
139 |
--------------------------------------------------------------------------------
/users/teodorlu/teodorlu.el:
--------------------------------------------------------------------------------
1 | (require 'matnyttig)
2 |
3 | ;; Auto-installed clojure-lsp has given me pain, so I use Homebrew.
4 | ;; This means `which clojure-lsp` finds the clojure-lsp that Emacs calls to.
5 | (setq lsp-clojure-custom-server-command '("clojure-lsp"))
6 |
7 | ;; Don't auto-wrap lines, I like one line per sentence
8 | ;; https://sive.rs/1s
9 | (remove-hook 'markdown-mode-hook 'auto-fill-mode)
10 |
11 | ;; A quicker save is helpful for non-interactive languages that require saving files to reload code
12 | (global-set-key (kbd "C-ø") 'save-buffer)
13 |
14 | (defun teodorlu-magnar-emacs-cheat-sheet ()
15 | (interactive)
16 | (find-file (expand-file-name "~/.emacs.d/README.md")))
17 |
18 | (defun teodorlu-today ()
19 | (interactive)
20 | (insert (format-time-string "%Y-%m-%d")))
21 |
22 | (defun teodorlu-current-time ()
23 | (shell-command-to-string "echo -n `date \"+%H:%M\"`"))
24 |
25 | (defun teodorlu-now ()
26 | (interactive)
27 | (insert (shell-command-to-string "echo -n `date \"+%H:%M\"`")))
28 |
29 | (defun teodorlu-insert-en-dash ()
30 | (interactive)
31 | (insert "-"))
32 |
33 | (defun teodorlu-insert-em-dash ()
34 | (interactive)
35 | (insert "—"))
36 |
37 | (defun teodorlu-add-clerk ()
38 | (interactive)
39 | (cider-interactive-eval "(clojure.repl.deps/add-lib 'io.github.nextjournal/clerk)"))
40 |
41 | (defun teodorlu-add-kaocha ()
42 | (interactive)
43 | (cider-interactive-eval "(clojure.repl.deps/add-lib 'lambdaisland/kaocha)"))
44 |
45 | (defun clerk-tap-viewer ()
46 | (interactive)
47 | (cider-interactive-eval "(nextjournal.clerk/show! 'nextjournal.clerk.tap)"))
48 |
49 | (defun clerk-serve ()
50 | (interactive)
51 | (cider-interactive-eval "((requiring-resolve 'nextjournal.clerk/serve!) {:port 7799})"))
52 |
53 | (defun clerk-serve-browse ()
54 | (interactive)
55 | (cider-interactive-eval "((requiring-resolve 'nextjournal.clerk/serve!) {:browse true :port 7799})"))
56 |
57 | (defun clerk-halt ()
58 | (interactive)
59 | (cider-interactive-eval "(nextjournal.clerk/halt!)"))
60 |
61 | (defun teodorlu-clojure-remove-namespace ()
62 | (interactive)
63 | (cider-interactive-eval "(remove-ns (symbol (str *ns*)))"))
64 |
65 | (defun teodorlu-garden-deploy ()
66 | (interactive)
67 | (projectile-run-shell-command-in-root "garden deploy"))
68 |
69 | (use-package clay)
70 | (use-package go-mode)
71 | ;; Husk å installere gopls
72 | ;; go install golang.org/x/tools/gopls@latest
73 | (add-hook 'go-mode-hook 'lsp-deferred)
74 |
75 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
76 | ;; English/Norwegian spell check on Mac with Homebrew and Hunspell
77 | ;;
78 | ;; 1. Install hunspell
79 | ;;
80 | ;; brew install hunspell
81 | ;;
82 | ;; 2. Clone the hunspell dictionary repo to a temporary location
83 | ;;
84 | ;; dir="${HOME}/tmp/temp-$(date "+%Y-%m-%d")"
85 | ;; mkdir -p $dir
86 | ;; cd $dir
87 | ;; git clone git://anongit.freedesktop.org/libreoffice/dictionaries --depth=1
88 | ;;
89 | ;; 3. Install hunspell dictionaries for your languages of choice.
90 | ;;
91 | ;; cp -r dictionaries/en/* ~/Library/Spelling/
92 | ;; cp -r dictionaries/no/* ~/Library/Spelling/
93 | ;;
94 | ;; 4. Set Emacs to use hunspell for spelling
95 | ;;
96 | (setenv "DICPATH" (concat (getenv "HOME") "/Library/Spelling"))
97 | (setq ispell-program-name "/opt/homebrew/bin/hunspell")
98 | ;;
99 | ;; 5. Validate dictionary installation
100 | ;;
101 | ;; hunspell -D
102 | ;;
103 | ;; You should see your installed dictionaries under AVAILABLE DICTIONARIES.
104 | ;;
105 | ;; 6. Activate flyspell-mode when you want spell checking
106 | ;;
107 | (add-hook 'org-mode-hook (lambda () (flyspell-mode 1)))
108 | (add-hook 'markdown-mode-hook (lambda () (flyspell-mode 1)))
109 | ;;
110 | ;; 7. Finally, when you want to change the spell checking language,
111 | ;;
112 | ;; M-x ispell-change-dictionary
113 |
114 | (setq cider-repl-display-help-banner nil)
115 | (pixel-scroll-precision-mode 1)
116 |
117 | (defun teodorlu-mblog-create-olorm ()
118 | "Write a new post at https://mikrobloggeriet.no/olorm/ with minimal friction!"
119 | (interactive)
120 | (projectile-run-shell-command-in-root "./mblog.sh create text/olorm"))
121 |
122 | (defun teodorlu-dir-locals ()
123 | (interactive)
124 | (insert (prin1-to-string
125 | '((nil
126 | (cider-clojure-cli-aliases . "-A:dev")
127 | (cider-preferred-build-tool . clojure-cli))))))
128 |
129 | (defun teodorlu-make ()
130 | (interactive)
131 | (projectile-run-shell-command-in-root "make"))
132 |
133 | ;; Teach projectile where to find projects
134 | (setq projectile-project-search-path '(("~/repo" . 2) ; github projects
135 | ("~/p" . 2) ; learn stuff
136 | ))
137 | ;; Find more repos :: M-x projectile-discover-projects-in-search-path
138 | ;; Cleanup :: M-x projectile-cleanup-known-projects
139 |
140 | (defun teodorlu-insert-bb-edn-refer-deps-edn ()
141 | (interactive)
142 | (let* ((ancestors (thread-last (f-this-file) f-dirname f-split nreverse))
143 | (project (car ancestors))
144 | (org (cadr ancestors))
145 | (bb-edn-string (s-concat "{:deps {io.github."
146 | org "/" project
147 | " {:local/root \".\"}}}")))
148 | (insert bb-edn-string)))
149 |
150 | (setq browse-at-remote-prefer-symbolic nil)
151 | (global-set-key (kbd "C-x v w") 'browse-at-remote-kill)
152 |
153 | (defun matnyttig-bb-dev ()
154 | (interactive)
155 | (async-shell-command
156 | (concat "/Applications/Ghostty.app/Contents/MacOS/ghostty"
157 | " --working-directory=/Users/teodorlu/repo/Mattilsynet/matnyttig"
158 | " -e zsh -c \"bb dev\"")
159 | nil nil))
160 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # .emacs.d
2 |
3 | An Emacs configuration for Norwegian keyboard on OSX (lol), as seen on emacsrocks.com and parens-of-the-dead.com.
4 |
5 | ## Installation
6 |
7 | Download [Emacs for Mac OSX](http://emacsformacosx.com/).
8 |
9 | ## Out of band dependencies
10 |
11 | - Spell checking:
12 |
13 | ```
14 | brew install aspell --lang=en
15 | ```
16 |
17 | - Static analysis for Clojure with LSP
18 |
19 | ```
20 | brew install clojure-lsp/brew/clojure-lsp-native
21 | ```
22 |
23 | or get the nightly:
24 |
25 | ```
26 | bash <(curl https://raw.githubusercontent.com/clojure-lsp/clojure-lsp/master/install) --version nightly --dir ~/bin
27 | ```
28 |
29 | (place somewhere on your path before homebrew)
30 |
31 |
32 | - Fast grepping:
33 |
34 | ```
35 | brew install ripgrep
36 | ```
37 |
38 | - Make dired happy, install `gls` as replacement for `ls`:
39 |
40 | ```
41 | brew install xz coreutils
42 | ```
43 |
44 | - Stop clojure-lsp from adding duplicate namespace declarations:
45 |
46 | Open `~/.config/clojure-lsp/config.edn` and add:
47 |
48 | ```
49 | {:auto-add-ns-to-new-files? false}
50 | ```
51 |
52 | This is already handled better by clj-refactor (which also inserts test
53 | declarations in relevant namespaces).
54 |
55 | - Add dependencies to the project without CIDER running:
56 |
57 | ```
58 | brew install babashka/brew/neil
59 | ```
60 |
61 | - Static analysis for CSS with LSP
62 |
63 | ```
64 | npm install -g vscode-langservers-extracted
65 | ```
66 |
67 | - On a Mac you might want to do this, to disable `C-M-d` in your OS, making it
68 | available for `paredit-forward-down`:
69 |
70 | ```
71 | defaults write com.apple.symbolichotkeys AppleSymbolicHotKeys -dict-add 70 'enabled'
72 | ```
73 |
74 | ## Tips for using these emacs settings
75 |
76 | If you want to use my settings straight out of the box, here are some things to note:
77 |
78 | * This is my personal emacs configuration. I am constantly tuning it to my
79 | preferences. You should consider doing the same. Maybe start with a blank emacs +
80 | [Technomancy's better-defaults package](https://git.sr.ht/~technomancy/better-defaults),
81 | and then dig through this repo for useful nuggets, instead of forking it directly.
82 |
83 | * The key bindings are optimized for a norwegian keyboard layout.
84 |
85 | * You quit emacs with `C-x r q`, mnemonic *Really Quit*.
86 |
87 | * Find file in project with `C-x p f`, in dir with `C-x C-f`, recent with `C-x f`
88 |
89 | * Switch to a project with `C-x p p`
90 |
91 | * Add your user- and project-specific stuff in .emacs.d/users/[machine name]/*.el
92 |
93 | * `C-h` is rebound to backspace, like in the shell. Get help on `F1` instead.
94 |
95 | * Autocomplete with `C-,` or `C-.`, try both to get a feel for them. (autocomplete entire lines with `C-:`)
96 |
97 | * expand-region is your friend. Find its bound key by doing `F1 f er/expand-region`
98 |
99 | * Undo with `C-_` and redo with `M-_`. Watch the undo-tree with `C-x u`
100 |
101 | * Indent and clean up white space in the entire buffer with `C-c n`
102 |
103 | * On a mac, the Meta key `M` is bound to Command.
104 |
105 | * I recommend rebinding Caps Lock to Ctrl and use that instead of the often badly placed Ctrl-key.
106 |
107 | * Watch [emacsrocks.com](http://emacsrocks.com)
108 |
109 | ## Survival guide for the first week of emacs
110 |
111 | When you start using emacs for the first time, your habits fight you every inch
112 | of the way. Your fingers long for the good old familiar keybindings. Here's an
113 | overview of the most commonly used shortcuts to get you through this pain:
114 |
115 | * `C ` Shorthand for the ctrl-key
116 | * `M ` Shorthand for the meta-key (bound to command on my mac settings)
117 | * `S ` Shorthand for the shift-key
118 | * `s ` Shorthand for the super-key (bount to option on my mac settings)
119 |
120 | ### Files
121 |
122 | * `C-x C-f` Open a file. Starts in the current directory
123 | * `C-x f ` Open a recently visited file
124 | * `C-x p f` Open a file in the current project (based on .git ++)
125 | * `C-x C-s` Save this file
126 | * `C-x C-w` Save as ...
127 | * `C-x C-j` Jump to this files' current directory
128 | * `C-x b ` Switch to another open file (buffer)
129 | * `C-x C-b` List all open files (buffers)
130 |
131 | ### Cut copy and paste
132 |
133 | * `C-space` Start marking stuff. C-g to cancel.
134 | * `C-w ` Cut (aka kill)
135 | * `C-k ` Cut till end of line
136 | * `M-w ` Copy
137 | * `C-y ` Paste (aka yank)
138 | * `M-y ` Cycle last paste through previous kills
139 | * `C-x C-y` Choose what to paste from previous kills
140 | * `C-@ ` Mark stuff quickly. Press multiple times
141 |
142 | ### General
143 |
144 | * `C-g ` Quit out of whatever mess you've gotten yourself into
145 | * `M-x ` Run a command by name
146 | * `C-. ` Autocomplete
147 | * `C-_ ` Undo
148 | * `M-_ ` Redo
149 | * `C-x u ` Show the undo-tree
150 | * `C-x m ` Open magit. It's a magical git interface for emacs
151 |
152 | ### Navigation
153 |
154 | * `C-arrow` Move past words/paragraphs
155 | * `C-a ` Go to start of line
156 | * `C-e ` Go to end of line
157 | * `M-g M-g` Go to line number
158 | * `C-x C-i` Go to symbol
159 | * `C-s ` Search forward. Press `C-s` again to go further.
160 | * `C-r ` Search backward. Press `C-r` again to go further.
161 |
162 | ### Window management
163 |
164 | * `C-x 0 ` Close this window
165 | * `C-x 1 ` Close other windows
166 | * `C-x 2 ` Split window horizontally
167 | * `C-x 3 ` Split window vertically
168 | * `S-arrow` Jump to window to the left/right/up/down
169 |
170 | ### Help
171 |
172 | * `F1 t ` Basic tutorial
173 | * `F1 k ` Help for a keybinding
174 | * `F1 r ` Emacs' extensive documentation
175 |
--------------------------------------------------------------------------------
/packages/setup-magit.el:
--------------------------------------------------------------------------------
1 | (use-package magit
2 | :defer t
3 |
4 | :custom
5 | (magit-section-initial-visibility-alist '((untracked . show)
6 | (unstaged . show)
7 | (unpushed . show)
8 | (unpulled . show)
9 | (stashes . show)))
10 | (magit-diff-refine-hunk t)
11 | (magit-push-always-verify nil)
12 | (magit-revert-buffers 'silent)
13 | (magit-no-confirm '(stage-all-changes
14 | unstage-all-changes))
15 |
16 | :bind (("C-x m" . magit-status)
17 | ("C-c p" . magit-toggle-pair-programming-mode)
18 | ("C-c P" . magit-add-pair-programming-partner)
19 | (:map git-commit-mode-map
20 | ("C-c C-p" . magit-add-pair-programming-partner))
21 | (:map magit-status-mode-map
22 | ("q" . magit-quit)))
23 |
24 | :config
25 | (wrap-fullscreen magit-status)
26 | (wrap-fullscreen magit-init)
27 |
28 | ;; move cursor into position when entering commit message
29 | (add-hook 'git-commit-mode-hook 'my/magit-cursor-fix))
30 |
31 | (use-package git-timemachine
32 | :defer t
33 | :bind (("C-x v t" . git-timemachine)))
34 |
35 | (defun b-a-r-k-commit ()
36 | (interactive)
37 | (browse-at-remote-kill)
38 | (message "Remote was killed 💀"))
39 |
40 | (defun b-a-r-k-branch ()
41 | (interactive)
42 | (setq browse-at-remote-prefer-symbolic t)
43 | (browse-at-remote-kill)
44 | (setq browse-at-remote-prefer-symbolic nil)
45 | (message "Remote was killed 🪓🪵"))
46 |
47 | (use-package browse-at-remote
48 | :defer t
49 | :custom
50 | (browse-at-remote-prefer-symbolic nil)
51 | :bind (("C-x v w" . b-a-r-k-commit)
52 | ("C-x v W" . b-a-r-k-branch)))
53 |
54 | (defun kill-magit-buffers ()
55 | (let ((current (current-buffer)))
56 | (dolist (buf (magit-mode-get-buffers))
57 | (unless (eq buf current)
58 | (kill-buffer buf)))))
59 |
60 | (defun magit-quit ()
61 | "Like magit-mode-bury-buffer, but also restores the window
62 | configuration stored by magit-status-fullscreen"
63 | (interactive)
64 | (let ((prev my/previous-window-configuration))
65 | (kill-magit-buffers)
66 | (funcall magit-bury-buffer-function 'kill-buffer)
67 | (when prev (register-val-jump-to prev nil))))
68 |
69 | (defvar magit-pair-programming-partners nil)
70 |
71 | (defun is-commit-message-buffer? ()
72 | (when (buffer-file-name)
73 | (equal (buffer-file-name-body) "COMMIT_EDITMSG")))
74 |
75 | (defun magit-insert-pair-programming-co-authors ()
76 | (dolist (partner magit-pair-programming-partners)
77 | (unless (save-excursion
78 | (goto-char (point-min))
79 | (search-forward (concat "Co-authored-by: " (car partner)) nil t))
80 | (apply #'git-commit-insert-header "Co-authored-by" partner))))
81 |
82 | (defun magit-enable-pair-programming-mode (details)
83 | (add-to-list 'magit-pair-programming-partners details)
84 | (when (is-commit-message-buffer?)
85 | (magit-insert-pair-programming-co-authors))
86 | (add-hook 'git-commit-setup-hook 'magit-insert-pair-programming-co-authors)
87 | (message "Enabled pair programming with %s" (car details)))
88 |
89 | (defun magit-disable-pair-programming-mode ()
90 | (setq magit-pair-programming-partners nil)
91 | (when (is-commit-message-buffer?)
92 | (save-excursion
93 | (goto-char (point-min))
94 | (flush-lines "Co-authored-by")))
95 | (remove-hook 'git-commit-setup-hook 'magit-insert-pair-programming-co-authors)
96 | (message "Disabled pair programming"))
97 |
98 | (defvar my/pair-programming-usual-suspects nil)
99 | (defvar my/pair-programming-myself nil)
100 |
101 | (defun my/remove-same-name (a b)
102 | (let ((names (--map (car (s-slice-at "<" it)) b)))
103 | (-remove (lambda (elem)
104 | (--any (s-starts-with? it elem) names))
105 | a)))
106 |
107 | (defun my/git-commit-read-ident-candidates ()
108 | (let* ((users-from-git-history (my/remove-same-name (delete-dups
109 | (magit-git-lines "log" "-n9999" "--format=%aN <%ae>"))
110 | my/pair-programming-myself))
111 | (usual-suspects-in-history (-intersection users-from-git-history
112 | my/pair-programming-usual-suspects))
113 | (missing-usual-suspects (my/remove-same-name my/pair-programming-usual-suspects
114 | usual-suspects-in-history)))
115 | (delete-dups
116 | (-concat usual-suspects-in-history
117 | missing-usual-suspects
118 | users-from-git-history))))
119 |
120 | (defun my/git-commit-read-ident (prompt)
121 | (let ((str (magit-completing-read
122 | prompt
123 | (my/git-commit-read-ident-candidates)
124 | nil nil nil 'git-commit-read-ident-history)))
125 | (save-match-data
126 | (if (string-match "\\`\\([^<]+\\) *<\\([^>]+\\)>\\'" str)
127 | (list (save-match-data (string-trim (match-string 1 str)))
128 | (string-trim (match-string 2 str)))
129 | (user-error "Invalid input")))))
130 |
131 | (defun magit-toggle-pair-programming-mode ()
132 | (interactive)
133 | (if magit-pair-programming-partners
134 | (magit-disable-pair-programming-mode)
135 | (magit-enable-pair-programming-mode
136 | (my/git-commit-read-ident "Pair programming with"))))
137 |
138 | (defun magit-add-pair-programming-partner ()
139 | (interactive)
140 | (magit-enable-pair-programming-mode
141 | (my/git-commit-read-ident "Pair programming with")))
142 |
143 | (defun my/magit-cursor-fix ()
144 | (beginning-of-buffer)
145 | (when (looking-at "#")
146 | (while (looking-at "#")
147 | (forward-line))
148 | (forward-line)))
149 |
150 | (provide 'setup-magit)
151 |
--------------------------------------------------------------------------------
/packages/setup-cider.el:
--------------------------------------------------------------------------------
1 | ;; CIDER
2 | ;;
3 | ;; Extends Emacs with support for interactive programming in Clojure. The
4 | ;; features are centered around cider-mode, an Emacs minor-mode that complements
5 | ;; clojure-mode. While clojure-mode supports editing Clojure source files,
6 | ;; cider-mode adds support for interacting with a running Clojure process for
7 | ;; compilation, debugging, definition and documentation lookup, running tests
8 | ;; and so on.
9 |
10 | (defun nrepl-warn-when-not-connected ()
11 | (interactive)
12 | (message "Oops! You're not connected to an nREPL server. Please run M-x cider or M-x cider-jack-in to connect."))
13 |
14 | (defun my/shadow-cider-keys-with-warning ()
15 | "Rebind all keys from `cider-mode-map` to `nrepl-warn-when-not-connected` in `clojure-mode-map`."
16 | (interactive)
17 | (map-keymap
18 | (lambda (key def)
19 | ;; Check if 'def' is a command or another keymap.
20 | (cond ((commandp def)
21 | ;; If 'def' is a command, rebind it in `clojure-mode-map`.
22 | (define-key clojure-mode-map (vector key) 'nrepl-warn-when-not-connected))
23 | ((keymapp def)
24 | ;; If 'def' is another keymap, recursively apply the same process.
25 | (map-keymap
26 | (lambda (sub-key sub-def)
27 | (when (commandp sub-def)
28 | (define-key clojure-mode-map (vconcat (vector key) (vector sub-key))
29 | 'nrepl-warn-when-not-connected)))
30 | def))))
31 | cider-mode-map))
32 |
33 | (use-package cider
34 | :after (clojure-mode)
35 | :diminish " CIDER"
36 | :defer t
37 |
38 | :bind ((:map cider-mode-map
39 | ([remap cider-quit] . sesman-quit))
40 | (:map cider-repl-mode-map
41 | ([remap cider-quit] . sesman-quit)))
42 | :config
43 | ;; Warn about missing nREPL instead of doing stupid things
44 | (my/shadow-cider-keys-with-warning)
45 |
46 | ;; Show the port number when figwheel comes online
47 | (add-to-list 'cider--repl-stderr-functions #'my/cider-maybe-log-figwheel-main-port)
48 |
49 | ;; Clear CIDER repl buffer with C-c C-l
50 | (define-key cider-mode-map (kbd "C-c C-l") 'cider-find-and-clear-repl-buffer)
51 | (define-key cider-repl-mode-map (kbd "C-c C-l") 'cider-repl-clear-buffer)
52 | (define-key clojure-mode-map (kbd "C-c C-l") 'nrepl-warn-when-not-connected)
53 |
54 | ;; Keybinding to switch to repl-buffer even if it is the wrong kind
55 | (define-key clojure-mode-map (kbd "C-c z") 'my/cider-select-repl-buffer)
56 | (define-key cider-repl-mode-map (kbd "C-c z") 'my/cider-select-repl-buffer)
57 |
58 | (autoload 'cider-run-in-dev-namespace "cider-run")
59 | (define-key clojure-mode-map (kbd "s-:") 'cider-run-in-dev-namespace)
60 | (define-key cider-repl-mode-map (kbd "s-:") 'cider-run-in-dev-namespace)
61 |
62 | (define-key cider-mode-map (kbd "C-c M-w") 'my/cider-eval-to-clipboard)
63 | (define-key cider-mode-map (kbd "C-c C-M-w") 'my/cider-eval-defun-to-clipboard)
64 |
65 | :custom
66 | ;; save files when evaluating them
67 | (cider-save-file-on-load t)
68 |
69 | ;; try working around a bug where sesman is way too friendly when selecting
70 | ;; repl-s from adjacent projects
71 | ;; https://clojurians.slack.com/archives/C0617A8PQ/p1718608002044069
72 | (sesman-use-friendly-sessions nil)
73 |
74 | ;; don't pop up repl when connecting
75 | (cider-repl-pop-to-buffer-on-connect nil)
76 |
77 | ;; re-use dead buffers without asking me about it when there is only one choice
78 | (cider-reuse-dead-repls 'auto)
79 |
80 | ;; show stacktraces for everything, until https://github.com/clojure-emacs/cider/issues/3495 is solved
81 | (cider-clojure-compilation-error-phases nil)
82 |
83 | ;; always scroll output from interactive evaluations into view
84 | (cider-repl-display-output-before-window-boundaries t))
85 |
86 | (defun my/cider-maybe-log-figwheel-main-port (buffer out)
87 | (when (string-match-p "\\[Figwheel\\] Starting Server at" out)
88 | (message (propertize out 'face 'cider-repl-stderr-face))))
89 |
90 | (defun my/get-sessions-with-same-project-dir (session sessions)
91 | "Returns a list of SESSIONS with the same project-dir as SESSION."
92 | (--filter
93 | (s-equals? (plist-get (cider--gather-session-params session) :project-dir)
94 | (plist-get (cider--gather-session-params it) :project-dir))
95 | sessions))
96 |
97 | (defun my/cider-select-repl-buffer ()
98 | (interactive)
99 | (pop-to-buffer
100 | (let ((buffer-names (-map #'buffer-name
101 | (or (cider--extract-connections (my/get-sessions-with-same-project-dir
102 | (sesman-current-session 'CIDER)
103 | (sesman-current-sessions 'CIDER)))
104 | (user-error "No linked %s sessions" 'CIDER)))))
105 | (if (cdr buffer-names)
106 | (completing-read "Which REPL, Sire?" buffer-names nil t)
107 | (car buffer-names)))))
108 |
109 | (defun cider-find-and-clear-repl-buffer ()
110 | (interactive)
111 | (cider-find-and-clear-repl-output t))
112 |
113 | (defun my/cider-eval-to-clipboard ()
114 | "Evaluate the Clojure form at point and put the result on the clipboard."
115 | (interactive)
116 | (let ((form (cider-last-sexp)))
117 | (cider-nrepl-request:eval
118 | form
119 | (lambda (response)
120 | (when (nrepl-dict-get response "value")
121 | (let ((result (nrepl-dict-get response "value")))
122 | (kill-new result)
123 | (message "Result copied to clipboard: %s" result))))
124 | (cider-current-ns))))
125 |
126 | (defun my/cider-eval-defun-to-clipboard ()
127 | "Evaluate the current top-level form and copy the result to the clipboard."
128 | (interactive)
129 | (cider-nrepl-request:eval
130 | (cider-defun-at-point)
131 | (lambda (response)
132 | (when (nrepl-dict-get response "value")
133 | (let ((result (nrepl-dict-get response "value")))
134 | (kill-new result)
135 | (message "Result copied to clipboard: %s" result))))
136 | (cider-current-ns)))
137 |
138 | (provide 'setup-cider)
139 |
--------------------------------------------------------------------------------
/settings/clj-clean-namespace.el:
--------------------------------------------------------------------------------
1 | ;; Provides basic namespace sorting functionality for clojure
2 |
3 | (require 'dash)
4 | (require 's)
5 |
6 | (defun clj-cn--goto-ns ()
7 | (goto-char (point-min))
8 | (if (re-search-forward clojure-namespace-name-regex nil t)
9 | (clj-cn--goto-toplevel)
10 | (error "No namespace declaration found")))
11 |
12 | (defun clj-cn--search-forward-within-sexp (s &optional save-excursion)
13 | "Searches forward for S in the current sexp.
14 |
15 | if SAVE-EXCURSION is T POINT does not move."
16 | (let ((bound (save-excursion (forward-list 1) (point))))
17 | (if save-excursion
18 | (save-excursion
19 | (re-search-forward (concat s "\\()\\| \\|$\\)") bound t))
20 | (when-let ((result (re-search-forward (concat s "\\()\\| \\|$\\)") bound t)))
21 | (when (or (looking-back " " 1)
22 | (looking-back ")" 1))
23 | (forward-char -1))
24 | result))))
25 |
26 | (defun clj-cn--comment-line? ()
27 | (save-excursion
28 | (back-to-indentation)
29 | (or (looking-at ";")
30 | (looking-at "#_"))))
31 |
32 | (defun clj-cn--delete-and-extract-sexp ()
33 | (let (sexp comment-before comment-after beg end)
34 | ;; start at the beginning
35 | (setq beg (point))
36 |
37 | ;; move forward to the the first non-comment sexp
38 | (clojure-forward-logical-sexp)
39 | (while (clj-cn--comment-line?)
40 | (clojure-forward-logical-sexp))
41 | (clojure-backward-logical-sexp)
42 |
43 | ;; extract any full-line comments before the sexp
44 | (setq comment-before (s-trim (buffer-substring-no-properties beg (point))))
45 |
46 | ;; extract the sexp itself
47 | (let ((here (point)))
48 | (clojure-forward-logical-sexp)
49 | (setq sexp (buffer-substring-no-properties here (point))))
50 |
51 | ;; extract any inline comments after the sexp
52 | (when (looking-at "\s*;")
53 | (let ((here (point)))
54 | (end-of-line)
55 | (setq comment-after (buffer-substring-no-properties here (point)))))
56 |
57 | (let ((contents (buffer-substring beg (point))))
58 | (delete-region beg (point))
59 | (list :sexp sexp
60 | :contents contents
61 | :comment-before (unless (string= "" comment-before)
62 | comment-before)
63 | :comment-after comment-after))))
64 |
65 | (defun clj-cn--end-of-statement? ()
66 | (not
67 | (ignore-errors
68 | (save-excursion (forward-sexp)) t)))
69 |
70 | (defun clj-cn--extract-ns-statements (statement-type)
71 | (clj-cn--goto-ns)
72 | (when (and (clj-cn--search-forward-within-sexp (concat "(" statement-type))
73 | (not (clj-cn--comment-line?)))
74 | (let (statements)
75 | (while (not (clj-cn--end-of-statement?))
76 | (push (clj-cn--delete-and-extract-sexp)
77 | statements))
78 | statements)))
79 |
80 | (defun clj-cn--prepare-insert-in-ns (type)
81 | (clj-cn--goto-ns)
82 | (if (clj-cn--search-forward-within-sexp (concat "(" type))
83 | (if (looking-at " *)")
84 | (progn
85 | (search-backward "(")
86 | (forward-list 1)
87 | (forward-char -1)
88 | (insert " "))
89 | (search-backward "(")
90 | (forward-list 1)
91 | (forward-char -1)
92 | (newline-and-indent))
93 | (forward-list 1)
94 | (forward-char -1)
95 | (newline-and-indent)
96 | (insert "(" type " )")
97 | (forward-char -1)))
98 |
99 | (defun clj-cn--goto-toplevel ()
100 | (paredit-backward-up (cljr--depth-at-point))
101 | (when (looking-back "#")
102 | (backward-char)))
103 |
104 | (defun clj-cn--extract-ns-form ()
105 | (save-excursion
106 | (clj-cn--goto-ns)
107 | (let ((beg (point))
108 | (end (progn (paredit-forward)
109 | (point))))
110 | (buffer-substring-no-properties beg end))))
111 |
112 | (defun clj-cn--comparator (a b)
113 | (string< (plist-get a :sexp)
114 | (plist-get b :sexp)))
115 |
116 | (defun clj-cn--remove-blank-lines (beg end)
117 | (save-excursion
118 | (goto-char beg)
119 | (while (re-search-forward "^\\s-*$" end t)
120 | (delete-char 1)
121 | (setq end (- end 1)))))
122 |
123 | (defun clj-cn--clean-up (statement-type f)
124 | (clj-cn--goto-ns)
125 | (when (and (clj-cn--search-forward-within-sexp (concat "(" statement-type))
126 | (not (clj-cn--comment-line?)))
127 | (paredit-backward-up)
128 | (let ((beg (point))
129 | (end (progn (paredit-forward)
130 | (point))))
131 | (funcall f beg end))))
132 |
133 | (defun clj-cn-sort-ns ()
134 | "Sort the `ns' form."
135 | (interactive)
136 | (let ((buf-already-modified? (buffer-modified-p))
137 | (ns-form-before (clj-cn--extract-ns-form)))
138 | (save-excursion
139 | (dolist (statement-type '(":require" ":use" ":import" ":require-macros"))
140 | (clj-cn--goto-ns)
141 | (when (clj-cn--search-forward-within-sexp (concat "(" statement-type))
142 | (let* ((own-line? (eolp))
143 | (statements (clj-cn--extract-ns-statements statement-type))
144 | (sorted-statement (->> statements
145 | (nreverse)
146 | (-sort 'clj-cn--comparator)
147 | (-distinct))))
148 | (while (not (looking-at ")"))
149 | (delete-char 1))
150 | (dolist (it sorted-statement)
151 | (clj-cn--prepare-insert-in-ns statement-type)
152 | (when own-line?
153 | (delete-char -1)
154 | (insert "\n"))
155 | (insert (s-trim (plist-get it :contents)))
156 | (when (plist-get it :comment-after)
157 | (insert "\n")))
158 | (clj-cn--clean-up statement-type #'clj-cn--remove-blank-lines)
159 | (clj-cn--clean-up statement-type #'indent-region)))))
160 | (when (and (not buf-already-modified?)
161 | (buffer-modified-p)
162 | (s-equals? ns-form-before
163 | (clj-cn--extract-ns-form)))
164 | (not-modified))))
165 |
166 | (provide 'clj-clean-namespace)
167 |
--------------------------------------------------------------------------------
/settings/multifiles.el:
--------------------------------------------------------------------------------
1 | ;;; multifiles.el --- View and edit parts of multiple files in one buffer
2 |
3 | ;; Copyright (C) 2011 Magnar Sveen
4 |
5 | ;; Author: Magnar Sveen
6 | ;; Keywords: multiple files
7 |
8 | ;; This program is free software; you can redistribute it and/or modify
9 | ;; it under the terms of the GNU General Public License as published by
10 | ;; the Free Software Foundation, either version 3 of the License, or
11 | ;; (at your option) any later version.
12 |
13 | ;; This program is distributed in the hope that it will be useful,
14 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | ;; GNU General Public License for more details.
17 |
18 | ;; You should have received a copy of the GNU General Public License
19 | ;; along with this program. If not, see .
20 |
21 | ;;; Commentary:
22 |
23 | ;; Bind a key to `mf/mirror-region-in-multifile`, let's say `C-!`. Now
24 | ;; mark a part of the buffer and press it. A new \*multifile\* buffer pops
25 | ;; up. Mark some other part of another file, and press `C-!` again. This
26 | ;; is added to the \*multifile\*.
27 |
28 | ;; You can now edit the \*multifile\* buffer, and watch the original files change.
29 | ;; Or you can edit the original files and watch the \*multifile\* buffer change.
30 |
31 | ;; **Warning** This API and functionality is highly volatile.
32 |
33 | ;;; Code:
34 |
35 | (require 'dash)
36 |
37 | (defun mf/mirror-region-in-multifile (beg end &optional multifile-buffer)
38 | (interactive (list (region-beginning) (region-end)
39 | (when current-prefix-arg
40 | (read-buffer "Mirror into buffer: " "*multifile*"))))
41 | (deactivate-mark)
42 | (let ((buffer (current-buffer))
43 | (mode major-mode))
44 | (switch-to-buffer-other-window (or multifile-buffer "*multifile*"))
45 | (funcall mode)
46 | (multifiles-minor-mode 1)
47 | (mf--add-mirror buffer beg end)
48 | (switch-to-buffer-other-window buffer)))
49 |
50 | (defvar multifiles-minor-mode-map nil
51 | "Keymap for multifiles minor mode.")
52 |
53 | (unless multifiles-minor-mode-map
54 | (setq multifiles-minor-mode-map (make-sparse-keymap)))
55 |
56 | (define-key multifiles-minor-mode-map (vector 'remap 'save-buffer) 'mf/save-original-buffers)
57 |
58 | (defun mf/save-original-buffers ()
59 | (interactive)
60 | (--each (mf--original-buffers)
61 | (with-current-buffer it
62 | (when buffer-file-name
63 | (save-buffer)))))
64 |
65 | (defun mf--original-buffers ()
66 | (->> (overlays-in (point-min) (point-max))
67 | (--filter (equal 'mf-mirror (overlay-get it 'type)))
68 | (--map (overlay-buffer (overlay-get it 'twin)))
69 | (-distinct)))
70 |
71 | (define-minor-mode multifiles-minor-mode
72 | "A minor mode for the *multifile* buffer."
73 | :lighter ""
74 | :keymap multifiles-minor-mode-map)
75 |
76 | (defun mf--add-mirror (buffer beg end)
77 | (let (contents original-overlay mirror-overlay)
78 | (mf--add-hook-if-necessary)
79 | (with-current-buffer buffer
80 | (mf--add-hook-if-necessary)
81 | (setq contents (buffer-substring beg end))
82 | (setq original-overlay (create-original-overlay beg end)))
83 | (mf---insert-contents)
84 | (setq mirror-overlay (create-mirror-overlay beg end))
85 | (overlay-put mirror-overlay 'twin original-overlay)
86 | (overlay-put original-overlay 'twin mirror-overlay)))
87 |
88 | (defun mf---insert-contents ()
89 | (end-of-buffer)
90 | (newline)
91 | (setq beg (point))
92 | (insert contents)
93 | (setq end (point))
94 | (newline 2))
95 |
96 | (defun mf--any-overlays-in-buffer ()
97 | (--any? (memq (overlay-get it 'type) '(mf-original mf-mirror))
98 | (overlays-in (point-min) (point-max))))
99 |
100 | (defun mf--add-hook-if-necessary ()
101 | (unless (mf--any-overlays-in-buffer)
102 | (add-hook 'post-command-hook 'mf--update-twins)))
103 |
104 | (defun mf--remove-hook-if-necessary ()
105 | (unless (mf--any-overlays-in-buffer)
106 | (remove-hook 'post-command-hook 'mf--update-twins)))
107 |
108 | (defun create-original-overlay (beg end)
109 | (let ((o (make-overlay beg end nil nil t)))
110 | (overlay-put o 'type 'mf-original)
111 | (overlay-put o 'modification-hooks '(mf--on-modification))
112 | (overlay-put o 'insert-in-front-hooks '(mf--on-modification))
113 | (overlay-put o 'insert-behind-hooks '(mf--on-modification))
114 | o))
115 |
116 | (defun create-mirror-overlay (beg end)
117 | (let ((o (make-overlay beg end nil nil t)))
118 | (overlay-put o 'type 'mf-mirror)
119 | (overlay-put o 'line-prefix mf--mirror-indicator)
120 | (overlay-put o 'modification-hooks '(mf--on-modification))
121 | (overlay-put o 'insert-in-front-hooks '(mf--on-modification))
122 | (overlay-put o 'insert-behind-hooks '(mf--on-modification))
123 | o))
124 |
125 | (defvar mf--changed-overlays nil)
126 | (make-variable-buffer-local 'mf--changed-overlays)
127 |
128 | (defun mf--on-modification (o after? beg end &optional delete-length)
129 | (when (not after?)
130 | (when (mf---removed-entire-overlay o)
131 | (mf--remove-mirror o)))
132 |
133 | (when (and after? (not (null (overlay-start o))))
134 | (add-to-list 'mf--changed-overlays o)))
135 |
136 | (defun mf---removed-entire-overlay (o)
137 | (and (<= beg (overlay-start o))
138 | (>= end (overlay-end o))))
139 |
140 | (defun mf--update-twins ()
141 | (when mf--changed-overlays
142 | (-each mf--changed-overlays 'mf--update-twin)
143 | (setq mf--changed-overlays nil)))
144 |
145 | (defun mf--remove-mirror (o)
146 | (let* ((twin (overlay-get o 'twin))
147 | (original (if (mf--is-original o) o twin))
148 | (mirror (if (mf--is-original o) twin o))
149 | (mirror-beg (overlay-start mirror))
150 | (mirror-end (overlay-end mirror)))
151 | (with-current-buffer (overlay-buffer mirror)
152 | (save-excursion
153 | (delete-overlay mirror)
154 | (delete-region mirror-beg mirror-end)
155 | (goto-char mirror-beg)
156 | (delete-blank-lines)
157 | (mf--remove-hook-if-necessary)))
158 | (with-current-buffer (overlay-buffer original)
159 | (delete-overlay original)
160 | (mf--remove-hook-if-necessary))))
161 |
162 | (defun mf--is-original (o)
163 | (equal 'mf-original (overlay-get o 'type)))
164 |
165 | (defun mf--update-twin (o)
166 | (let* ((beg (overlay-start o))
167 | (end (overlay-end o))
168 | (contents (buffer-substring beg end))
169 | (twin (overlay-get o 'twin))
170 | (buffer (overlay-buffer twin))
171 | (beg (overlay-start twin))
172 | (end (overlay-end twin)))
173 | (with-current-buffer buffer
174 | (save-excursion
175 | (goto-char beg)
176 | (insert contents)
177 | (delete-char (- end beg))
178 | ))))
179 |
180 | (defvar mf--mirror-indicator "| ")
181 | (add-text-properties
182 | 0 1
183 | `(face (:foreground ,(format "#%02x%02x%02x" 128 128 128)
184 | :background ,(format "#%02x%02x%02x" 128 128 128)))
185 | mf--mirror-indicator)
186 |
187 | (provide 'multifiles)
188 |
189 | ;;; multifiles.el ends here
190 |
--------------------------------------------------------------------------------
/settings/editing.el:
--------------------------------------------------------------------------------
1 | ;; Manipulating the contents of a buffer
2 |
3 | ;; Killing words backwards
4 | (global-set-key (kbd "C-w") 'kill-region-or-backward-word)
5 | (global-set-key (kbd "M-h") 'kill-region-or-backward-word) ;; matches C-h
6 |
7 | ;; Duplicate region
8 | (global-set-key (kbd "C-c d") 'duplicate-current-line-or-region)
9 |
10 | ;; Increase and decrease number at point
11 | (global-set-key (kbd "C-+") 'inc-number-at-point)
12 | (global-set-key (kbd "C-?") 'dec-number-at-point)
13 |
14 | ;; Clean up whitespace
15 | (global-set-key (kbd "C-c n") 'cleanup-buffer)
16 |
17 | ;; Copy to end of current line if no region
18 | (global-set-key (kbd "M-w") 'copy-region-or-current-line)
19 |
20 | ;; Completion at point
21 | (global-set-key (kbd "C-,") 'completion-at-point)
22 |
23 | ;; Use shell-like backspace C-h, rebind help to F1
24 | (define-key key-translation-map [?\C-h] [?\C-?])
25 | (global-set-key (kbd "") 'help-command)
26 |
27 | ;; Revert entire buffer without any fuss
28 | (global-set-key (kbd "M-") (λ (revert-buffer t t)))
29 |
30 | ;; Join lines with ease
31 | (global-set-key (kbd "M-j") (λ (join-line -1)))
32 |
33 | ;; Query replace regex key binding
34 | (global-set-key (kbd "M-&") 'query-replace-regexp)
35 |
36 | ;; Delete blank lines
37 | (global-set-key (kbd "C-c C-") 'delete-blank-lines)
38 |
39 | ;; Eval emacs-lisp expressions anywhere.
40 | (global-set-key (kbd "C-c C-e") 'eval-and-replace)
41 | (global-set-key (kbd "M-s-e") 'eval-and-replace)
42 |
43 | ;; Clever newlines
44 | (global-set-key (kbd "C-o") 'open-line-and-indent)
45 | (global-set-key (kbd "") 'open-line-below)
46 | (global-set-key (kbd "") 'open-line-above)
47 | (global-set-key (kbd "") 'new-line-dwim)
48 |
49 | ;; Move whole lines
50 | (global-set-key (kbd "") 'move-text-down)
51 | (global-set-key (kbd "") 'move-text-up)
52 |
53 | ;; Sorting lines alphabetically
54 | (global-set-key (kbd "M-s l") 'sort-lines)
55 |
56 | ;; Display and edit occurances of regexp in buffer
57 | (global-set-key (kbd "C-c o") 'occur)
58 |
59 | ;;;; Implementations
60 |
61 | (use-package move-text)
62 |
63 | (defun duplicate-region (&optional num start end)
64 | "Duplicates the region bounded by START and END NUM times.
65 | If no START and END is provided, the current region-beginning and
66 | region-end is used."
67 | (interactive "p")
68 | (save-excursion
69 | (let* ((start (or start (region-beginning)))
70 | (end (or end (region-end)))
71 | (region (buffer-substring start end)))
72 | (goto-char end)
73 | (dotimes (i num)
74 | (insert region)))))
75 |
76 | (defun paredit-duplicate-current-line ()
77 | (back-to-indentation)
78 | (let (kill-ring kill-ring-yank-pointer)
79 | (paredit-kill)
80 | (yank)
81 | (newline-and-indent)
82 | (yank)))
83 |
84 | (defun duplicate-current-line (&optional num)
85 | "Duplicate the current line NUM times."
86 | (interactive "p")
87 | (if (bound-and-true-p paredit-mode)
88 | (paredit-duplicate-current-line)
89 | (save-excursion
90 | (when (eq (point-at-eol) (point-max))
91 | (goto-char (point-max))
92 | (newline)
93 | (forward-char -1))
94 | (duplicate-region num (point-at-bol) (1+ (point-at-eol))))))
95 |
96 | (defun duplicate-current-line-or-region (arg)
97 | "Duplicates the current line or region ARG times.
98 | If there's no region, the current line will be duplicated."
99 | (interactive "p")
100 | (if (region-active-p)
101 | (let ((beg (region-beginning))
102 | (end (region-end)))
103 | (duplicate-region arg beg end)
104 | (one-shot-keybinding "d" (λ (duplicate-region 1 beg end))))
105 | (duplicate-current-line arg)
106 | (one-shot-keybinding "d" 'duplicate-current-line)))
107 |
108 | (defun incs (s &optional num)
109 | (let* ((inc (or num 1))
110 | (new-number (number-to-string (+ inc (string-to-number s))))
111 | (zero-padded? (s-starts-with? "0" s)))
112 | (if zero-padded?
113 | (s-pad-left (length s) "0" new-number)
114 | new-number)))
115 |
116 | (defun goto-closest-number ()
117 | (interactive)
118 | (let ((closest-behind (save-excursion (search-backward-regexp "[0-9]" nil t)))
119 | (closest-ahead (save-excursion (search-forward-regexp "[0-9]" nil t))))
120 | (push-mark)
121 | (goto-char
122 | (cond
123 | ((and (not closest-ahead) (not closest-behind)) (error "No numbers in buffer"))
124 | ((and closest-ahead (not closest-behind)) closest-ahead)
125 | ((and closest-behind (not closest-ahead)) closest-behind)
126 | ((> (- closest-ahead (point)) (- (point) closest-behind)) closest-behind)
127 | ((> (- (point) closest-behind) (- closest-ahead (point))) closest-ahead)
128 | :else closest-ahead))))
129 |
130 | (defun inc-number-at-point (arg)
131 | (interactive "p")
132 | (unless (or (looking-at "[0-9]")
133 | (looking-back "[0-9]"))
134 | (goto-closest-number))
135 | (save-excursion
136 | (while (looking-back "[0-9]")
137 | (forward-char -1))
138 | (re-search-forward "[0-9]+" nil)
139 | (replace-match (incs (match-string 0) arg) nil nil)))
140 |
141 | (defun dec-number-at-point (arg)
142 | (interactive "p")
143 | (inc-number-at-point (- arg)))
144 |
145 | (defun cleanup-buffer ()
146 | "Perform a bunch of operations on the whitespace content of a buffer.
147 | Including indent-buffer, which should not be called automatically on save."
148 | (interactive)
149 | (untabify (point-min) (point-max))
150 | (delete-trailing-whitespace)
151 | (indent-region (point-min) (point-max)))
152 |
153 | (defun kill-region-or-backward-word ()
154 | (interactive)
155 | (if (region-active-p)
156 | (kill-region (region-beginning) (region-end))
157 | (backward-kill-word 1)))
158 |
159 | (defun copy-to-end-of-line ()
160 | (interactive)
161 | (kill-ring-save (point)
162 | (line-end-position))
163 | (message "Copied to end of line"))
164 |
165 | (defun copy-region-or-current-line ()
166 | (interactive)
167 | (if (region-active-p)
168 | (kill-ring-save (region-beginning) (region-end))
169 | (copy-to-end-of-line)))
170 |
171 | (defun eval-and-replace ()
172 | "Replace the preceding sexp with its value."
173 | (interactive)
174 | (backward-kill-sexp)
175 | (condition-case nil
176 | (prin1 (eval (read (current-kill 0)))
177 | (current-buffer))
178 | (error (message "Invalid expression")
179 | (insert (current-kill 0)))))
180 |
181 | (defun open-line-and-indent ()
182 | (interactive)
183 | (newline-and-indent)
184 | (end-of-line 0)
185 | (indent-for-tab-command))
186 |
187 | (defun open-line-below ()
188 | (interactive)
189 | (end-of-line)
190 | (newline)
191 | (indent-for-tab-command))
192 |
193 | (defun open-line-above ()
194 | (interactive)
195 | (beginning-of-line)
196 | (newline)
197 | (forward-line -1)
198 | (indent-for-tab-command))
199 |
200 | (defun new-line-dwim ()
201 | (interactive)
202 | (let ((break-open-pair (or (and (looking-back "{" 1) (looking-at "}"))
203 | (and (looking-back ">" 1) (looking-at "<"))
204 | (and (looking-back "(" 1) (looking-at ")"))
205 | (and (looking-back "\\[" 1) (looking-at "\\]")))))
206 | (newline)
207 | (when break-open-pair
208 | (save-excursion
209 | (newline)
210 | (indent-for-tab-command)))
211 | (indent-for-tab-command)))
212 |
213 | (provide 'editing)
214 |
--------------------------------------------------------------------------------
/settings/matnyttig.el:
--------------------------------------------------------------------------------
1 | (require 'parseedn)
2 |
3 | ;; The following code is a starting point for integrating Emacs with
4 | ;; "matnyttig", our Clojure code base.
5 | ;;
6 | ;; At first, I tried cider-interactive-eval. Then, I was sad.
7 | ;; cider-interactive-eval doesn't block, and doesn't provide an easy-to-use
8 | ;; mechanism to return control to the function that called it. For example, you
9 | ;; may get multiple responses if you're running multiple REPLs.
10 | ;;
11 | ;; The next thing I want to try is to shell out to Babashka.
12 | ;; shell-command-to-string just returns the script's stdout, so it's perfect for
13 | ;; our use.
14 |
15 | (defun matnyttig-add-page ()
16 | (interactive)
17 | (let* ((page-id (read-string "page-id: ")))
18 | (cider-interactive-eval (concat "(do"
19 | " (require 'matnyttig.page-admin)"
20 | " (matnyttig.page-admin/add \"" page-id "\")"
21 | ")"))))
22 |
23 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
24 | ;; Renaming a page requires listing existing pages! This is hard with CIDER, but
25 | ;; maybe easy with Babashka. My CIDER-based starting point follows.
26 | ;;
27 | ;; (defun matnyttig-list-pages ()
28 | ;; ;; (interactive)
29 | ;; (let* ((pages-edn-str (cider-interactive-eval
30 | ;; (concat "(do"
31 | ;; " (require 'matnyttig.feed-admin)"
32 | ;; " (matnyttig.feed-admin/list-pages)"
33 | ;; ")"))))
34 | ;; (parseedn-read-str pages-edn-str)))
35 |
36 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
37 | ;; Helper code to develop interactive Emacs functions with a primitive UI.
38 | ;;
39 | ;; (defun demo-callback (something)
40 | ;; (message something))
41 | ;;
42 | ;; (defun demo ()
43 | ;; ;; (interactive)
44 | ;; (let* ((edn-str (cider-interactive-eval "(map (partial * 10) '(1 2 3))"
45 | ;; 'demo-callback))
46 | ;; (elisp-values (parseedn-read-str edn-str)))
47 | ;; elisp-values))
48 | ;; ;; then M-x demo from a buffer with a running REPL.
49 |
50 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
51 | ;; Evaluate and print with e->map
52 |
53 | (defun matnyttig-wrap-e->map (form)
54 | (format "((or (requiring-resolve 'clojure.core/e->map) identity) %s)" form))
55 |
56 | (defun matnyttig-cider-pprint-eval-last-sexp-with-e->map (prefixed)
57 | (interactive "P")
58 | (if prefixed
59 | (cider--pprint-eval-form (cider-last-sexp))
60 | (cider--pprint-eval-form
61 | (matnyttig-wrap-e->map (cider-last-sexp)))))
62 |
63 | (defun matnyttig-cider-pprint-eval-defun-at-point-with-e->map (prefixed)
64 | (interactive "P")
65 | (if prefixed
66 | (cider--pprint-eval-form (cider-defun-at-point))
67 | (cider--pprint-eval-form
68 | (matnyttig-wrap-e->map (cider-defun-at-point)))))
69 |
70 | (define-key cider-mode-map (kbd "C-c C-p") #'matnyttig-cider-pprint-eval-last-sexp-with-e->map)
71 | (define-key cider-mode-map (kbd "C-c C-f") #'matnyttig-cider-pprint-eval-defun-at-point-with-e->map)
72 |
73 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
74 | ;; Find first class definitions (like feeds, etc.)
75 |
76 | ;; Patterns
77 | (defun matnyttig-collector-pattern (thing)
78 | (format "(source-definition/define-collector\n {:id %s" thing))
79 |
80 | (defun matnyttig-refiner-pattern (thing)
81 | (format "(source-definition/define-refiner\n {:id %s" thing))
82 |
83 | (defun matnyttig-feed-pattern (thing)
84 | (format "(source-definition/define-feed\n {:id %s" thing))
85 |
86 | (defun matnyttig-page-pattern (thing)
87 | (format "(page-definition/define\n {:id %s" thing))
88 |
89 | ;; Files
90 | (defun matnyttig-src-files ()
91 | (directory-files-recursively
92 | (file-name-concat (projectile-project-root) "src")
93 | "\\.clj[sc]?$"))
94 |
95 | (defun matnyttig-collector-files (files)
96 | (--filter (string-match-p "/collectors/" it) files))
97 |
98 | (defun matnyttig-refiner-files (files)
99 | (--filter (string-match-p "/refiners/" it) files))
100 |
101 | (defun matnyttig-feed-files (files)
102 | (--filter (string-match-p "/feeds/" it) files))
103 |
104 | (defun matnyttig-page-files (files)
105 | (--filter (string-match-p "/sider/" it) files))
106 |
107 | ;; Effects
108 | (defun matnyttig-find-effect-definition (thing)
109 | (interactive)
110 | (let ((effects-file (file-name-concat (projectile-project-root) "src/matnyttig/imperative_shell/effects.clj"))
111 | (result nil))
112 | (when (file-exists-p effects-file)
113 | (with-temp-buffer
114 | (insert-file-contents effects-file)
115 | (goto-char (point-min))
116 | (when (search-forward "(case (:effect/kind effect)" nil t)
117 | (when (search-forward thing nil t)
118 | (paredit-forward-down)
119 | (when (re-search-backward
120 | (format "(defn \\(\\^{:indent 1} \\)?%s"
121 | (thing-at-point 'symbol t)))
122 | (setq result (cons effects-file (line-number-at-pos)))))))
123 | result)))
124 |
125 | ;; Logic
126 | (defun matnyttig-search-first-class-definition (files pattern)
127 | (let ((result nil))
128 | (catch 'found
129 | (dolist (file files)
130 | (with-temp-buffer
131 | (insert-file-contents file)
132 | (goto-char (point-min))
133 | (when (search-forward pattern nil t)
134 | (setq result (cons file (line-number-at-pos)))
135 | (throw 'found t)))))
136 | result))
137 |
138 | (defun matnyttig-goto-first-class-definition (floc)
139 | (xref-push-marker-stack)
140 | (find-file (car floc))
141 | (goto-line (cdr floc))
142 | (goto-char (point-at-eol)))
143 |
144 | (defun matnyttig-find-first-class-definition ()
145 | (interactive)
146 | (let ((thing (thing-at-point 'symbol t))
147 | (matnyttig-src-files (matnyttig-src-files))
148 | (floc nil))
149 | (cond
150 | ((string-prefix-p ":feed/" thing)
151 | (setq floc (matnyttig-search-first-class-definition
152 | (matnyttig-feed-files matnyttig-src-files)
153 | (matnyttig-feed-pattern thing))))
154 |
155 | ((string-prefix-p ":pages/" thing)
156 | (setq floc (matnyttig-search-first-class-definition
157 | (matnyttig-page-files matnyttig-src-files)
158 | (matnyttig-page-pattern thing))))
159 |
160 | ((string-prefix-p ":data/" thing)
161 | (when-let ((result (matnyttig-search-first-class-definition
162 | (matnyttig-collector-files matnyttig-src-files)
163 | (matnyttig-collector-pattern thing))))
164 | (setq floc result))
165 | (when-let ((result (matnyttig-search-first-class-definition
166 | (matnyttig-refiner-files matnyttig-src-files)
167 | (matnyttig-refiner-pattern thing))))
168 | (setq floc result)))
169 |
170 | ((string-prefix-p ":effects." thing)
171 | (setq floc (matnyttig-find-effect-definition thing))))
172 | (if floc
173 | (matnyttig-goto-first-class-definition floc)
174 | (xref-find-definitions thing))))
175 |
176 | (define-key clojure-mode-map (kbd "M-.") 'matnyttig-find-first-class-definition)
177 |
178 | ;; Ignore annoyingly abundant files that hang Emacs on Vertico analyses
179 | (with-eval-after-load 'lsp-mode
180 | (add-to-list 'lsp-file-watch-ignored-directories "[/\\\\].nats-cache\\'"))
181 |
182 | (provide 'matnyttig)
183 |
--------------------------------------------------------------------------------
/packages/setup-clojure-mode.el:
--------------------------------------------------------------------------------
1 | (use-package clojure-mode
2 | :hook ((clojure-mode . setup-clojure-mode-so)
3 | (clojurescript-mode-hook . setup-clojure-mode-so)
4 | (clojurec-mode-hook . setup-clojure-mode-so))
5 |
6 | :custom
7 | (clojure-toplevel-inside-comment-form t)
8 |
9 | :config
10 | ;; don't steal hippie-expand-lines keybinding
11 | (unbind-key (kbd "C-:") clojure-mode-map)
12 |
13 | (require 'i18n-edn)
14 |
15 | ;; After threading all forms, check if we should maybe unwind once
16 | ;; according to my tastes
17 | (defadvice clojure--thread-all (after possibly-unwind-once activate)
18 | (when (my/clojure-should-unwind-once?)
19 | (clojure-unwind)))
20 |
21 | :bind (:map clojure-mode-map
22 | ([remap paredit-forward] . clojure-forward-logical-sexp)
23 | ([remap paredit-backward] . clojure-backward-logical-sexp)
24 | ("C-\"" . clojure-toggle-keyword-string)
25 | ("C-x M-e" . my/cider-eval-including-lets)
26 | ("C-c C-M-s" . my/cider-eval-def-symbol)
27 | ("C-." . clj-hippie-expand-no-case-fold)
28 | ("C-c i 1 8 n" . i18n-edn-edit-in-multifile)
29 | ("" . cider-eval-last-sexp)
30 | ("" . cider-pprint-eval-last-sexp)
31 | ("" . delete-other-windows)
32 | ("s-" . clerk-show)))
33 |
34 | (use-package zprint-mode
35 | :defer 2)
36 |
37 | ;; Set up jumping to other file (src/test, component/scene)
38 |
39 | (require 's)
40 | (require 'significant-other)
41 |
42 | (defun setup-clojure-mode-so ()
43 | (with-significant-others file-name
44 | ("/portfolio/.+/components/" (list (s-with file-name
45 | (s-replace "/portfolio/" "/src/")
46 | (s-replace "_scenes.cljs" ".cljc"))))
47 |
48 | ("/ui/src/.+/components/" (list (s-with file-name
49 | (s-replace "/src/" "/portfolio/")
50 | (s-replace ".cljc" "_scenes.cljs"))
51 | (s-with file-name
52 | (s-replace "/src/" "/test/")
53 | (s-replace ".cljc" "_test.clj"))))
54 |
55 | ("/src/.+\.cljc" (list (s-with file-name
56 | (s-replace "/src/" "/test/")
57 | (s-replace ".cljc" "_test.clj"))
58 | (s-with file-name
59 | (s-replace "/src/" "/test/")
60 | (s-replace ".cljc" "_test.cljc"))))
61 |
62 | ("/src/.+\.clj" (list (s-with file-name
63 | (s-replace "/src/" "/test/")
64 | (s-replace ".clj" "_test.clj"))))
65 |
66 | ("/dev/.+\.clj" (list (s-with file-name
67 | (s-replace "/dev/" "/test/")
68 | (s-replace ".clj" "_test.clj"))))
69 |
70 | ("/test/.+\.clj" (list
71 | (s-with file-name
72 | (s-replace "/test/" "/src/")
73 | (s-replace "_test.clj" ".clj"))
74 | (s-with file-name
75 | (s-replace "/test/" "/src/")
76 | (s-replace "_test.clj" ".cljc"))
77 | (s-with file-name
78 | (s-replace "/test/" "/dev/")
79 | (s-replace "_test.clj" ".clj"))))))
80 |
81 | ;; Set up Clojure CSS completions
82 |
83 | (use-package css-completions
84 | :after (cider projectile)
85 | :ensure nil
86 | :defer t
87 | :commands (cssc/enable-for-clojure)
88 | :init
89 | (add-hook 'clojure-mode-hook 'cssc/enable-for-clojure)
90 | (add-hook 'clojurescript-mode-hook 'cssc/enable-for-clojure)
91 | (add-hook 'clojurec-mode-hook 'cssc/enable-for-clojure)
92 | (add-hook 'mhtml-mode-hook 'cssc/enable-for-html))
93 |
94 | ;; Don't fully unthread always
95 |
96 | (defun my/clojure-should-unwind-once? ()
97 | (save-excursion
98 | (ignore-errors
99 | (when (looking-at "(")
100 | (forward-char 1)
101 | (forward-sexp 1)))
102 | (let ((forms nil))
103 | (while (not (looking-at ")"))
104 | (clojure-forward-logical-sexp)
105 | (clojure-backward-logical-sexp)
106 | (setq forms (cons (buffer-substring-no-properties (point) (+ 1 (point))) forms))
107 | (clojure-forward-logical-sexp))
108 | (and (--any? (s-equals? it "(") forms)
109 | (< 2 (length forms))))))
110 |
111 | ;; eval-current-sexp while also including surrounding lets
112 |
113 | (defun my/cider-looking-at-lets? ()
114 | (or (looking-at "(let ")
115 | (looking-at "(letfn ")
116 | (looking-at "(when-let ")
117 | (looking-at "(if-let ")))
118 |
119 | (defun my/cider-collect-lets (&optional max-point)
120 | (let* ((beg-of-defun (save-excursion (beginning-of-defun) (point)))
121 | (lets nil))
122 | (save-excursion
123 | (while (not (= (point) beg-of-defun))
124 | (paredit-backward-up 1)
125 | (when (my/cider-looking-at-lets?)
126 | (save-excursion
127 | (let ((beg (point)))
128 | (paredit-forward-down 1)
129 | (paredit-forward 2)
130 | (when (and max-point (< max-point (point)))
131 | (goto-char max-point))
132 | (setq lets (cons (concat (buffer-substring-no-properties beg (point))
133 | (if max-point "]" ""))
134 | lets))))))
135 | lets)))
136 |
137 | (defun my/inside-let-block? ()
138 | (save-excursion
139 | (paredit-backward-up 2)
140 | (my/cider-looking-at-lets?)))
141 |
142 | (defun my/cider-eval-including-lets (&optional output-to-current-buffer)
143 | "Evaluates the current sexp form, wrapped in all parent lets."
144 | (interactive "P")
145 | (let* ((beg-of-sexp (save-excursion (paredit-backward 1) (point)))
146 | (code (buffer-substring-no-properties beg-of-sexp (point)))
147 | (lets (my/cider-collect-lets (when (my/inside-let-block?)
148 | (save-excursion (paredit-backward 2) (point)))))
149 | (code (concat (s-join " " lets)
150 | " " code
151 | (s-repeat (length lets) ")"))))
152 | (cider-interactive-eval code
153 | (when output-to-current-buffer
154 | (cider-eval-print-handler))
155 | nil
156 | (cider--nrepl-pr-request-map))))
157 |
158 | (defun my/cider-eval-def-symbol ()
159 | "Evaluate and pretty-print the value of the symbol of the def at point."
160 | (interactive)
161 | (save-excursion
162 | (beginning-of-defun)
163 | (paredit-forward-down)
164 | (when (looking-at "def\\(\\w*\\)")
165 | (paredit-forward 2)
166 | (cider-pprint-eval-last-sexp))))
167 |
168 | (defun clj-hippie-expand-no-case-fold ()
169 | "Consider / as whitespace when doing hippie-expand i clojure-mode"
170 | (interactive)
171 | (let ((old-syntax (char-to-string (char-syntax ?/))))
172 | (modify-syntax-entry ?/ " ")
173 | (hippie-expand-no-case-fold)
174 | (modify-syntax-entry ?/ old-syntax)))
175 |
176 | (defun clerk-show ()
177 | (interactive)
178 | (when-let
179 | ((filename
180 | (buffer-file-name)))
181 | (save-buffer)
182 | (cider-interactive-eval
183 | (concat "(nextjournal.clerk/show! \"" filename "\")"))))
184 |
185 | (defun my/cider-unload-current-namespace-aliases ()
186 | ;; A clojure.tools.namespace.refresh can leave namespaces with aliases that
187 | ;; point to nothingness! Those namespaces pointing to nothingness prevent the
188 | ;; (ns ,,,) form from evaluating. A workaround is to unload the aliases for
189 | ;; your currently open namespace.
190 | (interactive)
191 | (cider-interactive-eval "(doseq [a (keys (ns-aliases *ns*))] (ns-unalias (symbol (str *ns*)) a))"))
192 |
193 | (use-package neil :defer t) ;; M-x neil-find-clojure-package
194 |
195 | (provide 'setup-clojure-mode)
196 |
--------------------------------------------------------------------------------
/packages/setup-hippie.el:
--------------------------------------------------------------------------------
1 | (require 'hippie-exp)
2 |
3 | (defvar he-search-loc-backward (make-marker))
4 | (defvar he-search-loc-forward (make-marker))
5 |
6 | (defun he--closest-in-this-buffer (old beg-function search-function)
7 | (let (expansion)
8 | (unless old
9 | (he-init-string (funcall beg-function) (point))
10 | (set-marker he-search-loc-backward he-string-beg)
11 | (set-marker he-search-loc-forward he-string-end))
12 |
13 | (if (not (equal he-search-string ""))
14 | (save-excursion
15 | (save-restriction
16 | (if hippie-expand-no-restriction
17 | (widen))
18 |
19 | (let (forward-point
20 | backward-point
21 | forward-distance
22 | backward-distance
23 | forward-expansion
24 | backward-expansion
25 | chosen)
26 |
27 | ;; search backward
28 | (goto-char he-search-loc-backward)
29 | (setq expansion (funcall search-function he-search-string t))
30 |
31 | (when expansion
32 | (setq backward-expansion expansion)
33 | (setq backward-point (point))
34 | (setq backward-distance (- he-string-beg backward-point)))
35 |
36 | ;; search forward
37 | (goto-char he-search-loc-forward)
38 | (setq expansion (funcall search-function he-search-string))
39 |
40 | (when expansion
41 | (setq forward-expansion expansion)
42 | (setq forward-point (point))
43 | (setq forward-distance (- forward-point he-string-beg)))
44 |
45 | ;; choose depending on distance
46 | (setq chosen (cond
47 | ((and forward-point backward-point)
48 | (if (< forward-distance backward-distance) :forward :backward))
49 |
50 | (forward-point :forward)
51 | (backward-point :backward)))
52 |
53 | (when (equal chosen :forward)
54 | (setq expansion forward-expansion)
55 | (set-marker he-search-loc-forward forward-point))
56 |
57 | (when (equal chosen :backward)
58 | (setq expansion backward-expansion)
59 | (set-marker he-search-loc-backward backward-point))
60 |
61 | ))))
62 |
63 | (if (not expansion)
64 | (progn
65 | (if old (he-reset-string))
66 | nil)
67 | (progn
68 | (he-substitute-string expansion t)
69 | t))))
70 |
71 | (defun try-expand-dabbrev-closest-first (old)
72 | "Try to expand word \"dynamically\", searching the current buffer.
73 | The argument OLD has to be nil the first call of this function, and t
74 | for subsequent calls (for further possible expansions of the same
75 | string). It returns t if a new expansion is found, nil otherwise."
76 | (he--closest-in-this-buffer old #'he-dabbrev-beg #'he-dabbrev-search))
77 |
78 | (defun try-expand-line-closest-first (old)
79 | "Try to complete the current line to an entire line in the buffer.
80 | The argument OLD has to be nil the first call of this function, and t
81 | for subsequent calls (for further possible completions of the same
82 | string). It returns t if a new completion is found, nil otherwise."
83 | (let ((expansion ())
84 | (strip-prompt (and (get-buffer-process (current-buffer))
85 | comint-use-prompt-regexp
86 | comint-prompt-regexp)))
87 | (unless old
88 | (he-init-string (he-line-beg strip-prompt) (point))
89 | (set-marker he-search-loc-backward he-string-beg)
90 | (set-marker he-search-loc-forward he-string-end))
91 |
92 | (unless (equal he-search-string "")
93 | (save-excursion
94 | (save-restriction
95 | (when hippie-expand-no-restriction
96 | (widen))
97 |
98 | (let (forward-point
99 | backward-point
100 | forward-distance
101 | backward-distance
102 | forward-expansion
103 | backward-expansion
104 | chosen)
105 |
106 | ;; search backward
107 | (goto-char he-search-loc-backward)
108 | (setq expansion (he-line-search he-search-string
109 | strip-prompt t))
110 |
111 | (when expansion
112 | (setq backward-expansion expansion)
113 | (setq backward-point (point))
114 | (setq backward-distance (- he-string-beg backward-point)))
115 |
116 | ;; search forward
117 | (goto-char he-search-loc-forward)
118 | (setq expansion (he-line-search he-search-string
119 | strip-prompt nil))
120 |
121 | (when expansion
122 | (setq forward-expansion expansion)
123 | (setq forward-point (point))
124 | (setq forward-distance (- forward-point he-string-beg)))
125 |
126 | ;; choose depending on distance
127 | (setq chosen (cond
128 | ((and forward-point backward-point)
129 | (if (< forward-distance backward-distance) :forward :backward))
130 |
131 | (forward-point :forward)
132 | (backward-point :backward)))
133 |
134 | (when (equal chosen :forward)
135 | (setq expansion forward-expansion)
136 | (set-marker he-search-loc-forward forward-point))
137 |
138 | (when (equal chosen :backward)
139 | (setq expansion backward-expansion)
140 | (set-marker he-search-loc-backward backward-point))
141 |
142 | ))))
143 |
144 | (if (not expansion)
145 | (progn
146 | (if old (he-reset-string))
147 | ())
148 | (progn
149 | (he-substitute-string expansion t)
150 | t))))
151 |
152 | (defun he-sexp-search (pattern &optional reverse limit)
153 | (when (if reverse
154 | (search-backward pattern nil t)
155 | (search-forward pattern nil t))
156 | (ignore-errors
157 | (buffer-substring-no-properties (if reverse
158 | (point)
159 | (save-excursion
160 | (paredit-backward-up 1)
161 | (point)))
162 | (save-excursion
163 | (if reverse
164 | (paredit-forward 1)
165 | (paredit-forward-up 1))
166 | (paredit-backward-down 1)
167 | (point))))))
168 |
169 | (defun he-sexp-beg ()
170 | (save-excursion (paredit-backward-up 1) (point)))
171 |
172 | (defun try-expand-sexp-closest-first (old)
173 | "Try to complete the current sexp to an entire sexp in the buffer.
174 | The argument OLD has to be nil the first call of this function, and t
175 | for subsequent calls (for further possible completions of the same
176 | string). It returns t if a new completion is found, nil otherwise."
177 | (he--closest-in-this-buffer old #'he-sexp-beg #'he-sexp-search))
178 |
179 | (defun try-expand-sexp-all-buffers (old)
180 | "Try to expand sexp \"dynamically\", searching all other buffers.
181 | The argument OLD has to be nil the first call of this function, and t
182 | for subsequent calls (for further possible expansions of the same
183 | string). It returns t if a new expansion is found, nil otherwise."
184 | (he--all-buffers old #'he-sexp-beg #'he-sexp-search))
185 |
186 | ;; Hippie expand: sometimes too hip
187 | (setq hippie-expand-try-functions-list '(try-expand-dabbrev-closest-first
188 | try-complete-file-name
189 | try-expand-dabbrev-all-buffers
190 | try-expand-dabbrev-from-kill
191 | try-expand-all-abbrevs
192 | try-complete-lisp-symbol-partially
193 | try-complete-lisp-symbol))
194 |
195 | ;; Create own function to expand lines (C-S-.)
196 | (defun hippie-expand-lines ()
197 | (interactive)
198 | (let ((hippie-expand-try-functions-list
199 | (if paredit-mode
200 | '(try-expand-sexp-closest-first
201 | try-expand-sexp-all-buffers)
202 | '(try-expand-line-closest-first
203 | try-expand-line-all-buffers))))
204 | (unless paredit-mode (end-of-line))
205 | (hippie-expand nil)
206 | (indent-region he-string-beg (point))))
207 |
208 | ;; Don't case-fold when expanding with hippe
209 | (defun hippie-expand-no-case-fold ()
210 | (interactive)
211 | (let ((case-fold-search nil))
212 | (hippie-expand nil)))
213 |
214 | (global-set-key (kbd "C-.") 'hippie-expand-no-case-fold)
215 | (global-set-key (kbd "C-:") 'hippie-expand-lines)
216 |
217 | (provide 'setup-hippie)
218 |
--------------------------------------------------------------------------------