Skip to content

Commit

Permalink
rustic-babel: support wrap BODY in a fn main if none exists
Browse files Browse the repository at this point in the history
close brotzeit#267

related: brotzeit#266
  • Loading branch information
Eric Wang committed Nov 5, 2021
1 parent 985c094 commit 4675590
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 3 deletions.
37 changes: 35 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
- [:features](#features)
- [:paths](#paths)
- [:toolchain](#toolchain)
- [:main](#main)
- [Spinner](#spinner)
- [inline-documentation](#inline-documentation)
- [Prequisites](#prequisites)
Expand Down Expand Up @@ -79,7 +80,7 @@ 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
The shared functions and options exist as aliases in the rust-mode and
rustic namespace for backwards compatability reasons(rustic has been a fork).

## Known issues
Expand Down Expand Up @@ -499,7 +500,7 @@ 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()
Expand Down Expand Up @@ -541,6 +542,38 @@ fn main() {
: a,b,c
```

#### :main

Auto wrap whole block body in a "fn main" function call if none exists.

This is very useful in most code snippets, so the default value is "yes".
"no" if you don't want this feature(for example if you don't want regex search slow things down).

```
#+begin_src rust
let x = vec![1, 2, 3].iter().map(|&x| x + 1).collect::<Vec<_>>();
println!("{:?}", x);
#+end_src
#+results:
: [2, 3, 4]
```

NOTE: the flowing snippet won't work, because the regex match unable to understand main within a raw string.

```
#+begin_src rust :exports both :main yes
// won't work
let r = "
fn main() {}
";
println!("{}", r);
// works
printlnt!("fn main{{}}")
#+end_src
```


## Spinner

Expand Down
10 changes: 9 additions & 1 deletion rustic-babel.el
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,12 @@ directory DIR."
(insert s)
(insert dependencies))))))

(defun rustic-babel-ensure-main-wrap (body)
"Wrap BODY in a \"fn main\" function call if none exists."
(if (string-match "^[ \t]*[fn]+[ \t\n\r]*main[ \t]*(.*)" body)
body
(format "fn main() {\n%s\n}\n" body)))

(defun org-babel-execute:rustic (body params)
"Execute a block of Rust code with org-babel.
Expand All @@ -272,6 +278,7 @@ kill the running process."
(let* ((default-directory org-babel-temporary-directory)
(project (rustic-babel-project))
(dir (setq rustic-babel-dir (expand-file-name project)))
(main-p (not (string= (cdr (assq :main params)) "no")))
(main (expand-file-name "main.rs" (concat dir "/src"))))
(make-directory (file-name-directory main) t)
(rustic-babel-cargo-toml dir params)
Expand All @@ -286,7 +293,8 @@ kill the running process."
(let ((default-directory dir)
(toolchain (cdr (assq :toolchain params))))
(write-region
(concat "#![allow(non_snake_case)]\n" body) nil main nil 0)
(concat "#![allow(non_snake_case)]\n"
(if main-p (rustic-babel-ensure-main-wrap body) body)) nil main nil 0)
(rustic-babel-eval dir toolchain)
(setq rustic-babel-src-location
(set-marker (make-marker) (point) (current-buffer)))
Expand Down
38 changes: 38 additions & 0 deletions test/rustic-babel-test.el
Original file line number Diff line number Diff line change
Expand Up @@ -187,3 +187,41 @@
(with-current-buffer buf
(rustic-test-babel-execute-block buf)
(should (eq (rustic-test-babel-check-results buf) nil)))))

(ert-deftest rustic-test-babel-ensure-main-wrap()
(let* ((string "let x = \"fn main(){}\";")
(params "")
(buf (rustic-test-get-babel-block string params)))
(with-current-buffer buf
(rustic-test-babel-execute-block buf)
(should (eq (rustic-test-babel-check-results buf) nil))))
(let* ((string "let x = \"fn main(){}\";")
(params ":main no")
(buf (rustic-test-get-babel-block string params)))
(with-current-buffer buf
(rustic-test-babel-execute-block buf)
(let ((re (format "error: Could not compile `%s`.\n"
(car (reverse (split-string rustic-babel-dir "/"))))))
(should (string= re (rustic-test-babel-check-results buf)))))))

(ert-deftest rustic-test-babel-ensure-main-wrap-yes-with-main()
(let* ((string "
fn main() {
let x = \"rustic\";
}")
(params ":main yes")
(buf (rustic-test-get-babel-block string params)))
(with-current-buffer buf
(rustic-test-babel-execute-block buf)
(should (eq (rustic-test-babel-check-results buf) nil)))))

(ert-deftest rustic-test-babel-ensure-main-wrap-no()
(let* ((string "
fn main() {
let x = \"rustic\";
}")
(params ":main no")
(buf (rustic-test-get-babel-block string params)))
(with-current-buffer buf
(rustic-test-babel-execute-block buf)
(should (eq (rustic-test-babel-check-results buf) nil)))))

0 comments on commit 4675590

Please sign in to comment.