Git Product home page Git Product logo

org-mode's Introduction

org-mode

Buildorg-mode Releaseorg-mode-lucid Release
https://github.com/fosskers/org-mode/workflows/Tests/badge.svghttps://img.shields.io/hackage/v/org-mode.svghttps://img.shields.io/hackage/v/org-mode-lucid.svg

The org-mode suite of libraries allow one to parse text in Emacs Org Mode format and manipulate it into other useful types.

org-mode's People

Contributors

dependabot[bot] avatar fosskers avatar srid avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

org-mode's Issues

Support babel source block header arguments

I was interested in writing a tangler and this would be needed.

I tried adding this a while back and got stuck with some recursion issue when trying to add this. I'll have to dig that up and make a draft PR linked to this.

Add todo states to AST

A section node is defined like this currently,

data Section = Section
  { sectionHeading :: NonEmpty Words  -- Contains "TODO Hello world"
  , sectionTags    :: [Text]
  , sectionDoc     :: OrgDoc }

Note that section text is just a list of Words. I'm looking to traverse my org files based on the todo state, and it occurred to me that adding todo state of sections to the Section node would make it straight forward to do so.

With this proposed change, the section node would look like:

data Section = Section
  { sectionHeading :: NonEmpty Words -- Contains "Hello World"
  , sectionTodoState :: Maybe TodoState  -- Contains Just "TODO"
  , sectionTags    :: [Text] 
  , sectionDoc     :: OrgDoc }

newtype TodoState = TodoState { unTodoState :: Text }

For bonus points, we can pass [Text] (based on org-todo-keywords) to the org-mode parser to override a default list of keywords (TODO, DONE, etc.). Alternatively, we can favour "convention over configuration" and select any capitalized first word in the section heading as todo state.

Ref: https://www.orgmode.org/manual/TODO-Items.html#TODO-Items

Add a function to extract tags?

I use something like this which is rough but works, but perhaps we can do better using a pandoc-like Walk type.

extractTags :: OrgFile -> Set Text
extractTags (Org.OrgFile _meta (Org.OrgDoc blocks sections)) =
  foldMap fromBlocks blocks <> foldMap fromSections sections
  where
    fromSections :: Org.Section -> Set Text
    fromSections (Org.Section heading tags (Org.OrgDoc bs ss)) =
      Set.fromList tags
        <> foldMap fromWords heading
        <> foldMap fromBlocks bs
        <> foldMap fromSections ss

    fromBlocks :: Org.Block -> Set Text
    fromBlocks = \case
      Org.Paragraph ws ->
        foldMap fromWords ws
      _ ->
        mempty

    fromWords :: Org.Words -> Set Text
    fromWords = \case
      Org.Tags ts -> Set.fromList (toList ts)
      _ -> mempty

EmaApps/orgself@f75d9d7#diff-67fe32f714f18086365a4415f3f7b0013f278237ac4c94cb5e7bb8e4d6780d49R119-R141

Make properties a sub-type of drawers

Properties are just a special case of drawers.

The following parses into Map Text Text

:PROPERTIES:
:DESCRIPTION: hello world
:END:

But the following does not,

:LOGBOOK:
CLOCK: [2021-04-30 Fri 11:04]
:END:

(The latter is to be used for time-tracking, cf. EmaApps/orgself#4)


It looks like the general syntax for drawers is as follows:

  • :<NAME>: in first line, followed by
  • zero or more lines of arbitrary text (how they are interpreted is dependent on <NAME>)
  • :END: as the last line

Then I propose that we replace

, sectionProps :: M.Map Text Text

with

, sectionProps     :: M.Map Text Text
, sectionDrawers     :: (Text, Text)

As this library implements more drawer types, we can lift the unparsed drawer out of sectionDrawers into its own type. For example, when handling the clocking logbook,

, sectionProps     :: M.Map Text Text
, sectionLogbook :: M.Map Text OrgClock -- Probably not right type
, sectionDrawers     :: (Text, Text)

(Again, would be happy to take a stab at this depending on what the agreed upon spec is)

Feedback on Todo & Priority types

Heya,

Just trying out master and I have a couple of suggestions.

  1. Since a priority can only be assigned to Todo headings, it would make sense to move it out of Section into Todo type.
  2. org-mode supports arbitrary number of todo states, so we might as well have a third constructor taking any Text in the Todo type, but the parser can accept it only if the first word is all capitalized (convention over configuration).

With these two applied, the Todo type would look like:

data TodoState = TODO | DONE | CustomTodo Text

data Todo = Todo 
  { todoState :: TodoState
  , todoPriority :: Maybe Priority
  }

I not even 100% confident of the TodoState type. I wonder if we should just use a newtype wrapper instead and have the library user code deal with the individual Todo states. After all, it is possible to set org-todo-keywords to something that does not even contain TODO or DONE keywords. So perhaps,

-- | The all-capitalized Todo keyword appearing as the first word in a section heading
newtype TodoState = TodoState { unTodoState :: Text }

data Todo = Todo 
  { todoState :: TodoState
  , todoPriority :: Maybe Priority
  }

Blocks under heading triggers parse failure of sub-outline

For the following input,

* Top-level heading
** Second-level heading
This is a paragraph in under this heading. There will be children too (see below)
*** Third-level item
*** Another item

... which renders as follows in emacs:

image

... this library parses the structure successfully only up to second-level heading, but it doesn't recognize the structure from third-level, because it consumes them as part of the paragraph block under the second-level heading. Here's the AST it produces:

image

Idea for collaboration

Hello, I found your project from the worg tools list. First, sorry for the semi-spam nature of this issue. I had a notion for a project that the org community might find useful and I'm looking for feedback. Feel free to close this issue if it doesn't sound useful to you.

My idea is to start a list of org-mode snippets which can serve as a test bed for people developing tools. The idea is that having a separate collection of examples makes it easier for others in the community to benefit from the examples developed through communication with users.

Users could use these samples to try to construct minimal examples of issues they're having and/or contribute examples there which others could benefit from. Exactly how it will take shape is still up in the air.

These samples could also serve as a place to discuss ideas about how to develop the grammar itself. According to worg, the spec is still in draft state.

There's not much there at the moment. Mostly because I don't want to commit too early to what seems like it might be useful. I'll add more examples as I go.

If you like the concept and/or want to contribute and/or just want to offer feedback, I'd very much appreciate it.

Again, sorry for the spam.

Bold and italics can be nested in each other.

This is not critical for me, but I thought I'd offer a heads up that the org-element.el parser does allow nesting of bold and italics text.

The GitHub org parser doesn't recognize it, but this is how emacs parses that file:

(org-data nil
	  (section
	   (:begin 1 :end 480 :contents-begin 1 :contents-end 480 :post-blank 0 :post-affiliated 1 :parent #0)
	   (paragraph
	    (:begin 1 :end 480 :contents-begin 1 :contents-end 480 :post-blank 0 :post-affiliated 1 :parent #1)
	    #("Let's try " 0 10
	      (:parent #2))
	    (bold
	     (:begin 11 :end 21 :contents-begin 12 :contents-end 20 :post-blank 0 :parent #2)
	     (italic
	      (:begin 12 :end 20 :contents-begin 13 :contents-end 19 :post-blank 0 :parent #3)
	      #("combos" 0 6
		(:parent #4))))
	    #("\nLet's try " 0 11
	      (:parent #2))
	    (bold
	     (:begin 32 :end 52 :contents-begin 33 :contents-end 51 :post-blank 0 :parent #2)
	     #("bold " 0 5
	       (:parent #3))
	     (italic
	      (:begin 38 :end 47 :contents-begin 39 :contents-end 45 :post-blank 1 :parent #3)
	      #("combos" 0 6
		(:parent #4)))
	     #("bold" 0 4
	       (:parent #3)))
	    #("\nLet's try " 0 11
	      (:parent #2))
	    (italic
	     (:begin 63 :end 73 :contents-begin 64 :contents-end 72 :post-blank 0 :parent #2)
	     (bold
	      (:begin 64 :end 72 :contents-begin 65 :contents-end 71 :post-blank 0 :parent #3)
	      #("combos" 0 6
		(:parent #4))))
	    #("\nLet's try " 0 11
	      (:parent #2))
	    (italic
	     (:begin 84 :end 104 :contents-begin 85 :contents-end 103 :post-blank 0 :parent #2)
	     #("bold " 0 5
	       (:parent #3))
	     (bold
	      (:begin 90 :end 99 :contents-begin 91 :contents-end 97 :post-blank 1 :parent #3)
	      #("combos" 0 6
		(:parent #4)))
	     #("bold" 0 4
	       (:parent #3)))
	    #("\nLet's try " 0 11
	      (:parent #2))
	    (bold
	     (:begin 115 :end 143 :contents-begin 116 :contents-end 142 :post-blank 0 :parent #2)
	     (italic
	      (:begin 116 :end 142 :contents-begin 117 :contents-end 141 :post-blank 0 :parent #3)
	      #("italics " 0 8
		(:parent #4))
	      (strike-through
	       (:begin 125 :end 134 :contents-begin 126 :contents-end 132 :post-blank 1 :parent #4)
	       #("combos" 0 6
		 (:parent #5)))
	      #("italics" 0 7
		(:parent #4))))
	    #("\nLet's try " 0 11
	      (:parent #2))
	    (bold
	     (:begin 154 :end 192 :contents-begin 155 :contents-end 191 :post-blank 0 :parent #2)
	     #("bold " 0 5
	       (:parent #3))
	     (italic
	      (:begin 160 :end 187 :contents-begin 161 :contents-end 185 :post-blank 1 :parent #3)
	      #("italics " 0 8
		(:parent #4))
	      (strike-through
	       (:begin 169 :end 178 :contents-begin 170 :contents-end 176 :post-blank 1 :parent #4)
	       #("combos" 0 6
		 (:parent #5)))
	      #("italics" 0 7
		(:parent #4)))
	     #("bold" 0 4
	       (:parent #3)))
	    #("\nLet's try " 0 11
	      (:parent #2))
	    (bold
	     (:begin 203 :end 231 :contents-begin 204 :contents-end 230 :post-blank 0 :parent #2)
	     (italic
	      (:begin 204 :end 230 :contents-begin 205 :contents-end 229 :post-blank 0 :parent #3)
	      #("italics " 0 8
		(:parent #4))
	      (underline
	       (:begin 213 :end 222 :contents-begin 214 :contents-end 220 :post-blank 1 :parent #4)
	       #("combos" 0 6
		 (:parent #5)))
	      #("italics" 0 7
		(:parent #4))))
	    #("\nLet's try " 0 11
	      (:parent #2))
	    (bold
	     (:begin 242 :end 280 :contents-begin 243 :contents-end 279 :post-blank 0 :parent #2)
	     #("bold " 0 5
	       (:parent #3))
	     (italic
	      (:begin 248 :end 275 :contents-begin 249 :contents-end 273 :post-blank 1 :parent #3)
	      #("italics " 0 8
		(:parent #4))
	      (underline
	       (:begin 257 :end 266 :contents-begin 258 :contents-end 264 :post-blank 1 :parent #4)
	       #("combos" 0 6
		 (:parent #5)))
	      #("italics" 0 7
		(:parent #4)))
	     #("bold" 0 4
	       (:parent #3)))
	    #("\nLet's try " 0 11
	      (:parent #2))
	    (bold
	     (:begin 291 :end 301 :contents-begin 292 :contents-end 300 :post-blank 0 :parent #2)
	     (strike-through
	      (:begin 292 :end 300 :contents-begin 293 :contents-end 299 :post-blank 0 :parent #3)
	      #("combos" 0 6
		(:parent #4))))
	    #("\nLet's try " 0 11
	      (:parent #2))
	    (bold
	     (:begin 312 :end 332 :contents-begin 313 :contents-end 331 :post-blank 0 :parent #2)
	     #("bold " 0 5
	       (:parent #3))
	     (strike-through
	      (:begin 318 :end 327 :contents-begin 319 :contents-end 325 :post-blank 1 :parent #3)
	      #("combos" 0 6
		(:parent #4)))
	     #("bold" 0 4
	       (:parent #3)))
	    #("\nLet's try " 0 11
	      (:parent #2))
	    (bold
	     (:begin 343 :end 353 :contents-begin 344 :contents-end 352 :post-blank 0 :parent #2)
	     (underline
	      (:begin 344 :end 352 :contents-begin 345 :contents-end 351 :post-blank 0 :parent #3)
	      #("combos" 0 6
		(:parent #4))))
	    #("\nLet's try " 0 11
	      (:parent #2))
	    (bold
	     (:begin 364 :end 384 :contents-begin 365 :contents-end 383 :post-blank 0 :parent #2)
	     #("bold " 0 5
	       (:parent #3))
	     (underline
	      (:begin 370 :end 379 :contents-begin 371 :contents-end 377 :post-blank 1 :parent #3)
	      #("combos" 0 6
		(:parent #4)))
	     #("bold" 0 4
	       (:parent #3)))
	    #("\nLet's try " 0 11
	      (:parent #2))
	    (bold
	     (:begin 395 :end 427 :contents-begin 396 :contents-end 426 :post-blank 0 :parent #2)
	     (underline
	      (:begin 396 :end 426 :contents-begin 397 :contents-end 425 :post-blank 0 :parent #3)
	      #("underline " 0 10
		(:parent #4))
	      (italic
	       (:begin 407 :end 416 :contents-begin 408 :contents-end 414 :post-blank 1 :parent #4)
	       #("combos" 0 6
		 (:parent #5)))
	      #("underline" 0 9
		(:parent #4))))
	    #("\nLet's try " 0 11
	      (:parent #2))
	    (bold
	     (:begin 438 :end 480 :contents-begin 439 :contents-end 479 :post-blank 0 :parent #2)
	     #("bold " 0 5
	       (:parent #3))
	     (underline
	      (:begin 444 :end 475 :contents-begin 445 :contents-end 473 :post-blank 1 :parent #3)
	      #("underline " 0 10
		(:parent #4))
	      (italic
	       (:begin 455 :end 464 :contents-begin 456 :contents-end 462 :post-blank 1 :parent #4)
	       #("combos" 0 6
		 (:parent #5)))
	      #("underline" 0 9
		(:parent #4)))
	     #("bold" 0 4
	       (:parent #3))))))

Somewhat surprisingly, though, on my Emacs the nesting isn't rendered for all the combinations. Compare the first two lines relative to the AST above.

Screen Shot 2021-11-11 at 7 02 42 PM

Interestingly, pandoc does a better job of it than emacs does. I believe pandoc is also written in Haskell, FWIW.

Again, this isn't critical, so feel free to close this issue.

Regards

P.S. Full disclosure: this is also a bit of an ad for my org-mode-samples. Hopefully this was more interesting than annoying. :D

Ascii emojis break section parser

Probably something to do with tag parsing (which looks for colon's). Reproduced in master branch. Test case,

* Test
** An heading that ends in an ascii emoji :-)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.