From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Tino Calancha Newsgroups: gmane.emacs.devel Subject: Re: [patch] Run occur command restricted to a region Date: Mon, 23 Jan 2017 16:32:44 +0900 Message-ID: <87inp6nsdf.fsf@gmail.com> References: <87vau3jl6f.fsf@gmail.com> <87shp6uwvj.fsf@mail.linkov.net> <83h95lua2f.fsf@gnu.org> <878tqxm1wh.fsf@mail.linkov.net> <87r34ozq20.fsf@gmail.com> <87inq0xhiw.fsf@mail.linkov.net> <87d1g55h8d.fsf@mail.linkov.net> <87r33ywquz.fsf@mail.linkov.net> <87ziilc05e.fsf@gmail.com> <8760l9wcci.fsf@mail.linkov.net> <87fukb2xmk.fsf@gmail.com> <87h94qu01u.fsf@mail.linkov.net> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Trace: blaine.gmane.org 1496094914 24072 195.159.176.226 (29 May 2017 21:55:14 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Mon, 29 May 2017 21:55:14 +0000 (UTC) User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.0.50 (gnu/linux) Cc: Emacs developers , Tino Calancha To: Juri Linkov Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Mon Jan 23 08:33:44 2017 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cVZ8E-0001gd-0t for ged-emacs-devel@m.gmane.org; Mon, 23 Jan 2017 08:33:38 +0100 Original-Received: from localhost ([::1]:39523 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cVZ8J-0004jz-04 for ged-emacs-devel@m.gmane.org; Mon, 23 Jan 2017 02:33:43 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:33750) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cVZ7Y-0004jj-4y for emacs-devel@gnu.org; Mon, 23 Jan 2017 02:32:58 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cVZ7T-0006WJ-GT for emacs-devel@gnu.org; Mon, 23 Jan 2017 02:32:56 -0500 Original-Received: from mail-pg0-x241.google.com ([2607:f8b0:400e:c05::241]:34070) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1cVZ7T-0006W6-6s for emacs-devel@gnu.org; Mon, 23 Jan 2017 02:32:51 -0500 Original-Received: by mail-pg0-x241.google.com with SMTP id t6so13040568pgt.1 for ; Sun, 22 Jan 2017 23:32:51 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:references:date:in-reply-to:message-id :user-agent:mime-version:content-transfer-encoding; bh=RysffLWfAaEvts+sKczexhDr3iqJSWkDrbDEUo9u3tg=; b=oNPRtq2sZXRQJ9pVqNnww1fJc2KCwnIC7aq2fsm+nESt2xlFiS1RUT86Rx1+/F5mqB o93JyuYHrNW7BCE6Id398EAwQN5mFPfJubuVdZX+JI14Dh+Mg8epUj9ETarf4e02P44H Ihze3/G5LLj24TIDlXZLBPvr6C/hBqDyfCNJnt+LsTCyyYc/gJzWXndEFWE2wEfiUzMs unz4gbxCe7XULTKtXrc7BPy44mMwHeqeh0Pz77G0TUnNWZUXnc2dGB+d/LeQXLTh1b2D gj6uRV2p9wzNZ4vPgLJcis7rG26HR5MhLQ7NHC0x4mA/2RUKTQW8lzR+zR0TqcX97L5p n06w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:references:date:in-reply-to :message-id:user-agent:mime-version:content-transfer-encoding; bh=RysffLWfAaEvts+sKczexhDr3iqJSWkDrbDEUo9u3tg=; b=J4FhCQ8DoB5p9Obk2PlluKiId5nUey68/wq0CoyK7tPV3c5eurQ+D/uvijgOCzjNrC ejjG/isYoBat24kFqzqkVWcUJN6A5nZYDk70ikknNGRWnolTuEZYncXmLYyWmfBqxwSn lpH4QqZTDTrvc7CXsJHm8Acja8RzRmqmgHnnj+1BnYqctXu0RqMwmWWvLi0kNbYC3d1f 7hdEzCoERpHzRzZDO/aUD4nB4nkeQJJZW8rHvLYn3qmpLl0hn6GEKpfhUo/1rlYdda3d J61xL2yqzgkLxywVz9aLaDo9BV/V5r5Qn/givCM8/Q//HYFVwsFtrPiSEJToc8VeptBr Ii/g== X-Gm-Message-State: AIkVDXIzq9tl0lJ6cq5r46ssYCQlyxnBOCy7WNTmMhG/q97pIJj+mkJTxnM/Cc/1E3C/gw== X-Received: by 10.84.206.37 with SMTP id f34mr41177557ple.35.1485156770140; Sun, 22 Jan 2017 23:32:50 -0800 (PST) Original-Received: from calancha-pc (33.94.100.220.dy.bbexcite.jp. [220.100.94.33]) by smtp.gmail.com with ESMTPSA id 21sm34240177pfy.4.2017.01.22.23.32.47 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Sun, 22 Jan 2017 23:32:49 -0800 (PST) In-Reply-To: <87h94qu01u.fsf@mail.linkov.net> (Juri Linkov's message of "Mon, 23 Jan 2017 01:50:21 +0200") X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2607:f8b0:400e:c05::241 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.org gmane.emacs.devel:215325 Juri Linkov writes: >> +(defface occur-current-line-face >> + '((t (:inherit lazy-highlight))) >> + "Face for highlighting the current line in *Occur* buffer." > > I'm not sure about the new face =E2=80=98occur-current-line-face=E2=80=99. > Looking at the list of faces from =E2=80=98M-x list-faces-display=E2=80= =99, there are > no other occur faces. It would be confusing for the users to see > a single occur-related face in this list, whereas all other occur-related > faces are customized by =E2=80=98list-matching-lines-*=E2=80=99 variables= only. > > For consistency with other occur faces, maybe better to have a variable > > (defcustom list-matching-lines-current-line-face 'lazy-highlight > > and another boolean customizable variable list-matching-lines-jump-to-cur= rent-line > to enable locating the current line. Thank you. Implemented in the new patch below: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;= ;;;; >From 56d13fa11b01260d9088d820a5cf6cd04d042848 Mon Sep 17 00:00:00 2001 From: Tino Calancha Date: Mon, 23 Jan 2017 16:26:22 +0900 Subject: [PATCH 1/2] Allow occur command to operate on the region See discussion in: https://lists.gnu.org/archive/html/emacs-devel/2016-12/msg01084.html * lisp/replace.el (occur--region-start, occur--region-end) (occur--matches-threshold): New variables. (occur-engine): Use them. (occur): Idem. Add optional arg REGION; if non-nil occur applies in that region. * doc/lispintro/emacs-lisp-intro.texi (Keybindings): Update manual * doc/emacs/search.texi (Other Repeating Search: Idem. ; etc/NEWS: Add entry to announce the change. --- doc/emacs/search.texi | 3 +++ doc/lispintro/emacs-lisp-intro.texi | 8 ++++--- etc/NEWS | 2 ++ lisp/replace.el | 46 +++++++++++++++++++++++++++++++--= ---- 4 files changed, 49 insertions(+), 10 deletions(-) diff --git a/doc/emacs/search.texi b/doc/emacs/search.texi index b728258973..28e25bec43 100644 --- a/doc/emacs/search.texi +++ b/doc/emacs/search.texi @@ -1672,6 +1672,9 @@ Other Repeating Search no upper-case letters and @code{case-fold-search} is non-@code{nil}. Aside from @code{occur} and its variants, all operate on the text from point to the end of the buffer, or on the region if it is active. +The command @code{occur} will operate on the region if +it is active as well; when the region is not active, @code{occur} +operates in the whole buffer. =20 @findex list-matching-lines @findex occur diff --git a/doc/lispintro/emacs-lisp-intro.texi b/doc/lispintro/emacs-lisp= -intro.texi index 830c072cf5..36d767737d 100644 --- a/doc/lispintro/emacs-lisp-intro.texi +++ b/doc/lispintro/emacs-lisp-intro.texi @@ -17151,9 +17151,11 @@ Keybindings =20 @findex occur The @code{occur} command shows all the lines in the current buffer -that contain a match for a regular expression. Matching lines are -shown in a buffer called @file{*Occur*}. That buffer serves as a menu -to jump to occurrences. +that contain a match for a regular expression. When the region is +active, @code{occur} restricts matches to such region. Otherwise it +uses the entire buffer. +Matching lines are shown in a buffer called @file{*Occur*}. +That buffer serves as a menu to jump to occurrences. =20 @findex global-unset-key @cindex Unbinding key diff --git a/etc/NEWS b/etc/NEWS index ca66df6261..9eb5d82099 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -310,6 +310,8 @@ substituted by a home directory by writing it as "/foo:= /:/~/file". * Editing Changes in Emacs 26.1 =20 + +** The 'occur' command can now operate on the region. +++ ** New bindings for 'query-replace-map'. 'undo', undo the last replacement; bound to 'u'. diff --git a/lisp/replace.el b/lisp/replace.el index ff91734445..00e73157ff 100644 --- a/lisp/replace.el +++ b/lisp/replace.el @@ -1360,7 +1360,12 @@ occur-rename-buffer "*") (or unique-p (not interactive-p))))) =20 -(defun occur (regexp &optional nlines) +;; Region limits when `occur' applies on a region. +(defvar occur--region-start nil) +(defvar occur--region-end nil) +(defvar occur--matches-threshold nil) + +(defun occur (regexp &optional nlines region) "Show all lines in the current buffer containing a match for REGEXP. If a match spreads across multiple lines, all those lines are shown. =20 @@ -1369,6 +1374,10 @@ occur NLINES defaults to `list-matching-lines-default-context-lines'. Interactively it is the prefix arg. =20 +Optional arg REGION, if non-nil, mean restrict search to the +specified region. Otherwise search the entire buffer. +When REGION is non-nil, it must be a cons (START . END). + The lines are shown in a buffer named `*Occur*'. It serves as a menu to find any of the occurrences in this buffer. \\\\[describe-mode] in that buffer will explain how. @@ -1386,8 +1395,24 @@ occur program. When there is no parenthesized subexpressions in REGEXP the entire match is collected. In any case the searched buffer is not modified." - (interactive (occur-read-primary-args)) - (occur-1 regexp nlines (list (current-buffer)))) + (interactive + (nconc (occur-read-primary-args) + (and (use-region-p) (region-bounds)))) + (let* ((start (car region)) + (end (cdr region)) + (in-region-p (or start end))) + (when in-region-p + (or start (setq start (point-min))) + (or end (setq end (point-max)))) + (let ((occur--region-start start) + (occur--region-end end) + (occur--matches-threshold + (and in-region-p + (line-number-at-pos (min start end))))) + (save-excursion ; If no matches `occur-1' doesn't restore the point. + (and in-region-p (narrow-to-region start end)) + (occur-1 regexp nlines (list (current-buffer))) + (and in-region-p (widen)))))) =20 (defvar ido-ignore-item-temp-list) =20 @@ -1545,13 +1570,15 @@ occur-engine (let ((global-lines 0) ;; total count of matching lines (global-matches 0) ;; total count of matches (coding nil) - (case-fold-search case-fold)) + (case-fold-search case-fold) + (in-region-p (and occur--region-start occur--region-end))) ;; Map over all the buffers (dolist (buf buffers) (when (buffer-live-p buf) (let ((lines 0) ;; count of matching lines (matches 0) ;; count of matches - (curr-line 1) ;; line count + (curr-line ;; line count + (or occur--matches-threshold 1)) (prev-line nil) ;; line number of prev match endpt (prev-after-lines nil) ;; context lines of prev match (matchbeg 0) @@ -1684,7 +1711,7 @@ occur-engine (let ((beg (point)) end) (insert (propertize - (format "%d match%s%s%s in buffer: %s\n" + (format "%d match%s%s%s in buffer: %s%s\n" matches (if (=3D matches 1) "" "es") ;; Don't display the same number of lines ;; and matches in case of 1 match per line. @@ -1694,7 +1721,12 @@ occur-engine ;; Don't display regexp for multi-buffer. (if (> (length buffers) 1) "" (occur-regexp-descr regexp)) - (buffer-name buf)) + (buffer-name buf) + (if in-region-p + (format " within region: %d-%d" + occur--region-start + occur--region-end) + "")) 'read-only t)) (setq end (point)) (add-text-properties beg end `(occur-title ,buf)) --=20 2.11.0 >From 417ad35f210d74231a3529fcc44cb8f77127fb86 Mon Sep 17 00:00:00 2001 From: Tino Calancha Date: Mon, 23 Jan 2017 16:26:35 +0900 Subject: [PATCH 2/2] Show current line highlighted in *Occur* buffer * lisp/replace.el (list-matching-lines-current-line-face) (list-matching-lines-jump-to-current-line): New user options. (occur--orig-line, occur--orig-line-str): New variables. (occur, occur-engine): Use them. (occur--final-pos): New variable. (occur-1): Use it. (occur-engine): Idem. Show the current line with 'list-matching-lines-current-line-face'. Set point on the first matching line after the current one. * etc/NEWS: Add entry for the new option. --- etc/NEWS | 4 ++++ lisp/replace.el | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++= ---- 2 files changed, 71 insertions(+), 5 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 9eb5d82099..9b74ce16ed 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -311,6 +311,10 @@ substituted by a home directory by writing it as "/foo= :/:/~/file". * Editing Changes in Emacs 26.1 =20 =20 +** Two new user options 'list-matching-lines-jump-to-current-line' and +'list-matching-lines-current-line-face' to show highlighted the current li= ne +in the *Occur* buffer. + ** The 'occur' command can now operate on the region. +++ ** New bindings for 'query-replace-map'. diff --git a/lisp/replace.el b/lisp/replace.el index 00e73157ff..1a80dc16c6 100644 --- a/lisp/replace.el +++ b/lisp/replace.el @@ -1304,6 +1304,19 @@ list-matching-lines-buffer-name-face :type 'face :group 'matching) =20 +(defcustom list-matching-lines-current-line-face 'lazy-highlight + "Face used by \\[list-matching-lines] to highlight the current line." + :type 'face + :group 'matching + :version "26.1") + +(defcustom list-matching-lines-jump-to-current-line nil + "If non-nil, \\[list-matching-lines] shows the current line highlighted. +Set the point right after such line when there are matches after it." +:type 'boolean +:group 'matching +:version "26.1") + (defcustom list-matching-lines-prefix-face 'shadow "Face used by \\[list-matching-lines] to show the prefix column. If the face doesn't differ from the default face, @@ -1364,6 +1377,9 @@ occur-rename-buffer (defvar occur--region-start nil) (defvar occur--region-end nil) (defvar occur--matches-threshold nil) +(defvar occur--orig-line nil) +(defvar occur--orig-line-str nil) +(defvar occur--final-pos nil) =20 (defun occur (regexp &optional nlines region) "Show all lines in the current buffer containing a match for REGEXP. @@ -1381,6 +1397,9 @@ occur The lines are shown in a buffer named `*Occur*'. It serves as a menu to find any of the occurrences in this buffer. \\\\[describe-mode] in that buffer will explain how. +If `list-matching-lines-jump-to-current-line' is non-nil, then show +highlighted the current line and, if there are matches after it, then +set point in the first of those matches. =20 If REGEXP contains upper case characters (excluding those preceded by `\\') and `search-upper-case' is non-nil, the matching is case-sensitive. @@ -1408,7 +1427,13 @@ occur (occur--region-end end) (occur--matches-threshold (and in-region-p - (line-number-at-pos (min start end))))) + (line-number-at-pos (min start end)))) + (occur--orig-line + (line-number-at-pos (point))) + (occur--orig-line-str + (buffer-substring-no-properties + (line-beginning-position) + (line-end-position)))) (save-excursion ; If no matches `occur-1' doesn't restore the point. (and in-region-p (narrow-to-region start end)) (occur-1 regexp nlines (list (current-buffer))) @@ -1507,7 +1532,8 @@ occur-1 (occur-mode)) (let ((inhibit-read-only t) ;; Don't generate undo entries for creation of the initial contents. - (buffer-undo-list t)) + (buffer-undo-list t) + (occur--final-pos nil)) (erase-buffer) (let ((count (if (stringp nlines) @@ -1559,6 +1585,10 @@ occur-1 (if (=3D count 0) (kill-buffer occur-buf) (display-buffer occur-buf) + (when occur--final-pos + (set-window-point + (get-buffer-window occur-buf 'all-frames) + occur--final-pos)) (setq next-error-last-buffer occur-buf) (setq buffer-read-only t) (set-buffer-modified-p nil) @@ -1571,7 +1601,8 @@ occur-engine (global-matches 0) ;; total count of matches (coding nil) (case-fold-search case-fold) - (in-region-p (and occur--region-start occur--region-end))) + (in-region-p (and occur--region-start occur--region-end)) + (multi-occur-p (cdr buffers))) ;; Map over all the buffers (dolist (buf buffers) (when (buffer-live-p buf) @@ -1579,12 +1610,16 @@ occur-engine (matches 0) ;; count of matches (curr-line ;; line count (or occur--matches-threshold 1)) + (orig-line occur--orig-line) + (orig-line-str occur--orig-line-str) + (orig-line-shown-p) (prev-line nil) ;; line number of prev match endpt (prev-after-lines nil) ;; context lines of prev match (matchbeg 0) (origpt nil) (begpt nil) (endpt nil) + (finalpt nil) (marker nil) (curstring "") (ret nil) @@ -1685,6 +1720,18 @@ occur-engine (nth 0 ret)))) ;; Actually insert the match display data (with-current-buffer out-buf + (when (and list-matching-lines-jump-to-current-line + (not multi-occur-p) + (not orig-line-shown-p) + (>=3D curr-line orig-line)) + (insert + (concat + (propertize + (format "%7d:%s" orig-line orig-line-str) + 'face list-matching-lines-current-line-face + 'mouse-face 'mode-line-highlight + 'help-echo "Current line") "\n")) + (setq orig-line-shown-p t finalpt (point))) (insert data))) (goto-char endpt)) (if endpt @@ -1698,6 +1745,18 @@ occur-engine (forward-line 1)) (goto-char (point-max))) (setq prev-line (1- curr-line))) + ;; Insert original line if haven't done yet. + (when (and list-matching-lines-jump-to-current-line + (not multi-occur-p) + (not orig-line-shown-p)) + (with-current-buffer out-buf + (insert + (concat + (propertize + (format "%7d:%s" orig-line orig-line-str) + 'face list-matching-lines-current-line-face + 'mouse-face 'mode-line-highlight + 'help-echo "Current line") "\n")))) ;; Flush remaining context after-lines. (when prev-after-lines (with-current-buffer out-buf @@ -1731,8 +1790,11 @@ occur-engine (setq end (point)) (add-text-properties beg end `(occur-title ,buf)) (when title-face - (add-face-text-property beg end title-face))) - (goto-char (point-min))))))) + (add-face-text-property beg end title-face)) + (goto-char (if finalpt + (setq occur--final-pos + (cl-incf finalpt (- end beg))) + (point-min))))))))) ;; Display total match count and regexp for multi-buffer. (when (and (not (zerop global-lines)) (> (length buffers) 1)) (goto-char (point-min)) --=20 2.11.0 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;= ;;;; In GNU Emacs 26.0.50.1 (x86_64-pc-linux-gnu, GTK+ Version 3.22.6) of 2017-01-22 Repository revision: 03de82fe7ca09ab40fbcae394d4fcdfe3374496e