X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/e61d39cddfd015032a6419ce75c36ecdf1e9fe9f..a8e1414c0d66903884059361ecc8ec70da37cf35:/lisp/sort.el diff --git a/lisp/sort.el b/lisp/sort.el index 44f90fff37..8bc71388ad 100644 --- a/lisp/sort.el +++ b/lisp/sort.el @@ -1,10 +1,10 @@ ;;; sort.el --- commands to sort text in an Emacs buffer -;; Copyright (C) 1986-1987, 1994-1995, 2001-2012 -;; Free Software Foundation, Inc. +;; Copyright (C) 1986-1987, 1994-1995, 2001-2016 Free Software +;; Foundation, Inc. ;; Author: Howie Kaye -;; Maintainer: FSF +;; Maintainer: emacs-devel@gnu.org ;; Keywords: unix ;; This file is part of GNU Emacs. @@ -77,8 +77,13 @@ ENDKEYFUN moves from the start of the sort key to the end of the sort key. ENDKEYFUN may be nil if STARTKEYFUN returns a value or if it would be the same as ENDRECFUN. -PREDICATE is the function to use to compare keys. If keys are numbers, -it defaults to `<', otherwise it defaults to `string<'." +PREDICATE, if non-nil, is the predicate function for comparing +keys; it is called with two arguments, the keys to compare, and +should return non-nil if the first key should sort before the +second key. If PREDICATE is nil, comparison is done with `<' if +the keys are numbers, with `compare-buffer-substrings' if the +keys are cons cells (the car and cdr of each cons cell are taken +as start and end positions), and with `string<' otherwise." ;; Heuristically try to avoid messages if sorting a small amt of text. (let ((messages (> (- (point-max) (point-min)) 50000))) (save-excursion @@ -311,7 +316,7 @@ FIELD, BEG and END. BEG and END specify region to sort." ;; (point) ;; (save-excursion ;; (re-search-forward -;; "[+-]?[0-9]*\.?[0-9]*\\([eE][+-]?[0-9]+\\)?") +;; "[+-]?[0-9]*\\.?[0-9]*\\([eE][+-]?[0-9]+\\)?") ;; (point)))))) ;; nil)) @@ -562,6 +567,68 @@ 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 keep-blanks + interactive) + "Delete all but one copy of any identical lines in the region. +Non-interactively, arguments BEG and END delimit the region. +Normally it searches forwards, keeping the first instance of +each identical line. If REVERSE is non-nil (interactively, with +a C-u prefix), it searches backwards and keeps the last instance of +each repeated line. + +Identical lines need not be adjacent, unless the argument +ADJACENT is non-nil (interactively, with a C-u C-u prefix). +This is a more efficient mode of operation, and may be useful +on large regions that have already been sorted. + +If the argument KEEP-BLANKS is non-nil (interactively, with a +C-u C-u C-u prefix), it retains repeated blank lines. + +Returns the number of deleted lines. Interactively, or if INTERACTIVE +is non-nil, it also prints a message describing the number of deletions." + (interactive + (progn + (barf-if-buffer-read-only) + (list (region-beginning) (region-end) + (equal current-prefix-arg '(4)) + (equal current-prefix-arg '(16)) + (equal current-prefix-arg '(64)) + t))) + (let ((lines (unless adjacent (make-hash-table :test 'equal))) + line prev-line first-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 + (not first-line) + (and (< (point) end) (not (eobp)))) + (setq first-line (and reverse (or (<= (point) beg) (bobp)))) + (setq line (buffer-substring-no-properties + (line-beginning-position) (line-end-position))) + (if (and keep-blanks (string= "" line)) + (forward-line 1) + (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