;;; mc-cycle-cursors.el ;; Copyright (C) 2012 Magnar Sveen ;; Author: Magnar Sveen ;; 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 . ;;; Commentary: ;; This scrolls the buffer to center each cursor in turn. ;; Scroll down with C-v, scroll up with M-v ;; This is nice when you have cursors that's outside of your view. ;;; Code: (require 'multiple-cursors-core) (eval-when-compile (require 'cl)) (defun mc/next-fake-cursor-after-point () (let ((pos (point)) (next-pos (1+ (point-max))) next) (mc/for-each-fake-cursor (let ((cursor-pos (overlay-get cursor 'point))) (when (and (< pos cursor-pos) (< cursor-pos next-pos)) (setq next-pos cursor-pos) (setq next cursor)))) next)) (defun mc/prev-fake-cursor-before-point () (let ((pos (point)) (prev-pos (1- (point-min))) prev) (mc/for-each-fake-cursor (let ((cursor-pos (overlay-get cursor 'point))) (when (and (> pos cursor-pos) (> cursor-pos prev-pos)) (setq prev-pos cursor-pos) (setq prev cursor)))) prev)) (defcustom mc/cycle-looping-behaviour 'continue "What to do if asked to cycle beyond the last cursor or before the first cursor." :type '(radio (const :tag "Loop around to beginning/end of document." continue) (const :tag "Warn and then loop around." warn) (const :tag "Signal an error." error) (const :tag "Don't loop." stop)) :group 'multiple-cursors) (defun mc/handle-loop-condition (error-message) (ecase mc/cycle-looping-behaviour (error (error error-message)) (warn (message error-message)) (continue 'continue) (stop 'stop))) (defun mc/first-fake-cursor-after (point) "Very similar to mc/furthest-cursor-before-point, but ignores (mark) and (point)." (let* ((cursors (mc/all-fake-cursors)) (cursors-after-point (remove-if (lambda (cursor) (< (mc/cursor-beg cursor) point)) cursors)) (cursors-in-order (sort* cursors-after-point '< :key 'mc/cursor-beg))) (first cursors-in-order))) (defun mc/last-fake-cursor-before (point) "Very similar to mc/furthest-cursor-before-point, but ignores (mark) and (point)." (let* ((cursors (mc/all-fake-cursors)) (cursors-before-point (remove-if (lambda (cursor) (> (mc/cursor-end cursor) point)) cursors)) (cursors-in-order (sort* cursors-before-point '> :key 'mc/cursor-end))) (first cursors-in-order))) (defun* mc/cycle (next-cursor fallback-cursor loop-message) (when (null next-cursor) (when (eql 'stop (mc/handle-loop-condition loop-message)) (return-from mc/cycle nil)) (setf next-cursor fallback-cursor)) (mc/create-fake-cursor-at-point) (mc/pop-state-from-overlay next-cursor) (recenter)) (defun mc/cycle-forward () (interactive) (mc/cycle (mc/next-fake-cursor-after-point) (mc/first-fake-cursor-after (point-min)) "We're already at the last cursor.")) (defun mc/cycle-backward () (interactive) (mc/cycle (mc/prev-fake-cursor-before-point) (mc/last-fake-cursor-before (point-max)) "We're already at the last cursor")) (define-key mc/keymap (kbd "C-v") 'mc/cycle-forward) (define-key mc/keymap (kbd "M-v") 'mc/cycle-backward) (provide 'mc-cycle-cursors) ;; Local Variables: ;; coding: utf-8 ;; byte-compile-warnings: (not cl-functions) ;; End: ;;; mc-cycle-cursors.el ends here