1use std::io::{self, Write};
16use std::str;
17use smallvec::SmallVec;
18use nom;
19use {Format, CSI};
20
21#[derive(Eq, PartialEq, Clone, Debug)]
22pub enum DEC {
23 AlignmentTest,
24 SaveCursor,
25 RestoreCursor,
26 ApplicationKeypad(bool),
27 BackIndex,
28 ForwardIndex,
29 SaveCursorPosition,
30 RestoreCursorPosition,
31 SelectCharset(u8, Charset),
32 Set(SmallVec<[Mode; CSI::SIZE]>),
33 Reset(SmallVec<[Mode; CSI::SIZE]>),
34 DeleteColumn(u32),
35 InsertColumn(u32),
36 Double(Half),
37 DoubleWidth,
38 SingleWidth,
39 CursorStyle(u8),
40 SoftReset,
41 ResetInitial,
42 SevenBits,
43 EightBits,
44 DefineFunctionKey(u8, String),
45 Unicode(bool),
46
47 ScrollRegion {
48 top: u32,
49 bottom: Option<u32>,
50 },
51}
52
53use self::DEC::*;
54
55impl Format for DEC {
56 fn fmt<W: Write>(&self, mut f: W) -> io::Result<()> {
57 macro_rules! write {
58 (csi $($value:tt)*) => (
59 try!(CSI::$($value)*.fmt(f.by_ref()));
60 );
61
62 (fmt $($value:tt)*) => (
63 try!($($value)*.fmt(f.by_ref()));
64 );
65
66 (code $code:expr) => (
67 try!(f.write_all(&[0x1B, $code - 0x40]));
68 );
69
70 ($string:expr) => (
71 try!(f.write_all($string));
72 );
73 }
74
75 match *self {
76 AlignmentTest =>
77 write!(b"\x1B#8"),
78
79 SaveCursor =>
80 write!(b"\x1B7"),
81
82 RestoreCursor =>
83 write!(b"\x1B8"),
84
85 ApplicationKeypad(true) =>
86 write!(b"\x1B="),
87
88 ApplicationKeypad(false) =>
89 write!(b"\x1B>"),
90
91 BackIndex =>
92 write!(b"\x1B6"),
93
94 ForwardIndex =>
95 write!(b"\x1B9"),
96
97 SaveCursorPosition =>
98 write!(csi Unknown(b's', None, small_vec![])),
99
100 RestoreCursorPosition =>
101 write!(csi Unknown(b'u', None, small_vec![])),
102
103 SelectCharset(group, charset) => {
104 use self::charset::*;
105
106 write!(b"\x1B");
107
108 match group {
109 0 => write!(b"("),
110 1 => write!(b")"),
111 2 => write!(b"*"),
112 3 => write!(b"+"),
113 _ => unreachable!(),
114 }
115
116 try!(f.write_all(match charset {
117 Charset::UserPreferred => b"<",
118
119 Charset::DEC(DEC::Supplemental) => b"%5",
120 Charset::DEC(DEC::Greek) => b"\"?",
121 Charset::DEC(DEC::Hebrew) => b"\"4",
122 Charset::DEC(DEC::Turkish) => b"%0",
123 Charset::DEC(DEC::Cyrillic) => b"&4",
124 Charset::DEC(DEC::Graphic) => b"0",
125 Charset::DEC(DEC::Technical) => b">",
126
127 Charset::NRCS(NRCS::UK) => b"A",
128 Charset::NRCS(NRCS::French) => b"R",
129 Charset::NRCS(NRCS::FrenchCanadian) => b"Q",
130 Charset::NRCS(NRCS::Norwegian) => b"E",
131 Charset::NRCS(NRCS::Finnish) => b"C",
132 Charset::NRCS(NRCS::German) => b"K",
133 Charset::NRCS(NRCS::Italian) => b"Y",
134 Charset::NRCS(NRCS::Swiss) => b"=",
135 Charset::NRCS(NRCS::Swedish) => b"7",
136 Charset::NRCS(NRCS::Spanish) => b"Z",
137 Charset::NRCS(NRCS::Portuguese) => b"%6",
138 Charset::NRCS(NRCS::Greek) => b"\">",
139 Charset::NRCS(NRCS::Hebrew) => b"%=",
140 Charset::NRCS(NRCS::Turkish) => b"%2",
141 Charset::NRCS(NRCS::SCS) => b"%3",
142 Charset::NRCS(NRCS::Russian) => b"&5",
143
144 Charset::ISO(ISO::Latin1) => b"A",
145 Charset::ISO(ISO::Latin2) => b"B",
146 Charset::ISO(ISO::Greek) => b"F",
147 Charset::ISO(ISO::Hebrew) => b"H",
148 Charset::ISO(ISO::Latin5) => b"M",
149 Charset::ISO(ISO::Cyrillic) => b"L",
150 }));
151 }
152
153 Set(ref modes) =>
154 write!(csi Private(b'h', None, modes.iter().map(|&m| Some(m.into())).collect())),
155
156 Reset(ref modes) =>
157 write!(csi Private(b'l', None, modes.iter().map(|&m| Some(m.into())).collect())),
158
159 DeleteColumn(n) =>
160 write!(csi Private(b'~', Some(b'\''), small_vec![Some(n)])),
161
162 InsertColumn(n) =>
163 write!(csi Private(b'}', Some(b'\''), small_vec![Some(n)])),
164
165 Double(Half::Top) =>
166 write!(b"\x1B#3"),
167
168 Double(Half::Bottom) =>
169 write!(b"\x1B#4"),
170
171 DoubleWidth =>
172 write!(b"\x1B#6"),
173
174 SingleWidth =>
175 write!(b"\x1B#5"),
176
177 CursorStyle(id) =>
178 write!(csi Unknown(b'q', Some(b' '), small_vec![Some(id as u32)])),
179
180 SoftReset =>
181 write!(csi Unknown(b'p', Some(b'!'), small_vec![])),
182
183 ResetInitial =>
184 write!(b"\x1Bc"),
185
186 SevenBits =>
187 write!(b"\x1B F"),
188
189 EightBits =>
190 write!(b"\x1B G"),
191
192 DefineFunctionKey(key, ref string) => {
193 write!(&[0x1B, b'Q', key + b'0' - 1]);
194 write!(b"'");
195 write!(string.as_bytes());
196 write!(b"'");
197 }
198
199 Unicode(value) => {
200 write!(b"\x1B%");
201 write!(&[if value { b'G' } else { b'@' }]);
202 }
203
204 ScrollRegion { top, bottom } =>
205 write!(csi Unknown(b'r', None, small_vec![Some(top + 1), bottom.map(|v| v + 1)])),
206 }
207
208 Ok(())
209 }
210}
211
212mod mode;
213pub use self::mode::Mode;
214
215mod half;
216pub use self::half::Half;
217
218pub mod charset;
219pub use self::charset::Charset;
220
221named!(pub parse<DEC>,
222 do_parse!(tag!(b"\x1B") >>
223 res: switch!(take!(1),
224 b"#" => switch!(take!(1),
225 b"3" => call!(DECDHLT) |
226 b"4" => call!(DECDHLB) |
227 b"5" => call!(DECSWL) |
228 b"6" => call!(DECDWL) |
229 b"8" => call!(DECALN)) |
230
231 b" " => switch!(take!(1),
232 b"F" => call!(S7C1T) |
233 b"G" => call!(S8C1T)) |
234
235 b"%" => switch!(take!(1),
236 b"G" => value!(Unicode(true)) |
237 b"@" => value!(Unicode(false))) |
238
239 b"Q" => call!(SCODFK) |
240
241 b"(" => map!(SCS, |c| SelectCharset(0, c)) |
242 b")" => map!(SCS, |c| SelectCharset(1, c)) |
243 b"*" => map!(SCS, |c| SelectCharset(2, c)) |
244 b"+" => map!(SCS, |c| SelectCharset(3, c)) |
245 b"-" => map!(SCS, |c| SelectCharset(1, c)) |
246 b"." => map!(SCS, |c| SelectCharset(2, c)) |
247 b"/" => map!(SCS, |c| SelectCharset(3, c)) |
248
249 b"c" => call!(RIS) |
250
251 b"6" => call!(DECBI) |
252 b"7" => call!(DECSC) |
253 b"8" => call!(DECRC) |
254 b"9" => call!(DECFI) |
255 b"=" => call!(DECKPAM) |
256 b">" => call!(DECKPNM)) >>
257
258 (res)));
259
260named!(DECALN<DEC>,
261 value!(AlignmentTest));
262
263named!(DECBI<DEC>,
264 value!(BackIndex));
265
266named!(DECSC<DEC>,
267 value!(SaveCursor));
268
269named!(DECRC<DEC>,
270 value!(RestoreCursor));
271
272named!(DECFI<DEC>,
273 value!(ForwardIndex));
274
275named!(DECKPAM<DEC>,
276 value!(ApplicationKeypad(true)));
277
278named!(DECKPNM<DEC>,
279 value!(ApplicationKeypad(false)));
280
281named!(DECDHLT<DEC>,
282 value!(Double(Half::Top)));
283
284named!(DECDHLB<DEC>,
285 value!(Double(Half::Bottom)));
286
287named!(DECSWL<DEC>,
288 value!(SingleWidth));
289
290named!(DECDWL<DEC>,
291 value!(DoubleWidth));
292
293named!(RIS<DEC>,
294 value!(ResetInitial));
295
296named!(S7C1T<DEC>,
297 value!(SevenBits));
298
299named!(S8C1T<DEC>,
300 value!(EightBits));
301
302named!(SCODFK<DEC>,
303 do_parse!(
304 key: is_key >>
305 delimiter: take!(1) >>
306 string: take_until!(delimiter) >>
307 tag!(delimiter) >>
308
309 (DefineFunctionKey(key, unsafe { str::from_utf8_unchecked(string) }.into()))));
310
311fn is_key(i: &[u8]) -> nom::IResult<&[u8], u8> {
312 if i.is_empty() {
313 return nom::IResult::Incomplete(nom::Needed::Unknown);
314 }
315
316 let key = i[0];
317
318 if key >= b'0' && key <= b'k' {
319 nom::IResult::Done(&i[1 ..], key - b'0' + 1)
320 }
321 else {
322 nom::IResult::Error(nom::ErrorKind::Custom(0))
323 }
324}
325
326named!(SCS<Charset>,
327 switch!(take!(1),
328 b"<" => value!(Charset::UserPreferred) |
329
330 b">" => value!(charset::DEC::Technical.into()) |
331 b"0" => value!(charset::DEC::Graphic.into()) |
332 b"9" => value!(charset::NRCS::FrenchCanadian.into()) |
333 b"Q" => value!(charset::NRCS::FrenchCanadian.into()) |
334 b"`" => value!(charset::NRCS::Norwegian.into()) |
335 b"E" => value!(charset::NRCS::Norwegian.into()) |
336 b"6" => value!(charset::NRCS::Norwegian.into()) |
337 b"5" => value!(charset::NRCS::Finnish.into()) |
338 b"C" => value!(charset::NRCS::Finnish.into()) |
339 b"7" => value!(charset::NRCS::Swedish.into()) |
340 b"R" => value!(charset::NRCS::French.into()) |
341 b"K" => value!(charset::NRCS::German.into()) |
342 b"Y" => value!(charset::NRCS::Italian.into()) |
343 b"=" => value!(charset::NRCS::Swiss.into()) |
344 b"Z" => value!(charset::NRCS::Spanish.into()) |
345
346 b"A" => value!(charset::ISO::Latin1.into()) |
347 b"B" => value!(charset::ISO::Latin2.into()) |
348 b"F" => value!(charset::ISO::Greek.into()) |
349 b"H" => value!(charset::ISO::Hebrew.into()) |
350 b"M" => value!(charset::ISO::Latin5.into()) |
351 b"L" => value!(charset::ISO::Cyrillic.into()) |
352
353 b"\"" => switch!(take!(1),
354 b"?" => value!(charset::DEC::Greek.into()) |
355 b"4" => value!(charset::DEC::Hebrew.into()) |
356 b">" => value!(charset::NRCS::Greek.into())) |
357
358 b"&" => switch!(take!(1),
359 b"4" => value!(charset::DEC::Cyrillic.into()) |
360 b"5" => value!(charset::NRCS::Russian.into())) |
361
362 b"%" => switch!(take!(1),
363 b"5" => value!(charset::DEC::Supplemental.into()) |
364 b"0" => value!(charset::DEC::Turkish.into()) |
365 b"6" => value!(charset::NRCS::Portuguese.into()) |
366 b"=" => value!(charset::NRCS::Hebrew.into()) |
367 b"2" => value!(charset::NRCS::Turkish.into()) |
368 b"3" => value!(charset::NRCS::SCS.into()))));
369
370pub mod csi;
371pub mod sixel;
372
373pub mod shim {
374 pub use super::DEC as T;
375 pub use super::DEC::*;
376 pub use super::parse;
377 pub use super::csi as CSI;
378 pub use super::sixel::shim as SIXEL;
379 pub use super::{Mode, Charset, Half};
380 pub use super::charset;
381}
382
383#[cfg(test)]
384mod test {
385 mod parse {
386 use {Control, DEC, parse};
387
388 macro_rules! test {
389 ($string:expr => $item:expr) => (
390 assert_eq!(Control::DEC($item),
391 parse($string).unwrap().1);
392 );
393 }
394
395 #[test]
396 fn decdhl() {
397 test!(b"\x1B#3" =>
398 DEC::Double(DEC::Half::Top));
399
400 test!(b"\x1B#4" =>
401 DEC::Double(DEC::Half::Bottom));
402 }
403
404 #[test]
405 fn decswl() {
406 test!(b"\x1B#5" =>
407 DEC::SingleWidth);
408 }
409
410 #[test]
411 fn decdwl() {
412 test!(b"\x1B#6" =>
413 DEC::DoubleWidth);
414 }
415
416 #[test]
417 fn decaln() {
418 test!(b"\x1B#8" =>
419 DEC::AlignmentTest);
420 }
421
422 #[test]
423 fn s7c1t() {
424 test!(b"\x1B F" =>
425 DEC::SevenBits);
426 }
427
428 #[test]
429 fn s8c1t() {
430 test!(b"\x1B G" =>
431 DEC::EightBits);
432 }
433
434 #[test]
435 fn scodfk() {
436 test!(b"\x1BQ0'hue'" =>
437 DEC::DefineFunctionKey(1, "hue".into()));
438
439 test!(b"\x1BQaahuea" =>
440 DEC::DefineFunctionKey(50, "hue".into()));
441 }
442
443 #[test]
444 fn scs() {
445 test!(b"\x1B(A" =>
446 DEC::SelectCharset(0, DEC::Charset::ISO(DEC::charset::ISO::Latin1)));
447
448 test!(b"\x1B)A" =>
449 DEC::SelectCharset(1, DEC::Charset::ISO(DEC::charset::ISO::Latin1)));
450
451 test!(b"\x1B*A" =>
452 DEC::SelectCharset(2, DEC::Charset::ISO(DEC::charset::ISO::Latin1)));
453
454 test!(b"\x1B+A" =>
455 DEC::SelectCharset(3, DEC::Charset::ISO(DEC::charset::ISO::Latin1)));
456
457 test!(b"\x1B-A" =>
458 DEC::SelectCharset(1, DEC::Charset::ISO(DEC::charset::ISO::Latin1)));
459
460 test!(b"\x1B.A" =>
461 DEC::SelectCharset(2, DEC::Charset::ISO(DEC::charset::ISO::Latin1)));
462
463 test!(b"\x1B/A" =>
464 DEC::SelectCharset(3, DEC::Charset::ISO(DEC::charset::ISO::Latin1)));
465 }
466
467 #[test]
468 fn ris() {
469 test!(b"\x1Bc" =>
470 DEC::ResetInitial);
471 }
472
473 #[test]
474 fn decbi() {
475 test!(b"\x1B6" =>
476 DEC::BackIndex);
477 }
478
479 #[test]
480 fn decsc() {
481 test!(b"\x1B7" =>
482 DEC::SaveCursor);
483 }
484
485 #[test]
486 fn decrc() {
487 test!(b"\x1B8" =>
488 DEC::RestoreCursor);
489 }
490
491 #[test]
492 fn decfi() {
493 test!(b"\x1B9" =>
494 DEC::ForwardIndex);
495 }
496
497 #[test]
498 fn deckpam() {
499 test!(b"\x1B=" =>
500 DEC::ApplicationKeypad(true));
501 }
502
503 #[test]
504 fn deckpnm() {
505 test!(b"\x1B>" =>
506 DEC::ApplicationKeypad(false));
507 }
508
509 #[test]
510 fn decstbm() {
511 test!(b"\x1B[r" =>
512 DEC::ScrollRegion { top: 0, bottom: None });
513
514 test!(b"\x1B[0;0r" =>
515 DEC::ScrollRegion { top: 0, bottom: None });
516
517 test!(b"\x1B[21;23r" =>
518 DEC::ScrollRegion { top: 20, bottom: Some(22) });
519 }
520
521 #[test]
522 fn decscusr() {
523 test!(b"\x1B[ q" =>
524 DEC::CursorStyle(0));
525
526 test!(b"\x1B[3 q" =>
527 DEC::CursorStyle(3));
528 }
529
530 #[test]
531 fn decstr() {
532 test!(b"\x1B[!p" =>
533 DEC::SoftReset);
534 }
535
536 #[test]
537 fn unicode() {
538 test!(b"\x1B%G" =>
539 DEC::Unicode(true));
540
541 test!(b"\x1B%@" =>
542 DEC::Unicode(false));
543 }
544 }
545
546 mod format {
547 use {Control, DEC, format, parse};
548
549 macro_rules! test {
550 ($code:expr) => (
551 let item = Control::DEC($code);
552 assert_eq!(item, parse(&format(&item)).unwrap().1);
553 );
554 }
555
556 #[test]
557 fn decdhl() {
558 test!(DEC::Double(DEC::Half::Top));
559 test!(DEC::Double(DEC::Half::Bottom));
560 }
561
562 #[test]
563 fn decswl() {
564 test!(DEC::SingleWidth);
565 }
566
567 #[test]
568 fn decdwl() {
569 test!(DEC::DoubleWidth);
570 }
571
572 #[test]
573 fn decaln() {
574 test!(DEC::AlignmentTest);
575 }
576
577 #[test]
578 fn s7c1t() {
579 test!(DEC::SevenBits);
580 }
581
582 #[test]
583 fn s8c1t() {
584 test!(DEC::EightBits);
585 }
586
587 #[test]
588 fn scodfk() {
589 test!(DEC::DefineFunctionKey(1, "hue".into()));
590 test!(DEC::DefineFunctionKey(50, "hue".into()));
591 }
592
593 #[test]
594 fn scs() {
595 test!(DEC::SelectCharset(0, DEC::Charset::ISO(DEC::charset::ISO::Latin1)));
596 test!(DEC::SelectCharset(1, DEC::Charset::ISO(DEC::charset::ISO::Latin1)));
597 test!(DEC::SelectCharset(2, DEC::Charset::ISO(DEC::charset::ISO::Latin1)));
598 test!(DEC::SelectCharset(3, DEC::Charset::ISO(DEC::charset::ISO::Latin1)));
599 test!(DEC::SelectCharset(1, DEC::Charset::ISO(DEC::charset::ISO::Latin1)));
600 test!(DEC::SelectCharset(2, DEC::Charset::ISO(DEC::charset::ISO::Latin1)));
601 test!(DEC::SelectCharset(3, DEC::Charset::ISO(DEC::charset::ISO::Latin1)));
602 }
603
604 #[test]
605 fn ris() {
606 test!(DEC::ResetInitial);
607 }
608
609 #[test]
610 fn decbi() {
611 test!(DEC::BackIndex);
612 }
613
614 #[test]
615 fn decsc() {
616 test!(DEC::SaveCursor);
617 }
618
619 #[test]
620 fn decrc() {
621 test!(DEC::RestoreCursor);
622 }
623
624 #[test]
625 fn decfi() {
626 test!(DEC::ForwardIndex);
627 }
628
629 #[test]
630 fn deckpam() {
631 test!(DEC::ApplicationKeypad(true));
632 }
633
634 #[test]
635 fn deckpnm() {
636 test!(DEC::ApplicationKeypad(false));
637 }
638
639 #[test]
640 fn decstbm() {
641 test!(DEC::ScrollRegion { top: 0, bottom: None });
642 test!(DEC::ScrollRegion { top: 20, bottom: Some(22) });
643 }
644
645 #[test]
646 fn unicode() {
647 test!(DEC::Unicode(true));
648 test!(DEC::Unicode(false));
649 }
650
651 #[test]
652 fn decscusr() {
653 test!(DEC::CursorStyle(0));
654 test!(DEC::CursorStyle(3));
655 }
656
657 #[test]
658 fn decstr() {
659 test!(DEC::SoftReset);
660 }
661 }
662}