mc-mark-more.el (22741B)
1 ;;; mc-mark-more.el 2 3 ;; Copyright (C) 2012 Magnar Sveen 4 5 ;; Author: Magnar Sveen <magnars@gmail.com> 6 ;; Keywords: editing cursors 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 ;; This file contains functions to mark more parts of the buffer. 24 ;; See ./features/mark-more.feature for examples. 25 26 ;; Please see multiple-cursors.el for more commentary. 27 28 ;;; Code: 29 30 (require 'multiple-cursors-core) 31 (require 'thingatpt) 32 33 (defun mc/cursor-end (cursor) 34 (if (overlay-get cursor 'mark-active) 35 (max (overlay-get cursor 'point) 36 (overlay-get cursor 'mark)) 37 (overlay-get cursor 'point))) 38 39 (defun mc/cursor-beg (cursor) 40 (if (overlay-get cursor 'mark-active) 41 (min (overlay-get cursor 'point) 42 (overlay-get cursor 'mark)) 43 (overlay-get cursor 'point))) 44 45 (defun mc/furthest-region-end () 46 (let ((end (max (mark) (point)))) 47 (mc/for-each-fake-cursor 48 (setq end (max end (mc/cursor-end cursor)))) 49 end)) 50 51 (defun mc/first-region-start () 52 (let ((beg (min (mark) (point)))) 53 (mc/for-each-fake-cursor 54 (setq beg (min beg (mc/cursor-beg cursor)))) 55 beg)) 56 57 (defun mc/furthest-cursor-before-point () 58 (let ((beg (if mark-active (min (mark) (point)) (point))) 59 furthest) 60 (mc/for-each-fake-cursor 61 (when (< (mc/cursor-beg cursor) beg) 62 (setq beg (mc/cursor-beg cursor)) 63 (setq furthest cursor))) 64 furthest)) 65 66 (defun mc/furthest-cursor-after-point () 67 (let ((end (if mark-active (max (mark) (point)) (point))) 68 furthest) 69 (mc/for-each-fake-cursor 70 (when (> (mc/cursor-end cursor) end) 71 (setq end (mc/cursor-end cursor)) 72 (setq furthest cursor))) 73 furthest)) 74 75 (defun mc/fake-cursor-at-point (&optional point) 76 "Return the fake cursor with its point right at POINT (defaults 77 to (point)), or nil." 78 (setq point (or point (point))) 79 (let ((cursors (mc/all-fake-cursors)) 80 (c nil)) 81 (catch 'found 82 (while (setq c (pop cursors)) 83 (when (eq (marker-position (overlay-get c 'point)) 84 point) 85 (throw 'found c)))))) 86 87 (defun mc/region-strings () 88 (let ((strings (list (buffer-substring-no-properties (point) (mark))))) 89 (mc/for-each-fake-cursor 90 (add-to-list 'strings (buffer-substring-no-properties 91 (mc/cursor-beg cursor) 92 (mc/cursor-end cursor)))) 93 strings)) 94 95 (defvar mc/enclose-search-term nil 96 "How should mc/mark-more-* search for more matches? 97 98 Match everything: nil 99 Match only whole words: 'words 100 Match only whole symbols: 'symbols 101 102 Use like case-fold-search, don't recommend setting it globally.") 103 104 (defun mc/mark-more-like-this (skip-last direction) 105 (let ((case-fold-search nil) 106 (re (regexp-opt (mc/region-strings) mc/enclose-search-term)) 107 (point-out-of-order (cl-ecase direction 108 (forwards (< (point) (mark))) 109 (backwards (not (< (point) (mark)))))) 110 (furthest-cursor (cl-ecase direction 111 (forwards (mc/furthest-cursor-after-point)) 112 (backwards (mc/furthest-cursor-before-point)))) 113 (start-char (cl-ecase direction 114 (forwards (mc/furthest-region-end)) 115 (backwards (mc/first-region-start)))) 116 (search-function (cl-ecase direction 117 (forwards 'search-forward-regexp) 118 (backwards 'search-backward-regexp))) 119 (match-point-getter (cl-ecase direction 120 (forwards 'match-beginning) 121 (backwards 'match-end)))) 122 (if (and skip-last (not furthest-cursor)) 123 (error "No cursors to be skipped") 124 (mc/save-excursion 125 (goto-char start-char) 126 (when skip-last 127 (mc/remove-fake-cursor furthest-cursor)) 128 (if (funcall search-function re nil t) 129 (progn 130 (push-mark (funcall match-point-getter 0)) 131 (when point-out-of-order 132 (exchange-point-and-mark)) 133 (mc/create-fake-cursor-at-point)) 134 (error "no more matches found.")))))) 135 136 ;;;###autoload 137 (defun mc/mark-next-like-this (arg) 138 "Find and mark the next part of the buffer matching the currently active region 139 If no region is active add a cursor on the next line 140 With negative ARG, delete the last one instead. 141 With zero ARG, skip the last one and mark next." 142 (interactive "p") 143 (if (< arg 0) 144 (let ((cursor (mc/furthest-cursor-after-point))) 145 (if cursor 146 (mc/remove-fake-cursor cursor) 147 (error "No cursors to be unmarked"))) 148 (if (region-active-p) 149 (mc/mark-more-like-this (= arg 0) 'forwards) 150 (mc/mark-lines arg 'forwards))) 151 (mc/maybe-multiple-cursors-mode)) 152 153 ;;;###autoload 154 (defun mc/mark-next-like-this-word (arg) 155 "Find and mark the next part of the buffer matching the currently active region 156 If no region is active, mark the word at the point and find the next match 157 With negative ARG, delete the last one instead. 158 With zero ARG, skip the last one and mark next." 159 (interactive "p") 160 (if (< arg 0) 161 (let ((cursor (mc/furthest-cursor-after-point))) 162 (if cursor 163 (mc/remove-fake-cursor cursor) 164 (error "No cursors to be unmarked"))) 165 (if (region-active-p) 166 (mc/mark-more-like-this (= arg 0) 'forwards) 167 (mc--select-thing-at-point 'word) 168 (mc/mark-more-like-this (= arg 0) 'forwards))) 169 (mc/maybe-multiple-cursors-mode)) 170 171 (defun mc/mark-next-like-this-symbol (arg) 172 "Find and mark the next part of the buffer matching the currently active region 173 If no region is active, mark the symbol at the point and find the next match 174 With negative ARG, delete the last one instead. 175 With zero ARG, skip the last one and mark next." 176 (interactive "p") 177 (if (< arg 0) 178 (let ((cursor (mc/furthest-cursor-after-point))) 179 (if cursor 180 (mc/remove-fake-cursor cursor) 181 (error "No cursors to be unmarked"))) 182 (if (region-active-p) 183 (mc/mark-more-like-this (= arg 0) 'forwards) 184 (mc--select-thing-at-point 'symbol) 185 (mc/mark-more-like-this (= arg 0) 'forwards))) 186 (mc/maybe-multiple-cursors-mode)) 187 188 189 ;;;###autoload 190 (defun mc/mark-next-word-like-this (arg) 191 (interactive "p") 192 (let ((mc/enclose-search-term 'words)) 193 (mc/mark-next-like-this arg))) 194 195 ;;;###autoload 196 (defun mc/mark-next-symbol-like-this (arg) 197 (interactive "p") 198 (let ((mc/enclose-search-term 'symbols)) 199 (mc/mark-next-like-this arg))) 200 201 ;;;###autoload 202 (defun mc/mark-previous-like-this (arg) 203 "Find and mark the previous part of the buffer matching the currently active region 204 With negative ARG, delete the last one instead. 205 With zero ARG, skip the last one and mark next." 206 (interactive "p") 207 (if (< arg 0) 208 (let ((cursor (mc/furthest-cursor-before-point))) 209 (if cursor 210 (mc/remove-fake-cursor cursor) 211 (error "No cursors to be unmarked"))) 212 (if (region-active-p) 213 (mc/mark-more-like-this (= arg 0) 'backwards) 214 (mc/mark-lines arg 'backwards))) 215 (mc/maybe-multiple-cursors-mode)) 216 217 ;;;###autoload 218 (defun mc/mark-previous-word-like-this (arg) 219 (interactive "p") 220 (let ((mc/enclose-search-term 'words)) 221 (mc/mark-previous-like-this arg))) 222 223 ;;;###autoload 224 (defun mc/mark-previous-symbol-like-this (arg) 225 (interactive "p") 226 (let ((mc/enclose-search-term 'symbols)) 227 (mc/mark-previous-like-this arg))) 228 229 (defun mc/mark-lines (num-lines direction) 230 (dotimes (i (if (= num-lines 0) 1 num-lines)) 231 (mc/save-excursion 232 (let ((furthest-cursor (cl-ecase direction 233 (forwards (mc/furthest-cursor-after-point)) 234 (backwards (mc/furthest-cursor-before-point))))) 235 (when (overlayp furthest-cursor) 236 (goto-char (overlay-get furthest-cursor 'point)) 237 (when (= num-lines 0) 238 (mc/remove-fake-cursor furthest-cursor)))) 239 (cl-ecase direction 240 (forwards (next-logical-line 1 nil)) 241 (backwards (previous-logical-line 1 nil))) 242 (mc/create-fake-cursor-at-point)))) 243 244 ;;;###autoload 245 (defun mc/mark-next-lines (arg) 246 (interactive "p") 247 (mc/mark-lines arg 'forwards) 248 (mc/maybe-multiple-cursors-mode)) 249 250 ;;;###autoload 251 (defun mc/mark-previous-lines (arg) 252 (interactive "p") 253 (mc/mark-lines arg 'backwards) 254 (mc/maybe-multiple-cursors-mode)) 255 256 ;;;###autoload 257 (defun mc/unmark-next-like-this () 258 "Deselect next part of the buffer matching the currently active region." 259 (interactive) 260 (mc/mark-next-like-this -1)) 261 262 ;;;###autoload 263 (defun mc/unmark-previous-like-this () 264 "Deselect prev part of the buffer matching the currently active region." 265 (interactive) 266 (mc/mark-previous-like-this -1)) 267 268 ;;;###autoload 269 (defun mc/skip-to-next-like-this () 270 "Skip the current one and select the next part of the buffer matching the currently active region." 271 (interactive) 272 (mc/mark-next-like-this 0)) 273 274 ;;;###autoload 275 (defun mc/skip-to-previous-like-this () 276 "Skip the current one and select the prev part of the buffer matching the currently active region." 277 (interactive) 278 (mc/mark-previous-like-this 0)) 279 280 ;;;###autoload 281 (defun mc/mark-all-like-this () 282 "Find and mark all the parts of the buffer matching the currently active region" 283 (interactive) 284 (unless (region-active-p) 285 (error "Mark a region to match first.")) 286 (mc/remove-fake-cursors) 287 (let ((master (point)) 288 (case-fold-search nil) 289 (point-first (< (point) (mark))) 290 (re (regexp-opt (mc/region-strings) mc/enclose-search-term))) 291 (mc/save-excursion 292 (goto-char 0) 293 (while (search-forward-regexp re nil t) 294 (push-mark (match-beginning 0)) 295 (when point-first (exchange-point-and-mark)) 296 (unless (= master (point)) 297 (mc/create-fake-cursor-at-point)) 298 (when point-first (exchange-point-and-mark))))) 299 (if (> (mc/num-cursors) 1) 300 (multiple-cursors-mode 1) 301 (multiple-cursors-mode 0))) 302 303 (defun mc--select-thing-at-point (thing) 304 (let ((bound (bounds-of-thing-at-point thing))) 305 (when bound 306 (set-mark (car bound)) 307 (goto-char (cdr bound)) 308 bound))) 309 310 (defun mc--select-thing-at-point-or-bark (thing) 311 (unless (or (region-active-p) (mc--select-thing-at-point thing)) 312 (error "Mark a region or set cursor on a %s." thing))) 313 314 ;;;###autoload 315 (defun mc/mark-all-words-like-this () 316 (interactive) 317 (mc--select-thing-at-point-or-bark 'word) 318 (let ((mc/enclose-search-term 'words)) 319 (mc/mark-all-like-this))) 320 321 ;;;###autoload 322 (defun mc/mark-all-symbols-like-this () 323 (interactive) 324 (mc--select-thing-at-point-or-bark 'symbol) 325 (let ((mc/enclose-search-term 'symbols)) 326 (mc/mark-all-like-this))) 327 328 ;;;###autoload 329 (defun mc/mark-all-in-region (beg end &optional search) 330 "Find and mark all the parts in the region matching the given search" 331 (interactive "r") 332 (let ((search (or search (read-from-minibuffer "Mark all in region: "))) 333 (case-fold-search nil)) 334 (if (string= search "") 335 (message "Mark aborted") 336 (progn 337 (mc/remove-fake-cursors) 338 (goto-char beg) 339 (while (search-forward search end t) 340 (push-mark (match-beginning 0)) 341 (mc/create-fake-cursor-at-point)) 342 (let ((first (mc/furthest-cursor-before-point))) 343 (if (not first) 344 (error "Search failed for %S" search) 345 (mc/pop-state-from-overlay first))) 346 (if (> (mc/num-cursors) 1) 347 (multiple-cursors-mode 1) 348 (multiple-cursors-mode 0)))))) 349 350 ;;;###autoload 351 (defun mc/mark-all-in-region-regexp (beg end) 352 "Find and mark all the parts in the region matching the given regexp." 353 (interactive "r") 354 (let ((search (read-regexp "Mark regexp in region: ")) 355 (case-fold-search nil)) 356 (if (string= search "") 357 (message "Mark aborted") 358 (progn 359 (mc/remove-fake-cursors) 360 (goto-char beg) 361 (let ((lastmatch)) 362 (while (and (< (point) end) ; can happen because of (forward-char) 363 (search-forward-regexp search end t)) 364 (push-mark (match-beginning 0)) 365 (mc/create-fake-cursor-at-point) 366 (setq lastmatch (point)) 367 (when (= (point) (match-beginning 0)) 368 (forward-char))) 369 (when lastmatch (goto-char lastmatch))) 370 (when (> (mc/num-cursors) 0) 371 (goto-char (match-end 0))) 372 (let ((first (mc/furthest-cursor-before-point))) 373 (if (not first) 374 (error "Search failed for %S" search) 375 (mc/pop-state-from-overlay first))) 376 (if (> (mc/num-cursors) 1) 377 (multiple-cursors-mode 1) 378 (multiple-cursors-mode 0)))))) 379 380 (when (not (fboundp 'set-temporary-overlay-map)) 381 ;; Backport this function from newer emacs versions 382 (defun set-temporary-overlay-map (map &optional keep-pred) 383 "Set a new keymap that will only exist for a short period of time. 384 The new keymap to use must be given in the MAP variable. When to 385 remove the keymap depends on user input and KEEP-PRED: 386 387 - if KEEP-PRED is nil (the default), the keymap disappears as 388 soon as any key is pressed, whether or not the key is in MAP; 389 390 - if KEEP-PRED is t, the keymap disappears as soon as a key *not* 391 in MAP is pressed; 392 393 - otherwise, KEEP-PRED must be a 0-arguments predicate that will 394 decide if the keymap should be removed (if predicate returns 395 nil) or kept (otherwise). The predicate will be called after 396 each key sequence." 397 398 (let* ((clearfunsym (make-symbol "clear-temporary-overlay-map")) 399 (overlaysym (make-symbol "t")) 400 (alist (list (cons overlaysym map))) 401 (clearfun 402 `(lambda () 403 (unless ,(cond ((null keep-pred) nil) 404 ((eq t keep-pred) 405 `(eq this-command 406 (lookup-key ',map 407 (this-command-keys-vector)))) 408 (t `(funcall ',keep-pred))) 409 (remove-hook 'pre-command-hook ',clearfunsym) 410 (setq emulation-mode-map-alists 411 (delq ',alist emulation-mode-map-alists)))))) 412 (set overlaysym overlaysym) 413 (fset clearfunsym clearfun) 414 (add-hook 'pre-command-hook clearfunsym) 415 416 (push alist emulation-mode-map-alists)))) 417 418 ;;;###autoload 419 (defun mc/mark-more-like-this-extended () 420 "Like mark-more-like-this, but then lets you adjust with arrows key. 421 The adjustments work like this: 422 423 <up> Mark previous like this and set direction to 'up 424 <down> Mark next like this and set direction to 'down 425 426 If direction is 'up: 427 428 <left> Skip past the cursor furthest up 429 <right> Remove the cursor furthest up 430 431 If direction is 'down: 432 433 <left> Remove the cursor furthest down 434 <right> Skip past the cursor furthest down 435 436 The bindings for these commands can be changed. See `mc/mark-more-like-this-extended-keymap'." 437 (interactive) 438 (mc/mmlte--down) 439 (set-temporary-overlay-map mc/mark-more-like-this-extended-keymap t)) 440 441 (defvar mc/mark-more-like-this-extended-direction nil 442 "When using mc/mark-more-like-this-extended are we working on the next or previous cursors?") 443 444 (make-variable-buffer-local 'mc/mark-more-like-this-extended) 445 446 (defun mc/mmlte--message () 447 (if (eq mc/mark-more-like-this-extended-direction 'up) 448 (message "<up> to mark previous, <left> to skip, <right> to remove, <down> to mark next") 449 (message "<down> to mark next, <right> to skip, <left> to remove, <up> to mark previous"))) 450 451 (defun mc/mmlte--up () 452 (interactive) 453 (mc/mark-previous-like-this 1) 454 (setq mc/mark-more-like-this-extended-direction 'up) 455 (mc/mmlte--message)) 456 457 (defun mc/mmlte--down () 458 (interactive) 459 (mc/mark-next-like-this 1) 460 (setq mc/mark-more-like-this-extended-direction 'down) 461 (mc/mmlte--message)) 462 463 (defun mc/mmlte--left () 464 (interactive) 465 (if (eq mc/mark-more-like-this-extended-direction 'down) 466 (mc/unmark-next-like-this) 467 (mc/skip-to-previous-like-this)) 468 (mc/mmlte--message)) 469 470 (defun mc/mmlte--right () 471 (interactive) 472 (if (eq mc/mark-more-like-this-extended-direction 'up) 473 (mc/unmark-previous-like-this) 474 (mc/skip-to-next-like-this)) 475 (mc/mmlte--message)) 476 477 (defvar mc/mark-more-like-this-extended-keymap (make-sparse-keymap)) 478 479 (define-key mc/mark-more-like-this-extended-keymap (kbd "<up>") 'mc/mmlte--up) 480 (define-key mc/mark-more-like-this-extended-keymap (kbd "<down>") 'mc/mmlte--down) 481 (define-key mc/mark-more-like-this-extended-keymap (kbd "<left>") 'mc/mmlte--left) 482 (define-key mc/mark-more-like-this-extended-keymap (kbd "<right>") 'mc/mmlte--right) 483 484 (defvar mc--restrict-mark-all-to-symbols nil) 485 486 ;;;###autoload 487 (defun mc/mark-all-like-this-dwim (arg) 488 "Tries to guess what you want to mark all of. 489 Can be pressed multiple times to increase selection. 490 491 With prefix, it behaves the same as original `mc/mark-all-like-this'" 492 (interactive "P") 493 (if arg 494 (mc/mark-all-like-this) 495 (if (and (not (use-region-p)) 496 (derived-mode-p 'sgml-mode) 497 (mc--on-tag-name-p)) 498 (mc/mark-sgml-tag-pair) 499 (let ((before (mc/num-cursors))) 500 (unless (eq last-command 'mc/mark-all-like-this-dwim) 501 (setq mc--restrict-mark-all-to-symbols nil)) 502 (unless (use-region-p) 503 (mc--mark-symbol-at-point) 504 (setq mc--restrict-mark-all-to-symbols t)) 505 (if mc--restrict-mark-all-to-symbols 506 (mc/mark-all-symbols-like-this-in-defun) 507 (mc/mark-all-like-this-in-defun)) 508 (when (<= (mc/num-cursors) before) 509 (if mc--restrict-mark-all-to-symbols 510 (mc/mark-all-symbols-like-this) 511 (mc/mark-all-like-this))) 512 (when (<= (mc/num-cursors) before) 513 (mc/mark-all-like-this)))))) 514 515 ;;;###autoload 516 (defun mc/mark-all-dwim (arg) 517 "Tries even harder to guess what you want to mark all of. 518 519 If the region is active and spans multiple lines, it will behave 520 as if `mc/mark-all-in-region'. With the prefix ARG, it will call 521 `mc/edit-lines' instead. 522 523 If the region is inactive or on a single line, it will behave like 524 `mc/mark-all-like-this-dwim'." 525 (interactive "P") 526 (if (and (use-region-p) 527 (not (> (mc/num-cursors) 1)) 528 (not (= (line-number-at-pos (region-beginning)) 529 (line-number-at-pos (region-end))))) 530 (if arg 531 (call-interactively 'mc/edit-lines) 532 (call-interactively 'mc/mark-all-in-region)) 533 (progn 534 (setq this-command 'mc/mark-all-like-this-dwim) 535 (mc/mark-all-like-this-dwim arg)))) 536 537 (defun mc--in-defun () 538 (bounds-of-thing-at-point 'defun)) 539 540 ;;;###autoload 541 (defun mc/mark-all-like-this-in-defun () 542 "Mark all like this in defun." 543 (interactive) 544 (if (mc--in-defun) 545 (save-restriction 546 (widen) 547 (narrow-to-defun) 548 (mc/mark-all-like-this)) 549 (mc/mark-all-like-this))) 550 551 ;;;###autoload 552 (defun mc/mark-all-words-like-this-in-defun () 553 "Mark all words like this in defun." 554 (interactive) 555 (mc--select-thing-at-point-or-bark 'word) 556 (if (mc--in-defun) 557 (save-restriction 558 (widen) 559 (narrow-to-defun) 560 (mc/mark-all-words-like-this)) 561 (mc/mark-all-words-like-this))) 562 563 ;;;###autoload 564 (defun mc/mark-all-symbols-like-this-in-defun () 565 "Mark all symbols like this in defun." 566 (interactive) 567 (mc--select-thing-at-point-or-bark 'symbol) 568 (if (mc--in-defun) 569 (save-restriction 570 (widen) 571 (narrow-to-defun) 572 (mc/mark-all-symbols-like-this)) 573 (mc/mark-all-symbols-like-this))) 574 575 (defun mc--mark-symbol-at-point () 576 "Select the symbol under cursor" 577 (interactive) 578 (when (not (use-region-p)) 579 (let ((b (bounds-of-thing-at-point 'symbol))) 580 (goto-char (car b)) 581 (set-mark (cdr b))))) 582 583 (defun mc--get-nice-sgml-context () 584 (car 585 (last 586 (progn 587 (when (looking-at "<") (forward-char 1)) 588 (when (looking-back ">") (forward-char -1)) 589 (sgml-get-context))))) 590 591 (defun mc--on-tag-name-p () 592 (let* ((context (save-excursion (mc--get-nice-sgml-context))) 593 (tag-name-len (length (aref context 4))) 594 (beg (aref context 2)) 595 (end (+ beg tag-name-len (if (eq 'open (aref context 1)) 1 3)))) 596 (and context 597 (>= (point) beg) 598 (<= (point) end)))) 599 600 ;;;###autoload 601 (defun mc/toggle-cursor-on-click (event) 602 "Add a cursor where you click, or remove a fake cursor that is 603 already there." 604 (interactive "e") 605 (mouse-minibuffer-check event) 606 ;; Use event-end in case called from mouse-drag-region. 607 ;; If EVENT is a click, event-end and event-start give same value. 608 (let ((position (event-end event))) 609 (if (not (windowp (posn-window position))) 610 (error "Position not in text area of window")) 611 (select-window (posn-window position)) 612 (let ((pt (posn-point position))) 613 (if (numberp pt) 614 ;; is there a fake cursor with the actual *point* right where we are? 615 (let ((existing (mc/fake-cursor-at-point pt))) 616 (if existing 617 (mc/remove-fake-cursor existing) 618 (save-excursion 619 (goto-char pt) 620 (mc/create-fake-cursor-at-point)))))) 621 (mc/maybe-multiple-cursors-mode))) 622 623 ;;;###autoload 624 (defalias 'mc/add-cursor-on-click 'mc/toggle-cursor-on-click) 625 626 ;;;###autoload 627 (defun mc/mark-sgml-tag-pair () 628 "Mark the tag we're in and its pair for renaming." 629 (interactive) 630 (when (not (mc--inside-tag-p)) 631 (error "Place point inside tag to rename.")) 632 (let ((context (mc--get-nice-sgml-context))) 633 (if (looking-at "</") 634 (setq context (car (last (sgml-get-context))))) 635 (goto-char (aref context 2)) 636 (let* ((tag-name (aref context 4)) 637 (num-chars (length tag-name)) 638 (master-start (1+ (point))) 639 (mirror-end (save-excursion 640 (sgml-skip-tag-forward 1) 641 (1- (point))))) 642 (goto-char (- mirror-end num-chars)) 643 (set-mark mirror-end) 644 (mc/create-fake-cursor-at-point) 645 (goto-char master-start) 646 (set-mark (+ (point) num-chars)))) 647 (mc/maybe-multiple-cursors-mode)) 648 649 (defun mc--inside-tag-p () 650 (save-excursion 651 (not (null (sgml-get-context))))) 652 653 (provide 'mc-mark-more) 654 655 ;;; mc-mark-more.el ends here