• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Blightmud / Blightmud / 21593863486

02 Feb 2026 02:24PM UTC coverage: 79.391% (-0.1%) from 79.502%
21593863486

push

github

web-flow
Filters ED sequences (Erase in display) from server (#1340)

ED sequences don't respect scroll regions and will mess up blightmuds UI.
To tackle this we now filter them from output and apply their effect
only to the output view.

112 of 160 new or added lines in 6 files covered. (70.0%)

1 existing line in 1 file now uncovered.

8625 of 10864 relevant lines covered (79.39%)

354.25 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

40.0
/src/ui/ui_wrapper.rs
1
use std::{
2
    io::{stdout, Write},
3
    sync::{Arc, Mutex},
4
};
5

6
use crate::{
7
    io::SaveData,
8
    model::{Settings, MOUSE_ENABLED, READER_MODE},
9
    session::Session,
10
    tts::TTSController,
11
};
12

13
use super::{history::History, HeadlessScreen, ReaderScreen, SplitScreen, UserInterface};
14
use anyhow::Result;
15
use termion::{input::MouseTerminal, raw::IntoRawMode, screen::IntoAlternateScreen};
16

17
/// Creates the io::Write terminal handler we draw to.
18
fn create_screen_writer(mouse_support: bool) -> Result<Box<dyn Write>> {
×
19
    let screen = stdout().into_raw_mode()?.into_alternate_screen()?;
×
20
    if mouse_support {
×
21
        Ok(Box::new(MouseTerminal::from(screen)))
×
22
    } else {
23
        Ok(Box::new(screen))
×
24
    }
25
}
×
26

27
pub struct UiWrapper {
28
    screen: Box<dyn UserInterface>,
29
    tts_ctrl: Arc<Mutex<TTSController>>,
30
}
31

32
impl UiWrapper {
33
    pub fn new(session: &Session) -> Result<Self> {
×
34
        let settings = Settings::try_load()?;
×
35
        let reader_mode = settings.get(READER_MODE)?;
×
36
        let screen: Box<dyn UserInterface> = if reader_mode {
×
37
            Box::new(ReaderScreen::new(
×
38
                create_screen_writer(false)?,
×
39
                History::new(),
×
40
            )?)
×
41
        } else {
42
            Box::new(SplitScreen::new(
×
43
                create_screen_writer(settings.get(MOUSE_ENABLED)?)?,
×
44
                History::new(),
×
45
            )?)
×
46
        };
47
        let tts_ctrl = session.tts_ctrl.clone();
×
48

49
        Ok(Self { screen, tts_ctrl })
×
50
    }
×
51

52
    pub fn new_from(
×
53
        screen: Box<dyn UserInterface>,
×
54
        session: &Session,
×
55
        reader_mode: bool,
×
56
    ) -> Result<Self> {
×
57
        let (writer, history) = screen.destroy()?;
×
58
        let mut screen: Box<dyn UserInterface> = if reader_mode {
×
59
            Box::new(ReaderScreen::new(writer, history)?)
×
60
        } else {
61
            Box::new(SplitScreen::new(writer, history)?)
×
62
        };
63
        screen.setup()?;
×
64
        Ok(Self {
×
65
            screen,
×
66
            tts_ctrl: session.tts_ctrl.clone(),
×
67
        })
×
68
    }
×
69

70
    pub fn headless(session: &Session) -> Result<Self> {
91✔
71
        Ok(Self {
91✔
72
            screen: Box::new(HeadlessScreen {}),
91✔
73
            tts_ctrl: session.tts_ctrl.clone(),
91✔
74
        })
91✔
75
    }
91✔
76
}
77

78
impl UserInterface for UiWrapper {
79
    fn setup(&mut self) -> Result<()> {
91✔
80
        self.screen.setup()
91✔
81
    }
91✔
82

83
    fn print_error(&mut self, output: &str) {
42✔
84
        self.tts_ctrl.lock().unwrap().speak_error(output);
42✔
85
        self.screen.print_error(output);
42✔
86
    }
42✔
87

88
    fn print_info(&mut self, output: &str) {
308✔
89
        self.tts_ctrl.lock().unwrap().speak_info(output);
308✔
90
        self.screen.print_info(output);
308✔
91
    }
308✔
92

93
    fn print_output(&mut self, line: &crate::model::Line) {
161✔
94
        self.tts_ctrl.lock().unwrap().speak_line(line);
161✔
95
        self.screen.print_output(line);
161✔
96
    }
161✔
97

98
    fn print_prompt(&mut self, prompt: &crate::model::Line) {
84✔
99
        self.tts_ctrl.lock().unwrap().speak_line(prompt);
84✔
100
        self.screen.print_prompt(prompt);
84✔
101
    }
84✔
102

103
    fn print_prompt_input(&mut self, input: &str, pos: usize) {
×
104
        self.screen.print_prompt_input(input, pos);
×
105
    }
×
106

107
    fn print_send(&mut self, send: &crate::model::Line) {
42✔
108
        if let Some(line) = send.print_line() {
42✔
109
            self.tts_ctrl.lock().unwrap().speak_input(line);
42✔
110
        }
42✔
111
        self.screen.print_send(send);
42✔
112
    }
42✔
113

114
    fn reset(&mut self) -> Result<()> {
91✔
115
        self.screen.reset()
91✔
116
    }
91✔
117

118
    fn reset_scroll(&mut self) -> Result<()> {
×
119
        self.screen.reset_scroll()
×
120
    }
×
121

NEW
122
    fn clear_output_area(&mut self) -> Result<()> {
×
NEW
123
        self.screen.clear_output_area()
×
NEW
124
    }
×
125

126
    fn scroll_down(&mut self) -> Result<()> {
×
127
        self.screen.scroll_down()
×
128
    }
×
129

130
    fn scroll_lock(&mut self, lock: bool) -> Result<()> {
×
131
        self.screen.scroll_lock(lock)
×
132
    }
×
133

134
    fn scroll_to(&mut self, row: usize) -> Result<()> {
×
135
        self.screen.scroll_to(row)
×
136
    }
×
137

138
    fn scroll_top(&mut self) -> Result<()> {
×
139
        self.screen.scroll_top()
×
140
    }
×
141

142
    fn scroll_up(&mut self) -> Result<()> {
×
143
        self.screen.scroll_up()
×
144
    }
×
145

146
    fn find_up(&mut self, pattern: &crate::model::Regex) -> Result<()> {
×
147
        self.screen.find_up(pattern)
×
148
    }
×
149

150
    fn find_down(&mut self, pattern: &crate::model::Regex) -> Result<()> {
×
151
        self.screen.find_down(pattern)
×
152
    }
×
153

154
    fn set_host(&mut self, host: &str, port: u16) -> Result<()> {
126✔
155
        self.screen.set_host(host, port)
126✔
156
    }
126✔
157

158
    fn add_tag(&mut self, proto: &str) -> Result<()> {
14✔
159
        self.screen.add_tag(proto)
14✔
160
    }
14✔
161

162
    fn remove_tag(&mut self, proto: &str) -> Result<()> {
×
163
        self.screen.remove_tag(proto)
×
164
    }
×
165

166
    fn clear_tags(&mut self) -> Result<()> {
63✔
167
        self.screen.clear_tags()
63✔
168
    }
63✔
169

170
    fn set_status_area_height(&mut self, height: u16) -> Result<()> {
×
171
        self.screen.set_status_area_height(height)
×
172
    }
×
173

174
    fn set_status_line(&mut self, line: usize, info: String) -> Result<()> {
×
175
        self.screen.set_status_line(line, info)
×
176
    }
×
177

178
    fn flush(&mut self) {
1,995✔
179
        self.screen.flush();
1,995✔
180
    }
1,995✔
181

182
    fn width(&self) -> u16 {
21✔
183
        self.screen.width()
21✔
184
    }
21✔
185

186
    fn height(&self) -> u16 {
21✔
187
        self.screen.height()
21✔
188
    }
21✔
189

190
    fn destroy(self: Box<Self>) -> Result<(Box<dyn Write>, History)> {
×
191
        self.screen.destroy()
×
192
    }
×
193
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc