#+TITLE: My Ever Changing Literate Emacs Configuration
#+AUTHOR: xulfer <xulfer at cheapbsd.net>
#+PROPERTY: header-args :tangle init.el :noweb yes :exports code

# For PDF export allow line wrapping.
#+LATEX_HEADER: \usepackage{listings}
#+LATEX_HEADER: \lstset{breaklines=true, breakatwhitespace=true, basicstyle=\ttfamily\footnotesize, columns=fullflexible}

#+begin_src emacs-lisp :exports none :tangle no
;; This asks for a file which it uses to store the processed org
;; data with the includes into.  It can be anything and can safely
;; be deleted afterwards.  I think README.org is a good file to
;; pick if using a repository.
(defun tangle-literate-config ()
  "Tangle config files with proper include handling."
  (interactive)
  (let ((org-confirm-babel-evaluate nil))
    ;; Create a temporary buffer with expanded includes
    (with-temp-buffer
      (insert-file-contents "config.org")
      (org-mode)
      ;; This expands all #+INCLUDE directives
      (org-export-expand-include-keyword)
      ;; Now tangle from this buffer which has everything in one place
      (org-babel-tangle nil "init.el"))
    (message "Configuration tangled!")))
#+end_src

#+BEGIN_SRC emacs-lisp :exports none
;;; init.el -*- lexical-binding: t; -*-

;;; Code:
#+END_SRC
#+begin_src emacs-lisp :tangle early-init.el :exports none
;;; early-init.el -*- lexical-binding: t; -*-

;;; Code:
#+end_src

* Quick Look

[[./img/preview.png]]

Just the usual flex of doing as little editing as possible in a screenshot.

* Motivation

Over a surprisingly short amount of time my emacs configuration has become quite a mess.
Almost every visit to it requiring some digging to get to the relevant configuration. So
as a result I've decided to make a literate configuration.  Mostly for my own mental
house keeping.  However, if some poor soul reads this and finds it useful, then that's a
bonus.

** Inspirations, and sometimes outright copy/paste sources
- [[https://github.com/progfolio/.emacs.d][Progfolio's Config]]

* Initial Bits and Bobs

Before anything else the appearance, and some performance settings need to be tweaked as
they can cause issues if done mid-start.

** Initial setup

The LSP packages perform better with plists so an environment variable needs to be
set to inform them that this is intended.  I've also removed default package handling
as I intend to use another package manager.  Lastly I suppress some compilation
warnings.

#+begin_src emacs-lisp :tangle early-init.el
(setq package-enable-at-startup nil)
(setq inhibit-default-init nil)

(setq native-comp-async-report-warnings-errors nil)
(setenv "LSP_USE_PLISTS" "true")
(setq lsp-use-plists t)
(setq read-process-output-max (* 1024 1024)) ;; 1MB
#+end_src

** Appearance

I like a minimal look, so I disable menu bars, tool bars, all the bars.  I have Emacs
loading as a blank slate with only the scratch buffer open.

#+begin_src emacs-lisp :tangle early-init.el
(defvar default-file-name-handler-alist file-name-handler-alist)
(setq file-name-handler-alist nil)

(push '(menu-bar-lines . 0) default-frame-alist)
(push '(tool-bar-lines . 0) default-frame-alist)
(push '(vertical-scroll-bars) default-frame-alist)

(setq server-client-instructions nil)

(when (and (fboundp 'startup-redirect-eln-cache)
           (fboundp 'native-comp-available-p)
           (native-comp-available-p))
  (startup-redirect-eln-cache
   (convert-standard-filename
    (expand-file-name  "var/eln-cache/" user-emacs-directory))))

(setq frame-inhibit-implied-resize t)
(advice-add #'x-apply-session-resources :override #'ignore)
(setq desktop-restore-forces-onscreen nil)
(setq ring-bell-function #'ignore
      inhibit-startup-screen t)

(push '(font . "MonoLisa-12") default-frame-alist)
(set-face-font 'default "MonoLisa-12")
(set-face-font 'variable-pitch "MonoLisa-12")

;; Can open in normal browser from within EWW.
(setq browse-url-browser-function 'eww-browse-url)

(copy-face 'default 'fixed-pitch)

(provide 'early-init)
;;; early-init.el ends here

;; Local Variables:
;; no-byte-compile: t
;; no-native-compile: t
;; no-update-autoloads: t
;; End:
#+end_src

* Package Management

I am using [[https://github.com/progfolio/elpaca][Elpaca]] as my package manager.  I've found it to be quite quick, and easy to
use.

#+name: elpaca-boilerplate
#+begin_src emacs-lisp :exports none :tangle no
(defvar elpaca-installer-version 0.11)
(defvar elpaca-directory (expand-file-name "elpaca/" user-emacs-directory))
(defvar elpaca-builds-directory (expand-file-name "builds/" elpaca-directory))
(defvar elpaca-repos-directory (expand-file-name "repos/" elpaca-directory))
(defvar elpaca-order '(elpaca :repo "https://github.com/progfolio/elpaca.git"
                              :ref nil :depth 1 :inherit ignore
                              :files (:defaults "elpaca-test.el" (:exclude "extensions"))
                              :build (:not elpaca--activate-package)))
(let* ((repo  (expand-file-name "elpaca/" elpaca-repos-directory))
       (build (expand-file-name "elpaca/" elpaca-builds-directory))
       (order (cdr elpaca-order))
       (default-directory repo))
  (add-to-list 'load-path (if (file-exists-p build) build repo))
  (unless (file-exists-p repo)
    (make-directory repo t)
    (when (<= emacs-major-version 28) (require 'subr-x))
    (condition-case-unless-debug err
        (if-let* ((buffer (pop-to-buffer-same-window "*elpaca-bootstrap*"))
                  ((zerop (apply #'call-process `("git" nil ,buffer t "clone"
                                                  ,@(when-let* ((depth (plist-get order :depth)))
                                                      (list (format "--depth=%d" depth) "--no-single-branch"))
                                                  ,(plist-get order :repo) ,repo))))
                  ((zerop (call-process "git" nil buffer t "checkout"
                                        (or (plist-get order :ref) "--"))))
                  (emacs (concat invocation-directory invocation-name))
                  ((zerop (call-process emacs nil buffer nil "-Q" "-L" "." "--batch"
                                        "--eval" "(byte-recompile-directory \".\" 0 'force)")))
                  ((require 'elpaca))
                  ((elpaca-generate-autoloads "elpaca" repo)))
            (progn (message "%s" (buffer-string)) (kill-buffer buffer))
          (error "%s" (with-current-buffer buffer (buffer-string))))
      ((error) (warn "%s" err) (delete-directory repo 'recursive))))
  (unless (require 'elpaca-autoloads nil t)
    (require 'elpaca)
    (elpaca-generate-autoloads "elpaca" repo)
    (let ((load-source-file-function nil)) (load "./elpaca-autoloads"))))
(add-hook 'after-init-hook #'elpaca-process-queues)
(elpaca `(,@elpaca-order))

(if debug-on-error
    (setq use-package-verbose t
          use-package-expand-minimally nil
          use-package-compute-statistics t)
  (setq use-package-verbose nil
        use-package-expand-minimally t))
#+end_src

Elpaca supports =use-package= so hook that up, and add a =use-feature= macro
that adds a similar construct for configuring already loaded emacs packages and
features.

#+begin_src emacs-lisp
<<elpaca-boilerplate>>

(defmacro use-feature (name &rest args)
  "Like `use-package' but accounting for asynchronous installation.
  NAME and ARGS are in `use-package'."
  (declare (indent defun))
  `(use-package ,name
     :ensure nil
     ,@args))

(elpaca elpaca-use-package
  (require 'elpaca-use-package)
  (elpaca-use-package-mode)
  (setq use-package-always-ensure t))
#+end_src

#+INCLUDE: "config/editing.org" :minlevel 1

#+INCLUDE: "config/gc.org" :minlevel 1

#+INCLUDE: "config/tidy.org" :minlevel 1

#+INCLUDE: "config/auth.org" :minlevel 1

#+INCLUDE: "config/path.org" :minlevel 1

#+INCLUDE: "config/profiling.org" :minlevel 1

#+INCLUDE: "config/general.org" :minlevel 1

#+INCLUDE: "config/formatting.org" :minlevel 1

#+INCLUDE: "config/documentation.org" :minlevel 1

#+INCLUDE: "config/social.org" :minlevel 1

#+INCLUDE: "config/modal.org" :minlevel 1

#+INCLUDE: "config/qol.org" :minlevel 1

#+INCLUDE: "config/hydra.org" :minlevel 1

# #+INCLUDE: "config/bufferlo.org" :minlevel 1
#+INCLUDE: "config/ibuffer.org" :minlevel 1

#+INCLUDE: "config/error.org" :minlevel 1

#+INCLUDE: "config/completion.org" :minlevel 1

#+INCLUDE: "config/files.org" :minlevel 1

#+INCLUDE: "config/terminal.org" :minlevel 1

#+INCLUDE: "config/style.org" :minlevel 1

#+INCLUDE: "config/vcs.org" :minlevel 1

#+INCLUDE: "config/lsp.org" :minlevel 1

#+INCLUDE: "config/treesitter.org" :minlevel 1

#+INCLUDE: "config/major_modes.org" :minlevel 1

#+INCLUDE: "config/org_mode.org" :minlevel 1

#+INCLUDE: "config/snippets.org" :minlevel 1

#+INCLUDE: "config/custom.org" :minlevel 1

#+begin_src emacs-lisp :exports none
(maybe-load-rel "custom.el")

(provide 'init)
;;; init.el ends here

#+end_src
