Klimi's new dotfiles with stow.
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.

709 lines
25 KiB

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