Skip to content

Commit

Permalink
feat: Detect and skip over ipython continue prompts.
Browse files Browse the repository at this point in the history
This change introduces a new type of mistty-skip, continue-prompt,
detected using regexps and use that to detect ipython continue prompts.
The goal is to avoid MisTTY being confused by these prompts when
replaying edits.
  • Loading branch information
szermatt committed Dec 29, 2024
1 parent 48fb19e commit 4d046c1
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 3 deletions.
36 changes: 34 additions & 2 deletions mistty-term.el
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,21 @@ For example:
:group 'mistty
:type 'boolean)

(defcustom mistty-multi-line-continue-prompts
'("^ *\\.\\.\\.: " ; ipython
)
"Regexp used to identify multi-line command prompts.
These regexps identifies prompts that tell the user that they can
type more, while still allowing them to edit what's above. MisTTY
uses these regexps to identify sections of texts it should ignore
when editing.
Note that bash \"> \" is not a continuation prompt, with this
definition, because it doesn't allow editing what's above."
:group 'mistty
:type '(list regexp))

(defconst mistty-right-str "\eOC"
"Sequence to send to the process when the rightarrow is pressed.")

Expand Down Expand Up @@ -772,8 +787,9 @@ properties, detecting the following regions in a prompt line:
(eol (pos-eol)))
(when (> eol bol)
(unless (mistty--detect-right-prompt bol eol)
(let ((indent (mistty--detect-indent bol eol)))
(mistty--detect-trailing-spaces indent eol)))))
(let ((end (or (mistty--detect-continue-prompt bol)
(mistty--detect-indent bol eol))))
(mistty--detect-trailing-spaces end eol)))))

;; process next line?
(forward-line 1)
Expand All @@ -800,6 +816,22 @@ BOL and EOL define the region to look in."

pos)))))

(defun mistty--detect-continue-prompt (bol)
"Detect continue prompt and return its right position or nil.
BOL define the start of the region to look in."
(catch 'mistty-return
(save-excursion
(goto-char bol)
(dolist (prompt mistty-multi-line-continue-prompts)
(when (looking-at prompt)
(let ((end (match-end 0)))
(when (> end bol)
(add-text-properties
bol end
'(mistty-skip continue-prompt yank-handler (nil "" nil nil)))
(throw 'mistty-return end))))))))

(defun mistty--detect-indent (bol eol)
"Detect line indentation and return its right position or nil.
Expand Down
2 changes: 1 addition & 1 deletion mistty.el
Original file line number Diff line number Diff line change
Expand Up @@ -3239,7 +3239,7 @@ This is meant to be added to `pre-redisplay-functions'"
(when (eq (car last-state) (current-buffer))
(setq last-pos (cdr last-state))))
(pcase-dolist (`(,beg . ,end) (mistty--cursor-skip-ranges
pos '(indent right-prompt)))
pos '(indent right-prompt continue-prompt)))
(unless move-to
(setq
move-to
Expand Down
23 changes: 23 additions & 0 deletions test/mistty-term-test.el
Original file line number Diff line number Diff line change
Expand Up @@ -212,3 +212,26 @@
(should-not (text-property-any (point-min) (point-max) 'mistty-skip 'trailing))
(should (string-match "^\\[ + < right \\]$"
(mistty-test-content :show-property '(mistty-skip right-prompt))))))

(ert-deftest mistty-test-prepare-term-for-refresh-ipython-continue-prompt ()
(ert-with-test-buffer ()
(setq-local term-width 80)

(insert (concat "In [3]: for i in (1, 2, 3):" (propertize " " 'mistty-maybe-skip t) "\n"))
(insert (concat " ...: if i > 1: " (propertize " " 'mistty-maybe-skip t) "\n"))
(insert (concat " ...: print(i) " (propertize " " 'mistty-maybe-skip t) "\n"))
(insert (concat "In [133]: for i in (1, 2, 3):\n"))
(insert (concat " ...: print(i)\n"))

(put-text-property (point-min) (point-max) 'mistty-changed t)
(mistty--prepare-term-for-refresh (current-buffer) (point-min))

(should-not (text-property-any (point-min) (point-max) 'mistty-skip 'right-prompt))
(should-not (text-property-any (point-min) (point-max) 'mistty-skip 'indent))
(should (equal
(concat "In [3]: for i in (1, 2, 3):\n"
"[ ...: ] if i > 1:\n"
"[ ...: ] print(i)\n"
"In [133]: for i in (1, 2, 3):\n"
"[ ...: ] print(i)")
(mistty-test-content :show-property '(mistty-skip continue-prompt))))))
39 changes: 39 additions & 0 deletions test/mistty-test.el
Original file line number Diff line number Diff line change
Expand Up @@ -4356,3 +4356,42 @@
(mistty-with-test-buffer (:shell ipython)
(mistty-send-text "print('hello')")
(should (equal "hello" (mistty-send-and-capture-command-output)))))

(ert-deftest mistty-test-ipython-detect-continue-prompt ()
(mistty-with-test-buffer (:shell ipython)
(mistty--send-string mistty-proc "for i in (1, 2, 3):\nif i > 2:\nprint(i)")
(mistty-wait-for-output :test (lambda () (save-excursion
(goto-char (point-min))
(and (search-forward "...:" nil 'noerror)
(search-forward "...:" nil 'noerror)))))

(should (equal (concat "In [1]: for i in (1, 2, 3):\n"
"[ ...: ] if i > 2:\n"
"[ ...: ] print(i)")
(mistty-test-content
:start (save-excursion
(goto-char (point-min))
(search-forward "In [")
(match-beginning 0))
:show-property '(mistty-skip continue-prompt))))))

(ert-deftest mistty-test-ipython-skip-continue-prompt ()
(mistty-with-test-buffer (:shell ipython :selected t)
(let ((win (selected-window))
(mistty-skip-empty-spaces t))
(mistty--send-string mistty-proc "for i in (1, 2, 3):\nif i > 2:\nprint(i)")
(mistty-wait-for-output :test (lambda () (save-excursion
(goto-char (point-min))
(and (search-forward "...:" nil 'noerror)
(search-forward "...:" nil 'noerror)))))

(mistty-test-goto " if i > 2")
(mistty--cursor-skip win)
(goto-char (1- (point)))
(mistty--cursor-skip win)

(should (equal
"In [1]: for i in (1, 2, 3):<>"
(mistty-test-content
:show (point)
:start (pos-bol) :end (pos-eol)))))))

0 comments on commit 4d046c1

Please sign in to comment.