Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions source/editor.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,20 @@
:leave-history-p t))
nil)

(defun line-editor--kill-word-right (editor)
"Delete separators and the word immediately after EDITOR's cursor."
(let* ((text (line-editor-text editor))
(cursor (line-editor-cursor editor))
(end (line-editor--word-end editor)))
(line-editor--set-state
editor
(concatenate 'string
(subseq text 0 cursor)
(subseq text end))
cursor
:leave-history-p t))
nil)

(defun line-editor--history-entry-matches-p (editor query entry)
"True when ENTRY is eligible for EDITOR's fixed history QUERY."
(let ((function (line-editor-history-match-function editor)))
Expand Down Expand Up @@ -528,6 +542,9 @@ return values. NIL and :IGNORED are no-op commands returning :IGNORED."
(:kill-word
(line-editor--kill-word editor)
(line-editor--continue-action))
(:kill-word-right
(line-editor--kill-word-right editor)
(line-editor--continue-action))
(:complete
(values :complete nil))
(:complete-previous
Expand Down Expand Up @@ -570,6 +587,7 @@ return values. NIL and :IGNORED are no-op commands returning :IGNORED."
:toggle-word-delimiter-mode :home :end
:backspace :delete :history-previous :history-next
:kill-to-end :kill-line :kill-word
:kill-word-right
:complete :complete-previous :up :down :submit
:interrupt :end-of-input :stream-end :escape
:clear-screen :ignore :ignored)))))
Expand Down
44 changes: 42 additions & 2 deletions source/input.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,40 @@ be balanced with DISABLE-KEYBOARD-ENHANCEMENT while the same terminal is owned."
:escape)
((string= body "127u")
:backspace)
((string= body "97;5u")
:home)
((string= body "98;5u")
:left)
((string= body "101;5u")
:end)
((string= body "102;5u")
:right)
((string= body "104;5u")
:backspace)
((string= body "105;5u")
:complete)
((member body '("106;5u" "109;5u") :test #'string=)
:submit)
((string= body "107;5u")
:kill-to-end)
((string= body "108;5u")
:clear-screen)
((string= body "110;5u")
:history-next)
((string= body "112;5u")
:history-previous)
((string= body "117;5u")
:kill-line)
((string= body "119;5u")
:kill-word)
((member body '("98;3u" "27;3;98~") :test #'string=)
:word-left)
((member body '("100;3u" "27;3;100~") :test #'string=)
:kill-word-right)
((member body '("102;3u" "27;3;102~") :test #'string=)
:word-right)
((member body '("127;3u" "27;3;8~" "27;3;127~") :test #'string=)
:kill-word)
((member body '("100;5u" "27;5;100~") :test #'string=)
:end-of-input)
((member body '("8;5u" "127;5u"
Expand Down Expand Up @@ -159,6 +193,10 @@ be balanced with DISABLE-KEYBOARD-ENHANCEMENT while the same terminal is owned."
(#\H :home)
(#\F :end)
(t :ignore)))
((#\b #\B) :word-left)
((#\d #\D) :kill-word-right)
((#\f #\F) :word-right)
((#\backspace #\rubout) :kill-word)
((#\newline #\return) :insert-newline)
(t :escape))))

Expand All @@ -168,8 +206,10 @@ be balanced with DISABLE-KEYBOARD-ENHANCEMENT while the same terminal is owned."
Printable input becomes (:INSERT text). Control and escape sequences become
editing keywords. Bracketed paste becomes one (:PASTE text) event, with terminal
controls sanitized before the text reaches an editor. CSI-u reports for Enter,
Tab, Shift-Tab, Escape, Backspace, and Ctrl-D map to their raw semantic events.
Modified Enter becomes :INSERT-NEWLINE when distinguishable from Enter.
Tab, Shift-Tab, Escape, Backspace, and supported Ctrl editing keys map to their
semantic events. Legacy escape-prefix and CSI-u reports for Alt-B and Alt-F
move by words, Alt-D deletes the following word, and Alt-Backspace deletes the
preceding word. Modified Enter becomes :INSERT-NEWLINE when distinguishable.
Ctrl-Backspace and Ctrl-W become :KILL-WORD. Ctrl-Left and Ctrl-Right become
:WORD-LEFT and :WORD-RIGHT. When a line editor enables word-delimiter mode,
these events also recognize that editor's configured word delimiters. Arrow Up
Expand Down
1 change: 1 addition & 0 deletions source/keymap.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ command values remain opaque and are retained."
(:kill-to-end . :kill-to-end)
(:kill-line . :kill-line)
(:kill-word . :kill-word)
(:kill-word-right . :kill-word-right)
(:complete . :complete)
(:complete-previous . :complete-previous)
(:up . :up)
Expand Down
6 changes: 6 additions & 0 deletions tests/editor.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,12 @@
(editor-tests--assert (and (string= (line-editor-text editor) "")
(zerop (line-editor-cursor editor)))
"Kill-line must clear text and cursor."))
(let ((editor (make-line-editor :text "alpha beta gamma" :cursor 5)))
(editor-tests--event editor :kill-word-right :continue)
(editor-tests--assert
(and (string= (line-editor-text editor) "alpha gamma")
(= (line-editor-cursor editor) 5))
"Kill-word-right must remove separators and the next word."))
nil)

(defun editor-tests--test-history ()
Expand Down
41 changes: 41 additions & 0 deletions tests/input.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,47 @@
(third case)
(input-test--event
(input-test--escape-sequence (second case)))))
(dolist (case '(("CSI-u control-A event" "[97;5u" :home)
("CSI-u control-B event" "[98;5u" :left)
("CSI-u control-E event" "[101;5u" :end)
("CSI-u control-F event" "[102;5u" :right)
("CSI-u control-H event" "[104;5u" :backspace)
("CSI-u control-I event" "[105;5u" :complete)
("CSI-u control-J event" "[106;5u" :submit)
("CSI-u control-K event" "[107;5u" :kill-to-end)
("CSI-u control-L event" "[108;5u" :clear-screen)
("CSI-u control-M event" "[109;5u" :submit)
("CSI-u control-N event" "[110;5u" :history-next)
("CSI-u control-P event" "[112;5u" :history-previous)
("CSI-u control-U event" "[117;5u" :kill-line)
("CSI-u control-W event" "[119;5u" :kill-word)))
(check-equal (first case)
(third case)
(input-test--event
(input-test--escape-sequence (second case)))))
(dolist (case '(("CSI-u alt-B event" "[98;3u" :word-left)
("CSI-u alt-D event" "[100;3u" :kill-word-right)
("CSI-u alt-F event" "[102;3u" :word-right)
("CSI-u alt-backspace event" "[127;3u" :kill-word)
("modify-other-keys alt-B event" "[27;3;98~" :word-left)
("modify-other-keys alt-D event" "[27;3;100~" :kill-word-right)
("modify-other-keys alt-F event" "[27;3;102~" :word-right)
("modify-other-keys alt-backspace event"
"[27;3;127~" :kill-word)))
(check-equal (first case)
(third case)
(input-test--event
(input-test--escape-sequence (second case)))))
(dolist (case `(("legacy alt-B event" "b" :word-left)
("legacy alt-D event" "d" :kill-word-right)
("legacy alt-F event" "f" :word-right)
("legacy alt-backspace event"
,(string (code-char 127))
:kill-word)))
(check-equal (first case)
(third case)
(input-test--event
(input-test--escape-sequence (second case)))))
(dolist (code '(10 13))
(loop for modifier from 2 to 8
do (check-equal
Expand Down