dotemacs

My Emacs configuration
git clone git://git.entf.net/dotemacs
Log | Files | Refs | LICENSE

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