From dc86c4cc0ba230c632b10cefb22b9fec1cd1d046 Mon Sep 17 00:00:00 2001 From: Juri Linkov <juri@linkov.net> Date: Wed, 23 Sep 2020 22:39:32 +0300 Subject: [PATCH] New command goto-line-relative (bug#5042, bug#9917) * lisp/simple.el (goto-line-read-args): New function with code from goto-line. (goto-line): New arg RELATIVE. Also use 'widen-automatically' to leave all lines accessible in the narrowed buffer. (goto-line-relative): New command. * lisp/info.el (Info-mode-map): Remap 'goto-line' to 'goto-line-relative'. * doc/emacs/basic.texi (Moving Point): * doc/emacs/display.texi (Optional Mode Line): Mention goto-line-relative. --- doc/emacs/basic.texi | 5 ++- doc/emacs/display.texi | 7 ++-- etc/NEWS | 7 ++++ lisp/info.el | 1 + lisp/simple.el | 86 ++++++++++++++++++++++++++++-------------- 5 files changed, 73 insertions(+), 33 deletions(-) diff --git a/doc/emacs/basic.texi b/doc/emacs/basic.texi index 444b2469cf1..cde7b475d95 100644 --- a/doc/emacs/basic.texi +++ b/doc/emacs/basic.texi @@ -311,13 +311,16 @@ Position 1 is the beginning of the buffer. @kindex M-g M-g @kindex M-g g @findex goto-line +@findex goto-line-relative Read a number @var{n} and move point to the beginning of line number @var{n} (@code{goto-line}). Line 1 is the beginning of the buffer. If point is on or just after a number in the buffer, that is the default for @var{n}. Just type @key{RET} in the minibuffer to use it. You can also specify @var{n} by giving @kbd{M-g M-g} a numeric prefix argument. @xref{Select Buffer}, for the behavior of @kbd{M-g M-g} when you give it -a plain prefix argument. +a plain prefix argument. Alternatively, you can use the command +@code{goto-line-relative} to move point to the line relative to the +accessible portion of the narrowed buffer. @item M-g @key{TAB} @kindex M-g TAB diff --git a/doc/emacs/display.texi b/doc/emacs/display.texi index e7b8745a044..6f1bc802b85 100644 --- a/doc/emacs/display.texi +++ b/doc/emacs/display.texi @@ -1452,9 +1452,10 @@ the displayed column number to count from one, you may set @cindex narrowing, and line number display If you have narrowed the buffer (@pxref{Narrowing}), the displayed line number is relative to the accessible portion of the buffer. -Thus, it isn't suitable as an argument to @code{goto-line}. (Use -@code{what-line} command to see the line number relative to the whole -file.) +Thus, it isn't suitable as an argument to @code{goto-line}. (The +command @code{what-line} shows the line number relative to the whole +file.) You can use @code{goto-line-relative} command to move point to +the line relative to the accessible portion of the narrowed buffer. @vindex line-number-display-limit If the buffer is very large (larger than the value of diff --git a/etc/NEWS b/etc/NEWS index a4c823072c9..fe2f5c37821 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -171,6 +171,13 @@ Each buffer will keep a separate history of line numbers used with 'goto-line'. This should help making faster the process of finding line numbers that were previously jumped to. ++++ +** New command 'goto-line-relative' to use in a narrowed buffer. +It moves point to the line relative to the accessible portion of the +narrowed buffer. 'M-g M-g' in Info is rebound to this command. +When 'widen-automatically' is non-nil, 'goto-line' widens the narrowed +buffer to be able to move point to the inaccessible portion. + +++ ** When 'suggest-key-bindings' is non-nil, the completion list of 'M-x' shows equivalent key bindings for all commands that have them. diff --git a/lisp/info.el b/lisp/info.el index e4f75b481fe..20633fd0598 100644 --- a/lisp/info.el +++ b/lisp/info.el @@ -4053,6 +4053,7 @@ If FORK is non-nil, it is passed to `Info-goto-node'." (define-key map "^" 'Info-up) (define-key map "," 'Info-index-next) (define-key map "\177" 'Info-scroll-down) + (define-key map [remap goto-line] 'goto-line-relative) (define-key map [mouse-2] 'Info-mouse-follow-nearest-node) (define-key map [follow-link] 'mouse-face) (define-key map [XF86Back] 'Info-history-back) diff --git a/lisp/simple.el b/lisp/simple.el index d7486e51ddc..825fec380cb 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -1231,7 +1231,39 @@ that uses or sets the mark." "History of values entered with `goto-line'.") (make-variable-buffer-local 'goto-line-history) -(defun goto-line (line &optional buffer) +(defun goto-line-read-args (&optional relative) + "Read arguments for `goto-line' related commands." + (if (and current-prefix-arg (not (consp current-prefix-arg))) + (list (prefix-numeric-value current-prefix-arg)) + ;; Look for a default, a number in the buffer at point. + (let* ((default + (save-excursion + (skip-chars-backward "0-9") + (if (looking-at "[0-9]") + (string-to-number + (buffer-substring-no-properties + (point) + (progn (skip-chars-forward "0-9") + (point))))))) + ;; Decide if we're switching buffers. + (buffer + (if (consp current-prefix-arg) + (other-buffer (current-buffer) t))) + (buffer-prompt + (if buffer + (concat " in " (buffer-name buffer)) + ""))) + ;; Read the argument, offering that number (if any) as default. + (list (read-number (format "Goto%s line%s: " + (if (= (point-min) 1) "" + ;; In a narrowed buffer. + (if relative " relative" " absolute")) + buffer-prompt) + (list default (line-number-at-pos)) + 'goto-line-history) + buffer)))) + +(defun goto-line (line &optional buffer relative) "Go to LINE, counting from line 1 at beginning of buffer. If called interactively, a numeric prefix argument specifies LINE; without a numeric prefix argument, read LINE from the @@ -1241,6 +1273,13 @@ If optional argument BUFFER is non-nil, switch to that buffer and move to line LINE there. If called interactively with \\[universal-argument] as argument, BUFFER is the most recently selected other buffer. +If optional argument RELATIVE is non-nil, counting starts at the beginning +of the accessible portion of the (potentially narrowed) buffer. + +If the variable `widen-automatically' is non-nil, cancel narrowing and +leave all lines accessible. If `widen-automatically' is nil, just move +point to the edge of visible portion and don't change the buffer bounds. + Prior to moving point, this function sets the mark (without activating it), unless Transient Mark mode is enabled and the mark is already active. @@ -1252,32 +1291,7 @@ What you probably want instead is something like: If at all possible, an even better solution is to use char counts rather than line counts." (declare (interactive-only forward-line)) - (interactive - (if (and current-prefix-arg (not (consp current-prefix-arg))) - (list (prefix-numeric-value current-prefix-arg)) - ;; Look for a default, a number in the buffer at point. - (let* ((default - (save-excursion - (skip-chars-backward "0-9") - (if (looking-at "[0-9]") - (string-to-number - (buffer-substring-no-properties - (point) - (progn (skip-chars-forward "0-9") - (point))))))) - ;; Decide if we're switching buffers. - (buffer - (if (consp current-prefix-arg) - (other-buffer (current-buffer) t))) - (buffer-prompt - (if buffer - (concat " in " (buffer-name buffer)) - ""))) - ;; Read the argument, offering that number (if any) as default. - (list (read-number (format "Goto line%s: " buffer-prompt) - (list default (line-number-at-pos)) - 'goto-line-history) - buffer)))) + (interactive (goto-line-read-args)) ;; Switch to the desired buffer, one way or another. (if buffer (let ((window (get-buffer-window buffer))) @@ -1286,13 +1300,27 @@ rather than line counts." ;; Leave mark at previous position (or (region-active-p) (push-mark)) ;; Move to the specified line number in that buffer. - (save-restriction - (widen) + (if (and (not relative) (not widen-automatically)) + (save-restriction + (widen) + (goto-char (point-min)) + (if (eq selective-display t) + (re-search-forward "[\n\C-m]" nil 'end (1- line)) + (forward-line (1- line)))) + (unless relative (widen)) (goto-char (point-min)) (if (eq selective-display t) (re-search-forward "[\n\C-m]" nil 'end (1- line)) (forward-line (1- line))))) +(defun goto-line-relative (line &optional buffer) + "Go to LINE, counting from line at (point-min). +The line number is relative to the accessible portion of the narrowed +buffer. The argument BUFFER is the same as in the function `goto-line'." + (declare (interactive-only forward-line)) + (interactive (goto-line-read-args t)) + (goto-line line buffer t)) + (defun count-words-region (start end &optional arg) "Count the number of words in the region. If called interactively, print a message reporting the number of -- 2.39.5