* [BUG] org-table-beginning/end-of-field @ 2014-09-08 5:37 Florian Beck 2014-09-08 10:25 ` Nicolas Goaziou 0 siblings, 1 reply; 8+ messages in thread From: Florian Beck @ 2014-09-08 5:37 UTC (permalink / raw) To: emacs-orgmode [-- Attachment #1: Type: text/plain, Size: 124 bytes --] Hi, The argument of `org-table-beginning-of-field' and `org-table-end-of-field' is in fact not optional. -- Florian Beck [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-Remove-optional-argument-spec.patch --] [-- Type: text/x-diff, Size: 1339 bytes --] From d1d12380a1c260bef7a2137831434614f7d9ec1f Mon Sep 17 00:00:00 2001 From: Florian Beck <fb@miszellen.de> Date: Mon, 8 Sep 2014 07:34:56 +0200 Subject: [PATCH] Remove &optional argument spec * lisp/org-table.el (org-table-beginning-of-field): fix argument (org-table-end-of-field): fix argument --- lisp/org-table.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/org-table.el b/lisp/org-table.el index 547f933..a17e95a 100644 --- a/lisp/org-table.el +++ b/lisp/org-table.el @@ -1061,7 +1061,7 @@ Before doing so, re-align the table if necessary." (if (looking-at "| ?") (goto-char (match-end 0)))) -(defun org-table-beginning-of-field (&optional n) +(defun org-table-beginning-of-field (n) "Move to the end of the current table field. If already at or after the end, move to the end of the next table field. With numeric argument N, move N-1 fields forward first." @@ -1076,7 +1076,7 @@ With numeric argument N, move N-1 fields forward first." (and (looking-at " ") (forward-char 1))) (if (>= (point) pos) (org-table-beginning-of-field 2)))) -(defun org-table-end-of-field (&optional n) +(defun org-table-end-of-field (n) "Move to the beginning of the current table field. If already at or before the beginning, move to the beginning of the previous field. -- 1.9.1 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [BUG] org-table-beginning/end-of-field 2014-09-08 5:37 [BUG] org-table-beginning/end-of-field Florian Beck @ 2014-09-08 10:25 ` Nicolas Goaziou 2014-09-08 12:17 ` [PATCH] org-table-beginning/end-of-field Florian Beck 0 siblings, 1 reply; 8+ messages in thread From: Nicolas Goaziou @ 2014-09-08 10:25 UTC (permalink / raw) To: Florian Beck; +Cc: emacs-orgmode Hello, Florian Beck <fb@miszellen.de> writes: > The argument of `org-table-beginning-of-field' and > `org-table-end-of-field' is in fact not optional. Thanks for the patch. Though, wouldn't it make more sense to properly handle a missing argument instead? Regards, -- Nicolas Goaziou ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] org-table-beginning/end-of-field 2014-09-08 10:25 ` Nicolas Goaziou @ 2014-09-08 12:17 ` Florian Beck 2014-09-08 15:30 ` Nicolas Goaziou 0 siblings, 1 reply; 8+ messages in thread From: Florian Beck @ 2014-09-08 12:17 UTC (permalink / raw) To: emacs-orgmode [-- Attachment #1: Type: text/plain, Size: 194 bytes --] Nicolas Goaziou <mail@nicolasgoaziou.fr> writes: > Thanks for the patch. Though, wouldn't it make more sense to properly > handle a missing argument instead? How about this? -- Florian Beck [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-org-table-fix-arguments-of-org-table-beginning-of-fi.patch --] [-- Type: text/x-diff, Size: 3011 bytes --] From 4fb2bbff2238d15ae7c896e0eb268b74ea4e56dc Mon Sep 17 00:00:00 2001 From: Florian Beck <fb@miszellen.de> Date: Mon, 8 Sep 2014 14:08:56 +0200 Subject: [PATCH] org-table: fix arguments of `org-table-beginning-of-field' and `org-table-end-of-field'. Also fix docstring and cleanup code. * lisp/org-table.el (org-table--border-of-field): new function (org-table-beginning-of-field): call it (org-table-end-of-field): call it --- lisp/org-table.el | 45 +++++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/lisp/org-table.el b/lisp/org-table.el index 547f933..31fda57 100644 --- a/lisp/org-table.el +++ b/lisp/org-table.el @@ -1061,37 +1061,34 @@ Before doing so, re-align the table if necessary." (if (looking-at "| ?") (goto-char (match-end 0)))) -(defun org-table-beginning-of-field (&optional n) - "Move to the end of the current table field. -If already at or after the end, move to the end of the next table field. -With numeric argument N, move N-1 fields forward first." - (interactive "p") +(defun org-table--border-of-field (n move-fn element cmp-fn) (let ((pos (point))) (while (> n 1) (setq n (1- n)) - (org-table-previous-field)) - (if (not (re-search-backward "|" (point-at-bol 0) t)) - (user-error "No more table fields before the current") - (goto-char (match-end 0)) - (and (looking-at " ") (forward-char 1))) - (if (>= (point) pos) (org-table-beginning-of-field 2)))) + (funcall move-fn)) + (goto-char (org-element-property element (org-element-context))) + (if (and (> n 0) (funcall cmp-fn (point) pos)) + (org-table--border-of-field 2 move-fn element cmp-fn)))) -(defun org-table-end-of-field (&optional n) +(defun org-table-beginning-of-field (&optional n) "Move to the beginning of the current table field. -If already at or before the beginning, move to the beginning of the -previous field. +If already at or before the beginning and N is not 0, move to the +beginning of the previous table field. With numeric argument N, move N-1 fields backward first." (interactive "p") - (let ((pos (point))) - (while (> n 1) - (setq n (1- n)) - (org-table-next-field)) - (when (re-search-forward "|" (point-at-eol 1) t) - (backward-char 1) - (skip-chars-backward " ") - (if (and (equal (char-before (point)) ?|) (looking-at " ")) - (forward-char 1))) - (if (<= (point) pos) (org-table-end-of-field 2)))) + (org-table--border-of-field (or n 1) + 'org-table-previous-field + :contents-begin '>=)) + +(defun org-table-end-of-field (&optional n) + "Move to the end of the current table field. +If already at or after the end and N is not 0, move to the end of the +next field. +With numeric argument N, move N-1 fields forward first." + (interactive "p") + (org-table--border-of-field (or n 1) + 'org-table-next-field + :contents-end '<=)) ;;;###autoload (defun org-table-next-row () -- 1.9.1 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH] org-table-beginning/end-of-field 2014-09-08 12:17 ` [PATCH] org-table-beginning/end-of-field Florian Beck @ 2014-09-08 15:30 ` Nicolas Goaziou 2014-09-09 11:09 ` Florian Beck 0 siblings, 1 reply; 8+ messages in thread From: Nicolas Goaziou @ 2014-09-08 15:30 UTC (permalink / raw) To: Florian Beck; +Cc: emacs-orgmode Florian Beck <fb@miszellen.de> writes: > How about this? Nice. Some comments follow. > > From 4fb2bbff2238d15ae7c896e0eb268b74ea4e56dc Mon Sep 17 00:00:00 2001 > From: Florian Beck <fb@miszellen.de> > Date: Mon, 8 Sep 2014 14:08:56 +0200 > Subject: [PATCH] org-table: fix arguments of `org-table-beginning-of-field' "fix" needs to be capitalized. > and `org-table-end-of-field'. Also fix docstring and cleanup code. You need a shorter summary, e.g., org-table: Fix org-table/beginning/end/-of-field. The second sentence should go at the end of the commit message. Also, there's no full stop on summary lines. > * lisp/org-table.el (org-table--border-of-field): new function "new" needs to be capitalized. Also there's a missing full stop. > (org-table-beginning-of-field): call it > (org-table-end-of-field): call it (org-table-beginning-of-field, org-table-end-of-field): Call it. > +(defun org-table--border-of-field (n move-fn element cmp-fn) A docstring would be nice, even for a helper function. > (let ((pos (point))) > (while (> n 1) > (setq n (1- n)) > - (org-table-previous-field)) > - (if (not (re-search-backward "|" (point-at-bol 0) t)) > - (user-error "No more table fields before the current") > - (goto-char (match-end 0)) > - (and (looking-at " ") (forward-char 1))) > - (if (>= (point) pos) (org-table-beginning-of-field 2)))) > + (funcall move-fn)) While you're at it, I suggest (dotimes (_ (1- n)) (funcall move-fn)) instead of (while (> n 1) ...) Also, note that you can avoid requiring MOVE-FN, ELEMENT and CMP-FN if you decide that (< n 0) => (#'org-table-next-field :contents-end #'<=) (> n 0) => (#'org-table-previous-fierd :contents-begin #'>=) Up to you. > + (goto-char (org-element-property element (org-element-context))) You need to be more careful here. You might be outside of a table, or within an object contained in a cell, e.g., | some *bold* object | where (org-element-context) on bold will return a `bold' type object with different :contents-begin and :contents-end values. IOW, you need to let-bind (org-element-context) and find the first `table', `table-row' or `table-cell' object/element among it and its parents. Then - if no such ancestor is found: return an error (not at a table) - if `table' is found but point is not within [:contents-begin :contents-end[ interval, return an error (not inside the table) - if `table' or `table-row' is found, you need to apply org-table/previous/next/-field once (and diminish N by one) to make sure point will be left on a regular cell, if possible. > + (if (and (> n 0) (funcall cmp-fn (point) pos)) > + (org-table--border-of-field 2 move-fn element cmp-fn)))) I don't think (> n 0) is necessary, is it? Also, I suggest to use `when' (or `and' if return value matters) over one-armed `if'. > -(defun org-table-end-of-field (&optional n) > +(defun org-table-beginning-of-field (&optional n) > "Move to the beginning of the current table field. > -If already at or before the beginning, move to the beginning of the > -previous field. > +If already at or before the beginning and N is not 0, move to the > +beginning of the previous table field. > With numeric argument N, move N-1 fields backward first." I wouldn't start a new line here. Also don't forget double spaces: If already at or before the beginning and N is not 0, move to the beginning of the previous table field. With numeric argument N, move N-1 fields backward first. > + (org-table--border-of-field (or n 1) > + 'org-table-previous-field > + :contents-begin '>=)) Nitpick: #'org-table-previous-field and #'>=. > +(defun org-table-end-of-field (&optional n) > + "Move to the end of the current table field. > +If already at or after the end and N is not 0, move to the end of the > +next field. > +With numeric argument N, move N-1 fields forward first." > + (interactive "p") > + (org-table--border-of-field (or n 1) > + 'org-table-next-field > + :contents-end '<=)) Ditto. Thank you for taking care of this. There are bonus points if you can write tests along with this change. Regards, -- Nicolas Goaziou ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] org-table-beginning/end-of-field 2014-09-08 15:30 ` Nicolas Goaziou @ 2014-09-09 11:09 ` Florian Beck 2014-09-10 13:42 ` Nicolas Goaziou 0 siblings, 1 reply; 8+ messages in thread From: Florian Beck @ 2014-09-09 11:09 UTC (permalink / raw) To: emacs-orgmode [-- Attachment #1: Type: text/plain, Size: 1691 bytes --] Hi Nicolas, thanks for the review. I hope the new version is an improvement. Nicolas Goaziou <mail@nicolasgoaziou.fr> writes: > Also, note that you can avoid requiring MOVE-FN, ELEMENT and CMP-FN if > you decide that > > (< n 0) => (#'org-table-next-field :contents-end #'<=) > (> n 0) => (#'org-table-previous-fierd :contents-begin #'>=) > > Up to you. I wanted to use the n=0 case to supress the conditional movement to the next field. It's probably not worth it and I removed it. Now everything simplifies to one function. > IOW, you need to let-bind (org-element-context) and find the first > `table', `table-row' or `table-cell' object/element among it and its > parents. Then > > - if no such ancestor is found: return an error (not at a table) > > - if `table' is found but point is not within > [:contents-begin :contents-end[ interval, return an error (not > inside the table) > > - if `table' or `table-row' is found, you need to apply > org-table/previous/next/-field once (and diminish N by one) to make > sure point will be left on a regular cell, if possible. But as long as I have a table cell ancestor, I should be fine. Am I missing something? I added a function `org-element-get' to help with that. What do you think? (If `cl-labels' is a no-go, we could split out a helper function.) > Thank you for taking care of this. There are bonus points if you can > write tests along with this change. I added a couple of tests. Not really succinct, though. Also, I modified `org-element-table-cell-parser', because otherwise :contents-begin and :contents-end point to the end of the cell. Not sure if this breaks anything. -- Florian Beck [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-org-element-Adjust-content-boundaries-in-empty-cells.patch --] [-- Type: text/x-diff, Size: 1267 bytes --] From 2b1a63e70830e7604c7f59dd0110aedf3a9c1e53 Mon Sep 17 00:00:00 2001 From: Florian Beck <fb@miszellen.de> Date: Tue, 9 Sep 2014 12:29:53 +0200 Subject: [PATCH 1/4] org-element: Adjust content boundaries in empty cells * lisp/org-element.el (org-element-table-cell-parser): Let :contents-begin and :contents-end point to the beginning of an empty table cell. --- lisp/org-element.el | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lisp/org-element.el b/lisp/org-element.el index f175fbc..47fa3f1 100644 --- a/lisp/org-element.el +++ b/lisp/org-element.el @@ -3333,12 +3333,15 @@ and `:post-blank' keywords." (let* ((begin (match-beginning 0)) (end (match-end 0)) (contents-begin (match-beginning 1)) - (contents-end (match-end 1))) + (contents-end (match-end 1)) + ;; Avoid having the contents at the end of an empty cell. + (empty-pos (when (= contents-begin contents-end) + (min (1+ begin) end)))) (list 'table-cell (list :begin begin :end end - :contents-begin contents-begin - :contents-end contents-end + :contents-begin (or empty-pos contents-begin) + :contents-end (or empty-pos contents-end) :post-blank 0)))) (defun org-element-table-cell-interpreter (table-cell contents) -- 1.9.1 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #3: 0002-org-element-Implement-org-element-get.patch --] [-- Type: text/x-diff, Size: 1425 bytes --] From 10f68bf26f82f4cbc0e097bac9a4d3b997c10bc4 Mon Sep 17 00:00:00 2001 From: Florian Beck <fb@miszellen.de> Date: Tue, 9 Sep 2014 12:31:35 +0200 Subject: [PATCH 2/4] org-element: Implement `org-element-get' * lisp/org-element.el (org-element-get): New function. --- lisp/org-element.el | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/lisp/org-element.el b/lisp/org-element.el index 47fa3f1..f55dd37 100644 --- a/lisp/org-element.el +++ b/lisp/org-element.el @@ -5873,6 +5873,26 @@ Providing it allows for quicker computation." ;; Store results in cache, if applicable. (org-element--cache-put element cache))))))) +(defun org-element-get (&optional type pom) + "Return the nearest object or element of TYPE at POM." + (let* ((pom (or pom (point))) + (context (with-current-buffer (if (markerp pom) + (marker-buffer pom) + (current-buffer)) + (save-excursion + (goto-char pom) + (org-element-context))))) + (cl-labels ((get-type (type context) + (cond ((not context) nil) + ((not type) context) + ((eql type (car context)) + context) + (t (get-type type + (plist-get + (cadr context) + :parent)))))) + (get-type type context)))) + (defun org-element-nested-p (elem-A elem-B) "Non-nil when elements ELEM-A and ELEM-B are nested." (let ((beg-A (org-element-property :begin elem-A)) -- 1.9.1 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #4: 0003-org-table-Handle-optional-arguments-and-cleanup.patch --] [-- Type: text/x-diff, Size: 3360 bytes --] From 64f937fe289e7aca41471ec731aec1590bebe947 Mon Sep 17 00:00:00 2001 From: Florian Beck <fb@miszellen.de> Date: Tue, 9 Sep 2014 12:35:09 +0200 Subject: [PATCH 3/4] org-table: Handle optional arguments and cleanup * lisp/org-table.el (org-table-beginning-of-field): Fix docstring. Call `org-table-end-of-field'. (org-table-end-of-field): Fix docstring. Handle missing and negative args. --- lisp/org-table.el | 60 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/lisp/org-table.el b/lisp/org-table.el index 547f933..290cdce 100644 --- a/lisp/org-table.el +++ b/lisp/org-table.el @@ -1062,36 +1062,44 @@ Before doing so, re-align the table if necessary." (goto-char (match-end 0)))) (defun org-table-beginning-of-field (&optional n) - "Move to the end of the current table field. -If already at or after the end, move to the end of the next table field. -With numeric argument N, move N-1 fields forward first." + "Move to the beginning of the current table field. +If already at or before the beginning, move to the +beginning of the previous table field. With numeric +argument N, move N-1 fields backward first." (interactive "p") - (let ((pos (point))) - (while (> n 1) - (setq n (1- n)) - (org-table-previous-field)) - (if (not (re-search-backward "|" (point-at-bol 0) t)) - (user-error "No more table fields before the current") - (goto-char (match-end 0)) - (and (looking-at " ") (forward-char 1))) - (if (>= (point) pos) (org-table-beginning-of-field 2)))) + (org-table-end-of-field (- (or n 1)))) (defun org-table-end-of-field (&optional n) - "Move to the beginning of the current table field. -If already at or before the beginning, move to the beginning of the -previous field. -With numeric argument N, move N-1 fields backward first." + "Move to the end of the current table field. +If already at or after the end, move to the end of the +next table field. With numeric argument N, move N-1 fields +forward first. If the numeric argument is negative, move backwards." (interactive "p") - (let ((pos (point))) - (while (> n 1) - (setq n (1- n)) - (org-table-next-field)) - (when (re-search-forward "|" (point-at-eol 1) t) - (backward-char 1) - (skip-chars-backward " ") - (if (and (equal (char-before (point)) ?|) (looking-at " ")) - (forward-char 1))) - (if (<= (point) pos) (org-table-end-of-field 2)))) + (let* ((pos (point)) + (n (or n 1))) + (dotimes (_ (1- (abs n))) + (funcall (if (> n 0) + #'org-table-next-field + #'org-table-previous-field))) + (let ((cell (or (org-element-get 'table-cell) + ;; Fuzzy matching when on a table border: + (org-element-get 'table-cell (1+ (point))) + (org-element-get 'table-cell (1- (point)))))) + (unless cell + (user-error "Not in a table cell")) + (goto-char (org-element-property + (if (< n 0) + :contents-begin + :contents-end) + cell)) + ;; Point already is at the end/beginning of the field, + ;; so we move to the next/previous field. + (cond + ((and (> n 0) (>= pos (point))) + (org-table-end-of-field 2)) + ((and (< n 0) (<= pos (point))) + (org-table-end-of-field -2)))))) + ;;;###autoload (defun org-table-next-row () -- 1.9.1 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #5: 0004-test-org-table-Add-tests.patch --] [-- Type: text/x-diff, Size: 4035 bytes --] From a6a00af0f3f291fb0b4eb19012b80d28d3419a38 Mon Sep 17 00:00:00 2001 From: Florian Beck <fb@miszellen.de> Date: Tue, 9 Sep 2014 12:40:27 +0200 Subject: [PATCH 4/4] test-org-table: Add tests * testing/lisp/test-org-table.el (test-org-table/org-table-end-of-field, test-org-table/org-table-beginning-of-field): New tests. --- testing/lisp/test-org-table.el | 105 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/testing/lisp/test-org-table.el b/testing/lisp/test-org-table.el index 40101be..49ed153 100644 --- a/testing/lisp/test-org-table.el +++ b/testing/lisp/test-org-table.el @@ -1168,6 +1168,111 @@ See also `test-org-table/copy-field'." (should (string= got expect))))) +(ert-deftest test-org-table/org-table-end-of-field () + "Test `org-table-end-of-field' specifications." + ;; Outside a table, return an error. + (should-error + (org-test-with-temp-text "Paragraph" + (goto-char 2) + (org-table-end-of-field))) + ;; Move to end of cell. + (should + (org-test-with-temp-text + "| Cell:1 | Cell2 |Cell3|\n| Cell4 | | Cell5|" + (search-forward ":") + (org-table-end-of-field) + (looking-back "Cell:1"))) + ;; Move to next cell if already at the end. + (should + (org-test-with-temp-text + "| Cell:1 | Cell2 |Cell3|\n| Cell4 | | Cell5|" + (search-forward ":") + (org-table-end-of-field) + (org-table-end-of-field) + (looking-back "Cell2"))) + ;; Work in unaligned cells. + (should + (org-test-with-temp-text + "| Cell1 | Cell2 |Cell:3|\n| Cell4 | | Cell5|" + (search-forward ":") + (org-table-end-of-field) + (looking-back "Cell:3"))) + ;; Move to next row + (should + (org-test-with-temp-text + "| Cell1 | Cell2 |Cell:3|\n| Cell4 | | Cell5|" + (search-forward ":") + (org-table-end-of-field) + (org-table-end-of-field) + (looking-back "Cell4"))) + ;; With argument, skip N-1 fields forward + (should + (org-test-with-temp-text + "| Cell:1 | Cell2 |Cell3|\n| Cell4 | | Cell5|" + (search-forward ":") + (org-table-end-of-field 4) + (looking-back "Cell4"))) + ;; Empty cells + (should + (org-test-with-temp-text + "| Cell1 | Cell2 |Cell3|\n| Cell4: | | Cell5|" + (search-forward ":") + (forward-char) + (org-table-end-of-field) + (looking-back "| "))) + (should + (org-test-with-temp-text + "| Cell1 | Cell2 |Cell3|\n| Cell4: | | Cell5|" + (search-forward ":") + (forward-char 6) + (org-table-end-of-field) + (looking-back "Cell5"))) + (should + (org-test-with-temp-text + "| Cell1 | Cell2 |Cell3|\n| Cell4: || Cell5|" + (search-forward ":") + (forward-char 3) + (org-table-end-of-field) + (looking-back "Cell5"))) + ;; On table border + (should + (org-test-with-temp-text + "| Cell1 | Cell2 |:Cell3|\n| Cell4 || Cell5|" + (search-forward ":") + (forward-char -2) + (org-table-end-of-field) + (looking-back ":Cell3")))) + +(ert-deftest test-org-table/org-table-beginning-of-field () + "Test `org-table-beginning-of-field' specifications." + ;; Outside a table, return an error. + (should-error + (org-test-with-temp-text "Paragraph" + (goto-char 2) + (org-table-beginning-of-field))) + ;; Move to end of cell. + (should + (org-test-with-temp-text + "| Cell:1 | Cell2 |Cell3|\n| Cell4 | | Cell5|" + (search-forward ":") + (org-table-beginning-of-field) + (looking-at "Cell:1"))) + ;; With argument, skip N-1 fields backwards + (should + (org-test-with-temp-text + "| Cell1 | Cell2 |Cell3|\n| Cell4 | | Cell:5|" + (search-forward ":") + (org-table-beginning-of-field 5) + (looking-at "Cell2"))) + ;; Empty cells + (should + (org-test-with-temp-text + "| Cell1 | Cell2 |Cell3|\n| Cell4: | | Cell5|" + (search-forward ":") + (forward-char 6) + (org-table-beginning-of-field) + (looking-back "| ")))) + (provide 'test-org-table) ;;; test-org-table.el ends here -- 1.9.1 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH] org-table-beginning/end-of-field 2014-09-09 11:09 ` Florian Beck @ 2014-09-10 13:42 ` Nicolas Goaziou 2014-09-10 17:08 ` Florian Beck 0 siblings, 1 reply; 8+ messages in thread From: Nicolas Goaziou @ 2014-09-10 13:42 UTC (permalink / raw) To: Florian Beck; +Cc: emacs-orgmode Hello, Florian Beck <fb@miszellen.de> writes: > I hope the new version is an improvement. Thanks for the update. > But as long as I have a table cell ancestor, I should be fine. Am > I missing something? Yes. There are some place where `org-element-context' will return a `table-row' or `table' object even though you can technically move to the next (or maybe previous) cell. You may want to try `org-element-context' in the following places, where X denotes cursor: | a | b | X c | d | X a | b | | c | d | X | a | b | | c | d | | a | b | X | c | d | | a | b | X | c | d | > I added a function `org-element-get' to help with that. What do you > think? (If `cl-labels' is a no-go, we could split out a helper > function.) I don't think `org-element-get' should go into "org-element.el" in its current implementation. It is tied to a position, which implies to take care of boring stuff like buffer narrowing. It doesn't allow to re-use an already computed element or object either, which is sub-optimal. However, the feature is useful enough that some function could provide something similar. Maybe the following one: (defun org-element-parent (blob &optional types genealogy) "Return BLOB's parent, or nil. BLOB is an object or element. When optional argument TYPES is a list of symbols, return the first element or object between BLOB and its ancestors whose type belongs to that list. When optional argument GENEALOGY is non-nil, return a list of all ancestors, from closest to farthest. When BLOB is obtained through `org-element-context' or `org-element-at-point', only ancestors from its section can be found. There is no such limitation when BLOB belongs to a full parse tree." (if (not (or types genealogy)) (org-element-property :parent blob) (let ((up blob) ancestors) (while (and up (not (memq (org-element-type up) types))) (when genealogy (push up ancestors)) (setq up (org-element-property :parent up))) (if genealogy (nreverse ancestors) up)))) Its name is a bit confusing since it can return BLOB under some optional argument combination (i.e., if BLOB's type belongs to TYPES). However, it covers most, if not all, needs about ancestors. WDYT? > I added a couple of tests. Not really succinct, though. Thanks. > Also, I modified `org-element-table-cell-parser', because otherwise > :contents-begin and :contents-end point to the end of the cell. Not sure > if this breaks anything. Usually, when an object has no contents (e.g., a link without description), both :contents-begin and :contents-end are nil. It is less confusing than providing an arbitrary buffer position. > + (let ((cell (or (org-element-get 'table-cell) > + ;; Fuzzy matching when on a table border: > + (org-element-get 'table-cell (1+ (point))) > + (org-element-get 'table-cell (1- (point)))))) We need to be more careful here, as explained above. > + (should > + (org-test-with-temp-text > + "| Cell:1 | Cell2 |Cell3|\n| Cell4 | | Cell5|" > + (search-forward ":") Minor note: you can insert "<point>" in the string to avoid finding the correct position later. E.g., "| Cell:<point>1 | Cell2 |Cell3|\n| Cell4 | | Cell5|" Regards, -- Nicolas Goaziou ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] org-table-beginning/end-of-field 2014-09-10 13:42 ` Nicolas Goaziou @ 2014-09-10 17:08 ` Florian Beck 2014-09-12 8:29 ` Nicolas Goaziou 0 siblings, 1 reply; 8+ messages in thread From: Florian Beck @ 2014-09-10 17:08 UTC (permalink / raw) To: emacs-orgmode Nicolas Goaziou <mail@nicolasgoaziou.fr> writes: > the next (or maybe previous) cell. You may want to try > `org-element-context' in the following places, where X denotes cursor: > > | a | b | > X c | d | > > X a | b | > | c | d | This I did. > X | a | b | > | c | d | > > | a | b | X > | c | d | > > | a | b | > X | c | d | This is arguably outside the scope of org-table-beginning/end, isn't it? Come to think of it, these functions should only move to the beginning or end of the field, period. Then handle the special case in org-forward/backward-sentence or create two new functions. > I don't think `org-element-get' should go into "org-element.el" in its > current implementation. It is tied to a position, which implies to take > care of boring stuff like buffer narrowing. It doesn't allow to re-use > an already computed element or object either, which is sub-optimal. Yes, it should be split into two functions. > However, the feature is useful enough that some function could provide > something similar. Maybe the following one: > > (defun org-element-parent (blob &optional types genealogy) > "Return BLOB's parent, or nil. > > BLOB is an object or element. > > When optional argument TYPES is a list of symbols, return the > first element or object between BLOB and its ancestors whose type > belongs to that list. > > When optional argument GENEALOGY is non-nil, return a list of all > ancestors, from closest to farthest. > > When BLOB is obtained through `org-element-context' or > `org-element-at-point', only ancestors from its section can be > found. There is no such limitation when BLOB belongs to a full > parse tree." > (if (not (or types genealogy)) (org-element-property :parent blob) > (let ((up blob) ancestors) > (while (and up (not (memq (org-element-type up) types))) > (when genealogy (push up ancestors)) > (setq up (org-element-property :parent up))) > (if genealogy (nreverse ancestors) up)))) > > Its name is a bit confusing since it can return BLOB under some optional > argument combination (i.e., if BLOB's type belongs to TYPES). However, > it covers most, if not all, needs about ancestors. WDYT? Yes this works. Making TYPES into a list is a nice touch. However: - the advertised functionality (returning the parent) is only marginally useful and handled in half a line of code; whereas most of the functionality is hidden as optional; - this leads to confusing behaviour, as you have noted, because the type of object I'm looking for, is not necessarily the parent; - BLOB on the other hand should be optional, because defaulting it to org-element-context would be highly useful. - not sure what GENEALOGY is useful for; if the user also specified TYPES, this returns the ancestors up to but NOT including those of TYPE. >> Also, I modified `org-element-table-cell-parser', because otherwise >> :contents-begin and :contents-end point to the end of the cell. Not sure >> if this breaks anything. > > Usually, when an object has no contents (e.g., a link without > description), both :contents-begin and :contents-end are nil. It is less > confusing than providing an arbitrary buffer position. That's another possibility. Unlike a link without description, one might argue that an empty cell has a natural contents position. > Minor note: you can insert "<point>" in the string to avoid finding the > correct position later. E.g., > > "| Cell:<point>1 | Cell2 |Cell3|\n| Cell4 | | Cell5|" Great, thanks! -- Florian Beck ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] org-table-beginning/end-of-field 2014-09-10 17:08 ` Florian Beck @ 2014-09-12 8:29 ` Nicolas Goaziou 0 siblings, 0 replies; 8+ messages in thread From: Nicolas Goaziou @ 2014-09-12 8:29 UTC (permalink / raw) To: Florian Beck; +Cc: emacs-orgmode Hello, Florian Beck <fb@miszellen.de> writes: Thanks for your feedback. > This I did. Well, (or (org-element-get 'table-cell) ;; Fuzzy matching when on a table border: (org-element-get 'table-cell (1+ (point))) (org-element-get 'table-cell (1- (point)))) is not necessary, since the first object/element returned should give you enough information. Also, I forgot the following case: | a | b | |---+-X-| | c | d | I think a correct analysis of the current object can solve all tricky cases, without blindly poking around. >> X | a | b | >> | c | d | >> >> | a | b | X >> | c | d | >> >> | a | b | >> X | c | d | > > This is arguably outside the scope of org-table-beginning/end, isn't it? The current implementation handles them (sometimes incorrectly). I find this sloppiness useful. > Come to think of it, these functions should only move to the > beginning or end of the field, period. Then handle the special case in > org-forward/backward-sentence or create two new functions. OTOH, is it really useful to isolate beginning/end-of-field feature? I'm not sure, but feel free to try if you think it can make the code better. >> (defun org-element-parent (blob &optional types genealogy) >> "Return BLOB's parent, or nil. >> >> BLOB is an object or element. >> >> When optional argument TYPES is a list of symbols, return the >> first element or object between BLOB and its ancestors whose type >> belongs to that list. >> >> When optional argument GENEALOGY is non-nil, return a list of all >> ancestors, from closest to farthest. >> >> When BLOB is obtained through `org-element-context' or >> `org-element-at-point', only ancestors from its section can be >> found. There is no such limitation when BLOB belongs to a full >> parse tree." >> (if (not (or types genealogy)) (org-element-property :parent blob) >> (let ((up blob) ancestors) >> (while (and up (not (memq (org-element-type up) types))) >> (when genealogy (push up ancestors)) >> (setq up (org-element-property :parent up))) >> (if genealogy (nreverse ancestors) up)))) >> >> Its name is a bit confusing since it can return BLOB under some optional >> argument combination (i.e., if BLOB's type belongs to TYPES). However, >> it covers most, if not all, needs about ancestors. WDYT? > > Yes this works. Making TYPES into a list is a nice touch. However: > - the advertised functionality (returning the parent) is only > marginally useful and handled in half a line of code; whereas most of > the functionality is hidden as optional; That's my intention. The functionality is very common so there is a high chance that it will be remembered. It is possible to separate the features and create, let's say, `org-element-genealogy'. However, in this case, I lean towards overloading a common function instead of creating a dedicated niche one. > - this leads to confusing behaviour, as you have noted, because > the type of object I'm looking for, is not necessarily the parent; This is why it can return the current object when TYPES is provided. If we create another function, you will need to check both the current item and the return value of that function. > - BLOB on the other hand should be optional, because defaulting it to > org-element-context would be highly useful. I don't consider "highly useful" the fact that you could call (org-element-parent) instead of (org-element-parent (org-element-context)) However I see two drawbacks in this optional argument: it hides the call to most expensive function and `org-element-context' is not always what you want (there's no reason to prefer it over `org-element-at-point' and the other way around). Eventually, I'd like to keep `org-element-at-point', `org-element-context' and `org-element-parse-buffer' as the highest level functions in "org-element.el" (i.e., no other function should call them there). Using these functions is out of the scope of the parser. > - not sure what GENEALOGY is useful for; You may grep for `org-export-get-genealogy'. There are a couple of places where this one is used. Actually, this function would also generalize: - `org-export-get-parent-headline' - `org-export-get-parent-element' - `org-export-get-parent-table' > if the user also specified TYPES, this returns the ancestors up to but > NOT including those of TYPE. I admit I didn't put more thoughts into TYPES + GENEALOGY combination. Of course, if this function is implemented, I agree it should also include the first element matching TYPES. > That's another possibility. Unlike a link without description, one might > argue that an empty cell has a natural contents position. For the time being, I prefer all parsing functions to be consistent. Regards, -- Nicolas Goaziou ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2014-09-12 8:29 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2014-09-08 5:37 [BUG] org-table-beginning/end-of-field Florian Beck 2014-09-08 10:25 ` Nicolas Goaziou 2014-09-08 12:17 ` [PATCH] org-table-beginning/end-of-field Florian Beck 2014-09-08 15:30 ` Nicolas Goaziou 2014-09-09 11:09 ` Florian Beck 2014-09-10 13:42 ` Nicolas Goaziou 2014-09-10 17:08 ` Florian Beck 2014-09-12 8:29 ` Nicolas Goaziou
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).