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, 22 Jan 2017 19:32:35 +0900 Message-ID: <87fukb2xmk.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> 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 1485081215 17280 195.159.176.226 (22 Jan 2017 10:33:35 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Sun, 22 Jan 2017 10:33:35 +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 Sun Jan 22 11:33:29 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 1cVFSg-0003mx-Rz for ged-emacs-devel@m.gmane.org; Sun, 22 Jan 2017 11:33:27 +0100 Original-Received: from localhost ([::1]:35561 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cVFSl-0001au-GY for ged-emacs-devel@m.gmane.org; Sun, 22 Jan 2017 05:33:31 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:60214) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cVFS6-0001aZ-D4 for emacs-devel@gnu.org; Sun, 22 Jan 2017 05:32:52 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cVFS1-0004Dw-NO for emacs-devel@gnu.org; Sun, 22 Jan 2017 05:32:50 -0500 Original-Received: from mail-pg0-x22e.google.com ([2607:f8b0:400e:c05::22e]:33461) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1cVFS1-0004BE-DO for emacs-devel@gnu.org; Sun, 22 Jan 2017 05:32:45 -0500 Original-Received: by mail-pg0-x22e.google.com with SMTP id 204so36490144pge.0 for ; Sun, 22 Jan 2017 02:32:43 -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=2iJCwBQjGBbdh1cO2iviqRxU/8lXs2fz9ELc+swW2WQ=; b=GwH37rHxELDWPBA6bcLYm5YHWZ94doEqwQrhN8Oly060xXqAUe8l2N2BHktqw2K+FS yI5KXBOfZ9g2knSwJHfQDkvLBz1HV5DC7U7veizMD/aQTUW5Zn2j7Flo1OMmB5E6Pg6C FW5fJOLMKYiEHRlSivoyEbehD6OWtqXBb4p47Kfibe2WgEZkpXf2SeJwA3c3szmN4Hd3 bxdWyVBQ9a+QOBDTQUEMfiW4e1YRowmOmts3NC4oK+icdnFB+Er+ZG/mRUGkx5UJiP1T P3H1Rs/PI0RskjWxP5G1Nn3lul/0OiiI507ANtvihr2FLPbPMBpLJNoi2sIeYWjl/vT7 i6zg== 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=2iJCwBQjGBbdh1cO2iviqRxU/8lXs2fz9ELc+swW2WQ=; b=kjAAt9jEzkySpoqpZi0Vsw6ey0xF/0sI3mpfs40Mhb0IA1SAeUKhbM3y0l9p6IRLTo pT9fvDfaWC2Rm5bKGytX3zazzz0g2ARWt3qFJ/QWh8jms5s7VdW+GWNoHpkNZGcUPcSI sRAwnnGPggVMe0iD6ekaWIfzS1HSeGL320cYJcH/+Ru0SarImryX7Gi5fB+FB4nj2ZiK tAkDCoYWHqXHDR7q0PEgQ22m7FxZ+3CvEhBdGqHaOnQJ4a6pkKxdpGZdaynmNK84byMF /hoGX7ATbaRiCiDFfJ9U6iT6R6npbcd3VRR9At3bzLjObv5m9Tucj5zYrvXQKNPWxtpf +uGQ== X-Gm-Message-State: AIkVDXJSlirK9dczVnLSsJSAzTui1/osdFO9flrxbniU1jP+GWCoycpvAcNyY88JNv75qg== X-Received: by 10.84.217.216 with SMTP id d24mr35124408plj.101.1485081162686; Sun, 22 Jan 2017 02:32:42 -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 o126sm28965339pga.34.2017.01.22.02.32.40 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Sun, 22 Jan 2017 02:32:41 -0800 (PST) In-Reply-To: <8760l9wcci.fsf@mail.linkov.net> (Juri Linkov's message of "Sat, 21 Jan 2017 01:17:17 +0200") X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2607:f8b0:400e:c05::22e 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:211518 Archived-At: Juri Linkov writes: >> OK. Updated the patch. >> *) First patch allow `occur' handle the region with the new convention, >> i.e., region argument instead of BEG, END. > > Thanks. As a prerequisite I'm going to install this patch: > +(defun region-bounds () > + "Return the boundaries of the region as a list of (START . END) positi= ons." > + (funcall region-extract-function 'bounds)) > + > (defvar region-insert-function > (lambda (lines) > (let ((first t)) Thank you. >> **) The second patch add your suggestion on showing highlighted the >> current line. When there are matches after the current line, the >> point in *Occur* is set right after such line. >> >> I am fine with just adding *). In case we also want **), >> an option to enable/disable that behaviour might be desirable. > > Keeping traditional behaviour means not jumping to the middle of the > *Occur* output by default. Then maybe we could use the same option > to highlight the current line and to jump to it? Like the existing > =E2=80=98list-matching-lines-buffer-name-face=E2=80=99, adding a nil/face= choice for > =E2=80=98list-matching-lines-current-line-face=E2=80=99, so when it's nil= then don't > highlight/jump? OK, why not? ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;= ;;;; >From c9a6891187de8c4df6294777ea745810d405b07a Mon Sep 17 00:00:00 2001 From: Tino Calancha Date: Sun, 22 Jan 2017 19:12:35 +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 31b578636731c0a67dc64aad8d880d82d7c8804d Mon Sep 17 00:00:00 2001 From: Tino Calancha Date: Sun, 22 Jan 2017 19:25:34 +0900 Subject: [PATCH 2/2] Show current line highlighted in *Occur* buffer * lisp/replace.el (occur-current-line-face): New face. (list-matching-lines-current-line-face): New user option. (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 'occur-current-line-face'. Set point on the first matching line after the current one. * etc/NEWS: Add entry for the new option. --- etc/NEWS | 3 +++ lisp/replace.el | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++= ---- 2 files changed, 70 insertions(+), 5 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 9eb5d82099..ff8246506d 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -311,6 +311,9 @@ substituted by a home directory by writing it as "/foo:= /:/~/file". * Editing Changes in Emacs 26.1 =20 =20 +** A new user option '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 00e73157ff..3de09b48cc 100644 --- a/lisp/replace.el +++ b/lisp/replace.el @@ -1081,6 +1081,12 @@ occur-mode-find-occurrence-hook :type 'hook :group 'matching) =20 +(defface occur-current-line-face + '((t (:inherit lazy-highlight))) + "Face for highlighting the current line in *Occur* buffer." + :group 'matching + :version "26.1") + (put 'occur-mode 'mode-class 'special) (define-derived-mode occur-mode special-mode "Occur" "Major mode for output from \\[occur]. @@ -1304,6 +1310,13 @@ list-matching-lines-buffer-name-face :type 'face :group 'matching) =20 +(defcustom list-matching-lines-current-line-face 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 '(choice (const :tag "Unset" nil) + (const :tag "highlight current line" occur-current-line-f= ace)) + :group 'matching) + (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-current-line-face' is non-nil, then show highlight= ed +the current line; if there are matches after it, then set the +point right after such line. =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-current-line-face + (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 'occur-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-current-line-face + (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 'occur-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: 0a49f158f1598fb92989f3cbdc238a7e5f1bd8a3