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: Sun, 29 Jan 2017 15:00:48 +0900 (JST) Message-ID: 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> <87inp6nsdf.fsf@gmail.com> <87lgtu4w5c.fsf@mail.linkov.net> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; BOUNDARY="8323329-981600245-1485669653=:1959" X-Trace: blaine.gmane.org 1485669678 29235 195.159.176.226 (29 Jan 2017 06:01:18 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Sun, 29 Jan 2017 06:01:18 +0000 (UTC) User-Agent: Alpine 2.20 (DEB 67 2015-01-07) Cc: Emacs developers , Tino Calancha To: Juri Linkov Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Sun Jan 29 07:01:12 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 1cXiXy-0006P5-3C for ged-emacs-devel@m.gmane.org; Sun, 29 Jan 2017 07:01:06 +0100 Original-Received: from localhost ([::1]:54205 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cXiY0-00019Y-83 for ged-emacs-devel@m.gmane.org; Sun, 29 Jan 2017 01:01:08 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:35855) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cXiXs-00018l-Aq for emacs-devel@gnu.org; Sun, 29 Jan 2017 01:01:02 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cXiXp-00031B-8N for emacs-devel@gnu.org; Sun, 29 Jan 2017 01:01:00 -0500 Original-Received: from mail-pf0-x244.google.com ([2607:f8b0:400e:c00::244]:33964) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1cXiXo-000311-Ud for emacs-devel@gnu.org; Sun, 29 Jan 2017 01:00:57 -0500 Original-Received: by mail-pf0-x244.google.com with SMTP id y143so21216939pfb.1 for ; Sat, 28 Jan 2017 22:00:55 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:date:to:cc:subject:in-reply-to:message-id:references :user-agent:mime-version; bh=Cxlmu97n+HMOdGlAffukRIXli0fMljtDBOEn0+xcKwU=; b=GrI33BHDhhauynYK5hEXkk6yHJ/Gz35i+7bktBkWg8CHn1vV4YlUDpL4fqtep+GZC+ eo3gipcyhZ+Kgu2oZKnEp3lUa+KvMk0Ic3Xhm0VvsgtUZH9KbQD7xH8rzdLNWScp063h DLgZpdryoKYzYCwH5vUKGTjlyfZ4SBamB8o0DiPr9jVmFpunKicHtjgIIwOmTIRZBJPb 6yP/fa76uK4ZqvKRZMLj4RM15p8dQXSLDNR2c9gSINu3yRrcaPlyEXeM/kYOgTTaYskB WmLkvuMDIq5jbqWAFaAW4Cu97W4k0mxmsaF0zASJnpnwPwhYSWk7UDh0GoE3ENqrtmrH iGaA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:date:to:cc:subject:in-reply-to:message-id :references:user-agent:mime-version; bh=Cxlmu97n+HMOdGlAffukRIXli0fMljtDBOEn0+xcKwU=; b=bdCSwOSKhkk1/C9Gg/K8WKTqhIRXNh78hOVybc59MzN9u+6EiBVM5jVVbG+WzYO5gE TjlchpyvMEQRbW+l2VDMzY7WKI5ld7YxY32GaGi4bM9Zgb7ATKaC46NpzpG+YWnIjRRf uxj7JEDzpb/LYMW6ulYZV1fWACdr6F/vPZjQchqGl9tCUFAlnFcG6eTaarCaoOcEAC0h 5q+CqWvfRXN2N+f7E+OYwM9KGpj/HFbOO0scd3BJOoRebQaiMw63sTPFKd1OyO5EfZjn AyY6q5LFnKD6V24bcnCLeNqUoDIHjEYKPg6yNtfOHo+1JUiUuV+GUPXmo9jft4ifBxwc LWvg== X-Gm-Message-State: AIkVDXJigyC0ahDyhRUSyiBiZD5GxzgMjZVgciRj0SvwAE/NRKAc3UMKVbtFaX6k6yperg== X-Received: by 10.99.173.14 with SMTP id g14mr17764742pgf.176.1485669654175; Sat, 28 Jan 2017 22:00:54 -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 j28sm22501770pfj.2.2017.01.28.22.00.51 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 28 Jan 2017 22:00:53 -0800 (PST) X-Google-Original-From: Tino Calancha X-X-Sender: calancha@calancha-pc In-Reply-To: <87lgtu4w5c.fsf@mail.linkov.net> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2607:f8b0:400e:c00::244 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:211719 Archived-At: --8323329-981600245-1485669653=:1959 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 8BIT On Sun, 29 Jan 2017, Juri Linkov wrote: > I think this is a useful addition, thanks. One note below. > >> +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). > > When someone decides to add support for rectangular regions in occur later, > your current implementation will make this problematic since it changes > the format ((START . END)) to (START . END), that makes difficult to support > ((START1 . END1) (START2 . END2) ...) later. > > Let's stick to the same format in all uses of the new ‘REGION’ arg, and > currently in occur support only the degenerate case of ((START . END)) > for non-rectangular regions. Thanks. I was also a bit worry with that detail. OK, i keep the general format ((START . END)). Let me know if the following patch is OK to be pushed: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; >From 40ac0b30445f9581a5b4d6988d31089468a6a969 Mon Sep 17 00:00:00 2001 From: Tino Calancha Date: Sun, 29 Jan 2017 14:46:10 +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 | 47 +++++++++++++++++++++++++++++++------ 4 files changed, 50 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. @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 @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. @findex global-unset-key @cindex Unbinding key diff --git a/etc/NEWS b/etc/NEWS index 12ff21f39a..a74cdb71df 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 + +** 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..0a8e480485 100644 --- a/lisp/replace.el +++ b/lisp/replace.el @@ -1360,7 +1360,12 @@ occur-rename-buffer "*") (or unique-p (not interactive-p))))) -(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. @@ -1369,6 +1374,11 @@ occur NLINES defaults to `list-matching-lines-default-context-lines'. Interactively it is the prefix arg. +Optional arg REGION, if non-nil, mean restrict search to the +specified region. Otherwise search the entire buffer. +REGION must be a list of (START . END) positions as returned by +`region-bounds'. + 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 +1396,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) (list (region-bounds))))) + (let* ((start (and (caar region) (max (caar region) (point-min)))) + (end (and (cdar region) (min (cdar region) (point-max)))) + (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)))))) (defvar ido-ignore-item-temp-list) @@ -1545,13 +1571,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 +1712,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 (= matches 1) "" "es") ;; Don't display the same number of lines ;; and matches in case of 1 match per line. @@ -1694,7 +1722,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)) -- 2.11.0 >From a1ac23d9b5384524591fa9f6586a2665175caf6f Mon Sep 17 00:00:00 2001 From: Tino Calancha Date: Sun, 29 Jan 2017 14:46:27 +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 a74cdb71df..90b53aca16 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 +** Two new user options 'list-matching-lines-jump-to-current-line' and +'list-matching-lines-current-line-face' to show highlighted the current line +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 0a8e480485..8e51792f5e 100644 --- a/lisp/replace.el +++ b/lisp/replace.el @@ -1304,6 +1304,19 @@ list-matching-lines-buffer-name-face :type 'face :group 'matching) +(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) (defun occur (regexp &optional nlines region) "Show all lines in the current buffer containing a match for REGEXP. @@ -1382,6 +1398,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. If REGEXP contains upper case characters (excluding those preceded by `\\') and `search-upper-case' is non-nil, the matching is case-sensitive. @@ -1409,7 +1428,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))) @@ -1508,7 +1533,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) @@ -1560,6 +1586,10 @@ occur-1 (if (= 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) @@ -1572,7 +1602,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) @@ -1580,12 +1611,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) @@ -1686,6 +1721,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) + (>= 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 @@ -1699,6 +1746,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 @@ -1732,8 +1791,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)) -- 2.11.0 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; In GNU Emacs 26.0.50.1 (x86_64-pc-linux-gnu, GTK+ Version 3.22.6) of 2017-01-29 Repository revision: d12e1ddf42cddcac56f98c5b3a65f5219d2d5968 --8323329-981600245-1485669653=:1959--