control_code/dec/
mod.rs

1//            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
2//                    Version 2, December 2004
3//
4// Copyleft (ↄ) meh. <meh@schizofreni.co> | http://meh.schizofreni.co
5//
6// Everyone is permitted to copy and distribute verbatim or modified
7// copies of this license document, and changing it is allowed as long
8// as the name is changed.
9//
10//            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
11//   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
12//
13//  0. You just DO WHAT THE FUCK YOU WANT TO.
14
15use 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}