This is a fork of rustic mode which is maintained. For more details, see here.
This package is based on rust-mode and provides additional features:
rustic only shares the rust-mode code from rust-mode.el and rust-utils.el. The other files provide functionality that is similar to some of the features of rustic, however can be considered light-weight compared to some rustic's functionality.
The shared functions and options exist as aliases in the rust-mode and rustic namespace for backwards compatibility reasons(rustic has been a fork).
rust-syntax-propertize and adaptive-wrap-prefix-mode can lead to
severe lag when editing larger files (#107)First, you may need to install rust-analyzer. See Automatic server installation.
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.
Add melpa as part of package archives:
(use-package package
:ensure nil
:config
(package-initialize)
:custom
(package-native-compile t)
(package-archives '(("gnu" . "http://elpa.gnu.org/packages/")
("melpa" . "https://melpa.org/packages/"))))
And then install rustic appropriately:
(use-package rustic
:ensure t
:config
(setq rustic-format-on-save nil)
:custom
(rustic-cargo-use-last-stored-arguments t))
(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))
(package-initialize)
(package-refresh-contents)
(use-package quelpa-use-package
:ensure t)
(use-package rustic
:quelpa (rustic :fetcher github
:repo "emacs-rustic/rustic"))
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.
(straight-use-package 'rustic)
rustfmt and most of the common cargo commands should work remotely. We are currently updating the code base. If you encounter any command that doesn't work remotely, please open an issue.

If you want to use a Makefile you can either use (setq rustic-compile-command "make") or run C-u + rustic-compile.
Commands:
rustic-compile compile project using rustic-compile-commandrustic-recompile recompile using compilation-argumentsrustic-compile-send-input send string to process of current bufferCustomization:
rustic-compile-display-method choose function that displays the
compilation buffer (use the function ignore, if you don't want the
buffer to be displayed)rustic-compile-backtrace change backtrace verbosityrustic-compile-rustflags set RUSTFLAGSrustic-compile-command default command for rust compilationrustic-compile-command-remote default command for remote rust compilationSupported compile.el variables:
t for automatic scrolling and first-error to scroll to first error)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).
rustic-compile-directory-method allows you to set the directory that
is used for compilation commands. The default is the current crate
which is returned by rustic-buffer-crate(there's also
rustic-buffer-workspace).
If you want to use the project root you can use rustic-project-root
instead.
FTR #174 #179 #236
The colors that are displayed in compilation buffers come from cargo
and are translated by xterm-color. You can change these colors by
modifying xterm-color-names and xterm-color-names-bright.
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-messagerustic-compilation-errorrustic-compilation-warningrustic-compilation-info
Ensure rustfmt is installed by running rustup component add rustfmt-preview
in your project's directory.
You can format your code with:
rustic-format-buffer format buffer with stdinrustic-format-file format file and revert bufferrustic-cargo-fmt run cargo-fmt on workspacerustic-format-region format active regionrustic-format-dwim run format on region,file or cargo fmtRustic uses the function rustic-save-some-buffers for saving buffers
before compilation.
To save buffers automatically, you can change the value of
compilation-ask-about-save, it has higher precedence than
buffer-save-without-query when compiling.
(defun rustic-mode-auto-save-hook ()
"Enable auto-saving in rustic-mode buffers."
(when buffer-file-name
(setq-local compilation-ask-about-save nil)))
(add-hook 'rustic-mode-hook 'rustic-mode-auto-save-hook)
Customization:
rustic-rustfmt-bin path to rustfmt executablerustic-rustfmt-bin-remote default path to remote rustfmt executablerustic-rustfmt-args additional args like +nightlyrustic-rustfmt-config-alist alist of rustfmt configuration optionsrustic-format-display-method default function used for displaying
rustfmt buffer (use the function ignore, if you don't want the
buffer to be displayed)rustic-format-on-save-method function to use for on-save formattingrustic-format-trigger
'on-save format buffer before saving'on-compile run 'cargo fmt' before compilationnil don't format automaticallyrustic-use-rust-save-some-buffers turn on to use automatic formatting
for save-some-buffersknown issues:
in case you are using hideshow you might want to set rustic-format-on-save-method to rustic-format-buffer(#274)
If you want to configure the following rustfmt call
rustfmt +nightly --config hard_tabs=true --config skip_children=false main.rs
you can use
(setq rustic-rustfmt-args "+nightly")
(setq rustic-rustfmt-config-alist '((hard_tabs . t) (skip_children . nil)))
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 have to put edition = "2018" in a
rustfmt.toml. See here for more
info.
Currently only rustic-format-buffer works remotely.
rustic-rustfmt-bin needs to be an absolute path to work remotely.
For using tree sitter integration, make sure to enable tree sitter in rust-mode:
(use-package rust-mode
:ensure t
:init
(setq rust-mode-treesitter-derive t))
And then make sure to have rustic load after rust-mode:
(use-package rustic
:ensure t
:after (rust-mode))
Alternatively, using straight without use-package:
(straight-use-package 'rust-mode)
(setq rust-mode-treesitter-derive t)
(straight-use-package 'rustic)
(with-eval-after-load 'rust-mode
(require 'rustic nil t))
Disable rustic-lsp-setup-p to turn off automatic LSP configuration.
If you want to turn off LSP temporarily you can set
rustic-lsp-client to nil. You have to restart emacs when you switch
lsp clients.
Don't forget that rustic doesn't contain the code for interacting with lsp servers. Therefore most issues are not related to rustic, but to the lsp client or server you are using.
rust-analyzer is the default and can be changed to rls if required (Note that rls
is deprecated and is slated to be removed). lsp-mode related code was
moved to the lsp-mode repo. rustic-lsp-server sets the value of
lsp-rust-server.
Change rust-analyzer path.
(setq rustic-analyzer-command '("~/.cargo/bin/rust-analyzer"))
If you are using rustup to manage your rust-analyzer, you would
have to configure like this to make it work with use-package:
(use-package rustic
:custom
(rustic-analyzer-command '("rustup" "run" "stable" "rust-analyzer")))
lsp-mode provides this feature, but eglot doesn't #403
Install rust-analyzer manually.
The default package is lsp-mode. But you can also use eglot.
(setq rustic-lsp-client 'eglot)
LSP commands:
xref-find-definitions find definitionsxref-find-references with helm and rust-analyzerrustic-cargo-add-missing-dependencies convenient command that adds missing dependencies to a crate's Cargo.toml
Turn off flymake.
(add-hook 'eglot--managed-mode-hook (lambda () (flymake-mode -1)))
lsp-describe-thing-at-point display documentationlsp-find-definition makes use of xrefYou can find more information in the lsp-mode documentation for Rust.
lsp-execute-code-actionThis 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.


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.

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.
This is an early experimental feature, and is disabled by default.
Source files not belonging to any crate, or detached source files,
are supported by rust-analyzer, and this feature can be enabled via
rustic-enable-detached-file-support. (Currently, only eglot is
supported.)
Caveat: Due to some current limitations, you should avoid opening a detached file in a large directory with this feature enabled.
Since the cargo commands also use the derived compilation mode, you can use the commands that are mentioned in the "compilation" section.
Customization:
rustic-cargo-bin Path to cargo executablerustic-cargo-bin-remote Path to remote cargo executablerustic-cargo-build-arguments default arguments for cargo buildrustic-cargo-check-arguments default arguments for cargo checkrustic-cargo-auto-add-missing-dependencies automatically add missing dependencies
to Cargo.toml by checking new diagnostics for 'unresolved import' errorsrustic-cargo-use-last-stored-arguments always use stored arguments that were provided with C-u(instead of requiring to run rustic "rerun" commands)rustic-cargo-populate-package-name for auto populating the correct package name when used with universal argument. This comes in handy when you are working with multiple projects. Not enabled by default, but recommened to enable it.Note that most commands support editing the exact cargo arguments and flags when called with the
prefix C-u.
| Keybinding | Command |
|---|---|
| C-c C-p | rustic-popup |
| C-c C-c C-u | rustic-compile |
| C-c C-c C-i | rustic-recompile |
| C-c C-c C-o | rustic-format-buffer |
| C-c C-c C-, | rustic-docstring-dwim |
| C-c C-c C-b | rustic-cargo-build |
| C-c C-c C-k | rustic-cargo-check |
| C-c C-c C-r | rustic-cargo-run |
| C-c C-c C-f | rustic-cargo-fmt |
| C-c C-c C-t | rustic-cargo-test |
| C-c C-c C-c | rustic-cargo-current-test |
| C-c C-c C-l | rustic-cargo-clippy |
| C-c C-c C-n | rustic-cargo-outdated |
| C-c C-c n | rustic-cargo-new |
| C-c C-c i | rustic-cargo-init |
| C-c C-c b | rustic-cargo-bench |
| C-c C-c d | rustic-cargo-doc |
| C-c C-c c | rustic-cargo-clean |
| C-c C-c k | rustic-cargo-clippy |
| C-c C-c f | rustic-cargo-clippy-fix |
| C-c C-c a | rustic-cargo-add |
| C-c C-c r | rustic-cargo-rm |
| C-c C-c u | rustic-cargo-upgrade |
More details on each command below
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'rustic-cargo-add-missing-dependencies Add the missing dependencies for the current buffer to Cargo.tomlIf you want to disable warnings when running cargo-test commands, you can set
(setq rustic-cargo-test-disable-warnings t).
Commands:
rustic-cargo-test run 'cargo test', when called with C-u edit the command
before running and store in rustic-test-arguments.rustic-cargo-test-rerun (g from compile buffer) rerun 'cargo test' with arguments stored in
rustic-test-argumentsrustic-cargo-current-test run test at point, whether it's a function or a modulerustic-cargo-test-rerun-current (C-c C-t or t from compile buffer) re-run the test at point
from the *cargo-test* compile buffer.rustic-cargo-run-nextest command for running nextestrustic-cargo-nextest-current-test is the nextest equivalent for rustic-cargo-current-test
Based on the usecase, we provide three variants of it:
rustic-cargo-runThis is meant for non interactive programs. It's creates a new mode
which is built on top of rustic-compilation-mode. You can press g
in this mode's buffer to make it re-run.
rustic-cargo-comint-runThis is meant for both interactive and non interactive programs. For
non interactive programs, you would need to pass data to it via stdin.
It's creates a new mode which is built on top of comint-mode. You
can press C-c C-g in this mode's buffer to make it re-run. You can
pass input to the program directly in it's output buffer and press RET.
rustic-cargo-plain-runThis is similar to the above rustic-cargo-comint-run. Input can be
sent to the program in one of two ways:
rustic-compile-send-input, which reads the input from the
minibuffer.rustic-cargo-run-use-comint: when this variable is set to t, the
input can be typed directly into the output buffer of 'cargo run'
and sent off with RET, just like in comint-mode. You need
polymode installed for this to work.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 upgrade and prompt user for version.U mark all upgradable crates.l mark single crate for upgrading to latest version.L mark all crates to latest version.m remove markx perform marked package menu actionsr refresh crate listq quit window
cargo-expand provides the ability to expand macros. It also
provides the ability to target a specific modules or a named item
within a module (eg: module::Type).
rustic-cargo-expand: runs cargo expand. You can also use
universal argument to target a specific named item to expand.cargo spellcheck checks the documentation for spelling and grammar mistakes.
rustic-cargo-spellcheck: runs cargo spellcheck and will open a
buffer where you can go through the various errors pointed out by
it.rustic-cargo-init run 'cargo init' to initialize a directoryrustic-cargo-new use 'cargo new' to create a new packagerustic-cargo-bench run 'cargo bench' for the current projectrustic-cargo-build-doc build the documentation for the current projectrustic-cargo-doc open the documentation for the current project in a browserrustic-cargo-lints called with rustic-lints-argumentsrustic-cargo-install run 'cargo install' on the current package.rustic-cargo-update run cargo update on the current package.rustic-cargo-custom-command run cargo with custom sub commands.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.
You can change the parameters rustic-default-clippy-arguments that
default to "--all-targets --all-features".
It's possible to run 'clippy --fix' automatically when starting a compile
process by setting rustic-cargo-clippy-trigger-fix to 'on-compile.
You can also use 'on-save, but this doesn't work in combination with
automatic formatting.
This feature can be used in combination with auto-formatting.
Works for:
rustic-cargo-buildrustic-compilerustic-recompilerustic-cargo-clippy to view the results in a derived compilation moderustic-cargo-clippy-fix run 'clippy fix' using rustic-cargo-clippy-fix-args
the default value is "--allow-dirty"In case you want to use clippy with flycheck but without LSP, 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 checker automatically detects the active toolchain and applies the correct parameters. You can set a default value for both stable and nightly toolchains. These are the default values.
rustic-flycheck-clippy-params-stable "--message-format=json"rustic-flycheck-clippy-params-nightly "--message-format=json -Zunstable-options"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.
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.
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 processrustic-babel-auto-wrap-main wrap body into main functionrustic-babel-default-toolchain active toolchain for babel blocksrustic-babel-display-error-popup displays error popup on
compilation failure or when the exit code is non zero. Set it to nil
if you want it to be displayed as part of result block.You can use lsp in babel blocks with lsp-org.
rustic-babel-format-block format block at pointrustic-babel-header-insert-crates include missing dependencies in :crates header argrustic-babel-visit-project find generated project of block at pointrustic-babel-clippy run clippy on block(currently doesn't honor babel params, you can open a feature request if you miss it)This block shows how to use crates with the latest version for both serde and regex.
The "*" will be added automatically for serde.
#+BEGIN_SRC rust :crates '(serde (regex . *))
extern crate regex;
extern crate serde;
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
Similarly, to depend on local Rust crates, you can set the :paths
argument:
#+BEGIN_SRC rust :crates '((foo . 1.0)) :paths '((foo . "/home/you/code/foo"))
use foo::Foo;
fn main() {
// Your code.
}
#+END_SRC
You can specify the :toolchain by quoted 'stable/'nightly/'beta,
or specify a toolchain version like "1.63.0", "nightly-2022-08-08".
#+begin_src rust :toolchain 'nightly
fn main() {
let foo: String = vec!["a", "b", "c"].into_iter().intersperse(",").collect();
println!("{}", foo);
}
#+end_src
#+RESULTS:
: a,b,c
Auto wrap whole block body in a fn main function call if none
exists.
Since this is very handy in most code snippets, so the default value
is yes. no if you don't want this feature(for example, you don't
want regex search slow things down).
You can also set a default value by:
;; By setq this default to `nil`, you'll have to explict set params to ":main yes" in each block
(setq rustic-babel-auto-wrap-main nil)
#+begin_src rust :main yes
let x = vec![1, 2, 3].iter().map(|&x| x + 1).collect::<Vec<_>>();
println!("{:?}", x);
#+end_src
#+results:
: [2, 3, 4]
This parameter allows you to run code that is located in different
babel blocks by using named blocks with the :include keyword. This
feature only concats the blocks so you don't need to import the code
you want to use.
You can still use :main to wrap the code of the main block.
#+name: b1
#+begin_src rust
pub fn b1_func() -> String {
String::from("b1 function called")
}
#+end_src
#+name: b2
#+begin_src rust
pub fn b2_func() -> String {
String::from("b2 function called")
}
#+end_src
#+begin_src rust :include '(b1 b2)
fn main() {
println!("{:?}", b1_func());
println!("{:?}", b2_func());
}
#+end_src
#+RESULTS:
: "b1 function called"
: "b2 function called"
When using this keyword blocks are treated as modules. The files are generated automatically.
#+name: mymodule
#+begin_src rust
pub fn myfunc() -> String {
String::from("mymodule function called")
}
#+end_src
#+begin_src rust :use '(mymodule)
use mymodule::myfunc;
fn main() {
println!("{:?}", myfunc());
}
#+end_src
#+RESULTS:
: "mymodule function called"
To load your Rust toolchain via envrc, ensure that the inheritenv package is available before loading rustic, so that auxiliary rustic buffers acquire the correct environment to find the toolchain.
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).
It is possible to read rust documentation inside Emacs! This currently
requires LSP-mode and cargo. Unfortunately, this probably won't work on Windows. 
Required:
Optional:
ripgrep and helm-ag are optional but highly recommended.
If only ripgrep is installed, it will be used with the emacs grep
command. In case neither is available, the emacs grep command will
use grep, like in the good old days.
When a required cargo package is missing you will be asked if you want to install them when running rustic-doc-setup.
rustic-doc-mode.rustic-doc-setup to download files that rustic-doc needs to
convert rust documentation and also convert std.rustic-doc-convert-current-packagerustic-doc-search (bound to C-# by
default) if you are in Rust mode, Rustic mode or Org mode. If
you hover over a symbol when you invoke the command,
rustic-doc-search will insert a default value.universal argument to only search for level 1 headers like
struct or enum names.You can change the defaults by modifying
rustic-doc-rg-search-commandrustic-doc-search-functionrustic-doc-setup once in a while, to update the
pandoc filter.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!You can execute commands with rustic-popup(call it with optional
argument C-u to choose a directory). 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 for recompilecargo testIf you want to close the popup after you ran a command you can set
rustic-kill-buffer-and-window to t.

View help buffer containing a command's flags with h:

rustic-mode derives from rust-mode, however we replace default key bindings and some hooks.
There are also some additional commands:
rust-dbg-wrap-or-unwrap Either remove or add the dbg! macrorust-toggle-mutability Toggles the mutability of the variable defined on the current linerust-promote-module-into-dir Promote the module file visited by the current buffer into its own directoryTo run the tests, you will need Eask.
eask emacs --batch -L . -L test -l test/all-tests.el -f ert-run-tests-batch-and-exit
alternatively you can use just test
PRs, feature requests and bug reports are very welcome. If you want to add a new feature please open an issue in advance so we can discuss the details.
(top 30 of 144)
Emacs Lisp
100.0%
This is a fork of rustic mode which is maintained. For more details, see here.
This package is based on rust-mode and provides additional features:
rustic only shares the rust-mode code from rust-mode.el and rust-utils.el. The other files provide functionality that is similar to some of the features of rustic, however can be considered light-weight compared to some rustic's functionality.
The shared functions and options exist as aliases in the rust-mode and rustic namespace for backwards compatibility reasons(rustic has been a fork).
rust-syntax-propertize and adaptive-wrap-prefix-mode can lead to
severe lag when editing larger files (#107)First, you may need to install rust-analyzer. See Automatic server installation.
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.
Add melpa as part of package archives:
(use-package package
:ensure nil
:config
(package-initialize)
:custom
(package-native-compile t)
(package-archives '(("gnu" . "http://elpa.gnu.org/packages/")
("melpa" . "https://melpa.org/packages/"))))
And then install rustic appropriately:
(use-package rustic
:ensure t
:config
(setq rustic-format-on-save nil)
:custom
(rustic-cargo-use-last-stored-arguments t))
(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))
(package-initialize)
(package-refresh-contents)
(use-package quelpa-use-package
:ensure t)
(use-package rustic
:quelpa (rustic :fetcher github
:repo "emacs-rustic/rustic"))
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.
(straight-use-package 'rustic)
rustfmt and most of the common cargo commands should work remotely. We are currently updating the code base. If you encounter any command that doesn't work remotely, please open an issue.

If you want to use a Makefile you can either use (setq rustic-compile-command "make") or run C-u + rustic-compile.
Commands:
rustic-compile compile project using rustic-compile-commandrustic-recompile recompile using compilation-argumentsrustic-compile-send-input send string to process of current bufferCustomization:
rustic-compile-display-method choose function that displays the
compilation buffer (use the function ignore, if you don't want the
buffer to be displayed)rustic-compile-backtrace change backtrace verbosityrustic-compile-rustflags set RUSTFLAGSrustic-compile-command default command for rust compilationrustic-compile-command-remote default command for remote rust compilationSupported compile.el variables:
t for automatic scrolling and first-error to scroll to first error)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).
rustic-compile-directory-method allows you to set the directory that
is used for compilation commands. The default is the current crate
which is returned by rustic-buffer-crate(there's also
rustic-buffer-workspace).
If you want to use the project root you can use rustic-project-root
instead.
FTR #174 #179 #236
The colors that are displayed in compilation buffers come from cargo
and are translated by xterm-color. You can change these colors by
modifying xterm-color-names and xterm-color-names-bright.
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-messagerustic-compilation-errorrustic-compilation-warningrustic-compilation-info
Ensure rustfmt is installed by running rustup component add rustfmt-preview
in your project's directory.
You can format your code with:
rustic-format-buffer format buffer with stdinrustic-format-file format file and revert bufferrustic-cargo-fmt run cargo-fmt on workspacerustic-format-region format active regionrustic-format-dwim run format on region,file or cargo fmtRustic uses the function rustic-save-some-buffers for saving buffers
before compilation.
To save buffers automatically, you can change the value of
compilation-ask-about-save, it has higher precedence than
buffer-save-without-query when compiling.
(defun rustic-mode-auto-save-hook ()
"Enable auto-saving in rustic-mode buffers."
(when buffer-file-name
(setq-local compilation-ask-about-save nil)))
(add-hook 'rustic-mode-hook 'rustic-mode-auto-save-hook)
Customization:
rustic-rustfmt-bin path to rustfmt executablerustic-rustfmt-bin-remote default path to remote rustfmt executablerustic-rustfmt-args additional args like +nightlyrustic-rustfmt-config-alist alist of rustfmt configuration optionsrustic-format-display-method default function used for displaying
rustfmt buffer (use the function ignore, if you don't want the
buffer to be displayed)rustic-format-on-save-method function to use for on-save formattingrustic-format-trigger
'on-save format buffer before saving'on-compile run 'cargo fmt' before compilationnil don't format automaticallyrustic-use-rust-save-some-buffers turn on to use automatic formatting
for save-some-buffersknown issues:
in case you are using hideshow you might want to set rustic-format-on-save-method to rustic-format-buffer(#274)
If you want to configure the following rustfmt call
rustfmt +nightly --config hard_tabs=true --config skip_children=false main.rs
you can use
(setq rustic-rustfmt-args "+nightly")
(setq rustic-rustfmt-config-alist '((hard_tabs . t) (skip_children . nil)))
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 have to put edition = "2018" in a
rustfmt.toml. See here for more
info.
Currently only rustic-format-buffer works remotely.
rustic-rustfmt-bin needs to be an absolute path to work remotely.
For using tree sitter integration, make sure to enable tree sitter in rust-mode:
(use-package rust-mode
:ensure t
:init
(setq rust-mode-treesitter-derive t))
And then make sure to have rustic load after rust-mode:
(use-package rustic
:ensure t
:after (rust-mode))
Alternatively, using straight without use-package:
(straight-use-package 'rust-mode)
(setq rust-mode-treesitter-derive t)
(straight-use-package 'rustic)
(with-eval-after-load 'rust-mode
(require 'rustic nil t))
Disable rustic-lsp-setup-p to turn off automatic LSP configuration.
If you want to turn off LSP temporarily you can set
rustic-lsp-client to nil. You have to restart emacs when you switch
lsp clients.
Don't forget that rustic doesn't contain the code for interacting with lsp servers. Therefore most issues are not related to rustic, but to the lsp client or server you are using.
rust-analyzer is the default and can be changed to rls if required (Note that rls
is deprecated and is slated to be removed). lsp-mode related code was
moved to the lsp-mode repo. rustic-lsp-server sets the value of
lsp-rust-server.
Change rust-analyzer path.
(setq rustic-analyzer-command '("~/.cargo/bin/rust-analyzer"))
If you are using rustup to manage your rust-analyzer, you would
have to configure like this to make it work with use-package:
(use-package rustic
:custom
(rustic-analyzer-command '("rustup" "run" "stable" "rust-analyzer")))
lsp-mode provides this feature, but eglot doesn't #403
Install rust-analyzer manually.
The default package is lsp-mode. But you can also use eglot.
(setq rustic-lsp-client 'eglot)
LSP commands:
xref-find-definitions find definitionsxref-find-references with helm and rust-analyzerrustic-cargo-add-missing-dependencies convenient command that adds missing dependencies to a crate's Cargo.toml
Turn off flymake.
(add-hook 'eglot--managed-mode-hook (lambda () (flymake-mode -1)))
lsp-describe-thing-at-point display documentationlsp-find-definition makes use of xrefYou can find more information in the lsp-mode documentation for Rust.
lsp-execute-code-actionThis 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.


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.

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.
This is an early experimental feature, and is disabled by default.
Source files not belonging to any crate, or detached source files,
are supported by rust-analyzer, and this feature can be enabled via
rustic-enable-detached-file-support. (Currently, only eglot is
supported.)
Caveat: Due to some current limitations, you should avoid opening a detached file in a large directory with this feature enabled.
Since the cargo commands also use the derived compilation mode, you can use the commands that are mentioned in the "compilation" section.
Customization:
rustic-cargo-bin Path to cargo executablerustic-cargo-bin-remote Path to remote cargo executablerustic-cargo-build-arguments default arguments for cargo buildrustic-cargo-check-arguments default arguments for cargo checkrustic-cargo-auto-add-missing-dependencies automatically add missing dependencies
to Cargo.toml by checking new diagnostics for 'unresolved import' errorsrustic-cargo-use-last-stored-arguments always use stored arguments that were provided with C-u(instead of requiring to run rustic "rerun" commands)rustic-cargo-populate-package-name for auto populating the correct package name when used with universal argument. This comes in handy when you are working with multiple projects. Not enabled by default, but recommened to enable it.Note that most commands support editing the exact cargo arguments and flags when called with the
prefix C-u.
| Keybinding | Command |
|---|---|
| C-c C-p | rustic-popup |
| C-c C-c C-u | rustic-compile |
| C-c C-c C-i | rustic-recompile |
| C-c C-c C-o | rustic-format-buffer |
| C-c C-c C-, | rustic-docstring-dwim |
| C-c C-c C-b | rustic-cargo-build |
| C-c C-c C-k | rustic-cargo-check |
| C-c C-c C-r | rustic-cargo-run |
| C-c C-c C-f | rustic-cargo-fmt |
| C-c C-c C-t | rustic-cargo-test |
| C-c C-c C-c | rustic-cargo-current-test |
| C-c C-c C-l | rustic-cargo-clippy |
| C-c C-c C-n | rustic-cargo-outdated |
| C-c C-c n | rustic-cargo-new |
| C-c C-c i | rustic-cargo-init |
| C-c C-c b | rustic-cargo-bench |
| C-c C-c d | rustic-cargo-doc |
| C-c C-c c | rustic-cargo-clean |
| C-c C-c k | rustic-cargo-clippy |
| C-c C-c f | rustic-cargo-clippy-fix |
| C-c C-c a | rustic-cargo-add |
| C-c C-c r | rustic-cargo-rm |
| C-c C-c u | rustic-cargo-upgrade |
More details on each command below
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'rustic-cargo-add-missing-dependencies Add the missing dependencies for the current buffer to Cargo.tomlIf you want to disable warnings when running cargo-test commands, you can set
(setq rustic-cargo-test-disable-warnings t).
Commands:
rustic-cargo-test run 'cargo test', when called with C-u edit the command
before running and store in rustic-test-arguments.rustic-cargo-test-rerun (g from compile buffer) rerun 'cargo test' with arguments stored in
rustic-test-argumentsrustic-cargo-current-test run test at point, whether it's a function or a modulerustic-cargo-test-rerun-current (C-c C-t or t from compile buffer) re-run the test at point
from the *cargo-test* compile buffer.rustic-cargo-run-nextest command for running nextestrustic-cargo-nextest-current-test is the nextest equivalent for rustic-cargo-current-test
Based on the usecase, we provide three variants of it:
rustic-cargo-runThis is meant for non interactive programs. It's creates a new mode
which is built on top of rustic-compilation-mode. You can press g
in this mode's buffer to make it re-run.
rustic-cargo-comint-runThis is meant for both interactive and non interactive programs. For
non interactive programs, you would need to pass data to it via stdin.
It's creates a new mode which is built on top of comint-mode. You
can press C-c C-g in this mode's buffer to make it re-run. You can
pass input to the program directly in it's output buffer and press RET.
rustic-cargo-plain-runThis is similar to the above rustic-cargo-comint-run. Input can be
sent to the program in one of two ways:
rustic-compile-send-input, which reads the input from the
minibuffer.rustic-cargo-run-use-comint: when this variable is set to t, the
input can be typed directly into the output buffer of 'cargo run'
and sent off with RET, just like in comint-mode. You need
polymode installed for this to work.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 upgrade and prompt user for version.U mark all upgradable crates.l mark single crate for upgrading to latest version.L mark all crates to latest version.m remove markx perform marked package menu actionsr refresh crate listq quit window
cargo-expand provides the ability to expand macros. It also
provides the ability to target a specific modules or a named item
within a module (eg: module::Type).
rustic-cargo-expand: runs cargo expand. You can also use
universal argument to target a specific named item to expand.cargo spellcheck checks the documentation for spelling and grammar mistakes.
rustic-cargo-spellcheck: runs cargo spellcheck and will open a
buffer where you can go through the various errors pointed out by
it.rustic-cargo-init run 'cargo init' to initialize a directoryrustic-cargo-new use 'cargo new' to create a new packagerustic-cargo-bench run 'cargo bench' for the current projectrustic-cargo-build-doc build the documentation for the current projectrustic-cargo-doc open the documentation for the current project in a browserrustic-cargo-lints called with rustic-lints-argumentsrustic-cargo-install run 'cargo install' on the current package.rustic-cargo-update run cargo update on the current package.rustic-cargo-custom-command run cargo with custom sub commands.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.
You can change the parameters rustic-default-clippy-arguments that
default to "--all-targets --all-features".
It's possible to run 'clippy --fix' automatically when starting a compile
process by setting rustic-cargo-clippy-trigger-fix to 'on-compile.
You can also use 'on-save, but this doesn't work in combination with
automatic formatting.
This feature can be used in combination with auto-formatting.
Works for:
rustic-cargo-buildrustic-compilerustic-recompilerustic-cargo-clippy to view the results in a derived compilation moderustic-cargo-clippy-fix run 'clippy fix' using rustic-cargo-clippy-fix-args
the default value is "--allow-dirty"In case you want to use clippy with flycheck but without LSP, 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 checker automatically detects the active toolchain and applies the correct parameters. You can set a default value for both stable and nightly toolchains. These are the default values.
rustic-flycheck-clippy-params-stable "--message-format=json"rustic-flycheck-clippy-params-nightly "--message-format=json -Zunstable-options"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.
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.
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 processrustic-babel-auto-wrap-main wrap body into main functionrustic-babel-default-toolchain active toolchain for babel blocksrustic-babel-display-error-popup displays error popup on
compilation failure or when the exit code is non zero. Set it to nil
if you want it to be displayed as part of result block.You can use lsp in babel blocks with lsp-org.
rustic-babel-format-block format block at pointrustic-babel-header-insert-crates include missing dependencies in :crates header argrustic-babel-visit-project find generated project of block at pointrustic-babel-clippy run clippy on block(currently doesn't honor babel params, you can open a feature request if you miss it)This block shows how to use crates with the latest version for both serde and regex.
The "*" will be added automatically for serde.
#+BEGIN_SRC rust :crates '(serde (regex . *))
extern crate regex;
extern crate serde;
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
Similarly, to depend on local Rust crates, you can set the :paths
argument:
#+BEGIN_SRC rust :crates '((foo . 1.0)) :paths '((foo . "/home/you/code/foo"))
use foo::Foo;
fn main() {
// Your code.
}
#+END_SRC
You can specify the :toolchain by quoted 'stable/'nightly/'beta,
or specify a toolchain version like "1.63.0", "nightly-2022-08-08".
#+begin_src rust :toolchain 'nightly
fn main() {
let foo: String = vec!["a", "b", "c"].into_iter().intersperse(",").collect();
println!("{}", foo);
}
#+end_src
#+RESULTS:
: a,b,c
Auto wrap whole block body in a fn main function call if none
exists.
Since this is very handy in most code snippets, so the default value
is yes. no if you don't want this feature(for example, you don't
want regex search slow things down).
You can also set a default value by:
;; By setq this default to `nil`, you'll have to explict set params to ":main yes" in each block
(setq rustic-babel-auto-wrap-main nil)
#+begin_src rust :main yes
let x = vec![1, 2, 3].iter().map(|&x| x + 1).collect::<Vec<_>>();
println!("{:?}", x);
#+end_src
#+results:
: [2, 3, 4]
This parameter allows you to run code that is located in different
babel blocks by using named blocks with the :include keyword. This
feature only concats the blocks so you don't need to import the code
you want to use.
You can still use :main to wrap the code of the main block.
#+name: b1
#+begin_src rust
pub fn b1_func() -> String {
String::from("b1 function called")
}
#+end_src
#+name: b2
#+begin_src rust
pub fn b2_func() -> String {
String::from("b2 function called")
}
#+end_src
#+begin_src rust :include '(b1 b2)
fn main() {
println!("{:?}", b1_func());
println!("{:?}", b2_func());
}
#+end_src
#+RESULTS:
: "b1 function called"
: "b2 function called"
When using this keyword blocks are treated as modules. The files are generated automatically.
#+name: mymodule
#+begin_src rust
pub fn myfunc() -> String {
String::from("mymodule function called")
}
#+end_src
#+begin_src rust :use '(mymodule)
use mymodule::myfunc;
fn main() {
println!("{:?}", myfunc());
}
#+end_src
#+RESULTS:
: "mymodule function called"
To load your Rust toolchain via envrc, ensure that the inheritenv package is available before loading rustic, so that auxiliary rustic buffers acquire the correct environment to find the toolchain.
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).
It is possible to read rust documentation inside Emacs! This currently
requires LSP-mode and cargo. Unfortunately, this probably won't work on Windows. 
Required:
Optional:
ripgrep and helm-ag are optional but highly recommended.
If only ripgrep is installed, it will be used with the emacs grep
command. In case neither is available, the emacs grep command will
use grep, like in the good old days.
When a required cargo package is missing you will be asked if you want to install them when running rustic-doc-setup.
rustic-doc-mode.rustic-doc-setup to download files that rustic-doc needs to
convert rust documentation and also convert std.rustic-doc-convert-current-packagerustic-doc-search (bound to C-# by
default) if you are in Rust mode, Rustic mode or Org mode. If
you hover over a symbol when you invoke the command,
rustic-doc-search will insert a default value.universal argument to only search for level 1 headers like
struct or enum names.You can change the defaults by modifying
rustic-doc-rg-search-commandrustic-doc-search-functionrustic-doc-setup once in a while, to update the
pandoc filter.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!You can execute commands with rustic-popup(call it with optional
argument C-u to choose a directory). 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 for recompilecargo testIf you want to close the popup after you ran a command you can set
rustic-kill-buffer-and-window to t.

View help buffer containing a command's flags with h:

rustic-mode derives from rust-mode, however we replace default key bindings and some hooks.
There are also some additional commands:
rust-dbg-wrap-or-unwrap Either remove or add the dbg! macrorust-toggle-mutability Toggles the mutability of the variable defined on the current linerust-promote-module-into-dir Promote the module file visited by the current buffer into its own directoryTo run the tests, you will need Eask.
eask emacs --batch -L . -L test -l test/all-tests.el -f ert-run-tests-batch-and-exit
alternatively you can use just test
PRs, feature requests and bug reports are very welcome. If you want to add a new feature please open an issue in advance so we can discuss the details.
(top 30 of 144)
Emacs Lisp
100.0%