Permalink
Browse files

update clojure-mode and add kibit-mode

  • Loading branch information...
dakrone committed May 21, 2012
1 parent 2196cd1 commit ad43d09a68f85dd0c8892d84537223bf6c014394
@@ -4,7 +4,7 @@
;;;### (autoloads (clojure-enable-slime-on-existing-buffers clojure-jack-in
-;;;;;; clojure-mode) "clojure-mode" "clojure-mode.el" (20207 22678))
+;;;;;; clojure-mode) "clojure-mode" "clojure-mode.el" (20406 41978))
;;; Generated autoloads from clojure-mode.el
(autoload 'clojure-mode "clojure-mode" "\
@@ -22,22 +22,36 @@ if that value is non-nil.
\(fn)" t nil)
(autoload 'clojure-jack-in "clojure-mode" "\
-Not documented
+
\(fn)" t nil)
(autoload 'clojure-enable-slime-on-existing-buffers "clojure-mode" "\
-Not documented
+
\(fn)" t nil)
(add-hook 'slime-connected-hook 'clojure-enable-slime-on-existing-buffers)
+(put 'clojure-test-ns-segment-position 'safe-local-variable 'integerp)
+
+(put 'clojure-mode-load-command 'safe-local-variable 'stringp)
+
+(put 'clojure-swank-command 'safe-local-variable 'stringp)
+
+(add-hook 'slime-connected-hook 'clojure-enable-slime-on-existing-buffers)
+
+(add-hook 'slime-indentation-update-hooks 'put-clojure-indent)
+
(add-to-list 'auto-mode-alist '("\\.clj$" . clojure-mode))
+(add-to-list 'interpreter-mode-alist '("jark" . clojure-mode))
+
+(add-to-list 'interpreter-mode-alist '("cake" . clojure-mode))
+
;;;***
-;;;### (autoloads nil nil ("clojure-mode-pkg.el") (20207 22679 30196))
+;;;### (autoloads nil nil ("clojure-mode-pkg.el") (20406 41978 525833))
;;;***
@@ -547,7 +547,7 @@ elements of a def* forms."
;; Constant values (keywords), including as metadata e.g. ^:static
("\\<^?:\\(\\sw\\|#\\)+\\>" 0 font-lock-constant-face)
;; Meta type annotation #^Type or ^Type
- ("#?^\\sw+" 0 font-lock-type-face)
+ ("#?^\\sw+" 0 font-lock-preprocessor-face)
("\\<io\\!\\>" 0 font-lock-warning-face)
;;Java interop highlighting
@@ -805,6 +805,7 @@ use (put-clojure-indent 'some-symbol 'defun)."
;; clojure.test
(testing 1)
(deftest 'defun)
+ (use-fixtures 'defun)
;; contrib
(handler-case 1)
@@ -951,13 +952,31 @@ returned."
+(defun clojure-expected-ns ()
+ "Returns the namespace name that the file should have."
+ (let* ((project-dir (file-truename
+ (locate-dominating-file default-directory
+ "project.clj")))
+ (relative (substring (buffer-file-name) (length project-dir) -4)))
+ (replace-regexp-in-string
+ "_" "-" (mapconcat 'identity (cdr (split-string relative "/")) "."))))
+
(defun clojure-insert-ns-form ()
(interactive)
(goto-char (point-min))
- (let* ((rel (car (last (split-string buffer-file-name "src/\\|test/"))))
- (relative (car (split-string rel "\\.clj")))
- (segments (split-string relative "/")))
- (insert (format "(ns %s)" (mapconcat #'identity segments ".")))))
+ (insert (format "(ns %s)" (clojure-expected-ns))))
+
+(defun clojure-update-ns ()
+ "Updates the namespace of the current buffer. Useful if a file has been renamed."
+ (interactive)
+ (let ((nsname (clojure-expected-ns)))
+ (when nsname
+ (save-restriction
+ (save-excursion
+ (save-match-data
+ (if (clojure-find-ns)
+ (replace-match nsname nil nil nil 4)
+ (error "Namespace not found"))))))))
;;; Slime help
@@ -1115,10 +1134,11 @@ The arguments are dir, hostname, and port. The return value should be an `alist
(defun clojure-find-ns ()
(let ((regexp clojure-namespace-name-regex))
- (save-excursion
- (when (or (re-search-backward regexp nil t)
- (re-search-forward regexp nil t))
- (match-string-no-properties 4)))))
+ (save-restriction
+ (save-excursion
+ (goto-char (point-min))
+ (when (re-search-forward regexp nil t)
+ (match-string-no-properties 4))))))
(defalias 'clojure-find-package 'clojure-find-ns)
@@ -0,0 +1,8 @@
+/pom.xml
+*jar
+/lib
+/classes
+/native
+/.lein-failures
+/checkouts
+/.lein-deps-sum
@@ -0,0 +1,22 @@
+Copyright (C) 2012 Alex Redington
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,73 @@
+# kibit-mode
+
+kibit-mode is a combination of a thin wrapper around the excellent
+[kibit](https://github.com/jonase/kibit) tool, and a minor for Clojure
+buffers that will help you find ways to make your Clojure code more
+idiomatic.
+
+## Requirements
+
+* [Emacs](http://www.gnu.org/software/emacs/) 24.0 or greater
+* [Clojure](http://clojure.org) 1.4 or greater
+* [Leiningen](https://github.com/technomancy/leiningen) 1.6.2 or greater
+* [clojure-mode](https://github.com/technomancy/clojure-mode) 1.11.5 or greater
+
+## Configuration
+
+I use el-get to manage my Emacs config. To add kibit-mode, I added the
+following to my package definitions:
+
+```
+(:name kibit-mode
+ :type git
+ :url "https://github.com/aredington/kibit-mode.git"
+ :after (lambda ()
+ (require 'kibit-mode)
+ (add-hook 'clojure-mode-hook 'kibit-mode)))
+```
+
+The important bits are to get kibit-mode.el on your load-path, require
+it, and add it as a hook to clojure-mode. Hopefully this works for you
+if you also use el-get, if you do not use el-get you are on your own.
+
+## Usage
+
+In an open Clojure buffer, hit C-c C-n (you can use the mnemonic that
+this **C**ompilation tool will help you catch **N**oob mistakes) to
+open a compilation buffer that will tell you where you can replace
+code with a terser, more idiomatic expression of the same semantics.
+
+The compilation buffer will output formatted filename and line number
+indicators of kibits suggestions, like follows:
+
+```
+/Users/alex/projects/pi/src/pi/core.clj:5:
+ Replace
+ (if (even? x) x nil)
+ with
+ (when (even? x) x)
+```
+
+You can jump immediately to the suggestion from the compilation buffer
+by hitting enter. If you do not have any code that kibit thinks it can
+improve, then it will exit happily and the compilation step will
+report success.
+
+## Reverse Double Secret Next Level Maneuver
+
+If you add the following to your emacs config:
+
+```
+(add-hook 'clojure-mode-hook 'flymake-mode-on)
+```
+
+Then kibit-mode will be registered as a flymake checker and check your
+code for you as you write. It will highlight the line which starts the
+form relevant to kibit's suggestion. This part is pretty ugly and
+hacked together with a shell script, be warned.
+
+## License
+
+Copyright (C) 2012 Alex Redington
+
+Distributed under the MIT License
@@ -0,0 +1,13 @@
+# Setting basedir on flymake tasks doesn't actually get set beyond a
+# logging statement, so we hijack the CWD using this script to farm
+# out the job to leiningen
+
+# normalize $0 on certain BSDs
+if [ "$(dirname "$0")" = "." ]; then
+ SCRIPT="$(which $(basename "$0"))"
+else
+ SCRIPT="$0"
+fi
+
+cd "$(dirname "$(dirname "$SCRIPT")")"
+lein run -m kibit-mode.flymake $1
@@ -0,0 +1,114 @@
+;;; kibit-mode.el --- Enhance clojure-mode with Kibit analysis
+
+;; Copyright (C) 2012 Alex Redington <http://www.holychao.com>
+;; Authors: Alex Redington
+;; Created: 2012
+;; Version: 0.1
+;; Keywords: clojure kibit
+;; Package-Requires: ((clojure-mode "1.11.5")
+;; (mode-compile "2.29"))
+
+;;; Commentary:
+;;
+;; This file is NOT part of GNU Emacs.
+;;
+;; Copyright (C) 2012 Alex Redington
+
+;; Permission is hereby granted, free of charge, to any person
+;; obtaining a copy of this software and associated documentation
+;; files (the "Software"), to deal in the Software without
+;; restriction, including without limitation the rights to use,
+;; copy, modify, merge, publish, distribute, sublicense, and/or sell
+;; copies of the Software, and to permit persons to whom the
+;; Software is furnished to do so, subject to the following
+;; conditions:
+
+;; The above copyright notice and this permission notice shall be
+;; included in all copies or substantial portions of the Software.
+
+;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+;; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+;; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+;; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+;; OTHER DEALINGS IN THE SOFTWARE.
+
+;;; Documentation:
+;;
+;; This minor mode acts as a compilation mechanism for interactively replacing
+;; clojure s-expressions by their more idiomatic representations. It provides
+;; the following capabilities:
+;;
+;; * Run a check over the currently open file (bound to `\C-c \C-n`). This will
+;; open a compilation mode buffer showing the kibit replacements.
+;;
+;; * Implement a suggested replacement (bound to `r`). This will destroy the
+;; extant formatting when the replacement is inserted
+
+;;; Dependencies:
+;; This minor mode depends on `mode-compile` and `clojure-mode`.
+
+;;; Change Log:
+;;
+;; 0.1 - First cut of kibit-mode
+
+;;; Code:
+
+(require 'clojure-mode)
+(require 'compile)
+
+(defconst kibit-mode-keymap (make-sparse-keymap) "Keymap used in kibit mode")
+
+(define-key kibit-mode-keymap (kbd "C-c C-n") 'kibit-check)
+
+(defgroup kibit-mode nil
+ "Kibit minor mode.")
+
+(eval-and-compile
+ (defvar kibit-mode-path
+ (let ((path (or (locate-library "kibit-mode") load-file-name)))
+ (and path (file-name-directory path)))
+ "Directory containing the kibit-mode package.
+This is used to execute the supporting kibit analysis execution environment.
+The default value is automatically computed from the location of the
+Emacs Lisp package."))
+
+
+;;;###autoload
+(define-minor-mode kibit-mode
+ "Minor mode for kibit compilation support"
+ :lighter " kibit"
+ :keymap kibit-mode-keymap)
+
+(defun kibit-check ()
+ "Runs the current file through kibit check"
+ (interactive)
+ (let ((default-directory kibit-mode-path))
+ (compile (concat "lein run -m kibit-mode.core "
+ (buffer-file-name)))))
+
+(add-to-list 'compilation-error-regexp-alist-alist
+ '(kibit-mode "\\([0-9A-Za-z_./\:-]+\\.clj\\):\\([0-9]+\\):" 1 2))
+(add-to-list 'compilation-error-regexp-alist 'kibit-mode)
+
+(require 'flymake)
+(defun flymake-kibit-init ()
+ (flymake-simple-make-init-impl
+ 'flymake-create-temp-with-folder-structure nil nil
+ buffer-file-name
+ 'flymake-get-kibit-cmdline))
+
+(defun flymake-get-kibit-cmdline (source base-dir)
+ (list (concat kibit-mode-path "bin/kibit-flymake.sh") (list source) kibit-mode-path))
+
+(push '(".+\\.clj$" flymake-kibit-init) flymake-allowed-file-name-masks)
+(push '(".+\\.cljs$" flymake-kibit-init) flymake-allowed-file-name-masks)
+
+(push '("\\(.*\\):\\([0-9]+\\): \\(ERROR: .* CORRECTION: .*\\)"
+ 1 2 nil 3)
+ flymake-err-line-patterns)
+
+(provide 'kibit-mode)
+;;; kibit-mode.el ends here
@@ -0,0 +1,4 @@
+(defproject kibit-mode "0.0.1"
+ :description "A kibit compiler for Clojure files"
+ :dependencies [[org.clojure/clojure "1.4.0"]
+ [jonase/kibit "0.0.3"]])
@@ -0,0 +1,30 @@
+(ns kibit-mode.core
+ (:require [kibit.check :as c]
+ [clojure.java.io :as io]
+ [clojure.string :as s]))
+
+(defn report-error
+ "Given a kibit simplification, print the line number and normalized
+ form of the expr and the replacement"
+ [file {:keys [expr alt line] :as simplify-map}]
+ (println (str file
+ ":"
+ line
+ ":\n Replace\n "
+ (pr-str expr)
+ "\n with\n "
+ (pr-str alt)
+ )))
+
+(defn check-file
+ [file reporter]
+ (with-open [reader (io/reader file)]
+ (let [errors (c/check-reader reader)]
+ (doseq [simplify-map errors]
+ (reporter file simplify-map))
+ errors)))
+
+(defn -main
+ [file]
+ (when-not (empty? (check-file file report-error))
+ (System/exit 1)))
Oops, something went wrong.

0 comments on commit ad43d09

Please sign in to comment.