org-ml icon indicating copy to clipboard operation
org-ml copied to clipboard

Title property of headlines and secondary-strings

Open garyo opened this issue 9 months ago • 3 comments

I'm a bit confused about the title property of headlines. It is a secondary-string:

(setq title (org-ml-get-property :title (org-ml-build-headline! :title-text "This is my headline")))
(#("This is my headline" 0 19
   (:parent
    (paragraph
     (:standard-properties
      [1 1 1 21 21 0 nil top-comment nil nil nil nil nil nil #<killed
         buffer> nil nil
         (section
          (:standard-properties
           [1 1 1 21 21 0 nil first-section nil nil nil 1 21 nil
              #<killed buffer> nil nil
              (org-data
               (:standard-properties
                [1 1 1 21 21 0 nil org-data nil nil nil 3 21 nil
                   #<killed buffer> nil nil nil]
                :path nil :CATEGORY nil)
               #9)])
          #4)])
     #(" This is my headline" 0 20 (:parent #4))))))

But I can't convert that back to a string. (I know about :raw-value but it is nil in the above case, and anyway I like to do things "properly".)

(org-ml-get-type title)
nil
(org-ml-to-string title)
 Eval error   Argument type error: "Can only stringify node or nil, got (This is my headline)"

Is there even a way to tell if something is a secondary-string? Is there a way to properly stringify it, especially when it's actually a list or tree of nodes? The above case is simple, with no formatting, no TODO -- so how to get the proper string value in the general case?

garyo avatar May 19 '25 14:05 garyo

But I can't convert that back to a string.

There's no built-in function but all you need is (-mapcat #'org-ml-to-string <nodes>)

Is there even a way to tell if something is a secondary-string?

Depends on how strict you want to be. The strictest is secondary string = list of org-element objects (plain-text, timestamp, etc) which you can get by testing each node with (org-ml-is-any-type org-ml-objects <x>).

If you want to test the list directly rather than mapping over it with a predicate, org-element itself has org-element-type which will return 'anonymous' for secondary strings with an optional argument (see docstring). This only tests if a) the thing being tested is a list and b) if the first member of said list has a car corresponding to an org-element type.

ndwarshuis avatar May 21 '25 00:05 ndwarshuis

I tried that but it fails, looks like it interprets some strings as sequences:

(-mapcat #'org-ml-to-string (org-ml-get-property :title (org-ml-build-headline! :title-text "This is *my* headline")))
;; => (84 104 105 115 32 105 115 32 42 109 121 42 32 . "headline")

garyo avatar May 21 '25 21:05 garyo

I didn't realize -mapcat only works on lists, use mapconcat instead:

(mapconcat #'org-ml-to-string (org-ml-get-property :title (org-ml-build-headline! :title-text "This is *my* headline")))

ndwarshuis avatar May 21 '25 22:05 ndwarshuis