emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
From: Jon Snader <jsnader@mac.com>
To: Nicolas Goaziou <mail@nicolasgoaziou.fr>
Cc: emacs-orgmode@gnu.org
Subject: Re: Patch to implement sorting Org tables by IP address
Date: Wed, 17 Dec 2014 12:31:55 -0500	[thread overview]
Message-ID: <ABF84C2E-2C3A-4C5F-9FCF-582D3B551319@mac.com> (raw)
In-Reply-To: <87ppbm6tgl.fsf@nicolasgoaziou.fr>


[-- Attachment #1.1: Type: text/plain, Size: 774 bytes --]


> On Dec 14, 2014, at 12:18 PM, Nicolas Goaziou <mail@nicolasgoaziou.fr> wrote:

>> As I said above, you’ve convinced me that ?f ?F is the right solution.
> 
> Fair enough. Let's settle on that, then.

Here is the new patch. It extends org-table-sort-lines to allow a user to specify custom extraction and comparison functions using the ?f ?F sorting type as in org-sort-list.

The user can call org-table-sort-lines programmatically specifying a SORTING-TYPE of ?f or ?F and provide custom extraction and comparison functions. If the user calls org-table-sort lines interactively and specifies ?f or ?F, org-do-sort will prompt for a custom extraction function. The comparison will be either string or numeric depending on the type of the first extracted key.

[-- Attachment #1.2: 0001-org.el-Implement-user-specified-sorting-functions.patch --]
[-- Type: application/octet-stream, Size: 6932 bytes --]

From 53f1929b7a8c1b98230d60e5313e7550ab3d1b13 Mon Sep 17 00:00:00 2001
From: Jon Snader <jcs@manfredII.local>
Date: Wed, 17 Dec 2014 11:52:23 -0500
Subject: [PATCH] org.el: Implement user specified sorting functions

* lisp/org.el (org-do-sort): Implemented the ability for the user
to specify custom extraction and comparison functions.	Updated
the DOC string.

* lisp/org-table.el (org-table-sort-lines): Added GETKEY-FUNC and
COMPARE-FUNC as optional arguments and passed them to
`org-do-sort'.	Updated DOC string to reflect the new
functionality.

* doc/org.texi (Structure editing): Document the ability for users
to specify their own extraction and comparison functions.
---
 doc/org.texi      |  6 ++++--
 lisp/org-table.el | 15 +++++++++++----
 lisp/org.el       | 36 ++++++++++++++++++++++++++++++------
 3 files changed, 45 insertions(+), 12 deletions(-)

diff --git a/doc/org.texi b/doc/org.texi
index d617259..f56e824 100644
--- a/doc/org.texi
+++ b/doc/org.texi
@@ -2205,8 +2205,10 @@ point is before the first column, you will be prompted for the sorting
 column.  If there is an active region, the mark specifies the first line
 and the sorting column, while point should be in the last line to be
 included into the sorting.  The command prompts for the sorting type
-(alphabetically, numerically, or by time).  When called with a prefix
-argument, alphabetic sorting will be case-sensitive.
+(alphabetically, numerically, or by time).  You can sort in normal or reverse
+order.  You can also supply your own key extraction and comparison
+functions.  When called with a prefix argument, alphabetic sorting will
+be case-sensitive.
 
 @tsubheading{Regions}
 @orgcmd{C-c C-x M-w,org-table-copy-region}
diff --git a/lisp/org-table.el b/lisp/org-table.el
index 06a8ab7..9048ac9 100644
--- a/lisp/org-table.el
+++ b/lisp/org-table.el
@@ -1657,7 +1657,7 @@ In particular, this does handle wide and invisible characters."
 			      dline -1 dline))))
 
 ;;;###autoload
-(defun org-table-sort-lines (with-case &optional sorting-type)
+(defun org-table-sort-lines (with-case &optional sorting-type getkey-func compare-func)
   "Sort table lines according to the column at point.
 
 The position of point indicates the column to be used for
@@ -1677,8 +1677,15 @@ With prefix argument WITH-CASE, alphabetic sorting will be case-sensitive.
 
 If SORTING-TYPE is specified when this function is called from a Lisp
 program, no prompting will take place.  SORTING-TYPE must be a character,
-any of (?a ?A ?n ?N ?t ?T) where the capital letter indicate that sorting
-should be done in reverse order."
+any of (?a ?A ?n ?N ?t ?T ?f ?F) where the capital letter indicate that sorting
+should be done in reverse order.
+
+If the SORTING-TYPE is ?f or ?F, then GETKEY-FUNC specifies
+a function to be called to extract the key.  It must return either
+a string or a number that should serve as the sorting key for that
+row.  It will then use COMPARE-FUNC to compare entries.  If GETKEY-FUNC
+is specified interactively, the comparison will be either a string or
+numeric compare based on the type of the first key in the table."
   (interactive "P")
   (let* ((thisline (org-current-line))
 	 (thiscol (org-table-current-column))
@@ -1730,7 +1737,7 @@ should be done in reverse order."
 					(org-split-string x "[ \t]*|[ \t]*")))
 				  x))
 		      (org-split-string (buffer-substring beg end) "\n")))
-    (setq lns (org-do-sort lns "Table" with-case sorting-type))
+    (setq lns (org-do-sort lns "Table" with-case sorting-type getkey-func compare-func))
     (when org-table-overlay-coordinates
       (org-table-toggle-coordinate-overlays))
     (delete-region beg end)
diff --git a/lisp/org.el b/lisp/org.el
index bed5cb9..23f5b07 100755
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -9051,21 +9051,27 @@ When sorting is done, call `org-after-sorting-entries-or-items-hook'."
 	(move-marker org-clock-marker (point))))
     (message "Sorting entries...done")))
 
-(defun org-do-sort (table what &optional with-case sorting-type)
+(defun org-do-sort (table what &optional with-case sorting-type getkey-func compare-func)
   "Sort TABLE of WHAT according to SORTING-TYPE.
 The user will be prompted for the SORTING-TYPE if the call to this
 function does not specify it.
 WHAT is only for the prompt, to indicate what is being sorted.
 The sorting key will be extracted from the car of the elements of
-the table.
-If WITH-CASE is non-nil, the sorting will be case-sensitive."
+the table. If WITH-CASE is non-nil, the sorting will be case-sensitive.
+
+If the SORTING-TYPE is ?f or ?F, then GETKEY-FUNC specifies
+a function to be called to extract the key.  It must return either
+a string or a number that should serve as the sorting key for that
+row.  It will then use COMPARE-FUNC to compare entries.  If GETKEY-FUNC
+is specified interactively, the comparison will be either a string or
+numeric compare based on the type of the first key in the table."
   (unless sorting-type
     (message
-     "Sort %s: [a]lphabetic, [n]umeric, [t]ime.  A/N/T means reversed:"
+     "Sort %s: [a]lphabetic, [n]umeric, [t]ime, [f]unc.  A/N/T/F means reversed:"
      what)
     (setq sorting-type (read-char-exclusive)))
   (let ((dcst (downcase sorting-type))
-	extractfun comparefun)
+	extractfun comparefun tempfun extract-string-p)
     ;; Define the appropriate functions
     (cond
      ((= dcst ?n)
@@ -9075,7 +9081,7 @@ If WITH-CASE is non-nil, the sorting will be case-sensitive."
       (setq extractfun (if with-case (lambda(x) (org-sort-remove-invisible x))
 			 (lambda(x) (downcase (org-sort-remove-invisible x))))
 	    comparefun (if (= dcst sorting-type)
-			   'string<
+			   #'string<
 			 (lambda (a b) (and (not (string< a b))
 					    (not (string= a b)))))))
      ((= dcst ?t)
@@ -9089,6 +9095,24 @@ If WITH-CASE is non-nil, the sorting will be case-sensitive."
 		     (org-hh:mm-string-to-minutes x))
 		    (t 0)))
 	    comparefun (if (= dcst sorting-type) '< '>)))
+     ((= dcst ?f)
+      (setq tempfun (or getkey-func
+			(intern (org-icompleting-read
+				 "Sort using function: "
+				 obarray 'fboundp t nil nil))))
+      (setq extract-string-p (stringp (funcall tempfun (caar table))))
+      (setq extractfun (if (and extract-string-p (not with-case))
+			   (lambda (x) (downcase (funcall tempfun x)))
+			 tempfun))
+      (setq comparefun (or compare-func
+			   (if extract-string-p 
+			       (if (= sorting-type ?f)
+				   #'string<
+				 (lambda (a b) (and (not (string< a b))
+						    (not (string= a b)))))
+			     (if (= sorting-type ?f)
+				 #'<
+			       #'>)))))
      (t (error "Invalid sorting type `%c'" sorting-type)))
 
     (sort (mapcar (lambda (x) (cons (funcall extractfun (car x)) (cdr x)))
-- 
1.9.3 (Apple Git-50)


[-- Attachment #2: Message signed with OpenPGP using GPGMail --]
[-- Type: application/pgp-signature, Size: 841 bytes --]

  reply	other threads:[~2014-12-17 17:32 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-12-09 19:16 Patch to implement sorting Org tables by IP address Jon Snader
2014-12-12 22:58 ` Nicolas Goaziou
2014-12-13 14:19   ` Jon Snader
2014-12-13 14:29     ` Nicolas Goaziou
2014-12-13 15:19       ` Jon Snader
2014-12-13 16:01         ` Nicolas Goaziou
2014-12-13 18:47           ` Jon Snader
2014-12-13 22:07             ` Nicolas Goaziou
2014-12-13 22:37               ` Jon Snader
2014-12-14 11:25                 ` Nicolas Goaziou
2014-12-14 15:19                   ` Jon Snader
2014-12-14 17:18                     ` Nicolas Goaziou
2014-12-17 17:31                       ` Jon Snader [this message]
2014-12-20 11:57                         ` Nicolas Goaziou
2014-12-20 18:40                           ` Jon Snader
2014-12-20 20:55                             ` Nicolas Goaziou

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=ABF84C2E-2C3A-4C5F-9FCF-582D3B551319@mac.com \
    --to=jsnader@mac.com \
    --cc=emacs-orgmode@gnu.org \
    --cc=mail@nicolasgoaziou.fr \
    /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).