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

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

[nongnu] elpa/typescript-mode e25c7ddb8a 062/222: Fix indentation of fun


From: ELPA Syncer
Subject: [nongnu] elpa/typescript-mode e25c7ddb8a 062/222: Fix indentation of funcs with return annotations.
Date: Sun, 6 Feb 2022 16:59:16 -0500 (EST)

branch: elpa/typescript-mode
commit e25c7ddb8a6418c7cf9d596d8cb4ab51d1b2b2ef
Author: Louis-Dominique Dubeau <ldd@lddubeau.com>
Commit: Louis-Dominique Dubeau <ldd@lddubeau.com>

    Fix indentation of funcs with return annotations.
---
 test-files/indentation-reference-document.ts | 207 +++++++++++++++++++++++++++
 typescript-mode.el                           | 147 ++++++++++++++++++-
 2 files changed, 352 insertions(+), 2 deletions(-)

diff --git a/test-files/indentation-reference-document.ts 
b/test-files/indentation-reference-document.ts
index da1dd7d80c..7a6ee48680 100644
--- a/test-files/indentation-reference-document.ts
+++ b/test-files/indentation-reference-document.ts
@@ -50,6 +50,8 @@ namespace ts.server {
         pid: number;
     }
 
+    export type SomeType = string | number;
+
     class Logger implements ts.server.Logger {
         private firstInGroup = true;
 
@@ -237,3 +239,208 @@ namespace ts.server {
             /def/);
     }
 }
+
+// Tests for return value annotations.
+
+// Unannotated.
+function moo(x: any,
+             f: string) {
+    return null;
+}
+
+// Parens around return type.
+function foo(x: any,
+             f: string): ((a: number) => void) {
+    return null;
+}
+
+class Moo {}
+
+// Type guard.
+function foo2(x: any,
+              f: string): x is Moo {
+    return x.something === 1;
+}
+
+// Usage of generic in return type.
+function foo3(a: number,
+              b: number): Array<Array<(a: number) => void>> {
+    return [];
+}
+
+// Curly brackets in return type.
+function bar(a: number,
+             b: number): { z(): string } {
+    return {
+        z() { return "a"; }
+    };
+}
+
+// The sequence ): in the return type.
+function bif(a: number,
+             b: number): "abc):d" {
+    return "abc):d";
+}
+
+// Comment where the return type would appear.
+function gogo(a: number,
+              b: number) /* foo */ {
+}
+
+// Function call in the list of arguments.
+function foo5(x: any,
+              f: string = bif(1, 2)): ((a: number) => void) {
+    return null;
+}
+
+// Dotted name in return type.
+function foo6(x: any,
+              f: number): ts.server.SomeType {
+    return "string";
+}
+
+// First parameter has function signature.
+function foo7(x: (a: string, b: string) => Array<number>,
+              b: number): void {
+}
+
+// Second parameter has function signature.
+function foo7b(a: string,
+               x: (a: number, b: number) => Array<number>): void {
+}
+
+function foo8(): void {
+    // Arrow function in first parameter.
+    foo7((a: string): Array<number> => {
+             return [1];
+         },
+         1);
+
+    // Arrow function in first parameter, line break in parameters.
+    foo7((a: string,
+          b: string): Array<number> => {
+             return [1];
+         },
+         1);
+
+    // Arrow function in second parameter.
+    foo7b("1",
+          (a: number, b: number): Array<number> => {
+              return [1];
+          });
+
+    // Arrow function in second parameter, line break in parameters.
+    foo7b("1",
+          (a: number,
+           b: number): Array<number> => {
+              return [1];
+          });
+}
+
+// Arrow function assignment, line break in parameters.
+const foo9 = (a: string,
+              b: string): Array<number> => {
+    return [1];
+}
+
+// Arrow function assignment.
+const foo10 = (a: string, b: string): Array<number> => {
+    return [1];
+}
+
+// Arrow function assignment, parenthesized.
+const foo11 = ((a: string, b: string): Array<number> => {
+                   return [1];
+               });
+
+function foo12(): void {
+    // Function in first parameter.
+    foo7(function (a: string): Array<number> {
+             return [1];
+         },
+         1);
+
+    // Function in first parameter, line break in parameters.
+    foo7(function (a: string,
+                   b: string): Array<number> {
+             return [1];
+         },
+         1);
+
+    // Arrow function in second parameter.
+    foo7b("1",
+          function (a: number, b: number): Array<number> {
+              return [1];
+          });
+
+    // Arrow function in second parameter, line break in parameters.
+    foo7b("1",
+          function (a: number,
+                    b: number): Array<number> {
+              return [1];
+          });
+
+    // Same cases as above but named.
+
+    // Function in first parameter.
+    foo7(function _mip(a: string): Array<number> {
+             return [1];
+         },
+         1);
+
+    // Function in first parameter, line break in parameters.
+    foo7(function _mip(a: string,
+                       b: string): Array<number> {
+             return [1];
+         },
+         1);
+
+    // Arrow function in second parameter.
+    foo7b("1",
+          function _mip(a: number, b: number): Array<number> {
+              return [1];
+          });
+
+    // Arrow function in second parameter, line break in parameters.
+    foo7b("1",
+          function _mip(a: number,
+                        b: number): Array<number> {
+              return [1];
+          });
+
+    // Same cases as above but generators.
+
+    // Function in first parameter.
+    foo7(function *(a: string): Array<number> {
+             return [1];
+         },
+         1);
+
+    // Function in first parameter, line break in parameters.
+    foo7(function *(a: string,
+                    b: string): Array<number> {
+             return [1];
+         },
+         1);
+
+    // Arrow function in second parameter.
+    foo7b("1",
+          function *(a: number, b: number): Array<number> {
+              return [1];
+          });
+
+    // Arrow function in second parameter, line break in parameters.
+    foo7b("1",
+          function *(a: number,
+                     b: number): Array<number> {
+              return [1];
+          });
+
+    // Check that JavaScript objects are still handled right. Whether
+    // in the 1st or subsequent position of a call.
+    function smurf(a: {}, b: {}) {}
+    smurf({
+          },
+          {
+          });
+}
diff --git a/typescript-mode.el b/typescript-mode.el
index 8baad489d3..e69a3db45b 100644
--- a/typescript-mode.el
+++ b/typescript-mode.el
@@ -1759,6 +1759,140 @@ nil."
          (list (cons 'c typescript-comment-lineup-func))))
     (c-get-syntactic-indentation (list (cons symbol anchor)))))
 
+(defun typescript--backward-over-generic-parameter-list ()
+  "Search backward for the start of a generic's parameter list and move to it.
+
+This is a utility function for
+`typescript--backward-to-parameter-list'.
+
+This function must be called with the point placed on the final >
+of the generic's parameter list.  It will scan backwards to find
+the start.  If successful, it will move the point to the start of
+the list.  If not, it does not move the point.
+
+Returns nil on failure, or the position to which the point was
+moved on success."
+  (when (eq (char-after) ?>)
+    (let ((depth 1))
+      (loop named search-loop
+            while (> depth 0)
+            do (progn
+                 (unless (re-search-backward "[<>]" nil t)
+                   (cl-return-from search-loop nil))
+                 (cond
+                  ((looking-at ">")
+                   (unless (eq (char-before) ?=)
+                     (setq depth (1+ depth))))
+                  ((looking-at "<") (setq depth (1- depth)))))
+            finally return (point)))))
+
+(defun typescript--backward-to-parameter-list ()
+  "Search backward for the end of a parameter list and move to it.
+
+This is a utility function for `typescript--proper-indentation'.
+
+This function must be called with the point placed before an
+opening curly brace.  It will try to skip over the type
+annotation that would mark the return value of a function and
+move to the end of the parameter list.  If it is unsuccessful, it
+does not move the point. \"Unsuccessful\" here also means that
+the position at which we started did not in fact mark the
+beginning of a function. The curly brace belonged to some other
+syntactic construct than a function.
+
+Returns nil on failure, or the position to which the point was
+moved on success."
+  (let ((location
+         (or
+          ;; This handles the case of a function with return type annotation.
+          (save-excursion
+            (loop named search-loop
+                  do (progn
+                       (if (eq (char-before) ?>)
+                           (if (looking-back "=>" (- (point) 2))
+                               ;; Move back over the arrow of an arrow 
function.
+                               (backward-char 2)
+                             ;; Otherwise, we are looking at the end of the 
parameters
+                             ;; list of a generic. We need to move back over 
the list.
+                             (backward-char)
+                             
(typescript--backward-over-generic-parameter-list))
+                         ;; General case: we just move back over the current 
sexp.
+                         (condition-case nil
+                             (backward-sexp)
+                           (scan-error nil)))
+                       (typescript--backward-syntactic-ws)
+                       (let ((before (char-before)))
+                         ;; Check whether we are at "):".
+                         (when (and (eq before ?\:)
+                                    (progn
+                                      (backward-char)
+                                      (skip-syntax-backward " ")
+                                      (eq (char-before) ?\))))
+                           ;; Success! This the end of the parameter list.
+                           (cl-return-from search-loop (point)))
+                         ;; All the following cases are constructs that are 
allowed to
+                         ;; appear between the opening brace of a function and 
the
+                         ;; end of a parameter list.
+                         (unless
+                             (or
+                              ;; End of a generic.
+                              (eq before ?>)
+                              ;; Union of types
+                              (eq before ?|)
+                              ;; Dotted names
+                              (eq before ?.)
+                              ;; Typeguard (eg. foo is SomeClass)
+                              (looking-back "is" (- (point) 2))
+                              ;; This is also dealing with dotted names. This 
may come
+                              ;; into play if a jump back moves over an entire 
dotted
+                              ;; name at once.
+                              ;;
+                              ;; The earlier test for dotted names comes into 
play if the
+                              ;; logic moves over one part of a dotted name at 
a time (which
+                              ;; is what `backward-sexp` normally does).
+                              (looking-back typescript--dotted-name-re nil)
+                             )
+                           ;; We did not encounter a valid construct, so
+                           ;; the search is unsuccessful.
+                           (cl-return-from search-loop nil))))))
+          ;; This handles the case of a function without return type 
annotation.
+          (progn
+            (typescript--backward-syntactic-ws)
+            (when (eq (char-before) ?\))
+              (point))))))
+    (when location
+      (goto-char location))))
+
+(defun typescript--backward-to-function-start ()
+  "Search backward for the start of a function and move to it.
+
+This function moves the point to the start of the function and
+returns the point.
+
+The point must already be at the start of the parameter list.
+See `typescript--backward-to-parameter-list' for a function that
+does this.  If the point is not at the start of the parameter
+list, this function may return an incorrect result."
+  (goto-char
+   (or (condition-case nil
+           (save-excursion
+             (skip-syntax-backward " ")
+             (backward-sexp)
+             ;; First, check for an anonymous function.
+             (or (when (looking-at "function")
+                   (point))
+                 ;; Otherwise check if we have a named function.
+                 (progn
+                   (skip-syntax-backward " ")
+                   (backward-sexp)
+                   (when (looking-at "function")
+                     (point)))))
+         ;; backward-sexp may cause a scan-error if the sexp is
+         ;; incomplete.
+         (scan-error nil))
+       ;; If we get here, what we are looking at is an arrow function.
+       (point))))
+
 (defun typescript--proper-indentation (parse-status)
   "Return the proper indentation for the current line."
   (save-excursion
@@ -1777,8 +1911,17 @@ nil."
              (if (looking-at "[({[]\\s-*\\(/[/*]\\|$\\)")
                  (progn
                    (skip-syntax-backward " ")
-                  (when (eq (char-before) ?\)) (backward-list))
-                   (back-to-indentation)
+                   (when (or (typescript--backward-to-parameter-list)
+                             (eq (char-before) ?\)))
+                     (backward-list))
+                   ;; If the parameter list is preceded by (, take the
+                   ;; start of the parameter list as our reference.
+                   ;; This allows handling functions in parameter
+                   ;; lists. Otherwise, we want to go back to the
+                   ;; start of function declaration.
+                   (when (not (and (typescript--backward-to-function-start)
+                                   (eq (char-before) ?\()))
+                     (back-to-indentation))
                    (cond (same-indent-p
                           (current-column))
                          (continued-expr-p



reply via email to

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