[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/code-cells 37dce1d908 02/36: Add existing code
From: |
ELPA Syncer |
Subject: |
[elpa] externals/code-cells 37dce1d908 02/36: Add existing code |
Date: |
Mon, 28 Feb 2022 15:57:41 -0500 (EST) |
branch: externals/code-cells
commit 37dce1d908abbc8a6dada9e20fafc2cb80990f39
Author: Augusto Stoffel <astoff@users.noreply.github.com>
Commit: Augusto Stoffel <astoff@users.noreply.github.com>
Add existing code
---
README.md | 109 ++++++++++++++++++++++++++++++++++++++++++
cells.el | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 269 insertions(+)
diff --git a/README.md b/README.md
new file mode 100644
index 0000000000..0ebc7b12d8
--- /dev/null
+++ b/README.md
@@ -0,0 +1,109 @@
+cells.el
+========
+
+This package lets you efficiently navigate, edit and execute code
+split into cells according to certain magic comments. Such files can
+be obtained, for instance, by converting a Jupyter notebook to a
+script in the web interface or with
+
+``` shell
+jupyter nbconvert --to script <FILE.ipynb>
+```
+
+It's also worth mentioning [jupytext] and [ipynb-py-convert], which
+can convert to and from notebook format.
+
+Instead of defining every conceivable command relevant to code with
+cells, this package provides a simple way to turn ordinary editing
+commands into “cell-aware” ones. The `cells-command` function takes
+as argument a function that acts a region, and returns an anonymous
+command that acts on the current cell. Thus, one can redefine `C-c
+C-c` in Python mode to evaluate the current cell by doing the
+following:
+
+``` elisp
+(define-key
+ python-mode-map
+ (kbd "C-c C-c")
+ (cells-command 'python-shell-send-region))
+```
+
+See below for a more substantial configuration example, which is
+specifically for Jupyter mode but can be easily adapted to any other
+mode or language with a REPL in Emacs.
+
+Also available in this package are the following; see the
+documentation for more details.
+
+- `cells-do`: a macro that makes the current cells bounds accessible
+ as variables.
+- `cells-mark-cell`: mark current cell and activate region
+- `cells-mode`: for now, just adds font locking to the cell
+ boundaries. Also provides a keymap where one can add any desired
+ cell-related commands.
+
+Keybindings for [emacs-jupyter]
+-------------------------------
+
+The following configuration snippet sets up cell navigation and
+evaluation functions on buffers associated to a Jupyter kernel:
+
+- Navigate cells with `M-p` and `M-n`.
+- Mark, copy and kill cells by prefixing the usual command with `C-c`.
+- Evaluate a cell with `C-c C-c`, but acts on region instead if it's
+ active.
+
+``` elisp
+(with-eval-after-load "jupyter-repl"
+ (require 'cells)
+ (let ((map jupyter-repl-interaction-mode-map))
+ (define-key map (kbd "M-p") 'cells-backward-cell)
+ (define-key map (kbd "M-n") 'cells-forward-cell)
+ (define-key map (kbd "C-c C-SPC") 'cells-mark-cell)
+ (define-key map (kbd "C-c C-w") (cells-command 'kill-region :use-region))
+ (define-key map (kbd "C-c M-w") (cells-command 'kill-ring-save
:use-region))
+ (define-key map (kbd "C-c C-c") (cells-command 'jupyter-eval-region
:use-region :pulse))))
+```
+
+A hydra for [emacs-jupyter]
+---------------------------
+
+The following defines a handy [hydra] for Jupyter mode. Activate it
+with `M-x notebook-hydra/body RET` or bind that command to a key in
+`jupyter-repl-interaction-mode-map`.
+
+``` elisp
+(defhydra notebook-hydra (:color red :hint nil)
+ "
+_j_/_k_: ↓/↑, _h_ome, _l_ast, _q_uit \
+Cell: _e_val, mark and e_x_ecute \
+Kernel: _r_estart, eval _a_bove, _z_: pop to
+"
+ ("h" beginning-of-buffer)
+ ("l" (progn (end-of-buffer)
+ (cells-backward-cell)))
+ ("j" cells-forward-cell)
+ ("k" cells-backward-cell)
+ ("z" jupyter-repl-pop-to-buffer :color blue)
+ ("x" (progn (cells-mark-cell)
+ (call-interactively 'execute-extended-command)))
+ ("SPC" cells-mark-cell)
+ ("r" jupyter-repl-restart-kernel)
+ ("a" (cells-do (pulse-momentary-highlight-region (point-min) beg)
+ (jupyter-eval-region (point-min) beg)))
+ ("e" (cells-do (pulse-momentary-highlight-region beg end)
+ (jupyter-eval-region beg end)
+ (cells-forward-cell)))
+ ("M-w" (cells-do (kill-ring-save beg end)))
+ ("C-w" (cells-do (kill-region beg end)))
+ ("q" nil :exit t))
+```
+
+The head `x` asks for a command like `M-x`, and executes it with the
+current cell as active region. Thus, for instance, typing `x
+comment-dwim RET` in this hydra will comment out the current cell.
+
+[jupytext]: https://github.com/mwouts/jupytext
+[ipynb-py-convert]: https://github.com/kiwi0fruit/ipynb-py-convert/
+[emacs-jupyter]: https://github.com/dzop/emacs-jupyter
+[hydra]: https://github.com/abo-abo/hydra
diff --git a/cells.el b/cells.el
new file mode 100644
index 0000000000..6ab06639ee
--- /dev/null
+++ b/cells.el
@@ -0,0 +1,160 @@
+;;; cells.el --- Utilities for code split into cells -*- lexical-binding: t;
-*-
+
+;; Copyright (C) 2020 Augusto Stoffel
+
+;; Version: 0.0
+;; Author: Augusto Stoffel <arstoffel@gmail.com>
+;; Maintainer: Augusto Stoffel <arstoffel@gmail.com>
+;; URL: https://github.com/astoff/cells.el
+;; Keywords: convenience, cells
+;; Package-Requires: ((emacs "26.1"))
+
+;; 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.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This package lets you efficiently navigate, edit and execute code
+;; split into cells according to certain magic comments. Such files
+;; can be obtained, for instance, by exporting a Jupyter notebook to a
+;; script.
+;;
+;; The simplest entry point of the package is the `cells-command'
+;; function. It takes as argument a command that can act on a region,
+;; and returns an anonymous command that acts on the current cell.
+;; Thus, one can redefine C-c C-c in Python mode to evaluate the
+;; current cell by doing the following:
+;;
+;; (define-key
+;; python-mode-map
+;; (kbd "C-c C-c")
+;; (cells-command 'python-shell-send-region))
+;;
+;; See the README for more examples, including a ready-to-use setup
+;; for Jupyter and a handy hydra.
+
+;;; Code:
+
+(require 'pulse)
+(require 'rx)
+
+(defgroup cells nil
+ "Utilities for code split into cells."
+ :group 'convenience
+ :prefix "cells-")
+
+(defcustom cells-cell-markers
+ '("%%"
+ (regexp "In\\s-*\\[.*?\\]"))
+ "A list of regular expressions in sexp form (see `rx').
+Each of regexp should match the content of a comment line which
+introduces a cell break."
+ :type '(repeat sexp))
+
+(defface cells-header-line '((t :inherit header-line))
+ "Face used by `cells-mode' to highlight cell boundaries.")
+
+(defun cells-boundary-regexp ()
+ "Return a regexp matching comment lines that serve as cell boundary."
+ (rx line-start
+ (+ (syntax comment-start))
+ (* (syntax whitespace))
+ (or (eval (cons 'or cells-cell-markers)))))
+
+(defun cells-forward-cell (&optional arg)
+ "Move to the next cell boundary, or end of buffer.
+With ARG, repeat this that many times. If ARG is negative, move
+backward."
+ (interactive "p")
+ (or arg (setq arg 1))
+ (when (and (> arg 0) (not (eobp)))
+ (forward-char))
+ (save-match-data
+ (or
+ (when (re-search-forward (cells-boundary-regexp) nil t arg)
+ (goto-char (match-beginning 0)))
+ (when (< arg 0) (goto-char (point-min)))
+ (when (> arg 0) (goto-char (point-max))))))
+
+(defun cells-backward-cell (&optional arg)
+ "Move to the previous cell boundary, or beginning of buffer.
+With ARG, repeat this that many times. If ARG is negative, move
+forward."
+ (interactive "p")
+ (cells-forward-cell (- (or arg 1))))
+
+(defmacro cells-do (&rest body)
+ "Find current cell bounds and evaluate BODY.
+Inside BODY, the variables `beg' and `end' are bound to the
+limits of the current cell.
+
+If the first element of BODY is the keyword `:use-region' and the
+region is active, use its bounds instead."
+ `(pcase (if (and ,(eq (car body) :use-region) (use-region-p))
+ (list t (region-end) (region-beginning))
+ (save-excursion
+ (list nil
+ (progn (cells-forward-cell) (point))
+ (progn (cells-backward-cell) (point)))))
+ (`(,using-region ,end ,beg)
+ ,@body)))
+
+(defun cells-mark-cell ()
+ "Put point at the beginning of this cell, mark at end."
+ ;; TODO: add arg; extend region when active
+ (interactive)
+ (cells-do
+ (goto-char beg)
+ (push-mark end nil t)))
+
+(defun cells-command (fun &optional docstring &rest options)
+ "Returns an anonymous command that calls FUN on the current cell.
+
+FUN is a function that takes two character positions as argument.
+Most interactive commands that act on a region are of this form
+and can be used here.
+
+If OPTIONS contains the keyword :use-region, the command will act
+on the region instead of the current cell if appropriate.
+
+If OPTIONS contains the keyword :pulse, provide visual feedback
+via `pulse-momentary-highlight-region'."
+ (declare (doc-string 2))
+ (unless (stringp docstring)
+ (setq options (cons docstring options))
+ (setq docstring (concat
+ "Call `" (symbol-name fun) "' on the current code cell."
+ (when (member :use-region options)
+ "\nIf region is active, use it instead."))))
+ (eval `(lambda ()
+ ,docstring
+ (interactive)
+ (cells-do ,(car (member :use-region options))
+ ,(when (member :pulse options)
+ '(pulse-momentary-highlight-region beg end))
+ (funcall ',fun beg end)))))
+
+(define-minor-mode cells-mode
+ "Minor mode for cell-oriented code."
+ ;; TODO: integrate with outline-mode?
+ :keymap (make-sparse-keymap)
+ (let ((spec `((,(concat "\\(" (cells-boundary-regexp) "\\).*\n")
+ 0 'cells-header-line prepend))))
+ (if cells-mode
+ (progn
+ (font-lock-add-keywords nil spec))
+ (font-lock-remove-keywords nil spec))
+ (font-lock-flush)))
+
+(provide 'cells)
+;;; cells.el ends here
- [elpa] externals/code-cells 1ca02d489d 23/36: Add code-cells-comment-or-uncomment, (continued)
- [elpa] externals/code-cells 1ca02d489d 23/36: Add code-cells-comment-or-uncomment, ELPA Syncer, 2022/02/28
- [elpa] externals/code-cells c16c0aa0af 13/36: Use named groups in alternative regexp branches, ELPA Syncer, 2022/02/28
- [elpa] externals/code-cells 1661efd9ae 18/36: Add MELPA badge; mention EIN, ELPA Syncer, 2022/02/28
- [elpa] externals/code-cells d03621b103 19/36: Change screenshot, ELPA Syncer, 2022/02/28
- [elpa] externals/code-cells 374edc6be7 20/36: Change package description, ELPA Syncer, 2022/02/28
- [elpa] externals/code-cells 1bd650391a 25/36: Update README, ELPA Syncer, 2022/02/28
- [elpa] externals/code-cells 4e973e0122 26/36: Do not assume Emacs has native JSON parsing available, ELPA Syncer, 2022/02/28
- [elpa] externals/code-cells 185c33b8b6 27/36: Fix cell movement for files without newline at the end, ELPA Syncer, 2022/02/28
- [elpa] externals/code-cells 031f726941 30/36: code-cells-eval: Fix check for a possibly active minor mode, ELPA Syncer, 2022/02/28
- [elpa] externals/code-cells ea7799c447 35/36: Release on ELPA, ELPA Syncer, 2022/02/28
- [elpa] externals/code-cells 37dce1d908 02/36: Add existing code,
ELPA Syncer <=
- [elpa] externals/code-cells 30c0359c36 03/36: Simplify motion code, ELPA Syncer, 2022/02/28
- [elpa] externals/code-cells aeddd889c2 04/36: Add ipynb support via Jupytext, ELPA Syncer, 2022/02/28
- [elpa] externals/code-cells e02bda5b68 09/36: Assorted refinements, ELPA Syncer, 2022/02/28
- [elpa] externals/code-cells aefabc4abf 10/36: Comments about ipynb conversion settings, ELPA Syncer, 2022/02/28
- [elpa] externals/code-cells 7bad8f1cf6 11/36: Speed keys, ELPA Syncer, 2022/02/28
- [elpa] externals/code-cells 2dc51b44a3 12/36: Correct outline level before first cell header, ELPA Syncer, 2022/02/28
- [elpa] externals/code-cells 9500e07f83 15/36: Fix byte-compilation issue, ELPA Syncer, 2022/02/28
- [elpa] externals/code-cells adda62ec82 16/36: Address some packaging issues, ELPA Syncer, 2022/02/28
- [elpa] externals/code-cells 67e1479a75 28/36: Add code-cells-mode-maybe, ELPA Syncer, 2022/02/28
- [elpa] externals/code-cells f93db2d65c 29/36: Refinement in Commentary section, ELPA Syncer, 2022/02/28