From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: martin rudalics Newsgroups: gmane.emacs.devel Subject: Re: transpose-regions Date: Thu, 22 Mar 2007 22:32:31 +0100 Message-ID: <4602F5EF.4080604@gmx.at> References: <46026277.7060305@gmx.at> <87odml9v67.fsf@stupidchicken.com> <4602A015.2080403@gmx.at> <87bqil5kxd.fsf@stupidchicken.com> <4602B7B5.1070705@gmx.at> <87y7lp886g.fsf@stupidchicken.com> <4602D6B9.1000503@gmx.at> <871wjh9gcy.fsf@stupidchicken.com> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------070403010002030807000403" X-Trace: sea.gmane.org 1174599235 781 80.91.229.12 (22 Mar 2007 21:33:55 GMT) X-Complaints-To: usenet@sea.gmane.org NNTP-Posting-Date: Thu, 22 Mar 2007 21:33:55 +0000 (UTC) Cc: emacs-devel To: Chong Yidong Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Thu Mar 22 22:33:44 2007 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([199.232.76.165]) by lo.gmane.org with esmtp (Exim 4.50) id 1HUUul-0007cn-F2 for ged-emacs-devel@m.gmane.org; Thu, 22 Mar 2007 22:33:44 +0100 Original-Received: from localhost ([127.0.0.1] helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1HUUwZ-0003Oi-J4 for ged-emacs-devel@m.gmane.org; Thu, 22 Mar 2007 16:35:35 -0500 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1HUUvw-00020l-Fs for emacs-devel@gnu.org; Thu, 22 Mar 2007 17:34:56 -0400 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1HUUvt-0001u8-NN for emacs-devel@gnu.org; Thu, 22 Mar 2007 17:34:55 -0400 Original-Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1HUUvt-0001td-Cu for emacs-devel@gnu.org; Thu, 22 Mar 2007 16:34:53 -0500 Original-Received: from mail.gmx.net ([213.165.64.20]) by monty-python.gnu.org with smtp (Exim 4.60) (envelope-from ) id 1HUUu2-0003yD-Ks for emacs-devel@gnu.org; Thu, 22 Mar 2007 17:32:59 -0400 Original-Received: (qmail invoked by alias); 22 Mar 2007 21:32:56 -0000 Original-Received: from N797P021.adsl.highway.telekom.at (EHLO [62.47.43.149]) [62.47.43.149] by mail.gmx.net (mp030) with SMTP; 22 Mar 2007 22:32:56 +0100 X-Authenticated: #14592706 X-Provags-ID: V01U2FsdGVkX1+xjZAGh/uxdfMBK+BryZ0I4ZTHpICawp80YbrPkS 1HDjUZmNSTsN1B User-Agent: Mozilla Thunderbird 1.0 (Windows/20041206) X-Accept-Language: de-DE, de, en-us, en In-Reply-To: <871wjh9gcy.fsf@stupidchicken.com> X-Y-GMX-Trusted: 0 X-detected-kernel: Linux 2.6, seldom 2.4 (older, 4) X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:68329 Archived-At: This is a multi-part message in MIME format. --------------070403010002030807000403 Content-Type: text/plain; charset=ISO-8859-15; format=flowed Content-Transfer-Encoding: 7bit > Does the problem occur when you compile with no optimizations? I never use any options to compile. What shall I use? >>I could send you the Elisp code I use to trigger this. You'd have >>to play around with it a bit, though. > > > Is this the m&d-drag-line-up function that KFS already posted? I've > been trying it out on various buffers, and have been unable to > reproduce it---is there a specific buffer you act on to produce the > error? There's also a m&d-drag-line-down function and a pre-command hook. Initially written while I worked with Emacs 20 (and transpose-regions was somehow broken IIRC) and awfully patched a couple of times afterwards. I attach it. To reproduce bind the drag-line functions to a key and use the auto-repeat functionality of the keyboard (I use a hyper key and the arrow keys for this purpose). --------------070403010002030807000403 Content-Type: text/plain; name="m&d.el" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="m&d.el" ;;; m&d.el --- move'n drag support functions ;; Copyright (C) 2005 Martin Rudalics ;; Time-stamp: "2007-02-26 07:56:15 martin" ;; Author: Martin Rudalics ;; Keywords: sexps ;; Version: 0.1 ;; m&d.el 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 2, or (at your option) ;; any later version. ;; m&d.el 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. ;;; Commentary: ;; move and drag support functions for GNU Emacs. ;;; Code: ;; _____________________________________________________________________________ ;; ;;; Faces ;; _____________________________________________________________________________ ;; (defgroup m&d nil "Move and drag." :version "22.1" :group 'faces) (defcustom m&d-alert-delay 0.2 "*Time m&d alerts when saving or replacing the m&d-region." :type '(choice number (const :tag "Don't alert" nil)) :group 'm&d) (defface m&d-alert '((((class color)) :background "Bisque") (t :bold t)) "Face for highlighting m&d alerts." :group 'm&d) (defface m&d-before '((((class color)) :foreground "Black" :background "Yellow") (t :bold t)) "Face for highlighting delimiter before m&d-region." :group 'm&d) (defface m&d-after '((((class color)) :foreground "Black" :background "Yellow") (t :bold t)) "Face for highlighting delimiter after m&d-region." :group 'm&d) (defface m&d-left '((((class color)) :background "Azure") (t :bold t)) "Face for highlighting sexp left to m&d-region." :group 'm&d) (defface m&d-right '((((class color)) :background "Azure") (t :bold t)) "Face for highlighting sexp right to m&d-region." :group 'm&d) (defface m&d-save '((t :underline t)) "Face for highlighting sexp right to m&d-region." :group 'm&d) ;; _____________________________________________________________________________ ;; ;;; Overlays ;; _____________________________________________________________________________ ;; ;; Observe: The following overlays are window-local (defvar m&d-alert-overlay (make-overlay 1 1)) (overlay-put m&d-alert-overlay 'face 'm&d-alert) (defvar m&d-before-overlay (make-overlay 1 1)) (overlay-put m&d-before-overlay 'face 'm&d-before) (defvar m&d-after-overlay (make-overlay 1 1)) (overlay-put m&d-after-overlay 'face 'm&d-after) (defvar m&d-left-overlay (make-overlay 1 1)) (overlay-put m&d-left-overlay 'face 'm&d-left) (defvar m&d-right-overlay (make-overlay 1 1)) (overlay-put m&d-right-overlay 'face 'm&d-right) ;; _____________________________________________________________________________ ;; ;;; Move ;; _____________________________________________________________________________ ;; (defsubst m&d-syntax-class-after (&optional at) (let ((at (or at (point)))) (syntax-class (syntax-after at)))) (defsubst m&d-syntax-class-before (&optional at) (let ((at (or at (point)))) (syntax-class (syntax-after (1- at))))) (defsubst m&d-escaped-p (&optional at) (save-excursion (when at (goto-char at)) (while (and (eq (m&d-syntax-class-before) '9) (eq (m&d-syntax-class-before (1- (point))) '9)) (backward-char 2)) (eq (m&d-syntax-class-before) '9))) (defun m&d-forward-sexp (&optional arg) "Like `forward-sexp' but within literal narrow to literal before. With `point' before character with close paren syntax highlight enclosing expression with `m&d-alert' face. Don't generate an error in any case." (interactive "p") (let ((at (point)) (state (syntax-ppss))) (condition-case nil (if (or (nth 3 state) (nth 4 state)) (save-restriction (narrow-to-region (nth 8 state) (condition-case nil (save-excursion (parse-partial-sexp (point) (point-max) nil nil state 'syntax-table) (point)) (error (point-max)))) (forward-sexp arg)) (forward-sexp arg)) (error (move-overlay m&d-alert-overlay (condition-case nil (save-excursion (m&d-beginning-of-list) (point)) (error (point-min))) at) (overlay-put m&d-alert-overlay 'window (selected-window)) (ding))))) (defun m&d-backward-sexp (&optional arg) "Like `backward-sexp' but within literal narrow to literal before. With `point' after character with open paren syntax highlight enclosing expression with `m&d-alert' face. Don't generate an error in any case." (interactive "p") (let ((at (point)) (state (syntax-ppss))) (condition-case nil (if (or (nth 3 state) (nth 4 state)) (save-restriction (narrow-to-region (nth 8 state) (condition-case nil (save-excursion (parse-partial-sexp (point) (point-max) nil nil state 'syntax-table) (point)) (error (point-max)))) (backward-sexp arg)) (backward-sexp arg)) (error (move-overlay m&d-alert-overlay at (condition-case nil (save-excursion (m&d-end-of-list) (point)) (error (point-max)))) (overlay-put m&d-alert-overlay 'window (selected-window)) (ding))))) (defun m&d-beginning-of-defun (&optional arg) "Like `beginning-of-defun' but don't generate an error." (interactive "p") (let ((at (point))) (condition-case nil (beginning-of-defun arg) (error (ding))))) (defun m&d-end-of-defun (&optional arg) "Like `end-of-defun' but don't generate an error." (interactive "p") (let ((at (point))) (condition-case nil (end-of-defun arg) (error (ding))))) (defun m&d-beginning-of-list (&optional arg) (interactive "p") (let ((at (point))) (condition-case nil (progn (backward-up-list arg) (forward-char)) (error (ding))))) (defun m&d-end-of-list (&optional arg) (interactive "p") (let ((at (point))) (condition-case nil (progn (up-list arg) (backward-char)) (error (ding))))) (defun m&d-forward-up (&optional arg) (interactive "p") (let ((at (point))) (condition-case nil (up-list arg) (error (ding))))) (defun m&d-backward-up (&optional arg) (interactive "p") (let ((at (point))) (condition-case nil (backward-up-list arg) (error (ding))))) (defun m&d-home () "In first call move point to beginning of line, in subsequent calls to beginning of buffer." (interactive) (if (eq last-command 'm&d-home) (goto-char (point-min)) (beginning-of-line))) (defun m&d-end () "In first call move point to end of line, in subsequent calls to end of buffer." (interactive) (if (eq last-command 'm&d-end) (goto-char (point-max)) (end-of-line))) ;; _____________________________________________________________________________ ;; ;;; Mark ;; _____________________________________________________________________________ ;; (defvar m&d-mark-history () ; remove duplicates, eventually "History for actual `m&d-mark-sexp', reset by `m&d-pre-command'. Each entry is a cons pair whose car is point and whose cdr mark.") (defvar m&d-mark nil) (defun m&d-ensure-mark () (when mark-active (setq deactivate-mark nil))) (defun m&d-mark-highlight (&optional from to) "Highlight various parts of m&d-region." (unless (memq major-mode '(sobar-mode sonderbar-mode)) (let ((from (or from (and mark-active (min (point) (mark))) (point))) (to (or to (and mark-active (max (point) (mark))) (point))) (window (selected-window)) before after beg end) (setq m&d-mark t) (condition-case nil (save-excursion (condition-case nil (progn (goto-char from) (backward-up-list) (setq before (point)) (move-overlay m&d-before-overlay before (1+ before)) (overlay-put m&d-before-overlay 'window window)) (error nil)) (condition-case nil (progn (goto-char to) (up-list) (setq after (point)) (move-overlay m&d-after-overlay (1- after) after) (overlay-put m&d-after-overlay 'window window)) (error nil)) (condition-case nil (progn (goto-char from) (backward-sexp) (setq beg (point)) (forward-sexp) (setq end (point)) (when (and (< beg end) (<= end from)) (move-overlay m&d-left-overlay beg end) (overlay-put m&d-left-overlay 'window window))) (error nil)) (condition-case nil (progn (goto-char to) (forward-sexp) (setq end (point)) (backward-sexp) (setq beg (point)) (when (and (<= to beg) (< beg end)) (move-overlay m&d-right-overlay beg end) (overlay-put m&d-right-overlay 'window window))) (error nil))) (error nil))))) (defun m&d-exchange-point-and-mark () "Like `exchange-point-and-mark' but highlight marked region." (interactive) (exchange-point-and-mark) (m&d-mark-highlight (min (point) (mark)) (max (point) (mark)))) (defun m&d-mark-sexp () "Enlarge m&d-region. Pushes previous values of `point' and `mark' on `m&d-mark-history'." (interactive) (if mark-active (let* ((state (syntax-ppss)) (beg (min (mark) (point))) (end (max (mark) (point))) (point-is-beg (= beg (point))) (point-mark (cons (point) (mark))) from to before-after) (cond ((eq (m&d-syntax-class-before beg) '6) (save-excursion (goto-char beg) (skip-syntax-backward "'") (setq from (point))) (save-excursion (goto-char end) (skip-syntax-forward "'") (setq to (point))) (setq before-after t)) ((or (nth 3 state) (nth 4 state)) ;; Within string or comment, mark entire string or comment. (setq from (nth 8 state)) (setq to (save-excursion (condition-case nil (progn (parse-partial-sexp (point) (point-max) nil nil state 'syntax-table) (point)) (error nil)))) (cond ((nth 3 state) (setq before-after t)) ((and from to (nth 4 state) (or (> from beg) (< to end) (and (= from beg) (= to end)))) ;; Failed to expand comment. (save-excursion (goto-char from) (forward-comment (- (buffer-size))) (setq from (point))) (save-excursion (goto-char to) (forward-comment (buffer-size)) (setq to (point)))))) ((let ((class-first (syntax-class (syntax-after beg))) (class-last (syntax-class (syntax-after (1- end)))) from-white to-white) ;; Before or after a comment: Mark entire sequence of comments ;; before and after the present. `from-white' and `to-white' ;; shall guarantee that the marked region encompasses entire ;; marked region before applying the present step. (and (or (memq class-first '(11 14)) (memq class-last '(12 14))) (condition-case nil (progn ;; The following is weird but I do want to distinguish ;; newlines that terminate comments from newlines that ;; don't. Hence I skip all comments before or after ;; point first. (save-excursion (setq from beg) (while (forward-comment -1) (setq from (point))) (setq from-white (point))) (save-excursion (setq to end) (while (forward-comment 1) (setq to (point))) (setq to-white (point))) ;; Something should have been enlarged here. (unless (and (<= from beg) (>= to end)) ;; Symmetrically include previously marked whitespace. (setq from from-white) (setq to to-white)) (or (< from beg) (> to end))) (error nil))))) ((nth 1 state) (setq from (save-excursion (goto-char (nth 1 state)) (point))) (condition-case nil (progn (parse-partial-sexp (point) (point-max) (1- (nth 0 state)) nil state) (setq to (point)) (setq before-after t)) (error nil))) (t (setq from (point-min)) (setq to (point-max)) (m&d-mark-highlight from to))) (if (and from to) (progn (setq m&d-mark-history (cons point-mark m&d-mark-history)) (when before-after (m&d-mark-highlight from to)) (set-mark (if point-is-beg to from)) (goto-char (if point-is-beg from to))) ;; This shouldn't happen. (message "Can't mark") (ding))) ;; Region inactive, move to some significant position: (let* ((at (save-excursion (skip-chars-forward " \t") (point))) (class (syntax-class (syntax-after at))) (point-mark (cons (point) nil)) from to before-after) (save-excursion (goto-char at) (cond ((memq class '(2 3 8 9 10 13)) ;; Word, symbol, open paren, and some others. (save-excursion (condition-case nil (backward-sexp) (error nil)) (skip-syntax-forward "'") (skip-syntax-backward "/\\") (setq from (point))) (forward-sexp) (backward-prefix-chars) (setq to (point)) (setq before-after 'check)) ((memq class '(4 6)) ;; Expression prefix. (save-excursion (skip-syntax-backward "'") (setq from (point))) (forward-sexp) (setq to (point)) (setq before-after 'check)) ((eq class '5) ;; Close paren. (forward-char) (condition-case nil (progn (backward-sexp) (setq from (point)) (forward-sexp) (backward-prefix-chars) (setq to (point)) (setq before-after 'check)) (error nil))) ((memq class '(7 15)) (let ((state (syntax-ppss))) (if (nth 3 state) ;; Within string. (save-restriction (narrow-to-region (nth 8 state) (condition-case nil (save-excursion (parse-partial-sexp (point) (point-max) nil nil state 'syntax-table) (point)) (error (point-max)))) (forward-char) (condition-case nil (progn (backward-sexp) (setq from (point)) (forward-sexp) (backward-prefix-chars) (setq to (point)) (when (and (= from (point-min)) (= to (point-max))) (setq before-after t))) (error nil))) ;; Before string (forward-sexp) (backward-prefix-chars) (setq to (point)) (condition-case nil (backward-sexp) (error nil)) (skip-syntax-forward "'") (setq from (point)) (setq before-after t)))) ((and (memq class '(11 12 14)) ;; Around comment, we wrap this in an `and' to give the ;; subsequent steps a chance. (let ((state (syntax-ppss))) (cond ((nth 4 state) ;; Within comment. (setq from (nth 8 state)) (condition-case nil (save-excursion (parse-partial-sexp (point) (point-max) nil nil state 'syntax-table) (setq to (point))) (error nil))) ((memq class '(11 14)) ;; Probably before comment. (setq from (point)) (condition-case nil (save-excursion (forward-comment 1) (setq to (point))) (error nil))))))) ((eq class '1) ;; Mark punctuation syntax. (save-excursion (skip-syntax-forward ".") (setq to (point))) (skip-syntax-backward ".") (setq from (point))) ((eq (char-after) ?\n) ;; Mark whitespace around newline, mark nothing at end of not ;; newline terminated buffer. (save-excursion (when (forward-comment -1) (forward-comment 1)) (setq from (point))) (save-excursion (when (forward-comment 1) (forward-comment -1)) (setq to (point)))))) (if (and from to) (progn (when before-after (if (eq before-after 'check) (let ((state (syntax-ppss)) narrow-from narrow-to) (if (or (nth 3 state) (nth 4 state)) (save-excursion (setq narrow-from (nth 8 state)) (setq narrow-to (condition-case nil (progn (parse-partial-sexp (point) (point-max) nil nil state 'syntax-table) (point)) (error nil))) (when (and narrow-from narrow-to) (save-restriction (narrow-to-region narrow-from narrow-to) (m&d-mark-highlight from to)))) (m&d-mark-highlight from to))) (m&d-mark-highlight from to))) (setq m&d-mark-history (cons point-mark m&d-mark-history)) (push-mark to t t) (goto-char from)) (message "Can't mark") (ding))))) (defun m&d-mark-undo () "Pop `m&d-mark-history'." (interactive) (if m&d-mark-history (let ((mark (cdar m&d-mark-history))) (when mark (set-mark mark)) (setq mark-active mark) (goto-char (caar m&d-mark-history)) (when mark (m&d-mark-highlight (min (point) (mark)) (max (point) (mark)))) (setq m&d-mark-history (cdr m&d-mark-history))) (message "No undo information") (ding))) ;; Maybe this should become a ring. (defvar m&d-saved-region nil "Region saved by last `m&d-save-region'.") (defun m&d-alert-region (beg end) "Temporarily highlight region with `m&d-alert' face." (when m&d-alert-delay (setq mark-active nil) (let ((overlay (make-overlay beg end))) (overlay-put overlay 'face 'm&d-alert) (overlay-put overlay 'priority 100000) (delete-overlay overlay)) (sit-for m&d-alert-delay) (setq mark-active t))) (defun m&d-save-region (beg end) "Save m&d-region into `m&d-saved-region'. Does not modify `m&d-mark-undo'." (interactive "r") (setq m&d-saved-region (buffer-substring-no-properties beg end)) (m&d-alert-region beg end) (m&d-mark-highlight beg end)) (defun m&d-replace-region (beg end) "Replace m&d-region by `m&d-saved-region'. Clears `m&d-mark-undo'." (interactive "r") (if m&d-saved-region (let ((to (+ beg (length m&d-saved-region)))) (delete-region beg end) (insert m&d-saved-region) (goto-char beg) (set-mark to) (setq deactivate-mark nil) (m&d-alert-region beg to) (m&d-mark-highlight beg to)) (error "Nothing saved"))) (defun m&d-kill-region (beg end) (interactive "r") (let (from to left right) (if (and (save-excursion (goto-char beg) (skip-chars-backward " \t") (cond ((bolp) (setq from (point))) ((bobp) nil) (t (setq from beg) (setq left t)))) (save-excursion (goto-char end) (skip-chars-forward " \t") (cond ((eolp) (setq to (point))) ((eobp) nil) (t (setq to end) (setq right t))))) (cond ((and left right) (delete-region end to) (kill-region beg end) (delete-region from beg) (fixup-whitespace)) (left ;; Remove everything from end till first non-whitespace. (goto-char end) (skip-chars-forward " \t\n\f") (delete-region end (point)) (kill-region beg end) (delete-region from beg)) (right (delete-region end to) (kill-region beg end) (goto-char beg) (skip-chars-backward " \t\n\f") (if (nth 4 (syntax-ppss)) (delete-region (1+ (point)) beg) (delete-region (point) beg))) (t (delete-region end (if (= to (point-max)) to (1+ to))) (kill-region beg end) (delete-region from beg))) (kill-region beg end)))) (defun m&d-copy () "Copy region or line and point and activate it." (interactive) (let ((copied-string (if mark-active (buffer-substring (min (mark) (point)) (max (mark) (point))) (buffer-substring (line-beginning-position) (line-beginning-position 2))))) (goto-char (if mark-active (max (mark) (point)) (line-beginning-position 2))) (insert copied-string) (set-mark (point)) (goto-char (- (point) (length copied-string))) (setq deactivate-mark nil) (setq mark-active t))) ;; _____________________________________________________________________________ ;; ;;; Drag ;; _____________________________________________________________________________ ;; (defun m&d-drag-char-right () "If region is active drag it right by one char else drag char at point right." (interactive) (cond (mark-active (let* ((beg (min (mark) (point))) (end (max (mark) (point))) (mark-beg (1+ (- (mark) beg))) (point-beg (1+ (- (point) beg)))) (if (= end (point-max)) (progn (message "Can't drag") (ding)) (transpose-regions beg end end (1+ end)) (set-mark (+ mark-beg beg)) (setq deactivate-mark nil) (goto-char (+ point-beg beg))))) ((or (eobp) (= (point) (1- (point-max)))) (m&d-ensure-mark) (message "Can't drag") (ding)) (t (let ((to (1+ (point)))) (transpose-regions (point) to to (1+ to)) (goto-char to))))) (defun m&d-drag-char-left () "If region is active drag it left by one char else drag char at point left." (interactive) (cond (mark-active (let* ((beg (min (mark) (point))) (end (max (mark) (point))) (mark-beg (- (mark) beg 1)) (point-beg (- (point) beg 1))) (if (= beg (point-min)) (progn (message "Can't drag") (ding)) (transpose-regions (1- beg) beg beg end) (set-mark (+ mark-beg beg)) (setq deactivate-mark nil) (goto-char (+ point-beg beg))))) ((or (bobp) (eobp)) (m&d-ensure-mark) (message "Can't drag") (ding)) (t (let ((to (1- (point)))) (transpose-regions to (point) (point) (1+ (point))) (goto-char to))))) (defun m&d-drag-line-down (&optional beg end) "Drag region down by one line. Region defaults to current line. Region is always rounded up to whole lines." (interactive) (let* ((beg (save-excursion (goto-char (or beg (and mark-active (min (point) (mark))) (point))) (line-beginning-position))) (end (save-excursion (goto-char (or end (and mark-active (max (point) (mark))) (line-beginning-position 2))) (if (bolp) (point) (line-beginning-position 2)))) (point-beg (and (<= beg (point)) (<= (point) end) (- (point) beg))) (mark-beg (and mark-active (<= beg (mark)) (<= (mark) end) (- (mark) beg))) (to (save-excursion (goto-char end) (line-beginning-position 2))) (recenter (when (= beg (window-start)) (1+ (count-lines beg end))))) (unless (and (>= (point) beg) (<= (point) end)) ;; `point' should be within dragged region. (goto-char end)) ;;; (condition-case nil ;; Wrapped in condition-case until we find out why `transpose-regions' ;; is broken. (if (> to end) (progn (if (save-excursion (goto-char to) (not (bolp))) ;; Pobably at eob. (progn (when (= (point) end) (backward-char)) (transpose-regions beg (1- end) end to)) (transpose-regions beg end end to)) ;; Don't push mark. (when mark-beg (set-mark (+ mark-beg beg (- to end))) (setq deactivate-mark nil)) (when point-beg (goto-char (+ point-beg beg (- to end)))) (when recenter (recenter recenter))) (m&d-ensure-mark) (message "Can't drag") (ding)) ;;; (error (m&d-ensure-mark))))) )) (defun m&d-drag-line-up (&optional beg end) "Drag region up by one line. Region defaults to current line. Region is always rounded up to whole lines." (interactive) (let* ((beg (save-excursion (goto-char (or beg (and mark-active (min (point) (mark))) (point))) (line-beginning-position))) (end (save-excursion (goto-char (or end (and mark-active (max (point) (mark))) (line-beginning-position 2))) (if (bolp) (point) (line-beginning-position 2)))) (point-beg (and (<= beg (point)) (<= (point) end) (- (point) beg))) (mark-beg (and mark-active (<= beg (mark)) (<= (mark) end) (- (mark) beg))) (from (save-excursion (goto-char beg) (line-beginning-position 0))) (recenter (when (= from (window-start)) (count-lines beg end)))) ;;; (condition-case nil ;; Wrapped in condition-case until we find out why `transpose-regions' ;; is broken. (if (> beg from) (progn (if (save-excursion (goto-char end) (not (bolp))) ;; Probably at eob. (transpose-regions from (1- beg) beg end) (transpose-regions from beg beg end)) (when mark-beg (set-mark (+ mark-beg from)) (setq deactivate-mark nil)) (when point-beg (goto-char (+ point-beg from))) (when recenter (recenter recenter))) (m&d-ensure-mark) (message "Can't drag") (ding)) ;;; (error (m&d-ensure-mark))))) )) (defun m&d-drag-sexp-right (&optional beg end) "Drag region right by one sexp. Region defaults to sexp at point. When the mark is active, this function may move point and set mark to make the dragged region suitable for further dragging." (interactive) (let* ((end (or end (and mark-active (save-excursion (goto-char (max (point) (mark))) (skip-chars-backward " \n\t\f") ;; The following might not skip any more newlines: (skip-syntax-backward " .") (point))) (save-excursion (forward-sexp) (backward-prefix-chars) (point)))) (beg (or beg (and mark-active (save-excursion (goto-char (min (point) (mark))) (skip-chars-forward " \n\t\f") ;; The following might not skip any more newlines: (skip-syntax-forward " .") (point))) (save-excursion (goto-char end) (backward-sexp) (point)))) (point-beg (and (<= beg (point)) (<= (point) end) (- (point) beg))) (mark-beg (and mark-active (<= beg (mark)) (<= (mark) end) (- (mark) beg))) (to (save-excursion (goto-char end) (condition-case nil (save-excursion (forward-sexp) (backward-prefix-chars) (point)) (error nil)))) (from (when to (save-excursion (goto-char to) (condition-case nil (save-excursion (backward-sexp) (point)) (error nil))))) point-beg mark-beg) (when mark-active (cond ((< (mark) beg) (set-mark beg)) ((< end (mark)) (set-mark end))) (setq mark-beg (- (mark) beg))) (setq point-beg (cond ((< (point) beg) 0) ((< end (point)) (- end beg)) (t (- (point) beg)))) (if (and from to (> to from) (>= from end)) (progn (transpose-regions beg end from to) (when mark-beg (set-mark (+ mark-beg beg (- to end))) (setq deactivate-mark nil)) (goto-char (+ point-beg beg (- to end))) (when mark-active (m&d-mark-highlight (min (point) (mark)) (max (point) (mark))))) (when mark-active (setq deactivate-mark nil) (m&d-mark-highlight (min (point) (mark)) (max (point) (mark)))) (message "Can't drag") (ding)))) (defun m&d-drag-sexp-left (&optional beg end) "Drag region left by one sexp. Region defaults to sexp at point. When the mark is active, this function may move point and set mark to make the dragged region suitable for further dragging." (interactive) (let* ((end (or end (and mark-active (save-excursion (goto-char (max (point) (mark))) (skip-chars-backward " \n\t\f") ;; The following might not skip any more newlines: (skip-syntax-backward " .") (point))) (save-excursion (forward-sexp) (backward-prefix-chars) (point)))) (beg (or beg (and mark-active (save-excursion (goto-char (min (point) (mark))) (skip-chars-forward " \n\t\f") ;; The following might not skip any more newlines: (skip-syntax-forward " .") (point))) (save-excursion (goto-char end) (backward-sexp) (point)))) (from (save-excursion (goto-char beg) (condition-case nil (save-excursion (backward-sexp) (point)) (error nil)))) (to (when from (save-excursion (goto-char from) (condition-case nil (save-excursion (forward-sexp) (backward-prefix-chars) (point)) (error nil))))) point-beg mark-beg) (when mark-active (cond ((< (mark) beg) (set-mark beg)) ((< end (mark)) (set-mark end))) (setq mark-beg (- (mark) beg))) (setq point-beg (cond ((< (point) beg) 0) ((< end (point)) (- end beg)) (t (- (point) beg)))) (if (and from to (> to from) (<= to beg)) (progn (transpose-regions from to beg end) (when mark-beg (set-mark (+ mark-beg from)) (setq deactivate-mark nil)) (goto-char (+ point-beg from)) (when mark-active (m&d-mark-highlight (min (point) (mark)) (max (point) (mark))))) (when mark-active (setq deactivate-mark nil) (m&d-mark-highlight (min (point) (mark)) (max (point) (mark)))) (message "Can't drag") (ding)))) ;; _____________________________________________________________________________ ;; ;;; Key bindings ;; _____________________________________________________________________________ ;; (global-set-key [(control right)] 'm&d-forward-sexp) (global-set-key [(control left)] 'm&d-backward-sexp) (global-set-key [(control up)] 'm&d-beginning-of-defun) (global-set-key [(control down)] 'm&d-end-of-defun) (global-set-key [(control meta left)] 'm&d-beginning-of-list) (global-set-key [(control meta right)] 'm&d-end-of-list) (global-set-key [(control meta up)] 'm&d-backward-up) (global-set-key [(control meta down)] 'm&d-forward-up) (global-set-key [home] 'm&d-home) (global-set-key [end] 'm&d-end) (define-key text-mode-map [(control right)] 'forward-word) (define-key text-mode-map [(control left)] 'backward-word) (define-key text-mode-map [(control down)] 'forward-paragraph) (define-key text-mode-map [(control up)] 'backward-paragraph) (define-key text-mode-map [(control meta right)] 'forward-sentence) (define-key text-mode-map [(control meta left)] 'backward-sentence) (global-set-key [capslock] 'm&d-mark-sexp) (global-set-key [(meta capslock)] 'm&d-exchange-point-and-mark) (global-set-key [(shift capslock)] 'm&d-mark-undo) (global-set-key [(hyper capslock)] 'm&d-save-region) (global-set-key [(hyper shift capslock)] 'm&d-kill-region) (global-set-key [(hyper meta capslock)] 'm&d-replace-region) (global-set-key [(hyper control left)] 'm&d-drag-sexp-left) (global-set-key [(hyper control right)] 'm&d-drag-sexp-right) (global-set-key [(hyper up)] 'm&d-drag-line-up) (global-set-key [(hyper down)] 'm&d-drag-line-down) (global-set-key [(hyper left)] 'm&d-drag-char-left) (global-set-key [(hyper right)] 'm&d-drag-char-right) (global-set-key [(kp-enter)] 'm&d-copy) ;; _____________________________________________________________________________ ;; ;;; Pre-command ;; _____________________________________________________________________________ ;; (dolist (cmd '(forward-char backward-char next-line previous-line forward-word backward-word end-of-line beginning-of-line move-end-of-line move-beginning-of-line end-of-buffer beginning-of-buffer scroll-up scroll-down up-list down-list backward-up-list end-of-defun beginning-of-defun m&d-forward-sexp m&d-backward-sexp m&d-beginning-of-defun m&d-end-of-defun m&d-beginning-of-list m&d-end-of-list m&d-forward-up m&d-backward-up m&d-home m&d-end forward-sexp backward-sexp forward-list backward-list forward-sentence backward-sentence forward-paragraph backward-paragraph)) (put cmd 'm&d 'move)) (dolist (cmd '(m&d-mark-sexp m&d-mark-undo m&d-mark-save m&d-exchange-point-and-mark)) (put cmd 'm&d 'save)) ;; REDO completely ...... (defun m&d-pre-command () (condition-case nil ;; We need a condition case to avoid that things like imenu mess up things. (progn (when (and m&d-mark-history (not (eq (get this-command 'm&d) 'save))) ;; Remove mark history. (setq m&d-mark-history nil)) ;; Delete overlays, make this conditional - they can be reused. (unless (memq major-mode '(sobar-mode sonderbar-mode)) (dolist (overlay (list m&d-alert-overlay m&d-before-overlay m&d-after-overlay m&d-left-overlay m&d-right-overlay ;; Delete show-paren's overlays to avoid flickering. show-paren-overlay show-paren-overlay-1)) (when (overlayp overlay) (delete-overlay overlay))) ;; Shifted movement. (if (not (eq (get this-command 'm&d) 'move)) (setq m&d-mark nil) (if (memq 'shift (event-modifiers (aref (this-single-command-raw-keys) 0))) (progn (unless mark-active (push-mark-command nil t)) (if m&d-mark (add-hook 'post-command-hook 'm&d-mark-highlight) (remove-hook 'post-command-hook 'm&d-mark-highlight))) (unless (eq (get last-command 'm&d) 'move) (push-mark-command nil t)) (remove-hook 'post-command-hook 'm&d-mark-highlight) (setq mark-active nil) (setq deactivate-mark t))))) (error nil))) (add-hook 'pre-command-hook 'm&d-pre-command) (provide 'm&d) ;;; up / down have to conceptually do: (1) Check whether the region is balanced, ;;; and if it is not try to extract the balanced part, remove that, adjust, (2) ;;; do the move, and (3) check whether the region is balanced again. ;;; m&d.el ends here ;; (1) m&d-mark-highlight can be wrong after shifted movement, use a stronger ;; criterium. ;; (2) backward-prefix-chars should not skip "'" after a `foo'. Hence, within ;; literals we should check whether these are used for this particular ;; thing. ;; (3) push-mark doesn't work correctly yet. ;; (4) shifted forward-/backward-char within string is awfully slow (defun m&d-mark-dwim () (interactive) (cond ((and (eq last-command this-command) mark-ring) (pop-to-mark-command)) ((mark t) (exchange-point-and-mark)) (t (let ((mark (marker-position (point-marker)))) (push-mark nil t)))) (setq deactivate-mark t)) (global-set-key [(hyper .)] 'm&d-mark-dwim) ;;; Debugger entered--Lisp error: (wrong-type-argument listp 4159323) ;;; transpose-regions(306379 306408 306408 306504) ;;; m&d-drag-line-up() ;;; call-interactively(m&d-drag-line-up) --------------070403010002030807000403 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://lists.gnu.org/mailman/listinfo/emacs-devel --------------070403010002030807000403--