;;; -*- lexical-binding: t; -*-

(require 'syd/base)
(require 'syd/handle)
(require 'syd/popups)
(require 'syd/leader)

(use-package clojure-mode
  :mode (("\\.\\(clj\\|cljd\\|dtm\\|edn\\|lpy\\)\\'" . clojure-mode)
         ("\\.cljc\\'" . clojurec-mode)
         ("\\.cljs\\'" . clojurescript-mode)
         ("\\(?:build\\|profile\\)\\.boot\\'" . clojure-mode))
  :interpreter (("bb" . clojure-mode)
                ("nbb" . clojurescript-mode))
  :config
  (add-hook 'clojure-mode-hook #'syd-lisp-mode)
  ;; Correctly indent some popular macros.
  (put-clojure-indent 'for-all 1)
  (put-clojure-indent 'match 1))

(use-package cider
  :after clojure-mode
  :config

  (defun syd-clojure-doc (arg)
    (interactive "P")
    (cider-doc arg)
    cider-doc-buffer)

  (defun syd-clojure-eval-region (beg end)
    (cider-eval-region beg end))

  (syd-handle '(clojure-mode clojurescript-mode cider-repl-mode)
    :docs #'cider-doc
    :eval-region #'syd-clojure-eval-region
    :load-buffer #'cider-load-buffer)

  (add-hook 'cider-repl-mode-hook #'syd-lisp-mode)

  (syd-push shackle-rules
            `("*cider-doc*" ,@syd-help-popup-options)
            '("*cider-test-report*")
            '("*cider-error*"))

  (defun syd-clojure-classpath-relative-file-name (file-name)
    (when (and cider-mode (cider-nrepl-eval-session))
      (let ((prefixes (-filter #'file-directory-p
                               (cider-classpath-entries))))
        (cl-loop for classpath-entry in prefixes
                 for prefix = (file-name-as-directory classpath-entry)
                 when (string-prefix-p prefix file-name)
                 return (string-remove-prefix prefix file-name)))))
  (add-to-list 'syd-insert-file-name-alist
               `(,#'syd-clojure-classpath-relative-file-name
                 . "Classpath-relative")))

(use-package cider-mode
  :straight nil        ; Part of `cider'.
  :hook (clojure-mode-local-vars . cider-mode)
  :custom ((cider-show-error-buffer nil)
           ;; Download Java source archives for local Javadoc and jump-to-def
           ;; functionality.
           (cider-download-java-sources t))
  :general
  (:keymaps 'cider-repl-mode-map
   :states '(normal insert)
   "C-k" #'cider-repl-backward-input
   "C-j" #'cider-repl-forward-input
   "C-s" #'consult-history)
  (:keymaps '(cider-repl-mode-map clojure-mode-map)
   :states '(normal visual motion emacs insert)
   :major-modes t
   :prefix syd-localleader-key
   :non-normal-prefix syd-alt-localleader-key
   "\"" #'cider-jack-in-cljs
   "'" #'cider-jack-in-clj
   "c" #'cider-connect-clj
   "C" #'cider-connect-cljs
   "r l" #'cider-load-buffer
   "r n" #'cider-repl-set-ns
   "r r" #'cider-ns-refresh
   "r R" #'cider-restart
   "r q" #'cider-quit
   "d d" #'cider-debug-defun-at-point
   "M-:" #'cider-read-and-eval
   "h d" #'cider-doc
   "h c" #'cider-cheatsheet
   "h j" #'cider-javadoc
   "h n" #'cider-browse-ns
   "T n" #'cider-test-run-ns-tests
   "T r" #'cider-test-rerun-failed-tests
   "T R" #'cider-test-rerun-test
   "x" #'cider-scratch
   "i" #'cider-inspect-last-result)
  (:keymaps 'cider-repl-mode-map
   :states 'insert
   "S-<return>" #'cider-repl-newline-and-indent)
  (:keymaps 'cider-inspector-mode-map
   :states '(motion insert)
   "C-o" #'cider-inspector-pop
   "C-i" #'cider-inspector-push)
  :config
  (add-hook 'cider-mode-hook #'eldoc-mode)
  (with-eval-after-load 'consult
    (add-to-list
     'consult-mode-histories
     '(cider-repl-mode cider-repl-input-history nil cider-repl-bol-mark)))
  
  ;; Lines of the form "!!!graph:/path/to/file.svg" are be displayed
  ;; in-buffer by this hook.
  (syd-add-hook 'cider-repl-preoutput-hook
    (defun syd-clojure--render-graphviz-h (s)
      (if (string-match (rx bol "!!!graph:"
                            (group (* anychar) ".svg"))
                        s)
          (let ((beg (match-beginning 0))
                (end (match-end 0))
                (file (match-string 1 s)))
            (message "%d %d %s" beg end file)
            (add-display-text-property
             beg end
             'display
             `(image :type svg
                     :file ,file)
             s)
            s)
        s))))

(defun syd-clojure--setup-clj-refactor ()
  (clj-refactor-mode 1)
  (yas-minor-mode 1)
  (cljr-add-keybindings-with-prefix "C-c r"))

(use-package clj-refactor
  :config
  (add-hook 'clojure-mode-hook #'syd-clojure--setup-clj-refactor)
  (dolist (x '(("p" . "babashka.process")
               ("fs" . "babashka.fs")))
    (add-to-list 'cljr-magic-require-namespaces x)))

(provide 'syd/clojure)
