1040 lines
37 KiB
EmacsLisp
1040 lines
37 KiB
EmacsLisp
(recentf-mode t)
|
||
|
||
(use-package golden-ratio
|
||
:ensure t
|
||
:init
|
||
(setq golden-ratio-auto-scale t)
|
||
(golden-ratio-mode 1))
|
||
|
||
(defun kylekrein/duplicate-line()
|
||
"Duplicate current line and move cursor to it"
|
||
(interactive)
|
||
(let ((column (- (point) (point-at-bol)))
|
||
(line (let ((s (thing-at-point 'line t)))
|
||
(if s (string-remove-suffix "\n" s) ""))))
|
||
(move-end-of-line 1)
|
||
(newline)
|
||
(insert line)
|
||
(move-beginning-of-line 1)
|
||
(forward-char column)))
|
||
|
||
(global-set-key [remap list-buffers] 'ibuffer)
|
||
(global-set-key (kbd "M-o") 'other-window)
|
||
(global-set-key (kbd "C-c o t") 'vterm-toggle)
|
||
(global-set-key (kbd "C-c o a") 'org-agenda)
|
||
(global-set-key (kbd "C-c o m") 'magit)
|
||
|
||
(global-set-key (kbd "C-.") 'kylekrein/duplicate-line)
|
||
;;(windmove-default-keybindings) ;; move between windows with S-<left>, S-<right>, S-<up>, S-<down>
|
||
|
||
(defun split-and-follow-horizontally ()
|
||
(interactive)
|
||
(split-window-below)
|
||
(balance-windows))
|
||
|
||
(defun split-and-follow-vertically ()
|
||
(interactive)
|
||
(split-window-right)
|
||
(balance-windows))
|
||
|
||
(use-package emacs
|
||
:bind (:map ctl-x-map
|
||
("2" . split-and-follow-horizontally)
|
||
("3" . split-and-follow-vertically))
|
||
:custom
|
||
(info-lookup-other-window-flag t)
|
||
(help-window-select t "Switch to help buffers automatically"))
|
||
;; Auto-select new Info buffer window when it’s created.
|
||
(advice-add 'info-lookup :after
|
||
(lambda (&rest _)
|
||
(when-let (window (get-buffer-window "*info*"))
|
||
(select-window window))))
|
||
|
||
;; Auto-select new window after splitting. Splitting commands almost
|
||
;;,all use `split-window’, so advice the function for auto selection.
|
||
(advice-add 'split-window :after
|
||
(lambda (&rest _) (select-window (get-lru-window))))
|
||
|
||
(defun git-package (url)
|
||
(let* ((pkg-name (file-name-base (directory-file-name url)))
|
||
(pkg-sym (intern pkg-name)))
|
||
(eval
|
||
`(use-package ,pkg-sym
|
||
:vc (:url ,url :rev :newest)
|
||
:ensure nil))))
|
||
|
||
;;(setq select-enable-primary t)
|
||
(defun kylekrein/copy-to-clipboard (text)
|
||
(with-temp-buffer
|
||
(insert text)
|
||
(copy-region-as-kill (point-min) (point-max))
|
||
(clipboard-kill-region (point-min) (point-max))))
|
||
|
||
(defun kylekrein/detect-wsl ()
|
||
(and (eq system-type 'gnu/linux)
|
||
(file-exists-p "/proc/sys/fs/binfmt_misc/WSLInterop")))
|
||
|
||
(use-package alert
|
||
:ensure t
|
||
)
|
||
|
||
(use-package alert-toast :ensure t :after alert)
|
||
|
||
(setq alert-default-style
|
||
(cond
|
||
((kylekrein/detect-wsl) 'toast)
|
||
(t 'libnotify)))
|
||
|
||
(unless (file-exists-p "~/.cache/emacs/tildafiles")
|
||
(make-directory "~/.cache/emacs/tildafiles"))
|
||
(setq backup-directory-alist '((".*" . "~/.cache/emacs/tildafiles")))
|
||
|
||
(use-package diminish :ensure t)
|
||
|
||
(defun kylekrein/copy-emoji-to-clipboard()
|
||
(interactive)
|
||
(let ((emoji (emoji--read-emoji)))
|
||
(when emoji
|
||
(kylekrein/copy-to-clipboard emoji)
|
||
(message "Copied: %s" (current-kill 0 t)))))
|
||
|
||
(setq ediff-split-window-function 'split-window-horizontally)
|
||
;;(setq ediff-window-setup-function 'ediff-setup-windows-plain)
|
||
|
||
(set-face-attribute 'variable-pitch nil
|
||
:family "DejaVu Sans";;"ET Bembo"
|
||
:height 220
|
||
:weight 'normal)
|
||
(set-face-attribute 'default nil
|
||
:family "Iosevka"
|
||
:height 210
|
||
:weight 'medium)
|
||
|
||
(set-face-attribute 'fixed-pitch nil
|
||
:family "Iosevka"
|
||
:height 210
|
||
:weight 'medium)
|
||
|
||
;; Makes commented text and keywords italics.
|
||
;; This is working in emacsclient but not emacs.
|
||
;; Your font must have an italic face available.
|
||
(set-face-attribute 'font-lock-comment-face nil
|
||
:slant 'italic)
|
||
(set-face-attribute 'font-lock-keyword-face nil
|
||
:slant 'italic)
|
||
|
||
;; This sets the default font on all graphical frames created after restarting Emacs.
|
||
;; Does the same thing as 'set-face-attribute default' above, but emacsclient fonts
|
||
;; are not right unless I also add this method of setting the default font.
|
||
;;(add-to-list 'default-frame-alist '(font . "Iosevka Mono-20"))
|
||
|
||
;; Uncomment the following line if line spacing needs adjusting.
|
||
(setq-default line-spacing 0.12)
|
||
|
||
|
||
(add-hook 'text-mode-hook #'variable-pitch-mode)
|
||
;; Enable variable-pitch-mode in Org
|
||
(add-hook 'org-mode-hook #'variable-pitch-mode)
|
||
|
||
;; Ensure code blocks, tables, and special elements remain fixed-pitch
|
||
(custom-set-faces
|
||
;; Keep code blocks, src, and tables fixed-pitch (Iosevka)
|
||
'(org-block ((t (:inherit fixed-pitch))))
|
||
'(org-block-begin-line ((t (:inherit fixed-pitch))))
|
||
'(org-block-end-line ((t (:inherit fixed-pitch))))
|
||
'(org-table ((t (:inherit fixed-pitch))))
|
||
'(org-code ((t (:inherit fixed-pitch))))
|
||
'(org-verbatim ((t (:inherit fixed-pitch))))
|
||
'(org-meta-line ((t (:inherit fixed-pitch))))
|
||
'(org-checkbox ((t (:inherit fixed-pitch))))
|
||
)
|
||
|
||
(electric-indent-mode -1) ;; Turn off the weird indenting that Emacs does by default.
|
||
(electric-pair-mode 1) ;; Turns on automatic parens pairing
|
||
;; The following prevents <> from auto-pairing when electric-pair-mode is on.
|
||
;; Otherwise, org-tempo is broken when you try to <s TAB...
|
||
(add-hook 'org-mode-hook (lambda ()
|
||
(setq-local electric-pair-inhibit-predicate
|
||
`(lambda (c)
|
||
(if (char-equal c ?<) t (,electric-pair-inhibit-predicate c))))))
|
||
(global-auto-revert-mode t) ;; Automatically show changes if the file has changed
|
||
;;(global-display-line-numbers-mode 1) ;; Display line numbers
|
||
(add-hook 'prog-mode-hook #'display-line-numbers-mode)
|
||
(global-visual-line-mode t) ;; Enable truncated lines
|
||
(winner-mode t) ;; Undo (C-c <left>) and Redo (C-c <right>) for windows
|
||
(setq sentence-end-double-space t) ;; Single space doesn't end a sentence
|
||
|
||
(save-place-mode t) ;; Restore cursor place in file
|
||
|
||
(use-package nov :ensure t)
|
||
(add-to-list 'auto-mode-alist '("\\.epub\\'" . nov-mode))
|
||
|
||
(use-package magit
|
||
:ensure t)
|
||
|
||
(use-package doom-modeline
|
||
:ensure t
|
||
:init (doom-modeline-mode 1)
|
||
:config
|
||
(setq doom-modeline-height 35 ;; sets modeline height
|
||
doom-modeline-bar-width 5 ;; sets right bar width
|
||
doom-modeline-persp-name nil ;; adds perspective name to modeline
|
||
doom-modeline-time t ;; shows time
|
||
doom-modeline-persp-icon nil)) ;; adds folder icon next to persp name
|
||
|
||
(use-package rainbow-delimiters
|
||
:ensure t
|
||
:hook ((emacs-lisp-mode . rainbow-delimiters-mode)
|
||
(clojure-mode . rainbow-delimiters-mode)))
|
||
|
||
(setq calendar-date-style "european")
|
||
(setq calendar-week-start-day 1)
|
||
|
||
;;Line truncation
|
||
(defun kylekrein/truncate-calendar-hook ()
|
||
"Turn line truncation on."
|
||
(toggle-truncate-lines 1))
|
||
|
||
(add-hook 'calendar-mode-hook #'kylekrein/truncate-calendar-hook)
|
||
|
||
;;Current month is the first
|
||
(add-hook 'calendar-initial-window-hook #'calendar-scroll-left)
|
||
|
||
;;Calendar in org agenda
|
||
(setq org-agenda-include-diary t)
|
||
|
||
(defadvice revert-buffer (after refresh-org-agenda-on-revert activate)
|
||
(if (member (buffer-file-name (current-buffer)) org-agenda-files)
|
||
(org-agenda-redo-all t)))
|
||
|
||
(org-babel-do-load-languages
|
||
'org-babel-load-languages
|
||
'((shell . t)
|
||
(C . t)
|
||
(python . t)))
|
||
|
||
(use-package org
|
||
:config
|
||
(org-link-set-parameters
|
||
"copy"
|
||
:follow (lambda (link) (kill-new link))
|
||
:export (lambda (_ desc &rest _) desc)))
|
||
|
||
;;;; Better Looking Bullets
|
||
(add-hook 'org-mode-hook 'org-indent-mode)
|
||
(use-package org-bullets :ensure t)
|
||
(add-hook 'org-mode-hook (lambda () (org-bullets-mode 1)))
|
||
|
||
(custom-set-faces
|
||
'(org-level-1 ((t (:inherit outline-1 :height 1.45))))
|
||
'(org-level-2 ((t (:inherit outline-2 :height 1.35))))
|
||
'(org-level-3 ((t (:inherit outline-3 :height 1.30))))
|
||
'(org-level-4 ((t (:inherit outline-4 :height 1.25))))
|
||
'(org-level-5 ((t (:inherit outline-5 :height 1.20))))
|
||
'(org-level-6 ((t (:inherit outline-5 :height 1.15))))
|
||
'(org-level-7 ((t (:inherit outline-5 :height 1.10)))))
|
||
|
||
(require 'org-tempo)
|
||
|
||
(defun org-update-table-by-name (name)
|
||
"Update the named table."
|
||
(org-table-map-tables
|
||
(lambda ()
|
||
(let ((table_name (org-element-property :name (org-element-at-point))))
|
||
(if (and table_name (string-match-p name table_name))
|
||
(org-table-recalculate))))))
|
||
|
||
(defun org-update-and-realign-tables ()
|
||
(interactive)
|
||
(org-map-dblocks 'org-update-dblock)
|
||
(redisplay)
|
||
(org-table-map-tables 'org-table-recalculate)
|
||
(org-table-map-tables 'org-table-align))
|
||
|
||
(global-set-key (kbd "C-c n u") 'org-update-and-realign-tables)
|
||
|
||
(use-package org-transclusion :ensure t)
|
||
(custom-set-faces
|
||
'(org-transclusion-fringe
|
||
((t
|
||
(:background "green"))))
|
||
'(org-transclusion-source-fringe
|
||
((t
|
||
(:background "blue")))))
|
||
|
||
(use-package org-roam
|
||
:ensure t
|
||
:init
|
||
(setq org-roam-v2-ack t)
|
||
:custom
|
||
(org-roam-directory "~/Documents/org")
|
||
(org-roam-completion-everywhere t)
|
||
(org-roam-capture-templates
|
||
'(("d" "default" plain
|
||
"%?"
|
||
:if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n#+category: ${title}\n")
|
||
:unnarrowed t)
|
||
("p" "project" plain "* Goals\n\n%?\n\n* Tasks\n\n** TODO Add initial tasks\n\n* Dates\n\n"
|
||
:if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n#+category: ${title}\n#+filetags: Project")
|
||
:unnarrowed t))
|
||
)
|
||
(org-roam-dailies-capture-templates
|
||
'(("d" "default" entry "* %<%I:%M %p>: %?"
|
||
:if-new (file+head "%<%Y-%m-%d>.org" "#+title: %<%Y-%m-%d>\n"))))
|
||
:bind (("C-c n l" . org-roam-buffer-toggle)
|
||
("C-c n f" . org-roam-node-find)
|
||
("C-c n i" . org-roam-node-insert)
|
||
:map org-mode-map
|
||
("C-M-i" . completion-at-point))
|
||
:bind-keymap
|
||
("C-c n d" . org-roam-dailies-map)
|
||
:config
|
||
(require 'org-roam-dailies) ;; Ensure the keymap is available
|
||
(org-roam-db-autosync-mode)
|
||
(org-roam-setup))
|
||
|
||
(defun kylekrein/org-roam-ripgrep ()
|
||
(interactive)
|
||
(require 'consult)
|
||
(require 'org-roam)
|
||
(let ((consult-ripgrep-command "rg --null --ignore-case --type org --line-buffered --color=always --max-columns=500 --no-heading --line-number . -e ARG OPTS"))
|
||
(consult-ripgrep org-roam-directory)))
|
||
(global-set-key (kbd "C-c n r") #'kylekrein/org-roam-ripgrep)
|
||
|
||
(defun kylekrein/org-roam-capture-inbox ()
|
||
(interactive)
|
||
(org-roam-capture- :node (org-roam-node-create)
|
||
:templates '(("i" "inbox" plain "* %?"
|
||
:if-new (file+head "Inbox.org" "#+title: Inbox\n#+category: Inbox\n#+filetags: Project")))))
|
||
(global-set-key (kbd "C-c n b") #'kylekrein/org-roam-capture-inbox)
|
||
|
||
(defun org-agenda-refresh ()
|
||
"Refresh all `org-agenda' buffers."
|
||
(dolist (buffer (buffer-list))
|
||
(with-current-buffer buffer
|
||
(when (derived-mode-p 'org-agenda-mode)
|
||
(org-agenda-maybe-redo)))))
|
||
|
||
(defadvice org-schedule (after refresh-agenda activate)
|
||
"Refresh org-agenda."
|
||
(org-agenda-refresh))
|
||
|
||
(require 'org-roam-node)
|
||
(defun kylekrein/org-roam-filter-by-tag (tag-name)
|
||
(lambda (node)
|
||
(member tag-name (org-roam-node-tags node))))
|
||
|
||
(defun kylekrein/org-roam-list-notes-by-tag (tag-name)
|
||
(mapcar #'org-roam-node-file
|
||
(seq-filter
|
||
(kylekrein/org-roam-filter-by-tag tag-name)
|
||
(org-roam-node-list))))
|
||
|
||
(defun kylekrein/org-roam-refresh-agenda-list ()
|
||
(interactive)
|
||
(setq org-agenda-files (kylekrein/org-roam-list-notes-by-tag "Project")))
|
||
|
||
|
||
(setq org-agenda-files nil
|
||
org-roam-node-display-template "${title} ${tags}"
|
||
org-agenda-start-on-weekday 1 ;; Week starts on Monday instead of Sunday
|
||
)
|
||
;; Build the agenda list the first time for the session
|
||
(kylekrein/org-roam-refresh-agenda-list)
|
||
|
||
;; Log time a task was set to DONE.
|
||
(setq org-log-done (quote time))
|
||
|
||
;; Don't log the time a task was rescheduled or redeadlined.
|
||
(setq org-log-redeadline nil)
|
||
(setq org-log-reschedule nil)
|
||
|
||
;; Prefer rescheduling to future dates and times
|
||
(setq org-read-date-prefer-future 'time)
|
||
|
||
(use-package emacs
|
||
:config
|
||
;; start warning 60 minutes before the appointment
|
||
(setq appt-message-warning-time 60)
|
||
|
||
;; warn me every 5 minutes
|
||
(setq appt-display-interval 15)
|
||
(setq appt-disp-window-function
|
||
(lambda (remaining new-time msg)
|
||
(alert (format "In %s minutes" remaining)
|
||
:title msg
|
||
:severity 'moderate
|
||
:category 'org-agenda
|
||
:id (intern msg))))
|
||
|
||
(advice-add 'appt-check
|
||
:before
|
||
(lambda (&rest args)
|
||
(org-agenda-to-appt t)))
|
||
|
||
(appt-activate t))
|
||
(setq alert-fade-time 50)
|
||
|
||
(use-package org-upcoming-modeline
|
||
:ensure t
|
||
:after org
|
||
:config
|
||
(setq appt-display-mode-line nil)
|
||
(org-upcoming-modeline-mode))
|
||
|
||
(use-package rainbow-mode
|
||
:ensure t
|
||
:hook
|
||
((org-mode prog-mode) . rainbow-mode))
|
||
|
||
(use-package gptel
|
||
:ensure t
|
||
:bind
|
||
("C-c a c" . gptel)
|
||
("C-c a r" . gptel-rewrite)
|
||
("C-c a s" . gptel-send)
|
||
("C-c a f" . gptel-add-file))
|
||
(setq
|
||
gptel-model 'llama3.1
|
||
gptel-backend (gptel-make-ollama "Ollama"
|
||
:host "localhost:11434"
|
||
:stream t
|
||
:models '(llama3.1 qwen2.5-coder:7b))
|
||
gptel-track-media t
|
||
gptel-default-mode 'org-mode)
|
||
(add-hook 'gptel-post-stream-hook 'gptel-auto-scroll)
|
||
(add-hook 'gptel-post-response-functions 'gptel-end-of-response)
|
||
|
||
(use-package eshell-syntax-highlighting
|
||
:ensure t
|
||
:after esh-mode
|
||
:config
|
||
(eshell-syntax-highlighting-global-mode +1))
|
||
|
||
(use-package vterm
|
||
:ensure t
|
||
)
|
||
|
||
(use-package vterm-toggle
|
||
:ensure t
|
||
:after vterm
|
||
:config
|
||
(setq vterm-toggle-fullscreen-p nil)
|
||
(setq vterm-toggle-scope 'project)
|
||
(add-to-list 'display-buffer-alist
|
||
'((lambda (buffer-or-name _)
|
||
(let ((buffer (get-buffer buffer-or-name)))
|
||
(with-current-buffer buffer
|
||
(or (equal major-mode 'vterm-mode)
|
||
(string-prefix-p vterm-buffer-name (buffer-name buffer))))))
|
||
(display-buffer-reuse-window display-buffer-at-bottom)
|
||
;;(display-buffer-reuse-window display-buffer-in-direction)
|
||
;;display-buffer-in-direction/direction/dedicated is added in emacs27
|
||
;;(direction . bottom)
|
||
;;(dedicated . t) ;dedicated is supported in emacs27
|
||
(reusable-frames . visible)
|
||
(window-height . 0.3))))
|
||
|
||
(git-package "https://github.com/darcamo/cmake-integration.git")
|
||
(use-package cmake-integration
|
||
:commands (cmake-integration-transient)
|
||
:custom
|
||
(cmake-integration-generator "Ninja")
|
||
(cmake-integration-use-separated-compilation-buffer-for-each-target t))
|
||
|
||
(defun is-cmake-project? ()
|
||
"Determine if the current directory is a CMake project."
|
||
(interactive)
|
||
(if-let* ((project (project-current))
|
||
(project-root (project-root project))
|
||
(cmakelist-path (expand-file-name "CMakeLists.txt" project-root)))
|
||
(file-exists-p cmakelist-path)))
|
||
|
||
|
||
(defun cmake-integration-keybindings-mode-turn-on-in-cmake-projects ()
|
||
"Turn on `cmake-integration-keybindings-mode' in CMake projects."
|
||
(when (is-cmake-project?)
|
||
(cmake-integration-keybindings-mode 1)))
|
||
|
||
|
||
(define-minor-mode cmake-integration-keybindings-mode
|
||
"A minor-mode for adding keybindings to compile C++ code using cmake-integration package."
|
||
nil
|
||
"cmake"
|
||
'(
|
||
([f5] . cmake-integration-transient) ;; Open main transient menu
|
||
([M-f9] . cmake-integration-save-and-compile) ;; Ask for the target name and compile it
|
||
([f9] . cmake-integration-save-and-compile-last-target) ;; Recompile the last target
|
||
([C-f9] . cmake-integration-run-ctest) ;; Run CTest
|
||
([f7] . cmake-integration-run-last-target) ;; Run the target (using any previously set command line parameters)
|
||
([S-f7] . kill-compilation)
|
||
([C-f7] . cmake-integration-debug-last-target) ;; Debug the target (using any previously set command line parameters)
|
||
([M-f7] . cmake-integration-run-last-target-with-arguments) ;; Ask for command line parameters to run the target
|
||
([M-f8] . cmake-integration-select-configure-preset) ;; Ask for a preset name and call CMake to configure the project
|
||
([f8] . cmake-integration-cmake-reconfigure) ;; Call CMake to configure the project using the last chosen preset
|
||
)
|
||
)
|
||
|
||
(define-globalized-minor-mode global-cmake-integration-keybindings-mode
|
||
cmake-integration-keybindings-mode cmake-integration-keybindings-mode-turn-on-in-cmake-projects)
|
||
|
||
|
||
(global-cmake-integration-keybindings-mode)
|
||
|
||
;; Extend project.el to recognize local projects based on a .project file
|
||
(cl-defmethod project-root ((project (head local)))
|
||
(cdr project))
|
||
|
||
(defun mu--project-files-in-directory (dir)
|
||
"Use `fd' to list files in DIR."
|
||
(let* ((default-directory dir)
|
||
(localdir (file-local-name (expand-file-name dir)))
|
||
(command (format "fd -t f -0 . %s" localdir)))
|
||
(project--remote-file-names
|
||
(sort (split-string (shell-command-to-string command) "\0" t)
|
||
#'string<))))
|
||
|
||
(cl-defmethod project-files ((project (head local)) &optional dirs)
|
||
"Override `project-files' to use `fd' in local projects."
|
||
(mapcan #'mu--project-files-in-directory
|
||
(or dirs (list (project-root project)))))
|
||
|
||
(defun mu-project-try-local (dir)
|
||
"Determine if DIR is a non-Git project.
|
||
DIR must include a .project file to be considered a project."
|
||
(let ((root (locate-dominating-file dir ".project")))
|
||
(and root (cons 'local root))))
|
||
|
||
(use-package project
|
||
:defer t
|
||
:config
|
||
(add-to-list 'project-find-functions 'mu-project-try-local)
|
||
)
|
||
|
||
(use-package direnv
|
||
:ensure t
|
||
:config
|
||
(direnv-mode))
|
||
|
||
(defun kylekrein/project-enable-direnv-flake ()
|
||
"Add `use flake` to .envrc and run `direnv allow` in the project root."
|
||
(interactive)
|
||
(let* ((project (project-current t))
|
||
(root (project-root project))
|
||
(envrc-path (expand-file-name ".envrc" root)))
|
||
(unless (file-exists-p envrc-path)
|
||
(with-temp-buffer
|
||
(insert "use flake\n")
|
||
(write-file envrc-path)))
|
||
(unless (string-match-p "use flake" (with-temp-buffer
|
||
(insert-file-contents envrc-path)
|
||
(buffer-string)))
|
||
(with-temp-buffer
|
||
(insert-file-contents envrc-path)
|
||
(goto-char (point-max))
|
||
(insert "\nuse flake\n")
|
||
(write-file envrc-path)))
|
||
(let ((default-directory root))
|
||
(direnv-allow))
|
||
(message "Added 'use flake' to .envrc and ran direnv allow in %s" root)))
|
||
|
||
(use-package glsl-mode
|
||
:ensure t)
|
||
|
||
(add-to-list 'auto-mode-alist '("\\.rml\\'" . html-ts-mode))
|
||
(add-to-list 'auto-mode-alist '("\\.rcss\\'" . css-ts-mode))
|
||
|
||
(add-to-list 'auto-mode-alist '("CMakeLists\\.txt\\'" . cmake-ts-mode))
|
||
(add-to-list 'auto-mode-alist '("\\.cmake\\'" . cmake-ts-mode))
|
||
|
||
(use-package treesit-auto
|
||
:ensure t
|
||
:demand t
|
||
:config
|
||
(global-treesit-auto-mode))
|
||
|
||
(use-package eldoc
|
||
:init
|
||
(global-eldoc-mode))
|
||
|
||
(use-package eglot
|
||
:hook (prog-mode . eglot-ensure)
|
||
;;:init
|
||
;;(setq eglot-stay-out-of '(flymake))
|
||
:bind (:map
|
||
eglot-mode-map
|
||
("C-c c a" . eglot-code-actions)
|
||
;;("C-c c o" . eglot-code-actions-organize-imports)
|
||
("C-c c r" . eglot-rename)
|
||
("C-c c f" . eglot-format)))
|
||
|
||
(use-package flymake
|
||
:hook (prog-mode . flymake-mode)
|
||
:bind (:map flymake-mode-map
|
||
("C-c ! n" . flymake-goto-next-error)
|
||
("C-c ! p" . flymake-goto-prev-error)
|
||
("C-c ! l" . flymake-show-buffer-diagnostics)))
|
||
|
||
(with-eval-after-load 'eglot
|
||
(add-to-list 'eglot-server-programs
|
||
'((c-ts-mode c++-ts-mode)
|
||
. ("clangd"
|
||
"-j=8"
|
||
"--log=error"
|
||
"--malloc-trim"
|
||
"--background-index"
|
||
"--clang-tidy"
|
||
"--cross-file-rename"
|
||
"--completion-style=detailed"
|
||
"--pch-storage=memory"
|
||
"--header-insertion=never"
|
||
"--header-insertion-decorators=0")))
|
||
(add-hook 'c-ts-mode-hook #'eglot-ensure)
|
||
(add-hook 'c++-ts-mode-hook #'eglot-ensure))
|
||
|
||
(with-eval-after-load 'eglot
|
||
(add-to-list 'eglot-server-programs
|
||
'(csharp-ts-mode
|
||
. ("csharp-ls")))
|
||
(add-hook 'csharp-ts-mode-hook #'eglot-ensure))
|
||
|
||
(with-eval-after-load 'eglot
|
||
(add-to-list 'eglot-server-programs
|
||
'(python-ts-mode
|
||
. ("ty")))
|
||
(add-hook 'python-ts-mode-hook #'eglot-ensure))
|
||
|
||
(use-package nerd-icons
|
||
:ensure t
|
||
;; :custom
|
||
;; The Nerd Font you want to use in GUI
|
||
;; "Symbols Nerd Font Mono" is the default and is recommended
|
||
;; but you can use any other Nerd Font if you want
|
||
;; (nerd-icons-font-family "Symbols Nerd Font Mono")
|
||
)
|
||
|
||
(use-package nerd-icons-completion
|
||
:ensure t
|
||
:after marginalia
|
||
:config
|
||
(nerd-icons-completion-mode)
|
||
(add-hook 'marginalia-mode-hook #'nerd-icons-completion-marginalia-setup))
|
||
|
||
(use-package persist-state
|
||
:ensure t
|
||
:after server
|
||
:if server-process
|
||
:config
|
||
(persist-state-mode))
|
||
|
||
(use-package multiple-cursors
|
||
:ensure t
|
||
:bind (
|
||
("C-S-c C-S-c" . mc/edit-lines)
|
||
("C->" . mc/mark-next-like-this)
|
||
("C-<" . mc/mark-previous-like-this)
|
||
("C-C C-<" . mc/mark-all-like-this)
|
||
("C-\"" . mc/skip-to-next-like-this)
|
||
("C-:" . mc/skip-to-previous-like-this)
|
||
("C-C C->" . mc/mark-more-like-this-extended)
|
||
("C-S-<mouse-1>" . mc/add-cursor-on-click)
|
||
))
|
||
|
||
(require 'windmove)
|
||
|
||
;;;###autoload
|
||
(defun buf-move-up ()
|
||
"Swap the current buffer and the buffer above the split.
|
||
If there is no split, ie now window above the current one, an
|
||
error is signaled."
|
||
;; "Switches between the current buffer, and the buffer above the
|
||
;; split, if possible."
|
||
(interactive)
|
||
(let* ((other-win (windmove-find-other-window 'up))
|
||
(buf-this-buf (window-buffer (selected-window))))
|
||
(if (null other-win)
|
||
(error "No window above this one")
|
||
;; swap top with this one
|
||
(set-window-buffer (selected-window) (window-buffer other-win))
|
||
;; move this one to top
|
||
(set-window-buffer other-win buf-this-buf)
|
||
(select-window other-win))))
|
||
|
||
;;;###autoload
|
||
(defun buf-move-down ()
|
||
"Swap the current buffer and the buffer under the split.
|
||
If there is no split, ie now window under the current one, an
|
||
error is signaled."
|
||
(interactive)
|
||
(let* ((other-win (windmove-find-other-window 'down))
|
||
(buf-this-buf (window-buffer (selected-window))))
|
||
(if (or (null other-win)
|
||
(string-match "^ \\*Minibuf" (buffer-name (window-buffer other-win))))
|
||
(error "No window under this one")
|
||
;; swap top with this one
|
||
(set-window-buffer (selected-window) (window-buffer other-win))
|
||
;; move this one to top
|
||
(set-window-buffer other-win buf-this-buf)
|
||
(select-window other-win))))
|
||
|
||
;;;###autoload
|
||
(defun buf-move-left ()
|
||
"Swap the current buffer and the buffer on the left of the split.
|
||
If there is no split, ie now window on the left of the current
|
||
one, an error is signaled."
|
||
(interactive)
|
||
(let* ((other-win (windmove-find-other-window 'left))
|
||
(buf-this-buf (window-buffer (selected-window))))
|
||
(if (null other-win)
|
||
(error "No left split")
|
||
;; swap top with this one
|
||
(set-window-buffer (selected-window) (window-buffer other-win))
|
||
;; move this one to top
|
||
(set-window-buffer other-win buf-this-buf)
|
||
(select-window other-win))))
|
||
|
||
;;;###autoload
|
||
(defun buf-move-right ()
|
||
"Swap the current buffer and the buffer on the right of the split.
|
||
If there is no split, ie now window on the right of the current
|
||
one, an error is signaled."
|
||
(interactive)
|
||
(let* ((other-win (windmove-find-other-window 'right))
|
||
(buf-this-buf (window-buffer (selected-window))))
|
||
(if (null other-win)
|
||
(error "No right split")
|
||
;; swap top with this one
|
||
(set-window-buffer (selected-window) (window-buffer other-win))
|
||
;; move this one to top
|
||
(set-window-buffer other-win buf-this-buf)
|
||
(select-window other-win))))
|
||
|
||
(use-package windmove
|
||
:bind
|
||
(("<C-up>" . windmove-up)
|
||
("<C-down>" . windmove-down)
|
||
("<C-left>" . windmove-left)
|
||
("<C-right>" . windmove-right)
|
||
("<C-M-S-up>" . buf-move-up)
|
||
("<C-M-S-down>" . buf-move-down)
|
||
("<C-M-S-left>" . buf-move-left)
|
||
("<C-M-S-right>" . buf-move-right)))
|
||
|
||
(use-package corfu
|
||
:ensure t
|
||
;; Optional customizations
|
||
:custom
|
||
(corfu-cycle t) ;; Enable cycling for `corfu-next/previous'
|
||
(corfu-auto t)
|
||
(corfu-auto-prefix 2)
|
||
(corfu-quit-at-boundary 'separator)
|
||
(corfu-echo-documentation 0.25)
|
||
(corfu-preselect-first nil)
|
||
(corfu-popupinfo-delay '(1.0 . 0.3)) ;;default '(2.0 . 1.0)
|
||
;; (corfu-quit-no-match nil) ;; Never quit, even if there is no match
|
||
;; (corfu-preview-current nil) ;; Disable current candidate preview
|
||
;; (corfu-preselect 'prompt) ;; Preselect the prompt
|
||
;; (corfu-on-exact-match nil) ;; Configure handling of exact matches
|
||
|
||
;; Enable Corfu only for certain modes. See also `global-corfu-modes'.
|
||
;; :hook ((prog-mode . corfu-mode)
|
||
;; (shell-mode . corfu-mode)
|
||
;; (eshell-mode . corfu-mode))
|
||
:bind (:map corfu-map
|
||
("M-SPC" . corfu-insert-separator)
|
||
("RET" . nil)
|
||
("TAB" . corfu-next)
|
||
([tab] . corfu-next)
|
||
("SHIFT-TAB" . corfu-previous)
|
||
([backtab] . corfu-previous)
|
||
("S-<return>" . corfu-insert))
|
||
|
||
;; Recommended: Enable Corfu globally. This is recommended since Dabbrev can
|
||
;; be used globally (M-/). See also the customization variable
|
||
;; `global-corfu-modes' to exclude certain modes.
|
||
:init
|
||
(global-corfu-mode)
|
||
(corfu-history-mode)
|
||
(corfu-popupinfo-mode))
|
||
|
||
;; A few more useful configurations...
|
||
(use-package emacs
|
||
:custom
|
||
;; TAB cycle if there are only few candidates
|
||
;; (completion-cycle-threshold 3)
|
||
|
||
;; Enable indentation+completion using the TAB key.
|
||
;; `completion-at-point' is often bound to M-TAB.
|
||
(tab-always-indent 'complete)
|
||
|
||
;; Emacs 30 and newer: Disable Ispell completion function.
|
||
;; Try `cape-dict' as an alternative.
|
||
(text-mode-ispell-word-completion nil)
|
||
|
||
;; Hide commands in M-x which do not apply to the current mode. Corfu
|
||
;; commands are hidden, since they are not used via M-x. This setting is
|
||
;; useful beyond Corfu.
|
||
(read-extended-command-predicate #'command-completion-default-include-p))
|
||
|
||
(use-package cape
|
||
:ensure t
|
||
:defer 10
|
||
:init
|
||
(add-to-list 'completion-at-point-functions #'cape-file))
|
||
|
||
;; Enable vertico
|
||
(use-package vertico
|
||
:ensure t
|
||
:custom
|
||
;; (vertico-scroll-margin 0) ;; Different scroll margin
|
||
;; (vertico-count 20) ;; Show more candidates
|
||
;; (vertico-resize t) ;; Grow and shrink the Vertico minibuffer
|
||
(vertico-cycle t) ;; Enable cycling for `vertico-next/previous'
|
||
:init
|
||
(vertico-mode))
|
||
|
||
(vertico-mode t) ;; enable vertico for all buffers
|
||
;; Persist history over Emacs restarts. Vertico sorts by history position.
|
||
(use-package savehist
|
||
:init
|
||
(savehist-mode))
|
||
|
||
;; A few more useful configurations...
|
||
(use-package emacs
|
||
:custom
|
||
;; Support opening new minibuffers from inside existing minibuffers.
|
||
(enable-recursive-minibuffers t)
|
||
;; Hide commands in M-x which do not work in the current mode. Vertico
|
||
;; commands are hidden in normal buffers. This setting is useful beyond
|
||
;; Vertico.
|
||
(read-extended-command-predicate #'command-completion-default-include-p)
|
||
:init
|
||
;; Add prompt indicator to `completing-read-multiple'.
|
||
;; We display [CRM<separator>], e.g., [CRM,] if the separator is a comma.
|
||
(defun crm-indicator (args)
|
||
(cons (format "[CRM%s] %s"
|
||
(replace-regexp-in-string
|
||
"\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" ""
|
||
crm-separator)
|
||
(car args))
|
||
(cdr args)))
|
||
(advice-add #'completing-read-multiple :filter-args #'crm-indicator)
|
||
|
||
;; Do not allow the cursor in the minibuffer prompt
|
||
(setq minibuffer-prompt-properties
|
||
'(read-only t cursor-intangible t face minibuffer-prompt))
|
||
(add-hook 'minibuffer-setup-hook #'cursor-intangible-mode))
|
||
|
||
;; Optionally use the `orderless' completion style.
|
||
(use-package orderless
|
||
:ensure t
|
||
:custom
|
||
;; Configure a custom style dispatcher (see the Consult wiki)
|
||
;; (orderless-style-dispatchers '(+orderless-consult-dispatch orderless-affix-dispatch))
|
||
;; (orderless-component-separator #'orderless-escapable-split-on-space)
|
||
(completion-styles '(orderless flex basic partial-completion))
|
||
|
||
(completion-category-defaults nil)
|
||
(completion-category-overrides '((file (styles partial-completion)))))
|
||
|
||
;; Example configuration for Consult
|
||
(use-package consult
|
||
:ensure t
|
||
;; Replace bindings. Lazily loaded by `use-package'.
|
||
:bind (;; C-c bindings in `mode-specific-map'
|
||
("C-c M-x" . consult-mode-command)
|
||
("C-c h" . consult-history)
|
||
("C-c k" . consult-kmacro)
|
||
("C-c m" . consult-man)
|
||
("C-c i" . consult-info)
|
||
([remap Info-search] . consult-info)
|
||
;; C-x bindings in `ctl-x-map'
|
||
("C-x M-:" . consult-complex-command) ;; orig. repeat-complex-command
|
||
("C-x b" . consult-buffer) ;; orig. switch-to-buffer
|
||
("C-x 4 b" . consult-buffer-other-window) ;; orig. switch-to-buffer-other-window
|
||
("C-x 5 b" . consult-buffer-other-frame) ;; orig. switch-to-buffer-other-frame
|
||
("C-x t b" . consult-buffer-other-tab) ;; orig. switch-to-buffer-other-tab
|
||
("C-x r b" . consult-bookmark) ;; orig. bookmark-jump
|
||
("C-x p b" . consult-project-buffer) ;; orig. project-switch-to-buffer
|
||
;; Custom M-# bindings for fast register access
|
||
("M-#" . consult-register-load)
|
||
("M-'" . consult-register-store) ;; orig. abbrev-prefix-mark (unrelated)
|
||
("C-M-#" . consult-register)
|
||
;; Other custom bindings
|
||
("M-y" . consult-yank-pop) ;; orig. yank-pop
|
||
;; M-g bindings in `goto-map'
|
||
("M-g e" . consult-compile-error)
|
||
("M-g f" . consult-flymake) ;; Alternative: consult-flycheck
|
||
("M-g g" . consult-goto-line) ;; orig. goto-line
|
||
("M-g M-g" . consult-goto-line) ;; orig. goto-line
|
||
("M-g o" . consult-outline) ;; Alternative: consult-org-heading
|
||
("M-g m" . consult-mark)
|
||
("M-g k" . consult-global-mark)
|
||
("M-g i" . consult-imenu)
|
||
("M-g I" . consult-imenu-multi)
|
||
;; M-s bindings in `search-map'
|
||
("M-s d" . consult-find) ;; Alternative: consult-fd
|
||
("M-s c" . consult-locate)
|
||
("M-s g" . consult-grep)
|
||
("M-s G" . consult-git-grep)
|
||
("M-s r" . consult-ripgrep)
|
||
("M-s l" . consult-line)
|
||
("M-s L" . consult-line-multi)
|
||
("M-s k" . consult-keep-lines)
|
||
("M-s u" . consult-focus-lines)
|
||
;; Isearch integration
|
||
("M-s e" . consult-isearch-history)
|
||
:map isearch-mode-map
|
||
("M-e" . consult-isearch-history) ;; orig. isearch-edit-string
|
||
("M-s e" . consult-isearch-history) ;; orig. isearch-edit-string
|
||
("M-s l" . consult-line) ;; needed by consult-line to detect isearch
|
||
("M-s L" . consult-line-multi) ;; needed by consult-line to detect isearch
|
||
;; Minibuffer history
|
||
:map minibuffer-local-map
|
||
("M-s" . consult-history) ;; orig. next-matching-history-element
|
||
("M-r" . consult-history)) ;; orig. previous-matching-history-element
|
||
|
||
;; Enable automatic preview at point in the *Completions* buffer. This is
|
||
;; relevant when you use the default completion UI.
|
||
:hook (completion-list-mode . consult-preview-at-point-mode)
|
||
|
||
;; The :init configuration is always executed (Not lazy)
|
||
:init
|
||
|
||
;; Tweak the register preview for `consult-register-load',
|
||
;; `consult-register-store' and the built-in commands. This improves the
|
||
;; register formatting, adds thin separator lines, register sorting and hides
|
||
;; the window mode line.
|
||
(advice-add #'register-preview :override #'consult-register-window)
|
||
(setq register-preview-delay 0.5)
|
||
|
||
;; Use Consult to select xref locations with preview
|
||
(setq xref-show-xrefs-function #'consult-xref
|
||
xref-show-definitions-function #'consult-xref)
|
||
|
||
;; Configure other variables and modes in the :config section,
|
||
;; after lazily loading the package.
|
||
:config
|
||
|
||
;; Optionally configure preview. The default value
|
||
;; is 'any, such that any key triggers the preview.
|
||
;; (setq consult-preview-key 'any)
|
||
;; (setq consult-preview-key "M-.")
|
||
;; (setq consult-preview-key '("S-<down>" "S-<up>"))
|
||
;; For some commands and buffer sources it is useful to configure the
|
||
;; :preview-key on a per-command basis using the `consult-customize' macro.
|
||
(consult-customize
|
||
consult-theme :preview-key '(:debounce 0.2 any)
|
||
consult-ripgrep consult-git-grep consult-grep consult-man
|
||
consult-bookmark consult-recent-file consult-xref
|
||
consult--source-bookmark consult--source-file-register
|
||
consult--source-recent-file consult--source-project-recent-file
|
||
;; :preview-key "M-."
|
||
:preview-key '(:debounce 0.4 any))
|
||
|
||
;; Optionally configure the narrowing key.
|
||
;; Both < and C-+ work reasonably well.
|
||
(setq consult-narrow-key "<") ;; "C-+"
|
||
|
||
;; Optionally make narrowing help available in the minibuffer.
|
||
;; You may want to use `embark-prefix-help-command' or which-key instead.
|
||
;; (keymap-set consult-narrow-map (concat consult-narrow-key " ?") #'consult-narrow-help)
|
||
)
|
||
(require 'consult)
|
||
;;(setq read-file-name-function #'consult-find-file-with-preview)
|
||
|
||
;;Previewing files in find-file
|
||
(defun consult-find-file-with-preview (prompt &optional dir default mustmatch initial pred)
|
||
(interactive)
|
||
(let ((default-directory (expand-file-name (or dir default-directory)))
|
||
(minibuffer-completing-file-name t))
|
||
(consult--read #'read-file-name-internal :state (consult--file-preview)
|
||
:prompt prompt
|
||
:initial initial
|
||
:require-match mustmatch
|
||
:predicate pred)))
|
||
|
||
;;Previewing files for project-find-file
|
||
(setq project-read-file-name-function #'consult-project-find-file-with-preview)
|
||
|
||
(defun consult-project-find-file-with-preview (prompt all-files &optional pred hist _mb)
|
||
(let ((prompt (if (and all-files
|
||
(file-name-absolute-p (car all-files)))
|
||
prompt
|
||
( concat prompt
|
||
( format " in %s"
|
||
(consult--fast-abbreviate-file-name default-directory)))))
|
||
(minibuffer-completing-file-name t))
|
||
(consult--read (mapcar
|
||
(lambda (file)
|
||
(file-relative-name file))
|
||
all-files)
|
||
:state (consult--file-preview)
|
||
:prompt (concat prompt ": ")
|
||
:require-match t
|
||
:history hist
|
||
:category 'file
|
||
:predicate pred)))
|
||
|
||
;; Enable rich annotations using the Marginalia package
|
||
(use-package marginalia
|
||
:ensure t
|
||
;; Bind `marginalia-cycle' locally in the minibuffer. To make the binding
|
||
;; available in the *Completions* buffer, add it to the
|
||
;; `completion-list-mode-map'.
|
||
:bind (:map minibuffer-local-map
|
||
("M-A" . marginalia-cycle))
|
||
|
||
;; The :init section is always executed.
|
||
:init
|
||
|
||
;; Marginalia must be activated in the :init section of use-package such that
|
||
;; the mode gets enabled right away. Note that this forces loading the
|
||
;; package.
|
||
(marginalia-mode))
|
||
|
||
(use-package doom-themes
|
||
:ensure t
|
||
:config
|
||
;; Global settings (defaults)
|
||
(setq doom-themes-enable-bold t ; if nil, bold is universally disabled
|
||
doom-themes-enable-italic t) ; if nil, italics is universally disabled
|
||
(load-theme 'doom-one t)
|
||
|
||
;; Enable flashing mode-line on errors
|
||
(doom-themes-visual-bell-config)
|
||
;; Enable custom neotree theme (nerd-icons must be installed!)
|
||
(doom-themes-neotree-config)
|
||
;; or for treemacs users
|
||
(setq doom-themes-treemacs-theme "doom-atom") ; use "doom-colors" for less minimal icon theme
|
||
(doom-themes-treemacs-config)
|
||
;; Corrects (and improves) org-mode's native fontification.
|
||
(doom-themes-org-config))
|
||
|
||
(unless (kylekrein/detect-wsl)
|
||
(add-to-list 'default-frame-alist '(alpha-background . 90))) ; For all new frames henceforth
|
||
|
||
(use-package which-key
|
||
:ensure t
|
||
:init
|
||
(which-key-mode 1)
|
||
:config
|
||
(setq which-key-side-window-location 'bottom
|
||
which-key-sort-order #'which-key-key-order-alpha
|
||
which-key-sort-uppercase-first nil
|
||
which-key-add-column-padding 1
|
||
which-key-max-display-columns nil
|
||
which-key-min-display-lines 6
|
||
which-key-side-window-slot -10
|
||
which-key-side-window-max-height 0.25
|
||
which-key-idle-delay 0.8
|
||
which-key-max-description-length 25
|
||
which-key-allow-imprecise-window-fit nil
|
||
which-key-separator " → " ))
|
||
|
||
(when (kylekrein/detect-wsl)
|
||
(setq select-active-regions nil)
|
||
(setq select-enable-clipboard 't)
|
||
(setq select-enable-primary nil)
|
||
(setq interprogram-cut-function #'gui-select-text)
|
||
)
|