diff --git a/cycle-quotes.el b/cycle-quotes.el index faac0cb..075ab98 100644 --- a/cycle-quotes.el +++ b/cycle-quotes.el @@ -45,9 +45,13 @@ Set the first time `cycle-quotes' is called in a buffer.") If this is different from the current mode, the quote chars need to be recomputed.") -(defun cycle-quotes--set-quote-chars () - "Set the quote chars for the current syntax table." - (let ((syntax-table (syntax-table))) +(defun cycle-quotes-quote-chars () + "Return a list of quote characters for the current mode. +This is the default value of `cycle-quotes-quote-chars-function'. +It uses the syntax table for the current mode to determine which +characters should be regarded as quote characters." + (let ((syntax-table (syntax-table)) + (quote-chars '())) (while syntax-table (map-char-table (lambda (char-code-or-range syntax) @@ -56,12 +60,50 @@ to be recomputed.") (let ((from (car char-code-or-range)) (to (cdr char-code-or-range))) (dolist (char-code (number-sequence from to)) - (add-to-list 'cycle-quotes--quote-chars char-code))) - (add-to-list - 'cycle-quotes--quote-chars char-code-or-range)))) + (add-to-list 'quote-chars char-code))) + (add-to-list 'quote-chars char-code-or-range)))) syntax-table) (setq syntax-table (char-table-parent syntax-table))) - (setq-local cycle-quotes--quote-chars-mode major-mode))) + quote-chars)) + +(defun cycle-quotes-surrounding-quote () + "Return the surrounding quote character if point is inside a string. +This is the default value of +`cycle-quotes-surrounding-quote-function'." + (nth 3 (syntax-ppss))) + +(defun cycle-quotes-forward-string () + "Move point across the string directly after point. +This is the default value of +`cycle-quotes-forward-string-function'." + (forward-sexp) + ;; `forward-sexp' fails to jump to the matching quote in some modes, + ;; for instance `js2-mode'. + (skip-syntax-backward "^\"|")) + +(defvar-local cycle-quotes-quote-chars-function + #'cycle-quotes-quote-chars + "Function returning quote characters for the current mode.") + +(defvar-local cycle-quotes-surrounding-quote-function + #'cycle-quotes-surrounding-quote + "Function returning the quote character surrounding point. +It should return the surrounding quote character if point is +inside a string. If not, it should return nil.") + +(defvar-local cycle-quotes-forward-string-function + #'cycle-quotes-forward-string + "Function moving point across a string directly after point. +For instance, if this function is called when point is at `★': + + ★'Let\'s go!' + +Point should end up at the end up after the last quote: + + 'Let\'s go!'★ + +Just calling `forward-sexp' should work for most modes, where +quote characters have been given string quote syntax.") (defun cycle-quotes--next-quote-char (char) "Return quote char after CHAR." @@ -93,10 +135,13 @@ character removed." "Cycle between string quote styles." (interactive) (unless (eq major-mode cycle-quotes--quote-chars-mode) - (cycle-quotes--set-quote-chars)) + (let ((quote-chars (funcall cycle-quotes-quote-chars-function))) + (setq-local cycle-quotes--quote-chars quote-chars)) + (setq-local cycle-quotes--quote-chars-mode major-mode)) (if (< (length cycle-quotes--quote-chars) 2) (message "The current mode has no alternative quote syntax") - (let ((quote-char (nth 3 (syntax-ppss)))) + (let ((quote-char + (funcall cycle-quotes-surrounding-quote-function))) (if (not quote-char) (message "Not inside a string") (let ((inside-generic-string (eq quote-char t)) @@ -127,10 +172,7 @@ character removed." (- (match-end 0) (match-beginning 0))))) (save-excursion (let ((beg (point))) - (forward-sexp) - ;; `forward-sexp' fails to jump to the matching quote - ;; in some modes, for instance `js2-mode'. - (skip-syntax-backward "^\"|") + (funcall cycle-quotes-forward-string-function) (cycle-quotes--fix-escapes (+ beg 1) (+ (point) 1) new-quote-char quote-char)) (delete-char (- repeat))