Add Rust preprocessor to handle code examples gracefully

Fixes #213
This commit is contained in:
Sebastian Thiel
2019-07-05 17:00:56 +08:00
parent 8cb73d66c2
commit f33fae47e9
11 changed files with 678 additions and 599 deletions

View File

@@ -7,7 +7,7 @@
REQUEST_MARKER_TRAIT, RESPONSE_MARKER_TRAIT, supports_scopes, to_api_version,
to_fqan, METHODS_RESOURCE, ADD_PARAM_MEDIA_EXAMPLE, PROTOCOL_TYPE_INFO, enclose_in,
upload_action_fn, unique_type_name, schema_doc_format, METHODS_BUILDER_MARKER_TRAIT,
to_extern_crate_name)
to_extern_crate_name, rust_doc_sanitize)
def pretty_name(name):
return ' '.join(split_camelcase_s(name).split('.'))
@@ -341,7 +341,7 @@ You can read the full text at the repository's [license file][repo-license].
#[derive(PartialEq, Eq, Hash)]
pub enum Scope {
% for url, scope in auth.oauth2.scopes.items():
${scope.description | rust_doc_comment}
${scope.description | rust_doc_sanitize, rust_doc_comment}
${scope_url_to_variant(name, url, fully_qualified=False)},
% if not loop.last:

View File

@@ -11,7 +11,7 @@
DELEGATE_PROPERTY_NAME, struct_type_bounds_s, scope_url_to_variant,
re_find_replacements, ADD_PARAM_FN, ADD_PARAM_MEDIA_EXAMPLE, upload_action_fn, METHODS_RESOURCE,
method_name_to_variant, unique_type_name, size_to_bytes, method_default_scope,
is_repeated_property, setter_fn_name, ADD_SCOPE_FN)
is_repeated_property, setter_fn_name, ADD_SCOPE_FN, rust_doc_sanitize)
def get_parts(part_prop):
if not part_prop:
@@ -58,7 +58,7 @@
parts = get_parts(part_prop)
%>\
% if 'description' in m:
${m.description | rust_doc_comment}
${m.description | rust_doc_sanitize, rust_doc_comment}
///
% endif
% if m.get('supportsMediaDownload', False):
@@ -82,7 +82,7 @@ ${m.description | rust_doc_comment}
/// It is not used directly, but through a `${rb_type(resource)}` instance.
///
% if part_desc:
${part_desc | rust_doc_comment}
${part_desc | rust_doc_sanitize, rust_doc_comment}
///
% if m.get('scopes'):
/// # Scopes
@@ -220,7 +220,7 @@ ${self._setter_fn(resource, method, m, p, part_prop, ThisType, c)}\
# end part description
%>\
% if 'description' in p:
${p.description | rust_doc_comment, indent_all_but_first_by(1)}
${p.description | rust_doc_sanitize, rust_doc_comment, indent_all_but_first_by(1)}
% endif
% if is_repeated_property(p):
///
@@ -244,7 +244,7 @@ ${self._setter_fn(resource, method, m, p, part_prop, ThisType, c)}\
% endif
% if part_desc:
///
${part_desc | rust_doc_comment, indent_all_but_first_by(1)}
${part_desc | rust_doc_sanitize, rust_doc_comment, indent_all_but_first_by(1)}
% endif
pub fn ${mangle_ident(setter_fn_name(p))}(mut self, ${value_name}: ${InType}) -> ${ThisType} {
% if p.get('repeated', False):
@@ -875,7 +875,7 @@ if enable_resource_parsing \
}
% for p in media_params:
${p.description | rust_doc_comment, indent_all_but_first_by(1)}
${p.description | rust_doc_sanitize, rust_doc_comment, indent_all_but_first_by(1)}
///
% for item_name, item in p.info.iteritems():
/// * *${split_camelcase_s(item_name)}*: ${isinstance(item, (list, tuple)) and put_and(enclose_in("'", item)) or str(item)}

View File

@@ -6,7 +6,7 @@
rust_copy_value_s, organize_params, REQUEST_VALUE_PROPERTY_NAME,
build_all_params, rb_type_params_s, hub_type_params_s, mb_type_params_s, mb_additional_type_params,
struct_type_bounds_s, METHODS_RESOURCE, SPACES_PER_TAB, prefix_all_but_first_with,
METHODS_BUILDER_MARKER_TRAIT, remove_empty_lines, method_default_scope)
METHODS_BUILDER_MARKER_TRAIT, remove_empty_lines, method_default_scope, rust_doc_sanitize)
%>\
<%namespace name="util" file="../../lib/util.mako"/>\
<%namespace name="lib" file="lib.mako"/>\
@@ -80,7 +80,7 @@ impl${rb_params} ${ThisType} {
% if 'description' in m:
/// Create a builder to help you perform the following task:
///
${m.description | rust_doc_comment, indent_all_but_first_by(1)}
${m.description | rust_doc_sanitize, rust_doc_comment, indent_all_but_first_by(1)}
% endif
% if required_props:
///

View File

@@ -2,7 +2,8 @@
from util import (schema_markers, rust_doc_comment, mangle_ident, to_rust_type, put_and,
IO_TYPES, activity_split, enclose_in, REQUEST_MARKER_TRAIT, mb_type, indent_all_but_first_by,
NESTED_TYPE_SUFFIX, RESPONSE_MARKER_TRAIT, split_camelcase_s, METHODS_RESOURCE, unique_type_name,
PART_MARKER_TRAIT, canonical_type_name, TO_PARTS_MARKER, UNUSED_TYPE_MARKER, is_schema_with_optionals)
PART_MARKER_TRAIT, canonical_type_name, TO_PARTS_MARKER, UNUSED_TYPE_MARKER, is_schema_with_optionals,
rust_doc_sanitize)
%>\
## Build a schema which must be an object
###################################################################################################################
@@ -12,7 +13,7 @@
% if properties:
${struct} {
% for pn, p in properties.iteritems():
${p.get('description', 'no description provided') | rust_doc_comment, indent_all_but_first_by(1)}
${p.get('description', 'no description provided') | rust_doc_sanitize, rust_doc_comment, indent_all_but_first_by(1)}
% if pn != mangle_ident(pn):
#[serde(rename="${pn}")]
% endif
@@ -28,7 +29,7 @@ ${struct}(${to_rust_type(schemas, s.id, NESTED_TYPE_SUFFIX, s, allow_optionals=a
%>\
pub enum ${et} {
% for p in s.variant.map:
${p.get('description', 'no description provided') | rust_doc_comment, indent_all_but_first_by(1)}
${p.get('description', 'no description provided') | rust_doc_sanitize, rust_doc_comment, indent_all_but_first_by(1)}
% if variant_type(p) != p.type_value:
#[serde(rename="${p.type_value}")]
% endif
@@ -72,7 +73,7 @@ ${struct} { _never_set: Option<bool> }
s_type = unique_type_name(s.id)
%>\
<%block filter="rust_doc_comment">\
<%block filter="rust_doc_sanitize, rust_doc_comment">\
${doc(s, c)}\
</%block>
#[derive(${', '.join(traits)})]

View File

@@ -3,10 +3,12 @@ import os
from random import (randint, random, choice, seed)
import collections
from copy import deepcopy
import subprocess
seed(1337)
re_linestart = re.compile('^', flags=re.MULTILINE)
re_spaces_after_newline = re.compile('^ {4}', flags=re.MULTILINE)
re_first_4_spaces = re.compile('^ {1,4}', flags=re.MULTILINE)
re_desc_parts = re.compile("((the part (names|properties) that you can include in the parameter value are)|(supported values are ))(.*?)\.", flags=re.IGNORECASE|re.MULTILINE)
@@ -125,6 +127,22 @@ def rust_module_doc_comment(s):
def rust_doc_comment(s):
return re_linestart.sub('/// ', s)
# returns true if there is an indication for something that is interpreted as doc comment by rustdoc
def has_markdown_codeblock_with_indentation(s):
return re_spaces_after_newline.search(s) != None
def preprocess(s):
p = subprocess.Popen([os.environ['PREPROC']], close_fds=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
res = p.communicate(s)
return res[0]
# runs the preprocessor in case there is evidence for code blocks using indentation
def rust_doc_sanitize(s):
if has_markdown_codeblock_with_indentation(s):
return preprocess(s)
else:
return s
# rust comment filter
def rust_comment(s):
return re_linestart.sub('// ', s)

View File

@@ -13,7 +13,6 @@ fn main() {
};
let mut output = String::with_capacity(2048);
cmark(
Parser::new_ext(&md, pulldown_cmark::Options::all()).map(|e| {
use pulldown_cmark::Event::*;
@@ -21,7 +20,7 @@ fn main() {
Start(ref tag) => {
use pulldown_cmark::Tag::*;
match tag {
CodeBlock(code) => Start(CodeBlock(format!("ignore{}", code).into())),
CodeBlock(code) => Start(CodeBlock(format!("text{}", code).into())),
_ => e,
}
}