Rust — mdwire-core

crates.io version

mdwire 의 코어입니다. 표준 라이브러리 외에는 의존성이 없습니다. 크레이트 이름은 mdwire-core 이고, 라이브러리는 mdwire 로 import 합니다. 전체 rustdoc 은 docs.rs/mdwire-core에 있습니다.

cargo add mdwire-core

render

use mdwire::{render, Channel};

let parts: Vec<String> = render("## 제목\n\n**굵게** 있는 문단", Channel::TelegramHtml);
assert_eq!(parts, vec!["<b>제목</b>\n\n<b>굵게</b> 있는 문단"]);

render(input: &str, channel: Channel) -> Vec<String> 은 완성된 문서를 변환합니다. 길이 제한을 넘으면 글자 수로 자르지 않고 열린 마크업이 없는 지점을 골라 나눕니다.

render_with

use mdwire::{render_with, Channel, Options};

let options = Options { limit: Some(4096), ..Default::default() };
let out = render_with("**굵게** 는 **영향 범위", Channel::SlackMarkdown, options);
assert_eq!(out.parts, vec!["**굵게** 는 **영향 범위**"]);
assert_eq!(out.repairs.closed_emphasis, 1);

시그니처는 render_with(input: &str, channel: Channel, options: Options) -> Rendered 이고, Rendered { parts: Vec<String>, repairs: Repairs } 를 반환합니다.

Options

pub struct Options {
    pub limit: Option<usize>,   // None = channel.limit(). MIN_LIMIT(256) 보다 작으면 올림
    pub html: HtmlOptions,      // Channel::Html 에서만
}

pub struct HtmlOptions {
    pub line_breaks: LineBreaks,          // Br(기본) | Space
    pub images: Images,                   // Link(기본) | Load
    pub schemes: Option<Vec<String>>,     // None = http, https, mailto. Some 이면 기본값을 대체
}

필드가 늘어날 수 있으니 Options { limit, ..Default::default() } 형태로 만드세요. MIN_LIMIT 은 256 입니다.

Streamer

use mdwire::{Channel, Streamer};

let mut s = Streamer::new(Channel::TelegramHtml);
let mut acc = String::new();
s.push_into("앞말 **굵", &mut acc);
assert_eq!(acc, "앞말 ");                                   // 지금까지 확정된 출력
assert_eq!(format!("{acc}{}", s.preview()), "앞말 <b>굵</b>"); // 지금 화면에 표시할 내용

s.push_into("게** 끝", &mut acc);
let last = format!("{acc}{}", s.preview());
s.finish_into(&mut acc);
assert_eq!(acc, last);
assert!(!s.revised());                                       // 마지막 화면이 곧 완성본
Streamer::new(channel) · Streamer::with_options(channel, options) 문서 하나에 스트리머 하나를 씁니다.
push(&mut self, chunk) -> &str 지금 보내도 안전한 출력입니다. 다음 호출 전까지만 빌려줍니다.
push_into(&mut self, chunk, out: &mut String) 같은 출력을 호출자 버퍼에 씁니다. 청크마다 할당이 없습니다.
finish(&mut self) -> &str · finish_into(&mut self, out) 남은 출력입니다. 열린 마크업은 닫아서 반환합니다.
preview(&mut self) -> &str · preview_into(&mut self, out) 메시지 전체를 다시 렌더링할 때 붙이는 뒷부분입니다. 비용이 열린 블록 수에 비례하므로 화면을 갱신할 때만 호출하세요.
close_open(&self, out: &mut String) 이미 보낸 블록 마크업의 닫는 태그만 붙입니다.
revised(&self) -> bool finish 다음에 호출합니다. 완성본이 마지막 preview 와 다른지 알려 줍니다. 참이면 “다를 수 있다”는 뜻입니다.
repairs(&self) -> Repairs 지금까지 센 정규화 보고를 반환합니다.

계약(push 출력은 확정이고, 이어 붙이면 render 결과와 같다)은 Concepts에 있습니다.

Channel

pub enum Channel { TelegramHtml, SlackMarkdown, GithubMarkdown, NotionMarkdown, Plain, Html }
Channel::name(self) -> &'static str · Channel::parse(&str) -> Option<Channel> 문자열 이름("telegram-html" …)과 채널을 서로 바꿉니다.
Channel::all() 모든 채널을 반환합니다.
Channel::limit(self) -> usize 조각 길이 제한을 반환합니다. Html 은 usize::MAX 입니다.

Repairs

pub struct Repairs {
    pub closed_emphasis: usize,
    pub closed_fence: usize,
    pub reverted_code_span: usize,
    pub dropped_marker: usize,
    pub guessed_pair: usize,
    // 채널에 맞춰 바꾼 것
    pub escaped_char: usize,
    pub tag_emphasis: usize,
    pub stripped_html: usize,
    pub rewritten_bullet: usize,
    pub rewritten_table: usize,
    pub converted_marker: usize,
}

any() 는 하나라도 고쳤는지(앞의 네 필드), changed() 는 고쳤든 바꿨든 하나라도 했는지 알려 줍니다. 각 필드가 세는 것은 Concepts에 있습니다.

mdwire::width

char_width(char) -> usize(0, 1, 2), str_width(&str) -> usize, is_cjk(char) -> bool 은 코어가 고정폭 표를 정렬할 때 쓰는 표시 폭 함수입니다.