;; [[file:~/.common/.emacs.d/init-emacs.org::*Init][Init:1]]
;; -*- mode: emacs-lisp; lexical-binding: t; no-byte-compile: t -*-
;;==============================================================================
;; init.el
;;
;;; Bootstrap Emacs Initialization File
;;
;; Author: Kyle W T Sherman
;;
;; This file was generated from init-emacs.org and should not be edited
;; manually.
;;
;; init-emacs.org ==> init.el
;;==============================================================================

;;------------------------------------------------------------------------------
;;; Bootstrap (Org/Babel)
;;------------------------------------------------------------------------------

;; generate elisp and compiled elisp files from an org-babel file
(defun org-babel-generate-elisp-file (file &optional byte-compile force)
  "Generate an emacs-lisp file from an org-babel FILE.
Additionally, byte compile the file if BYTE-COMPILE is non-nil.
Process file even if timestamp is not newer than target if FORCE is non-nil."
  (let* ((file-base (expand-file-name (file-name-sans-extension file)))
         (file-org (concat (file-name-base file) ".org"))
         (file-elisp (concat file-base ".el"))
         (file-comp (concat file-elisp "c"))
         (heading-regexp "^\*+ ")
         (heading-comment-regexp "^\*+ COMMENT ")
         (begin-regexp "^#\\+BEGIN_SRC emacs-lisp")
         (begin-tangle-regexp "^#\\+BEGIN_SRC .*:tangle ")
         (end-regexp "^#\\+END_SRC")
         (indent-regexp "^  "))
    ;; generate elisp file if needed
    (when (or force
              (not (file-exists-p file-elisp))
              (file-newer-than-file-p file-org file-elisp))
      (message "Writing %s..." file-elisp)
      (with-temp-file file-elisp
        (insert-file-contents file)
        (goto-char (point-min))
        (let (code
              headings-counts
              (level 1)
              (comment-level 0)
              (end-comment ""))
          (while (not (eobp))
            (cond
             ;; comment heading
             ((looking-at heading-comment-regexp)
              (setq level (/ (- (match-end 0) (point-at-bol) 8) 2))
              (when (or (zerop comment-level)
                        (< level comment-level))
                (setq comment-level level))
              (delete-region (point-at-bol) (progn (forward-line) (point))))
             ;; normal heading
             ((looking-at heading-regexp)
              (setq level (/ (- (match-end 0) (point-at-bol)) 2))
              (when (or (zerop comment-level)
                        (<= level comment-level))
                (setq comment-level 0)
                (if (assoc level headings-counts)
                    (setf (cdr (assoc level headings-counts))
                          (cons (buffer-substring-no-properties (match-end 0) (point-at-eol)) 1))
                  (setq headings-counts (append headings-counts (list (cons level (cons "No heading" 1)))))))
              (delete-region (point-at-bol) (progn (forward-line) (point))))
             ;; start of tangled source block
             ((and (looking-at begin-regexp)
                   (zerop comment-level)
                   (not (looking-at begin-tangle-regexp))) ; skip blocks with their own tangle directive
              (let* ((heading-count (cdr (assoc level headings-counts)))
                     (heading (car heading-count))
                     (count (cdr heading-count)))
                (delete-region (point-at-bol) (progn (forward-line) (point)))
                (unless (bobp)
                  (newline))
                (when (fboundp 'org-link-escape)
                  (insert (format ";; [[file:%s::*%s][%s:%s]]\n" file-org (org-link-escape heading) heading count))
                  (setq end-comment (format ";; %s:%s ends here\n" heading count))
                  (incf (cddr (assoc level headings-counts))))
                (setq code t)))
             ;; end of tangled source block
             ((and code
                   (looking-at end-regexp))
              (delete-region (point-at-bol) (progn (forward-line) (point)))
              (insert end-comment)
              (setq code nil
                    end-comment ""))
             ;; inside tangled source block
             (code
              (when (looking-at indent-regexp)
                (delete-char (if (boundp 'org-edit-src-content-indentation)
                                 org-edit-src-content-indentation
                               2)))
              (forward-line))
             ;; outside tangled source block
             (t
              (delete-region (point-at-bol) (progn (forward-line) (point))))))
          (time-stamp))
        (message "Wrote %s..." file-elisp)))
    ;; byte compile elisp file if needed
    (when (and byte-compile
               (or (not (file-exists-p file-comp))
                   (file-newer-than-file-p file-elisp file-comp)))
      (byte-compile-file file-elisp))))

;; generate and load main init file
(let* ((file-base (expand-file-name "~/.emacs.d/init-emacs"))
       (file-org (concat file-base ".org"))
       (file-elisp (concat file-base ".el")))
  ;; do not try to byte compile the generated file as it will fail since our environment is not setup
  (org-babel-generate-elisp-file file-org)
  (if (file-exists-p file-elisp)
      (load file-elisp)
    (message "Error loading %s" file-elisp)))

;;------------------------------------------------------------------------------
;;; Slow Bootstrap (Org/Babel)
;;------------------------------------------------------------------------------

;; (let* ((emacs-dir (expand-file-name (file-name-directory (or (buffer-file-name) load-file-name))))
;;        (modules-dir (expand-file-name "modules" emacs-dir)))
;;   (add-to-list 'load-path (expand-file-name "org-mode/lisp" modules-dir))
;;   (add-to-list 'load-path (expand-file-name "org-mode/contrib/lisp" modules-dir))

;;   ;; load org-mode and org-babel
;;   (require 'org-install)
;;   (require 'ob-tangle)

;;   ;; load all literate org-mode files in this directory
;;   (mapc #'org-babel-load-file (directory-files emacs-dir t "\\.org$")))

;;==============================================================================
;;; init.el ends here
;;==============================================================================
;; Init:1 ends here