diff --git a/README.md b/README.md index bdc92df..8f9b66f 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,9 @@ sessions. `M-x compiler-explorer-make-link` generates a link for current compilation so it can be opened in a browser and shared. +`M-x compiler-explorer-restore-from-link` restores a session from a URL, +generated by the website or by this package. + `M-x compiler-explorer-layout` cycles between different layouts. `M-x compiler-explorer-exit` kills the current session. diff --git a/compiler-explorer-test.el b/compiler-explorer-test.el index 2b42fc9..07d4ed3 100644 --- a/compiler-explorer-test.el +++ b/compiler-explorer-test.el @@ -407,6 +407,31 @@ int main(int argc, char** argv) { (should (string= "boost" (caar compiler-explorer--selected-libraries))) (should (string= "174" (cadar compiler-explorer--selected-libraries))))) +(ert-deftest compiler-explorer-restoring-from-shortlink () + (let ((url nil) + (compiler-explorer-new-session-hook nil)) + (let ((compiler-explorer--session-ring (make-ring 5)) + compiler-explorer--last-session) + (compiler-explorer-test--with-session "C++" nil + (with-current-buffer compiler-explorer--buffer + (compiler-explorer-set-compiler "x86-64 clang (trunk)") + (compiler-explorer-set-compiler-args "-Wall -Wextra") + (compiler-explorer-set-execution-args "1 2 3") + (compiler-explorer-set-input "test") + (compiler-explorer-add-library "boost" "174") + (setq url (compiler-explorer-make-link))))) + (compiler-explorer-restore-from-link url) + + (with-current-buffer compiler-explorer--buffer + (should (equal (plist-get compiler-explorer--language-data :name) "C++")) + (should (equal (plist-get compiler-explorer--compiler-data :name) + "x86-64 clang (trunk)")) + (should (equal compiler-explorer--compiler-arguments "-Wall -Wextra")) + (should (equal compiler-explorer--execution-arguments "1 2 3")) + (should (equal compiler-explorer--execution-input "test")) + (should (equal (caar compiler-explorer--selected-libraries) "boost")) + (should (equal (cadar compiler-explorer--selected-libraries) "174"))))) + (ert-deftest compiler-explorer-mappings () (compiler-explorer-test--with-session "C++" nil (with-current-buffer compiler-explorer--buffer diff --git a/compiler-explorer.el b/compiler-explorer.el index 572464a..2fbf216 100644 --- a/compiler-explorer.el +++ b/compiler-explorer.el @@ -67,6 +67,9 @@ ;; M-x `compiler-explorer-make-link' generates a link for current ;; compilation so it can be opened in a browser and shared. ;; +;; M-x `compiler-explorer-restore-from-link' restores a session from a +;; URL, generated by the website or by this package. +;; ;; M-x `compiler-explorer-layout' cycles between different layouts. ;; ;; M-x `compiler-explorer-exit' kills the current session. @@ -1665,7 +1668,7 @@ Interactively, this prompts for an example to load for the current language." (error "Unknown example %S" example))) (defun compiler-explorer-make-link (&optional open) - "Save URL to current session in the kill ring. + "Save URL to current session in the kill ring and return it. With an optional prefix argument OPEN, open that link in a browser." (interactive "P") (unless (compiler-explorer--active-p) @@ -1704,16 +1707,61 @@ With an optional prefix argument OPEN, open that link in a browser." :as #'compiler-explorer--parse-json)) (url (plist-get response :url))) (message (kill-new url)) - (when open (browse-url-xdg-open url)))) + (prog1 url (when open (browse-url-xdg-open url))))) + +(defun compiler-explorer-restore-from-link (url) + "Restore a compiler-explorer session from the given URL. +URL should be a shortened compiler explorer URL, e.g. generated +by `compiler-explorer-make-link', or created by the website itself." + (interactive "MRestore session from link: ") + (pcase-let* (((cl-struct url filename) (url-generic-parse-url url)) + (shortlink + (if (string-prefix-p "/z/" filename) + (substring filename 3) + (error "%s is not a valid compiler-explorer shortlink" url))) + ((map (:sessions (seq session))) + (compiler-explorer--request-sync + (format "Fetching state from %s" url) + (compiler-explorer--url "shortlinkinfo" shortlink))) + ((map :language + :source + (:compilers + (seq (map (:id compiler-id) :options :libs))) + (:executors + (seq (map :arguments :stdin)))) + session) + (compiler-explorer--inhibit-request t)) + (compiler-explorer-new-session language compiler-id) + (seq-do (pcase-lambda ((and lib (map :id :version))) + (if (and id version) + (compiler-explorer-add-library id version) + (display-warning 'compiler-explorer + (format "Invalid library: %s" lib) + :warning))) + libs) + (compiler-explorer-set-compiler-args options) + (when arguments + (compiler-explorer-set-execution-args arguments)) + (when stdin + (compiler-explorer-set-input stdin)) + (with-current-buffer compiler-explorer--buffer + (erase-buffer) + (insert source))) + (compiler-explorer--request-async)) (defvar compiler-explorer-new-session-hook '(compiler-explorer-layout) "Hook run after creating new session. The source buffer is current when this hook runs.") (defun compiler-explorer-new-session-1 (lang &optional compiler interactive) - "Start new session for LANG. + "Start new session for LANG (name or id). This is a subr of `compiler-explorer-new-session' that uses given LANG, COMPILER, INTERACTIVE." + (when-let ((ent (cl-find lang (compiler-explorer--languages) + :key (lambda (l) (plist-get l :id)) + :test #'string=))) + (setq lang (plist-get ent :name))) + ;; Clean everything up (compiler-explorer--cleanup) (when-let ((session compiler-explorer--last-session))