From a5d571fc750f32005541d984b5191631ec4290d1 Mon Sep 17 00:00:00 2001 From: Geir Okkenhaug Jerstad Date: Wed, 28 May 2025 09:48:23 +0200 Subject: [PATCH] some more work on emacs init.el --- Emacs/emacs.org | 77 +++++-- init.el | 569 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 625 insertions(+), 21 deletions(-) create mode 100644 init.el diff --git a/Emacs/emacs.org b/Emacs/emacs.org index ff11e9a..34889ac 100644 --- a/Emacs/emacs.org +++ b/Emacs/emacs.org @@ -7,7 +7,15 @@ * About My attempt at a litterate configuration for Emacs. -* Prep +to tangle this file, run the following command in Emacs: +#+BEGIN_SRC emacs-lisp +(org-babel-tangle) +#+END_SRC +or keyboard shortcut `C-c C-v t` (org-babel-tangle) in Emacs. +This will generate the `~/.emacs.d/init.el` file with the configuration. + +* Prep + ** Copilot Authentication To use GitHub Copilot, you need to authenticate with your GitHub account. This is done by running the following command in Emacs: after installing the copilot package: @@ -19,6 +27,29 @@ Try to trigger the GitHub OAuth flow from within Emacs: * Configuration +** Setup lexical binding +Here we set up lexical binding, which is a feature in Emacs Lisp that allows for more efficient variable scoping and function closures. This is recommended for performance reasons. +#+BEGIN_SRC emacs-lisp +;; enable lexical binding +(setq lexical-binding t) +#+END_SRC + +** Set automatic update of packages + +We set up Emacs to automatically update packages on startup. This ensures that we always have the latest versions of the packages we use. +#+BEGIN_SRC emacs-lisp +(defun geokkjer/display-startup-time () + (message "Emacs loaded in %s with %d grabage collections." + (format "%.2f seconds" + (float-time + (time-subtract after-init-time before-init-time))) + gcs-done)) + +(add-hook 'emacs-startup-hook #'geokkjer/display-startup-time) + +(setq gc-cons-threshold (* 50 1000 1000)) +#+END_SRC + ** Customize UI Here we set up the UI to our liking. We disable the menu bar, tool bar, and scroll bar, and set the font size to 14pt. #+BEGIN_SRC emacs-lisp @@ -67,6 +98,30 @@ Set up doom modeline, which is a nice status line for Emacs. We set it up to sho (setq use-package-always-ensure t) #+END_SRC +** Org Mode +Configure Org-mode for literate programming and note-taking. + +#+BEGIN_SRC emacs-lisp +;; ensure org-mode is installed and up to date +(use-package org + :ensure t + :mode ("\\.org\\'" . org-mode) + :config + ;; enable syntax highlighting in code blocks + (setq org-src-fontify-natively t) + ;; preserve indentation in code blocks + (setq org-src-preserve-indentation t) + ;; enable babel for code execution + (org-babel-do-load-languages + 'org-babel-load-languages + '((emacs-lisp . t) + (shell . t) + (python . t) + (nix . t))) + ;; don't ask for confirmation when evaluating code blocks + (setq org-confirm-babel-evaluate nil)) +#+END_SRC + * Code Completion and ide features ** LSP Mode Here we install lsp-mode and lsp-ui, which are the core components of the LSP (Language Server Protocol) support in Emacs. We also set up keybindings for common LSP commands. @@ -105,27 +160,7 @@ Here we install from MELPA, enable it in all prog-modes and bind keys for comple ** Language support Here we install and configure support for various programming languages. We use the `use-package` macro to ensure that the packages are installed and configured correctly. -#+BEGIN_SRC emacs-lisp -;; install and configure javscript-mode -(use-package javscript-mode - :ensure t - :mode "\\.js\\'") -;; lsp support for javascript -(use-package lsp-javascript - :ensure t - :mode "\\.js\\'") - -;; install and configure gleam-mode -(use-package gleam-mode - :ensure t - :mode "\\.gleam\\'") - #+END_SRC -;; lsp support for gleam -(use-package lsp-gleam - :ensure t - :mode "\\.gleam\\'") -#+END_SRC ** NixOS from Emacs Editing Nix files and doing NixOS admin stuff like nixos-rebuild boot --upgrade diff --git a/init.el b/init.el new file mode 100644 index 0000000..e071cbd --- /dev/null +++ b/init.el @@ -0,0 +1,569 @@ +;;; -*- lexical-binding: t -*- +(defun geokkjer/display-startup-time () + (message "Emacs loaded in %s with %d grabage collections." + (format "%.2f seconds" + (float-time + (time-subtract after-init-time before-init-time))) + gcs-done)) + +(add-hook 'emacs-startup-hook #'geokkjer/display-startup-time) + +(setq gc-cons-threshold (* 50 1000 1000)) + +;; Initialize package sources +(require 'package) + +;; Set the repos +(setq package-archives '(("melpa" . "https://melpa.org/packages/") + ("org" . "https://orgmode.org/elpa/") + ("nongnu" . "https://elpa.nongnu.org/nongnu/") + ("elpa" . "https://elpa.gnu.org/packages/"))) + +(package-initialize) +(unless package-archive-contents + (package-refresh-contents)) + +;; Initialize use-package in case we are on non-Linux platform +(unless (package-installed-p 'use-package) + (package-install 'use-package)) + +(require 'use-package) +(setq use-package-always-ensure t) + +(use-package auto-package-update + :custom + (auto-package-update-interval 7) + (auto-package-update-prompt-before-update t) + (auto-package-update-hide-results t) + :config + (auto-package-update-maybe) + (auto-package-update-at-time "09:00")) + +;; Turns off the startup-message +(setq inhibit-startup-message t) + +;; Disable UI-elements +(scroll-bar-mode -1) ; Disable visible scrollbar +(tool-bar-mode -1) ; Disable the toolbar +(tooltip-mode -1) ; Disable tooltips +(set-fringe-mode 10) ; Give us some breathing room + +(menu-bar-mode -1) ; Disable the menu bar +;; Set up the visual bell +(setq visible-bell t) +;; Setting to auto reload files +(setq auto-revert-mode t) + +;; Doom modline, all-the-icons and doom-theme +(use-package doom-modeline + :ensure t + :init (doom-modeline-mode 1) + :custom ((doom-modeline-height 15))) + +(setq doom-modeline-icon t) +(use-package all-the-icons) + +(use-package doom-themes + :init (load-theme 'doom-monokai-pro t)) + +;; Enable line numbers +(column-number-mode) +(global-display-line-numbers-mode t) + +;; Disable line numbers for some modes +(dolist (mode '(org-mode-hook + geiser-mode-hook + term-mode-hook + shell-mode-hook + vterm-mode-hook + eshell-mode-hook)) + (add-hook mode (lambda () (display-line-numbers-mode 0)))) + +(use-package spacious-padding + :ensure t + :hook (after-init . spacious-padding-mode)) + +(defvar geokkjer/default-font-size 140) + +(set-face-attribute 'default nil :font "Fira Code Nerd Font Mono" :height geokkjer/default-font-size) + +;; Set the fixed pitch face +(set-face-attribute 'fixed-pitch nil :font "Fira Code Nerd Font Mono" :height 140) + +;; Set the variable pitch face +(set-face-attribute 'variable-pitch nil :font "Fira Code Nerd Font" :height 130 :weight 'regular) + +(use-package swiper) + +(use-package ivy + :diminish + :bind (("C-s" . swiper) + :map ivy-minibuffer-map + ("TAB" . ivy-alt-done) + ("C-l" . ivy-alt-done) + ("C-j" . ivy-next-line) + ("C-k" . ivy-previous-line) + :map ivy-switch-buffer-map + ("C-k" . ivy-previous-line) + ("C-l" . ivy-done) + ("C-d" . ivy-reverse-buffer-kill) + :map ivy-reverse-i-search-map + ("C-k" . ivy-previous-line) + ("C-d" . ivy-reversee-i-search-kill)) + :config + (ivy-mode 1)) + +(use-package ivy-rich + :after ivy + :init + (ivy-rich-mode 1)) + +(use-package ivy-posframe + :after ivy + :init + (ivy-posframe-mode 1)) + +(use-package counsel + :bind (("M-x" . counsel-M-x) + ("C-x b" . counsel-ibuffer) + ("C-x C-f" . counsel-find-file) + :map minibuffer-local-map + ("C-r" .'counsel-minibuffer-history)) + :config + (setq ivy-initial-inputs-alist nil) + (counsel-mode 1)) + +(use-package which-key + :defer 0 + :diminish which-key-mode + :config + (which-key-mode) + (setq which-key-idle-delay 1)) + +(defun efs/org-mode-setup () + (org-indent-mode) + (variable-pitch-mode 1) + (visual-line-mode 1)) + +;; Org Mode Configuration + +(defun efs/org-font-setup () + ;; Replace list hyphen with dot + (font-lock-add-keywords 'org-mode + '(("^ *\\([-]\\) " + (0 (prog1 () (compose-region + (match-beginning1) + (match-end 1) + "•"))))))) + +;; Show overview when open +(setq org-startup-folded t) + +;; Set faces for heading levels +(with-eval-after-load 'org-faces + (dolist (face '((org-level-1 . 1.2) + (org-level-2 . 1.1) + (org-level-3 . 1.05) + (org-level-4 . 1.0) + (org-level-5 . 1.1) + (org-level-6 . 1.1) + (org-level-7 . 1.1) + (org-level-8 . 1.1))) + (set-face-attribute (car face) nil :font "Fira Code Nerd Font" :weight 'regular + :height (cdr face)) + + ;; Ensure that anything that should be fixed-pitch in Org files appears that way + (set-face-attribute 'org-block nil :foreground nil :inherit 'fixed-pitch) + (set-face-attribute 'org-code nil :inherit '(shadow fixed-pitch)) + (set-face-attribute 'org-table nil :inherit '(shadow fixed-pitch)) + (set-face-attribute 'org-verbatim nil :inherit '(shadow fixed-pitch)) + (set-face-attribute 'org-special-keyword nil :inherit + '(font-lock-comment-face fixed-pitch)) + (set-face-attribute 'org-meta-line nil :inherit '(font-lock-comment-face + fixed-pitch)) + (set-face-attribute 'org-checkbox nil :inherit 'fixed-pitch))) + +(use-package org + :pin org + :commands (org-capture org-agenda) + :hook (org-mode . efs/org-mode-setup) + :config + (setq org-ellipsis " ▾") + + (use-package org-bullets + :hook (org-mode . org-bullets-mode) + :custom + (org-bullets-bullet-list '("◉" "○" "●" "○" "●" "○" "●"))) + + (defun efs/org-mode-visual-fill () + (setq visual-fill-column-width 100 + visual-fill-column-center-text t) + (visual-fill-column-mode 1)) + + (use-package visual-fill-column + :hook (org-mode . efs/org-mode-visual-fill))) + +(with-eval-after-load 'org + (org-babel-do-load-languages + 'org-babel-load-languages + '((lisp . t) + (scheme . t) + (emacs-lisp . t) + (shell . t) + (python . t))) + + (push '("conf-unix" . conf-unix) org-src-lang-modes)) + +(setq org-confirm-babel-evaluate nil) + +;; This is needed as of Org 9.2 +(with-eval-after-load 'org + (require 'org-tempo) + + (add-to-list 'org-structure-template-alist '("sh" . "src shell")) + (add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp")) + (add-to-list 'org-structure-template-alist '("py" . "src python")) + (add-to-list 'org-structure-template-alist '("go" . "src go")) + (add-to-list 'org-structure-template-alist '("sc" . "src scheme")) + (add-to-list 'org-structure-template-alist '("li" . "src lisp")) + (add-to-list 'org-structure-template-alist '("ru" . "src rust")) + (add-to-list 'org-structure-template-alist '("nx" . "src nix"))) + +(setq org-src-tab-acts-natively t) + +(use-package lorem-ipsum + :after org) + +(use-package treemacs + :ensure t + :bind ("" . treemacs) + :custom (treemacs-is-never-other-window t) + :hook (treemacs-mode . treemacs-project-follow-mode)) + +(defun geokkjer/lsp-mode-setup () + (setq lsp-headerline-breadcrumb-segments '(path-up-to-project file symbols)) + (lsp-headerline-breadcrumb-mode)) + +(use-package lsp-mode + :commands (lsp lsp-deferred) + :hook ((lsp-mode . geokkjer/lsp-mode-setup) + (lsp-mode . lsp-enable-which-key-integration) + + + :init + (setq lsp-keymap-prefix "C-c l"))) + +;; (use-package lsp-org +;; :after lsp) + +(use-package lsp-ivy + :after lsp) + +(use-package lsp-ui + :hook (lsp-mode . lsp-ui-mode) + :custom + (lsp-ui-doc-psition 'bottom)) + +(setq lsp-ui-sidline-enable nil) +(setq lsp-ui-sideline-show-hover nil) + +(use-package lsp-treemacs + :after lsp) + +(use-package ccls + :defer t + :hook ((c-mode c++-mode objc-mode) . + (lambda () (require 'ccls) (lsp))) + :custom + (ccls-executable (executable-find "ccls")) ; Add ccls to path if you haven't done so + (ccls-sem-highlight-method 'font-lock) + (ccls-enable-skipped-ranges nil) + :config + (lsp-register-client + (make-lsp-client + :new-connection (lsp-tramp-connection (cons ccls-executable ccls-args)) + :major-modes '(c-mode c++-mode cuda-mode objc-mode) + :server-id 'ccls-remote + :multi-root nil + :remote? t + :notification-handlers + (lsp-ht ("$ccls/publishSkippedRanges" #'ccls--publish-skipped-ranges) + ("$ccls/publishSemanticHighlight" #'ccls--publish-semantic-highlight)) + :initialization-options (lambda () ccls-initialization-options) + :library-folders-fn nil))) + +;; C sharp +(use-package csharp-mode + :hook (csharp-mode . (lambda () + (require 'csharp-ls) + (lsp))) + :mode "\\.cs\\'") + +;; Zig +(use-package zig-mode + :ensure t + :hook (zig-mode . (lambda () + (require 'zls + (lsp-deferred)) + (prettify-symbols-mode))) + :mode "\\.zig\\'") + +(use-package geiser-racket + :ensure t) +(use-package geiser-guile + :ensure t) +(use-package lsp-scheme) +(require 'lsp-scheme) +(add-hook 'scheme-mode-hook #'lsp-scheme-guile) +(setq lsp-scheme-implementation "guile") + +(use-package go-mode + :ensure t + :hook (go-mode . (lambda () + (require 'golsp + (lsp-deferred)) + (prettify-symbols-mode))) + :mode "\\.go\\'") + +(use-package flycheck-gometalinter + :ensure t + :config + (progn + (flycheck-gometalinter-setup))) + +(use-package web-mode + :mode "\\.html\\'" + :hook (web-mode . lsp-deferred) + :config + (add-to-list 'auto-mode-alist '("\\.html?\\'" . web-mode)) + (setq web-mode-engines-alist '(("django" . "\\.html\\'")))) + +;; Simple-httpd webserver to preview webpages +(use-package simple-httpd + :ensure t) + +(use-package python-mode + :ensure nil + :hook (python-mode . lsp-deferred) + :custom + (python-shell-interpreter "python3") + :mode "\\.py\\'" + :config + ) + +(use-package pyvenv + :after python-mode + :config + (pyvenv-mode 1)) + +(use-package lsp-python-ms + :ensure t + :hook (python-mode . (lambda () + (require 'lsp-python-ms) + (lsp-deferred))) + :init + (setq lsp-python-ms-executable (executable-find "python-language-server"))) +;; Javascript +(use-package js2-mode + :hook (js2-mode . (lambda () + (require 'ts-ls + (lsp-deferred)))) + :mode "\\.js\\'") +(use-package rust-mode + :ensure nil + :hook (rust-mode . (lambda () + (require 'lsp-rust-server + (lsp-deferred)) + (prettify-symbols-mode))) + :mode "\\.rs\\'") + +(setq rust-format-on-save t) + +(use-package flycheck-rust) +(with-eval-after-load 'rust-mode + (add-hook 'flycheck-mode-hook #'flycheck-rust-setup)) + +(use-package sql-indent) + +(use-package nix-mode + :mode "\\.nix\\'") + +(add-to-list 'lsp-language-id-configuration '(nix-mode . "nix")) +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection '("rnix-lsp")) + :major-modes '(nix-mode) + :server-id 'nix)) + +(use-package kubernetes + :commands kubernetes-overview + :config + (setq kubernetes-poll-frequency 3600 + kubernetes-redraw-frequency 3600)) + +(use-package yaml-mode) + +(use-package company + :after lsp-mode + :hook (lsp-mode . company-mode) + :bind (:map company-active-map + ("" . company-complete-section)) + (:map lsp-mode-map + ("" . company-indent-or-complete-common)) + :custom + (company-minimum-orefix-lenght 1) + (company-idle-delay 0.0)) + +(use-package company-box + :hook (company-mode . company-box-mode)) + +;; rainbow-delimiters +(use-package rainbow-delimiters + :hook (prog-mode . rainbow-delimiters-mode)) + +(use-package flycheck + :ensure t + :init (global-flycheck-mode)) + +;; TODO learn to use projectile +(use-package projectile + :diminish + :config + :custom ((projectile-completion-system 'ivy)) + :bind-keymap + ("C-c p" . projectile-command-map) + :init + (when (file-directory-p "~/Projects/Code") + (setq projectile-projects-search-path '("~/Projects/Code"))) + (setq projectile-switch-project-action #'projectile-dired)) + +(use-package counsel-projectile + :after projectile + :config (counsel-projectile-mode)) + +;; TODO learn git and Magit +(use-package magit + :commands magit-status + :custom + (magit-display-buffer-function + #'magit-display-buffer-same-window-except-diff-v1)) + +;; TODO config for service +(use-package forge + :after magit) + +(use-package helpful + :commands (helpful-callable helpful-variable helpful-command helpful-key) + :custom + (counsel-describe-function-function #'helpful-callable) + (counsel-describe-variable-function #'helpful-variable) + :bind + ([remap describe-function] . counsel-describe-function) + ([remap describe-command] . helpful-command) + ([remap describe-variable] . counsel-describe-variable) + ([remap describe-key] . helpful-key)) + +(use-package general + :config + (general-create-definer geokkjer/leader-keys + :keymaps '(normal insert visual emacs) + :prefix "SPC" + :global-prefix "C-SPC") + (geokkjer/leader-keys + "t" '(:ignore t :which-key "toggles") + "tt" '(counsel-load-theme :which-key "choose theme"))) + +(use-package term + :commands term + :config + (setq explicit-shell-file-name "bash") + ;; (setq explicit-zsh-args '()) + (setq term-prompt-regexp "^[^#$%>\n]*[#$%>] *")) + +(use-package eterm-256color + :hook (term-mode . eterm-256color-mode)) + +(use-package vterm + :ensure t + :commands vterm + :config + (setq vterm-shell "zsh") + (setq vterm-max-scrollback 10000)) + +(defun geokkjer/configure-eshell () + ;; Make eshell svae history when it is open + (add-hook 'eshell-pre-command-hook 'eshell-save-some-history) + + ;; Truncate buffer for performance + (add-to-list 'eshell-output-filter-functions 'eshell-truncate-buffer) + + (setq eshell-history-size 10000 + eshell-buffer-maximum-lines 10000 + eshell-hist-ignoredups t + eshell-scroll-to-bottom-on-input t)) + +(use-package eshell-git-prompt + :after eshell) + +(use-package eshell + :hook (eshell-first-time-mode . geokkjer/configure-eshell) + :config + (with-eval-after-load 'esh-opt + (setq eshell-destroy-buffer-when-process-dies t) + (setq eshell-visual-commands '("htop" "zsh" "vim" "glances"))) + + (eshell-git-prompt-use-theme 'powerline)) + +(use-package dired + :ensure nil + :commands (dired dired-jump) + :bind (("C-x C-j" . dired-jump)) + :custom ((dired-listing-switches "-agho --group-directories-first"))) + +(use-package dired-single + :after dired) + +(use-package all-the-icons-dired + :hook (dired-mode . all-the-icons-dired-mode)) + +(use-package dired-open + :after dired + :config + (setq dired-open-exstensions '(("png" . "feh") + ("mkv" . "mpv")))) +(use-package dired-hide-dotfiles + :hook (dired-mode . dired-hide-dotfiles-mode)) + +;; Make gc pauses faster by decreasing the threshold +(setq gc-cons-threshold (* 2 1000 1000)) +(server-start) +(custom-set-variables + ;; custom-set-variables was added by Custom. + ;; If you edit it by hand, you could mess it up, so be careful. + ;; Your init file should contain only one such instance. + ;; If there is more than one, they won't work right. + '(package-selected-packages + '(lsp-scheme tree-sitter-indent tree-sitter-langs tree-sitter dired-hide-dotfiles dired-open all-the-icons-dired dired-single eshell-git-prompt vterm eterm-256color general helpful forge magit counsel-projectile projectile rainbow-delimiters company-box company yaml-mode kubernetes nix-mode sql-indent flycheck-rust lsp-python-ms pyvenv simple-httpd web-mode flycheck-gometalinter go-mode geiser-guile geiser-racket zig-mode ccls lsp-treemacs lsp-ui lsp-ivy lsp-mode visual-fill-column org-bullets treemacs lorem-ipsum which-key counsel ivy-posframe ivy-rich swiper use-package spacious-padding doom-themes doom-modeline auto-package-update all-the-icons)) + '(warning-suppress-log-types '((comp)))) +(custom-set-faces + ;; custom-set-faces was added by Custom. + ;; If you edit it by hand, you could mess it up, so be careful. + ;; Your init file should contain only one such instance. + ;; If there is more than one, they won't work right. + '(fringe ((t :background "#282a36"))) + '(header-line ((t :box (:line-width 4 :color "#22232d" :style nil)))) + '(header-line-highlight ((t :box (:color "#f8f8f2")))) + '(keycast-key ((t))) + '(line-number ((t :background "#282a36"))) + '(mode-line ((t :box (:line-width 6 :color "#22232d" :style nil)))) + '(mode-line-active ((t :box (:line-width 6 :color "#22232d" :style nil)))) + '(mode-line-highlight ((t :box (:color "#f8f8f2")))) + '(mode-line-inactive ((t :box (:line-width 6 :color "#252631" :style nil)))) + '(tab-bar-tab ((t :box (:line-width 4 :color "#282a36" :style nil)))) + '(tab-bar-tab-inactive ((t :box (:line-width 4 :color "#1E2029" :style nil)))) + '(tab-line-tab ((t))) + '(tab-line-tab-active ((t))) + '(tab-line-tab-inactive ((t))) + '(vertical-border ((t :background "#282a36" :foreground "#282a36"))) + '(window-divider ((t (:background "#282a36" :foreground "#282a36")))) + '(window-divider-first-pixel ((t (:background "#282a36" :foreground "#282a36")))) + '(window-divider-last-pixel ((t (:background "#282a36" :foreground "#282a36")))))