@@ -693,139 +693,179 @@ tests =
693693 "Paragraph\n" =?>
694694 para "Paragraph"
695695
696− , "First Level Header" =:
697− "* Headline\n" =?>
698− headerWith ("headline", [], []) 1 "Headline"
699−
700− , "Third Level Header" =:
701− "*** Third Level Headline\n" =?>
702− headerWith ("third-level-headline", [], [])
703− 3
704− ("Third" <> space <> "Level" <> space <> "Headline")
705−
706− , "Compact Headers with Paragraph" =:
707− unlines [ "* First Level"
708− , "** Second Level"
709− , " Text"
710− ] =?>
711− mconcat [ headerWith ("first-level", [], [])
712− 1
713− ("First" <> space <> "Level")
714− , headerWith ("second-level", [], [])
715− 2
716− ("Second" <> space <> "Level")
717− , para "Text"
718− ]
719−
720− , "Separated Headers with Paragraph" =:
721− unlines [ "* First Level"
722− , ""
723− , "** Second Level"
724− , ""
725− , " Text"
726− ] =?>
727− mconcat [ headerWith ("first-level", [], [])
728− 1
729− ("First" <> space <> "Level")
730− , headerWith ("second-level", [], [])
731− 2
732− ("Second" <> space <> "Level")
733− , para "Text"
734− ]
735−
736− , "Headers not preceded by a blank line" =:
737− unlines [ "** eat dinner"
738− , "Spaghetti and meatballs tonight."
739− , "** walk dog"
740− ] =?>
741− mconcat [ headerWith ("eat-dinner", [], [])
742− 2
743− ("eat" <> space <> "dinner")
744− , para $ spcSep [ "Spaghetti", "and", "meatballs", "tonight." ]
745− , headerWith ("walk-dog", [], [])
746− 2
747− ("walk" <> space <> "dog")
748− ]
749−
750− , "Tagged headers" =:
751− unlines [ "* Personal :PERSONAL:"
752− , "** Call Mom :@PHONE:"
753− , "** Call John :@PHONE:JOHN: "
754− ] =?>
755− let tagSpan t = spanWith ("", ["tag"], [("data-tag-name", t)]) mempty
756− in mconcat [ headerWith ("personal", [], [])
757− 1
758− ("Personal" <> tagSpan "PERSONAL")
759− , headerWith ("call-mom", [], [])
760− 2
761− ("Call Mom" <> tagSpan "@PHONE")
762− , headerWith ("call-john", [], [])
763− 2
764− ("Call John" <> tagSpan "@PHONE" <> tagSpan "JOHN")
765− ]
766−
767− , "Untagged header containing colons" =:
768− "* This: is not: tagged" =?>
769− headerWith ("this-is-not-tagged", [], []) 1 "This: is not: tagged"
770−
771− , "Header starting with strokeout text" =:
772− unlines [ "foo"
773− , ""
774− , "* +thing+ other thing"
775− ] =?>
776− mconcat [ para "foo"
777− , headerWith ("thing-other-thing", [], [])
778− 1
779− ((strikeout "thing") <> " other thing")
780− ]
696+ , testGroup "headers" $
697+ [ "First Level Header" =:
698+ "* Headline\n" =?>
699+ headerWith ("headline", [], []) 1 "Headline"
700+
701+ , "Third Level Header" =:
702+ "*** Third Level Headline\n" =?>
703+ headerWith ("third-level-headline", [], [])
704+ 3
705+ ("Third" <> space <> "Level" <> space <> "Headline")
706+
707+ , "Compact Headers with Paragraph" =:
708+ unlines [ "* First Level"
709+ , "** Second Level"
710+ , " Text"
711+ ] =?>
712+ mconcat [ headerWith ("first-level", [], [])
713+ 1
714+ ("First" <> space <> "Level")
715+ , headerWith ("second-level", [], [])
716+ 2
717+ ("Second" <> space <> "Level")
718+ , para "Text"
719+ ]
720+
721+ , "Separated Headers with Paragraph" =:
722+ unlines [ "* First Level"
723+ , ""
724+ , "** Second Level"
725+ , ""
726+ , " Text"
727+ ] =?>
728+ mconcat [ headerWith ("first-level", [], [])
729+ 1
730+ ("First" <> space <> "Level")
731+ , headerWith ("second-level", [], [])
732+ 2
733+ ("Second" <> space <> "Level")
734+ , para "Text"
735+ ]
736+
737+ , "Headers not preceded by a blank line" =:
738+ unlines [ "** eat dinner"
739+ , "Spaghetti and meatballs tonight."
740+ , "** walk dog"
741+ ] =?>
742+ mconcat [ headerWith ("eat-dinner", [], [])
743+ 2
744+ ("eat" <> space <> "dinner")
745+ , para $ spcSep [ "Spaghetti", "and", "meatballs", "tonight." ]
746+ , headerWith ("walk-dog", [], [])
747+ 2
748+ ("walk" <> space <> "dog")
749+ ]
750+
751+ , testGroup "Todo keywords"
752+ [ "Header with known todo keyword" =:
753+ "* TODO header" =?>
754+ let todoSpan = spanWith ("", ["todo", "TODO"], []) "TODO"
755+ in headerWith ("header", [], []) 1 (todoSpan <> space <> "header")
756+
757+ , "Header marked as done" =:
758+ "* DONE header" =?>
759+ let todoSpan = spanWith ("", ["done", "DONE"], []) "DONE"
760+ in headerWith ("header", [], []) 1 (todoSpan <> space <> "header")
761+
762+ , "Header with unknown todo keyword" =:
763+ "* WAITING header" =?>
764+ headerWith ("waiting-header", [], []) 1 "WAITING header"
765+
766+ , "Custom todo keywords" =:
767+ unlines [ "#+TODO: WAITING CANCELLED"
768+ , "* WAITING compile"
769+ , "* CANCELLED lunch"
770+ ] =?>
771+ let todoSpan = spanWith ("", ["todo", "WAITING"], []) "WAITING"
772+ doneSpan = spanWith ("", ["done", "CANCELLED"], []) "CANCELLED"
773+ in headerWith ("compile", [], []) 1 (todoSpan <> space <> "compile")
774+ <> headerWith ("lunch", [], []) 1 (doneSpan <> space <> "lunch")
775+
776+ , "Custom todo keywords with multiple done-states" =:
777+ unlines [ "#+TODO: WAITING | DONE CANCELLED "
778+ , "* WAITING compile"
779+ , "* CANCELLED lunch"
780+ , "* DONE todo-feature"
781+ ] =?>
782+ let waiting = spanWith ("", ["todo", "WAITING"], []) "WAITING"
783+ cancelled = spanWith ("", ["done", "CANCELLED"], []) "CANCELLED"
784+ done = spanWith ("", ["done", "DONE"], []) "DONE"
785+ in headerWith ("compile", [], []) 1 (waiting <> space <> "compile")
786+ <> headerWith ("lunch", [], []) 1 (cancelled <> space <> "lunch")
787+ <> headerWith ("todo-feature", [], []) 1 (done <> space <> "todo-feature")
788+ ]
781789
782− , "Comment Trees" =:
783− unlines [ "* COMMENT A comment tree"
784− , " Not much going on here"
785− , "** This will be dropped"
786− , "* Comment tree above"
787− ] =?>
788− headerWith ("comment-tree-above", [], []) 1 "Comment tree above"
790+ , "Tagged headers" =:
791+ unlines [ "* Personal :PERSONAL:"
792+ , "** Call Mom :@PHONE:"
793+ , "** Call John :@PHONE:JOHN: "
794+ ] =?>
795+ let tagSpan t = spanWith ("", ["tag"], [("data-tag-name", t)]) mempty
796+ in mconcat [ headerWith ("personal", [], [])
797+ 1
798+ ("Personal" <> tagSpan "PERSONAL")
799+ , headerWith ("call-mom", [], [])
800+ 2
801+ ("Call Mom" <> tagSpan "@PHONE")
802+ , headerWith ("call-john", [], [])
803+ 2
804+ ("Call John" <> tagSpan "@PHONE" <> tagSpan "JOHN")
805+ ]
789806
790− , "Nothing but a COMMENT header" =:
791− "* COMMENT Test" =?>
792− (mempty::Blocks)
807+ , "Untagged header containing colons" =:
808+ "* This: is not: tagged" =?>
809+ headerWith ("this-is-not-tagged", [], []) 1 "This: is not: tagged"
793810
794− , "Tree with :noexport:" =:
795− unlines [ "* Should be ignored :archive:noexport:old:"
796− , "** Old stuff"
797− , " This is not going to be exported"
798− ] =?>
799− (mempty::Blocks)
811+ , "Header starting with strokeout text" =:
812+ unlines [ "foo"
813+ , ""
814+ , "* +thing+ other thing"
815+ ] =?>
816+ mconcat [ para "foo"
817+ , headerWith ("thing-other-thing", [], [])
818+ 1
819+ ((strikeout "thing") <> " other thing")
820+ ]
821+
822+ , "Comment Trees" =:
823+ unlines [ "* COMMENT A comment tree"
824+ , " Not much going on here"
825+ , "** This will be dropped"
826+ , "* Comment tree above"
827+ ] =?>
828+ headerWith ("comment-tree-above", [], []) 1 "Comment tree above"
800829
801− , "Subtree with :noexport:" =:
802− unlines [ "* Exported"
803− , "** This isn't exported :noexport:"
804− , "*** This neither"
805− , "** But this is"
806− ] =?>
807− mconcat [ headerWith ("exported", [], []) 1 "Exported"
808− , headerWith ("but-this-is", [], []) 2 "But this is"
809− ]
830+ , "Nothing but a COMMENT header" =:
831+ "* COMMENT Test" =?>
832+ (mempty::Blocks)
810833
811− , "Preferences are treated as header attributes" =:
812− unlines [ "* foo"
813− , " :PROPERTIES:"
814− , " :custom_id: fubar"
815− , " :bar: baz"
816− , " :END:"
817− ] =?>
818− headerWith ("fubar", [], [("bar", "baz")]) 1 "foo"
834+ , "Tree with :noexport:" =:
835+ unlines [ "* Should be ignored :archive:noexport:old:"
836+ , "** Old stuff"
837+ , " This is not going to be exported"
838+ ] =?>
839+ (mempty::Blocks)
819840
841+ , "Subtree with :noexport:" =:
842+ unlines [ "* Exported"
843+ , "** This isn't exported :noexport:"
844+ , "*** This neither"
845+ , "** But this is"
846+ ] =?>
847+ mconcat [ headerWith ("exported", [], []) 1 "Exported"
848+ , headerWith ("but-this-is", [], []) 2 "But this is"
849+ ]
850+
851+ , "Preferences are treated as header attributes" =:
852+ unlines [ "* foo"
853+ , " :PROPERTIES:"
854+ , " :custom_id: fubar"
855+ , " :bar: baz"
856+ , " :END:"
857+ ] =?>
858+ headerWith ("fubar", [], [("bar", "baz")]) 1 "foo"
820859
821− , "Headers marked with a unnumbered property get a class of the same name" =:
822− unlines [ "* Not numbered"
823− , " :PROPERTIES:"
824− , " :UNNUMBERED: t"
825− , " :END:"
826− ] =?>
827− headerWith ("not-numbered", ["unnumbered"], []) 1 "Not numbered"
828860
861+ , "Headers marked with a unnumbered property get a class of the same name" =:
862+ unlines [ "* Not numbered"
863+ , " :PROPERTIES:"
864+ , " :UNNUMBERED: t"
865+ , " :END:"
866+ ] =?>
867+ headerWith ("not-numbered", ["unnumbered"], []) 1 "Not numbered"
868+ ]
829869 , "Paragraph starting with an asterisk" =:
830870 "*five" =?>
831871 para "*five"