ndwarshuis / org-ml Goto Github PK
View Code? Open in Web Editor NEW(formerly om.el) A functional library for org-mode
License: GNU General Public License v3.0
(formerly om.el) A functional library for org-mode
License: GNU General Public License v3.0
I have a node of the form:
(org-data (:begin 1 :end 700) (section) (headline) (headline))
I want to change the number of headlines. Specfically I want to add my own headlines and make sure the headlines are in alphabetical order based on title. However, org-ml-set-children
raises the error (error "Child type restrictions not found for %s" type)
for org-data
. I'd like to be able to modify the children of the org-data
type and use (setf (buffer-string) (org-ml-to-string modified-node))
to change the buffer.
Also I could not find a build function for the org-data
type.
I'm getting the points of headlines to use with org-ml-update-headline-at
and found a false positive when using (org-ml-parse-headlines 'all)
:
*this is some bold text* in a paragraph
* this is a headline
Both of these get returned as headlines
I think this is the pattern?:
Line 6988 in a2f7101
I find this project more promising and accessible than org-element.
Thanks for the efforts!
But is there somewhere a "hello world"?
Yeah I see a good amt of documentation in docs/api-refeence.md
I am looking for a simple end-to-end reference with setting up of hooks, export etc
ie some toy example that uses org-ml API and say transforms some org file into another?
If possible something that transforms:
*** Lorem Ipsum :LAW:
into
#+begin_law
Lorem Ipsum
#+end_law
would be wonderful.
But if even a simpler eg is given/pointed out I can hack from there on.
org-ml 20200902.133 incompat melpa Functional Org Mode API
emacs 26.3 on windows 10
org 9.3.7
(setq package-archives '(
("gnu" . "http://elpa.gnu.org/packages/")
("org" . "http://orgmode.org/elpa/")
("melpa" . "http://melpa.org/packages/")))
I wonder if you could provide some examples of filtering an org node tree, maybe analogously to the way org agenda or org-sparse-tree allow filtering? I am trying to convert a library to use org-ml, and I'd like to be able to parse a buffer, then filter for the headlines I need & use some properties from those headlines for an HTTP request. Does org-ml have dedicated functions for the parsing, or will I need to just become a better programmer and write my own? Thanks!
Hi,
In Org commit fc80d052d
, which was recently merged into the 9.5 release, the following addition was made to org-element--parse-elements
:
(defun org-element--parse-elements
(beg end mode structure granularity visible-only acc)
...
+ (org-element-put-property acc :granularity granularity)
...)
The definition of org-element-put-property
does not allow for acc
to be nil:
(defsubst org-element-put-property (element property value)
"In ELEMENT set PROPERTY to VALUE.
Return modified element."
(if (stringp element) (org-add-props element nil property value)
(setcar (cdr element) (plist-put (nth 1 element) property value))
element))
I haven't investigated the scope on which Org-ml has been affected, just for example org-ml--parse-headline-subtree-at
has the following call:
(org-element--parse-elements b e 'first-section
nil nil nil nil)
In effect, the above call results in (setcar nil ...)
throwing an error (wrong-type-argument consp nil)
.
** second level
(org-parse-subtrees 'all) => nil
Surprising and not documented. But the code is clear:
(defun org-ml-parse-subtrees (which)
"Return list of subtree nodes from current buffer.
WHICH has analogous meaning to that in `org-ml-parse-headlines'
except applied to subtrees not individual headlines."
(org-ml--parse-patterns-where which "^\\* "))
Hi and thanks for org-ml!
I was looking for functions doing what in org is usually called "promoting" and "demoting" (for example org-promote
) and realized that this is achieved with the indent/unindent functions.
Would it be better to use function names like "demote" and "promote" to better reflect the terminology in org-mode (even though I realize that org-ml intentionally departs from some of the terminology in org-element)? "Indent" is also used for things relating to real or displayed whitespace in org-mode.
Consider this org-mode file:
#+TITLE: Test Title
There’s still room for improvement:
+ A few big chunks of this file are still mostly verbatim copies from
my old configuration file with little by way of new documentation.
+ There’s still a bunch of undocumented configuration in libraries in
=~/.emacs.d/personal/*.el= that would benefit from greater
documentation.
* heading
Insert something here.
I'm trying to walk through it, parsing each org element. Suppose I get to point 59.
If you goto point 59 and run (org-element-at-point)
, it will return something like this:
(plain-list (:type unordered :begin 59 :end 347
:contents-begin 59 :contents-end 346 :structure ...)
If you run (om-parse-element-at 59)
, it will return something like this:
(plain-list (:type unordered :begin 59 :end 346
:contents-begin 59 :contents-end 346 :structure ...)
Note that :end
is one character short here. Unfortunately, if you run (om-parse-element-at 346)
, you'll discover that you get back the same plain-list and you're in an infinite loop.
Unfortunately, it isn't always one character short, so I don't think the solution is to always add one. But I haven't worked out from the output of om-parse-element-at
when I should add one.
Bug or misundertanding on my part?
Here's a test case. Evaluate the following elisp while on the foo
headline (e.g. with eval-expression
):
(let ((headline (org-ml-parse-this-subtree)))
(save-excursion
(goto-char (point-min))
(insert (org-ml-to-string (org-ml-headline-set-node-property "FOO" "BAR" headline)))))
* foo
** bar
With org-ml Version: 4.0.1, this inserts on my machine:
* foo
:PROPERTIES:
:FOO: BAR
:END:
** bar
This (missing newline) works fine:
* foo
** bar
It seems that set-node-property returns a weird section before the property drawer?:
(headline (:raw-value "foo" :begin 1 :end 15 :pre-blank 0 :contents-begin 7 :contents-end 14 ...)
(section (:post-blank 0 :begin nil :end nil :parent nil :contents-begin nil :contents-end nil ...)
(property-drawer (:post-blank 0 :begin nil :end nil :parent nil :contents-begin nil :contents-end nil ...) (node-property ...)))
(headline (:raw-value "bar" :begin 7 :end 14 :pre-blank 0 :contents-begin nil :contents-end nil ...)))
Hi again,
FYI, you may find this useful: https://github.com/alphapapa/makem.sh I recently pushed some improvements that make it even easier to use, both locally and as a GitHub action.
I'm writing code that extracts elements from a number of org-mode buffers and writes new elements based on them into a new buffer. I've encountered two places where I've wanted to change the parent:
nil
.This led me to look for ways to reparent/orphan elements/objects in the API, but this doesn't seem to be supported, and in some cases is specifically disallowed. (Property ’:parent’ is unsettable for type ’headline’
when trying to set :parent
with org-ml-set-property
, for instance.)
I assume you have reasons for this; I was wondering what those are. Is there a semantic difference between the node referred to by the :parent
property and whichever org-element list a node is currently enclosed in? Are there approved ways to create a node from the content of another node, but with a different/empty :parent
property?
Sorry if this is already documented; I looked, but didn't come across anything. Thanks for humoring my curiosity, and thanks for this outstanding library.
I think I'm asking a well-formed questions, but I do feel a little unsure, os apologies if this is inaccurate.
From what I can tell, org-element and org-ql store headline properties as simple plist properties in the headline's definition. org-ml seems to separate them out into a property drawer. I'd like to, for instance, grab a headline with properties from one buffer and reproduce it in a different buffer with a couple of property changes and a large number of child headlines. My thought was to do something like:
(let* ((assignment (car (org-ql-select "./Assignments.org"
'(and (heading "Fake Assignment for Testing")(tags "assignment")))))
(students '("Jimmy" "Mary" "Sunit" "Jasmine"))
(children (--map (org-ml-build-headline :level 2 :title `(,it)) students)))
(->> (org-ml-set-children children assignment)
(org-ml-to-trimmed-string)))
but the resultant string eliminates the parent's property drawer. I guess I need to manually recreate the property drawer and add it a a child? Yet this seems unnecessarily complex. Is there some trick for extracting the property drawer from a headline object returned by org-element?
Hello!
I love om.el
, but I've hit one problem that might be a bug.
I use org-link abbreviations in my orgmode files, where an initial keyword in a link, followed by a colon, can cause the rest of the link to be converted or changed before the link is followed. So "wiki:blah" as a link could end up taking the user to a "~/txt/wiki/blah.org" file instead. The transformations are defined in org-link-abbrev-alist.
When I'm parsing one of these files, this link destination is expanded in the parsed results -- which means that if I use that value to update the current file, the original abbreviation is changed into its fully expanded form. That means that updating can create a side-effect of expanding these links.
Here's a small test-case which I think works on its own:
(let ((test-org "Hello [[test:foo]]")
(org-link-abbrev-alist '(("test" . "i-am-transformed-from-"))))
(with-temp-buffer
(insert test-org)
(om-to-trimmed-string (om-parse-this-element))))
As you should hopefully see, the result doesn't match the input.
* bar foo
# (org-ml-to-string (org-ml-get-property :title (org-ml-parse-this-headline)))
# this evaluates to 1:
# (length (org-ml-get-property :title (org-ml-parse-this-headline)))
Just evaluate the call in the comment, it returns the title text concatenated four times. Am I somehow still using this incorrectly?
Edit: again, this seems to be an org-element bug? The org-format is also not very strict and/or explicit on this...
Evalute
(org-ml-update* (org-ml-headline-set-node-property "TEST" "TEST" it) (org-ml-parse-this-subtree))
on
* test
:END:
results in:
* test
:PROPERTIES:
:TEST: TEST
:END:
:END:
:END:
Subsequent evaluations of the same quickly spiral into oblivion:
* test
:PROPERTIES:
:TEST: TEST
:END:
:PROPERTIES:
:TEST: TEST
:END:
:END:
:END:
:END:
:END:
$ ls -alh
-rwxr-xr-x 1 hrehfeld hrehfeld 4.1M Oct 31 22:59 test.org
(org-ml-parse-this-subtree)
and (org-element-parse-buffer)
parse a drawer named END
:
(headline
(:raw-value "TEST" :begin 1 :end 15 :pre-blank 1 :contents-begin 9 :contents-end 15 :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 :title (#("TEST" 0 4 (:parent #0))) :parent nil)
(section (:begin 9 :end 15 :contents-begin 9 :contents-end 15 :post-blank 0 :post-affiliated 9 :parent #0)
(drawer (:begin 9 :end 15 :drawer-name "END" :contents-begin nil :contents-end nil :post-blank 0 :post-affiliated 9 :parent #1))))
Interestingly, this doesn't duplicate:
(org-ml-update* #'identity (org-ml-parse-this-subtree))
but this does:
(org-ml-insert-tail (point) (org-ml-parse-this-subtree))
So does this:
(org-ml-update* (org-ml-headline-set-title! "TEST" nil it) (org-ml-parse-this-subtree))
Maybe because the first doesn't update at all?
If I got a headline
* TODO [[https://xyz.tld][FooBar]]
And try to get the raw-link via
(->> (om-parse-this-headline)
(om-get-property :title)
(-first-item)
(om-get-property :raw-link))
I get the error
om--arg-error: Argument type error: "Unsettable property ’:raw-link’ for type ’link’ requested; settable properties are :path, :format, :type, :raw-link, :application, :search-option, :post-blank"
I reported a bug against straight.el
that appears to be a problem in om.el
:
I get:
Debugger entered--Lisp error: (void-variable om-elements)
(-intersection om-branch-nodes-permitting-child-objects om-elements)
(defconst om-branch-elements-permitting-child-objects (-intersection om-branch-nodes-permitting-child-objects om-elements) ("/Users/ndw/.emacs.d/straight/build/om/om.elc" . 741))
require(om)
eval((require (quote om)) nil)
elisp--eval-last-sexp(t)
eval-last-sexp(t)
eval-print-last-sexp(nil)
funcall-interactively(eval-print-last-sexp nil)
call-interactively(eval-print-last-sexp nil nil)
command-execute(eval-print-last-sexp)
The maintainer of straight.el
says:
That is a bug in the package as far as I can tell. It should not be using eval-when-compile for that code. When I run make compile from the package's Makefile, then manually evaluate the resulting .elc files, I get the same error. Given that, I don't think the problem lies with straight.el.
Hope this is useful.
Hi,
it seems the parser for tables doesn't work. Here is an example:
| 2 | 1 | 1 | 0 | -1 | -1 | 0 |
|------+---+------+-------+----+------+---|
| P(a) | a | a | a | a | V(a) | |
| | | P(b) | b | b | b | b |
| | | | P(c)) | c- | c- | c |
running (org-ml-to-string (org-ml-parse-this-element))
returns this
| 2 | 1 | 1 | 0 | -1 | -1 | 0 |
|-------+----+----+---+----+------+---|
| P(a) | a | a | a | a | V(a) | |
| P(b) | b | b | b | b | | |
| P(c)) | c- | c- | c | | | |
So it seems empty cells are shifted to the end of the table.
Both build-headline
functions seem to be broken.
With either
(om-build-headline :title "really impressive title")
(om-build-headline! :title-text "really impressive title")
I get om--arg-error: Argument type error: "Unsettable property ’:post-blank’ for type ’headline’ requested; settable properties are :archivedp, :commentedp, :footnote-section-p, :level, :pre-blank, :priority, :tags, :title, :todo-keyword, :raw-value, :todo-type"
Emacs Version:
GNU Emacs 26.3 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.10)
The documentation for org-ml-build-table! says that "row-lists is a list of lists," but when I try to use a list of lists I get an error. E.g., (org-ml-build-table! '(("R" "A") ("G" "E")))
throws an error, whereas (apply #'org-ml-build-table! '(("R" "A") ("G" "E")))
works as expected (as does the example in the documentation).
Please take a look at https://list.orgmode.org/874jnudps5.fsf@localhost/T/#u
The upcoming changes to Org element API are likely going to break org-ml as the internal representation of Org parse tree is going to be altered.
* Foo Bar
# doesn't change point
# (org-ml-update* (identity it) (org-ml-parse-this-headline))
# changes point to beginning of * Foo
# (org-ml-update* (org-ml-headline-set-node-property "title" "test" it) (org-ml-parse-this-headline))
# changes point to beginning of * Foo
# (save-excursion (org-ml-update* (org-ml-headline-set-node-property "title" "test" it) (org-ml-parse-this-headline)))
I sortof understand why this might happen, however it would be awesome to have better behavior here.
Doesn't org-mode have some sort of logic to save & find context around links? Maybe we can hijack that, otherwise it might be possible to save a priority queue of things to jump to near point.
The API documentation is missing entries for org-ml-parse-this-object
, org-ml-parse-this-headline
, etc.
Great package! Very useful.
Hi,
I'm trying to frame a proper response to your helpful comment in #33, but am running into an issue that looksl ike it might be a bug.
I'm generating a long set of subtrees with this code:
* Fake Assignment forTesting :ASSIGNMENT:
:PROPERTIES:
:ASSIGNMENT_WEIGHT: 10
:ASSIGNMENTID: 735871
:ASSIGNMENT_NAME: Fake Assignment for Testing
:ORG_LMS_ASSIGNMENT_DIRECTORY: fake-assignment-for-testing
:GRADING_TYPE: letter_grade
:IS_QUIZ: nil
:ORG_LMS_EMAIL_COMMENTS: t
:ORG_LMS_CANVAS_COMMENTS: t
:END:
#+begin_src emacs-lisp
(save-excursion
(forward-line)
(--map (insert
(format "** TODO Matthew Price %s
:PROPERTIES:
:GRADE: %s
:CHITS: 0
:NICKNAME: Matthew
:FIRSTNAME: Matthew
:LASTNAME: Price
:MAIL_TO: [email protected]
:GITHUB:
:ORG_LMS_REPO_BASENAME:
:STUDENTID: 85514
:GRADE_URL: https://q.utoronto.ca/courses/35724/gradebook/speed_grader?assignment_id=735871
:COURSEID: 35724
:BASECOMMIT: none
:ORG_LMS_ASSIGNMENT_DIRECTORY: fake-assignment-for-testing
:MAIL_REPLY: [email protected]
:MAIL_SUBJECT: Comments on Assignment
:END:
fdsfds %s %s %s
" it it it it it )) (number-sequence 1 100)))
#+end_src
After the trees have been created, I try to modify them in place with:
** Final Subtree
#+begin_src emacs-lisp :results code
(save-excursion
(outline-up-heading 1)
(let ((items
(->> (org-ml-parse-subtree-at (point))
(org-ml-match '((:todo-keyword "TODO"))))))
(--map
(org-ml-update (lambda (hl)
(org-ml-set-property :todo-keyword "READY" hl))
it) items)))
#+end_src
When I run this code, I lose any whitespace at the end of an updated subtree, so that the next subtree pops up into the section of the previous heading. As a result, the structure breaks down.
I'm assuming this is an issue with mapping over multiple headlings -- I don't see the issue when I replace only one heading at a time.
Do you see an obvious problem with my code?
getting this error on load:
Warning (initialization): An error occurred while loading ‘c:/users/ian/.emacs.d/init.el’:Symbol's value as variable is void: om-elements
Hi! I've just started experimenting with org-ml
and find it awesome!
It seems that org-ml-parse-table-row-at
parses only the first table row of a table and return nil if point it elsewhere in the table.
Here's the following minimal example to reproduce the issue:
test.org:
| a | b |
|---+---|
| c | d |
test.el:
(with-current-buffer "test.org"
(->> (org-ml-parse-table-row-at 10) ;; first row, (point) 1 to 10
(org-ml-get-type)))
=> table-row
(with-current-buffer "test.org"
(->> (org-ml-parse-table-row-at 11) ;; second row and onwards
(org-ml-get-type)))
=> nil
This looks like https://github.com/alphapapa/org-ql, though it looks like org-ml might be more comprehensive?
What are the differences / what's the relationship between the two?
this is what is shown in the instructions:
M-x package-install RET org-sql RET
I just updated the package, is this related to something else?
Debugger entered--Lisp error: (invalid-function (make-plist (arg init) (let* ((kw (org-ml--symbol-to-keyword arg)) (kw-get `(cadr (plist-member ... ...))) (val (if init `(or ... ...) kw-get))) (cons kw `(,arg ,val)))))
(make-plist (arg init) (let* ((kw (org-ml--symbol-to-keyword arg)) (kw-get `(cadr (plist-member ,kws-sym '...))) (val (if init `(or ,kw-get ,init) kw-get))) (cons kw `(,arg ,val))))()
org-ml--make-kwarg-let(--kw-args inside-header)
#f(compiled-function (it) #<bytecode 0x1580d089ebe1>)(inside-header)
mapcar(#f(compiled-function (it) #<bytecode 0x1580d089ebe1>) (inside-header arguments end-header post-blank))
org-ml--transform-lambda((call &key inside-header arguments end-header post-blank) ("Build a babel-call element node.\n\nThe following pr..." (->> (org-ml--build-leaf-node 'babel-call post-blank) (org-ml--set-properties-nocheck-nil (list :value :begin :end :parent :post-affiliated)) (org-ml-set-properties (list :inside-header inside-header :arguments arguments :end-header end-header :call call)))) org-ml-build-babel-call)
#f(compiled-function (name arglist &rest body) "Define NAME as a function with BODY.\n\nThis is like `cl-defun' except it allows &key to be used in\nconjunction with &rest without freaking out. ARGLIST can be specified\nusing the following syntax:\n\n([VAR] ...\n [&key (VAR [INITFORM])...]\n [&rest VAR])\n\nwhere VAR is a symbol for the variable identifier and INITFORM is an\natom or form that will be the default value for keyword VAR if it is\nnot give in a function call.\n\nWhen calling functions defined with this, keywords can be given in any\norder as long as they are after all positional arguments, and rest\narguments will be interpreted as anything not belonging to a key-val\npair (but only if &rest was used to define the function). This implies\nthat keywords may not be used as values for the rest argument in\nfunction calls." #<bytecode 0x1580cfb1bf01>)(org-ml-build-babel-call (call &key inside-header arguments end-header post-blank) "Build a babel-call element node.\n\nThe following pr..." (->> (org-ml--build-leaf-node 'babel-call post-blank) (org-ml--set-properties-nocheck-nil (list :value :begin :end :parent :post-affiliated)) (org-ml-set-properties (list :inside-header inside-header :arguments arguments :end-header end-header :call call))))
macroexpand((org-ml--defun-kw org-ml-build-babel-call (call &key inside-header arguments end-header post-blank) "Build a babel-call element node.\n\nThe following pr..." (->> (org-ml--build-leaf-node 'babel-call post-blank) (org-ml--set-properties-nocheck-nil (list :value :begin :end :parent :post-affiliated)) (org-ml-set-properties (list :inside-header inside-header :arguments arguments :end-header end-header :call call)))))
(let* ((type (car entry)) (name (intern (format "org-ml-build-%s" type))) (props (->> (cdr entry) (--remove (eq :post-blank (car it))) (-non-nil) (-group-by #'org-ml--autodef-categorize-prop))) (pos-args (->> (alist-get 'req props) (--map (org-ml--autodef-kwd-to-sym (car it))))) (kw-args (->> (alist-get 'key props) (--map (let ((prop ...) (default ...)) (if default `... prop))))) (rest-arg (cond ((memq type org-element-greater-elements) 'element-nodes) ((memq type org-element-object-containers) 'object-nodes))) (args (let ((a `(... &key ... post-blank))) (if rest-arg `(,@a &rest ,rest-arg) a))) (const-props (-some->> (alist-get 'const props) (--mapcat (list (car it) (plist-get (cdr it) :const))) (org-ml--autodef-prop-form 2 #'org-ml--set-property-nocheck #'org-ml--set-properties-nocheck))) (nil-props (-some->> (alist-get 'null props) (-map #'car) (org-ml--autodef-prop-form 1 #'org-ml--set-property-nocheck-nil #'org-ml--set-properties-nocheck-nil))) (strict-props (-some->> (append (alist-get 'key props) (alist-get 'req props)) (-map #'car) (--mapcat (list it (org-ml--autodef-kwd-to-sym it))) (org-ml--autodef-prop-form 2 #'org-ml-set-property #'org-ml-set-properties))) (doc (org-ml--autodef-make-docstring type rest-arg props)) (builder (let ((a `(... post-blank))) (if rest-arg `(org-ml--build-branch-node ,@a ,rest-arg) `(org-ml--build-leaf-node ,@a)))) (body (if (or strict-props nil-props const-props) `(->> ,@(-non-nil ...)) builder))) (macroexpand `(org-ml--defun-kw ,name ,args ,doc ,body)))
org-ml--autodef-build-node-form((babel-call (:call :pred org-ml--is-oneline-string :type-desc "a oneline string" :require t) (:inside-header :encode org-ml--encode-plist :pred org-ml--is-plist :decode org-ml--decode-plist :plist t :type-desc "a plist") (:arguments :encode org-ml--encode-string-list-comma-delim :decode org-ml--decode-string-list-comma-delim :pred org-ml--is-string-list :string-list t :type-desc "a lthing elist of oneline strings") (:end-header :encode org-ml--encode-plist :pred org-ml--is-plist :decode org-ml--decode-plist :plist t :type-desc "a plist") (:value) (:post-blank :pred org-ml--is-non-neg-integer :shift org-ml--shift-non-neg-integer) (:begin) (:end) (:parent) (:post-affiliated)))
(closure (... t) (it) (org-ml--autodef-build-node-form it))((babel-call (:call :pred org-ml--is-oneline-string :type-desc "a oneline string" :require t) (:inside-header :encode org-ml--encode-plist :pred org-ml--is-plist :decode org-ml--decode-plist :plist t :type-desc "a plist") (:arguments :encode org-ml--encode-string-list-comma-delim :decode org-ml--decode-string-list-comma-delim :pred org-ml--is-string-list :string-list t :type-desc "a list of oneline strings") (:end-header :encode org-ml--encode-plist :pred org-ml--is-plist :decode org-ml--decode-plist :plist t :type-desc "a plist") (:value) (:post-blank :pred org-ml--is-non-neg-integer :shift org-ml--shift-non-neg-integer) (:begin) (:end) (:parent) (:post-affiliated)))
mapcar((closure ... ... ...) (... ... ... ... ... ... ... ... ... ... ... ... ... ... ...))
(--map (org-ml--autodef-build-node-form it) it)
(-as-> (--map (org-ml--autodef-build-node-form it) it) it)
(let ((it (--remove (eq 'plain-text (car it)) org-ml--property-alist))) (-as-> (--map (org-ml--autodef-build-node-form it) it) it))
(-as-> (--remove (eq 'plain-text (car it)) org-ml--property-alist) it (--map (org-ml--autodef-build-node-form it) it))
(--> (--remove (eq 'plain-text (car it)) org-ml--property-alist) (--map (org-ml--autodef-build-node-form it) it))
(let ((forms (--> (--remove (eq 'plain-text (car it)) org-ml--property-alist) (--map (org-ml--autodef-build-node-form it) it)))) `(progn ,@forms))
(closure (t) nil "Define all build node functions." (let ((forms (--> (--remove (eq 'plain-text (car it)) org-ml--property-alist) (--map (org-ml--autodef-build-node-form it) it)))) `(progn ,@forms)))()
(org-ml--autodef-build-node-functions)
eval-buffer(#<buffer *load*> nil "/home/hrehfeld/.emacs.d/elpa/org-ml-20200927.1906/..." nil t) ; Reading at buffer position 59573
load-with-code-conversion("/home/hrehfeld/.emacs.d/elpa/org-ml-20200927.1906/..." "/home/hrehfeld/.emacs.d/elpa/org-ml-20200927.1906/..." t t)
require(org-ml nil t)
(not (require 'org-ml nil t))
(if (not (require 'org-ml nil t)) (display-warning 'use-package (format "Cannot load %s" 'org-ml) :error))
(condition-case err (if (not (require 'org-ml nil t)) (display-warning 'use-package (format "Cannot load %s" 'org-ml) :error)) ((debug error) (funcall use-package--warning285 :catch err)))
(progn (use-package-ensure-elpa 'org-ml '(t) 'nil) (defvar use-package--warning285 #'(lambda (keyword err) (let ((msg (format "%s/%s: %s" ... keyword ...))) (display-warning 'use-package msg :error)))) (condition-case err (if (not (require 'org-ml nil t)) (display-warning 'use-package (format "Cannot load %s" 'org-ml) :error)) ((debug error) (funcall use-package--warning285 :catch err))))
(progn (progn (use-package-ensure-elpa 'org-ml '(t) 'nil) (defvar use-package--warning285 #'(lambda (keyword err) (let ((msg ...)) (display-warning 'use-package msg :error)))) (condition-case err (if (not (require 'org-ml nil t)) (display-warning 'use-package (format "Cannot load %s" 'org-ml) :error)) ((debug error) (funcall use-package--warning285 :catch err)))))
eval((progn (progn (use-package-ensure-elpa 'org-ml '(t) 'nil) (defvar use-package--warning285 #'(lambda (keyword err) (let (...) (display-warning ... msg :error)))) (condition-case err (if (not (require 'org-ml nil t)) (display-warning 'use-package (format "Cannot load %s" 'org-ml) :error)) ((debug error) (funcall use-package--warning285 :catch err))))) t)
elisp--eval-last-sexp(nil)
eval-last-sexp(nil)
funcall-interactively(eval-last-sexp nil)
call-interactively(eval-last-sexp nil nil)
command-execute(eval-last-sexp)
Version flag in org-ml.el
: ;; Version: 4.0.1
GNU Emacs 27.1.50 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.22, cairo version 1.17.3) of 2020-08-23
This also happens with:
$ emacs -Q
(add-to-list 'load-path "~/.emacs.d/elpa/org-ml-20200927.1906/")
(add-to-list 'load-path "~/.emacs.d/elpa/dash-20200803.1520/")
(add-to-list 'load-path "~/.emacs.d/elpa/s-20180406.808/")
(require 'org-ml)
and also if I add the recently updated org
packages:
(add-to-list 'load-path "~/.emacs.d/elpa/org-plus-contrib-20201005/")
(add-to-list 'load-path "~/.emacs.d/elpa/org-20201005/")
Is this the recommended way to do that:
#+BEGIN_SRC emacs-lisp
(concat (->> (om-build-headline :todo-keyword "TODO" :archivedp t :commentedp t :priority 65)
(om-to-trimmed-string))
"\n"
(->>
(om-build-property-drawer! '(key val))
(om-to-trimmed-string)))
#+END_SRC
Is there a way to get the properties indented?
I thought the properties would be a child node of a headline, but that seems to be illegal.
context: I'm trying to remove the properties drawer from a node before I render it as a string.
The issue I'm running into can be shown with the last example in the docs here.
with the content:
* headline
:PROPERTIES:
:ID: fake
:END:
The example code returns the whole content, instead of just the headline like in the example:
(->> (org-ml-parse-this-headline)
(org-ml-headline-set-node-property "ID" nil)
(org-ml-to-trimmed-string))
;; => "* headline\n:PROPERTIES:\n:ID: fake\n:END:"
;; ! expected: "* headline"
EDIT: org version: Org mode version 9.4 (release_9.4-174-gf6e41c @ /home/neeasade/.emacs.d/straight/build/org/)
EDIT: org-ml version: d856ac6
OT: Thank you so much for org-ml. It has given me the tools for shaping org the way I want, and helped me cross the gap to "complete" WRT my personal notes system.
Hi. As the title says, running org-ml-get-headlines
in the following buffer only returns the headlines "Heading 1" and "Heading 2".
* Heading 1
** Heading 2
*** Heading 3
Is this supposed to be the expected behaviour?
Given two source blocks with a tangle parameter, accessing the tangle parameter is quite different depending on if it is found in a HEADER or on the BEGIN_SRC line.
As a minimal example, here is the contents of an org file named org-ml-header-bug-minimal-example.org with the following contents:
#+TITLE: Org Ml Header Bug Minimal Example
* A code block with a tangle argument in a HEADER
#+HEADER: :tangle ~/path/to/hello-org-ml.el
#+BEGIN_SRC emacs-lisp
(message "%s" "hello org-ml")
#+END_SRC
* A code block with a tangle argument on the BEGIN_SRC line
#+BEGIN_SRC emacs-lisp :tangle ~/path/to/hello-org-ml.el
(message "%s" "hello org-ml")
#+END_SRC
I can access the tangle parameter of the second source block in the following way:
ELISP> (save-excursion (set-buffer "org-ml-header-bug-minimal-example.org") (org-ml-parse-element-at 316))
(src-block
(:language "emacs-lisp" :switches nil :parameters ":tangle ~/path/to/hello-org-ml.el" :begin 261 :end 358 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(message \"%s\" \"hello org-ml\")
" :post-blank 0 :post-affiliated 261 :parent nil))
ELISP> (org-ml-get-property :parameters *)
(:tangle ~/path/to/hello-org-ml\.el)
ELISP> (plist-get * :tangle)
~/path/to/hello-org-ml\.el
ELISP> (with-temp-file * (insert "hello org-ml"))
*** Eval error *** Wrong type argument: stringp, ~/path/to/hello-org-ml\.el
ELISP> (symbol-name *)
"~/path/to/hello-org-ml.el"
ELISP> (with-temp-file * (insert "hello org-ml"))
nil
Whereas with the first block, where the tangle parameter is in the header, I can access the tangle parameter like this:
ELISP> (save-excursion (set-buffer "org-ml-header-bug-minimal-example.org") (org-ml-parse-element-at 160))
(src-block
(:language "emacs-lisp" :switches nil :parameters nil :begin 94 :end 201 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(message \"%s\" \"hello org-ml\")
" :post-blank 0 :post-affiliated 138 :header
(":tangle ~/path/to/hello-org-ml.el")
:parent nil))
ELISP> (org-ml-get-property :header *)
*** Eval error *** Argument type error: "Type ’src-block’ does not have property ’:header’"
ELISP> (org-ml--get-property-nocheck :header *)
(":tangle ~/path/to/hello-org-ml.el")
ELISP> (car *)
":tangle ~/path/to/hello-org-ml.el"
ELISP> (s-chop-prefix ":tangle " *)
"~/path/to/hello-org-ml.el"
ELISP> (with-temp-file * (insert "Hello org-ml"))
nil
It would be nice if there was a function for consistently getting a source block parameter regardless of whether or not that parameter is in a HEADER. At a more granular level, it would be nice if source block parameters were consistently parsed as either plists of symbols or lists of strings, but not both depending on where it is specified. It would also be preferable for org-ml-get-property
to not throw an error when accessing the :header
property of a source block.
I realize this stuff may not be trivial to change in a way that makes sense for the overall functionality of this library, and I completely understand if you don't want to spend time on this. This library is generally great to work with, so thank you for all your hard work putting it together!
Trying to set properties with om-headline-set-node-property
returns the error:
om--arg-error: Argument type error: "Type ’node-property’ does not have property ’:post-blank’"
Here's the function:
(->> (om-parse-this-headline)
(om-update (lambda (hl)
(->> hl
(om-headline-set-node-property "FOO" "BAR")))))
And it errors on headers with properties as well as headers without.
There is a slight issue with the org-ml-match-map
in org-ml. When the text starts with bold formatting, the *text*
will be recognized as an org heading and ignored. As a result, any text starting with *
cannot be synchronized to Anki.
Is there an elegant way to parse a timestamp string like "[2020-10-30 09:25]"
?
Currently I'm doing:
(defun my-org-ml-parse-timestamp (str)
(with-temp-buffer
(insert str)
(goto-char (point-min))
(org-ml-parse-this-object)))
Hello, I have encountered a bug while trying to use this library to build an Org document from a parsed HTML document.
I'll show you just a couple of examples:
(org-ml-build-headline! :title-text "Hello")
; => OK
(org-ml-build-headline! :title-text "1. Hello")
; => Argument type error: "Secondary string must only contain objects"
This is because org-ml-headline-set-title!
uses org-ml-build-secondary-string!
internally, which uses org-ml--from-string
to parse title-text. The function is aware of the Org syntax, so it parses even lists:
;; If `string` is "1. Hello", the result will contain a list item
(->> (org-ml--from-string (concat " " string))
(org-ml--get-descendent '(0))
(org-ml-get-children))
Consider the following toplevel section:
#+STYLE: <link rel="stylesheet" type="text/css" href="style.css">
#+STARTUP: indent
#+TITLE: This is the title of the file
Toplevel section text
This generates the following org-element
tree (via org-ml-parse-this-toplevel-section
):
(section
(:begin 1 :end 148 :contents-begin 1 :contents-end 147 :post-blank 1 :post-affiliated 1 :parent nil)
(keyword
(:key "STYLE" :value "<link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\">" :begin 1 :end 67 :post-blank 0 :post-affiliated 1 :parent #0))
(keyword
(:key "STARTUP" :value "indent" :begin 67 :end 85 :post-blank 0 :post-affiliated 67 :parent #0))
(keyword
(:key "TITLE" :value "This is the title of the file" :begin 85 :end 125 :post-blank 1 :post-affiliated 85 :parent #0))
(paragraph
(:begin 125 :end 147 :contents-begin 125 :contents-end 147 :post-blank 0 :post-affiliated 125 :parent #0)
#("Toplevel section text\n" 0 22
(:parent #1))))
My goal is to get the value of the TITLE
keyword. (I.e., "This is the title of the file") I don't see how I can get there directly with the org-ml
API, other than filtering the section
node's children for keyword
objects with the appropriate key.
Am I missing a more straightforward way to get key/value information from the child keywords of an element? If not, I think some kind of simple API for access to keywords would be useful.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.