;;; ob-elixir.el --- Org Babel functions for Elixir -*- lexical-binding: t; -*- ;; Copyright (C) 2024 Your Name ;; Author: Your Name ;; URL: https://github.com/username/ob-elixir ;; Keywords: literate programming, reproducible research, elixir ;; Version: 0.1.0 ;; Package-Requires: ((emacs "27.1") (org "9.4")) ;; This file is not part of GNU Emacs. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;;; Commentary: ;; Org Babel support for evaluating Elixir code blocks. ;; ;; Features: ;; - Execute Elixir code in org-mode source blocks ;; - Support for :results value and :results output ;; - Variable passing with :var header argument ;; - Mix project context support ;; ;; Usage: ;; Add (elixir . t) to `org-babel-load-languages': ;; ;; (org-babel-do-load-languages ;; 'org-babel-load-languages ;; '((elixir . t))) ;;; Code: (require 'ob) (require 'ob-eval) ;;; Customization (defgroup ob-elixir nil "Org Babel support for Elixir." :group 'org-babel :prefix "ob-elixir-") (defcustom ob-elixir-command "elixir" "Command to execute Elixir code. Can be a full path or command name if in PATH." :type 'string :group 'ob-elixir :safe #'stringp) ;;; Header Arguments (defvar org-babel-default-header-args:elixir '((:results . "value") (:session . "none")) "Default header arguments for Elixir code blocks.") ;;; Language Registration ;; File extension for tangling (add-to-list 'org-babel-tangle-lang-exts '("elixir" . "ex")) ;; Associate with elixir-mode for syntax highlighting (if available) (with-eval-after-load 'org-src (add-to-list 'org-src-lang-modes '("elixir" . elixir))) ;;; Execution (defconst ob-elixir--value-wrapper "result = ( %s ) IO.puts(inspect(result, limit: :infinity, printable_limit: :infinity, charlists: :as_lists)) " "Wrapper template for capturing Elixir expression value. %s is replaced with the user's code.") (defun ob-elixir--wrap-for-value (body) "Wrap BODY to capture its return value. 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) "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. Returns the result as a string." (let* ((tmp-file (org-babel-temp-file "ob-elixir-" ".exs")) (code (if (eq result-type 'value) (ob-elixir--wrap-for-value body) body))) (with-temp-file tmp-file (insert code)) (let ((result (org-babel-eval (format "%s %s" ob-elixir-command (org-babel-process-file-name tmp-file)) ""))) (string-trim result)))) (defun org-babel-execute:elixir (body params) "Execute a block of Elixir code with org-babel. BODY is the Elixir code to execute. PARAMS is an alist of header arguments. This function is called by `org-babel-execute-src-block'." (let* ((result-type (cdr (assq :result-type params))) (result-params (cdr (assq :result-params params))) (result (ob-elixir--execute body result-type))) (org-babel-reassemble-table (org-babel-result-cond result-params result (org-babel-script-escape result)) (org-babel-pick-name (cdr (assq :colname-names params)) (cdr (assq :colnames params))) (org-babel-pick-name (cdr (assq :rowname-names params)) (cdr (assq :rownames params)))))) (provide 'ob-elixir) ;;; ob-elixir.el ends here