summaryrefslogtreecommitdiff
path: root/elpa/js2-refactor-20210306.2003/js2r-paredit.el
diff options
context:
space:
mode:
Diffstat (limited to 'elpa/js2-refactor-20210306.2003/js2r-paredit.el')
-rw-r--r--elpa/js2-refactor-20210306.2003/js2r-paredit.el227
1 files changed, 227 insertions, 0 deletions
diff --git a/elpa/js2-refactor-20210306.2003/js2r-paredit.el b/elpa/js2-refactor-20210306.2003/js2r-paredit.el
new file mode 100644
index 0000000..3907558
--- /dev/null
+++ b/elpa/js2-refactor-20210306.2003/js2r-paredit.el
@@ -0,0 +1,227 @@
+;;; js2r-paredit.el --- Paredit-like extensions 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 'js2r-helpers)
+
+(defun js2r--nesting-node-p (node)
+ (or (js2-function-node-p node)
+ (js2-if-node-p node)
+ (js2-for-node-p node)
+ (js2-while-node-p node)))
+
+(defun js2r--standalone-node-p (node)
+ (or (js2-stmt-node-p node)
+ (and (js2-function-node-p node)
+ (eq 'FUNCTION_STATEMENT (js2-function-node-form node)))))
+
+(defun js2r-kill ()
+ "Kill a line like `kill-line' but tries to respect node boundaries.
+Falls back to `kill-line' if the buffer has parse errors.
+
+if(|foo) {bar();} -> if() {bar();}
+
+function foo() {|2 + 3} -> function foo() {}
+
+// some |comment -> // some
+
+'this is a| string' -> 'this is a'
+"
+ (interactive)
+ (if js2-parsed-errors
+ (progn
+ (message "Buffer has parse errors. Killing the line")
+ (kill-line))
+ (condition-case error
+ (js2r--kill-line)
+ (progn
+ (message "Error occured while trying to kill AST node. Killing the line.")
+ (kill-line)))))
+
+(defun js2r--kill-line ()
+ "Kill a line, but respecting node boundaries."
+ (let ((node (js2r--next-node)))
+ (cond
+ ((js2-comment-node-p node) (kill-line))
+ ((js2-string-node-p node) (js2r--kill-line-in-string))
+ (t (js2r--kill-line-in-sexp)))))
+
+(defun js2r--next-node ()
+ "Return the node at point, or the node after the point if the
+ point is at the exact end of a node."
+ (save-excursion
+ (when (= (js2-node-abs-end (js2-node-at-point))
+ (point))
+ (forward-char 1))
+ (js2-node-at-point)))
+
+(defun js2r--kill-line-in-sexp ()
+ "Kill a line, but only kills until the closest outer sexp on
+ the current line, delimited with \")}]\". If no sexp is found
+ on the current line, falls back to
+ `js2r--kill-line-with-inner-sexp'."
+ (condition-case error
+ (let* ((beg (point))
+ (end (save-excursion
+ (up-list)
+ (forward-char -1)
+ (point))))
+ (if (js2-same-line end)
+ (kill-region beg end)
+ (js2r--kill-line-with-inner-sexp)))
+ (scan-error
+ (js2r--kill-line-with-inner-sexp))))
+
+(defun js2r--kill-line-with-inner-sexp ()
+ "Kill a line, but respecting inner killed sexps, ensuring that
+we kill up to the end to the next inner sexp if it starts in
+the current line.
+
+If the parentheses are unbalanced, fallback to `kill-line' and
+warn the user."
+ (condition-case error
+ (let* ((beg (point))
+ (end (save-excursion
+ (forward-visible-line 1)
+ (point)))
+ (beg-of-sexp (save-excursion
+ (js2r--goto-last-sexp-on-line)
+ (point)))
+ (end-of-sexp (save-excursion
+ (goto-char beg-of-sexp)
+ (forward-list)
+ ;; Kill all remaining semi-colons as well
+ (while (looking-at ";")
+ (forward-char))
+ (point))))
+ (if (js2-same-line beg-of-sexp)
+ (kill-region beg (max end end-of-sexp))
+ (kill-line)))
+ (scan-error
+ (message "Unbalanced parentheses. Killing the line.")
+ (kill-line))))
+
+(defun js2r--goto-last-sexp-on-line ()
+ "Move the cursor to the opening of the last sexp on the current
+line, or to the end of the line if no sexp is found."
+ (let ((pos (point)))
+ (down-list)
+ (backward-char 1)
+ (forward-list)
+ (if (js2-same-line pos)
+ (js2r--goto-last-sexp-on-line)
+ (backward-list))))
+
+(defun js2r--kill-line-in-string ()
+ "Kill a line in a string node, respecting the node boundaries.
+When at the beginning of the node, kill from outside of it."
+ (let* ((node (js2-node-at-point))
+ (beg (point))
+ (node-start (js2-node-abs-pos node))
+ (node-end (js2-node-abs-end node)))
+ (if (= beg node-start)
+ (js2r--kill-line-in-sexp)
+ (kill-region beg (1- node-end)))))
+
+(defun js2r-forward-slurp (&optional arg)
+ "Add the expression following the current function into it.
+
+The addition is performed by moving the closing brace of the
+function down.
+
+When called with a prefix argument ARG, slurp ARG expressions
+following the current function."
+ (interactive "p")
+ (js2r--guard)
+ (js2r--wait-for-parse
+ (let* ((nesting (js2r--closest 'js2r--nesting-node-p))
+ (standalone (if (js2r--standalone-node-p nesting)
+ nesting
+ (js2-node-parent-stmt nesting)))
+ (next-sibling (js2-node-next-sibling standalone))
+ (beg (js2-node-abs-pos next-sibling))
+ (last-sibling (if (wholenump arg)
+ (let ((num arg)
+ (iter-sibling next-sibling))
+ (while (> num 1) ;; Do next-sibling arg nbr of times
+ (setq iter-sibling (js2-node-next-sibling iter-sibling))
+ (setq num (1- num)))
+ iter-sibling)
+ next-sibling)) ;; No optional arg. Just use next-sibling
+ (end (js2-node-abs-end last-sibling))
+ (text (buffer-substring beg end)))
+ (save-excursion
+ (delete-region beg end)
+ ;; Delete newline character if the deleted AST node was at the end of the line
+ (goto-char beg)
+ (when (and (eolp)
+ (not (eobp)))
+ (delete-char 1))
+ (goto-char (js2-node-abs-end nesting))
+ (forward-char -1)
+ (when (looking-back "{ *")
+ (newline))
+ (setq beg (point))
+ (insert text)
+ (when (looking-at " *}")
+ (newline))
+ (setq end (point))
+ (indent-region beg end)))))
+
+(defun js2r-forward-barf (&optional arg)
+ (interactive "p")
+ (js2r--guard)
+ (js2r--wait-for-parse
+ (let* ((nesting (js2r--closest 'js2r--nesting-node-p))
+ (standalone (if (js2r--standalone-node-p nesting)
+ nesting
+ (js2-node-parent-stmt nesting)))
+ (standalone-end (js2-node-abs-end standalone))
+ (last-child (car (last (if (js2-if-node-p nesting)
+ (js2-scope-kids (js2r--closest 'js2-scope-p))
+ (js2r--node-kids nesting)))))
+ (first-barf-child (if (wholenump arg)
+ (let ((num arg)
+ (iter-child last-child))
+ (while (> num 1) ;; Do prev-sibling arg nbr of times
+ (setq iter-child (js2-node-prev-sibling iter-child))
+ (setq num (1- num)))
+ iter-child)
+ last-child)) ; No optional arg. Just use last-child
+ (last-child-beg (save-excursion
+ (goto-char (js2-node-abs-pos first-barf-child))
+ (skip-syntax-backward " ")
+ (while (looking-back "\n") (backward-char))
+ (point)))
+ (last-child-end (js2-node-abs-end last-child))
+ (text (buffer-substring last-child-beg last-child-end)))
+ (save-excursion
+ (js2r--execute-changes
+ (list
+ (list :beg last-child-beg :end last-child-end :contents "")
+ (list :beg standalone-end :end standalone-end :contents text)))))))
+
+(provide 'js2r-paredit)
+;;; js2r-paredit.el ends here