From 9c413aaa386cd10a26975384d8fe7f04e4b6ce48 Mon Sep 17 00:00:00 2001 From: Alexander Rosenberg Date: Sat, 8 Feb 2025 00:09:42 -0800 Subject: [PATCH] Add jupyter stuff --- init.el | 173 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) diff --git a/init.el b/init.el index 618d255..ddc3de1 100644 --- a/init.el +++ b/init.el @@ -2020,6 +2020,179 @@ line in the block and manually deal with indentation." (apply oldfun r))) (advice-add 'hyperspec-lookup :around #'my/-hyperspec-loopup-in-eww)) +;; jupyter +(use-package jupyter + :hook (jupyter-repl-mode . my/-setup-jupyter-mode) + :config + (defun company-doc-buffer (&optional string) + "Emulate company's `company-doc-buffer'." + (with-current-buffer (get-buffer-create "*company-documentation*") + (erase-buffer) + (fundamental-mode) + (when string + (save-excursion + (insert string) + (visual-line-mode))) + (current-buffer))) + (defun my/-jupyter-dont-use-ts-modes (retval) + "Prevent `jupyter-kernel-language-mode-properties' from selecting TS modes." + (cl-destructuring-bind (mode syntax-table) retval + (if-let (((string-suffix-p "-ts-mode" (symbol-name mode))) + (non-ts (car (rassq mode major-mode-remap-alist))) + ((not (string-suffix-p "-ts-mode" (symbol-name non-ts))))) + (list non-ts + (if-let ((table-sym (intern-soft (format "%s-syntax-table" + non-ts)))) + (symbol-value table-sym) + syntax-table)) + retval))) + (advice-add 'jupyter-kernel-language-mode-properties + :filter-return #'my/-jupyter-dont-use-ts-modes) + (defun my/-jupyter-kick-use-back-to-cell () + "Kick the point out of the invisible read only area at the start of cells." + (let ((props (text-properties-at (point)))) + (when (and (plist-get props 'invisible) + (plist-get props 'read-only)) + (forward-char)))) + (defun my/-setup-jupyter-mode () + "Setup `jupyter-repl-mode'." + (display-line-numbers-mode -1) + (add-hook 'post-command-hook #'my/-jupyter-kick-use-back-to-cell + nil t)) + (cl-defmethod jupyter-indent-line (&context (jupyter-lang c++)) + (let ((res (syntax-ppss (pos-bol)))) + ;; no paren depth + (if (zerop (cl-first res)) + (save-excursion + (back-to-indentation) + (delete-region (pos-bol) (point))) + (indent-for-tab-command))))) + +;; C/C++ and jupyter +(defvar my/jupyter-extra-language-associations + '((c . c++))) + +(defun my/-find-jupyter-buffer-for-lang (lang) + "Find a Jupyter buffer supporint LANG." + (let ((res (cl-find-if (lambda (buf) + (with-current-buffer buf + (and (derived-mode-p 'jupyter-repl-mode) + jupyter-current-client + (eq lang (jupyter-kernel-language + jupyter-current-client))))) + (buffer-list)))) + (when-let (((not res)) + (real (alist-get lang my/jupyter-extra-language-associations))) + (setq res (my/-find-jupyter-buffer-for-lang real))) + res)) + +(defun my/-jupyter-buffer-for-major-mode (&optional mode) + "Return a Jupyter buffer that can evaluate the code MODE is editing. +MODE defaults to `major-mode'." + (when-let ((name (symbol-name (or mode major-mode))) + ((string-match (rx bos (group (+? any)) (? "-ts") "-mode" eos) + name)) + (sym (intern-soft (match-string 1 name)))) + (my/-find-jupyter-buffer-for-lang sym))) + +(defun my/-jupyter-find-proper-buffer () + "Find the buffer for `my/jupyter-eval-in-proper-buffer'." + (if (and (derived-mode-p 'jupyter-repl-mode) + jupyter-current-client) + (current-buffer) + (my/-jupyter-buffer-for-major-mode major-mode))) + +(defun my/jupyter-eval-in-proper-buffer (code &optional no-error) + "Eval CODE a buffer suitable for `major-mode'. +If NO-ERROR is non-nil, signal an error if a buffer fails to be found. If the +current buffer is a Jupyter buffer, just use that." + (interactive (list (if-let ((buffer (my/-jupyter-find-proper-buffer))) + (with-current-buffer buffer + (jupyter-read-expression)) + (user-error "No Jupyter buffer found for mode: %s" + major-mode)))) + (if-let ((buffer (my/-jupyter-find-proper-buffer))) + (with-current-buffer buffer + (goto-char (point-max)) + (let ((cur (jupyter-repl-cell-code))) + (jupyter-repl-clear-input) + (insert code) + (jupyter-repl-ret t) + (goto-char (point-max)) + (insert cur))) + (unless no-error (user-error "No Jupyter buffer found for mode: %s" + major-mode)))) + +(defun my/c++-ts-jupyter-eval-defun () + "Eval the defun under point by sending it to a Jupyter repl." + (interactive) + (if-let ((code (thing-at-point 'defun))) + (progn + (my/jupyter-eval-in-proper-buffer code) + (message "Evaluated defun")) + (user-error "Nothing to evaluate under point"))) + +(defun my/c++-ts-jupyter-eval-expression () + "Eval the expression under point by sending it to a Jupyter repl." + (interactive) + (save-excursion + (let ((start (point))) + (back-to-indentation) + (unless (> (point) start) + (goto-char start))) + (if-let + ((root (treesit-buffer-root-node)) + (res (car (or (treesit-query-range + root + '([(expression_statement) (call_expression) + (declaration)] + @exp) + (point) (1+ (point))) + (treesit-query-range + root + '([(binary_expression) (update_expression)] @exp) + (point) (1+ (point))) + (treesit-query-range + root + '((return_statement (_) @exp)) + (point) (1+ (point)))))) + (code (buffer-substring-no-properties (car res) (cdr res)))) + (progn + (when (string-suffix-p ";" code) + (setq code (substring code 0 (1- (length code))))) + (my/jupyter-eval-in-proper-buffer code) + (message "Evaluated: %s" code)) + (user-error "Nothing to evaluate under point")))) + +(defun my/c++-ts-jupyter-eval-region () + "Eval the region by sending it to a Jupyter repl." + (interactive) + (if mark-active + (let ((code (buffer-substring-no-properties (region-beginning) + (region-end)))) + (when (string-suffix-p ";" code) + (setq code (substring code 0 (1- (length code))))) + (my/jupyter-eval-in-proper-buffer code) + (message "Evaluated region")) + (user-error "No active region"))) + +(defun my/c++-ts-jupyter-eval-buffer () + "Eval the current buffer by sending it to a Jupyter repl." + (interactive) + (my/jupyter-eval-in-proper-buffer (buffer-substring-no-properties + (point-min) (point-max))) + (message "Evaluated buffer")) + +(with-eval-after-load 'c-ts-mode + (keymap-set c-ts-base-mode-map + "C-M-x" #'my/c++-ts-jupyter-eval-defun) + (keymap-set c-ts-base-mode-map + "C-c C-e" #'my/c++-ts-jupyter-eval-expression) + (keymap-set c-ts-base-mode-map + "C-c C-r" #'my/c++-ts-jupyter-eval-region) + (keymap-set c-ts-base-mode-map + "C-c C-b" #'my/c++-ts-jupyter-eval-buffer)) + ;; pdf-tools (use-package pdf-tools :hook (pdf-view-mode . my/setup-pdf-view-mode)