]> code.delx.au - gnu-emacs/blobdiff - lisp/sort.el
*** empty log message ***
[gnu-emacs] / lisp / sort.el
index 30dd6916ba97640cc58480e47a9664f6a4837681..f5ad0765dc2203d3b29d9846226253c8f7b7f52f 100644 (file)
@@ -48,7 +48,8 @@ It should move point to the end of the record.
 STARTKEYFUN may moves from the start of the record to the start of the key.
 It may return either return a non-nil value to be used as the key, or
 else the key will be the substring between the values of point after
-STARTKEYFUNC and ENDKEYFUN are called.
+STARTKEYFUN and ENDKEYFUN are called.  If STARTKEYFUN is nil, the key
+starts at the beginning of the record.
 
 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
@@ -66,6 +67,7 @@ same as ENDRECFUN."
              (if (fboundp 'sortcar)
                  (sortcar sort-lists
                           (cond ((numberp (car (car sort-lists)))
+                                 ;; This handles both ints and floats.
                                  '<)
                                 ((consp (car (car sort-lists)))
                                  'buffer-substring-lessp)
@@ -91,7 +93,7 @@ same as ENDRECFUN."
   nil)
 
 ;; Parse buffer into records using the arguments as Lisp expressions;
-;; return a list of records.  Each record looks like (KEY STARTPOS ENDPOS)
+;; return a list of records.  Each record looks like (KEY STARTPOS ENDPOS)
 ;; where KEY is the sort key (a number or string),
 ;; and STARTPOS and ENDPOS are the bounds of this record in the buffer.
 
@@ -129,8 +131,8 @@ same as ENDRECFUN."
                                          (equal (car key) start-rec)
                                          (equal (cdr key) (point)))
                                     (cons key key)
-                                    (list key start-rec (point)))
-                               sort-lists)))
+                                  (cons key (cons start-rec (point))))
+                                sort-lists)))
       (and (not done) nextrecfun (funcall nextrecfun)))
     sort-lists))
 
@@ -152,8 +154,8 @@ same as ENDRECFUN."
       (goto-char (point-max))
       (insert-buffer-substring (current-buffer)
                               (nth 1 (car sort-lists))
-                              (nth 2 (car sort-lists)))
-      (setq last (nth 2 (car old))
+                              (cdr (cdr (car sort-lists))))
+      (setq last (cdr (cdr (car old)))
            sort-lists (cdr sort-lists)
            old (cdr old)))
     (goto-char (point-max))
@@ -167,6 +169,7 @@ same as ENDRECFUN."
     (narrow-to-region min (1+ (point)))
     (delete-region (point) (1+ (point)))))
 
+;;;###autoload
 (defun sort-lines (reverse beg end) 
   "Sort lines in region alphabetically; argument means descending order.
 Called from a program, there are three arguments:
@@ -178,6 +181,7 @@ REVERSE (non-nil means reverse order), BEG and END (region to sort)."
       (goto-char (point-min))
       (sort-subr reverse 'forward-line 'end-of-line))))
 
+;;;###autoload
 (defun sort-paragraphs (reverse beg end)
   "Sort paragraphs in region alphabetically; argument means descending order.
 Called from a program, there are three arguments:
@@ -191,6 +195,7 @@ REVERSE (non-nil means reverse order), BEG and END (region to sort)."
                 (function (lambda () (skip-chars-forward "\n \t\f")))
                 'forward-paragraph))))
 
+;;;###autoload
 (defun sort-pages (reverse beg end)
   "Sort pages in region alphabetically; argument means descending order.
 Called from a program, there are three arguments:
@@ -217,11 +222,12 @@ REVERSE (non-nil means reverse order), BEG and END (region to sort)."
     (modify-syntax-entry ?\. "_" table)        ; for floating pt. numbers. -wsr
     (setq sort-fields-syntax-table table)))
 
+;;;###autoload
 (defun sort-numeric-fields (field beg end)
   "Sort lines in region numerically by the ARGth field of each line.
 Fields are separated by whitespace and numbered from 1 up.
 Specified field must contain a number in each line of the region.
-With a negative arg, sorts by the -ARG'th field, in decending order.
+With a negative arg, sorts by the ARGth field counted from the right.
 Called from a program, there are three arguments:
 FIELD, BEG and END.  BEG and END specify region to sort."
   (interactive "p\nr")
@@ -238,10 +244,31 @@ FIELD, BEG and END.  BEG and END specify region to sort."
                                  (point))))))
                 nil))
 
+(defun sort-float-fields (field beg end)
+  "Sort lines in region numerically by the ARGth field of each line.
+Fields are separated by whitespace and numbered from 1 up.  Specified field
+must contain a floating point number in each line of the region.  With a
+negative arg, sorts by the ARGth field counted from the right.  Called from a
+program, there are three arguments: FIELD, BEG and END.  BEG and END specify
+region to sort."
+  (interactive "p\nr")
+  (sort-fields-1 field beg end
+                (function (lambda ()
+                            (sort-skip-fields (1- field))
+                            (string-to-float
+                             (buffer-substring
+                              (point)
+                              (save-excursion
+                                (re-search-forward
+                                 "[+-]?[0-9]*\.?[0-9]*\\([eE][+-]?[0-9]+\\)?")
+                                (point))))))
+                nil))
+
+;;;###autoload
 (defun sort-fields (field beg end)
   "Sort lines in region lexicographically by the ARGth field of each line.
 Fields are separated by whitespace and numbered from 1 up.
-With a negative arg, sorts by the -ARG'th field, in decending order.
+With a negative arg, sorts by the ARGth field counted from the right.
 Called from a program, there are three arguments:
 FIELD, BEG and END.  BEG and END specify region to sort."
   (interactive "p\nr")
@@ -252,31 +279,36 @@ FIELD, BEG and END.  BEG and END specify region to sort."
                 (function (lambda () (skip-chars-forward "^ \t\n")))))
 
 (defun sort-fields-1 (field beg end startkeyfun endkeyfun)
-  (let ((reverse (< field 0))
-       (tbl (syntax-table)))
-    (setq field (max 1 field (- field)))
+  (let ((tbl (syntax-table)))
+    (if (zerop field) (setq field 1))
     (unwind-protect
        (save-excursion
          (save-restriction
            (narrow-to-region beg end)
            (goto-char (point-min))
            (set-syntax-table sort-fields-syntax-table)
-           (sort-subr reverse
+           (sort-subr nil
                       'forward-line 'end-of-line
                       startkeyfun endkeyfun)))
       (set-syntax-table tbl))))
 
 (defun sort-skip-fields (n)
-  (let ((eol (save-excursion (end-of-line 1) (point))))
-    (forward-word n)
-    (if (> (point) eol)
+  (let ((bol (point))
+       (eol (save-excursion (end-of-line 1) (point))))
+    (if (> n 0) (forward-word n)
+      (end-of-line)
+      (forward-word (1+ n)))
+    (if (or (and (>= (point) eol) (> n 0))
+           ;; this is marginally wrong; if the first line of the sort
+           ;; at bob has the wrong number of fields the error won't be
+           ;; reported until the next short line.
+           (and (< (point) bol) (< n 0)))
        (error "Line has too few fields: %s"
-              (buffer-substring (save-excursion
-                                  (beginning-of-line) (point))
-                                eol)))
+              (buffer-substring bol eol)))
     (skip-chars-forward " \t")))
 
 \f
+;;;###autoload
 (defun sort-regexp-fields (reverse record-regexp key-regexp beg end)
   "Sort the region lexicographically as specifed by RECORD-REGEXP and KEY.
 RECORD-REGEXP specifies the textual units which should be sorted.
@@ -294,6 +326,9 @@ With a negative prefix arg sorts in reverse order.
 For example: to sort lines in the region by the first word on each line
  starting with the letter \"f\",
  RECORD-REGEXP would be \"^.*$\" and KEY would be \"\\=\\<f\\w*\\>\""
+  ;; using negative prefix arg to mean "reverse" is now inconsistent with
+  ;; other sort-.*fields functions but then again this was before, since it
+  ;; didn't use the magnitude of the arg to specify anything.
   (interactive "P\nsRegexp specifying records to sort: 
 sRegexp specifying key within record: \nr")
   (cond ((or (equal key-regexp "") (equal key-regexp "\\&"))
@@ -335,6 +370,7 @@ sRegexp specifying key within record: \nr")
 \f
 (defvar sort-columns-subprocess t)
 
+;;;###autoload
 (defun sort-columns (reverse &optional beg end)
   "Sort lines in region alphabetically by a certain range of columns.
 For the purpose of this command, the region includes
@@ -376,3 +412,35 @@ Use \\[untabify] to convert tabs to spaces before sorting."
            (sort-subr reverse 'forward-line 'end-of-line
                       (function (lambda () (move-to-column col-start) nil))
                       (function (lambda () (move-to-column col-end) nil)))))))))
+
+;;;###autoload
+(defun reverse-region (beg end)
+  "Reverse the order of lines in a region.
+From a program takes two point or marker arguments, BEG and END."
+  (interactive "r")
+  (if (> beg end)
+      (let (mid) (setq mid end end beg beg mid)))
+  (save-excursion
+    ;; put beg at the start of a line and end and the end of one --
+    ;; the largest possible region which fits this criteria
+    (goto-char beg)
+    (or (bolp) (forward-line 1))
+    (setq beg (point))
+    (goto-char end)
+    ;; the test for bolp is for those times when end is on an empty line;
+    ;; it is probably not the case that the line should be included in the
+    ;; reversal; it isn't difficult to add it afterward.
+    (or (and (eolp) (not (bolp))) (progn (forward-line -1) (end-of-line)))
+    (setq end (point-marker))
+    ;; the real work.  this thing cranks through memory on large regions.
+    (let (ll (do t))
+      (while do
+       (goto-char beg)
+       (setq ll (cons (buffer-substring (point) (progn (end-of-line) (point)))
+                      ll))
+       (setq do (/= (point) end))
+       (delete-region beg (if do (1+ (point)) (point))))
+      (while (cdr ll)
+       (insert (car ll) "\n")
+       (setq ll (cdr ll)))
+      (insert (car ll)))))