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 multiple binary targets in rust-run #471

Open
thblt opened this issue Nov 19, 2022 · 5 comments
Open

Support multiple binary targets in rust-run #471

thblt opened this issue Nov 19, 2022 · 5 comments

Comments

@thblt
Copy link

thblt commented Nov 19, 2022

rust-run fails if cargo run needs a --bin argument, which is the case if:

  1. The workspace has multiple binary targets.
  2. No target is listed as the package's default-run

It is probably reasonably easy to support this. A possible interface update to rust-run could simply prompt for a target name iff both conditions above hold (multiple binary target, no default) OR it's called with an argument. The chosen target's name could be saved somewhere so further invocations of rust-run can just reuse it (unless called with an arg)

This is a quick and dirty way to get all binary targets from the current workspace, and the default target:

(let* ((json (with-temp-buffer
               (call-process "cargo" nil (current-buffer) nil
                             "metadata" "--format-version" "1")
               (goto-char (point-min))
               (json-parse-buffer)))
       ;; !! this is a bit dirty. !!
       (members (seq-map (lambda (wm)
                           (car (split-string wm " ")))
                         (gethash "workspace_members" json)))
       (targets
        (-flatten ; from dash.el, but not strictly required.
         (seq-map (lambda (v)
                    (seq-keep
                     (lambda (target)
                       (when (seq-contains-p
                              (gethash "kind" target) "bin" 'string=)
                         (gethash "name" target))) v))
                  (seq-map (lambda (package) (gethash "targets" package))
                           (seq-filter
                            (lambda (pkg) (seq-contains-p members (gethash "name" pkg)))
                            (gethash "packages" json))))))
       (default-run (gethash "default_run"
                             (car
                              (seq-filter
                               (lambda (item) (string= "raoc2021" (gethash "name" item)))
                               (gethash "packages" json))))))
  (message "Workspace members: %s" members)
  (message "Binary targets: %s" targets)
  (message "Default run target is: %s" default-run))

What do you think?

@brotzeit
Copy link
Contributor

I want to avoid complaints from other users. But maybe we can add this as wrapper around cargo-run ? I've seen this kind of request before so other users would certainly also benefit.

@thblt
Copy link
Author

thblt commented Dec 12, 2022

Do you mean rust-run? There's no cargo-run defined in my Emacs.

@brotzeit
Copy link
Contributor

Yeah, I mean rust-run.

@thblt
Copy link
Author

thblt commented Dec 12, 2022

This is how I've implemented this in my Emacs:

(defvar-local thblt/rust-run-target nil
  "The current binary target, set by `thblt/rust-run'.")

(defun thblt/rust-run (target)
  "Like `rust-run', but prompt for a target if necessary.

The last run target is stored in `thblt/rust-run-target'.  To
force target selection, use a prefix argument."
  ;; Notice this could be generalized to all targets, eg for `rust-build'.
  (interactive
   (list
    (let*
        ((json
          (with-temp-buffer
            (call-process "cargo" nil (current-buffer) nil
                          "metadata" "--format-version" "1")
            (goto-char (point-min))
            (json-parse-buffer :null-object nil)))
         ;; !! this is a bit dirty. !!
         (members
          (seq-map (lambda (wm)
                     (car (split-string wm " ")))
                   (gethash "workspace_members" json)))
         (targets
          (-flatten ; from dash.el, but not strictly required.
           (seq-map (lambda (v)
                      (seq-keep (lambda (target)
                                  (when
                                      (seq-contains-p
                                       ;; Filter out non-binary targets.
                                       (gethash "kind" target) "bin" 'string=)
                                    (gethash "name" target))) v))
                    (seq-map (lambda (package)
                               (gethash "targets" package))
                             (seq-filter
                              (lambda (pkg)
                                (seq-contains-p members
                                                (gethash "name" pkg)))
                              (gethash "packages" json))))))
         (default-run
          (gethash "default_run"
                   (car
                    (seq-filter
                     (lambda (item)
                       ;;(string= "raoc2021" (gethash "name" item))
                       t )
                     (gethash "packages" json))))))
      (or default-run
          (and (not current-prefix-arg)
               (member thblt/rust-run-target targets)
               thblt/rust-run-target)
          (completing-read "Target: " targets)))))
  ;; Save buffers
  (when-let (project-current (project-current))
    (mapc (lambda (buf) (with-current-buffer buf (when (buffer-file-name) (save-buffer))))
          (project-buffers project-current)))
  ;; Compile
  (rust--compile "%s run %s --bin %s" rust-cargo-bin rust-cargo-default-arguments target)
  ;; @TODO Should we still save if this is the default target?
  (when (called-interactively-p 'any) (setq thblt/rust-run-target target)))

This is a draft, of course.

Its main advantage is that it has no visible effect in all cases where rust-run “just works”, ie projects with a single binary target or an explicit default target. The prompt only appears if called with a prefix arg or if the call to cargo run would have failed.

@thblt
Copy link
Author

thblt commented Dec 12, 2022

I may have misunderstood which possible complaints you were referring to. My point above is that the change is a noop in all cases where rust-run worked as expected, and does the right thing (IMHO) in other cases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants