;;; emacs-lisp.el -*- lexical-binding: t; -*-

(require 'syd-handle-repl)
(require 'syd-handle-lookup)
(require 'syd-handle-eval)
(require 'syd-lisp-lib)
;; (require 'handle)

;; Don't `use-package' `ielm', since it's loaded by Emacs.  You'll get weird
;; autoload errors if you do.
;; https://www.reddit.com/r/emacs/comments/q7fjbi/comment/lml127d
(use-package emacs
  :custom ((ielm-history-file-name ; Stay out of my config dir!
            (file-name-concat syd-cache-dir "ielm-history.eld"))))

;;;###autoload
(defun syd/open-emacs-lisp-repl ()
  (interactive)
  (pop-to-buffer
   (or (get-buffer "*ielm*")
       (progn (ielm) ; Creates the *ielm* buffer.
              (let ((b (get-buffer "*ielm*")))
                ;; We leave it to the enclosing `pop-to-buffer' to display the
                ;; buffer.
                (bury-buffer b)
                b)))))

;;;###autoload
(defun syd-emacs-lisp-lookup-documentation (identifier)
  "Lookup IDENTIFIER with `describe-symbol'"
  ;; HACK: Much to my frustration, `describe-symbol' has no defined return
  ;; value.  To test if the call was successful or not, we check if any window
  ;; is displaying the help buffer.  This breaks if
  ;; `syd-emacs-lisp-lookup-documentation' is called while the help buffer is
  ;; already open.
  (describe-symbol (intern identifier))
  (let ((buffer (get-buffer (help-buffer))))
    (and (get-buffer-window-list buffer)
         buffer)))

;;;###autoload
(defun syd-emacs-lisp-eval (beg end)
  "Evaluate a region and print it to the echo area (if one line long), otherwise
to a pop up buffer."
  (syd-eval-display-results
   (string-trim-right
    (let ((buffer (generate-new-buffer " *eval-output*"))
          (debug-on-error t))
      (unwind-protect
          (condition-case-unless-debug e
              (progn (eval-region beg end buffer load-read-function)
                     (with-current-buffer buffer
                       (let ((pp-max-width nil))
                         (require 'pp)
                         (pp-buffer)
                         (replace-regexp-in-string
                          "\\\\n" "\n" (string-trim-left (buffer-string))))))
            (error (format "ERROR: %s" e)))
        (kill-buffer buffer))))
   :source-buffer (current-buffer)
   :force-popup current-prefix-arg))

(dolist (m '(emacs-lisp-mode lisp-data-mode))
  (set-repl-handler! m
    #'syd/open-emacs-lisp-repl)
  (set-eval-handler! m
    #'syd-emacs-lisp-eval))

(syd-add-hook '(emacs-lisp-mode-hook lisp-data-mode-hook)
  #'syd-lisp-mode)

;; DEPRECATED: Remove once syd-strategies is working.
(syd-add-hook '(emacs-lisp-mode-hook help-mode-hook lisp-data-mode-hook)
  (defun syd-emacs-set-handlers-h ()
    (setq-local syd-lookup-documentation-handlers
                (list #'syd-emacs-lisp-lookup-documentation))))

;; Semantic highlighting for Elisp.
(use-package highlight-defined
  :hook (emacs-lisp-mode-hook . highlight-defined-mode))

;; Automatically and inteligently expand abbreviations.  E.g. `wcb` will be
;; expanded to `(with-current-buffer)`, but only where it makes sense for a
;; function/macro call to be.
(use-package sotlisp
  :straight (:host github
             :repo "Malabarba/speed-of-thought-lisp")
  :hook (emacs-lisp-mode . speed-of-thought-mode))

;; Give different pairs of delimiters different colours.
(use-package rainbow-delimiters
  :hook (emacs-lisp-mode . rainbow-delimiters-mode))

(use-package macrostep
  :commands (macrostep-expand)
  :init
  (general-define-key
   :keymaps 'emacs-lisp-mode-map
   :states '(normal visual motion emacs insert)
   :major-modes t
   :prefix syd-localleader-key
   :non-normal-prefix syd-alt-localleader-key
   "m" #'macrostep-expand))

(provide 'syd-lang-emacs-lisp)
