diff options
author | mattkae <mattkae@protonmail.com> | 2022-05-11 09:23:58 -0400 |
---|---|---|
committer | mattkae <mattkae@protonmail.com> | 2022-05-11 09:23:58 -0400 |
commit | 3f4a0d5370ae6c34afe180df96add3b8522f4af1 (patch) | |
tree | ae901409e02bde8ee278475f8cf6818f8f680a60 /elpa/js2-refactor-20210306.2003/js2r-helpers.el |
initial commit
Diffstat (limited to 'elpa/js2-refactor-20210306.2003/js2r-helpers.el')
-rw-r--r-- | elpa/js2-refactor-20210306.2003/js2r-helpers.el | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/elpa/js2-refactor-20210306.2003/js2r-helpers.el b/elpa/js2-refactor-20210306.2003/js2r-helpers.el new file mode 100644 index 0000000..8f600fe --- /dev/null +++ b/elpa/js2-refactor-20210306.2003/js2r-helpers.el @@ -0,0 +1,221 @@ +;;; js2r-helpers.el --- Private helper functions for js2-refactor -*- 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: + +(require 'dash) +(require 's) +(require 'js2-mode) + +(defmacro js2r--wait-for-parse (&rest body) + "Evaluate BODY once the current buffer has been parsed." + (declare (debug def-body)) + `(js2-mode-wait-for-parse (lambda () ,@body))) + +(defun js2r--wrap-text (&rest text) + "Wrap TEXT with the prefered quotes. The prefered quotes is set with `js2r-prefered-quote-type'." + (let ((prefered-quotes "\"")) + (when (= 2 js2r-prefered-quote-type) + (setq prefered-quotes "'")) + (concat prefered-quotes (apply 'concat text) prefered-quotes))) + +(defun js2r--fix-special-modifier-combinations (key) + (case key + ("C-s-i" "s-TAB") + ("C-s-m" "s-RET") + (otherwise key))) + +(defun js2r--key-pairs-with-modifier (modifier keys) + (->> (string-to-list keys) + (--map (js2r--fix-special-modifier-combinations + (concat modifier (char-to-string it)))) + (s-join " ") + (read-kbd-macro))) + +(defun js2r--key-pairs-with-prefix (prefix keys) + (read-kbd-macro (concat prefix " " keys))) + +(defun js2r--guard () + (when js2-parsed-errors + (error "Can't refactor while buffer has parse errors"))) + +(defun js2r--current-quotes-char () + "The char that is the current quote delimiter" + (nth 3 (syntax-ppss))) + +(defalias 'js2r--point-inside-string-p 'js2r--current-quotes-char) + +(defun js2r--closest-node-where (p node) + (if (or (null node) + (apply p node nil)) + node + (js2r--closest-node-where p (js2-node-parent node)))) + +(defun js2r--closest (p) + (save-excursion + (cond + ((bolp) (back-to-indentation)) + ((looking-at ";") (forward-char -1)) + ((looking-back ";") (forward-char -2)) + ((looking-back "}") (forward-char -1))) + (js2r--closest-node-where p (js2-node-at-point)))) + +(defun js2r--goto-and-delete-node (node) + (goto-char (js2-node-abs-pos node)) + (delete-char (js2-node-len node))) + + +(defun js2r--path-to-root (node) + (when node + (cons node (js2r--path-to-root (js2-node-parent node))))) + +(defun js2r--first-common-ancestor (node1 node2) + (if (eq node1 node2) + node1 + (let ((path1 (reverse (js2r--path-to-root node1))) + (path2 (reverse (js2r--path-to-root node2))) + (last-common nil)) + (while (eq (car path1) (car path2)) + (setq last-common (car path1)) + (setq path1 (cdr path1)) + (setq path2 (cdr path2))) + last-common))) + +(defun js2r--first-common-ancestor-in-region (beg end) + (js2r--first-common-ancestor (js2-node-at-point beg) + (js2-node-at-point end))) + +;; abstract away node type on some common property getters +(defun js2r--node-target (node) + (cond + ((js2-call-node-p node) (js2-call-node-target node)) + ((js2-new-node-p node) (js2-new-node-target node)) + (:else nil))) + +(defun js2r--node-args (node) + (cond + ((js2-call-node-p node) (js2-call-node-args node)) + ((js2-new-node-p node) (js2-new-node-args node)) + (:else nil))) + +(defun js2r--node-lp (node) + (cond + ((js2-call-node-p node) (js2-call-node-lp node)) + ((js2-new-node-p node) (js2-new-node-lp node)) + (:else nil))) + +(defun js2r--node-rp (node) + (cond + ((js2-call-node-p node) (js2-call-node-rp node)) + ((js2-new-node-p node) (js2-new-node-rp node)) + (:else nil))) + +(defun js2r--node-kids (node) + (cond + ((js2-function-node-p node) (js2-block-node-kids (js2-function-node-body node))) + ((js2-if-node-p node) (js2-scope-kids (js2-if-node-then-part node))) + ((js2-for-node-p node) (js2-block-node-kids (js2-for-node-body node))) + ((js2-while-node-p node) (js2-block-node-kids (js2-while-node-body node))))) + +;; finding expressions and arguments + +(defun js2r--closest-extractable-node () + "Return the most appropriate node the be extracted into a variable or paramter. +Lookup the closest expression node from the point, or the closest literal node instead. +If no node is found, signal an error." + (or (or (js2r--closest #'js2r--expression-p) + (js2r--closest #'js2r--literal-node-p)) + (error "Cannot perform refactoring: Nothing to extract at point"))) + +(defun js2r--closest-stmt-node () + "Return the closest standalone statement node. +Special care is taken for if branch nodes: if a statement node is +part of an if branch node (like 'else if' nodes), return the +parent node." + (let* ((node (js2-node-parent-stmt (js2-node-at-point))) + (parent (js2-node-parent node))) + (if (and (js2-if-node-p node) + (js2-if-node-p parent)) + parent + node))) + +(defun js2r--argument-p (node) + (let ((parent (js2-node-parent node))) + (and (js2-call-node-p parent) + (member node (js2-call-node-args parent))))) + +(defun js2r--expression-p (node) + (or (js2-call-node-p node) + (js2r--argument-p node) + (and (js2-prop-get-node-p node) + (not (js2-call-node-p (js2-node-parent node)))))) + +(defun js2r--literal-node-p (node) + (or (js2-object-node-p node) + (js2-string-node-p node) + (js2-number-node-p node) + (js2r--boolean-node-p node))) + +(defun js2r--boolean-node-p (node) + (let* ((beg (js2-node-abs-pos node)) + (end (js2-node-abs-end node)) + (content (buffer-substring beg end))) + (and (js2-keyword-node-p node) + (member content '("true" "false"))))) + +(defun js2r--single-complete-expression-between-p (beg end) + (let ((ancestor (js2r--first-common-ancestor-in-region beg (- end 1)))) + (and (= beg (js2-node-abs-pos ancestor)) + (= end (js2-node-abs-end ancestor))))) + + +;; executing a list of changes +;; ensures changes are executed from last to first + +(defun js2r--by-end-descending (change1 change2) + (> (plist-get change1 :end) + (plist-get change2 :end))) + +(defun js2r--any-overlapping-changes (sorted-changes) + (--any? + (let ((one (car it)) + (two (cadr it))) + (< (plist-get one :beg) + (plist-get two :end))) + (-partition-in-steps 2 1 sorted-changes))) + +(defun js2r--execute-changes (changes) + (when changes + (let ((sorted-changes (sort changes 'js2r--by-end-descending))) + (when (js2r--any-overlapping-changes sorted-changes) + (error "These changes overlap, cannot execute properly.")) + (let ((abs-end (set-marker (make-marker) (1+ (plist-get (car sorted-changes) :end)))) + (abs-beg (plist-get (car (last sorted-changes)) :beg))) + (--each sorted-changes + (goto-char (plist-get it :beg)) + (delete-char (- (plist-get it :end) (plist-get it :beg))) + (insert (plist-get it :contents))) + (indent-region abs-beg abs-end) + (set-marker abs-end nil))))) + +(provide 'js2r-helpers) +;;; js2-helpers.el ends here |