ansi_control_codes/
explain.rs

1//! # Explanations of ansi-control-codes
2//!
3//! This module provides functionality to explain and inspect any ansi-control-code.
4//!
5//! Enable this module by using the feature `explain`
6//!
7//! ```text
8//! cargo add ansi-control-codes --features explain
9//! ```
10//!
11//! ## Names of Control Codes
12//!
13//! The functions [`short_name`][Explain::short_name] and [`long_name`][Explain::long_name] of the trait [`Explain`]
14//! provide access to a control function's name. Short names are the abbreviated names of control functions, whereas
15//! long names are the human readable equivalents.
16//!
17//! ```
18//! use ansi_control_codes::categories::format_effectors::CR;
19//! use ansi_control_codes::explain::Explain;
20//! println!("short name: {}, long name: {}", CR.short_name().unwrap(), CR.long_name());
21//! // this will print "short name: CR, long name: Carriage Return"
22//! ```
23//!
24//! Short names of control functions are available for all control functions except for private-use control codes.
25//!
26//! ## Descriptions of Control Codes
27//!
28//! The functions [`short_description`][Explain::short_description] and [`long_description`][Explain::long_description]
29//! of the trait [`Explain`] provide access to a control function's short and long descriptions. Not all control
30//! functions have long descriptions, in which case the `long_description` returns the same description text as the
31//! `short_description` functions.
32//!
33//! ```
34//! use ansi_control_codes::categories::format_effectors::CR;
35//! use ansi_control_codes::explain::Explain;
36//! println!("short description: {}, long description: {}", CR.short_description(), CR.long_description());
37//! ```
38
39use std::{convert::Infallible, str::FromStr};
40
41use crate::{control_sequences::*, modes::Mode, ControlFunction, ControlFunctionType};
42
43macro_rules! param {
44    ($self:ident, $index:literal, $default:literal) => {
45        get_param(&$self.parameters, $index, $default)
46    };
47    ($self:ident, ordinal $index:literal, $default:literal) => {
48        ordinal_indicator(get_param(&$self.parameters, $index, $default))
49    };
50}
51
52macro_rules! explain_selection {
53    ($selection:ident, $self:ident, $index:literal) => {
54        $selection::from_str(
55            $self
56                .parameters
57                .get($index)
58                .map(&String::as_ref)
59                .unwrap_or(""),
60        )
61        .expect("Reached infallible code.")
62        .explain()
63    };
64}
65
66#[derive(Debug)]
67enum Function {
68    // C0
69    ACK,
70    BEL,
71    BS,
72    CAN,
73    CR,
74    DC1,
75    DC2,
76    DC3,
77    DC4,
78    DLE,
79    EM,
80    ENQ,
81    EOT,
82    ESC,
83    ETB,
84    ETX,
85    FF,
86    HT,
87    IS1,
88    IS2,
89    IS3,
90    IS4,
91    LF,
92    LS0,
93    LS1,
94    NAK,
95    NUL,
96    SOH,
97    STX,
98    SUB,
99    SYN,
100    VT,
101    // C1
102    APC,
103    BPH,
104    CCH,
105    CSI,
106    DCS,
107    EPA,
108    ESA,
109    HTJ,
110    HTS,
111    MW,
112    NBH,
113    NEL,
114    OSC,
115    PLD,
116    PLU,
117    PM,
118    PU1,
119    PU2,
120    RI,
121    SCI,
122    SOS,
123    SPA,
124    SSA,
125    SS2,
126    SS3,
127    ST,
128    STS,
129    VTS,
130    // Independent Control Functions
131    CMD,
132    DMI,
133    EMI,
134    INT,
135    LS1R,
136    LS2,
137    LS2R,
138    LS3,
139    LS3R,
140    RIS,
141    // Control Sequences
142    CBT,
143    CHA,
144    CHT,
145    CNL,
146    CPL,
147    CPR,
148    CTC,
149    CUB,
150    CUD,
151    CUF,
152    CUP,
153    CUU,
154    CVT,
155    DA,
156    DAQ,
157    DCH,
158    DL,
159    DSR,
160    DTA,
161    EA,
162    ECH,
163    ED,
164    EF,
165    EL,
166    FNK,
167    FNT,
168    GCC,
169    GSM,
170    GSS,
171    HPA,
172    HPB,
173    HPR,
174    HVP,
175    ICH,
176    IDCS,
177    IGS,
178    IL,
179    JFY,
180    MC,
181    NP,
182    PEC,
183    PFS,
184    PP,
185    PPA,
186    PPB,
187    PPR,
188    PTX,
189    QUAD,
190    REP,
191    RM,
192    SACS,
193    SAPV,
194    SCO,
195    SCP,
196    SCS,
197    SD,
198    SDS,
199    SEE,
200    SEF,
201    SGR,
202    SHS,
203    SIMD,
204    SL,
205    SLH,
206    SLL,
207    SLS,
208    SM,
209    SPD,
210    SPH,
211    SPI,
212    SPL,
213    SPQR,
214    SR,
215    SRCS,
216    SRS,
217    SSU,
218    SSW,
219    STAB,
220    SU,
221    SVS,
222    TAC,
223    TALE,
224    TATE,
225    TBC,
226    TCC,
227    TSR,
228    TSS,
229    VPA,
230    VPB,
231    VPR,
232    PRIVATE,
233}
234
235fn function(control_function: &ControlFunction<'_>) -> Function {
236    match control_function.function_type {
237        ControlFunctionType::C0 => {
238            // C0 control functions are always 1 byte long
239            let byte = control_function.value.as_bytes()[0];
240
241            match byte {
242                0 => Function::NUL,
243                1 => Function::SOH,
244                2 => Function::STX,
245                3 => Function::ETX,
246                4 => Function::EOT,
247                5 => Function::ENQ,
248                6 => Function::ACK,
249                7 => Function::BEL,
250                8 => Function::BS,
251                9 => Function::HT,
252                10 => Function::LF,
253                11 => Function::VT,
254                12 => Function::FF,
255                13 => Function::CR,
256                14 => Function::LS1,
257                15 => Function::LS0,
258                16 => Function::DLE,
259                17 => Function::DC1,
260                18 => Function::DC2,
261                19 => Function::DC3,
262                20 => Function::DC4,
263                21 => Function::NAK,
264                22 => Function::SYN,
265                23 => Function::ETB,
266                24 => Function::CAN,
267                25 => Function::EM,
268                26 => Function::SUB,
269                27 => Function::ESC,
270                28 => Function::IS4,
271                29 => Function::IS3,
272                30 => Function::IS2,
273                31 => Function::IS1,
274                _ => {
275                    unreachable!("No C0 control function exists outside of above range")
276                }
277            }
278        }
279        ControlFunctionType::C1 => {
280            // C1 control functions are always 1 byte long
281            let byte = control_function.value.as_bytes()[0];
282
283            match byte {
284                66 => Function::BPH,
285                67 => Function::NBH,
286                69 => Function::NEL,
287                70 => Function::SSA,
288                71 => Function::ESA,
289                72 => Function::HTS,
290                73 => Function::HTJ,
291                74 => Function::VTS,
292                75 => Function::PLD,
293                76 => Function::PLU,
294                77 => Function::RI,
295                78 => Function::SS2,
296                79 => Function::SS3,
297                80 => Function::DCS,
298                81 => Function::PU1,
299                82 => Function::PU2,
300                83 => Function::STS,
301                84 => Function::CCH,
302                85 => Function::MW,
303                86 => Function::SPA,
304                87 => Function::EPA,
305                88 => Function::SOS,
306                90 => Function::SCI,
307                91 => Function::CSI,
308                92 => Function::ST,
309                93 => Function::OSC,
310                94 => Function::PM,
311                95 => Function::APC,
312                _ => {
313                    unreachable!("No C1 control function exists outside of above range")
314                }
315            }
316        }
317        ControlFunctionType::IndependentControlFunction => {
318            // Independent control functions are always 1 byte long
319            let byte = control_function.value.as_bytes()[0];
320
321            match byte {
322                96 => Function::DMI,
323                97 => Function::INT,
324                98 => Function::EMI,
325                99 => Function::RIS,
326                100 => Function::CMD,
327                110 => Function::LS2,
328                111 => Function::LS3,
329                124 => Function::LS3R,
330                125 => Function::LS2R,
331                126 => Function::LS1R,
332                _ => {
333                    unreachable!("No independent control function exists outside of above range")
334                }
335            }
336        }
337        ControlFunctionType::ControlSequence => {
338            let bytes = control_function.value.as_bytes();
339            if bytes.len() == 1 {
340                // control sequence with no intermediate byte
341                let byte = bytes[0];
342                return match byte {
343                    64 => Function::ICH,
344                    65 => Function::CUU,
345                    66 => Function::CUD,
346                    67 => Function::CUF,
347                    68 => Function::CUB,
348                    69 => Function::CNL,
349                    70 => Function::CPL,
350                    71 => Function::CHA,
351                    72 => Function::CUP,
352                    73 => Function::CHT,
353                    74 => Function::ED,
354                    75 => Function::EL,
355                    76 => Function::IL,
356                    77 => Function::DL,
357                    78 => Function::EF,
358                    79 => Function::EA,
359                    80 => Function::DCH,
360                    81 => Function::SEE,
361                    82 => Function::CPR,
362                    83 => Function::SU,
363                    84 => Function::SD,
364                    85 => Function::NP,
365                    86 => Function::PP,
366                    87 => Function::CTC,
367                    88 => Function::ECH,
368                    89 => Function::CVT,
369                    90 => Function::CBT,
370                    91 => Function::SRS,
371                    92 => Function::PTX,
372                    93 => Function::SDS,
373                    94 => Function::SIMD,
374                    96 => Function::HPA,
375                    97 => Function::HPR,
376                    98 => Function::REP,
377                    99 => Function::DA,
378                    100 => Function::VPA,
379                    101 => Function::VPR,
380                    102 => Function::HVP,
381                    103 => Function::TBC,
382                    104 => Function::SM,
383                    105 => Function::MC,
384                    106 => Function::HPB,
385                    107 => Function::VPB,
386                    108 => Function::RM,
387                    109 => Function::SGR,
388                    110 => Function::DSR,
389                    111 => Function::DAQ,
390                    112..=127 => Function::PRIVATE,
391                    _ => {
392                        unreachable!("No valid control sequence exist outside of above range")
393                    }
394                };
395            }
396            if bytes.len() == 2 {
397                // control sequence with intermediate byte
398                let byte = bytes[1];
399                return match byte {
400                    64 => Function::SL,
401                    65 => Function::SR,
402                    66 => Function::GSM,
403                    67 => Function::GSS,
404                    68 => Function::FNT,
405                    69 => Function::TSS,
406                    70 => Function::JFY,
407                    71 => Function::SPI,
408                    72 => Function::QUAD,
409                    73 => Function::SSU,
410                    74 => Function::PFS,
411                    75 => Function::SHS,
412                    76 => Function::SVS,
413                    77 => Function::IGS,
414                    79 => Function::IDCS,
415                    80 => Function::PPA,
416                    81 => Function::PPR,
417                    82 => Function::PPB,
418                    83 => Function::SPD,
419                    84 => Function::DTA,
420                    85 => Function::SLH,
421                    86 => Function::SLL,
422                    87 => Function::FNK,
423                    88 => Function::SPQR,
424                    89 => Function::SEF,
425                    90 => Function::PEC,
426                    91 => Function::SSW,
427                    92 => Function::SACS,
428                    93 => Function::SAPV,
429                    94 => Function::STAB,
430                    95 => Function::GCC,
431                    96 => Function::TATE,
432                    97 => Function::TALE,
433                    98 => Function::TAC,
434                    99 => Function::TCC,
435                    100 => Function::TSR,
436                    101 => Function::SCO,
437                    102 => Function::SRCS,
438                    103 => Function::SCS,
439                    104 => Function::SLS,
440                    105 => Function::SPH,
441                    106 => Function::SPL,
442                    107 => Function::SCP,
443                    112..=127 => Function::PRIVATE,
444                    _ => {
445                        unreachable!("No valid control sequence exist outside of above range")
446                    }
447                };
448            }
449            unreachable!("No valid control sequence exist outside of above range")
450        }
451    }
452}
453
454fn ordinal_indicator(numeric_value: String) -> String {
455    numeric_value
456        .parse::<u64>()
457        .map(|value| match value % 10 {
458            0 | 4..=9 => numeric_value.clone(),
459            1 => format!("{}st", value),
460            2 => format!("{}nd", value),
461            3 => format!("{}rd", value),
462            _ => {
463                unreachable!("This is not reachable, all possible values of modulo 10 are covered.")
464            }
465        })
466        .unwrap_or_else(|_| numeric_value)
467}
468
469fn get_param(parameters: &Vec<String>, index: usize, default_value: u64) -> String {
470    parameters
471        .get(index)
472        .map(|value| value.to_owned())
473        .unwrap_or_else(|| format!("{default_value}"))
474}
475
476trait ExplainSelection {
477    fn explain(&self) -> String;
478}
479
480trait ExplainMode {
481    fn name(&self) -> String;
482    fn explain_reset(&self) -> String;
483    fn explain_set(&self) -> String;
484}
485
486/// Explanation of an ansi-control-code.
487pub trait Explain {
488    /// Returns the short name (abbreviation) of this control function, e.g. `CR`, `LF`.
489    ///
490    /// An abbreviated name is available for all ansi-escape-codes, except for those in the private use area.
491    fn short_name(&self) -> Option<&'static str>;
492
493    /// Returns the name of this control function, e.g. `Carriage Return`, `Line Feed`.
494    fn long_name(&self) -> &'static str;
495
496    /// Returns the short description of what this function does.
497    fn short_description(&self) -> String;
498
499    /// Returns a long description of what this function does.
500    ///
501    /// Not all control functions have a long description, in which case this will return the
502    /// same as `short_description()`.
503    fn long_description(&self) -> String;
504}
505
506impl Explain for ControlFunction<'_> {
507    fn short_name(&self) -> Option<&'static str> {
508        match function(&self) {
509            Function::ACK => Some("ACK"),
510            Function::BEL => Some("BEL"),
511            Function::BS => Some("BS"),
512            Function::CAN => Some("CAN"),
513            Function::CR => Some("CR"),
514            Function::DC1 => Some("DC1"),
515            Function::DC2 => Some("DC2"),
516            Function::DC3 => Some("DC3"),
517            Function::DC4 => Some("DC4"),
518            Function::DLE => Some("DLE"),
519            Function::EM => Some("EM"),
520            Function::ENQ => Some("ENQ"),
521            Function::EOT => Some("EOT"),
522            Function::ESC => Some("ESC"),
523            Function::ETB => Some("ETB"),
524            Function::ETX => Some("ETX"),
525            Function::FF => Some("FF"),
526            Function::HT => Some("HT"),
527            Function::IS1 => Some("IS1"),
528            Function::IS2 => Some("IS2"),
529            Function::IS3 => Some("IS3"),
530            Function::IS4 => Some("IS4"),
531            Function::LF => Some("LF"),
532            Function::LS0 => Some("LS0"),
533            Function::LS1 => Some("LS1"),
534            Function::NAK => Some("NAK"),
535            Function::NUL => Some("NUL"),
536            Function::SOH => Some("SOH"),
537            Function::STX => Some("STX"),
538            Function::SUB => Some("SUB"),
539            Function::SYN => Some("SYN"),
540            Function::VT => Some("VT"),
541            Function::APC => Some("APC"),
542            Function::BPH => Some("BPH"),
543            Function::CCH => Some("CCH"),
544            Function::CSI => Some("CSI"),
545            Function::DCS => Some("DCS"),
546            Function::EPA => Some("EPA"),
547            Function::ESA => Some("ESA"),
548            Function::HTJ => Some("HTJ"),
549            Function::HTS => Some("HTS"),
550            Function::MW => Some("MW"),
551            Function::NBH => Some("NBH"),
552            Function::NEL => Some("NEL"),
553            Function::OSC => Some("OSC"),
554            Function::PLD => Some("PLD"),
555            Function::PLU => Some("PLU"),
556            Function::PM => Some("PM"),
557            Function::PU1 => Some("PU1"),
558            Function::PU2 => Some("PU2"),
559            Function::RI => Some("RI"),
560            Function::SCI => Some("SCI"),
561            Function::SOS => Some("SOS"),
562            Function::SPA => Some("SPA"),
563            Function::SSA => Some("SSA"),
564            Function::SS2 => Some("SS2"),
565            Function::SS3 => Some("SS3"),
566            Function::ST => Some("ST"),
567            Function::STS => Some("STS"),
568            Function::VTS => Some("VTS"),
569            Function::CMD => Some("CMD"),
570            Function::DMI => Some("DMI"),
571            Function::EMI => Some("EMI"),
572            Function::INT => Some("INT"),
573            Function::LS1R => Some("LS1R"),
574            Function::LS2 => Some("LS2"),
575            Function::LS2R => Some("LS2R"),
576            Function::LS3 => Some("LS3"),
577            Function::LS3R => Some("LS3R"),
578            Function::RIS => Some("RIS"),
579            Function::CBT => Some("CBT"),
580            Function::CHA => Some("CHA"),
581            Function::CHT => Some("CHT"),
582            Function::CNL => Some("CNL"),
583            Function::CPL => Some("CPL"),
584            Function::CPR => Some("CPR"),
585            Function::CTC => Some("CTC"),
586            Function::CUB => Some("CUB"),
587            Function::CUD => Some("CUD"),
588            Function::CUF => Some("CUF"),
589            Function::CUP => Some("CUP"),
590            Function::CUU => Some("CUU"),
591            Function::CVT => Some("CVT"),
592            Function::DA => Some("DA"),
593            Function::DAQ => Some("DAQ"),
594            Function::DCH => Some("DCH"),
595            Function::DL => Some("DL"),
596            Function::DSR => Some("DSR"),
597            Function::DTA => Some("DTA"),
598            Function::EA => Some("EA"),
599            Function::ECH => Some("ECH"),
600            Function::ED => Some("ED"),
601            Function::EF => Some("EF"),
602            Function::EL => Some("EL"),
603            Function::FNK => Some("FNK"),
604            Function::FNT => Some("FNT"),
605            Function::GCC => Some("GCC"),
606            Function::GSM => Some("GSM"),
607            Function::GSS => Some("GSS"),
608            Function::HPA => Some("HPA"),
609            Function::HPB => Some("HPB"),
610            Function::HPR => Some("HPR"),
611            Function::HVP => Some("HVP"),
612            Function::ICH => Some("ICH"),
613            Function::IDCS => Some("IDCS"),
614            Function::IGS => Some("IGS"),
615            Function::IL => Some("IL"),
616            Function::JFY => Some("JFY"),
617            Function::MC => Some("MC"),
618            Function::NP => Some("NP"),
619            Function::PEC => Some("PEC"),
620            Function::PFS => Some("PFS"),
621            Function::PP => Some("PP"),
622            Function::PPA => Some("PPA"),
623            Function::PPB => Some("PPB"),
624            Function::PPR => Some("PPR"),
625            Function::PTX => Some("PTX"),
626            Function::QUAD => Some("QUAD"),
627            Function::REP => Some("REP"),
628            Function::RM => Some("RM"),
629            Function::SACS => Some("SACS"),
630            Function::SAPV => Some("SAPV"),
631            Function::SCO => Some("SCO"),
632            Function::SCP => Some("SCP"),
633            Function::SCS => Some("SCS"),
634            Function::SD => Some("SD"),
635            Function::SDS => Some("SDS"),
636            Function::SEE => Some("SEE"),
637            Function::SEF => Some("SEF"),
638            Function::SGR => Some("SGR"),
639            Function::SHS => Some("SHS"),
640            Function::SIMD => Some("SIMD"),
641            Function::SL => Some("SL"),
642            Function::SLH => Some("SLH"),
643            Function::SLL => Some("SLL"),
644            Function::SLS => Some("SLS"),
645            Function::SM => Some("SM"),
646            Function::SPD => Some("SPD"),
647            Function::SPI => Some("SPI"),
648            Function::SPL => Some("SPL"),
649            Function::SPH => Some("SPH"),
650            Function::SPQR => Some("SPQR"),
651            Function::SR => Some("SR"),
652            Function::SRCS => Some("SRCS"),
653            Function::SRS => Some("SRS"),
654            Function::SSU => Some("SSU"),
655            Function::SSW => Some("SSW"),
656            Function::STAB => Some("STAB"),
657            Function::SU => Some("SU"),
658            Function::SVS => Some("SVS"),
659            Function::TAC => Some("TAC"),
660            Function::TALE => Some("TALE"),
661            Function::TATE => Some("TATE"),
662            Function::TBC => Some("TBC"),
663            Function::TCC => Some("TCC"),
664            Function::TSR => Some("TSR"),
665            Function::TSS => Some("TSS"),
666            Function::VPA => Some("VPA"),
667            Function::VPB => Some("VPB"),
668            Function::VPR => Some("VPR"),
669            Function::PRIVATE => None,
670        }
671    }
672
673    fn long_name(&self) -> &'static str {
674        match function(&self) {
675            Function::ACK => "Acknowledge",
676            Function::BEL => "Bell",
677            Function::BS => "Backspace",
678            Function::CAN => "Cancel",
679            Function::CR => "Carriage Return",
680            Function::DC1 => "Device Control One",
681            Function::DC2 => "Device Control Two",
682            Function::DC3 => "Device Control Three",
683            Function::DC4 => "Device Control Four",
684            Function::DLE => "Data Link Escape",
685            Function::EM => "End of Medium",
686            Function::ENQ => "Enquiry",
687            Function::EOT => "End of Transmission",
688            Function::ESC => "Escape",
689            Function::ETB => "End of Transmission Block",
690            Function::ETX => "End of Text",
691            Function::FF => "Form Feed",
692            Function::HT => "Character Tabulation",
693            Function::IS1 => "Information Separator One (US - Unit Separator)",
694            Function::IS2 => "Information Separator Two (RS - Record Separator)",
695            Function::IS3 => "Information Separator Three (GS - Group Separator)",
696            Function::IS4 => "Information Separator Four (FS - File Separator)",
697            Function::LF => "Line Feed",
698            Function::LS0 => "Locking-Shift Zero (Shift-In)",
699            Function::LS1 => "Locking-Shift One (Shift-Out)",
700            Function::NAK => "Negative Acknowledge",
701            Function::NUL => "Null",
702            Function::SOH => "Start of Heading",
703            Function::STX => "Start of Text",
704            Function::SUB => "Substitute",
705            Function::SYN => "Synchronous Idle",
706            Function::VT => "Line Tabulation",
707            Function::APC => "Application Program Command",
708            Function::BPH => "Break Permitted Here",
709            Function::CCH => "Cancel Character",
710            Function::CSI => "Control Sequence Introducer",
711            Function::DCS => "Device Control String",
712            Function::EPA => "End of Guarded Area",
713            Function::ESA => "End of Selected Area",
714            Function::HTJ => "Character Tabulation With Justification",
715            Function::HTS => "Character Tabulation Set",
716            Function::MW => "Message Waiting",
717            Function::NBH => "No Break Here",
718            Function::NEL => "Next Line",
719            Function::OSC => "Operating System Command",
720            Function::PLD => "Partial Line Forward",
721            Function::PLU => "Partial Line Backwards",
722            Function::PM => "Privacy Message",
723            Function::PU1 => "Private Use One",
724            Function::PU2 => "Private Use Two",
725            Function::RI => "Reverse Line Feed",
726            Function::SCI => "Single Character Introducer",
727            Function::SOS => "Start of String",
728            Function::SPA => "Start of Guarded Area",
729            Function::SSA => "Start of Selected Area",
730            Function::SS2 => "Single-Shift Two",
731            Function::SS3 => "Single-Shift Three",
732            Function::ST => "String Terminator",
733            Function::STS => "Set Transmit State",
734            Function::VTS => "Line Tabulation Set",
735            Function::CMD => "Coding Method Delimiter",
736            Function::DMI => "Disable Manual Input",
737            Function::EMI => "Enable Manual Input",
738            Function::INT => "Interrupt",
739            Function::LS1R => "Locking-Shift One Right",
740            Function::LS2 => "Locking-Shift Two",
741            Function::LS2R => "Locking-Shift Two Right",
742            Function::LS3 => "Locking-Shift Three",
743            Function::LS3R => "Locking-Shift Three Right",
744            Function::RIS => "Reset to Initial State",
745            Function::CBT => "Cursor Backwards Tabulation",
746            Function::CHA => "Cursor Character Absolute",
747            Function::CHT => "Cursor Forward Tabulation",
748            Function::CNL => "Cursors Next Line",
749            Function::CPL => "Cursor Preceding Line",
750            Function::CPR => "Active Position Report",
751            Function::CTC => "Cursor Tabulation Control",
752            Function::CUB => "Cursor Left",
753            Function::CUD => "Cursor Down",
754            Function::CUF => "Cursor Right",
755            Function::CUP => "Cursor Position",
756            Function::CUU => "Cursor Up",
757            Function::CVT => "Cursor Line Tabulation",
758            Function::DA => "Device Attributes",
759            Function::DAQ => "Define Area Qualification",
760            Function::DCH => "Delete Character",
761            Function::DL => "Delete Line",
762            Function::DSR => "Device Status Report",
763            Function::DTA => "Dimension Text Area",
764            Function::EA => "Erase Area",
765            Function::ECH => "Erase Character",
766            Function::ED => "Erase in Page",
767            Function::EF => "Erase in Field",
768            Function::EL => "Erase in Line",
769            Function::FNK => "Function Key",
770            Function::FNT => "Font Selection",
771            Function::GCC => "Graphic Character Combination",
772            Function::GSM => "Graphic Size Modification",
773            Function::GSS => "Graphic Size Selection",
774            Function::HPA => "Character Position Absolute",
775            Function::HPB => "Character Position Backwards",
776            Function::HPR => "Character Position Forward",
777            Function::HVP => "Character and Line Position",
778            Function::ICH => "Insert Character",
779            Function::IDCS => "Identify Device Control String",
780            Function::IGS => "Identify Graphic Subrepertoire",
781            Function::IL => "Insert Line",
782            Function::JFY => "Justify",
783            Function::MC => "Media Copy",
784            Function::NP => "Next Page",
785            Function::PEC => "Presentation Expand or Contract",
786            Function::PFS => "Page Format Selection",
787            Function::PP => "Preceding Page",
788            Function::PPA => "Page Position Absolute",
789            Function::PPB => "Page Position Backwards",
790            Function::PPR => "Page Position Forward",
791            Function::PTX => "Parallel Texts",
792            Function::QUAD => "Quad",
793            Function::REP => "Repeat",
794            Function::RM => "Reset Mode",
795            Function::SACS => "Set Additional Character Representation",
796            Function::SAPV => "Select Alternative Presentation Variants",
797            Function::SCO => "Select Character Orientation",
798            Function::SCP => "Select Character Path",
799            Function::SCS => "Set Character Spacing",
800            Function::SD => "Scroll Down",
801            Function::SDS => "Start Directed String",
802            Function::SEE => "Select Editing Extent",
803            Function::SEF => "Sheet Eject and Feed",
804            Function::SGR => "Select Graphic Rendition",
805            Function::SHS => "Select Character Spacing",
806            Function::SIMD => "Select Implicit Movement Direction",
807            Function::SL => "Scroll Left",
808            Function::SLH => "Set Line Home",
809            Function::SLL => "Set Line Limit",
810            Function::SLS => "Set Line Spacing",
811            Function::SM => "Set Mode",
812            Function::SPD => "Select Presentation Direction",
813            Function::SPH => "Set Page Home",
814            Function::SPI => "Spacing Increment",
815            Function::SPL => "Set Page Limit",
816            Function::SPQR => "Select Page Quality and Rapidity",
817            Function::SR => "Scroll Right",
818            Function::SRCS => "Set Reduced Character Separation",
819            Function::SRS => "Start Reversed String",
820            Function::SSU => "Select Size Unit",
821            Function::SSW => "Set Space Width",
822            Function::STAB => "Selective Tabulation",
823            Function::SU => "Scroll Up",
824            Function::SVS => "Select Line Spacing",
825            Function::TAC => "Tabulation Aligned Centred",
826            Function::TALE => "Tabulation Aligned Leading Edge",
827            Function::TATE => "Tabulation Aligned Trailing Edge",
828            Function::TBC => "Tabulation Clear",
829            Function::TCC => "Tabulation Centred on Character",
830            Function::TSR => "Tabulation Stop Remove",
831            Function::TSS => "Thin Space Specification",
832            Function::VPA => "Line Position Absolute",
833            Function::VPB => "Line Position Backwards",
834            Function::VPR => "Line Position Forward",
835            Function::PRIVATE => "Private Use / Experimental Use",
836        }
837    }
838
839    fn short_description(&self) -> String {
840        match function(&self) {
841            Function::ACK => {
842                String::from("Transmitted by a receiver as an affirmative response to the sender.")
843            }
844            Function::BEL => String::from("Calls for attention."),
845            Function::BS => {
846                String::from("Causes the active data position to be moved one character backwards.")
847            }
848            Function::CAN => String::from("Indicate that the preceding data is in error."),
849            Function::CR => String::from("Move to the beginning of the line."),
850            Function::DC1 => {
851                String::from("Primarily intended for turning on or starting an ancillary device.")
852            }
853            Function::DC2 => {
854                String::from("Primarily intended for turning on or starting an ancillary device.")
855            }
856            Function::DC3 => {
857                String::from("Primarily intended for turning off or stopping an ancillary device.")
858            }
859            Function::DC4 => String::from(
860                "Primarily intended for turning off, stopping, or interrupting an ancillary device."
861            ),
862            Function::DLE => String::from("Used exclusively to provide supplementary transmission control functions."),
863            Function::EM => String::from("Identifies the physical end of a medium."),
864            Function::ENQ => String::from("Transmitted by a sender as a request for a response from a receiver."),
865            Function::EOT => String::from("Indicates the conclusion of the transmission of one or more texts."),
866            Function::ESC => String::from("Used for code extension purposes."),
867            Function::ETB => String::from(
868                concat!(
869                    "Indicates the end of a block of data, where the data are divided into such blocks for ",
870                    "transmission purposes."
871                )
872            ),
873            Function::ETX => String::from("Indicates the end of a text."),
874            Function::FF => String::from(
875                "Causes the active presentation position to be moved to the line home position of the next line."
876            ),
877            Function::HT => String::from(
878                concat!(
879                    "Causes the active presentation position to be moved to the following character tabulation stop ",
880                    "in the presentation component."
881                )
882            ),
883            Function::IS1 => String::from("Separates and qualifies data logically."),
884            Function::IS2 => String::from("Separates and qualifies data logically."),
885            Function::IS3 => String::from("Separates and qualifies data logically."),
886            Function::IS4 => String::from("Separates and qualifies data logically."),
887            Function::LF => String::from("Move to following line."),
888            Function::LS0 => String::from("Used for code extension purposes."),
889            Function::LS1 => String::from("Used for code extension purposes."),
890            Function::NAK => String::from("Transmitted by a receiver as a negative response to the sender."),
891            Function::NUL => String::from("Used for media-fill or time-fill."),
892            Function::SOH => String::from("Indicates the beginning of a heading."),
893            Function::STX => String::from("Indicates the beginning of a text and the end of a heading."),
894            Function::SUB => String::from(
895                "Used in the place of a character that has been found to be invalid or in error"
896            ),
897            Function::SYN => String::from(
898                "Used by a synchronous transmission system in the absence of any other character."
899            ),
900            Function::VT => String::from("Move to the next line that has a line tabulation stop."),
901            Function::APC => String::from("Opening delimiter of a control string for application program use."),
902            Function::BPH => String::from("A break may occur here when text is formatted."),
903            Function::CCH => String::from(
904                concat!(
905                    "Indicates that both the preceding graphic character in the data stream, and this character ",
906                    "should be ignored."
907                )
908            ),
909            Function::CSI => String::from("Used as the first character of a longer control sequence."),
910            Function::DCS => String::from("Opening delimiter of a control string for device control use."),
911            Function::EPA => String::from("End of an area that protects its content against unwanted alteration."),
912            Function::ESA => String::from(
913                "End of an area selected for transferring or transmitting to an ancillary input/output device."
914            ),
915            Function::HTJ => String::from(
916                concat!(
917                    "Shift the contents of the active field forward, so that it ends in before of the next character ",
918                    "tabulation stop."
919                )
920            ),
921            Function::HTS => String::from("Set a character tabulation stop at the current position."),
922            Function::MW => String::from("Sets a message waiting indicator in the receiving device."),
923            Function::NBH => String::from("A line break shall not occur here when the text is formatted."),
924            Function::NEL => String::from("Move to the next line."),
925            Function::OSC => String::from("Opening delimiter of a control string for operating system use."),
926            Function::PLD => String::from(
927                "Move to an imaginary line with a partial offset downwards of the current line."
928            ),
929            Function::PLU => String::from(
930                "Move to an imaginary line with a partial offset upwards of the current line."
931            ),
932            Function::PM => String::from("Opening delimiter of a control string for privacy message use."),
933            Function::PU1 => String::from(
934                "Reserved for function without standardized meaning, for private use as required."
935            ),
936            Function::PU2 => String::from(
937                "Reserved for function without standardized meaning, for private use as required."
938            ),
939            Function::RI => String::from("Move to the preceding line."),
940            Function::SCI => String::from(
941                "This character and the following one represent a control function or a graphic character."
942            ),
943            Function::SOS => String::from("Opening delimiter of a control String."),
944            Function::SPA => String::from("
945                First position of a string that is guarded against manual alteration, transmission, transferor deletion."
946            ),
947            Function::SSA => String::from(
948                concat!(
949                    "First position of a string that is eligible to be transmitted or transferred to an ancillary ",
950                    "input/output device."
951                )
952            ),
953            Function::SS2 => String::from(
954                concat!(
955                    "Used for code extension purposes. Changes the meaning of the bit combinations following it in ",
956                    "the data stream."
957                )
958            ),
959            Function::SS3 => String::from(
960                concat!(
961                    "Used for code extension purposes. Changes the meaning of the bit combinations following it in ",
962                    "the data stream."
963                )
964            ),
965            Function::ST => String::from("Closing delimiter of a control string opened by APC, DCS, OSC, PM or SOS."),
966            Function::STS => String::from(
967                concat!(
968                    "Establish the transmit state in the receiving device. In this state the transmission of data ",
969                    "from the device is possible."
970                )
971            ),
972            Function::VTS => String::from("Set a line tabulation stop at the active line."),
973            Function::CMD => String::from("Delimits a string of data coded according to standard ECMA-35."),
974            Function::DMI => String::from("Causes the manual input facilities of a device to be disabled."),
975            Function::EMI => String::from("Causes the manual input facilities of a device to be enabled."),
976            Function::INT => String::from(
977                concat!(
978                    "Indicate to the receiving device that the current process is to be interrupted and an agreed ",
979                    "procedure is to be initiated."
980                )
981            ),
982            Function::LS1R => String::from(
983                "Used for code extension purposes. Changes the meaning of the following characters in the data stream."
984            ),
985            Function::LS2 => String::from(
986                "Used for code extension purposes. Changes the meaning of the following characters in the data stream."
987            ),
988            Function::LS2R => String::from(
989                "Used for code extension purposes. Changes the meaning of the following characters in the data stream."
990            ),
991            Function::LS3 => String::from(
992                "Used for code extension purposes. Changes the meaning of the following characters in the data stream."
993            ),
994            Function::LS3R => String::from(
995                "Used for code extension purposes. Changes the meaning of the following characters in the data stream."
996            ),
997            Function::RIS => String::from("Causes a device to be reset to its initial state."),
998            Function::CBT => format!(
999                "Causes the active position to be moved backwards by {} tabulation stops.", 
1000                param!(self, 0, 1)
1001            ),
1002            Function::CHA => format!(
1003                "Causes the active position to be set to character position {} in the active line",
1004                param!(self, 0, 1)
1005            ),
1006            Function::CHT => format!(
1007                "Causes the active position to be moved forward by {} tabulation stops.",
1008                param!(self, 0, 1)
1009            ),
1010            Function::CNL => format!(
1011                "Causes the active position to be moved to the first character of the {} following line.",
1012                param!(self, ordinal 0, 1)
1013            ),
1014            Function::CPL => format!(
1015                concat!(
1016                    "Causes the active position to be moved to the first character of the {} preceding line."
1017                ),
1018                param!(self, ordinal 0, 1)
1019            ),
1020            Function::CPR => format!(
1021                concat!(
1022                    "The active position is reported to be in line {} at character position {}."
1023                ),
1024                param!(self, 0, 1), param!(self, 1, 1)
1025            ),
1026            Function::CTC => explain_selection!(TabulationControl, self, 0),
1027            Function::CUB => format!(
1028                "Move the active position {} characters to the left.",
1029                param!(self, 0, 1)
1030            ),
1031            Function::CUD => format!(
1032                "Move the active position {} lines downwards.",
1033                param!(self, 0, 1)
1034            ),
1035            Function::CUF => format!(
1036                "Move the active position {} characters to the right.",
1037                param!(self, 0, 1)
1038            ),
1039            Function::CUP => format!(
1040                "Move the active position to line {} and character {}.",
1041                param!(self, 0, 1),
1042                param!(self, 1, 1),
1043            ),
1044            Function::CUU => format!(
1045                "Move the active position {} lines upwards.",
1046                param!(self, 0, 1)
1047            ),
1048            Function::CVT => format!(
1049                "Causes the active position to the {} following line tabulation stop.",
1050                param!(self, ordinal 0, 1)
1051            ),
1052            Function::DA => explain_selection!(DeviceAttributes, self, 0),
1053            Function::DAQ => format!(
1054                "The active position is the first position of a qualified area. This area {}.",
1055                explain_selection!(AreaQualification, self, 0),
1056            ),
1057            Function::DCH => format!(
1058                "Delete {} characters, starting from the active position to the left.",
1059                param!(self, 0, 1)
1060            ),
1061            Function::DL => format!(
1062                "Delete {} lines",
1063                param!(self, 0, 1)
1064            ),
1065            Function::DSR => explain_selection!(DeviceStatusReport, self, 0),
1066            Function::DTA => format!(
1067                concat!(
1068                    "Establishes the dimension of the text area for subsequent pages. Dimension perpendicular to the ",
1069                    "line orientation: {}. Dimension parallel to the line orientation: {}."
1070                ),
1071                param!(self, 0, 0),
1072                param!(self, 1, 0)
1073            ),
1074            Function::EA => format!("This {}.", explain_selection!(EraseArea, self, 0)),
1075            Function::ECH => format!(
1076                concat!(
1077                    "Erase {} characters from the active position to the right."
1078                ),
1079                param!(self, 0, 1)
1080            ),
1081            Function::ED => format!("This {}.", explain_selection!(ErasePage, self, 0)),
1082            Function::EF => format!("This {}.", explain_selection!(EraseField, self, 0)),
1083            Function::EL => format!("This {}.", explain_selection!(EraseLine, self, 0)),
1084            Function::FNK => format!("Function Key number {} has been pressed.",
1085                param!(self, 0, 1)
1086            ),
1087            Function::FNT => format!(
1088                concat!(
1089                    "Indicates that the {} should be set to font {} and be accessible as {} from here on."
1090                ),
1091                explain_selection!(Font, self, 0),
1092                param!(self, 1, 0),
1093                explain_selection!(Font, self, 0)
1094            ),
1095            Function::GCC => explain_selection!(GraphicCharacterCombination, self, 0),
1096            Function::GSM => format!(
1097                "Modify the text height and / or width of all fonts to {}% height and  {}% width.",
1098                param!(self, 0, 100),
1099                param!(self, 1, 100)
1100            ),
1101            Function::GSS => format!(
1102                "Modify the text height of all fonts to {}. The width is implicitly defined by the height.",
1103                param!(self, 0, 0)
1104            ),
1105            Function::HPA => format!(
1106                "Move the active data position to character position {} in the active line.",
1107                param!(self, 0, 1)
1108            ),
1109            Function::HPB => format!(
1110                "Move the active data position backwards by {} characters.",
1111                param!(self, 0, 1)
1112            ),
1113            Function::HPR => format!(
1114                "Move the active data position forward by {} characters.",
1115                param!(self, 0, 1)
1116            ),
1117            Function::HVP => format!(
1118                "Move the active data position to the {} line and {} character.",
1119                param!(self, ordinal 0, 1),
1120                param!(self, ordinal 1, 1)
1121            ),
1122            Function::ICH => format!(
1123                "Prepare the insertion of {} characters.",
1124                param!(self, 0, 1)
1125            ),
1126            Function::IDCS => explain_selection!(IdentifyDeviceControlString, self, 0),
1127            Function::IGS => format!(
1128                "The graphic subrepertoire {} is used in the subsequent text.",
1129                param!(self, 0, 0)
1130            ),
1131            Function::IL => format!(
1132                "Prepare the insertion of {} liens.",
1133                param!(self, 0, 1)
1134            ),
1135            Function::JFY => explain_selection!(Justification, self, 0),
1136            Function::MC => explain_selection!(MediaCopy, self, 0),
1137            Function::NP => format!(
1138                "Display the {} following page in the presentation component.",
1139                param!(self, ordinal 0, 1)
1140            ),
1141            Function::PEC => format!(
1142                concat!(
1143                    "Display the following graphic characters with spacing and extent in {}."
1144                ),
1145                explain_selection!(PresentationExpandContract, self, 0)
1146            ),
1147            Function::PFS => explain_selection!(PageFormat, self, 0),
1148            Function::PP => format!(
1149                "Display the {} preceding page in the presentation component.",
1150                param!(self, ordinal 0, 1)
1151            ),
1152            Function::PPA => format!(
1153                "Causes the active data position to be moved to the corresponding character position on page {}.",
1154                param!(self, 0, 1)
1155            ),
1156            Function::PPB => format!(
1157                concat!(
1158                    "Causes the active data position to be moved to the corresponding character position on the {} ",
1159                    "previous pages."
1160                ),
1161                param!(self, ordinal 0, 1)
1162            ),
1163            Function::PPR => format!(
1164                concat!(
1165                    "Causes the active data position to be moved to the corresponding character position on the {} ",
1166                    "following pages."
1167                ),
1168                param!(self, ordinal 0, 1)
1169            ),
1170            Function::PTX => explain_selection!(ParallelText, self, 0),
1171            Function::QUAD => format!(
1172                "Indicates the end of a string of graphic characters that are to be positioned on a single line {}.",
1173                explain_selection!(Alignment, self, 0)
1174            ),
1175            Function::REP => format!(
1176                "Repeat the previous graphic character {} times.",
1177                param!(self, 0, 1)
1178            ),
1179            Function::RM => format!(
1180                "Reset the following Modes: {}",
1181                self.parameters.iter().map(|value| {
1182                    value.parse::<Mode>().expect("Expect only valid Modes").name()
1183                }).fold(String::new(), |mut modes, mode| {
1184                    modes.push_str(", ");
1185                    modes.push_str(&mode);
1186                    modes
1187                })
1188            ),
1189            Function::SACS => format!(
1190                "Enlarge inter-character escapement by {} units.",
1191                param!(self, 0, 0)
1192            ),
1193            Function::SAPV => format!(
1194                "Select an alternative presentation variant for the subsequent text. {}",
1195                explain_selection!(PresentationVariant, self, 0)
1196            ),
1197            Function::SCO => format!(
1198                "Establishes the amount of rotation of graphic characters following. {}",
1199                explain_selection!(CharacterOrientation, self, 0)
1200            ),
1201            Function::SCP => format!(
1202                "Change the character path. {} {}",
1203                explain_selection!(CharacterPath, self, 0),
1204                explain_selection!(CharacterPathScope, self, 1)
1205            ),
1206            Function::SCS => format!(
1207                "Character are spaced by {} units",
1208                param!(self, 0, 0)
1209            ),
1210            Function::SD => format!(
1211                concat!(
1212                    "Scroll down by {} lines."
1213                ),
1214                param!(self, 0, 1)
1215            ),
1216            Function::SDS => explain_selection!(StringDirection, self, 0),
1217            Function::SEE => format!(
1218                "When character or line insertions or deletions require content to be shifted, {}.",
1219                explain_selection!(EditingExtend, self, 0)
1220            ),
1221            Function::SEF => format!(
1222                "{} {}",
1223                explain_selection!(Load, self, 0),
1224                explain_selection!(Stack, self, 1)
1225            ),
1226            Function::SGR => format!(
1227                "Change the representation of following text. {}.",
1228                self.parameters.iter().map(|value| {
1229                    value.parse::<GraphicRendition>().expect("Expect only valid Graphic Renditions").explain()
1230                }).fold(String::new(), |mut renditions, rendition| {
1231                    renditions.push_str(", ");
1232                    renditions.push_str(&rendition);
1233                    renditions
1234                })
1235            ),
1236            Function::SHS => explain_selection!(CharacterSpacing, self, 0),
1237            Function::SIMD => explain_selection!(MovementDirection, self, 0),
1238            Function::SL => format!(
1239                "Scroll left by {} characters",
1240                param!(self, 0, 1)
1241            ),
1242            Function::SLH => format!(
1243                "Set the line home position to line {} for the active and following lines.",
1244                param!(self, 0, 0)
1245            ),
1246            Function::SLL => format!(
1247                "Set the line limit position to character position {} for the active and following lines.",
1248                param!(self, 0, 0)
1249            ),
1250            Function::SLS => format!(
1251                "Set the line spacing to {}, expressed in the unit established by 'Select Size Unit' (SSU).",
1252                param!(self, 0, 0)
1253            ),
1254            Function::SM => format!(
1255                "Set the following Modes: {}",
1256                self.parameters.iter().map(|value| {
1257                    value.parse::<Mode>().expect("Expect only valid Modes").name()
1258                }).fold(String::new(), |mut modes, mode| {
1259                    modes.push_str(", ");
1260                    modes.push_str(&mode);
1261                    modes
1262                })
1263            ),
1264            Function::SPD => format!(
1265                "In {}, set the presentation direction to {}.",
1266                explain_selection!(PresentationDirectionScope, self, 1),
1267                explain_selection!(PresentationDirection, self, 0)
1268            ),
1269            Function::SPH => format!(
1270                "Set the page home position to line position {}.",
1271                param!(self, 0, 0)
1272            ),
1273            Function::SPI => format!(
1274                concat!(
1275                    "Establish the spacing increment to {} line spacing and {} character spacing, expressed in the ",
1276                    "unit established by 'Select Size Unit' (SSU)."
1277                ),
1278                param!(self, 0, 0),
1279                param!(self, 1, 0)
1280            ),
1281            Function::SPL => format!(
1282                "Set the page limit position to line {} for the active and following lines.",
1283                param!(self, 0, 0)
1284            ),
1285            Function::SPQR => explain_selection!(PrintQuality, self, 0),
1286            Function::SR => format!(
1287                "Scroll right by {} characters.",
1288                param!(self, 0, 1)
1289            ),
1290            Function::SRCS => format!(
1291                "Establish reduced inter-character escapement by {} units for subsequent text.",
1292                param!(self, 0, 0)
1293            ),
1294            Function::SRS => explain_selection!(ReversedString, self, 0),
1295            Function::SSU => format!(
1296                "The size unit for operation is expressed as {}",
1297                explain_selection!(SizeUnit, self, 0)
1298            ),
1299            Function::SSW => format!(
1300                "Set the escapement of space to {} units.",
1301                param!(self, 0, 0)
1302            ),
1303            Function::STAB => format!(
1304                concat!(
1305                    "Causes subsequent text in the presentation component to be aligned according to the position and ",
1306                    "properties of a tabulation stop which is selected from a list according to the value of the ",
1307                    "parameter: {}."
1308                ),
1309                param!(self, 0, 0)
1310            ),
1311            Function::SU => format!(
1312                "Scroll up by {} lines.",
1313                param!(self, 0, 1)
1314            ),
1315            Function::SVS => explain_selection!(LineSpacing, self, 0),
1316            Function::TAC => format!(
1317                concat!(
1318                    "Causes a character tabulation stop calling for centring to be set at character position {} in ",
1319                    "the active line."
1320                ),
1321                param!(self, 0, 0)
1322            ),
1323            Function::TALE => format!(
1324                concat!(
1325                    "Causes a character tabulation stop calling for leading edge alignment to be set at character ",
1326                    "position {} in the active line."
1327                ),
1328                param!(self, 0, 0)
1329            ),
1330            Function::TATE => format!(
1331                concat!(
1332                    "Causes a character tabulation stop calling for trailing edge alignment to be set at character ",
1333                    "position {} in the active line."
1334                ),
1335                param!(self, 0, 0)
1336            ),
1337            Function::TBC => explain_selection!(ClearTabulation, self, 0),
1338            Function::TCC => format!(
1339                concat!(
1340                    "Causes a character tabulation stop calling for alignment of a target graphic character {} to be ",
1341                    "set at character position {} in the active line."
1342                ),
1343                param!(self, 1, 32),
1344                param!(self, 0, 0)
1345            ),
1346            Function::TSR => format!(
1347                concat!(
1348                    "Causes any character tabulation stop at character position {} in the active line and subsequent ",
1349                    "lines to be cleared."
1350                ),
1351                param!(self, 0, 0)
1352            ),
1353            Function::TSS => format!(
1354                "Establish the width of a thin space for subsequent text to be {} units.",
1355                param!(self, 0, 0)
1356            ),
1357            Function::VPA => format!(
1358                concat!(
1359                    "Causes the active data position to be moved to line position {} in the data component in a ",
1360                    "direction parallel to the line progression."
1361                ),
1362                param!(self, 0, 1)
1363            ),
1364            Function::VPB => format!(
1365                concat!(
1366                    "Causes the active data position to be moved by {} line positions in the data component in a ",
1367                    "direction opposite of that of the line progression."
1368                ),
1369                param!(self, 0, 1)
1370            ),
1371            Function::VPR => format!(
1372                concat!(
1373                    "Causes the active data position to be moved {} line positions in the data component in a ",
1374                    "direction parallel of the line progression."
1375                ),
1376                param!(self, 0, 1)
1377            ),
1378            Function::PRIVATE => String::from("Reserved for private use / not standardized."),
1379        }
1380    }
1381
1382    fn long_description(&self) -> String {
1383        match function(&self) {
1384            Function::BEL => String::from(
1385                "Calls for the attention of the user by controlling an alarm or attention device.",
1386            ),
1387            Function::BS => String::from(
1388                concat!(
1389                    "Causes the active data position to be moved one character position in the direction opposite to ",
1390                    "that of the implicit character movement. The direction of the implicit movement depends on the ",
1391                    "parameter value of 'Select Implicit Movement Direction' (SIMD)."
1392                )
1393            ),
1394            Function::CAN => String::from(
1395                concat!(
1396                    "Indicates that the data preceding it is in error. As a result, this data shall be ignored. ",
1397                    "The specific meaning of this control function shall be defined for each application and/or ",
1398                    "between sender and recipient."
1399                )
1400            ),
1401            Function::CR => String::from(
1402                concat!(
1403                    "Move the cursor to the beginning of the line. The exact meaning depends on the setting of ",
1404                    "'Device Component Select Mode' (DCSM) and on the parameter value of 'Select Implicit Movement ",
1405                    "Direction' (SIMD).",
1406                    "\n",
1407                    "\n",
1408                    "If the DCSM is set to 'Presentation' and SIMD is set to 'Normal', it ",
1409                    "causes the active presentation position to be moved to the line home position of the same line ",
1410                    "in the presentation component. The line home position is established by the parameter value of ",
1411                    "'Set Line Home' SLH.",
1412                    "\n",
1413                    "With SIMD set to 'Opposite', it causes the active presentation position ",
1414                    "to be moved to the line limit position of the same line in the presentation component. ",
1415                    "The line limit position is established by the parameter value of 'Set Line Limit' (SLL).",
1416                    "\n",
1417                    "\n",
1418                    "If the DCSM is set to 'Data' and SIMD is set to 'Normal', it causes the active data position to ",
1419                    "be moved to the line home position of the same line in the data component. The line home ",
1420                    "position is established by the parameter value of 'Set Line Home' (SLH)",
1421                    "\n",
1422                    "With SIMD set to 'Opposite', it causes the active data position to be moved to the line limit ",
1423                    "position of the same line in the data component. The line limit position position is established ",
1424                    "by the parameter value of 'Set Line Limit' (SLL)."
1425                )
1426            ),
1427            Function::DC1 => String::from(
1428                concat!(
1429                    "Primarily intended for turning on or starting an ancillary device. If it is not required for ",
1430                    "this purpose, it may be used to restore a device to the basic mode of operation. When used for ",
1431                    "data flow control, it is also sometimes called X-ON."
1432                )
1433            ),
1434            Function::DC2 => String::from(
1435                concat!(
1436                    "Primarily intended for turning on or starting an ancillary device. If it is not required for ",
1437                    "this purpose, it may be used to set a device to a special mode of operation (in which case DC1 ",
1438                    "is used to restore the mode of operation to the normal mode), or for any other device control ",
1439                    "function not provided by other DCs."
1440                )
1441            ),
1442            Function::DC3 => String::from(
1443                concat!(
1444                    "Primarily intended for turning off or stopping an ancillary device. This function may be a ",
1445                    "secondary level stop, for example wait, pause, stand-by, or halt (in which case DC1 is used to ",
1446                    "restore normal operation). If it is not required for this purpose, it may be used for any other ",
1447                    "device control function not provided by other DCs."
1448                )
1449            ),
1450            Function::DC4 => String::from(
1451                concat!(
1452                    "Primarily intended for turning off, stopping, or interrupting an ancillary device. If it is not ",
1453                    "required for this purpose, it may be used for any other device control function not provided by ",
1454                    "other DCs."
1455                )
1456            ),
1457            Function::EM => String::from(
1458                concat!(
1459                    "Identifies the physical end of a medium, or the end of the used portion of a medium, or the end ",
1460                    "of the wanted portion of data recorded on a medium."
1461                )
1462            ),
1463            Function::ESC => String::from(
1464                concat!(
1465                    "Used for code extension purposes. It causes the meanings of a limited number of bit combinations ",
1466                    "following it in the data stream to be changed."
1467                )
1468            ),
1469            Function::FF => String::from(
1470                concat!(
1471                    "Causes the active presentation position to be moved to the corresponding character position of ",
1472                    "the line at the page home position of the next form or page in the presentation component. The ",
1473                    "page home position is established by the parameter value of 'Set Page Home' (SPH)."
1474                )
1475            ),
1476            Function::HT => String::from(
1477                concat!(
1478                    "Causes the active presentation position to be moved to the following character tabulation stop ",
1479                    "in the presentation component. In addition, if that following character tabulation stop has been ",
1480                    "set by 'Tabulation Align Center' (TAC), 'Tabulation Align Leading Edge' (TALE), or 'Tabulation ",
1481                    "Centred On Character' (TACE), it causes the beginning of a string of text which is to be ",
1482                    "positioned within a line according to the properties of that tabulation stop. The end of the ",
1483                    "string is indicated by the next occurrence of HT, CR, or NEL in the data stream."
1484                )
1485            ),
1486            Function::IS1 => String::from(
1487                concat!(
1488                    "Separates and qualifies data logically, its specific meaning has to be defined for each ",
1489                    "application. If this control function is used in hierarchical order, it may delimit a data item ",
1490                    "called a unit."
1491                )
1492            ),
1493            Function::IS2 => String::from(
1494                concat!(
1495                    "Separates and qualifies data logically, its specific meaning has to be defined for each ",
1496                    "application. If this control function is used in hierarchical order, it may delimit a data item ",
1497                    "called a record."
1498                )
1499            ),
1500            Function::IS3 => String::from(
1501                concat!(
1502                    "Separates and qualifies data logically, its specific meaning has to be defined for each ",
1503                    "application. If this control function is used in hierarchical order, it may delimit a data item ",
1504                    "called a group."
1505                )
1506            ),
1507            Function::IS4 => String::from(
1508                concat!(
1509                    "Separates and qualifies data logically, its specific meaning has to be defined for each ",
1510                    "application. If this control function is used in hierarchical order, it may delimit a data item ",
1511                    "called a file."
1512                )
1513            ),
1514            Function::LF => String::from(
1515                concat!(
1516                    "If the 'Device Component Select Mode' is set to 'Presentation', it causes the active ", 
1517                    "presentation position to be moved to the corresponding character position of the following line ",
1518                    "in the presentation component.",
1519                    "\n",
1520                    "\n",
1521                    "If the 'Device Component Select Mode' is set to 'Data', it causes the active data position to be ",
1522                    "moved to the corresponding character position of the following line in the data component."
1523                )
1524            ),
1525            Function::LS0 => String::from(
1526                concat!(
1527                    "Used for code extension purposes. It causes the meanings of the bit combinations following it in ",
1528                    "the data stream to be changed."
1529                )
1530            ),
1531            Function::LS1 => String::from(
1532                concat!(
1533                    "Used for code extension purposes. It causes the meanings of the bit combinations following it in ",
1534                    "the data stream to be changed."
1535                )
1536            ),
1537            Function::NUL => String::from(
1538                concat!(
1539                    "Used for media-fill or time-fill. NUL characters may be inserted into, or removed from, a data ",
1540                    "stream without affecting information content of that stream, but such action may affect the ",
1541                    "information layout and/or the control of equipment."
1542                )
1543            ),
1544            Function::SYN => String::from(
1545                concat!(
1546                    "Used by a synchronous transmission system in the absence of any other character (idle condition) ",
1547                    "to provide a signal from which synchronism may be achieved or retained between data terminal ",
1548                    "equipment."
1549                )
1550            ),
1551            Function::VT => String::from(
1552                concat!(
1553                    "Causes the active presentation position to be moved in the presentation component to the ",
1554                    "corresponding character position on th e line at which the following line tabulation stop is ",
1555                    "set."
1556                )
1557            ),
1558            Function::APC => String::from(
1559                concat!(
1560                    "Used as the opening delimiter of a control string for application program use. The command ",
1561                    "string following may consist of bit combinations in the range 00/08 to 00/13 and 02/00 to 07/14. ",
1562                    "The control string is closed by the terminating delimiter 'String Terminator' (ST). The ",
1563                    "interpretation of the command string depends on the relevant application program."
1564                )
1565            ),
1566            Function::CCH => String::from(
1567                concat!(
1568                    "Indicates that both the preceding graphic character in the data stream (represented by one or ",
1569                    "more bit combinations), including 'Space', and the control function itself are to be ignored ",
1570                    "for further interpretation in the data stream.",
1571                    "\n",
1572                    "\n",
1573                    "If the character preceding CCH in the data stream is a control function (represented by one or ",
1574                    "more bit combinations), the effect of CCH is not defined."
1575                )
1576            ),
1577            Function::DCS => String::from(
1578                concat!(
1579                    "Used as the opening delimiter of a control string for device control use. The command string ", 
1580                    "following may consist of bit combinations in the range 00/08 to 00/13 and 02/00 to 07/14. The ",
1581                    "control string is closed by the terminating delimiter 'String Terminator' (ST)."
1582                )
1583            ),
1584            Function::EPA => String::from(
1585                concat!(
1586                    "Indicates that the active presentation position is the last of a string of character positions ",
1587                    "in the presentation component, the contents of which are protected against manual alteration, ",
1588                    "are guarded against transmission or transfer, depending on the settings of 'Guarded Area ",
1589                    "Transfer Mode' (GATM), and may be protected against erasure, depending on the setting of ",
1590                    "'Erasure Mode' (ERM). The beginning of this string is indicated by 'Start of Guarded Area' (SPA)."
1591                )
1592            ),
1593            Function::ESA => String::from(
1594                concat!(
1595                    "Indicates that the active presentation position is the last of a string of character positions ",
1596                    "in the presentation component, the contents of which are eligible to be transmitted in the form ",
1597                    "of a data stream or transferred to an auxiliary input/output device. The beginning of the string ",
1598                    "is indicated by 'Start of Selected Area' (SSA)"
1599                )
1600            ),
1601            Function::HTJ => String::from(
1602                concat!(
1603                    "Causes the contents of the active field (the field in the presentation component that contains ",
1604                    "active presentation position) to be shifted forwarded, so that it ends at the character position ",
1605                    "preceding the following character tabulation stop. The active presentation position is moved to ",
1606                    "that following character tabulation stop. The character position which precede the beginning of ",
1607                    "the shifted string are put into the erased state."
1608                )
1609            ),
1610            Function::HTS => String::from(
1611                concat!(
1612                    "Causes a character tabulation stop to be set at the active presentation position in the ",
1613                    "presentation component. The number of lines affected depends on the setting of the ",
1614                    "'Tabulation Stop Mode' (TSM)."
1615                )
1616            ),
1617            Function::MW => String::from(
1618                concat!(
1619                    "Sets a message waiting indicated in the receiving device. An appropriate acknowledgement to the ",
1620                    "receipt of MW may be given by using 'Device Status Report' (DSR)."
1621                )
1622            ),
1623            Function::NBH => String::from(
1624                concat!(
1625                    "Indicates a point where a line break shall not occur when text is formatted. This may occur ",
1626                    "between two graphic characters, either or both which may be 'Space'."
1627                )
1628            ),
1629            Function::NEL => String::from(
1630                concat!(
1631                    "The effect of NEL depends on the setting of the 'Device Component Select Mode' (DCSM) and the ",
1632                    "parameter value of 'Select Implicit Movement Direction' (SIMD).",
1633                    "\n",
1634                    "\n",
1635                    "If DCSM is set to 'Presentation' and SIMD equal to 'Normal', it causes the active presentation ",
1636                    "position to be moved to the line home position of the following line in the presentation ",
1637                    "component. The line home position may be established by the parameter of 'Set Line Home' (SLH). ",
1638                    "\n",
1639                    "With SIMD equal to 'Opposite', it causes the active presentation position to be moved to the ",
1640                    "line limit position of the following line in the presentation component. The line limit position ",
1641                    "may be established by the parameter of 'Set Line Limit' (SLL).",
1642                    "\n",
1643                    "\n",
1644                    "If DCSM is set to 'Data' and SIMD equal to 'Normal', it causes the active data ",
1645                    "position to be moved to the line home position of the following line in the data ",
1646                    "component. The line home position may be established by the parameter of 'Set Line Home' (SLH). ",
1647                    "\n",
1648                    "With SIMD equal to 'Opposite', it causes the active data position to be moved to the ",
1649                    "line limit position of the following line in the data component. The line limit position ",
1650                    "may be established by the parameter of 'Set Line Limit' (SLL)."
1651                )
1652            ),
1653            Function::OSC => String::from(
1654                concat!(
1655                    "Opening delimiter of a control string for operating system use. The command string following may ",
1656                    "consist of a sequence of bit combinations in the range 00/08 to 00/13 and 02/00 to 07/14. The ",
1657                    "control string is closed by the terminating delimiter 'String Terminator' (ST). The ",
1658                    "interpretation of the command string depends on the relevant operating system."
1659                )
1660            ),
1661            Function::PLD => String::from(
1662                concat!(
1663                    "Move the active presentation position in the presentation component to the corresponding ",
1664                    "position of an imaginary line with a partial offset in the direction of line progression. This ",
1665                    "offset should be sufficient either to image following characters as subscripts until the first ",
1666                    "following occurrence of 'Partial Line Backwards' (PLU) in the data stream, or, if preceding ",
1667                    "characters were imaged as superscripts, to restore imaging of following characters to the active ",
1668                    "line."
1669                )
1670            ),
1671            Function::PLU => String::from(
1672                concat!(
1673                    "Move the active presentation position in the presentation component to the corresponding ",
1674                    "position of an imaginary line with a partial offset in the direction opposite of line ",
1675                    "progression. This offset should be sufficient either to image following characters as ",
1676                    "superscripts until the first following occurrence of 'Partial Line Forward' (PLD) in the data ",
1677                    "stream, or, if preceding characters were imaged as subscripts, to restore imaging of following ",
1678                    "characters to the active line."
1679                )
1680            ),
1681            Function::PM => String::from(
1682                concat!(
1683                    "Indicates the beginning of a control string privacy message use. The command string following ",
1684                    "may consist of bit combination sin the range 00/08 to 00/13 and 02/00 to 07/14. The control ",
1685                    "string is closed by the terminating delimiter 'String Terminator' (ST). The interpretation", 
1686                    "of the command string depends on the relevant privacy discipline."
1687                )
1688            ),
1689            Function::RI => String::from(
1690                concat!(
1691                    "If the 'Device Component Select Mode' (DCSM) is set to 'Presentation', it causes the active ",
1692                    "presentation position to be moved in the presentation component to the corresponding character ",
1693                    "position of the preceding line.",
1694                    "\n",
1695                    "\n",
1696                    "If the 'Device Component Select Mode' (DCSM) is set to 'Data', it causes the active ",
1697                    "data position to be moved in the data component to the corresponding character ",
1698                    "position of the preceding line."
1699                )
1700            ),
1701            Function::SCI => String::from(
1702                concat!(
1703                    "This and the bit combination following it are used to represent a control function or a graphic ",
1704                    "character. The bit combination following SCI must be from 00/08 to 00/13 or 02/00 to 07/14. The ",
1705                    "use of SCI is reserved for future standardization."
1706                )
1707            ),
1708            Function::SOS => String::from(
1709                concat!(
1710                    "Used as the opening delimiter of a control string. The character string following may consist of ",
1711                    "any bit combinations, except those representing SOS or 'String Terminator' (ST). The control ",
1712                    "string is closed by the terminating delimiter 'String Terminator' (ST). The interpretation of the ",
1713                    "character string depends on the application."
1714                )
1715            ),
1716            Function::SPA => String::from(
1717                concat!(
1718                    "Used to indicate that the active presentation position is the first of a string of character ",
1719                    "positions in the presentation component, the contents of which are protected against manual ",
1720                    "alteration, are guarded against transmission or transfer, depending on the setting of 'Guarded ",
1721                    "Area Transfer Mode' (GATM), and may be protected against erasure, depending on the setting of ",
1722                    "the 'Erasure Mode' (ERM). The end of this string is indicated by 'End of Guarded Area' (EPA)."
1723                )
1724            ),
1725            Function::SSA => String::from(
1726                concat!(
1727                    "Indicates that the active presentation position is the first of a string of character positions ",
1728                    "in the presentation component, the contents of which are eligible to be transmitted in the form ",
1729                    "of a data stream or transferred to an ancillary input/output device. The end of this string is ",
1730                    "indicated by 'End of Selected Area' (ESA). ",
1731                    "\n",
1732                    "\n",
1733                    "The string of character actually transmitted or transferred depends on the setting of 'Guarded ",
1734                    "Area Transfer mode' (GATM) and on any guarded areas established by 'Define Area Qualification' ",
1735                    "(DAQ), or by 'Start of Guarded Area' (SPA) and 'End of Guarded Area' (EPA)."
1736                )
1737            ),
1738            Function::STS => String::from(
1739                concat!(
1740                    "Used to establish the transmit state in the receiving device. In this state the transmission of ",
1741                    "data from the device is possible. The actual initiation of transmission of data is performed by ",
1742                    "a data communication or input/output interface control procedure, which is outside of the scope ",
1743                    "of this Standard.",
1744                    "\n",
1745                    "\n",
1746                    "The transmit state is established either by this appearing in the received data stream, or by ",
1747                    "the operation of an appropriate key on a keyboard."
1748                )
1749            ),
1750            Function::CMD => String::from(
1751                concat!(
1752                    "Delimits a string of data coded according to standard ECMA-35, and to switch to a general level ",
1753                    "of control. The use of this is not mandatory if the higher level protocol defines means of ",
1754                    "delimiting the string, for instance by specifying the length of the string."
1755                )
1756            ),
1757            Function::RIS => String::from(
1758                concat!(
1759                    "Reset the receiving device to its initial state, i.e. the state it has after it is made ",
1760                    "operational. This may imply, if applicable: clear tabulation stops, remove qualified areas, ",
1761                    "reset graphic rendition, put all character positions into the erased state, move the active ",
1762                    "presentation position to the first position of the first line in the presentation component, ",
1763                    "move the active data position to the first character position in the first line in the data ",
1764                    "component, set the modes into the reset state, etc.."
1765                )
1766            ),
1767            Function::CBT => format!(
1768                concat!(
1769                    "Causes the active presentation position to be moved to the character position corresponding ",
1770                    "to the {} preceding character tabulation stop in the presentation component, according to ",
1771                    "the character path.",
1772
1773                ),
1774                param!(self, ordinal 0, 1)
1775            ),
1776            Function::CHA => format!(
1777                concat!(
1778                    "Causes the active presentation position to be moved to character position {} in the active line ",
1779                    "in the presentation component"
1780                ),
1781                param!(self, 0, 1)
1782            ),
1783            Function::CHT => format!(
1784                concat!(
1785                    "Causes the active presentation position to be moved to the character position corresponding to ",
1786                    "the {} following character tabulation stop in the presentation component, according to the ",
1787                    "character path."
1788                ),
1789                param!(self, ordinal 0, 1)
1790            ),
1791            Function::CNL => format!(
1792                concat!(
1793                    "Causes the active presentation position to be moved to the first character position of the {} ",
1794                    "following line in the presentation component."
1795                ),
1796                param!(self, ordinal 0, 1)
1797            ),
1798            Function::CPL => format!(
1799                concat!(
1800                    "Causes the active presentation position to be moved to the first character position of the {} ",
1801                    "preceding line in the presentation component."
1802                ),
1803                param!(self, ordinal 0, 1)
1804            ),
1805            Function::CPR => format!(
1806                concat!(
1807                    "If the 'Device Component Select Mode' (DCSM) is set to 'Presentation', reports the active ",
1808                    "presentation position of the sending device as residing in the presentation component at the {} ",
1809                    "line position according to the line progress and at the {} character position according to the ",
1810                    "character path.",
1811                    "\n\n",
1812                    "If the 'Device Component Select Mode' (DCSM) is set to 'Data', reports the active data position ",
1813                    "of the sending device as residing in the data component at the {} line position according to the ",
1814                    "line progression and at the {} character position according to the character progression.",
1815                    "\n\n",
1816                    "CPR may be solicited by a 'Device Status Report' (DSR) or be sent unsolicited."
1817                ),
1818                param!(self, ordinal 0, 1),
1819                param!(self, ordinal 1, 1),
1820                param!(self, ordinal 0, 1),
1821                param!(self, ordinal 1, 1),
1822            ),
1823            Function::CUB => format!(
1824                concat!(
1825                    "Causes the active presentation position to be moved leftwards in the presentation component by ",
1826                    "{} character positions, if the character path is horizontal, or by {} line positions, if the ",
1827                    "character path is vertical."
1828                ),
1829                param!(self, 0, 1),
1830                param!(self, 0, 1)
1831            ),
1832            Function::CUD => format!(
1833                concat!(
1834                    "Causes the active presentation position to be moved downwards in the presentation component by ",
1835                    "{} line positions, if the character path is horizontal, or by {} character positions, if the ",
1836                    "character path is vertical."
1837                ),
1838                param!(self, 0, 1),
1839                param!(self, 0, 1)
1840            ),
1841            Function::CUF => format!(
1842                concat!(
1843                    "Causes the active presentation position to be moved rightwards in the presentation component by ",
1844                    "{} character positions, if the character path is horizontal, or by {} line positions, if the ",
1845                    "character path is vertical."
1846                ),
1847                param!(self, 0, 1),
1848                param!(self, 0, 1)
1849            ),
1850            Function::CUP => format!(
1851                concat!(
1852                    "Causes the active presentation position to be moved in the presentation component to the {} line ",
1853                    "position according to the line progression, and to the {} character position according to the ",
1854                    "character path.",
1855                ),
1856                param!(self, ordinal 0, 1),
1857                param!(self, ordinal 1, 1)
1858            ),
1859            Function::CUU => format!(
1860                concat!(
1861                    "Causes the active presentation position to be moved upwards in the presentation component by {} ",
1862                    "line positions, if the character path is horizontal, or by {} character positions, if the ",
1863                    "character path is vertical."
1864                ),
1865                param!(self, 0, 1),
1866                param!(self, 0, 1)
1867            ),
1868            Function::CVT => format!(
1869                concat!(
1870                    "Causes the active presentation position to be moved to the character position of the line ",
1871                    "corresponding to the {} following line tabulation stop in the presentation component."
1872                ),
1873                param!(self, ordinal 0, 1)
1874            ),
1875            Function::DAQ => format!(
1876                concat!(
1877                    "This is used to indicate that the active presentation position in the presentation component is ",
1878                    "the first character position of a qualified area. The last character position of the qualified ",
1879                    "area is the character position in the presentation component immediately preceding the first ",
1880                    "character position of the following qualified area. This area {}."
1881                ),
1882                explain_selection!(AreaQualification, self, 0)
1883            ),
1884            Function::DCH => format!(
1885                concat!(
1886                    "If the 'Device Component Select Mode' (DSCM) is set to 'Presentation', it causes the contents ",
1887                    "of the active presentation position and, depending on the setting of 'Character Editing Mode' ",
1888                    "(HEM), the contents of the preceding or following character positions to be removed from the ",
1889                    "presentation component. The resulting gap of {} characters is closed by shifting the contents of ",
1890                    "the adjacent character positions towards the active presentation position. At the other end of ",
1891                    "the shifter part {} character positions are put into the erased state.",
1892                    "\n\n",
1893                    "The extend of the shifted part is established by 'Select Editing Extend' (SEE).",
1894                    "\n\n",
1895                    "The effect of this on the start or end of a selected area, the start or end of a qualified area, ",
1896                    "or a tabulation stop in the shifted part is undefined.",
1897                    "\n\n",
1898                    "If the 'Device Component Select Mode' (DCSM) is set to 'Data', it causes the contents of the ",
1899                    "active data position and, depending on the setting of 'Character Editing Mode' (HEM), the ",
1900                    "contents of the preceding or following character positions to be removed from the data ",
1901                    "component. The resulting gap of {} characters is closed by shifting the contents of the adjacent ",
1902                    "character positions towards the active data position. At the other end of the shifted part, {} ",
1903                    "character positions are put into the erased state."
1904                ),
1905                param!(self, 0, 1),
1906                param!(self, 0, 1),
1907                param!(self, 0, 1),
1908                param!(self, 0, 1)
1909            ),
1910            Function::DL => format!(
1911                concat!(
1912                    "If the 'Device Component Select Mode' (DSCM) is set to 'Presentation', it causes the contents of ",
1913                    "the active line (the line that contains the active presentation position) and, depending on the ",
1914                    "setting of the 'Line Editing Mode' (VEM), the contents of the preceding or following lines to be ",
1915                    "removed from the presentation component. The resulting gap of {} lines is closed by shifting the ",
1916                    "contents of a number of adjacent lines towards the active line. At the end of the shifted part, ",
1917                    "{} lines are put into the erased state. The active presentation position is moved to the line ",
1918                    "home position in the active line. The line home position is established by the parameter value ",
1919                    "of 'Set Line Home' (SLH). If the 'Tabulation Stop Mode' (TSM) is set to 'Single', character ",
1920                    "tabulation stops are cleared in the lines that are put into the erased state.",
1921                    "\n\n",
1922                    "The extend of the shifted part is established by 'Select Editing Extend' (SEE).",
1923                    "\n\n",
1924                    "Any occurrences of the start or end of a selected area, the start or end of a qualified area, or ",
1925                    "a tabulation stop in the shifted part, are also shifted.",
1926                    "\n\n",
1927                    "If the 'Device Component Select Mode (DCSM) is set to 'Data', it causes the contents of the ",
1928                    "active line (the line that contains the active data position) and, depending on the settings of ",
1929                    "the 'Line Editing Mode' (VEM), the contents of the preceding or following lines to be removed ",
1930                    "from the data component. The resulting gap of {} lines is closed by shifting the contents of a ",
1931                    "number of adjacent lines towards the active line. At the other end of the shifted part, {} lines ",
1932                    "are put into the erased state. The active data position is moved to the line home position in ",
1933                    "the active line. The line home position is established by the parameter value of 'Set Line Home' ",
1934                    "(SLH)."
1935                ),
1936                param!(self, 0, 1),
1937                param!(self, 0, 1),
1938                param!(self, 0, 1),
1939                param!(self, 0, 1)
1940            ),
1941            Function::DTA => format!(
1942                concat!(
1943                    "Establishes the dimension of the text area for subsequent pages. The established dimensions ",
1944                    "remain in effect until the next occurrence of DTA in the data stream. The new dimension is ",
1945                    "specified to be {} in the direction perpendicular to the line orientation and {} parallel to the ",
1946                    "line orientation. The unit in which the value is expressed is that established by the parameter ",
1947                    "value of 'Select Size Unit' (SSU)."
1948                ),
1949                param!(self, 0, 0),
1950                param!(self, 1, 0)
1951            ),
1952            Function::EA => format!(
1953                concat!(
1954                    "If the 'Device Component Select Mode' (DCSM) is set to 'Presentation', {} in the presentation ",
1955                    "component. The contents of the removed area are put into the erased state.",
1956                    "\n\n",
1957                    "If the 'Device Component Select Mode' (DCSM) is set to 'Data', {} in the data component. The ",
1958                    "contents of the removed area are put into the erased state.",
1959                    "\n\n",
1960                    "Whether the character positions of protected areas are put into the erased state, or the ",
1961                    "character positions of unprotected areas only, depends on the settings of 'Erasure Mode' (ERM)."
1962                ),
1963                explain_selection!(EraseArea, self, 0),
1964                explain_selection!(EraseArea, self, 0)
1965            ),
1966            Function::ECH => format!(
1967                concat!(
1968                    "If the 'Device Component Select Mode' (DCSM) is set to 'Presentation', it causes the active ",
1969                    "presentation position and the following character positions in the presentation component to be ",
1970                    "put into the erased state. {} characters will be erased.",
1971                    "\n\n",
1972                    "If the 'Device Component Select Mode' (DCSM) is set to 'Data', it causes the active data position ",
1973                    "and the following character positions in the data component to be put into the erased state. {} ",
1974                    "characters will be erased.",
1975                    "\n\n",
1976                    "Whether the character positions of protected areas are put into the erased state, or the ",
1977                    "character positions of unprotected areas only, depends on the settings of 'Erasure Mode' (ERM)."
1978                ),
1979                param!(self, 0, 1),
1980                param!(self, 0, 1)
1981            ),
1982            Function::ED => format!(
1983                concat!(
1984                    "If the 'Device Component Select Mode' (DCSM) is set to 'Presentation', {} in the presentation ",
1985                    "component. The contents of the removed page are put into the erased state.",
1986                    "\n\n",
1987                    "If the 'Device Component Select Mode' (DCSM) is set to 'Data', {} in the data component. The ",
1988                    "contents of the removed page are put into the erased state.",
1989                    "\n\n",
1990                    "Whether the character positions of protected areas are put into the erased state, or the ",
1991                    "character positions of unprotected areas only, depends on the settings of 'Erasure Mode' (ERM)."
1992                ),
1993                explain_selection!(EraseArea, self, 0),
1994                explain_selection!(EraseArea, self, 0)
1995            ),
1996            Function::EF => format!(
1997                concat!(
1998                    "If the 'Device Component Select Mode' (DCSM) is set to 'Presentation', {} in the presentation ",
1999                    "component. The contents of the removed field are put into the erased state.",
2000                    "\n\n",
2001                    "If the 'Device Component Select Mode' (DCSM) is set to 'Data', {} in the data component. The ",
2002                    "contents of the removed field are put into the erased state.",
2003                    "\n\n",
2004                    "Whether the character positions of protected areas are put into the erased state, or the ",
2005                    "character positions of unprotected areas only, depends on the settings of 'Erasure Mode' (ERM)."
2006                ),
2007                explain_selection!(EraseArea, self, 0),
2008                explain_selection!(EraseArea, self, 0)
2009            ),
2010            Function::EL => format!(
2011                concat!(
2012                    "If the 'Device Component Select Mode' (DCSM) is set to 'Presentation', {} in the presentation ",
2013                    "component. The contents of the removed line are put into the erased state.",
2014                    "\n\n",
2015                    "If the 'Device Component Select Mode' (DCSM) is set to 'Data', {} in the data component. The ",
2016                    "contents of the removed line are put into the erased state.",
2017                    "\n\n",
2018                    "Whether the character positions of protected areas are put into the erased state, or the ",
2019                    "character positions of unprotected areas only, depends on the settings of 'Erasure Mode' (ERM)."
2020                ),
2021                explain_selection!(EraseArea, self, 0),
2022                explain_selection!(EraseArea, self, 0)
2023            ),
2024            Function::FNT => format!(
2025                concat!(
2026                    "{}\n\n",
2027                    "The active Font might be switched in the following data stream by 'Select Graphic Rendition (SGR)."
2028                ),
2029                self.short_description()
2030            ),
2031            Function::GSM => format!(
2032                concat!(
2033                    "Used to modify the text height and / or width of the subsequent text for all primary and ",
2034                    "alternatives fonts and established 'Graphic Size Select' (GSS). The established values remain in ",
2035                    "effect until the next occurrence of GSM or GSS in the data stream. The new size is set to to {}% ",
2036                    "height and {}% width."
2037                ),
2038                param!(self, 0, 100),
2039                param!(self, 1, 100)
2040            ),
2041            Function::GSS => format!(
2042                concat!(
2043                    "Used to establish the height for the subsequent text for all primary and alternative fonts. The ",
2044                    "established value remains in effect until the next occurrence of GSS in the data stream. The new ",
2045                    "height is set to {} with a unit established by 'Select Size Unit' (SSU)."
2046                ),
2047                param!(self, 0, 0)
2048            ),
2049            Function::HPA => format!(
2050                concat!(
2051                    "Causes the active data position to be moved to the character position {} in the active line (the ",
2052                    "line in the data component that contains the active data position)"
2053                ),
2054                param!(self, 0, 1)
2055            ),
2056            Function::HPB => format!(
2057                concat!(
2058                    "Causes the active data position to be moved by {} character positions in the data component in ",
2059                    "the direction opposite to that of the character progression."
2060                ),
2061                param!(self, 0, 1)
2062            ),
2063            Function::HPR => format!(
2064                concat!(
2065                    "Causes the active data position to be moved by {} character positions in the data component in ",
2066                    "the direction of character progression."
2067                ),
2068                param!(self, 0, 1)
2069            ),
2070            Function::HVP => format!(
2071                concat!(
2072                    "Causes the active data position to be moved in the data component to the {} line position ",
2073                    "according to the line progression and to the {} character position according to the character ",
2074                    "position."
2075                ),
2076                param!(self, ordinal 0, 1),
2077                param!(self, ordinal 1, 1)
2078            ),
2079            Function::ICH => format!(
2080                concat!(
2081                    "If the 'Device Component Select Mode' (DCSM) is set to 'Presentation', this is used to prepare ",
2082                    "the insertion of {} characters, by putting into the erased state the active presentation ",
2083                    "position and, depending on the setting of the Character Editing Mode (HEM), the preceding or ",
2084                    "following character positions in the presentation component. The previous contents of the active ",
2085                    "presentation position and an adjacent string of character positions are shifted away from the ",
2086                    "active presentation position. The contents of {} character positions at the other end of the ",
2087                    "shifted part are removed. The active presentation position is moved to the line home position in ",
2088                    "the active line. The line home position is established by the parameter value of 'Set Line Home' ",
2089                    "(SLH).",
2090                    "\n\n",
2091                    "The extent of the shifted part is established by Select Editing Extend (SEE).",
2092                    "\n\n",
2093                    "The effect of this on the start or end of a selected area, the start or end of a qualified area, ",
2094                    "or a tabulation stop in the shifted part is undefined.",
2095                    "\n\n",
2096                    "If the 'Device Component Select Mode' (DCSM) is set to 'Data', this is used to prepare the ",
2097                    "insertion of {} characters, by putting into the erased state the active data position and, ",
2098                    "depending on the setting of the Character Editing Mode (HEM), the preceding or following ",
2099                    "character positions in the data component. The previous contents of the active data position and ",
2100                    "and adjacent string of character positions are shifted away from the active data position. ",
2101                    "The contents of {} character positions at the other end of the shifted part are removed. The ",
2102                    "active data position is moved to the line home position in the active line. The line ",
2103                    "home position is established by the parameter value of Set Line Home (SLH)."
2104                ),
2105                param!(self, ordinal 0, 1),
2106                param!(self, ordinal 0, 1),
2107                param!(self, ordinal 0, 1),
2108                param!(self, ordinal 0, 1)
2109            ),
2110            Function::IGS => format!(
2111                concat!(
2112                    "Indicates that the graphic subrepertoire {} is used in the subsequent text according to the ",
2113                    "graphic characters of ISO/IEC 10367. The graphic subrepertoire {} is registered in accordance ",
2114                    "with ISO/IEC 7350"
2115                ),
2116                param!(self, 0, 0),
2117                param!(self, 0, 0)
2118            ),
2119            Function::IL => format!(
2120                concat!(
2121                    "If the 'Device Component Select Mode' (DCSM) is set to 'Presentation', this is used to prepare ",
2122                    "the insertion of {} lines, by putting into the erased state in the presentation component the ",
2123                    "active line (the line that contains the active presentation position) and, depending on the ",
2124                    "setting of the 'Line Editing Mode' (VEM), the preceding or following lines. The previous contents ",
2125                    "of the active line and of adjacent lines are shifted away from the active line. The contents of ",
2126                    "{} lines at the other end of the shifted part are removed. The active presentation position is ",
2127                    "moved to the line home position in the active line. The line home position is established by the ",
2128                    "parameter value of 'Set Line Home' (SLH).",
2129                    "\n\n",
2130                    "The extent of the shifted part is established by 'Select Editing Extent' (SEE).",
2131                    "\n\n",
2132                    "Any occurrence of the start or end of a selected area, the start or end of a qualified area, or ",
2133                    "a tabulation stop in the shifted part, are also shifted.",
2134                    "\n\n",
2135                    "If the 'Tabulation Stop Mode' (TSM) is set to 'Single', character tabulation stops are cleared ",
2136                    "in the lines that are put into the erased state.",
2137                    "\n\n",
2138                    "If the 'Device Component Select Mode' (DCSM) is set to 'Data', this is used to prepare the ",
2139                    "insertion of {} lines, by putting into the erased state in the data component the active line ",
2140                    "(the line that contains the active data position) and, depending on the setting of the 'Line ",
2141                    "Editing Mode' (VEM), the preceding or following lines. The previous contents of the active line ",
2142                    "and of adjacent lines are shifted away from the active line. The contents of {} lines at the ",
2143                    "other end of the shifted part are removed. The active data position is moved to the line home ",
2144                    "position in the active line. The line home position is established by the parameter value of ",
2145                    "'Set Line Home' (SLH)."
2146                ),
2147                param!(self, 0, 1),
2148                param!(self, 0, 1),
2149                param!(self, 0, 1),
2150                param!(self, 0, 1)
2151            ),
2152            Function::JFY => format!(
2153                concat!(
2154                    "Indicates the beginning of a string of graphic characters in the presentation component that are ",
2155                    "to be justified according to the layout specified: {}"
2156                ),
2157                self.short_description()
2158            ),
2159            Function::PEC => format!(
2160                concat!(
2161                    "Establish the spacing and the extent of graphic characters for subsequent text. {}",
2162                    "\n\n",
2163                    "The spacing is specified in the line as multiples of the spacing established by the most recent ",
2164                    "occurrence of 'Set Character Spacing' (SCS), of 'Select Character Spacing' (SHS), or of 'Spacing ",
2165                    "Increment' (SPI) in the data stream. The extent of characters is implicitly established by these ",
2166                    "control functions. The established spacing and extent remain in effect until the next occurrence ",
2167                    "of PEC. "
2168                ),
2169                self.short_description()
2170            ),
2171            Function::PFS => format!(
2172                concat!(
2173                    "Establish the available area for the imaging of pages of text based on paper size. {}",
2174                    "\n\n",
2175                    "The pages are introduced by the subsequent occurrences of 'Form Feed' (FF) in the data stream. ",
2176                    "The established area stays into effect until the next occurrence.",
2177                    "\n\n",
2178                    "The page home position is established by 'Set Page Home' (SPH), the page limit position is ",
2179                    "established by 'Set Page Limit' (SPL)."
2180                ),
2181                self.short_description()
2182            ),
2183            Function::PTX => format!(
2184                concat!(
2185                    "Used to delimit strings of graphic characters that are communicated one after another in the ",
2186                    "data stream, but that are intended to be presented in parallel with another one, usually in ",
2187                    "adjacent lines.",
2188                    "\n\n",
2189                    "{}"
2190                ),
2191                self.short_description()
2192            ),
2193            Function::QUAD => format!(
2194                concat!(
2195                    "Indicates the end of a string of graphic characters that are to be positioned on a single line ",
2196                    "{}.\n\n",
2197                    "The beginning of the string to be positioned is indicated by the preceding occurrence in the data ",
2198                    "stream of either another QUAD, or one of the following formator functions: FF, LF, NEL, RI, VT, ",
2199                    "HVP, HPA, PPB, PPR, VPA, VPB.",
2200                    "\n\n",
2201                    "The line home position is established by the parameter value of 'Set Line Home' (SLH). The line ",
2202                    "limit position is established by the parameter value of 'Set Line Home' (SLH)."
2203                ),
2204                self.short_description()
2205            ),
2206            Function::REP => format!(
2207                concat!(
2208                    "Used to indicate that the preceding character in the data stream, if it is a graphic character, ",
2209                    "including 'Space', is to be repeated {} times. If the preceding character is a control function ",
2210                    "or part of a control function, the effect is undefined."
2211                ),
2212                param!(self, 0, 1)
2213            ),
2214            Function::RM =>
2215                self.parameters.iter().map(|value| {
2216                    value.parse::<Mode>().expect("Expect only valid Modes").explain_reset()
2217                }).fold(String::new(), |mut modes, mode| {
2218                    modes.push_str(", ");
2219                    modes.push_str(&mode);
2220                    modes
2221                }
2222            ),
2223            Function::SACS => format!(
2224                concat!(
2225                    "Used to establish extra inter-character escapement for subsequent text. The established extra ",
2226                    "escapement remains in effect until the next occurrence of SACS or of 'Set Reduced Character ",
2227                    "Separation' (SRCS) in the data stream or until it is reset to the default value by a subsequent ",
2228                    "occurrence of 'Carriage Return Line Feed' (CR LF) or of 'Next Line' (NEL) in the data stream.",
2229                    "\n\n",
2230                    "The inter-character escapement is enlarged by {} units",
2231                    "\n\n",
2232                    "the unit in which the parameter value is expressed is that established by the parameter value of ",
2233                    "'Select Size Unit' (SSU)."
2234                ),
2235                param!(self, 0, 0)
2236            ),
2237            Function::SCS => format!(
2238                concat!(
2239                    "Establishes the character spacing for subsequent text. The established spacing remains in effect ",
2240                    "until the next occurrence, or of 'Select Character Spacing' (SHS) or of 'Spacing Increment' ",
2241                    "(SPI) in the data stream.\n\nCharacters are spaced by {} units.",
2242                    "\n\n",
2243                    "The units in which the value is expressed is that established by the parameter value of 'Select ",
2244                    "Size Unit' (SSU)."
2245                ),
2246                param!(self, 0, 0)
2247            ),
2248            Function::SD => format!(
2249                concat!(
2250                    "Causes the data in the presentation component to be moved by {} line positions if the line ",
2251                    "orientation is horizontal, or by {} character positions if the line orientation is vertical, ",
2252                    "such that the data appear to move down.",
2253                    "\n\n",
2254                    "The active presentation position is not affected by this function."
2255                ),
2256                param!(self, 0, 1),
2257                param!(self, 0, 1)
2258            ),
2259            Function::SDS => format!(
2260                concat!(
2261                    "Establishes in the data component the beginning and end of a string of characters, as well as ",
2262                    "the direction of the string. This direction may be different from that currently established. ",
2263                    "The indicated string follows the preceding text. The established character progression is not ",
2264                    "affected. {}"
2265                ),
2266                self.short_description()
2267            ),
2268            Function::SEE => format!(
2269                concat!(
2270                    "Used to establish the editing extend for subsequent character or line insertion or deletion. The ",
2271                    "established context remains in effect until the next occurrence of SEE in the data stream. {}"
2272                ),
2273                self.short_description()
2274            ),
2275            Function::SEF => format!(
2276                concat!(
2277                    "Causes a sheet of paper to be ejected from a printing device into a specified output stacker an ",
2278                    "another sheet to be loaded into the printing device from a specified paper bin. {} {}"
2279                ),
2280                explain_selection!(Load, self, 0),
2281                explain_selection!(Stack, self, 1)
2282            ),
2283            Function::SGR => format!(
2284                concat!(
2285                    "Establishes one or more graphic rendition aspects for subsequent text. The established aspects ",
2286                    "remain in effect until the next occurrence, depending on the setting of the 'Graphic Rendition ",
2287                    "Combination Mode' (GRCM).\n\n{}"
2288                ),
2289                self.parameters.iter().map(|value| {
2290                    value.parse::<GraphicRendition>().expect("Expect only valid Graphic Renditions").explain()
2291                }).fold(String::new(), |mut renditions, rendition| {
2292                    renditions.push_str(", ");
2293                    renditions.push_str(&rendition);
2294                    renditions
2295                })
2296            ),
2297            Function::SHS => format!(
2298                concat!(
2299                    "Used to establish the character spacing for subsequent text. {} The established spacing remains ",
2300                    "in effect until the next occurrence of SHS or of 'Set Character Spacing' (SHS) or of 'Spacing ",
2301                    "Increment' (SPI)."
2302                ),
2303                self.short_description()
2304            ),
2305            Function::SIMD => format!(
2306                concat!(
2307                    "Used to select the direction of implicit movement of the data position relative to the character ",
2308                    "position. Remains in effect until the next occurrence of SIMD. {}"
2309                ),
2310                self.short_description()
2311            ),
2312            Function::SL => format!(
2313                concat!(
2314                    "Causes the data in the presentation component to be moved by {} character positions if the line ",
2315                    "orientation is horizontal, or by {} line positions if the line orientation is vertical, such ",
2316                    "that the data appear to move to the left. The active presentation position is not affected by ",
2317                    "this control function."
2318                ),
2319                param!(self, 0, 1),
2320                param!(self, 0, 1)
2321            ),
2322            Function::SLH => format!(
2323                concat!(
2324                    "If the 'Device Component Select Mode' (DCSM) is set to 'Presentation', this is used to establish ",
2325                    "at character position {} in the active line (the line that contains the active presentation ",
2326                    "position) and lines of subsequent text in the presentation component, the position to which the ",
2327                    "active presentation position will be moved by subsequent occurrences of 'Carriage Return' (CR), ",
2328                    "'Delete Line' (DL), 'Insert Line' (IL) or 'Next Line' (NEL) in the data stream. In the case of a ",
2329                    "device without a data component, it is also the position ahead of which no implicit movement of ",
2330                    "the active presentation position shall occur.",
2331                    "\n\n",
2332                    "If the 'Device Component Select Mode' (DCSM) is set to 'Data', this is used to establish at ",
2333                    "character position {} in the active line (the line that contains the active data position) and ",
2334                    "lines of subsequent text in the data component, the position to which the active data position ",
2335                    "will be moved by subsequent occurrences of 'Carriage Return' (CR), 'Delete Line' (DL), 'Insert ",
2336                    "Line' (IL), or 'Next Line' (NEL) in the data stream. It is also the position ahead of which no ",
2337                    "implicit movement of the active data position shall occur.",
2338                    "\n\n",
2339                    "The established position is called the line home position and remains in effect until the next ",
2340                    "occurrence of SLH in the data stream."
2341                ),
2342                param!(self, 0, 0),
2343                param!(self, 0, 0)
2344            ),
2345            Function::SLL => format!(
2346                concat!(
2347                    "If the 'Device Component Select Mode' (DCSM) is set to 'Presentation', this is used to establish ",
2348                    "at character position {} in the active line (the line that contains the active presentation ",
2349                    "position) and lines of subsequent text in the presentation component, the position to which the ",
2350                    "active presentation position will be moved by subsequent occurrences of 'Carriage Return' (CR) ",
2351                    "or 'Next Line' (NEL) in the data stream, if the parameter value of 'Select Implicit Movement ",
2352                    "Direction' (SIMD) is equal to 'Opposite'. In the case of a device without data component, it is ",
2353                    "also the position beyond which no implicit movement of the active presentation position shall ",
2354                    "occur.",
2355                    "\n\n",
2356                    "If the 'Device Component Select Mode' (DSCM) is set to 'Data', this is used to establish at ",
2357                    "character position {} in the active line (the line that contains the active data position) and ",
2358                    "lines of subsequent text in the data component, the position beyond which no implicit movement ",
2359                    "of the active data position shall occur. It is also the position in the data component to which ",
2360                    "the active data position will be moved by subsequent occurrences of 'Carriage Return' (CR) or ",
2361                    "'Next Line' (NEL) in the data stream, if the parameter value of 'Select Implicit Movement ",
2362                    "Direction' (SIMD) is equal to 'Opposite'.",
2363                    "\n\n",
2364                    "The established position is called the line limit position and remains in effect until the next ",
2365                    "occurrence of SLL in the data stream."
2366                ),
2367                param!(self, 0, 0),
2368                param!(self, 0, 0)
2369            ),
2370            Function::SLS => format!(
2371                concat!(
2372                    "Establishes the line spacing for subsequent text. The established spacing remains in effect ",
2373                    "until the next occurrence of SLS or of 'Select Line Spacing' (SVS) in the data stream. {}"
2374                ),
2375                self.short_description()
2376            ),
2377            Function::SM =>
2378                self.parameters.iter().map(|value| {
2379                    value.parse::<Mode>().expect("Expect only valid Modes").explain_set()
2380                }).fold(String::new(), |mut modes, mode| {
2381                    modes.push_str(", ");
2382                    modes.push_str(&mode);
2383                    modes
2384                }
2385            ),
2386            Function::SPH => format!(
2387                concat!(
2388                    "If the 'Device Component Select Mode' (DCSM) is set to 'Presentation', this is used to establish ",
2389                    "at line position {} in the active page (the page that contains the active presentation position) ",
2390                    "and subsequent pages in the presentation component, the position to which the active ",
2391                    "presentation position will be moved by subsequent occurrences of 'Form Feed' (FF) in the data ",
2392                    "stream. In the case of a device without data component, it is also the position ahead of which ",
2393                    "no implicit movement of the active presentation position shall occur.",
2394                    "\n\n",
2395                    "If the 'Device Component Select Mode' (DCSM) is set to 'Data', this is used to establish at line ",
2396                    "position {} in the active page (the page that contains the active data position) and subsequent ",
2397                    "pages in the data component, the position to which the active data position will be moved by ",
2398                    "subsequent occurrences of 'Form Feed' (FF) in the data stream. It is also the position ahead of ",
2399                    "which no implicit movement of the active presentation position shall occur.",
2400                    "\n\n",
2401                    "The established position is called the page home position and remains in effect until the next ",
2402                    "occurrence of SPH in the data stream."
2403                ),
2404                param!(self, 0, 0),
2405                param!(self, 0, 0)
2406            ),
2407            Function::SPI => format!(
2408                concat!(
2409                    "Used to establish the line spacing and the character spacing for subsequent text. The ",
2410                    "established line spacing remains in effect until the next occurrence of SPI or 'Set Line ",
2411                    "Spacing' (SLS) or of 'Select Line Spacing' (SVS) in the data stream. The established character ",
2412                    "spacing remains in effect until the next occurrence of 'Set Character Spacing' (SCS) or of ",
2413                    "'Select Character Spacing' (SHS) in the data stream.",
2414                    "\n\n",
2415                    "Line spacing is set to {}, character spacing is set to {}, expressed in the unit that is ",
2416                    "established by 'Select Size Unit' (SSU)."
2417
2418                ),
2419                param!(self, 0, 0),
2420                param!(self, 1, 0)
2421            ),
2422            Function::SPL => format!(
2423                concat!(
2424                    "If the 'Device Component Select Mode' (DCSM) is set to 'Presentation', this is used to establish ",
2425                    "at line position {} in the active page (the page that contains the active presentation position) ",
2426                    "and pages of subsequent text in the presentation component, the position beyond which the active ",
2427                    "presentation position can normally not be moved. In the case of a device without data component, ",
2428                    "it is also the position beyond which no implicit movement of the active presentation position ",
2429                    "shall occur.",
2430                    "\n\n",
2431                    "If the 'Device Component Select Mode' (DCSM) is set to 'Data', this is used to establish at line ",
2432                    "position {} in the active page (the page that contains the active data position) and pages of ",
2433                    "subsequent text in the data component, the position beyond which no implicit movement of the ",
2434                    "active data position shall occur.",
2435                    "\n\n",
2436                    "The established position is called the page limit position and remains in effect until the next ",
2437                    "occurrence of SPL in the data stream."
2438                ),
2439                param!(self, 0, 0),
2440                param!(self, 0, 0)
2441            ),
2442            Function::SPQR => format!(
2443                concat!(
2444                    "Select the relative print quality and print speed for devices where the output quality and ",
2445                    "speed are inversely related. The selected value will remain in effect until the next ",
2446                    "occurrence of SPQR. {}"
2447                ),
2448                self.short_description()
2449            ),
2450            Function::SR => format!(
2451                concat!(
2452                    "Causes the data in the presentation component to be moved by {} character positions if the ",
2453                    "line orientation is horizontal, or by {} line positions if the line orientation is ",
2454                    "vertical, such that the data appear to be moved to the right.",
2455                    "\n\n",
2456                    "The active presentation position is not affected by this control function."
2457                ),
2458                param!(self, 0, 1),
2459                param!(self, 0, 1)
2460            ),
2461            Function::SRCS => format!(
2462                concat!(
2463                    "Used to establish reduced inter-character escapement by {} units. The established reduced ",
2464                    "escapement remains in effect until the next occurrence of SRCS or of 'Set Additional ",
2465                    "Character Separation' (SACS) in the data stream or until it is reset to the default value ",
2466                    "by a subsequent occurrence of 'Carriage Return/Line Feed' (CRLF) or of 'Next Line' (NEL) in ",
2467                    "the data stream.",
2468                    "\n\n",
2469                    "The unit in which the escapement is reduced is that established by 'Select Size Unit' (SSU)."
2470                ),
2471                param!(self, 0, 0)
2472            ),
2473            Function::SRS => format!(
2474                concat!(
2475                    "Used to establish in the data component the beginning and the end of a string of ",
2476                    "characters as well as the direction of this string. This direction is opposite to that ",
2477                    "currently established. The indicated string follows the preceding text. The established ",
2478                    "character progression is not affected. {}"
2479                ),
2480                self.short_description()
2481            ),
2482            Function::SSU => format!(
2483                concat!(
2484                    "Used to establish the unit in which the numeric parameters of certain control functions ",
2485                    "are expressed. The establish unit remains in effect until the next occurrence of SSU in ",
2486                    "the data stream. {}"
2487                ),
2488                self.short_description()
2489            ),
2490            Function::SSW => format!(
2491                concat!(
2492                    "Used to establish for subsequent text the character escapement associated with the ",
2493                    "character 'SPACE'. The established escapement remains in effect until the next occurrence ",
2494                    "of SSW in the data stream or until it is reset to the default value by a subsequent ",
2495                    "occurrence of 'Carriage Return/Line Feed' (CRLF), 'Carriage Return/Form Feed' (CRFF), or ",
2496                    "'Next Line' (NEL) in the data stream.",
2497                    "\n\n",
2498                    "{}",
2499                    "\n\n",
2500                    "The unit in which the value is expressed is defined by 'Select Size Unit' (SSU).",
2501                    "\n\n",
2502                    "The default character escapement of 'SPACE' is specified by the most recent occurrence of ",
2503                    "'Set Character Spacing' (SCS) or of 'Select Character Spacing' (SHS) or of 'Select Spacing ",
2504                    "Increment' (SPI) in the data stream if the current font has constant spacing, or is ",
2505                    "specified by the normal width of the character 'SPACE' in the current font if that font ",
2506                    "has proportional spacing."
2507                ),
2508                self.short_description()
2509            ),
2510            Function::STAB => format!(
2511                concat!(
2512                    "{} The use of this control function and means of specifying a list of tabulation stop to ",
2513                    "be referenced by the control function are specified in other standards, for example ISO ",
2514                    "8613-6."
2515                ),
2516                self.short_description()
2517            ),
2518            Function::SU => format!(
2519                concat!(
2520                    "Causes the data in the presentation component to be moved by {} line positions, if the line ",
2521                    "operation is horizontal, or by {} character positions, if the line orientation is vertical, ",
2522                    "such that the data appear to move up. The active presentation position is not affected by ",
2523                    "this control function."
2524                ),
2525                param!(self, 0, 1),
2526                param!(self, 0, 1)
2527            ),
2528            Function::SVS => format!(
2529                concat!(
2530                    "Used to establish the line spacing for subsequent text. {} The established spacing remains ",
2531                    "in effect until the next occurrence of SVS or of 'Set Line Spacing' (SLS) or of 'Spacing ",
2532                    "Increment' (SPI) in the data stream."
2533                ),
2534                explain_selection!(LineSpacing, self, 0)
2535            ),
2536            Function::TAC => format!(
2537                concat!(
2538                    "Causes a character tabulation stop calling for centring to be set at character position {} ",
2539                    "in the active line (the line that contains the active presentation position) and lines of ",
2540                    "subsequent text in the presentation component. TAC causes the replacement of any ",
2541                    "tabulation stop previously set at that character position, but does not affect other ",
2542                    "tabulation stops.",
2543                    "\n\n",
2544                    "A text string centred upon a tabulation stop set by TAC will be positioned so that the ",
2545                    "(trailing edge of the) first graphic character and the (leading edge of the) last graphic ",
2546                    "character are at approximately equal distances from the tabulation stop."
2547                ),
2548                param!(self, 0, 0)
2549            ),
2550            Function::TALE => format!(
2551                concat!(
2552                    "Causes a character tabulation stop calling for leading edge alignment to be set at ",
2553                    "character position {} in the active line (the line that contains the active presentation ",
2554                    "position) and lines of subsequent text in the presentation component. TALE causes the ",
2555                    "replacement of any tabulation stop previously set at that character position, but does not ",
2556                    "affect other tabulation stops.",
2557                    "\n\n",
2558                    "A text string aligned with a tabulation stop set by TALE will be positioned so that the ",
2559                    "(leading edge of the) last graphic character of the string is placed at the tabulation stop."
2560                ),
2561                param!(self, 0, 0)
2562            ),
2563            Function::TATE => format!(
2564                concat!(
2565                    "Causes a character tabulation stop calling for trailing edge alignment to be set at ",
2566                    "character position {} in the active line (the line that contains the active presentation ",
2567                    "position) and lines of subsequent text in the presentation component. TATE causes the ",
2568                    "replacement of any tabulation stop previously set at the character position, but does not ",
2569                    "affect other tabulation stops.",
2570                    "\n\n",
2571                    "A text string aligned with a tabulation stop set by TATE will be positioned so that the ",
2572                    "(trailing edge of the) first graphic character of the string is placed at the tabulation ",
2573                    "stop."
2574                ),
2575                param!(self, 0, 0)
2576            ),
2577            Function::TCC => format!(
2578                concat!(
2579                    "Causes a character tabulation stop calling for alignment of a target graphic character {} ",
2580                    "to be set at character position {} in the active line (the line that contains the active ",
2581                    "presentation position) and lines of subsequent text in the presentation component. TCC ",
2582                    "causes the replacement of any tabulation stop previously set at that character position, ",
2583                    "but does not affect other tabulation stops.",
2584                    "\n\n",
2585                    "The positioning of a text string aligned with a tabulation stop set by TCC will be ",
2586                    "determined by the first occurrence in the string of the target graphic character; that ",
2587                    "character will be centred upon the tabulation stop. If the target character does not occur ",
2588                    "within the string, then the trailing edge of the first character of the string will be ",
2589                    "positioned at the tabulation stop.",
2590                    "\n\n",
2591                    "The value of {} indicates the code table position (binary value) of the target character ",
2592                    "in the currently invoked code. For a 7-bit code, the permissible range of values is 32 ",
2593                    "to 127; for an 8-bit code, the permissible range of values is 32 to 127 and 160 to 255."
2594                ),
2595                param!(self, 1, 32),
2596                param!(self, 0, 0),
2597                param!(self, 1, 32)
2598            ),
2599            Function::TSS => format!(
2600                concat!(
2601                    "Used to establish the width of a thin space for subsequent text to be {} units. The ",
2602                    "established width remains in effect until the next occurrence of TSS in the data stream.",
2603                    "\n\n",
2604                    "The unit in which the parameter is expressed is that established by the value of 'Select ",
2605                    "Size Unit' (SSU)."
2606                ),
2607                param!(self, 0, 0)
2608            ),
2609            _ => self.short_description(),
2610        }
2611    }
2612}
2613
2614impl FromStr for TabulationControl {
2615    type Err = Infallible;
2616
2617    fn from_str(s: &str) -> Result<Self, Self::Err> {
2618        Ok(match s {
2619            "1" => Self::SetLineTabulationStop,
2620            "2" => Self::ClearCharacterTabulationStop,
2621            "3" => Self::ClearLineTabulationStop,
2622            "4" => Self::ClearCharacterTabulationStopsInLine,
2623            "5" => Self::ClearAllCharacterTabulationStops,
2624            "6" => Self::ClearLineTabulationStop,
2625            _ => Self::SetCharacterTabulationStop,
2626        })
2627    }
2628}
2629
2630impl ExplainSelection for TabulationControl {
2631    fn explain(&self) -> String {
2632        match self {
2633            Self::SetCharacterTabulationStop => {
2634                String::from("Set a character tabulation at the active position.")
2635            }
2636            Self::SetLineTabulationStop => {
2637                String::from("Set a line tabulation stop at the active line.")
2638            }
2639            Self::ClearCharacterTabulationStop => {
2640                String::from("Clear the character tabulation stop at the active position.")
2641            }
2642            Self::ClearLineTabulationStop => {
2643                String::from("Clear the line tabulation stop at the active line.")
2644            }
2645            Self::ClearCharacterTabulationStopsInLine => {
2646                String::from("Clear all character tabulation stops in the active line.")
2647            }
2648            Self::ClearAllCharacterTabulationStops => {
2649                String::from("Clear all character tabulation stops.")
2650            }
2651            Self::ClearAllLineTabulationStops => String::from("Clear all line tabulation stops."),
2652        }
2653    }
2654}
2655
2656impl FromStr for DeviceAttributes {
2657    type Err = Infallible;
2658
2659    fn from_str(s: &str) -> Result<Self, Self::Err> {
2660        Ok(match s {
2661            "0" => Self::Request,
2662            value @ _ => Self::Identify(
2663                value
2664                    .parse::<u32>()
2665                    .expect("Expected valid Device Attributes."),
2666            ),
2667        })
2668    }
2669}
2670
2671impl ExplainSelection for DeviceAttributes {
2672    fn explain(&self) -> String {
2673        match self {
2674            Self::Request => {
2675                String::from("Request Device Attribute identification from the receiving device.")
2676            }
2677            Self::Identify(v) => {
2678                format!(
2679                    "The device sending this identifies as device with code {}.",
2680                    v
2681                )
2682            }
2683        }
2684    }
2685}
2686
2687impl FromStr for AreaQualification {
2688    type Err = Infallible;
2689
2690    fn from_str(s: &str) -> Result<Self, Self::Err> {
2691        Ok(match s {
2692            "1" => Self::ProtectedGuarded,
2693            "2" => Self::GraphicCharacterInput,
2694            "3" => Self::NumericInput,
2695            "4" => Self::AlphabeticInput,
2696            "5" => Self::InputAlignedRight,
2697            "6" => Self::FillZeros,
2698            "7" => Self::SetCharacterTabulationStop,
2699            "8" => Self::ProtectedUnguarded,
2700            "9" => Self::FillSpaces,
2701            "10" => Self::InputAlignedLeft,
2702            "11" => Self::Reversed,
2703            _ => Self::UnprotectedUnguarded,
2704        })
2705    }
2706}
2707
2708impl ExplainSelection for AreaQualification {
2709    fn explain(&self) -> String {
2710        match self {
2711            Self::UnprotectedUnguarded => String::from("is unprotected an unguarded"),
2712            Self::ProtectedGuarded => String::from("is protected and guarded"),
2713            Self::GraphicCharacterInput => String::from("is a graphic input area"),
2714            Self::NumericInput => String::from("is a numeric input area"),
2715            Self::AlphabeticInput => String::from("is an alphabetic input area"),
2716            Self::InputAlignedRight => {
2717                String::from("has input aligned to the last position of this area")
2718            }
2719            Self::FillZeros => String::from("will be filled with ZEROs"),
2720            Self::SetCharacterTabulationStop => String::from("indicates a beginning of a field"),
2721            Self::ProtectedUnguarded => String::from("is protected and unguarded"),
2722            Self::FillSpaces => String::from("will be filled with SPACEs"),
2723            Self::InputAlignedLeft => {
2724                String::from("has input aligned to the first position of the area")
2725            }
2726            Self::Reversed => {
2727                String::from("has the order of character positions in the input field reversed.")
2728            }
2729        }
2730    }
2731}
2732
2733impl FromStr for DeviceStatusReport {
2734    type Err = Infallible;
2735
2736    fn from_str(s: &str) -> Result<Self, Self::Err> {
2737        Ok(match s {
2738            "1" => Self::BusyRepeat,
2739            "2" => Self::BusyLater,
2740            "3" => Self::MalfunctionRepeat,
2741            "4" => Self::MalfunctionLater,
2742            "5" => Self::RequestDeviceStatusReport,
2743            "6" => Self::RequestActivePositionReport,
2744            _ => Self::Ready,
2745        })
2746    }
2747}
2748
2749impl ExplainSelection for DeviceStatusReport {
2750    fn explain(&self) -> String {
2751        match self {
2752            Self::Ready => String::from(
2753                "The sending device reports to be read and no malfunctions have been detected."
2754            ),
2755            Self::BusyRepeat => String::from(
2756                "The sending device is busy. Another Device Status Report must be requested later."
2757            ),
2758            Self::BusyLater => String::from(
2759                "The sending device is busy. Another Device Status Report will be sent later."
2760            ),
2761            Self::MalfunctionRepeat => String::from(
2762                concat!(
2763                    "Some malfunction has been detected by the sending device. Another Device Status Report must be ",
2764                    "requested later."
2765                )
2766            ),
2767            Self::MalfunctionLater => String::from(
2768                concat!(
2769                    "Some malfunction has been detected by the sending device. Another Device Status Report will ",
2770                    "be sent later."
2771                )
2772            ),
2773            Self::RequestDeviceStatusReport => String::from(
2774                "A device status report is requested."
2775            ),
2776            Self::RequestActivePositionReport => String::from(
2777                concat!(
2778                    "A report of the active presentation position or of the active data position in form of 'Active ",
2779                    "Position Report' (CPR) is requested from the receiving device."
2780                )
2781            )
2782        }
2783    }
2784}
2785
2786impl FromStr for EraseArea {
2787    type Err = Infallible;
2788
2789    fn from_str(s: &str) -> Result<Self, Self::Err> {
2790        Ok(match s {
2791            "1" => Self::BeginToActivePosition,
2792            "2" => Self::BeginToEnd,
2793            _ => Self::ActivePositionToEnd,
2794        })
2795    }
2796}
2797
2798impl ExplainSelection for EraseArea {
2799    fn explain(&self) -> String {
2800        match self {
2801            Self::ActivePositionToEnd => String::from(
2802                "erases the contents of the currently active qualified area from the current position to the end"
2803            ),
2804            Self::BeginToActivePosition => String::from(
2805                concat!(
2806                    "erases the contents of the currently active qualified area from the beginning of format area to ",
2807                    "the current position"
2808                )
2809            ),
2810            Self::BeginToEnd => String::from(
2811                "erases all contents of the currently active qualified area"
2812            ),
2813        }
2814    }
2815}
2816
2817impl FromStr for ErasePage {
2818    type Err = Infallible;
2819
2820    fn from_str(s: &str) -> Result<Self, Self::Err> {
2821        Ok(match s {
2822            "1" => Self::BeginToActivePosition,
2823            "2" => Self::BeginToEnd,
2824            _ => Self::ActivePositionToEnd,
2825        })
2826    }
2827}
2828
2829impl ExplainSelection for ErasePage {
2830    fn explain(&self) -> String {
2831        match self {
2832            Self::ActivePositionToEnd => String::from(
2833                "erases the contents of the currently active page from the current position to the end"
2834            ),
2835            Self::BeginToActivePosition => String::from(
2836                concat!(
2837                    "erases the contents of the currently active page from the beginning of format area to ",
2838                    "the current position"
2839                )
2840            ),
2841            Self::BeginToEnd => String::from(
2842                "erases all contents of the currently active page"
2843            ),
2844        }
2845    }
2846}
2847
2848impl FromStr for EraseField {
2849    type Err = Infallible;
2850
2851    fn from_str(s: &str) -> Result<Self, Self::Err> {
2852        Ok(match s {
2853            "1" => Self::BeginToActivePosition,
2854            "2" => Self::BeginToEnd,
2855            _ => Self::ActivePositionToEnd,
2856        })
2857    }
2858}
2859
2860impl ExplainSelection for EraseField {
2861    fn explain(&self) -> String {
2862        match self {
2863            Self::ActivePositionToEnd => String::from(
2864                "erases the contents of the currently active field from the current position to the end"
2865            ),
2866            Self::BeginToActivePosition => String::from(
2867                concat!(
2868                    "erases the contents of the currently active field from the beginning of format area to ",
2869                    "the current position"
2870                )
2871            ),
2872            Self::BeginToEnd => String::from(
2873                "erases all contents of the currently active field"
2874            ),
2875        }
2876    }
2877}
2878
2879impl FromStr for EraseLine {
2880    type Err = Infallible;
2881
2882    fn from_str(s: &str) -> Result<Self, Self::Err> {
2883        Ok(match s {
2884            "1" => Self::BeginToActivePosition,
2885            "2" => Self::BeginToEnd,
2886            _ => Self::ActivePositionToEnd,
2887        })
2888    }
2889}
2890
2891impl ExplainSelection for EraseLine {
2892    fn explain(&self) -> String {
2893        match self {
2894            Self::ActivePositionToEnd => String::from(
2895                "erases the contents of the currently active line from the current position to the end"
2896            ),
2897            Self::BeginToActivePosition => String::from(
2898                concat!(
2899                    "erases the contents of the currently active line from the beginning of format area to ",
2900                    "the current position"
2901                )
2902            ),
2903            Self::BeginToEnd => String::from(
2904                "erases all contents of the currently active line"
2905            ),
2906        }
2907    }
2908}
2909
2910impl FromStr for Font {
2911    type Err = Infallible;
2912
2913    fn from_str(s: &str) -> Result<Self, Self::Err> {
2914        Ok(match s {
2915            "1" => Self::Alternative1,
2916            "2" => Self::Alternative2,
2917            "3" => Self::Alternative3,
2918            "4" => Self::Alternative4,
2919            "5" => Self::Alternative5,
2920            "6" => Self::Alternative6,
2921            "7" => Self::Alternative7,
2922            "8" => Self::Alternative8,
2923            "9" => Self::Alternative9,
2924            _ => Self::Primary,
2925        })
2926    }
2927}
2928
2929impl ExplainSelection for Font {
2930    fn explain(&self) -> String {
2931        match self {
2932            Self::Primary => String::from("primary font"),
2933            Self::Alternative1 => String::from("alternative font 1"),
2934            Self::Alternative2 => String::from("alternative font 2"),
2935            Self::Alternative3 => String::from("alternative font 3"),
2936            Self::Alternative4 => String::from("alternative font 4"),
2937            Self::Alternative5 => String::from("alternative font 5"),
2938            Self::Alternative6 => String::from("alternative font 6"),
2939            Self::Alternative7 => String::from("alternative font 7"),
2940            Self::Alternative8 => String::from("alternative font 8"),
2941            Self::Alternative9 => String::from("alternative font 9"),
2942        }
2943    }
2944}
2945
2946impl FromStr for GraphicCharacterCombination {
2947    type Err = Infallible;
2948
2949    fn from_str(s: &str) -> Result<Self, Self::Err> {
2950        Ok(match s {
2951            "1" => Self::StartOfCombination,
2952            "2" => Self::EndOfCombination,
2953            _ => Self::CombineTwo,
2954        })
2955    }
2956}
2957
2958impl ExplainSelection for GraphicCharacterCombination {
2959    fn explain(&self) -> String {
2960        match self {
2961            Self::CombineTwo => String::from(
2962                "Combine the following two graphic characters into a single symbol."
2963            ),
2964            Self::StartOfCombination => String::from(
2965                concat!(
2966                    "Combine all following graphic characters into a single symbol, until the end of combination of ",
2967                    "characters is indicated."
2968                )
2969            ),
2970            Self::EndOfCombination => String::from(
2971                "Indicates the end of combining all previous graphic characters into a single symbol."
2972            ),
2973        }
2974    }
2975}
2976
2977impl FromStr for IdentifyDeviceControlString {
2978    type Err = Infallible;
2979
2980    fn from_str(s: &str) -> Result<Self, Self::Err> {
2981        Ok(match s {
2982            "0" => Self::Diagnostic,
2983            "1" => Self::DynamicallyRedefinableCharacterSet,
2984            value @ _ => Self::Private(
2985                value
2986                    .parse::<u32>()
2987                    .expect("Expected valid Identify Device Control String."),
2988            ),
2989        })
2990    }
2991}
2992
2993impl ExplainSelection for IdentifyDeviceControlString {
2994    fn explain(&self) -> String {
2995        match self {
2996            Self::Diagnostic => String::from(
2997                concat!(
2998                    "Subsequent 'Device Control Strings' (DCS) are intended for the diagnostic state of the ",
2999                    "'Status Report Transfer Mode'"
3000                )
3001            ),
3002            Self::DynamicallyRedefinableCharacterSet => String::from(
3003                concat!(
3004                    "Subsequent 'Device Control Strings' (DCS) are reserved for dynamically refinable character sets ",
3005                    "according to Standard ECMA-35."
3006                )
3007            ),
3008            Self::Private(_) => String::from(
3009                "Subsequent 'Device Control Strings' (DCS) are for private use."
3010            ),
3011        }
3012    }
3013}
3014
3015impl FromStr for Justification {
3016    type Err = Infallible;
3017
3018    fn from_str(s: &str) -> Result<Self, Self::Err> {
3019        Ok(match s {
3020            "1" => Self::WordFill,
3021            "2" => Self::WordSpace,
3022            "3" => Self::LetterSpace,
3023            "4" => Self::Hyphenation,
3024            "5" => Self::Left,
3025            "6" => Self::Centre,
3026            "7" => Self::Right,
3027            "8" => Self::ItalianHyphenation,
3028            _ => Self::None,
3029        })
3030    }
3031}
3032
3033impl ExplainSelection for Justification {
3034    fn explain(&self) -> String {
3035        match self {
3036            Self::None => {
3037                String::from("The following text is not formatted to a special justification.")
3038            }
3039            Self::WordFill => String::from("The following text uses word-fill justification."),
3040            Self::WordSpace => String::from("The following text uses word-space justification."),
3041            Self::LetterSpace => {
3042                String::from("The following text uses letter-space justification.")
3043            }
3044            Self::Hyphenation => String::from("The following text uses hyphenation justification."),
3045            Self::Left => String::from("The following text is left aligned."),
3046            Self::Centre => String::from("The following text is centred."),
3047            Self::Right => String::from("The following text is right aligned."),
3048            Self::ItalianHyphenation => {
3049                String::from("The following text uses italian hyphenation justification.")
3050            }
3051        }
3052    }
3053}
3054
3055impl FromStr for MediaCopy {
3056    type Err = Infallible;
3057
3058    fn from_str(s: &str) -> Result<Self, Self::Err> {
3059        Ok(match s {
3060            "1" => Self::BeginTransferFromPrimary,
3061            "2" => Self::BeginTransferToSecondary,
3062            "3" => Self::BeginTransferFromSecondary,
3063            "4" => Self::StopRelayPrimary,
3064            "5" => Self::StartRelayPrimary,
3065            "6" => Self::StopRelaySecondary,
3066            "7" => Self::StartRelaySecondary,
3067            _ => Self::BeginTransferToPrimary,
3068        })
3069    }
3070}
3071
3072impl ExplainSelection for MediaCopy {
3073    fn explain(&self) -> String {
3074        match self {
3075            Self::BeginTransferToPrimary => {
3076                String::from("Initiate transfer to a primary auxiliary device.")
3077            }
3078            Self::BeginTransferFromPrimary => {
3079                String::from("Initiate transfer from a primary auxiliary device.")
3080            }
3081            Self::BeginTransferToSecondary => {
3082                String::from("Initiate transfer to a secondary auxiliary device.")
3083            }
3084            Self::BeginTransferFromSecondary => {
3085                String::from("Initiate transfer from a secondary auxiliary device.")
3086            }
3087            Self::StopRelayPrimary => String::from("Stop relay to a primary auxiliary device."),
3088            Self::StartRelayPrimary => String::from("Start relay to a primary auxiliary device."),
3089            Self::StopRelaySecondary => String::from("Stop relay to a secondary auxiliary device."),
3090            Self::StartRelaySecondary => {
3091                String::from("Start relay to a secondary auxiliary device.")
3092            }
3093        }
3094    }
3095}
3096
3097impl FromStr for PresentationExpandContract {
3098    type Err = Infallible;
3099
3100    fn from_str(s: &str) -> Result<Self, Self::Err> {
3101        Ok(match s {
3102            "1" => Self::Expanded,
3103            "2" => Self::Condensed,
3104            _ => Self::Normal,
3105        })
3106    }
3107}
3108
3109impl ExplainSelection for PresentationExpandContract {
3110    fn explain(&self) -> String {
3111        match self {
3112            Self::Normal => String::from("normal mode, as specified by SCS, SHS or SPI"),
3113            Self::Expanded => {
3114                String::from("extended mode, multiplied by a factor not greater than 2")
3115            }
3116            Self::Condensed => {
3117                String::from("condensed mode, multiplied by a factor not less than 0.5")
3118            }
3119        }
3120    }
3121}
3122
3123impl FromStr for PageFormat {
3124    type Err = Infallible;
3125
3126    fn from_str(s: &str) -> Result<Self, Self::Err> {
3127        Ok(match s {
3128            "1" => Self::WideBasicText,
3129            "2" => Self::TallBasicA4,
3130            "3" => Self::WideBasicA4,
3131            "4" => Self::TallLetter,
3132            "5" => Self::WideLetter,
3133            "6" => Self::TallExtendedA4,
3134            "7" => Self::WideExtendedA4,
3135            "8" => Self::TallLegal,
3136            "9" => Self::WideLegal,
3137            "10" => Self::A4ShortLines,
3138            "11" => Self::A4LongLines,
3139            "12" => Self::B5ShortLines,
3140            "13" => Self::B5LongLines,
3141            "14" => Self::B4ShortLines,
3142            "15" => Self::B4LongLines,
3143            _ => Self::TallBasicText,
3144        })
3145    }
3146}
3147
3148impl ExplainSelection for PageFormat {
3149    fn explain(&self) -> String {
3150        match self {
3151            Self::TallBasicText => String::from("Set the page to tall basic communication format."),
3152            Self::WideBasicText => String::from("Set the page to wide basic communication format."),
3153            Self::TallBasicA4 => String::from("Set the page to tall basic A4 format."),
3154            Self::WideBasicA4 => String::from("Set the page to wide basic A4 format."),
3155            Self::TallLetter => String::from("Set the page to north american tall letter format."),
3156            Self::WideLetter => String::from("Set the page to north american wide letter format."),
3157            Self::TallExtendedA4 => String::from("Set the page to tall extended A4 format."),
3158            Self::WideExtendedA4 => String::from("Set the page to wide extended A4 format."),
3159            Self::TallLegal => String::from("Set the page to north american tall legal format."),
3160            Self::WideLegal => String::from("Set the page to north american wide legal format."),
3161            Self::A4ShortLines => String::from("Set the page to A4 short lines format."),
3162            Self::A4LongLines => String::from("Set the page to A4 long lines format."),
3163            Self::B5ShortLines => String::from("Set the page to B5 short lines format."),
3164            Self::B5LongLines => String::from("Set the page to B5 long lines format."),
3165            Self::B4ShortLines => String::from("Set the page to B4 short lines format."),
3166            Self::B4LongLines => String::from("Set the page to B4 long lines format."),
3167        }
3168    }
3169}
3170
3171impl FromStr for ParallelText {
3172    type Err = Infallible;
3173
3174    fn from_str(s: &str) -> Result<Self, Self::Err> {
3175        Ok(match s {
3176            "1" => Self::BeginPrincipal,
3177            "2" => Self::BeginSupplementary,
3178            "3" => Self::BeginJapanesePhonetic,
3179            "4" => Self::BeginChinesePhonetic,
3180            "5" => Self::EndPhonetic,
3181            _ => Self::End,
3182        })
3183    }
3184}
3185
3186impl ExplainSelection for ParallelText {
3187    fn explain(&self) -> String {
3188        match self {
3189            Self::End => String::from(
3190                "End of parallel texts."
3191            ),
3192            Self::BeginPrincipal => String::from(
3193                concat!(
3194                    "Beginning of principal text that should be displayed in parallel with one or more strings of ",
3195                    "supplementary text."
3196                )
3197            ),
3198            Self::BeginSupplementary => String::from(
3199                "Beginning of supplementary text that should be displayed in parallel to the principal text."
3200            ),
3201            Self::BeginJapanesePhonetic => String::from(
3202                concat!(
3203                    "Beginning of supplementary japanese phonetic annotation that should be displayed in parallel to ",
3204                    "the principal text."
3205                )
3206            ),
3207            Self::BeginChinesePhonetic => String::from(
3208                concat!(
3209                    "Beginning of supplementary chinese phonetic annotation that should be displayed in parallel to ",
3210                    "the principal text."
3211                )
3212            ),
3213            Self::EndPhonetic => String::from(
3214                "End of a string of supplementary phonetic annotations."
3215            ),
3216        }
3217    }
3218}
3219
3220impl FromStr for Alignment {
3221    type Err = Infallible;
3222
3223    fn from_str(s: &str) -> Result<Self, Self::Err> {
3224        Ok(match s {
3225            "1" => Self::LineHomeLeader,
3226            "2" => Self::Centre,
3227            "3" => Self::CentreLeader,
3228            "4" => Self::LineLimit,
3229            "5" => Self::LineLimitLeader,
3230            "6" => Self::Justify,
3231            _ => Self::LineHome,
3232        })
3233    }
3234}
3235
3236impl ExplainSelection for Alignment {
3237    fn explain(&self) -> String {
3238        match self {
3239            Self::LineHome => String::from(
3240                "flush to the line home position"
3241            ),
3242            Self::LineHomeLeader => String::from(
3243                "flush to the line home position, margin and fill with leader"
3244            ),
3245            Self::Centre => String::from(
3246                "centred between line home position and line limit position margins"
3247            ),
3248            Self::CentreLeader => String::from(
3249                "centred between line home position and line limit position margins and fill with leader"
3250            ),
3251            Self::LineLimit => String::from(
3252                "flush to the line limit position margin"
3253            ),
3254            Self::LineLimitLeader => String::from(
3255                "flush to the line limit position margin and fill with leader"
3256            ),
3257            Self::Justify => String::from(
3258                "flush to both margins"
3259            ),
3260        }
3261    }
3262}
3263
3264impl FromStr for Mode {
3265    type Err = Infallible;
3266
3267    fn from_str(s: &str) -> Result<Self, Self::Err> {
3268        Ok(match s {
3269            "2" => Self::KeyboardActionMode,
3270            "3" => Self::ControlPresentationMode,
3271            "4" => Self::InsertionReplacementMode,
3272            "5" => Self::StatusReportTransferMode,
3273            "6" => Self::ErasureMode,
3274            "7" => Self::LineEditingMode,
3275            "8" => Self::BiDirectionalSupportMode,
3276            "9" => Self::DeviceComponentSelectMode,
3277            "10" => Self::CharacterEditingMode,
3278            "11" => Self::PositioningUnitMode,
3279            "12" => Self::SendReceiveMode,
3280            "13" => Self::FormatEffectorActionMode,
3281            "14" => Self::FormatEffectorTransferMode,
3282            "15" => Self::MultipleAreaTransferMode,
3283            "16" => Self::TransferTerminationMode,
3284            "17" => Self::StatusReportTransferMode,
3285            "18" => Self::TabulationStopMode,
3286            "21" => Self::GraphicRenditionCombinationMode,
3287            "22" => Self::ZeroDefaultMode,
3288            _ => Self::GuardedAreaTransferMode,
3289        })
3290    }
3291}
3292
3293impl ExplainMode for Mode {
3294    fn name(&self) -> String {
3295        match self {
3296            Self::GuardedAreaTransferMode => String::from("Guarded Area Transfer Mode"),
3297            Self::KeyboardActionMode => String::from("Keyboard Action Mode"),
3298            Self::ControlPresentationMode => String::from("Control Presentation Mode"),
3299            Self::InsertionReplacementMode => String::from("Insertion Replacement Mode"),
3300            Self::StatusReportTransferMode => String::from("Status Report Transfer Mode"),
3301            Self::ErasureMode => String::from("Erasure Mode"),
3302            Self::LineEditingMode => String::from("Line Editing Mode"),
3303            Self::BiDirectionalSupportMode => String::from("Bi-Directional Support Mode"),
3304            Self::DeviceComponentSelectMode => String::from("Device Component Select Mode"),
3305            Self::CharacterEditingMode => String::from("Character Editing Mode"),
3306            Self::PositioningUnitMode => String::from("Positioning Unit Mode"),
3307            Self::SendReceiveMode => String::from("Send Receive Mode"),
3308            Self::FormatEffectorActionMode => String::from("Format Effector Action Mode"),
3309            Self::FormatEffectorTransferMode => String::from("Format Effector Transfer Mode"),
3310            Self::MultipleAreaTransferMode => String::from("Multiple Area Transfer mode"),
3311            Self::TransferTerminationMode => String::from("Transfer Termination Mode"),
3312            Self::SelectedAreaTransferMode => String::from("Selected Area Transfer Mode"),
3313            Self::TabulationStopMode => String::from("Tabulation Stop Mode"),
3314            Self::GraphicRenditionCombinationMode => {
3315                String::from("Graphic Rendition Combination Mode")
3316            }
3317            Self::ZeroDefaultMode => String::from("Zero Default Mode"),
3318        }
3319    }
3320
3321    fn explain_reset(&self) -> String {
3322        match self {
3323            Self::GuardedAreaTransferMode => String::from(
3324                "Only the contents of unguarded areas in an eligible area are transmitted or transferred."
3325            ),
3326            Self::KeyboardActionMode => String::from(
3327                "All or part of the manual input facilities are enabled to be used."
3328            ),
3329            Self::ControlPresentationMode => String::from(
3330                "All control functions are performed as defined."
3331            ),
3332            Self::InsertionReplacementMode => String::from(
3333                concat!(
3334                    "The graphic symbol of a graphic character or a control function, for which a graphical ",
3335                    "representation is required, replaces (or, depending on the implementation, is combined with) the ",
3336                    "graphic symbol imaged at the active presentation position"
3337                )
3338            ),
3339            Self::StatusReportTransferMode => String::from(
3340                "Status reports in the form of 'Device Control String' (DCS) are not generated automatically."
3341            ),
3342            Self::ErasureMode => String::from(
3343                "Only the contents of unprotected areas are affected by an erasure control function."
3344            ),
3345            Self::LineEditingMode => String::from(
3346                concat!(
3347                    "The insertion of a line causes the contents of the active line and the following lines to be ",
3348                    "shifted in the direction of line progression. A line deletion causes the contents of the ",
3349                    "following lines to shifted in the opposite direction of line progression."
3350                )
3351            ),
3352            Self::BiDirectionalSupportMode => String::from(
3353                "Control functions are performed in the data component or the presentation component."
3354            ),
3355            Self::DeviceComponentSelectMode => String::from(
3356                "Certain control functions are performed in the presentation component at the current position."
3357            ),
3358            Self::CharacterEditingMode => String::from(
3359                concat!(
3360                    "The insertion of a character causes the following contents to be shifted in the direction of ",
3361                    "character progression. A character deletion causes the following contents to be shifted in the ",
3362                    "direction opposite of character progression."
3363                )
3364            ),
3365            Self::PositioningUnitMode => String::from(
3366                "The unit for numeric parameters of the position format effectors is one character position."
3367            ),
3368            Self::SendReceiveMode => String::from(
3369                "Data which are locally entered are immediately imaged."
3370            ),
3371            Self::FormatEffectorActionMode => String::from(
3372                "Formator functions are performed immediately and may be stored in addition to being performed."
3373            ),
3374            Self::FormatEffectorTransferMode => String::from(
3375                concat!(
3376                    "Formator functions may be inserted in a data stream to be transmitted or in data to be ",
3377                    "transferred to an auxiliary input/output device."
3378                )
3379            ),
3380            Self::MultipleAreaTransferMode => String::from(
3381                concat!(
3382                    "Only the contents of the selected area which contains the active presentation position are ",
3383                    "eligible to be transmitted or transferred."
3384                )
3385            ),
3386            Self::TransferTerminationMode => String::from(
3387                concat!(
3388                    "Only the contents of the character positions preceding the active presentation position in the ",
3389                    "presentation component are eligible to be transmitted or transferred."
3390                )
3391            ),
3392            Self::SelectedAreaTransferMode => String::from(
3393                "Only the contents of selected areas are eligible to be transmitted or transferred."
3394            ),
3395            Self::TabulationStopMode => String::from(
3396                concat!(
3397                    "Character tabulation stops in the presentation component are set or cleared in the active line ",
3398                    "and in the corresponding character positions of the preceding lines and the following lines."
3399                )
3400            ),
3401            Self::GraphicRenditionCombinationMode => String::from(
3402                concat!(
3403                    "Each occurrence of the control function 'Select Graphic Rendition' (SGR) cancels the effect of ",
3404                    "any preceding occurrence."
3405                )
3406            ),
3407            Self::ZeroDefaultMode => String::from(
3408                "A parameter value of 0 of a control functions means the number 0."
3409            ),
3410        }
3411    }
3412
3413    fn explain_set(&self) -> String {
3414        match self {
3415            Self::GuardedAreaTransferMode => String::from(
3416                concat!(
3417                    "The contents of guarded as well as of unguarded areas in an eligible area are transmitted or ",
3418                    "transferred."
3419                )
3420            ),
3421            Self::KeyboardActionMode => String::from(
3422                "All or part of the manual input facilities are disabled."
3423            ),
3424            Self::ControlPresentationMode => String::from(
3425                "All control functions, except 'Reset Mode' are treated as graphic characters."
3426            ),
3427            Self::InsertionReplacementMode => String::from(
3428                concat!(
3429                    "The graphic symbol of a graphic character or a control function, for which a graphical ",
3430                    "representation is required,is inserted at the active presentation position."
3431                )
3432            ),
3433            Self::StatusReportTransferMode => String::from(
3434                concat!(
3435                    "Status reports in the form of 'Device Control String' (DCS) are included in every data stream ",
3436                    "transmitted or transferred."
3437                )
3438            ),
3439            Self::ErasureMode => String::from(
3440                "Only the contents of protected as well as protected areas are affected by an erasure control function."
3441            ),
3442            Self::LineEditingMode => String::from(
3443                concat!(
3444                    "The insertion of a line causes the contents of the active line and the following lines to be ",
3445                    "shifted in the direction of line progression. A line deletion causes the contents of the ",
3446                    "following lines to shifted in the opposite direction of line progression."
3447                )
3448            ),
3449            Self::BiDirectionalSupportMode => String::from(
3450                concat!(
3451                    "Control functions are performed in the data component. All bi-directional aspects of data are ",
3452                    "handled by the device itself."
3453                )
3454            ),
3455            Self::DeviceComponentSelectMode => String::from(
3456                "Certain control functions are performed in the data component at the current position."
3457            ),
3458            Self::CharacterEditingMode => String::from(
3459                concat!(
3460                    "The insertion of a character causes the following contents to be shifted in the direction ",
3461                    "opposite of character progression. A character deletion causes the following contents to be ",
3462                    "shifted in the direction of character progression."
3463                )
3464            ),
3465            Self::PositioningUnitMode => String::from(
3466                concat!(
3467                    "The unit for numeric parameters of the position format effectors is that established by 'Select ",
3468                    "Size Unit' (SSU)."
3469                )
3470            ),
3471            Self::SendReceiveMode => String::from(
3472                "Local input facilities are logically disconnected from the output mechanism."
3473            ),
3474            Self::FormatEffectorActionMode => String::from(
3475                "Formator functions are stored but not performed."
3476            ),
3477            Self::FormatEffectorTransferMode => String::from(
3478                concat!(
3479                    "No formator functions other than those received while the 'Format Effector Action Mode' (FEAM) ",
3480                    "is set to 'Store' are included in a transmitted data stream."
3481                )
3482            ),
3483            Self::MultipleAreaTransferMode => String::from(
3484                "The contents of all selected areas are eligible to be transmitted or transferred."
3485            ),
3486            Self::TransferTerminationMode => String::from(
3487                concat!(
3488                    "The contents of character positions preceding, following, and at the active position are ",
3489                    "eligible to be transmitted or transferred."
3490                )
3491            ),
3492            Self::SelectedAreaTransferMode => String::from(
3493                concat!(
3494                    "The contents of all character positions, irrespective of any explicitly defined selected areas, ",
3495                    "are eligible to be transmitted or transferred."
3496                )
3497            ),
3498            Self::TabulationStopMode => String::from(
3499                "Character tabulation stops in the presentation component are set or cleared in the active line only."
3500            ),
3501            Self::GraphicRenditionCombinationMode => String::from(
3502                concat!(
3503                    "Each occurrence of the control function 'Select Graphic Rendition' (SGR) cancels only those ",
3504                    "graphic rendition aspects to be changed that are specified by that SGR. All other graphic ",
3505                    "rendition aspects remain unchanged."
3506                )
3507            ),
3508            Self::ZeroDefaultMode => String::from(
3509                "A parameter value of 0 of a control functions means a default value that might be different from 0."
3510            ),
3511        }
3512    }
3513}
3514
3515impl FromStr for PresentationVariant {
3516    type Err = Infallible;
3517
3518    fn from_str(s: &str) -> Result<Self, Self::Err> {
3519        Ok(match s {
3520            "1" => Self::LatinDecimals,
3521            "2" => Self::ArabicDecimals,
3522            "3" => Self::MirrorPairs,
3523            "4" => Self::MirrorFormulae,
3524            "5" => Self::Isolated,
3525            "6" => Self::Initial,
3526            "7" => Self::Medial,
3527            "8" => Self::Final,
3528            "9" => Self::DecimalFullStop,
3529            "10" => Self::DecimalComma,
3530            "11" => Self::VowelAboveOrBelow,
3531            "12" => Self::VowelAfterPreceding,
3532            "13" => Self::ContextualShapeArabicScriptWithLamAleph,
3533            "14" => Self::ContextualShapeArabicScript,
3534            "15" => Self::NoMirroring,
3535            "16" => Self::NoVowels,
3536            "17" => Self::SlantFollowsStringDirection,
3537            "18" => Self::NoContextualShapeArabicScript,
3538            "19" => Self::NoContextualShapeArabicScriptExceptDigits,
3539            "20" => Self::DeviceDependentDecimalDigits,
3540            "21" => Self::PersistCharacterForm,
3541            "22" => Self::DesistCharacterForm,
3542            _ => Self::Default,
3543        })
3544    }
3545}
3546
3547impl ExplainSelection for PresentationVariant {
3548    fn explain(&self) -> String {
3549        match self {
3550            Self::Default => String::from(
3551                "Default presentation. Cancels the effect of any other preceding SAPV."
3552            ),
3553            Self::LatinDecimals => String::from(
3554                "The decimal digits are presented by means of the graphic symbols used in the Latin script."
3555            ),
3556            Self::ArabicDecimals => String::from(
3557                concat!(
3558                    "The decimal digits are presented by means of the graphic symbols used in the Arabic script, i.e. ",
3559                    "the Hindi symbols."
3560                )
3561            ),
3562            Self::MirrorPairs => String::from(
3563                concat!(
3564                    "When the direction of the character path is right-to-left, each of the graphic characters in the ",
3565                    "character set(s) in use which is one of a left/right handed pair (parenthesis, square brackets, ",
3566                    "curly brackets, greater-than/less-than signs, etc.) is presented as mirrored"
3567                )
3568            ),
3569            Self::MirrorFormulae => String::from(
3570                concat!(
3571                    "When the direction of the character path is right-to-left, all graphic characters which ",
3572                    "represent operators and delimiters in mathematical formulae and which are not symmetrical about ",
3573                    "a vertical axis are presented as mirrored about that vertical axis."
3574                )
3575            ),
3576            Self::Isolated => String::from(
3577                "The following graphic character is presented in its isolated form."
3578            ),
3579            Self::Initial => String::from(
3580                "The following graphic character is presented in its initial form."
3581            ),
3582            Self::Medial => String::from(
3583                "The following graphic character is presented in its medial form."
3584            ),
3585            Self::Final => String::from(
3586                "The following graphic character is presented in its final form."
3587            ),
3588            Self::DecimalFullStop => String::from(
3589                concat!(
3590                    "Where the bit combination 02/14 (FULL STOP) is intended to represent a decimal mark in a decimal ",
3591                    "number it shall be represented by means of the graphic symbol FULL STOP."
3592                )
3593            ),
3594            Self::DecimalComma => String::from(
3595                concat!(
3596                    "Where the bit combination 02/14 (FULL STOP) is intended to represent a decimal mark in a decimal ",
3597                    "number it shall be presented by means of the graphic symbol COMMA."
3598                )
3599            ),
3600            Self::VowelAboveOrBelow => String::from(
3601                "Vowels are presented above or below the preceding character."
3602            ),
3603            Self::VowelAfterPreceding => String::from(
3604                "Vowels are presented after the preceding character."
3605            ),
3606            Self::ContextualShapeArabicScriptWithLamAleph => String::from(
3607                concat!(
3608                    "Contextual shap determination of Arabic scripts, including the LAM-ALEPH ligature but excluding ",
3609                    "all other Arabic ligatures."
3610                )
3611            ),
3612            Self::ContextualShapeArabicScript => String::from(
3613                "Contextual shape determination of Arabic scripts, excluding all Arabic ligatures."
3614            ),
3615            Self::NoMirroring => String::from(
3616                "Cancels the effect of mirroring settings."
3617            ),
3618            Self::NoVowels => String::from(
3619                "Vowels are not presented."
3620            ),
3621            Self::SlantFollowsStringDirection => String::from(
3622                concat!(
3623                    "When the string direction is right-to-left, the italicized characters are slanted to the left, ",
3624                    "when the string direction is left-to-right, the italicized characters are slanted to the left."
3625                )
3626            ),
3627            Self::NoContextualShapeArabicScript => String::from(
3628                concat!(
3629                    "Contextual shape determination of Arabic scripts is not used, the graphic characters - including ",
3630                    "the digits - are presented in the form they are stored (pass-through)."
3631                )
3632            ),
3633            Self::NoContextualShapeArabicScriptExceptDigits => String::from(
3634                concat!(
3635                    "Contextual shape determination of Arabic scripts is not used, the graphic characters - excluding ",
3636                    "the digits - are presented in the form they are stored (pass-through)."
3637                )
3638            ),
3639            Self::DeviceDependentDecimalDigits => String::from(
3640                "The graphic symbols used to present the decimal digits are device dependent."
3641            ),
3642            Self::PersistCharacterForm => String::from(
3643                concat!(
3644                    "Establishes the effect of parameter values 'Isolated', 'Initial, 'Medial', and 'Final' for the ",
3645                    "following graphic characters until cancelled."
3646                )
3647            ),
3648            Self::DesistCharacterForm => String::from(
3649                concat!(
3650                    "Establishes the effect of parameter values 'Isolated', 'Initial', 'Medial', and 'Final' for the ",
3651                    "next single graphic character only."
3652                )
3653            ),
3654        }
3655    }
3656}
3657
3658impl FromStr for CharacterOrientation {
3659    type Err = Infallible;
3660
3661    fn from_str(s: &str) -> Result<Self, Self::Err> {
3662        Ok(match s {
3663            "1" => Self::Rotate45,
3664            "2" => Self::Rotate90,
3665            "3" => Self::Rotate135,
3666            "4" => Self::Rotate180,
3667            "5" => Self::Rotate225,
3668            "6" => Self::Rotate270,
3669            "7" => Self::Rotate315,
3670            _ => Self::Normal,
3671        })
3672    }
3673}
3674
3675impl ExplainSelection for CharacterOrientation {
3676    fn explain(&self) -> String {
3677        match self {
3678            Self::Normal => String::from("Rotate by 0°."),
3679            Self::Rotate45 => String::from("Rotate by 45°."),
3680            Self::Rotate90 => String::from("Rotate by 90°."),
3681            Self::Rotate135 => String::from("Rotate by 135°."),
3682            Self::Rotate180 => String::from("Rotate by 180°."),
3683            Self::Rotate225 => String::from("Rotate by 225°."),
3684            Self::Rotate270 => String::from("Rotate by 270°."),
3685            Self::Rotate315 => String::from("Rotate by 315°."),
3686        }
3687    }
3688}
3689
3690impl FromStr for CharacterPath {
3691    type Err = Infallible;
3692
3693    fn from_str(s: &str) -> Result<Self, Self::Err> {
3694        Ok(match s {
3695            "2" => Self::RightToLeft,
3696            _ => Self::LefToRight,
3697        })
3698    }
3699}
3700
3701impl ExplainSelection for CharacterPath {
3702    fn explain(&self) -> String {
3703        match self {
3704            Self::LefToRight => String::from("Left-to-right, or top-to-bottom."),
3705            Self::RightToLeft => String::from("Right-to-left, or bottom-to-top."),
3706        }
3707    }
3708}
3709
3710impl FromStr for CharacterPathScope {
3711    type Err = Infallible;
3712
3713    fn from_str(s: &str) -> Result<Self, Self::Err> {
3714        Ok(match s {
3715            "1" => Self::InPresentationComponent,
3716            "2" => Self::InDataComponent,
3717            _ => Self::Undefined,
3718        })
3719    }
3720}
3721
3722impl ExplainSelection for CharacterPathScope {
3723    fn explain(&self) -> String {
3724        match self {
3725            CharacterPathScope::Undefined => String::from(
3726                "The scope of the new character path is undefined."
3727            ),
3728            CharacterPathScope::InPresentationComponent => String::from(
3729                concat!(
3730                    "The content of the active line in the presentation component is updated to correspond to the ",
3731                    "content of the active line in the data component according to the newly established character ",
3732                    "path characteristics in the presentation component."
3733                )
3734            ),
3735            CharacterPathScope::InDataComponent => String::from(
3736                concat!(
3737                    "The content of the active line in the data component is updated to correspond to the content of ",
3738                    "the active line in the presentation component according to the newly established character path ",
3739                    "characteristics in the presentation component."
3740                )
3741            ),
3742        }
3743    }
3744}
3745
3746impl FromStr for StringDirection {
3747    type Err = Infallible;
3748
3749    fn from_str(s: &str) -> Result<Self, Self::Err> {
3750        Ok(match s {
3751            "1" => Self::StartLeftToRight,
3752            "2" => Self::StartRightToLeft,
3753            _ => Self::End,
3754        })
3755    }
3756}
3757
3758impl ExplainSelection for StringDirection {
3759    fn explain(&self) -> String {
3760        match self {
3761            Self::End => {
3762                String::from("End of a directed string - re-establish the previous direction.")
3763            }
3764            Self::StartLeftToRight => {
3765                String::from("Start of a directed string, establish the direction left-to-right.")
3766            }
3767            Self::StartRightToLeft => {
3768                String::from("Start of a directed string, establish the direction right-to-left.")
3769            }
3770        }
3771    }
3772}
3773
3774impl FromStr for EditingExtend {
3775    type Err = Infallible;
3776
3777    fn from_str(s: &str) -> Result<Self, Self::Err> {
3778        Ok(match s {
3779            "1" => Self::ActiveLine,
3780            "2" => Self::ActiveField,
3781            "3" => Self::QualifiedArea,
3782            "4" => Self::All,
3783            _ => Self::ActivePage,
3784        })
3785    }
3786}
3787
3788impl ExplainSelection for EditingExtend {
3789    fn explain(&self) -> String {
3790        match self {
3791            Self::ActivePage => String::from("the shifted part is limited to the active page"),
3792            Self::ActiveLine => String::from("the shifted part is limited to the active line"),
3793            Self::ActiveField => String::from("the shifted part is limited to the active field"),
3794            Self::QualifiedArea => {
3795                String::from("the shifted part is limited to the active qualified area")
3796            }
3797            Self::All => String::from("the shifted part is not limited"),
3798        }
3799    }
3800}
3801
3802impl FromStr for Load {
3803    type Err = Infallible;
3804
3805    fn from_str(s: &str) -> Result<Self, Self::Err> {
3806        Ok(match s {
3807            "0" => Self::None,
3808            value @ _ => Self::Bin(
3809                value
3810                    .parse::<u32>()
3811                    .expect("Expected valid value for Load directive"),
3812            ),
3813        })
3814    }
3815}
3816
3817impl ExplainSelection for Load {
3818    fn explain(&self) -> String {
3819        match self {
3820            Self::None => String::from("Eject sheet, no new sheet loaded."),
3821            Self::Bin(bin) => format!("Eject sheet, load a new sheet from bin {}.", bin),
3822        }
3823    }
3824}
3825
3826impl FromStr for Stack {
3827    type Err = Infallible;
3828
3829    fn from_str(s: &str) -> Result<Self, Self::Err> {
3830        Ok(match s {
3831            "0" => Self::None,
3832            value @ _ => Self::Stacker(
3833                value
3834                    .parse::<u32>()
3835                    .expect("Expected valid value for Load directive"),
3836            ),
3837        })
3838    }
3839}
3840
3841impl ExplainSelection for Stack {
3842    fn explain(&self) -> String {
3843        match self {
3844            Self::None => String::from("Eject sheet, no stacker specified."),
3845            Self::Stacker(stacker) => format!("Eject sheet into the stacker {}.", stacker),
3846        }
3847    }
3848}
3849
3850impl FromStr for GraphicRendition {
3851    type Err = Infallible;
3852
3853    fn from_str(s: &str) -> Result<Self, Self::Err> {
3854        Ok(match s {
3855            "1" => Self::HighIntensity,
3856            "2" => Self::LowIntensity,
3857            "3" => Self::Italicized,
3858            "4" => Self::Underlined,
3859            "5" => Self::SlowlyBlinking,
3860            "6" => Self::RapidlyBlinking,
3861            "7" => Self::Negative,
3862            "8" => Self::Concealed,
3863            "9" => Self::CrossedOut,
3864            "10" => Self::PrimaryFont,
3865            "11" => Self::FirstAlternativeFont,
3866            "12" => Self::SecondAlternativeFont,
3867            "13" => Self::ThirdAlternativeFont,
3868            "14" => Self::ForthAlternativeFont,
3869            "15" => Self::FifthAlternativeFont,
3870            "16" => Self::SixthAlternativeFont,
3871            "17" => Self::SeventhAlternativeFont,
3872            "18" => Self::EighthAlternativeFont,
3873            "19" => Self::NinthAlternativeFont,
3874            "20" => Self::Fraktur,
3875            "21" => Self::DoublyUnderlined,
3876            "22" => Self::NormalIntensity,
3877            "23" => Self::NormalStyle,
3878            "24" => Self::NotUnderlined,
3879            "25" => Self::NotBlinking,
3880            "27" => Self::Positive,
3881            "28" => Self::Revealed,
3882            "29" => Self::NotCrossedOut,
3883            "30" => Self::BlackForeground,
3884            "31" => Self::RedForeground,
3885            "32" => Self::GreenForeground,
3886            "33" => Self::YellowForeground,
3887            "34" => Self::BlueForeground,
3888            "35" => Self::MagentaForeground,
3889            "36" => Self::CyanForeground,
3890            "37" => Self::WhiteForeground,
3891            "39" => Self::DefaultForeground,
3892            "40" => Self::BlackBackground,
3893            "41" => Self::RedBackground,
3894            "42" => Self::GreenBackground,
3895            "43" => Self::YellowBackground,
3896            "44" => Self::BlueBackground,
3897            "45" => Self::MagentaBackground,
3898            "46" => Self::CyanBackground,
3899            "47" => Self::WhiteBackground,
3900            "49" => Self::DefaultBackground,
3901            "51" => Self::Framed,
3902            "52" => Self::Encircled,
3903            "53" => Self::Overlined,
3904            "54" => Self::NotFramed,
3905            "55" => Self::NotOverlined,
3906            "60" => Self::IdeogramUnderline,
3907            "61" => Self::IdeogramUnderline,
3908            "62" => Self::IdeogramStressMarking,
3909            "63" => Self::CancelIdeogramRendition,
3910            _ => Self::Default,
3911        })
3912    }
3913}
3914
3915impl ExplainSelection for GraphicRendition {
3916    fn explain(&self) -> String {
3917        match self {
3918            Self::Default => String::from("Default rendition, cancel all effects."),
3919            Self::HighIntensity => String::from("Bold or increased intensity."),
3920            Self::LowIntensity => String::from("Faint, decreased intensity or second color."),
3921            Self::Italicized => String::from("Italicized."),
3922            Self::Underlined => String::from("Singly underlined."),
3923            Self::SlowlyBlinking => String::from("Slowly blinking (less than 150 per minute)."),
3924            Self::RapidlyBlinking => String::from("Rapidly blinking (more than 150 per minute)."),
3925            Self::Negative => String::from("Negative image."),
3926            Self::Concealed => String::from("Concealed characters."),
3927            Self::CrossedOut => {
3928                String::from("Crossed-out (characters still legible but marked as to be deleted).")
3929            }
3930            Self::PrimaryFont => String::from("Primary (default) font."),
3931            Self::FirstAlternativeFont => String::from("First alternative font."),
3932            Self::SecondAlternativeFont => String::from("Second alternative font."),
3933            Self::ThirdAlternativeFont => String::from("Third alternative font."),
3934            Self::ForthAlternativeFont => String::from("Forth alternative font."),
3935            Self::FifthAlternativeFont => String::from("Fifth alternative font."),
3936            Self::SixthAlternativeFont => String::from("Sixth alternative font."),
3937            Self::SeventhAlternativeFont => String::from("Seventh alternative font."),
3938            Self::EighthAlternativeFont => String::from("Eighth alternative font."),
3939            Self::NinthAlternativeFont => String::from("Ninth alternative font."),
3940            Self::Fraktur => String::from("Fraktur (Gothic)."),
3941            Self::DoublyUnderlined => String::from("Doubly underlined."),
3942            Self::NormalIntensity => String::from("Normal intensity or normal color."),
3943            Self::NormalStyle => String::from("Normal style, not italicized, not fraktur."),
3944            Self::NotUnderlined => String::from("Not underlined."),
3945            Self::NotBlinking => String::from("Not blinking."),
3946            Self::Positive => String::from("Positive image."),
3947            Self::Revealed => String::from("Revealed characters."),
3948            Self::NotCrossedOut => String::from("Not crossed out."),
3949            Self::BlackForeground => String::from("Black foreground color."),
3950            Self::RedForeground => String::from("Red foreground color."),
3951            Self::GreenForeground => String::from("Green foreground color."),
3952            Self::YellowForeground => String::from("Yellow foreground color."),
3953            Self::BlueForeground => String::from("Blue foreground color."),
3954            Self::MagentaForeground => String::from("Magenta foreground color."),
3955            Self::CyanForeground => String::from("Cyan foreground color."),
3956            Self::WhiteForeground => String::from("White foreground color."),
3957            Self::DefaultForeground => String::from("Default foreground color."),
3958            Self::BlackBackground => String::from("Black background color."),
3959            Self::RedBackground => String::from("Red background color."),
3960            Self::GreenBackground => String::from("Green background color."),
3961            Self::YellowBackground => String::from("Yellow background color."),
3962            Self::BlueBackground => String::from("Blue background color."),
3963            Self::MagentaBackground => String::from("Magenta background color."),
3964            Self::CyanBackground => String::from("Cyan background color."),
3965            Self::WhiteBackground => String::from("White background color."),
3966            Self::DefaultBackground => String::from("Default background color."),
3967            Self::Framed => String::from("Framed."),
3968            Self::Encircled => String::from("Encircled."),
3969            Self::Overlined => String::from("Overlined."),
3970            Self::NotFramed => String::from("Not Framed."),
3971            Self::NotOverlined => String::from("Not Overlined."),
3972            Self::IdeogramUnderline => String::from("Ideogram underline or right side line."),
3973            Self::IdeogramDoubleUnderline => {
3974                String::from("Ideogram double underline or double line on the right side.")
3975            }
3976            Self::IdeogramStressMarking => String::from("Ideogram stress marking."),
3977            Self::CancelIdeogramRendition => String::from("Cancel Ideogram rendition settings."),
3978        }
3979    }
3980}
3981
3982impl FromStr for CharacterSpacing {
3983    type Err = Infallible;
3984
3985    fn from_str(s: &str) -> Result<Self, Self::Err> {
3986        Ok(match s {
3987            "1" => Self::TwelveCharacters,
3988            "2" => Self::FifteenCharacters,
3989            "3" => Self::SixCharacters,
3990            "4" => Self::ThreeCharacters,
3991            "5" => Self::NineCharacters,
3992            "6" => Self::FourCharacters,
3993            _ => Self::TenCharacters,
3994        })
3995    }
3996}
3997
3998impl ExplainSelection for CharacterSpacing {
3999    fn explain(&self) -> String {
4000        match self {
4001            Self::TenCharacters => {
4002                String::from("Set character spacing to 10 characters per 25.4mm.")
4003            }
4004            Self::TwelveCharacters => {
4005                String::from("Set character spacing to 12 characters per 25.4mm.")
4006            }
4007            Self::FifteenCharacters => {
4008                String::from("Set character spacing to 15 characters per 25.4mm.")
4009            }
4010            Self::SixCharacters => {
4011                String::from("Set character spacing to 6 characters per 25.4mm.")
4012            }
4013            Self::ThreeCharacters => {
4014                String::from("Set character spacing to 3 characters per 25.4mm.")
4015            }
4016            Self::NineCharacters => {
4017                String::from("Set character spacing to 9 characters per 25.4mm.")
4018            }
4019            Self::FourCharacters => {
4020                String::from("Set character spacing to 4 characters per 25.4mm.")
4021            }
4022        }
4023    }
4024}
4025
4026impl FromStr for MovementDirection {
4027    type Err = Infallible;
4028
4029    fn from_str(s: &str) -> Result<Self, Self::Err> {
4030        Ok(match s {
4031            "1" => Self::Opposite,
4032            _ => Self::Normal,
4033        })
4034    }
4035}
4036
4037impl ExplainSelection for MovementDirection {
4038    fn explain(&self) -> String {
4039        match self {
4040            Self::Normal => String::from(
4041                "Implicit movement is in the same direction as that of character progression.",
4042            ),
4043            Self::Opposite => String::from(
4044                "Implicit movement is in the opposite direction as that of character progression.",
4045            ),
4046        }
4047    }
4048}
4049
4050impl FromStr for PresentationDirection {
4051    type Err = Infallible;
4052
4053    fn from_str(s: &str) -> Result<Self, Self::Err> {
4054        Ok(match s {
4055            "1" => Self::VerticalLinesRightToLeftTopToBottom,
4056            "2" => Self::VerticalLinesLeftToRightTopToBottom,
4057            "3" => Self::HorizontalLinesTopToBottomRightToLeft,
4058            "4" => Self::VerticalLinesLeftToRightBottomToTop,
4059            "5" => Self::HorizontalLinesBottomToTopRightToLeft,
4060            "6" => Self::HorizontalLinesBottomToTopLefToRight,
4061            "7" => Self::VerticalLinesRightToLeftBottomToTop,
4062            _ => Self::HorizontalLinesTopToBottomLeftToRight,
4063        })
4064    }
4065}
4066
4067impl ExplainSelection for PresentationDirection {
4068    fn explain(&self) -> String {
4069        match self {
4070            Self::HorizontalLinesTopToBottomLeftToRight => String::from(
4071                "horizontal line orientation, top-to-bottom line progression, left-to-right character path"
4072            ),
4073            Self::VerticalLinesRightToLeftTopToBottom => String::from(
4074                "vertical line orientation, right-to-left line progression, top-to-bottom character path"
4075            ),
4076            Self::VerticalLinesLeftToRightTopToBottom => String::from(
4077                "vertical line orientation, left-to-right line progression, top-to-bottom character path"
4078            ),
4079            Self::HorizontalLinesTopToBottomRightToLeft => String::from(
4080                "horizontal line orientation, top-to-bottom line progression, right-to-left character path"
4081            ),
4082            Self::VerticalLinesLeftToRightBottomToTop => String::from(
4083                "vertical line orientation, left-to-right line progression, bottom-to-top character path"
4084            ),
4085            Self::HorizontalLinesBottomToTopRightToLeft => String::from(
4086                "horizontal line orientation, bottom-to-top line progression, right-to-left character path"
4087            ),
4088            Self::HorizontalLinesBottomToTopLefToRight => String::from(
4089                "horizontal line orientation, bottom-to-top line progression, left-to-right character path"
4090            ),
4091            Self::VerticalLinesRightToLeftBottomToTop => String::from(
4092                "vertical line orientation, right to left line progression, bottom-to-top character path"
4093            ),
4094        }
4095    }
4096}
4097
4098impl FromStr for PresentationDirectionScope {
4099    type Err = Infallible;
4100
4101    fn from_str(s: &str) -> Result<Self, Self::Err> {
4102        Ok(match s {
4103            "1" => Self::InPresentationComponent,
4104            "2" => Self::InDataComponent,
4105            _ => Self::Undefined,
4106        })
4107    }
4108}
4109
4110impl ExplainSelection for PresentationDirectionScope {
4111    fn explain(&self) -> String {
4112        match self {
4113            Self::Undefined => String::from("an undefined scope"),
4114            Self::InPresentationComponent => String::from("the presentation component"),
4115            Self::InDataComponent => String::from("the data component"),
4116        }
4117    }
4118}
4119
4120impl FromStr for PrintQuality {
4121    type Err = Infallible;
4122
4123    fn from_str(s: &str) -> Result<Self, Self::Err> {
4124        Ok(match s {
4125            "1" => Self::MediumQualityMediumSpeed,
4126            "2" => Self::LowQualityHighSpeed,
4127            _ => Self::HighQualityLowSpeed,
4128        })
4129    }
4130}
4131
4132impl ExplainSelection for PrintQuality {
4133    fn explain(&self) -> String {
4134        match self {
4135            Self::HighQualityLowSpeed => String::from("Print in high quality with low speed."),
4136            Self::MediumQualityMediumSpeed => {
4137                String::from("Print in medium quality with medium speed.")
4138            }
4139            Self::LowQualityHighSpeed => String::from("Print in low quality with high speed."),
4140        }
4141    }
4142}
4143
4144impl FromStr for ReversedString {
4145    type Err = Infallible;
4146
4147    fn from_str(s: &str) -> Result<Self, Self::Err> {
4148        Ok(match s {
4149            "1" => Self::Start,
4150            _ => Self::End,
4151        })
4152    }
4153}
4154
4155impl ExplainSelection for ReversedString {
4156    fn explain(&self) -> String {
4157        match self {
4158            Self::End => {
4159                String::from("End of a reversed string; re-establish the previous direction.")
4160            }
4161            Self::Start => String::from("Beginning of a reversed string; reverse the direction."),
4162        }
4163    }
4164}
4165
4166impl FromStr for SizeUnit {
4167    type Err = Infallible;
4168
4169    fn from_str(s: &str) -> Result<Self, Self::Err> {
4170        Ok(match s {
4171            "1" => Self::Millimetre,
4172            "2" => Self::ComputerDecipoint,
4173            "3" => Self::Decidot,
4174            "4" => Self::Mil,
4175            "5" => Self::BasicMeasuringUnit,
4176            "6" => Self::Micrometer,
4177            "7" => Self::Pixel,
4178            "8" => Self::Decipoint,
4179            _ => Self::Character,
4180        })
4181    }
4182}
4183
4184impl ExplainSelection for SizeUnit {
4185    fn explain(&self) -> String {
4186        match self {
4187            Self::Character => {
4188                String::from("Character. The dimension of this unit is device-dependent.")
4189            }
4190            Self::Millimetre => String::from("Millimetre."),
4191            Self::ComputerDecipoint => {
4192                String::from("Computer decipoint (0.03528 mm - 1/720 of 25.4 mm).")
4193            }
4194            Self::Decidot => String::from("Decidot (0.03759 mm - 10/266 mm)."),
4195            Self::Mil => String::from("Mil (0.0254 mm - 1/1000 of 25.4 mm)."),
4196            Self::BasicMeasuringUnit => {
4197                String::from("Basic Measuring Unit (BMU) (0.02117 mm - 1/1200 of 25.4 mm).")
4198            }
4199            Self::Micrometer => String::from("Micrometer (0.001 mm)"),
4200            Self::Pixel => {
4201                String::from("Pixel, the smallest increment that can be specified in the device.")
4202            }
4203            Self::Decipoint => String::from("Decipoint (0.03514mm - 35/996 mm)."),
4204        }
4205    }
4206}
4207
4208impl FromStr for LineSpacing {
4209    type Err = Infallible;
4210
4211    fn from_str(s: &str) -> Result<Self, Self::Err> {
4212        Ok(match s {
4213            "1" => Self::FourLinesPer25,
4214            "2" => Self::ThreeLinesPer25,
4215            "3" => Self::TwelveLinesPer25,
4216            "4" => Self::EightLinesPer25,
4217            "5" => Self::SixLinesPer30,
4218            "6" => Self::FourLinesPer30,
4219            "7" => Self::ThreeLinesPer30,
4220            "8" => Self::TwelveLinesPer30,
4221            "9" => Self::TwoLinesPer25,
4222            _ => Self::SixLinesPer25,
4223        })
4224    }
4225}
4226
4227impl ExplainSelection for LineSpacing {
4228    fn explain(&self) -> String {
4229        match self {
4230            Self::SixLinesPer25 => String::from("Set line spacing to 6 lines per 25 mm."),
4231            Self::FourLinesPer25 => String::from("Set line spacing to 4 lines per 25 mm."),
4232            Self::ThreeLinesPer25 => String::from("Set line spacing to 3 lines per 25 mm."),
4233            Self::TwelveLinesPer25 => String::from("Set line spacing to 12 lines per 25 mm."),
4234            Self::EightLinesPer25 => String::from("Set line spacing to 8 lines per 25 mm."),
4235            Self::SixLinesPer30 => String::from("Set line spacing to 6 lines per 30 mm."),
4236            Self::FourLinesPer30 => String::from("Set line spacing to 4 lines per 30 mm."),
4237            Self::ThreeLinesPer30 => String::from("Set line spacing to 3 lines per 30 mm."),
4238            Self::TwelveLinesPer30 => String::from("Set line spacing to 12 lines per 30 mm."),
4239            Self::TwoLinesPer25 => String::from("Set line spacing to 2 lines per 25 mm."),
4240        }
4241    }
4242}
4243
4244impl FromStr for ClearTabulation {
4245    type Err = Infallible;
4246
4247    fn from_str(s: &str) -> Result<Self, Self::Err> {
4248        Ok(match s {
4249            "1" => Self::LineTabulationStopActiveLine,
4250            "2" => Self::AllCharacterTabulationStopsActiveLine,
4251            "3" => Self::AllCharacterTabulationStops,
4252            "4" => Self::AllTabulationStops,
4253            "5" => Self::AllTabulationStops,
4254            _ => Self::CharacterTabulationStopActivePosition,
4255        })
4256    }
4257}
4258
4259impl ExplainSelection for ClearTabulation {
4260    fn explain(&self) -> String {
4261        match self {
4262            Self::CharacterTabulationStopActivePosition => String::from(
4263                "Clear the character tabulation stop at the active presentation position.",
4264            ),
4265            Self::LineTabulationStopActiveLine => {
4266                String::from("Clear the line tabulation stop at the active line.")
4267            }
4268            Self::AllCharacterTabulationStopsActiveLine => {
4269                String::from("Clear all character tabulation stops at the active line.")
4270            }
4271            Self::AllCharacterTabulationStops => {
4272                String::from("Clear all character tabulation stops.")
4273            }
4274            Self::AllLineTabulationStops => String::from("Clear all line tabulation stops."),
4275            Self::AllTabulationStops => String::from("Clear all tabulation stops."),
4276        }
4277    }
4278}
4279
4280#[cfg(test)]
4281mod tests {
4282    use crate::{c0::CR, explain::Explain};
4283
4284    /// Test the output of short_name
4285    #[test]
4286    fn get_short_name() {
4287        assert_eq!(CR.short_name(), Some("CR"))
4288    }
4289
4290    /// Test the output of long_name
4291    #[test]
4292    fn get_long_name() {
4293        assert_eq!(CR.long_name(), "Carriage Return")
4294    }
4295
4296    /// Test the output of short_description
4297    #[test]
4298    fn get_short_description() {
4299        assert_eq!(CR.short_description(), "Move to the beginning of the line.")
4300    }
4301
4302    /// Test the output of long_description
4303    #[test]
4304    fn get_long_description() {
4305        assert_eq!(CR.long_description(),
4306        concat!(
4307            "Move the cursor to the beginning of the line. The exact meaning depends on the setting of 'Device ",
4308            "Component Select Mode' (DCSM) and on the parameter value of 'Select Implicit Movement Direction' (SIMD).",
4309            "\n\nIf the DCSM is set to 'Presentation' and SIMD is set to 'Normal', it causes the active presentation ",
4310            "position to be moved to the line home position of the same line in the presentation component. The line ",
4311            "home position is established by the parameter value of 'Set Line Home' SLH.\nWith SIMD set to ",
4312            "'Opposite', it causes the active presentation position to be moved to the line limit position of the ",
4313            "same line in the presentation component. The line limit position is established by the parameter value ",
4314            "of 'Set Line Limit' (SLL).\n\nIf the DCSM is set to 'Data' and SIMD is set to 'Normal', it causes the ",
4315            "active data position to be moved to the line home position of the same line in the data component. The ",
4316            "line home position is established by the parameter value of 'Set Line Home' (SLH)\nWith SIMD set to ",
4317            "'Opposite', it causes the active data position to be moved to the line limit position of the same line ",
4318            "in the data component. The line limit position position is established by the parameter value of ",
4319            "'Set Line Limit' (SLL)."
4320        )
4321    )
4322    }
4323}