From 860dc7673400329e038370610b3543a7344ee254 Mon Sep 17 00:00:00 2001 From: Nilay Kumar Date: Mon, 30 Dec 2024 13:40:21 -0500 Subject: [PATCH 1/8] Starting work on code formatting --- ob-python-extras.el | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/ob-python-extras.el b/ob-python-extras.el index d69cbc2..0050a46 100644 --- a/ob-python-extras.el +++ b/ob-python-extras.el @@ -524,5 +524,26 @@ In regular org-mode, tries to view image or executes normal C-c C-c." (this-dir (file-name-directory this-file))) (load (expand-file-name "ob-python-extras-alerts" this-dir)))) + +;; TODO note there are also inline source code blocks? +(defun ob-python-extras-format-ruff () + (interactive) + (when (member 'org-src-mode local-minor-modes) + (let ((created-temp-file + (make-temp-file + (concat (file-name-as-directory (org-babel-temp-directory)) "ob-python-extras-format-ruff-") + nil + nil + (buffer-string)))) + (async-start-process "ruff" + "ruff" + (apply-partially 'ob-python-extras--format-ruff-callback created-temp-file (current-buffer)) + "format" created-temp-file)))) + +(defun ob-python-extras--format-ruff-callback (temp-file-name src-edit-buffer process-obj) + (message "formatted code: %s" temp-file-name) + (with-current-buffer src-edit-buffer + (insert-file-contents temp-file-name nil nil nil t))) + (provide 'ob-python-extras) ;;; ob-python-extras.el ends here From fa7a0390ed4bf2f1a4d29ab146f174726ed74d87 Mon Sep 17 00:00:00 2001 From: Nilay Kumar Date: Wed, 1 Jan 2025 01:59:04 -0800 Subject: [PATCH 2/8] Initial src-block formatting work --- ob-python-extras.el | 90 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 70 insertions(+), 20 deletions(-) diff --git a/ob-python-extras.el b/ob-python-extras.el index 0050a46..d3674c2 100644 --- a/ob-python-extras.el +++ b/ob-python-extras.el @@ -509,6 +509,76 @@ In regular org-mode, tries to view image or executes normal C-c C-c." (script-path (concat ob-python-extras-dir "bashscripts/convert_org_to_ipynb.sh" ))) (compile (concat "cd " current-dir " && "script-path))))) +(defun ob-python-extras-format-ruff () + (interactive) + (when (member 'org-src-mode local-minor-modes) + (let ((created-temp-file + (make-temp-file + (concat (file-name-as-directory (org-babel-temp-directory)) "ob-python-extras-format-ruff-") + nil + nil + (buffer-string)))) + (async-start-process "ob-python-extras-format-process" + "uvx" + (apply-partially 'ob-python-extras-format-callback created-temp-file (current-buffer)) + "ruff" "format" created-temp-file)))) + +(defun ob-python-extras-format-buffer-callback (temp-file-name src-edit-buffer process-obj) + (with-current-buffer src-edit-buffer + (insert-file-contents temp-file-name nil nil nil t)) + (message "Formatted org-src-edit-buffer")) + +(defun ob-python-extras-format-src-block-callback (temp-file-name src-block-buffer beg end process-obj) + (set-buffer src-block-buffer) + (save-restriction + (narrow-to-region beg end) + (insert-file-contents temp-file-name nil nil nil t)) + (message "Formatted org-src-block")) + +;; TODO check to make sure that it's a python source block +(defun ob-python-extras-format-black () + (interactive) + (if (org-src-edit-buffer-p) + (let ((created-temp-file + (make-temp-file + (concat (file-name-as-directory (org-babel-temp-directory)) "ob-python-extras-format-black-") + nil + nil + (buffer-string)))) + (async-start-process "ob-python-extras-format-process" + "black" + (apply-partially 'ob-python-extras-format-buffer-callback created-temp-file (current-buffer)) + created-temp-file)) + ;; note that we place this in the else clause + ;; because org-in-src-block-p does not like running in org-src-edit-buffers + (if (org-in-src-block-p t) + (let* ((created-temp-file + (make-temp-file + (concat (file-name-as-directory (org-babel-temp-directory)) "ob-python-extras-format-black-") + nil + nil + (org-element-property :value (org-element-at-point)))) + (content-area (org-src--contents-area (org-element-at-point))) + (beg (car content-area)) + (end (cadr content-area))) + (async-start-process "ob-python-extras-format-process" + "black" + (apply-partially 'ob-python-extras-format-src-block-callback created-temp-file (current-buffer) beg end) + created-temp-file)) + (message "Nothing to format")))) + +;; start by using (org-src--contents-area (org-element-at-point)) +;; here's the trick for replacing the contents. +;; (if (version< emacs-version "27.1") +;; (progn (delete-region beg end) +;; (insert (with-current-buffer write-back-buf +;; (buffer-string)))) +;; (save-restriction +;; (narrow-to-region beg end) +;; (org-replace-buffer-contents write-back-buf 0.1 nil) +;; (goto-char (point-max)))) +;; (when (and expecting-bol (not (bolp))) (insert "\n"))))) + ;;; Load other packages (defun ob-python-extras-load-gptel-integration () @@ -525,25 +595,5 @@ In regular org-mode, tries to view image or executes normal C-c C-c." (load (expand-file-name "ob-python-extras-alerts" this-dir)))) -;; TODO note there are also inline source code blocks? -(defun ob-python-extras-format-ruff () - (interactive) - (when (member 'org-src-mode local-minor-modes) - (let ((created-temp-file - (make-temp-file - (concat (file-name-as-directory (org-babel-temp-directory)) "ob-python-extras-format-ruff-") - nil - nil - (buffer-string)))) - (async-start-process "ruff" - "ruff" - (apply-partially 'ob-python-extras--format-ruff-callback created-temp-file (current-buffer)) - "format" created-temp-file)))) - -(defun ob-python-extras--format-ruff-callback (temp-file-name src-edit-buffer process-obj) - (message "formatted code: %s" temp-file-name) - (with-current-buffer src-edit-buffer - (insert-file-contents temp-file-name nil nil nil t))) - (provide 'ob-python-extras) ;;; ob-python-extras.el ends here From 2b25057a7dc95b13945cb843e7949533df52ef82 Mon Sep 17 00:00:00 2001 From: Nilay Kumar Date: Wed, 1 Jan 2025 09:44:32 -0800 Subject: [PATCH 3/8] Adding option for formatting, black or ruff Set the variable ob-python-extras-formatter to either "ruff" or "black". --- ob-python-extras.el | 54 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/ob-python-extras.el b/ob-python-extras.el index d3674c2..1cac660 100644 --- a/ob-python-extras.el +++ b/ob-python-extras.el @@ -519,9 +519,9 @@ In regular org-mode, tries to view image or executes normal C-c C-c." nil (buffer-string)))) (async-start-process "ob-python-extras-format-process" - "uvx" + "ruff" (apply-partially 'ob-python-extras-format-callback created-temp-file (current-buffer)) - "ruff" "format" created-temp-file)))) + "format" created-temp-file)))) (defun ob-python-extras-format-buffer-callback (temp-file-name src-edit-buffer process-obj) (with-current-buffer src-edit-buffer @@ -535,6 +535,15 @@ In regular org-mode, tries to view image or executes normal C-c C-c." (insert-file-contents temp-file-name nil nil nil t)) (message "Formatted org-src-block")) +(defun ob-python-extras-format () + (interactive) + ;; check first that the var is set + (if (boundp 'ob-python-extras-formatter) + (cond ((equal ob-python-extras-formatter "black") (ob-python-extras-format-black)) + ((equal ob-python-extras-formatter "ruff") (ob-python-extras-format-ruff)) + (t (message "No formatter %s found" ob-python-extras-formatter))) + (message "No formatter set in ob-python-extras-formatter"))) + ;; TODO check to make sure that it's a python source block (defun ob-python-extras-format-black () (interactive) @@ -567,17 +576,36 @@ In regular org-mode, tries to view image or executes normal C-c C-c." created-temp-file)) (message "Nothing to format")))) -;; start by using (org-src--contents-area (org-element-at-point)) -;; here's the trick for replacing the contents. -;; (if (version< emacs-version "27.1") -;; (progn (delete-region beg end) -;; (insert (with-current-buffer write-back-buf -;; (buffer-string)))) -;; (save-restriction -;; (narrow-to-region beg end) -;; (org-replace-buffer-contents write-back-buf 0.1 nil) -;; (goto-char (point-max)))) -;; (when (and expecting-bol (not (bolp))) (insert "\n"))))) +(defun ob-python-extras-format-ruff () + (interactive) + (if (org-src-edit-buffer-p) + (let ((created-temp-file + (make-temp-file + (concat (file-name-as-directory (org-babel-temp-directory)) "ob-python-extras-format-ruff-") + nil + nil + (buffer-string)))) + (async-start-process "ob-python-extras-format-process" + "ruff" + (apply-partially 'ob-python-extras-format-buffer-callback created-temp-file (current-buffer)) + "format" created-temp-file)) + ;; note that we place this in the else clause + ;; because org-in-src-block-p does not like running in org-src-edit-buffers + (if (org-in-src-block-p t) + (let* ((created-temp-file + (make-temp-file + (concat (file-name-as-directory (org-babel-temp-directory)) "ob-python-extras-format-ruff-") + nil + nil + (org-element-property :value (org-element-at-point)))) + (content-area (org-src--contents-area (org-element-at-point))) + (beg (car content-area)) + (end (cadr content-area))) + (async-start-process "ob-python-extras-format-process" + "ruff" + (apply-partially 'ob-python-extras-format-src-block-callback created-temp-file (current-buffer) beg end) + "format" created-temp-file)) + (message "Nothing to format")))) ;;; Load other packages From a7c4862d84cc31f3167422e0c3a27915be89b8b0 Mon Sep 17 00:00:00 2001 From: Nilay Kumar Date: Thu, 2 Jan 2025 22:41:25 -0800 Subject: [PATCH 4/8] Removing old code --- ob-python-extras.el | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/ob-python-extras.el b/ob-python-extras.el index 1cac660..9ebfbef 100644 --- a/ob-python-extras.el +++ b/ob-python-extras.el @@ -509,19 +509,6 @@ In regular org-mode, tries to view image or executes normal C-c C-c." (script-path (concat ob-python-extras-dir "bashscripts/convert_org_to_ipynb.sh" ))) (compile (concat "cd " current-dir " && "script-path))))) -(defun ob-python-extras-format-ruff () - (interactive) - (when (member 'org-src-mode local-minor-modes) - (let ((created-temp-file - (make-temp-file - (concat (file-name-as-directory (org-babel-temp-directory)) "ob-python-extras-format-ruff-") - nil - nil - (buffer-string)))) - (async-start-process "ob-python-extras-format-process" - "ruff" - (apply-partially 'ob-python-extras-format-callback created-temp-file (current-buffer)) - "format" created-temp-file)))) (defun ob-python-extras-format-buffer-callback (temp-file-name src-edit-buffer process-obj) (with-current-buffer src-edit-buffer From 7110f9df941dddd1af9a2ecbc53876d29b0bc53e Mon Sep 17 00:00:00 2001 From: Nilay Kumar Date: Fri, 3 Jan 2025 00:44:25 -0800 Subject: [PATCH 5/8] Refactor black+ruff, check if in python source --- ob-python-extras.el | 71 ++++++++++++++------------------------------- 1 file changed, 22 insertions(+), 49 deletions(-) diff --git a/ob-python-extras.el b/ob-python-extras.el index 9ebfbef..09827bd 100644 --- a/ob-python-extras.el +++ b/ob-python-extras.el @@ -523,31 +523,33 @@ In regular org-mode, tries to view image or executes normal C-c C-c." (message "Formatted org-src-block")) (defun ob-python-extras-format () + "Formats python code in an org-src-edit buffer or an org-src block. +The formatter uses either black or ruff according to the variable +ob-python-extras-formatter." (interactive) - ;; check first that the var is set (if (boundp 'ob-python-extras-formatter) - (cond ((equal ob-python-extras-formatter "black") (ob-python-extras-format-black)) - ((equal ob-python-extras-formatter "ruff") (ob-python-extras-format-ruff)) - (t (message "No formatter %s found" ob-python-extras-formatter))) + (if (member ob-python-extras-formatter (list "black" "ruff")) (ob-python-extras-dispatch-format) + (message "No formatter %s found" ob-python-extras-formatter)) (message "No formatter set in ob-python-extras-formatter"))) -;; TODO check to make sure that it's a python source block -(defun ob-python-extras-format-black () - (interactive) - (if (org-src-edit-buffer-p) +;; do we need to require/import something for async-start-process? +(defun ob-python-extras-dispatch-format () + (if (and (org-src-edit-buffer-p) (eq major-mode 'python-mode)) (let ((created-temp-file (make-temp-file (concat (file-name-as-directory (org-babel-temp-directory)) "ob-python-extras-format-black-") nil nil (buffer-string)))) - (async-start-process "ob-python-extras-format-process" - "black" - (apply-partially 'ob-python-extras-format-buffer-callback created-temp-file (current-buffer)) - created-temp-file)) + (apply #'async-start-process + "ob-python-extras-format-process" + ob-python-extras-formatter + (apply-partially 'ob-python-extras-format-buffer-callback created-temp-file (current-buffer)) + (cond ((equal ob-python-extras-formatter "black") created-temp-file) + ((equal ob-python-extras-formatter "ruff") (list "format" created-temp-file))))) ;; note that we place this in the else clause ;; because org-in-src-block-p does not like running in org-src-edit-buffers - (if (org-in-src-block-p t) + (if (and (org-in-src-block-p t) (equal (org-element-property :language (org-element-at-point)) "python")) (let* ((created-temp-file (make-temp-file (concat (file-name-as-directory (org-babel-temp-directory)) "ob-python-extras-format-black-") @@ -557,42 +559,13 @@ In regular org-mode, tries to view image or executes normal C-c C-c." (content-area (org-src--contents-area (org-element-at-point))) (beg (car content-area)) (end (cadr content-area))) - (async-start-process "ob-python-extras-format-process" - "black" - (apply-partially 'ob-python-extras-format-src-block-callback created-temp-file (current-buffer) beg end) - created-temp-file)) - (message "Nothing to format")))) - -(defun ob-python-extras-format-ruff () - (interactive) - (if (org-src-edit-buffer-p) - (let ((created-temp-file - (make-temp-file - (concat (file-name-as-directory (org-babel-temp-directory)) "ob-python-extras-format-ruff-") - nil - nil - (buffer-string)))) - (async-start-process "ob-python-extras-format-process" - "ruff" - (apply-partially 'ob-python-extras-format-buffer-callback created-temp-file (current-buffer)) - "format" created-temp-file)) - ;; note that we place this in the else clause - ;; because org-in-src-block-p does not like running in org-src-edit-buffers - (if (org-in-src-block-p t) - (let* ((created-temp-file - (make-temp-file - (concat (file-name-as-directory (org-babel-temp-directory)) "ob-python-extras-format-ruff-") - nil - nil - (org-element-property :value (org-element-at-point)))) - (content-area (org-src--contents-area (org-element-at-point))) - (beg (car content-area)) - (end (cadr content-area))) - (async-start-process "ob-python-extras-format-process" - "ruff" - (apply-partially 'ob-python-extras-format-src-block-callback created-temp-file (current-buffer) beg end) - "format" created-temp-file)) - (message "Nothing to format")))) + (apply #'async-start-process + "ob-python-extras-format-process" + ob-python-extras-formatter + (apply-partially 'ob-python-extras-format-src-block-callback created-temp-file (current-buffer) beg end) + (cond ((equal ob-python-extras-formatter "black") created-temp-file) + ((equal ob-python-extras-formatter "ruff") (list "format" created-temp-file))))) + (message "No python code to format")))) ;;; Load other packages From ac4db0c917507d5d5ab837caa0b6f0aa09596ed9 Mon Sep 17 00:00:00 2001 From: Nilay Kumar Date: Fri, 3 Jan 2025 19:18:55 -0800 Subject: [PATCH 6/8] Added documentation --- ob-python-extras.el | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/ob-python-extras.el b/ob-python-extras.el index 09827bd..88b1348 100644 --- a/ob-python-extras.el +++ b/ob-python-extras.el @@ -510,12 +510,18 @@ In regular org-mode, tries to view image or executes normal C-c C-c." (compile (concat "cd " current-dir " && "script-path))))) -(defun ob-python-extras-format-buffer-callback (temp-file-name src-edit-buffer process-obj) +(defun ob-python-extras--format-buffer-callback (temp-file-name src-edit-buffer _process-obj) + "Callback function to replace buffer contents with formatted code. +Reads formatted code from TEMP-FILE-NAME and replaces the contents of +SRC-EDIT-BUFFER with it." (with-current-buffer src-edit-buffer (insert-file-contents temp-file-name nil nil nil t)) (message "Formatted org-src-edit-buffer")) -(defun ob-python-extras-format-src-block-callback (temp-file-name src-block-buffer beg end process-obj) +(defun ob-python-extras--format-src-block-callback (temp-file-name src-block-buffer beg end _process-obj) + "Callback function to replace org source block contents with formatted code. +Reads formatted code from TEMP-FILE-NAME and replaces the contents of +an org source block located between BEG and END in SRC-BLOCK-BUFFER with it." (set-buffer src-block-buffer) (save-restriction (narrow-to-region beg end) @@ -523,28 +529,39 @@ In regular org-mode, tries to view image or executes normal C-c C-c." (message "Formatted org-src-block")) (defun ob-python-extras-format () - "Formats python code in an org-src-edit buffer or an org-src block. + "Asynchronously format python code in org code blocks. The formatter uses either black or ruff according to the variable ob-python-extras-formatter." (interactive) (if (boundp 'ob-python-extras-formatter) - (if (member ob-python-extras-formatter (list "black" "ruff")) (ob-python-extras-dispatch-format) + (if (member ob-python-extras-formatter (list "black" "ruff")) (ob-python-extras--dispatch-format) (message "No formatter %s found" ob-python-extras-formatter)) (message "No formatter set in ob-python-extras-formatter"))) -;; do we need to require/import something for async-start-process? -(defun ob-python-extras-dispatch-format () +(defun ob-python-extras--dispatch-format () + "Asynchronously format python code in org code blocks. +If the context is an `org-src-edit-buffer' for python code (opened with, for +example, \\[org-edit-special]), copy the buffer contents into a temporary +file, asynchronously execute the formatter, and replace the buffer contents +with the formatted code. If the context is an org source block, do the same, +but using `org-element-at-point' and `org-src--contents-area' to copy and +replace the code. + +The formatter uses either black or ruff according to the variable +ob-python-extras-formatter." (if (and (org-src-edit-buffer-p) (eq major-mode 'python-mode)) (let ((created-temp-file (make-temp-file - (concat (file-name-as-directory (org-babel-temp-directory)) "ob-python-extras-format-black-") + (concat (file-name-as-directory (org-babel-temp-directory)) "ob-python-extras-format") nil nil + ;; the org-src-edit-buffer contents are precisely the code (buffer-string)))) (apply #'async-start-process "ob-python-extras-format-process" ob-python-extras-formatter - (apply-partially 'ob-python-extras-format-buffer-callback created-temp-file (current-buffer)) + (apply-partially 'ob-python-extras--format-buffer-callback created-temp-file (current-buffer)) + ;; note that ruff takes "format" as its first argument (cond ((equal ob-python-extras-formatter "black") created-temp-file) ((equal ob-python-extras-formatter "ruff") (list "format" created-temp-file))))) ;; note that we place this in the else clause @@ -552,9 +569,10 @@ ob-python-extras-formatter." (if (and (org-in-src-block-p t) (equal (org-element-property :language (org-element-at-point)) "python")) (let* ((created-temp-file (make-temp-file - (concat (file-name-as-directory (org-babel-temp-directory)) "ob-python-extras-format-black-") + (concat (file-name-as-directory (org-babel-temp-directory)) "ob-python-extras-format") nil nil + ;; get the contents of the source block (org-element-property :value (org-element-at-point)))) (content-area (org-src--contents-area (org-element-at-point))) (beg (car content-area)) @@ -562,7 +580,8 @@ ob-python-extras-formatter." (apply #'async-start-process "ob-python-extras-format-process" ob-python-extras-formatter - (apply-partially 'ob-python-extras-format-src-block-callback created-temp-file (current-buffer) beg end) + (apply-partially 'ob-python-extras--format-src-block-callback created-temp-file (current-buffer) beg end) + ;; note that ruff takes "format" as its first argument (cond ((equal ob-python-extras-formatter "black") created-temp-file) ((equal ob-python-extras-formatter "ruff") (list "format" created-temp-file))))) (message "No python code to format")))) From 45badc7c65fb188ce2f01be3055b613cd7ce10ef Mon Sep 17 00:00:00 2001 From: Nilay Kumar Date: Fri, 10 Jan 2025 23:46:00 -0500 Subject: [PATCH 7/8] Refactored and added configuration file support --- Readme.org | 23 +++++-- ob-python-extras.el | 143 +++++++++++++++++++++++++------------------- 2 files changed, 100 insertions(+), 66 deletions(-) diff --git a/Readme.org b/Readme.org index d7f37c4..631f5f2 100644 --- a/Readme.org +++ b/Readme.org @@ -142,11 +142,26 @@ Then blocks will be sent automatically when a traceback is detected in the respo #+end_src ** Matplotlib image transparency + Matplotlib is configured to save and display images without transparency by -default. The default can be changed with ~(setq -ob-python-extras/transparent-images t)~. This default, in turn, can be -overridden at the org-src-block level with =:transparent nil= or =:transparent -t=. +default. The default can be changed with =(setq ob-python-extras/transparent-images t)=. +This default, in turn, can be overridden at the org-src-block level with +=:transparent nil= or =:transparent t=. + +** Setting up code formatting + +The code formatters =ruff= and =black= are supported. Set the variable +=ob-python-extras-formatter= to "ruff" or "black" and then execute =M-x +ob-python-extras-format= when in a python code block (or source edit buffer). +The formatter searches for its configuration options as usual, with the search +path starting at the directory containing the org file. The default +configurations can be overridden by specifying the file in the variable +=ob-python-extras-formatter-config=. + +To format code automatically upon execution of source code blocks, add a hook: +#+begin_src emacs-lisp +(add-hook 'org-babel-after-execute-hook 'ob-python-extras-format) +#+end_src * Examples: [[file:tests/babel-formatting.org][See this org file for examples of the different functionality and configurations.]] diff --git a/ob-python-extras.el b/ob-python-extras.el index 88b1348..59c6d45 100644 --- a/ob-python-extras.el +++ b/ob-python-extras.el @@ -509,83 +509,102 @@ In regular org-mode, tries to view image or executes normal C-c C-c." (script-path (concat ob-python-extras-dir "bashscripts/convert_org_to_ipynb.sh" ))) (compile (concat "cd " current-dir " && "script-path))))) +(defun ob-python-extras-format () + "Asynchronously format python code in org code blocks. +The formatter uses either black or ruff according to the variable +ob-python-extras-formatter." + (interactive) + (if (boundp 'ob-python-extras-formatter) + ;; make sure that the specified formatter is supported + (if (member ob-python-extras-formatter (list "black" "ruff")) + ;; org-src-edit buffer + (if (and (org-src-edit-buffer-p) (eq major-mode 'python-mode)) + (ob-python-extras--format-buffer) + ;; org source block + (if (and (org-in-src-block-p t) (equal (org-element-property :language (org-element-at-point)) "python")) + (ob-python-extras--format-block) + ;; neither + (message "No python code to format"))) + (message "No formatter %s found" ob-python-extras-formatter)) + (message "No formatter set in ob-python-extras-formatter"))) + +(defun ob-python-extras--format-buffer () + "Asynchronously format python code in org-src-edit buffers. +Copies the buffer contents into a temporary file, asynchronously +execute the formatter, and replace the buffer contents with the +formatted code. + +The formatter uses either black or ruff according to the variable +ob-python-extras-formatter." + (let* ((code-to-format (buffer-string)) + (temp-file + (make-temp-file + (concat (file-name-directory org-src-source-file-name) ".ob-python-extras-format") + nil nil code-to-format))) + (apply #'async-start-process + "ob-python-extras-format-process" + ob-python-extras-formatter + (apply-partially 'ob-python-extras--format-buffer-callback temp-file (current-buffer)) + (ob-python-extras--get-formatter-args temp-file)))) + +(defun ob-python-extras--format-block () + "Asynchronously format python code in org code blocks. +Copies the code block contents into a temporary file, +asynchronously execute the formatter, and replace the code block +contents with the formatted code. + +The formatter uses either black or ruff according to the variable +ob-python-extras-formatter." + (let* ((code-to-format (org-element-property :value (org-element-at-point))) + (temp-file + (make-temp-file + (concat (file-name-directory (buffer-file-name)) ".ob-python-extras-format") + nil nil code-to-format)) + (content-area (org-src--contents-area (org-element-at-point))) + (beg (car content-area)) + (end (cadr content-area))) + (message "LOG: %s" (ob-python-extras--get-formatter-args temp-file)) + (apply #'async-start-process + "ob-python-extras-format-process" + ob-python-extras-formatter + (apply-partially 'ob-python-extras--format-src-block-callback temp-file (current-buffer) beg end) + (ob-python-extras--get-formatter-args temp-file)))) + +(defun ob-python-extras--get-formatter-args (temp-file-name) + "Set up command-line arguments for the formatter. +The file TEMP-FILE-NAME is specified to be formatted." + (cl-remove-if #'null + (list + (when (equal ob-python-extras-formatter "ruff") "format") + temp-file-name + (when (boundp 'ob-python-extras-formatter-config) "--config") + (when (boundp 'ob-python-extras-formatter-config) + (expand-file-name ob-python-extras-formatter-config))))) (defun ob-python-extras--format-buffer-callback (temp-file-name src-edit-buffer _process-obj) "Callback function to replace buffer contents with formatted code. -Reads formatted code from TEMP-FILE-NAME and replaces the contents of -SRC-EDIT-BUFFER with it." +Reads formatted code from TEMP-FILE-NAME and replaces the +contents of SRC-EDIT-BUFFER with it. Finally, deletes +TEMP-FILE-NAME." (with-current-buffer src-edit-buffer (insert-file-contents temp-file-name nil nil nil t)) + (when (file-exists-p temp-file-name) + (delete-file temp-file-name)) (message "Formatted org-src-edit-buffer")) (defun ob-python-extras--format-src-block-callback (temp-file-name src-block-buffer beg end _process-obj) "Callback function to replace org source block contents with formatted code. -Reads formatted code from TEMP-FILE-NAME and replaces the contents of -an org source block located between BEG and END in SRC-BLOCK-BUFFER with it." +Reads formatted code from TEMP-FILE-NAME and replaces the +contents of an org source block located between BEG and END in +SRC-BLOCK-BUFFER with it. Finally, deletes TEMP-FILE-NAME." (set-buffer src-block-buffer) (save-restriction (narrow-to-region beg end) (insert-file-contents temp-file-name nil nil nil t)) + (when (file-exists-p temp-file-name) + (delete-file temp-file-name)) (message "Formatted org-src-block")) -(defun ob-python-extras-format () - "Asynchronously format python code in org code blocks. -The formatter uses either black or ruff according to the variable -ob-python-extras-formatter." - (interactive) - (if (boundp 'ob-python-extras-formatter) - (if (member ob-python-extras-formatter (list "black" "ruff")) (ob-python-extras--dispatch-format) - (message "No formatter %s found" ob-python-extras-formatter)) - (message "No formatter set in ob-python-extras-formatter"))) - -(defun ob-python-extras--dispatch-format () - "Asynchronously format python code in org code blocks. -If the context is an `org-src-edit-buffer' for python code (opened with, for -example, \\[org-edit-special]), copy the buffer contents into a temporary -file, asynchronously execute the formatter, and replace the buffer contents -with the formatted code. If the context is an org source block, do the same, -but using `org-element-at-point' and `org-src--contents-area' to copy and -replace the code. - -The formatter uses either black or ruff according to the variable -ob-python-extras-formatter." - (if (and (org-src-edit-buffer-p) (eq major-mode 'python-mode)) - (let ((created-temp-file - (make-temp-file - (concat (file-name-as-directory (org-babel-temp-directory)) "ob-python-extras-format") - nil - nil - ;; the org-src-edit-buffer contents are precisely the code - (buffer-string)))) - (apply #'async-start-process - "ob-python-extras-format-process" - ob-python-extras-formatter - (apply-partially 'ob-python-extras--format-buffer-callback created-temp-file (current-buffer)) - ;; note that ruff takes "format" as its first argument - (cond ((equal ob-python-extras-formatter "black") created-temp-file) - ((equal ob-python-extras-formatter "ruff") (list "format" created-temp-file))))) - ;; note that we place this in the else clause - ;; because org-in-src-block-p does not like running in org-src-edit-buffers - (if (and (org-in-src-block-p t) (equal (org-element-property :language (org-element-at-point)) "python")) - (let* ((created-temp-file - (make-temp-file - (concat (file-name-as-directory (org-babel-temp-directory)) "ob-python-extras-format") - nil - nil - ;; get the contents of the source block - (org-element-property :value (org-element-at-point)))) - (content-area (org-src--contents-area (org-element-at-point))) - (beg (car content-area)) - (end (cadr content-area))) - (apply #'async-start-process - "ob-python-extras-format-process" - ob-python-extras-formatter - (apply-partially 'ob-python-extras--format-src-block-callback created-temp-file (current-buffer) beg end) - ;; note that ruff takes "format" as its first argument - (cond ((equal ob-python-extras-formatter "black") created-temp-file) - ((equal ob-python-extras-formatter "ruff") (list "format" created-temp-file))))) - (message "No python code to format")))) - ;;; Load other packages (defun ob-python-extras-load-gptel-integration () From dd5dca1bcc1cddf9ee9230fe17b7cb436393ac70 Mon Sep 17 00:00:00 2001 From: Nilay Kumar Date: Sat, 11 Jan 2025 00:14:50 -0500 Subject: [PATCH 8/8] Inhibit messages when formatting --- Readme.org | 4 ++-- ob-python-extras.el | 15 +++++++-------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Readme.org b/Readme.org index 631f5f2..cd401c1 100644 --- a/Readme.org +++ b/Readme.org @@ -151,8 +151,8 @@ This default, in turn, can be overridden at the org-src-block level with ** Setting up code formatting The code formatters =ruff= and =black= are supported. Set the variable -=ob-python-extras-formatter= to "ruff" or "black" and then execute =M-x -ob-python-extras-format= when in a python code block (or source edit buffer). +=ob-python-extras-formatter= to "ruff" or "black" and then execute +=M-x ob-python-extras-format= when in a python code block (or source edit buffer). The formatter searches for its configuration options as usual, with the search path starting at the directory containing the org file. The default configurations can be overridden by specifying the file in the variable diff --git a/ob-python-extras.el b/ob-python-extras.el index 59c6d45..50cce49 100644 --- a/ob-python-extras.el +++ b/ob-python-extras.el @@ -557,13 +557,14 @@ The formatter uses either black or ruff according to the variable ob-python-extras-formatter." (let* ((code-to-format (org-element-property :value (org-element-at-point))) (temp-file - (make-temp-file - (concat (file-name-directory (buffer-file-name)) ".ob-python-extras-format") - nil nil code-to-format)) + (let ((inhibit-message t) + (message-log-max nil)) + (make-temp-file + (concat (file-name-directory (buffer-file-name)) ".ob-python-extras-format") + nil nil code-to-format))) (content-area (org-src--contents-area (org-element-at-point))) (beg (car content-area)) (end (cadr content-area))) - (message "LOG: %s" (ob-python-extras--get-formatter-args temp-file)) (apply #'async-start-process "ob-python-extras-format-process" ob-python-extras-formatter @@ -589,8 +590,7 @@ TEMP-FILE-NAME." (with-current-buffer src-edit-buffer (insert-file-contents temp-file-name nil nil nil t)) (when (file-exists-p temp-file-name) - (delete-file temp-file-name)) - (message "Formatted org-src-edit-buffer")) + (delete-file temp-file-name))) (defun ob-python-extras--format-src-block-callback (temp-file-name src-block-buffer beg end _process-obj) "Callback function to replace org source block contents with formatted code. @@ -602,8 +602,7 @@ SRC-BLOCK-BUFFER with it. Finally, deletes TEMP-FILE-NAME." (narrow-to-region beg end) (insert-file-contents temp-file-name nil nil nil t)) (when (file-exists-p temp-file-name) - (delete-file temp-file-name)) - (message "Formatted org-src-block")) + (delete-file temp-file-name))) ;;; Load other packages