diff --git a/home-manager/suites/base/emacs/default.nix b/home-manager/suites/base/emacs/default.nix index b241e4b..0ddbb01 100644 --- a/home-manager/suites/base/emacs/default.nix +++ b/home-manager/suites/base/emacs/default.nix @@ -22,10 +22,20 @@ in pname = "azos-emacs-base"; version = "0.1.6"; src = ./el/azos-emacs-base.org; - packageRequires = [ - emacspkgs.evil - emacspkgs.magit - emacspkgs.vterm + packageRequires = with emacspkgs; [ + evil + evil-collection + magit + vterm + undo-tree + ivy + ivy-hydra + ivy-avy + counsel + counsel-tramp + counsel-projectile + swiper + projectile ]; }))]; @@ -33,6 +43,8 @@ in [((emacsPackagesFor config.azos.emacs.emacspkg).emacsWithPackages ( config.azos.emacs.pkgs )) ]; + + home.file."/.emacs.el".text = ''(require 'azos-emacs-base)''; }; imports = [ diff --git a/home-manager/suites/base/emacs/el/azos-emacs-base.org b/home-manager/suites/base/emacs/el/azos-emacs-base.org index 4a9f032..33c0a49 100644 --- a/home-manager/suites/base/emacs/el/azos-emacs-base.org +++ b/home-manager/suites/base/emacs/el/azos-emacs-base.org @@ -1,12 +1,324 @@ -Hello! +#+title: Aner's Emacs Base Configuration +#+property: header-args :results silent + +* Bootstrapping + +Taken from [[https://stackoverflow.com/questions/151945/how-do-i-control-how-emacs-makes-backup-files][this post on StackOverflow]] + +Backups are moved to a =.cache= directory in order to keep them out of local dirs. + +Follow symlinks #+begin_src emacs-lisp +(setq + vc-follow-symlinks t + backup-directory-alist `(("." . "~/.cache/emacs-backups/")) + auto-save-file-name-transforms '((".*" "~/.cache/emacs-backups/" t)) + backup-by-copying t + delete-old-versions t + kept-new-versions 6 + kept-old-versions 2 + version-control t + gc-cons-threshold 100000000 ;Setting garbage collection to 100M. +) + +#+end_src + +Make sure CL is loaded + +CL is a base library that has a bunch of useful stuff, primarily for lists. +We are using the built-in version, no need to pull from anywhere. +This just makes sure the code is loaded early on for later use. + +#+begin_src emacs-lisp +(require 'cl-lib) +#+end_src + +* Keymap setup + +In this section global keybindings are defined using a global minor mode. + +First, utility functions that will be bound are defined. + +The first, =azos/set-window-width= is a helper function that resizes a window. Used because I wanted a function +that resizes a window to 85 cols easily. + +The second, =azos/open-conf-file=, opens the configuration file. + +#+begin_src emacs-lisp +(defun azos/set-window-width (n) + (adjust-window-trailing-edge (selected-window) ( - n (window-width)) t)) + +(defun azos/open-conf-file () + (interactive) + (find-file (concat user-emacs-directory "config.org"))) +#+end_src + +Now let's define keybindings. To start, we'd like =M-o= to be available to us, so let's unbind it. + +#+begin_src emacs-lisp +;Unbind face menu map +(define-key global-map (kbd "M-o") nil) +#+end_src + +This creates an "open keymap", a bunch of keybindings we'll use to open basic applications and files. +This will be mapped to =M-o=, and things will be opened form this sub-menu. +We'll start it with a binding to open the conf file with =M-o o= (MOO!) + +Setting of keybindings based on [[https://stackoverflow.com/questions/49853494/the-best-way-to-set-a-key-to-do-nothing][this]] + +#+begin_src emacs-lisp +;We'll define a basic keymap and already load window-manip funcs +(defvar azos/global-minor-mode/open-keymap + (let ((map (make-sparse-keymap))) + (define-key map (kbd "o") 'azos/open-conf-file) + map) + "global keymap for opening stuff on azos") +#+end_src + +At this stage a minor-mode-map is defined with keybindings, and an accompanying minor-mode is added. + +#+begin_src emacs-lisp +(defvar azos/global-minor-mode/keymap + (let ((map (make-sparse-keymap))) + + ;Window movement and manipulation + (define-key map (kbd "M-h") 'windmove-left) + (define-key map (kbd "M-l") 'windmove-right) + (define-key map (kbd "M-k") 'windmove-up) + (define-key map (kbd "M-j") 'windmove-down) + + (define-key map (kbd "M-") 'windmove-left) + (define-key map (kbd "M-") 'windmove-right) + (define-key map (kbd "M-") 'windmove-up) + (define-key map (kbd "M-") 'windmove-down) + (define-key map (kbd "M-d M-d") 'delete-window) + (define-key map (kbd "M-d D") 'kill-buffer-and-window) + (define-key map (kbd "M-\\") 'split-window-horizontally) + (define-key map (kbd "M-\-") 'split-window-vertically) + (define-key map (kbd "M-d R") (lambda () (interactive) + (set-window-width 85))) + (define-key map (kbd "M-o") azos/global-minor-mode/open-keymap) + map) + "azos/global-minor-mode keymap.") + +(define-minor-mode azos/global-minor-mode + "A minor mode for azos global keymaps." + :init-value t + :lighter "azos" + :keymap azos/global-minor-mode/keymap) + +(azos/global-minor-mode 1) +#+end_src + +This keymap will be referenced many times during this document at relevant points. + +Keymaps are included with relevant sections. + +* EVIL mode + +Using evil mode. + +This section includes unbinding =C-w= (I honestly forget why). + +This section binds keys for changing window size. Done here because can only do after evil loads. + +Unbinding C-w taken from https://stackoverflow.com/questions/24988406/unbinding-evils-c-w-mappings + +#+begin_src emacs-lisp +(setq evil-want-keybinding nil) + (use-package evil :init - :ensure t - :config (setq evil-want-C-i-jump nil) - (evil-mode 1)) + :config + (require 'evil ) + (evil-mode 1) + :bind + (:map azos/global-minor-mode/keymap + ("M-w h" . evil-window-decreace-width) + ("M-w l" . evil-window-increase-width) + ("M-w k" . evil-window-decrease-height) + ("M-w j" . evil-window-increase-height)) +) +#+end_src + +Loading evil collection. Functions from this package will be referenced many times later in the configuration. + +#+begin_src emacs-lisp +(use-package evil-collection + :config + (setq evil-collection-setup-minibuffer t) +) +#+end_src + +Setting theme colors + +#+begin_src emacs-lisp +(defvar azos/evil-color-normal "LightGoldenrod1") +(defvar azos/evil-color-emacs "LightBlue1") +(defvar azos/evil-color-insert "PaleGreen1") +(defvar azos/evil-color-replace "LightPink") +(defvar azos/evil-color-motion "LightCyan") +(defvar azos/evil-color-visual "LightGray") +(defvar azos/evil-color-operate "sandy brown") +#+end_src + +* Undo tree + +Loading =undo-tree= for undo/redo functionality with evil. + +Redo taken from https://github.com/syl20bnr/spacemacs/issues/14036 + +#+begin_src emacs-lisp +(use-package undo-tree + :after evil + :config + (evil-set-undo-system 'undo-tree) + (setq undo-tree-history-directory-alist + (list (cons "." (concat user-emacs-directory "undo-tree")))) + (global-undo-tree-mode 1) +) +#+end_src + +* IVY + +Enabling IVY. Taken from [[https://github.com/abo-abo/swiper][their website]]. + +Using ivy, hydra, counsel. + +#+begin_src emacs-lisp +(use-package ivy + :custom + (ivy-use-virtual-buffers t) + (enable-recursive-minibuffers t) + (ivy-count-format "(%d/%d) ") + :config + (ivy-mode 1) +) + +(use-package ivy-hydra + :after ivy) +(use-package ivy-avy + :after ivy) +(use-package counsel + :after ivy + + :bind + (:map azos/global-minor-mode/keymap + ("M-i" . counsel-imenu) + ("M-b" . counsel-switch-buffer) + ("C-x C-f" . counsel-find-file)) + (:map azos/global-minor-mode/open-keymap + ("l" . counsel-linux-app)) +) +#+end_src + +Using swiper. Replacing evil search with swiper search. + +#+begin_src emacs-lisp +(use-package swiper + :after ivy evil + :config + (setq evil-search-module 'swiper-isearch) + + :bind + (:map azos/global-minor-mode/keymap + ("C-s" . swiper-isearch)) +) +#+end_src + +Setting up keymaps + +#+begin_src emacs-lisp +(evil-collection-ivy-setup) +#+end_src + +* Projectile + +Startup up projectile. + +A config line here disables modeline display because I don't want my modeline to be cluttered. + +Mapping modeline commands to =M-p= prefix. Also adding a shortcut to add project. + +#+begin_src emacs-lisp +(use-package projectile + :config + (projectile-mode +1) + (setq projectile-mode-line-function (lambda () "")) + :bind + (:map projectile-command-map + ("a" . projectile-add-known-project) + ) + (:map azos/global-minor-mode/keymap + ("M-p" . projectile-command-map)) +) +#+end_src + +Ivy for projectile: +Parts taken from [[https://emacs.stackexchange.com/questions/40787/display-corresponding-key-binding-of-command-during-m-x-completion][this post]] and [[https://emacs.stackexchange.com/questions/38841/counsel-m-x-always-shows][this post]] from StackOverflow. + +Helps with many functions to use counsel's/ivy's autocomplete with projectile. + +#+begin_src emacs-lisp +(use-package counsel-projectile + :after counsel projectile + :config + (counsel-projectile-mode +1) + (setq projectile-completion-system 'ivy) + ;Making counsel start with empty regex + (when (commandp 'counsel-M-x) + (global-set-key [remap execute-extended-command] 'counsel-M-x)) + (setcdr (assoc 'counsel-M-x ivy-initial-inputs-alist) "") +) +#+end_src + + +** Tramp + +Ensuring tramp is loaded, and loading counsel-tramp for easy tramping. + +#+begin_src emacs-lisp +(use-package tramp + :straight (:type built-in)) + +(use-package counsel-tramp) +#+end_src + +* Assorted utility functions + +Defining a function to copy filename. + +#+begin_src emacs-lisp +(defun azos/copy-file-name () (interactive) + (let ((fpath buffer-file-name)) + (if fpath (kill-new fpath) (message "No current file!")))) +#+end_src + +Need to define this here so that other parts of code have access to it + +#+begin_src emacs-lisp +(defun azos/font-candidate (&rest fonts) + "Return existing font which first match." + (cl-find-if (lambda (f) (find-font (font-spec :name f))) fonts)) +#+end_src + +#+begin_src emacs-lisp +(defun azos/re-seq (regexp string) + "Get a list of all regexp matches in a string" + (save-match-data + (let ((pos 0) + matches) + (while (string-match regexp string pos) + (push (match-string 0 string) matches) + (setq pos (match-end 0))) + matches))) +#+end_src + +* Tie it up + +#+begin_src emacs-lisp (provide 'azos-emacs-base) #+end_src