Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "dacli"
version = "0.4.26"
version = "0.4.27"
description = "Documentation Access CLI - Navigate and query large documentation projects"
readme = "README.md"
license = { text = "MIT" }
Expand Down
2 changes: 1 addition & 1 deletion src/dacli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
"""


__version__ = "0.4.26"
__version__ = "0.4.27"
4 changes: 3 additions & 1 deletion src/dacli/api/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
from pydantic import BaseModel, Field

# Valid element types for GET /elements endpoint
VALID_ELEMENT_TYPES = frozenset(["admonition", "code", "image", "list", "plantuml", "table"])
VALID_ELEMENT_TYPES = frozenset(
["admonition", "blockquote", "code", "image", "list", "plantuml", "table"]
)


class LocationResponse(BaseModel):
Expand Down
2 changes: 1 addition & 1 deletion src/dacli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,7 @@ def search(ctx: CliContext, query: str, scope: str | None, max_results: int):
""")
@click.argument("section_path", required=False, default=None)
@click.option("--type", "element_type", default=None,
help="Element type: admonition, code, image, list, plantuml, table")
help="Element type: admonition, blockquote, code, image, list, plantuml, table")
@click.option("--recursive", is_flag=True, default=False,
help="Include elements from child sections")
@click.option("--include-content", is_flag=True, default=False,
Expand Down
87 changes: 86 additions & 1 deletion src/dacli/markdown_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,13 @@
IMAGE_PATTERN = re.compile(r"!\[([^\]]*)\]\(([^)\s]+)(?:\s+\"([^\"]*)\")?\)")

# List patterns
TASK_LIST_PATTERN = re.compile(r"^[\s]*-\s+\[([ xX])\]\s+.+$")
UNORDERED_LIST_PATTERN = re.compile(r"^[\s]*[-*+]\s+.+$")
ORDERED_LIST_PATTERN = re.compile(r"^[\s]*\d+\.\s+.+$")

# Blockquote pattern
BLOCKQUOTE_PATTERN = re.compile(r"^>\s?(.*)$")

# Setext heading patterns (for warning detection - not supported)
# H1: line of text followed by line of ='s (at least 3)
SETEXT_H1_UNDERLINE = re.compile(r"^={3,}\s*$")
Expand Down Expand Up @@ -535,6 +539,11 @@ def _parse_elements(
current_list_type: str | None = None
current_list_element: Element | None = None

# Track blockquote state
in_blockquote = False
blockquote_start_line = 0
blockquote_content: list[str] = []

# Content tracking for Issue #159
table_content: list[str] = []
list_content: list[str] = []
Expand Down Expand Up @@ -681,8 +690,67 @@ def _parse_elements(
current_list_element = None
continue

# Handle lists (unordered and ordered)
# Handle blockquotes (Issue #28)
blockquote_match = BLOCKQUOTE_PATTERN.match(line)
if blockquote_match and not in_code_block and not in_table:
# Finalize any open list before starting blockquote
if current_list_element is not None and list_content:
current_list_element.attributes["content"] = "\n".join(list_content)
current_list_type = None
current_list_element = None

if not in_blockquote:
in_blockquote = True
blockquote_start_line = line_num
blockquote_content = []
blockquote_content.append(line)
continue

if in_blockquote:
# Non-blockquote line ends the blockquote
elements.append(
Element(
type="blockquote",
source_location=SourceLocation(
file=file_path,
line=blockquote_start_line,
end_line=blockquote_start_line + len(blockquote_content) - 1,
),
attributes={
"content": "\n".join(blockquote_content),
},
parent_section=current_section_path,
)
)
in_blockquote = False
blockquote_content = []

# Handle lists (unordered, ordered, and task lists)
if not in_code_block and not in_table:
# Check for task list (- [ ] or - [x]) before unordered list
# since task list items also match unordered list pattern
if TASK_LIST_PATTERN.match(line):
if current_list_type != "task":
# Save previous list content if any (Issue #159)
if current_list_element is not None and list_content:
current_list_element.attributes["content"] = "\n".join(list_content)
current_list_type = "task"
list_content = []
element = Element(
type="list",
source_location=SourceLocation(
file=file_path, line=line_num, end_line=line_num
),
attributes={"list_type": "task"},
parent_section=current_section_path,
)
elements.append(element)
current_list_element = element
list_content.append(line)
if current_list_element is not None:
current_list_element.source_location.end_line = line_num
continue

# Check for unordered list (*, -, +)
if UNORDERED_LIST_PATTERN.match(line):
if current_list_type != "unordered":
Expand Down Expand Up @@ -741,6 +809,23 @@ def _parse_elements(
current_list_type = None
current_list_element = None

# Handle blockquote at end of file (Issue #28)
if in_blockquote and blockquote_content:
elements.append(
Element(
type="blockquote",
source_location=SourceLocation(
file=file_path,
line=blockquote_start_line,
end_line=blockquote_start_line + len(blockquote_content) - 1,
),
attributes={
"content": "\n".join(blockquote_content),
},
parent_section=current_section_path,
)
)

# Handle unclosed code block at end of file
if in_code_block:
logger.warning(
Expand Down
2 changes: 1 addition & 1 deletion src/dacli/mcp_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ def get_elements(
the documentation, such as code examples, tables, or diagrams.
Args:
element_type: Filter by type - 'admonition', 'code', 'image',
element_type: Filter by type - 'admonition', 'blockquote', 'code', 'image',
'list', 'plantuml', 'table'. None returns all elements.
section_path: Filter by section path (e.g., '/architecture').
recursive: If True, include elements from child sections.
Expand Down
2 changes: 1 addition & 1 deletion src/dacli/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class Element:
index: 0-based index within the parent section (set during indexing)
"""

type: Literal["code", "table", "image", "plantuml", "admonition", "list"]
type: Literal["code", "table", "image", "plantuml", "admonition", "list", "blockquote"]
source_location: SourceLocation
attributes: dict[str, Any]
parent_section: str
Expand Down
Loading
Loading