Clean up how text is inserted in REPL buffer

This commit is contained in:
Nathaniel Nicandro 2017-12-27 21:13:23 -06:00
parent c3c3f7c44e
commit 3071b64611

View file

@ -81,51 +81,85 @@
,@body))) ,@body)))
(defun jupyter-repl-insert (&rest args) (defun jupyter-repl-insert (&rest args)
"Insert text into the `current-buffer' as read-only. "Insert text into the `current-buffer', possibly with text properties.
As a special case if the first element of ARGS is a symbol,
insert the rest of ARGS as editable text by removing any This acts like `insert' except that the leading elements of ARGS
`read-only' text properties." can contain the following keywords along with their values:
- `:read-only' :: A non-nil value makes the text to be inserted,
read only. This is t by default, so to make text editable you
will have to do something like:
(jupyter-repl-insert :read-only nil \"<editable text>\")
- `:properties' :: A list of text properties and their values to
be added to the inserted text. This defaults to an empty list.
- `:inherit-properties' :: A non-nil value will use
`insert-and-inherit' instead of `insert' for the function used
to insert the text. This is nil by default."
(let ((arg nil) (let ((arg nil)
(read-only t) (read-only t)
(properties nil)) (properties nil)
(insert-fun #'insert))
(while (keywordp (setq arg (car args))) (while (keywordp (setq arg (car args)))
(cond (cl-case arg
((eq arg :read-only) (:read-only (setq read-only (cadr args)))
(setq read-only (cadr args))) (:properties (setq properties (cadr args)))
((eq arg :properties) (:inherit-properties
(setq properties (cadr args)))) (setq insert-fun (if (cadr args) #'insert-and-inherit #'insert)))
(otherwise
(error "Keyword not one of `:read-only', `:properties', `:inherit-properties' (`%s')." arg)))
(setq args (cddr args))) (setq args (cddr args)))
(when read-only (when read-only
(if properties (plist-put properties 'read-only t) (if properties
(setq properties (append '(read-only t) properties))
(setq properties '(read-only t)))) (setq properties '(read-only t))))
(apply #'insert (mapcar (lambda (s) (apply insert-fun (mapcar (lambda (s)
(prog1 s (prog1 s
(when properties (when properties
(add-text-properties (add-text-properties
0 (length s) properties s)))) 0 (length s) properties s))))
args)))) args))))
(defun jupyter-repl-inherit-text-properties (str offset properties) ;;; Prompt
(add-text-properties
0 (length str)
(cl-loop with pos = (+ (point) offset)
for prop in properties
collect prop and collect (get-text-property pos prop))
str)
str)
(defun jupyter-repl--insert-prompt (str face) (defun jupyter-repl-insert-output-prompt (count)
(let ((count (oref jupyter-repl-current-client execution-count))) (let ((props (list 'fontified t
'font-lock-face 'jupyter-repl-output-prompt
'field (list 'jupyter-cell 'out count))))
;; Handled by `jupyter-repl-do-request-output'
;; (jupyter-repl-insert "\n")
(jupyter-repl-insert :properties props (format "Out[%d]:" count))
(jupyter-repl-insert :read-only nil :properties props " ")))
(defun jupyter-repl-insert-input-prompt (count)
(let ((props (list 'fontified t
'font-lock-face 'jupyter-repl-input-prompt
'field (list 'jupyter-cell 'in count))))
(jupyter-repl-insert "\n") (jupyter-repl-insert "\n")
(jupyter-repl-insert (jupyter-repl-insert
:properties (list 'jupyter-prompt count :properties (append '(front-sticky t) props)
'font-lock-face face (let ((str (format "In [%d]:" count)))
'fontified t) (add-text-properties 0 1 '(jupyter-cell beginning) str)
str) str))
(jupyter-repl-insert (jupyter-repl-insert
:properties (list 'rear-nonsticky t :properties props (propertize " " 'rear-nonsticky t))))
'jupyter-prompt count)
" "))) (defun jupyter-repl-insert-continuation-prompt (field)
(let ((props (list 'fontified t
'font-lock-face 'jupyter-repl-input-prompt
'field field
'cursor-intangible t)))
;; (jupyter-repl-insert :read-only nil "\n")
(jupyter-repl-insert
:properties (append '(front-sticky t) props)
(let ((len (- (jupyter-repl-cell-prompt-width) 2)))
(concat (make-string len ? ) ":")))
(jupyter-repl-insert
;; Deleting this space, deletes the whole continuation prompt. See
;; `jupyter-repl-before-buffer-change'
:read-only nil
:properties props (propertize " " 'rear-nonsticky t))))
(defun jupyter-repl-insert-prompt (&optional type) (defun jupyter-repl-insert-prompt (&optional type)
"Insert a REPL promp in CLIENT's buffer according to type. "Insert a REPL promp in CLIENT's buffer according to type.
@ -134,42 +168,16 @@ If TYPE is nil or `in' insert a new input prompt. If TYPE is
(setq type (or type 'in)) (setq type (or type 'in))
(unless (memq type '(in out busy continuation)) (unless (memq type '(in out busy continuation))
(error "Prompt type can only be (`in', `out', `busy', or `continuation')")) (error "Prompt type can only be (`in', `out', `busy', or `continuation')"))
(let ((count (oref jupyter-repl-current-client execution-count))) (let ((count (oref jupyter-repl-current-client execution-count))
(inhibit-modification-hooks (memq type '(in out))))
(cond (cond
((eq type 'busy)
(save-excursion
(when (re-search-backward "In \\[\\([0-9]+\\)\\]" nil t)
(replace-match
(jupyter-repl-inherit-text-properties
"*" 1 '(font-lock-face jupyter-prompt read-only))
nil nil nil 1))))
((eq type 'in) ((eq type 'in)
(save-excursion (jupyter-repl-insert-input-prompt count))
(when (re-search-backward "In \\[\\(\\*\\)\\]" nil t)
(let ((pnum (number-to-string (get-text-property
(point) 'jupyter-prompt))))
(replace-match
(jupyter-repl-inherit-text-properties
pnum 1 '(font-lock-face jupyter-prompt read-only))
nil nil nil 1))))
(jupyter-repl--insert-prompt
(format "In [%d]:" count) 'jupyter-repl-input-prompt)
(add-text-properties (point-at-bol) (1+ (point-at-bol))
'(jupyter-cell begin)))
((eq type 'out) ((eq type 'out)
(jupyter-repl--insert-prompt (jupyter-repl-insert-output-prompt count))
(format "Out[%d]:" count) 'jupyter-repl-output-prompt)) ((eq type 'continuation)
(t ; continuation (jupyter-repl-insert-continuation-prompt
(let ((padding (save-excursion (field-at-pos (1+ (jupyter-repl-cell-beginning-position))))))))
(goto-char (oref jupyter-repl-current-client
input-start-marker))
(make-string (- (point) (point-at-bol) 2) ? ))))
(jupyter-repl--insert-prompt
(concat padding ":") 'jupyter-repl-input-prompt))))
(when (eq type 'in)
(set-marker (oref jupyter-repl-current-client
input-start-marker)
(point)))))
(defun jupyter-repl-finalize-cell () (defun jupyter-repl-finalize-cell ()
"Make the current cell un-editable." "Make the current cell un-editable."