This commit is contained in:
2026-01-25 00:06:56 +01:00
parent 00afc36c9e
commit 4e07ffa70c
8 changed files with 978 additions and 35 deletions

View File

@@ -215,7 +215,7 @@ Returns the cleaned result string."
(signal (if (eq (plist-get error-info :type) 'compile)
'ob-elixir-compile-error
'ob-elixir-runtime-error)
(list (ob-elixir--format-error error-info)))
(list (plist-get error-info :full-output)))
;; Return error as result
(plist-get error-info :full-output))
;; No error, return trimmed result
@@ -419,6 +419,11 @@ Each statement has the form: var_name = value"
"Regexp matching a deps block.
Group 1 captures the deps content.")
(defconst ob-elixir--imports-block-regexp
"^[ \t]*#\\+BEGIN_IMPORTS[ \t]+elixir[ \t]*\n\\(\\(?:.*\n\\)*?\\)[ \t]*#\\+END_IMPORTS"
"Regexp matching an imports block.
Group 1 captures the imports content.")
(defun ob-elixir--find-deps-for-position (pos)
"Find the most recent deps block before POS.
@@ -433,6 +438,19 @@ Returns the deps content as a string, or nil if no deps block found."
(setq found (match-string-no-properties 1))))
found)))
(defun ob-elixir--find-imports-for-position (pos)
"Find the most recent imports block before POS.
Returns the imports content as a string, or nil if no imports block found."
(save-excursion
(goto-char pos)
(let ((found nil))
(while (and (not found)
(re-search-backward ob-elixir--imports-block-regexp nil t))
(when (< (match-end 0) pos)
(setq found (match-string-no-properties 1))))
found)))
(defun ob-elixir--normalize-deps (deps-string)
"Normalize DEPS-STRING for consistent hashing.
@@ -540,16 +558,20 @@ Returns the project directory path."
;;; Execution with Dependencies
(defun ob-elixir--execute-with-deps (body result-type deps-string)
(defun ob-elixir--execute-with-deps (body result-type deps-string &optional imports-string)
"Execute BODY with dependencies from DEPS-STRING.
RESULT-TYPE is `value' or `output'."
RESULT-TYPE is `value' or `output'.
IMPORTS-STRING, if provided, is prepended to the code before execution."
(let* ((project-dir (ob-elixir--get-deps-project deps-string))
(default-directory project-dir)
(tmp-file (org-babel-temp-file "ob-elixir-" ".exs"))
(code (if (eq result-type 'value)
(ob-elixir--wrap-for-value body)
body)))
(wrapped (if (eq result-type 'value)
(ob-elixir--wrap-for-value body)
body))
(code (if imports-string
(concat (string-trim imports-string) "\n\n" wrapped)
wrapped)))
;; Write code to temp file
(with-temp-file tmp-file
@@ -660,14 +682,18 @@ IO.puts(\"__ob_value_end__\")
"Wrap BODY to capture its value in session mode."
(format ob-elixir--session-value-wrapper body))
(defun ob-elixir--evaluate-in-session (session body result-type)
(defun ob-elixir--evaluate-in-session (session body result-type &optional imports-string)
"Evaluate BODY in SESSION, return result.
RESULT-TYPE is `value' or `output'."
RESULT-TYPE is `value' or `output'.
IMPORTS-STRING, if provided, is prepended to the code before execution."
(let* ((buffer (org-babel-elixir-initiate-session session nil))
(code (if (eq result-type 'value)
(ob-elixir--session-wrap-for-value body)
body))
(wrapped (if (eq result-type 'value)
(ob-elixir--session-wrap-for-value body)
body))
(code (if imports-string
(concat (string-trim imports-string) "\n\n" wrapped)
wrapped))
(eoe-indicator ob-elixir--eoe-marker)
(full-body (concat code "\nIO.puts(\"" eoe-indicator "\")"))
output)
@@ -810,14 +836,18 @@ DEPS-STRING contains the dependencies specification."
(puthash name deps-hash ob-elixir--session-deps)
buffer))))
(defun ob-elixir--evaluate-in-session-with-deps (session body result-type deps-string)
(defun ob-elixir--evaluate-in-session-with-deps (session body result-type deps-string &optional imports-string)
"Evaluate BODY in SESSION with DEPS-STRING context.
RESULT-TYPE is `value' or `output'."
RESULT-TYPE is `value' or `output'.
IMPORTS-STRING, if provided, is prepended to the code before execution."
(let* ((buffer (ob-elixir--get-or-create-session-with-deps session deps-string))
(code (if (eq result-type 'value)
(ob-elixir--session-wrap-for-value body)
body))
(wrapped (if (eq result-type 'value)
(ob-elixir--session-wrap-for-value body)
body))
(code (if imports-string
(concat (string-trim imports-string) "\n\n" wrapped)
wrapped))
(eoe-indicator ob-elixir--eoe-marker)
(full-body (concat code "\nIO.puts(\"" eoe-indicator "\")"))
output)
@@ -886,20 +916,24 @@ The wrapper evaluates BODY, then prints the result using
`inspect/2` with infinite limits to avoid truncation."
(format ob-elixir--value-wrapper body))
(defun ob-elixir--execute (body result-type)
(defun ob-elixir--execute (body result-type &optional imports-string)
"Execute BODY as Elixir code.
RESULT-TYPE is either `value' or `output'.
For `value', wraps code to capture return value.
For `output', captures stdout directly.
IMPORTS-STRING, if provided, is prepended to the code before execution.
Returns the result as a string.
May signal `ob-elixir-error' if execution fails and
`ob-elixir-signal-errors' is non-nil."
(let* ((tmp-file (org-babel-temp-file "ob-elixir-" ".exs"))
(code (if (eq result-type 'value)
(ob-elixir--wrap-for-value body)
body)))
(wrapped (if (eq result-type 'value)
(ob-elixir--wrap-for-value body)
body))
(code (if imports-string
(concat (string-trim imports-string) "\n\n" wrapped)
wrapped)))
(with-temp-file tmp-file
(insert code))
(let ((result (with-temp-buffer
@@ -921,24 +955,30 @@ This function is called by `org-babel-execute-src-block'."
(result-params (cdr (assq :result-params params)))
;; Find deps for this block's position
(deps-string (ob-elixir--find-deps-for-position (point)))
;; Find imports for this block's position
(imports-string (ob-elixir--find-imports-for-position (point)))
;; Expand body with variable assignments
(full-body (org-babel-expand-body:generic
body params
(org-babel-variable-assignments:elixir params)))
(result (cond
;; Session mode with deps
((and session (not (string= session "none")) deps-string)
(ob-elixir--evaluate-in-session-with-deps
session full-body result-type deps-string))
;; Session mode without deps
((and session (not (string= session "none")))
(ob-elixir--evaluate-in-session session full-body result-type))
;; Non-session with deps
(deps-string
(ob-elixir--execute-with-deps full-body result-type deps-string))
;; Plain execution
(t
(ob-elixir--execute full-body result-type)))))
(result (condition-case err
(cond
;; Session mode with deps
((and session (not (string= session "none")) deps-string)
(ob-elixir--evaluate-in-session-with-deps
session full-body result-type deps-string imports-string))
;; Session mode without deps
((and session (not (string= session "none")))
(ob-elixir--evaluate-in-session session full-body result-type imports-string))
;; Non-session with deps
(deps-string
(ob-elixir--execute-with-deps full-body result-type deps-string imports-string))
;; Plain execution
(t
(ob-elixir--execute full-body result-type imports-string)))
(ob-elixir-error
;; Return error message so it appears in buffer
(cadr err)))))
(org-babel-reassemble-table
(org-babel-result-cond result-params
;; For output/scalar/verbatim - return as-is