1use std::borrow::Cow;
2
3use indextree::NodeId;
4use log::trace;
5use ropey::{Rope, RopeSlice};
6
7use crate::{emit::section_tree_to_rope, errors::*, iter::*, *};
8
9#[cfg(feature = "headline-parser")]
10use crate::headline::*;
11
12#[derive(Debug, PartialEq, Clone, Copy, Hash, Eq)]
13pub struct Section {
14 pub(crate) id: NodeId,
15}
16
17#[derive(Debug, PartialEq, Clone, Copy, Hash, Eq)]
18pub struct Document {
19 pub root: Section,
20
21 pub empty_root_section: bool,
27
28 pub terminal_newline: bool,
31}
32
33impl Document {
34 pub fn to_rope(&self, arena: &Arena) -> Rope {
35 section_tree_to_rope(
36 self.root.id,
37 arena,
38 self.terminal_newline,
39 self.empty_root_section,
40 )
41 }
42
43 pub fn at(&self, arena: &Arena, mut pos: usize) -> Option<(Section, usize)> {
44 let ct = self.to_rope(arena);
45 let k = ct.len_chars();
46 trace!("at: {} in buffer of length {}.", pos, k);
47
48 if pos >= k {
49 trace!("at: beyond end of buffer");
50 return None;
51 }
52
53 if pos == 0 && (!self.empty_root_section || ct == "\n") {
54 trace!("at: in implicit newline of newline empty root section");
55 return Some((self.root, pos));
56 }
57
58 let s = Section { id: self.root.id };
59 let terminal_newline_in_play = if pos == k - 1 && self.terminal_newline {
60 trace!("at: terminal newline in play; adjusting pos");
61 pos = k - 2;
62 true
63 } else {
64 trace!("at: terminal not newline in play");
65 false
66 };
67 if !self.empty_root_section && pos > 0 {
68 trace!(
69 "at: implicit newline of newline empty root section means we need to adjust pos"
70 );
71 pos -= 1;
72 }
73 trace!("at: delegating to section at function");
74 match s.at(arena, pos) {
75 Some((section, offset)) => {
76 if terminal_newline_in_play {
77 Some((section, offset + 1))
78 } else {
79 Some((section, offset))
80 }
81 }
82 None => None,
83 }
84 }
85
86 pub fn text_offset_of_child(&self, arena: &Arena, child: Section) -> Option<usize> {
89 match self.root.text_offset_of_child(arena, child) {
90 None => None,
91 Some(offset) => {
92 let entry = &arena.arena[self.root.id].get();
93 if entry.text.len_chars() == 0 && !self.empty_root_section && offset > 0 {
94 Some(offset + 1)
97 } else {
98 Some(offset)
99 }
100 }
101 }
102 }
103}
104
105impl Section {
107 pub fn to_rope(self, arena: &Arena) -> Rope {
109 section_tree_to_rope(
110 self.id, arena, true, true,
111 )
112 }
113
114 pub fn at(self, arena: &Arena, mut pos: usize) -> Option<(Section, usize)> {
116 let root = &arena.arena[self.id].get();
117 let k = root.text.len_chars();
118 trace!("at: section at {} in {} char section", pos, k);
119 if pos < k {
120 trace!("at: in section text");
121 return Some((self, pos));
122 }
123 pos -= k;
124 for (j, child_id) in self.id.children(&arena.arena).enumerate() {
125 trace!(
126 "at: in child {} (id {}) of node id {}",
127 j,
128 child_id,
129 self.id
130 );
131 let k = Section { id: child_id }.to_rope(&arena).len_chars();
132 if pos < k {
133 let s = Section { id: child_id };
134 return match s.at(arena, pos) {
135 Some((section, offset)) => Some((section, offset)),
136 None => Some((s, pos)),
137 };
138 }
139 pos -= k;
140 }
141
142 trace!("Exhausted all children of node {}", self.id);
143
144 None
145 }
146
147 pub fn clone_subtree(self, arena: &mut Arena) -> Section {
150 let new_self = arena.clone_section(self);
151 let mut stack = vec![(self, new_self)];
152 let mut scratch = Vec::default();
153 while let Some((old_parent, new_parent)) = stack.pop() {
154 scratch.extend(old_parent.children(arena));
155 for old_child in scratch.drain(..) {
156 let new_child = arena.clone_section(old_child);
157 new_parent.unchecked_append(arena, new_child);
158 stack.push((old_child, new_child));
159 }
160 }
161 new_self
162 }
163
164 pub fn text_offset_of_child(&self, arena: &Arena, child: Section) -> Option<usize> {
167 let entry = &arena.arena[self.id].get();
168
169 let mut offset = entry.text.len_chars();
176 if offset > 0 {
177 offset += 1;
178 }
179
180 for c in self.descendants(arena) {
181 if c == child {
182 return Some(offset);
183 }
184
185 offset += arena.arena[c.id].get().text.len_chars() + 1;
186 }
187
188 None
189 }
190}
191
192impl Section {
194 pub fn level(self, arena: &Arena) -> u16 {
198 arena.arena[self.id].get().level
199 }
200
201 pub fn text<'a>(self, arena: &'a Arena) -> RopeSlice<'a> {
202 arena.arena[self.id].get().text.slice(..)
203 }
204
205 pub fn parent(self, arena: &Arena) -> Option<Section> {
206 arena.arena[self.id].parent().map(|p| Section { id: p })
207 }
208
209 pub fn children(self, arena: &Arena) -> Children {
210 Children {
211 children: self.id.children(&arena.arena),
212 }
213 }
214
215 pub fn ancestors(self, arena: &Arena) -> Ancestors {
216 Ancestors {
217 ancestors: self.id.ancestors(&arena.arena),
218 }
219 }
220
221 pub fn descendants(self, arena: &Arena) -> Descendants {
222 Descendants {
223 descendants: self.id.descendants(&arena.arena),
224 }
225 }
226
227 pub fn preceding_siblings(self, arena: &Arena) -> PrecedingSiblings {
228 PrecedingSiblings {
229 preceding_siblings: self.id.preceding_siblings(&arena.arena),
230 }
231 }
232
233 pub fn following_siblings(self, arena: &Arena) -> FollowingSiblings {
234 FollowingSiblings {
235 following_siblings: self.id.following_siblings(&arena.arena),
236 }
237 }
238
239 pub fn reverse_children(self, arena: &Arena) -> ReverseChildren {
240 ReverseChildren {
241 reverse_children: self.id.reverse_children(&arena.arena),
242 }
243 }
244}
245
246impl Section {
248 pub fn append(self, arena: &mut Arena, new_child: Section) -> Result<(), StructureError> {
252 let min_level = arena.arena[self.id].get().level + 1;
253 arena.section_min_level(new_child, min_level);
254 Ok(self.id.checked_append(new_child.id, &mut arena.arena)?)
255 }
256
257 pub fn prepend(self, arena: &mut Arena, new_child: Section) -> Result<(), StructureError> {
261 let min_level = arena.arena[self.id].get().level + 1;
262 arena.section_min_level(new_child, min_level);
263 Ok(self.id.checked_prepend(new_child.id, &mut arena.arena)?)
264 }
265
266 pub fn insert_after(
269 self,
270 arena: &mut Arena,
271 new_sibling: Section,
272 ) -> Result<(), StructureError> {
273 let min_level = match self.parent(arena) {
274 Some(parent) => parent.level(arena) + 1,
275 None => {
276 return Err(StructureError::LevelError);
277 }
278 };
279
280 arena.section_min_level(new_sibling, min_level);
281 Ok(self
282 .id
283 .checked_insert_after(new_sibling.id, &mut arena.arena)?)
284 }
285
286 pub fn insert_before(
289 self,
290 arena: &mut Arena,
291 new_sibling: Section,
292 ) -> Result<(), StructureError> {
293 let min_level = match self.parent(arena) {
294 Some(parent) => parent.level(arena) + 1,
295 None => {
296 return Err(StructureError::LevelError);
297 }
298 };
299
300 arena.section_min_level(new_sibling, min_level);
301 Ok(self
302 .id
303 .checked_insert_before(new_sibling.id, &mut arena.arena)?)
304 }
305
306 pub fn checked_append(
310 self,
311 arena: &mut Arena,
312 new_child: Section,
313 ) -> Result<(), StructureError> {
314 if arena.arena[new_child.id].get().level <= arena.arena[self.id].get().level {
315 return Err(StructureError::LevelError);
316 } else {
317 Ok(self.id.checked_append(new_child.id, &mut arena.arena)?)
318 }
319 }
320
321 pub fn checked_prepend(
325 self,
326 arena: &mut Arena,
327 new_child: Section,
328 ) -> Result<(), StructureError> {
329 if arena.arena[new_child.id].get().level <= arena.arena[self.id].get().level {
330 return Err(StructureError::LevelError);
331 } else {
332 Ok(self.id.checked_prepend(new_child.id, &mut arena.arena)?)
333 }
334 }
335
336 pub fn checked_insert_after(
340 self,
341 arena: &mut Arena,
342 new_sibling: Section,
343 ) -> Result<(), StructureError> {
344 if let Some(parent) = arena.arena[self.id].parent() {
345 if arena.arena[new_sibling.id].get().level <= arena.arena[parent].get().level {
346 return Err(StructureError::LevelError);
347 }
348 }
349
350 Ok(self
351 .id
352 .checked_insert_after(new_sibling.id, &mut arena.arena)?)
353 }
354
355 pub fn checked_insert_before(
359 self,
360 arena: &mut Arena,
361 new_sibling: Section,
362 ) -> Result<(), StructureError> {
363 if let Some(parent) = arena.arena[self.id].parent() {
364 if arena.arena[new_sibling.id].get().level <= arena.arena[parent].get().level {
365 return Err(StructureError::LevelError);
366 }
367 }
368
369 Ok(self
370 .id
371 .checked_insert_before(new_sibling.id, &mut arena.arena)?)
372 }
373
374 pub fn unchecked_append(self, arena: &mut Arena, new_child: Section) {
378 self.checked_append(arena, new_child)
379 .expect("Checked append failed")
380 }
381
382 pub fn unchecked_insert_after(self, arena: &mut Arena, new_sibling: Section) {
386 self.checked_insert_after(arena, new_sibling)
387 .expect("Checked insert after failed")
388 }
389
390 pub fn unchecked_insert_before(self, arena: &mut Arena, new_sibling: Section) {
394 self.checked_insert_before(arena, new_sibling)
395 .expect("Checked insert before failed")
396 }
397
398 pub fn unchecked_prepend(self, arena: &mut Arena, new_sibling: Section) {
402 self.checked_prepend(arena, new_sibling)
403 .expect("Checked prepend failed")
404 }
405
406 pub fn remove_subtree(self, arena: &mut Arena) {
410 self.id.detach(&mut arena.arena)
411 }
412
413 pub fn replace_with_children(self, arena: &mut Arena) {
416 self.id.remove(&mut arena.arena)
417 }
418
419 pub fn remove_children(self, arena: &mut Arena) {
421 while let Some(child) = self.children(arena).next() {
422 child.remove_subtree(arena);
423 }
424 }
425}
426
427#[cfg(feature = "headline-parser")]
434impl Section {
435 pub fn priority(
436 self,
437 arena: &Arena,
438 context: Option<&Context>,
439 ) -> Result<Option<char>, HeadlineError> {
440 match self.headline(arena, context) {
441 None => Err(HeadlineError::InvalidHeadlineError),
442 Some(h) => Ok(h.priority()),
443 }
444 }
445
446 pub fn raw_tags<'a>(
447 self,
448 arena: &'a Arena,
449 context: Option<&Context>,
450 ) -> Result<Cow<'a, str>, HeadlineError> {
451 match self.headline(arena, context) {
452 None => Err(HeadlineError::InvalidHeadlineError),
453 Some(h) => Ok(Cow::Owned(h.raw_tags().to_string())),
454 }
455 }
456
457 pub fn tags<'a>(
458 self,
459 arena: &'a Arena,
460 context: Option<&Context>,
461 ) -> Result<Vec<String>, HeadlineError> {
462 match self.headline(arena, context) {
463 None => Err(HeadlineError::InvalidHeadlineError),
464 Some(h) => Ok(h.tags().map(|s| s.to_string()).collect()),
465 }
466 }
467
468 pub fn has_tag(
469 self,
470 tag: &str,
471 arena: &Arena,
472 context: Option<&Context>,
473 ) -> Result<bool, HeadlineError> {
474 match self.headline(arena, context) {
475 None => Err(HeadlineError::InvalidHeadlineError),
476 Some(h) => Ok(h.has_tag(tag)),
477 }
478 }
479
480 pub fn keyword<'a>(
481 self,
482 arena: &'a Arena,
483 context: Option<&Context>,
484 ) -> Result<Option<Cow<'a, str>>, HeadlineError> {
485 match self.headline(arena, context) {
486 None => Err(HeadlineError::InvalidHeadlineError),
487 Some(h) => Ok(h.keyword().map(|s| Cow::Owned(s.to_string()))),
488 }
489 }
490
491 pub fn title<'a>(
492 self,
493 arena: &'a Arena,
494 context: Option<&Context>,
495 ) -> Result<Cow<'a, str>, HeadlineError> {
496 match self.headline(arena, context) {
497 None => Err(HeadlineError::InvalidHeadlineError),
498 Some(h) => Ok(Cow::Owned(h.title().to_string())),
499 }
500 }
501
502 pub fn commented(
503 self,
504 arena: &Arena,
505 context: Option<&Context>,
506 ) -> Result<bool, HeadlineError> {
507 match self.headline(arena, context) {
508 None => Err(HeadlineError::InvalidHeadlineError),
509 Some(h) => Ok(h.commented()),
510 }
511 }
512
513 pub fn planning(
514 &self,
515 arena: &Arena,
516 context: Option<&Context>,
517 ) -> Result<Planning<'static>, HeadlineError> {
518 match self.headline(arena, context) {
519 None => Err(HeadlineError::InvalidHeadlineError),
520 Some(h) => Ok(h.planning().clone().into_owned()),
521 }
522 }
523
524 pub fn scheduled(
525 &self,
526 arena: &Arena,
527 context: Option<&Context>,
528 ) -> Result<Option<Timestamp<'static>>, HeadlineError> {
529 self.planning(arena, context).map(|p| p.scheduled)
530 }
531
532 pub fn deadline(
533 &self,
534 arena: &Arena,
535 context: Option<&Context>,
536 ) -> Result<Option<Timestamp<'static>>, HeadlineError> {
537 self.planning(arena, context).map(|p| p.deadline)
538 }
539
540 pub fn closed(
541 &self,
542 arena: &Arena,
543 context: Option<&Context>,
544 ) -> Result<Option<Timestamp<'static>>, HeadlineError> {
545 self.planning(arena, context).map(|p| p.closed)
546 }
547
548 pub fn body<'a>(
549 self,
550 arena: &'a Arena,
551 context: Option<&Context>,
552 ) -> Result<Cow<'a, str>, HeadlineError> {
553 match self.headline(arena, context) {
554 None => Err(HeadlineError::InvalidHeadlineError),
555 Some(h) => Ok(Cow::Owned(h.body().to_string())),
556 }
557 }
558
559 #[cfg(feature = "orgize-integration")]
560 pub fn has_property(
561 &self,
562 arena: &Arena,
563 property: &str,
564 context: Option<&Context>,
565 ) -> Result<bool, HeadlineError> {
566 let org = self.orgize_headline(arena, context)?;
567 has_property_internal(property, &org)
568 }
569
570 #[cfg(feature = "orgize-integration")]
571 pub fn get_property(
572 &self,
573 arena: &Arena,
574 property: &str,
575 context: Option<&Context>,
576 ) -> Result<Option<Cow<'static, str>>, HeadlineError> {
577 let org = self.orgize_headline(arena, context)?;
578 get_property_internal(property, &org)
579 }
580
581 #[cfg(feature = "orgize-integration")]
582 pub fn get_id(
583 &self,
584 arena: &Arena,
585 context: Option<&Context>,
586 ) -> Result<Option<Cow<'static, str>>, HeadlineError> {
587 let org = self.orgize_headline(arena, context)?;
588 get_id_internal(&org)
589 }
590
591 #[cfg(feature = "orgize-integration")]
592 pub fn properties(
593 &self,
594 arena: &Arena,
595 context: Option<&Context>,
596 ) -> Result<indexmap::IndexMap<Cow<'static, str>, Cow<'static, str>>, HeadlineError> {
597 let org = self.orgize_headline(arena, context)?;
598 properties_internal(&org)
599 }
600
601 #[cfg(feature = "orgize-integration")]
603 fn orgize_headline(
604 &self,
605 arena: &Arena,
606 context: Option<&Context>,
607 ) -> Result<orgize::Org, HeadlineError> {
608 match self.headline(arena, context) {
609 None => Err(HeadlineError::InvalidHeadlineError),
610 Some(h) => Ok(parse_orgize(&h.body())),
611 }
612 }
613}
614
615#[cfg(feature = "headline-parser")]
619impl Section {
620 pub fn set_raw_tags(
621 self,
622 arena: &mut Arena,
623 raw_tags: &str,
624 context: Option<&Context>,
625 ) -> Result<(), HeadlineError> {
626 match self.headline(arena, context).map(|h| h.to_owned()) {
627 None => Err(HeadlineError::InvalidHeadlineError),
628 Some(h) => {
629 let mut h = h.to_builder();
630 h.set_raw_tags(raw_tags);
631 self.set_headline(arena, &h.headline(context)?)
632 }
633 }
634 }
635
636 pub fn set_tags<'a, I>(
637 self,
638 arena: &'a mut Arena,
639 tags: I,
640 context: Option<&Context>,
641 ) -> Result<(), HeadlineError>
642 where
643 I: Iterator<Item = Cow<'a, str>>,
644 {
645 match self.headline(arena, context).map(|h| h.to_owned()) {
646 None => Err(HeadlineError::InvalidHeadlineError),
647 Some(h) => {
648 let mut h = h.to_builder();
649 h.set_tags(tags.map(|s| s.to_owned()));
651 self.set_headline(arena, &h.headline(context)?)
652 }
653 }
654 }
655
656 pub fn update_tags<'a, I>(
657 self,
658 arena: &'a mut Arena,
659 tags: I,
660 context: Option<&Context>,
661 ) -> Result<(), HeadlineError>
662 where
663 I: Iterator<Item = Cow<'a, str>>,
664 {
665 match self.headline(arena, context).map(|h| h.to_owned()) {
666 None => Err(HeadlineError::InvalidHeadlineError),
667 Some(h) => {
668 let mut h = h.to_builder();
669 h.update_tags(tags.map(|s| s.to_owned()));
671 self.set_headline(arena, &h.headline(context)?)
672 }
673 }
674 }
675
676 pub fn remove_tags(
677 self,
678 arena: &mut Arena,
679 tags: &[&str],
680 context: Option<&Context>,
681 ) -> Result<(), HeadlineError> {
682 match self.headline(arena, context).map(|h| h.to_owned()) {
683 None => Err(HeadlineError::InvalidHeadlineError),
684 Some(h) => {
685 let mut h = h.to_builder();
686 h.remove_tags(tags);
687 self.set_headline(arena, &h.headline(context)?)
688 }
689 }
690 }
691
692 pub fn clear_tags(
693 self,
694 arena: &mut Arena,
695 context: Option<&Context>,
696 ) -> Result<(), crate::errors::HeadlineError> {
697 match self.headline(arena, None).map(|h| h.to_owned()) {
698 None => Err(HeadlineError::InvalidHeadlineError),
699 Some(h) => {
700 let mut h = h.to_builder();
701 h.clear_tags();
702 self.set_headline(arena, &h.headline(context)?)
703 }
704 }
705 }
706
707 pub fn add_tag(
708 self,
709 arena: &mut Arena,
710 tag: &str,
711 context: Option<&Context>,
712 ) -> Result<(), crate::errors::HeadlineError> {
713 match self.headline(arena, context).map(|h| h.to_owned()) {
714 None => Err(HeadlineError::InvalidHeadlineError),
715 Some(h) => {
716 let mut h = h.to_builder();
717 h.add_tag(tag);
718 self.set_headline(arena, &h.headline(context)?)
719 }
720 }
721 }
722
723 pub fn clear_tag<'a>(
724 self,
725 arena: &mut Arena,
726 tag: &str,
727 context: Option<&Context>,
728 ) -> Result<(), crate::errors::HeadlineError> {
729 match self.headline(arena, context).map(|h| h.to_owned()) {
730 None => Err(HeadlineError::InvalidHeadlineError),
731 Some(h) => {
732 let mut h = h.to_builder();
733 h.clear_tag(tag);
734 self.set_headline(arena, &h.headline(context)?)
735 }
736 }
737 }
738
739 pub fn set_keyword(
740 self,
741 arena: &mut Arena,
742 keyword: Option<Rope>,
743 context: Option<&Context>,
744 ) -> Result<(), crate::errors::HeadlineError> {
745 match self.headline(arena, context).map(|h| h.to_owned()) {
746 None => Err(HeadlineError::InvalidHeadlineError),
747 Some(h) => {
748 let mut h = h.to_builder();
749 h.keyword(keyword);
750 self.set_headline(arena, &h.headline(context)?)
751 }
752 }
753 }
754
755 pub fn set_title(
756 self,
757 arena: &mut Arena,
758 title: Rope,
759 context: Option<&Context>,
760 ) -> Result<(), crate::errors::HeadlineError> {
761 match self.headline(arena, context).map(|h| h.to_owned()) {
762 None => Err(HeadlineError::InvalidHeadlineError),
763 Some(h) => {
764 let mut h = h.to_builder();
765 h.title(title);
766 self.set_headline(arena, &h.headline(context)?)
767 }
768 }
769 }
770
771 pub fn set_commented(
772 self,
773 arena: &mut Arena,
774 commented: bool,
775 context: Option<&Context>,
776 ) -> Result<(), crate::errors::HeadlineError> {
777 match self.headline(arena, context).map(|h| h.to_owned()) {
778 None => Err(HeadlineError::InvalidHeadlineError),
779 Some(h) => {
780 let mut h = h.to_builder();
781 h.commented(commented);
782 self.set_headline(arena, &h.headline(context)?)
783 }
784 }
785 }
786
787 pub fn set_planning(
788 self,
789 arena: &mut Arena,
790 planning: Planning,
791 context: Option<&Context>,
792 ) -> Result<(), crate::errors::HeadlineError> {
793 match self.headline(arena, context) {
794 None => Err(HeadlineError::InvalidHeadlineError),
795 Some(h) => {
796 let mut h = h.to_builder();
797 h.planning(planning);
798 self.set_headline(arena, &h.headline(context)?)
799 }
800 }
801 }
802
803 pub fn set_scheduled(
804 self,
805 arena: &mut Arena,
806 scheduled: Option<Timestamp<'_>>,
807 context: Option<&Context>,
808 ) -> Result<(), crate::errors::HeadlineError> {
809 match self.headline(arena, context) {
810 None => Err(HeadlineError::InvalidHeadlineError),
811 Some(h) => {
812 let mut planning = h.planning().to_borrowed();
813 planning.scheduled = scheduled;
814 let mut h = h.to_builder();
815 h.planning(planning);
816 self.set_headline(arena, &h.headline(context)?)
817 }
818 }
819 }
820
821 pub fn set_deadline(
822 self,
823 arena: &mut Arena,
824 deadline: Option<Timestamp<'_>>,
825 context: Option<&Context>,
826 ) -> Result<(), crate::errors::HeadlineError> {
827 match self.headline(arena, context) {
828 None => Err(HeadlineError::InvalidHeadlineError),
829 Some(h) => {
830 let mut planning = h.planning().to_borrowed();
831 planning.deadline = deadline;
832 let mut h = h.to_builder();
833 h.planning(planning);
834 self.set_headline(arena, &h.headline(context)?)
835 }
836 }
837 }
838
839 pub fn set_closed(
840 self,
841 arena: &mut Arena,
842 closed: Option<Timestamp<'_>>,
843 context: Option<&Context>,
844 ) -> Result<(), crate::errors::HeadlineError> {
845 match self.headline(arena, context) {
846 None => Err(HeadlineError::InvalidHeadlineError),
847 Some(h) => {
848 let mut planning = h.planning().to_borrowed();
849 planning.closed = closed;
850 let mut h = h.to_builder();
851 h.planning(planning);
852 self.set_headline(arena, &h.headline(context)?)
853 }
854 }
855 }
856
857 pub fn set_body(
858 self,
859 arena: &mut Arena,
860 body: Rope,
861 context: Option<&Context>,
862 ) -> Result<(), crate::errors::HeadlineError> {
863 match self.headline(arena, context).map(|h| h.to_owned()) {
864 None => Err(HeadlineError::InvalidHeadlineError),
865 Some(h) => {
866 let mut h = h.to_builder();
867 h.body(body);
868 self.set_headline(arena, &h.headline(context)?)
869 }
870 }
871 }
872
873 #[cfg(feature = "orgize-integration")]
874 pub fn set_property(
875 self,
876 arena: &mut Arena,
877 property: &str,
878 value: &str,
879 context: Option<&Context>,
880 ) -> Result<(), crate::errors::HeadlineError> {
881 match self.headline(arena, context) {
882 None => Err(HeadlineError::InvalidHeadlineError),
883 Some(h) => {
884 let mut org = parse_orgize(h.body());
885 set_property_internal(&mut org, property, value)?;
886 let mut h = h.to_builder();
887 h.body(emit_orgize(&org));
888 let h = h.headline(context)?;
889 self.set_headline(arena, &h)
890 }
891 }
892 }
893
894 #[cfg(feature = "orgize-integration")]
895 pub fn clear_property(
896 self,
897 arena: &mut Arena,
898 property: &str,
899 context: Option<&Context>,
900 ) -> Result<(), crate::errors::HeadlineError> {
901 match self.headline(arena, context) {
902 None => Err(HeadlineError::InvalidHeadlineError),
903 Some(h) => {
904 let mut org = parse_orgize(h.body());
905 clear_property_internal(&mut org, property)?;
906 let mut h = h.to_builder();
907 h.body(emit_orgize(&org));
908 let h = h.headline(context)?;
909 self.set_headline(arena, &h)
910 }
911 }
912 }
913
914 #[cfg(feature = "orgize-integration")]
915 pub fn set_properties(
916 self,
917 arena: &mut Arena,
918 properties: indexmap::IndexMap<Cow<'static, str>, Cow<'static, str>>,
919 context: Option<&Context>,
920 ) -> Result<(), crate::errors::HeadlineError> {
921 match self.headline(arena, context) {
922 None => Err(HeadlineError::InvalidHeadlineError),
923 Some(h) => {
924 let mut org = parse_orgize(h.body());
925 set_properties_internal(&mut org, properties)?;
926 let mut h = h.to_builder();
927 h.body(emit_orgize(&org));
928 let h = h.headline(context)?;
929 self.set_headline(arena, &h)
930 }
931 }
932 }
933
934 #[cfg(feature = "orgize-integration")]
935 pub fn generate_id(
936 self,
937 arena: &mut Arena,
938 context: Option<&Context>,
939 ) -> Result<Cow<'static, str>, crate::errors::HeadlineError> {
940 match self.headline(arena, context) {
941 None => Err(HeadlineError::InvalidHeadlineError),
942 Some(h) => {
943 let mut org = parse_orgize(h.body());
944 if let Some(id) = get_property_internal("ID", &org)? {
945 return Ok(id.to_owned());
946 }
947 let id = generate_id_internal(&mut org)?;
948 let mut h = h.to_builder();
949 h.body(emit_orgize(&org));
950 let h = h.headline(context)?;
951 self.set_headline(arena, &h)?;
952 Ok(id)
953 }
954 }
955 }
956}
957
958#[cfg(test)]
959mod tests {
960 use super::*;
961
962 #[test]
963 fn test_newline() {
964 let mut arena = Arena::default();
965 let doc = arena.parse_str("");
966
967 assert!(doc.at(&arena, 0).is_none());
968
969 let doc = arena.parse_str("\n");
970
971 let (section, offset) = doc.at(&arena, 0).unwrap();
972 assert_eq!(section.id, doc.root.id);
973 assert_eq!(offset, 0);
974
975 assert!(doc.at(&arena, 1).is_none());
976
977 let doc = arena.parse_str("\n\n");
978
979 let (section, offset) = doc.at(&arena, 0).unwrap();
980 assert_eq!(section.id, doc.root.id);
981 assert_eq!(offset, 0);
982
983 let (section, offset) = doc.at(&arena, 1).unwrap();
984 assert_eq!(section.id, doc.root.id);
985 assert_eq!(offset, 1);
986
987 assert!(doc.at(&arena, 2).is_none());
988 }
989
990 #[test]
991 fn test_empty() {
992 let mut arena = Arena::default();
993 let doc = arena.parse_str("");
994 assert!(doc.at(&arena, 0).is_none());
995 }
996
997 #[test]
998 fn test_at_o() {
999 let mut arena = Arena::default();
1000 let doc = arena.parse_str("* foo\n* bar\n");
1001
1002 let (section, offset) = doc.at(&arena, 0).unwrap();
1003 assert_eq!(section.id, doc.root.children(&arena).next().unwrap().id);
1004 assert_eq!(offset, 0);
1005
1006 let (section, offset) = doc.at(&arena, 1).unwrap();
1007 assert_eq!(section.id, doc.root.children(&arena).next().unwrap().id);
1008 assert_eq!(offset, 1);
1009
1010 let (section, offset) = doc.at(&arena, 2).unwrap();
1011 assert_eq!(section.id, doc.root.children(&arena).next().unwrap().id);
1012 assert_eq!(offset, 2);
1013
1014 let (section, offset) = doc.at(&arena, 3).unwrap();
1015 assert_eq!(section.id, doc.root.children(&arena).next().unwrap().id);
1016 assert_eq!(offset, 3);
1017
1018 let (section, offset) = doc.at(&arena, 4).unwrap();
1019 assert_eq!(section.id, doc.root.children(&arena).next().unwrap().id);
1020 assert_eq!(offset, 4);
1021
1022 let (section, offset) = doc.at(&arena, 5).unwrap();
1024 assert_eq!(section.id, doc.root.children(&arena).next().unwrap().id);
1025 assert_eq!(offset, 5);
1026
1027 let (section, offset) = doc.at(&arena, 6).unwrap();
1028 assert_eq!(
1029 section.id,
1030 doc.root.children(&arena).skip(1).next().unwrap().id
1031 );
1032 assert_eq!(offset, 0);
1033
1034 let (section, offset) = doc.at(&arena, 7).unwrap();
1035 assert_eq!(
1036 section.id,
1037 doc.root.children(&arena).skip(1).next().unwrap().id
1038 );
1039 assert_eq!(offset, 1);
1040
1041 let (section, offset) = doc.at(&arena, 8).unwrap();
1042 assert_eq!(
1043 section.id,
1044 doc.root.children(&arena).skip(1).next().unwrap().id
1045 );
1046 assert_eq!(offset, 2);
1047
1048 let (section, offset) = doc.at(&arena, 9).unwrap();
1049 assert_eq!(
1050 section.id,
1051 doc.root.children(&arena).skip(1).next().unwrap().id
1052 );
1053 assert_eq!(offset, 3);
1054
1055 let (section, offset) = doc.at(&arena, 10).unwrap();
1056 assert_eq!(
1057 section.id,
1058 doc.root.children(&arena).skip(1).next().unwrap().id
1059 );
1060 assert_eq!(offset, 4);
1061
1062 let (section, offset) = doc.at(&arena, 11).unwrap();
1063 assert_eq!(
1064 section.id,
1065 doc.root.children(&arena).skip(1).next().unwrap().id
1066 );
1067 assert_eq!(offset, 5);
1068
1069 assert!(doc.at(&arena, 12).is_none());
1070 }
1071
1072 #[test]
1073 fn test_at_two() {
1074 let mut arena = Arena::default();
1075 let doc = arena.parse_str("* foo\n* bar");
1076
1077 let (section, offset) = doc.at(&arena, 0).unwrap();
1078 assert_eq!(section.id, doc.root.children(&arena).next().unwrap().id);
1079 assert_eq!(offset, 0);
1080
1081 let (section, offset) = doc.at(&arena, 1).unwrap();
1082 assert_eq!(section.id, doc.root.children(&arena).next().unwrap().id);
1083 assert_eq!(offset, 1);
1084
1085 let (section, offset) = doc.at(&arena, 2).unwrap();
1086 assert_eq!(section.id, doc.root.children(&arena).next().unwrap().id);
1087 assert_eq!(offset, 2);
1088
1089 let (section, offset) = doc.at(&arena, 3).unwrap();
1090 assert_eq!(section.id, doc.root.children(&arena).next().unwrap().id);
1091 assert_eq!(offset, 3);
1092
1093 let (section, offset) = doc.at(&arena, 4).unwrap();
1094 assert_eq!(section.id, doc.root.children(&arena).next().unwrap().id);
1095 assert_eq!(offset, 4);
1096
1097 let (section, offset) = doc.at(&arena, 5).unwrap();
1099 assert_eq!(section.id, doc.root.children(&arena).next().unwrap().id);
1100 assert_eq!(offset, 5);
1101
1102 let (section, offset) = doc.at(&arena, 6).unwrap();
1103 assert_eq!(
1104 section.id,
1105 doc.root.children(&arena).skip(1).next().unwrap().id
1106 );
1107 assert_eq!(offset, 0);
1108
1109 let (section, offset) = doc.at(&arena, 7).unwrap();
1110 assert_eq!(
1111 section.id,
1112 doc.root.children(&arena).skip(1).next().unwrap().id
1113 );
1114 assert_eq!(offset, 1);
1115
1116 let (section, offset) = doc.at(&arena, 8).unwrap();
1117 assert_eq!(
1118 section.id,
1119 doc.root.children(&arena).skip(1).next().unwrap().id
1120 );
1121 assert_eq!(offset, 2);
1122
1123 let (section, offset) = doc.at(&arena, 9).unwrap();
1124 assert_eq!(
1125 section.id,
1126 doc.root.children(&arena).skip(1).next().unwrap().id
1127 );
1128 assert_eq!(offset, 3);
1129
1130 let (section, offset) = doc.at(&arena, 10).unwrap();
1131 assert_eq!(
1132 section.id,
1133 doc.root.children(&arena).skip(1).next().unwrap().id
1134 );
1135 assert_eq!(offset, 4);
1136
1137 assert!(doc.at(&arena, 11).is_none());
1138 }
1139
1140 #[test]
1141 fn test_at_thre() {
1142 let mut arena = Arena::default();
1143 let doc = arena.parse_str("\n* foo\n* bar");
1144
1145 let (section, offset) = doc.at(&arena, 0).unwrap();
1146 assert_eq!(section.id, doc.root.id);
1147 assert_eq!(offset, 0);
1148
1149 let (section, offset) = doc.at(&arena, 1).unwrap();
1150 assert_eq!(section.id, doc.root.children(&arena).next().unwrap().id);
1151 assert_eq!(offset, 0);
1152
1153 let (section, offset) = doc.at(&arena, 2).unwrap();
1154 assert_eq!(section.id, doc.root.children(&arena).next().unwrap().id);
1155 assert_eq!(offset, 1);
1156
1157 let (section, offset) = doc.at(&arena, 3).unwrap();
1158 assert_eq!(section.id, doc.root.children(&arena).next().unwrap().id);
1159 assert_eq!(offset, 2);
1160
1161 let (section, offset) = doc.at(&arena, 4).unwrap();
1162 assert_eq!(section.id, doc.root.children(&arena).next().unwrap().id);
1163 assert_eq!(offset, 3);
1164
1165 let (section, offset) = doc.at(&arena, 5).unwrap();
1166 assert_eq!(section.id, doc.root.children(&arena).next().unwrap().id);
1167 assert_eq!(offset, 4);
1168
1169 let (section, offset) = doc.at(&arena, 6).unwrap();
1171 assert_eq!(section.id, doc.root.children(&arena).next().unwrap().id);
1172 assert_eq!(offset, 5);
1173
1174 let (section, offset) = doc.at(&arena, 7).unwrap();
1175 assert_eq!(
1176 section.id,
1177 doc.root.children(&arena).skip(1).next().unwrap().id
1178 );
1179 assert_eq!(offset, 0);
1180
1181 let (section, offset) = doc.at(&arena, 8).unwrap();
1182 assert_eq!(
1183 section.id,
1184 doc.root.children(&arena).skip(1).next().unwrap().id
1185 );
1186 assert_eq!(offset, 1);
1187
1188 let (section, offset) = doc.at(&arena, 9).unwrap();
1189 assert_eq!(
1190 section.id,
1191 doc.root.children(&arena).skip(1).next().unwrap().id
1192 );
1193 assert_eq!(offset, 2);
1194
1195 let (section, offset) = doc.at(&arena, 10).unwrap();
1196 assert_eq!(
1197 section.id,
1198 doc.root.children(&arena).skip(1).next().unwrap().id
1199 );
1200 assert_eq!(offset, 3);
1201
1202 let (section, offset) = doc.at(&arena, 11).unwrap();
1203 assert_eq!(
1204 section.id,
1205 doc.root.children(&arena).skip(1).next().unwrap().id
1206 );
1207 assert_eq!(offset, 4);
1208
1209 assert!(doc.at(&arena, 12).is_none());
1210 }
1211
1212 #[test]
1213 fn test_at_fo() {
1214 let mut arena = Arena::default();
1215 let doc = arena.parse_str("\n* foo\n* bar\n");
1216
1217 let (section, offset) = doc.at(&arena, 0).unwrap();
1218 assert_eq!(section.id, doc.root.id);
1219 assert_eq!(offset, 0);
1220
1221 let (section, offset) = doc.at(&arena, 1).unwrap();
1222 assert_eq!(section.id, doc.root.children(&arena).next().unwrap().id);
1223 assert_eq!(offset, 0);
1224
1225 let (section, offset) = doc.at(&arena, 2).unwrap();
1226 assert_eq!(section.id, doc.root.children(&arena).next().unwrap().id);
1227 assert_eq!(offset, 1);
1228
1229 let (section, offset) = doc.at(&arena, 3).unwrap();
1230 assert_eq!(section.id, doc.root.children(&arena).next().unwrap().id);
1231 assert_eq!(offset, 2);
1232
1233 let (section, offset) = doc.at(&arena, 4).unwrap();
1234 assert_eq!(section.id, doc.root.children(&arena).next().unwrap().id);
1235 assert_eq!(offset, 3);
1236
1237 let (section, offset) = doc.at(&arena, 5).unwrap();
1238 assert_eq!(section.id, doc.root.children(&arena).next().unwrap().id);
1239 assert_eq!(offset, 4);
1240
1241 let (section, offset) = doc.at(&arena, 6).unwrap();
1243 assert_eq!(section.id, doc.root.children(&arena).next().unwrap().id);
1244 assert_eq!(offset, 5);
1245
1246 let (section, offset) = doc.at(&arena, 7).unwrap();
1247 assert_eq!(
1248 section.id,
1249 doc.root.children(&arena).skip(1).next().unwrap().id
1250 );
1251 assert_eq!(offset, 0);
1252
1253 let (section, offset) = doc.at(&arena, 8).unwrap();
1254 assert_eq!(
1255 section.id,
1256 doc.root.children(&arena).skip(1).next().unwrap().id
1257 );
1258 assert_eq!(offset, 1);
1259
1260 let (section, offset) = doc.at(&arena, 9).unwrap();
1261 assert_eq!(
1262 section.id,
1263 doc.root.children(&arena).skip(1).next().unwrap().id
1264 );
1265 assert_eq!(offset, 2);
1266
1267 let (section, offset) = doc.at(&arena, 10).unwrap();
1268 assert_eq!(
1269 section.id,
1270 doc.root.children(&arena).skip(1).next().unwrap().id
1271 );
1272 assert_eq!(offset, 3);
1273
1274 let (section, offset) = doc.at(&arena, 11).unwrap();
1275 assert_eq!(
1276 section.id,
1277 doc.root.children(&arena).skip(1).next().unwrap().id
1278 );
1279 assert_eq!(offset, 4);
1280
1281 let (section, offset) = doc.at(&arena, 12).unwrap();
1282 assert_eq!(
1283 section.id,
1284 doc.root.children(&arena).skip(1).next().unwrap().id
1285 );
1286 assert_eq!(offset, 5);
1287
1288 assert!(doc.at(&arena, 13).is_none());
1289 }
1290
1291 #[test]
1292 fn test_at_nest() {
1293 let mut arena = Arena::default();
1294 let s = "* foo\n** bar\n*** baz\n* qux\n".to_string();
1295 let doc = arena.parse_str(&s);
1296 let foo = doc.root.children(&arena).next().unwrap();
1297 let bar = foo.children(&arena).next().unwrap();
1298 let baz = bar.children(&arena).next().unwrap();
1299
1300 let (section, offset) = doc.at(&arena, 0).unwrap();
1301 assert_eq!(section.id, foo.id);
1302 assert_eq!(offset, 0);
1303
1304 let (section, offset) = doc.at(&arena, 8).unwrap();
1305 assert_eq!(section.id, bar.id);
1306 assert_eq!(offset, 3);
1307
1308 let (section, offset) = doc.at(&arena, 18).unwrap();
1309 assert_eq!(section.id, baz.id);
1310 assert_eq!(offset, 7);
1311 }
1312}