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
4 changes: 4 additions & 0 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"doctest",
"mkdn",
"repr",
"rustc",
"rustlang",
"rustup"
],
Expand All @@ -31,6 +32,9 @@
"filename": "Cargo.toml",
"dictionaries": [
"crates"
],
"words": [
"cfgs"
]
},
{
Expand Down
11 changes: 8 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ jobs:
- macos-latest
- ubuntu-latest
- windows-latest
toolchain:
- stable
include:
- os: ubuntu-latest
toolchain: '1.85'
steps:
- name: Checkout
uses: actions/checkout@v4
Expand All @@ -42,9 +47,9 @@ jobs:
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
key: ${{ runner.os }}-cargo-${{ matrix.toolchain }}-${{ hashFiles('**/Cargo.lock') }}
- name: Set up toolchain
run: rustup install
run: rustup override set ${{ matrix.toolchain }}
- name: Test
run: cargo test --all-features --workspace

Expand All @@ -62,7 +67,7 @@ jobs:
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
key: ${{ runner.os }}-cargo-stable-${{ hashFiles('**/Cargo.lock') }}
- name: Set up toolchain
run: rustup show
- name: Check formatting
Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Cache
uses: actions/cache@v4
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-stable-${{ hashFiles('**/Cargo.lock') }}
- name: Set up toolchain
run: rustup install
- name: Release
Expand Down
7 changes: 6 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
{
"rust-analyzer.cargo.cfgs": [
"debug_assertions",
"miri",
"rust_analyzer"
],
"rust-analyzer.cargo.features": "all",
"rust-analyzer.check.command": "clippy",
"rust-analyzer.checkOnSave": true,
Expand All @@ -8,4 +13,4 @@
"[toml]": {
"editor.formatOnSave": true
}
}
}
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 8 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "include-file"
version = "0.4.0"
version = "0.5.0"
description = "Include sections of files into Rust source code"
readme = "README.md"
authors = ["Heath Stewart (https://github.com/heaths)"]
Expand All @@ -15,11 +15,17 @@ license = "MIT"
proc-macro = true

[dependencies]
proc-macro2 = "1.0.103"
proc-macro2 = { version = "1.0.103", features = ["span-locations"] }
syn = "2.0.109"

[dev-dependencies]
quote = "1.0.42"

[lints.clippy]
test_attr_in_doctest = "allow"

[lints.rust]
unexpected_cfgs = { level = "allow", check-cfg = [
"cfg(rust_analyzer)",
"cfg(span_locations)",
] }
17 changes: 13 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,19 @@ You can demonstrate just the code you want in markdown while maintaining the ben

## Macros

* `include_asciidoc!(path, name)` includes Rust snippets from AsciiDoc files, commonly with `.asciidoc`, `.adoc`, or `.asc` extensions.
* `include_markdown!(path, name)` includes Rust snippets from Markdown files, commonly with `.markdown`, `.mdown`, `.mkdn`, or `.md` extensions.
* `include_org!(path, name)` includes Rust snippets from Org files, commonly with `.org` extension.
* `include_textile!(path, name)` includes Rust snippets from Textile files, commonly with `.textile` extension.
Macro | Description
------------------------------- | ---
`include_asciidoc!(path, name)` | Includes Rust snippets from AsciiDoc files, commonly with `.asciidoc`, `.adoc`, or `.asc` extensions.
`include_markdown!(path, name)` | Includes Rust snippets from Markdown files, commonly with `.markdown`, `.mdown`, `.mkdn`, or `.md` extensions.
`include_org!(path, name)` | Includes Rust snippets from Org files, commonly with `.org` extension.
`include_textile!(path, name)` | Includes Rust snippets from Textile files, commonly with `.textile` extension.

All of these macros also support the following parameters:

Parameter | Description
---------- | ---
`relative` | (*Requires rustc 1.88 or newer*) The path is relative to the source file calling the macro. May show an error in rust-analyzer until [rust-lang/rust-analyzer#15950](https://github.com/rust-lang/rust-analyzer/issues/15950) is fixed.
`scope` | Includes the Rust snippet in braces `{ .. }`.

## Examples

Expand Down
82 changes: 82 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,88 @@
// Copyright 2025 Heath Stewart.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.

use std::{cmp::Ordering, env, process::Command, str::FromStr};

const MIN_SPAN_LOCATIONS_VER: Version = Version::new(1, 88, 0);

fn main() {
println!("cargo::rerun-if-changed=README.md");
if matches!(rustc_version(), Ok(version) if version >= MIN_SPAN_LOCATIONS_VER) {
println!("cargo::rustc-cfg=span_locations");
}
}

fn rustc_version() -> Result<Version, Box<dyn std::error::Error>> {
let output = Command::new(env::var("RUSTC")?).arg("--version").output()?;
let stdout = String::from_utf8(output.stdout)?;
let mut words = stdout.split_whitespace();
words.next().ok_or("expected `rustc`")?;

let version: Version = words.next().ok_or("expected version")?.parse()?;
Ok(version)
}

#[derive(Debug, Default, Eq)]
struct Version {
major: u16,
minor: u16,
patch: u16,
}

impl Version {
const fn new(major: u16, minor: u16, patch: u16) -> Self {
Self {
major,
minor,
patch,
}
}
}

impl FromStr for Version {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
// cspell:ignore splitn
let mut values = s.splitn(3, ".").map(str::parse::<u16>);
Ok(Self {
major: values
.next()
.ok_or("no major version")?
.map_err(|err| err.to_string())?,
minor: values
.next()
.ok_or("no minor version")?
.map_err(|err| err.to_string())?,
patch: values
.next()
.ok_or("no patch version")?
.map_err(|err| err.to_string())?,
})
}
}

impl PartialEq for Version {
fn eq(&self, other: &Self) -> bool {
self.major == other.major && self.minor == other.minor && self.patch == other.patch
}
}

impl Ord for Version {
fn cmp(&self, other: &Self) -> Ordering {
let cmp = self.major.cmp(&other.major);
if cmp != Ordering::Equal {
return cmp;
}
let cmp = self.minor.cmp(&other.minor);
if cmp != Ordering::Equal {
return cmp;
}
self.patch.cmp(&other.patch)
}
}

impl PartialOrd for Version {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
Loading