Skip to content

Latest commit

 

History

History
286 lines (248 loc) · 11.2 KB

ha-programming-clojure.org

File metadata and controls

286 lines (248 loc) · 11.2 KB

Clojure Programming

A literate programming file for programming in Clojure.

I like Clojure as a modern Lisp, but I don’t get to play with it much anymore. 😢 The following instructions create a fully blinged-out Emacs-Clojure setup.

Introduction

To get Clojure working on a new MacOS system using Homebrew, try the following:

brew install clojure/tools/clojure
brew install leiningen

And make sure it works:

clojure --help

Or by starting a REPL:

clj

Then for each project, create the project directory with this command:

lein new app fresh-app

Emacs Support

Install and configure clojure-mode:

(use-package clojure-mode
  :init
  (add-to-list 'org-babel-load-languages '(clojure . t))

  :config
  (defun ha-prettify-clojure ()
    "Make the Clojure syntax prettier."
    (push '("fn"   . ?𝝀) prettify-symbols-alist)
    (push '("__"   . ?⁈) prettify-symbols-alist)
    (prettify-symbols-mode))

  :hook (clojure-mode . ha-prettify-clojure))

Need the IDE features associated with Cider:

(use-package cider
  :after clojure-mode
  :commands (cider-connect cider-jack-in cider)
  :init
  (setq cider-show-error-buffer t
        ;; The use of paredit when editing Clojure (or any other Lisp) code is
        ;; highly recommended. You're probably using it already in your
        ;; clojure-mode buffers (if you're not you probably should). You might
        ;; also want to enable paredit in the REPL buffer as well.
        ;; (add-hook 'cider-repl-mode-hook #'paredit-mode)

        ;; Don't select the error buffer when it's displayed:
        cider-auto-select-error-buffer nil

        ;; Controls whether to pop to the REPL buffer on connect.
        cider-repl-pop-to-buffer-on-connect nil

        cider-repl-use-clojure-font-lock t

        ;; T to wrap history around when the end is reached.
        cider-repl-wrap-history t

        cider-repl-history-size 1000

        ;; Hide `*nrepl-connection*' and `*nrepl-server*' buffers from appearing
        ;; in some buffer switching commands like switch-to-buffer
        nrepl-hide-special-buffers t

        ;; Stop error buffer from popping up while working in buffers other than the REPL:
        nrepl-popup-stacktraces nil)

  ;; Enabling CamelCase support for editing commands (like forward-word,
  ;; backward-word, etc) in the REPL is quite useful since we often have
  ;; to deal with Java class and method names. The built-in Emacs minor
  ;; mode subword-mode provides such functionality
  :hook (cider-repl-mode . #'subword-mode)

  :config
  (ha-local-leader :keymaps clojure-mode-map
    "w" '(:ignore t :which-key "cider")
    "w s" '("start"            . cider-jack-in)
    "w r" '("restart"          . cider-restart)
    "w c" '("connect"          . cider-connect)
    "w b" '("switch"           . cider-switch-repl-buffer)
    "w n" '("namespace"        . cider-repl-set-ns)
    "w e" '("describe"         . cider-describe-connection)
    "w x" '("interrupt"        . cider-interrupt)
    "w q" '("quit"             . cider-quit)

    "b" '(:ignore t :which-key "load")
    "b b" '("load buffer"      . cider-load-buffer)
    "b f" '("load file"        . cider-load-file)
    "b f" '("load all"         . cider-load-all-files)
    "b r" '("refresh all"      . cider-ns-refresh)

    "e" '(:ignore t :which-key "eval")
    "e e" '("last s-expr"      . cider-eval-last-sexp)
    "e E" '("replace s-expr"   . cider-eval-last-sexp-and-replace)
    "e ." '("s-expr point"     . cider-eval-sexp-at-point)
    "e f" '("defun"            . cider-eval-defun-at-point)
    "e F" '("file"             . cider-eval-file)
    "e b" '("buffer"           . cider-eval-buffer)
    "e r" '("region"           . cider-eval-region)
    "e R" '("to repl"          . cider-eval-last-sexp-to-repl)
    "e n" '("namespace"        . cider-eval-ns-form)
    "e ;" '("expression"       . cider-read-and-eval)
    "e i" '("inspect"          . cider-inspect)

    "e p" '(:ignore t :which-key "pprint")
    "e p p" '("last s-expr"    . cider-pprint-eval-last-sexp)
    "e p f" '("defun"          . cider-pprint-eval-defun-at-point)
    "e p r" '("to repl"        . cider-pprint-eval-last-sexp-to-repl)

    ;; Overshadowing xref menu in `ha-programming':
    "s" '(:ignore t :which-key "search")
    "s d" '("definition"       . cider-find-resource)
    "s s" '("var"              . cider-find-var)
    "s f" '("file"             . cider-find-ns)
    "s o" '("other window"     . xref-find-definitions-other-window)
    "s D" '("deps"             . cider-xref-fn-deps)
    "s b" '("back"             . cider-pop-back)

    "t" '(:ignore t :which-key "test")
    "t t" '("run test"         . cider-test-run-test)
    "t r" '("rerun test"       . cider-test-rerun-test)
    "t a" '("run all"          . cider-test-run-ns-tests)
    "t p" '("run project"      . cider-test-run-project-tests)
    "t f" '("run failed"       . cider-test-rerun-failed-tests)
    "t R" '("show report"      . cider-test-show-report)

    "d" '(:ignore t :which-key "docs")
    "d d" '("documentation"    . cider-doc)
    "d s" '("search docs"      . cider-apropos-documentation)
    "d j" '("javadocs"         . cider-javadoc)
    "d c" '("clojuredocs"      . cider-clojuredocs)
    "d a" '("apropos"          . cider-apropos)))

Read the entire CIDER manual, specifically the Usage document.

Linting

Note: The Spacemacs community recommends using clj-kondo in combination with joker. Add lint warnings to Flycheck:

(use-package flycheck-clojure
  :after flycheck
  :config
  (flycheck-clojure-setup))

To install the joker binary:

brew install candid82/brew/joker

And the flycheck-joker package should do the trick:

(use-package flycheck-joker)

To install the clj-kondo binary is a bit more involved:

curl -sLO https://raw.githubusercontent.com/clj-kondo/clj-kondo/master/script/install-clj-kondo
chmod +x install-clj-kondo
./install-clj-kondo

And the flycheck-clj-kondo project should do the integration:

(use-package flycheck-clj-kondo)

Search on Clojars more easily This clojars extension allows you to search for projects on clojars.org and copies your selection to the kill ring in a format suitable for your project.clj.

(use-package clojars
  :after clojure-mode
  :config
  (ha-local-leader :keymaps clojure-mode-map
   "h j" '("clojars" . clojars)))

Clojure Cheatsheet

The clojure-cheatsheet

(use-package clojure-cheatsheet
  :after clojure-mode
  :config
  (ha-local-leader :keymaps clojure-mode-map
   "h c" '("cheatsheet" . clojure-cheatsheet)))

Snippets

For clojure-specific templates for yasnippets, we use David Nolen’s clojure-snippets repository:

(use-package clojure-snippets)

Refactoring

The clj-refactor project:

(use-package clj-refactor
  :after clojure-mode
  :hook
  (clojure-mode . clj-refactor-mode)

  :config
  ;; Configure the Clojure Refactoring prefix.
  (cljr-add-keybindings-with-prefix "C-c .")

  (ha-local-leader :keymaps clojure-mode-map
   ;; Would really like to have this on the , prefix:
   "r"  '("refactoring" . hydra-cljr-help-menu/body)

   "h d" '("describe refactoring" . cljr-describe-refactoring)
   "h r" '("refactoring" . hydra-cljr-toplevel-form-menu/body))

  :diminish clj-refactor-mode)

The advanced refactorings require the refactor-nrepl middleware, which should explain why we added the refactor-nrepl to the :plugins section in the ~/.lein/profiles.clj file (see below).

The real problem is trying to remember all the refactoring options. Remember: C-c . h h

Org Babel

And of course, we want to put this with org blocks:

(use-package ob-clojure
  :straight (:type built-in)
  :custom
  (org-babel-clojure-backend 'cider)
  :config
  (add-to-list 'org-babel-load-languages '(clojure . t)))

Does this now work?

(format "The answer is %d" (+ (* 4 10) 2))

Technical Artifacts

Let’s provide a name so we can require this file: