diff options
Diffstat (limited to '.emacs.d/lisp/rust-cargo.el')
| -rw-r--r-- | .emacs.d/lisp/rust-cargo.el | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/.emacs.d/lisp/rust-cargo.el b/.emacs.d/lisp/rust-cargo.el new file mode 100644 index 0000000..cfbcd81 --- /dev/null +++ b/.emacs.d/lisp/rust-cargo.el | |||
| @@ -0,0 +1,124 @@ | |||
| 1 | ;;; rust-cargo.el --- Support for cargo -*-lexical-binding: t-*- | ||
| 2 | ;;; Commentary: | ||
| 3 | |||
| 4 | ;; This library implements support for running `cargo'. | ||
| 5 | |||
| 6 | ;;; Code: | ||
| 7 | |||
| 8 | (require 'json) | ||
| 9 | |||
| 10 | ;;; Options | ||
| 11 | |||
| 12 | (defcustom rust-cargo-bin "cargo" | ||
| 13 | "Path to cargo executable." | ||
| 14 | :type 'string | ||
| 15 | :group 'rust-mode) | ||
| 16 | |||
| 17 | (defcustom rust-always-locate-project-on-open nil | ||
| 18 | "Whether to run `cargo locate-project' every time `rust-mode' is activated." | ||
| 19 | :type 'boolean | ||
| 20 | :group 'rust-mode) | ||
| 21 | |||
| 22 | (defcustom rust-cargo-default-arguments "" | ||
| 23 | "Default arguments when running common cargo commands." | ||
| 24 | :type 'string | ||
| 25 | :group 'rust-mode) | ||
| 26 | |||
| 27 | ;;; Buffer Project | ||
| 28 | |||
| 29 | (defvar-local rust-buffer-project nil) | ||
| 30 | |||
| 31 | (defun rust-buffer-project () | ||
| 32 | "Get project root if possible." | ||
| 33 | ;; Copy environment variables into the new buffer, since | ||
| 34 | ;; with-temp-buffer will re-use the variables' defaults, even if | ||
| 35 | ;; they have been changed in this variable using e.g. envrc-mode. | ||
| 36 | ;; See https://github.com/purcell/envrc/issues/12. | ||
| 37 | (let ((env process-environment) | ||
| 38 | (path exec-path)) | ||
| 39 | (with-temp-buffer | ||
| 40 | ;; Copy the entire environment just in case there's something we | ||
| 41 | ;; don't know we need. | ||
| 42 | (setq-local process-environment env) | ||
| 43 | ;; Set PATH so we can find cargo. | ||
| 44 | (setq-local exec-path path) | ||
| 45 | (let ((ret (process-file rust-cargo-bin nil (list (current-buffer) nil) nil "locate-project" "--workspace"))) | ||
| 46 | (when (/= ret 0) | ||
| 47 | (error "`cargo locate-project' returned %s status: %s" ret (buffer-string))) | ||
| 48 | (goto-char 0) | ||
| 49 | (let ((output (json-read))) | ||
| 50 | (cdr (assoc-string "root" output))))))) | ||
| 51 | |||
| 52 | (defun rust-buffer-crate () | ||
| 53 | "Try to locate Cargo.toml using `locate-dominating-file'." | ||
| 54 | (let ((dir (locate-dominating-file default-directory "Cargo.toml"))) | ||
| 55 | (if dir dir default-directory))) | ||
| 56 | |||
| 57 | (defun rust-update-buffer-project () | ||
| 58 | (setq-local rust-buffer-project (rust-buffer-project))) | ||
| 59 | |||
| 60 | (defun rust-maybe-initialize-buffer-project () | ||
| 61 | (setq-local rust-buffer-project nil) | ||
| 62 | (when rust-always-locate-project-on-open | ||
| 63 | (rust-update-buffer-project))) | ||
| 64 | |||
| 65 | (add-hook 'rust-mode-hook #'rust-maybe-initialize-buffer-project) | ||
| 66 | |||
| 67 | ;;; Internal | ||
| 68 | |||
| 69 | (defun rust--compile (format-string &rest args) | ||
| 70 | (when (null rust-buffer-project) | ||
| 71 | (rust-update-buffer-project)) | ||
| 72 | (let ((default-directory | ||
| 73 | (or (and rust-buffer-project | ||
| 74 | (file-name-directory rust-buffer-project)) | ||
| 75 | default-directory))) | ||
| 76 | (compile (apply #'format format-string args)))) | ||
| 77 | |||
| 78 | ;;; Commands | ||
| 79 | |||
| 80 | (defun rust-check () | ||
| 81 | "Compile using `cargo check`" | ||
| 82 | (interactive) | ||
| 83 | (rust--compile "%s check %s" rust-cargo-bin rust-cargo-default-arguments)) | ||
| 84 | |||
| 85 | (defun rust-compile () | ||
| 86 | "Compile using `cargo build`" | ||
| 87 | (interactive) | ||
| 88 | (rust--compile "%s build %s" rust-cargo-bin rust-cargo-default-arguments)) | ||
| 89 | |||
| 90 | (defun rust-compile-release () | ||
| 91 | "Compile using `cargo build --release`" | ||
| 92 | (interactive) | ||
| 93 | (rust--compile "%s build --release" rust-cargo-bin)) | ||
| 94 | |||
| 95 | (defun rust-run () | ||
| 96 | "Run using `cargo run`" | ||
| 97 | (interactive) | ||
| 98 | (rust--compile "%s run %s" rust-cargo-bin rust-cargo-default-arguments)) | ||
| 99 | |||
| 100 | (defun rust-run-release () | ||
| 101 | "Run using `cargo run --release`" | ||
| 102 | (interactive) | ||
| 103 | (rust--compile "%s run --release" rust-cargo-bin)) | ||
| 104 | |||
| 105 | (defun rust-test () | ||
| 106 | "Test using `cargo test`" | ||
| 107 | (interactive) | ||
| 108 | (rust--compile "%s test %s" rust-cargo-bin rust-cargo-default-arguments)) | ||
| 109 | |||
| 110 | (defun rust-run-clippy () | ||
| 111 | "Run `cargo clippy'." | ||
| 112 | (interactive) | ||
| 113 | (when (null rust-buffer-project) | ||
| 114 | (rust-update-buffer-project)) | ||
| 115 | (let* ((args (list rust-cargo-bin "clippy" | ||
| 116 | (concat "--manifest-path=" rust-buffer-project))) | ||
| 117 | ;; set `compile-command' temporarily so `compile' doesn't | ||
| 118 | ;; clobber the existing value | ||
| 119 | (compile-command (mapconcat #'shell-quote-argument args " "))) | ||
| 120 | (rust--compile compile-command))) | ||
| 121 | |||
| 122 | ;;; _ | ||
| 123 | (provide 'rust-cargo) | ||
| 124 | ;;; rust-cargo.el ends here | ||
