diff options
author | Chris Kauffman <kauffman@ecs.gmu.edu> | 2017-07-23 00:13:11 -0400 |
---|---|---|
committer | Nicolas Goaziou <mail@nicolasgoaziou.fr> | 2018-10-03 18:44:34 +0200 |
commit | d0a5308435d35c21d24965383970cd70d61f5886 (patch) | |
tree | 2af96eb6bdf02717e8e0496617aada9c0d6c82f2 | |
parent | 74f769f85045bd37bbe4cdd953613cf4a38de673 (diff) | |
download | org-mode-d0a5308435d35c21d24965383970cd70d61f5886.tar.gz |
org-table: Adding single cell movement functions
* lisp/org-table.el (org-table--swap-cells):
(org-table--move-cell):
(org-table-move-cell-up):
(org-table-move-cell-down):
(org-table-move-cell-left):
(org-table-move-cell-right): New functions.
* testing/lisp/test-org-table.el (test-org-table/move-cell-down):
(test-org-table/move-cell-up):
(test-org-table/move-cell-right):
(test-org-table/move-cell-left): New tests.
* doc/org-manual.org (Column and row editing): Document functions and
keybindings for single cell movement.
-rw-r--r-- | doc/org-manual.org | 24 | ||||
-rw-r--r-- | lisp/org-table.el | 74 | ||||
-rw-r--r-- | testing/lisp/test-org-table.el | 385 |
3 files changed, 483 insertions, 0 deletions
diff --git a/doc/org-manual.org b/doc/org-manual.org index 535aa9d..9db0092 100644 --- a/doc/org-manual.org +++ b/doc/org-manual.org @@ -1556,6 +1556,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-cell-up~) :: + + #+kindex: S-UP + #+findex: org-table-move-cell-up + Move cell up by swapping with adjacent cell. + +- {{{kbd(S-DOWN)}}} (~org-table-move-cell-down~) :: + + #+kindex: S-DOWN + #+findex: org-table-move-cell-down + Move cell down by swapping with adjacent cell. + +- {{{kbd(S-LEFT)}}} (~org-table-move-cell-left~) :: + + #+kindex: S-LEFT + #+findex: org-table-move-cell-left + Move cell left by swapping with adjacent cell. + +- {{{kbd(S-RIGHT)}}} (~org-table-move-cell-right~) :: + + #+kindex: S-RIGHT + #+findex: org-table-move-cell-right + Move cell right by swapping with adjacent cell. + - {{{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 8eb38ef..634dd14 100644 --- a/lisp/org-table.el +++ b/lisp/org-table.el @@ -1442,6 +1442,80 @@ non-nil, the one above is used." (above min) (t max))))))) +(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))) + +(defun org-table--move-cell (direction) + "Move the current cell in a cardinal direction. +DIRECTION is a symbol among `up', `down', `left', and `right'. +The contents the current cell are swapped with cell in the +indicated direction. Raise an error if the move cannot be done." + (let ((row-shift (pcase direction (`up -1) (`down 1) (_ 0))) + (column-shift (pcase direction (`left -1) (`right 1) (_ 0)))) + (when (and (= 0 row-shift) (= 0 column-shift)) + (error "Invalid direction: %S" direction)) + ;; Initialize `org-table-current-ncol' and `org-table-dlines'. + (org-table-analyze) + (let* ((row (org-table-current-line)) + (column (org-table-current-column)) + (target-row (+ row row-shift)) + (target-column (+ column column-shift)) + (org-table-current-nrow (1- (length org-table-dlines)))) + (when (or (< target-column 1) + (< target-row 1) + (> target-column org-table-current-ncol) + (> target-row org-table-current-nrow)) + (user-error "Cannot move cell further")) + (org-table--swap-cells row column target-row target-column) + (org-table-goto-line target-row) + (org-table-goto-column target-column)))) + +;;;###autoload +(defun org-table-move-cell-up () + "Move a single cell up in a table. +Swap with anything in target cell." + (interactive) + (unless (org-table-check-inside-data-field) + (error "No table at point")) + (org-table--move-cell 'up) + (org-table-align)) + +;;;###autoload +(defun org-table-move-cell-down () + "Move a single cell down in a table. +Swap with anything in target cell." + (interactive) + (unless (org-table-check-inside-data-field) + (error "No table at point")) + (org-table--move-cell 'down) + (org-table-align)) + +;;;###autoload +(defun org-table-move-cell-left () + "Move a single cell left in a table. +Swap with anything in target cell." + (interactive) + (unless (org-table-check-inside-data-field) + (error "No table at point")) + (org-table--move-cell 'left) + (org-table-align)) + +;;;###autoload +(defun org-table-move-cell-right () + "Move a single cell right in a table. +Swap with anything in target cell." + (interactive) + (unless (org-table-check-inside-data-field) + (error "No table at point")) + (org-table--move-cell 'right) + (org-table-align)) + ;;;###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 ecef7ea..7af5c9f 100644 --- a/testing/lisp/test-org-table.el +++ b/testing/lisp/test-org-table.el @@ -2278,6 +2278,391 @@ See also `test-org-table/copy-field'." +;;; Moving single cells +(ert-deftest test-org-table/move-cell-down () + "Test `org-table-move-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-cell-down))) + (should-error + (org-test-with-temp-text "| a |" + (org-table-move-cell-down))) + (should-error + (org-test-with-temp-text "| a |\n" + (org-table-move-cell-down))) + (should-error + (org-test-with-temp-text "| a | <point>b |\n" + (org-table-move-cell-down))) + (should-error + (org-test-with-temp-text "| a | b |\n| <point>c | d |\n" + (org-table-move-cell-down))) + (should-error + (org-test-with-temp-text "| a | b |\n| c | <point>d |\n" + (org-table-move-cell-down))) + (should-error + (org-test-with-temp-text "| <point>a |\n|---|\n" + (org-table-move-cell-down))) + (should-error + (org-test-with-temp-text "|<point>---|\n| a |\n" + (org-table-move-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-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-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-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-cell-down) + (org-table-move-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-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-cell-down) + (org-table-move-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-cell-down) + (buffer-string)))) + ;; Move single cell even without a final newline. + (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-cell-down) + (org-table-move-cell-down) + (buffer-string))))) + +(ert-deftest test-org-table/move-cell-up () + "Test `org-table-move-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-cell-up))) + (should-error + (org-test-with-temp-text "| a |" + (org-table-move-cell-up))) + (should-error + (org-test-with-temp-text "| a |\n" + (org-table-move-cell-up))) + (should-error + (org-test-with-temp-text "| <point>a | b |\n" + (org-table-move-cell-up))) + (should-error + (org-test-with-temp-text "| a | <point>b |\n| c | d |\n" + (org-table-move-cell-up))) + (should-error + (org-test-with-temp-text "| <point>a |\n|---|\n" + (org-table-move-cell-up))) + (should-error + (org-test-with-temp-text "|<point>---|\n| a |\n" + (org-table-move-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-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-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-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-cell-up) + (org-table-move-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-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-cell-up) + (org-table-move-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-cell-up) + (buffer-string)))) + ;; Move single cell even without a final newline. + (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-cell-up) + (org-table-move-cell-up) + (buffer-string))))) + +(ert-deftest test-org-table/move-cell-right () + "Test `org-table-move-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-cell-right))) + (should-error + (org-test-with-temp-text "| a |" + (org-table-move-cell-right))) + (should-error + (org-test-with-temp-text "| a |\n" + (org-table-move-cell-right))) + (should-error + (org-test-with-temp-text "| <point>a |\n| b |\n" + (org-table-move-cell-right))) + (should-error + (org-test-with-temp-text "| a | <point>b |\n| c | d |\n" + (org-table-move-cell-right))) + (should-error + (org-test-with-temp-text "| <point>a |\n|---|\n" + (org-table-move-cell-right))) + (should-error + (org-test-with-temp-text "|<point>---|\n| a |\n" + (org-table-move-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-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-cell-right) + (org-table-move-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-cell-right) + (org-table-move-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-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-cell-right) + (org-table-move-cell-right) + (buffer-string)))) + ;; Move single cell even without a final newline. + (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-cell-right) + (buffer-string))))) + +(ert-deftest test-org-table/move-cell-left () + "Test `org-table-move-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-cell-left))) + (should-error + (org-test-with-temp-text "| a |" + (org-table-move-cell-left))) + (should-error + (org-test-with-temp-text "| a |\n" + (org-table-move-cell-left))) + (should-error + (org-test-with-temp-text "| <point>a |\n| b |\n" + (org-table-move-cell-left))) + (should-error + (org-test-with-temp-text "| <point>a | b |\n| c | d |\n" + (org-table-move-cell-left))) + (should-error + (org-test-with-temp-text "| <point>a |\n|---|\n" + (org-table-move-cell-left))) + (should-error + (org-test-with-temp-text "|<point>---|\n| a |\n" + (org-table-move-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-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-cell-left) + (org-table-move-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-cell-left) + (org-table-move-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-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-cell-left) + (org-table-move-cell-left) + (buffer-string)))) + ;; Move single cell even without a final newline. + (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-cell-left) + (buffer-string))))) + + ;;; Moving rows, moving columns (ert-deftest test-org-table/move-row-down () |