js-mode-expansions.el (6227B)
1 ;;; js-mode-expansions.el --- JS-specific expansions for expand-region -*- lexical-binding: t; -*- 2 3 ;; Copyright (C) 2011-2023 Free Software Foundation, Inc 4 5 ;; Author: Magnar Sveen <magnars@gmail.com> 6 ;; Keywords: marking region 7 8 ;; This program is free software; you can redistribute it and/or modify 9 ;; it under the terms of the GNU General Public License as published by 10 ;; the Free Software Foundation, either version 3 of the License, or 11 ;; (at your option) any later version. 12 13 ;; This program is distributed in the hope that it will be useful, 14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 ;; GNU General Public License for more details. 17 18 ;; You should have received a copy of the GNU General Public License 19 ;; along with this program. If not, see <http://www.gnu.org/licenses/>. 20 21 ;;; Commentary: 22 23 ;; Extra expansions for JavaScript that I've found useful so far: 24 ;; 25 ;; er/mark-js-function 26 ;; er/mark-js-object-property-value 27 ;; er/mark-js-object-property 28 ;; er/mark-js-if 29 ;; er/mark-js-inner-return 30 ;; er/mark-js-outer-return 31 ;; 32 ;; Feel free to contribute any other expansions for JavaScript at 33 ;; 34 ;; https://github.com/magnars/expand-region.el 35 36 ;;; Code: 37 38 (require 'expand-region-core) 39 (require 'er-basic-expansions) 40 41 (defun er/mark-js-function () 42 "Mark the current JavaScript function." 43 (interactive) 44 (condition-case nil 45 (forward-char 8) 46 (error nil)) 47 (word-search-backward "function") 48 (while (or (er--point-inside-string-p) 49 (er--point-is-in-comment-p)) 50 (word-search-backward "function")) 51 (set-mark (point)) 52 (while (not (looking-at "{")) 53 (forward-char)) 54 (forward-list) 55 (exchange-point-and-mark)) 56 57 (defun er/mark-js-outer-return () 58 "Mark the current return statement, including return and ending semi-colon" 59 (interactive) 60 (condition-case nil 61 (forward-char 6) 62 (error nil)) 63 (word-search-backward "return") 64 (while (or (er--point-inside-string-p) 65 (er--point-is-in-comment-p)) 66 (word-search-backward "return")) 67 (set-mark (point)) 68 (while (not (looking-at ";")) 69 (if (looking-at "\\s(") 70 (forward-list) 71 (forward-char))) 72 (forward-char) 73 (exchange-point-and-mark)) 74 75 (defun er/mark-js-inner-return () 76 ` "Mark contents of the current return statement. 77 Does not include return or semi-colon." 78 (interactive) 79 (condition-case nil 80 (forward-char 6) 81 (error nil)) 82 (word-search-backward "return") 83 (while (or (er--point-inside-string-p) 84 (er--point-is-in-comment-p)) 85 (word-search-backward "return")) 86 (search-forward " ") 87 (set-mark (point)) 88 (while (not (looking-at ";")) 89 (if (looking-at "\\s(") 90 (forward-list) 91 (forward-char))) 92 (exchange-point-and-mark)) 93 94 (defun er/mark-js-if () 95 "Mark the current if-statement." 96 (interactive) 97 (condition-case nil 98 (forward-char 2) 99 (error nil)) 100 (word-search-backward "if") 101 (while (or (er--point-inside-string-p) 102 (er--point-is-in-comment-p)) 103 (word-search-backward "if")) 104 (set-mark (point)) 105 (while (not (looking-at "(")) 106 (forward-char)) 107 (forward-list) 108 (while (not (looking-at "{")) 109 (forward-char)) 110 (forward-list) 111 (exchange-point-and-mark)) 112 113 (defun er/mark-js-object-property-value () 114 "Mark the current object property value, ie. from : to , or }" 115 (interactive) 116 (unless (er--point-inside-pairs-p) 117 (error "Point is not inside an object")) 118 (search-backward ":") 119 (forward-char) 120 (search-forward-regexp "[^\s]") 121 (backward-char) 122 (set-mark (point)) 123 (while (not (looking-at "[},]")) 124 (if (looking-at "\\s(") 125 (forward-list) 126 (forward-char))) 127 (when (er/looking-back-max "[\s\n]" 400) 128 (search-backward-regexp "[^\s\n]") 129 (forward-char)) 130 (exchange-point-and-mark)) 131 132 (defun er/mark-js-object-property () 133 "Mark js-object-property. 134 Presumes that point is at the assignment part of key: value. 135 If point is inside the value, that will be marked first anyway." 136 (interactive) 137 (when (or (looking-at "\"?\\(\\s_\\|\\sw\\| \\)*\":") 138 (looking-at "\\(\\s_\\|\\sw\\)*:") 139 (er/looking-back-max ": ?" 2)) 140 (search-backward-regexp "[{,]") 141 (forward-char) 142 (search-forward-regexp "[^\s\n]") 143 (backward-char) 144 (set-mark (point)) 145 (search-forward ":") 146 (while (or (not (looking-at "[},]")) 147 (er--point-inside-string-p)) 148 (if (looking-at "\\s(") 149 (forward-list) 150 (forward-char))) 151 (when (er/looking-back-max "[\s\n]" 400) 152 (search-backward-regexp "[^\s\n]") 153 (forward-char)) 154 (exchange-point-and-mark))) 155 156 (defun er/mark-js-call () 157 "Mark the current symbol (including dots) and then parens or squares." 158 (interactive) 159 (let ((symbol-regexp "\\(\\s_\\|\\sw\\|\\.\\)+")) 160 (when (or (looking-at symbol-regexp) 161 (er/looking-back-on-line symbol-regexp)) 162 (skip-syntax-backward "_w.") 163 (when (looking-at "!") 164 (forward-char 1)) 165 (set-mark (point)) 166 (when (looking-at symbol-regexp) 167 (goto-char (match-end 0))) 168 (if (looking-at "\\[\\|(") 169 (forward-list)) 170 (exchange-point-and-mark)))) 171 172 (defun er/add-js-mode-expansions () 173 "Adds JS-specific expansions for buffers in js-mode" 174 (set (make-local-variable 'er/try-expand-list) (append 175 er/try-expand-list 176 '(er/mark-js-function 177 er/mark-js-object-property-value 178 er/mark-js-object-property 179 er/mark-js-if 180 er/mark-js-inner-return 181 er/mark-js-outer-return 182 er/mark-js-call)))) 183 184 (er/enable-mode-expansions 'js-mode #'er/add-js-mode-expansions) 185 (er/enable-mode-expansions 'js2-mode #'er/add-js-mode-expansions) 186 (er/enable-mode-expansions 'js3-mode #'er/add-js-mode-expansions) 187 188 (provide 'js-mode-expansions) 189 190 ;; js-mode-expansions.el ends here