Skip to content

Commit e0cfa1d

Browse files
Eric WangEric Wang
authored andcommitted
rustic-babel: support wrap BODY in a fn main if none exists
close brotzeit#267 related: brotzeit#266
1 parent 985c094 commit e0cfa1d

3 files changed

Lines changed: 76 additions & 4 deletions

File tree

README.md

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
- [:features](#features)
4343
- [:paths](#paths)
4444
- [:toolchain](#toolchain)
45+
- [:main](#main)
4546
- [Spinner](#spinner)
4647
- [inline-documentation](#inline-documentation)
4748
- [Prequisites](#prequisites)
@@ -79,7 +80,7 @@ The other files provide functionality that is similar to some of the features
7980
of rustic, however can be considered light-weight compared to some rustic's
8081
functionality.
8182

82-
The shared functions and options exist as aliases in the rust-mode and
83+
The shared functions and options exist as aliases in the rust-mode and
8384
rustic namespace for backwards compatability reasons(rustic has been a fork).
8485

8586
## Known issues
@@ -499,7 +500,7 @@ then a string, instead of a list, will also be accepted:
499500
```
500501
#+BEGIN_SRC rust :crates '((tokio . 1.0)) :features '((tokio . ("rt-multi-thread" "time")))
501502
extern crate tokio;
502-
503+
503504
fn main() {
504505
tokio::runtime::Runtime::new()
505506
.unwrap()
@@ -541,6 +542,28 @@ fn main() {
541542
: a,b,c
542543
```
543544

545+
#### :main
546+
547+
Auto wrap whole block body in a `fn main` function call if none exists.
548+
549+
Since this is very handy in most code snippets, so the default value is `yes`.
550+
`no` if you don't want this feature(for example, you don't want regex search slow things down).
551+
552+
You can also set a default value by:
553+
``` elisp
554+
;; By setq this default to `nil`, you'll have to explict set params to ":main yes" in each block
555+
(setq rustic-babel-auto-wrap-main nil)
556+
```
557+
558+
```
559+
#+begin_src rust :main yes
560+
let x = vec![1, 2, 3].iter().map(|&x| x + 1).collect::<Vec<_>>();
561+
println!("{:?}", x);
562+
#+end_src
563+
564+
#+results:
565+
: [2, 3, 4]
566+
```
544567

545568
## Spinner
546569

rustic-babel.el

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@
2626
:type 'boolean
2727
:group 'rustic-babel)
2828

29+
(defcustom rustic-babel-auto-wrap-main t
30+
"Whether to auto wrap body in 'fn main' to function call if none exists."
31+
:type 'boolean
32+
:group 'rustic-babel)
33+
2934
(defcustom rustic-babel-format-src-block t
3035
"Whether to format a src block automatically after successful execution."
3136
:type 'boolean
@@ -259,6 +264,12 @@ directory DIR."
259264
(insert s)
260265
(insert dependencies))))))
261266

267+
(defun rustic-babel-ensure-main-wrap (body)
268+
"Wrap BODY in a 'fn main' function call if none exists."
269+
(if (string-match "^[ \t]*[fn]+[ \t\n\r]*main[ \t]*(.*)" body)
270+
body
271+
(format "fn main() {\n%s\n}\n" body)))
272+
262273
(defun org-babel-execute:rustic (body params)
263274
"Execute a block of Rust code with org-babel.
264275
@@ -272,7 +283,12 @@ kill the running process."
272283
(let* ((default-directory org-babel-temporary-directory)
273284
(project (rustic-babel-project))
274285
(dir (setq rustic-babel-dir (expand-file-name project)))
275-
(main (expand-file-name "main.rs" (concat dir "/src"))))
286+
(main-p (cdr (assq :main params)))
287+
(main (expand-file-name "main.rs" (concat dir "/src")))
288+
(wrap-main (cond ((string= main-p "yes") t)
289+
((string= main-p "no") nil)
290+
(t rustic-babel-auto-wrap-main))))
291+
276292
(make-directory (file-name-directory main) t)
277293
(rustic-babel-cargo-toml dir params)
278294
(setq rustic-info (org-babel-get-src-block-info))
@@ -286,7 +302,8 @@ kill the running process."
286302
(let ((default-directory dir)
287303
(toolchain (cdr (assq :toolchain params))))
288304
(write-region
289-
(concat "#![allow(non_snake_case)]\n" body) nil main nil 0)
305+
(concat "#![allow(non_snake_case)]\n"
306+
(if wrap-main (rustic-babel-ensure-main-wrap body) body)) nil main nil 0)
290307
(rustic-babel-eval dir toolchain)
291308
(setq rustic-babel-src-location
292309
(set-marker (make-marker) (point) (current-buffer)))

test/rustic-babel-test.el

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,3 +187,35 @@
187187
(with-current-buffer buf
188188
(rustic-test-babel-execute-block buf)
189189
(should (eq (rustic-test-babel-check-results buf) nil)))))
190+
191+
(ert-deftest rustic-test-babel-ensure-main-wrap-no()
192+
(let* ((string "let x = \"fn main(){}\";")
193+
(params ":main no")
194+
(buf (rustic-test-get-babel-block string params)))
195+
(with-current-buffer buf
196+
(rustic-test-babel-execute-block buf)
197+
(let ((re (format "error: Could not compile `%s`.\n"
198+
(car (reverse (split-string rustic-babel-dir "/"))))))
199+
(should (string= re (rustic-test-babel-check-results buf)))))))
200+
201+
(ert-deftest rustic-test-babel-ensure-main-wrap-yes-with-main()
202+
(let* ((string "
203+
fn main() {
204+
let x = \"rustic\";
205+
}")
206+
(params ":main yes")
207+
(buf (rustic-test-get-babel-block string params)))
208+
(with-current-buffer buf
209+
(rustic-test-babel-execute-block buf)
210+
(should (eq (rustic-test-babel-check-results buf) nil)))))
211+
212+
(ert-deftest rustic-test-babel-ensure-main-wrap-no-with-main()
213+
(let* ((string "
214+
fn main() {
215+
let x = \"rustic\";
216+
}")
217+
(params ":main no")
218+
(buf (rustic-test-get-babel-block string params)))
219+
(with-current-buffer buf
220+
(rustic-test-babel-execute-block buf)
221+
(should (eq (rustic-test-babel-check-results buf) nil)))))

0 commit comments

Comments
 (0)