diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2f2e174f..b5402cc8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,53 +1,47 @@ name: CI -on: [push, pull_request] +on: + push: + branches: [main] + pull_request: + workflow_dispatch: jobs: - unix-test: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest] - emacs-version: - - 27.2 - - 28.1 - steps: - - uses: actions/checkout@v2 - - - uses: purcell/setup-emacs@master - with: - version: ${{ matrix.emacs-version }} - - - uses: conao3/setup-cask@master - with: - version: 0.8.4 - - - name: Install requirements - run: | - echo "$HOME/.cask/bin" >> $GITHUB_PATH - echo "$HOME/bin" >> $GITHUB_PATH - - sudo apt update - sudo apt install -y gnutls-bin gnupg2 dirmngr - sudo apt install -y texinfo libgif-dev libxpm-dev - - - name: Install needed rust stuff - run: | - curl -sSf https://build.travis-ci.com/files/rustup-init.sh | sh -s -- --default-toolchain=stable -y - source $HOME/.cargo/env - rustup component add rustfmt-preview - - - name: rustic-doc prerequisites - run: | - wget https://github.com/jgm/pandoc/releases/download/2.17.0.1/pandoc-2.17.0.1-1-amd64.deb - sudo dpkg -i pandoc-2.17.0.1-1-amd64.deb - mkdir -p ~/.local/bin - mkdir -p ~/.local/share/emacs/rustic-doc/std/ - curl -sL https://github.com/sharkdp/fd/releases/download/v8.3.2/fd-v8.3.2-x86_64-unknown-linux-musl.tar.gz | tar xz --wildcards --strip-components=1 -C /usr/local/bin '*/fd' - curl -sL https://github.com/BurntSushi/ripgrep/releases/download/13.0.0/ripgrep-13.0.0-x86_64-unknown-linux-musl.tar.gz | tar xz --wildcards --strip-components=1 -C /usr/local/bin '*/rg' - rustup component add rust-docs - - - name: Run tests - run: | - make test + unix-test: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest] + emacs-version: + - 27.2 + - 28.1 + - 29.1 + - 29.2 + steps: + - uses: actions/checkout@v4 + - uses: taiki-e/install-action@v2 + with: + tool: just@1.16.0 + - uses: purcell/setup-emacs@master + with: + version: ${{ matrix.emacs-version }} + + - uses: cask/setup-cask@v1 + with: + version: 0.9.0 + + - name: Install requirements + run: | + echo "$HOME/.cask/bin" >> $GITHUB_PATH + echo "$HOME/bin" >> $GITHUB_PATH + + - uses: dtolnay/rust-toolchain@master + with: + toolchain: 1.76.0 + components: clippy, rustfmt + + - name: Run tests + run: | + just build + just test diff --git a/CHANGELOG.org b/CHANGELOG.org new file mode 100644 index 00000000..e571e133 --- /dev/null +++ b/CHANGELOG.org @@ -0,0 +1,22 @@ +* Unreleased + +- Revamp testing in CI: Use only cask. +- Replace Makefile with justfile. +- Pin Rust version in CI to avoid spurious failure. +- Create a new babel variable to create temporary directory and not + rely on babel's internal stuff. This was needed to fix the tests. +- Fix flaky tests. +- Enable tests for Emacs 29.1 +- Update rustc to 1.76.0 +- Fix bugs in rustic-cargo-outdated mode in the presence of git + repositories as dependency. +- Remove racer integrace since it's development has been discontinued. +- Enable tests for Emacs 29.2 +- Add fixes for enabling tree sitter support from rust-mode. +- Make ~rustic-cargo-clippy~ remember it's universal arguments. +- Populate minibuffer entries for ~rustic-cargo-clippy~ and + ~rustic-cargo-build~ with it's previous entry. +- Fix integration with lsp-mode during format of buffers. +- Make ~rustic-cargo-test~ rembmer it's universal arguments. +- ~rustic-recompile~ will remember any universal arguments that is + passed to it. diff --git a/Makefile b/Makefile deleted file mode 100644 index c1c8053e..00000000 --- a/Makefile +++ /dev/null @@ -1,153 +0,0 @@ -## Common - -.PHONY: test - --include config.mk - -all: lisp - -PKG = rustic - -EMACS ?= emacs -EMACS_ARGS ?= - -ELS = rustic.el -ELS += rustic-racer.el -ELS += rustic-flycheck.el -ELS += rustic-interaction.el -ELS += rustic-compile.el -ELS += rustic-cargo.el -ELS += rustic-clippy.el -ELS += rustic-popup.el -ELS += rustic-rustfix.el -ELS += rustic-rustfmt.el -ELS += rustic-babel.el -ELS += rustic-lsp.el -ELS += rustic-flycheck.el -ELS += rustic-doc.el -ELCS = $(ELS:.el=.elc) - -rustic.elc: -rustic-racer.elc: rustic.elc -rustic-flycheck.elc: rustic.elc -rustic-interaction.elc: rustic.elc -rustic-compile.elc: rustic.elc -rustic-cargo.elc: rustic-compile.elc rustic-interaction.elc -rustic-clippy.elc: rustic-compile.elc -rustic-popup.elc: rustic-cargo.elc -rustic-rustfix.elc: rustic-cargo.elc -rustic-rustfmt.elc: rustic-cargo.elc -rustic-babel.elc: rustic-rustfmt.elc -rustic-lsp.elc: rustic-rustfmt.elc -rustic-playground.elc: -rustic-doc.elc: - -## Without Cask -ifdef WITHOUT_CASK - -DEPS = company -DEPS += dash -DEPS += f -DEPS += flycheck -DEPS += eglot -DEPS += helm-ag -DEPS += ht -DEPS += hydra -DEPS += lsp-mode -DEPS += lsp-mode/clients -DEPS += lv -DEPS += markdown-mode -DEPS += org/lisp -DEPS += projectile -DEPS += s -DEPS += spinner -DEPS += xterm-color -DEPS += yasnippet -DEPS += rust-mode - -LOAD_PATH ?= $(addprefix -L ../,$(DEPS)) -LOAD_PATH += -L . - -TEST_ELS = test/test-helper.el -TEST_ELS += $(wildcard test/rustic-*-test.el) -TEST_ELCS = $(TEST_ELS:.el=.elc) - -lisp: $(ELCS) loaddefs - -%.elc: %.el - @printf "Compiling $<\n" - @$(EMACS) -Q --batch $(EMACS_ARGS) $(LOAD_PATH) \ - --funcall batch-byte-compile $< - -test-lisp: $(TEST_ELCS) - -test/%.elc: test/%.el - @printf "Compiling $<\n" - @$(EMACS) -Q --batch $(EMACS_ARGS) $(LOAD_PATH) -L test \ - --load $(CURDIR)/test/test-helper \ - --funcall batch-byte-compile $< - -test: $(TEST_ELCS) - @$(EMACS) -Q --batch $(EMACS_ARGS) $(LOAD_PATH) -L test \ - --load $(CURDIR)/test/test-helper \ - $(addprefix -l ,$(TEST_ELS)) \ - --funcall ert-run-tests-batch-and-exit - -## With Cask -else - -CASK_DIR := $(shell EMACS=$(EMACS) cask package-directory) - -$(CASK_DIR): Cask - EMACS=$(EMACS) cask install - touch $(CASK_DIR) - -cask-install: $(CASK_DIR) - -cask-build: loaddefs - EMACS=$(EMACS) cask build - -lisp: clean cask-install cask-build - -test: lisp - if [ -f "$(HOME)/.cargo/env" ] ; then . "$(HOME)/.cargo/env" ; fi ; \ - EMACS=$(EMACS) cask exec ert-runner --reporter ert - -## Common -endif - -CLEAN = $(ELCS) $(PKG)-autoloads.el $(TEST_ELCS) - -clean: - @printf "Cleaning...\n" - @rm -rf $(CLEAN) - -loaddefs: $(PKG)-autoloads.el - -define LOADDEFS_TMPL -;;; $(PKG)-autoloads.el --- automatically extracted autoloads -;; -;;; Code: -(add-to-list 'load-path (directory-file-name \ -(or (file-name-directory #$$) (car load-path)))) - -;; Local Variables: -;; version-control: never -;; no-byte-compile: t -;; no-update-autoloads: t -;; End: -;;; $(PKG)-autoloads.el ends here -endef -export LOADDEFS_TMPL -#' - -$(PKG)-autoloads.el: $(ELS) - @printf "Generating $@\n" - @printf "%s" "$$LOADDEFS_TMPL" > $@ - @$(EMACS) -Q --batch --eval "(progn\ - (setq make-backup-files nil)\ - (setq vc-handled-backends nil)\ - (setq default-directory (file-truename default-directory))\ - (setq generated-autoload-file (expand-file-name \"$@\"))\ - (setq find-file-visit-truename t)\ - (update-directory-autoloads default-directory))" diff --git a/README.md b/README.md index a4d5987c..3efc8777 100644 --- a/README.md +++ b/README.md @@ -1,80 +1,80 @@ # Rustic -[![MELPA](https://melpa.org/packages/rustic-badge.svg)](https://melpa.org/#/rustic) -[![](https://github.com/brotzeit/rustic/workflows/CI/badge.svg)](https://github.com/brotzeit/rustic/actions?query=workflow%3ACI) - - -**Table of Contents** +[![CI](https://github.com/psibi/rustic/actions/workflows/test.yml/badge.svg)](https://github.com/psibi/rustic/actions/workflows/test.yml) + - [Rustic](#rustic) - - [Intro](#intro) - - [Known issues](#known-issues) - - [Installation](#installation) - - [package](#package) - - [straight](#straight) + - [Intro](#intro) + - [Known issues](#known-issues) + - [Installation](#installation) + - [quelpa](#quelpa) + - [straight](#straight) + - [remote](#remote) + - [Compilation](#compilation) + - [Navigating errors](#navigating-errors) + - [default directory](#default-directory) + - [Faces](#faces) + - [rustc errors](#rustc-errors) + - [Rustfmt](#rustfmt) + - [Change default arguments](#change-default-arguments) + - [edition 2018](#edition-2018) - [remote](#remote) - - [Compilation](#compilation) - - [Navigating errors](#navigating-errors) - - [default directory](#default-directory) - - [Faces](#faces) - - [rustc errors](#rustc-errors) - - [Rustfmt](#rustfmt) - - [Change default arguments](#change-default-arguments) - - [edition 2018](#edition-2018) - - [remote](#remote-1) - - [LSP](#lsp) - - [Server](#server) - - [Automatic server installation](#automatic-server-installation) - - [Client](#client) - - [eglot](#eglot) - - [lsp-mode](#lsp-mode) - - [`lsp-execute-code-action`](#lsp-execute-code-action) - - [Applying code actions](#applying-code-actions) - - [Auto import](#auto-import) - - [Macro expansion](#macro-expansion) - - [LSP + TRAMP](#lsp--tramp) - - [Detached file](#detached-file) - - [Cargo](#cargo) - - [Edit](#edit) - - [Test](#test) - - [Run](#run) - - [Outdated](#outdated) - - [Expand](#expand) - - [Spellcheck](#spellcheck) - - [More cargo commands](#more-cargo-commands) - - [Clippy](#clippy) - - [auto-fixing before compilation](#auto-fixing-before-compilation) - - [Commands](#commands) - - [Flycheck](#flycheck) - - [lsp-mode](#lsp-mode-1) - - [Org-babel](#org-babel) - - [Intro](#intro-1) - - [lsp-mode](#lsp-mode-2) - - [Commands](#commands-1) - - [Parameters](#parameters) - - [:crates](#crates) - - [:features](#features) - - [:paths](#paths) - - [:toolchain](#toolchain) - - [:main](#main) - - [:include](#include) - - [:use](#use) - - [Envrc](#envrc) - - [Spinner](#spinner) - - [rust docs in org-mode](#rust-docs-in-org-mode) - - [Prerequisites](#prerequisites) - - [Usage](#usage) - - [Notes](#notes) - - [Popup](#popup) - - [rust-mode](#rust-mode) - - [elisp tests](#elisp-tests) - - [Contributing](#contributing) - - - + - [Tree sitter](#tree-sitter) + - [LSP](#lsp) + - [Server](#server) + - [Automatic server installation](#automatic-server-installation) + - [Client](#client) + - [eglot](#eglot) + - [lsp-mode](#lsp-mode) + - [`lsp-execute-code-action`](#lsp-execute-code-action) + - [Applying code actions](#applying-code-actions) + - [Auto import](#auto-import) + - [Macro expansion](#macro-expansion) + - [LSP + TRAMP](#lsp-tramp) + - [Detached file](#detached-file) + - [Cargo](#cargo) + - [Edit](#edit) + - [Test](#test) + - [Run](#run) + - [Outdated](#outdated) + - [Expand](#expand) + - [Spellcheck](#spellcheck) + - [More cargo commands](#more-cargo-commands) + - [Clippy](#clippy) + - [auto-fixing before compilation](#auto-fixing-before-compilation) + - [Commands](#commands) + - [Flycheck](#flycheck) + - [lsp-mode](#lsp-mode) + - [Org-babel](#org-babel) + - [Intro](#intro) + - [lsp-mode](#lsp-mode) + - [Commands](#commands) + - [Parameters](#parameters) + - [:crates](#crates) + - [:features](#features) + - [:paths](#paths) + - [:toolchain](#toolchain) + - [:main](#main) + - [:include](#include) + - [:use](#use) + - [envrc](#envrc) + - [Spinner](#spinner) + - [rust docs in org-mode](#rust-docs-in-org-mode) + - [Prerequisites](#prerequisites) + - [Usage](#usage) + - [Notes](#notes) + - [Popup](#popup) + - [rust-mode](#rust-mode) + - [elisp tests](#elisp-tests) + - [Contributing](#contributing) + ## Intro +This is a fork of [rustic](https://github.com/brotzeit/rustic) mode which is maintained. For more +details, [see +here](https://github.com/brotzeit/rustic/pull/551#issuecomment-1959124829). + This package is based on [rust-mode](https://github.com/rust-lang/rust-mode) and provides additional features: - cargo popup @@ -110,18 +110,20 @@ environment variables probably don't work in emacs. Try [exec-path-from-shell](https://github.com/purcell/exec-path-from-shell/tree/81125c5adbc903943c016c2984906dc089372a41#usage) to fix this. -### package +### quelpa -This section explains how to install rustic with the default package manager. -It's necessary to include elpa for a package dependency: - -```elisp +``` emacs-lisp (require 'package) -(setq package-archives '(("melpa" . "http://melpa.org/packages/") - ("gnu" . "http://elpa.gnu.org/packages/"))) +(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/")) (package-initialize) (package-refresh-contents) -(use-package rustic) + +(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 @@ -129,6 +131,7 @@ need to update GPG keys used by the ELPA package manager. Try installing [gnu-elpa-keyring-update](https://elpa.gnu.org/packages/gnu-elpa-keyring-update.html). + ### straight [straight.el](https://github.com/raxod502/straight.el#install-packages) @@ -299,6 +302,18 @@ Currently only `rustic-format-buffer` works remotely. `rustic-rustfmt-bin` needs to be an absolute path to work remotely. +## Tree sitter + +For using tree sitter integration, make sure to enable tree sitter in +rust-mode: + +``` emacs-lisp +(use-package rust-mode + :ensure t + :init + (setq rust-mode-treesitter-derive t)) +``` + ## LSP Disable `rustic-lsp-setup-p` to turn off automatic LSP configuration. @@ -939,10 +954,10 @@ There are also some additional commands: To run the tests, you will need [Cask](https://github.com/cask/cask). ``` bash -cask exec ert-runner +cask emacs --batch -L . -L test -l test/all-tests.el -f ert-run-tests-batch-and-exit ``` -alternatively you can use `make test` +alternatively you can use `just test` ## Contributing diff --git a/justfile b/justfile new file mode 100644 index 00000000..91d02716 --- /dev/null +++ b/justfile @@ -0,0 +1,14 @@ +# List all recipes +just: + just --list --unsorted + +# Install dependencies and build via cask +build: + emacs --version + cask install + cask build + +# Test +test: + cask emacs --batch -L . -L test -f batch-byte-compile $(cask files) + cask emacs --batch -L . -L test -l test/all-tests.el -f ert-run-tests-batch-and-exit diff --git a/rustic-babel.el b/rustic-babel.el index aeeaeafd..f728c315 100644 --- a/rustic-babel.el +++ b/rustic-babel.el @@ -11,10 +11,6 @@ (require 'rustic-rustfmt) -;; FIXME This variable doesn't exist in noninteractive emacs sessions, -;; which probably means that it is internal and we shouldn't use it. -(defvar org-babel-temporary-directory) - (defvar rustic-info nil) (add-to-list 'org-src-lang-modes '("rust" . rustic)) @@ -160,7 +156,7 @@ execution with rustfmt." (save-excursion (save-match-data (goto-char (point-min)) - (when (re-search-forward "^thread '[^']+' panicked at '[^']+', ") + (when (re-search-forward "^thread '[^']+' panicked at .*") (goto-char (match-beginning 0)) (setq result (buffer-substring-no-properties (point) (line-end-position))))))) (rustic-babel-run-update-result-block result) @@ -210,10 +206,13 @@ after successful compilation." (buffer-string))))))) (kill-buffer "rustic-babel-format-buffer")))) +(defvar rustic-org-babel-temporary-directory + (make-temp-file "babel-" t)) + (defun rustic-babel-generate-project (&optional expand) - "Create rust project in `org-babel-temporary-directory'. + "Create rust project in `rustic-org-babel-temporary-directory'. Return full path if EXPAND is t." - (let* ((default-directory org-babel-temporary-directory) + (let* ((default-directory rustic-org-babel-temporary-directory) (dir (make-temp-file-internal "cargo" 0 "" nil))) (shell-command-to-string (format "cargo new %s --bin --quiet" dir)) (if expand @@ -224,14 +223,14 @@ Return full path if EXPAND is t." "In order to reduce the execution time when the project has dependencies, the project name is stored as a text property in the header of the org-babel block to check if the project already exists -in `org-babel-temporary-directory'. If the project exists, reuse it. +in `rustic-org-babel-temporary-directory'. If the project exists, reuse it. Otherwise create it with `rustic-babel-generate-project'." (let* ((beg (org-babel-where-is-src-block-head)) (end (save-excursion (goto-char beg) (line-end-position))) (line (buffer-substring beg end))) (let* ((project (symbol-name (get-text-property 0 'project line))) - (path (concat org-babel-temporary-directory "/" project "/"))) + (path (concat rustic-org-babel-temporary-directory "/" project "/"))) (if (file-directory-p path) (progn (put-text-property beg end 'project (make-symbol project)) @@ -348,7 +347,7 @@ kill the running process." (progn (rustic-process-kill-p p t) nil) - (let* ((default-directory org-babel-temporary-directory) + (let* ((default-directory rustic-org-babel-temporary-directory) (project (rustic-babel-project)) (dir (setq rustic-babel-dir (expand-file-name project))) (main-p (cdr (assq :main params))) @@ -392,7 +391,7 @@ at least one time in this emacs session before this command can be used." (line-end-position))) (line (buffer-substring beg end)) (project (symbol-name (get-text-property 0 'project line))) - (path (concat org-babel-temporary-directory "/" project "/src/main.rs"))) + (path (concat rustic-org-babel-temporary-directory "/" project "/src/main.rs"))) (if (file-exists-p path) (find-file path) (message "Run block first to visit generated project.")))) @@ -403,7 +402,7 @@ at least one time in this emacs session before this command can be used." (interactive) (rustic--inheritenv (let* ((err-buff (get-buffer-create rustic-babel-compilation-buffer-name)) - (default-directory org-babel-temporary-directory) + (default-directory rustic-org-babel-temporary-directory) (body (org-element-property :value (org-element-at-point))) (project (rustic-babel-project)) (params (list "cargo" "clippy"))) diff --git a/rustic-cargo.el b/rustic-cargo.el index 19d61fe1..495a0af2 100644 --- a/rustic-cargo.el +++ b/rustic-cargo.el @@ -177,25 +177,26 @@ stored in this variable.") (defun rustic-cargo-test (&optional arg) "Run 'cargo test'. -If ARG is not nil, use value as argument and store it in `rustic-test-arguments'. -When calling this function from `rustic-popup-mode', always use the value of +If ARG is not nil, use value as argument and store it in +`rustic-test-arguments'. When calling this function from +`rustic-popup-mode', always use the value of `rustic-test-arguments'." (interactive "P") - (rustic-cargo-test-run - (cond (arg - (setq rustic-test-arguments (read-from-minibuffer "Cargo test arguments: " rustic-default-test-arguments))) - (rustic-cargo-use-last-stored-arguments - (if (> (length rustic-test-arguments) 0) - rustic-test-arguments - rustic-default-test-arguments)) - (t - rustic-default-test-arguments)))) + (when arg + (setq rustic-test-arguments + (read-from-minibuffer "Cargo test arguments: " + (rustic--populate-minibuffer + (list rustic-test-arguments + rustic-cargo-build-arguments + rustic-default-test-arguments))))) + (rustic-cargo-test-run rustic-test-arguments)) ;;;###autoload (defun rustic-cargo-test-rerun () "Run 'cargo test' with `rustic-test-arguments'." (interactive) - (rustic-cargo-test-run rustic-test-arguments)) + (let ((default-directory (or rustic-compilation-directory default-directory))) + (rustic-cargo-test-run rustic-test-arguments))) ;;;###autoload (defun rustic-cargo-current-test () @@ -312,7 +313,7 @@ Execute process in PATH." (inhibit-read-only t)) (make-process :name rustic-cargo-outdated-process-name :buffer buf - :command `(,(rustic-cargo-bin) "outdated" "--depth" "1") + :command `(,(rustic-cargo-bin) "outdated" "--quiet" "--depth" "1" "--format" "json") :sentinel #'rustic-cargo-outdated-sentinel :file-handler t) (with-current-buffer buf @@ -332,6 +333,14 @@ Execute process in PATH." (interactive) (rustic-cargo-outdated default-directory)) +(defun rustic-cargo-outdated--skip-to-packages () + "Move line forward till we reach the package name." + (goto-char (point-min)) + (let ((line (buffer-substring-no-properties (line-beginning-position) (line-end-position)))) + (while (not (or (eobp) (s-starts-with? "{" line))) + (forward-line 1) + (setf line (buffer-substring-no-properties (line-beginning-position) (line-end-position)))))) + (defun rustic-cargo-outdated-sentinel (proc _output) "Sentinel for rustic-cargo-outdated-process." (let ((buf (process-buffer proc)) @@ -339,14 +348,11 @@ Execute process in PATH." (exit-status (process-exit-status proc))) (if (zerop exit-status) (with-current-buffer buf - (let ((packages - (mapcar - (lambda (arg) - (split-string arg "================" t "[\n\s]")) - (split-string (buffer-string) "\n\n" t)))) - (if (and (length packages) (= (length (car packages)) 1)) - (setq packages (list (push "---" (car packages))))) - (rustic-cargo-outdated-generate-menu packages)) + (rustic-cargo-outdated--skip-to-packages) + (let* ((packages (buffer-substring-no-properties (point) (point-max))) + (json-packages (json-read-from-string packages))) + (erase-buffer) + (rustic-cargo-outdated-generate-menu (alist-get 'dependencies json-packages))) (pop-to-buffer buf)) (with-current-buffer buf (let ((out (buffer-string))) @@ -363,32 +369,29 @@ Execute process in PATH." (defun rustic-cargo-outdated-generate-menu (packages) "Re-populate the `tabulated-list-entries' with PACKAGES." - (let* ((name-with-split-deps - (mapcan - (lambda (arg0) - (nthcdr 2 (mapcar (lambda (arg1) (push (nth 0 arg0) arg1)) - (split-string (nth 1 arg0) "\n" t)))) - packages))) - (setq tabulated-list-entries - (mapcar #'rustic-cargo-outdated-menu-entry name-with-split-deps)) - (tabulated-list-print t))) + (setq tabulated-list-entries + (mapcar #'rustic-cargo-outdated-menu-entry packages)) + (tabulated-list-print t)) (defun rustic-cargo-outdated-menu-entry (crate) "Return a package entry of CRATE suitable for `tabulated-list-entries'." - (let* ((fields (split-string (cdr crate) "\s+")) - (name (nth 0 fields)) - (project (nth 1 fields)) - (compat (nth 2 fields))) + (let* ((name (alist-get 'name crate)) + (project (alist-get 'project crate)) + (compat (alist-get 'compat crate))) (list name `[,name ,project ,(if (when (not (string-match "^-" compat)) (version< project compat)) (propertize compat 'font-lock-face 'rustic-cargo-outdated) compat) - ,(nth 3 fields) - ,(nth 4 fields) - ,(car crate) - ,(nth 5 fields)]))) + ,(alist-get 'latest crate) + ,(alist-get 'kind crate) + ,(if (alist-get 'platform crate) + (alist-get 'platform crate) + "NA") + ,"NA" + ,"NA" + ]))) ;;;###autoload (defun rustic-cargo-mark-upgrade () @@ -519,7 +522,7 @@ The CRATE-LINE is a single line from the `rustic-cargo-oudated-buffer-name'" (let (upgrade) (dolist (crate crates) (setq upgrade (concat upgrade (format "-p %s@%s " (rustic-crate-name crate) (rustic-crate-version crate))))) - (let ((output (shell-command-to-string (format "cargo upgrade %s" upgrade)))) + (let ((output (shell-command-to-string (format "cargo upgrade --offline %s" upgrade)))) (if (string-match "error: no such subcommand:" output) (rustic-cargo-install-crate-p "edit") (rustic-cargo-reload-outdated))))) @@ -617,7 +620,8 @@ When calling this function from `rustic-popup-mode', always use the value of (defun rustic-cargo-run-rerun () "Run 'cargo run' with `rustic-run-arguments'." (interactive) - (rustic-cargo-run-command rustic-run-arguments)) + (let ((default-directory (or rustic-compilation-directory default-directory))) + (rustic-cargo-run-command rustic-run-arguments))) (defun rustic--get-run-arguments () "Helper utility for getting arguments related to 'examples' directory." @@ -669,7 +673,7 @@ in your project like `pwd'" (interactive "P") (when arg (setq rustic-cargo-build-arguments - (read-string "Cargo build arguments: " ""))) + (read-string "Cargo build arguments: " (rustic--populate-minibuffer (list rustic-cargo-build-arguments))))) (rustic-run-cargo-command `(,(rustic-cargo-bin) ,rustic-cargo-build-exec-command ,@(split-string rustic-cargo-build-arguments)) @@ -945,5 +949,11 @@ If running with prefix command `C-u', read whole command from minibuffer." (rustic-compilation-start c (list :buffer buf :process proc :mode mode :directory default-directory)))) +(defun rustic--populate-minibuffer (list) + "Return first non nil element in LIST." + (cond ((null list) nil) + ((not (s-blank? (car list))) (car list)) + (t (rustic--populate-minibuffer (cdr list))))) + (provide 'rustic-cargo) ;;; rustic-cargo.el ends here diff --git a/rustic-clippy.el b/rustic-clippy.el index 2dbb6b54..e3feca05 100644 --- a/rustic-clippy.el +++ b/rustic-clippy.el @@ -4,7 +4,7 @@ ;; This library implements support for `clippy'. ;;; Code: - +(require 'rustic-cargo) (require 'rustic-compile) (defcustom rustic-cargo-clippy-fix-args "--allow-dirty" @@ -80,13 +80,19 @@ When calling this function from `rustic-popup-mode', always use the value of (interactive "P") (rustic-cargo-clippy-run :params (cond (arg - (setq rustic-clippy-arguments (read-from-minibuffer "Cargo clippy arguments: " rustic-default-clippy-arguments))) - ((eq major-mode 'rustic-popup-mode) - (if (> (length rustic-clippy-arguments) 0) - rustic-clippy-arguments - rustic-default-clippy-arguments)) - (t - rustic-default-clippy-arguments)))) + (setq rustic-clippy-arguments + (read-from-minibuffer "Cargo clippy arguments: " + (rustic--populate-minibuffer + (list + rustic-clippy-arguments + rustic-cargo-build-arguments + rustic-default-clippy-arguments + ))))) + (t + (if (> (length rustic-clippy-arguments) 0) + rustic-clippy-arguments + rustic-default-clippy-arguments) + )))) ;;;###autoload (defun rustic-cargo-clippy-rerun () diff --git a/rustic-compile.el b/rustic-compile.el index 33b08fc3..bce6d791 100644 --- a/rustic-compile.el +++ b/rustic-compile.el @@ -209,6 +209,9 @@ Error matching regexes from compile.el are removed." ;;; Compilation Process +(defvar-local rustic-compilation-directory nil + "original directory for rust compilation process.") + (defvar rustic-compilation-process-name "rustic-compilation-process" "Process name for rust compilation processes.") @@ -251,6 +254,7 @@ Set environment variables for rust process." (erase-buffer) (setq default-directory dir) (funcall mode) + (setq-local rustic-compilation-directory dir) (unless no-mode-line (setq mode-line-process '((:propertize ":%s" face compilation-mode-line-run) @@ -579,7 +583,7 @@ It's a list that looks like (list command mode name-function highlight-regexp)." (defun rustic-recompile () "Re-compile the program using `compilation-arguments'." (interactive) - (let* ((command (or (car compilation-arguments) (rustic-compile-command))) + (let* ((command (or (car compilation-arguments) (format "%s %s" (rustic-compile-command) rustic-cargo-build-arguments))) (dir compilation-directory)) (rustic-compilation-process-live) (rustic-compilation-start (split-string command) diff --git a/rustic-racer.el b/rustic-racer.el deleted file mode 100644 index 3dc748a9..00000000 --- a/rustic-racer.el +++ /dev/null @@ -1,516 +0,0 @@ -;;; rustic-racer.el --- Racer support -*-lexical-binding: t-*- - -;;; Code: - -(require 'f) -(require 's) - -(require 'button) -(require 'etags) -(require 'help-mode) -(require 'thingatpt) - -(require 'rustic) - -(defvar rustic-racer-args nil) - -(defgroup racer nil - "Docs browsing for Rust via racer." - :link '(url-link "https://github.com/racer-rust/emacs-racer/") - :group 'rustic-mode) - -;;; Customization - -(defcustom rustic-racer-cmd - (or (executable-find "racer") - (f-expand "~/.cargo/bin/racer") - "/usr/local/bin/racer") - "Path to the racer binary." - :type 'file - :group 'racer) - -(defcustom rustic-racer-rust-src-path - (or - (getenv "RUST_SRC_PATH") - (when (executable-find "rustc") - (let* ((sysroot (s-trim-right - (shell-command-to-string - (format "%s --print sysroot" (executable-find "rustc"))))) - (src-path (f-join sysroot "lib/rustlib/src/rust/src"))) - (when (file-exists-p src-path) - src-path) - src-path)) - "/usr/local/src/rust/src") - - "Path to the rust source tree. -If nil, we will query $RUST_SRC_PATH at runtime. -If $RUST_SRC_PATH is not set, look for rust source -in rustup's install directory." - :type 'file - :group 'racer) - -(defcustom rustic-racer-cargo-home - (or - (getenv "CARGO_HOME") - "~/.cargo") - "Path to your current cargo home. Usually `~/.cargo'. -If nil, we will query $CARGO_HOME at runtime." - :type 'file - :group 'racer) - -;;; Faces - -(define-obsolete-face-alias 'rustic-racer-help-heading-face - 'rustic-racer-help-heading "1.2") - -(defface rustic-racer-help-heading - '((t :weight bold)) - "Face for markdown headings in *Racer Help* buffers.") - -(defface rustic-racer-tooltip - '((((min-colors 16777216)) - :background "#292C33" :foreground "white") - (t - :background "black" :foreground "white")) - "Face used for the tooltip with `racer-describe-tooltip'") - -;;; Help-mode - -(defvar rustic-racer-help-mode-map - (let ((map (make-sparse-keymap))) - (set-keymap-parent map (make-composed-keymap button-buffer-map - special-mode-map)) - map) - "Keymap for racer help mode.") - -(define-derived-mode rustic-racer-help-mode fundamental-mode - "Racer-Help" - "Major mode for *Racer Help* buffers. -Commands: -\\{racer-help-mode-map}") - -(defun rustic-racer-header (text) - "Helper function for adding text properties to TEXT." - (propertize text 'face 'rustic-racer-help-heading)) - -(defun rustic-racer-button-go-to-src (button) - (rustic-racer-find-file - (button-get button 'path) - (button-get button 'line) - (button-get button 'column))) - -(define-button-type 'racer-src-button - 'action 'rustic-racer-button-go-to-src - 'follow-link t - 'help-echo "Go to definition") - -(defun rustic-racer-url-button (text url) - "Return a button that opens a browser at URL." - (with-temp-buffer - (insert-text-button - text - :type 'help-url - 'help-args (list url)) - (buffer-string))) - -(defun rustic-racer-src-button (path line column) - "Return a button that navigates to PATH at LINE number and -COLUMN number." - ;; Convert "/foo/bar/baz/foo.rs" to "baz/foo.rs" - (let* ((filename (f-filename path)) - (parent-dir (f-filename (f-parent path))) - (short-path (f-join parent-dir filename))) - (with-temp-buffer - (insert-text-button - short-path - :type 'racer-src-button - 'path path - 'line line - 'column column) - (buffer-string)))) - -(defun rustic-racer-help-buf (contents) - "Create a *Racer Help* buffer with CONTENTS." - (rustic--inheritenv - (let ((buf (get-buffer-create "*Racer Help*")) - ;; If the buffer already existed, we need to be able to - ;; override `buffer-read-only'. - (inhibit-read-only t)) - (with-current-buffer buf - (erase-buffer) - (insert contents) - (setq buffer-read-only t) - (goto-char (point-min)) - (rustic-racer-help-mode)) - buf))) - -;;; Racer - -(defvar rustic-racer-prev-state nil) - -(defun rustic-racer-call (command &rest args) - "Call racer command COMMAND with args ARGS. -Return stdout if COMMAND exits normally, otherwise show an -error." - (let ((rust-src-path (or rustic-racer-rust-src-path (getenv "RUST_SRC_PATH"))) - (cargo-home (or rustic-racer-cargo-home (getenv "CARGO_HOME")))) - (when (null rust-src-path) - (user-error "You need to set `rustic-racer-rust-src-path' or `RUST_SRC_PATH'")) - (unless (file-exists-p rust-src-path) - (user-error "No such directory: %s. Please set `rustic-racer-rust-src-path' or `RUST_SRC_PATH'" - rust-src-path)) - (let ((default-directory (funcall rustic-compile-directory-method)) - (process-environment (append (list - (format "RUST_SRC_PATH=%s" (expand-file-name rust-src-path)) - (format "CARGO_HOME=%s" (expand-file-name cargo-home))) - process-environment))) - (-let [(exit-code stdout _stderr) - (rustic-racer-shell-command rustic-racer-cmd (cons command args))] - ;; Use `equal' instead of `zero' as exit-code can be a string - ;; "Aborted" if racer crashes. - (unless (equal 0 exit-code) - (user-error "%s exited with %s. `M-x rustic-racer-debug' for more info" - rustic-racer-cmd exit-code)) - stdout)))) - -(defun rustic-racer-doc (name) - "Return a *Racer Help* buffer for the function or type at point. -If there are multiple candidates at point, use NAME to find the -correct value." - (let ((description (rustic-racer-describe-at-point name))) - (when description - (let* ((name (plist-get description :name)) - (raw-docstring (plist-get description :docstring)) - (docstring (if raw-docstring - (rustic-racer-propertize-docstring raw-docstring) - "Not documented.")) - (kind (plist-get description :kind))) - (rustic-racer-help-buf - (format - "%s is %s defined in %s.\n\n%s%s" - name - (rustic-racer-kind-description kind) - (rustic-racer-src-button - (plist-get description :path) - (plist-get description :line) - (plist-get description :column)) - (if (equal kind "Module") - ;; No point showing the 'signature' of modules, which is - ;; just their full path. - "" - (format " %s\n\n" (rustic-racer-syntax-highlight (plist-get description :signature)))) - docstring)))))) - -(defun rustic-racer-describe-at-point (name) - "Get a description of the symbol at point matching NAME. -If there are multiple possibilities with this NAME, prompt -the user to choose." - (let* ((output-lines (save-excursion - ;; Move to the end of the current symbol, to - ;; increase racer accuracy. - (skip-syntax-forward "w_") - (rustic-racer-call-at-point "complete-with-snippet"))) - (all-matches (--map (when (s-starts-with-p "MATCH " it) - (rustic-racer-split-snippet-match it)) - output-lines)) - (relevant-matches (--filter (equal (plist-get it :name) name) - all-matches))) - (if (> (length relevant-matches) 1) - ;; We might have multiple matches with the same name but - ;; different types. E.g. Vec::from. - (let ((signature - (completing-read "Multiple matches: " - (--map (plist-get it :signature) relevant-matches)))) - (--first (equal (plist-get it :signature) signature) relevant-matches)) - (-first-item relevant-matches)))) - -(defmacro rustic-racer-with-temporary-file (path-sym &rest body) - "Create a temporary file, and bind its path to PATH-SYM. -Evaluate BODY, then delete the temporary file." - (declare (indent 1) (debug (symbolp body))) - `(let ((,path-sym (make-temp-file "racer"))) - (unwind-protect - (progn ,@body) - (delete-file ,path-sym)))) - -(defun rustic-racer-call-at-point (command) - "Call racer command COMMAND at point of current buffer. -Return a list of all the lines returned by the command." - (rustic-racer-with-temporary-file tmp-file - (write-region nil nil tmp-file nil 'silent) - (let ((racer-args (list - command - (number-to-string (line-number-at-pos)) - (number-to-string (rustic-racer-current-column))))) - ;; If this buffer is backed by a file, pass that to racer too. - (-when-let (file-name (buffer-file-name (buffer-base-buffer))) - (setq rustic-racer-args - (append racer-args (list file-name)))) - - (setq rustic-racer-args (append rustic-racer-args (list tmp-file))) - (s-lines - (s-trim-right - (apply #'rustic-racer-call rustic-racer-args)))))) - -(defun rustic-racer-shell-command (program args) - "Execute PROGRAM with ARGS. -Return a list (exit-code stdout stderr)." - (rustic-racer-with-temporary-file tmp-file-for-stderr - (let (exit-code stdout stderr) - ;; Create a temporary buffer for `call-process` to write stdout - ;; into. - (rustic--with-temp-process-buffer - (setq exit-code - (apply #'call-process program nil - (list (current-buffer) tmp-file-for-stderr) - nil args)) - (setq stdout (buffer-string))) - (setq stderr (rustic-racer-slurp tmp-file-for-stderr)) - (setq rustic-racer-prev-state - (list - :program program - :args args - :exit-code exit-code - :stdout stdout - :stderr stderr - :default-directory default-directory - :process-environment process-environment)) - (list exit-code stdout stderr)))) - -;;; Utility Functions - -(defun rustic-racer-slurp (file) - "Return the contents of FILE as a string." - (with-temp-buffer - (insert-file-contents-literally file) - (buffer-string))) - -(defun rustic-racer-read-rust-string (string) - "Convert STRING, a rust string literal, to an elisp string." - (when string - (->> string - ;; Remove outer double quotes. - (s-chop-prefix "\"") - (s-chop-suffix "\"") - ;; Replace escaped characters. - (s-replace "\\n" "\n") - (s-replace "\\\"" "\"") - (s-replace "\\'" "'") - (s-replace "\\;" ";")))) - -(defun rustic-racer-url-p (target) - "Return t if TARGET looks like a fully qualified URL." - (not (null - (string-match-p (rx bol "http" (? "s") "://") target)))) - -(defun rustic-racer-propertize-links (markdown) - "Propertize links in MARKDOWN." - (replace-regexp-in-string - ;; Text of the form [foo](http://example.com) - (rx "[" (group (+? (not (any "]")))) "](" (group (+? anything)) ")") - ;; For every match: - (lambda (whole-match) - ;; Extract link and target. - (let ((link-text (match-string 1 whole-match)) - (link-target (match-string 2 whole-match))) - ;; If it's a web URL, use a clickable link. - (if (rustic-racer-url-p link-target) - (rustic-racer-url-button link-text link-target) - ;; Otherwise, just discard the target. - link-text))) - markdown)) - -(defun rustic-racer-propertize-all-inline-code (markdown) - "Given a single line MARKDOWN, replace all instances of `foo` or -\[`foo`\] with a propertized string." - (let ((highlight-group - (lambda (whole-match) - (rustic-racer-syntax-highlight (match-string 1 whole-match))))) - (->> markdown - (replace-regexp-in-string - (rx "[`" (group (+? anything)) "`]") - highlight-group) - (replace-regexp-in-string - (rx "`" (group (+? anything)) "`") - highlight-group)))) - -(defun rustic-racer-indent-block (str) - "Indent every line in STR." - (s-join "\n" (--map (concat " " it) (s-lines str)))) - -(defun rustic-racer-trim-newlines (str) - "Remove newlines from the start and end of STR." - (->> str - (s-chop-prefix "\n") - (s-chop-suffix "\n"))) - -(defun rustic-racer-remove-footnote-links (str) - "Remove footnote links from markdown STR." - (->> (s-lines str) - (--remove (string-match-p (rx bol "[`" (+? anything) "`]: ") it)) - (s-join "\n") - ;; Collapse consecutive blank lines caused by removing footnotes. - (s-replace "\n\n\n" "\n\n"))) - -(defun rustic-racer-docstring-sections (docstring) - "Split DOCSTRING into text, code and heading sections." - (let* ((sections nil) - (current-section-lines nil) - (section-type :text) - ;; Helper function. - (finish-current-section - (lambda () - (when current-section-lines - (let ((current-section - (s-join "\n" (nreverse current-section-lines)))) - (unless (s-blank? current-section) - (push (list section-type current-section) sections)) - (setq current-section-lines nil)))))) - (dolist (line (s-lines docstring)) - (cond - ;; If this is a closing ``` - ((and (s-starts-with-p "```" line) (eq section-type :code)) - (push line current-section-lines) - (funcall finish-current-section) - (setq section-type :text)) - ;; If this is an opening ``` - ((s-starts-with-p "```" line) - (funcall finish-current-section) - (push line current-section-lines) - (setq section-type :code)) - ;; Headings - ((and (not (eq section-type :code)) (s-starts-with-p "# " line)) - (funcall finish-current-section) - (push (list :heading line) sections)) - ;; Normal text. - (t - (push line current-section-lines)))) - (funcall finish-current-section) - (nreverse sections))) - -(defun rustic-racer-clean-code-section (section) - "Given a SECTION, a markdown code block, remove -fenced code delimiters and code annotations." - (->> (s-lines section) - (-drop 1) - (-drop-last 1) - ;; Ignore annotations like # #[allow(dead_code)] - (--remove (s-starts-with-p "# " it)) - (s-join "\n"))) - -(defun rustic-racer-propertize-docstring (docstring) - "Replace markdown syntax in DOCSTRING with text properties." - (let* ((sections (rustic-racer-docstring-sections docstring)) - (propertized-sections - (--map (-let [(section-type section) it] - ;; Remove trailing newlines, so we can ensure we - ;; have consistent blank lines between sections. - (rustic-racer-trim-newlines - (pcase section-type - (:text - (rustic-racer-propertize-all-inline-code - (rustic-racer-propertize-links - (rustic-racer-remove-footnote-links - section)))) - (:code - (rustic-racer-indent-block - (rustic-racer-syntax-highlight - (rustic-racer-clean-code-section section)))) - (:heading - (rustic-racer-header - (s-chop-prefix "# " section)))))) - sections))) - (s-join "\n\n" propertized-sections))) - -(defun rustic-racer-find-file (path line column) - "Open PATH and move point to LINE and COLUMN." - (find-file path) - (goto-char (point-min)) - (forward-line (1- line)) - (forward-char column)) - -(defun rustic-racer-kind-description (raw-kind) - "Human friendly description of a rust kind. -For example, 'EnumKind' -> 'an enum kind'." - (let* ((parts (s-split-words raw-kind)) - (description (s-join " " (--map (downcase it) parts))) - (a (if (string-match-p (rx bos (or "a" "e" "i" "o" "u")) description) - "an" "a"))) - (format "%s %s" a description))) - -(defun rustic-racer-current-column () - "Get the current column based on underlying character representation." - (length (buffer-substring-no-properties - (line-beginning-position) (point)))) - -(defun rustic-racer-syntax-highlight (str) - "Apply font-lock properties to a string STR of Rust code." - (let (result) - ;; Load all of STR in a rustic-mode buffer, and use its - ;; highlighting. - (with-temp-buffer - (insert str) - (delay-mode-hooks (rustic-mode)) - (if (fboundp 'font-lock-ensure) - (font-lock-ensure) - (with-no-warnings - (font-lock-fontify-buffer))) - (setq result (buffer-string))) - (when (and - ;; If we haven't applied any properties yet, - (null (text-properties-at 0 result)) - ;; and if it's a standalone symbol, then assume it's a - ;; variable. - (string-match-p (rx bos (+ (any lower "_")) eos) str)) - (setq result (propertize str 'face 'font-lock-variable-name-face))) - result)) - -(defun rustic-racer-split-parts (raw-output) - "Given RAW-OUTPUT from racer, split on semicolons and doublequotes. -Unescape strings as necessary." - (let ((parts nil) - (current "") - (i 0)) - (while (< i (length raw-output)) - (let ((char (elt raw-output i)) - (prev-char (and (> i 0) (elt raw-output (1- i))))) - (cond - ;; A semicolon that wasn't escaped, start a new part. - ((and (equal char ?\;) (not (equal prev-char ?\\))) - (push current parts) - (setq current "")) - (t - (setq current (concat current (string char)))))) - (setq i (1+ i))) - (push current parts) - (mapcar #'rustic-racer-read-rust-string (nreverse parts)))) - -(defun rustic-racer-split-snippet-match (line) - "Given LINE, a string \"MATCH ...\" from complete-with-snippet, -split it into its constituent parts." - (let* ((match-parts (rustic-racer-split-parts line)) - (docstring (nth 7 match-parts))) - (when (and match-parts (equal (length match-parts) 8)) - (list :name (s-chop-prefix "MATCH " (nth 0 match-parts)) - :line (string-to-number (nth 2 match-parts)) - :column (string-to-number (nth 3 match-parts)) - :path (nth 4 match-parts) - ;; Struct or Function: - :kind (nth 5 match-parts) - :signature (nth 6 match-parts) - :docstring (if (> (length docstring) 0) docstring nil))))) - -;;; Interactive - -;;;###autoload -(defun rustic-racer-describe () - "Show a *Racer Help* buffer for the function or type at point." - (interactive) - (let ((buf (rustic-racer-doc (thing-at-point 'symbol)))) - (if buf - (pop-to-buffer buf) - (user-error "No function or type found at point")))) - -;;; _ -(provide 'rustic-racer) -;;; rustic-racer.el ends here diff --git a/rustic.el b/rustic.el index c3c58f3e..42cc2c01 100644 --- a/rustic.el +++ b/rustic.el @@ -4,7 +4,7 @@ ;; Author: Mozilla ;; ;; Keywords: languages -;; Package-Requires: ((emacs "26.1") (rust-mode "1.0.3") (dash "2.13.0") (f "0.18.2") (let-alist "1.0.4") (markdown-mode "2.3") (project "0.3.0") (s "1.10.0") (seq "2.3") (spinner "1.7.3") (xterm-color "1.6")) +;; Package-Requires: ((emacs "26.1") (rust-mode "1.0.3") (dash "2.13.0") (f "0.18.2") (let-alist "1.0.4") (markdown-mode "2.3") (project "0.3.0") (s "1.10.0") (spinner "1.7.3") (xterm-color "1.6") (flycheck "34.0")) ;; This file is distributed under the terms of both the MIT license and the ;; Apache License (version 2.0). @@ -30,7 +30,6 @@ (require 'cl-lib) (require 'pcase) -(require 'seq) (require 'subr-x) (require 'dash) @@ -49,13 +48,18 @@ ;;; Define aliases for removed rustic functions -(defvaralias 'rustic-indent-offset 'rust-indent-offset) -(defvaralias 'rustic-indent-method-chain 'rust-indent-method-chain) -(defvaralias 'rustic-indent-where-clause 'rust-indent-where-clause) -(defvaralias 'rustic-match-angle-brackets 'rust-match-angle-brackets) -(defvaralias 'rustic-indent-return-type-to-arguments 'rust-indent-return-type-to-arguments) -(defalias 'rustic-indent-line #'rust-mode-indent-line) -(defalias 'rustic-end-of-defun #'rust-end-of-defun) +(if (and (version<= "29.1" emacs-version) rust-mode-treesitter-derive) + (progn + (require 'rust-ts-mode) + (defvaralias 'rustic-indent-offset 'rust-ts-mode-indent-offset)) + (progn + (defvaralias 'rustic-indent-offset 'rust-indent-offset) + (defvaralias 'rustic-indent-method-chain 'rust-indent-method-chain) + (defvaralias 'rustic-indent-where-clause 'rust-indent-where-clause) + (defvaralias 'rustic-match-angle-brackets 'rust-match-angle-brackets) + (defvaralias 'rustic-indent-return-type-to-arguments 'rust-indent-return-type-to-arguments) + (defalias 'rustic-indent-line #'rust-mode-indent-line) + (defalias 'rustic-end-of-defun #'rust-end-of-defun))) ;;; workaround for with-temp-buffer not propagating the environment, as per ;;; https://github.com/magit/magit/pull/4169 @@ -127,7 +131,6 @@ this variable." (define-key map (kbd "C-c C-c C-u") 'rustic-compile) (define-key map (kbd "C-c C-c C-i") 'rustic-recompile) (define-key map (kbd "C-c C-c C-o") 'rustic-format-buffer) - (define-key map (kbd "C-c C-c C-d") 'rustic-racer-describe) (define-key map (kbd "C-c C-c C-,") 'rustic-docstring-dwim) (define-key map (kbd "C-c C-c C-b") 'rustic-cargo-build) @@ -165,10 +168,13 @@ this variable." ;;;###autoload (add-to-list 'auto-mode-alist '("\\.rs\\'" . rustic-mode)) -;; remove rust-mode from `auto-mode-alist' -(let ((mode '("\\.rs\\'" . rust-mode))) +;; remove rust-mode and rust-ts-mode from `auto-mode-alist' +(let ((mode '("\\.rs\\'" . rust-mode)) + (ts-mode '("\\.rs\\'" . rust-ts-mode))) (when (member mode auto-mode-alist) - (setq auto-mode-alist (remove mode auto-mode-alist)))) + (setq auto-mode-alist (remove mode auto-mode-alist))) + (when (member ts-mode auto-mode-alist) + (setq auto-mode-alist (remove ts-mode auto-mode-alist)))) ;;; envrc support @@ -211,7 +217,6 @@ This variable might soon be remove again.") (require 'rustic-clippy) (require 'rustic-comint) (require 'rustic-babel) - (require 'rustic-racer) (require 'rustic-rustfmt) (require 'rustic-rustfix) (require 'rustic-playground) diff --git a/test/all-tests.el b/test/all-tests.el new file mode 100644 index 00000000..99d62c98 --- /dev/null +++ b/test/all-tests.el @@ -0,0 +1,9 @@ +(require 'rustic-clippy-test) +(require 'rustic-cargo-test) +(require 'rustic-babel-test) +(require 'rustic-compilation-error-tests) +(require 'rustic-compile-test) +;; (require 'rustic-doc-test) +(require 'rustic-format-test) +(require 'rustic-window-test) +(require 'rustic-workspace-test) diff --git a/test/rustic-babel-test.el b/test/rustic-babel-test.el index 52e3631c..328ee4be 100644 --- a/test/rustic-babel-test.el +++ b/test/rustic-babel-test.el @@ -1,6 +1,9 @@ ;; -*- lexical-binding: t -*- ;; Before editing, eval (load-file "test-helper.el") +(require 'ert) +(require 'test-helper) + (setq org-confirm-babel-evaluate nil) (defun rustic-test-get-babel-block (contents &optional params) @@ -72,7 +75,7 @@ }") (buf (rustic-test-get-babel-block string))) (rustic-test-babel-execute-block buf) - (let ((re "^thread '[^']+' panicked at '[^']+', ")) + (let ((re "^thread '[^']+' panicked at .*")) (should (string-match re (rustic-test-babel-check-results buf)))))) (ert-deftest rustic-test-babel-spinner () @@ -113,6 +116,7 @@ (should-not (spinner-p rustic-babel-spinner)) (should (eq mode-line-process nil))))) + (ert-deftest rustic-test-babel-format () (let* ((string "fn main() {}") (formatted-string " fn main() {}\n") @@ -243,3 +247,5 @@ (with-current-buffer buf (rustic-test-babel-execute-block buf) (should (eq (rustic-test-babel-check-results buf) nil))))) + +(provide 'rustic-babel-test) diff --git a/test/rustic-cargo-test.el b/test/rustic-cargo-test.el index 55788622..b22fefc1 100644 --- a/test/rustic-cargo-test.el +++ b/test/rustic-cargo-test.el @@ -1,5 +1,7 @@ ;; -*- lexical-binding: t -*- ;; Before editing, eval (load-file "test-helper.el") +(require 'rustic) +(require 'test-helper) (ert-deftest rustic-test-cargo-test () (let* ((string "#[test] @@ -13,8 +15,7 @@ fn it_works2() { (default-directory (rustic-test-count-error-helper string)) (proc (call-interactively 'rustic-cargo-test)) (buf (process-buffer proc))) - (while (eq (process-status proc) 'run) - (sit-for 0.1)) + (rustic-test--wait-till-finished rustic-test-buffer-name) (should (string= rustic-test-arguments "")) (with-current-buffer buf ;; check if buffer has correct name and correct major mode @@ -34,11 +35,9 @@ fn it_works2() { assert_eq!(2 + 2, 3); }") (default-directory (rustic-test-count-error-helper string)) - (proc (rustic-cargo-test-run "it_works2")) - (buf (process-buffer proc))) - (while (eq (process-status proc) 'run) - (sit-for 0.1)) - (with-current-buffer buf + (proc (rustic-cargo-test-run "it_works2"))) + (rustic-test--wait-till-finished rustic-test-buffer-name) + (with-current-buffer rustic-test-buffer-name ;; only test it_works2 is supposed to run (should-not (string-match "it_works1" (buffer-substring-no-properties (point-min) (point-max)))) (should (string-match "it_works2" (buffer-substring-no-properties (point-min) (point-max))))))) @@ -58,8 +57,7 @@ fn test2() { (forward-line 1) (let* ((proc (rustic-cargo-current-test)) (proc-buf (process-buffer proc))) - (while (eq (process-status proc) 'run) - (sit-for 0.1)) + (rustic-test--wait-till-finished rustic-test-buffer-name) (with-current-buffer proc-buf (should (string-match "test1" (buffer-substring-no-properties (point-min) (point-max)))) (should-not (string-match "test2" (buffer-substring-no-properties (point-min) (point-max))))) @@ -83,8 +81,7 @@ fn test1() { (forward-line 3) (let* ((proc (rustic-cargo-current-test)) (proc-buf (process-buffer proc))) - (while (eq (process-status proc) 'run) - (sit-for 0.1)) + (rustic-test--wait-till-finished rustic-test-buffer-name) (with-current-buffer proc-buf (should (string-match "test1" (buffer-substring-no-properties (point-min) (point-max))))) (kill-buffer proc-buf))) @@ -107,8 +104,7 @@ use std; (forward-line 3) (let* ((proc (call-interactively 'rustic-cargo-current-test)) (proc-buf (process-buffer proc))) - (while (eq (process-status proc) 'run) - (sit-for 0.1)) + (rustic-test--wait-till-finished rustic-test-buffer-name) (with-current-buffer proc-buf (should (string-match "test1" (buffer-substring-no-properties (point-min) (point-max))))) (kill-buffer proc-buf))) @@ -124,8 +120,7 @@ use std; (default-directory (rustic-test-count-error-helper string)) (proc (call-interactively 'rustic-cargo-test)) (buf (process-buffer proc))) - (while (eq (process-status proc) 'run) - (sit-for 0.1)) + (rustic-test--wait-till-finished rustic-test-buffer-name) (with-current-buffer buf (should-not (string-match "^warning:\s" (buffer-substring-no-properties (point-min) (point-max))))) (kill-buffer buf)) @@ -241,8 +236,8 @@ fn test() { (with-current-buffer buffer (should (eq major-mode 'rustic-cargo-test-mode))) (should (string= (s-join " " (process-get proc 'command)) - (concat (rustic-cargo-bin) " test " - rustic-default-test-arguments))))))) + (s-trim (concat (rustic-cargo-bin) " test " + rustic-test-arguments)))))))) (ert-deftest rustic-cargo-expand-test () (let* ((string "fn main() {()}") @@ -257,7 +252,7 @@ fn test() { (ert-deftest rustic-cargo-login-test () (let* ((process-environment (cl-copy-list process-environment)) (tempdir (concat (temporary-file-directory) (file-name-as-directory "rustic-cargo-login-test"))) - (credfile (concat tempdir "credentials"))) + (credfile (concat tempdir "credentials.toml"))) (when (file-exists-p credfile) (delete-file credfile)) @@ -268,5 +263,6 @@ fn test() { (with-temp-buffer (find-file credfile) (let ((buf-string (buffer-string))) - (message buf-string) (should (string-match "\\\[registry\\\]\ntoken = \"test-credentials\"\n" buf-string)))))) + +(provide 'rustic-cargo-test) diff --git a/test/rustic-clippy-test.el b/test/rustic-clippy-test.el index 7141f16a..edb40672 100644 --- a/test/rustic-clippy-test.el +++ b/test/rustic-clippy-test.el @@ -1,5 +1,7 @@ ;; -*- lexical-binding: t -*- +(require 'rustic) +(require 'test-helper) (ert-deftest rustic-test-trigger-and-fix-format-on-compile () (ignore-errors (kill-buffer (get-buffer rustic-compilation-buffer-name))) @@ -46,8 +48,7 @@ (write-file file1)) (if-let ((proc (call-interactively 'rustic-compile))) - (while (eq (process-status proc) 'run) - (sit-for 0.01))) + (rustic-test--wait-till-finished rustic-compilation-buffer-name)) (with-current-buffer buffer1 (revert-buffer t t) @@ -72,8 +73,7 @@ (write-file file1)) (if-let ((proc (call-interactively 'rustic-cargo-build))) - (while (eq (process-status proc) 'run) - (sit-for 0.5))) + (rustic-test--wait-till-finished rustic-compilation-buffer-name)) (with-current-buffer buffer1 (revert-buffer t t) @@ -91,8 +91,7 @@ (call-interactively 'rustic-cargo-clippy) (let* ((proc (get-process rustic-clippy-process-name)) (buffer (process-buffer proc))) - (while (eq (process-status proc) 'run) - (sit-for 0.01)) + (rustic-test--wait-till-finished rustic-clippy-buffer-name) (with-current-buffer buffer (should (string-match "^warning:\s" (buffer-substring-no-properties (point-min) (point-max))))) (should (string= (s-join " " (process-get proc 'command)) @@ -121,3 +120,5 @@ (rustic-test--wait-till-finished rustic-clippy-buffer-name) (revert-buffer t t) (should (string= (buffer-string) "#![allow(non_snake_case)]\nfn main() { let _s = 1;}")))))) + +(provide 'rustic-clippy-test) diff --git a/test/rustic-compilation-error-tests.el b/test/rustic-compilation-error-tests.el index 2a0411b2..36593342 100644 --- a/test/rustic-compilation-error-tests.el +++ b/test/rustic-compilation-error-tests.el @@ -1,18 +1,20 @@ ;; -*- lexical-binding: t -*- ;; Before editing, eval (load-file "test-helper.el") +(require 'rustic) +(require 'test-helper) + (ert-deftest rustic-test-count-errors () ;; test error without error code (let* ((string "fn main() {") (default-directory (rustic-test-count-error-helper string)) (rustic-format-trigger nil)) (let ((proc (rustic-compilation-start (split-string "cargo build")))) - (while (eq (process-status proc) 'run) - (sit-for 0.1)) + (rustic-test--wait-till-finished (process-buffer proc)) (with-current-buffer (get-buffer rustic-compilation-buffer-name) (should (= compilation-num-errors-found 1)))))) -(ert-deftest rustic-test-cargo-test () +(ert-deftest rustic-test-cargo-test-compilation () ;; NOTE: this doesn't seem to be the case anymore ;; compilation-num-errors-found would be 8 with regular compilation mode ;; due to parsing issues https://github.com/rust-lang/rust-mode/pull/254 @@ -65,10 +67,10 @@ }") (default-directory (rustic-test-count-error-helper string)) (proc (rustic-cargo-test))) - (while (eq (process-status proc) 'run) - (sit-for 0.1)) + (rustic-test--wait-till-finished rustic-test-buffer-name) (with-current-buffer (get-buffer rustic-test-buffer-name) - (should (= compilation-num-errors-found 10)))))) + (should (= compilation-num-errors-found 0))) + (kill-buffer rustic-test-buffer-name)))) (ert-deftest rustic-test-count-warnings () (let* ((string "fn main() { @@ -99,6 +101,7 @@ (sit-for 0.1)) (with-current-buffer (get-buffer rustic-compilation-buffer-name) (should (= compilation-num-warnings-found 20))))) + (ert-deftest rustic-test-crate-path-error () (let* ((test-workspace (expand-file-name "test/test-project/")) (test-crate (expand-file-name "test/test-project/crates/test-crate/"))) @@ -106,8 +109,7 @@ (rustic-cargo-build) (let* ((proc (get-process rustic-compilation-process-name)) (buffer (process-buffer proc))) - (while (eq (process-status proc) 'run) - (sit-for 0.01)) + (rustic-test--wait-till-finished buffer) (with-current-buffer buffer (goto-char (point-min)) (when (re-search-forward "-->") @@ -130,8 +132,7 @@ (rustic-cargo-build) (let* ((proc (get-process rustic-compilation-process-name)) (buffer (process-buffer proc))) - (while (eq (process-status proc) 'run) - (sit-for 0.01)) + (rustic-test--wait-till-finished buffer) (with-current-buffer buffer (goto-char (point-min)) (when (re-search-forward "-->") @@ -157,8 +158,7 @@ (rustic-cargo-build) (let* ((proc (get-process rustic-compilation-process-name)) (buffer (process-buffer proc))) - (while (eq (process-status proc) 'run) - (sit-for 0.01)) + (rustic-test--wait-till-finished buffer) (with-current-buffer buffer (goto-char (point-min)) (compilation-next-error 1) @@ -181,8 +181,7 @@ (rustic-cargo-build) (let* ((proc (get-process rustic-compilation-process-name)) (buffer (process-buffer proc))) - (while (eq (process-status proc) 'run) - (sit-for 0.01)) + (rustic-test--wait-till-finished buffer) (with-current-buffer buffer (should (string= default-directory test-workspace)) (let* ((msg (get-text-property (point) 'compilation-message)) @@ -201,8 +200,7 @@ (rustic-cargo-build) (let* ((proc (get-process rustic-compilation-process-name)) (buffer (process-buffer proc))) - (while (eq (process-status proc) 'run) - (sit-for 0.01)) + (rustic-test--wait-till-finished buffer) (with-current-buffer buffer (should (string= default-directory test-workspace)) (let* ((msg (get-text-property (point) 'compilation-message)) @@ -222,8 +220,9 @@ (rustic-cargo-build) (let* ((proc (get-process rustic-compilation-process-name)) (buffer (process-buffer proc))) - (while (eq (process-status proc) 'run) - (sit-for 0.01)) + (rustic-test--wait-till-finished buffer) (with-current-buffer buffer (should (string= default-directory test-workspace)) (should-not (get-text-property (point) 'compilation-message))))))) + +(provide 'rustic-compilation-error-tests) diff --git a/test/rustic-compile-test.el b/test/rustic-compile-test.el index 0f627ff7..4c823f42 100644 --- a/test/rustic-compile-test.el +++ b/test/rustic-compile-test.el @@ -1,5 +1,7 @@ ;; -*- lexical-binding: t -*- ;; Before editing, eval (load-file "test-helper.el") +(require 'rustic) +(require 'test-helper) (ert-deftest rustic-test-format-next-error-last-buffer () (let* ((string "fn main() {}") @@ -128,16 +130,18 @@ (while (eq (process-status proc) 'run) (sit-for 0.1)) (with-current-buffer (get-buffer rustic-compilation-buffer-name) - (should (= compilation-num-errors-found 1)))) + (should (= compilation-num-errors-found 0)))) (let ((rustic-compile-backtrace "1") (proc (rustic-compilation-start (split-string "cargo run")))) (while (eq (process-status proc) 'run) (sit-for 0.1)) (with-current-buffer (get-buffer rustic-compilation-buffer-name) - (should (= compilation-num-errors-found 1)))) + (should (= compilation-num-errors-found 0)))) (let ((rustic-compile-backtrace "full") (proc (rustic-compilation-start (split-string "cargo run")))) (while (eq (process-status proc) 'run) (sit-for 0.1)) (with-current-buffer (get-buffer rustic-compilation-buffer-name) - (should (= compilation-num-errors-found 1)))))) + (should (= compilation-num-errors-found 0)))))) + +(provide 'rustic-compile-test) diff --git a/test/rustic-doc-test.el b/test/rustic-doc-test.el index 659e81a0..cef86b0b 100644 --- a/test/rustic-doc-test.el +++ b/test/rustic-doc-test.el @@ -1,6 +1,5 @@ ;; -*- lexical-binding: t -*- -(require 'rustic-doc) -(require 'f) +(require 'rustic) (ert-deftest rustic-doc-setup-test () (rustic-doc-setup nil t) @@ -11,3 +10,5 @@ (sleep-for 1)) (should (file-exists-p "~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/doc/rust/html/std/option")) (should (file-exists-p (f-join rustic-doc-save-loc "std" "option" "enum.Option.org")))) + +(provide 'rustic-doc-test) diff --git a/test/rustic-format-test.el b/test/rustic-format-test.el index b92fb39a..a0bb5dc8 100644 --- a/test/rustic-format-test.el +++ b/test/rustic-format-test.el @@ -1,5 +1,7 @@ ;; -*- lexical-binding: t -*- ;; Before editing, eval (load-file "test-helper.el") +(require 'rustic) +(require 'test-helper) (ert-deftest rustic-test-format-buffer () (let* ((string "fn main() {}") @@ -35,7 +37,6 @@ (fundamental-mode) ;; no rustic-mode buffer (should-error (rustic-format-buffer)) - (should-not (get-buffer rustic-format-buffer-name)) (erase-buffer) (rustic-mode) (insert string-dummy) @@ -262,13 +263,11 @@ 'rustic-format-file-sentinel :buffer buf :files main))) - (while (eq (process-status proc) 'run) - (sit-for 0.1)))) + (rustic-test--wait-till-finished rustic-format-buffer-name))) (with-temp-buffer (insert-file-contents main) (should (string= (buffer-string) formatted-string))))) - ;; rustfmt.toml (defun rustic-test-format-create-rustfmt-toml (dir contents) @@ -320,4 +319,4 @@ (insert-file-contents main) (should (string= (buffer-string) formatted-string))))) - +(provide 'rustic-format-test) diff --git a/test/rustic-window-test.el b/test/rustic-window-test.el index 0ac9ada9..91c6abc2 100644 --- a/test/rustic-window-test.el +++ b/test/rustic-window-test.el @@ -1,4 +1,6 @@ ;; -*- lexical-binding: t -*- +(require 'rustic) +(require 'test-helper) (ert-deftest rustic-test-window-count () (should (= (length (window-list)) 1)) @@ -27,3 +29,5 @@ (should (= (length (window-list)) 2)) (should (get-buffer-window rustic-format-buffer-name))) (kill-buffer buf))) + +(provide 'rustic-window-test) diff --git a/test/rustic-workspace-test.el b/test/rustic-workspace-test.el index c0ecd5d9..d8ed205d 100644 --- a/test/rustic-workspace-test.el +++ b/test/rustic-workspace-test.el @@ -1,5 +1,7 @@ ;; -*- lexical-binding: t -*- ;; Before editing, eval (load-file "test-helper.el") +(require 'rustic) +(require 'test-helper) (ert-deftest rust-test-workspace-crate-location () (should (equal (funcall rustic-compile-directory-method) default-directory)) @@ -36,9 +38,10 @@ (rustic-cargo-build) (let* ((proc (get-process rustic-compilation-process-name)) (buffer (process-buffer proc))) - (while (eq (process-status proc) 'run) - (sit-for 0.01)) + (rustic-test--wait-till-finished rustic-compilation-buffer-name) (with-current-buffer buffer ;; (print (buffer-substring-no-properties (point-min) (point-max))) (should (string-match "Compiling test-crate" (buffer-substring-no-properties (point-min) (point-max)))) (should (string-match "Compiling another-test-crate" (buffer-substring-no-properties (point-min) (point-max))))))))) + +(provide 'rustic-workspace-test) diff --git a/test/test-helper.el b/test/test-helper.el index aa4ee77f..aec2def1 100644 --- a/test/test-helper.el +++ b/test/test-helper.el @@ -14,24 +14,6 @@ (custom-set-variables '(indent-tabs-mode nil)) -;; variable doesn't exist in noninteractive emacs sessions -(when noninteractive - (defvar org-babel-temporary-directory - (or (and (boundp 'org-babel-temporary-directory) - (file-exists-p org-babel-temporary-directory) - org-babel-temporary-directory) - (make-temp-file "babel-" t)) - "Directory to hold temporary files created to execute code blocks. -Used by `org-babel-temp-file'. This directory will be removed on -Emacs shutdown.") - - (defun remove-temporary-babel-directory () - (when (and (boundp 'org-babel-temporary-directory) - (file-exists-p org-babel-temporary-directory)) - (delete-directory org-babel-temporary-directory t))) - - (add-hook 'kill-emacs-hook 'remove-temporary-babel-directory)) - (defsubst rustic-compare-code-after-manip (_original _point-pos _manip-func expected got) (equal expected got)) @@ -60,7 +42,7 @@ Emacs shutdown.") (defun rustic-test-count-error-helper-new (string) (let* ((buffer (get-buffer-create "b")) - (default-directory org-babel-temporary-directory) + (default-directory rustic-org-babel-temporary-directory) (dir (rustic-babel-generate-project t)) (file (expand-file-name "main.rs" (concat dir "/src"))) (default-directory dir)) @@ -129,3 +111,5 @@ list of substrings of `STR' each followed by its face." (let* ((proc (get-buffer-process buffer))) (while (not (eq (process-status proc) 'exit)) (sit-for 0.2)))) + +(provide 'test-helper)