From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Chong Yidong Newsgroups: gmane.emacs.devel Subject: Re: line-line-move-visual: was line motion problem Date: Wed, 16 Jul 2008 14:26:44 -0400 Message-ID: <87hcap3ct7.fsf@stupidchicken.com> References: <18557.63556.231489.523637@gargle.gargle.HOWL> <5F62534C-D5CE-4364-8F73-E1AE0D61B4E2@gmail.com> <87abghlqs2.fsf@stupidchicken.com> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: ger.gmane.org 1216232862 16477 80.91.229.12 (16 Jul 2008 18:27:42 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Wed, 16 Jul 2008 18:27:42 +0000 (UTC) Cc: emacs-devel@gnu.org, Stefan Monnier , raman@users.sourceforge.net To: David Reitter Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Wed Jul 16 20:28:29 2008 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 1KJBjj-0007G8-KM for ged-emacs-devel@m.gmane.org; Wed, 16 Jul 2008 20:28:24 +0200 Original-Received: from localhost ([127.0.0.1]:40786 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1KJBir-0006nK-2w for ged-emacs-devel@m.gmane.org; Wed, 16 Jul 2008 14:27:29 -0400 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1KJBhP-0006MU-7k for emacs-devel@gnu.org; Wed, 16 Jul 2008 14:25:59 -0400 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1KJBhO-0006M2-DO for emacs-devel@gnu.org; Wed, 16 Jul 2008 14:25:58 -0400 Original-Received: from [199.232.76.173] (port=43402 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1KJBhO-0006Ls-6e for emacs-devel@gnu.org; Wed, 16 Jul 2008 14:25:58 -0400 Original-Received: from cyd.mit.edu ([18.115.2.24]:38583 helo=cyd) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1KJBhO-0000iE-8J for emacs-devel@gnu.org; Wed, 16 Jul 2008 14:25:58 -0400 Original-Received: by cyd (Postfix, from userid 1000) id BC55F57E2BE; Wed, 16 Jul 2008 14:26:44 -0400 (EDT) In-Reply-To: <87abghlqs2.fsf@stupidchicken.com> (Chong Yidong's message of "Wed, 16 Jul 2008 12:47:41 -0400") User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.0.60 (gnu/linux) X-detected-kernel: by monty-python.gnu.org: Linux 2.6 (newer, 3) 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:100829 Archived-At: Chong Yidong writes: > I think we should have a defcustom that sets the default value of > line-move-visual, and a minor mode (I guess it'll be called > visual-line-mode, since there doesn't seem to be any better name) that > provides the rest of the visual editing features. The following patch implements this approach. I've taken bits from visual-line.el, and re-written other bits to make use of the new features of vertical-motion in Emacs 23. Could people try it out and see if it DTRT? As Richard suggested, it binds M-[ and M-] to logical previous-line and next-line. I don't know, OTOH, where a logical kill-line should be bound (visual-line.el bound it to C-K, but this doesn't seem optimal, since OTOH we try not to use upcased keybindings where possible). *** trunk/lisp/simple.el.~1.934.~ 2008-07-15 14:47:32.000000000 -0400 --- trunk/lisp/simple.el 2008-07-16 14:23:26.000000000 -0400 *************** *** 3906,3916 **** :type 'boolean :group 'editing-basics) ! (defvar line-move-visual t "When non-nil, `line-move' moves point by visual lines. This movement is based on where the cursor is displayed on the screen, instead of relying on buffer contents alone. It takes ! into account variable-width characters and line continuation.") ;; Returns non-nil if partial move was done. (defun line-move-partial (arg noerror to-end) --- 3906,3919 ---- :type 'boolean :group 'editing-basics) ! (defcustom line-move-visual t "When non-nil, `line-move' moves point by visual lines. This movement is based on where the cursor is displayed on the screen, instead of relying on buffer contents alone. It takes ! into account variable-width characters and line continuation." ! :type 'boolean ! :group 'editing-basics) ! (make-variable-buffer-local 'line-move-visual) ;; Returns non-nil if partial move was done. (defun line-move-partial (arg noerror to-end) *************** *** 4017,4022 **** --- 4020,4027 ---- (let ((inhibit-point-motion-hooks t) (opoint (point)) (orig-arg arg)) + (if (floatp temporary-goal-column) + (setq temporary-goal-column (truncate temporary-goal-column))) (unwind-protect (progn (if (not (memq last-command '(next-line previous-line))) *************** *** 4365,4371 **** --- 4370,4499 ---- ) nil) + ;;; Editing based on visual lines, as opposed to logical lines. + + (defun end-of-visual-line (&optional n) + "Move point to end of current visual line. + With argument N not nil or 1, move forward N - 1 visual lines first. + If point reaches the beginning or end of buffer, it stops there. + To ignore intangibility, bind `inhibit-point-motion-hooks' to t." + (interactive "^p") + (or n (setq n 1)) + (if (/= n 1) + (let ((line-move-visual t)) + (line-move (1- n) t))) + (vertical-motion (cons (window-width) 0))) + + (defun beginning-of-visual-line (&optional n) + "Move point to beginning of current visual line. + With argument N not nil or 1, move forward N - 1 visual lines first. + If point reaches the beginning or end of buffer, it stops there. + To ignore intangibility, bind `inhibit-point-motion-hooks' to t." + (interactive "^p") + (or n (setq n 1)) + (if (/= n 1) + (let ((line-move-visual t)) + (line-move (1- n) t))) + (vertical-motion 0)) + + (defun kill-visual-line (&optional arg) + "Kill the rest of the visual line. + If there are only whitespace characters there, kill through the + newline as well. + + With prefix argument, kill that many lines from point. + Negative arguments kill lines backward. + With zero argument, kill the text before point on the current line. + + When calling from a program, nil means \"no arg\", + a number counts as a prefix arg. + + If `kill-whole-line' is non-nil, then this command kills the whole line + including its terminating newline, when used at the beginning of a line + with no argument. As a consequence, you can always kill a whole line + by typing \\[beginning-of-line] \\[kill-line]. + + If you want to append the killed line to the last killed text, + use \\[append-next-kill] before \\[kill-line]. + + If the buffer is read-only, Emacs will beep and refrain from deleting + the line, but put the line in the kill ring anyway. This means that + you can use this command to copy text from a read-only buffer. + \(If the variable `kill-read-only-ok' is non-nil, then this won't + even beep.)" + (interactive "P") + (let ((opoint (point)) + (line-move-visual t) + end) + ;; It is better to move point to the other end of the kill before + ;; killing. That way, in a read-only buffer, point moves across + ;; the text that is copied to the kill ring. The choice has no + ;; effect on undo now that undo records the value of point from + ;; before the command was run. + (if arg + (vertical-motion (prefix-numeric-value arg)) + (if (eobp) + (signal 'end-of-buffer nil)) + (setq end (save-excursion + (end-of-visual-line) (point))) + (if (or (save-excursion + ;; If trailing whitespace is visible, + ;; don't treat it as nothing. + (unless show-trailing-whitespace + (skip-chars-forward " \t" end)) + (= (point) end)) + (and kill-whole-line (bolp))) + (line-move 1) + (goto-char end))) + (kill-region opoint (point)))) + + (defun next-logical-line (&optional arg try-vscroll) + "Move cursor vertically down ARG lines. + This is identical to `previous-line', except that it always moves + by logical lines instead of visual lines, ignoring the value of + `line-move-visual'." + (interactive "^p\np") + (let ((line-move-visual nil)) + (with-no-warnings + (next-line arg try-vscroll)))) + + (defun previous-logical-line (&optional arg try-vscroll) + "Move cursor vertically up ARG lines. + This is identical to `previous-line', except that it always moves + by logical lines instead of visual lines, ignoring the value of + `line-move-visual'." + (interactive "^p\np") + (let ((line-move-visual nil)) + (with-no-warnings + (previous-line arg try-vscroll)))) + (defvar visual-line-mode-map + (let ((map (make-sparse-keymap))) + (define-key map [remap kill-line] 'kill-visual-line) + (define-key map [remap move-beginning-of-line] 'beginning-of-visual-line) + (define-key map [remap move-end-of-line] 'end-of-visual-line) + (define-key map "\M-[" 'previous-logical-line) + (define-key map "\M-]" 'next-logical-line) + map)) + + (define-minor-mode visual-line-mode + "Define key binding for visual line moves." + :keymap visual-line-mode-map + :group 'convenience + (if visual-line-mode + (progn + (setq line-move-visual t + word-wrap t)) + (kill-local-variable 'line-move-visual) + (kill-local-variable 'word-wrap))) + + (defun turn-on-visual-line-mode () + (visual-line-mode 1)) + + (define-globalized-minor-mode global-visual-line-mode + visual-line-mode turn-on-visual-line-mode + :lighter " vl") + (defun scroll-other-window-down (lines) "Scroll the \"other window\" down. For more details, see the documentation for `scroll-other-window'."