emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
* Adding single cell movement to org-table
@ 2017-07-27 20:20 Chris Kauffman
  2017-07-28  8:19 ` Nicolas Goaziou
  2017-07-28  8:53 ` Carsten Dominik
  0 siblings, 2 replies; 11+ messages in thread
From: Chris Kauffman @ 2017-07-27 20:20 UTC (permalink / raw)
  To: emacs-orgmode; +Cc: Uwe Brauer

[-- Attachment #1: Type: text/plain, Size: 965 bytes --]

Greetings from a first-time contributor. Another patch contributor, Uwe
Brauer, recruited me after finding some code I had written to move single
org-table cells up/down/left/right.  I found this feature to be useful in
certain kinds of tables so wrote the functions for myself but am told that
others might benefit from it.

I have formalized that code into a git repo with a feature branch on it
which may be found here:
  https://github.com/kauffman77/org-mode/tree/single-cell-table-move

I have included documentation in org-table.el for the new functions and
tests for them.  If further work or documentation needs to be done, please
let me know. I am also not sure if I got the commit messages formatted to
the specification mentioned on the contributing page.  I am happy to
explain more if needed.

I just mailed assign@gnu.org to get the copyright for the code resolved but
thought I would put up this branch now so others can have a look.

Cheers,
Chris

[-- Attachment #2: Type: text/html, Size: 1226 bytes --]

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

* Re: Adding single cell movement to org-table
  2017-07-27 20:20 Adding single cell movement to org-table Chris Kauffman
@ 2017-07-28  8:19 ` Nicolas Goaziou
  2017-07-29  3:00   ` Chris Kauffman
  2017-07-28  8:53 ` Carsten Dominik
  1 sibling, 1 reply; 11+ messages in thread
From: Nicolas Goaziou @ 2017-07-28  8:19 UTC (permalink / raw)
  To: Chris Kauffman; +Cc: Uwe Brauer, emacs-orgmode

Hello,

Chris Kauffman <kauffman@cs.gmu.edu> writes:

> Greetings from a first-time contributor. Another patch contributor, Uwe
> Brauer, recruited me after finding some code I had written to move single
> org-table cells up/down/left/right.  I found this feature to be useful in
> certain kinds of tables so wrote the functions for myself but am told that
> others might benefit from it.
>
> I have formalized that code into a git repo with a feature branch on it
> which may be found here:
>   https://github.com/kauffman77/org-mode/tree/single-cell-table-move
>
> I have included documentation in org-table.el for the new functions and
> tests for them.  If further work or documentation needs to be done, please
> let me know. I am also not sure if I got the commit messages formatted to
> the specification mentioned on the contributing page.  I am happy to
> explain more if needed.

Thank you. 

Could you send the patch here? It will ease reviewing it.

It will also require an entry in ORG-NEWS and some documentation in
org.texi.

> I just mailed assign@gnu.org to get the copyright for the code resolved but
> thought I would put up this branch now so others can have a look.

Great!

Regards,

-- 
Nicolas Goaziou

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

* Re: Adding single cell movement to org-table
  2017-07-27 20:20 Adding single cell movement to org-table Chris Kauffman
  2017-07-28  8:19 ` Nicolas Goaziou
@ 2017-07-28  8:53 ` Carsten Dominik
  1 sibling, 0 replies; 11+ messages in thread
From: Carsten Dominik @ 2017-07-28  8:53 UTC (permalink / raw)
  To: Chris Kauffman; +Cc: Uwe Brauer, org-mode list

[-- Attachment #1: Type: text/plain, Size: 1226 bytes --]

Hi Chris,

I really like this functionality, thank you!

Has there been a discussion about a possible key binding for this feature?

Carsten

On Thu, Jul 27, 2017 at 10:20 PM, Chris Kauffman <kauffman@cs.gmu.edu>
wrote:

> Greetings from a first-time contributor. Another patch contributor, Uwe
> Brauer, recruited me after finding some code I had written to move single
> org-table cells up/down/left/right.  I found this feature to be useful in
> certain kinds of tables so wrote the functions for myself but am told that
> others might benefit from it.
>
> I have formalized that code into a git repo with a feature branch on it
> which may be found here:
>   https://github.com/kauffman77/org-mode/tree/single-cell-table-move
>
> I have included documentation in org-table.el for the new functions and
> tests for them.  If further work or documentation needs to be done, please
> let me know. I am also not sure if I got the commit messages formatted to
> the specification mentioned on the contributing page.  I am happy to
> explain more if needed.
>
> I just mailed assign@gnu.org to get the copyright for the code resolved
> but thought I would put up this branch now so others can have a look.
>
> Cheers,
> Chris
>

[-- Attachment #2: Type: text/html, Size: 1855 bytes --]

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

* Re: Adding single cell movement to org-table
  2017-07-28  8:19 ` Nicolas Goaziou
@ 2017-07-29  3:00   ` Chris Kauffman
  2017-08-03 10:37     ` Nicolas Goaziou
  0 siblings, 1 reply; 11+ messages in thread
From: Chris Kauffman @ 2017-07-29  3:00 UTC (permalink / raw)
  To: Nicolas Goaziou; +Cc: Uwe Brauer, emacs-orgmode


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

Apologies for the earlier diff-blast: I did not see the advice on the
org-mode contributions page that patches generated via
  git format-patch master
are preferred.  Please find four patches attached which now include
modifications to ORG-NEWS, org.texi, orgguid.texi, and keybindings
suggested by Carsten: S-up, S-down, S-left, S-right in org.el (via
org-shiftup etc.).

Cheers,
Chris


On Fri, Jul 28, 2017 at 4:19 AM, Nicolas Goaziou <mail@nicolasgoaziou.fr>
wrote:

> Hello,
>
> Chris Kauffman <kauffman@cs.gmu.edu> writes:
>
> > Greetings from a first-time contributor. Another patch contributor, Uwe
> > Brauer, recruited me after finding some code I had written to move single
> > org-table cells up/down/left/right.  I found this feature to be useful in
> > certain kinds of tables so wrote the functions for myself but am told
> that
> > others might benefit from it.
> >
> > I have formalized that code into a git repo with a feature branch on it
> > which may be found here:
> >   https://github.com/kauffman77/org-mode/tree/single-cell-table-move
> >
> > I have included documentation in org-table.el for the new functions and
> > tests for them.  If further work or documentation needs to be done,
> please
> > let me know. I am also not sure if I got the commit messages formatted to
> > the specification mentioned on the contributing page.  I am happy to
> > explain more if needed.
>
> Thank you.
>
> Could you send the patch here? It will ease reviewing it.
>
> It will also require an entry in ORG-NEWS and some documentation in
> org.texi.
>
> > I just mailed assign@gnu.org to get the copyright for the code resolved
> but
> > thought I would put up this branch now so others can have a look.
>
> Great!
>
> Regards,
>
> --
> Nicolas Goaziou
>

[-- Attachment #1.2: Type: text/html, Size: 2606 bytes --]

[-- Attachment #2: 0005-Modified-orgguide.texi-to-include-documentation-of-s.patch --]
[-- Type: text/x-patch, Size: 849 bytes --]

From b43054c9892f7e08fa958bcb5d8df978e6392d57 Mon Sep 17 00:00:00 2001
From: Chris Kauffman <kauffman@ecs.gmu.edu>
Date: Fri, 28 Jul 2017 22:46:12 -0400
Subject: [PATCH 5/5] Modified orgguide.texi to include documentation of single
 cell movement functions.

---
 doc/orgguide.texi | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/doc/orgguide.texi b/doc/orgguide.texi
index 8c91aae3a..fc5c0c22c 100644
--- a/doc/orgguide.texi
+++ b/doc/orgguide.texi
@@ -647,6 +647,12 @@ Re-align, move to previous field.
 @item @key{RET}
 Re-align the table and move down to next row.  Creates a new row if
 necessary.
+@c
+@item S-@key{up}
+@itemx S-@key{down}
+@itemx S-@key{left}
+@itemx S-@key{right}
+Move single cells up, down, left, and right by swapping with adjacent cells.
 
 @tsubheading{Column and row editing}
 @item M-@key{left}
-- 
2.12.2


[-- Attachment #3: 0004-Modified-org.texi-to-include-documentation-of-single.patch --]
[-- Type: text/x-patch, Size: 1125 bytes --]

From 6682b22642c34f61feee27cd44a503dd4c21e9cb Mon Sep 17 00:00:00 2001
From: Chris Kauffman <kauffman@ecs.gmu.edu>
Date: Fri, 28 Jul 2017 22:37:31 -0400
Subject: [PATCH 4/5] Modified org.texi to include documentation of single cell
 movement functions.

---
 doc/org.texi | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/doc/org.texi b/doc/org.texi
index 101d532e3..55c8ebd27 100644
--- a/doc/org.texi
+++ b/doc/org.texi
@@ -2156,6 +2156,12 @@ NEWLINE, so it can be used to split a table.
 Move to beginning of the current table field, or on to the previous field.
 @orgcmd{M-e,org-table-end-of-field}
 Move to end of the current table field, or on to the next field.
+@c
+@orgcmd{S-@key{up},org-table-move-single-cell-up}
+@orgcmd{S-@key{down},org-table-move-single-cell-down}
+@orgcmd{S-@key{left},org-table-move-single-cell-left}
+@orgcmd{S-@key{right},org-table-move-single-cell-right}
+Move single cells up, down, left, and right by swapping with adjacent cells.
 
 @tsubheading{Column and row editing}
 @orgcmdkkcc{M-@key{left},M-@key{right},org-table-move-column-left,org-table-move-column-right}
-- 
2.12.2


[-- Attachment #4: 0003-Updates-to-ORG-NEWS-describing-single-cell-movement-.patch --]
[-- Type: text/x-patch, Size: 1516 bytes --]

From 6be32b39c590d003be75a33033bb3301a11db483 Mon Sep 17 00:00:00 2001
From: Chris Kauffman <kauffman@ecs.gmu.edu>
Date: Fri, 28 Jul 2017 22:18:28 -0400
Subject: [PATCH 3/5] Updates to ORG-NEWS describing single-cell movement
 functions.

---
 etc/ORG-NEWS | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS
index d7bd3e2ce..05efce4f4 100644
--- a/etc/ORG-NEWS
+++ b/etc/ORG-NEWS
@@ -291,6 +291,11 @@ This variable allow computed durations in tables to be zero-padded.
 *** New mode switch for table formulas : =U=
 This mode omits seconds in durations.
 
+*** New single table cell movement options : ~org-table-move-single-cell-up~
+Shift-Up, Shift-Down, Shift-Right, and Shift-Left now move single
+table cells in the corresponding directions by swapping with the
+adjacent cell.
+
 ** Removed functions
 
 *** Org Timeline
@@ -368,6 +373,21 @@ It is the reciprocal of ~org-list-to-lisp~, which see.
 
 Call ~org-agenda-set-restriction-lock~ from the agenda.
 
+*** ~org-table-move-single-cell~ and related
+
+Four new user functions to move single table cells in cardinal
+directions.
+
+- ~org-table-move-single-cell-up~
+- ~org-table-move-single-cell-down~
+- ~org-table-move-single-cell-left~
+- ~org-table-move-single-cell-right~
+
+Support functions which are used to facilitate single cell movement.
+- ~org-table-move-single-cell~ 
+- ~org-table-swap-cells~ 
+- ~org-table-max-line-col~
+
 ** Miscellaneous
 
 *** Allow multiple columns view
-- 
2.12.2


[-- Attachment #5: 0002-Added-keybindings-for-org-table-move-single-cell-fun.patch --]
[-- Type: text/x-patch, Size: 4606 bytes --]

From 9c900805937ebc21d468612d1c594381cca53cd2 Mon Sep 17 00:00:00 2001
From: Chris Kauffman <kauffman@ecs.gmu.edu>
Date: Fri, 28 Jul 2017 22:06:05 -0400
Subject: [PATCH 2/5] Added keybindings for org-table-move-single-cell-*
 functions: S-up, S-down, etc. Done via modifications to org-shiftup,
 org-shiftdown, etc.  Dispatching at the end of available contexts between
 behavior for clock table and function hooks.

---
 lisp/org.el | 21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)

diff --git a/lisp/org.el b/lisp/org.el
index 44abc0dbe..fc740bdca 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -20477,8 +20477,10 @@ commands for more information."
 
 (defun org-shiftup (&optional arg)
   "Increase item in timestamp or increase priority of current headline.
-Calls `org-timestamp-up' or `org-priority-up', or `org-previous-item',
-depending on context.  See the individual commands for more information."
+Calls `org-timestamp-up' or `org-priority-up', or
+`org-previous-item', or `org-table-move-single-cell-up',
+depending on context.  See the individual commands for more
+information."
   (interactive "P")
   (cond
    ((run-hook-with-args-until-success 'org-shiftup-hook))
@@ -20494,6 +20496,7 @@ depending on context.  See the individual commands for more information."
    ((and (not org-support-shift-select) (org-at-item-p))
     (call-interactively 'org-previous-item))
    ((org-clocktable-try-shift 'up arg))
+   ((org-at-table-p) (org-table-move-single-cell-up))
    ((run-hook-with-args-until-success 'org-shiftup-final-hook))
    (org-support-shift-select
     (org-call-for-shift-select 'previous-line))
@@ -20501,8 +20504,9 @@ depending on context.  See the individual commands for more information."
 
 (defun org-shiftdown (&optional arg)
   "Decrease item in timestamp or decrease priority of current headline.
-Calls `org-timestamp-down' or `org-priority-down', or `org-next-item'
-depending on context.  See the individual commands for more information."
+Calls `org-timestamp-down' or `org-priority-down', or
+`org-next-item', or `org-table-move-single-cell-down', depending
+on context.  See the individual commands for more information."
   (interactive "P")
   (cond
    ((run-hook-with-args-until-success 'org-shiftdown-hook))
@@ -20518,6 +20522,7 @@ depending on context.  See the individual commands for more information."
    ((and (not org-support-shift-select) (org-at-item-p))
     (call-interactively 'org-next-item))
    ((org-clocktable-try-shift 'down arg))
+   ((org-at-table-p) (org-table-move-single-cell-down))
    ((run-hook-with-args-until-success 'org-shiftdown-final-hook))
    (org-support-shift-select
     (org-call-for-shift-select 'next-line))
@@ -20531,7 +20536,8 @@ Depending on context, this does one of the following:
 - on a headline, switch to the next TODO keyword.
 - on an item, switch entire list to the next bullet type
 - on a property line, switch to the next allowed value
-- on a clocktable definition line, move time block into the future"
+- on a clocktable definition line, move time block into the future
+- on a normal table, move a single cell right"
   (interactive "P")
   (cond
    ((run-hook-with-args-until-success 'org-shiftright-hook))
@@ -20554,6 +20560,7 @@ Depending on context, this does one of the following:
 	 (org-at-property-p))
     (call-interactively 'org-property-next-allowed-value))
    ((org-clocktable-try-shift 'right arg))
+   ((org-at-table-p) (org-table-move-single-cell-right))
    ((run-hook-with-args-until-success 'org-shiftright-final-hook))
    (org-support-shift-select
     (org-call-for-shift-select 'forward-char))
@@ -20567,7 +20574,8 @@ Depending on context, this does one of the following:
 - on a headline, switch to the previous TODO keyword.
 - on an item, switch entire list to the previous bullet type
 - on a property line, switch to the previous allowed value
-- on a clocktable definition line, move time block into the past"
+- on a clocktable definition line, move time block into the past
+- on a normal table, move a single cell left"
   (interactive "P")
   (cond
    ((run-hook-with-args-until-success 'org-shiftleft-hook))
@@ -20590,6 +20598,7 @@ Depending on context, this does one of the following:
 	 (org-at-property-p))
     (call-interactively 'org-property-previous-allowed-value))
    ((org-clocktable-try-shift 'left arg))
+   ((org-at-table-p) (org-table-move-single-cell-left))
    ((run-hook-with-args-until-success 'org-shiftleft-final-hook))
    (org-support-shift-select
     (org-call-for-shift-select 'backward-char))
-- 
2.12.2


[-- Attachment #6: 0001-org-table-Adding-single-cell-movement-functions-and-.patch --]
[-- Type: text/x-patch, Size: 16529 bytes --]

From 6f50526fa642ea74716dd4668e2b36b0ff9c6134 Mon Sep 17 00:00:00 2001
From: Chris Kauffman <kauffman@ecs.gmu.edu>
Date: Sun, 23 Jul 2017 00:13:11 -0400
Subject: [PATCH 1/5] org-table: Adding single cell movement functions and
 tests.

* org-mode/lisp/org-table.el: New functions for single table cell
  movement such as (org-table-move-single-cell-down)
* testing/lisp/test-org-table.el: Added tests for single table cell
  movement such as (test-org-table/move-single-cell-down)
---
 lisp/org-table.el              |  71 ++++++++
 testing/lisp/test-org-table.el | 385 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 456 insertions(+)

diff --git a/lisp/org-table.el b/lisp/org-table.el
index 37e40de1e..2b80bfc3a 100644
--- a/lisp/org-table.el
+++ b/lisp/org-table.el
@@ -1437,6 +1437,77 @@ non-nil, the one above is used."
 	       (if above min max))))))
 
 ;;;###autoload
+(defun org-table-max-line-col ()
+  "Return the maximum line and column of the current table as a
+list of two numbers"
+  (when (not (org-at-table-p))
+    (user-error "Not in an org-table"))
+  (let ((table-end (org-table-end)))
+    (save-mark-and-excursion
+     (goto-char table-end)
+     (org-table-previous-field)
+     (list (org-table-current-line) (org-table-current-column)))))
+
+;;;###autoload
+(defun org-table-swap-cells (row1 col1 row2 col2)
+  "Swap two cells indicated by the coordinates provided"
+  (let ((content1 (org-table-get row1 col1))
+	(content2 (org-table-get row2 col2)))
+    (org-table-put row1 col1 content2)
+    (org-table-put row2 col2 content1)
+    (org-table-align)))
+
+;;;###autoload
+(defun org-table-move-single-cell (direction)
+  "Move the current cell in a cardinal direction according to the
+parameter symbol: 'up 'down 'left 'right. Swaps contents of
+adjacent cell with current one."
+  (unless (org-at-table-p)
+    (error "No table at point"))
+  (let ((drow 0) (dcol 0))
+    (cond ((equal direction 'up)    (setq drow -1))
+	  ((equal direction 'down)  (setq drow +1))
+	  ((equal direction 'left)  (setq dcol -1))
+	  ((equal direction 'right) (setq dcol +1))
+	  (t (error "Not a valid direction, must be one of 'up 'down 'left 'right")))
+    (let* ((row1 (org-table-current-line))
+	   (col1 (org-table-current-column))
+	   (row2 (+ row1 drow))
+	   (col2 (+ col1 dcol))
+	   (max-row-col (org-table-max-line-col))
+	   (max-row (car max-row-col))
+	   (max-col (cadr max-row-col)))
+      (when (or (< col1 1) (< col2 1) (> col2 max-col) (< row2 1) (> row2 max-row))
+	(user-error "Cannot move cell further"))
+      (org-table-swap-cells row1 col1 row2 col2)
+      (org-table-goto-line row2)
+      (org-table-goto-column col2))))
+
+;;;###autoload
+(defun org-table-move-single-cell-up ()
+  "Move a single cell up in a table; swap with anything in target cell"
+  (interactive)
+  (org-table-move-single-cell 'up))
+
+;;;###autoload
+(defun org-table-move-single-cell-down ()
+  "Move a single cell down in a table; swap with anything in target cell"
+  (interactive)
+  (org-table-move-single-cell 'down))
+
+;;;###autoload
+(defun org-table-move-single-cell-left ()
+  "Move a single cell left in a table; swap with anything in target cell"
+  (interactive)
+  (org-table-move-single-cell 'left))
+
+;;;###autoload
+(defun org-table-move-single-cell-right ()
+  "Move a single cell right in a table; swap with anything in target cell"
+  (interactive)
+  (org-table-move-single-cell 'right))
+	
+;;;###autoload
 (defun org-table-delete-column ()
   "Delete a column from the table."
   (interactive)
diff --git a/testing/lisp/test-org-table.el b/testing/lisp/test-org-table.el
index 99f593c25..de9a1ad4b 100644
--- a/testing/lisp/test-org-table.el
+++ b/testing/lisp/test-org-table.el
@@ -2102,6 +2102,391 @@ is t, then new columns should be added as needed"
 
 
 \f
+;;; Moving single cells
+(ert-deftest test-org-table/move-single-cell-down ()
+  "Test `org-table-move-single-cell-down' specifications."
+  ;; Error out when cell cannot be moved due to not in table,
+  ;; in the last row of the table, or is on a hline
+  (should-error
+   (org-test-with-temp-text "not in\na table\n"
+     (org-table-move-single-cell-down)))
+  (should-error
+   (org-test-with-temp-text "| a |"
+     (org-table-move-single-cell-down)))
+  (should-error
+   (org-test-with-temp-text "| a |\n"
+     (org-table-move-single-cell-down)))
+  (should-error
+   (org-test-with-temp-text "| a | <point>b |\n"
+     (org-table-move-single-cell-down)))
+  (should-error
+   (org-test-with-temp-text "| a | b |\n| <point>c | d |\n"
+     (org-table-move-single-cell-down)))
+  (should-error
+   (org-test-with-temp-text "| a | b |\n| c | <point>d |\n"
+     (org-table-move-single-cell-down)))
+  (should-error
+   (org-test-with-temp-text "| <point>a |\n|---|\n"
+     (org-table-move-single-cell-down)))
+  (should-error
+   (org-test-with-temp-text "|<point>---|\n| a |\n"
+     (org-table-move-single-cell-down)))
+  ;; Check for correct cell movement
+  (should (equal (concat "| c | b |\n"
+			 "| a | d |\n"
+			 "| e | f |\n")
+		 (org-test-with-temp-text
+		     (concat "| <point>a | b |\n"
+			     "| c | d |\n"
+			     "| e | f |\n")
+		   (org-table-move-single-cell-down)
+		   (buffer-string))))
+  (should (equal (concat "| a | d |\n"
+			 "| c | b |\n"
+			 "| e | f |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | <point>b |\n"
+			     "| c | d |\n"
+			     "| e | f |\n")
+		   (org-table-move-single-cell-down)
+		   (buffer-string))))
+  (should (equal (concat "| a | b |\n"
+			 "| e | d |\n"
+			 "| c | f |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b |\n"
+			     "| <point>c | d |\n"
+			     "| e | f |\n")
+		   (org-table-move-single-cell-down)
+		   (buffer-string))))
+  (should (equal (concat "| a | d |\n"
+			 "| c | f |\n"
+			 "| e | b |\n")
+		 (org-test-with-temp-text
+		     (concat "| a |<point> b |\n"
+			     "| c | d |\n"
+			     "| e | f |\n")
+		   (org-table-move-single-cell-down)
+		   (org-table-move-single-cell-down)
+		   (buffer-string))))
+  ;; Check for correct handling of hlines which should not change
+  ;; position on single cell moves
+  (should (equal (concat "| c | b |\n"
+			 "|---+---|\n"
+			 "| a | d |\n"
+			 "| e | f |\n")
+		 (org-test-with-temp-text
+		     (concat "| <point>a | b |\n"
+			     "|---+---|\n"
+			     "| c | d |\n"
+			     "| e | f |\n")
+		   (org-table-move-single-cell-down)
+		   (buffer-string))))
+  (should (equal (concat "| a | d |\n"
+			 "|---+---|\n"
+			 "| c | f |\n"
+			 "| e | b |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | <point>b |\n"
+			     "|---+---|\n"
+			     "| c | d |\n"
+			     "| e | f |\n")
+		   (org-table-move-single-cell-down)
+		   (org-table-move-single-cell-down)
+		   (buffer-string))))
+  (should (equal (concat "| a | b |\n"
+			 "|---+---|\n"
+			 "| c | f |\n"
+			 "| e | d |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b |\n"
+			     "|---+---|\n"
+			     "| c | <point>d |\n"
+			     "| e | f |\n")
+		   (org-table-move-single-cell-down)
+		   (buffer-string))))
+
+  ;; Move single cell even without a final newline. Seems that some
+  (should (equal (concat "| a | d |\n"
+			 "|---+---|\n"
+			 "| c | f |\n"
+			 "| e | b |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | <point>b |\n"
+			     "|---+---|\n"
+			     "| c | d |\n"
+			     "| e | f |")
+		   (org-table-move-single-cell-down)
+		   (org-table-move-single-cell-down)
+		   (buffer-string)))))
+(ert-deftest test-org-table/move-single-cell-up ()
+  "Test `org-table-move-single-cell-up' specifications."
+  ;; Error out when cell cannot be moved due to not in table,
+  ;; in the last row of the table, or is on a hline
+  (should-error
+   (org-test-with-temp-text "not in\na table\n"
+     (org-table-move-single-cell-up)))
+  (should-error
+   (org-test-with-temp-text "| a |"
+     (org-table-move-single-cell-up)))
+  (should-error
+   (org-test-with-temp-text "| a |\n"
+     (org-table-move-single-cell-up)))
+  (should-error
+   (org-test-with-temp-text "| <point>a | b |\n"
+     (org-table-move-single-cell-up)))
+  (should-error
+   (org-test-with-temp-text "| a | <point>b |\n| c | d |\n"
+     (org-table-move-single-cell-up)))
+  (should-error
+   (org-test-with-temp-text "| <point>a |\n|---|\n"
+     (org-table-move-single-cell-up)))
+  (should-error
+   (org-test-with-temp-text "|<point>---|\n| a |\n"
+     (org-table-move-single-cell-up)))
+  ;; Check for correct cell movement
+  (should (equal (concat "| c | b |\n"
+			 "| a | d |\n"
+			 "| e | f |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b |\n"
+			     "| <point>c | d |\n"
+			     "| e | f |\n")
+		   (org-table-move-single-cell-up)
+		   (buffer-string))))
+  (should (equal (concat "| a | d |\n"
+			 "| c | b |\n"
+			 "| e | f |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b |\n"
+			     "| c | <point>d |\n"
+			     "| e | f |\n")
+		   (org-table-move-single-cell-up)
+		   (buffer-string))))
+  (should (equal (concat "| a | b |\n"
+			 "| e | d |\n"
+			 "| c | f |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b |\n"
+			     "| c | d |\n"
+			     "| <point>e | f |\n")
+		   (org-table-move-single-cell-up)
+		   (buffer-string))))
+  (should (equal (concat "| a | f |\n"
+			 "| c | b |\n"
+			 "| e | d |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b |\n"
+			     "| c | d |\n"
+			     "| e |<point> f |\n")
+		   (org-table-move-single-cell-up)
+		   (org-table-move-single-cell-up)
+		   (buffer-string))))
+  ;; Check for correct handling of hlines which should not change
+  ;; position on single cell moves
+  (should (equal (concat "| c | b |\n"
+			 "|---+---|\n"
+			 "| a | d |\n"
+			 "| e | f |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b |\n"
+			     "|---+---|\n"
+			     "| <point>c | d |\n"
+			     "| e | f |\n")
+		   (org-table-move-single-cell-up)
+		   (buffer-string))))
+  (should (equal (concat "| a | f |\n"
+			 "|---+---|\n"
+			 "| c | b |\n"
+			 "| e | d |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b |\n"
+			     "|---+---|\n"
+			     "| c | d |\n"
+			     "| e | <point>f |\n")
+		   (org-table-move-single-cell-up)
+		   (org-table-move-single-cell-up)
+		   (buffer-string))))
+  (should (equal (concat "| a | b |\n"
+			 "|---+---|\n"
+			 "| c | f |\n"
+			 "| e | d |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b |\n"
+			     "|---+---|\n"
+			     "| c | d |\n"
+			     "| e | <point>f |\n")
+		   (org-table-move-single-cell-up)
+		   (buffer-string))))
+
+  ;; Move single cell even without a final newline. Seems that some
+  (should (equal (concat "| a | f |\n"
+			 "|---+---|\n"
+			 "| c | b |\n"
+			 "| e | d |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b |\n"
+			     "|---+---|\n"
+			     "| c | d |\n"
+			     "| e | <point>f |")
+		   (org-table-move-single-cell-up)
+		   (org-table-move-single-cell-up)
+		   (buffer-string)))))
+(ert-deftest test-org-table/move-single-cell-right ()
+  "Test `org-table-move-single-cell-right' specifications."
+  ;; Error out when cell cannot be moved due to not in table,
+  ;; in the last col of the table, or is on a hline
+  (should-error
+   (org-test-with-temp-text "not in\na table\n"
+     (org-table-move-single-cell-right)))
+  (should-error
+   (org-test-with-temp-text "| a |"
+     (org-table-move-single-cell-right)))
+  (should-error
+   (org-test-with-temp-text "| a |\n"
+     (org-table-move-single-cell-right)))
+  (should-error
+   (org-test-with-temp-text "| <point>a |\n| b |\n"
+     (org-table-move-single-cell-right)))
+  (should-error
+   (org-test-with-temp-text "| a | <point>b |\n| c | d |\n"
+     (org-table-move-single-cell-right)))
+  (should-error
+   (org-test-with-temp-text "| <point>a |\n|---|\n"
+     (org-table-move-single-cell-right)))
+  (should-error
+   (org-test-with-temp-text "|<point>---|\n| a |\n"
+     (org-table-move-single-cell-right)))
+  ;; Check for correct cell movement
+  (should (equal (concat "| b | a | c |\n"
+			 "| d | e | f |\n")
+		 (org-test-with-temp-text
+		     (concat "| <point>a | b | c |\n"
+			     "| d | e | f |\n")
+		   (org-table-move-single-cell-right)
+		   (buffer-string))))
+  (should (equal (concat "| b | c | a |\n"
+			 "| d | e | f |\n")
+		 (org-test-with-temp-text
+		     (concat "| <point>a | b | c |\n"
+			     "| d | e | f |\n")
+		   (org-table-move-single-cell-right)
+		   (org-table-move-single-cell-right)
+		   (buffer-string))))
+  (should (equal (concat "| a | b | c |\n"
+			 "| e | f | d |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b | c |\n"
+			     "| <point> d | e | f |\n")
+		   (org-table-move-single-cell-right)
+		   (org-table-move-single-cell-right)
+		   (buffer-string))))
+  (should (equal (concat "| a | b | c |\n"
+			 "| d | f | e |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b | c |\n"
+			     "| d | <point>e | f |\n")
+		   (org-table-move-single-cell-right)
+		   (buffer-string))))
+  (should (equal (concat "| a | b | c |\n"
+			 "|---+---+---|\n"
+			 "| e | f | d |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b | c |\n"
+			     "|---+---+---|\n"
+			     "| <point>d | e | f |\n")
+		   (org-table-move-single-cell-right)
+		   (org-table-move-single-cell-right)
+		   (buffer-string))))
+  ;; Move single cell even without a final newline. Seems that some
+  (should (equal (concat "| a | b | c |\n"
+			 "|---+---+---|\n"
+			 "| e | d | f |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b | c |\n"
+			     "|---+---+---|\n"
+			     "| <point>d | e | f |")
+		   (org-table-move-single-cell-right)
+		   (buffer-string)))))
+(ert-deftest test-org-table/move-single-cell-left ()
+  "Test `org-table-move-single-cell-left' specifications."
+  ;; Error out when cell cannot be moved due to not in table,
+  ;; in the last col of the table, or is on a hline
+  (should-error
+   (org-test-with-temp-text "not in\na table\n"
+     (org-table-move-single-cell-left)))
+  (should-error
+   (org-test-with-temp-text "| a |"
+     (org-table-move-single-cell-left)))
+  (should-error
+   (org-test-with-temp-text "| a |\n"
+     (org-table-move-single-cell-left)))
+  (should-error
+   (org-test-with-temp-text "| <point>a |\n| b |\n"
+     (org-table-move-single-cell-left)))
+  (should-error
+   (org-test-with-temp-text "| <point>a | b |\n| c | d |\n"
+     (org-table-move-single-cell-left)))
+  (should-error
+   (org-test-with-temp-text "| <point>a |\n|---|\n"
+     (org-table-move-single-cell-left)))
+  (should-error
+   (org-test-with-temp-text "|<point>---|\n| a |\n"
+     (org-table-move-single-cell-left)))
+  ;; Check for correct cell movement
+  (should (equal (concat "| b | a | c |\n"
+			 "| d | e | f |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | <point>b | c |\n"
+			     "| d | e | f |\n")
+		   (org-table-move-single-cell-left)
+		   (buffer-string))))
+  (should (equal (concat "| c | a | b |\n"
+			 "| d | e | f |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b | <point>c |\n"
+			     "| d | e | f |\n")
+		   (org-table-move-single-cell-left)
+		   (org-table-move-single-cell-left)
+		   (buffer-string))))
+  (should (equal (concat "| a | b | c |\n"
+			 "| f | d | e |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b | c |\n"
+			     "| d | e | <point>f |\n")
+		   (org-table-move-single-cell-left)
+		   (org-table-move-single-cell-left)
+		   (buffer-string))))
+  (should (equal (concat "| a | b | c |\n"
+			 "| d | f | e |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b | c |\n"
+			     "| d | e | <point>f |\n")
+		   (org-table-move-single-cell-left)
+		   (buffer-string))))
+  (should (equal (concat "| a | b | c |\n"
+			 "|---+---+---|\n"
+			 "| f | d | e |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b | c |\n"
+			     "|---+---+---|\n"
+			     "| d | e | <point>f |\n")
+		   (org-table-move-single-cell-left)
+		   (org-table-move-single-cell-left)
+		   (buffer-string))))
+  ;; Move single cell even without a final newline. Seems that some
+  (should (equal (concat "| a | b | c |\n"
+			 "|---+---+---|\n"
+			 "| e | d | f |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b | c |\n"
+			     "|---+---+---|\n"
+			     "| d | <point>e | f |")
+		   (org-table-move-single-cell-left)
+		   (buffer-string))))
+  )
+
+\f
 ;;; Moving rows, moving columns
 
 (ert-deftest test-org-table/move-row-down ()
-- 
2.12.2


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

* Re: Adding single cell movement to org-table
  2017-07-29  3:00   ` Chris Kauffman
@ 2017-08-03 10:37     ` Nicolas Goaziou
  2018-05-04 12:29       ` stardiviner
  0 siblings, 1 reply; 11+ messages in thread
From: Nicolas Goaziou @ 2017-08-03 10:37 UTC (permalink / raw)
  To: Chris Kauffman; +Cc: Uwe Brauer, emacs-orgmode

Hello,

Chris Kauffman <kauffman@cs.gmu.edu> writes:

> Apologies for the earlier diff-blast: I did not see the advice on the
> org-mode contributions page that patches generated via
>   git format-patch master
> are preferred.  Please find four patches attached which now include
> modifications to ORG-NEWS, org.texi, orgguid.texi, and keybindings
> suggested by Carsten: S-up, S-down, S-left, S-right in org.el (via
> org-shiftup etc.).

Thank you! Some comments follow.

>  ;;;###autoload
> +(defun org-table-max-line-col ()
> +  "Return the maximum line and column of the current table as a
> +list of two numbers"
> +  (when (not (org-at-table-p))
> +    (user-error "Not in an org-table"))
> +  (let ((table-end (org-table-end)))
> +    (save-mark-and-excursion
> +     (goto-char table-end)
> +     (org-table-previous-field)
> +     (list (org-table-current-line) (org-table-current-column)))))

I don't think this function is necessary. There is already a similar
mechanism with `org-table-current-ncol' and `org-table-current-dlines'.
Besides, you only need to check if point is within the table, which is
trivial:

  (skip-chars-backward " \t")
  (or (bolp) (looking-at-p "[ \t]*$"))

for the row, `org-table-goto-line' returns nil if there is no such line.

> +;;;###autoload
> +(defun org-table-swap-cells (row1 col1 row2 col2)
> +  "Swap two cells indicated by the coordinates provided"

Final dot missing. ROW1 COL1 ROW2 COL2 should be explained.

> +  (let ((content1 (org-table-get row1 col1))
> +	(content2 (org-table-get row2 col2)))
> +    (org-table-put row1 col1 content2)
> +    (org-table-put row2 col2 content1)
> +    (org-table-align)))

This function can be made internal: no need to autoload it, and rename
it as `org-table--swap-cells'. Besides, it shouldn't call
`org-table-align', which is out of its scope.

> +;;;###autoload
> +(defun org-table-move-single-cell (direction)
> +  "Move the current cell in a cardinal direction according to the

First line should be a sentence on its own.

DIRECTION should be more explicit in the docstring.

> +parameter symbol: 'up 'down 'left 'right. Swaps contents of

`up', `down', `left' or `right'.

Also, mind the two spaces after a full stop.

> +adjacent cell with current one."
> +  (unless (org-at-table-p)
> +    (error "No table at point"))
> +  (let ((drow 0) (dcol 0))
> +    (cond ((equal direction 'up)    (setq drow -1))
> +	  ((equal direction 'down)  (setq drow +1))
> +	  ((equal direction 'left)  (setq dcol -1))
> +	  ((equal direction 'right) (setq dcol +1))
> +	  (t (error "Not a valid direction, must be one of 'up 'down 'left 'right")))
> +    (let* ((row1 (org-table-current-line))
> +	   (col1 (org-table-current-column))
> +	   (row2 (+ row1 drow))
> +	   (col2 (+ col1 dcol))
> +	   (max-row-col (org-table-max-line-col))
> +	   (max-row (car max-row-col))
> +	   (max-col (cadr max-row-col)))
> +      (when (or (< col1 1) (< col2 1) (> col2 max-col) (< row2 1) (> row2 max-row))
> +	(user-error "Cannot move cell further"))
> +      (org-table-swap-cells row1 col1 row2 col2)
> +      (org-table-goto-line row2)
> +      (org-table-goto-column col2))))

This should be an internal function: `org-table--move-single-cell', and
not autoloaded.

As an internal function, there is no need to check for `org-at-table-p'.
It's the responsibility of the callers to do so. Also,
`org-table-check-inside-data-field' is more appropriate here.

> +;;;###autoload
> +(defun org-table-move-single-cell-up ()
> +  "Move a single cell up in a table; swap with anything in target cell"

Missing final full stop.

> +  (interactive)
> +  (org-table-move-single-cell 'up))

Per above, I suggest adding (org-table-check-inside-data-field) after
the (interactive). The same goes for the other functions.

Could you send an updated patch?

Regards,

-- 
Nicolas Goaziou                                                0x80A93738

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

* Re: Adding single cell movement to org-table
  2017-08-03 10:37     ` Nicolas Goaziou
@ 2018-05-04 12:29       ` stardiviner
  2018-05-04 14:04         ` Chris Kauffman
  0 siblings, 1 reply; 11+ messages in thread
From: stardiviner @ 2018-05-04 12:29 UTC (permalink / raw)
  To: Nicolas Goaziou; +Cc: Chris Kauffman, emacs-orgmode, Uwe Brauer

Hi, dear Nicolas. Is this patch merged or not?
I "git log --grep 'cell'", have not found this commit.
Does this patch move single cell or move single row/column?
Currently, Org-mode built-in movement support for row and column only.

-- 
[ stardiviner ] don't need to convince with trends.
       Blog: https://stardiviner.github.io/
       IRC(freenode): stardiviner
       GPG: F09F650D7D674819892591401B5DF1C95AE89AC3
      

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

* Re: Adding single cell movement to org-table
  2018-05-04 12:29       ` stardiviner
@ 2018-05-04 14:04         ` Chris Kauffman
  2018-05-04 14:31           ` Uwe Brauer
  2018-05-05  0:18           ` stardiviner
  0 siblings, 2 replies; 11+ messages in thread
From: Chris Kauffman @ 2018-05-04 14:04 UTC (permalink / raw)
  To: numbchild; +Cc: Uwe Brauer, emacs-orgmode, Nicolas Goaziou

[-- Attachment #1: Type: text/plain, Size: 1288 bytes --]

I was the original person who was working on code for single cell movement
but got distracted by a move to the midwest, job change, and marriage. I
will attempt to complete the code in the next month to submit a patch.

Chris Kauffman

On Fri, May 4, 2018 at 7:29 AM, stardiviner <numbchild@gmail.com> wrote:

> Hi, dear Nicolas. Is this patch merged or not?
> I "git log --grep 'cell'", have not found this commit.
> Does this patch move single cell or move single row/column?
> Currently, Org-mode built-in movement support for row and column only.
>
> --
> [ stardiviner ] don't need to convince with trends.
>        Blog: https://secure-web.cisco.com/1sdj-
> xZLR6NqcfmWcqPL8xws9NwGLGIqxtf3bLvpn-RTcdJC0NapZkgAE_S_L7_
> 7FQ8W1k3rTbTZzLaYAAiRF8n8fIQJT5s0Sr-4G3n3a-hyOiksPjPSA_1BnaCm-
> Fg7Amnwx2bB5F9wCuHrxtDhxEHh6RXVg03NeXnLzw_YjFaS8w5gvnhWqSIy9hZvn6aOWvlkP
> Dy1hes_WNng6C3Qxy6ihxmpaPnSxvogd_rE1Ze31NZLD9Sv78ivAZwFmVIo7XHM
> oqs7veAKqUQC34vVSTuuFOHTYwq6owLfaqIjwmM0PfF0pwhisMsEg9TUH_q11NPRKZmq_
> QDFgqNXgPAjptiFrPBU1l9t4IUw_Bv9YCoAoqT7ZLERUfLPj_
> 9osdz3g18A6DgpJuCUNJBlInzsqGSP5zv6-v7yXKRFHr61Q24_z0nNUeUzMneqeCHpRL13-
> i7admqXNqD-HAlBD1WxP1g/https%3A%2F%2Fstardiviner.github.io%2F
>        IRC(freenode): stardiviner
>        GPG: F09F650D7D674819892591401B5DF1C95AE89AC3
>
>
>

[-- Attachment #2: Type: text/html, Size: 2418 bytes --]

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

* Re: Adding single cell movement to org-table
  2018-05-04 14:04         ` Chris Kauffman
@ 2018-05-04 14:31           ` Uwe Brauer
  2018-05-05  0:18           ` stardiviner
  1 sibling, 0 replies; 11+ messages in thread
From: Uwe Brauer @ 2018-05-04 14:31 UTC (permalink / raw)
  To: Chris Kauffman; +Cc: Uwe Brauer, emacs-orgmode, Nicolas Goaziou

[-- Attachment #1: Type: text/plain, Size: 373 bytes --]

>>> "Chris" == Chris Kauffman <kauffman@cs.gmu.edu> writes:

   > I was the original person who was working on code for single cell movement
   > but got distracted by a move to the midwest, job change, and marriage. I
   > will attempt to complete the code in the next month to submit a patch.

All very good reasons, especially the last one! All the best to both of you.

[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 5025 bytes --]

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

* Re: Adding single cell movement to org-table
  2018-05-04 14:04         ` Chris Kauffman
  2018-05-04 14:31           ` Uwe Brauer
@ 2018-05-05  0:18           ` stardiviner
  2018-05-29 20:29             ` Chris Kauffman
  1 sibling, 1 reply; 11+ messages in thread
From: stardiviner @ 2018-05-05  0:18 UTC (permalink / raw)
  To: Chris Kauffman; +Cc: Uwe Brauer, emacs-orgmode, Nicolas Goaziou

That's really great. Thanks.

-- 
[ stardiviner ] don't need to convince with trends.
       Blog: https://stardiviner.github.io/
       IRC(freenode): stardiviner
       GPG: F09F650D7D674819892591401B5DF1C95AE89AC3
      

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

* Re: Adding single cell movement to org-table
  2018-05-05  0:18           ` stardiviner
@ 2018-05-29 20:29             ` Chris Kauffman
  2018-06-13 13:35               ` Nicolas Goaziou
  0 siblings, 1 reply; 11+ messages in thread
From: Chris Kauffman @ 2018-05-29 20:29 UTC (permalink / raw)
  To: 路Ricardo M.; +Cc: Uwe Brauer, emacs-orgmode, Nicolas Goaziou


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

All-

Attached are the updated patches for single cell movement in org tables.

Notes:
- Implemented all of Nicolas Goaziou's suggestions on this with some
caveats described below

- Part of the logic of the code requires boundary checking. I used the
(org-table-analyze) to set variables org-table-current-ncol and
org-table-dlines which are the limits of the table. This eliminated an
internal helper function in the original version.

- I made several of the functions internal with the naming convention
`org-table--name' as per Nicolas' suggestion

- Checks for in-table and table alignment are in the top-level functions
`org-table-move-single-cell-up' etc.; I kept alignment in as otherwise the
table looks awful as cells move around

- Modified org.el to bind these to Shift-up and the like as per Carsten's
suggestion

- Tests defined in testing/lisp/org-test-table.el and I've done a fair
amount of interactive testing to ensure the behavior looks correct.

- Not sure if the patches will work exactly correctly due to the large gap
in time between my initial work and completion; let me know if things don't
look correct.

- Attempted to get close to a correctly formatted commit messages but do
make any necessary formatting changes for compliance.

Cheers,
Chris Kauffman

On Fri, May 4, 2018 at 7:18 PM, stardiviner <numbchild@gmail.com> wrote:

> That's really great. Thanks.
>
> --
> [ stardiviner ] don't need to convince with trends.
>        Blog: https://secure-web.cisco.com/1hJRqsuxlpwmP971H8dAeGulRNSKNY
> 87qhElIE0kGFNVU8wi5u2jTzEhayLSBa8GhYPZPyxSM3aWcEqi0yTtMPyedB
> ey2od2ROikNbAYTnTptEFLNGp6HovNx1ukbSykVmN4jthKPhqhL-
> zPqBtiblX6c8EibrNqBfI2YR_DfuTSNew8YeBmyRu0Mr_
> et5PfrTaMoyrIurSC1ogXRXRMh8ds6CXnNjU7bhWZeOcjRQfyLbssZQ-
> zuRp5pSm2JMyC0h7QmqikJC6pNGBrSYPaxd37aLkMNyqhF6LyEpq2LrpWkms4s56sq9R4_
> MUrvT16dpqMPPcp1pfA1DAaPt0DBOlZIDWuieyVZSmscuGyWN6hhiYyTc0EY-_
> iwmxe0UCfRK4t0adbHcAj0cYCdGjgliGOk9jHInQTGngBOSNT_htY/https%
> 3A%2F%2Fstardiviner.github.io%2F
>        IRC(freenode): stardiviner
>        GPG: F09F650D7D674819892591401B5DF1C95AE89AC3
>
>
>

[-- Attachment #1.2: Type: text/html, Size: 3360 bytes --]

[-- Attachment #2: 0001-org-table-Adding-single-cell-movement-functions-and-.patch --]
[-- Type: text/x-patch, Size: 16530 bytes --]

From 6f50526fa642ea74716dd4668e2b36b0ff9c6134 Mon Sep 17 00:00:00 2001
From: Chris Kauffman <kauffman@ecs.gmu.edu>
Date: Sun, 23 Jul 2017 00:13:11 -0400
Subject: [PATCH 1/8] org-table: Adding single cell movement functions and
 tests.

* org-mode/lisp/org-table.el: New functions for single table cell
  movement such as (org-table-move-single-cell-down)
* testing/lisp/test-org-table.el: Added tests for single table cell
  movement such as (test-org-table/move-single-cell-down)
---
 lisp/org-table.el              |  71 ++++++
 testing/lisp/test-org-table.el | 385 +++++++++++++++++++++++++++++++++
 2 files changed, 456 insertions(+)

diff --git a/lisp/org-table.el b/lisp/org-table.el
index 37e40de1e..2b80bfc3a 100644
--- a/lisp/org-table.el
+++ b/lisp/org-table.el
@@ -1436,6 +1436,77 @@ non-nil, the one above is used."
 			 (t (setq min mean)))))
 	       (if above min max))))))
 
+;;;###autoload
+(defun org-table-max-line-col ()
+  "Return the maximum line and column of the current table as a
+list of two numbers"
+  (when (not (org-at-table-p))
+    (user-error "Not in an org-table"))
+  (let ((table-end (org-table-end)))
+    (save-mark-and-excursion
+     (goto-char table-end)
+     (org-table-previous-field)
+     (list (org-table-current-line) (org-table-current-column)))))
+
+;;;###autoload
+(defun org-table-swap-cells (row1 col1 row2 col2)
+  "Swap two cells indicated by the coordinates provided"
+  (let ((content1 (org-table-get row1 col1))
+	(content2 (org-table-get row2 col2)))
+    (org-table-put row1 col1 content2)
+    (org-table-put row2 col2 content1)
+    (org-table-align)))
+
+;;;###autoload
+(defun org-table-move-single-cell (direction)
+  "Move the current cell in a cardinal direction according to the
+parameter symbol: 'up 'down 'left 'right. Swaps contents of
+adjacent cell with current one."
+  (unless (org-at-table-p)
+    (error "No table at point"))
+  (let ((drow 0) (dcol 0))
+    (cond ((equal direction 'up)    (setq drow -1))
+	  ((equal direction 'down)  (setq drow +1))
+	  ((equal direction 'left)  (setq dcol -1))
+	  ((equal direction 'right) (setq dcol +1))
+	  (t (error "Not a valid direction, must be one of 'up 'down 'left 'right")))
+    (let* ((row1 (org-table-current-line))
+	   (col1 (org-table-current-column))
+	   (row2 (+ row1 drow))
+	   (col2 (+ col1 dcol))
+	   (max-row-col (org-table-max-line-col))
+	   (max-row (car max-row-col))
+	   (max-col (cadr max-row-col)))
+      (when (or (< col1 1) (< col2 1) (> col2 max-col) (< row2 1) (> row2 max-row))
+	(user-error "Cannot move cell further"))
+      (org-table-swap-cells row1 col1 row2 col2)
+      (org-table-goto-line row2)
+      (org-table-goto-column col2))))
+
+;;;###autoload
+(defun org-table-move-single-cell-up ()
+  "Move a single cell up in a table; swap with anything in target cell"
+  (interactive)
+  (org-table-move-single-cell 'up))
+
+;;;###autoload
+(defun org-table-move-single-cell-down ()
+  "Move a single cell down in a table; swap with anything in target cell"
+  (interactive)
+  (org-table-move-single-cell 'down))
+
+;;;###autoload
+(defun org-table-move-single-cell-left ()
+  "Move a single cell left in a table; swap with anything in target cell"
+  (interactive)
+  (org-table-move-single-cell 'left))
+
+;;;###autoload
+(defun org-table-move-single-cell-right ()
+  "Move a single cell right in a table; swap with anything in target cell"
+  (interactive)
+  (org-table-move-single-cell 'right))
+	
 ;;;###autoload
 (defun org-table-delete-column ()
   "Delete a column from the table."
diff --git a/testing/lisp/test-org-table.el b/testing/lisp/test-org-table.el
index 99f593c25..de9a1ad4b 100644
--- a/testing/lisp/test-org-table.el
+++ b/testing/lisp/test-org-table.el
@@ -2102,6 +2102,391 @@ is t, then new columns should be added as needed"
 
 
 \f
+;;; Moving single cells
+(ert-deftest test-org-table/move-single-cell-down ()
+  "Test `org-table-move-single-cell-down' specifications."
+  ;; Error out when cell cannot be moved due to not in table,
+  ;; in the last row of the table, or is on a hline
+  (should-error
+   (org-test-with-temp-text "not in\na table\n"
+     (org-table-move-single-cell-down)))
+  (should-error
+   (org-test-with-temp-text "| a |"
+     (org-table-move-single-cell-down)))
+  (should-error
+   (org-test-with-temp-text "| a |\n"
+     (org-table-move-single-cell-down)))
+  (should-error
+   (org-test-with-temp-text "| a | <point>b |\n"
+     (org-table-move-single-cell-down)))
+  (should-error
+   (org-test-with-temp-text "| a | b |\n| <point>c | d |\n"
+     (org-table-move-single-cell-down)))
+  (should-error
+   (org-test-with-temp-text "| a | b |\n| c | <point>d |\n"
+     (org-table-move-single-cell-down)))
+  (should-error
+   (org-test-with-temp-text "| <point>a |\n|---|\n"
+     (org-table-move-single-cell-down)))
+  (should-error
+   (org-test-with-temp-text "|<point>---|\n| a |\n"
+     (org-table-move-single-cell-down)))
+  ;; Check for correct cell movement
+  (should (equal (concat "| c | b |\n"
+			 "| a | d |\n"
+			 "| e | f |\n")
+		 (org-test-with-temp-text
+		     (concat "| <point>a | b |\n"
+			     "| c | d |\n"
+			     "| e | f |\n")
+		   (org-table-move-single-cell-down)
+		   (buffer-string))))
+  (should (equal (concat "| a | d |\n"
+			 "| c | b |\n"
+			 "| e | f |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | <point>b |\n"
+			     "| c | d |\n"
+			     "| e | f |\n")
+		   (org-table-move-single-cell-down)
+		   (buffer-string))))
+  (should (equal (concat "| a | b |\n"
+			 "| e | d |\n"
+			 "| c | f |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b |\n"
+			     "| <point>c | d |\n"
+			     "| e | f |\n")
+		   (org-table-move-single-cell-down)
+		   (buffer-string))))
+  (should (equal (concat "| a | d |\n"
+			 "| c | f |\n"
+			 "| e | b |\n")
+		 (org-test-with-temp-text
+		     (concat "| a |<point> b |\n"
+			     "| c | d |\n"
+			     "| e | f |\n")
+		   (org-table-move-single-cell-down)
+		   (org-table-move-single-cell-down)
+		   (buffer-string))))
+  ;; Check for correct handling of hlines which should not change
+  ;; position on single cell moves
+  (should (equal (concat "| c | b |\n"
+			 "|---+---|\n"
+			 "| a | d |\n"
+			 "| e | f |\n")
+		 (org-test-with-temp-text
+		     (concat "| <point>a | b |\n"
+			     "|---+---|\n"
+			     "| c | d |\n"
+			     "| e | f |\n")
+		   (org-table-move-single-cell-down)
+		   (buffer-string))))
+  (should (equal (concat "| a | d |\n"
+			 "|---+---|\n"
+			 "| c | f |\n"
+			 "| e | b |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | <point>b |\n"
+			     "|---+---|\n"
+			     "| c | d |\n"
+			     "| e | f |\n")
+		   (org-table-move-single-cell-down)
+		   (org-table-move-single-cell-down)
+		   (buffer-string))))
+  (should (equal (concat "| a | b |\n"
+			 "|---+---|\n"
+			 "| c | f |\n"
+			 "| e | d |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b |\n"
+			     "|---+---|\n"
+			     "| c | <point>d |\n"
+			     "| e | f |\n")
+		   (org-table-move-single-cell-down)
+		   (buffer-string))))
+
+  ;; Move single cell even without a final newline. Seems that some
+  (should (equal (concat "| a | d |\n"
+			 "|---+---|\n"
+			 "| c | f |\n"
+			 "| e | b |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | <point>b |\n"
+			     "|---+---|\n"
+			     "| c | d |\n"
+			     "| e | f |")
+		   (org-table-move-single-cell-down)
+		   (org-table-move-single-cell-down)
+		   (buffer-string)))))
+(ert-deftest test-org-table/move-single-cell-up ()
+  "Test `org-table-move-single-cell-up' specifications."
+  ;; Error out when cell cannot be moved due to not in table,
+  ;; in the last row of the table, or is on a hline
+  (should-error
+   (org-test-with-temp-text "not in\na table\n"
+     (org-table-move-single-cell-up)))
+  (should-error
+   (org-test-with-temp-text "| a |"
+     (org-table-move-single-cell-up)))
+  (should-error
+   (org-test-with-temp-text "| a |\n"
+     (org-table-move-single-cell-up)))
+  (should-error
+   (org-test-with-temp-text "| <point>a | b |\n"
+     (org-table-move-single-cell-up)))
+  (should-error
+   (org-test-with-temp-text "| a | <point>b |\n| c | d |\n"
+     (org-table-move-single-cell-up)))
+  (should-error
+   (org-test-with-temp-text "| <point>a |\n|---|\n"
+     (org-table-move-single-cell-up)))
+  (should-error
+   (org-test-with-temp-text "|<point>---|\n| a |\n"
+     (org-table-move-single-cell-up)))
+  ;; Check for correct cell movement
+  (should (equal (concat "| c | b |\n"
+			 "| a | d |\n"
+			 "| e | f |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b |\n"
+			     "| <point>c | d |\n"
+			     "| e | f |\n")
+		   (org-table-move-single-cell-up)
+		   (buffer-string))))
+  (should (equal (concat "| a | d |\n"
+			 "| c | b |\n"
+			 "| e | f |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b |\n"
+			     "| c | <point>d |\n"
+			     "| e | f |\n")
+		   (org-table-move-single-cell-up)
+		   (buffer-string))))
+  (should (equal (concat "| a | b |\n"
+			 "| e | d |\n"
+			 "| c | f |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b |\n"
+			     "| c | d |\n"
+			     "| <point>e | f |\n")
+		   (org-table-move-single-cell-up)
+		   (buffer-string))))
+  (should (equal (concat "| a | f |\n"
+			 "| c | b |\n"
+			 "| e | d |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b |\n"
+			     "| c | d |\n"
+			     "| e |<point> f |\n")
+		   (org-table-move-single-cell-up)
+		   (org-table-move-single-cell-up)
+		   (buffer-string))))
+  ;; Check for correct handling of hlines which should not change
+  ;; position on single cell moves
+  (should (equal (concat "| c | b |\n"
+			 "|---+---|\n"
+			 "| a | d |\n"
+			 "| e | f |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b |\n"
+			     "|---+---|\n"
+			     "| <point>c | d |\n"
+			     "| e | f |\n")
+		   (org-table-move-single-cell-up)
+		   (buffer-string))))
+  (should (equal (concat "| a | f |\n"
+			 "|---+---|\n"
+			 "| c | b |\n"
+			 "| e | d |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b |\n"
+			     "|---+---|\n"
+			     "| c | d |\n"
+			     "| e | <point>f |\n")
+		   (org-table-move-single-cell-up)
+		   (org-table-move-single-cell-up)
+		   (buffer-string))))
+  (should (equal (concat "| a | b |\n"
+			 "|---+---|\n"
+			 "| c | f |\n"
+			 "| e | d |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b |\n"
+			     "|---+---|\n"
+			     "| c | d |\n"
+			     "| e | <point>f |\n")
+		   (org-table-move-single-cell-up)
+		   (buffer-string))))
+
+  ;; Move single cell even without a final newline. Seems that some
+  (should (equal (concat "| a | f |\n"
+			 "|---+---|\n"
+			 "| c | b |\n"
+			 "| e | d |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b |\n"
+			     "|---+---|\n"
+			     "| c | d |\n"
+			     "| e | <point>f |")
+		   (org-table-move-single-cell-up)
+		   (org-table-move-single-cell-up)
+		   (buffer-string)))))
+(ert-deftest test-org-table/move-single-cell-right ()
+  "Test `org-table-move-single-cell-right' specifications."
+  ;; Error out when cell cannot be moved due to not in table,
+  ;; in the last col of the table, or is on a hline
+  (should-error
+   (org-test-with-temp-text "not in\na table\n"
+     (org-table-move-single-cell-right)))
+  (should-error
+   (org-test-with-temp-text "| a |"
+     (org-table-move-single-cell-right)))
+  (should-error
+   (org-test-with-temp-text "| a |\n"
+     (org-table-move-single-cell-right)))
+  (should-error
+   (org-test-with-temp-text "| <point>a |\n| b |\n"
+     (org-table-move-single-cell-right)))
+  (should-error
+   (org-test-with-temp-text "| a | <point>b |\n| c | d |\n"
+     (org-table-move-single-cell-right)))
+  (should-error
+   (org-test-with-temp-text "| <point>a |\n|---|\n"
+     (org-table-move-single-cell-right)))
+  (should-error
+   (org-test-with-temp-text "|<point>---|\n| a |\n"
+     (org-table-move-single-cell-right)))
+  ;; Check for correct cell movement
+  (should (equal (concat "| b | a | c |\n"
+			 "| d | e | f |\n")
+		 (org-test-with-temp-text
+		     (concat "| <point>a | b | c |\n"
+			     "| d | e | f |\n")
+		   (org-table-move-single-cell-right)
+		   (buffer-string))))
+  (should (equal (concat "| b | c | a |\n"
+			 "| d | e | f |\n")
+		 (org-test-with-temp-text
+		     (concat "| <point>a | b | c |\n"
+			     "| d | e | f |\n")
+		   (org-table-move-single-cell-right)
+		   (org-table-move-single-cell-right)
+		   (buffer-string))))
+  (should (equal (concat "| a | b | c |\n"
+			 "| e | f | d |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b | c |\n"
+			     "| <point> d | e | f |\n")
+		   (org-table-move-single-cell-right)
+		   (org-table-move-single-cell-right)
+		   (buffer-string))))
+  (should (equal (concat "| a | b | c |\n"
+			 "| d | f | e |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b | c |\n"
+			     "| d | <point>e | f |\n")
+		   (org-table-move-single-cell-right)
+		   (buffer-string))))
+  (should (equal (concat "| a | b | c |\n"
+			 "|---+---+---|\n"
+			 "| e | f | d |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b | c |\n"
+			     "|---+---+---|\n"
+			     "| <point>d | e | f |\n")
+		   (org-table-move-single-cell-right)
+		   (org-table-move-single-cell-right)
+		   (buffer-string))))
+  ;; Move single cell even without a final newline. Seems that some
+  (should (equal (concat "| a | b | c |\n"
+			 "|---+---+---|\n"
+			 "| e | d | f |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b | c |\n"
+			     "|---+---+---|\n"
+			     "| <point>d | e | f |")
+		   (org-table-move-single-cell-right)
+		   (buffer-string)))))
+(ert-deftest test-org-table/move-single-cell-left ()
+  "Test `org-table-move-single-cell-left' specifications."
+  ;; Error out when cell cannot be moved due to not in table,
+  ;; in the last col of the table, or is on a hline
+  (should-error
+   (org-test-with-temp-text "not in\na table\n"
+     (org-table-move-single-cell-left)))
+  (should-error
+   (org-test-with-temp-text "| a |"
+     (org-table-move-single-cell-left)))
+  (should-error
+   (org-test-with-temp-text "| a |\n"
+     (org-table-move-single-cell-left)))
+  (should-error
+   (org-test-with-temp-text "| <point>a |\n| b |\n"
+     (org-table-move-single-cell-left)))
+  (should-error
+   (org-test-with-temp-text "| <point>a | b |\n| c | d |\n"
+     (org-table-move-single-cell-left)))
+  (should-error
+   (org-test-with-temp-text "| <point>a |\n|---|\n"
+     (org-table-move-single-cell-left)))
+  (should-error
+   (org-test-with-temp-text "|<point>---|\n| a |\n"
+     (org-table-move-single-cell-left)))
+  ;; Check for correct cell movement
+  (should (equal (concat "| b | a | c |\n"
+			 "| d | e | f |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | <point>b | c |\n"
+			     "| d | e | f |\n")
+		   (org-table-move-single-cell-left)
+		   (buffer-string))))
+  (should (equal (concat "| c | a | b |\n"
+			 "| d | e | f |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b | <point>c |\n"
+			     "| d | e | f |\n")
+		   (org-table-move-single-cell-left)
+		   (org-table-move-single-cell-left)
+		   (buffer-string))))
+  (should (equal (concat "| a | b | c |\n"
+			 "| f | d | e |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b | c |\n"
+			     "| d | e | <point>f |\n")
+		   (org-table-move-single-cell-left)
+		   (org-table-move-single-cell-left)
+		   (buffer-string))))
+  (should (equal (concat "| a | b | c |\n"
+			 "| d | f | e |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b | c |\n"
+			     "| d | e | <point>f |\n")
+		   (org-table-move-single-cell-left)
+		   (buffer-string))))
+  (should (equal (concat "| a | b | c |\n"
+			 "|---+---+---|\n"
+			 "| f | d | e |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b | c |\n"
+			     "|---+---+---|\n"
+			     "| d | e | <point>f |\n")
+		   (org-table-move-single-cell-left)
+		   (org-table-move-single-cell-left)
+		   (buffer-string))))
+  ;; Move single cell even without a final newline. Seems that some
+  (should (equal (concat "| a | b | c |\n"
+			 "|---+---+---|\n"
+			 "| e | d | f |\n")
+		 (org-test-with-temp-text
+		     (concat "| a | b | c |\n"
+			     "|---+---+---|\n"
+			     "| d | <point>e | f |")
+		   (org-table-move-single-cell-left)
+		   (buffer-string))))
+  )
+
+\f
 ;;; Moving rows, moving columns
 
 (ert-deftest test-org-table/move-row-down ()
-- 
2.17.0


[-- Attachment #3: 0002-Added-keybindings-for-org-table-move-single-cell-fun.patch --]
[-- Type: text/x-patch, Size: 4606 bytes --]

From 9c900805937ebc21d468612d1c594381cca53cd2 Mon Sep 17 00:00:00 2001
From: Chris Kauffman <kauffman@ecs.gmu.edu>
Date: Fri, 28 Jul 2017 22:06:05 -0400
Subject: [PATCH 2/8] Added keybindings for org-table-move-single-cell-*
 functions: S-up, S-down, etc. Done via modifications to org-shiftup,
 org-shiftdown, etc.  Dispatching at the end of available contexts between
 behavior for clock table and function hooks.

---
 lisp/org.el | 21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)

diff --git a/lisp/org.el b/lisp/org.el
index 44abc0dbe..fc740bdca 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -20477,8 +20477,10 @@ commands for more information."
 
 (defun org-shiftup (&optional arg)
   "Increase item in timestamp or increase priority of current headline.
-Calls `org-timestamp-up' or `org-priority-up', or `org-previous-item',
-depending on context.  See the individual commands for more information."
+Calls `org-timestamp-up' or `org-priority-up', or
+`org-previous-item', or `org-table-move-single-cell-up',
+depending on context.  See the individual commands for more
+information."
   (interactive "P")
   (cond
    ((run-hook-with-args-until-success 'org-shiftup-hook))
@@ -20494,6 +20496,7 @@ depending on context.  See the individual commands for more information."
    ((and (not org-support-shift-select) (org-at-item-p))
     (call-interactively 'org-previous-item))
    ((org-clocktable-try-shift 'up arg))
+   ((org-at-table-p) (org-table-move-single-cell-up))
    ((run-hook-with-args-until-success 'org-shiftup-final-hook))
    (org-support-shift-select
     (org-call-for-shift-select 'previous-line))
@@ -20501,8 +20504,9 @@ depending on context.  See the individual commands for more information."
 
 (defun org-shiftdown (&optional arg)
   "Decrease item in timestamp or decrease priority of current headline.
-Calls `org-timestamp-down' or `org-priority-down', or `org-next-item'
-depending on context.  See the individual commands for more information."
+Calls `org-timestamp-down' or `org-priority-down', or
+`org-next-item', or `org-table-move-single-cell-down', depending
+on context.  See the individual commands for more information."
   (interactive "P")
   (cond
    ((run-hook-with-args-until-success 'org-shiftdown-hook))
@@ -20518,6 +20522,7 @@ depending on context.  See the individual commands for more information."
    ((and (not org-support-shift-select) (org-at-item-p))
     (call-interactively 'org-next-item))
    ((org-clocktable-try-shift 'down arg))
+   ((org-at-table-p) (org-table-move-single-cell-down))
    ((run-hook-with-args-until-success 'org-shiftdown-final-hook))
    (org-support-shift-select
     (org-call-for-shift-select 'next-line))
@@ -20531,7 +20536,8 @@ Depending on context, this does one of the following:
 - on a headline, switch to the next TODO keyword.
 - on an item, switch entire list to the next bullet type
 - on a property line, switch to the next allowed value
-- on a clocktable definition line, move time block into the future"
+- on a clocktable definition line, move time block into the future
+- on a normal table, move a single cell right"
   (interactive "P")
   (cond
    ((run-hook-with-args-until-success 'org-shiftright-hook))
@@ -20554,6 +20560,7 @@ Depending on context, this does one of the following:
 	 (org-at-property-p))
     (call-interactively 'org-property-next-allowed-value))
    ((org-clocktable-try-shift 'right arg))
+   ((org-at-table-p) (org-table-move-single-cell-right))
    ((run-hook-with-args-until-success 'org-shiftright-final-hook))
    (org-support-shift-select
     (org-call-for-shift-select 'forward-char))
@@ -20567,7 +20574,8 @@ Depending on context, this does one of the following:
 - on a headline, switch to the previous TODO keyword.
 - on an item, switch entire list to the previous bullet type
 - on a property line, switch to the previous allowed value
-- on a clocktable definition line, move time block into the past"
+- on a clocktable definition line, move time block into the past
+- on a normal table, move a single cell left"
   (interactive "P")
   (cond
    ((run-hook-with-args-until-success 'org-shiftleft-hook))
@@ -20590,6 +20598,7 @@ Depending on context, this does one of the following:
 	 (org-at-property-p))
     (call-interactively 'org-property-previous-allowed-value))
    ((org-clocktable-try-shift 'left arg))
+   ((org-at-table-p) (org-table-move-single-cell-left))
    ((run-hook-with-args-until-success 'org-shiftleft-final-hook))
    (org-support-shift-select
     (org-call-for-shift-select 'backward-char))
-- 
2.17.0


[-- Attachment #4: 0003-Updates-to-ORG-NEWS-describing-single-cell-movement-.patch --]
[-- Type: text/x-patch, Size: 1516 bytes --]

From 6be32b39c590d003be75a33033bb3301a11db483 Mon Sep 17 00:00:00 2001
From: Chris Kauffman <kauffman@ecs.gmu.edu>
Date: Fri, 28 Jul 2017 22:18:28 -0400
Subject: [PATCH 3/8] Updates to ORG-NEWS describing single-cell movement
 functions.

---
 etc/ORG-NEWS | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS
index d7bd3e2ce..05efce4f4 100644
--- a/etc/ORG-NEWS
+++ b/etc/ORG-NEWS
@@ -291,6 +291,11 @@ This variable allow computed durations in tables to be zero-padded.
 *** New mode switch for table formulas : =U=
 This mode omits seconds in durations.
 
+*** New single table cell movement options : ~org-table-move-single-cell-up~
+Shift-Up, Shift-Down, Shift-Right, and Shift-Left now move single
+table cells in the corresponding directions by swapping with the
+adjacent cell.
+
 ** Removed functions
 
 *** Org Timeline
@@ -368,6 +373,21 @@ It is the reciprocal of ~org-list-to-lisp~, which see.
 
 Call ~org-agenda-set-restriction-lock~ from the agenda.
 
+*** ~org-table-move-single-cell~ and related
+
+Four new user functions to move single table cells in cardinal
+directions.
+
+- ~org-table-move-single-cell-up~
+- ~org-table-move-single-cell-down~
+- ~org-table-move-single-cell-left~
+- ~org-table-move-single-cell-right~
+
+Support functions which are used to facilitate single cell movement.
+- ~org-table-move-single-cell~ 
+- ~org-table-swap-cells~ 
+- ~org-table-max-line-col~
+
 ** Miscellaneous
 
 *** Allow multiple columns view
-- 
2.17.0


[-- Attachment #5: 0004-Modified-org.texi-to-include-documentation-of-single.patch --]
[-- Type: text/x-patch, Size: 1125 bytes --]

From 6682b22642c34f61feee27cd44a503dd4c21e9cb Mon Sep 17 00:00:00 2001
From: Chris Kauffman <kauffman@ecs.gmu.edu>
Date: Fri, 28 Jul 2017 22:37:31 -0400
Subject: [PATCH 4/8] Modified org.texi to include documentation of single cell
 movement functions.

---
 doc/org.texi | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/doc/org.texi b/doc/org.texi
index 101d532e3..55c8ebd27 100644
--- a/doc/org.texi
+++ b/doc/org.texi
@@ -2156,6 +2156,12 @@ NEWLINE, so it can be used to split a table.
 Move to beginning of the current table field, or on to the previous field.
 @orgcmd{M-e,org-table-end-of-field}
 Move to end of the current table field, or on to the next field.
+@c
+@orgcmd{S-@key{up},org-table-move-single-cell-up}
+@orgcmd{S-@key{down},org-table-move-single-cell-down}
+@orgcmd{S-@key{left},org-table-move-single-cell-left}
+@orgcmd{S-@key{right},org-table-move-single-cell-right}
+Move single cells up, down, left, and right by swapping with adjacent cells.
 
 @tsubheading{Column and row editing}
 @orgcmdkkcc{M-@key{left},M-@key{right},org-table-move-column-left,org-table-move-column-right}
-- 
2.17.0


[-- Attachment #6: 0005-Modified-orgguide.texi-to-include-documentation-of-s.patch --]
[-- Type: text/x-patch, Size: 849 bytes --]

From b43054c9892f7e08fa958bcb5d8df978e6392d57 Mon Sep 17 00:00:00 2001
From: Chris Kauffman <kauffman@ecs.gmu.edu>
Date: Fri, 28 Jul 2017 22:46:12 -0400
Subject: [PATCH 5/8] Modified orgguide.texi to include documentation of single
 cell movement functions.

---
 doc/orgguide.texi | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/doc/orgguide.texi b/doc/orgguide.texi
index 8c91aae3a..fc5c0c22c 100644
--- a/doc/orgguide.texi
+++ b/doc/orgguide.texi
@@ -647,6 +647,12 @@ Re-align, move to previous field.
 @item @key{RET}
 Re-align the table and move down to next row.  Creates a new row if
 necessary.
+@c
+@item S-@key{up}
+@itemx S-@key{down}
+@itemx S-@key{left}
+@itemx S-@key{right}
+Move single cells up, down, left, and right by swapping with adjacent cells.
 
 @tsubheading{Column and row editing}
 @item M-@key{left}
-- 
2.17.0


[-- Attachment #7: 0006-Code-changes-for-single-cell-movement-with-notes.patch --]
[-- Type: text/x-patch, Size: 7332 bytes --]

From 4f5a8ae4eaed79b52b5f3529102611e06577e439 Mon Sep 17 00:00:00 2001
From: Chris Kauffman <kauffman77@gmail.com>
Date: Tue, 29 May 2018 14:37:24 -0500
Subject: [PATCH 6/8] Code changes for single-cell movement with notes.

This version has some remaining contents and commented code.
---
 doc/org-manual.org        | 24 ++++++++++
 lisp/org-table.el         | 94 +++++++++++++++++++++++----------------
 testing/examples/pub/link |  1 -
 3 files changed, 80 insertions(+), 39 deletions(-)
 delete mode 120000 testing/examples/pub/link

diff --git a/doc/org-manual.org b/doc/org-manual.org
index 51884ec99..40f542335 100644
--- a/doc/org-manual.org
+++ b/doc/org-manual.org
@@ -1577,6 +1577,30 @@ you, configure the option ~org-table-auto-blank-field~.
      #+findex: org-table-kill-row
      Kill the current row or horizontal line.
 
+- {{{kbd(S-UP)}}} (~org-table-move-single-cell-up~) ::
+
+     #+kindex: S-UP
+     #+findex: org-table-move-single-cell-up
+     Move single cell up by swapping with adjacent cells.
+
+- {{{kbd(S-DOWN)}}} (~org-table-move-single-cell-down~) ::
+
+     #+kindex: S-DOWN
+     #+findex: org-table-move-single-cell-down
+     Move single cell down by swapping with adjacent cells.
+
+- {{{kbd(S-LEFT)}}} (~org-table-move-single-cell-left~) ::
+
+     #+kindex: S-LEFT
+     #+findex: org-table-move-single-cell-left
+     Move single cell left by swapping with adjacent cells.
+
+- {{{kbd(S-RIGHT)}}} (~org-table-move-single-cell-right~) ::
+
+     #+kindex: S-RIGHT
+     #+findex: org-table-move-single-cell-right
+     Move single cell right by swapping with adjacent cells.
+
 - {{{kbd(M-S-DOWN)}}} (~org-table-insert-row~) ::
 
      #+kindex: M-S-DOWN
diff --git a/lisp/org-table.el b/lisp/org-table.el
index e8898a1cb..009f50d19 100644
--- a/lisp/org-table.el
+++ b/lisp/org-table.el
@@ -1441,76 +1441,94 @@ non-nil, the one above is used."
 			 (t (setq min mean)))))
 	       (if above min max))))))
 
-;;;###autoload
-(defun org-table-max-line-col ()
-  "Return the maximum line and column of the current table as a
-list of two numbers"
-  (when (not (org-at-table-p))
-    (user-error "Not in an org-table"))
-  (let ((table-end (org-table-end)))
-    (save-mark-and-excursion
-     (goto-char table-end)
-     (org-table-previous-field)
-     (list (org-table-current-line) (org-table-current-column)))))
-
-;;;###autoload
-(defun org-table-swap-cells (row1 col1 row2 col2)
-  "Swap two cells indicated by the coordinates provided"
+;; replaced with call to org-table-analyze and use of variables set by it
+
+;; ;;;###autoload
+;; (defun org-table-max-line-col ()
+;;   "Return the maximum line and column of the current table as a
+;; list of two numbers"
+;;   (when (not (org-at-table-p))
+;;     (user-error "Not in an org-table"))
+;;   (let ((table-end (org-table-end)))
+;;     (save-mark-and-excursion
+;;      (goto-char table-end)
+;;      (org-table-previous-field)
+;;      (list (org-table-current-line) (org-table-current-column)))))
+
+; ;;;###autoload  ;; told not to autoload by Nicolas Goaziou
+(defun org-table--swap-cells (row1 col1 row2 col2)
+  "Swap two cells indicated by the coordinates provided. 
+row1, col1, row2, col2 are integers indicating the row/column
+position of the two cells that will be swapped in the table."
   (let ((content1 (org-table-get row1 col1))
 	(content2 (org-table-get row2 col2)))
     (org-table-put row1 col1 content2)
     (org-table-put row2 col2 content1)
-    (org-table-align)))
-
-;;;###autoload
-(defun org-table-move-single-cell (direction)
-  "Move the current cell in a cardinal direction according to the
-parameter symbol: 'up 'down 'left 'right. Swaps contents of
-adjacent cell with current one."
-  (unless (org-at-table-p)
-    (error "No table at point"))
-  (let ((drow 0) (dcol 0))
+;    (org-table-align) ;; told by Nicolas Goaziou that this is "out of scope"
+    ))
+
+; ;;;###autoload ; told not to auto-load by Nicolas Goaziou, also reformatted comment
+(defun org-table--move-single-cell (direction)
+  "Move the current cell in a cardinal direction.
+Parameter direction is a symbol which mathes 'up 'down 'left or
+'right.  The contents the current cell are swapped with cell in
+the indicated direction."
+;removed check for in table; moved to public functions
+  (let ((drow 0) (dcol 0))		
     (cond ((equal direction 'up)    (setq drow -1))
 	  ((equal direction 'down)  (setq drow +1))
 	  ((equal direction 'left)  (setq dcol -1))
 	  ((equal direction 'right) (setq dcol +1))
 	  (t (error "Not a valid direction, must be one of 'up 'down 'left 'right")))
+    (org-table-analyze)		;to set org-table-current-ncol and org-table-dlines
     (let* ((row1 (org-table-current-line))
 	   (col1 (org-table-current-column))
 	   (row2 (+ row1 drow))
 	   (col2 (+ col1 dcol))
-	   (max-row-col (org-table-max-line-col))
-	   (max-row (car max-row-col))
-	   (max-col (cadr max-row-col)))
-      (when (or (< col1 1) (< col2 1) (> col2 max-col) (< row2 1) (> row2 max-row))
+	   (org-table-current-nrow (- (length org-table-dlines) 1)))
+      (when (or (< col1 1) (< col2 1) (< row2 1)
+		(> col2 org-table-current-ncol)
+		(> row2 org-table-current-nrow))
 	(user-error "Cannot move cell further"))
-      (org-table-swap-cells row1 col1 row2 col2)
+      (org-table--swap-cells row1 col1 row2 col2)
       (org-table-goto-line row2)
       (org-table-goto-column col2))))
 
 ;;;###autoload
 (defun org-table-move-single-cell-up ()
-  "Move a single cell up in a table; swap with anything in target cell"
+  "Move a single cell up in a table; swap with anything in target cell."
   (interactive)
-  (org-table-move-single-cell 'up))
+  (unless (org-table-check-inside-data-field)
+    (error "No table at point"))
+  (org-table--move-single-cell 'up)
+  (org-table-align))
 
 ;;;###autoload
 (defun org-table-move-single-cell-down ()
-  "Move a single cell down in a table; swap with anything in target cell"
+  "Move a single cell down in a table; swap with anything in target cell."
   (interactive)
-  (org-table-move-single-cell 'down))
+  (unless (org-table-check-inside-data-field)
+    (error "No table at point"))
+  (org-table--move-single-cell 'down)
+  (org-table-align))
 
 ;;;###autoload
 (defun org-table-move-single-cell-left ()
-  "Move a single cell left in a table; swap with anything in target cell"
+  "Move a single cell left in a table; swap with anything in target cell."
   (interactive)
-  (org-table-move-single-cell 'left))
+  (unless (org-table-check-inside-data-field)
+    (error "No table at point"))
+  (org-table--move-single-cell 'left)
+  (org-table-align))
 
 ;;;###autoload
 (defun org-table-move-single-cell-right ()
-  "Move a single cell right in a table; swap with anything in target cell"
+  "Move a single cell right in a table; swap with anything in target cell."
   (interactive)
-  (org-table-move-single-cell 'right))
+  (unless (org-table-check-inside-data-field)
+    (error "No table at point"))
+  (org-table--move-single-cell 'right)
+  (org-table-align))
 	
 ;;;###autoload
 (defun org-table-delete-column ()
diff --git a/testing/examples/pub/link b/testing/examples/pub/link
deleted file mode 120000
index 01bb51522..000000000
--- a/testing/examples/pub/link
+++ /dev/null
@@ -1 +0,0 @@
-../pub-symlink
\ No newline at end of file
-- 
2.17.0


[-- Attachment #8: 0007-org-table.el-Added-single-cell-movement.patch --]
[-- Type: text/x-patch, Size: 2435 bytes --]

From 84d576b029f02f4880bc5c3f4eb9f7dd0609a729 Mon Sep 17 00:00:00 2001
From: Chris Kauffman <kauffman77@gmail.com>
Date: Tue, 29 May 2018 14:44:26 -0500
Subject: [PATCH 7/8] org-table.el: Added single cell movement

* lisp/org-table.el: New functions `org-table-move-single-cell-*'
along with supporting internal functions.

* doc/org-manual.org: Added documentation associated with single cell
movement.
---
 lisp/org-table.el | 21 +--------------------
 1 file changed, 1 insertion(+), 20 deletions(-)

diff --git a/lisp/org-table.el b/lisp/org-table.el
index 009f50d19..1c8c97f43 100644
--- a/lisp/org-table.el
+++ b/lisp/org-table.el
@@ -1441,21 +1441,6 @@ non-nil, the one above is used."
 			 (t (setq min mean)))))
 	       (if above min max))))))
 
-;; replaced with call to org-table-analyze and use of variables set by it
-
-;; ;;;###autoload
-;; (defun org-table-max-line-col ()
-;;   "Return the maximum line and column of the current table as a
-;; list of two numbers"
-;;   (when (not (org-at-table-p))
-;;     (user-error "Not in an org-table"))
-;;   (let ((table-end (org-table-end)))
-;;     (save-mark-and-excursion
-;;      (goto-char table-end)
-;;      (org-table-previous-field)
-;;      (list (org-table-current-line) (org-table-current-column)))))
-
-; ;;;###autoload  ;; told not to autoload by Nicolas Goaziou
 (defun org-table--swap-cells (row1 col1 row2 col2)
   "Swap two cells indicated by the coordinates provided. 
 row1, col1, row2, col2 are integers indicating the row/column
@@ -1463,17 +1448,13 @@ position of the two cells that will be swapped in the table."
   (let ((content1 (org-table-get row1 col1))
 	(content2 (org-table-get row2 col2)))
     (org-table-put row1 col1 content2)
-    (org-table-put row2 col2 content1)
-;    (org-table-align) ;; told by Nicolas Goaziou that this is "out of scope"
-    ))
+    (org-table-put row2 col2 content1)))
 
-; ;;;###autoload ; told not to auto-load by Nicolas Goaziou, also reformatted comment
 (defun org-table--move-single-cell (direction)
   "Move the current cell in a cardinal direction.
 Parameter direction is a symbol which mathes 'up 'down 'left or
 'right.  The contents the current cell are swapped with cell in
 the indicated direction."
-;removed check for in table; moved to public functions
   (let ((drow 0) (dcol 0))		
     (cond ((equal direction 'up)    (setq drow -1))
 	  ((equal direction 'down)  (setq drow +1))
-- 
2.17.0


[-- Attachment #9: 0008-org-table.el-added-single-cell-movement.patch --]
[-- Type: text/x-patch, Size: 926 bytes --]

From c780234afee982a231a988d71ea352bab9670f0f Mon Sep 17 00:00:00 2001
From: Chris Kauffman <kauffman77@gmail.com>
Date: Tue, 29 May 2018 15:04:25 -0500
Subject: [PATCH 8/8] org-table.el: added single cell movement

* lisp/org-table.el: added functions `org-table-move-single-cell-*'
along with internal support functions for cell swapping.

* lisp/org.el: added bindings for shift+arrows for
`org-table-move-single-cell-up' etc.

* doc/org-manual.org: added docs for the single cell movement.

* testing/lisp/test-org-table.el: added tests associated with single
cell movement.
---
 testing/examples/pub/link | 1 +
 1 file changed, 1 insertion(+)
 create mode 120000 testing/examples/pub/link

diff --git a/testing/examples/pub/link b/testing/examples/pub/link
new file mode 120000
index 000000000..01bb51522
--- /dev/null
+++ b/testing/examples/pub/link
@@ -0,0 +1 @@
+../pub-symlink
\ No newline at end of file
-- 
2.17.0


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

* Re: Adding single cell movement to org-table
  2018-05-29 20:29             ` Chris Kauffman
@ 2018-06-13 13:35               ` Nicolas Goaziou
  0 siblings, 0 replies; 11+ messages in thread
From: Nicolas Goaziou @ 2018-06-13 13:35 UTC (permalink / raw)
  To: Chris Kauffman; +Cc: Uwe Brauer, emacs-orgmode

Hello,

Chris Kauffman <kauffman@cs.gmu.edu> writes:

> Attached are the updated patches for single cell movement in org
> tables.

Thank you!

I squashed the various patches, fixed the docstrings and refactored
a bit some functions.

I also renamed `org-table-move-single-cell-*' into
`org-table-move-cell-*', which is shorter and, IMO, not ambiguous.

I pushed it in "next" branch, which will be merged with master once Org
9.2 is out.

BTW, what is current status wrt FSF papers now?

Regards,

-- 
Nicolas Goaziou                                                0x80A93738

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

end of thread, other threads:[~2018-06-13 13:35 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-07-27 20:20 Adding single cell movement to org-table Chris Kauffman
2017-07-28  8:19 ` Nicolas Goaziou
2017-07-29  3:00   ` Chris Kauffman
2017-08-03 10:37     ` Nicolas Goaziou
2018-05-04 12:29       ` stardiviner
2018-05-04 14:04         ` Chris Kauffman
2018-05-04 14:31           ` Uwe Brauer
2018-05-05  0:18           ` stardiviner
2018-05-29 20:29             ` Chris Kauffman
2018-06-13 13:35               ` Nicolas Goaziou
2017-07-28  8:53 ` 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).