Annotation of 43BSDReno/contrib/emacs-18.55/lisp/sort.el, revision 1.1

1.1     ! root        1: ;; Commands to sort text in an Emacs buffer.
        !             2: ;; Copyright (C) 1986, 1987 Free Software Foundation, Inc.
        !             3: 
        !             4: ;; This file is part of GNU Emacs.
        !             5: 
        !             6: ;; GNU Emacs is distributed in the hope that it will be useful,
        !             7: ;; but WITHOUT ANY WARRANTY.  No author or distributor
        !             8: ;; accepts responsibility to anyone for the consequences of using it
        !             9: ;; or for whether it serves any particular purpose or works at all,
        !            10: ;; unless he says so in writing.  Refer to the GNU Emacs General Public
        !            11: ;; License for full details.
        !            12: 
        !            13: ;; Everyone is granted permission to copy, modify and redistribute
        !            14: ;; GNU Emacs, but only under the conditions described in the
        !            15: ;; GNU Emacs General Public License.   A copy of this license is
        !            16: ;; supposed to have been given to you along with GNU Emacs so you
        !            17: ;; can know your rights and responsibilities.  It should be in a
        !            18: ;; file named COPYING.  Among other things, the copyright notice
        !            19: ;; and this notice must be preserved on all copies.
        !            20: 
        !            21: (provide 'sort)
        !            22: 
        !            23: ;; Original version of most of this contributed by Howie Kaye
        !            24: 
        !            25: (defun sort-subr (reverse nextrecfun endrecfun &optional startkeyfun endkeyfun)
        !            26:   "General text sorting routine to divide buffer into records and sort them.
        !            27: Arguments are REVERSE NEXTRECFUN ENDRECFUN &optional STARTKEYFUN ENDKEYFUN.
        !            28: 
        !            29: We consider this portion of the buffer to be divided into disjoint pieces
        !            30: called sort records.  A portion of each sort record (perhaps all of it)
        !            31: is designated as the sort key.  The records are rearranged in the buffer
        !            32: in order by their sort keys.  The records may or may not be contiguous.
        !            33: 
        !            34: Usually the records are rearranged in order of ascending sort key.
        !            35: If REVERSE is non-nil, they are rearranged in order of descending sort key.
        !            36: 
        !            37: The next four arguments are functions to be called to move point
        !            38: across a sort record.  They will be called many times from within sort-subr.
        !            39: 
        !            40: NEXTRECFUN is called with point at the end of the previous record.
        !            41: It moves point to the start of the next record.
        !            42: The first record is assumed to start at the position of point when sort-subr
        !            43: is called.
        !            44: 
        !            45: ENDRECFUN is is called with point within the record.
        !            46: It should move point to the end of the record.
        !            47: 
        !            48: STARTKEYFUN may moves from the start of the record to the start of the key.
        !            49: It may return either return a non-nil value to be used as the key, or
        !            50: else the key will be the substring between the values of point after
        !            51: STARTKEYFUNC and ENDKEYFUN are called.
        !            52: 
        !            53: ENDKEYFUN moves from the start of the sort key to the end of the sort key.
        !            54: ENDRECFUN may be nil if STARTKEYFUN returns a value or if it would be the
        !            55: same as ENDRECFUN."
        !            56:   (save-excursion
        !            57:     (message "Finding sort keys...")
        !            58:     (let* ((sort-lists (sort-build-lists nextrecfun endrecfun
        !            59:                                        startkeyfun endkeyfun))
        !            60:           (old (reverse sort-lists)))
        !            61:       (if (null sort-lists)
        !            62:          ()
        !            63:        (or reverse (setq sort-lists (nreverse sort-lists)))
        !            64:        (message "Sorting records...")
        !            65:        (setq sort-lists
        !            66:              (if (fboundp 'sortcar)
        !            67:                  (sortcar sort-lists
        !            68:                           (cond ((numberp (car (car sort-lists)))
        !            69:                                  '<)
        !            70:                                 ((consp (car (car sort-lists)))
        !            71:                                  'buffer-substring-lessp)
        !            72:                                 (t
        !            73:                                  'string<)))
        !            74:                  (sort sort-lists
        !            75:                        (cond ((numberp (car (car sort-lists)))
        !            76:                               (function
        !            77:                                (lambda (a b)
        !            78:                                  (< (car a) (car b)))))
        !            79:                              ((consp (car (car sort-lists)))
        !            80:                               (function
        !            81:                                (lambda (a b)
        !            82:                                  (buffer-substring-lessp (car a) (car b)))))
        !            83:                              (t
        !            84:                               (function
        !            85:                                (lambda (a b)
        !            86:                                  (string< (car a) (car b)))))))))
        !            87:        (if reverse (setq sort-lists (nreverse sort-lists)))
        !            88:        (message "Reordering buffer...")
        !            89:        (sort-reorder-buffer sort-lists old)))
        !            90:     (message "Reordering buffer... Done")))
        !            91: 
        !            92: ;; Parse buffer into records using the arguments as Lisp expressions;
        !            93: ;; return a list of records.  Each record looks like (KEY STARTPOS ENDPOS)
        !            94: ;; where KEY is the sort key (a number or string),
        !            95: ;; and STARTPOS and ENDPOS are the bounds of this record in the buffer.
        !            96: 
        !            97: ;; The records appear in the list lastmost first!
        !            98: 
        !            99: (defun sort-build-lists (nextrecfun endrecfun startkeyfun endkeyfun)
        !           100:   (let ((sort-lists ())
        !           101:        (start-rec nil)
        !           102:        done key)
        !           103:     ;; Loop over sort records.
        !           104:     ;(goto-char (point-min)) -- it is the caller's responsibility to
        !           105:     ;arrange this if necessary
        !           106:     (while (not (eobp))
        !           107:       (setq start-rec (point))         ;save record start
        !           108:       (setq done nil)
        !           109:       ;; Get key value, or move to start of key.
        !           110:       (setq key (catch 'key
        !           111:                  (or (and startkeyfun (funcall startkeyfun))
        !           112:                      ;; If key was not returned as value,
        !           113:                      ;; move to end of key and get key from the buffer.
        !           114:                      (let ((start (point)))
        !           115:                        (funcall (or endkeyfun
        !           116:                                     (prog1 endrecfun (setq done t))))
        !           117:                        (if (fboundp 'buffer-substring-lessp)
        !           118:                            (cons start (point))
        !           119:                          (buffer-substring start (point)))))))
        !           120:       ;; Move to end of this record (start of next one, or end of buffer).
        !           121:       (cond ((prog1 done (setq done nil)))
        !           122:            (endrecfun (funcall endrecfun))
        !           123:            (nextrecfun (funcall nextrecfun) (setq done t)))
        !           124:       (if key (setq sort-lists (cons
        !           125:                                 ;; consing optimization in case in which key
        !           126:                                 ;; is same as record.
        !           127:                                 (if (and (consp key)
        !           128:                                          (equal (car key) start-rec)
        !           129:                                          (equal (cdr key) (point)))
        !           130:                                     (cons key key)
        !           131:                                     (list key start-rec (point)))
        !           132:                                sort-lists)))
        !           133:       (and (not done) nextrecfun (funcall nextrecfun)))
        !           134:     sort-lists))
        !           135: 
        !           136: (defun sort-reorder-buffer (sort-lists old)
        !           137:   (let ((inhibit-quit t)
        !           138:        (last (point-min))
        !           139:        (min (point-min)) (max (point-max)))
        !           140:     (while sort-lists
        !           141:       (goto-char (point-max))
        !           142:       (insert-buffer-substring (current-buffer)
        !           143:                               last
        !           144:                               (nth 1 (car old)))
        !           145:       (goto-char (point-max))
        !           146:       (insert-buffer-substring (current-buffer)
        !           147:                               (nth 1 (car sort-lists))
        !           148:                               (nth 2 (car sort-lists)))
        !           149:       (setq last (nth 2 (car old))
        !           150:            sort-lists (cdr sort-lists)
        !           151:            old (cdr old)))
        !           152:     (goto-char (point-max))
        !           153:     (insert-buffer-substring (current-buffer)
        !           154:                             last
        !           155:                             max)
        !           156:     (delete-region min max)))  ;get rid of old version
        !           157: 
        !           158: (defun sort-lines (reverse beg end) 
        !           159:   "Sort lines in region alphabetically; argument means descending order.
        !           160: Called from a program, there are three arguments:
        !           161: REVERSE (non-nil means reverse order), BEG and END (region to sort)."
        !           162:   (interactive "P\nr")
        !           163:   (save-restriction
        !           164:     (narrow-to-region beg end)
        !           165:     (goto-char (point-min))
        !           166:     (sort-subr reverse 'forward-line 'end-of-line)))
        !           167: 
        !           168: (defun sort-paragraphs (reverse beg end)
        !           169:   "Sort paragraphs in region alphabetically; argument means descending order.
        !           170: Called from a program, there are three arguments:
        !           171: REVERSE (non-nil means reverse order), BEG and END (region to sort)."
        !           172:   (interactive "P\nr")
        !           173:   (save-restriction
        !           174:     (narrow-to-region beg end)
        !           175:     (goto-char (point-min))
        !           176:     (sort-subr reverse
        !           177:               (function (lambda () (skip-chars-forward "\n \t\f")))
        !           178:               'forward-paragraph)))
        !           179: 
        !           180: (defun sort-pages (reverse beg end)
        !           181:   "Sort pages in region alphabetically; argument means descending order.
        !           182: Called from a program, there are three arguments:
        !           183: REVERSE (non-nil means reverse order), BEG and END (region to sort)."
        !           184:   (interactive "P\nr")
        !           185:   (save-restriction
        !           186:     (narrow-to-region beg end)
        !           187:     (goto-char (point-min))
        !           188:     (sort-subr reverse
        !           189:               (function (lambda () (skip-chars-forward "\n")))
        !           190:               'forward-page)))
        !           191: 
        !           192: (defvar sort-fields-syntax-table nil)
        !           193: (if sort-fields-syntax-table nil
        !           194:   (let ((table (make-syntax-table))
        !           195:        (i 0))
        !           196:     (while (< i 256)
        !           197:       (modify-syntax-entry i "w" table)
        !           198:       (setq i (1+ i)))
        !           199:     (modify-syntax-entry ?\  " " table)
        !           200:     (modify-syntax-entry ?\t " " table)
        !           201:     (modify-syntax-entry ?\n " " table)
        !           202:     (setq sort-fields-syntax-table table)))
        !           203: 
        !           204: (defun sort-numeric-fields (field beg end)
        !           205:   "Sort lines in region numerically by the ARGth field of each line.
        !           206: Fields are separated by whitespace and numbered from 1 up.
        !           207: Specified field must contain a number in each line of the region.
        !           208: With a negative arg, sorts by the -ARG'th field, in reverse order.
        !           209: Called from a program, there are three arguments:
        !           210: FIELD, BEG and END.  BEG and END specify region to sort."
        !           211:   (interactive "p\nr")
        !           212:   (sort-fields-1 field beg end
        !           213:                 (function (lambda ()
        !           214:                             (sort-skip-fields (1- field))
        !           215:                             (string-to-int
        !           216:                              (buffer-substring
        !           217:                                (point)
        !           218:                                (save-excursion
        !           219:                                  (skip-chars-forward "[0-9]")
        !           220:                                  (point))))))
        !           221:                 nil))
        !           222: 
        !           223: (defun sort-fields (field beg end)
        !           224:   "Sort lines in region lexicographically by the ARGth field of each line.
        !           225: Fields are separated by whitespace and numbered from 1 up.
        !           226: With a negative arg, sorts by the -ARG'th field, in reverse order.
        !           227: Called from a program, there are three arguments:
        !           228: FIELD, BEG and END.  BEG and END specify region to sort."
        !           229:   (interactive "p\nr")
        !           230:   (sort-fields-1 field beg end
        !           231:                 (function (lambda ()
        !           232:                             (sort-skip-fields (1- field))
        !           233:                             nil))
        !           234:                 (function (lambda () (skip-chars-forward "^ \t\n")))))
        !           235: 
        !           236: (defun sort-fields-1 (field beg end startkeyfun endkeyfun)
        !           237:   (let ((reverse (< field 0))
        !           238:        (tbl (syntax-table)))
        !           239:     (setq field (max 1 field (- field)))
        !           240:     (unwind-protect
        !           241:        (save-restriction
        !           242:          (narrow-to-region beg end)
        !           243:          (goto-char (point-min))
        !           244:          (set-syntax-table sort-fields-syntax-table)
        !           245:          (sort-subr reverse
        !           246:                     'forward-line 'end-of-line
        !           247:                     startkeyfun endkeyfun))
        !           248:       (set-syntax-table tbl))))
        !           249: 
        !           250: (defun sort-skip-fields (n)
        !           251:   (let ((eol (save-excursion (end-of-line 1) (point))))
        !           252:     (forward-word n)
        !           253:     (if (> (point) eol)
        !           254:        (error "Line has too few fields: %s"
        !           255:               (buffer-substring (save-excursion
        !           256:                                   (beginning-of-line) (point))
        !           257:                                 eol)))
        !           258:     (skip-chars-forward " \t")))
        !           259: 
        !           260: 
        !           261: (defun sort-regexp-fields (reverse record-regexp key-regexp beg end)
        !           262:   "Sort the region lexicographically as specifed by RECORD-REGEXP and KEY.
        !           263: RECORD-REGEXP specifies the textual units which should be sorted.
        !           264:   For example, to sort lines RECORD-REGEXP would be \"^.*$\"
        !           265: KEY specifies the part of each record (ie each match for RECORD-REGEXP)
        !           266:   is to be used for sorting.
        !           267:   If it is \"\\digit\" then the digit'th \"\\(...\\)\" match field from
        !           268:   RECORD-REGEXP is used.
        !           269:   If it is \"\\&\" then the whole record is used.
        !           270:   Otherwise, it is a regular-expression for which to search within the record.
        !           271: If a match for KEY is not found within a record then that record is ignored.
        !           272: 
        !           273: With a negative prefix arg sorts in reverse order.
        !           274: 
        !           275: For example: to sort lines in the region by the first word on each line
        !           276:  starting with the letter \"f\",
        !           277:  RECORD-REGEXP would be \"^.*$\" and KEY \"\\<f\\w*\\>\""
        !           278:   (interactive "P\nsRegexp specifying records to sort: 
        !           279: sRegexp specifying key within record: \nr")
        !           280:   (cond ((or (equal key-regexp "") (equal key-regexp "\\&"))
        !           281:         (setq key-regexp 0))
        !           282:        ((string-match "\\`\\\\[1-9]\\'" key-regexp)
        !           283:         (setq key-regexp (- (aref key-regexp 1) ?0))))
        !           284:   (save-restriction
        !           285:     (narrow-to-region beg end)
        !           286:     (goto-char (point-min))
        !           287:     (let (sort-regexp-record-end) ;isn't dynamic scoping wonderful?
        !           288:       (re-search-forward record-regexp)
        !           289:       (setq sort-regexp-record-end (point))
        !           290:       (goto-char (match-beginning 0))
        !           291:       (sort-subr reverse
        !           292:                 (function (lambda ()
        !           293:                             (and (re-search-forward record-regexp nil 'move)
        !           294:                                  (setq sort-regexp-record-end (match-end 0))
        !           295:                                  (goto-char (match-beginning 0)))))
        !           296:                 (function (lambda ()
        !           297:                             (goto-char sort-regexp-record-end)))
        !           298:                 (function (lambda ()
        !           299:                             (let ((n 0))
        !           300:                               (cond ((numberp key-regexp)
        !           301:                                      (setq n key-regexp))
        !           302:                                     ((re-search-forward
        !           303:                                        key-regexp sort-regexp-record-end t)
        !           304:                                      (setq n 0))
        !           305:                                     (t (throw 'key nil)))
        !           306:                               (condition-case ()
        !           307:                                   (if (fboundp 'buffer-substring-lessp)
        !           308:                                       (cons (match-beginning n)
        !           309:                                             (match-end n))
        !           310:                                       (buffer-substring (match-beginning n)
        !           311:                                                         (match-end n)))
        !           312:                                 ;; if there was no such register
        !           313:                                 (error (throw 'key nil))))))))))
        !           314: 
        !           315: 
        !           316: (defun sort-columns (reverse &optional beg end)
        !           317:   "Sort lines in region alphabetically by a certain range of columns.
        !           318: For the purpose of this command, the region includes
        !           319: the entire line that point is in and the entire line the mark is in.
        !           320: The column positions of point and mark bound the range of columns to sort on.
        !           321: A prefix argument means sort into reverse order.
        !           322: 
        !           323: Note that sort-columns uses the sort utility program and therefore
        !           324: cannot work on text containing TAB characters.  Use M-x untabify
        !           325: to convert tabs to spaces before sorting."
        !           326:   (interactive "P\nr")
        !           327:   (save-excursion
        !           328:     (let (beg1 end1 col-beg1 col-end1 col-start col-end)
        !           329:       (goto-char (min beg end))
        !           330:       (setq col-beg1 (current-column))
        !           331:       (beginning-of-line)
        !           332:       (setq beg1 (point))
        !           333:       (goto-char (max beg end))
        !           334:       (setq col-end1 (current-column))
        !           335:       (forward-line)
        !           336:       (setq end1 (point))
        !           337:       (setq col-start (min col-beg1 col-end1))
        !           338:       (setq col-end (max col-beg1 col-end1))
        !           339:       (if (search-backward "\t" beg1 t)
        !           340:          (error "sort-columns does not work with tabs.  Use M-x untabify."))
        !           341:       (call-process-region beg1 end1 "sort" t t nil
        !           342:                           (if reverse "-rt\n" "-t\n")
        !           343:                            (concat "+0." col-start)
        !           344:                            (concat "-0." col-end)))))

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.