From d63b8422e2fc63fe7a94358c142f53f04fd02d62 Mon Sep 17 00:00:00 2001 From: Grant Shangreaux Date: Fri, 11 Nov 2022 21:41:12 -0600 Subject: Add: inital commit of WIP coorgi-client.org literate program - emacs package template comments - add cl-lib dependency - add coorg-properties defvar - add coorgify-at-point wip implementation - add test org docs for coorgify-at-point --- coorgi-client.org | 272 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 272 insertions(+) create mode 100644 coorgi-client.org (limited to 'coorgi-client.org') diff --git a/coorgi-client.org b/coorgi-client.org new file mode 100644 index 0000000..4844c31 --- /dev/null +++ b/coorgi-client.org @@ -0,0 +1,272 @@ +#+PROPERTY: header-args:emacs-lisp :lexical t + +* Coorgi Client - A collaborative org document sync client. + +#+begin_src emacs-lisp :tangle yes :noweb no-export + ;;; coorgi-client.el --- A collaborative org document sync client. -*- lexical-binding: t; -*- + + <> + + <> + + <> + <> + <> + <> + + ;;; coorgi-client.el ends here +#+end_src + +* dependencies + +#+begin_src emacs-lisp :tangle yes :results none :noweb-ref dependencies + (require 'cl-lib) +#+end_src + +* defvars +:PROPERTIES: +:header-args:emacs-lisp+: :noweb-ref defvars :noweb-sep "\n\n" :results silent +:END: + +** coorgi-properties + +This variable stores a list of upcased symbols that appear in the headline +element's parsed property drawer. + +#+begin_src emacs-lisp :tangle yes :results none + (defvar coorgi-properties '(:COORGI-KEY + :COORGI-LAST-MODIFIED + :COORGI-LAST-MODIFIED-BY + :COORGI-VERSION) + "List of properties coorgi cares about.") +#+end_src + +* Functions +** coorgify-at-point + +Converts the current org outline section into a coorgi-node data structure. + +#+name: coorgify-at-point +#+begin_src emacs-lisp :results none + (defun coorgify-at-point () + (save-excursion + (let* ((current-element (org-element-at-point)) + (entry (if (not (equal (car current-element) 'heading)) + (progn (org-up-heading-safe) + (org-element-at-point)) + current-element)) + (parsed (print (org-element-parse-buffer))) + (props (org-element--get-node-properties)) + (non-coorgi-props (cl-loop for (key value) on props by #'cddr + unless (member key coorgi-properties) + append (list key value))) + (content-bounds (cons (progn (org-down-element) (org-forward-element) (point)) (plist-get (cadr entry) :contents-end)))) + `( type entry + headline ,(plist-get (cadr entry) :title) + version ,(string-to-number (plist-get props :COORGI-VERSION)) + last-modified-by ,(plist-get props :COORGI-LAST-MODIFIED-BY) + last-modified ,(plist-get props :COORGI-LAST-MODIFIED) + key ,(plist-get props :COORGI-KEY) + properties ,non-coorgi-props + contents ,(buffer-substring-no-properties (car content-bounds) (cdr content-bounds)))))) +#+end_src + +*** helpers +**** coorgi--find-heading + +We need to used the parsed version of the org buffer to look up the elements +we're turning into coorgi nodes and get the relevant data to pack it up recursively. + +#+name: coorgi--find-heading +#+begin_src emacs-lisp :results none + (defun coorgi--find-heading (heading org-data) + (car (org-element-map org-data 'headline + (lambda (hl) + (when (string-equal (org-element-property :raw-value hl) + (org-element-property :raw-value heading)) + hl))))) +#+end_src + +#+begin_src emacs-lisp :var org-doc=trivial-example() :results code + (let ((org-data (with-temp-buffer (insert org-doc) (org-element-parse-buffer)))) + (coorgi--find-heading '(headline (:raw-value "MOO")) org-data)) +#+end_src + +#+RESULTS: +#+begin_src emacs-lisp +(headline + (:raw-value "MOO" :begin 1 :end 142 :pre-blank 0 :contents-begin 7 :contents-end 142 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 1 :FOO "bar" :COORGI-KEY "101" :COORGI-LAST-MODIFIED "123" :COORGI-LAST-MODIFIED-BY "colin/123" :COORGI-VERSION "1" :title + (#("MOO" 0 3 + (:parent #0))) + :parent + (org-data nil #0)) + (section + (:begin 7 :end 142 :contents-begin 7 :contents-end 142 :post-blank 0 :post-affiliated 7 :parent #0) + (property-drawer + (:begin 7 :end 136 :contents-begin 20 :contents-end 129 :post-blank 1 :post-affiliated 7 :parent #1) + (node-property + (:key "coorgi-version" :value "1" :begin 20 :end 39 :post-blank 0 :post-affiliated 20 :parent #2)) + (node-property + (:key "coorgi-last-modified-by" :value "colin/123" :begin 39 :end 75 :post-blank 0 :post-affiliated 39 :parent #2)) + (node-property + (:key "coorgi-last-modified" :value "123" :begin 75 :end 102 :post-blank 0 :post-affiliated 75 :parent #2)) + (node-property + (:key "coorgi-key" :value "101" :begin 102 :end 119 :post-blank 0 :post-affiliated 102 :parent #2)) + (node-property + (:key "foo" :value "bar" :begin 119 :end 129 :post-blank 0 :post-affiliated 119 :parent #2))) + (paragraph + (:begin 136 :end 142 :contents-begin 136 :contents-end 142 :post-blank 0 :post-affiliated 136 :parent #1) + #("hello\n" 0 6 + (:parent #2))))) +#+end_src + +*** Testing + +**** Trivial Org Example + +Given this org document: + +#+name: trivial-example +#+begin_src org +,* MOO +:PROPERTIES: +:coorgi-version: 1 +:coorgi-last-modified-by: colin/123 +:coorgi-last-modified: 123 +:coorgi-key: 101 +:foo: bar +:END: + +hello + +#+end_src + +~coorgify-at-point~ should return something like this: + +#+name: trivial-expected-value +#+begin_src emacs-lisp + '(type entry + headline "MOO" + version 1 + last-modified-by "colin/123" + last-modified "123" + key "101" + properties (:FOO "bar") + content " + hello + + " + children ()) +#+end_src + +No matter where the cursor is in the buffer (there's only one coorgi node) + +***** TODO When the cursor is in the body of the heading + +#+name: test-trivial-example-cursor-in-body +#+begin_src emacs-lisp :var org-doc=trivial-example() expected=trivial-expected-value :results code + (let ((subject (with-temp-buffer (insert org-doc) (coorgify-at-point)))) + (if (not (equal subject expected)) + `((actual ,subject) (expected ,expected)) + "PASS")) +#+end_src + +#+RESULTS: test-trivial-example-cursor-in-body +#+begin_src emacs-lisp +((actual + (type entry headline "MOO" version 1 last-modified-by "colin/123" last-modified "123" key "101" properties + (:FOO "bar") + contents "hello\n")) + (expected + (type entry headline "MOO" version 1 last-modified-by "colin/123" last-modified "123" key "101" properties + (:FOO "bar") + content "\n\nhello\n\n" children nil))) +#+end_src + +***** TODO When the cursor at the top of the document + +#+name: test-trivial-example-cursor-at-top +#+begin_src emacs-lisp :var org-doc=trivial-example() expected=trivial-expected-value :results code + (let ((subject (with-temp-buffer (insert org-doc) (beginning-of-buffer) (coorgify-at-point)))) + (if (not (equal subject expected)) + `((actual ,subject) (expected ,expected)) + "PASS")) +#+end_src + +#+RESULTS: test-trivial-example-cursor-at-top +#+begin_src emacs-lisp +((actual + (type entry headline "MOO" version 1 last-modified-by "colin/123" last-modified "123" key "101" properties + (:FOO "bar"))) + (expected + (type entry headline "MOO" version 1 last-modified-by "colin/123" last-modified "123" key "101" properties + (:FOO "bar") + content "\n\nhello\n\n" children nil))) +#+end_src + +**** Basic Org Example + +#+name: basic-example +#+begin_src org +,* MOO +:PROPERTIES: +:coorgi-version: 211 +:coorgi-last-modified-by: “colin/1231234123” +:coorgi-last-modified: 123124331 +:coorgi-key: “1010101010101” +:foo: “bar” +:END: + +hello + +,** TODO [#B] Cow :foobar: +:PROPERTIES: +:coorgi-version: 32 +:coorgi-last-modified-by: “colin/1231234123” +:coorgi-last-modified: 123124331 +:coorgi-key: “123sdfas3wasd” +:foo: “bar” +:END: + +Cows say moo. CURSORPOSITION + +,*** Hunky + +a cow + +,*** Dory + +another cow +#+end_src + +* Copyright + +#+begin_src emacs-lisp :noweb-ref copyright + ;; Copyright (C) 2022 Grant Shangreaux + + ;; Author: Grant Shangreaux + ;; Maintainer: Grant Shangreaux + ;; Created: 11 Nov 2022 + ;; Keywords: org sync collaborative + ;; URL: https://cicadas.surf/cgit/coorgi-client.git +#+end_src + +* License +** GNU General Public License version 3 + +#+begin_src emacs-lisp :noweb-ref license + ;; This file is not part of GNU Emacs. + + ;; This file is free software: you can redistribute it and/or modify + ;; it under the terms of the GNU General Public License as published by + ;; the Free Software Foundation, either version 3 of the License, or + ;; (at your option) any later version. + ;; + ;; GNU Emacs is distributed in the hope that it will be useful, + ;; but WITHOUT ANY WARRANTY; without even the implied warranty of + ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + ;; GNU General Public License for more details. + ;; + ;; You should have received a copy of the GNU General Public License + ;; along with this file. If not, see . +#+end_src -- cgit v1.2.3