cmark-writer 0.6.2

A CommonMark writer implementation in Rust for serializing AST nodes to CommonMark format
Documentation
# GFM Task Lists Example

This example demonstrates how to create GitHub Flavored Markdown task lists, which are essentially checkboxes that can be either checked or unchecked.

## Basic Task List Example

```rust
#[cfg(feature = "gfm")]
use cmark_writer::ast::{Node, ListItem, TaskListStatus};
use cmark_writer::options::WriterOptionsBuilder;
use cmark_writer::writer::CommonMarkWriter;

#[cfg(feature = "gfm")]
fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create a document with task lists
    let document = Node::Document(vec![
        Node::heading(1, vec![Node::Text("Project Tasks".to_string())]),
        
        Node::Paragraph(vec![
            Node::Text("The following tasks need to be completed:".to_string())
        ]),
        
        // Unordered list with task items
        Node::UnorderedList(vec![
            // Unchecked task
            ListItem::Task {
                status: TaskListStatus::Unchecked,
                content: vec![Node::Paragraph(vec![
                    Node::Text("Implement feature X".to_string())
                ])],
            },
            
            // Checked task
            ListItem::Task {
                status: TaskListStatus::Checked,
                content: vec![Node::Paragraph(vec![
                    Node::Text("Write documentation".to_string())
                ])],
            },
            
            // Another unchecked task
            ListItem::Task {
                status: TaskListStatus::Unchecked,
                content: vec![Node::Paragraph(vec![
                    Node::Text("Test on various platforms".to_string())
                ])],
            },
            
            // Nested tasks
            ListItem::Task {
                status: TaskListStatus::Unchecked,
                content: vec![
                    Node::Paragraph(vec![Node::Text("Deploy to production".to_string())]),
                    // Nested task list
                    Node::UnorderedList(vec![
                        ListItem::Task {
                            status: TaskListStatus::Checked,
                            content: vec![Node::Paragraph(vec![
                                Node::Text("Prepare staging environment".to_string())
                            ])],
                        },
                        ListItem::Task {
                            status: TaskListStatus::Unchecked,
                            content: vec![Node::Paragraph(vec![
                                Node::Text("Configure CI/CD pipeline".to_string())
                            ])],
                        },
                    ]),
                ],
            },
        ]),
    ]);
    
    // Configure writer with GFM task lists enabled
    let options = WriterOptionsBuilder::new()
        .gfm_tasklists(true)
        .build();
    
    let mut writer = CommonMarkWriter::with_options(options);
    writer.write(&document)?;
    let markdown = writer.into_string();
    
    // Print the generated markdown
    println!("{}", markdown);
    
    Ok(())
}

#[cfg(not(feature = "gfm"))]
fn main() {
    println!("This example requires the 'gfm' feature to be enabled");
}
```

With the `gfm` feature enabled, this produces:

```markdown
# Project Tasks

The following tasks need to be completed:

- [ ] Implement feature X
- [x] Write documentation
- [ ] Test on various platforms
- [ ] Deploy to production
  - [x] Prepare staging environment
  - [ ] Configure CI/CD pipeline
```

## Mixed List Types Example

You can mix task list items with regular list items:

```rust
#[cfg(feature = "gfm")]
use cmark_writer::ast::{Node, ListItem, TaskListStatus};
use cmark_writer::options::WriterOptionsBuilder;
use cmark_writer::writer::CommonMarkWriter;

#[cfg(feature = "gfm")]
fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create a document with mixed list types
    let document = Node::Document(vec![
        Node::heading(1, vec![Node::Text("Mixed List Example".to_string())]),
        
        // Unordered list with both task and regular items
        Node::UnorderedList(vec![
            // Regular list item
            ListItem::Unordered {
                content: vec![Node::Paragraph(vec![
                    Node::Text("This is a regular list item".to_string())
                ])],
            },
            
            // Task list item
            ListItem::Task {
                status: TaskListStatus::Unchecked,
                content: vec![Node::Paragraph(vec![
                    Node::Text("This is a task list item".to_string())
                ])],
            },
            
            // Another regular list item
            ListItem::Unordered {
                content: vec![Node::Paragraph(vec![
                    Node::Text("Another regular item".to_string())
                ])],
            },
            
            // Completed task
            ListItem::Task {
                status: TaskListStatus::Checked,
                content: vec![Node::Paragraph(vec![
                    Node::Text("A completed task".to_string())
                ])],
            },
        ]),
        
        // Also works with ordered lists
        Node::heading(2, vec![Node::Text("With Ordered Lists".to_string())]),
        
        Node::OrderedList {
            start: 1,
            items: vec![
                // Regular ordered item
                ListItem::Ordered {
                    number: None,
                    content: vec![Node::Paragraph(vec![
                        Node::Text("First ordered item".to_string())
                    ])],
                },
                
                // Task item in ordered list
                ListItem::Task {
                    status: TaskListStatus::Unchecked,
                    content: vec![Node::Paragraph(vec![
                        Node::Text("Task in ordered list".to_string())
                    ])],
                },
                
                // Another regular ordered item
                ListItem::Ordered {
                    number: None,
                    content: vec![Node::Paragraph(vec![
                        Node::Text("Another ordered item".to_string())
                    ])],
                },
            ],
        },
    ]);
    
    // Configure writer with GFM task lists enabled
    let options = WriterOptionsBuilder::new()
        .gfm_tasklists(true)
        .build();
    
    let mut writer = CommonMarkWriter::with_options(options);
    writer.write(&document)?;
    let markdown = writer.into_string();
    
    // Print the generated markdown
    println!("{}", markdown);
    
    Ok(())
}
```

With GFM enabled, this produces:

```markdown
# Mixed List Example

- This is a regular list item
- [ ] This is a task list item
- Another regular item
- [x] A completed task

## With Ordered Lists

1. First ordered item
2. [ ] Task in ordered list
3. Another ordered item
```

## Task List Best Practices

1. **Use task lists for actionable items**: Task lists are best for tracking to-do items, rather than general information
2. **Keep task descriptions concise**: Brief, clear descriptions work best in task lists
3. **Use nesting for hierarchical tasks**: Group related sub-tasks under parent tasks
4. **Combine with other Markdown elements**: Task list descriptions can include other formatting like emphasis or links
5. **Consider state representation**: Checked items typically represent completed tasks, use them consistently

## Implementation Notes

When implementing task lists:

- Remember to enable the `gfm` feature in your `Cargo.toml`
- Use the `WriterOptionsBuilder` to enable GFM task lists
- Task lists can be nested within other lists
- Task items work in both ordered and unordered lists