;; [[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 (asynchronously if it is :async).

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-base ".elc"))
         (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
              (level 1)
              (comment-level 0)
              (end-comment ""))
          (while (not (eobp))
             ;; comment heading
             ((looking-at heading-comment-regexp)
              (setq level (/ (- (match-end 0) (line-beginning-position) 8) 2))
              (when (or (zerop comment-level)
                        (< level comment-level))
                (setq comment-level level))
              (delete-region (line-beginning-position) (progn (forward-line) (point))))
             ;; normal heading
             ((looking-at heading-regexp)
              (setq level (/ (- (match-end 0) (line-beginning-position)) 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) (line-end-position)) 1))
                  (setq headings-counts (append headings-counts (list (cons level (cons "No heading" 1)))))))
              (delete-region (line-beginning-position) (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 (line-beginning-position) (progn (forward-line) (point)))
                (unless (bobp)
                (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 (line-beginning-position) (progn (forward-line) (point)))
              (insert end-comment)
              (setq code nil
                    end-comment ""))
             ;; inside tangled source block
              (when (looking-at indent-regexp)
                (delete-char (if (boundp 'org-edit-src-content-indentation)
             ;; outside tangled source block
              (delete-region (line-beginning-position) (progn (forward-line) (point))))))
        (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)))
      (if (and (eq byte-compile :async)
               (fboundp 'async-start))
           `(lambda ()
              (message "Byte compiling %s..." ,file-elisp)
              (byte-compile-file ,file-elisp))
        (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 load-file-name (buffer-file-name) (buffer-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