Last active
February 1, 2024 11:44
-
-
Save fast-90/3d7ce3252fff59b0f6d6d1bcadcf4938 to your computer and use it in GitHub Desktop.
My setup for Quarto in Emacs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(use-package python | |
:init | |
(defun python-comint-filter (output) | |
"Filter out '__PYTHON_EL_' when sending region to inferior Python shell. | |
See also: https://stackoverflow.com/questions/75103221/emacs-remove-python-el-eval-message" | |
(let* ((regexp "^.*__PYTHON_EL_\\(.*\\)\\(.*\\)[[:space:]]*$") | |
(lines (split-string output "\n")) | |
(filtered-lines (cl-remove-if (lambda (line) | |
(or (string-match-p regexp line) | |
(string-match-p "^\\s-*$" line))) | |
lines))) | |
(if (equal (length lines) (length filtered-lines)) | |
output | |
(mapconcat 'identity filtered-lines "\n")))) | |
:hook | |
(comint-preoutput-filter-functions . python-comint-filter) | |
:custom | |
(python-indent-guess-indent-offset-verbose nil) | |
(python-shell-completion-native-enable nil)) | |
(use-package pyvenv | |
:init | |
(pyvenv-mode t)) | |
(use-package pet | |
:hook | |
(python-base-mode-hook . dn/python-pet-hook) | |
:init | |
(defun dn/python-pet-hook () | |
"Activate pet mode, and set the local variables to identify the correct executables." | |
(pet-mode) | |
(setq-local pyvenv-activate (pet-virtualenv-root)) | |
(setq-local python-shell-interpreter (pet-executable-find "python")) | |
(setq-local python-shell-interpreter-args "-i") | |
(when-let ((black-executable (pet-executable-find "black"))) | |
(setq-local python-black-command black-executable)))) | |
(use-package quarto-mode | |
:init | |
;; (defvar dn/quarto-preview-port nil | |
;; "Port which was last used for `dn/quarto-preview'.") | |
(defun dn/quarto-preview () | |
"Start quarto preview process via shell command." | |
(interactive) | |
;; (setq dn/quarto-preview-port (number-to-string (+ 3000 (random 5000)))) | |
(let ((shell-command-switch "-ic")) | |
(start-process-shell-command | |
"quarto-preview" | |
"*quarto-preview*" | |
(concat "quarto preview " buffer-file-name " --no-browser")) | |
) | |
(with-current-buffer (process-buffer (get-process "quarto-preview")) | |
(display-buffer (current-buffer)))) | |
(defun dn/quarto-preview-xwidget () | |
"Open the preview file with xwidget-webkit." | |
(interactive) | |
(if (get-process "quarto-preview") | |
(let ((previous-buffer (buffer-name)) | |
(port (with-current-buffer (process-buffer (get-process "quarto-preview")) | |
(goto-char (point-max)) | |
(search-backward-regexp "\\(Browse at.*\\)\\(localhost:\\)\\([0-9]\\{4\\}\\)" nil nil) | |
(match-string 3)))) | |
(xwidget-webkit-browse-url (concat "http://localhost:" port)) | |
(switch-to-buffer-other-window previous-buffer)) | |
(message "No preview server running! Run M-x dn/quarto-preview first."))) | |
(defun poly-python-eval-region (beg end msg) | |
(python-shell-send-region beg end nil msg t)) | |
(defun poly-python-mode-setup () | |
(setq-local polymode-eval-region-function #'poly-python-eval-region)) | |
(defun dn/quarto-insert-python-code-blocks (count) | |
"Inserts `count` number of Python code blocks starting from the line below the cursor." | |
(interactive "nEnter the number of Python code blocks to insert: ") | |
(save-excursion | |
(forward-line) ; Move to the line below the cursor | |
(dotimes (_ count) | |
(insert "```{python}\n\n```\n\n") | |
(forward-line 3))) | |
(forward-line)) | |
(defun dn/quarto-next-block () | |
"Move the cursor to the beginning of the line under the next code block." | |
(interactive) | |
(goto-char (line-beginning-position)) | |
(search-forward-regexp "^```{.*}$" nil t) | |
(forward-line)) | |
(defun dn/quarto-previous-block () | |
"Move the cursor to the beginning of the line under the next code block." | |
(interactive) | |
(search-backward-regexp "^```$" nil t) | |
(previous-line) | |
(search-backward "```{" nil t) | |
(forward-line)) | |
(defun dn/quarto-eval-block () | |
"Evaluate current code block. | |
If cursor is not in a code block, evaluate the previous code block." | |
(interactive) | |
(let* ((current (save-excursion (point))) | |
(beg (save-excursion | |
(search-backward-regexp "^```{.*}" nil t) | |
(forward-line) | |
(point))) | |
(end (save-excursion | |
(goto-char beg) | |
(search-forward-regexp "```$" nil t) | |
(previous-line)(end-of-line) | |
(point)))) | |
;; Don't send to Python shell if the block is empty. | |
(unless (eq beg end) | |
(push-mark beg) | |
(goto-char end) | |
(activate-mark) | |
(elpy-shell-send-region-or-buffer-and-step) | |
(deactivate-mark) | |
(goto-char current)))) | |
(defun dn/quarto-eval-blocks-below () | |
"Evaluate all blocks below point." | |
(interactive) | |
(let ((current (save-excursion (point)))) | |
(while (progn | |
(dn/quarto-next-block) | |
(dn/quarto-eval-block) | |
(search-forward-regexp "^```{.*?}$" nil t))) | |
(goto-char current))) | |
(defun dn/quarto-eval-all-blocks () | |
"Evaluate all blocks in notebook." | |
(interactive) | |
(let ((current (save-excursion (point)))) | |
(goto-char (point-min)) | |
(dn/quarto-eval-blocks-below) | |
(goto-char current))) | |
(defhydra dn/quarto-block-hydra () | |
"Code blocks" | |
("n" dn/quarto-next-block "Next block") | |
("p" dn/quarto-previous-block "Previous block") | |
("e" dn/quarto-eval-block "Evaluate block") | |
("E" (lambda() (interactive) (dn/quarto-eval-block) (dn/quarto-next-block)) "Eval and next") | |
("a" dn/quarto-eval-blocks-below "Eval blocks below") | |
("A" dn/quarto-eval-all-blocks "Eval notebook")) | |
:hook | |
(python-base-mode-hook . poly-python-mode-setup) | |
:bind (:map dn/prog-map | |
("o" . dn/quarto-block-hydra/body))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment