251 lines
8.9 KiB
EmacsLisp
251 lines
8.9 KiB
EmacsLisp
;;; js2r-formatting.el --- Private helper functions for formatting -*- lexical-binding: t; -*-
|
|
|
|
;; Copyright (C) 2012-2014 Magnar Sveen
|
|
;; Copyright (C) 2015-2016 Magnar Sveen and Nicolas Petton
|
|
|
|
;; Author: Magnar Sveen <magnars@gmail.com>,
|
|
;; Nicolas Petton <nicolas@petton.fr>
|
|
;; Keywords: conveniences
|
|
|
|
;; This program is free software; you can redistribute it and/or modify
|
|
;; it under the terms of the GNU General Public License as published by
|
|
;; the Free Software Foundation, either version 3 of the License, or
|
|
;; (at your option) any later version.
|
|
|
|
;; This program is distributed in the hope that it will be useful,
|
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
;; GNU General Public License for more details.
|
|
|
|
;; You should have received a copy of the GNU General Public License
|
|
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
;;; Code:
|
|
|
|
|
|
(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)
|
|
(unless (js2-comment-node-p (js2-node-at-point))
|
|
,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 ()
|
|
;; (or
|
|
;; (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]*")))
|
|
;; ;; arrow functions
|
|
;; (and (looking-at "{")
|
|
;; (looking-back "=>[\s\n]*")
|
|
;; (not (js2r--point-inside-string-p)))))
|
|
|
|
(defun js2r--looking-at-function-start ()
|
|
"Return non-nil if the point is at the start of a function body."
|
|
(let* ((node (js2-node-at-point))
|
|
(parent (js2-node-parent node)))
|
|
(and (looking-at "{")
|
|
(js2-block-node-p node)
|
|
(js2-function-node-p parent))))
|
|
|
|
(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)
|
|
";")
|
|
|
|
(defun js2r--looking-at-call-start ()
|
|
(looking-at "("))
|
|
|
|
(defun js2r--goto-closest-call-start ()
|
|
(while (not (js2r--looking-at-call-start))
|
|
(if (eq (car (syntax-ppss)) 0)
|
|
(error "Cursor is not on a call")
|
|
(goto-char (nth 1 (syntax-ppss))))))
|
|
|
|
(js2r--create-bracketed-whitespace-traverser js2r-expand-call-args
|
|
(js2r--ensure-newline)
|
|
(js2r--looking-at-call-start)
|
|
(js2r--goto-closest-call-start)
|
|
",")
|
|
|
|
(js2r--create-bracketed-whitespace-traverser js2r-contract-call-args
|
|
(js2r--ensure-just-one-space)
|
|
(js2r--looking-at-call-start)
|
|
(js2r--goto-closest-call-start)
|
|
",")
|
|
|
|
(defun js2r--expand-contract-node-at-point (&optional is-contract)
|
|
"Expand or contract bracketed list according to node type in point.
|
|
Currently working on array, object, function and call args node types.
|
|
With argument, contract closest expression, otherwise expand."
|
|
(let ((pos (point))
|
|
(array-start (point-max))
|
|
(object-start (point-max))
|
|
(function-start (point-max))
|
|
(call-start (point-max)))
|
|
(save-excursion
|
|
(ignore-errors
|
|
(js2r--goto-closest-array-start)
|
|
(setq array-start (- pos (point)))))
|
|
(save-excursion
|
|
(ignore-errors
|
|
(js2r--goto-closest-object-start)
|
|
(setq object-start (- pos (point)))))
|
|
(save-excursion
|
|
(ignore-errors
|
|
(js2r--goto-closest-function-start)
|
|
(setq function-start (- pos (point)))))
|
|
(save-excursion
|
|
(ignore-errors
|
|
(js2r--goto-closest-call-start)
|
|
(setq call-start (- pos (point)))))
|
|
(setq pos (-min (list array-start object-start function-start call-start)))
|
|
(when (= pos array-start)
|
|
(if is-contract
|
|
(js2r-contract-array)
|
|
(js2r-expand-array)))
|
|
(when (= pos object-start)
|
|
(if is-contract
|
|
(js2r-contract-object)
|
|
(js2r-expand-object)))
|
|
(when (= pos function-start)
|
|
(if is-contract
|
|
(js2r-contract-function)
|
|
(js2r-expand-function)))
|
|
(when (= pos call-start)
|
|
(if is-contract
|
|
(js2r-contract-call-args)
|
|
(js2r-expand-call-args)))))
|
|
|
|
(defun js2r-expand-node-at-point ()
|
|
"Expand bracketed list according to node type at point."
|
|
(interactive)
|
|
(js2r--expand-contract-node-at-point))
|
|
|
|
(defun js2r-contract-node-at-point ()
|
|
"Contract bracketed list according to node type at point."
|
|
(interactive)
|
|
(js2r--expand-contract-node-at-point t))
|
|
|
|
(provide 'js2r-formatting)
|
|
;;; js2-formatting.el ends here
|