Skip to content

Commit

Permalink
Replace jupyter-repl-cell-cond with jupyter-repl-map-cells
Browse files Browse the repository at this point in the history
* jupyter-repl.el
(jupyter-repl-map-cells): New function.
(jupyter-repl-cell-cond): Remove. Update callers with new function.

* jupyter-julia.el: Ditto.

* test/jupyter-test.el
(jupyter-repl-map-cells): New test.
(jupyter-repl-cell-cond): Remove.
  • Loading branch information
nnicandro committed Apr 14, 2020
1 parent 25270f7 commit a9ae0bc
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 76 deletions.
7 changes: 4 additions & 3 deletions jupyter-julia.el
Expand Up @@ -171,8 +171,8 @@ nil."
;;; REPL font lock

(defun jupyter-julia--propertize-repl-mode-char (beg end)
(jupyter-repl-cell-cond
beg end
(jupyter-repl-map-cells beg end
(lambda ()
;; Handle Julia package prompt so `syntax-ppss' works properly.
(when (and (eq (char-syntax (char-after (point-min))) ?\))
(= (point-min)
Expand All @@ -182,7 +182,8 @@ nil."
;; which is why the widen is needed here.
(jupyter-repl-cell-code-beginning-position))))
(put-text-property
(point-min) (1+ (point-min)) 'syntax-table '(1 . ?.)))))
(point-min) (1+ (point-min)) 'syntax-table '(1 . ?.))))
#'ignore))

;;; `jupyter-repl-after-init'

Expand Down
119 changes: 54 additions & 65 deletions jupyter-repl.el
Expand Up @@ -264,42 +264,6 @@ The cell is narrowed to the region between and including
(jupyter-repl-cell-code-end-position))
,@body)))

(defmacro jupyter-repl-cell-cond (beg end input-form &rest output-forms)
"Conditionally evaluate INPUT-FORM or OUTPUT-FORMS between BEG and END.
INPUT-FORM is evaluated for every input cell between BEG and END
with the buffer narrowed to the region of the input cell.
Similarly, OUTPUT-FORMS is evaluated for every output cell region
with the buffer narrowed to the output cell.
Note the narrowed regions may not be full input/output cells if
BEG and END are within an input/output cell."
(declare (indent 3) (debug ([&or symbolp form] [&or symbolp form]
form &rest form)))
(let ((start (make-symbol "start"))
(next (make-symbol "next"))
(-end (make-symbol "-end")))
`(save-excursion
(save-restriction
(let ((,start ,beg)
(,-end ,end)
,next)
(while (/= ,start ,-end)
(widen)
(cond
((eq (get-text-property ,start 'field) 'cell-code)
(setq ,next (min ,-end (field-end ,start t)))
(narrow-to-region ,start ,next)
,input-form)
(t
(setq ,next (or (text-property-any
,start ,-end 'field 'cell-code)
,-end))
,@(when output-forms
`((narrow-to-region ,start ,next)
,@output-forms))))
(setq ,start ,next)))))))

(defmacro jupyter-repl-inhibit-undo-when (cond &rest body)
"Evaluate BODY, disabling undo beforehand if COND is non-nil.
Undo is re-enabled after BODY is evaluated.
Expand Down Expand Up @@ -670,6 +634,33 @@ ARG is the number of cells to move and defaults to 1."
(jupyter-repl-previous-cell arg)
(goto-char (jupyter-repl-cell-code-beginning-position)))

(defun jupyter-repl-map-cells (beg end input output)
"Call INPUT or OUTPUT on the corresponding cells between BEG and END.
For every input or output cell between BEG and END, call INPUT or
OUTPUT, respectively, with the buffer narrowed to the cell.
INPUT and OUTPUT are functions of no arguments.
Note the narrowed regions may not be full input/output cells if
BEG and END are within an input/output cell."
(declare (indent 2))
(save-excursion
(save-restriction
(let (next)
(while (/= beg end)
(widen)
(cond
((eq (get-text-property beg 'field) 'cell-code)
(setq next (min end (field-end beg t)))
(narrow-to-region beg next)
(funcall input))
(t
(setq next (or (text-property-any
beg end 'field 'cell-code)
end))
(narrow-to-region beg next)
(funcall output)))
(setq beg next))))))

;;; Predicates

(defun jupyter-repl-cell-beginning-p (&optional pos)
Expand Down Expand Up @@ -1779,46 +1770,44 @@ would look like
"Use FONTIFY-FUN to fontify input cells between BEG and END.
VERBOSE has the same meaning as in
`font-lock-fontify-region-function'."
(jupyter-repl-cell-cond
beg end
;; Ensure that the buffer is narrowed to the actual cell code before
;; calling the REPL language's `major-mode' specific fontification
;; functions since those functions don't know anything about input cells
;; or output cells and may traverse cell boundaries.
;;
;;
;; It is OK that we do not update BEG and END using the return value of
;; this function as long as the default value of
;; `font-lock-extend-region-functions' is used since an input cell always
;; starts at the beginning of a line and ends at the end of a line and
;; does not use the font-lock-multiline property (2018-12-20).
(funcall fontify-fun (point-min) (point-max) verbose)
;; Unfontify the region mainly to remove the font-lock-multiline property
;; in the output, e.g. added by markdown. These regions will get
;; highlighted syntactically in some scenarios.
(font-lock-unfontify-region (point-min) (point-max)))
(jupyter-repl-map-cells beg end
;; Ensure that the buffer is narrowed to the actual cell code before calling
;; the REPL language's `major-mode' specific fontification functions since
;; those functions don't know anything about input cells or output cells and
;; may traverse cell boundaries.
;;
;; It is OK that we do not update BEG and END using the return value of this
;; function as long as the default value of
;; `font-lock-extend-region-functions' is used since an input cell always
;; starts at the beginning of a line and ends at the end of a line and does
;; not use the font-lock-multiline property (2018-12-20).
(lambda () (funcall fontify-fun (point-min) (point-max) verbose))
;; Unfontify the region mainly to remove the font-lock-multiline property in
;; the output, e.g. added by markdown. These regions will get highlighted
;; syntactically in some scenarios.
(lambda () (font-lock-unfontify-region (point-min) (point-max))))
`(jit-lock-bounds ,beg . ,end))

(defun jupyter-repl-syntax-propertize-function (propertize-fun beg end)
"Use PROPERTIZE-FUN to syntax propertize text between BEG and END."
(jupyter-repl-cell-cond
beg end
;; See note in `jupyter-repl-font-lock-fontify-region' on why the buffer
;; should be narrowed to the input cell before calling this function.
(funcall propertize-fun (point-min) (point-max))
(jupyter-repl-map-cells beg end
;; See note in `jupyter-repl-font-lock-fontify-region' on why the buffer
;; should be narrowed to the input cell before calling this function.
(lambda () (funcall propertize-fun (point-min) (point-max)))
;; Treat parenthesis and string characters as punctuation when parsing the
;; syntax of the output. Although we don't fontify output regions,
;; `syntax-ppss' still looks at the whole contents of the buffer. If there
;; are unmatched parenthesis or string delimiters in the output, it will
;; interfere with `syntax-ppss'. Note, this requires
;; `parse-sexp-lookup-properties' to be non-nil so that `syntax-ppss' will
;; look at the `syntax-table' property.
(goto-char (point-min))
(skip-syntax-forward "^()\"")
(while (not (eobp))
(put-text-property (point) (1+ (point)) 'syntax-table '(1 . ?.))
(forward-char)
(skip-syntax-forward "^()\""))))
(lambda ()
(goto-char (point-min))
(skip-syntax-forward "^()\"")
(while (not (eobp))
(put-text-property (point) (1+ (point)) 'syntax-table '(1 . ?.))
(forward-char)
(skip-syntax-forward "^()\"")))))

(defun jupyter-repl-font-lock-syntactic-face-function (face-fun state)
"Narrow to the input cell, use FACE-FUN to obtain the face given STATE."
Expand Down
15 changes: 7 additions & 8 deletions test/jupyter-test.el
Expand Up @@ -1578,19 +1578,18 @@ last element being the newest element added to the history."
(should-error (jupyter-repl-cell-beginning-position))
(should-error (jupyter-repl-cell-end-position)))))

(ert-deftest jupyter-repl-cell-cond ()
(ert-deftest jupyter-repl-map-cells ()
:tags '(repl)
(with-temp-buffer
(insert "foo")
(insert (propertize "bar" 'field 'cell-code))
(insert "baz")
(jupyter-repl-cell-cond
(point-min) (point-max)
(should (equal (buffer-string) "bar"))
(should (member (buffer-string) '("foo" "baz"))))
(jupyter-repl-cell-cond
(point-min) (point-max)
(should (equal (buffer-string) "bar")))))
(let (input output)
(jupyter-repl-map-cells (point-min) (point-max)
(lambda () (push (buffer-string) input))
(lambda () (push (buffer-string) output)))
(should (equal input '("bar")))
(should (equal output '("baz" "foo"))))))

(ert-deftest jupyter-repl-restart-kernel ()
:tags '(repl restart)
Expand Down

0 comments on commit a9ae0bc

Please sign in to comment.