Files
ob-elixir/tasks/11-fix-error-display-in-buffer.md
2026-01-25 00:06:56 +01:00

134 lines
5.1 KiB
Markdown

# Task 11: Fix Exception Display in Org Buffer
## Problem
When an Elixir code block throws an exception, the error is not displayed in the org buffer. The error is only shown in the minibuffer/messages, leaving the user without visible feedback in their document.
### Root Cause
1. The variable `ob-elixir-signal-errors` defaults to `t` (line 57-63 in `ob-elixir.el`)
2. When an error is detected, `ob-elixir--process-result` (line 206-222) calls `signal`, which throws an Emacs error
3. The signaled error propagates up and prevents `org-babel-execute:elixir` from returning a result
4. Since no result is returned, org-babel has nothing to insert into the buffer
### Current Behavior
| `ob-elixir-signal-errors` | What happens |
|--------------------------|--------------|
| `t` (default) | Error is signaled, shown in minibuffer, **NOT inserted in buffer** |
| `nil` | Error is returned as the result string, **inserted in buffer** |
### Desired Behavior
Errors should always be displayed in the org buffer as the result, regardless of the `ob-elixir-signal-errors` setting.
## Scope
- Non-session execution mode only
- Session mode is out of scope for this fix
## Implementation Plan
### Step 1: Modify `ob-elixir--process-result` to pass full error output
**File:** `ob-elixir.el` (line 218)
**Change:** When signaling an error, pass the full error output instead of the formatted short message.
**Current code (line 218):**
```elisp
(list (ob-elixir--format-error error-info)))
```
**Proposed change:**
```elisp
(list (plist-get error-info :full-output)))
```
**Rationale:**
- The `:full-output` field contains the complete multi-line error output including stack traces
- This ensures the `condition-case` in `org-babel-execute:elixir` returns the same full output that would be returned when `ob-elixir-signal-errors` is `nil`
- The formatted short message from `ob-elixir--format-error` only includes the exception name and first-line message, which is insufficient for debugging
### Step 2: Wrap result computation in `org-babel-execute:elixir` (ALREADY DONE)
**File:** `ob-elixir.el` (lines 928-945)
**Status:** This step was already implemented. The `condition-case` wraps the result computation and catches `ob-elixir-error`, returning `(cadr err)` which will now contain the full error output after Step 1 is applied.
```elisp
(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))
;; 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)))
(ob-elixir-error
;; Return error message so it appears in buffer
(cadr err))))
```
### Step 3: Add tests for the new behavior
**File:** `test/test-ob-elixir-errors.el`
**Add new test:** Verify that errors appear in org buffer output when `ob-elixir-signal-errors` is `t`.
```elisp
(ert-deftest ob-elixir-test-error-appears-in-result ()
"Test that errors appear in result even when signaling is enabled."
(skip-unless (executable-find ob-elixir-command))
(let ((ob-elixir-signal-errors t))
;; Execute via the main entry point (not ob-elixir--execute directly)
(let ((result (org-babel-execute:elixir "raise \"test error\""
'((:result-type . value)
(:result-params . ("replace"))))))
;; Result should contain the error, not be nil/empty
(should result)
(should (string-match-p "RuntimeError" result)))))
```
**Rationale:** The existing test `ob-elixir-test-error-signaling` tests that `ob-elixir--execute` signals an error, but doesn't test the full flow through `org-babel-execute:elixir`. The new test verifies the end-to-end behavior.
### Step 4: Update TODO.org
**File:** `TODO.org`
**Change:** Mark the first item ("errors should be printed in the org buffer") as DONE.
## Summary of Changes
| File | Change |
|------|--------|
| `ob-elixir.el` | Change signal data to pass `:full-output` instead of formatted message |
| `ob-elixir.el` | Wrap result computation in `condition-case` to catch `ob-elixir-error` (already done) |
| `test/test-ob-elixir-errors.el` | Add test for error display in org buffer |
| `TODO.org` | Mark issue as resolved |
## Files NOT Modified
- Session-related code
- `ob-elixir--process-result` (keeps existing signaling behavior)
- `ob-elixir-signal-errors` default value (stays `t`)
## Verification
After implementation, test with:
```org
#+begin_src elixir
raise "This error should appear in the buffer"
#+end_src
```
Expected: The RuntimeError message should appear as the result block below the code block.