FINAL CUT
ftermoutput.h
1 /***********************************************************************
2 * ftermoutput.h - Implements the terminal output *
3 * *
4 * This file is part of the FINAL CUT widget toolkit *
5 * *
6 * Copyright 2021-2026 Markus Gans *
7 * *
8 * FINAL CUT is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU Lesser General Public License as *
10 * published by the Free Software Foundation; either version 3 of *
11 * the License, or (at your option) any later version. *
12 * *
13 * FINAL CUT is distributed in the hope that it will be useful, but *
14 * WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU Lesser General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU Lesser General Public *
19 * License along with this program. If not, see *
20 * <http://www.gnu.org/licenses/>. *
21 ***********************************************************************/
22 
23 /* Standalone class
24  * ════════════════
25  *
26  * ▕▔▔▔▔▔▔▔▔▔▏
27  * ▕ FOutput ▏
28  * ▕▁▁▁▁▁▁▁▁▁▏
29  * ▲
30  * │
31  * ▕▔▔▔▔▔▔▔▔▔▔▔▔▔▏
32  * ▕ FTermOutput ▏
33  * ▕▁▁▁▁▁▁▁▁▁▁▁▁▁▏
34  */
35 
36 #ifndef FTERMOUTPUT_H
37 #define FTERMOUTPUT_H
38 
39 #if !defined (USE_FINAL_H) && !defined (COMPILE_FINAL_CUT)
40  #error "Only <final/final.h> can be included directly."
41 #endif
42 
43 #include <memory>
44 #include <string>
45 #include <tuple>
46 #include <utility>
47 
48 #include "final/output/foutput.h"
49 #include "final/output/tty/fterm.h"
50 #include "final/util/char_ringbuffer.h"
51 
52 namespace finalcut
53 {
54 
55 namespace internal
56 {
57 
58 struct terminal
59 {
60  static Encoding encoding;
61 };
62 
63 } // namespace internal
64 
65 // class forward declaration
66 class FStartOptions;
67 class FTermData;
68 template <typename T, std::size_t Capacity>
70 
71 //----------------------------------------------------------------------
72 // struct FCharBuffer
73 //----------------------------------------------------------------------
75 {
76  public:
77  explicit FCharBuffer (std::size_t initial_cap = 4096)
78  {
79  buffer.reserve(initial_cap);
80  }
81 
82  inline void append (const char* data, std::size_t len)
83  {
84  buffer.insert(buffer.end(), data, data + len);
85  }
86 
87  inline auto appendUnicode (wchar_t ucs) -> uInt32
88  {
89  return UTF8::encode(ucs, buffer);
90  }
91 
92  inline auto data() const noexcept -> const char*
93  {
94  return buffer.data();
95  }
96 
97  inline auto size() const noexcept -> std::size_t
98  {
99  return buffer.size();
100  }
101 
102  inline void expand (std::size_t addend)
103  {
104  buffer.resize(buffer.size() + addend);
105  }
106 
107  inline void clear() noexcept
108  {
109  buffer.clear();
110  }
111 
112  private:
113  std::vector<char> buffer;
114 };
115 
116 
117 //----------------------------------------------------------------------
118 // struct FOutputBuffer
119 //----------------------------------------------------------------------
120 
122 {
123  // Constant - output buffer size
124  static constexpr std::size_t BUFFER_SIZE = 32'768; // 32 KB
125 
126  // Enumerations
127  enum class OutputType : uInt8 // Output data type of the terminal
128  {
129  String,
130  Control
131  };
132 
133  struct TypeSlice
134  {
135  OutputType type{OutputType::String};
136  uInt32 length{0};
137 
138  TypeSlice() = default;
139 
140  TypeSlice (OutputType t, uInt32 len)
141  : type{t}
142  , length{len}
143  { }
144  };
145 
146  // Using-declaration
147  using TypeSliceBuffer = FRingBuffer<TypeSlice, BUFFER_SIZE>;
148 
149  FOutputBuffer() = default;
150 
151  inline auto isEmpty() const noexcept -> bool
152  {
153  return slices.isEmpty();
154  }
155 
156  // Data members
157  TypeSliceBuffer slices{};
158  FCharBuffer data{2 * BUFFER_SIZE};
159 };
160 
161 
162 //----------------------------------------------------------------------
163 // class FTermOutput
164 //----------------------------------------------------------------------
165 
166 class FTermOutput final : public FOutput
167 {
168  public:
169  // Constructor
170  FTermOutput() = default;
171 
172  explicit FTermOutput (const FVTerm&);
173 
174  // Destructor
175  ~FTermOutput() noexcept override;
176 
177  // Accessors
178  auto getClassName() const -> FString override;
179  auto getFTerm() noexcept -> FTerm&;
180  auto getColumnNumber() const -> std::size_t override;
181  auto getLineNumber() const -> std::size_t override;
182  auto getTabstop() const -> int override;
183  auto getMaxColor() const -> int override;
184  auto getEncoding() const -> Encoding override;
185  auto getKeyName (FKey) const -> FString override;
186 
187  // Mutators
188  void setCursor (FPoint) override;
189  void setCursor (CursorMode) override;
190  void hideCursor (bool = true) override;
191  void showCursor() noexcept override;
192  void setTerminalSize (FSize) override;
193  auto setVGAFont() -> bool override;
194  auto setNewFont() -> bool override;
195  void setNonBlockingRead (bool = true) override;
196 
197  // Predicates
198  auto isCursorHideable() const noexcept -> bool override;
199  auto isMonochron() const -> bool override;
200  auto isNewFont() const -> bool override;
201  auto isEncodable (const wchar_t&) const -> bool override;
202  auto isFlushTimeout() const noexcept -> bool override;
203  auto hasTerminalResized() const -> bool override;
204  auto allowsTerminalSizeManipulation() const -> bool override;
205  auto canChangeColorPalette() const -> bool override;
206  auto hasHalfBlockCharacter() const -> bool override;
207  auto hasShadowCharacter() const -> bool override;
208  auto areMetaAndArrowKeysSupported() const -> bool override;
209 
210  // Methods
211  void initTerminal (FVTerm::FTermRegion*) override;
212  void finishTerminal() override;
213  auto updateTerminal() -> bool override;
214  void detectTerminalSize() override;
215  void commitTerminalResize() override;
216  void initScreenSettings() override;
217  auto scrollTerminalForward() -> bool override;
218  auto scrollTerminalReverse() -> bool override;
219  void clearTerminalAttributes() override;
220  void clearTerminalState() override;
221  auto clearTerminal (wchar_t = L' ') -> bool override;
222  void flush() override;
223  void beep() const override;
224 
225  private:
226  // Constants
227  struct FTermControl
228  {
229  FTermcap::TermcapString termcap;
230  };
231 
232  // Enumerations
233  enum class PrintState : uInt8
234  {
235  NothingPrinted,
236  RepeatCharacterPrinted,
237  WhitespacesPrinted,
238  LineCompletelyPrinted
239  };
240 
241  enum class Repetition : uInt8
242  {
243  ASCII,
244  UTF8,
245  NotOptimized
246  };
247 
248  enum class CursorMoved : bool { No, Yes };
249 
250  // Constants
251  // Upper and lower flush limit
252  static constexpr uInt64 MIN_FLUSH_WAIT = 16'667; // 16.6 ms = 60 Hz
253  static constexpr uInt64 MAX_FLUSH_WAIT = 200'000; // 200.0 ms = 5 Hz
254  static constexpr uInt64 RESET_THRESHOLD = 400'000; // 400.0 ms = 2.5 Hz
255 
256  // Using-declaration
257  using clock = std::chrono::steady_clock;
258  using FChar_iterator = FVTerm::FTermRegion::FCharVec::iterator;
259  using FChar_const_iterator = FVTerm::FTermRegion::FCharVec::const_iterator;
260 
261  // Accessors
262  auto getFSetPaletteRef() const & -> const FSetPalette& override;
263 
264  // Methods
265  auto getStartOptions() & -> FStartOptions&;
266  auto isInputCursorInsideTerminal() const noexcept -> bool;
267  auto isDefaultPaletteTheme() const -> bool override;
268  void redefineColorPalette() override;
269  void restoreColorPalette() override;
270  void init_characterLengths();
271  void init_combined_character();
272  auto canClearToEOL (uInt, uInt) const -> bool;
273  auto canClearLeadingWS (uInt&, uInt) const -> bool;
274  auto canClearTrailingWS (uInt&, uInt) const -> bool;
275  auto skipUnchangedCharacters (uInt&, uInt, uInt, FChar_iterator) -> bool;
276  void printRange (uInt, uInt, uInt);
277  void replaceNonPrintableFullwidth (uInt, uInt, FChar&) const noexcept;
278  void printCharacter (uInt&, uInt, bool, const FChar_iterator&);
279  void printFullWidthCharacter (uInt&, uInt, const FChar_iterator&);
280  void printFullWidthPaddingCharacter (uInt&, uInt, const FChar_iterator&);
281  void printHalfCovertFullWidthCharacter (uInt, uInt, const FChar_iterator&);
282  void printEllipsis (uInt, uInt, FChar&);
283  void skipPaddingCharacter (uInt&, uInt, const FChar&) const noexcept;
284  auto eraseCharacters (uInt&, uInt, uInt, const FChar_iterator&) -> PrintState;
285  auto repeatCharacter (uInt&, uInt, uInt, const FChar_iterator&) -> PrintState;
286  auto countRepetitions (FChar_const_iterator, uInt, uInt) const noexcept -> uInt;
287  auto canUseEraseCharacters (const FChar&, uInt) const noexcept -> bool;
288  auto canUseCharacterRepetitions (const FChar&, uInt) const noexcept -> bool;
289  auto getRepetitionType (const FChar&, uInt) const noexcept -> Repetition;
290  auto isFullWidthChar (const FChar&) const noexcept -> bool;
291  auto isFullWidthPaddingChar (const FChar&) const noexcept -> bool;
292  void cursorWrap() const noexcept;
293  void adjustCursorPosition (FPoint&) const noexcept;
294  auto updateTerminalLine (uInt) -> bool;
295  auto updateTerminalCursor() -> bool;
296  void flushTimeAdjustment() noexcept;
297  void markAsPrinted (uInt, uInt) const noexcept;
298  void markAsPrinted (uInt, uInt, uInt) const noexcept;
299  void newFontChanges (FChar&) const;
300  void charsetChanges (FChar&) const;
301  void appendCharacter (const FChar_iterator&);
302  void appendCharacter_n (const FChar_iterator&, uInt);
303  void appendChar (FChar&);
304  void appendAttributes (FChar&);
305  void appendLowerRight (const FChar_iterator&);
306  void characterFilter (FChar&);
307  auto moveCursorLeft() -> CursorMoved;
308  void checkFreeBufferSize();
309  void appendOutputBuffer (const FTermControl&);
310  void appendOutputBuffer (wchar_t);
311  void appendOutputBuffer (const UniChar&);
312  void appendOutputBuffer (FOutputBuffer::OutputType, const char*, uInt32);
313 
314  // Data members
315  FTerm fterm{};
316  static FVTerm::FTermRegion* vterm;
317  static FTermData* fterm_data;
318  std::shared_ptr<FOutputBuffer> output_buffer{};
319  std::shared_ptr<FPoint> term_pos{}; // terminal cursor position
320  FChar term_attribute{};
321  bool cursor_hideable{false};
322  bool combined_char_support{false};
323  uInt erase_char_length{};
324  uInt repeat_char_length{};
325  uInt clr_bol_length{};
326  uInt clr_eol_length{};
327  uInt cursor_address_length{};
328  uInt64 time_last_flush_us{};
329  uInt64 flush_wait{MIN_FLUSH_WAIT};
330  uInt64 flush_average{MIN_FLUSH_WAIT};
331  uInt64 flush_median{MIN_FLUSH_WAIT};
332 };
333 
334 // FTermOutput inline functions
335 //----------------------------------------------------------------------
336 inline auto FTermOutput::getClassName() const -> FString
337 { return "FTermOutput"; }
338 
339 //----------------------------------------------------------------------
340 inline auto FTermOutput::getFTerm() noexcept -> FTerm&
341 { return fterm; }
342 
343 //----------------------------------------------------------------------
344 inline auto FTermOutput::getColumnNumber() const -> std::size_t
345 { return FTerm::getColumnNumber(); }
346 
347 //----------------------------------------------------------------------
348 inline auto FTermOutput::getLineNumber() const -> std::size_t
349 { return FTerm::getLineNumber(); }
350 
351 //----------------------------------------------------------------------
352 inline auto FTermOutput::getTabstop() const -> int
353 { return FTerm::getTabstop(); }
354 
355 //----------------------------------------------------------------------
356 inline auto FTermOutput::getMaxColor() const -> int
357 { return FTerm::getMaxColor(); }
358 
359 //----------------------------------------------------------------------
360 inline auto FTermOutput::getEncoding() const -> Encoding
361 { return internal::terminal::encoding; }
362 
363 //----------------------------------------------------------------------
364 inline auto FTermOutput::getKeyName (FKey keynum) const -> FString
365 { return FTerm::getKeyName(keynum); }
366 
367 //----------------------------------------------------------------------
368 inline void FTermOutput::showCursor() noexcept
369 { return hideCursor(false); }
370 
371 //----------------------------------------------------------------------
372 inline void FTermOutput::setTerminalSize (FSize size)
373 { FTerm::setTermSize(size); }
374 
375 //----------------------------------------------------------------------
376 inline auto FTermOutput::setVGAFont() -> bool
377 { return FTerm::setVGAFont(); }
378 
379 //----------------------------------------------------------------------
380 inline auto FTermOutput::setNewFont() -> bool
381 { return FTerm::setNewFont(); }
382 
383 //----------------------------------------------------------------------
384 inline auto FTermOutput::isCursorHideable() const noexcept -> bool
385 { return cursor_hideable; }
386 //----------------------------------------------------------------------
387 inline auto FTermOutput::isMonochron() const -> bool
388 { return FTerm::isMonochron(); }
389 
390 //----------------------------------------------------------------------
391 inline auto FTermOutput::isNewFont() const -> bool
392 { return FTerm::isNewFont(); }
393 
394 //----------------------------------------------------------------------
395 inline auto FTermOutput::isEncodable (const wchar_t& wide_char) const -> bool
396 { return FTerm::isEncodable(wide_char); }
397 
398 //----------------------------------------------------------------------
399 inline auto FTermOutput::hasTerminalResized() const -> bool
400 { return FTerm::hasChangedTermSize(); }
401 
402 //----------------------------------------------------------------------
403 inline auto FTermOutput::allowsTerminalSizeManipulation() const -> bool
404 { return fterm_data->isTermType(FTermType::xterm); }
405 
406 //----------------------------------------------------------------------
407 inline auto FTermOutput::canChangeColorPalette() const -> bool
408 { return FTerm::canChangeColorPalette(); }
409 
410 //----------------------------------------------------------------------
411 inline auto FTermOutput::hasHalfBlockCharacter() const -> bool
412 { return FTerm::hasHalfBlockCharacter(); }
413 
414 //----------------------------------------------------------------------
415 inline auto FTermOutput::hasShadowCharacter() const -> bool
416 { return FTerm::hasShadowCharacter(); }
417 
418 //----------------------------------------------------------------------
419 inline auto FTermOutput::areMetaAndArrowKeysSupported() const -> bool
420 { return ! fterm_data->isTermType(FTermType::linux_con); }
421 
422 //----------------------------------------------------------------------
423 inline void FTermOutput::detectTerminalSize()
424 { FTerm::detectTermSize(); }
425 
426 //----------------------------------------------------------------------
427 inline void FTermOutput::commitTerminalResize()
428 { FTerm::changeTermSizeFinished(); }
429 
430 //----------------------------------------------------------------------
431 inline void FTermOutput::initScreenSettings()
432 { FTerm::initScreenSettings(); }
433 
434 //----------------------------------------------------------------------
435 inline void FTermOutput::clearTerminalAttributes()
436 { FTerm::clearTerminalAttributes(); }
437 
438 //----------------------------------------------------------------------
439 inline void FTermOutput::beep() const
440 { return FTerm::beep(); }
441 
442 //----------------------------------------------------------------------
443 inline auto FTermOutput::getFSetPaletteRef() const & -> const FSetPalette&
444 {
445  static const FSetPalette& f = &FTerm::setPalette;
446  return f;
447 }
448 
449 } // namespace finalcut
450 
451 #endif // FTERMOUTPUT_H
452 
Definition: fvterm.h:441
Definition: class_template.cpp:25
Definition: fpoint.h:50
Definition: fsize.h:55
Definition: ftypes.h:1081
Definition: ftermoutput.h:121
Definition: fstartoptions.h:52
Definition: ftermoutput.h:74
Definition: fstring.h:82
Definition: ftermdata.h:140
Definition: ftermoutput.h:69
Definition: ftermoutput.h:58
Definition: fterm.h:144