Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 138 lines (122 sloc) 4.897 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
(defun js2r--ensure-newline ()
  (if (and (not (looking-at "\s*\n"))
           (not (looking-back "\n\s*")))
      (newline-and-indent)))

(defun js2r--ensure-just-one-space ()
  (interactive)
  (while (or (looking-at "\s*\n")
             (looking-back "\n\s*"))
    (when (looking-at "\n")
      (delete-char 1))
    (when (looking-back "\n\s")
      (backward-char)
      (delete-char -1))
    (just-one-space))
  (just-one-space))

(defmacro js2r--create-bracketed-whitespace-traverser
  (name ws-fix-func looking-at-start-func
goto-closest-start-func subexpr-str)
  "Build a function to expand or contract a given type of
bracketed expression, i.e., function body, object literal, or
array (any of which may be nested).
Parameters:
name: name of the function to be built
ws-fix-func: function to adjust whitespace at point
looking-at-start-func: returns t if point is at
the start of the bracketed
thing we want to act on
goto-closest-start-func: moves point if necessary
until looking-at-start-func
is true
subexpr-str: literal delimiter of parts of the
thing to be expanded or contracted"
  `(defun ,name ()
     (interactive)
     (save-excursion
       (if (not ,looking-at-start-func)
           ,goto-closest-start-func)
       (let ((end (make-marker)))
         (set-marker end (save-excursion
                           (forward-list)
                           (point)))
         (forward-char)
         ,ws-fix-func
         (while (< (point) end)
           (while (js2r--point-inside-string-p)
             (forward-char))
           (when (looking-at ,subexpr-str)
             (forward-char)
             ,ws-fix-func)
           (if (looking-at "\\s(")
               (forward-list)
             (forward-char)))
         (backward-char)
         ,ws-fix-func))))

(defun js2r--looking-at-object-start ()
  (and (looking-at "{")
       (not (looking-back ")[\s\n]*"))))

(defun js2r--goto-closest-object-start ()
  (while (not (js2r--looking-at-object-start))
    (if (eq (car (syntax-ppss)) 0)
        (error "Cursor is not on an object")
      (goto-char (nth 1 (syntax-ppss))))))

(js2r--create-bracketed-whitespace-traverser js2r-expand-object
(js2r--ensure-newline)
(js2r--looking-at-object-start)
(js2r--goto-closest-object-start)
",")

(js2r--create-bracketed-whitespace-traverser js2r-contract-object
(js2r--ensure-just-one-space)
(js2r--looking-at-object-start)
(js2r--goto-closest-object-start)
",")

(defun js2r--looking-at-array-start ()
  (looking-at "\\["))

(defun js2r--goto-closest-array-start ()
  (while (not (js2r--looking-at-array-start))
    (if (eq (car (syntax-ppss)) 0)
        (error "Cursor is not on an array")
      (goto-char (nth 1 (syntax-ppss))))))

(js2r--create-bracketed-whitespace-traverser js2r-expand-array
(js2r--ensure-newline)
(js2r--looking-at-array-start)
(js2r--goto-closest-array-start)
",")

(js2r--create-bracketed-whitespace-traverser js2r-contract-array
(js2r--ensure-just-one-space)
(js2r--looking-at-array-start)
(js2r--goto-closest-array-start)
",")

(defun js2r--looking-at-function-start ()
  (and (looking-at "{")
       (looking-back
;; This horrible-looking regexp is actually pretty simple. It
;; matches "function <optional_name> (<optional_parameters,...>)"
;; allowing for whitespace. TODO: support Unicode in function and
;; parameter names.
(concat "function[\s\n]*"
"\\\([a-zA-Z_$][a-zA-Z_$0-9]*[\s\n]*\\\)?"
"\(\\\([a-zA-Z_$][a-zA-Z_$0-9]*"
"[\s\n]*,[\s\n]*\\\)*[\s\n]*"
"\\\([a-zA-Z_$][a-zA-Z_$0-9]*[\s\n]*\\\)*"
"[\s\n]*\)[\s\n]*"))))

(defun js2r--goto-closest-function-start ()
  (while (not (js2r--looking-at-function-start))
    (if (eq (car (syntax-ppss)) 0)
        (error "Cursor is not on a function body")
      (goto-char (nth 1 (syntax-ppss))))))

(js2r--create-bracketed-whitespace-traverser js2r-expand-function
(js2r--ensure-newline)
(js2r--looking-at-function-start)
(js2r--goto-closest-function-start)
";")

;; TODO: It'd be great if js2r-contract-function could recognize
;; newlines that are implied statement terminators and insert
;; semicolons correctly, but that would probably mean not using the
;; same macro as the other "contract" function definitions.
(js2r--create-bracketed-whitespace-traverser js2r-contract-function
(js2r--ensure-just-one-space)
(js2r--looking-at-function-start)
(js2r--goto-closest-function-start)
";")

(provide 'js2r-formatting)
Something went wrong with that request. Please try again.