Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support running interactive programs #544

Merged
merged 1 commit into from
May 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@
*-autoloads.el
/rust-mode-pkg.el
.eask
/dist
/dist
test-project/Cargo.lock
test-project/target/
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ compile:

test:
$(EASK) test ert rust-mode-tests.el
$(EASK) test ert rust-cargo-tests.el

checkdoc:
$(EASK) lint checkdoc
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,9 @@ By default these are bound to:
- <kbd>C-c C-c C-t</kbd> `rust-test`
- <kbd>C-c C-c C-r</kbd> `rust-run`

To run programs requiring user input use universal argument when invoking
`rust-run` (<kbd>C-u C-c C-c C-r</kbd>).

### Clippy

`rust-run-clippy` runs
Expand Down
53 changes: 53 additions & 0 deletions rust-cargo-tests.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
;;; rust-cargo-tests.el --- ERT tests for rust-cargo.el -*- lexical-binding: t; -*-
(require 'rust-cargo)
(require 'ert)

(defun rust-test--wait-process-exit ()
"Wait for comint process for current buffer to exit."
(let ((proc (get-buffer-process (current-buffer))))
(while (not (eq (process-status proc) 'exit))
(sit-for 0.2))))

(defun rust-test--send-process-string (string)
"Send STRING to comint process for current buffer."
(let ((proc (get-buffer-process (current-buffer))))
(comint-send-string proc string)))

(defmacro rust-test--with-main-file-buffer (expr)
`(let* ((test-dir (expand-file-name "test-project/" default-directory))
(main-file (expand-file-name "src/main.rs" test-dir)))
(save-current-buffer
(find-file main-file)
,expr)))

(defun rust-test--find-string (string)
"Find STRING in current buffer."
(goto-char (point-min))
(not (null (search-forward string nil t))))


(ert-deftest rust-test-compile ()
(skip-unless (executable-find rust-cargo-bin))
(setq rust-cargo-default-arguments "")
(rust-test--with-main-file-buffer
(with-current-buffer (rust-compile)
(rust-test--wait-process-exit)
(should (rust-test--find-string "Compilation finished")))))

(ert-deftest rust-test-run ()
(skip-unless (executable-find rust-cargo-bin))
(setq rust-cargo-default-arguments "")
(rust-test--with-main-file-buffer
(with-current-buffer (rust-run)
(rust-test--wait-process-exit)
(should (rust-test--find-string "***run not interactive")))))

(ert-deftest rust-test-run-interactive ()
(skip-unless (executable-find rust-cargo-bin))
(setq rust-cargo-default-arguments "interactive")
(rust-test--with-main-file-buffer
;; '(4) is default value when called interactively with universal argument
(with-current-buffer (rust-run '(4))
(rust-test--send-process-string "1234\n")
(rust-test--wait-process-exit)
(should (rust-test--find-string "***run interactive: 1234")))))
40 changes: 24 additions & 16 deletions rust-cargo.el
Original file line number Diff line number Diff line change
Expand Up @@ -67,46 +67,54 @@

;;; Internal

(defun rust--compile (format-string &rest args)
(defun rust--compile (comint format-string &rest args)
(when (null rust-buffer-project)
(rust-update-buffer-project))
(let ((default-directory
(or (and rust-buffer-project
(file-name-directory rust-buffer-project))
default-directory)))
(compile (apply #'format format-string args))))
default-directory))
;; make sure comint is a boolean value
(comint (not (not comint))))
(compile (apply #'format format-string args) comint)))

;;; Commands

(defun rust-check ()
"Compile using `cargo check`"
(interactive)
(rust--compile "%s check %s" rust-cargo-bin rust-cargo-default-arguments))
(rust--compile nil "%s check %s" rust-cargo-bin rust-cargo-default-arguments))

(defun rust-compile ()
"Compile using `cargo build`"
(interactive)
(rust--compile "%s build %s" rust-cargo-bin rust-cargo-default-arguments))
(rust--compile nil "%s build %s" rust-cargo-bin rust-cargo-default-arguments))

(defun rust-compile-release ()
"Compile using `cargo build --release`"
(interactive)
(rust--compile "%s build --release" rust-cargo-bin))
(rust--compile nil "%s build --release" rust-cargo-bin))

(defun rust-run ()
"Run using `cargo run`"
(interactive)
(rust--compile "%s run %s" rust-cargo-bin rust-cargo-default-arguments))
(defun rust-run (&optional comint)
"Run using `cargo run`

(defun rust-run-release ()
"Run using `cargo run --release`"
(interactive)
(rust--compile "%s run --release" rust-cargo-bin))
If optional arg COMINT is t or invoked with universal prefix arg,
output buffer will be in comint mode, i.e. interactive."
(interactive "P")
(rust--compile comint "%s run %s" rust-cargo-bin rust-cargo-default-arguments))

(defun rust-run-release (&optional comint)
"Run using `cargo run --release`

If optional arg COMINT is t or invoked with universal prefix arg,
output buffer will be in comint mode, i.e. interactive."
(interactive "P")
(rust--compile comint "%s run --release" rust-cargo-bin))

(defun rust-test ()
"Test using `cargo test`"
(interactive)
(rust--compile "%s test %s" rust-cargo-bin rust-cargo-default-arguments))
(rust--compile nil "%s test %s" rust-cargo-bin rust-cargo-default-arguments))

(defun rust-run-clippy ()
"Run `cargo clippy'."
Expand All @@ -118,7 +126,7 @@
;; set `compile-command' temporarily so `compile' doesn't
;; clobber the existing value
(compile-command (mapconcat #'shell-quote-argument args " ")))
(rust--compile compile-command)))
(rust--compile nil compile-command)))

;;; _
(provide 'rust-cargo)
Expand Down
25 changes: 25 additions & 0 deletions test-project/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use std::{env, io};

fn main() {
let mut args = env::args();

if args.len() == 1 {
println!("***run not interactive");
} else {
match args.nth(1).unwrap().as_str() {
"interactive" => {
let mut line = String::new();

io::stdin()
.read_line(&mut line)
.expect("Failed to read line");

println!("***run interactive: {line}");
}

_ => {
panic!("unexpected argument");
}
}
}
}
Loading