Commit c38a186c authored by Juri Linkov's avatar Juri Linkov
Browse files

* lisp/sort.el (delete-duplicate-lines): New command.

Fixes: debbugs:13032
parent 9320b007
......@@ -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'
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)
......@@ -562,6 +562,62 @@ From a program takes two point or marker arguments, BEG and END."
(setq ll (cdr ll)))
(insert (car ll)))))
(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."
(list (region-beginning) (region-end)
(equal current-prefix-arg '(4))
(equal current-prefix-arg '(16))
(let ((lines (unless adjacent (make-hash-table :weakness 'key :test 'equal)))
line prev-line
(count 0)
(beg (copy-marker beg))
(end (copy-marker end)))
(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))
(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"
(if adjacent "adjacent " "")
(if (= count 1) "" "s")
(if reverse " backward" "")))
(provide 'sort)
;;; sort.el ends here
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment