emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
* How to set a set of headlines (at the same level)
@ 2006-11-16  1:07 Charles Cave
  2006-11-16 12:12 ` Carsten Dominik
  0 siblings, 1 reply; 2+ messages in thread
From: Charles Cave @ 2006-11-16  1:07 UTC (permalink / raw)
  To: emacs-orgmode

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.

Here is an example:

Before sorting

* New words
** bird 
A bird can fly
*** sub topic
blah blah
** fred
A Fred is a frog
** cat
A cat is an animal
** aviary
Where birds are kept


After sorting...

* New words
** aviary
Where birds are kept
** bird 
A bird can fly
*** sub topic
blah blah (sub topics could appear in the tree)
** cat
A cat is an animal
** fred
A Fred is a frog


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

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: How to set a set of headlines (at the same level)
  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
  0 siblings, 0 replies; 2+ messages in thread
From: Carsten Dominik @ 2006-11-16 12:12 UTC (permalink / raw)
  To: charles_cave; +Cc: emacs-orgmode

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) ""))))

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2006-11-16 12:12 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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

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).