Metadata-Version: 2.4
Name: mdselect
Version: 0.1.0
Summary: Select Markdown sections by heading path
Author: Bowen Yu
License-Expression: MIT
Project-URL: Homepage, https://github.com/stevenybw/mdselect
Project-URL: Repository, https://github.com/stevenybw/mdselect.git
Project-URL: Issues, https://github.com/stevenybw/mdselect/issues
Keywords: markdown,cli,query,outline,sections
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Text Processing :: Markup :: Markdown
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: test
Requires-Dist: pytest>=7.0; extra == "test"
Dynamic: license-file

# mdselect

[中文说明](README.zh-CN.md)

Select Markdown sections by heading path.

`mdselect` is a small, zero-runtime-dependency command-line tool for inspecting
a Markdown outline and extracting complete sections without losing their
original formatting.

## Why mdselect?

Line-oriented tools such as `grep` can find a heading, but they do not know
where that section ends. A full Markdown AST library understands much more of
the format, but usually requires writing a program and choosing rendering
semantics.

`mdselect` fills the gap:

- query the heading hierarchy directly from the shell;
- return a matched heading together with its body and descendants;
- preserve the original Markdown content without parsing and re-rendering it;
- use regular expressions in a compact heading path expression;
- run with only the Python standard library.

## Installation

`mdselect` requires Python 3.10 or newer.

```bash
pipx install mdselect
# or
uv tool install mdselect
# or
python -m pip install mdselect
```

To install a development checkout:

```bash
python -m pip install -e ".[test]"
```

## Quick start

Given `handbook.md`:

```markdown
# Engineering Handbook

## Getting Started

Introductory material.

### Local Setup

Create a virtual environment.

## Operations

Operational notes.
```

Print its outline:

```bash
mdselect outline handbook.md
```

```text
# Engineering Handbook
  ## Getting Started
    ### Local Setup
  ## Operations
```

Extract the complete `Getting Started` subtree:

```bash
mdselect select --mpath '/Engineering/Getting Started' handbook.md
```

```markdown
## Getting Started

Introductory material.

### Local Setup

Create a virtual environment.
```

Add a trailing slash to omit the matched heading line:

```bash
mdselect select --mpath '/Engineering/Getting Started/' handbook.md
```

## mpath syntax

An mpath is a slash-separated heading path:

| Form | Meaning |
|---|---|
| `/Guide/Install` | Absolute query: the first segment only matches level-one headings. |
| `Install` | Relative query: the first segment matches headings at any level. |
| `/^Guide$/^Install$/` | Each segment is a Python regular expression; anchors make matches exact. The trailing slash omits the matched heading. |
| `/` | Return the original document unchanged. |

The complete rules are:

1. Each non-empty segment is compiled as a Python regular expression and
   matched with `re.search`.
2. A leading slash makes the query absolute: its first segment is tested only
   against level-one (`#`) headings.
3. Without a leading slash, the first segment is tested against every heading.
4. Every later segment is tested against descendants of the current matches,
   at any depth.
5. A trailing slash excludes the final matched heading line while keeping its
   body and descendants.
6. `/`, `//`, and an empty expression are no-ops that return the original
   document.
7. A slash cannot appear inside a segment.
8. Multiple matches retain document order and are separated by one blank line.
9. When both an ancestor and its descendant match, only the ancestor is
   rendered as a result because its subtree already contains the descendant.

`mdselect select -h` prints these rules without requiring the README.

## Exit status

| Situation | Status |
|---|---:|
| Successful outline or selection | `0` |
| No matching section | `0`, with empty standard output |
| Invalid arguments or regular expression | `2` |
| File cannot be read | non-zero |

The no-match behavior is intentional so selection can be used in shell
pipelines without treating an optional section as a command failure.

## Supported Markdown and boundaries

- ATX headings from `#` through `######` are supported when the marker starts
  in column one and is followed by whitespace.
- Optional closing hash markers are removed from the heading title used for
  matching.
- Backtick and tilde fenced code blocks are recognized; heading-like lines
  inside a fence are ignored.
- Selected content is rendered from the original lines, preserving tables,
  blockquotes, blank lines, inline markup, and fences.
- Files are read as UTF-8.
- Setext headings are not supported.
- `mdselect` does not interpret front matter, links, inline Markdown, or HTML
  as an AST.

## Comparison

| Tool | Best for | Structural section extraction |
|---|---|---|
| `grep` / `rg` | Finding matching lines across files | No |
| Markdown AST library | Full parsing, transformation, and custom rendering | Yes, with application code |
| `mdselect` | Shell-friendly outline and heading-subtree selection | Yes, directly from the CLI |

Use `grep` or `rg` to discover candidate files, then use `mdselect` when
the unit you need is a Markdown section rather than a line.

## Python API

```python
from mdselect import outline, select

print(outline(markdown_text))
section = select(markdown_text, "/Guide/Install")
```

The package also exports `Section`, `parse`, `render_subtree`, and
`InvalidPattern`.

## Contributing and security

See [CONTRIBUTING.md](CONTRIBUTING.md) for development and pull request
guidance. Report security issues privately as described in
[SECURITY.md](SECURITY.md).

## License

MIT
