#!/usr/bin/env bash
# ----------------------------------------------------------------------
#  INITIALIZE the HAMACS SYSTEM
# ----------------------------------------------------------------------

# shellcheck disable=SC2164
HAMACS_DIR=$(cd "$(dirname "$0")"; pwd)
HAMACS_DEST=$HOME/.emacs.d

cd "$HAMACS_DIR"
mkdir -p "$HAMACS_DEST"

for LINK in snippets templates elisp
do
    echo "Symlinking $HAMACS_DEST/$LINK to $HAMACS_DIR/$LINK ..."
    rm -rf "${HAMACS_DEST:-~}/$LINK"
    ln -s "$HAMACS_DIR/$LINK" "$HAMACS_DEST"
done

cat > "$HAMACS_DEST/early-init.el" <<EOF
;;; early-init.el --- Hamacs Early Init -*- lexical-binding: t; -*-
;;
;;    ▄████████   ▄▄▄▄███▄▄▄▄     ▄████████  ▄████████  ▄████████
;;   ███    ███ ▄██▀▀▀███▀▀▀██▄  ███    ███ ███    ███ ███    ███
;;   ███    █▀  ███   ███   ███  ███    ███ ███    █▀  ███    █▀
;;  ▄███▄▄▄     ███   ███   ███  ███    ███ ███        ███
;; ▀▀███▀▀▀     ███   ███   ███▀███████████ ███      ▀███████████
;;   ███    █▄  ███   ███   ███  ███    ███ ███    █▄         ███
;;   ███    ███ ███   ███   ███  ███    ███ ███    ███  ▄█    ███
;;   ██████████  ▀█   ███   █▀   ███    █▀  ████████▀ ▄████████▀
;;
;;; Commentary:
;;
;; This is my early Emacs configuration file. See init.el for the real
;; boot process. Since we are using elpaca, we just need to stop the
;; normal package process.
;;
;;; Code:

;; Need the package system near the front:
;; (require 'package)

;; We'll be using elpaca. So, we don't want duplicated package loading:
(setq package-enable-at-startup nil)

;; While I would rather program my configurations, sometimes the Emacs
;; menu system is _good enough_, but I want it in its own file:

(setq custom-file (expand-file-name "custom.el" user-emacs-directory))
(when (file-exists-p custom-file)
  (load custom-file))

;; Let's build the \`exec-path' from the _real_ shell path:
EOF

IFS=":" read -r -a PATH_ARRAY <<< "${PATH}"
for P in "${PATH_ARRAY[@]}"
do
  echo "(add-to-list 'exec-path \"${P}\")" >> "$HAMACS_DEST/early-init.el"
done

cat >> "$HAMACS_DEST/early-init.el" <<EOF
;; Local Variables:
;; no-byte-compile: t
;; no-native-compile: t
;; no-update-autoloads: t
;; End:

;;; early-init.el ends here
EOF

echo "Created $HAMACS_DEST/early-init.el"


cat > "$HAMACS_DEST/init.el" <<EOF
;;; init.el --- Hamacs Init -*- lexical-binding: t; -*-
;;
;;   :::::::::: ::::    ::::      :::      ::::::::   ::::::::
;;   :+:        +:+:+: :+:+:+   :+: :+:   :+:    :+: :+:    :+:
;;   +:+        +:+ +:+:+ +:+  +:+   +:+  +:+        +:+
;;   +#++:++#   +#+  +:+  +#+ +#++:++#++: +#+        +#++:++#++
;;   +#+        +#+       +#+ +#+     +#+ +#+               +#+
;;   #+#        #+#       #+# #+#     #+# #+#    #+# #+#    #+#
;;   ########## ###       ### ###     ###  ########   ########
;;
;;; Commentary:
;;
;; This is my Emacs Bootloader. Simply put, I initialize the package
;; management system, and then tangle my literate files. This simple
;; idea came from https://github.com/susamn/dotfiles
;;
;;; Code:

(defvar hamacs-source-dir "$HAMACS_DIR" "Where we be.")

;; Bug fixes for ORG (there always seems to be something):
(defvar native-comp-deferred-compilation-deny-list nil)

;; Elpaca doesn't use package.el, so no package archives are needed.
;; Install and configure Elpaca, see the installer at:
;; https://github.com/progfolio/elpaca#installer

(defvar elpaca-installer-version 0.12)
(defvar elpaca-directory (expand-file-name "elpaca/" user-emacs-directory))
(defvar elpaca-builds-directory (expand-file-name "builds/" elpaca-directory))
(defvar elpaca-sources-directory (expand-file-name "sources/" 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)))
(let* ((repo  (expand-file-name "elpaca/" elpaca-sources-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))

;; Enable the :elpaca keyword for use-package, and wait for it, since
;; everything else in my configuration depends on it:

(require 'use-package)

(elpaca elpaca-use-package
  (elpaca-use-package-mode))
(elpaca-wait)

;; Replace straight's \`straight-use-package-by-default'. Every
;; use-package declaration installs its package, unless it says
;; otherwise, e.g. ':elpaca nil' for built-in features. Note that
;; \`use-package-always-ensure' won't work, as it only considers the
;; :ensure keyword.

(add-to-list 'use-package-defaults
             '(:elpaca (list t)
                       (lambda (name args)
                         (not (or (plist-member args :ensure)
                                  (plist-member args :load-path)
                                  (elpaca-get name))))) t)

;; Eglot and its dependencies (project, flymake, xref, jsonrpc, etc.)
;; ship with Emacs. Elpaca already ignores built-in packages when
;; resolving dependencies, see \`elpaca-ignored-dependencies'.

;; Install the latest org-mode, and wait, since we need it to load
;; the rest of the configuration:

(use-package org)
(elpaca-wait)

;; Let's rock:
(org-babel-load-file "$HAMACS_DIR/bootstrap.org")

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

echo "Created $HAMACS_DEST/init.el"
