├── README.creole └── clojure-env.el /README.creole: -------------------------------------------------------------------------------- 1 | often I see complicated Emacs installation procedures for building an 2 | environment for an external language such as JavaScript or Clojure. 3 | 4 | This is an attempt to make an opinionated Clojure specific setup from 5 | inside Emacs. 6 | 7 | 8 | === leiningen === 9 | 10 | {{{clojure-env}}} gets and installs leiningen, lazily. That is if you 11 | use any {{{clojure-env}}} command it will check whether it has 12 | leiningen and go get it for you if it doesn't have it. 13 | 14 | Right now I use a simple file existence check for leiningen because I 15 | don't want an HTTP request happening every time. A more complicated 16 | caching strategy seems like an obvious optimization. 17 | 18 | 19 | === cider === 20 | 21 | I'm depending on the cider package for most of an Emacs Clojure 22 | environment. This is a bit out of date on marmalade because of the 23 | problems with marmalade in the past. It should get updated soon. 24 | 25 | === clojurescript === 26 | 27 | I'm depending on the clojurescript-mode package for clojurescript 28 | support. 29 | 30 | ClojureScript is actually my main interest in Clojure so I hope to 31 | provide something more to the Emacs community there. 32 | 33 | I suspect Elnode can help a bit in making ClojureScript useful. I am 34 | already using {{{elnode-make-webserver}}} to serve ClojureScript 35 | websites. 36 | 37 | 38 | === required dependencies === 39 | 40 | Java. You have to have java installed. I don't bother detecting if you 41 | have it or not. I probably will add a check at least before we even 42 | try and download leiningen. 43 | 44 | 45 | === customize environment === 46 | 47 | Most things that could be choices are provided as Emacs customization 48 | options in the group {{{clojure-env}}} in languages. 49 | 50 | 51 | === commands === 52 | 53 | Here are the two commands this package currenty provides: 54 | 55 | ==== clojure-env-new-clojurescript project-name ==== 56 | 57 | Make a new ClojureScript project. 58 | 59 | Uses {{{clojure-env-clojurescript-template}}} as the name of the 60 | leiningen template to use. 61 | 62 | 63 | ==== clojure-env-new-om project-name ==== 64 | 65 | Make a new ClojureScript/OM project. 66 | 67 | Uses {{{clojure-env-om-template}}} as the name of the 68 | leiningen template to use. 69 | 70 | 71 | -------------------------------------------------------------------------------- /clojure-env.el: -------------------------------------------------------------------------------- 1 | ;;; clojure-env.el --- manage clojure environments with Emacs -*- lexical-binding: t -*- 2 | 3 | ;; Copyright (C) 2014 Nic Ferrier 4 | 5 | ;; Author: Nic Ferrier 6 | ;; Keywords: languages 7 | ;; Package-depends: ((cider "0.6.0")(clojurescript-mode "0.5")(web "0.4.2")(noflet "0.0.8")) 8 | ;; Version: 0.0.4 9 | 10 | ;; This program is free software; you can redistribute it and/or modify 11 | ;; it under the terms of the GNU General Public License as published by 12 | ;; the Free Software Foundation, either version 3 of the License, or 13 | ;; (at your option) any later version. 14 | 15 | ;; This program is distributed in the hope that it will be useful, 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | ;; GNU General Public License for more details. 19 | 20 | ;; You should have received a copy of the GNU General Public License 21 | ;; along with this program. If not, see . 22 | 23 | ;;; Commentary: 24 | 25 | ;; Clojure has complex external dependencies, not least Clojure 26 | ;; itself. For those of us who only use Clojure through Emacs it would 27 | ;; be nice to just use Emacs to get Clojure. This package allows that. 28 | 29 | 30 | ;;; Code: 31 | 32 | (require 'web) 33 | (require 'noflet) 34 | 35 | (defconst clojure-env/lein-url "https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein" 36 | "Where to find the Leiningen script.") 37 | 38 | (defgroup clojure-env nil 39 | "Manage a clojure environment." 40 | :group 'languages) 41 | 42 | (defcustom clojure-env-clojurescript-template "mies" 43 | "What template should be used for ClojureScript projects." 44 | :group 'clojure-env 45 | :type 'string) 46 | 47 | (defcustom clojure-env-om-template "mies-om" 48 | "What template should be used for Om projects." 49 | :group 'clojure-env 50 | :type 'string) 51 | 52 | (defcustom clojure-env-bin-dir "~/.clojure-env/bin" 53 | "Where binaries we need should be installed." 54 | :group 'clojure-env 55 | :type 'directory) 56 | 57 | (defun clojure-env/lein-get (&optional next) 58 | "Get the lein script from github. 59 | 60 | Call NEXT when we've got it." 61 | (web-http-get 62 | (lambda (con header data) 63 | (with-current-buffer (get-buffer-create "*clojure-env/lein*") 64 | (erase-buffer) 65 | (when data 66 | (insert data) 67 | (let ((dir (expand-file-name clojure-env-bin-dir))) 68 | (make-directory dir t) 69 | (write-file (expand-file-name "lein" dir)))) 70 | (when (functionp next) 71 | (funcall next)))) 72 | :url clojure-env/lein-url)) 73 | 74 | (defun clojure-env/lein-call (args &optional next) 75 | "Call \"lein\" with ARGS. 76 | 77 | If \"lein\" does not exist in `clojure-env-bin-dir' then we get 78 | it. 79 | 80 | Once we're done call NEXT if we have it." 81 | (let ((lein-bin (expand-file-name "lein" clojure-env-bin-dir))) 82 | (noflet ((action () 83 | (set-process-sentinel 84 | (start-process-shell-command 85 | "*clojure-env-lein*" "*clojure-env-lein*" 86 | (format "bash %s %s" lein-bin args)) 87 | (lambda (proc evt) 88 | (cond 89 | ((equal evt "finished\n") 90 | (when (functionp next) 91 | (funcall next)))))) 92 | (pop-to-buffer (get-buffer "*clojure-env-lein*")))) 93 | (if (file-exists-p lein-bin) 94 | (action) 95 | (clojure-env/lein-get 'action))))) 96 | 97 | (defun clojure-env/clojurescript-compile () 98 | "Produce the `compile-command' for clojurescript." 99 | (format "bash %s cljsbuild once" 100 | (expand-file-name "lein" clojure-env-bin-dir))) 101 | 102 | (defun clojure-env/make-dir-locals (dir) 103 | (with-temp-file (expand-file-name ".dir-locals.el" dir) 104 | (let ((command (clojure-env/clojurescript-compile))) 105 | (print 106 | `((clojure-mode . ((compile-command . ,command)))) 107 | (current-buffer))))) 108 | 109 | ;; Make sure we get the compile key - not sure if it would be better 110 | ;; to add it to the keymap directly 111 | (add-hook 112 | 'clojure-mode-hook 113 | (lambda () 114 | (local-set-key (kbd "C-c C-k") 'compile))) 115 | 116 | ;;;###autoload 117 | (defun clojure-env-new-clojurescript (project-name) 118 | "Make a new ClojureScript project. 119 | 120 | Uses `clojure-env-clojurescript-template' as the name of the 121 | leiningen template to use." 122 | (interactive 123 | (list 124 | (read-from-minibuffer "New project name: "))) 125 | (let ((dir (expand-file-name project-name default-directory))) 126 | (clojure-env/lein-call 127 | (format "new %s %s" 128 | clojure-env-clojurescript-template 129 | project-name) 130 | (lambda () 131 | (clojure-env/make-dir-locals dir) 132 | (find-file dir))))) 133 | 134 | ;;;###autoload 135 | (defun clojure-env-new-om (project-name) 136 | "Make a new ClojureScript/OM project. 137 | 138 | Uses `clojure-env-om-template' as the name of the leiningen 139 | template to use." 140 | (interactive 141 | (list 142 | (read-from-minibuffer "New project name: "))) 143 | (let ((dir (expand-file-name project-name default-directory))) 144 | (clojure-env/lein-call 145 | (format "new %s %s" 146 | clojure-env-om-template 147 | project-name) 148 | (lambda () 149 | (clojure-env/make-dir-locals dir) 150 | (find-file dir))))) 151 | 152 | (defun clojure-env-new-app (project-name) 153 | "Make a new Clojure project with the app template." 154 | (interactive 155 | (list 156 | (read-from-minibuffer "New project name: "))) 157 | (let ((dir (expand-file-name project-name default-directory))) 158 | (clojure-env/lein-call 159 | (format "new %s %s" "app" project-name) 160 | (lambda () 161 | (clojure-env/make-dir-locals dir) 162 | (find-file dir))))) 163 | 164 | (provide 'clojure-env) 165 | 166 | ;;; clojure-env.el ends here 167 | --------------------------------------------------------------------------------