mirror of
https://github.com/magnars/multiple-cursors.el.git
synced 2025-10-13 13:03:03 +00:00
Remove mark-multiple integration
- it caused more problems than it was solving Fixes #9
This commit is contained in:
parent
d534132728
commit
241e34ef2d
@ -3,14 +3,14 @@ Feature: Marking multiple parts of the buffer
|
|||||||
Scenario: Marking next like this, cursors
|
Scenario: Marking next like this, cursors
|
||||||
When I insert "This text has the word text in it"
|
When I insert "This text has the word text in it"
|
||||||
And I select "text"
|
And I select "text"
|
||||||
And I press "M->"
|
And I press "C->"
|
||||||
Then I should have 2 cursors
|
Then I should have 2 cursors
|
||||||
|
|
||||||
Scenario: Marking next like this, region
|
Scenario: Marking next like this, region
|
||||||
Given I turn on delete-selection-mode
|
Given I turn on delete-selection-mode
|
||||||
When I insert "This text has the word text in it"
|
When I insert "This text has the word text in it"
|
||||||
And I select "text"
|
And I select "text"
|
||||||
And I press "M->"
|
And I press "C->"
|
||||||
And I type "sentence"
|
And I type "sentence"
|
||||||
Then I should see "This sentence has the word sentence in it"
|
Then I should see "This sentence has the word sentence in it"
|
||||||
|
|
||||||
@ -18,39 +18,39 @@ Feature: Marking multiple parts of the buffer
|
|||||||
Given I turn on delete-selection-mode
|
Given I turn on delete-selection-mode
|
||||||
When I insert "Here's text, text and text"
|
When I insert "Here's text, text and text"
|
||||||
And I select "text"
|
And I select "text"
|
||||||
And I press "M->"
|
And I press "C->"
|
||||||
And I press "C-0 M->"
|
And I press "C-0 C->"
|
||||||
And I type "more"
|
And I type "more"
|
||||||
Then I should see "Here's more, text and more"
|
Then I should see "Here's more, text and more"
|
||||||
|
|
||||||
Scenario: Removing last fake
|
Scenario: Removing last fake
|
||||||
When I insert "Here's text, text and text"
|
When I insert "Here's text, text and text"
|
||||||
And I select "text"
|
And I select "text"
|
||||||
And I press "M->"
|
And I press "C->"
|
||||||
And I press "C-- M->"
|
And I press "C-- C->"
|
||||||
Then I should have one cursor
|
Then I should have one cursor
|
||||||
|
|
||||||
Scenario: Removing furthest mark
|
Scenario: Removing furthest mark
|
||||||
Given I turn on delete-selection-mode
|
Given I turn on delete-selection-mode
|
||||||
When I insert "Here's text, text and text"
|
When I insert "Here's text, text and text"
|
||||||
And I select "text"
|
And I select "text"
|
||||||
And I press "M->"
|
And I press "C->"
|
||||||
And I press "M->"
|
And I press "C->"
|
||||||
And I press "C-- M->"
|
And I press "C-- C->"
|
||||||
And I type "more"
|
And I type "more"
|
||||||
Then I should see "Here's more, more and text"
|
Then I should see "Here's more, more and text"
|
||||||
|
|
||||||
Scenario: Marking prev like this, cursors
|
Scenario: Marking prev like this, cursors
|
||||||
When I insert "This text has the word text in it"
|
When I insert "This text has the word text in it"
|
||||||
And I select the last "text"
|
And I select the last "text"
|
||||||
And I press "M-<"
|
And I press "C-<"
|
||||||
Then I should have 2 cursors
|
Then I should have 2 cursors
|
||||||
|
|
||||||
Scenario: Marking prev like this, region
|
Scenario: Marking prev like this, region
|
||||||
Given I turn on delete-selection-mode
|
Given I turn on delete-selection-mode
|
||||||
When I insert "This text has the word text in it"
|
When I insert "This text has the word text in it"
|
||||||
And I select the last "text"
|
And I select the last "text"
|
||||||
And I press "M-<"
|
And I press "C-<"
|
||||||
And I type "sentence"
|
And I type "sentence"
|
||||||
Then I should see "This sentence has the word sentence in it"
|
Then I should see "This sentence has the word sentence in it"
|
||||||
|
|
||||||
@ -58,25 +58,25 @@ Feature: Marking multiple parts of the buffer
|
|||||||
Given I turn on delete-selection-mode
|
Given I turn on delete-selection-mode
|
||||||
When I insert "Here's text, text and text"
|
When I insert "Here's text, text and text"
|
||||||
And I select the last "text"
|
And I select the last "text"
|
||||||
And I press "M-<"
|
And I press "C-<"
|
||||||
And I press "C-0 M-<"
|
And I press "C-0 C-<"
|
||||||
And I type "more"
|
And I type "more"
|
||||||
Then I should see "Here's more, text and more"
|
Then I should see "Here's more, text and more"
|
||||||
|
|
||||||
Scenario: Removing first fake
|
Scenario: Removing first fake
|
||||||
When I insert "Here's text, text and text"
|
When I insert "Here's text, text and text"
|
||||||
And I select the last "text"
|
And I select the last "text"
|
||||||
And I press "M-<"
|
And I press "C-<"
|
||||||
And I press "C-- M-<"
|
And I press "C-- C-<"
|
||||||
Then I should have one cursor
|
Then I should have one cursor
|
||||||
|
|
||||||
Scenario: Removing first mark
|
Scenario: Removing first mark
|
||||||
Given I turn on delete-selection-mode
|
Given I turn on delete-selection-mode
|
||||||
When I insert "Here's text, text and text"
|
When I insert "Here's text, text and text"
|
||||||
And I select the last "text"
|
And I select the last "text"
|
||||||
And I press "M-<"
|
And I press "C-<"
|
||||||
And I press "M-<"
|
And I press "C-<"
|
||||||
And I press "C-- M-<"
|
And I press "C-- C-<"
|
||||||
And I type "more"
|
And I type "more"
|
||||||
Then I should see "Here's text, more and more"
|
Then I should see "Here's text, more and more"
|
||||||
|
|
||||||
|
@ -42,8 +42,8 @@
|
|||||||
(search-forward needle)
|
(search-forward needle)
|
||||||
(set-mark (point))
|
(set-mark (point))
|
||||||
(goto-char (match-beginning 0))
|
(goto-char (match-beginning 0))
|
||||||
(mark-all-like-this)
|
(mc/mark-all-like-this)
|
||||||
(mc/switch-from-mark-multiple-to-cursors)))
|
(mc/keyboard-quit)))
|
||||||
|
|
||||||
(When "^I copy \"\\(.+\\)\" in another program$"
|
(When "^I copy \"\\(.+\\)\" in another program$"
|
||||||
(lambda (text)
|
(lambda (text)
|
||||||
|
@ -7,9 +7,7 @@
|
|||||||
(add-to-list 'load-path multiple-cursors-root-path)
|
(add-to-list 'load-path multiple-cursors-root-path)
|
||||||
(add-to-list 'load-path multiple-cursors-util-path)
|
(add-to-list 'load-path multiple-cursors-util-path)
|
||||||
(add-to-list 'load-path (expand-file-name "espuds" multiple-cursors-util-path))
|
(add-to-list 'load-path (expand-file-name "espuds" multiple-cursors-util-path))
|
||||||
(add-to-list 'load-path (expand-file-name "vendor" multiple-cursors-util-path))
|
|
||||||
|
|
||||||
(require 'mark-more-like-this)
|
|
||||||
(require 'multiple-cursors)
|
(require 'multiple-cursors)
|
||||||
(require 'espuds)
|
(require 'espuds)
|
||||||
(require 'ert)
|
(require 'ert)
|
||||||
@ -19,10 +17,8 @@
|
|||||||
(Before
|
(Before
|
||||||
(multiple-cursors-mode 0)
|
(multiple-cursors-mode 0)
|
||||||
(rectangular-region-mode 0)
|
(rectangular-region-mode 0)
|
||||||
(mm/clear-all)
|
(global-set-key (kbd "C->") 'mc/mark-next-like-this)
|
||||||
(global-set-key (kbd "C->") 'mark-next-like-this)
|
(global-set-key (kbd "C-<") 'mc/mark-previous-like-this)
|
||||||
(global-set-key (kbd "M->") 'mc/mark-next-like-this)
|
|
||||||
(global-set-key (kbd "M-<") 'mc/mark-previous-like-this)
|
|
||||||
(global-set-key (kbd "M-!") 'mc/mark-all-like-this)
|
(global-set-key (kbd "M-!") 'mc/mark-all-like-this)
|
||||||
(global-set-key (kbd "M-#") 'mc/mark-all-in-region)
|
(global-set-key (kbd "M-#") 'mc/mark-all-in-region)
|
||||||
(global-set-key (kbd "H-SPC") 'set-rectangular-region-anchor)
|
(global-set-key (kbd "H-SPC") 'set-rectangular-region-anchor)
|
||||||
|
@ -33,10 +33,7 @@
|
|||||||
(defun mc/edit-lines ()
|
(defun mc/edit-lines ()
|
||||||
"Add one cursor to each line of the active region.
|
"Add one cursor to each line of the active region.
|
||||||
Starts from mark and moves in straight down or up towards the
|
Starts from mark and moves in straight down or up towards the
|
||||||
line point is on.
|
line point is on."
|
||||||
|
|
||||||
Could possibly be used to mark multiple regions with
|
|
||||||
mark-multiple if point and mark is on different columns."
|
|
||||||
(interactive)
|
(interactive)
|
||||||
(when (not (use-region-p))
|
(when (not (use-region-p))
|
||||||
(error "Mark a set of lines first."))
|
(error "Mark a set of lines first."))
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
;;; mc-mark-multiple-integration.el
|
|
||||||
|
|
||||||
;; Copyright (C) 2012 Magnar Sveen
|
|
||||||
|
|
||||||
;; Author: Magnar Sveen <magnars@gmail.com>
|
|
||||||
;; Keywords: editing cursors
|
|
||||||
|
|
||||||
;; This program is free software; you can redistribute it and/or modify
|
|
||||||
;; it under the terms of the GNU General Public License as published by
|
|
||||||
;; the Free Software Foundation, either version 3 of the License, or
|
|
||||||
;; (at your option) any later version.
|
|
||||||
|
|
||||||
;; This program is distributed in the hope that it will be useful,
|
|
||||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
;; GNU General Public License for more details.
|
|
||||||
|
|
||||||
;; You should have received a copy of the GNU General Public License
|
|
||||||
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
;;; Commentary:
|
|
||||||
|
|
||||||
;; When using mark-multiple, you can now use C-g to switch to multiple-cursors
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
(require 'multiple-cursors-core)
|
|
||||||
(require 'mark-multiple)
|
|
||||||
|
|
||||||
(defun mc/switch-from-mark-multiple-to-cursors ()
|
|
||||||
"Removes mark-multiple and switches to multiple cursors instead"
|
|
||||||
(interactive)
|
|
||||||
(let ((offset (- (point) (overlay-start mm/master))))
|
|
||||||
(deactivate-mark)
|
|
||||||
(save-excursion
|
|
||||||
(dolist (mirror mm/mirrors)
|
|
||||||
(goto-char (+ offset (overlay-start mirror)))
|
|
||||||
(mc/create-fake-cursor-at-point)))
|
|
||||||
(mm/clear-all)
|
|
||||||
(multiple-cursors-mode)))
|
|
||||||
|
|
||||||
(define-key mm/keymap (kbd "C-g") 'mc/switch-from-mark-multiple-to-cursors)
|
|
||||||
|
|
||||||
(provide 'mc-mark-multiple-integration)
|
|
||||||
|
|
||||||
;;; mc-mark-multiple-integration.el ends here
|
|
@ -411,8 +411,7 @@ for running commands with multiple cursors.")
|
|||||||
(defvar mc--default-cmds-to-run-once nil
|
(defvar mc--default-cmds-to-run-once nil
|
||||||
"Default set of commands to run only once in multiple-cursors-mode.")
|
"Default set of commands to run only once in multiple-cursors-mode.")
|
||||||
|
|
||||||
(setq mc--default-cmds-to-run-once '(mc/switch-from-mark-multiple-to-cursors
|
(setq mc--default-cmds-to-run-once '(mc/edit-lines
|
||||||
mc/edit-lines
|
|
||||||
mc/edit-ends-of-lines
|
mc/edit-ends-of-lines
|
||||||
mc/edit-beginnings-of-lines
|
mc/edit-beginnings-of-lines
|
||||||
mc/mark-next-like-this
|
mc/mark-next-like-this
|
||||||
|
@ -131,9 +131,6 @@
|
|||||||
(require 'mc-mark-more)
|
(require 'mc-mark-more)
|
||||||
(require 'rectangular-region-mode)
|
(require 'rectangular-region-mode)
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(eval-after-load "mark-multiple" '(require 'mc-mark-multiple-integration))
|
|
||||||
|
|
||||||
(provide 'multiple-cursors)
|
(provide 'multiple-cursors)
|
||||||
|
|
||||||
;;; multiple-cursors.el ends here
|
;;; multiple-cursors.el ends here
|
||||||
|
192
util/vendor/mark-more-like-this.el
vendored
192
util/vendor/mark-more-like-this.el
vendored
@ -1,192 +0,0 @@
|
|||||||
;;; mark-more-like-this.el --- Mark additional regions in buffer matching current region.
|
|
||||||
;;
|
|
||||||
;; Copyright (C) 2011 Magnar Sveen
|
|
||||||
;;
|
|
||||||
;; Author: Magnar Sveen <magnars@gmail.com>
|
|
||||||
;; Keywords: marking replace
|
|
||||||
;;
|
|
||||||
;; This program is free software; you can redistribute it and/or modify
|
|
||||||
;; it under the terms of the GNU General Public License as published by
|
|
||||||
;; the Free Software Foundation, either version 3 of the License, or
|
|
||||||
;; (at your option) any later version.
|
|
||||||
;;
|
|
||||||
;; This program is distributed in the hope that it will be useful,
|
|
||||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
;; GNU General Public License for more details.
|
|
||||||
;;
|
|
||||||
;; You should have received a copy of the GNU General Public License
|
|
||||||
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
;;
|
|
||||||
;;; Commentary:
|
|
||||||
;;
|
|
||||||
;; These commands will look for strings in the buffer that matches your currently
|
|
||||||
;; active region and make them mirrors. The mirrors are updated inline as you type.
|
|
||||||
;;
|
|
||||||
;; (require 'mark-more-like-this)
|
|
||||||
;; (global-set-key (kbd "C-<") 'mark-previous-like-this)
|
|
||||||
;; (global-set-key (kbd "C->") 'mark-next-like-this)
|
|
||||||
;; (global-set-key (kbd "C-M-m") 'mark-more-like-this)
|
|
||||||
;;
|
|
||||||
;; You should feel free to make your own keybindings.
|
|
||||||
;;
|
|
||||||
;; 'mark-more-like-this marks the ARG next matches (previous if negative)
|
|
||||||
;;
|
|
||||||
;; 'mark-next-like-this marks the next occurance.
|
|
||||||
;; - with a negative ARG, removes the last occurance.
|
|
||||||
;; - with a zero ARG, skips the last occurance and marks the next.
|
|
||||||
;;
|
|
||||||
;; 'mark-previous-like-this works like -next- but in the other direction.
|
|
||||||
;;
|
|
||||||
;; This extension is dependent on the mark-multiple library.
|
|
||||||
;; https://github.com/magnars/mark-multiple.el
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
(require 'mark-multiple)
|
|
||||||
|
|
||||||
(defun mark-next-like-this (arg)
|
|
||||||
"Find and mark the next part of the buffer matching the currently active region
|
|
||||||
With negative ARG, delete the last one instead.
|
|
||||||
With zero ARG, skip the last one and mark next."
|
|
||||||
(interactive "p")
|
|
||||||
(unless (or (region-active-p)
|
|
||||||
mm/master)
|
|
||||||
(error "Mark a region to match first."))
|
|
||||||
(if (< arg 0)
|
|
||||||
(mm/remove-mirror (mm/furthest-mirror-after-master)))
|
|
||||||
(if (>= arg 0)
|
|
||||||
(progn
|
|
||||||
(when (null mm/master)
|
|
||||||
(mm/create-master (region-beginning) (region-end)))
|
|
||||||
|
|
||||||
(save-excursion
|
|
||||||
(goto-char (mm/last-overlay-end))
|
|
||||||
(if (= arg 0)
|
|
||||||
(mm/remove-mirror (mm/furthest-mirror-after-master)))
|
|
||||||
(let ((case-fold-search nil)
|
|
||||||
(master-str (mm/master-substring)))
|
|
||||||
(if (search-forward master-str nil t)
|
|
||||||
(mm/add-mirror (- (point) (length master-str)) (point))
|
|
||||||
(error "no more found \"%s\" forward"
|
|
||||||
(substring-no-properties master-str))))))))
|
|
||||||
|
|
||||||
(defun mark-previous-like-this (arg)
|
|
||||||
"Find and mark the previous part of the buffer matching the currently active region
|
|
||||||
With negative ARG, delete the last one instead.
|
|
||||||
With zero ARG, skip the last one and mark previous."
|
|
||||||
(interactive "p")
|
|
||||||
(unless (or (region-active-p)
|
|
||||||
mm/master)
|
|
||||||
(error "Mark a region to match first."))
|
|
||||||
(if (< arg 0)
|
|
||||||
(mm/remove-mirror (mm/furthest-mirror-before-master)))
|
|
||||||
(if (>= arg 0)
|
|
||||||
(progn
|
|
||||||
(when (null mm/master)
|
|
||||||
(mm/create-master (region-beginning) (region-end)))
|
|
||||||
|
|
||||||
(save-excursion
|
|
||||||
(goto-char (mm/first-overlay-start))
|
|
||||||
(if (= arg 0)
|
|
||||||
(mm/remove-mirror (mm/furthest-mirror-before-master)))
|
|
||||||
(let ((case-fold-search nil)
|
|
||||||
(master-str (mm/master-substring)))
|
|
||||||
(if (search-backward master-str nil t)
|
|
||||||
(mm/add-mirror (point) (+ (point) (length master-str)))
|
|
||||||
(error "no more found \"%s\" backward"
|
|
||||||
(substring-no-properties master-str))))))))
|
|
||||||
|
|
||||||
(defun mark-all-like-this ()
|
|
||||||
"Find and mark all the parts of the buffer matching the currently active region"
|
|
||||||
(interactive)
|
|
||||||
(unless (or (region-active-p) mm/master) (error "Mark a region to match first."))
|
|
||||||
(if (not mm/master)
|
|
||||||
(mm/create-master (region-beginning) (region-end)))
|
|
||||||
(dolist (mirror mm/mirrors)
|
|
||||||
(delete-overlay mirror))
|
|
||||||
(setq mm/mirrors ())
|
|
||||||
(save-excursion
|
|
||||||
(goto-char 0)
|
|
||||||
(let ((case-fold-search nil)
|
|
||||||
(master-str (mm/master-substring)))
|
|
||||||
(while (search-forward master-str nil t)
|
|
||||||
(let ((start (- (point) (length master-str)))
|
|
||||||
(end (point)))
|
|
||||||
(if (/= (overlay-start mm/master) start)
|
|
||||||
(mm/add-mirror start end)))))))
|
|
||||||
|
|
||||||
(defun mark-all-like-this-in-region (reg-start reg-end)
|
|
||||||
"Find and mark all the parts in the region matching the given search"
|
|
||||||
(interactive "r")
|
|
||||||
(let ((search (read-from-minibuffer "Mark all in region: "))
|
|
||||||
(case-fold-search nil))
|
|
||||||
(deactivate-mark)
|
|
||||||
(save-excursion
|
|
||||||
(goto-char reg-start)
|
|
||||||
(while (search-forward search reg-end t)
|
|
||||||
(mm/create-master-or-mirror (- (point) (length search)) (point))))
|
|
||||||
(unless mm/master
|
|
||||||
(error "Search failed for %S" search))
|
|
||||||
(goto-char (mm/master-start))))
|
|
||||||
|
|
||||||
(defun mark-more-like-this (arg)
|
|
||||||
"Marks next part of buffer that matches the currently active region ARG times.
|
|
||||||
Given a negative ARG it searches backwards instead."
|
|
||||||
(interactive "p")
|
|
||||||
(unless (or (region-active-p)
|
|
||||||
mm/master)
|
|
||||||
(error "Mark a region to match first."))
|
|
||||||
(if (> arg 0)
|
|
||||||
(dotimes (i arg) (mark-next-like-this 1))
|
|
||||||
(dotimes (i (- arg)) (mark-previous-like-this 1))))
|
|
||||||
|
|
||||||
(defun mark-more-like-this-extended ()
|
|
||||||
"Like mark-more-like-this, but then lets you adjust with arrows key.
|
|
||||||
The actual adjustment made depends on the final component of the
|
|
||||||
key-binding used to invoke the command, with all modifiers removed:
|
|
||||||
|
|
||||||
<up> Mark previous like this
|
|
||||||
<down> Mark next like this
|
|
||||||
<left> If last was previous, skip it
|
|
||||||
If last was next, remove it
|
|
||||||
<right> If last was next, skip it
|
|
||||||
If last was previous, remove it
|
|
||||||
|
|
||||||
Then, continue to read input events and further add or move marks
|
|
||||||
as long as the input event read (with all modifiers removed)
|
|
||||||
is one of the above."
|
|
||||||
(interactive)
|
|
||||||
(let ((first t)
|
|
||||||
(ev last-command-event)
|
|
||||||
(cmd 'mark-next-like-this)
|
|
||||||
(arg 1)
|
|
||||||
last echo-keystrokes)
|
|
||||||
(while cmd
|
|
||||||
(let ((base (event-basic-type ev)))
|
|
||||||
(cond ((eq base 'left)
|
|
||||||
(if (eq last 'mark-previous-like-this)
|
|
||||||
(setq cmd last arg 0)
|
|
||||||
(setq cmd 'mark-next-like-this arg -1)))
|
|
||||||
((eq base 'up)
|
|
||||||
(setq cmd 'mark-previous-like-this arg 1))
|
|
||||||
((eq base 'right)
|
|
||||||
(if (eq last 'mark-next-like-this)
|
|
||||||
(setq cmd last arg 0)
|
|
||||||
(setq cmd 'mark-previous-like-this arg -1)))
|
|
||||||
((eq base 'down)
|
|
||||||
(setq cmd 'mark-next-like-this arg 1))
|
|
||||||
(first
|
|
||||||
(setq cmd 'mark-next-like-this arg 1))
|
|
||||||
(t
|
|
||||||
(setq cmd nil))))
|
|
||||||
(when cmd
|
|
||||||
(ignore-errors
|
|
||||||
(funcall cmd arg))
|
|
||||||
(setq first nil last cmd)
|
|
||||||
(setq ev (read-event "Use arrow keys for more marks: "))))
|
|
||||||
(push ev unread-command-events)))
|
|
||||||
|
|
||||||
(provide 'mark-more-like-this)
|
|
||||||
|
|
||||||
;;; mark-more-like-this.el ends here
|
|
269
util/vendor/mark-multiple.el
vendored
269
util/vendor/mark-multiple.el
vendored
@ -1,269 +0,0 @@
|
|||||||
;;; mark-multiple.el --- A library that sorta lets you mark several regions at once
|
|
||||||
|
|
||||||
;; Copyright (C) 2011 Magnar Sveen
|
|
||||||
|
|
||||||
;; Author: Magnar Sveen <magnars@gmail.com>
|
|
||||||
;; Keywords: marking library
|
|
||||||
|
|
||||||
;; This program is free software; you can redistribute it and/or modify
|
|
||||||
;; it under the terms of the GNU General Public License as published by
|
|
||||||
;; the Free Software Foundation, either version 3 of the License, or
|
|
||||||
;; (at your option) any later version.
|
|
||||||
|
|
||||||
;; This program is distributed in the hope that it will be useful,
|
|
||||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
;; GNU General Public License for more details.
|
|
||||||
|
|
||||||
;; You should have received a copy of the GNU General Public License
|
|
||||||
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
;;; Commentary:
|
|
||||||
|
|
||||||
;; An emacs extension that sorta lets you mark several regions at once.
|
|
||||||
;;
|
|
||||||
;; More precisely, it allows for one master region, with several mirror
|
|
||||||
;; regions. The mirrors are updated inline while you type. This allows for some
|
|
||||||
;; awesome functionality. Or at least, some more visually pleasing insert and
|
|
||||||
;; replace operations.
|
|
||||||
;;
|
|
||||||
;; Video
|
|
||||||
;; -----
|
|
||||||
;; You can [watch an intro to mark-multiple at Emacs Rocks](http://emacsrocks.com/e08.html).
|
|
||||||
;;
|
|
||||||
;; Done
|
|
||||||
;; ----
|
|
||||||
;; * A general library for managing master and mirrors
|
|
||||||
;; * `mark-more-like-this` which selects next/previous substring in the buffer that
|
|
||||||
;; matches the current region.
|
|
||||||
;; * `inline-string-rectangle` which works like `string-rectangle` but lets you
|
|
||||||
;; write inline - making it less error prone.
|
|
||||||
;; * `rename-sgml-tag` which updates the matching tag while typing.
|
|
||||||
;; * `js2-rename-var` which renames the variable on point and all occurrences
|
|
||||||
;; in its lexical scope.
|
|
||||||
;;
|
|
||||||
;; Installation
|
|
||||||
;; ------------
|
|
||||||
;;
|
|
||||||
;; git submodule add https://github.com/magnars/mark-multiple.el.git site-lisp/mark-multiple
|
|
||||||
;;
|
|
||||||
;; Then add the modules you want to your init-file:
|
|
||||||
;;
|
|
||||||
;; (require 'inline-string-rectangle)
|
|
||||||
;; (global-set-key (kbd "C-x r t") 'inline-string-rectangle)
|
|
||||||
;;
|
|
||||||
;; (require 'mark-more-like-this)
|
|
||||||
;; (global-set-key (kbd "C-<") 'mark-previous-like-this)
|
|
||||||
;; (global-set-key (kbd "C->") 'mark-next-like-this)
|
|
||||||
;; (global-set-key (kbd "C-M-m") 'mark-more-like-this) ; like the other two, but takes an argument (negative is previous)
|
|
||||||
;;
|
|
||||||
;; (require 'rename-sgml-tag)
|
|
||||||
;; (define-key sgml-mode-map (kbd "C-c C-r") 'rename-sgml-tag)
|
|
||||||
;;
|
|
||||||
;; Feel free to come up with your own keybindings.
|
|
||||||
;;
|
|
||||||
;; Ideas for more
|
|
||||||
;; --------------
|
|
||||||
;; * `js-rename-local-var` which renames the variable at point in the local file.
|
|
||||||
;;
|
|
||||||
;; Bugs and gotchas
|
|
||||||
;; ----------------
|
|
||||||
;; * Adding a master and mirrors does not remove the active region. This might feel
|
|
||||||
;; strange, but turns out to be practical.
|
|
||||||
;;
|
|
||||||
;; * The current mark-multiple general library lets you do stupid shit, like adding
|
|
||||||
;; overlapping mirrors. That's only a problem for people who want to write their
|
|
||||||
;; own functions using `mm/create-master` and `mm/add-mirror`.
|
|
||||||
;;
|
|
||||||
;; * Seems like there is some conflict with undo-tree.el, which sometimes clobbers
|
|
||||||
;; the undo history. I might be doing something particularly stupid. Looking into it.
|
|
||||||
;;
|
|
||||||
;; * Reverting the buffer with active marks makes them unremovable.
|
|
||||||
;;
|
|
||||||
;; A wild idea
|
|
||||||
;; -----------
|
|
||||||
;;
|
|
||||||
;; Is this a subset of a crazy multiple-point module? How would that even work?
|
|
||||||
;;
|
|
||||||
;; There is one use for it I can see, which is editing the end of lines. Set up one
|
|
||||||
;; cursor at the end of each line, then just edit normally. The command is repeated
|
|
||||||
;; for each position.
|
|
||||||
;;
|
|
||||||
;; Might be too far out there. I still want to do edit-end-of-lines tho.
|
|
||||||
;;
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
(defvar mm/master nil
|
|
||||||
"The master overlay has the point. Moving point out of master clears all.")
|
|
||||||
|
|
||||||
(defvar mm/mirrors nil
|
|
||||||
"A list of overlays that mirrors master after each change.")
|
|
||||||
|
|
||||||
(make-variable-buffer-local 'mm/master)
|
|
||||||
(make-variable-buffer-local 'mm/mirrors)
|
|
||||||
|
|
||||||
(defvar mm/keymap (make-sparse-keymap))
|
|
||||||
(define-key mm/keymap (kbd "C-g") 'mm/deactivate-region-or-clear-all)
|
|
||||||
(define-key mm/keymap (kbd "C-m") 'mm/deactivate-region-and-clear-all)
|
|
||||||
(define-key mm/keymap (kbd "<return>") 'mm/deactivate-region-and-clear-all)
|
|
||||||
|
|
||||||
(defface mm/master-face
|
|
||||||
'((((class color) (background light)) (:background "DarkSeaGreen1"))
|
|
||||||
(t (:background "DimGrey")))
|
|
||||||
"The face used to highlight master"
|
|
||||||
:group 'mark-multiple)
|
|
||||||
|
|
||||||
(defface mm/mirror-face
|
|
||||||
'((((class color) (background light)) (:background "DarkSeaGreen1"))
|
|
||||||
(t (:background "DimGrey")))
|
|
||||||
"The face used to highlight mirror"
|
|
||||||
:group 'mark-multiple)
|
|
||||||
|
|
||||||
(defun mm/create-master (start end)
|
|
||||||
"Start a new multiple mark selection by defining the master region from START to END.
|
|
||||||
Point must be within the region."
|
|
||||||
(if (or (< (point) start)
|
|
||||||
(> (point) end))
|
|
||||||
(error "Point must be inside master region"))
|
|
||||||
(mm/clear-all)
|
|
||||||
(setq mm/master
|
|
||||||
(make-overlay start end nil nil t))
|
|
||||||
(overlay-put mm/master 'priority 100)
|
|
||||||
(overlay-put mm/master 'face 'mm/master-face)
|
|
||||||
(overlay-put mm/master 'keymap mm/keymap)
|
|
||||||
(overlay-put mm/master 'modification-hooks '(mm/on-master-modification))
|
|
||||||
(overlay-put mm/master 'insert-in-front-hooks '(mm/on-master-modification))
|
|
||||||
(overlay-put mm/master 'insert-behind-hooks '(mm/on-master-modification))
|
|
||||||
(setq mm/mirrors ())
|
|
||||||
(add-hook 'post-command-hook 'mm/post-command-handler nil t))
|
|
||||||
|
|
||||||
(defun mm/add-mirror (start end)
|
|
||||||
"Add a region START to END that will mirror the current master."
|
|
||||||
(if (null mm/master)
|
|
||||||
(error "No master defined to mirror. Start with mm/create-master."))
|
|
||||||
(let ((mirror (make-overlay start end nil nil t)))
|
|
||||||
(setq mm/mirrors (cons mirror mm/mirrors))
|
|
||||||
(overlay-put mirror 'priority 100)
|
|
||||||
(overlay-put mirror 'face 'mm/mirror-face)))
|
|
||||||
|
|
||||||
(defun mm/deactivate-region-or-clear-all ()
|
|
||||||
"Deactivate mark if active, otherwise clear all."
|
|
||||||
(interactive)
|
|
||||||
(if (use-region-p)
|
|
||||||
(deactivate-mark)
|
|
||||||
(mm/clear-all)))
|
|
||||||
|
|
||||||
(defun mm/deactivate-region-and-clear-all ()
|
|
||||||
"Deactivate mark and clear all."
|
|
||||||
(interactive)
|
|
||||||
(deactivate-mark)
|
|
||||||
(mm/clear-all))
|
|
||||||
|
|
||||||
(defun mm/clear-all ()
|
|
||||||
"Remove all marks"
|
|
||||||
(interactive)
|
|
||||||
(when (overlayp mm/master)
|
|
||||||
(delete-overlay mm/master)
|
|
||||||
(dolist (mirror mm/mirrors)
|
|
||||||
(delete-overlay mirror))
|
|
||||||
(setq mm/master nil)
|
|
||||||
(setq mm/mirrors ())
|
|
||||||
(remove-hook 'post-command-hook 'mm/post-command-handler)))
|
|
||||||
|
|
||||||
(defun mm/master-start ()
|
|
||||||
(overlay-start mm/master))
|
|
||||||
|
|
||||||
(defun mm/master-end ()
|
|
||||||
(overlay-end mm/master))
|
|
||||||
|
|
||||||
(defun mm/point-is-outside-of-master ()
|
|
||||||
"Is point outside of master?"
|
|
||||||
(or (null mm/master)
|
|
||||||
(< (point) (mm/master-start))
|
|
||||||
(> (point) (mm/master-end))))
|
|
||||||
|
|
||||||
(defun mm/active-region-is-outside-of-master ()
|
|
||||||
"Is region active and mark outside master?"
|
|
||||||
(and (region-active-p)
|
|
||||||
(or (< (mark) (mm/master-start))
|
|
||||||
(> (mark) (mm/master-end)))))
|
|
||||||
|
|
||||||
(defun mm/post-command-handler ()
|
|
||||||
"Clear all marks if point or region is outside of master"
|
|
||||||
(if (or (mm/point-is-outside-of-master)
|
|
||||||
(mm/active-region-is-outside-of-master))
|
|
||||||
(mm/clear-all)))
|
|
||||||
|
|
||||||
(defun mm/master-substring ()
|
|
||||||
"Get the buffer substring that is in master"
|
|
||||||
(buffer-substring (mm/master-start) (mm/master-end)))
|
|
||||||
|
|
||||||
(defun mm/on-master-modification (overlay after? beg end &optional length)
|
|
||||||
"Update all mirrors after a change"
|
|
||||||
(save-excursion
|
|
||||||
(dolist (mirror mm/mirrors)
|
|
||||||
(mm/replace-mirror-substring mirror (mm/master-substring)))))
|
|
||||||
|
|
||||||
(defun mm/replace-mirror-substring (mirror substring)
|
|
||||||
"Replace the contents of MIRROR with SUBSTRING"
|
|
||||||
(goto-char (overlay-start mirror))
|
|
||||||
(delete-char (- (overlay-end mirror) (overlay-start mirror)))
|
|
||||||
(insert substring))
|
|
||||||
|
|
||||||
;; Define some utility functions for users of mark-multiple:
|
|
||||||
|
|
||||||
(defun mm/create-master-or-mirror (start end)
|
|
||||||
"Create master from START to END if there is none, otherwise add mirror."
|
|
||||||
(if (null mm/master)
|
|
||||||
(mm/create-master start end)
|
|
||||||
(mm/add-mirror start end)))
|
|
||||||
|
|
||||||
(defun mm/remove-mirror (mirror)
|
|
||||||
"Removes all traces of MIRROR"
|
|
||||||
(setq mm/mirrors (remove mirror mm/mirrors))
|
|
||||||
(delete-overlay mirror))
|
|
||||||
|
|
||||||
(defun mm/furthest-mirror-before-master ()
|
|
||||||
"Find the mirror with the lowest start position before master"
|
|
||||||
(if (null mm/mirrors)
|
|
||||||
(error "No mirrors to be found, sir."))
|
|
||||||
(let ((first nil)
|
|
||||||
(start (mm/master-start)))
|
|
||||||
(dolist (mirror mm/mirrors)
|
|
||||||
(when (< (overlay-start mirror) start)
|
|
||||||
(setq first mirror)
|
|
||||||
(setq start (overlay-start mirror))))
|
|
||||||
first))
|
|
||||||
|
|
||||||
(defun mm/furthest-mirror-after-master ()
|
|
||||||
"Find the mirror with the highest end position after master"
|
|
||||||
(if (null mm/mirrors)
|
|
||||||
(error "No mirrors to be found, sir."))
|
|
||||||
(let ((last nil)
|
|
||||||
(end (mm/master-end)))
|
|
||||||
(dolist (mirror mm/mirrors)
|
|
||||||
(when (> (overlay-end mirror) end)
|
|
||||||
(setq last mirror)
|
|
||||||
(setq end (overlay-end mirror))))
|
|
||||||
last))
|
|
||||||
|
|
||||||
(defun mm/first-overlay-start ()
|
|
||||||
"Find first buffer position covered by master and mirrors"
|
|
||||||
(let ((start (mm/master-start)))
|
|
||||||
(dolist (mirror mm/mirrors)
|
|
||||||
(if (< (overlay-start mirror) start)
|
|
||||||
(setq start (overlay-start mirror))))
|
|
||||||
start))
|
|
||||||
|
|
||||||
(defun mm/last-overlay-end ()
|
|
||||||
"Find last buffer position covered by master and mirrors"
|
|
||||||
(let ((end (mm/master-end)))
|
|
||||||
(dolist (mirror mm/mirrors)
|
|
||||||
(if (> (overlay-end mirror) end)
|
|
||||||
(setq end (overlay-end mirror))))
|
|
||||||
end))
|
|
||||||
|
|
||||||
(provide 'mark-multiple)
|
|
||||||
|
|
||||||
;;; mark-multiple.el ends here
|
|
Loading…
x
Reference in New Issue
Block a user