From b59ec3b532d6b5b477f3d9791f23ebba2d3a38db Mon Sep 17 00:00:00 2001 From: Encryptoid <89423557+Encryptoid@users.noreply.github.com> Date: Thu, 9 Jan 2025 14:14:29 +0000 Subject: [PATCH] vi-mode: Add paragraph text object (#1740) * vi-mode: Add paragraph text object * Add missing declare ignore --- extensions/vi-mode/binds.lisp | 2 + extensions/vi-mode/commands.lisp | 10 +++++ extensions/vi-mode/tests/text-objects.lisp | 9 +++++ extensions/vi-mode/text-objects.lisp | 43 +++++++++++++++++++--- 4 files changed, 58 insertions(+), 6 deletions(-) diff --git a/extensions/vi-mode/binds.lisp b/extensions/vi-mode/binds.lisp index be10e0ace..41bc236dd 100644 --- a/extensions/vi-mode/binds.lisp +++ b/extensions/vi-mode/binds.lisp @@ -194,6 +194,8 @@ (define-key *inner-text-objects-keymap* "(" 'vi-inner-paren) (define-key *inner-text-objects-keymap* ")" 'vi-inner-paren) (define-key *inner-text-objects-keymap* "b" 'vi-inner-paren) +(define-key *outer-text-objects-keymap* "p" 'vi-a-paragraph) +(define-key *inner-text-objects-keymap* "p" 'vi-inner-paragraph) (setf (gethash (lem:make-key :sym "a") (keymap-table *operator-keymap*)) (keymap-table *outer-text-objects-keymap*)) diff --git a/extensions/vi-mode/commands.lisp b/extensions/vi-mode/commands.lisp index 4bef86c5a..719f096f7 100644 --- a/extensions/vi-mode/commands.lisp +++ b/extensions/vi-mode/commands.lisp @@ -136,6 +136,8 @@ :vi-inner-double-quote :vi-a-paren :vi-inner-paren + :vi-a-paragraph + :vi-inner-paragraph :vi-repeat :vi-normal :vi-keyboard-quit @@ -1101,6 +1103,14 @@ on the same line or at eol if there are none." (:expand-selection t) (inner-range-of 'paren-object (current-state) count)) +(define-text-object-command vi-a-paragraph (count) ("p") + (:expand-selection t) + (a-range-of 'paragraph-object (current-state) count)) + +(define-text-object-command vi-inner-paragraph (count) ("p") + (:expand-selection t) + (inner-range-of 'paragraph-object (current-state) count)) + (define-command vi-normal () () (change-state 'normal)) diff --git a/extensions/vi-mode/tests/text-objects.lisp b/extensions/vi-mode/tests/text-objects.lisp index 20b6156fa..14a220e11 100644 --- a/extensions/vi-mode/tests/text-objects.lisp +++ b/extensions/vi-mode/tests/text-objects.lisp @@ -76,3 +76,12 @@ (cmd "va\"") (ok (buf= " <\"foo\" [ ]>\"bar\"")))))) +(deftest paragraph-object + (with-fake-interface () + (with-vi-buffer (#?" \n \n f[o]o \n bar \n \n \n") + (cmd "vip") + (ok (buf= #?" \n \n< foo \n bar [\n]> \n \n"))) + (with-vi-buffer (#?" \n \n f[o]o \n bar \n \n \n") + (cmd "vap") + (ok (buf= #?" \n \n< foo \n bar \n \n [\n]>"))))) + diff --git a/extensions/vi-mode/text-objects.lisp b/extensions/vi-mode/text-objects.lisp index 688b2dd61..981753be9 100644 --- a/extensions/vi-mode/text-objects.lisp +++ b/extensions/vi-mode/text-objects.lisp @@ -25,6 +25,7 @@ :word-object :broad-word-object :paren-object + :paragraph-object :double-quoted-object :vi-operator-surrounding-blanks)) (in-package :lem-vi-mode/text-objects) @@ -292,13 +293,13 @@ ;; No quote-char found ((null prev-char) (keyboard-quit)) - + ;; Skip escape & quote-char - ((and escape-char + ((and escape-char (character-at point -2) ;; Bound check (char= (character-at point -2) escape-char)) (character-offset point -2)) - + ;; Successfully found unescaped quote (t (character-offset point -1) @@ -311,13 +312,13 @@ ;; No quote-char found ((null next-char) (keyboard-quit)) - + ;; Skip escape & quote-char ((and escape-char (character-at point 2) ;; Bound Check (char= (character-at point -1) escape-char)) - (character-offset point 2)) - + (character-offset point 2)) + ;; Successfully found (t (character-offset point 1) @@ -392,3 +393,33 @@ (defclass double-quoted-object (quoted-text-object) () (:default-initargs :quote-char #\")) + +;; +;; paragraph-object +(defclass paragraph-object (text-object) ()) + +(defmethod inner-range-of ((object paragraph-object) state count) + (declare (ignore state count)) + (with-point ((start (current-point)) + (end (current-point))) + ;; Start + (loop until (or (start-buffer-p start) + (blank-line-p start)) + do (line-offset start -1)) + (when (blank-line-p start) ;; pull back into paragraph + (line-offset start 1)) + + ;; End + (loop until (or (end-buffer-p end) + (blank-line-p end)) + do (line-offset end 1)) + (make-range start end))) + +;; adds on additional blank lines for inner paragraph-object +(defmethod a-range-of ((object paragraph-object) state count) + (let ((range (inner-range-of 'paragraph-object state count))) + (line-offset (range-end range) 1) + (loop until (or (end-buffer-p (range-end range)) + (not (blank-line-p (range-end range)))) + do (line-offset (range-end range) 1)) + range))