From c38a186c2e06e0a351d166c5ef06d7307e145f45 Mon Sep 17 00:00:00 2001 From: Juri Linkov Date: Tue, 4 Dec 2012 01:49:08 +0200 Subject: [PATCH] * lisp/sort.el (delete-duplicate-lines): New command. Fixes: debbugs:13032 --- etc/NEWS | 5 +++++ lisp/ChangeLog | 4 ++++ lisp/sort.el | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+) diff --git a/etc/NEWS b/etc/NEWS index fd1e5bb2a21..b175843828d 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -69,6 +69,11 @@ New features include: name and arguments. Useful to trace the value of (current-buffer) or (point) when the function is invoked. +** New command `delete-duplicate-lines' has two types of operation: +when its arg ADJACENT is non-nil (when called interactively with C-u C-u) +it works like the utility `uniq'. Otherwise by default it deletes +duplicate lines everywhere in the region without regard to adjacency. + ** Woman *** The commands `woman-default-faces' and `woman-monochrome-faces' diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 891e6771503..f4963a07a92 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,7 @@ +2012-12-03 Juri Linkov + + * sort.el (delete-duplicate-lines): New command. (Bug#13032) + 2012-12-03 Agustín Martín Domingo * textmodes/ispell.el (ispell-init-process) diff --git a/lisp/sort.el b/lisp/sort.el index 44f90fff379..cd0b4433ab3 100644 --- a/lisp/sort.el +++ b/lisp/sort.el @@ -562,6 +562,62 @@ From a program takes two point or marker arguments, BEG and END." (setq ll (cdr ll))) (insert (car ll))))) +;;;###autoload +(defun delete-duplicate-lines (beg end &optional reverse adjacent interactive) + "Delete duplicate lines in the region between BEG and END. + +If REVERSE is nil, search and delete duplicates forward keeping the first +occurrence of duplicate lines. If REVERSE is non-nil (when called +interactively with C-u prefix), search and delete duplicates backward +keeping the last occurrence of duplicate lines. + +If ADJACENT is non-nil (when called interactively with two C-u prefixes), +delete repeated lines only if they are adjacent. It works like the utility +`uniq' and is useful when lines are already sorted in a large file since +this is more efficient in performance and memory usage than when ADJACENT +is nil that uses additional memory to remember previous lines. + +When called from Lisp and INTERACTIVE is omitted or nil, return the number +of deleted duplicate lines, do not print it; if INTERACTIVE is t, the +function behaves in all respects as if it had been called interactively." + (interactive + (progn + (barf-if-buffer-read-only) + (list (region-beginning) (region-end) + (equal current-prefix-arg '(4)) + (equal current-prefix-arg '(16)) + t))) + (let ((lines (unless adjacent (make-hash-table :weakness 'key :test 'equal))) + line prev-line + (count 0) + (beg (copy-marker beg)) + (end (copy-marker end))) + (save-excursion + (goto-char (if reverse end beg)) + (if (and reverse (bolp)) (forward-char -1)) + (while (if reverse + (and (> (point) beg) (not (bobp))) + (and (< (point) end) (not (eobp)))) + (setq line (buffer-substring-no-properties + (line-beginning-position) (line-end-position))) + (if (if adjacent (equal line prev-line) (gethash line lines)) + (progn + (delete-region (progn (forward-line 0) (point)) + (progn (forward-line 1) (point))) + (if reverse (forward-line -1)) + (setq count (1+ count))) + (if adjacent (setq prev-line line) (puthash line t lines)) + (forward-line (if reverse -1 1))))) + (set-marker beg nil) + (set-marker end nil) + (when interactive + (message "Deleted %d %sduplicate line%s%s" + count + (if adjacent "adjacent " "") + (if (= count 1) "" "s") + (if reverse " backward" ""))) + count)) + (provide 'sort) ;;; sort.el ends here -- 2.39.5