emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
From: Carsten Dominik <dominik@science.uva.nl>
To: charles_cave@optusnet.com.au
Cc: emacs-orgmode@gnu.org
Subject: Re: How to set a set of headlines (at the same level)
Date: Thu, 16 Nov 2006 13:12:09 +0100	[thread overview]
Message-ID: <c9744de43e47b18cc39f604e1693fe2e@science.uva.nl> (raw)
In-Reply-To: <200611160107.kAG176x0000353@mail01.syd.optusnet.com.au>

On Nov 16, 2006, at 2:07, Charles Cave wrote:

> I would like to see a feature to sort the set of branches into 
> alphabetical order.
> At the moment I have to manually move the subtrees up and done.

[...]

> The sorting algorithm needs to call  org-move-subtree-up  and
> org-move-subtree-down depending on the comparison of adjacent headings.
>
> How difficult would it be to add this functionality? The command should
> work on a region.  I want to create an org-mode file of vocabulary.
> I note that it is possible to sort table rows so that is a possible
> work around for me.
>
> Charles


Sorting could indeed be done with a bubble algorithm or something
like that, using org-move-subtree commands to swap entries.
However, for long lists this would become very slow indeed, because you
would all the time search for the next headline and swap entries, both
slow things.

It is much better to build a list that then can be sorted
efficiently by the internal Emacs command `sort'.

I quickly hacked the following function which should do the job,
but I have not extensively tested it.  Maybe you could do the testing,
and I could included an improved version later with org.el.

(defun org-sort-entries (&optional case-sensitively)
   "Sort entries on a certain level of an outline tree alphabetically.
If there is an active region, the entries in the region are sorted.
If not, the children of the entry at point are sorted.

Comparing entries ignores case by default.  However, with an optional 
argument
CASE-SENSITIVELY, the sorting considers case as well.  With two prefix 
arguments
`C-u C-u', sorting is case-sensitive and duplicate entries will be 
removed."
   (interactive "P")
   (let ((unique (equal case-sensitively '(16)))
	(casefun (if case-sensitively 'identity 'downcase))
	start beg end entries stars re re2 p nentries (nremoved 0) last txt)
     ;; Find beginning and end of region to sort
     (if (org-region-active-p)
	(progn
	  ;; we will sort the region
	  (setq end (region-end))
	  (goto-char (1- (setq start (region-beginning)))))
       ;; we will sort the children of the current headline
       (setq start (point) end (org-end-of-subtree))
       (goto-char start)
       (show-subtree))
     (outline-next-heading) ; this is the first heading to be included
     (setq beg (point))
     (if (>= (point) end) (error "Nothing to sort"))
     (looking-at "\\(\\*+\\)")
     (setq stars (match-string 1)
	  re (concat "^" (regexp-quote stars) " +")
	  re2 (concat "^" (regexp-quote (substring stars 0 -1)) "[^*]")
	  txt (buffer-substring beg end))
     (if (string-match re2 txt)
	(error "Region to sort contains a level above the first entry"))
     ;; Make a list that can be sorted.
     ;; The car is the string for comparison, the cdr is the subtree
     (message "Sorting entries...")
     (setq entries
	  (mapcar
	   (lambda (x)
	     (string-match "^.*" x)
	     (cons (funcall casefun (match-string 0 x)) x))
	   (org-split-string txt re)))
     ;; Sort the list
     (setq entries (sort entries (lambda (a b) (string< (car a) (car 
b)))))
     ;; Remove the old stuff
     (goto-char beg)
     (kill-region beg end)
     (setq nentries (length entries))
     ;; Insert the sorted entries, and remove duplicate if this is 
required
     (while (setq p (pop entries))
       (if (and unique (equal last (setq last (org-trim (cdr p)))))
	  (setq nremoved (1+ nremoved)) ; same entry as before, skip it
	(insert stars " " (cdr p))))
     (goto-char start)
     (message "Sorting entries...done (%d entries%s)"
	     nentries
	     (if unique (format ", %d duplicates removed" nremoved) ""))))

      reply	other threads:[~2006-11-16 12:12 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-11-16  1:07 How to set a set of headlines (at the same level) Charles Cave
2006-11-16 12:12 ` Carsten Dominik [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.orgmode.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=c9744de43e47b18cc39f604e1693fe2e@science.uva.nl \
    --to=dominik@science.uva.nl \
    --cc=charles_cave@optusnet.com.au \
    --cc=emacs-orgmode@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).