From fca7618b90f30603a54205c76be996322d412cb0 Mon Sep 17 00:00:00 2001 From: phga Date: Sat, 26 Apr 2025 23:18:35 +0200 Subject: [PATCH] init: A "minimal" config for Emacs --- .gitignore | 27 ++++ cnf/additionals.el | 136 +++++++++++++++++++ cnf/app/a-dired.el | 83 ++++++++++++ cnf/app/a-orgmode.el | 274 ++++++++++++++++++++++++++++++++++++++ cnf/essentials.el | 151 +++++++++++++++++++++ cnf/functions.el | 20 +++ cnf/global-keybindings.el | 96 +++++++++++++ cnf/ui.el | 146 ++++++++++++++++++++ early-init.el | 23 ++++ init.el | 31 +++++ 10 files changed, 987 insertions(+) create mode 100644 .gitignore create mode 100644 cnf/additionals.el create mode 100644 cnf/app/a-dired.el create mode 100644 cnf/app/a-orgmode.el create mode 100644 cnf/essentials.el create mode 100644 cnf/functions.el create mode 100644 cnf/global-keybindings.el create mode 100644 cnf/ui.el create mode 100644 early-init.el create mode 100644 init.el diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..62e1643 --- /dev/null +++ b/.gitignore @@ -0,0 +1,27 @@ +* +# This one is new to allow directories by default +!*/ + +# Straight specific +/straight/repos +/straight/build +!/straight/versions/* + +# Allow to WL subdirs +!/.gitignore +!cnf/ +!cnf/** +!local-pkgs/ +!local-pkgs/** +!snippets/ +!snippets/** +!plugins +!init.el +!early-init.el +!ec.sh +!minimal.el +!test/ +!test/** + +# Ignore again +# *~undo-tree~ \ No newline at end of file diff --git a/cnf/additionals.el b/cnf/additionals.el new file mode 100644 index 0000000..25cdba1 --- /dev/null +++ b/cnf/additionals.el @@ -0,0 +1,136 @@ +(push (concat user-emacs-directory "cnf/app") load-path) +;; DIRED: file browser +(require 'a-dired) + +;; ORD-MODE: Basically jupiter notebooks/markdown on steroids +(with-eval-after-load 'org (require 'a-orgmode)) + +;; MAGIT: A nice git frontend +(straight-use-package 'magit) +(setq magit-bury-buffer-function #'quit-window + magit-display-buffer-function #'display-buffer) + +(with-eval-after-load 'magit + (transient-append-suffix 'magit-push "-u" + '(1 "=s" "Skip gitlab pipeline" "--push-option=ci.skip")) + (transient-append-suffix 'magit-push "=s" + '(1 "=D" "DEBUG" "--push-option=ci.variable=DEBUG=1")) ;; no special meaning for gitlab + (transient-append-suffix 'magit-push "=D" + '(1 "=V" "Set CI variable" "--push-option=ci.variable=")) ;; Will prompt, can only set one extra variable + (transient-append-suffix 'magit-push "=V" + '(1 "=O" "Set push option" "--push-option=")) + ) + +;; DICTCC: query dict.cc without leaving emacs +(straight-use-package 'dictcc) + +;; GIT-GUTTER: Indicators for git status inside the fringe +(straight-use-package 'git-gutter) +(straight-use-package 'git-gutter-fringe) +(require 'git-gutter-fringe) +;; 0 means only update on save, otherwise set to 0.02 +;; otherwise cursor stutters (e.g. at 2 or 8) +(setq git-gutter:update-interval 0 + git-gutter:handled-backends '(git hg)) + +;; Indicator style (It's ASCII art - yaayyy) +(fringe-helper-define 'git-gutter-fr:added 'center + "..XXX.." + "..XXX.." + "..XXX.." + "..XXX.." + "..XXX.." + "..XXX.." + "..XXX.." + "..XXX.." + "..XXX..") + +(fringe-helper-define 'git-gutter-fr:modified 'center + "..XXX.." + "..XXX.." + "..XXX.." + "..XXX.." + "..XXX.." + "..XXX.." + "..XXX.." + "..XXX.." + "..XXX..") + +(fringe-helper-define 'git-gutter-fr:deleted 'center + "..XXX.." + "..XXX.." + "..XXX.." + "..XXX.." + "..XXX.." + "..XXX.." + "..XXX.." + "..XXX.." + "..XXX..") + +(add-hook 'prog-mode-hook #'git-gutter-mode) + +;; More sane defaults +(defvar emacs-autosave-directory + (concat user-emacs-directory "autosaves/")) +(unless (file-exists-p emacs-autosave-directory) + (mkdir emacs-autosave-directory t)) + +(setq backup-directory-alist + `((".*" . ,emacs-autosave-directory)) + auto-save-file-name-transforms + `((".*" ,emacs-autosave-directory t))) + +(setq make-backup-files nil + create-lockfiles nil) + +;; There is also require-final-newline which is a per mode setting +;; This seems to override this global value -> See mode specific configs (e.g. yaml) +(setq-default require-final-newline t) +(setq mode-require-final-newline t) + +(setq warning-minimum-level :emergency) + +(defalias 'yes-or-no-p 'y-or-n-p) +(setq read-answer-short t) +;; Advice around the new kill-buffer--possibly-save function +;; This never calls the original function which basically replaces it +;; defalias is not possible here since this takes different arguments +(defun phga/kill-buffer-y-or-n--advice (orig-fun buffer &rest args) + "Replace the default behavior of the new `kill-buffer--possibly-save' function. +`ORIG-FUN' is the original function that was called and +`BUFFER'is the buffer that should be killed whilst beeing +modified and not saved. `ARGS' is the rest of the arguments." + (y-or-n-p (concat "Kill buffer " (buffer-name buffer) " without saving?"))) + +(advice-add 'kill-buffer--possibly-save :around #'phga/kill-buffer-y-or-n--advice) + +(setq auto-revert-interval 1 ; Refresh buffers fast + echo-keystrokes 0.1 ; Show keystrokes asap + inhibit-startup-message t ; No splash screen please + initial-scratch-message nil ; Clean scratch buffer + initial-major-mode 'org-mode + recentf-max-saved-items 100 ; Show more recent files + ring-bell-function 'ignore) ; Quiet + +(setq mouse-yank-at-point t) + +;; Should help with reeeeally long lines e.g. json +;; there is also (setq-default bidi-display-reordering nil) +;; which is apparently not recommended by dev Eli because +;; it was never intended to be nil (could still improve things tho) +(setq-default bidi-paragraph-direction 'left-to-right) +;; gnupg +(require 'epa-file) +(setq epg-pinentry-mode 'ask) +(push '("\\.gpg\\'" . epa-file-enable) auto-mode-alist) +;; only use the encrypted version of .authinfo +(setq auth-sources '("~/.authinfo.gpg")) + +;; save unsaved buffers before killing frame +(add-hook 'delete-frame-functions 'save-some-buffers) +(add-hook 'kill-emacs-hook 'save-some-buffers) + +;; Width used to draw the column indicator + used in fill-paragraph +(setq-default fill-column 90) + +(provide 'additionals) \ No newline at end of file diff --git a/cnf/app/a-dired.el b/cnf/app/a-dired.el new file mode 100644 index 0000000..5229c0b --- /dev/null +++ b/cnf/app/a-dired.el @@ -0,0 +1,83 @@ +;; DIRED: Filebrowser +(straight-use-package 'dired-narrow) +;; (require 'dired-async) +;; (dired-async-mode 0) +(setq dired-listing-switches "-lFahv --group-directories-first" + dired-dwim-target t + delete-by-moving-to-trash t + dired-ls-F-marks-symlinks t + dired-compress-files-alist '(("\\.tar\\.gz\\'" . "tar -cf - %i | gzip -c9 > %o") + ("\\.tar\\.bz2\\'" . "tar -cf - %i | bzip2 -c9 > %o") + ("\\.tar\\.xz\\'" . "tar -cf - %i | xz -c9 > %o") + ("\\.tar\\.zst\\'" . "tar -cf - %i | zstd -19 -o %o") + ("\\.tar\\.lz\\'" . "tar -cf - %i | lzip -c9 > %o") + ("\\.tar\\.lzo\\'" . "tar -cf - %i | lzop -c9 > %o") + ("\\.zip\\'" . "zip %o -r --filesync %i") + ("\\.pax\\'" . "pax -wf %o %i")) + dired-compress-file-suffixes '(("\\.tar\\.gz\\'" #1="" "gzip -dc %i | tar -xf -") + ("\\.tar\\.xz\\'" #1# "xz -dc %i | tar -xf -") + ("\\.tgz\\'" #1# "gzip -dc %i | tar -xf -") + ("\\.gz\\'" #1# "gzip -d") + ("\\.lz\\'" #1# "lzip -d") + ("\\.Z\\'" #1# "uncompress") + ("\\.z\\'" #1# "gzip -d") + ("\\.dz\\'" #1# "dictunzip") + ("\\.tbz\\'" ".tar" "bunzip2") + ("\\.bz2\\'" #1# "bunzip2") + ("\\.xz\\'" #1# "unxz") + ("\\.zip\\'" #1# "7z x -aoa -o%o %i") + ("\\.tar\\.zst\\'" #1# "unzstd -c %i | tar -xf -") + ("\\.tzst\\'" #1# "unzstd -c %i | tar -xf -") + ("\\.zst\\'" #1# "unzstd --rm") + ("\\.7z\\'" #1# "7z x -aoa -o%o %i") + ("\\.tar\\'" ".tgz" nil))) + +(add-hook 'dired-mode-hook + (lambda () + (dired-hide-details-mode) + (when (file-remote-p dired-directory) + (setq-local dired-actual-switches "-lFah")))) + +(put 'dired-find-alternate-file 'disabled nil) + +;; ;; PEEP-DIRED: preview files in dired +;; (straight-use-package 'peep-dired) +;; ;; variables +;; (setq peep-dired-cleanup-on-disable t +;; peep-dired-cleanup-eagerly nil +;; peep-dired-enable-on-directories t) +;; ;; hooks +;; (add-hook 'peep-dired-hook 'evil-normalize-keymaps) +(straight-use-package 'dired-preview) +(setq dired-preview-delay 0.2 + dired-preview-ignored-extensions-regexp (concat "\\." + "\\(mkv\\|webm\\|mp4\\|mp3\\|ogg\\|m4a" + "\\|gz\\|zst\\|tar\\|xz\\|rar\\|zip" + "\\|iso\\|epub\\)")) + +;; Keybindings +(general-def + :states 'normal + :keymaps 'dired-mode-map + "f" 'dired-narrow + "p" 'dired-preview-mode + "h" (lambda() (interactive) (find-alternate-file "..")) + "l" (lambda() (interactive) (dired-find-alternate-file))) + +;; DIRED-LAUNCH: Launch apps depending on file extension +(straight-use-package 'dired-launch) +(setq dired-launch-command '("xdg-open")) +(setf dired-launch-extensions-map + '(;; xml files with bpmn in it + ("xopp" ("xournalpp")) + ("drawio.html" ("drawio")) + ("drawio" ("drawio")))) + +(add-hook 'dired-mode-hook + (lambda () + (general-def + :states 'normal + :keymaps 'dired-mode-map + "W" 'dired-launch-command))) + +(provide 'a-dired) \ No newline at end of file diff --git a/cnf/app/a-orgmode.el b/cnf/app/a-orgmode.el new file mode 100644 index 0000000..848ba50 --- /dev/null +++ b/cnf/app/a-orgmode.el @@ -0,0 +1,274 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; NOTE: org-mode is required in essentials.el so we use the git instead of the shipped version ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; HTMLIZE: html export for orgmode +(straight-use-package 'htmlize) + +;; There was a long discussion on reddit that this package slows +;; down the redisplay optimizations of emacs +;; https://old.reddit.com/r/emacs/comments/p9yjgq/turn_off_fontlock_under_cursor/ha6zor6/ +;; ORG-APPEAR: shows emphasis symbols when required +(straight-use-package 'org-appear) +(setq org-appear-autolinks nil ;;'just-brackets + org-appear-autosubmarkers t + org-appear-autoentities t + org-appear-autokeywords t + org-appear-inside-latex t) +(add-hook 'org-mode-hook 'org-appear-mode) + +;; ORG-DOWNLOAD: insert screenshots on the fly +(straight-use-package 'org-download) +(require 'org-download) + +;; OB-GO: Org babel support for go +(straight-use-package 'ob-go) +;; (with-eval-after-load 'ob-go (require 'l-go)) ;; enable highlighting, etc + +;; EVIL-ORG: more org bindings +(straight-use-package 'evil-org) +(add-hook 'org-mode-hook 'evil-org-mode) +(with-eval-after-load 'org-mode + (evil-org-set-key-theme '(navigation insert textobjects additional calendar))) + +;; ORG-SRC: Load language specific configs when fontifying src blocks for languages which +;; configs are dynamically loaded and not present at the time of the fontification process +;; (defun phga/advice-load-config-for-org-src-block-language (lang start end) +;; "Look in `load-path' for a file that provides the feature l-LANG. +;; LANG is the language used by `org-src-font-lock-fontify-block'. +;; START and END are not used by this advice" +;; (ignore-errors (require (intern (concat "l-" lang))))) + +;; (advice-add 'org-src-font-lock-fontify-block +;; :before #'phga/advice-load-config-for-org-src-block-language) + +(defvar phga/org-export-directory) +(defun phga/advice-create-and-set-org-export-directory (f extension + &optional subtreep pub-dir) + "Create and set `phga/org-export-directory' which is used as PUB-DIR in F. +F is `org-export-output-file-name' SUBTREEP and EXTENSION are not +modified here." + (let ((pub-dir (or pub-dir (and (boundp 'phga/org-export-directory) + phga/org-export-directory)))) + (unless (file-directory-p pub-dir) + (make-directory phga/org-export-directory)) + (apply f extension subtreep pub-dir '()))) ;; '() is required by apply + +(advice-add 'org-export-output-file-name :around #'phga/advice-create-and-set-org-export-directory) + +(setq phga/org-export-directory "./auto") + +(evil-set-initial-state 'org-agenda-mode 'normal) +(add-to-list 'org-export-backends 'md) +(setq org-agenda-tags-column org-tags-column + org-babel-min-lines-for-block-output 50 + org-confirm-babel-evaluate nil + ;; Since ORG-Mode 9.1.9 functions inside of (file "FILENAME") are no longer + ;; evaluated if the template list is prefixed with ' + ;; Solution: use ` to prefix list and ,(concat) to indicate req. evaluation + org-duration-format 'h:mm + + ;; TODO: If you want latex support + ;; Latex + ;; org-latex-listings 'minted + ;; org-latex-listings nil + ;; org-latex-packages-alist '(("outputdir=auto" "minted")) + ;; org-latex-inputenc-alist '(("utf8" . "utf8x")) + ;; org-latex-prefer-user-labels t + ;; org-latex-pdf-process + ;; '("pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f" + ;; "pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f" + ;; "pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f") + + ;; Export Config + org-export-preserve-breaks nil + org-export-with-email t + org-export-with-sub-superscripts t + org-export-in-background nil + org-html-htmlize-output-type 'inline-css + + ;; REQUIRES: y -S plantuml graphviz + ;; org-plantuml-jar-path (expand-file-name "/usr/share/java/plantuml/plantuml.jar") + + ;; Visuals like nice looking headings, fontification (bold, italic, etc.) + org-pretty-entities t + org-pretty-entities-include-sub-superscripts t + org-edit-src-content-indentation 0 + org-src-fontify-natively t + org-src-tab-acts-natively t + org-src-preserve-indentation t + org-src-window-setup 'current-window + org-use-sub-superscripts '{} + org-ellipsis " ↷" + org-cycle-separator-lines 0 + org-hide-emphasis-markers t + + ;; Sane defaults when opening new files + org-startup-folded nil + org-startup-with-inline-images t + org-startup-with-latex-preview t + org-image-actual-width nil + + org-blank-before-new-entry '((heading . t) + (plain-list-item . nil)) + + ;; Tags + org-tags-column 60 + org-fast-tag-selection-include-todo t + org-fast-tag-selection-single-key 'expert + + ;; Todos + org-todo-keywords + '((sequence "TODO(t)" "|" "DONE(d)") + (type "NEXT(n)") + (type "MEET(m)") + (type "IDEA(i)")) + ;; '((type "TODO") + ;; ;; (type "DONE") + ;; (type "NEXT") + ;; (type "IDEA") + ;; (type "MEET") + ;; (sequence "TODO(t)" "NEXT(n)" "|" "DONE(d)") + ;; (sequence "IDEA(i)" "|" "TODO(t)") + ;; ) + org-todo-keyword-faces + '(("TODO" :inherit org-todo :weight bold) + ("DONE" :inherit org-done :weight bold) + ("NEXT" :weight bold) + ("MEET" :weight bold) + ("IDEA" :foreground "#cea7f0" :weight bold)) + org-use-fast-todo-selection t + org-fontify-todo-headline nil + org-fontify-done-headline nil) + +;; leads to unwanted buffer visits on first clock-in +;; Probably because it tries to scan for clocks in all agenda files +;; org-agenda-files (list org-directory) + +;; org-latex-listings 'listings + +;; Pretty bullet points +(font-lock-add-keywords + 'org-mode + '(("^ *\\(-\\) " ; change '-' into a unicode bullet + (0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "•")))))) + +(font-lock-add-keywords + 'org-mode + '(("^ *\\(\\+\\) " ; change '+' into a unicode bullet + (0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "◦")))))) + +;; Get rid of the ,* in code blocks (visually) +(font-lock-add-keywords + 'org-mode + '(("^ *\\(,\\*\\).*" ; change ',*' into * + (0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "*")))))) + +(add-hook 'org-babel-after-execute-hook 'org-redisplay-inline-images) +;; Scale of the latex fragments +;; (plist-put org-format-latex-options :scale 1.3) ;; b4 presentation +(plist-put org-format-latex-options :scale 2.5) + +;; Run/highlight code using babel in org-mode +;; Languages: https://orgmode.org/worg/org-contrib/babel/languages/index.html +(setq org-babel-load-languages + '((emacs-lisp . t) + (lisp . t) + (python . t) + (js . t) + (java . t) + (C . t) + (sql . t) + (calc . t) + (perl . t) + (shell . t) + (plantuml . t) + (haskell . t) + (go . t))) + +(org-babel-do-load-languages 'org-babel-load-languages org-babel-load-languages) + +;; TODO: If you want custom css in your html exports +;; export html with styles +;; (defvar org-style-css "~/sync/mvtn/setup/org.css") + +;; (defun my-org-inline-css-hook (exporter) +;; "Insert custom inline css" +;; (when (eq exporter 'html) +;; (let* ((dir (ignore-errors (file-name-directory (buffer-file-name)))) +;; (path (concat dir "style.css")) +;; (homestyle (or (null dir) (null (file-exists-p path)))) +;; (final (if homestyle org-style-css path))) ;; <- set your own style file path +;; (setq org-html-head-include-default-style nil) +;; (setq org-html-head (concat +;; "\n"))))) + +;; (add-hook 'org-export-before-processing-hook 'my-org-inline-css-hook) + +;; (setq org-html-htmlize-font-prefix "org-") ; default: "org-" + +;; TODO: If you want to manage your time with org-mode +;; ORG-CLOCK +;; (setq org-clock-history-length 23 +;; org-clock-in-resume t +;; org-drawers '("PROPERTIES" "LOGBOOK") +;; org-clock-into-drawer t +;; org-clock-out-remove-zero-time-clocks t +;; org-clock-out-when-done t +;; org-clock-persist 'history +;; org-clock-persist-query-resume nil +;; org-clock-auto-clock-resolution 'when-no-clock-is-running +;; org-clock-report-include-clocking-task t) + +;; (org-clock-persistence-insinuate) + +;; ORG-AGENDA +;; (defvar org-agenda-window-setup) +;; (setq org-agenda-window-setup 'current-window) + +;; ORG-DOWNLOAD +;; TODO: Setup for seemless insertion of screenshots +(setq org-download-screenshot-file "~/sync/screenshots/tmp/orgcapture.png" + org-download-screenshot-method "grim -g $(slurp -b '#000000a0' -c '#00000000') -o %s" + org-download-image-attr-list '("#+ATTR_ORG: :width 600") + org-download-annotate-function (lambda(link) "")) +(setq-default org-download-image-dir "./ORGPICS" + +;; KEYBINDINGS +(my-leader + :states 'normal + :definer 'minor-mode + :keymaps 'org-src-mode + "'" 'org-edit-src-exit) + +(my-leader + :states '(normal visual) + :keymaps 'org-mode-map + "'" 'org-edit-src-code + "SPC p" 'fill-paragraph + "SPC i" '(:ignore t :which-key "Insert") + "SPC i s" 'org-download-screenshot + "SPC i t" 'org-todo + "SPC i l" 'org-insert-link + "SPC s l" 'org-store-link + "SPC t" '(:ignore t :which-key "Toggle") + "SPC t i" 'org-toggle-inline-images + "SPC t l" 'org-latex-preview + ;; "SPC c" '(:ignore t :which-key "C Funktions (clock, execute)") + ;; "SPC c i" 'org-clock-in + ;; "SPC c o" 'org-clock-out + ;; "SPC c l" 'org-clock-in-last + "SPC c c" 'org-babel-execute-src-block + "SPC r" '(:ignore t :which-key "Remove") + "SPC r r" 'org-babel-remove-result + "SPC r a" (lambda () (interactive) (org-babel-remove-result-one-or-many t)) + "SPC o" 'org-open-at-point + "SPC e" 'org-export-dispatch) + +(provide 'a-orgmode) diff --git a/cnf/essentials.el b/cnf/essentials.el new file mode 100644 index 0000000..13defa6 --- /dev/null +++ b/cnf/essentials.el @@ -0,0 +1,151 @@ +;; ENVIRONMENT +;; COMPAT +(straight-use-package 'compat) + +;; ORG-MODE: FIX so the correct org package is loaded (not the one shipped with emacs) +;; Has to be as early in the config as possible, so no other package can load the +;; incorrect org version beforehand +;; (straight-use-package 'org) + +;; ASYNC: Asynchronous functionality +(straight-use-package 'async) +(require 'async) + +;; GENERAL: Keybindings +(straight-use-package 'general) +(require 'general) + +;; TODO: Rename the leader key (if you want) +(general-create-definer my-leader + :prefix "" + :non-normal-prefix "C-SPC") + +;; EVIL: +;; depends on: goto-chg, undo-tree +(straight-use-package 'evil) +(straight-use-package 'undo-fu) +(straight-use-package 'undo-fu-session) +(undo-fu-session-global-mode) +(straight-use-package 'vundo) + +;; variables +(setq evil-want-C-u-scroll t + evil-want-integration t + evil-want-keybinding nil + evil-undo-system 'undo-fu) +(require 'evil) +;; start mode +(evil-mode t) + +;; https://github.com/emacs-evil/evil/issues/1288 +;; Credit goes to: https://github.com/nnicandro +;; Fix for the broken org-src-tab-acts-natively functionality +;; Tab in fact does nothing in src blocks if evil is enabled +(defun evil-org-insert-state-in-edit-buffer (fun &rest args) + "Bind `evil-default-state' to `insert' before calling FUN with ARGS." + (let ((evil-default-state 'insert) + ;; Force insert state + evil-emacs-state-modes + evil-normal-state-modes + evil-motion-state-modes + evil-visual-state-modes + evil-operator-state-modes + evil-replace-state-modes) + (apply fun args) + (evil-refresh-cursor))) + +;; MESSAGE BUFFER: +(evil-set-initial-state 'message-mode 'normal) + +(advice-add 'org-babel-do-key-sequence-in-edit-buffer + :around #'evil-org-insert-state-in-edit-buffer) + +;; EVIL-NERD-COMMENTER: Easy un/comment +(straight-use-package 'evil-nerd-commenter) + +;; EVIL-VILUALSTAR: Search selected thing with * +(straight-use-package 'evil-visualstar) +(global-evil-visualstar-mode) + +;; EVIL-SURROUND: +(straight-use-package 'evil-surround) +;; start mode +(global-evil-surround-mode t) + +;; EVIL-COLLECTION: improved evil support for multiple packages +(straight-use-package 'evil-collection) +;; variables +(setq evil-collection-setup-minibuffer t + evil-collection-mode-list + '(ibuffer help calc nov man calendar ivy minibuffer dired debug + doc-view arc-mode magit vterm)) +;; start mode +(evil-collection-init) + +;; IVY: better popup menu (Alternative: Helm) +(straight-use-package 'ivy) +;; variables +(setq ivy-use-virtual-buffers t + ivy-re-builders-alist '((t . ivy--regex-ignore-order)) + enable-recursive-minibuffers t + ivy-wrap t + ivy-magic-slash-non-match-action 'ivy-magic-slash-non-match-create + ivy-count-format "%d/%d ") +;; remove caret (has to be counsel not ivy #thanksfornothinginternet) +(with-eval-after-load 'counsel (setq ivy-initial-inputs-alist nil)) +;; start mode +(ivy-mode t) + +;; Keybindings +;; Allow the creation of files/folders even if a file/folder with a similar name +;; is matched in the ivy buffer. +(my-leader + :states 'normal + :keymaps 'ivy-minibuffer-map + "SPC f" 'ivy-immediate-done) + +;; IVY-PRESCIENT: better suggestions for ivy +(straight-use-package 'ivy-prescient) +;; start mode +(ivy-prescient-mode) + +;; COUNSEL: several improved functions like find-file, etc. +(straight-use-package 'counsel) +(setq counsel-grep-base-command "grep -R -i -n -H --color=never %s ." + counsel-rg-base-command "rg -i -M 250 --hidden --no-heading --line-number --color never %s") + +;; WHICH-KEY: hints in the mini bar +(straight-use-package 'which-key) +(which-key-setup-minibuffer) +;; start mode +(which-key-mode) + +;; ACE-WINDOW: jump between windows faster +;; TODO: Set your own keys (; +(straight-use-package 'ace-window) +(setq aw-scope 'frame + aw-keys '(?j ?k ?l ?f ?d ?s)) + +;; ELECTRIC-PAIR: auto-balance brackets +(electric-pair-mode t) +;; electric-indent-mode is a bit buggy in src blocks... +;; Unfortunately it adds a bug, where the cursor jumps to the start of the src +;; block after inserting a nested block of any sort {}, [], () and pressing RET +;; This is triggered by: org-return -> newline-and-indent +;; Adding an advice did not work, since the point must not only be recovered +;; but also increased by the level of indention... Also, it seemed like another +;; function is responsible for the reset since I added the advice to +;; org-babel-do-key-sequence-in-edit-buffer (Probably newline-and-indent) +;; TODO: Check if this bug is still present in newer versions + +;; hooks +(add-hook 'org-mode-hook + (lambda () + (setq-local electric-pair-inhibit-predicate + `(lambda (c) + (if (char-equal c ?<) t (,electric-pair-inhibit-predicate c)))))) +;; SAVE PLACE MODE +;; Return to the point in a buffer when reopening it after some time +(save-place-mode 1) + +(provide 'essentials) \ No newline at end of file diff --git a/cnf/functions.el b/cnf/functions.el new file mode 100644 index 0000000..ba09283 --- /dev/null +++ b/cnf/functions.el @@ -0,0 +1,20 @@ +;; Run a terminal in the current folder +;; TODO: Check the command for your terminal emulator for this to work properly +(defun phga/run-terminal-here () + (interactive "@") + (shell-command (concat "TERM_FROM_EMACS=true alacritty -e sh -c 'cd " default-directory + "; /run/current-system/sw/bin/bash' > /dev/null 2>&1 & disown ") + nil nil)) + +;; https://gist.github.com/mads-hartmann/3402786 +;; Allows for emacs to toggle window "maximization" +(defun toggle-maximize-buffer () + "Maxmize current buffer, when called again, restore previous buffer setup" + (interactive) + (if (= 1 (length (window-list))) + (jump-to-register '_) + (progn + (window-configuration-to-register '_) + (delete-other-windows)))) + +(provide 'functions) \ No newline at end of file diff --git a/cnf/global-keybindings.el b/cnf/global-keybindings.el new file mode 100644 index 0000000..25a7235 --- /dev/null +++ b/cnf/global-keybindings.el @@ -0,0 +1,96 @@ +;; EXAMPLE: Global override of keybinding +;; Ged rid of default bindings I don't enjoy :< +(general-def :states '(normal insert emacs visual) :keymaps 'override + ;; This motherf***** + another ESC used to close my windows. NOO MOOORE! + "M-ESC" (lambda () (interactive) (message "You pressed it again Mr. Fatfinger..."))) + +;; GLOBAL BINDINGS +(general-def + :states '(normal insert visual) + :keymaps 'override + + "C-j" 'evil-scroll-down + "C-k" 'evil-scroll-up + ;; "" 'evil-scroll-down + ;; "" 'evil-scroll-up + ) + +;; This is a reference to the leader key defined in essentials.el +;; It basically means: + whatever is configured below +;; E.g. "SPC SPC" actually means "SPC SPC SPC" because it is prefix with `my-leader' +(my-leader + ;; These are the states for which the keybinding should work + :states '(normal visual emacs) + ;; This is the keymap for which the keybinding should work. + ;; Override is the GLOBAL keymap but there are specific ones for each mode + :keymaps 'override + + ;; This ignores the sole keybinding of "SPC SPC" to use this "namespace" for mode specific bindings + "SPC" '(:ignore t :which-key "Mode Specific Binds") + "SPC SPC" 'counsel-M-x + + "f" 'counsel-find-file + "g" 'magit-status + "h" 'evil-avy-goto-line + "i" 'counsel-imenu + "y" 'counsel-yank-pop + ";" 'evilnc-comment-or-uncomment-lines + "." 'save-buffer + + ;; window stuff + "w" '(:ignore t :which-key "Window") + ;; quick switch to other window + "a" 'ace-window + "w v" 'split-window-right + "w h" 'split-window-below + "w f" 'toggle-maximize-buffer + "w L" 'windsize-right + "w H" 'windsize-left + "w J" 'windsize-down + "w K" 'windsize-up + + ;; switch stuff + "s" '(:ignore t :which-key "Switch") + "s b" 'switch-to-buffer + "s n" 'switch-to-next-buffer + "s p" 'switch-to-prev-buffer + "s s" 'counsel-switch-buffer + "s a" 'ace-swap-window + ;; kill stuff + "k" '(:ignore t :which-key "Kill") + "k b" 'kill-buffer + "k w" 'delete-window + "k W" 'kill-buffer-and-window + "k o b" 'kill-some-buffers + "k o w" 'delete-other-windows + "k q q" 'kill-emacs + "k k" 'kill-current-buffer + + ;; buffer stuff + "b" '(:ignore t :which-key "Buffer (revert)") + "b r" 'revert-buffer + "b a r" 'auto-revert-mode + + ;; edit stuff + "e" '(:ignore t :which-key "Edit") + "e c" '((lambda() (interactive) (dired my/emacsconf)) :which-key "edit emacs config") + + ;; ui stuff + "q" '(:ignore t :which-key "Quality :)") + "q t" 'phga/cycle-themes + "q =" 'phga/text-scale-adjust + + ;; tools + "t u" 'vundo + + ;; describe stuff + "?" '(:ignore t :which-key "Describe") + "? v" 'describe-variable + "? f" 'describe-function + "? c" 'describe-char + "? m" 'describe-mode + "? k" 'describe-key + "? F" 'describe-face +) + +(provide 'global-keybindings) \ No newline at end of file diff --git a/cnf/ui.el b/cnf/ui.el new file mode 100644 index 0000000..a8add27 --- /dev/null +++ b/cnf/ui.el @@ -0,0 +1,146 @@ +;; GENERAL UI +(setq x-stretch-cursor t + blink-cursor-mode nil + show-paren-delay 0 + scroll-conservatively 5 + scroll-margin 0 + mouse-wheel-scroll-amount '(2 ((shift) . 2)) ;; one line at a time + mouse-wheel-progressive-speed nil ;; don't accelerate scrolling + mouse-wheel-follow-mouse 't ;; scroll window under mouse + scroll-step 2 ;; keyboard scroll two lines at a time + frame-resize-pixelwise t + frame-title-format "Allmighty Editor w/o Kitchen Sink") + +;; Highlight matching parens +(show-paren-mode t) +;; Show line numbers on the left side of the buffer +(global-display-line-numbers-mode 0) +;; Highlight current horizontal line with a different background +(global-hl-line-mode t) +;; Also display the current column index in e.g. the mode-line +(column-number-mode t) +;; Show tooltip on hover in minibuffer +(tooltip-mode 0) +;; Default encoding +(set-language-environment "UTF-8") +;; Show line that indicates maximum number of "allowed" characters +(add-hook 'prog-mode-hook 'display-fill-column-indicator-mode) + +;; FONT SETUP +(defvar phga/font "Jetbrains Mono") +(defvar phga/font-size "19") +(defvar phga/font-family (concat phga/font ":size=" phga/font-size)) +;; These are required to have the correct font size with the first frame (emacs server) +(add-to-list 'default-frame-alist `(font . ,phga/font-family)) + +;; TEXT-SCALE: Scale text globally +(defvar phga/text-scale-amount 2) +(defvar phga/text-scale--current-size (string-to-number phga/font-size)) +(defun phga/text-scale-adjust () + "Adjust the size of the frame-font by `phga/text-scale-amount'." + (interactive) + (phga/text-scale--adjust)) + +(defun phga/text-scale--scale (inc) + "Scale the frame-font by `phga/text-scale-amount'. +If INC is not nil increase the font size else decrease it" + (if inc (setq phga/text-scale--current-size + (+ phga/text-scale--current-size phga/text-scale-amount)) + (setq phga/text-scale--current-size + (- phga/text-scale--current-size phga/text-scale-amount))) + (set-frame-font (concat phga/font ":size=" + (number-to-string phga/text-scale--current-size)) t t)) + +(defun phga/text-scale--adjust () + "Actual function which will call itself with the temporary keymap to scale the text." + (let ((ev last-command-event) + (echo-keystrokes nil)) + (pcase (event-basic-type ev) + ((or ?= ?k) (phga/text-scale--scale t)) + ((or ?- ?j) (phga/text-scale--scale nil)) + ((or ?0) (progn (set-frame-font phga/font-family t t) + (setq phga/text-scale--current-size + (string-to-number phga/font-size)) + (error "Reset to normal text scale")))) + (message "Use j/=, k/-, 0 for further adjustment") + (set-transient-map + (let ((map (make-sparse-keymap))) + (dolist (key '(?- ?j ?k ?= ?0)) + (define-key map (vector (list key)) + (lambda () (interactive) (phga/text-scale--adjust)))) + map)))) + +;; LIGATURES +(straight-use-package 'ligature) +;; Enable the "www" ligature in every possible major mode +;; (ligature-set-ligatures 't '("www")) +;; Enable all Cascadia Code ligatures in programming modes +(ligature-set-ligatures + 'prog-mode + '("|||>" "<|||" "<==>" "" "---" "-<<" + "<~~" "<~>" "<*>" "<||" "<|>" "<$>" "<==" "<=>" "<=<" "<->" + "<--" "<-<" "<<=" "<<-" "<<<" "<+>" "" "###" "#_(" "..<" + "..." "+++" "/==" "///" "_|_" "www" "&&" "^=" "~~" "~@" "~=" + "~>" "~-" "**" "*>" "*/" "||" "|}" "|]" "|=" "|>" "|-" "{|" + "[|" "]#" "::" ":=" ":>" ":<" "$>" "==" "=>" "!=" "!!" ">:" + ">=" ">>" ">-" "-~" "-|" "->" "--" "-<" "<~" "<*" "<|" "<:" + "<$" "<=" "<>" "<-" "<<" "<+" "" "++" "?:" + "?=" "?." "??" ";;" "/*" "/=" "/>" "//" "__" "~~" "(*" "*)" + "\\\\" "://")) + +(global-ligature-mode t) + +;; THEMES +;; SHANTY +(straight-use-package 'shanty-themes) +(defvar phga/dark-theme 'shanty-themes-dark) +(defvar phga/light-theme 'shanty-themes-light) + +(defvar phga/current-theme phga/dark-theme) +(load-theme phga/current-theme t) + +(defun phga/cycle-themes () + "Cycle through my preferred dark and light theme" + (interactive) + (if (eq phga/current-theme phga/dark-theme) + (progn + (disable-theme phga/dark-theme) + (load-theme phga/light-theme t) + (message "Loaded light theme") + (setq phga/current-theme phga/light-theme)) + (progn + (disable-theme phga/light-theme) + (load-theme phga/dark-theme t) + (message "Loaded dark theme") + (setq phga/current-theme phga/dark-theme)))) + +;; MODE-LINE +;; https://emacs.stackexchange.com/questions/5529/how-to-right-align-some-items-in-the-modeline +(defun simple-mode-line-render (left right) + "Return a string of `window-width' length containing LEFT, and RIGHT aligned respectively." + (let* ((available-width (- (window-total-width) (length left) 2))) + (format (format " %%s %%%ds " available-width) left right))) + +(setq-default mode-line-format + '((:eval (simple-mode-line-render + ;; left + (format-mode-line + '("" + ;; (:eval (propertize "%* %b")) + (:eval (propertize "%* %b" 'face 'mode-line-buffer-id)) + evil-mode-line-tag + (:eval (propertize "%m")))) + ;; (:eval (propertize "%m" 'face 'font-lock-comment-face)))) + ;; right + (format-mode-line mode-line-position))))) + +;; FIXES +;; Shell mode line highlighted +;; (set-face-attribute 'comint-highlight-prompt nil :inherit nil) +;; (custom-set-faces '(comint-highlight-prompt ((t nil)))) + +(message "ui.el was succesfully loaded") +(provide 'ui) \ No newline at end of file diff --git a/early-init.el b/early-init.el new file mode 100644 index 0000000..91e0bbd --- /dev/null +++ b/early-init.el @@ -0,0 +1,23 @@ +;;; early-init.el -*- lexical-binding: t; -*- + +;; Emacs HEAD (27+) introduces early-init.el, which is run before init.el, +;; before package and UI initialization happens. + +;; Defer garbage collection further back in the startup process +(setq gc-cons-threshold most-positive-fixnum) +;; In Emacs 27+, package initialization occurs before `user-init-file' is +;; loaded, but after `early-init-file'. Doom handles package initialization, so +;; we must prevent Emacs from doing it early! +(setq package-enable-at-startup nil) +(advice-add #'package--ensure-init-file :override #'ignore) + +;; Prevent the glimpse of un-styled Emacs by disabling these UI elements early. +(push '(menu-bar-lines . 0) default-frame-alist) +(push '(tool-bar-lines . 0) default-frame-alist) +(push '(vertical-scroll-bars . nil) default-frame-alist) +(push '(horizontal-scroll-bars . nil) default-frame-alist) + +;; Resizing the Emacs frame can be a terribly expensive part of changing the +;; font. By inhibiting this, we easily halve startup times with fonts that are +;; larger than the system default. +(setq frame-inhibit-implied-resize t) diff --git a/init.el b/init.el new file mode 100644 index 0000000..efc8dc4 --- /dev/null +++ b/init.el @@ -0,0 +1,31 @@ +(setq gc-cons-threshold most-positive-fixnum) +;; install straight.el +(defvar bootstrap-version) +(let ((bootstrap-file + (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory)) + (bootstrap-version 5)) + (unless (file-exists-p bootstrap-file) + (with-current-buffer + (url-retrieve-synchronously + "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el" + 'silent 'inhibit-cookies) + (goto-char (point-max)) + (eval-print-last-sexp))) + (load bootstrap-file nil 'nomessage)) + +;; load own config files +(setq custom-file (concat user-emacs-directory "customs.el")) +(unless (file-exists-p custom-file) + (make-empty-file custom-file)) +(load-file custom-file) + +(push (concat user-emacs-directory "cnf") load-path) + +(require 'essentials) +(require 'ui) +(require 'additionals) +(require 'global-keybindings) +(require 'functions) + +;; set gc values back to smth reasonable +(setq gc-cons-threshold 104857600) ;; 100 MegaByte (LSP)