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-paredit.el |
initial commit
Diffstat (limited to 'elpa/js2-refactor-20210306.2003/js2r-paredit.el')
-rw-r--r-- | elpa/js2-refactor-20210306.2003/js2r-paredit.el | 227 |
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 |