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

gansm / finalcut / #768

11 Feb 2026 01:01AM UTC coverage: 69.071% (+0.001%) from 69.07%
#768

push

travis-ci

gansm
Use faster bit logic

22 of 24 new or added lines in 4 files covered. (91.67%)

4 existing lines in 1 file now uncovered.

37629 of 54479 relevant lines covered (69.07%)

250.25 hits per line

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

93.3
/final/output/tty/foptiattr.cpp
1
/***********************************************************************
2
* foptiattr.cpp - Sets video attributes in optimized order             *
3
*                                                                      *
4
* This file is part of the FINAL CUT widget toolkit                    *
5
*                                                                      *
6
* Copyright 2016-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
#include <strings.h>  // need for ffs()
24

25
#include <array>
26
#include <cstring>
27
#include <functional>
28
#include <memory>
29
#include <utility>
30

31
#include "final/fc.h"
32
#include "final/fstartoptions.h"
33
#include "final/output/tty/foptiattr.h"
34
#include "final/output/tty/ftermcap.h"
35

36
namespace finalcut
37
{
38

39
namespace internal
40
{
41

42
template<typename F>
43
constexpr auto createMask(F setter) noexcept -> uInt32
44
{
45
  FCharAttribute mask{};
46
  setter(mask);
47
  return FCharAttribute_to_uInt32(mask);
48
}
49

50
constexpr void setReverseMask (FCharAttribute& attr) noexcept
51
{
52
  attr.reverse = true;
53
  attr.standout = true;
54
}
55

56
constexpr void setAltCharsetMask (FCharAttribute& attr) noexcept
57
{
58
  attr.alt_charset = true;
59
}
60

61
constexpr void setPcCharsetMask (FCharAttribute& attr) noexcept
62
{
63
  attr.pc_charset = true;
64
}
65

66
constexpr void setAttributeMask (FCharAttribute& attr) noexcept
67
{
68
  attr.bold = true;
69
  attr.dim = true;
70
  attr.italic = true;
71
  attr.underline = true;
72
  attr.blink = true;
73
  attr.reverse = true;
74
  attr.standout = true;
75
  attr.invisible = true;
76
  attr.protect = true;
77
  attr.crossed_out = true;
78
  attr.dbl_underline = true;
79
  attr.alt_charset = true;
80
  attr.pc_charset = true;
81
}
82

83
constexpr void setResetMask (FCharAttribute& attr) noexcept
84
{
85
  // Set bits that must not be reset
86
  attr.transparent = true;
87
  attr.color_overlay = true;
88
  attr.inherit_background = true;
89
  attr.no_changes = true;
90
  attr.printed = true;
91
}
92

93
struct var
94
{
95
  static constexpr auto reverse_mask           = createMask(setReverseMask);
96
  static constexpr auto alt_charset_mask       = createMask(setAltCharsetMask);
97
  static constexpr auto pc_charset_mask        = createMask(setPcCharsetMask);
98
  static constexpr auto attribute_mask         = createMask(setAttributeMask);
99
  static constexpr auto alt_charset_reset_mask = ~alt_charset_mask;
100
  static constexpr auto pc_charset_reset_mask  = ~pc_charset_mask;
101
  static constexpr auto reset_mask             = createMask(setResetMask);
102
  static constexpr char sgr_39[]               = {CSI "39m"};
103
  static constexpr char sgr_39_49[]            = {CSI "39;49m"};
104
};
105

106
constexpr uInt32 var::reverse_mask;
107
constexpr uInt32 var::alt_charset_mask;
108
constexpr uInt32 var::pc_charset_mask;
109
constexpr uInt32 var::attribute_mask;
110
constexpr uInt32 var::alt_charset_reset_mask;
111
constexpr uInt32 var::pc_charset_reset_mask;
112
constexpr uInt32 var::reset_mask;
113
constexpr char   var::sgr_39[];
114
constexpr char   var::sgr_39_49[];
115

116
}  // namespace internal
117

118
// Function prototypes
119
auto has_foreground_changes (const FChar&, FColor, bool) noexcept -> bool;
120
auto has_background_changes (const FChar&, FColor, bool) noexcept -> bool;
121

122

123
//----------------------------------------------------------------------
124
// class FOptiAttr
125
//----------------------------------------------------------------------
126

127
// constructors and destructor
128
//----------------------------------------------------------------------
129
FOptiAttr::FOptiAttr()
15✔
130
{
131
  attr_buf.reserve(SGRoptimizer::ATTR_BUF_SIZE);
15✔
132
}
15✔
133

134

135
// public methods of FOptiAttr
136
//----------------------------------------------------------------------
137
auto FOptiAttr::getInstance() -> FOptiAttr&
×
138
{
139
  static const auto& opti_attr = std::make_unique<FOptiAttr>();
×
140
  return *opti_attr;
×
141
}
142

143
//----------------------------------------------------------------------
144
void FOptiAttr::setTermEnvironment (const TermEnv& term_env)
1✔
145
{
146
  // Set all required termcap values at once
147
  // and initialize the FOptiAttr environment
148

149
  set_enter_bold_mode (term_env.t_set_bold.on);
1✔
150
  set_exit_bold_mode (term_env.t_set_bold.off);
1✔
151
  set_enter_dim_mode (term_env.t_set_dim.on);
1✔
152
  set_exit_dim_mode (term_env.t_set_dim.off);
1✔
153
  set_enter_italics_mode (term_env.t_set_italics.on);
1✔
154
  set_exit_italics_mode (term_env.t_set_italics.off);
1✔
155
  set_enter_underline_mode (term_env.t_set_underline.on);
1✔
156
  set_exit_underline_mode (term_env.t_set_underline.off);
1✔
157
  set_enter_blink_mode (term_env.t_set_blink.on);
1✔
158
  set_exit_blink_mode (term_env.t_set_blink.off);
1✔
159
  set_enter_reverse_mode (term_env.t_set_reverse.on);
1✔
160
  set_exit_reverse_mode (term_env.t_set_reverse.off);
1✔
161
  set_enter_standout_mode (term_env.t_set_standout.on);
1✔
162
  set_exit_standout_mode (term_env.t_set_standout.off);
1✔
163
  set_enter_secure_mode (term_env.t_set_secure.on);
1✔
164
  set_exit_secure_mode (term_env.t_set_secure.off);
1✔
165
  set_enter_protected_mode (term_env.t_set_protected.on);
1✔
166
  set_exit_protected_mode (term_env.t_set_protected.off);
1✔
167
  set_enter_crossed_out_mode (term_env.t_set_crossed_out.on);
1✔
168
  set_exit_crossed_out_mode (term_env.t_set_crossed_out.off);
1✔
169
  set_enter_dbl_underline_mode (term_env.t_set_dbl_underline.on);
1✔
170
  set_exit_dbl_underline_mode (term_env.t_set_dbl_underline.off);
1✔
171
  set_set_attributes (term_env.t_set_attributes.on);
1✔
172
  set_exit_attribute_mode (term_env.t_set_attributes.off);
1✔
173
  set_enter_alt_charset_mode (term_env.t_set_alt_charset.on);
1✔
174
  set_exit_alt_charset_mode (term_env.t_set_alt_charset.off);
1✔
175
  set_enter_pc_charset_mode (term_env.t_set_pc_charset.on);
1✔
176
  set_exit_pc_charset_mode (term_env.t_set_pc_charset.off);
1✔
177
  set_a_foreground_color (term_env.t_set_color.a_foreground);
1✔
178
  set_a_background_color (term_env.t_set_color.a_background);
1✔
179
  set_foreground_color (term_env.t_set_color.foreground);
1✔
180
  set_background_color (term_env.t_set_color.background);
1✔
181
  set_term_color_pair (term_env.t_set_color.color_pair);
1✔
182
  set_orig_pair (term_env.t_set_color.orig_pair);
1✔
183
  set_orig_colors (term_env.t_set_color.orig_colors);
1✔
184

185
  F_color.max_color = term_env.t_set_color.max_color;
1✔
186
  F_color.attr_without_color = term_env.t_set_color.attr_without_color;
1✔
187
  F_color.ansi_default_color = term_env.t_set_color.ansi_default_color;
1✔
188

189
  initialize();
1✔
190
}
1✔
191

192
//----------------------------------------------------------------------
193
void FOptiAttr::set_enter_bold_mode (const char cap[]) noexcept
12✔
194
{
195
  set_mode_on (F_bold, cap, false);
12✔
196
}
12✔
197

198
//----------------------------------------------------------------------
199
void FOptiAttr::set_exit_bold_mode (const char cap[]) noexcept
12✔
200
{
201
  set_mode_off (F_bold, cap, false);
12✔
202
}
12✔
203

204
//----------------------------------------------------------------------
205
void FOptiAttr::set_enter_dim_mode (const char cap[]) noexcept
12✔
206
{
207
  set_mode_on (F_dim, cap, false);
12✔
208
}
12✔
209

210
//----------------------------------------------------------------------
211
void FOptiAttr::set_exit_dim_mode (const char cap[]) noexcept
12✔
212
{
213
  set_mode_off (F_dim, cap, false);
12✔
214
}
12✔
215

216
//----------------------------------------------------------------------
217
void FOptiAttr::set_enter_italics_mode (const char cap[]) noexcept
12✔
218
{
219
  set_mode_on (F_italics, cap, false);
12✔
220
}
12✔
221

222
//----------------------------------------------------------------------
223
void FOptiAttr::set_exit_italics_mode (const char cap[]) noexcept
12✔
224
{
225
  set_mode_off (F_italics, cap, false);
12✔
226
}
12✔
227

228
//----------------------------------------------------------------------
229
void FOptiAttr::set_enter_underline_mode (const char cap[]) noexcept
12✔
230
{
231
  set_mode_on (F_underline, cap, false);
12✔
232
}
12✔
233

234
//----------------------------------------------------------------------
235
void FOptiAttr::set_exit_underline_mode (const char cap[]) noexcept
12✔
236
{
237
  set_mode_off (F_underline, cap, false);
12✔
238
}
12✔
239

240
//----------------------------------------------------------------------
241
void FOptiAttr::set_enter_blink_mode (const char cap[]) noexcept
12✔
242
{
243
  set_mode_on (F_blink, cap, false);
12✔
244
}
12✔
245

246
//----------------------------------------------------------------------
247
void FOptiAttr::set_exit_blink_mode (const char cap[]) noexcept
12✔
248
{
249
  set_mode_off (F_blink, cap, false);
12✔
250
}
12✔
251

252
//----------------------------------------------------------------------
253
void FOptiAttr::set_enter_reverse_mode (const char cap[]) noexcept
12✔
254
{
255
  set_mode_on (F_reverse, cap, false);
12✔
256
}
12✔
257

258
//----------------------------------------------------------------------
259
void FOptiAttr::set_exit_reverse_mode (const char cap[]) noexcept
12✔
260
{
261
  set_mode_off (F_reverse, cap, false);
12✔
262
}
12✔
263

264
//----------------------------------------------------------------------
265
void FOptiAttr::set_enter_secure_mode (const char cap[]) noexcept
12✔
266
{
267
  set_mode_on (F_secure, cap, false);
12✔
268
}
12✔
269

270
//----------------------------------------------------------------------
271
void FOptiAttr::set_exit_secure_mode (const char cap[]) noexcept
12✔
272
{
273
  set_mode_off (F_secure, cap, false);
12✔
274
}
12✔
275

276
//----------------------------------------------------------------------
277
void FOptiAttr::set_enter_protected_mode (const char cap[]) noexcept
12✔
278
{
279
  set_mode_on (F_protected, cap, false);
12✔
280
}
12✔
281

282
//----------------------------------------------------------------------
283
void FOptiAttr::set_exit_protected_mode (const char cap[]) noexcept
12✔
284
{
285
  set_mode_off (F_protected, cap, false);
12✔
286
}
12✔
287

288
//----------------------------------------------------------------------
289
void FOptiAttr::set_enter_crossed_out_mode (const char cap[]) noexcept
12✔
290
{
291
  set_mode_on (F_crossed_out, cap, false);
12✔
292
}
12✔
293

294
//----------------------------------------------------------------------
295
void FOptiAttr::set_exit_crossed_out_mode (const char cap[]) noexcept
12✔
296
{
297
  set_mode_off (F_crossed_out, cap, false);
12✔
298
}
12✔
299

300
//----------------------------------------------------------------------
301
void FOptiAttr::set_enter_dbl_underline_mode (const char cap[]) noexcept
12✔
302
{
303
  set_mode_on (F_dbl_underline, cap, false);
12✔
304
}
12✔
305

306
//----------------------------------------------------------------------
307
void FOptiAttr::set_exit_dbl_underline_mode (const char cap[]) noexcept
12✔
308
{
309
  set_mode_off (F_dbl_underline, cap, false);
12✔
310
}
12✔
311

312
//----------------------------------------------------------------------
313
void FOptiAttr::set_enter_standout_mode (const char cap[]) noexcept
12✔
314
{
315
  set_mode_on (F_standout, cap, false);
12✔
316
}
12✔
317

318
//----------------------------------------------------------------------
319
void FOptiAttr::set_exit_standout_mode (const char cap[]) noexcept
12✔
320
{
321
  set_mode_off (F_standout, cap, false);
12✔
322
}
12✔
323

324
//----------------------------------------------------------------------
325
void FOptiAttr::set_set_attributes (const char cap[]) noexcept
12✔
326
{
327
  set_mode_on (F_attributes, cap, true);
12✔
328
}
12✔
329

330
//----------------------------------------------------------------------
331
void FOptiAttr::set_exit_attribute_mode (const char cap[]) noexcept
12✔
332
{
333
  set_mode_off (F_attributes, cap, true);
12✔
334
}
12✔
335

336
//----------------------------------------------------------------------
337
void FOptiAttr::set_enter_alt_charset_mode (const char cap[]) noexcept
12✔
338
{
339
  set_mode_on (F_alt_charset, cap, false);
12✔
340
}
12✔
341

342
//----------------------------------------------------------------------
343
void FOptiAttr::set_exit_alt_charset_mode (const char cap[]) noexcept
12✔
344
{
345
  set_mode_off (F_alt_charset, cap, false);
12✔
346
}
12✔
347

348
//----------------------------------------------------------------------
349
void FOptiAttr::set_enter_pc_charset_mode (const char cap[]) noexcept
12✔
350
{
351
  set_mode_on (F_pc_charset, cap, false);
12✔
352
}
12✔
353

354
//----------------------------------------------------------------------
355
void FOptiAttr::set_exit_pc_charset_mode (const char cap[]) noexcept
12✔
356
{
357
  set_mode_off (F_pc_charset, cap, false);
12✔
358
}
12✔
359

360
//----------------------------------------------------------------------
361
void FOptiAttr::set_a_foreground_color (const char cap[]) noexcept
12✔
362
{
363
  set_mode (F_color.a_foreground, cap, false);
12✔
364
}
12✔
365

366
//----------------------------------------------------------------------
367
void FOptiAttr::set_a_background_color (const char cap[]) noexcept
12✔
368
{
369
  set_mode (F_color.a_background, cap, false);
12✔
370
}
12✔
371

372
//----------------------------------------------------------------------
373
void FOptiAttr::set_foreground_color (const char cap[]) noexcept
12✔
374
{
375
  set_mode (F_color.foreground, cap, false);
12✔
376
}
12✔
377

378
//----------------------------------------------------------------------
379
void FOptiAttr::set_background_color (const char cap[]) noexcept
12✔
380
{
381
  set_mode (F_color.background, cap, false);
12✔
382
}
12✔
383

384
//----------------------------------------------------------------------
385
void FOptiAttr::set_term_color_pair (const char cap[]) noexcept
12✔
386
{
387
  set_mode (F_color.color_pair, cap, false);
12✔
388
}
12✔
389

390
//----------------------------------------------------------------------
391
void FOptiAttr::set_orig_pair (const char cap[]) noexcept
12✔
392
{
393
  set_mode (F_color.orig_pair, cap, false);
12✔
394
}
12✔
395

396
//----------------------------------------------------------------------
397
void FOptiAttr::set_orig_colors (const char cap[]) noexcept
12✔
398
{
399
  set_mode (F_color.orig_colors, cap, false);
12✔
400
}
12✔
401

402
//----------------------------------------------------------------------
403
auto FOptiAttr::isNormal (const FChar& ch) noexcept -> bool
3✔
404
{
405
  return ! hasAttribute(ch) && ! hasColor(ch);
3✔
406
}
407

408
//----------------------------------------------------------------------
409
void FOptiAttr::initialize()
13✔
410
{
411
  F_color.monochron = F_color.max_color < 8;
13✔
412
  init_reset_attribute (F_bold.off);
13✔
413
  init_reset_attribute (F_dim.off);
13✔
414
  init_reset_attribute (F_italics.off);
13✔
415
  init_reset_attribute (F_blink.off);
13✔
416
  init_reset_attribute (F_underline.off, all_tests & ~same_like_ue);
13✔
417
  init_reset_attribute (F_reverse.off);
13✔
418
  init_reset_attribute (F_secure.off);
13✔
419
  init_reset_attribute (F_protected.off);
13✔
420
  init_reset_attribute (F_crossed_out.off);
13✔
421
  init_reset_attribute (F_dbl_underline.off);
13✔
422
  init_reset_attribute (F_standout.off, all_tests & ~same_like_se);
13✔
423
  alt_equal_pc_charset = hasCharsetEquivalence();
13✔
424
}
13✔
425

426
//----------------------------------------------------------------------
427
auto FOptiAttr::vga2ansi (FColor color) noexcept -> FColor
158✔
428
{
429
  //   VGA   |  ANSI
430
  // i R G B | i B G R
431
  //---------+---------
432
  // 0 0 0 0 | 0 0 0 0    i = intensity bit
433
  // 0 0 0 1 | 0 1 0 0    R = red
434
  // 0 0 1 0 | 0 0 1 0    G = green
435
  // 0 0 1 1 | 0 1 1 0    B = blue
436
  // 0 1 0 0 | 0 0 0 1
437
  // 0 1 0 1 | 0 1 0 1
438
  // 0 1 1 0 | 0 0 1 1
439
  // 0 1 1 1 | 0 1 1 1
440
  // 1 0 0 0 | 1 0 0 0
441
  // 1 0 0 1 | 1 1 0 0
442
  // 1 0 1 0 | 1 0 1 0
443
  // 1 0 1 1 | 1 1 1 0
444
  // 1 1 0 0 | 1 0 0 1
445
  // 1 1 0 1 | 1 1 0 1
446
  // 1 1 1 0 | 1 0 1 1
447
  // 1 1 1 1 | 1 1 1 1
448

449
  if ( color == FColor::Default )
158✔
450
    color = FColor::Black;
×
451
  else if ( color < 16 )
158✔
452
  {
453
    static constexpr std::array<FColor, 16> lookup_table
454
    {{
455
      FColor(0), FColor(4),  FColor(2),  FColor(6),
456
      FColor(1), FColor(5),  FColor(3),  FColor(7),
457
      FColor(8), FColor(12), FColor(10), FColor(14),
458
      FColor(9), FColor(13), FColor(11), FColor(15)
459
    }};
460

461
    color = lookup_table[uInt16(color)];
154✔
462
  }
463

464
  return color;
158✔
465
}
466

467
//----------------------------------------------------------------------
468
auto FOptiAttr::changeAttribute (FChar& term, FChar& next) -> std::string
966✔
469
{
470
  const bool next_has_color = hasColor(next);
966✔
471
  fake_reverse = false;
966✔
472
  attr_buf.clear();
966✔
473
  prevent_no_color_video_attributes (term, next_has_color);
966✔
474
  prevent_no_color_video_attributes (next);
966✔
475
  detectSwitchOn (term, next);
966✔
476
  detectSwitchOff (term, next);
966✔
477

478
  // Simulate invisible characters
479
  if ( ! F_secure.on.cap && next.attr.bit.invisible )
966✔
480
    next.encoded_char.unicode_data[0] = ' ';
130✔
481

482
  // Look for no changes
483
  if ( ! (switchOn() || switchOff() || hasColorChanged(term, next)) )
966✔
484
    return {};
493✔
485

486
  if ( hasNoAttribute(next) )
473✔
487
  {
488
    deactivateAttributes (term, next);
190✔
489
  }
490
  else if ( F_attributes.on.cap
283✔
491
         && (! (term.attr.data & internal::var::pc_charset_mask) || alt_equal_pc_charset) )
254✔
492
  {
493
    changeAttributeSGR (term, next);
157✔
494
  }
495
  else
496
  {
497
    changeAttributeSeparately (term, next);
126✔
498
  }
499

500
  static const auto& start_options = FStartOptions::getInstance();
473✔
501

502
  if ( start_options.sgr_optimizer )
473✔
503
    sgr_optimizer.optimize();
2✔
504

505
  return attr_buf;
473✔
506
}
507

508

509
// private methods of FOptiAttr
510
//----------------------------------------------------------------------
511
inline void FOptiAttr::set_mode ( Capability& capability
420✔
512
                                , const char cap[]
513
                                , bool caused_reset ) const noexcept
514
{
515
  if ( cap )
420✔
516
  {
517
    capability.cap = cap;
235✔
518
    capability.caused_reset = caused_reset;
235✔
519
  }
520
}
420✔
521

522
//----------------------------------------------------------------------
523
inline void FOptiAttr::set_mode_on ( TextStyle& style
168✔
524
                                   , const char cap[]
525
                                   , bool caused_reset ) const noexcept
526
{
527
  set_mode (style.on, cap, caused_reset);
168✔
528
}
168✔
529

530
//----------------------------------------------------------------------
531
inline void FOptiAttr::set_mode_off ( TextStyle& style
168✔
532
                                    , const char cap[]
533
                                    , bool caused_reset ) const noexcept
534
{
535
  set_mode (style.off, cap, caused_reset);
168✔
536
}
168✔
537

538
//----------------------------------------------------------------------
539
inline auto FOptiAttr::setTermBold (FChar& term) noexcept -> bool
3✔
540
{
541
  term.attr.bit.bold = true;
3✔
542
  return append_sequence(F_bold.on.cap);
3✔
543
}
544

545
//----------------------------------------------------------------------
546
inline auto FOptiAttr::unsetTermBold (FChar& term) noexcept -> bool
10✔
547
{
548
  // Back to normal intensity (turns off bold + dim)
549

550
  if ( F_bold.off.caused_reset )
10✔
551
    reset(term);
2✔
552
  else
553
  {
554
    term.attr.bit.bold = false;
8✔
555
    term.attr.bit.dim = false;
8✔
556
  }
557

558
  return append_sequence(F_bold.off.cap);
10✔
559
}
560

561
//----------------------------------------------------------------------
562
inline auto FOptiAttr::setTermDim (FChar& term) noexcept -> bool
9✔
563
{
564
  term.attr.bit.dim = true;
9✔
565
  return append_sequence(F_dim.on.cap);
9✔
566
}
567

568
//----------------------------------------------------------------------
569
inline auto FOptiAttr::unsetTermDim (FChar& term) noexcept -> bool
9✔
570
{
571
  // Back to normal intensity (turns off bold + dim)
572

573
  if ( F_dim.off.caused_reset )
9✔
574
    reset(term);
2✔
575
  else
576
  {
577
    term.attr.bit.bold = false;
7✔
578
    term.attr.bit.dim = false;
7✔
579
  }
580

581
  return append_sequence(F_dim.off.cap);
9✔
582
}
583

584
//----------------------------------------------------------------------
585
inline auto FOptiAttr::setTermItalic (FChar& term) noexcept -> bool
37✔
586
{
587
  term.attr.bit.italic = true;
37✔
588
  return append_sequence(F_italics.on.cap);
37✔
589
}
590

591
//----------------------------------------------------------------------
592
inline auto FOptiAttr::unsetTermItalic (FChar& term) noexcept -> bool
11✔
593
{
594
  if ( F_italics.off.caused_reset )
11✔
595
    reset(term);
×
596
  else
597
    term.attr.bit.italic = false;
11✔
598

599
  return append_sequence(F_italics.off.cap);
11✔
600
}
601

602
//----------------------------------------------------------------------
603
inline auto FOptiAttr::setTermUnderline (FChar& term) noexcept -> bool
6✔
604
{
605
  term.attr.bit.underline = true;
6✔
606
  return append_sequence(F_underline.on.cap);
6✔
607
}
608

609
//----------------------------------------------------------------------
610
inline auto FOptiAttr::unsetTermUnderline (FChar& term) noexcept -> bool
7✔
611
{
612
  // Turns off every underlining
613

614
  if ( F_underline.off.caused_reset )
7✔
615
    reset(term);
2✔
616
  else
617
  {
618
    term.attr.bit.underline = false;
5✔
619
    term.attr.bit.dbl_underline = false;
5✔
620
  }
621

622
  return append_sequence(F_underline.off.cap);
7✔
623
}
624

625
//----------------------------------------------------------------------
626
inline auto FOptiAttr::setTermBlink (FChar& term) noexcept -> bool
8✔
627
{
628
  term.attr.bit.blink = true;
8✔
629
  return append_sequence(F_blink.on.cap);
8✔
630
}
631

632
//----------------------------------------------------------------------
633
inline auto FOptiAttr::unsetTermBlink (FChar& term) noexcept -> bool
9✔
634
{
635
  if ( F_blink.off.caused_reset )
9✔
636
    reset(term);
2✔
637
  else
638
    term.attr.bit.blink = false;
7✔
639

640
  return append_sequence(F_blink.off.cap);
9✔
641
}
642

643
//----------------------------------------------------------------------
644
inline auto FOptiAttr::setTermReverse (FChar& term) noexcept -> bool
11✔
645
{
646
  term.attr.bit.reverse = true;
11✔
647
  return ( ! fake_reverse && append_sequence(F_reverse.on.cap) );
11✔
648
}
649

650
//----------------------------------------------------------------------
651
inline auto FOptiAttr::unsetTermReverse (FChar& term) noexcept -> bool
11✔
652
{
653
  if ( F_reverse.off.caused_reset )
11✔
654
    reset(term);
2✔
655
  else
656
    term.attr.bit.reverse = false;
9✔
657

658
  return ( ! fake_reverse && append_sequence(F_reverse.off.cap) );
11✔
659
}
660

661
//----------------------------------------------------------------------
662
inline auto FOptiAttr::setTermStandout (FChar& term) noexcept -> bool
12✔
663
{
664
  term.attr.bit.standout = true;
12✔
665

666
  return ( ! fake_reverse && append_sequence(F_standout.on.cap) );
12✔
667
}
668

669
//----------------------------------------------------------------------
670
inline auto FOptiAttr::unsetTermStandout (FChar& term) noexcept -> bool
8✔
671
{
672
  if ( F_standout.off.caused_reset )
8✔
673
    reset(term);
2✔
674
  else
675
    term.attr.bit.standout = false;
6✔
676

677
  return ( ! fake_reverse && append_sequence(F_standout.off.cap) );
8✔
678
}
679

680
//----------------------------------------------------------------------
681
inline auto FOptiAttr::setTermInvisible (FChar& term) noexcept -> bool
14✔
682
{
683
  term.attr.bit.invisible = true;
14✔
684
  return append_sequence(F_secure.on.cap);
14✔
685
}
686

687
//----------------------------------------------------------------------
688
inline auto FOptiAttr::unsetTermInvisible (FChar& term) noexcept -> bool
10✔
689
{
690
  if ( F_secure.off.caused_reset )
10✔
691
    reset(term);
2✔
692
  else
693
    term.attr.bit.invisible = false;
8✔
694

695
  return append_sequence(F_secure.off.cap);
10✔
696
}
697

698
//----------------------------------------------------------------------
699
inline auto FOptiAttr::setTermProtected (FChar& term) noexcept -> bool
16✔
700
{
701
  term.attr.bit.protect = true;
16✔
702
  return append_sequence(F_protected.on.cap);
16✔
703
}
704

705
//----------------------------------------------------------------------
706
inline auto FOptiAttr::unsetTermProtected (FChar& term) noexcept -> bool
10✔
707
{
708
  if ( F_protected.off.caused_reset )
10✔
709
    reset(term);
6✔
710
  else
711
    term.attr.bit.protect = false;
4✔
712

713
  return append_sequence(F_protected.off.cap);
10✔
714
}
715

716
//----------------------------------------------------------------------
717
inline auto FOptiAttr::setTermCrossedOut (FChar& term) noexcept -> bool
47✔
718
{
719
  term.attr.bit.crossed_out = true;
47✔
720
  return append_sequence(F_crossed_out.on.cap);
47✔
721
}
722

723
//----------------------------------------------------------------------
724
inline auto FOptiAttr::unsetTermCrossedOut (FChar& term) noexcept -> bool
10✔
725
{
726
  if ( F_crossed_out.off.caused_reset )
10✔
727
    reset(term);
2✔
728
  else
729
    term.attr.bit.crossed_out = false;
8✔
730

731
  return append_sequence(F_crossed_out.off.cap);
10✔
732
}
733

734
//----------------------------------------------------------------------
735
inline auto FOptiAttr::setTermDoubleUnderline (FChar& term) noexcept -> bool
54✔
736
{
737
  term.attr.bit.dbl_underline = true;
54✔
738
  return append_sequence(F_dbl_underline.on.cap);
54✔
739
}
740

741
//----------------------------------------------------------------------
742
inline auto FOptiAttr::unsetTermDoubleUnderline (FChar& term) noexcept -> bool
10✔
743
{
744
  // Turns off every underlining
745

746
  if ( F_dbl_underline.off.caused_reset )
10✔
747
    reset(term);
×
748
  else
749
  {
750
    term.attr.bit.underline = false;
10✔
751
    term.attr.bit.dbl_underline = false;
10✔
752
  }
753

754
  return append_sequence(F_dbl_underline.off.cap);
10✔
755
}
756

757
//----------------------------------------------------------------------
758
auto FOptiAttr::setTermAttributes (FChar& term, const TCapAttributes& attr) -> bool
156✔
759
{
760
  if ( F_attributes.on.cap )
156✔
761
  {
762
    const auto sgr = FTermcap::encodeParameter ( F_attributes.on.cap
763
                                               , attr.p1 && ! fake_reverse
156✔
764
                                               , attr.p2
156✔
765
                                               , attr.p3 && ! fake_reverse
156✔
766
                                               , attr.p4
156✔
767
                                               , attr.p5
156✔
768
                                               , attr.p6
156✔
769
                                               , attr.p7
156✔
770
                                               , attr.p8
156✔
771
                                               , attr.p9 );
468✔
772
    append_sequence (sgr);
156✔
773
    resetColor(term);
156✔
774
    term.attr.bit.standout      = attr.p1;
156✔
775
    term.attr.bit.underline     = attr.p2;
156✔
776
    term.attr.bit.reverse       = attr.p3;
156✔
777
    term.attr.bit.blink         = attr.p4;
156✔
778
    term.attr.bit.dim           = attr.p5;
156✔
779
    term.attr.bit.bold          = attr.p6;
156✔
780
    term.attr.bit.invisible     = attr.p7;
156✔
781
    term.attr.bit.protect       = attr.p8;
156✔
782
    term.attr.bit.alt_charset   = attr.p9;
156✔
783
    term.attr.bit.pc_charset    = false;
156✔
784
    term.attr.bit.italic        = false;
156✔
785
    term.attr.bit.crossed_out   = false;
156✔
786
    term.attr.bit.dbl_underline = false;
156✔
787
    return true;
156✔
788
  }
156✔
789

790
  return false;
×
791
}
792

793
//----------------------------------------------------------------------
794
inline auto FOptiAttr::unsetTermAttributes (FChar& term) noexcept -> bool
135✔
795
{
796
  reset(term);
135✔
797
  return append_sequence(F_attributes.off.cap);
135✔
798
}
799

800
//----------------------------------------------------------------------
801
inline auto FOptiAttr::setTermAltCharset (FChar& term) noexcept -> bool
24✔
802
{
803
  term.attr.data |= internal::var::alt_charset_mask;
24✔
804

805
  if ( alt_equal_pc_charset
24✔
NEW
806
    && term.attr.data & internal::var::pc_charset_mask )
×
UNCOV
807
    return false;
×
808

809
  return append_sequence(F_alt_charset.on.cap);
24✔
810
}
811

812
//----------------------------------------------------------------------
813
inline auto FOptiAttr::unsetTermAltCharset (FChar& term) noexcept -> bool
19✔
814
{
815
  term.attr.data &= internal::var::alt_charset_reset_mask;
19✔
816

817
  if ( alt_equal_pc_charset
19✔
818
    && term.attr.data & internal::var::pc_charset_mask )
1✔
UNCOV
819
    return false;
×
820

821
  return append_sequence(F_alt_charset.off.cap);
19✔
822
}
823

824
//----------------------------------------------------------------------
825
inline auto FOptiAttr::setTermPCcharset (FChar& term) noexcept -> bool
42✔
826
{
827
  term.attr.data |= internal::var::pc_charset_mask;
42✔
828

829
  if ( alt_equal_pc_charset
42✔
830
    && term.attr.data & internal::var::alt_charset_mask )
2✔
UNCOV
831
    return false;
×
832

833
  return append_sequence(F_pc_charset.on.cap);
42✔
834
}
835

836
//----------------------------------------------------------------------
837
inline auto FOptiAttr::unsetTermPCcharset (FChar& term) noexcept -> bool
20✔
838
{
839
  term.attr.data &= internal::var::pc_charset_reset_mask;
20✔
840

841
  if ( alt_equal_pc_charset
20✔
842
    && term.attr.data & internal::var::alt_charset_mask )
2✔
UNCOV
843
    return false;
×
844

845
  return append_sequence(F_pc_charset.off.cap);
20✔
846
}
847

848
//----------------------------------------------------------------------
849
auto FOptiAttr::setTermDefaultColor (FChar& term) -> bool
7✔
850
{
851
  term.color.pair = {FColor::Default, FColor::Default};
7✔
852

853
  if ( append_sequence(F_color.orig_pair.cap)
7✔
854
    || append_sequence(F_color.orig_colors.cap) )
7✔
855
    return true;
7✔
856

857
  if ( F_color.ansi_default_color )
×
858
  {
859
    append_sequence (internal::var::sgr_39_49);
×
860
    return true;
×
861
  }
862

863
  return false;
×
864
}
865

866
//----------------------------------------------------------------------
867
void FOptiAttr::setAttributesOn (FChar& term)
126✔
868
{
869
  static const auto& attribute_on_handlers = getAttributeOnHandlers();
126✔
870
  setAttributes (changes.on.attr, attribute_on_handlers, term);
126✔
871
}
126✔
872

873
//----------------------------------------------------------------------
874
void FOptiAttr::setAttributesOff (FChar& term)
142✔
875
{
876
  static const auto& attribute_off_handlers = getAttributeOffHandlers();
142✔
877
  setAttributes (changes.off.attr, attribute_off_handlers, term);
142✔
878
}
142✔
879

880
//----------------------------------------------------------------------
881
void FOptiAttr::setAttributes ( FAttribute attribute
268✔
882
                              , const AttributeHandlers& attribute_handlers
883
                              , FChar& term )
884
{
885
  if ( ! attribute.data )
268✔
886
    return;
106✔
887

888
  for (const auto& handler : attribute_handlers)
1,335✔
889
  {
890
    const auto& mask = handler.mask;
1,335✔
891

892
    for (std::size_t b{0}; b < 2; b++)
4,005✔
893
    {
894
      if ( ! (attribute.byte[b] & mask.byte[b]) )
2,670✔
895
        continue;
2,369✔
896

897
      handler.function(this, term);  // Call function
301✔
898
      attribute.byte[b] ^= mask.byte[b];  // Clear found bit
301✔
899
    }
900

901
    if ( ! attribute.data )
1,335✔
902
      break;
162✔
903
  }
904
}
905

906
//----------------------------------------------------------------------
907
auto FOptiAttr::hasColor (const FChar& attr) noexcept -> bool
2,901✔
908
{
909
  return ( attr.color.pair.fg != FColor::Default
2,901✔
910
        || attr.color.pair.bg != FColor::Default );
2,901✔
911
}
912

913
//----------------------------------------------------------------------
914
auto FOptiAttr::hasAttribute (const FChar& attr) noexcept -> bool
2,605✔
915
{
916
  return attr.attr.data & internal::var::attribute_mask;
2,605✔
917
}
918

919
//----------------------------------------------------------------------
920
auto FOptiAttr::hasNoAttribute (const FChar& attr) noexcept -> bool
473✔
921
{
922
  return ! hasAttribute(attr);
473✔
923
}
924

925
//----------------------------------------------------------------------
926
inline auto FOptiAttr::isItalicsUsed ( const FChar& term
157✔
927
                                     , const FChar& next ) const noexcept -> bool
928
{
929
  return ! term.attr.bit.italic && next.attr.bit.italic;
157✔
930
}
931

932
//----------------------------------------------------------------------
933
inline auto FOptiAttr::isCrossedOutUsed ( const FChar& term
157✔
934
                                        , const FChar& next ) const noexcept -> bool
935
{
936
  return ! term.attr.bit.crossed_out && next.attr.bit.crossed_out;
157✔
937
}
938

939
//----------------------------------------------------------------------
940
inline auto FOptiAttr::isDoubleUnderlineUsed ( const FChar& term
157✔
941
                                             , const FChar& next ) const noexcept -> bool
942
{
943
  return ! term.attr.bit.dbl_underline && next.attr.bit.dbl_underline;
157✔
944
}
945

946
//----------------------------------------------------------------------
947
inline auto FOptiAttr::isPCcharsetUsed ( const FChar& term
157✔
948
                                       , const FChar& next ) const noexcept -> bool
949
{
950
  return ! (term.attr.data & internal::var::pc_charset_mask)
157✔
951
      && next.attr.data & internal::var::pc_charset_mask;
157✔
952
}
953

954
//----------------------------------------------------------------------
955
inline auto FOptiAttr::isPCcharsetUsable ( FChar& term
157✔
956
                                         , const FChar& next ) noexcept -> bool
957
{
958
  if ( alt_equal_pc_charset
157✔
959
    && F_pc_charset.on.cap
29✔
960
    && next.attr.data & internal::var::alt_charset_mask )
29✔
961
  {
962
    term.attr.bit.pc_charset = next.attr.bit.pc_charset;
12✔
963
    changes.off.attr.data &= internal::var::pc_charset_reset_mask;
12✔
964
    return false;
12✔
965
  }
966

967
  return true;
145✔
968
}
969

970
//----------------------------------------------------------------------
971
inline auto FOptiAttr::hasColorChanged ( const FChar& term
1,016✔
972
                                       , const FChar& next ) const noexcept -> bool
973
{
974
  const auto& reverse_mask = internal::var::reverse_mask;
1,016✔
975
  const bool frev ( ( (changes.on.attr.data & reverse_mask)
2,032✔
976
                   || (changes.off.attr.data & reverse_mask) ) && fake_reverse );
1,016✔
977
  return frev
978
      || term.color.pair.fg != next.color.pair.fg
1,014✔
979
      || term.color.pair.bg != next.color.pair.bg;
2,030✔
980
}
981

982
//----------------------------------------------------------------------
983
inline void FOptiAttr::resetColor (FChar& attr) const noexcept
313✔
984
{
985
  attr.color.pair = {FColor::Default, FColor::Default};
313✔
986
}
313✔
987

988
//----------------------------------------------------------------------
989
inline void FOptiAttr::prevent_no_color_video_attributes ( FChar& attr
1,932✔
990
                                                         , bool next_has_color )
991
{
992
  // Ignore video attributes which can not combined with a color
993

994
  if ( ! (hasColor(attr) || next_has_color) || F_color.attr_without_color <= 0 )
1,932✔
995
    return;
1,513✔
996

997
  static const auto& no_color_video_handlers = getNoColorVideoHandlerTable();
419✔
998
  auto set_bits = uInt(F_color.attr_without_color);
419✔
999

1000
  while ( set_bits )
1,318✔
1001
  {
1002
    const uInt bit = set_bits & (~set_bits + 1);  // Get rightmost set bit
899✔
1003
    set_bits &= ~bit;  // Clear rightmost set bit
899✔
1004

1005
    if ( ! bit )
899✔
1006
      continue;
×
1007

1008
    const auto mode_index = unsigned(ffs(int(bit)));
899✔
1009
    const auto& handler = no_color_video_handlers[mode_index];
899✔
1010

1011
    if ( handler )
899✔
1012
      handler(this, attr);
899✔
1013
  }
1014
}
1015

1016
//----------------------------------------------------------------------
1017
inline void FOptiAttr::deactivateAttributes (FChar& term, FChar& next)
190✔
1018
{
1019
  if ( hasAttribute(term) )
190✔
1020
  {
1021
    if ( F_attributes.off.cap )
151✔
1022
    {
1023
      if ( changes.off.attr.data & internal::var::alt_charset_mask )  // Required for rxvt terminals
135✔
1024
        unsetTermAltCharset(term);
9✔
1025

1026
      unsetTermAttributes(term);
135✔
1027

1028
      if ( changes.off.attr.data & internal::var::pc_charset_mask )
135✔
1029
        unsetTermPCcharset(term);
18✔
1030
    }
1031
    else
1032
      setAttributesOff(term);
16✔
1033
  }
1034

1035
  if ( hasColorChanged(term, next) )
190✔
1036
    change_color (term, next);
55✔
1037
}
190✔
1038

1039
//----------------------------------------------------------------------
1040
inline void FOptiAttr::changeAttributeSGR (FChar& term, FChar& next)
157✔
1041
{
1042
  if ( switchOn() || switchOff() )
157✔
1043
    setTermAttributes ( term
156✔
1044
                      , { next.attr.bit.standout
156✔
1045
                        , next.attr.bit.underline
156✔
1046
                        , next.attr.bit.reverse
156✔
1047
                        , next.attr.bit.blink
156✔
1048
                        , next.attr.bit.dim
156✔
1049
                        , next.attr.bit.bold
156✔
1050
                        , next.attr.bit.invisible
156✔
1051
                        , next.attr.bit.protect
156✔
1052
                        , next.attr.bit.alt_charset } );
156✔
1053

1054
  const auto pc_charset_usable = isPCcharsetUsable(term, next);
157✔
1055

1056
  if ( changes.off.attr.data & internal::var::pc_charset_mask )
157✔
1057
    unsetTermPCcharset(term);
×
1058

1059
  if ( isItalicsUsed(term, next) )
157✔
1060
    setTermItalic(term);
30✔
1061

1062
  if ( isCrossedOutUsed(term, next) )
157✔
1063
    setTermCrossedOut(term);
25✔
1064

1065
  if ( isDoubleUnderlineUsed(term, next) )
157✔
1066
    setTermDoubleUnderline(term);
26✔
1067

1068
  if ( isPCcharsetUsed(term, next) && pc_charset_usable )
157✔
1069
    setTermPCcharset(term);
18✔
1070

1071
  if ( hasColorChanged(term, next) )
157✔
1072
    change_color(term, next);
22✔
1073
}
157✔
1074

1075
//----------------------------------------------------------------------
1076
inline void FOptiAttr::changeAttributeSeparately (FChar& term, FChar& next)
126✔
1077
{
1078
  setAttributesOff(term);
126✔
1079

1080
  if ( hasColorChanged(term, next) )
126✔
1081
    change_color (term, next);
17✔
1082

1083
  detectSwitchOn (term, next);  // After reset all attributes
126✔
1084
  setAttributesOn(term);
126✔
1085
}
126✔
1086

1087
//----------------------------------------------------------------------
1088
void FOptiAttr::change_color (FChar& term, FChar& next)
94✔
1089
{
1090
  if ( F_color.monochron )
94✔
1091
  {
1092
    next.color.pair = {FColor::Default, FColor::Default};
10✔
1093
    return;
10✔
1094
  }
1095

1096
  normalizeColor (next.color.pair.fg);
84✔
1097
  normalizeColor (next.color.pair.bg);
84✔
1098
  auto fg = next.color.pair.fg;
84✔
1099
  auto bg = next.color.pair.bg;
84✔
1100
  handleDefaultColors (term, next, fg, bg);
84✔
1101

1102
  if ( fake_reverse )
84✔
1103
  {
1104
    if ( fg == FColor::Default && bg == FColor::Default )
4✔
1105
      return;
×
1106

1107
    if ( next.attr.bit.reverse || next.attr.bit.standout )
4✔
1108
    {
1109
      std::swap (fg, bg);
2✔
1110
      handleDefaultColors (term, next, fg, bg);
2✔
1111
    }
1112
  }
1113

1114
  change_current_color (term, fg, bg);
84✔
1115
  term.color.data = next.color.data;
84✔
1116
}
1117

1118
//----------------------------------------------------------------------
1119
inline void FOptiAttr::normalizeColor (FColor& color) const noexcept
168✔
1120
{
1121
  if ( color != FColor::Default )
168✔
1122
    color %= uInt16(F_color.max_color);
150✔
1123
}
168✔
1124

1125
//----------------------------------------------------------------------
1126
inline void FOptiAttr::handleDefaultColors ( FChar& term, FChar& next
86✔
1127
                                           , FColor& fg, FColor& bg )
1128
{
1129
  if ( fg == FColor::Default || bg == FColor::Default )
86✔
1130
    change_to_default_color(term, next, fg, bg);
17✔
1131
}
86✔
1132

1133
//----------------------------------------------------------------------
1134
inline void FOptiAttr::change_to_default_color ( FChar& term, FChar& next
17✔
1135
                                               , FColor& fg, FColor& bg )
1136
{
1137
  if ( F_color.ansi_default_color )
17✔
1138
  {
1139
    const auto set_default_fg = fg == FColor::Default && term.color.pair.fg != FColor::Default;
10✔
1140
    const auto set_default_bg = bg == FColor::Default && term.color.pair.bg != FColor::Default;
10✔
1141

1142
    if ( set_default_fg && set_default_bg )
10✔
1143
      setTermDefaultColor(term);
×
1144
    else if ( set_default_fg )
10✔
1145
      setDefaultForeground(term);
5✔
1146
    else if ( set_default_bg )
5✔
1147
      setDefaultBackground(term);
×
1148
  }
1149
  else if ( ! setTermDefaultColor(term) )
7✔
1150
  {
1151
    // Fallback to gray on black
1152
    fg = next.color.pair.fg = FColor::LightGray;
×
1153
    bg = next.color.pair.bg = FColor::Black;
×
1154
  }
1155
}
17✔
1156

1157
//----------------------------------------------------------------------
1158
inline void FOptiAttr::setDefaultForeground (FChar& term)
5✔
1159
{
1160
  append_sequence (internal::var::sgr_39);
5✔
1161
  term.color.pair.fg = FColor::Default;
5✔
1162
}
5✔
1163

1164
//----------------------------------------------------------------------
1165
inline void FOptiAttr::setDefaultBackground (FChar& term)
×
1166
{
1167
  const char* sgr_49;
1168
  const auto& op = F_color.orig_pair.cap;
×
1169

1170
  if ( op && std::memcmp (op, CSI "39;49;25m", 11) == 0 )
×
1171
    sgr_49 = CSI "49;25m";
×
1172
  else
1173
    sgr_49 = CSI "49m";
×
1174

1175
  append_sequence (sgr_49);
×
1176
  term.color.pair.bg = FColor::Default;
×
1177
}
×
1178

1179
//----------------------------------------------------------------------
1180
inline void FOptiAttr::change_current_color ( const FChar& term
84✔
1181
                                            , const FColor fg, const FColor bg )
1182
{
1183
  const auto& AF = F_color.a_foreground.cap;
84✔
1184
  const auto& AB = F_color.a_background.cap;
84✔
1185
  const auto& Sf = F_color.foreground.cap;
84✔
1186
  const auto& Sb = F_color.background.cap;
84✔
1187
  const auto& sp = F_color.color_pair.cap;
84✔
1188
  const bool frev = fake_reverse_color_change(term);
84✔
1189
  static constexpr auto ANSI = 0;
1190
  static constexpr auto VGA = 1;
1191

1192
  auto apply_color_change = [this, &term, fg, bg, frev] ( const char* fg_cap
92✔
1193
                                                        , const char* bg_cap
1194
                                                        , int cm ) noexcept
1195
  {
1196
    if ( ! fg_cap || ! bg_cap )
92✔
1197
      return false;
8✔
1198

1199
    if ( has_foreground_changes(term, fg, frev) )
84✔
1200
    {
1201
      const auto fg_value = ( cm == VGA ) ? uInt16(vga2ansi(fg)) : uInt16(fg);
75✔
1202
      append_sequence(FTermcap::encodeParameter(fg_cap, fg_value));
225✔
1203
    }
1204

1205
    if ( has_background_changes(term, bg, frev) )
84✔
1206
    {
1207
      const auto bg_value = ( cm == VGA ) ? uInt16(vga2ansi(bg)) : uInt16(bg);
62✔
1208
      append_sequence(FTermcap::encodeParameter(bg_cap, bg_value));
186✔
1209
    }
1210

1211
    return true;
84✔
1212
  };
84✔
1213

1214
  if ( ! apply_color_change(AF, AB, VGA)
84✔
1215
    && ! apply_color_change(Sf, Sb, ANSI)
8✔
1216
    && sp )
92✔
1217
  {
1218
    const auto fg_value = uInt16(vga2ansi(fg));
×
1219
    const auto bg_value = uInt16(vga2ansi(bg));
×
1220
    append_sequence (FTermcap::encodeParameter(sp, fg_value, bg_value));
×
1221
  }
1222
}
84✔
1223

1224
//----------------------------------------------------------------------
1225
inline void FOptiAttr::resetAttribute (FChar& attr) const noexcept
157✔
1226
{
1227
  attr.attr.data &= internal::var::reset_mask;
157✔
1228
}
157✔
1229

1230
//----------------------------------------------------------------------
1231
inline void FOptiAttr::reset (FChar& attr) const noexcept
157✔
1232
{
1233
  resetAttribute(attr);
157✔
1234
  resetColor(attr);
157✔
1235
}
157✔
1236

1237
//----------------------------------------------------------------------
1238
auto FOptiAttr::caused_reset_attributes (const char cap[], uChar test) const noexcept -> bool
143✔
1239
{
1240
  // test if "cap" reset all attributes
1241

1242
  if ( ! cap )
143✔
1243
    return false;
58✔
1244

1245
  const auto& ue = F_underline.off.cap;
85✔
1246
  const auto& se = F_standout.off.cap;
85✔
1247
  const auto& me = F_attributes.off.cap;
85✔
1248

1249
  return ( (test & test_ansi_reset) && std::memcmp (cap, CSI "m", 3) == 0 )
85✔
1250
      || ( (test & test_adm3_reset) && std::memcmp (cap, ESC "G0", 3) == 0 )
82✔
1251
      || ( (test & same_like_ue) && ue && std::strcmp (cap, ue) == 0
80✔
1252
                                 && std::memcmp (cap, CSI "24m", 5) != 0 )
4✔
1253
      || ( (test & same_like_se) && se && std::strcmp (cap, se) == 0
80✔
1254
                                 && std::memcmp (cap, CSI "27m", 5) != 0 )
6✔
1255
      || ( (test & same_like_me) && me && std::strcmp (cap, me) == 0 );
170✔
1256
}
1257

1258
//----------------------------------------------------------------------
1259
void FOptiAttr::init_reset_attribute (Capability& off, uChar test) const noexcept
143✔
1260
{
1261
  if ( caused_reset_attributes(off.cap, test) )
143✔
1262
    off.caused_reset = true;
31✔
1263
}
143✔
1264

1265
//----------------------------------------------------------------------
1266
inline auto FOptiAttr::fake_reverse_color_change (const FChar& term) const noexcept -> bool
84✔
1267
{
1268
  const auto& reverse_mask = internal::var::reverse_mask;
84✔
1269
  return ( (changes.off.attr.data & reverse_mask)
84✔
1270
        || (term.attr.data & reverse_mask) ) && fake_reverse;
84✔
1271
}
1272

1273
//----------------------------------------------------------------------
1274
inline auto FOptiAttr::hasCharsetEquivalence() const noexcept -> bool
13✔
1275
{
1276
  // Detect if alt charset and pc charset are the same sequences
1277

1278
  const auto& alt_on  = F_alt_charset.on.cap;
13✔
1279
  const auto& alt_off = F_alt_charset.off.cap;
13✔
1280
  const auto& pc_on   = F_pc_charset.on.cap;
13✔
1281
  const auto& pc_off  = F_pc_charset.off.cap;
13✔
1282

1283
  return ( alt_on && pc_on && std::strcmp (alt_on, pc_on) == 0 )
10✔
1284
      || ( alt_off && pc_off && std::strcmp (alt_off, pc_off) == 0 );
23✔
1285
}
1286

1287
//----------------------------------------------------------------------
1288
auto FOptiAttr::getNoColorVideoHandlerTable() -> const NoColorVideoHandlerTable&
1✔
1289
{
1290
  static const auto& no_color_video_handlers = std::make_unique<NoColorVideoHandlerTable>
1291
  (
1292
    NoColorVideoHandlerTable
2✔
1293
    {{
1294
      nullptr,                                                                      // No bit set (0)
1295
      [] (const FOptiAttr*, FChar& fchar) { fchar.attr.bit.standout = false; },     // Standout mode (1)
×
1296
      [] (const FOptiAttr*, FChar& fchar) { fchar.attr.bit.underline = false; },    // Underline mode (2)
×
1297
      [] (FOptiAttr* obj, const FChar&)   { obj->fake_reverse = true; },            // Reverse mode (4)
×
1298
      [] (const FOptiAttr*, FChar& fchar) { fchar.attr.bit.blink = false; },        // Blink mode (8)
×
1299
      [] (const FOptiAttr*, FChar& fchar) { fchar.attr.bit.dim = false; },          // Dim mode (16)
×
1300
      [] (const FOptiAttr*, FChar& fchar) { fchar.attr.bit.bold = false; },         // Bold mode (32)
×
1301
      [] (const FOptiAttr*, FChar& fchar) { fchar.attr.bit.invisible = false; },    // Invisible mode (64)
×
1302
      [] (const FOptiAttr*, FChar& fchar) { fchar.attr.bit.protect = false; },      // Protected mode (128)
×
1303
      [] (const FOptiAttr*, FChar& fchar) { fchar.attr.bit.alt_charset = false; },  // Alt_charset mode (256)
×
1304
      nullptr,                                                                      // Horizontal mode (512)
1305
      nullptr,                                                                      // Left mode (1024)
1306
      nullptr,                                                                      // Low mode (2048)
1307
      nullptr,                                                                      // Right mode (4096)
1308
      nullptr,                                                                      // Top mode (8192)
1309
      nullptr,                                                                      // Vertical mode (1638)
1310
      [] (const FOptiAttr*, FChar& fchar) { fchar.attr.bit.italic = false; },       // Italic mode (32768)
1✔
1311
      nullptr                                                                       // No mode (65536)
1312
    }}
1313
  );
2✔
1314

1315
  return *no_color_video_handlers;
1✔
1316
}
1317

1318
//----------------------------------------------------------------------
1319
auto FOptiAttr::getAttributeOnHandlers() -> const AttributeHandlers&
1✔
1320
{
1321
  static const auto& attribute_on_handlers = std::make_unique<AttributeHandlers>
1322
  (
1323
    AttributeHandlers
2✔
1324
    {{
1325
      { {{0x00, 0x08, 0x00, 0x00}}, [] (FOptiAttr* obj, FChar& fchar) { return obj->setTermAltCharset(fchar); } },
24✔
1326
      { {{0x00, 0x10, 0x00, 0x00}}, [] (FOptiAttr* obj, FChar& fchar) { return obj->setTermPCcharset(fchar); } },
24✔
1327
      { {{0x01, 0x00, 0x00, 0x00}}, [] (FOptiAttr* obj, FChar& fchar) { return obj->setTermBold(fchar); } },
3✔
1328
      { {{0x02, 0x00, 0x00, 0x00}}, [] (FOptiAttr* obj, FChar& fchar) { return obj->setTermDim(fchar); } },
9✔
1329
      { {{0x04, 0x00, 0x00, 0x00}}, [] (FOptiAttr* obj, FChar& fchar) { return obj->setTermItalic(fchar); } },
7✔
1330
      { {{0x08, 0x00, 0x00, 0x00}}, [] (FOptiAttr* obj, FChar& fchar) { return obj->setTermUnderline(fchar); } },
6✔
1331
      { {{0x10, 0x00, 0x00, 0x00}}, [] (FOptiAttr* obj, FChar& fchar) { return obj->setTermBlink(fchar); } },
8✔
1332
      { {{0x20, 0x00, 0x00, 0x00}}, [] (FOptiAttr* obj, FChar& fchar) { return obj->setTermReverse(fchar); } },
11✔
1333
      { {{0x40, 0x00, 0x00, 0x00}}, [] (FOptiAttr* obj, FChar& fchar) { return obj->setTermStandout(fchar); } },
12✔
1334
      { {{0x80, 0x00, 0x00, 0x00}}, [] (FOptiAttr* obj, FChar& fchar) { return obj->setTermInvisible(fchar); } },
14✔
1335
      { {{0x00, 0x01, 0x00, 0x00}}, [] (FOptiAttr* obj, FChar& fchar) { return obj->setTermProtected(fchar); } },
16✔
1336
      { {{0x00, 0x02, 0x00, 0x00}}, [] (FOptiAttr* obj, FChar& fchar) { return obj->setTermCrossedOut(fchar); } },
22✔
1337
      { {{0x00, 0x04, 0x00, 0x00}}, [] (FOptiAttr* obj, FChar& fchar) { return obj->setTermDoubleUnderline(fchar); } }
29✔
1338
    }}
1339
  );
2✔
1340

1341
  return *attribute_on_handlers;
1✔
1342
}
1343

1344
//----------------------------------------------------------------------
1345
auto FOptiAttr::getAttributeOffHandlers() -> const AttributeHandlers&
1✔
1346
{
1347
  static const auto& attribute_off_handlers = std::make_unique<AttributeHandlers>
1348
  (
1349
    AttributeHandlers
2✔
1350
    {{
1351
      { {{0x00, 0x10, 0x00, 0x00}}, [] (FOptiAttr* obj, FChar& fchar) { return obj->unsetTermPCcharset(fchar); } },
2✔
1352
      { {{0x00, 0x08, 0x00, 0x00}}, [] (FOptiAttr* obj, FChar& fchar) { return obj->unsetTermAltCharset(fchar); } },
10✔
1353
      { {{0x01, 0x00, 0x00, 0x00}}, [] (FOptiAttr* obj, FChar& fchar) { return obj->unsetTermBold(fchar); } },
10✔
1354
      { {{0x02, 0x00, 0x00, 0x00}}, [] (FOptiAttr* obj, FChar& fchar) { return obj->unsetTermDim(fchar); } },
9✔
1355
      { {{0x04, 0x00, 0x00, 0x00}}, [] (FOptiAttr* obj, FChar& fchar) { return obj->unsetTermItalic(fchar); } },
11✔
1356
      { {{0x08, 0x00, 0x00, 0x00}}, [] (FOptiAttr* obj, FChar& fchar) { return obj->unsetTermUnderline(fchar); } },
7✔
1357
      { {{0x10, 0x00, 0x00, 0x00}}, [] (FOptiAttr* obj, FChar& fchar) { return obj->unsetTermBlink(fchar); } },
9✔
1358
      { {{0x20, 0x00, 0x00, 0x00}}, [] (FOptiAttr* obj, FChar& fchar) { return obj->unsetTermReverse(fchar); } },
11✔
1359
      { {{0x40, 0x00, 0x00, 0x00}}, [] (FOptiAttr* obj, FChar& fchar) { return obj->unsetTermStandout(fchar); } },
8✔
1360
      { {{0x80, 0x00, 0x00, 0x00}}, [] (FOptiAttr* obj, FChar& fchar) { return obj->unsetTermInvisible(fchar); } },
10✔
1361
      { {{0x00, 0x01, 0x00, 0x00}}, [] (FOptiAttr* obj, FChar& fchar) { return obj->unsetTermProtected(fchar); } },
10✔
1362
      { {{0x00, 0x02, 0x00, 0x00}}, [] (FOptiAttr* obj, FChar& fchar) { return obj->unsetTermCrossedOut(fchar); } },
10✔
1363
      { {{0x00, 0x04, 0x00, 0x00}}, [] (FOptiAttr* obj, FChar& fchar) { return obj->unsetTermDoubleUnderline(fchar); } }
11✔
1364
    }}
1365
  );
2✔
1366

1367
  return *attribute_off_handlers;
1✔
1368
}
1369

1370
//----------------------------------------------------------------------
1371
inline void FOptiAttr::detectSwitchOn (const FChar& term, const FChar& next) noexcept
1,092✔
1372
{
1373
  // Detect switched on attributes on transition from "term" to "next"
1374
  // and store the result in "on"
1375

1376
  const auto& mask = internal::var::attribute_mask;
1,092✔
1377
  changes.on.attr.data = ~(term.attr.data) & next.attr.data & mask;
1,092✔
1378
}
1,092✔
1379

1380
//----------------------------------------------------------------------
1381
inline void FOptiAttr::detectSwitchOff (const FChar& term, const FChar& next) noexcept
966✔
1382
{
1383
  // Detect switched off attributes on transition from "term" to "next"
1384
  // and store the result in "on"
1385

1386
  const auto& mask = internal::var::attribute_mask;
966✔
1387
  changes.off.attr.data = term.attr.data & ~(next.attr.data) & mask;
966✔
1388
}
966✔
1389

1390
//----------------------------------------------------------------------
1391
inline auto FOptiAttr::switchOn() const noexcept -> bool
1,123✔
1392
{
1393
  return hasAttribute(changes.on);
1,123✔
1394
}
1395

1396
//----------------------------------------------------------------------
1397
inline auto FOptiAttr::switchOff() const noexcept -> bool
816✔
1398
{
1399
  return hasAttribute(changes.off);
816✔
1400
}
1401

1402
//----------------------------------------------------------------------
1403
inline auto FOptiAttr::append_sequence (const std::string& seq) noexcept -> bool
636✔
1404
{
1405
  if ( seq.empty() )
636✔
1406
    return false;
×
1407

1408
  attr_buf.append(seq);
636✔
1409
  return true;
636✔
1410
}
1411

1412

1413
// non-member functions
1414
//----------------------------------------------------------------------
1415
inline auto has_foreground_changes (const FChar& term, FColor fg, bool frev) noexcept -> bool
84✔
1416
{
1417
  return term.color.pair.fg != fg || frev;
84✔
1418
}
1419

1420
//----------------------------------------------------------------------
1421
inline auto has_background_changes (const FChar& term, FColor bg, bool frev) noexcept -> bool
84✔
1422
{
1423
  return term.color.pair.bg != bg || frev;
84✔
1424
}
1425

1426
}  // namespace finalcut
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