Serenity Operating System
at portability 228 lines 6.7 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#pragma once 28 29#include <AK/String.h> 30#include <AK/NonnullOwnPtrVector.h> 31#include <AK/Vector.h> 32#include <LibVT/Position.h> 33 34namespace VT { 35 36class TerminalClient { 37public: 38 virtual ~TerminalClient() {} 39 40 virtual void beep() = 0; 41 virtual void set_window_title(const StringView&) = 0; 42 virtual void terminal_did_resize(u16 columns, u16 rows) = 0; 43 virtual void terminal_history_changed() = 0; 44 virtual void emit_char(u8) = 0; 45}; 46 47struct Attribute { 48 Attribute() { reset(); } 49 50 static const u8 default_foreground_color = 7; 51 static const u8 default_background_color = 0; 52 53 void reset() 54 { 55 foreground_color = default_foreground_color; 56 background_color = default_background_color; 57 flags = Flags::NoAttributes; 58 } 59 u8 foreground_color; 60 u8 background_color; 61 62 enum Flags : u8 { 63 NoAttributes = 0x00, 64 Bold = 0x01, 65 Italic = 0x02, 66 Underline = 0x04, 67 Negative = 0x08, 68 Blink = 0x10, 69 Touched = 0x20, 70 }; 71 72 bool is_untouched() const { return !(flags & Touched); } 73 74 // TODO: it would be really nice if we had a helper for enums that 75 // exposed bit ops for class enums... 76 u8 flags = Flags::NoAttributes; 77 78 bool operator==(const Attribute& other) const 79 { 80 return foreground_color == other.foreground_color && background_color == other.background_color && flags == other.flags; 81 } 82 bool operator!=(const Attribute& other) const 83 { 84 return !(*this == other); 85 } 86}; 87 88class Terminal { 89public: 90 explicit Terminal(TerminalClient&); 91 ~Terminal(); 92 93 bool m_need_full_flush { false }; 94 95 void invalidate_cursor(); 96 void on_char(u8); 97 98 void clear(); 99 void set_size(u16 columns, u16 rows); 100 u16 columns() const { return m_columns; } 101 u16 rows() const { return m_rows; } 102 103 u16 cursor_column() const { return m_cursor_column; } 104 u16 cursor_row() const { return m_cursor_row; } 105 106 struct Line { 107 explicit Line(u16 columns); 108 ~Line(); 109 void clear(Attribute); 110 bool has_only_one_background_color() const; 111 void set_length(u16); 112 StringView text() const { return { characters, m_length }; } 113 114 u8* characters { nullptr }; 115 Attribute* attributes { nullptr }; 116 bool dirty { false }; 117 u16 m_length { 0 }; 118 }; 119 120 Line& line(size_t index) 121 { 122 ASSERT(index < m_rows); 123 return m_lines[index]; 124 } 125 const Line& line(size_t index) const 126 { 127 ASSERT(index < m_rows); 128 return m_lines[index]; 129 } 130 131 size_t max_history_size() const { return 500; } 132 const NonnullOwnPtrVector<Line>& history() const { return m_history; } 133 134 void inject_string(const StringView&); 135 136private: 137 typedef Vector<unsigned, 4> ParamVector; 138 139 void scroll_up(); 140 void scroll_down(); 141 void newline(); 142 void set_cursor(unsigned row, unsigned column); 143 void put_character_at(unsigned row, unsigned column, u8 ch); 144 void set_window_title(const String&); 145 146 void unimplemented_escape(); 147 void unimplemented_xterm_escape(); 148 149 void emit_string(const StringView&); 150 151 void alter_mode(bool should_set, bool question_param, const ParamVector&); 152 153 void CUU(const ParamVector&); 154 void CUD(const ParamVector&); 155 void CUF(const ParamVector&); 156 void CUB(const ParamVector&); 157 void CUP(const ParamVector&); 158 void ED(const ParamVector&); 159 void EL(const ParamVector&); 160 void escape$M(const ParamVector&); 161 void escape$P(const ParamVector&); 162 void escape$G(const ParamVector&); 163 void escape$X(const ParamVector&); 164 void escape$b(const ParamVector&); 165 void escape$d(const ParamVector&); 166 void SGR(const ParamVector&); 167 void escape$s(const ParamVector&); 168 void escape$u(const ParamVector&); 169 void escape$t(const ParamVector&); 170 void DECSTBM(const ParamVector&); 171 void escape$S(const ParamVector&); 172 void escape$T(const ParamVector&); 173 void escape$L(const ParamVector&); 174 void RM(bool question_param, const ParamVector&); 175 void SM(bool question_param, const ParamVector&); 176 void DA(const ParamVector&); 177 void HVP(const ParamVector&); 178 void NEL(); 179 void IND(); 180 void RI(); 181 182 TerminalClient& m_client; 183 184 NonnullOwnPtrVector<Line> m_history; 185 NonnullOwnPtrVector<Line> m_lines; 186 187 size_t m_scroll_region_top { 0 }; 188 size_t m_scroll_region_bottom { 0 }; 189 190 u16 m_columns { 1 }; 191 u16 m_rows { 1 }; 192 193 u16 m_cursor_row { 0 }; 194 u16 m_cursor_column { 0 }; 195 u16 m_saved_cursor_row { 0 }; 196 u16 m_saved_cursor_column { 0 }; 197 bool m_swallow_current { false }; 198 bool m_stomp { false }; 199 200 Attribute m_current_attribute; 201 202 void execute_escape_sequence(u8 final); 203 void execute_xterm_command(); 204 void execute_hashtag(u8); 205 206 enum EscapeState { 207 Normal, 208 GotEscape, 209 ExpectParameter, 210 ExpectIntermediate, 211 ExpectFinal, 212 ExpectHashtagDigit, 213 ExpectXtermParameter1, 214 ExpectXtermParameter2, 215 ExpectXtermFinal, 216 }; 217 EscapeState m_escape_state { Normal }; 218 Vector<u8> m_parameters; 219 Vector<u8> m_intermediates; 220 Vector<u8> m_xterm_param1; 221 Vector<u8> m_xterm_param2; 222 Vector<bool> m_horizontal_tabs; 223 u8 m_final { 0 }; 224 225 u8 m_last_char { 0 }; 226}; 227 228}