Rustic
Table of Contents
- Rustic
Intro
This package is a fork of rust-mode
Differences with rust-mode:
- flycheck integration
- cargo popup
- multiline error parsing
- translation of ANSI control sequences through xterm-color
- async org babel
- custom compilation process
- rustfmt errors in a rust compilation mode
- automatic LSP configuration with eglot or lsp-mode
- Optional rust inline documentation
- cask for testing
- requires emacs 26
- etc.
Why fork ?
Installation
Simply put (use-package rustic)
in your config and most stuff gets configured automatically. (use-package)
It's necessary to include elpa for a package dependency:
(setq package-archives '(("melpa" . "http://melpa.org/packages/")
("gnu" . "http://elpa.gnu.org/packages/")))
If ‘spinner-1.7.3’ is unavailable” when trying to install rustic, you need to update GPG keys used by the ELPA package manager. Try installing gnu-elpa-keyring-update.
If you have rust-mode
installed, ensure it is required before rustic since it has to be removed from auto-mode-alist
. However you only need rust-mode
if you want to use emacs-racer
. There's some stuff that isn't included in rustic.
If you have any issues with rustic, please try running emacs without rust-mode
loaded.
If you can't run rust-analyzer or cargo can't be found, your environment variables probably don't work in emacs. Try exec-path-from-shell to fix this.
straight
straight.el clones each of your packages directly from its source. There are good additional installation instructions for moving your package management from package.el to straight.
Compilation
Rustic defines a derived compilation-mode. Colors can be customized with several defcustoms. You can use next-error
and compilation-next-error
as for any other compilation buffer.
However it's possible to also jump to line numbers that are displayed at the beginning of a line. This feature is provided by a hook around compile-goto-error
(RET
).
Commands:
rustic-compile
compile project usingrustic-compile-command
rustic-recompile
recompile usingcompilation-arguments
rustic-compile-send-input
send string to process of current buffer
Customization:
rustic-compile-display-method
choose function that displays the compilation bufferrustic-compile-backtrace
change backtrace verbosityrustic-compile-command
default command for rust compilation
Supported compile.el variables:
- compilation-arguments
- compilation-scroll-output
Faces
The colors that are displayed in compilation buffers come from cargo and are translated by xterm-color. You can change these colors by modifying rustic-ansi-faces
.
rustic-compilation-mode
doesn't use the default faces of compile.el. If you want to change these colors you can use something similar to:
(custom-set-faces
'(rustic-compilation-column ((t (:inherit compilation-column-number))))
'(rustic-compilation-line ((t (:foreground "LimeGreen")))))
Additional faces:
rustic-message
rustic-compilation-error
rustic-compilation-warning
rustic-compilation-info
rustc errors
Rustfmt
You can format your code with:
rustic-format-buffer
format buffer with stdinrustic-format-file
form file and revert bufferrustic-cargo-fmt
run cargo-fmt on workspace
Rustic uses the function rustic-save-some-buffers
for saving buffers before compilation. To save buffers automatically, you can change the value of buffer-save-without-query
. In case you prefer using lsp for formatting, turn off rustic-format-on-save
and set rustic-lsp-format
to t
.
Customization:
rustic-rustfmt-bin
path to rustfmt executablerustic-rustfmt-config-alist
alist of rustfmt configuration optionsrustic-format-display-method
default function used for displaying rustfmt buffer (use the functionignore
, if you don't want the buffer to be displayed)rustic-format-trigger
'on-save
format buffer before saving'on-compile
run 'cargo fmt' before compilationnil
don't format automatically
edition 2018
If you are struggling with errors relating to the rust edition in cargo.toml
, this may in fact be a problem with rustfmt
and its default settings. To solve this, even though the error message mentions cargo.toml
, you you have to put edition = "2018"
in a rustfmt.toml
. See here for more info.
LSP
Disable LSP support by setting rustic-lsp-client
to nil. You have to restart emacs when you switch lsp clients.
Server
rust-analyzer is the default and can be changed to rls. lsp-mode related code was moved to the lsp-mode repo. rustic-lsp-server
sets the value of lsp-rust-server
.
(setq rustic-lsp-server 'rls)
Change rust-analyzer path.
(setq lsp-rust-analyzer-server-command '("~/.cargo/bin/rust-analyzer"))
Client
The default package is lsp-mode
. But you can also use eglot
.
(setq rustic-lsp-client 'eglot)
LSP commands:
xref-find-definitions
xref-find-references
with helm and rust-analyzer
eglot
Turn off flymake.
(add-hook 'eglot--managed-mode-hook (lambda () (flymake-mode -1)))
lsp-mode
lsp-describe-thing-at-point
display documentationlsp-find-definition
makes use of xref
You can find more information in the lsp-mode wiki.
lsp-execute-code-action
This command can be extremely convenient when applying code actions or using auto-imports.
Run lsp-execute-code-action
when lsp-ui displays code actions at the top of the sideline.
Applying code actions
Auto import
Macro expansion
lsp-rust-analyzer-expand-macro
expand macro call at point recursively
The results are formatted and highlighted by default, but you can use your own function by customizing lsp-rust-analyzer-macro-expansion-method
.
LSP + TRAMP
rust-analyzer
does work over TRAMP, but you have to register the client manually:
(with-eval-after-load "lsp-rust"
(lsp-register-client
(make-lsp-client
:new-connection (lsp-stdio-connection
(lambda ()
`(,(or (executable-find
(cl-first lsp-rust-analyzer-server-command))
(lsp-package-path 'rust-analyzer)
"rust-analyzer")
,@(cl-rest lsp-rust-analyzer-server-args))))
:remote? t
:major-modes '(rust-mode rustic-mode)
:initialization-options 'lsp-rust-analyzer--make-init-options
:notification-handlers (ht<-alist lsp-rust-notification-handlers)
:action-handlers (ht ("rust-analyzer.runSingle" #'lsp-rust--analyzer-run-single))
:library-folders-fn (lambda (_workspace) lsp-rust-library-directories)
:after-open-fn (lambda ()
(when lsp-rust-analyzer-server-display-inlay-hints
(lsp-rust-analyzer-inlay-hints-mode)))
:ignore-messages nil
:server-id 'rust-analyzer-remote)))
If you have Emacs 28, due to some compatibility issues, you might have to additionally use:
(defun start-file-process-shell-command@around (start-file-process-shell-command name buffer &rest args)
"Start a program in a subprocess. Return the process object for it. Similar to `start-process-shell-command', but calls `start-file-process'."
;; On remote hosts, the local `shell-file-name' might be useless.
(let ((command (mapconcat 'identity args " ")))
(funcall start-file-process-shell-command name buffer command)))
(advice-add 'start-file-process-shell-command :around #'start-file-process-shell-command@around)
(thanks to https://github.com/emacs-lsp/lsp-mode/issues/2514#issuecomment-759452037)
You'll have to have rust-analyzer
already installed on the target machine.
Cargo
Edit
cargo-edit provides commands to edit your dependencies quickly.
The rustic commands can be called with prefix C-u
if you want to modify the parameters of a command.
rustic-cargo-add
Add crate to Cargo.toml using 'cargo add'rustic-cargo-rm
Remove crate from Cargo.toml using 'cargo rm'rustic-cargo-upgrade
Upgrade dependencies as specified in the local manifest file using 'cargo upgrade'
Test
rustic-cargo-test
run 'cargo test', when called with C-u
store arguments in rustic-test-arguments
rustic-cargo-test-rerun
rerun 'cargo test' with arguments stored in rustic-test-arguments
rustic-cargo-current-test
run test at point
Outdated
Use rustic-cargo-outdated
to get a list of dependencies that are out of date. The results are displayed in tabulated-list-mode
and you can use most commands you know from the emacs package menu. This option requires the rust package cargo-outdated
to be installed before being used.
u
mark single crate for upgradeU
mark all upgradable cratesm
remove markx
perform marked package menu actionsr
refresh crate listq
quit window
Clippy
Currently cargo does not display the correct installation command for some toolchains when clippy isn't installed. If you have problems try it with rustup component add --toolchain nightly clippy
.
Use rustic-cargo-clippy
to view the results in a derived compilation mode.
Flycheck
In case you want to see clippy lints with flycheck, you can activate this checker and use the command flycheck-list-errors
(push 'rustic-clippy flycheck-checkers)
Turn off flycheck.
(remove-hook 'rustic-mode-hook 'flycheck-mode)
The parameters of the checker can be modified with rustic-flycheck-clippy-params
and are by default configured for using unstable options that are only available on the nightly toolchains.
If you are using the stable toolchain you have to change the value:
(setq rustic-flycheck-clippy-params "--message-format=json")
lsp-mode
If you are using lsp-mode
with rust-analyzer, you can set lsp-rust-analyzer-cargo-watch-command
to clippy instead of activating the checker rustic-clippy
.
Org-babel
Blocks run asynchronously and a running babel process is indicated by a spinner in the mode-line. It's possible to use crates in babel blocks.
Execute babel block with org-babel-execute-src-block
#+BEGIN_SRC rust :crates '((regex . "0.2"))
extern crate regex;
use regex::Regex;
fn main() {
let re = Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap();
assert!(re.is_match("2014-01-01"));
}
#+END_SRC
If specific crate features are required then these can be specified with the :features
argument. Note that if it is just a single feature then a string, instead of a list, will also be accepted:
#+BEGIN_SRC rust :crates '((tokio . 1.0)) :features '((tokio . ("rt-multi-thread" "time")))
extern crate tokio;
fn main() {
tokio::runtime::Runtime::new()
.unwrap()
.block_on(async {
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
});
}
#+END_SRC
Supported org babel parameters:
Write to file :results file :file ~/babel-output
Customization:
rustic-babel-format-src-block
format block after successful buildrustic-babel-display-compilation-buffer
display compilation buffer of babel process
Spinner
In case you want to use a different spinner type you can modify rustic-spinner-type
or turn it off completely with rustic-display-spinner
.(Available spinner types).
inline-documentation
With some setup, it is possible to read rust documentation inside Emacs! This currently requires LSP-mode.
Prequisites
- Install Pandoc https://pandoc.org/installing.html
- Install cargo https://doc.rust-lang.org/cargo/getting-started/installation.html
- Install helm-ag https://github.com/emacsorphanage/helm-ag (Optional, but highly recommended) If you do not have them, you will be prompted to install
fd-find
,ripgrep
andcargo-makedocs
when you runrustic-doc-setup
.ripgrep
is optional but highly recommended. If helm-ag and ripgrep is installed, those will be used by default. If only ripgrep is installed, it will be used with the emacsgrep
command. If neither is installed, the emacsgrep
command will usegrep
, like in the good old days. You can change this by providing your own search function by changingrustic-doc-search-function
.
Usage
- Enable
rustic-doc-mode
. - Run
M-x rustic-doc-setup
to download files that rustic-doc needs to convert rust documentation and also convertstd
. - You can now convert package-specific documentation with
M-x rustic-doc-convert-current-package
- Search the org files with
rustic-doc-search
(bound toC-#
by default) if you are inRust mode
,Rustic mode
orOrg mode
. If you hover over a symbol when you invoke the command,rustic-doc-search
will insert a default value. - Add
universal argument
to only search for level 1 headers like struct or enum names.
Notes
- We are waiting for an update to Pandoc that will make the generated documents prettier, it should be available soon https://github.com/jgm/pandoc/issues/6554
- You should re-run
rustic-doc-setup
once in a while, to update the pandoc filter. - If rustic-doc does not find the documentation for something, the first thing to do is check the project's
target/doc
folder for the corresponding.html-file
. If there is no file there, there is nothing for rustic-doc to convert. If there is a file there, please create an issue!
Popup
You can execute commands with rustic-popup
. The list of commands can be customized with rustic-popup-commands
. The command rustic-popup-default-action
(RET
or TAB
) allows you to change:
RUST_BACKTRACE
environment variablecompilation-arguments
forrecompile
- arguments for
cargo test
View help buffer containing a command's flags with h
:
elisp tests
To run the tests, you will need Cask.
cask exec ert-runner
Contributing
PRs, feature requests and bug reports are very welcome.