emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[nongnu] elpa/go-mode d6aa01a 287/495: Merge branch 'movement'


From: ELPA Syncer
Subject: [nongnu] elpa/go-mode d6aa01a 287/495: Merge branch 'movement'
Date: Sat, 7 Aug 2021 09:05:33 -0400 (EDT)

branch: elpa/go-mode
commit d6aa01a1dc299efd1ab1470b2c33b39deb8bd315
Merge: dccb56c abc56d4
Author: Dominik Honnef <dominik@honnef.co>
Commit: Dominik Honnef <dominik@honnef.co>

    Merge branch 'movement'
    
    This adds new functions for jumping to various parts of a function's
    signature:
    
    - go-goto-arguments
    - go-goto-docstring
    - go-goto-function
    - go-goto-function-name
    - go-goto-return-values
    - go-goto-method-receiver
    
    All of these functions are aware of anonymous functions.
    go-goto-docstring and go-goto-method-receiver, however, will skip over
    anonymous functions if called interactively.
    
    All of these functions accept a prefix argument to force them to skip
    over anonymous functions.
    
    All of these functions, and the existing go-goto-imports, are added to a
    new prefix keymap, bound to `C-c C-g`.
    
    Closes gh-117
---
 README.md  |  18 ++++-
 go-mode.el | 248 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 264 insertions(+), 2 deletions(-)

diff --git a/README.md b/README.md
index 6e5a780..826c725 100644
--- a/README.md
+++ b/README.md
@@ -26,7 +26,8 @@ the following extra features to provide an improved 
experience:
   - `go-download-play` to download a Playground entry into a new
     buffer
 - Managing imports
-  - A function for jumping to the file's imports (`go-goto-imports`)
+  - A function for jumping to the file's imports (`go-goto-imports` -
+    `C-c C-g i`)
   - A function for adding imports, including tab completion
     (`go-import-add`, bound to `C-c C-a`)
   - A function for removing or commenting unused imports
@@ -40,6 +41,21 @@ the following extra features to provide an improved 
experience:
 - Basic support for imenu (functions and variables)
 - Built-in support for displaying code coverage as calculated by `go
   test` (`go-coverage`)
+- Several functions for jumping to and manipulating the individual
+  parts of function signatures. These functions support anonymous
+  functions, but are smart enough to skip them when required (e.g.
+  when jumping to a method receiver or docstring.)
+  - Jump to the argument list (`go-goto-arguments` - `C-c C-g a`)
+  - Jump to the docstring, create it if it does not exist yet
+    (`go-goto-docstring` - `C-c C-g d`).
+  - Jump to the function keyword (`go-goto-function` - `C-c C-g f`)
+  - Jump to the function name (`go-goto-function-name` - `C-c C-g n`)
+  - Jump to the return values (`go-goto-return-values` - `C-c C-g r`)
+  - Jump to the method receiver, adding a pair of parentheses if no
+    method receiver exists (`go-goto-method-receiver` - `C-c C-g m`).
+
+  All of these functions accept a prefix argument (`C-u`), causing
+  them to skip anonymous functions.
 
 # Installation
 
diff --git a/go-mode.el b/go-mode.el
index 851b937..bf5505e 100644
--- a/go-mode.el
+++ b/go-mode.el
@@ -365,6 +365,15 @@ For mode=set, all covered lines will have this weight."
      (2 (15 . nil))  ;; 15 = "generic string"
      (3 (7 . ?`)))))
 
+(let ((m (define-prefix-command 'go-goto-map)))
+  (define-key m "a" #'go-goto-arguments)
+  (define-key m "d" #'go-goto-docstring)
+  (define-key m "f" #'go-goto-function)
+  (define-key m "i" #'go-goto-imports)
+  (define-key m "m" #'go-goto-method-receiver)
+  (define-key m "n" #'go-goto-function-name)
+  (define-key m "r" #'go-goto-return-values))
+
 (defvar go-mode-map
   (let ((m (make-sparse-keymap)))
     (define-key m "}" #'go-mode-insert-and-indent)
@@ -376,6 +385,7 @@ For mode=set, all covered lines will have this weight."
     (define-key m (kbd "C-c C-j") #'godef-jump)
     (define-key m (kbd "C-x 4 C-c C-j") #'godef-jump-other-window)
     (define-key m (kbd "C-c C-d") #'godef-describe)
+    (define-key m (kbd "C-c C-g") 'go-goto-map)
     m)
   "Keymap used by Go mode to implement electric keys.")
 
@@ -600,7 +610,7 @@ current line will be returned."
     ;; breaks if there's a comment between the struct/interface keyword and
     ;; bracket, like this:
     ;;
-    ;;     struct /* why? */ { 
+    ;;     struct /* why? */ {
     (while (progn
       (skip-chars-forward "^{")
       (forward-char)
@@ -845,7 +855,13 @@ The following extra functions are defined:
 - `godoc'
 - `go-import-add'
 - `go-remove-unused-imports'
+- `go-goto-arguments'
+- `go-goto-docstring'
+- `go-goto-function'
+- `go-goto-function-name'
 - `go-goto-imports'
+- `go-goto-return-values'
+- `go-goto-method-receiver'
 - `go-play-buffer' and `go-play-region'
 - `go-download-play'
 - `godef-describe' and `godef-jump'
@@ -1562,6 +1578,236 @@ for."
       (if (not (eq cur-buffer (current-buffer)))
           (display-buffer (current-buffer) 
`(,go-coverage-display-buffer-func))))))
 
+(defun go-goto-function (&optional arg)
+  "Go to the function defintion (named or anonymous) surrounding point.
+
+If we are on a docstring, follow the docstring down.
+If no function is found, assume that we are at the top of a file
+and search forward instead.
+
+If point is looking at the func keyword of an anonymous function,
+go to the surrounding function.
+
+If ARG is non-nil, anonymous functions are ignored."
+  (interactive "P")
+  (let ((p (point)))
+    (cond
+     ((save-excursion
+        (beginning-of-line)
+        (looking-at "^//"))
+      ;; In case we are looking at the docstring, move on forward until we are
+      ;; not anymore
+      (beginning-of-line)
+      (while (looking-at "^//")
+        (forward-line 1))
+      ;; If we are still not looking at a function, retry by calling self 
again.
+      (when (not (looking-at "\\<func\\>"))
+        (go-goto-function arg)))
+
+     ;; If we're already looking at an anonymous func, look for the
+     ;; surrounding function.
+     ((and (looking-at "\\<func\\>")
+           (not (looking-at "^func\\>")))
+      (re-search-backward "\\<func\\>" nil t))
+
+     ((not (looking-at "\\<func\\>"))
+      ;; If point is on the "func" keyword, step back a word and retry
+      (if (string= (symbol-name (symbol-at-point)) "func")
+          (backward-word)
+        ;; If we are not looking at the beginning of a function line, do a 
regexp
+        ;; search backwards
+        (re-search-backward "\\<func\\>" nil t))
+
+      ;; If nothing is found, assume that we are at the top of the file and
+      ;; should search forward instead.
+      (when (not (looking-at "\\<func\\>"))
+        (re-search-forward "\\<func\\>" nil t)
+        (forward-word -1))
+
+      ;; If we have landed at an anonymous function, it is possible that we
+      ;; were not inside it but below it. If we were not inside it, we should
+      ;; go to the containing function.
+      (while (and (not (go--in-function-p p))
+                  (not (looking-at "^func\\>")))
+        (go-goto-function arg)))))
+
+  (cond
+   ((go-in-comment-p)
+    ;; If we are still in a comment, redo the call so that we get out of it.
+    (go-goto-function arg))
+
+   ((and (looking-at "\\<func(") arg)
+    ;; If we are looking at an anonymous function and a prefix argument has
+    ;; been supplied, redo the call so that we skip the anonymous function.
+    (go-goto-function arg))))
+
+(defun go--goto-opening-curly-brace ()
+  ;; Find the { that starts the function, i.e., the next { that isn't
+  ;; preceded by struct or interface, or a comment or struct tag.  BUG:
+  ;; breaks if there's a comment between the struct/interface keyword and
+  ;; bracket, like this:
+  ;;
+  ;;     struct /* why? */ {
+  (go--goto-return-values)
+  (while (progn
+           (skip-chars-forward "^{")
+           (forward-char)
+           (or (go-in-string-or-comment-p)
+               (looking-back "\\(struct\\|interface\\)\\s-*{"))))
+  (backward-char))
+
+(defun go--in-function-p (compare-point)
+  "Return t if COMPARE-POINT lies inside the function immediately surrounding 
point."
+  (save-excursion
+    (when (not (looking-at "\\<func\\>"))
+      (go-goto-function))
+    (let ((start (point)))
+      (go--goto-opening-curly-brace)
+
+      (unless (looking-at "{")
+        (error "expected to be looking at opening curly brace"))
+      (forward-list 1)
+      (and (>= compare-point start)
+           (<= compare-point (point))))))
+
+(defun go-goto-function-name (&optional arg)
+  "Go to the name of the current function.
+
+If the function is a test, place point after 'Test'.
+If the function is anonymous, place point on the 'func' keyword.
+
+If ARG is non-nil, anonymous functions are skipped."
+  (interactive "P")
+  (when (not (looking-at "\\<func\\>"))
+    (go-goto-function arg))
+  ;; If we are looking at func( we are on an anonymous function and
+  ;; nothing else should be done.
+  (when (not (looking-at "\\<func("))
+    (let ((words 1)
+          (chars 1))
+      (when (looking-at "\\<func (")
+        (setq words 3
+              chars 2))
+      (forward-word words)
+      (forward-char chars)
+      (when (looking-at "Test")
+        (forward-char 4)))))
+
+(defun go-goto-arguments (&optional arg)
+  "Go to the arguments of the current function.
+
+If ARG is non-nil, anonymous functions are skipped."
+  (interactive "P")
+  (go-goto-function-name arg)
+  (forward-word 1)
+  (forward-char 1))
+
+(defun go--goto-return-values (&optional arg)
+  "Go to the declaration of return values for the current function."
+  (go-goto-arguments arg)
+  (backward-char)
+  (forward-list)
+  (forward-char))
+
+(defun go-goto-return-values (&optional arg)
+  "Go to the return value declaration of the current function.
+
+If there are multiple ones contained in a parenthesis, enter the parenthesis.
+If there is none, make space for one to be added.
+
+If ARG is non-nil, anonymous functions are skipped."
+  (interactive "P")
+  (go--goto-return-values arg)
+
+  ;; Opening parenthesis, enter it
+  (when (looking-at "(")
+    (forward-char 1))
+
+  ;; No return arguments, add space for adding
+  (when (looking-at "{")
+    (insert " ")
+    (backward-char 1)))
+
+(defun go-goto-method-receiver (&optional arg)
+  "Go to the receiver of the current method.
+
+If there is none, add parenthesis to add one.
+
+Anonymous functions cannot have method receivers, so when this is called
+interactively anonymous functions will be skipped. If called programmatically,
+an error is raised unless ARG is non-nil."
+  (interactive "P")
+
+  (when (and (not (called-interactively-p 'interactive))
+             (not arg)
+             (go--in-anonymous-funcion-p))
+    (error "Anonymous functions cannot have method receivers"))
+
+  (go-goto-function t)  ; Always skip anonymous functions
+  (forward-char 5)
+  (when (not (looking-at "("))
+    (save-excursion
+      (insert "() ")))
+  (forward-char 1))
+
+(defun go-goto-docstring (&optional arg)
+  "Go to the top of the docstring of the current function.
+
+If there is none, add one beginning with the name of the current function.
+
+Anonymous functions do not have docstrings, so when this is called
+interactively anonymous functions will be skipped. If called programmatically,
+an error is raised unless ARG is non-nil."
+  (interactive "P")
+
+  (when (and (not (called-interactively-p 'interactive))
+             (not arg)
+             (go--in-anonymous-funcion-p))
+    (error "Anonymous functions do not have docstrings"))
+
+  (go-goto-function t)
+  (forward-line -1)
+  (beginning-of-line)
+
+  (while (looking-at "^//")
+    (forward-line -1))
+  (forward-line 1)
+  (beginning-of-line)
+
+  (cond
+   ;; If we are looking at an empty comment, add a single space in front of it.
+   ((looking-at "^//$")
+    (forward-char 2)
+    (insert (format " %s " (go--function-name t))))
+   ;; If we are not looking at the function signature, we are looking at a 
docstring.
+   ;; Move to the beginning of the first word of it.
+   ((not (looking-at "^func"))
+    (forward-char 3))
+   ;; If we are still at the function signature, we should add a new docstring.
+   (t
+    (forward-line -1)
+    (newline)
+    (insert (format "// %s " (go--function-name t))))))
+
+(defun go--function-name (&optional arg)
+  "Return the name of the surrounding function.
+
+If ARG is non-nil, anonymous functions will be ignored and the
+name returned will be that of the top-level function. If ARG is
+nil and the surrounding function is anonymous, nil will be
+returned."
+  (when (or (not (go--in-anonymous-funcion-p))
+            arg)
+    (save-excursion
+      (go-goto-function-name t)
+      (symbol-name (symbol-at-point)))))
+
+(defun go--in-anonymous-funcion-p ()
+  "Return t if point is inside an anonymous function, nil otherwise."
+  (save-excursion
+    (go-goto-function)
+    (looking-at "\\<func(")))
+
 (provide 'go-mode)
 
 ;;; go-mode.el ends here



reply via email to

[Prev in Thread] Current Thread [Next in Thread]