Skip to content

Commit

Permalink
Merge pull request #544 from isvilen/run-interactive
Browse files Browse the repository at this point in the history
Support running interactive programs
  • Loading branch information
psibi authored May 15, 2024
2 parents e54bbae + 947ebf9 commit 5e96cd0
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 17 deletions.
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");
}
}
}
}

0 comments on commit 5e96cd0

Please sign in to comment.