imports
This commit is contained in:
133
tasks/11-fix-error-display-in-buffer.md
Normal file
133
tasks/11-fix-error-display-in-buffer.md
Normal file
@@ -0,0 +1,133 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user