From mboxrd@z Thu Jan 1 00:00:00 1970 From: John Kitchin Subject: Re: org table integrity Date: Sun, 2 Feb 2020 20:50:48 -0500 Message-ID: References: Mime-Version: 1.0 Content-Type: multipart/alternative; boundary="000000000000ae8467059da22779" Return-path: Received: from eggs.gnu.org ([2001:470:142:3::10]:55887) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iyQtD-00034e-Mz for emacs-orgmode@gnu.org; Sun, 02 Feb 2020 20:51:06 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iyQtB-0003rp-Td for emacs-orgmode@gnu.org; Sun, 02 Feb 2020 20:51:03 -0500 Received: from mail-wm1-x335.google.com ([2a00:1450:4864:20::335]:51143) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1iyQtB-0003pP-Fq for emacs-orgmode@gnu.org; Sun, 02 Feb 2020 20:51:01 -0500 Received: by mail-wm1-x335.google.com with SMTP id a5so14055492wmb.0 for ; Sun, 02 Feb 2020 17:51:00 -0800 (PST) In-Reply-To: List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane-mx.org@gnu.org Sender: "Emacs-orgmode" To: Jude DaShiell Cc: org-mode-email --000000000000ae8467059da22779 Content-Type: text/plain; charset="UTF-8" This is a little tricky to guarantee; there are just so many ways to edit a table. One way to do this is like the following. The idea is to use the org-cycle-hook to check the last cell you were in when you pressed TAB in a table. This of course does not work if you don't use tab, and in its current form does not work on shift-tab. You set an #+attr_org line to have list of predicate functions for each column. stringp is tricky, all the cells are strings, so I tried a regexp for numbers. numberp is also not quite right, for me "1a" converts to 1. This code is pretty lightly tested, so tread warily! I had to add the advice for some reason. I don't know why, but it appears to me the org-cycle-hook does not get run inside org-cycle. I don't think this should be necessary, but it was to test this out. Here is the code. After you run it, each time you tab through the table, you should see some messages telling you what was tested, and some of them should cause an error with a message about it. #+BEGIN_SRC emacs-lisp (defun org-timestamp-p (contents) "Return non-nil if CONTENTS is a legal org timestamp" (with-temp-buffer (insert contents) (goto-char (point-min)) (re-search-forward org-element--timestamp-regexp nil t))) (defun check-table-integrity (_state) (interactive) ;; get previous contents (let* ((column) (element (org-element-context)) (attr) (funcs) (field) (valid)) (while (and (org-at-table-p) (not (eq 'table (car element))) (setq element (org-element-property :parent element)))) (when (eq 'table (car element)) (setq attr (car (org-element-property :attr_org element)) funcs (plist-get (read (format "(%s)" attr)) :types)) (save-excursion (org-table-previous-field) (setq column (org-table-current-column) func (nth (- column 1) funcs) field (org-table-get-field) valid (funcall (eval func) (s-trim field))) (message "checking %s field with %s" field func) ;; this is a little tricky. valid is non-nil, and 0 is considered non-nil (unless valid (error "%s did not pass %s" field func)))))) (add-hook 'org-cycle-hook 'check-table-integrity) (advice-add 'org-cycle :after (lambda (x) (cl-loop for func in org-cycle-hook do (funcall func "")))) #+END_SRC #+RESULTS: #+attr_org: :types ('org-timestamp-p (lambda (x) (string-match-p "[0-9]+" x)) 'stringp) | [2020-02-02 Sun] | 1 | no | | [2020-02-09 Sun] | no | yes | | not a ts | 3 | 3 | An alternative way to do this might be to have a function that runs when you leave a table, then it could validate the cells in a similar way. The easy way to do this is with a post-command hook, but this is hard to do without performance hits. The harder way to do it is with cursor sensor functions, but this requires a hack on font-lock for tables. A final way is to make a save/kill-buffer hook function that would map over each table and validate them before allowing the save/kill to complete. John ----------------------------------- Professor John Kitchin Doherty Hall A207F Department of Chemical Engineering Carnegie Mellon University Pittsburgh, PA 15213 412-268-7803 @johnkitchin http://kitchingroup.cheme.cmu.edu On Sat, Feb 1, 2020 at 9:09 PM Jude DaShiell wrote: > Does a way exist in orgmode to fix a column so that it only stores time > stamps? A table I'm using has two columns that could this kind of error > protection and two that should contain text. > > > > -- > > > --000000000000ae8467059da22779 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
This is a little tricky to guarantee; there are just so ma= ny ways to edit a table.

One way to do this is like the = following. The idea is to use the org-cycle-hook to check the last cell you= were in when you pressed TAB in a table. This of course does not work if y= ou don't use tab, and in its current form does not work on shift-tab.= =C2=A0 You set an #+attr_org line to have list of predicate functions for e= ach column. stringp is tricky, all the cells are strings, so I tried a rege= xp for numbers. numberp is also not quite right, for me "1a" conv= erts to 1. This code is pretty lightly tested, so tread warily!
<= br>
I had to add the advice for some reason. I don't know why= , but it appears to me the org-cycle-hook does not get run inside org-cycle= . I don't think this should be necessary, but it was to test this out.<= /div>

Here is the code. After you run it, each time you = tab through the table, you should see some messages telling you what was te= sted, and some of them should cause an error with a message about it.
=

#+BEGIN_SRC emacs-lisp
(defun org-timesta= mp-p (contents)
=C2=A0 "Return non-nil if CONTENTS is a legal org t= imestamp"
=C2=A0 (with-temp-buffer
=C2=A0 =C2=A0 (insert content= s)
=C2=A0 =C2=A0 (goto-char (point-min))
=C2=A0 =C2=A0 (re-search-for= ward org-element--timestamp-regexp nil t)))

(defun check-table-integ= rity (_state)
=C2=A0 (interactive)
=C2=A0 ;; get previous contents=C2=A0 (let* ((column)
(element (org-element-context))
(attr) (funcs)
(field)
(valid))

=C2=A0 =C2=A0 (while (and (org= -at-table-p) (not (eq 'table (car element)))
(setq element (org-el= ement-property :parent element))))

=C2=A0 =C2=A0 (when (eq 'tabl= e (car element))

=C2=A0 =C2=A0 =C2=A0 (setq attr (car (org-element-p= roperty :attr_org element))
=C2=A0 =C2=A0funcs (plist-get (read (forma= t "(%s)" attr)) :types))

=C2=A0 =C2=A0 =C2=A0 (save-excurs= ion
(org-table-previous-field)
(setq column (org-table-current-colu= mn)
=C2=A0 =C2=A0 =C2=A0func (nth (- column 1) funcs)
=C2=A0 =C2= =A0 =C2=A0field (org-table-get-field)
=C2=A0 =C2=A0 =C2=A0valid (funca= ll (eval func) (s-trim field)))

(message "checking %s field wi= th %s" field func)

;; this is a little tricky. valid is non-ni= l, and 0 is considered non-nil
(unless valid
=C2=A0(error "%s= did not pass %s" field func))))))


(add-hook 'org-cycle= -hook 'check-table-integrity)

(advice-add 'org-cycle :after = (lambda (x) (cl-loop for func in org-cycle-hook
=C2=A0 do (funcal= l func ""))))
#+END_SRC

#+RESULTS:

#+attr_org: := types ('org-timestamp-p (lambda (x) (string-match-p "[0-9]+" = x)) 'stringp)
| [2020-02-02 Sun] | =C2=A01 | no =C2=A0|
| [2020-0= 2-09 Sun] | no | yes |
| not a ts =C2=A0 =C2=A0 =C2=A0 =C2=A0 | =C2=A03 = | 3 =C2=A0 |

An alternative way to do this mig= ht be to have a function that runs when you leave a table, then it could va= lidate the cells in a similar way. The easy way to do this is with a post-c= ommand hook, but this is hard to do without performance hits. The harder wa= y to do it is with cursor sensor functions, but this requires a hack on fon= t-lock for tables. A final way is to make a save/kill-buffer hook function = that would map over each table and validate them before allowing the save/k= ill to complete.



=
John

----------------= -------------------
Professor John Kitchin=C2=A0
Doherty Hall A207FDepartment of Chemical Engineering
Carnegie Mellon University
Pitts= burgh, PA 15213
412-268-7803

=
On Sat= , Feb 1, 2020 at 9:09 PM Jude DaShiell <jdashiel@panix.com> wrote:
Does a way exist in orgmode to fix a column so that= it only stores time
stamps?=C2=A0 A table I'm using has two columns that could this kind of= error
protection and two that should contain text.



--


--000000000000ae8467059da22779--