///|
fn Parser::parameter(
self : Parser,
name : String,
value : Int?,
span : Span,
) -> Int? {
if value is None {
self.report(
"missing_parameter",
Error,
"Control \\\{name} requires a numeric parameter",
span,
)
}
value
}
///|
fn Parser::control(
self : Parser,
name : String,
value : Int?,
span : Span,
) -> Unit {
self.flush_utf8()
if self.time_control(name, value, span) {
return
}
if self.state.destination == "skip" {
self.state.starred = false
return
}
if self.destination(name, span) {
self.state.starred = false
return
}
if self.state.starred {
self.state.starred = false
self.state.destination = "skip"
self.warn_once(
"unknown_destination", "Unknown starred destination was omitted", span,
)
return
}
if name == "u" {
if self.parameter(name, value, span) is Some(v) {
self.emit_unicode(v, span)
}
return
}
if name == "uc" {
if self.parameter(name, value, span) is Some(v) {
if v >= 0 && v <= 32767 {
self.state.uc = v
} else {
self.report(
"fallback_range",
Error,
"Unicode fallback count must be between 0 and 32767",
span,
)
}
}
return
}
self.flush_surrogate()
self.flush_run()
let on = value.unwrap_or(1) != 0
let style = self.state.style
let paragraph = self.state.paragraph
match name {
"rtf" => {
if self.seen_version || self.stack.length() != 1 || value != Some(1) {
self.report(
"invalid_version",
Error,
"Expected one root-level \\rtf1 header",
span,
)
}
self.seen_version = true
}
"ansi" => self.state.codepage = 1252
"mac" => self.state.codepage = 10000
"pc" => self.state.codepage = 437
"pca" => self.state.codepage = 850
"ansicpg" =>
if self.parameter(name, value, span) is Some(v) {
if v > 0 {
self.state.codepage = v
} else {
self.report(
"invalid_codepage",
Error,
"Code page must be positive",
span,
)
}
}
"deff" =>
if self.parameter(name, value, span) is Some(v) {
self.default_font = v
self.state.style = { ..style, font: v, }
}
"f" =>
if self.parameter(name, value, span) is Some(v) {
if self.state.destination == "fonttbl" {
self.state.font_id = v
self.state.capture = StringBuilder()
self.state.charset = 0
self.state.font_codepage = None
} else {
self.state.style = { ..style, font: v, }
}
}
"fcharset" =>
if self.parameter(name, value, span) is Some(v) {
self.state.charset = v
}
"cpg" => self.state.font_codepage = self.parameter(name, value, span)
"fnil" => self.state.family = "nil"
"froman" => self.state.family = "roman"
"fswiss" => self.state.family = "swiss"
"fmodern" => self.state.family = "modern"
"fscript" => self.state.family = "script"
"fdecor" => self.state.family = "decor"
"ftech" => self.state.family = "technical"
"fbidi" => self.state.family = "bidi"
"red" | "green" | "blue" =>
if self.parameter(name, value, span) is Some(v) {
if v < 0 || v > 255 {
self.report(
"color_range",
Error,
"Color channel must be between 0 and 255",
span,
)
} else {
self.state.color_set = true
match name {
"red" => self.state.red = v
"green" => self.state.green = v
_ => self.state.blue = v
}
}
}
"b" => self.state.style = { ..style, bold: on, }
"i" => self.state.style = { ..style, italic: on, }
"ul" => self.state.style = { ..style, underline: on, }
"ulnone" => self.state.style = { ..style, underline: false, }
"strike" | "striked" => self.state.style = { ..style, strike: on, }
"v" => self.state.style = { ..style, hidden: on, }
"super" => self.state.style = { ..style, superscript: 1, }
"sub" => self.state.style = { ..style, superscript: -1, }
"nosupersub" => self.state.style = { ..style, superscript: 0, }
"plain" =>
self.state.style = { ..Style::default(), font: self.default_font, }
"fs" =>
if self.parameter(name, value, span) is Some(v) {
if v > 0 && v <= 32767 {
self.state.style = { ..style, size_half_points: v, }
} else {
self.report(
"font_size_range",
Error,
"Font size must be a positive half-point value",
span,
)
}
}
"cf" | "highlight" | "cb" =>
if self.parameter(name, value, span) is Some(v) {
if v < 0 {
self.report(
"color_index_range",
Error,
"Color index cannot be negative",
span,
)
} else if name == "cf" {
self.state.style = { ..style, foreground: v, }
} else {
self.state.style = { ..style, background: v, }
}
}
"pard" => {
self.state.paragraph = ParagraphStyle::default()
self.state.in_table = false
}
"ql" => self.state.paragraph = { ..paragraph, alignment: Left, }
"qr" => self.state.paragraph = { ..paragraph, alignment: Right, }
"qc" => self.state.paragraph = { ..paragraph, alignment: Center, }
"qj" => self.state.paragraph = { ..paragraph, alignment: Justify, }
"keep" => self.state.paragraph = { ..paragraph, keep_together: on, }
"keepn" => self.state.paragraph = { ..paragraph, keep_next: on, }
"li" | "ri" | "fi" | "sb" | "sa" | "sl" =>
if self.parameter(name, value, span) is Some(v) {
self.state.paragraph = match name {
"li" => { ..paragraph, left_indent: v, }
"ri" => { ..paragraph, right_indent: v, }
"fi" => { ..paragraph, first_indent: v, }
"sb" => { ..paragraph, space_before: v, }
"sa" => { ..paragraph, space_after: v, }
_ => { ..paragraph, line_spacing: v, }
}
}
"par" => self.finish_paragraph(span.end, true)
"line" => self.append_scalar(10, span)
"tab" => self.append_scalar(9, span)
"page" | "sect" => {
self.finish_paragraph(span.end, true)
self.warn_once(
"page_layout", "Page and section layout is represented as paragraph boundaries",
span,
)
}
"emdash" => self.append_scalar(0x2014, span)
"endash" => self.append_scalar(0x2013, span)
"emspace" => self.append_scalar(0x2003, span)
"enspace" => self.append_scalar(0x2002, span)
"qmspace" => self.append_scalar(0x2005, span)
"bullet" => self.append_scalar(0x2022, span)
"lquote" => self.append_scalar(0x2018, span)
"rquote" => self.append_scalar(0x2019, span)
"ldblquote" => self.append_scalar(0x201C, span)
"rdblquote" => self.append_scalar(0x201D, span)
"zwj" => self.append_scalar(0x200D, span)
"zwnj" => self.append_scalar(0x200C, span)
"trowd" => {
self.finish_paragraph(span.start, false)
self.state.in_table = true
self.cell = 0
}
"intbl" => self.state.in_table = on
"cell" => {
self.state.in_table = true
self.finish_paragraph(span.end, true)
self.cell += 1
}
"row" => {
self.finish_paragraph(span.end, false)
self.row += 1
self.cell = 0
self.state.in_table = false
}
"nestcell" | "nestrow" | "clmgf" | "clmrg" | "clvmgf" | "clvmrg" =>
self.warn_once(
"complex_table", "Nested or merged table structure is not reconstructed",
span,
)
"itap" =>
if value.unwrap_or(1) > 1 {
self.warn_once(
"complex_table", "Nested table structure is not reconstructed", span,
)
}
"picw" => self.state.width = self.parameter(name, value, span)
"pich" => self.state.height = self.parameter(name, value, span)
"bin" => ()
"cellx"
| "trgaph"
| "trleft"
| "trrh"
| "trql"
| "trqr"
| "trqc"
| "lang"
| "langfe"
| "deflang"
| "deflangfe"
| "viewkind"
| "viewscale"
| "fet"
| "widowctrl"
| "deftab"
| "paperw"
| "paperh"
| "margl"
| "margr"
| "margt"
| "margb"
| "landscape"
| "cocoartf"
| "cocoatextscaling"
| "cocoaplatform"
| "pngblip"
| "jpegblip"
| "wmetafile"
| "emfblip"
| "picscalex"
| "picscaley"
| "picwgoal"
| "pichgoal"
| "objemb"
| "objlink"
| "objw"
| "objh" => ()
_ =>
self.warn_once(
"unknown_control_\{name}",
"Unrecognized control \\\{name}; surrounding text is retained",
span,
)
}
}