diff --git a/extensions/vi-mode/options.lisp b/extensions/vi-mode/options.lisp index 7d2e22e91..a055e9157 100644 --- a/extensions/vi-mode/options.lisp +++ b/extensions/vi-mode/options.lisp @@ -317,9 +317,7 @@ (:set-hook (new-value) (setf (lem:variable-value 'lem/line-numbers:line-numbers :global) new-value))) -(defvar *default-iskeyword* '("@" "48-57" "_" "192-255")) - -(defun compile-iskeyword (value) +(defun compile-rules (value option-name) (apply #'disjoin (mapcar (lambda (rule) (check-type rule string) @@ -343,13 +341,18 @@ (progn (unless (= (length rule) 1) (error 'option-error - :format-control "Invalid rule in iskeyword: ~A" - :format-arguments (list rule))) + :format-control "Invalid rule in ~A: ~A" + :format-arguments (list option-name rule))) (let ((rule-char (aref rule 0))) (lambda (c) (char= c rule-char)))))))) value))) +(defvar *default-iskeyword* '("@" "48-57" "_" "192-255")) + +(defun compile-iskeyword (value) + (compile-rules value "iskeyword")) + (define-option "iskeyword" ((cons *default-iskeyword* (compile-iskeyword *default-iskeyword*)) :type list @@ -376,6 +379,37 @@ (option-value option)) :test 'equal))))) +(defvar *default-isseparator* (mapcar #'string '(#\Newline #\Space #\Tab))) + +(defun compile-isseparator (value) + (compile-rules value "isseparator")) + +(define-option "isseparator" + ((cons *default-isseparator* + (compile-isseparator *default-isseparator*)) + :type list + :aliases ("iss") + :scope :buffer) + (:documentation "Comma-separated string to specify the characters that should be recognized as non broad word characters. (buffer local) + Aliases: iss") + (:getter (option) + (car (option-raw-value option))) + (:setter (new-value option) + (setf (option-%value option) + (cons new-value + (compile-isseparator new-value)))) + (:initializer (option) + (let ((syntax-table (lem:mode-syntax-table (lem:buffer-major-mode (lem:current-buffer))))) + (setf (option-value option) + (delete-duplicates + (nconc (mapcar (lambda (c) + (if (char= c #\@) + "@-@" + (string c))) + (lem-base::syntax-table-space-chars syntax-table)) + (option-value option)) + :test 'equal))))) + (define-option "scrolloff" (0 :type number :aliases ("so")) (:documentation "The minimal number of lines to keep above of below the cursor. Default: 0 diff --git a/extensions/vi-mode/tests/options.lisp b/extensions/vi-mode/tests/options.lisp index d4c0f5fa1..473868c9c 100644 --- a/extensions/vi-mode/tests/options.lisp +++ b/extensions/vi-mode/tests/options.lisp @@ -7,9 +7,13 @@ (:import-from :lem-fake-interface :with-fake-interface) (:shadowing-import-from :lem-vi-mode/tests/utils - :with-current-buffer)) + :with-current-buffer) + (:import-from :named-readtables + :in-readtable)) (in-package :lem-vi-mode/tests/options) +(in-readtable :interpol-syntax) + (deftest get-option (ok (typep (get-option "number") 'option) "Can get a global option") @@ -24,3 +28,18 @@ (with-current-buffer (buf) (ok (equalp (option-value "iskeyword") isk) "Another buffer's local option is not changed")))))) + +(deftest isseparator-option + (ok (typep (get-option "isseparator") 'option) + "Can get isseparator option") + (ok (typep (get-option "iss") 'option) + "Can get isseparator option by alias") + (with-fake-interface () + (with-vi-buffer (#?"abc\n[(]def)\n") + (cmd "E") + (ok (buf= #?"abc\n(def[)]\n"))) + (with-vi-buffer (#?"abc\n[(]def)\n") + (execute-set-command "iss+=(") + (execute-set-command "iss+=)") + (cmd "WE") + (ok (buf= #?"abc\n(de[f])\n"))))) \ No newline at end of file diff --git a/extensions/vi-mode/word.lisp b/extensions/vi-mode/word.lisp index 2353514f8..3f00867a1 100644 --- a/extensions/vi-mode/word.lisp +++ b/extensions/vi-mode/word.lisp @@ -30,10 +30,15 @@ ((blank-char-p char) :blank) (t :non-word)))) +(defun non-broad-word-char-p (char) + (funcall (cdr (option-raw-value "isseparator")) + char)) + (defun broad-word-char-type (char) (when char (cond ((blank-char-p char) :blank) + ((non-broad-word-char-p char) :non-word) (t :word)))) (defun forward-word-begin (char-type-fn &optional (point (current-point)))