Personal emacs config
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

221 lines
11 KiB

  1. ;;; js2-refactor.el --- The beginnings of a JavaScript refactoring library in emacs. -*- lexical-binding: t; -*-
  2. ;; Copyright (C) 2012-2014 Magnar Sveen
  3. ;; Copyright (C) 2015-2016 Magnar Sveen and Nicolas Petton
  4. ;; Author: Magnar Sveen <magnars@gmail.com>,
  5. ;; Nicolas Petton <nicolas@petton.fr>
  6. ;; Keywords: conveniences
  7. ;; This program is free software; you can redistribute it and/or modify
  8. ;; it under the terms of the GNU General Public License as published by
  9. ;; the Free Software Foundation, either version 3 of the License, or
  10. ;; (at your option) any later version.
  11. ;; This program is distributed in the hope that it will be useful,
  12. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. ;; GNU General Public License for more details.
  15. ;; You should have received a copy of the GNU General Public License
  16. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. ;;; Commentary:
  18. ;; This is a collection of small refactoring functions to further the idea of a
  19. ;; JavaScript IDE in Emacs that started with js2-mode.
  20. ;; ## Installation
  21. ;; Start by installing the dependencies:
  22. ;; * js2-mode https://github.com/mooz/js2-mode/
  23. ;; * dash https://github.com/magnars/dash.el
  24. ;; * multiple-cursors https://github.com/magnars/multiple-cursors.el
  25. ;; It is also recommended to get
  26. ;; [expand-region](https://github.com/magnars/expand-region.el) to more easily mark
  27. ;; vars, method calls and functions for refactorings.
  28. ;; Then add this to your Emacs settings:
  29. ;; (require 'js2-refactor)
  30. ;; (add-hook 'js2-mode-hook #'js2-refactor-mode)
  31. ;; (js2r-add-keybindings-with-prefix "C-c C-m")
  32. ;; Note: I am working on a smoother installation path through package.el,
  33. ;; but I haven't had the time to whip this project into that sort of
  34. ;; structure - yet.
  35. ;; ## Usage
  36. ;; All refactorings start with `C-c C-m` and then a two-letter mnemonic shortcut.
  37. ;; * `ee` is `expand-node-at-point`: Expand bracketed list according to node type at point (array, object, function, call args).
  38. ;; * `cc` is `contract-node-at-point`: Contract bracketed list according to node type at point (array, object, function, call args).
  39. ;; * `ef` is `extract-function`: Extracts the marked expressions out into a new named function.
  40. ;; * `em` is `extract-method`: Extracts the marked expressions out into a new named method in an object literal.
  41. ;; * `tf` is `toggle-function-expression-and-declaration`: Toggle between function name() {} and var name = function ();
  42. ;; * `ta` is `toggle-arrow-function-and-expression`: Toggle between function expression to arrow function.
  43. ;; * `ip` is `introduce-parameter`: Changes the marked expression to a parameter in a local function.
  44. ;; * `lp` is `localize-parameter`: Changes a parameter to a local var in a local function.
  45. ;; * `wi` is `wrap-buffer-in-iife`: Wraps the entire buffer in an immediately invoked function expression
  46. ;; * `ig` is `inject-global-in-iife`: Creates a shortcut for a marked global by injecting it in the wrapping immediately invoked function expression
  47. ;; * `ag` is `add-to-globals-annotation`: Creates a `/*global */` annotation if it is missing, and adds the var at point to it.
  48. ;; * `ev` is `extract-var`: Takes a marked expression and replaces it with a var.
  49. ;; * `iv` is `inline-var`: Replaces all instances of a variable with its initial value.
  50. ;; * `rv` is `rename-var`: Renames the variable on point and all occurrences in its lexical scope.
  51. ;; * `vt` is `var-to-this`: Changes local `var a` to be `this.a` instead.
  52. ;; * `ao` is `arguments-to-object`: Replaces arguments to a function call with an object literal of named arguments.
  53. ;; * `3i` is `ternary-to-if`: Converts ternary operator to if-statement.
  54. ;; * `sv` is `split-var-declaration`: Splits a `var` with multiple vars declared, into several `var` statements.
  55. ;; * `ss` is `split-string`: Splits a `string`.
  56. ;; * `uw` is `unwrap`: Replaces the parent statement with the selected region.
  57. ;; * `lt` is `log-this`: Adds a console.log() statement for what is at point (or region). With a prefix argument, use JSON pretty-printing.
  58. ;; * `dt` is `debug-this`: Adds a debug() statement for what is at point (or region).
  59. ;; * `sl` is `forward-slurp`: Moves the next statement into current function, if-statement, for-loop or while-loop.
  60. ;; * `ba` is `forward-barf`: Moves the last child out of current function, if-statement, for-loop or while-loop.
  61. ;; * `k` is `kill`: Kills to the end of the line, but does not cross semantic boundaries.
  62. ;; There are also some minor conveniences bundled:
  63. ;; * `C-S-down` and `C-S-up` moves the current line up or down. If the line is an
  64. ;; element in an object or array literal, it makes sure that the commas are
  65. ;; still correctly placed.
  66. ;; * `k` `kill-line`: Like `kill-line` but respecting the AST.
  67. ;; ## Todo
  68. ;; A list of some wanted improvements for the current refactorings.
  69. ;; * expand- and contract-array: should work recursively with nested object literals and nested arrays.
  70. ;; * expand- and contract-function: should deal better with nested object literals, array declarations, and statements terminated only by EOLs (without semicolons).
  71. ;; * wrap-buffer-in-iife: should skip comments and namespace initializations at buffer start.
  72. ;; * extract-variable: could end with a query-replace of the expression in its scope.
  73. ;; ## Contributions
  74. ;; * [Matt Briggs](https://github.com/mbriggs) contributed `js2r-add-to-globals-annotation`
  75. ;; * [Alex Chamberlain](https://github.com/apchamberlain) contributed contracting and expanding arrays and functions.
  76. ;; * [Nicolas Petton](https://github.com/NicolasPetton) contributed `js2r-kill`
  77. ;; Thanks!
  78. ;; ## Contribute
  79. ;; This project is still in its infancy, and everything isn't quite sorted out
  80. ;; yet. If you're eager to contribute, please add an issue here on github and we
  81. ;; can discuss your changes a little before diving into the elisp :-).
  82. ;; To fetch the test dependencies:
  83. ;; $ cd /path/to/multiple-cursors
  84. ;; $ git submodule init
  85. ;; $ git submodule update
  86. ;; Run the tests with:
  87. ;; $ ./util/ecukes/ecukes features
  88. ;;; Code:
  89. (require 'js2-mode)
  90. (require 'js2r-helpers)
  91. (require 'js2r-formatting)
  92. (require 'js2r-iife)
  93. (require 'js2r-vars)
  94. (require 'js2r-functions)
  95. (require 'js2r-wrapping)
  96. (require 'js2r-conditionals)
  97. (require 'js2r-conveniences)
  98. (require 'js2r-paredit)
  99. (defvar js2-refactor-mode-map
  100. (make-sparse-keymap)
  101. "Keymap for js2-refactor.")
  102. (defvar js2-refactor-keybinding-prefix
  103. nil
  104. "Store keybinding prefix used by js2-refactor.")
  105. ;;;###autoload
  106. (define-minor-mode js2-refactor-mode
  107. "Minor mode providing JavaScript refactorings."
  108. :lighter " js2r"
  109. :keymap js2-refactor-mode-map
  110. (when js2-refactor-mode
  111. (yas-minor-mode-on)))
  112. ;;; Settings ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  113. (defgroup js2-refactor nil
  114. "Minor mode providing JavaScript refactorings."
  115. :group 'tools
  116. :prefix "js2r-"
  117. :link '(url-link :tag "Repository" "https://github.com/magnars/js2-refactor.el"))
  118. (defcustom js2r-use-strict nil
  119. "When non-nil, js2r inserts strict declarations in IIFEs."
  120. :group 'js2-refactor
  121. :type 'boolean)
  122. (defcustom js2r-prefered-quote-type 1
  123. "The prefered quote style for strings."
  124. :group 'js2-refactor
  125. :type '(choice (const :tag "Double" 1)
  126. (const :tag "Single" 2)))
  127. (defcustom js2r-always-insert-parens-around-arrow-function-params nil
  128. "When non-nil, js2r always inserts parenthesis around arrow function params.
  129. This only affects arrow functions with one parameter."
  130. :group 'js2-refactor
  131. :type 'boolean)
  132. (defcustom js2r-prefer-let-over-var nil
  133. "When non-nil, js2r uses let constructs over var when performing refactorings.")
  134. ;;; Keybindings ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  135. (defun js2r--add-keybindings (key-fn)
  136. "Add js2r refactoring keybindings to `js2-mode-map' using KEY-FN to create each keybinding."
  137. (define-key js2-refactor-mode-map (funcall key-fn "ee") #'js2r-expand-node-at-point)
  138. (define-key js2-refactor-mode-map (funcall key-fn "cc") #'js2r-contract-node-at-point)
  139. (define-key js2-refactor-mode-map (funcall key-fn "wi") #'js2r-wrap-buffer-in-iife)
  140. (define-key js2-refactor-mode-map (funcall key-fn "ig") #'js2r-inject-global-in-iife)
  141. (define-key js2-refactor-mode-map (funcall key-fn "ev") #'js2r-extract-var)
  142. (define-key js2-refactor-mode-map (funcall key-fn "iv") #'js2r-inline-var)
  143. (define-key js2-refactor-mode-map (funcall key-fn "rv") #'js2r-rename-var)
  144. (define-key js2-refactor-mode-map (funcall key-fn "vt") #'js2r-var-to-this)
  145. (define-key js2-refactor-mode-map (funcall key-fn "ag") #'js2r-add-to-globals-annotation)
  146. (define-key js2-refactor-mode-map (funcall key-fn "sv") #'js2r-split-var-declaration)
  147. (define-key js2-refactor-mode-map (funcall key-fn "ss") #'js2r-split-string)
  148. (define-key js2-refactor-mode-map (funcall key-fn "ef") #'js2r-extract-function)
  149. (define-key js2-refactor-mode-map (funcall key-fn "em") #'js2r-extract-method)
  150. (define-key js2-refactor-mode-map (funcall key-fn "ip") #'js2r-introduce-parameter)
  151. (define-key js2-refactor-mode-map (funcall key-fn "lp") #'js2r-localize-parameter)
  152. (define-key js2-refactor-mode-map (funcall key-fn "tf") #'js2r-toggle-function-expression-and-declaration)
  153. (define-key js2-refactor-mode-map (funcall key-fn "ta") #'js2r-toggle-arrow-function-and-expression)
  154. (define-key js2-refactor-mode-map (funcall key-fn "ao") #'js2r-arguments-to-object)
  155. (define-key js2-refactor-mode-map (funcall key-fn "uw") #'js2r-unwrap)
  156. (define-key js2-refactor-mode-map (funcall key-fn "wl") #'js2r-wrap-in-for-loop)
  157. (define-key js2-refactor-mode-map (funcall key-fn "3i") #'js2r-ternary-to-if)
  158. (define-key js2-refactor-mode-map (funcall key-fn "lt") #'js2r-log-this)
  159. (define-key js2-refactor-mode-map (funcall key-fn "dt") #'js2r-debug-this)
  160. (define-key js2-refactor-mode-map (funcall key-fn "sl") #'js2r-forward-slurp)
  161. (define-key js2-refactor-mode-map (funcall key-fn "ba") #'js2r-forward-barf)
  162. (define-key js2-refactor-mode-map (funcall key-fn "k") #'js2r-kill)
  163. (define-key js2-refactor-mode-map (kbd "<C-S-down>") #'js2r-move-line-down)
  164. (define-key js2-refactor-mode-map (kbd "<C-S-up>") #'js2r-move-line-up))
  165. ;;;###autoload
  166. (defun js2r-add-keybindings-with-prefix (prefix)
  167. "Add js2r keybindings using the prefix PREFIX."
  168. (setq js2-refactor-keybinding-prefix (read-kbd-macro prefix))
  169. (js2r--add-keybindings (-partial #'js2r--key-pairs-with-prefix prefix)))
  170. ;;;###autoload
  171. (defun js2r-add-keybindings-with-modifier (modifier)
  172. "Add js2r keybindings using the modifier MODIFIER."
  173. (js2r--add-keybindings (-partial #'js2r--key-pairs-with-modifier modifier)))
  174. (provide 'js2-refactor)
  175. ;;; js2-refactor.el ends here