[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/swift-mode 4b2c628 372/496: Add forward/backward sentence
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/swift-mode 4b2c628 372/496: Add forward/backward sentence |
Date: |
Sun, 29 Aug 2021 11:34:09 -0400 (EDT) |
branch: elpa/swift-mode
commit 4b2c6284f7deaae363f2455e324071fecd97a2bf
Author: taku0 <mxxouy6x3m_github@tatapa.org>
Commit: taku0 <mxxouy6x3m_github@tatapa.org>
Add forward/backward sentence
---
swift-mode-beginning-of-defun.el | 431 ++++++++++++++++++++++++++++++++++++++-
swift-mode.el | 2 +
2 files changed, 430 insertions(+), 3 deletions(-)
diff --git a/swift-mode-beginning-of-defun.el b/swift-mode-beginning-of-defun.el
index dfac13e..afb324e 100644
--- a/swift-mode-beginning-of-defun.el
+++ b/swift-mode-beginning-of-defun.el
@@ -198,6 +198,8 @@ Return nil otherwise."
"Move backward to the beginning of a statement.
Statements include comments on the same line.
+When called at the beginning of a statement, keep the position.
+
Intended for internal use."
(let ((pos (point))
(previous-token (save-excursion
@@ -263,6 +265,17 @@ Intended for internal use."
(goto-char (swift-mode:token:end parent)))
(swift-mode:skip-whitespaces)))
+(defun swift-mode:backward-statement ()
+ "Move backward to the beginning of a statement.
+Statements include comments on the same line.
+
+Intended for internal use."
+ (let ((pos (point)))
+ (swift-mode:beginning-of-statement)
+ (when (eq pos (point))
+ (swift-mode:backward-token-or-list)
+ (swift-mode:beginning-of-statement))))
+
(defun swift-mode:end-of-statement ()
"Move forward to the end of a statement.
@@ -453,17 +466,17 @@ nesting level, mark the whole outer defun."
(and (eq last-command this-command) (mark t))
(region-active-p)))
;; Extends region.
- (let ((forward-p (<= (point) (mark))))
+ (let ((is-forward (<= (point) (mark))))
(set-mark
(save-excursion
(goto-char (mark))
- (if forward-p
+ (if is-forward
(swift-mode:end-of-defun)
(swift-mode:beginning-of-defun))
(point)))
;; Marks the whole outer defun if the mark got out of the outer defun.
(goto-char
- (if forward-p
+ (if is-forward
(min (point)
(save-excursion
(goto-char (mark))
@@ -585,6 +598,418 @@ Interactively, the behavior depends on
‘narrow-to-defun-include-comments’."
(message "No defun found"))
(narrow-to-region (car restriction) (cdr restriction))))))
+(defun swift-mode:forward-sentence (&optional arg)
+ "Skip forward sentences or statements.
+
+In comments or strings, skip a sentence. Otherwise, skip a stateement.
+
+With ARG, repeat ARG times. If ARG is negative, Skip backwards."
+ (interactive "p")
+ (setq arg (or arg 1))
+ (if (< arg 0)
+ (swift-mode:backward-sentence (- arg))
+ (while (< 0 arg)
+ (unless (swift-mode:forward-sentence-1)
+ (setq arg 1))
+ (setq arg (1- arg)))))
+
+(defun swift-mode:backward-sentence (&optional arg)
+"Skip backward sentences or statements.
+
+In comments or strings, skip a sentence. Otherwise, skip a stateement.
+
+With ARG, repeat ARG times. If ARG is negative, Skip forwards."
+ (interactive "p")
+ (setq arg (or arg 1))
+ (if (< arg 0)
+ (swift-mode:forward-sentence (- arg))
+ (while (< 0 arg)
+ (unless (swift-mode:backward-sentence-1)
+ (setq arg 1))
+ (setq arg (1- arg)))))
+
+(defun swift-mode:forward-sentence-1 ()
+ "Skip forward a sentence or a statement.
+
+In comments or strings, skip a sentence. Otherwise, skip a stateement."
+ (let ((chunk (swift-mode:chunk-after)))
+ (cond
+ ((swift-mode:chunk:comment-p chunk)
+ (swift-mode:forward-sentence-inside-comment
+ (swift-mode:chunk:single-line-comment-p chunk)))
+ ((swift-mode:chunk:string-p chunk)
+ (swift-mode:forward-sentence-inside-string))
+ ;; Spaces at the beginning of 2nd and following lines.
+ ;;
+ ;; class Foo {
+ ;; // aaa
+ ;;
+ ;; // bbb
+ ;; // ccc ← spaces before //
+ ;; // ddd ← spaces before //
+ ;; func foo() { // eee
+ ;; }
+ ;; }
+ ;;
+ ;; Not including spaces before the first line of blocks.
+ ((save-excursion
+ (skip-syntax-backward " ")
+ (skip-chars-backward "/")
+ (skip-syntax-backward " ")
+ (and (bolp)
+ (looking-at "[ \t]*//")
+ (not (bobp))
+ (progn
+ (backward-char)
+ (swift-mode:chunk:comment-p (swift-mode:chunk-after)))))
+ (forward-line 0)
+ (skip-syntax-forward " ")
+ (forward-char 2)
+ (swift-mode:forward-sentence-inside-comment t))
+ (t
+ (swift-mode:forward-sentence-inside-code)))))
+
+(defun swift-mode:backward-sentence-1 ()
+ "Skip backward a sentence or a statement.
+
+In comments or strings, skip a sentence. Otherwise, skip a stateement."
+ (let ((chunk (swift-mode:chunk-after)))
+ (cond
+ ((swift-mode:chunk:comment-p chunk)
+ (swift-mode:backward-sentence-inside-comment
+ (swift-mode:chunk:single-line-comment-p chunk)))
+ ((swift-mode:chunk:string-p chunk)
+ (swift-mode:backward-sentence-inside-string))
+ ;; Spaces at the beginning of 2nd and following lines.
+ ;;
+ ;; class Foo {
+ ;; // aaa
+ ;;
+ ;; // bbb
+ ;; // ccc ← spaces before //
+ ;; // ddd ← spaces before //
+ ;; func foo() { // eee
+ ;; }
+ ;; }
+ ;;
+ ;; Not including spaces before the first line of blocks.
+ ((save-excursion
+ (skip-syntax-backward " ")
+ (and (bolp)
+ (looking-at "[ \t]*//")
+ (not (bobp))
+ (progn
+ (backward-char)
+ (nth 4 (syntax-ppss)))))
+ (forward-line 0)
+ (skip-syntax-forward " ")
+ (forward-char 2)
+ (swift-mode:backward-sentence-inside-comment t))
+ (t
+ (swift-mode:backward-sentence-inside-code)))))
+
+(defun swift-mode:forward-sentence-inside-comment (is-single-line)
+ "Skip forward a sentence in a comment.
+
+IS-SINGLE-LINE should be non-nil when called inside a single-line comment."
+ (let ((current-buffer (current-buffer))
+ (pos (point))
+ (comment-block-end-position
+ (if is-single-line
+ (swift-mode:comment-block-end-position-single-line)
+ (swift-mode:comment-block-end-position-multiline)))
+ offset-from-line-end
+ line-count)
+ (swift-mode:with-temp-comment-buffer
+ (insert-buffer-substring current-buffer pos comment-block-end-position)
+ (goto-char (point-min))
+ ;; Removes comment starters.
+ (save-excursion
+ (if is-single-line
+ (while (re-search-forward "^[ \t]*/+[ \t]*" nil t)
+ (replace-match ""))
+ (when (looking-at "\\*+")
+ (replace-match ""))))
+ ;; Forwards sentence.
+ (let ((old-position (point)))
+ (unless (eobp)
+ (forward-sentence))
+ ;; Backwards spaces at end.
+ (when (save-excursion
+ (skip-syntax-forward " >")
+ (eobp))
+ (when (and (not is-single-line)
+ (eq (char-before) ?/))
+ (backward-char)
+ (skip-chars-backward "*"))
+ (skip-syntax-backward " >")
+ (when (< (point) old-position)
+ (goto-char old-position)))
+ ;; Locates current position.
+ (setq offset-from-line-end (- (line-end-position) (point)))
+ (setq line-count 0)
+ (while (< old-position (line-beginning-position))
+ (forward-line -1)
+ (setq line-count (1+ line-count)))))
+ (forward-line line-count)
+ (goto-char (- (line-end-position) offset-from-line-end))
+ (when (= (point) pos)
+ (goto-char comment-block-end-position)
+ (swift-mode:forward-sentence-inside-code))))
+
+(defun swift-mode:backward-sentence-inside-comment (is-single-line)
+ "Skip backward a sentence in a comment.
+
+IS-SINGLE-LINE should be non-nil when called inside a single-line comment."
+ (when (and (not is-single-line)
+ (eq (char-before) ?*)
+ (eq (char-after) ?/))
+ (backward-char))
+ (let ((current-buffer (current-buffer))
+ (pos (point))
+ (line-end-position (line-end-position))
+ (comment-block-beginning-position
+ (if is-single-line
+ (swift-mode:comment-block-beginning-position-single-line)
+ (swift-mode:comment-block-beginning-position-multiline)))
+ offset-from-line-end
+ line-count)
+ (swift-mode:with-temp-comment-buffer
+ (insert-buffer-substring
+ current-buffer comment-block-beginning-position line-end-position)
+ (goto-char (- (line-end-position) (- line-end-position pos)))
+ ;; Removes comment starters.
+ (save-excursion
+ (goto-char (point-min))
+ (if is-single-line
+ (while (re-search-forward "^[ \t]*/+[ \t]*" nil t)
+ (replace-match ""))
+ (when (looking-at "[ \t]*/\\*+[ \t\n]*")
+ (replace-match "")))
+ ;; Removes empty lines at the beginning.
+ (goto-char (point-min))
+ (when (looking-at "\n+")
+ (replace-match "")))
+ ;; Backwards sentence.
+ (let ((old-position (point)))
+ (backward-sentence)
+ ;; Locates current position.
+ (setq offset-from-line-end (- (line-end-position) (point)))
+ (setq line-count 0)
+ (while (< (line-end-position) old-position)
+ (forward-line 1)
+ (setq line-count (1+ line-count)))))
+ (forward-line (- line-count))
+ (goto-char (- (line-end-position) offset-from-line-end))
+ (when (<= pos (point))
+ (goto-char comment-block-beginning-position)
+ (swift-mode:backward-sentence-inside-code))))
+
+(defmacro swift-mode:with-temp-comment-buffer (&rest body)
+ "Eval BODY inside a temporary buffer keeping sentence related variables."
+ (declare (indent 0) (debug t))
+ (let ((current-sentence-end (make-symbol "current-sentence-end"))
+ (current-paragraph-start (make-symbol "current-paragraph-start"))
+ (current-paragraph-separate (make-symbol "current-paragraph-separate"))
+ (current-paragraph-ignore-fill-prefix
+ (make-symbol "current-paragraph-ignore-fill-prefix"))
+ (current-fill-prefix (make-symbol "current-fill-prefix")))
+ `(let ((,current-sentence-end (sentence-end))
+ (,current-paragraph-start paragraph-start)
+ (,current-paragraph-separate paragraph-separate)
+ (,current-paragraph-ignore-fill-prefix paragraph-ignore-fill-prefix)
+ (,current-fill-prefix fill-prefix))
+ (with-temp-buffer
+ (setq-local sentence-end ,current-sentence-end)
+ (setq-local paragraph-start ,current-paragraph-start)
+ (setq-local paragraph-separate ,current-paragraph-separate)
+ (setq-local paragraph-ignore-fill-prefix
+ ,current-paragraph-ignore-fill-prefix)
+ (setq-local fill-prefix ,current-fill-prefix)
+ ,@body))))
+
+(defun swift-mode:comment-block-end-position-single-line ()
+ "Return the position of the end of a single-line comment block.
+
+A single-line comment block consists of a single-line comments at the beginning
+of lines. Empty lines split blocks. Example:
+ // A block begins here.
+ //
+ // ...
+ //
+ // The block ends here.
+
+ // Another block begins here.
+ //
+ // ...
+ //
+ // The block ends here.
+ foo() // This comment is not a part of the block."
+ (save-excursion
+ (let ((comment-block-end-position nil))
+ (while (and (swift-mode:chunk:single-line-comment-p
+ (swift-mode:chunk-after))
+ (not (eobp)))
+ (end-of-line)
+ (setq comment-block-end-position (point))
+ (forward-line)
+ (skip-chars-forward " \t")
+ (skip-chars-forward "/"))
+ comment-block-end-position)))
+
+(defun swift-mode:comment-block-beginning-position-single-line ()
+ "Return the position of the beginning of a single-line comment block.
+
+A single-line comment block consists of a single-line comments at the beginning
+of lines. Empty lines split blocks. Example:
+ // A block begins here.
+ //
+ // ...
+ //
+ // The block ends here.
+
+ // Another block begins here.
+ //
+ // ...
+ //
+ // The block ends here.
+ foo() // This comment is not a part of the block."
+ (save-excursion
+ (let (chunk
+ (comment-block-beginning-position nil))
+ (while (progn
+ (setq chunk (swift-mode:chunk-after))
+ (swift-mode:chunk:single-line-comment-p chunk))
+ (goto-char (swift-mode:chunk:start chunk))
+ (setq comment-block-beginning-position (point))
+ (skip-syntax-backward " ")
+ (unless (bobp) (backward-char)))
+ comment-block-beginning-position)))
+
+(defun swift-mode:comment-block-end-position-multiline ()
+ "Return the position of the end of a multiline comment."
+ (save-excursion
+ (goto-char (swift-mode:chunk:start (swift-mode:chunk-after)))
+ (forward-comment 1)
+ (point)))
+
+(defun swift-mode:comment-block-beginning-position-multiline ()
+ "Return the position of the beginning of a multiline comment."
+ (swift-mode:chunk:start (swift-mode:chunk-after)))
+
+(defun swift-mode:forward-sentence-inside-string ()
+ "Skip forward a sentence in a string."
+ (let ((string-end-position
+ (save-excursion
+ (goto-char (swift-mode:chunk:start (swift-mode:chunk-after)))
+ (swift-mode:forward-string-chunk)
+ (point))))
+ (forward-sentence)
+ (when (< string-end-position (point))
+ (goto-char string-end-position)
+ (if (eq (char-before) ?\()
+ (swift-mode:forward-sentence-inside-interpolated-expression)
+ (swift-mode:forward-sentence-inside-code t)))))
+
+(defun swift-mode:backward-sentence-inside-string ()
+ "Skip backward a sentence in a string."
+ ;; Skips quotes at the end.
+ (when (and
+ (eq (char-after) ?\")
+ (save-excursion
+ (skip-chars-forward "\"")
+ (equal (get-text-property (1- (point)) 'syntax-table)
+ (string-to-syntax "|"))))
+ (skip-chars-backward "\""))
+ (let ((pos (point))
+ (string-beginning-position
+ (swift-mode:chunk:start (swift-mode:chunk-after))))
+ (backward-sentence)
+ (when (< (point) string-beginning-position)
+ (goto-char string-beginning-position)
+ (cond
+ ((and (looking-at "\"\"\"")
+ (save-excursion
+ (skip-chars-forward "\"")
+ (skip-syntax-forward " >")
+ (< (point) pos)))
+ (skip-chars-forward "\"")
+ (skip-syntax-forward " >"))
+ ((eq (char-after) ?\))
+ (swift-mode:backward-sentence-inside-interpolated-expression))
+ (t
+ (swift-mode:backward-sentence-inside-code t))))))
+
+(defun swift-mode:forward-sentence-inside-interpolated-expression ()
+ "Skip forward a sentence in a interpolated expression."
+ (let* ((string-chunk (swift-mode:find-following-string-chunk))
+ (interpolated-expression-end-position
+ (swift-mode:token:start string-chunk)))
+ (swift-mode:forward-statement)
+ (when (< interpolated-expression-end-position (point))
+ (goto-char interpolated-expression-end-position)
+ (forward-char)
+ (swift-mode:forward-sentence-inside-string))))
+
+(defun swift-mode:backward-sentence-inside-interpolated-expression ()
+ "Skip backward a sentence in a interpolated expression."
+ (let* ((string-chunk (swift-mode:find-preceeding-string-chunk))
+ (interpolated-expression-beginning-position
+ (swift-mode:token:end string-chunk)))
+ (swift-mode:backward-statement)
+ (when (< (point) interpolated-expression-beginning-position)
+ (goto-char interpolated-expression-beginning-position)
+ (backward-char)
+ (swift-mode:backward-sentence-inside-string))))
+
+(defun swift-mode:find-following-string-chunk ()
+ "Return the following string-chunk token."
+ (save-excursion
+ (let (token)
+ (while (progn
+ (setq token (swift-mode:forward-token-or-list))
+ (not (memq
+ (swift-mode:token:type token)
+ '(outside-of-buffer
+ string-chunk-after-interpolated-expression)))))
+ token)))
+
+(defun swift-mode:find-preceeding-string-chunk ()
+ "Return the preceeding string-chunk token."
+ (save-excursion
+ (swift-mode:backward-sexps-until
+ '(string-chunk-before-interpolated-expression))))
+
+(defun swift-mode:forward-sentence-inside-code
+ (&optional keep-position-if-at-end-of-statement)
+ "Skip forward a statement.
+
+If KEEP-POSITION-IF-AT-END-OF-STATEMENT is non-nil and the cursor is already at
+the end of a statement, keep the position."
+ (if (and (get-text-property (point) 'syntax-multiline)
+ (not (bobp))
+ ;; Not just before a string.
+ (get-text-property (1- (point)) 'syntax-multiline))
+ (swift-mode:forward-sentence-inside-interpolated-expression)
+ (if keep-position-if-at-end-of-statement
+ (swift-mode:end-of-statement)
+ (swift-mode:forward-statement))))
+
+(defun swift-mode:backward-sentence-inside-code
+ (&optional keep-position-if-at-beginning-of-statement)
+ "Skip backward a statement.
+
+If KEEP-POSITION-IF-AT-BEGINNING-OF-STATEMENT is non-nil and the cursor is
+already at the beginning of a statement, keep the position."
+ (if (and (get-text-property (point) 'syntax-multiline)
+ (not (bobp))
+ ;; Not just before a string.
+ (get-text-property (1- (point)) 'syntax-multiline))
+ (swift-mode:backward-sentence-inside-interpolated-expression)
+ (if keep-position-if-at-beginning-of-statement
+ (swift-mode:beginning-of-statement)
+ (swift-mode:backward-statement))))
+
(provide 'swift-mode-beginning-of-defun)
;;; swift-mode-beginning-of-defun.el ends here
diff --git a/swift-mode.el b/swift-mode.el
index f9e9aba..44a5875 100644
--- a/swift-mode.el
+++ b/swift-mode.el
@@ -63,6 +63,8 @@
(define-key map (kbd "ESC <C-end>") #'swift-mode:end-of-defun)
(define-key map (kbd "C-M-h") #'swift-mode:mark-defun)
(define-key map (kbd "C-x n d") #'swift-mode:narrow-to-defun)
+ (define-key map (kbd "M-a") #'swift-mode:backward-sentence)
+ (define-key map (kbd "M-e") #'swift-mode:forward-sentence)
(easy-menu-define swift-menu map "Swift Mode menu"
`("Swift"
- [nongnu] elpa/swift-mode 5df00bc 367/496: Fix typo, (continued)
- [nongnu] elpa/swift-mode 5df00bc 367/496: Fix typo, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode 1167fec 369/496: Fix comment, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode e58e4e0 368/496: Tweak test, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode 089853c 384/496: Fix typo "identifer" to "identifier", ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode e81ab53 381/496: Fix comments, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode 8d4a5a5 373/496: Add kill/mark/narrow-to-sentence, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode a042764 374/496: Fix indentation of comments, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode 8c45f69 383/496: Bump version to 4.0.1, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode ed03fde 377/496: Refactor tests, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode 1970f1d 380/496: Fix `beginning-of-defun' inside class methods, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode 4b2c628 372/496: Add forward/backward sentence,
ELPA Syncer <=
- [nongnu] elpa/swift-mode c67b950 388/496: Fixes which-function-mode hang when running swift-mode:current-defun-name in a non swift-mode buffer., ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode 9809fb6 391/496: Add more comprehensive support for highlighting built-ins, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode 544c265 397/496: Move macro before its use, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode 3751335 398/496: Tweak and checkdoc compliance, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode 4c5a1d9 401/496: Add support for running on device via ios-deploy, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode 7ea1d4e 404/496: Bump version to 5.0.0, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode e229d69 405/496: Fix typo, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode cfbec0a 406/496: Update copyrights, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode 7f89b8c 411/496: Change swift-mode:mark-defun to match Emacs 26, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode c48907c 407/496: Update font-lock for standard library, ELPA Syncer, 2021/08/29