1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
use arrayvec::ArrayVec;
use sunrise_libkern::MemoryPermissions;
use crate::error::Error;
use crate::mem::PAGE_SIZE;
use crate::types::SharedMemory;
use crate::vi::ViInterfaceProxy;
use crate::utils::align_up;
#[derive(Debug, Clone, Copy)]
pub enum WindowSize {
Fullscreen,
FontLines(i32, bool),
Manual(i32, i32, u32, u32)
}
#[derive(Debug)]
pub struct Terminal {
buffer: ArrayVec<[u8; 256]>,
pipe: crate::twili::IPipeProxy
}
impl Terminal {
#[allow(clippy::cast_sign_loss)]
#[allow(clippy::cast_possible_wrap)]
pub fn new(size: WindowSize) -> Result<Terminal, Error> {
let vi_interface = ViInterfaceProxy::raw_new()?;
let (fullscreen_width, fullscreen_height) = vi_interface.get_screen_resolution()?;
let (top, left, width, height) = match size {
WindowSize::Fullscreen => (0, 0, fullscreen_width, fullscreen_height),
WindowSize::FontLines(lines, is_bottom) => {
let my_linespace = vi_interface.get_font_height()? as usize;
let height = if lines < 0 {
let max_lines = (fullscreen_height as usize) / my_linespace;
my_linespace * ((max_lines as i32) + lines) as usize
} else if lines == 1 {
(my_linespace + 1) as usize
} else {
my_linespace * lines as usize
};
let top = if is_bottom {
(fullscreen_height as usize) - height
} else {
0
};
(top as i32, 0, fullscreen_width, height as u32)
}
WindowSize::Manual(top, left, width, height) => (top, left, width, height)
};
let vi = ViInterfaceProxy::raw_new()?;
let bpp = 32;
let size = height * width * bpp / 8;
let sharedmem = SharedMemory::new(align_up(size, PAGE_SIZE as _) as _, MemoryPermissions::READABLE | MemoryPermissions::WRITABLE, MemoryPermissions::READABLE)?;
let pipe = vi.create_terminal(&sharedmem, top, left, width, height)?;
Ok(Terminal {
pipe,
buffer: ArrayVec::new()
})
}
pub fn draw(&mut self) -> Result<(), Error> {
if !self.buffer.is_empty() {
self.pipe.write(&self.buffer[..])?;
self.buffer.clear();
}
Ok(())
}
pub fn clone_pipe(&self) -> Result<crate::twili::IPipeProxy, Error> {
self.pipe.clone_current_object()
}
pub fn read(&mut self, data: &mut [u8]) -> Result<u64, Error> {
self.pipe.read(data)
}
}
impl core::fmt::Write for Terminal {
fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> {
self.buffer.extend(s.as_bytes().iter().cloned());
if s.contains('\n') {
if let Err(err) = self.draw() {
log::error!("{:?}", err);
return Err(core::fmt::Error);
}
}
Ok(())
}
}
impl core::fmt::Write for crate::twili::IPipeProxy {
fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> {
if let Err(err) = self.write(s.as_bytes()) {
log::error!("{:?}", err);
return Err(core::fmt::Error);
}
Ok(())
}
}