From 190deb134a1c04333c052e4a551913a142514d00 Mon Sep 17 00:00:00 2001 From: Sameer Rahmani Date: Thu, 22 Sep 2016 22:08:54 +0330 Subject: [PATCH] clojure mode enhanced --- fg42 | 4 +- fg42-config.el | 7 +- lib/extensions/clojure.el | 3 + lib/extensions/clojure/core.el | 310 +++++++++++++++++++++++++++++++ lib/extensions/clojure/init.el | 64 ++----- lib/extensions/clojure/utils.el | 311 ++++++++++++++++++++++++++++++++ 6 files changed, 646 insertions(+), 53 deletions(-) create mode 100644 lib/extensions/clojure/core.el create mode 100644 lib/extensions/clojure/utils.el diff --git a/fg42 b/fg42 index 1e549c4..9795983 100755 --- a/fg42 +++ b/fg42 @@ -1,7 +1,7 @@ #! /bin/sh #export FG42_HOME=--PATH-- -export FG42_HOME=$HOME/FG42 +export FG42_HOME=$HOME/src/FG42 #emacs -Q --no-splash --name FG42 --title FG42 -q -l --PATH--/fg42-config.el "$@" -emacs --name FG42 -q --no-site-file --no-site-lisp --no-splash --title FG42 -l $FG42_HOME/fg42-config.el "$@" +emacs-snapshot --name FG42 -q --no-site-file --no-site-lisp --no-splash --title FG42 -l $FG42_HOME/fg42-config.el "$@" diff --git a/fg42-config.el b/fg42-config.el index a35fd5c..7a4f306 100644 --- a/fg42-config.el +++ b/fg42-config.el @@ -13,12 +13,13 @@ 'development 'web 'editor-theme - 'arduino + ;'arduino 'javascript ;'php - ;'clojure + 'clojure ;'python - 'ruby) + ;'ruby + ) ;; Load user config file in ~/.fg42 (load-user-config "~/.fg42") diff --git a/lib/extensions/clojure.el b/lib/extensions/clojure.el index df36ac6..c1396b1 100644 --- a/lib/extensions/clojure.el +++ b/lib/extensions/clojure.el @@ -12,6 +12,9 @@ (depends-on 'clj-refactor) (depends-on 'let-alist) (depends-on 'flycheck-clojure) +(depends-on 'clojure-mode-extra-font-locking) +;(depends-on 'core-async-mode) +(depends-on 'yesql-ghosts) ;; Extension ------------------------------------- (extension clojure diff --git a/lib/extensions/clojure/core.el b/lib/extensions/clojure/core.el new file mode 100644 index 0000000..6957d35 --- /dev/null +++ b/lib/extensions/clojure/core.el @@ -0,0 +1,310 @@ +;; Add requires to blank devcards files +(defun cljr--find-source-ns-of-devcard-ns (test-ns test-file) + (let* ((ns-chunks (split-string test-ns "[.]" t)) + (test-name (car (last ns-chunks))) + (src-dir-name (s-replace "devcards/" "src/" (file-name-directory test-file))) + (replace-underscore (-partial 's-replace "_" "-")) + (src-ns (car (--filter (or (s-prefix-p it test-name) + (s-suffix-p it test-name)) + (-map (lambda (file-name) + (funcall replace-underscore + (file-name-sans-extension file-name))) + (directory-files src-dir-name)))))) + (when src-ns + (mapconcat 'identity (append (butlast ns-chunks) (list src-ns)) ".")))) + +(defun clj--find-devcards-component-name () + (or + (ignore-errors + (with-current-buffer + (find-file-noselect (clj--src-file-name-from-cards (buffer-file-name))) + (save-excursion + (goto-char (point-max)) + (search-backward "defcomponent ") + (clojure-forward-logical-sexp) + (skip-syntax-forward " ") + (let ((beg (point)) + (end (progn (re-search-forward "\\w+") + (point)))) + (buffer-substring-no-properties beg end))))) + "")) + +(defun cljr--add-card-declarations () + (save-excursion + (let* ((ns (clojure-find-ns)) + (source-ns (cljr--find-source-ns-of-devcard-ns ns (buffer-file-name)))) + (cljr--insert-in-ns ":require") + (when source-ns + (insert "[" source-ns " :refer [" (clj--find-devcards-component-name) "]]")) + (cljr--insert-in-ns ":require") + (insert "[devcards.core :refer-macros [defcard]]")) + (indent-region (point-min) (point-max)))) + +(defun live-delete-and-extract-sexp () + "Delete the sexp and return it." + (interactive) + (let* ((begin (point))) + (forward-sexp) + (let* ((result (buffer-substring-no-properties begin (point)))) + (delete-region begin (point)) + result))) + +(defun live-cycle-clj-coll () + "convert the coll at (point) from (x) -> {x} -> [x] -> (x) recur" + (interactive) + (let* ((original-point (point))) + (while (and (> (point) 1) + (not (equal "(" (buffer-substring-no-properties (point) (+ 1 (point))))) + (not (equal "{" (buffer-substring-no-properties (point) (+ 1 (point))))) + (not (equal "[" (buffer-substring-no-properties (point) (+ 1 (point)))))) + (backward-char)) + (cond + ((equal "(" (buffer-substring-no-properties (point) (+ 1 (point)))) + (insert "{" (substring (live-delete-and-extract-sexp) 1 -1) "}")) + ((equal "{" (buffer-substring-no-properties (point) (+ 1 (point)))) + (insert "[" (substring (live-delete-and-extract-sexp) 1 -1) "]")) + ((equal "[" (buffer-substring-no-properties (point) (+ 1 (point)))) + (insert "(" (substring (live-delete-and-extract-sexp) 1 -1) ")")) + ((equal 1 (point)) + (message "beginning of file reached, this was probably a mistake."))) + (goto-char original-point))) + + +(defun my-toggle-expect-focused () + (interactive) + (save-excursion + (search-backward "(expect" (cljr--point-after 'cljr--goto-toplevel)) + (forward-word) + (if (looking-at "-focused") + (paredit-forward-kill-word) + (insert "-focused")))) + +(defun my-remove-all-focused () + (interactive) + (save-excursion + (goto-char (point-min)) + (while (search-forward "(expect-focused" nil t) + (delete-char -8)))) + +(defun clj-duplicate-top-level-form () + (interactive) + (save-excursion + (cljr--goto-toplevel) + (insert (cljr--extract-sexp) "\n") + (cljr--just-one-blank-line))) + +(defun clj-hippie-expand-no-case-fold () + (interactive) + (let ((old-syntax (char-to-string (char-syntax ?/)))) + (modify-syntax-entry ?/ " ") + (hippie-expand-no-case-fold) + (modify-syntax-entry ?/ old-syntax))) + +(defun nrepl-warn-when-not-connected () + (interactive) + (message "Oops! You're not connected to an nREPL server. Please run M-x cider or M-x cider-jack-in to connect.")) + + +;;;###autoload +(defun cljr-init () + (interactive) + (require 'clj-refactor) + + (clj-refactor-mode 1) + + (setq cljr-magic-require-namespaces + '(("io" . "clojure.java.io") + ("set" . "clojure.set") + ("str" . "clojure.string") + ("walk" . "clojure.walk") + ("zip" . "clojure.zip") + ("time" . "clj-time.core") + ("log" . "clojure.tools.logging") + ("json" . "cheshire.core"))) + + ;; refer all from expectations + (setq cljr-expectations-test-declaration "[expectations :refer :all]") + + ;; insert keybinding setup here + (cljr-add-keybindings-with-prefix "C-c RET") + (setq cljr-favor-prefix-notation nil) + (setq cljr-favor-private-functions nil) + + ;; Don't warn me about the dangers of clj-refactor, fire the missiles! + (setq cljr-warn-on-eval nil) + + (add-hook 'clojure-mode-hook #'yas-minor-mode) + + ;; no auto sort + (setq cljr-auto-sort-ns nil) + + ;; do not prefer prefixes when using clean-ns + (setq cljr-favor-prefix-notation nil) + + (cljr-add-keybindings-with-modifier "C-s-") + + (define-key clj-refactor-map (kbd "C-x C-r") 'cljr-rename-file) + (define-key clojure-mode-map [remap paredit-forward] 'clojure-forward-logical-sexp) + (define-key clojure-mode-map [remap paredit-backward] 'clojure-backward-logical-sexp) + (define-key clojure-mode-map (kbd "C->") 'cljr-thread) + (define-key clojure-mode-map (kbd "C-<") 'cljr-unwind) + (define-key clj-refactor-map + (cljr--key-pairs-with-modifier "C-s-" "xf") 'my-toggle-expect-focused) + + (define-key clj-refactor-map + (cljr--key-pairs-with-modifier "C-s-" "xr") 'my-remove-all-focused) + + (defadvice cljr--add-ns-if-blank-clj-file (around add-devcards activate) + (ignore-errors + (when (and cljr-add-ns-to-blank-clj-files + (cljr--clojure-ish-filename-p (buffer-file-name)) + (= (point-min) (point-max))) + ad-do-it + (when (clj--is-card? (buffer-file-name)) + (cljr--add-card-declarations))))) + + (defadvice cljr-find-usages (before setup-grep activate) + (window-configuration-to-register ?$))) + +;;;###autoload +(defun clojure-mode-init () + (interactive) + + (require 'clojure-mode-extra-font-locking) + (require 'cider) + (require 'yesql-ghosts) + (require 'hl-sexp) + (require 'paredit) + + ;; indent [quiescent.dom :as d] specially + (define-clojure-indent + (d/a 1) + (d/button 1) + (d/div 1) + (d/form 1) + (d/h1 1) + (d/h2 1) + (d/h3 1) + (d/h4 1) + (d/h5 1) + (d/hr 1) + (d/img 1) + (d/label 1) + (d/li 1) + (d/option 1) + (d/p 1) + (d/pre 1) + (d/select 1) + (d/small 1) + (d/span 1) + (d/strong 1) + (d/ul 1) + (d/svg 1) + + ;; Hafslund specifics + (e/prose 1) + (e/value 1) + (e/section 1) + (e/section-prose 1) + (e/page 1) + (e/instructions 1) + (l/padded 1) + (l/bubble-grid 1) + (l/slider 1) + (l/bottom-fixed 1) + (c/box 1) + (c/group 1) + (c/list 1)) + + (defadvice clojure-test-run-tests (before save-first activate) + (save-buffer)) + + (defadvice nrepl-load-current-buffer (before save-first activate) + (save-buffer)) + + (setq cider-pprint-fn 'pprint) + + (setq cider-repl-history-file tmp-directory) + + ;; nice pretty printing + (setq cider-repl-use-pretty-printing t) + + ;; nicer font lock in REPL + (setq cider-repl-use-clojure-font-lock t) + + ;; result prefix for the REPL + (setq cider-repl-result-prefix ";; => ") + + ;; never ending REPL history + (setq cider-repl-wrap-history t) + + ;; looong history + (setq cider-repl-history-size 3000) + + + ;; error buffer not popping up + (setq cider-show-error-buffer nil) + + ;; Use figwheel for cljs repl + (setq cider-cljs-lein-repl "(do (use 'figwheel-sidecar.repl-api) (start-figwheel!) (cljs-repl))") + + ;; Indent and highlight more commands + (put-clojure-indent 'match 'defun) + + ;; Hide nrepl buffers when switching buffers (switch to by prefixing with space) + (setq nrepl-hide-special-buffers t) + + ;; Enable error buffer popping also in the REPL: + (setq cider-repl-popup-stacktraces t) + + ;; Specify history file + (setq cider-history-file "~/.tmp/nrepl-history") + + ;; auto-select the error buffer when it's displayed + (setq cider-auto-select-error-buffer t) + + ;; Prevent the auto-display of the REPL buffer in a separate window after connection is established + (setq cider-repl-pop-to-buffer-on-connect nil) + + ;; Pretty print results in repl + (setq cider-repl-use-pretty-printing t) + + ;; Don't prompt for symbols + (setq cider-prompt-for-symbol nil) + + ;; eldoc for clojure + (add-hook 'cider-mode-hook #'eldoc-mode) + (add-hook 'clojure-mode-hook #'paredit-mode) + (add-hook 'cider-repl-mode-hook #'paredit-mode) + (add-hook 'clojure-mode-hook #'hl-sexp-mode) + + (define-key clojure-mode-map (kbd "C-`") 'live-cycle-clj-coll) + (define-key cider-repl-mode-map (kbd "") nil) + (define-key cider-repl-mode-map (kbd "C-,") 'complete-symbol) + (define-key cider-mode-map (kbd "C-,") 'complete-symbol) + (define-key cider-mode-map (kbd "C-c C-q") 'nrepl-close) + (define-key cider-mode-map (kbd "C-c C-Q") 'cider-quit) + (define-key clojure-mode-map (kbd "M-s-d") 'clj-duplicate-top-level-form) + + (add-to-list 'cljr-project-clean-functions 'cleanup-buffer) + + (define-key clojure-mode-map (kbd "s-j") 'clj-jump-to-other-file) + (define-key clojure-mode-map (kbd "C-.") 'clj-hippie-expand-no-case-fold) + (define-key clojure-mode-map (kbd "C-M-x") 'nrepl-warn-when-not-connected) + (define-key clojure-mode-map (kbd "C-x C-e") 'nrepl-warn-when-not-connected) + (define-key clojure-mode-map (kbd "C-c C-e") 'nrepl-warn-when-not-connected) + (define-key clojure-mode-map (kbd "C-c C-l") 'nrepl-warn-when-not-connected) + (define-key clojure-mode-map (kbd "C-c C-r") 'nrepl-warn-when-not-connected) + (define-key clojure-mode-map (kbd "C-c C-z") 'nrepl-warn-when-not-connected) + (define-key clojure-mode-map (kbd "C-c C-k") 'nrepl-warn-when-not-connected) + (define-key clojure-mode-map (kbd "C-c C-n") 'nrepl-warn-when-not-connected) + (define-key clojure-mode-map (kbd "C-c C-q") 'nrepl-warn-when-not-connected) + (define-key clojure-mode-map (kbd "M-") 'paredit-forward-slurp-sexp) + (define-key clojure-mode-map (kbd "M-") 'paredit-backward-slurp-sexp) + (define-key clojure-mode-map (kbd "C-") 'right-word) + (define-key clojure-mode-map (kbd "C-") 'left-word) + + + (message "Clojure mode hook ran and initialized clojure-editor ability.")) + +(provide 'extensions/clojure/core) diff --git a/lib/extensions/clojure/init.el b/lib/extensions/clojure/init.el index 03ad109..b76a332 100644 --- a/lib/extensions/clojure/init.el +++ b/lib/extensions/clojure/init.el @@ -1,42 +1,12 @@ +(require 'extensions/clojure/core) + ;;;###autoload (defun extensions/clojure-initialize () ; Clojure development initialization (ability clojure-editor ('flycheck) - (setq tmp-directory "~/.tmp") - (setq cider-repl-history-file tmp-directory) + (add-hook 'clojure-mode-hook 'clojure-mode-init) - ;; nice pretty printing - (setq cider-repl-use-pretty-printing t) - - ;; nicer font lock in REPL - (setq cider-repl-use-clojure-font-lock t) - - ;; result prefix for the REPL - (setq cider-repl-result-prefix ";; => ") - - ;; never ending REPL history - (setq cider-repl-wrap-history t) - - ;; looong history - (setq cider-repl-history-size 3000) - - ;; eldoc for clojure - (add-hook 'cider-mode-hook #'eldoc-mode) - - ;; error buffer not popping up - (setq cider-show-error-buffer nil) - (require 'hl-sexp) - - ;; Paredit - (require 'paredit) - (add-hook 'clojure-mode-hook #'paredit-mode) - (add-hook 'cider-repl-mode-hook #'paredit-mode) - ;(define-key clojure-mode-map (kbd "M-") 'paredit-forward-slurp-sexp) - ;(define-key clojure-mode-map (kbd "M-") 'paredit-backward-slurp-sexp) - ;(define-key clojure-mode-map (kbd "C-") 'right-word) - ;(define-key clojure-mode-map (kbd "C-") 'left-word) - - (add-hook 'clojure-mode-hook #'hl-sexp-mode)) + (setq tmp-directory "~/.tmp")) (ability clojure-completion ('code-completion) ;; company mode for completion @@ -45,22 +15,20 @@ (ability clojure-refactore () - (add-hook 'clojure-mode-hook - (lambda () - (clj-refactor-mode 1) - ;; insert keybinding setup here - (cljr-add-keybindings-with-prefix "C-c RET"))) - - (add-hook 'clojure-mode-hook #'yas-minor-mode) - - ;; no auto sort - (setq cljr-auto-sort-ns nil) - - ;; do not prefer prefixes when using clean-ns - (setq cljr-favor-prefix-notation nil)) + (add-hook 'clojure-mode-hook 'cljr-init)) (ability clojure-check ('flycheck) + (require 'flycheck-clojure) + (eval-after-load 'flycheck '(add-to-list 'flycheck-checkers 'clojure-cider-eastwood)) (eval-after-load 'flycheck '(flycheck-clojure-setup)) - (add-hook 'after-init-hook #'global-flycheck-mode))) + (add-hook 'after-init-hook #'global-flycheck-mode) + ;; Set up linting of clojure code with eastwood + + ;; Make sure to add [acyclic/squiggly-clojure "0.1.2-SNAPSHOT"] + ;; to your :user :dependencies in .lein/profiles.clj + + (add-hook 'cider-mode-hook + '(lambda () + (message "Make sure to add [acyclic/squiggly-clojure \"0.1.2-SNAPSHOT\"] to your :user :dependencies in .lein/profiles.clj"))))) (provide 'extensions/clojure/init) diff --git a/lib/extensions/clojure/utils.el b/lib/extensions/clojure/utils.el new file mode 100644 index 0000000..db783c0 --- /dev/null +++ b/lib/extensions/clojure/utils.el @@ -0,0 +1,311 @@ +(require 'clojure-mode) +(require 'clojure-mode-extra-font-locking) + +(defadvice clojure-test-run-tests (before save-first activate) + (save-buffer)) + +(defadvice nrepl-load-current-buffer (before save-first activate) + (save-buffer)) + +(require 'clj-refactor) + +(setq cljr-favor-prefix-notation nil) +(setq cljr-favor-private-functions nil) + +(cljr-add-keybindings-with-modifier "C-s-") +(define-key clj-refactor-map (kbd "C-x C-r") 'cljr-rename-file) + +(define-key clojure-mode-map [remap paredit-forward] 'clojure-forward-logical-sexp) +(define-key clojure-mode-map [remap paredit-backward] 'clojure-backward-logical-sexp) + +(setq cider-pprint-fn 'pprint) + +(require 'core-async-mode) + +(defun enable-clojure-mode-stuff () + (clj-refactor-mode 1) + (when (not (s-ends-with-p "/dev/user.clj" (buffer-file-name))) + (core-async-mode 1))) + +(add-hook 'clojure-mode-hook 'enable-clojure-mode-stuff) + +(require 'symbol-focus) +(define-key clojure-mode-map (kbd "M-s-f") 'sf/focus-at-point) + +(defun clj-duplicate-top-level-form () + (interactive) + (save-excursion + (cljr--goto-toplevel) + (insert (cljr--extract-sexp) "\n") + (cljr--just-one-blank-line))) + +(define-key clojure-mode-map (kbd "M-s-d") 'clj-duplicate-top-level-form) + +(add-to-list 'cljr-project-clean-functions 'cleanup-buffer) + +(define-key clojure-mode-map (kbd "C->") 'cljr-thread) +(define-key clojure-mode-map (kbd "C-<") 'cljr-unwind) + +(define-key clojure-mode-map (kbd "s-j") 'clj-jump-to-other-file) + +(define-key clojure-mode-map (kbd "C-.") 'clj-hippie-expand-no-case-fold) + +(defun clj-hippie-expand-no-case-fold () + (interactive) + (let ((old-syntax (char-to-string (char-syntax ?/)))) + (modify-syntax-entry ?/ " ") + (hippie-expand-no-case-fold) + (modify-syntax-entry ?/ old-syntax))) + +(require 'cider) + +(define-key cider-repl-mode-map (kbd "") nil) +(define-key cider-repl-mode-map (kbd "C-,") 'complete-symbol) +(define-key cider-mode-map (kbd "C-,") 'complete-symbol) +(define-key cider-mode-map (kbd "C-c C-q") 'nrepl-close) +(define-key cider-mode-map (kbd "C-c C-Q") 'cider-quit) + +(require 'yesql-ghosts) + +;; indent [quiescent.dom :as d] specially + +(define-clojure-indent + (d/a 1) + (d/button 1) + (d/div 1) + (d/form 1) + (d/h1 1) + (d/h2 1) + (d/h3 1) + (d/h4 1) + (d/h5 1) + (d/hr 1) + (d/img 1) + (d/label 1) + (d/li 1) + (d/option 1) + (d/p 1) + (d/pre 1) + (d/select 1) + (d/small 1) + (d/span 1) + (d/strong 1) + (d/ul 1) + (d/svg 1) + + ;; Hafslund specifics + (e/prose 1) + (e/value 1) + (e/section 1) + (e/section-prose 1) + (e/page 1) + (e/instructions 1) + (l/padded 1) + (l/bubble-grid 1) + (l/slider 1) + (l/bottom-fixed 1) + (c/box 1) + (c/group 1) + (c/list 1)) + +;; Don't warn me about the dangers of clj-refactor, fire the missiles! +(setq cljr-warn-on-eval nil) + +;; Use figwheel for cljs repl +(setq cider-cljs-lein-repl "(do (use 'figwheel-sidecar.repl-api) (start-figwheel!) (cljs-repl))") + +;; Indent and highlight more commands +(put-clojure-indent 'match 'defun) + +;; Hide nrepl buffers when switching buffers (switch to by prefixing with space) +(setq nrepl-hide-special-buffers t) + +;; Enable error buffer popping also in the REPL: +(setq cider-repl-popup-stacktraces t) + +;; Specify history file +(setq cider-history-file "~/.emacs.d/nrepl-history") + +;; auto-select the error buffer when it's displayed +(setq cider-auto-select-error-buffer t) + +;; Prevent the auto-display of the REPL buffer in a separate window after connection is established +(setq cider-repl-pop-to-buffer-on-connect nil) + +;; Pretty print results in repl +(setq cider-repl-use-pretty-printing t) + +;; Don't prompt for symbols +(setq cider-prompt-for-symbol nil) + +;; Enable eldoc in Clojure buffers +(add-hook 'cider-mode-hook #'eldoc-mode) + +;; Some expectations features + +(require 'clj-autotest) + +(defun my-toggle-expect-focused () + (interactive) + (save-excursion + (search-backward "(expect" (cljr--point-after 'cljr--goto-toplevel)) + (forward-word) + (if (looking-at "-focused") + (paredit-forward-kill-word) + (insert "-focused")))) + +(defun my-remove-all-focused () + (interactive) + (save-excursion + (goto-char (point-min)) + (while (search-forward "(expect-focused" nil t) + (delete-char -8)))) + +(define-key clj-refactor-map + (cljr--key-pairs-with-modifier "C-s-" "xf") 'my-toggle-expect-focused) + +(define-key clj-refactor-map + (cljr--key-pairs-with-modifier "C-s-" "xr") 'my-remove-all-focused) + +;; Cycle between () {} [] + +(defun live-delete-and-extract-sexp () + "Delete the sexp and return it." + (interactive) + (let* ((begin (point))) + (forward-sexp) + (let* ((result (buffer-substring-no-properties begin (point)))) + (delete-region begin (point)) + result))) + +(defun live-cycle-clj-coll () + "convert the coll at (point) from (x) -> {x} -> [x] -> (x) recur" + (interactive) + (let* ((original-point (point))) + (while (and (> (point) 1) + (not (equal "(" (buffer-substring-no-properties (point) (+ 1 (point))))) + (not (equal "{" (buffer-substring-no-properties (point) (+ 1 (point))))) + (not (equal "[" (buffer-substring-no-properties (point) (+ 1 (point)))))) + (backward-char)) + (cond + ((equal "(" (buffer-substring-no-properties (point) (+ 1 (point)))) + (insert "{" (substring (live-delete-and-extract-sexp) 1 -1) "}")) + ((equal "{" (buffer-substring-no-properties (point) (+ 1 (point)))) + (insert "[" (substring (live-delete-and-extract-sexp) 1 -1) "]")) + ((equal "[" (buffer-substring-no-properties (point) (+ 1 (point)))) + (insert "(" (substring (live-delete-and-extract-sexp) 1 -1) ")")) + ((equal 1 (point)) + (message "beginning of file reached, this was probably a mistake."))) + (goto-char original-point))) + +(define-key clojure-mode-map (kbd "C-`") 'live-cycle-clj-coll) + +;; Warn about missing nREPL instead of doing stupid things + +(defun nrepl-warn-when-not-connected () + (interactive) + (message "Oops! You're not connected to an nREPL server. Please run M-x cider or M-x cider-jack-in to connect.")) + +(define-key clojure-mode-map (kbd "C-M-x") 'nrepl-warn-when-not-connected) +(define-key clojure-mode-map (kbd "C-x C-e") 'nrepl-warn-when-not-connected) +(define-key clojure-mode-map (kbd "C-c C-e") 'nrepl-warn-when-not-connected) +(define-key clojure-mode-map (kbd "C-c C-l") 'nrepl-warn-when-not-connected) +(define-key clojure-mode-map (kbd "C-c C-r") 'nrepl-warn-when-not-connected) +(define-key clojure-mode-map (kbd "C-c C-z") 'nrepl-warn-when-not-connected) +(define-key clojure-mode-map (kbd "C-c C-k") 'nrepl-warn-when-not-connected) +(define-key clojure-mode-map (kbd "C-c C-n") 'nrepl-warn-when-not-connected) +(define-key clojure-mode-map (kbd "C-c C-q") 'nrepl-warn-when-not-connected) + +(setq cljr-magic-require-namespaces + '(("io" . "clojure.java.io") + ("set" . "clojure.set") + ("str" . "clojure.string") + ("walk" . "clojure.walk") + ("zip" . "clojure.zip") + ("time" . "clj-time.core") + ("log" . "clojure.tools.logging") + ("json" . "cheshire.core"))) + +;; refer all from expectations +(setq cljr-expectations-test-declaration "[expectations :refer :all]") + +;; Add requires to blank devcards files +(defun cljr--find-source-ns-of-devcard-ns (test-ns test-file) + (let* ((ns-chunks (split-string test-ns "[.]" t)) + (test-name (car (last ns-chunks))) + (src-dir-name (s-replace "devcards/" "src/" (file-name-directory test-file))) + (replace-underscore (-partial 's-replace "_" "-")) + (src-ns (car (--filter (or (s-prefix-p it test-name) + (s-suffix-p it test-name)) + (-map (lambda (file-name) + (funcall replace-underscore + (file-name-sans-extension file-name))) + (directory-files src-dir-name)))))) + (when src-ns + (mapconcat 'identity (append (butlast ns-chunks) (list src-ns)) ".")))) + +(defun clj--find-devcards-component-name () + (or + (ignore-errors + (with-current-buffer + (find-file-noselect (clj--src-file-name-from-cards (buffer-file-name))) + (save-excursion + (goto-char (point-max)) + (search-backward "defcomponent ") + (clojure-forward-logical-sexp) + (skip-syntax-forward " ") + (let ((beg (point)) + (end (progn (re-search-forward "\\w+") + (point)))) + (buffer-substring-no-properties beg end))))) + "")) + +(defun cljr--add-card-declarations () + (save-excursion + (let* ((ns (clojure-find-ns)) + (source-ns (cljr--find-source-ns-of-devcard-ns ns (buffer-file-name)))) + (cljr--insert-in-ns ":require") + (when source-ns + (insert "[" source-ns " :refer [" (clj--find-devcards-component-name) "]]")) + (cljr--insert-in-ns ":require") + (insert "[devcards.core :refer-macros [defcard]]")) + (indent-region (point-min) (point-max)))) + +(defadvice cljr--add-ns-if-blank-clj-file (around add-devcards activate) + (ignore-errors + (when (and cljr-add-ns-to-blank-clj-files + (cljr--clojure-ish-filename-p (buffer-file-name)) + (= (point-min) (point-max))) + ad-do-it + (when (clj--is-card? (buffer-file-name)) + (cljr--add-card-declarations))))) + +;; Set up linting of clojure code with eastwood + +;; Make sure to add [acyclic/squiggly-clojure "0.1.2-SNAPSHOT"] +;; to your :user :dependencies in .lein/profiles.clj + +(require 'flycheck-clojure) + +(defun my-cider-mode-enable-flycheck () + ;; (when (and (s-ends-with-p ".clj" (buffer-file-name)) + ;; (not (s-ends-with-p "/dev/user.clj" (buffer-file-name)))) + ;; (flycheck-mode 1)) + ) + +(add-hook 'cider-mode-hook 'my-cider-mode-enable-flycheck) + +(eval-after-load 'flycheck '(add-to-list 'flycheck-checkers 'clojure-cider-eastwood)) + +;; Make q quit out of find-usages to previous window config + +(defadvice cljr-find-usages (before setup-grep activate) + (window-configuration-to-register ?$)) + +;; ------------ + +;; TODO: Loot more stuff from: +;; - https://github.com/overtone/emacs-live/blob/master/packs/dev/clojure-pack/config/paredit-conf.el + + +(provide 'setup-clojure-mode)