537 lines
17 KiB
EmacsLisp
537 lines
17 KiB
EmacsLisp
;;; init --- Summary
|
||
|
||
;;; Commentary:
|
||
|
||
;;; Code:
|
||
|
||
(setq custom-file (concat user-emacs-directory "customizations.el"))
|
||
(load custom-file)
|
||
|
||
;; Initialize the package system and use-package
|
||
(setq load-prefer-newer t)
|
||
|
||
;; Add my own, version controlled ~lisp~ directory to ~load-path~
|
||
|
||
(add-to-list 'load-path (expand-file-name
|
||
(convert-standard-filename "lisp/")
|
||
user-emacs-directory))
|
||
|
||
;; Do the same with the local ~site-lisp~ if it’s there
|
||
|
||
(let ((site-lisp-dir "/usr/local/share/emacs/site-lisp"))
|
||
(when (file-directory-p site-lisp-dir)
|
||
(dolist (elt (directory-files site-lisp-dir))
|
||
(unless (or (string= elt ".") (string= elt ".."))
|
||
(add-to-list 'load-path (expand-file-name elt site-lisp-dir))))))
|
||
|
||
;; I prefer using freedesktop’s desktop specification everywhere
|
||
(load "xdg-paths")
|
||
|
||
;; Set up the package manager
|
||
|
||
;; Package archives
|
||
|
||
(require 'package)
|
||
|
||
;; GNU ELPA
|
||
(add-to-list 'package-archives '("gnu" . "https://elpa.gnu.org/packages/"))
|
||
;; MELPA Stable
|
||
(add-to-list 'package-archives '("melpa-stable" . "https://stable.melpa.org/packages/") t)
|
||
;; MELPA
|
||
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
|
||
|
||
;; Finally, initialise the package manager
|
||
(package-initialize)
|
||
|
||
;; use-package is a really convenient way to install packages. It’s installed in 30.1, but let’s stay on the safe side.
|
||
(unless (package-installed-p 'use-package)
|
||
(package-refresh-contents)
|
||
(package-install 'use-package))
|
||
(require 'use-package)
|
||
|
||
(use-package use-package
|
||
:custom
|
||
(use-package-always-ensure t)
|
||
(use-package-verbose nil))
|
||
|
||
(use-package bind-key)
|
||
|
||
;; Custom functions and commands
|
||
(load "gpolonkai/utilities")
|
||
(load "gpolonkai/windows")
|
||
(load "gpolonkai/org-utils")
|
||
(load "gpolonkai/text-utils")
|
||
(load "gpolonkai/nav-utils")
|
||
(load "gpolonkai/file-utils")
|
||
(load "gpolonkai/magit-utils")
|
||
|
||
(defun crm-indicator (args)
|
||
"Generate a prompt for `completing-read-multiple'.
|
||
|
||
ARGS is a cons cell of two strings, which will be used in the prompt in reverse
|
||
order."
|
||
(cons (format "[CRM%s] %s"
|
||
(replace-regexp-in-string
|
||
"\\`\\[.*?]\\*\\|\\[.*?]\\*\\'"
|
||
""
|
||
crm-separator)
|
||
(car args))
|
||
(cdr args)))
|
||
|
||
(use-package emacs
|
||
:ensure nil
|
||
:init
|
||
;; Required for Consult/Vertico
|
||
(advice-add #'completing-read-multiple :filter-args #'crm-indicator)
|
||
(setq frame-title-format
|
||
'((:eval (concat system-name
|
||
": "
|
||
(if (buffer-file-name)
|
||
(abbreviate-file-name (buffer-file-name))
|
||
"%b")))))
|
||
:custom
|
||
(user-full-name "Gergely Polonkai")
|
||
(user-mail-address "gergely@polonkai.eu")
|
||
(kill-read-only-ok t)
|
||
(use-dialog-box nil)
|
||
(cursor-type 'bar)
|
||
(echo-keystrokes .01)
|
||
(fill-column 120)
|
||
(initial-scratch-message "")
|
||
(minibuffer-prompt-properties '(read-only t cursor-intangible t face minibuffer-prompt))
|
||
(enable-recursive-minibuffers t)
|
||
(completion-cycle-threshold 3)
|
||
(tab-always-indent 'complete)
|
||
:hook
|
||
(minibuffer-setup . cursor-intangible-mode))
|
||
|
||
;; Basic settings
|
||
;;
|
||
;; Now that we have package management configured we can set up defaults more
|
||
;; easily. This includes every builtin packages, font faces, and the like.
|
||
|
||
;; Set Org’s main directory
|
||
;;
|
||
;; Since a lot of packages (org-projectile, org-caldav, etc.) rely on it, it
|
||
;; needs to be set as early as possible.
|
||
|
||
(setq org-directory (expand-file-name "~/Nextcloud/orgmode"))
|
||
|
||
;; Set up my personal keymap
|
||
|
||
(defvar gpolonkai/pers-map (make-sparse-keymap)
|
||
"My own, personal, keymap!")
|
||
(define-prefix-command 'gpolonkai/pers-map)
|
||
(define-key ctl-x-map "t" 'gpolonkai/pers-map)
|
||
(define-key global-map (kbd "C-t") 'gpolonkai/pers-map)
|
||
|
||
;; Set up some faces
|
||
|
||
(use-package faces
|
||
:ensure nil
|
||
:custom-face
|
||
(default ((t (:family "Fira Code Retina" :foundry "simp" :slant normal :weight normal :height 100 :width normal))))
|
||
(trailing-whitespace ((t (:inherit nil :background "red3")))))
|
||
|
||
;; Fira Code comes with nice ligatures, let’s use them!
|
||
|
||
(use-package ligature
|
||
:config
|
||
;; Enable the "www" ligature in every possible major mode
|
||
(ligature-set-ligatures 't '("www"))
|
||
;; Enable traditional ligature support in eww-mode, if the
|
||
;; `variable-pitch' face supports it
|
||
(ligature-set-ligatures 'eww-mode '("ff" "fi" "ffi"))
|
||
;; Enable all Cascadia and Fira Code ligatures in programming modes
|
||
(ligature-set-ligatures 'prog-mode
|
||
'(;; == === ==== => =| =>>=>=|=>==>> ==< =/=//=// =~
|
||
;; =:= =!=
|
||
("=" (rx (+ (or ">" "<" "|" "/" "~" ":" "!" "="))))
|
||
;; ;; ;;;
|
||
(";" (rx (+ ";")))
|
||
;; && &&&
|
||
("&" (rx (+ "&")))
|
||
;; !! !!! !. !: !!. != !== !~
|
||
("!" (rx (+ (or "=" "!" "\." ":" "~"))))
|
||
;; ?? ??? ?: ?= ?.
|
||
("?" (rx (or ":" "=" "\." (+ "?"))))
|
||
;; %% %%%
|
||
("%" (rx (+ "%")))
|
||
;; |> ||> |||> ||||> |] |} || ||| |-> ||-||
|
||
;; |->>-||-<<-| |- |== ||=||
|
||
;; |==>>==<<==<=>==//==/=!==:===>
|
||
("|" (rx (+ (or ">" "<" "|" "/" ":" "!" "}" "\]"
|
||
"-" "=" ))))
|
||
;; \\ \\\ \/
|
||
("\\" (rx (or "/" (+ "\\"))))
|
||
;; ++ +++ ++++ +>
|
||
("+" (rx (or ">" (+ "+"))))
|
||
;; :: ::: :::: :> :< := :// ::=
|
||
(":" (rx (or ">" "<" "=" "//" ":=" (+ ":"))))
|
||
;; // /// //// /\ /* /> /===:===!=//===>>==>==/
|
||
("/" (rx (+ (or ">" "<" "|" "/" "\\" "\*" ":" "!"
|
||
"="))))
|
||
;; .. ... .... .= .- .? ..= ..<
|
||
("\." (rx (or "=" "-" "\?" "\.=" "\.<" (+ "\."))))
|
||
;; -- --- ---- -~ -> ->> -| -|->-->>->--<<-|
|
||
("-" (rx (+ (or ">" "<" "|" "~" "-"))))
|
||
;; *> */ *) ** *** ****
|
||
("*" (rx (or ">" "/" ")" (+ "*"))))
|
||
;; www wwww
|
||
("w" (rx (+ "w")))
|
||
;; <> <!-- <|> <: <~ <~> <~~ <+ <* <$ </ <+> <*>
|
||
;; <$> </> <| <|| <||| <|||| <- <-| <-<<-|-> <->>
|
||
;; <<-> <= <=> <<==<<==>=|=>==/==//=!==:=>
|
||
;; << <<< <<<<
|
||
("<" (rx (+ (or "\+" "\*" "\$" "<" ">" ":" "~" "!"
|
||
"-" "/" "|" "="))))
|
||
;; >: >- >>- >--|-> >>-|-> >= >== >>== >=|=:=>>
|
||
;; >> >>> >>>>
|
||
(">" (rx (+ (or ">" "<" "|" "/" ":" "=" "-"))))
|
||
;; #: #= #! #( #? #[ #{ #_ #_( ## ### #####
|
||
("#" (rx (or ":" "=" "!" "(" "\?" "\[" "{" "_(" "_"
|
||
(+ "#"))))
|
||
;; ~~ ~~~ ~= ~- ~@ ~> ~~>
|
||
("~" (rx (or ">" "=" "-" "@" "~>" (+ "~"))))
|
||
;; __ ___ ____ _|_ __|____|_
|
||
("_" (rx (+ (or "_" "|"))))
|
||
;; Fira code: 0xFF 0x12
|
||
("0" (rx (and "x" (+ (in "A-F" "a-f" "0-9")))))
|
||
;; Fira code:
|
||
"Fl" "Tl" "fi" "fj" "fl" "ft"
|
||
;; The few not covered by the regexps.
|
||
"{|" "[|" "]#" "(*" "}#" "$>" "^="))
|
||
;; Enables ligature checks globally in all buffers. You can also do it
|
||
;; per mode with `ligature-mode'.
|
||
(global-ligature-mode t))
|
||
|
||
;; Set the default font and configure font resizing
|
||
|
||
;; Before this can be used, make sure the Symbola font
|
||
;; (https://zhm.github.io/symbola/) font is installed.
|
||
|
||
(defun gpolonkai/set-font-size (frame)
|
||
"Set default fonts and font sizes in FRAME."
|
||
(when (display-graphic-p frame)
|
||
(set-face-attribute 'default frame :font "Fira Code Retina-10")
|
||
(set-frame-font "Fira Code Retina-10" t (list frame))))
|
||
|
||
(defun --set-emoji-font (frame)
|
||
"Adjust the font setting of FRAME so Emacs can display Emoji properly."
|
||
(when (display-graphic-p frame)
|
||
(set-fontset-font t 'symbol
|
||
(font-spec :family "Symbola")
|
||
frame 'prepend)
|
||
(set-fontset-font t 'unicode
|
||
"Noto Emoji"
|
||
nil 'append)))
|
||
|
||
(add-hook 'after-make-frame-functions 'gpolonkai/set-font-size)
|
||
(add-hook 'after-make-frame-functions '--set-emoji-font)
|
||
|
||
(gpolonkai/set-font-size nil)
|
||
(--set-emoji-font nil)
|
||
|
||
;; Set UTF-8 as the default encoding
|
||
(set-language-environment "UTF-8")
|
||
(set-default-coding-systems 'utf-8)
|
||
|
||
(use-package frame
|
||
:ensure nil
|
||
:custom
|
||
(blink-cursor-mode t))
|
||
|
||
;; I really don’t want to type more than i really must…
|
||
|
||
(defalias 'yes-or-no-p 'y-or-n-p)
|
||
|
||
;; Tweak window chrome, AKA let’s set up the UI!
|
||
|
||
;; Turn off the toolbar
|
||
(tool-bar-mode 0)
|
||
;; Turn off the menu bar
|
||
(menu-bar-mode 0)
|
||
|
||
;; If we are running in a graphical environment, turn off the scroll bar
|
||
;;
|
||
;; TODO: This is not done for every new frame!
|
||
(when window-system
|
||
(scroll-bar-mode -1))
|
||
|
||
;; Maximise newly created frames (AKA DE windows)
|
||
(set-frame-parameter nil 'fullscreen 'maximized)
|
||
|
||
;; Enable all the commands! These are disabled for a reason, but i’m a rockstar,
|
||
;; so who cares‽
|
||
;;
|
||
;; TODO: There must be a way to do it programatically
|
||
(put 'downcase-region 'disabled nil)
|
||
(put 'upcase-region 'disabled nil)
|
||
(put 'erase-buffer 'disabled nil)
|
||
(put 'narrow-to-region 'disabled nil)
|
||
(put 'narrow-to-page 'disabled nil)
|
||
(put 'set-goal-column 'disabled nil)
|
||
(put 'scroll-left 'disabled nil)
|
||
(put 'dired-find-alternate-file 'disabled nil)
|
||
(put 'Info-edit 'disabled nil)
|
||
(put 'list-timers 'disabled nil)
|
||
|
||
;; simple to always show the current column, and using visual lines in text
|
||
;; modes
|
||
|
||
(use-package simple
|
||
:ensure nil
|
||
:custom
|
||
(column-number-mode t)
|
||
:hook
|
||
(text-mode . (lambda () (visual-line-mode t))))
|
||
|
||
(use-package prog-mode
|
||
:ensure nil
|
||
:init
|
||
(setq prettify-symbols-alist
|
||
'(("lambda" . ?λ)
|
||
("function" . ?ƒ)
|
||
("map" . ?↦)
|
||
("not" . ?¬)
|
||
("and" . ?∧)
|
||
("or" . ?∨)))
|
||
:config
|
||
(global-prettify-symbols-mode t))
|
||
|
||
(use-package thingatpt
|
||
:ensure nil)
|
||
|
||
(use-package nxml-mode
|
||
:ensure nil
|
||
:custom
|
||
(nxml-attribute-indent 4)
|
||
(nxml-child-indent 4)
|
||
(nxml-outline-child-indent 4))
|
||
|
||
(use-package recentf
|
||
:ensure nil
|
||
:config
|
||
(run-at-time nil (* 5 60) 'recentf-save-list)
|
||
(add-to-list 'recentf-exclude (expand-file-name "elpa" user-emacs-directory)))
|
||
|
||
(use-package files
|
||
:ensure nil
|
||
:custom
|
||
(make-backup-file-name-function 'xah/backup-file-name))
|
||
|
||
(defun prevent-whitespace-mode-for-some ()
|
||
"Prevent `whitespace-mode' from running in some modes."
|
||
(and
|
||
(not (derived-mode-p 'magit-mode))
|
||
(not (derived-mode-p 'org-mode))))
|
||
|
||
(use-package whitespace
|
||
:demand
|
||
:config
|
||
(add-function :before-while whitespace-enable-predicate 'prevent-whitespace-mode-for-some)
|
||
(global-whitespace-mode 1)
|
||
:custom
|
||
(whitespace-line-column 120)
|
||
:bind
|
||
(([f10] . whitespace-mode)
|
||
([(shift f10)] . global-whitespace-mode)
|
||
:map gpolonkai/pers-map
|
||
("w" . whitespace-cleanup))
|
||
:custom-face
|
||
(whitespace-line ((t (:inherit nil :background "orange4")))))
|
||
|
||
;; Taken from https://ryuslash.org/posts/C-d-to-close-eshell.html
|
||
|
||
(defun eshell-C-d ()
|
||
"Either call `delete-char' interactively or quit."
|
||
(interactive)
|
||
|
||
(condition-case err
|
||
(call-interactively #'delete-char)
|
||
(error (if (and (eq (car err) 'end-of-buffer)
|
||
(looking-back eshell-prompt-regexp nil))
|
||
(kill-buffer)
|
||
(signal (car err) (cdr err))))))
|
||
|
||
(defun gpolonkai/eshell-set-c-d-locally ()
|
||
"Bind my `eshell-C-d' function locally."
|
||
(local-set-key (kbd "C-d") #'eshell-C-d))
|
||
|
||
;; Taken from https://blog.hoetzel.info/post/eshell-notifications/
|
||
|
||
(defun eshell-command-alert (process status)
|
||
"Send `alert' with severity based on STATUS when PROCESS finished."
|
||
(let* ((cmd (process-command process))
|
||
(buffer (process-buffer process))
|
||
(msg (format "%s: %s" (mapconcat 'identity cmd " ") status)))
|
||
(if (string-prefix-p "finished" status)
|
||
(alert msg :buffer buffer :severity 'normal)
|
||
(alert msg :buffer buffer :severity 'urgent))))
|
||
|
||
(use-package eshell
|
||
:bind
|
||
(:map gpolonkai/pers-map
|
||
("e" . eshell))
|
||
:hook
|
||
(eshell-mode . gpolonkai/eshell-set-c-d-locally)
|
||
(eshell-kill . eshell-command-alert))
|
||
|
||
(use-package calendar
|
||
:ensure nil
|
||
:custom
|
||
(calendar-week-start-day 1))
|
||
|
||
(use-package cal-dst
|
||
:ensure nil
|
||
:custom
|
||
(calendar-time-zone 60)
|
||
(calendar-standard-time-zone-name "CET")
|
||
(calendar-daylight-time-zone-name "CEST"))
|
||
|
||
(use-package solar
|
||
:ensure nil
|
||
:custom
|
||
(calendar-latitude 47.4)
|
||
(calendar-longitude 19.0)
|
||
(calendar-location-name "Budapest, Hungary"))
|
||
|
||
;; TODO: This :config call can be omitted if i add it to the calendar-load-hook
|
||
(use-package hungarian-holidays
|
||
:config
|
||
(hungarian-holidays-add))
|
||
|
||
(add-to-list 'holiday-other-holidays '(holiday-float 7 5 -1 "SysAdmin Day") t)
|
||
(add-to-list 'holiday-other-holidays '(holiday-fixed 10 21 "Reptile Awareness Day") t)
|
||
|
||
(use-package saveplace
|
||
:ensure nil
|
||
:config
|
||
(save-place-mode 1)
|
||
:custom
|
||
(save-place-file (expand-file-name ".places" user-emacs-directory)))
|
||
|
||
(use-package ediff
|
||
:ensure nil
|
||
:custom
|
||
(ediff-merge-split-window-function 'split-window-horizontally)
|
||
(ediff-split-window-function 'split-window-vertically)
|
||
(ediff-window-setup-function 'ediff-setup-windows-plain))
|
||
|
||
(use-package autorevert
|
||
:ensure nil
|
||
:config
|
||
(global-auto-revert-mode 1))
|
||
|
||
(use-package eww
|
||
:custom
|
||
(eww-search-prefix "https://duckduckgo.com/html/?q="))
|
||
|
||
;; TODO: This :config call can be omitted if i add it to prog-mode-hook
|
||
(use-package electric
|
||
:config
|
||
;; This seems to be the default, but let’s make sure…
|
||
(electric-indent-mode 1))
|
||
|
||
(use-package savehist
|
||
:config
|
||
(savehist-mode 1))
|
||
|
||
(use-package webjump
|
||
:bind
|
||
(:map gpolonkai/pers-map
|
||
("j" . webjump)))
|
||
|
||
(defun gpolonkai/activate-which-func-mode ()
|
||
"Activate `which-func-mode' if it exists."
|
||
(if (fboundp 'which-function-mode)
|
||
(which-function-mode)
|
||
(which-func-mode)))
|
||
|
||
;; This :config call can be omitted if i add it to which-function-mode-hook
|
||
(use-package which-func
|
||
:config
|
||
(setq which-func-unknown "∅")
|
||
:hook
|
||
(prog-mode . gpolonkai/activate-which-func-mode))
|
||
|
||
;; “Fortunes” are from the Hungarian version an ancient MS-DOS based program called TAGLINE
|
||
|
||
(use-package cookie1
|
||
:demand t
|
||
:custom
|
||
(cookie-file (expand-file-name "fortune-cookies.txt" user-emacs-directory))
|
||
:bind
|
||
(:map gpolonkai/pers-map
|
||
("k" . cookie)))
|
||
|
||
(use-package dired
|
||
:ensure nil
|
||
:custom
|
||
(dired-dwim-target t)
|
||
(wdired-create-parent-directories t)
|
||
(wdired-allow-to-change-permissions t)
|
||
:bind
|
||
(:map dired-mode-map
|
||
("RET" . dired-find-alternate-file)
|
||
("^" . (lambda () (interactive) (find-alternate-file "..")))
|
||
("W" . wdired-change-to-wdired-mode)))
|
||
|
||
(use-package goto-addr
|
||
:hook ((compilation-mode . goto-address-mode)
|
||
(prog-mode . goto-address-prog-mode)
|
||
(eshell-mode . goto-address-mode)
|
||
(shell-mode . goto-address-mode))
|
||
:bind
|
||
(:map goto-address-highlight-keymap
|
||
("<RET>" . goto-address-at-point)
|
||
("M-<RET>" . newline))
|
||
:commands (goto-address-prog-mode goto-address-mode))
|
||
|
||
;; Close unused buffers at midnight.
|
||
(use-package midnight
|
||
:ensure nil
|
||
:custom
|
||
(clean-buffer-list-kill-never-buffer-names '("*scratch*"
|
||
"*Messages*"
|
||
"*dashboard*"))
|
||
:config
|
||
(midnight-mode t))
|
||
|
||
(use-package display-line-numbers
|
||
:bind
|
||
(:map gpolonkai/pers-map
|
||
("C-n" . display-line-numbers-mode)))
|
||
|
||
(use-package ispell
|
||
:custom
|
||
(ispell-dictionary "en_GB")
|
||
(ispell-program-name "/usr/bin/hunspell")
|
||
:hook
|
||
(mail-send . ispell-message)
|
||
(message-send . ispell-message))
|
||
|
||
(use-package speedbar)
|
||
|
||
;; A Termux-specific override for `browse-url'
|
||
(when (gpolonkai/termux-p)
|
||
(use-package browse-url
|
||
:ensure nil
|
||
:config
|
||
(advice-add 'browse-url-default-browser :override
|
||
(lambda (url &rest args)
|
||
(start-process-shell-command
|
||
"open-url"
|
||
nil
|
||
(concat "am start -a android.intent.action.VIEW --user 0 -d "
|
||
url))))))
|
||
|
||
(use-package dabbrev
|
||
:bind (("M-/" . dabbrev-completion)
|
||
("C-M-/" . dabbrev-expand)))
|
||
|
||
;; I started moving my configuration to this Org file. It’s easier to document this way.
|
||
(org-babel-load-file (expand-file-name "configuration.org" user-emacs-directory))
|
||
|
||
;;; init.el ends here
|