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

MorganKryze / ConsoleAppVisuals / 7473998763

10 Jan 2024 11:06AM UTC coverage: 37.669% (+1.7%) from 35.959%
7473998763

push

github

MorganKryze
🤖 (ci and docs) remove obsolete attribute from coverage

365 of 1034 branches covered (0.0%)

Branch coverage included in aggregate %.

750 of 1926 relevant lines covered (38.94%)

157.53 hits per line

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

0.0
/src/ConsoleAppVisuals/elements/interactive/TableSelector.cs
1
/*
2
    MIT License 2023 MorganKryze
3
    For full license information, please visit: https://github.com/MorganKryze/ConsoleAppVisuals/blob/main/LICENSE
4
*/
5
namespace ConsoleAppVisuals;
6

7
/// <summary>
8
/// The <see cref="TableSelector{T}"/> class that contains the methods to create a table and display it.
9
/// </summary>
10
///
11
public class TableSelector<T> : InteractiveElement<int>
12
{
13
    #region Fields: title, headers, lines, display array, rounded corners
14
    private string? _title;
15
    private List<string>? _rawHeaders;
16
    private List<List<T>>? _rawLines;
17
    private readonly bool _excludeHeader;
18
    private readonly bool _excludeFooter;
19
    private readonly string? _footerText;
20
    private string[]? _displayArray;
21
    private bool _roundedCorners = true;
×
22
    private readonly int _line;
23
    private readonly Placement _placement;
24

25
    #endregion
26

27
    #region Properties: get headers, get lines
28
    /// <summary>
29
    /// This property returns the headers of the table.
30
    /// </summary>
31
    public List<string>? GetRawHeaders => _rawHeaders;
×
32

33
    /// <summary>
34
    /// This property returns the lines of the table.
35
    /// </summary>
36
    public List<List<T>>? GetRawLines => _rawLines;
×
37

38
    /// <summary>
39
    /// This property returns the title of the table.
40
    /// </summary>
41
    public override Placement Placement => _placement;
×
42

43
    /// <summary>
44
    /// This property returns the line to display the table on.
45
    /// </summary>
46
    public override int Line => _line;
×
47

48
    /// <summary>
49
    /// This property returns the height of the table.
50
    /// </summary>
51
    public override int Height => _displayArray?.Length ?? 0;
×
52

53
    /// <summary>
54
    /// This property returns the width of the table.
55
    /// </summary>
56
    public override int Width => _displayArray?.Max(x => x.Length) ?? 0;
×
57
    #endregion
58

59
    #region Constructor
60
    /// <summary>
61
    /// The <see cref="TableSelector{T}"/> natural constructor.
62
    /// </summary>
63
    /// <param name="title">The title of the table.</param>
64
    /// <param name="lines">The lines of the table.</param>
65
    /// <param name="headers">The headers of the table.</param>
66
    /// <param name="excludeHeader">Whether to exclude the header from selectable elements.</param>
67
    /// <param name="excludeFooter">Whether to exclude the footer from selectable elements.</param>
68
    /// <param name="footerText">The text to display in the footer.</param>
69
    /// <param name="placement">The placement of the table.</param>
70
    /// <param name="line">The line to display the table on.</param>
71
    /// <exception cref="ArgumentException">Is thrown when the number of columns in the table is not consistent with itself or with the headers.</exception>
72
    /// <exception cref="NullReferenceException">Is thrown when no body lines were provided.</exception>
73
    /// <remarks>Refer to the example project to understand how to implement it available at https://github.com/MorganKryze/ConsoleAppVisuals/blob/main/example/Program.cs </remarks>
74
    public TableSelector(
×
75
        string? title = null,
×
76
        List<string>? headers = null,
×
77
        List<List<T>>? lines = null,
×
78
        bool excludeHeader = true,
×
79
        bool excludeFooter = true,
×
80
        string? footerText = null,
×
81
        Placement placement = Placement.TopCenter,
×
82
        int? line = null
×
83
    )
×
84
    {
85
        _title = title;
×
86
        _rawHeaders = headers;
×
87
        _rawLines = lines;
×
88
        _excludeHeader = excludeHeader;
×
89
        _excludeFooter = excludeFooter;
×
90
        _footerText = footerText;
×
91
        _placement = placement;
×
92
        _line = Window.CheckLine(line) ?? Window.GetLineAvailable(placement);
×
93
        if (CompatibilityCheck())
×
94
        {
95
            BuildTable();
×
96
        }
97
    }
×
98
    #endregion
99

100
    #region Check Methods
101
    private bool CompatibilityCheck()
102
    {
103
        if (_rawHeaders is null)
×
104
        {
105
            return CheckRawLines();
×
106
        }
107
        else if (_rawLines is null)
×
108
        {
109
            return true;
×
110
        }
111
        else
112
        {
113
            return CheckRawHeadersAndLines();
×
114
        }
115
    }
116

117
    private bool CheckRawLines()
118
    {
119
        if (_rawLines is null || _rawLines.Count == 0)
×
120
        {
121
            return false;
×
122
        }
123

124
        for (int i = 0; i < _rawLines.Count; i++)
×
125
        {
126
            if (_rawLines[i].Count != _rawLines[0].Count)
×
127
            {
128
                throw new ArgumentException(
×
129
                    "The number of columns in the table is not consistent."
×
130
                );
×
131
            }
132
        }
133

134
        return true;
×
135
    }
136

137
    private bool CheckRawHeadersAndLines()
138
    {
139
        if (_rawLines is null || _rawLines.Count == 0)
×
140
        {
141
            return false;
×
142
        }
143

144
        if (_rawLines.Count > 0)
×
145
        {
146
            for (int i = 0; i < _rawLines.Count; i++)
×
147
            {
148
                if (_rawLines[i].Count != _rawHeaders?.Count)
×
149
                {
150
                    throw new ArgumentException(
×
151
                        "The number of columns in the table is not consistent(Headers or Lines)."
×
152
                    );
×
153
                }
154
            }
155

156
            return true;
×
157
        }
158

159
        return false;
×
160
    }
161
    #endregion
162

163
    #region Build Methods
164
    private void BuildTable()
165
    {
166
        if (_rawHeaders is null)
×
167
        {
168
            if (_rawLines is not null)
×
169
            {
170
                BuildLines();
×
171
            }
172
        }
173
        else
174
        {
175
            if (_rawLines is null)
×
176
            {
177
                BuildHeaders();
×
178
            }
179
            else
180
            {
181
                BuildHeadersAndLines();
×
182
            }
183
        }
184
    }
×
185

186
    private void BuildHeadersAndLines()
187
    {
188
        if (_rawHeaders is not null && _rawLines is not null)
×
189
        {
190
            var stringList = new List<string>();
×
191
            var localMax = new int[_rawHeaders.Count];
×
192
            for (int i = 0; i < _rawHeaders.Count; i++)
×
193
            {
194
                if (_rawHeaders[i]?.Length > localMax[i])
×
195
                {
196
                    localMax[i] = _rawHeaders[i]?.Length ?? 0;
×
197
                }
198
            }
199

200
            for (int i = 0; i < _rawLines.Count; i++)
×
201
            {
202
                for (int j = 0; j < _rawLines[i].Count; j++)
×
203
                {
204
                    if (_rawLines[i][j]?.ToString()?.Length > localMax[j])
×
205
                    {
206
                        localMax[j] = _rawLines[i][j]?.ToString()?.Length ?? 0;
×
207
                    }
208
                }
209
            }
210

211
            StringBuilder headerBuilder = new("│ ");
×
212
            for (int i = 0; i < _rawHeaders.Count; i++)
×
213
            {
214
                headerBuilder.Append(_rawHeaders[i]?.PadRight(localMax[i]) ?? "");
×
215
                if (i != _rawHeaders.Count - 1)
×
216
                {
217
                    headerBuilder.Append(" │ ");
×
218
                }
219
                else
220
                {
221
                    headerBuilder.Append(" │");
×
222
                }
223
            }
224
            stringList.Add(headerBuilder.ToString());
×
225

226
            StringBuilder upperBorderBuilder = new(GetCorners[0].ToString());
×
227
            for (int i = 0; i < _rawHeaders.Count; i++)
×
228
            {
229
                upperBorderBuilder.Append(new string('─', localMax[i] + 2));
×
230
                upperBorderBuilder.Append(
×
231
                    (i != _rawHeaders.Count - 1) ? "┬" : GetCorners[1].ToString()
×
232
                );
×
233
            }
234
            stringList.Insert(0, upperBorderBuilder.ToString());
×
235

236
            StringBuilder intermediateBorderBuilder = new("├");
×
237
            for (int i = 0; i < _rawHeaders.Count; i++)
×
238
            {
239
                intermediateBorderBuilder.Append(new string('─', localMax[i] + 2));
×
240
                intermediateBorderBuilder.Append((i != _rawHeaders.Count - 1) ? "┼" : "┤");
×
241
            }
242
            stringList.Add(intermediateBorderBuilder.ToString());
×
243

244
            for (int i = 0; i < _rawLines.Count; i++)
×
245
            {
246
                StringBuilder lineBuilder = new("│ ");
×
247
                for (int j = 0; j < _rawLines[i].Count; j++)
×
248
                {
249
                    lineBuilder.Append(_rawLines[i][j]?.ToString()?.PadRight(localMax[j]) ?? "");
×
250
                    if (j != _rawLines[i].Count - 1)
×
251
                    {
252
                        lineBuilder.Append(" │ ");
×
253
                    }
254
                    else
255
                    {
256
                        lineBuilder.Append(" │");
×
257
                    }
258
                }
259
                stringList.Add(lineBuilder.ToString());
×
260
            }
261

262
            StringBuilder lowerBorderBuilder = new(GetCorners[2].ToString());
×
263
            for (int i = 0; i < _rawHeaders.Count; i++)
×
264
            {
265
                lowerBorderBuilder.Append(new string('─', localMax[i] + 2));
×
266
                lowerBorderBuilder.Append(
×
267
                    (i != _rawHeaders.Count - 1) ? "┴" : GetCorners[3].ToString()
×
268
                );
×
269
            }
270
            stringList.Add(lowerBorderBuilder.ToString());
×
271

272
            _displayArray = stringList.ToArray();
×
273
            BuildTitle();
×
274
        }
275
    }
×
276

277
    private void BuildHeaders()
278
    {
279
        if (_rawHeaders is not null)
×
280
        {
281
            var stringList = new List<string>();
×
282
            var localMax = new int[_rawHeaders.Count];
×
283
            for (int i = 0; i < _rawHeaders.Count; i++)
×
284
            {
285
                if (_rawHeaders[i]?.Length > localMax[i])
×
286
                {
287
                    localMax[i] = _rawHeaders[i]?.Length ?? 0;
×
288
                }
289
            }
290
            StringBuilder headerBuilder = new("│ ");
×
291
            for (int i = 0; i < _rawHeaders.Count; i++)
×
292
            {
293
                headerBuilder.Append(_rawHeaders[i]?.PadRight(localMax[i]) ?? "");
×
294
                if (i != _rawHeaders.Count - 1)
×
295
                {
296
                    headerBuilder.Append(" │ ");
×
297
                }
298
                else
299
                {
300
                    headerBuilder.Append(" │");
×
301
                }
302
            }
303
            stringList.Add(headerBuilder.ToString());
×
304
            StringBuilder upperBorderBuilder = new(GetCorners[0].ToString());
×
305
            for (int i = 0; i < _rawHeaders.Count; i++)
×
306
            {
307
                upperBorderBuilder.Append(new string('─', localMax[i] + 2));
×
308
                upperBorderBuilder.Append(
×
309
                    (i != _rawHeaders.Count - 1) ? "┬" : GetCorners[1].ToString()
×
310
                );
×
311
            }
312
            stringList.Insert(0, upperBorderBuilder.ToString());
×
313
            StringBuilder lowerBorderBuilder = new(GetCorners[2].ToString());
×
314
            for (int i = 0; i < _rawHeaders.Count; i++)
×
315
            {
316
                lowerBorderBuilder.Append(new string('─', localMax[i] + 2));
×
317
                lowerBorderBuilder.Append(
×
318
                    (i != _rawHeaders.Count - 1) ? "┴" : GetCorners[3].ToString()
×
319
                );
×
320
            }
321
            stringList.Add(lowerBorderBuilder.ToString());
×
322
            _displayArray = stringList.ToArray();
×
323
            BuildTitle();
×
324
        }
325
    }
×
326

327
    private void BuildLines()
328
    {
329
        if (_rawLines is not null)
×
330
        {
331
            var stringList = new List<string>();
×
332
            var localMax = new int[_rawLines[0].Count];
×
333
            for (int i = 0; i < _rawLines.Count; i++)
×
334
            {
335
                for (int j = 0; j < _rawLines[i].Count; j++)
×
336
                {
337
                    if (_rawLines[i][j]?.ToString()?.Length > localMax[j])
×
338
                    {
339
                        localMax[j] = _rawLines[i][j]?.ToString()?.Length ?? 0;
×
340
                    }
341
                }
342
            }
343
            for (int i = 0; i < _rawLines.Count; i++)
×
344
            {
345
                StringBuilder line = new("│ ");
×
346
                for (int j = 0; j < _rawLines[i].Count; j++)
×
347
                {
348
                    line.Append(_rawLines[i][j]?.ToString()?.PadRight(localMax[j]) ?? "");
×
349
                    if (j != _rawLines[i].Count - 1)
×
350
                    {
351
                        line.Append(" │ ");
×
352
                    }
353
                    else
354
                    {
355
                        line.Append(" │");
×
356
                    }
357
                }
358
                stringList.Add(line.ToString());
×
359
            }
360
            StringBuilder upperBorderBuilder = new(GetCorners[0].ToString());
×
361
            for (int i = 0; i < _rawLines.Count; i++)
×
362
            {
363
                upperBorderBuilder.Append(new string('─', localMax[i] + 2));
×
364
                upperBorderBuilder.Append(
×
365
                    (i != _rawLines.Count - 1) ? "┬" : GetCorners[1].ToString()
×
366
                );
×
367
            }
368
            stringList.Insert(0, upperBorderBuilder.ToString());
×
369
            StringBuilder lowerBorderBuilder = new(GetCorners[2].ToString());
×
370
            for (int i = 0; i < _rawLines.Count; i++)
×
371
            {
372
                lowerBorderBuilder.Append(new string('─', localMax[i] + 2));
×
373
                lowerBorderBuilder.Append(
×
374
                    (i != _rawLines.Count - 1) ? "┴" : GetCorners[3].ToString()
×
375
                );
×
376
            }
377
            stringList.Add(lowerBorderBuilder.ToString());
×
378
            _displayArray = stringList.ToArray();
×
379
            BuildTitle();
×
380
        }
381
    }
×
382

383
    private void BuildTitle()
384
    {
385
        if (_title is not null)
×
386
        {
387
            var len = _displayArray![0].Length;
×
388
            var title = _title.ResizeString(len - 4);
×
389
            title = $"│ {title} │";
×
390
            var upperBorderBuilder = new StringBuilder(GetCorners[0].ToString());
×
391
            upperBorderBuilder.Append(new string('─', len - 2));
×
392
            upperBorderBuilder.Append(GetCorners[1].ToString());
×
393
            var display = _displayArray.ToList();
×
394
            display[0] = display[0]
×
395
                .Remove(0, 1)
×
396
                .Insert(0, "├")
×
397
                .Remove(display[1].Length - 1, 1)
×
398
                .Insert(display[1].Length - 1, "┤");
×
399
            display.Insert(0, title);
×
400
            display.Insert(0, upperBorderBuilder.ToString());
×
401
            _displayArray = display.ToArray();
×
402
        }
403
    }
×
404
    #endregion
405

406
    #region Properties: get corners, count
407
    private string GetCorners => _roundedCorners ? "╭╮╰╯" : "┌┐└┘";
×
408

409
    /// <summary>
410
    /// This property returns the number of lines in the table.
411
    /// </summary>
412
    public int Count => _rawLines?.Count ?? 0;
×
413

414
    #endregion
415

416
    #region Methods: Get, Add, Update, Remove, Clear
417
    /// <summary>
418
    /// This method adds headers to the table.
419
    /// </summary>
420
    /// <param name="headers">The headers to add.</param>
421
    public void AddHeaders(List<string> headers)
422
    {
423
        _rawHeaders = headers;
×
424
        if (CompatibilityCheck())
×
425
        {
426
            BuildTable();
×
427
        }
428
        else
429
        {
430
            _rawHeaders = null;
×
431
        }
432
    }
×
433

434
    /// <summary>
435
    /// This method updates the headers of the table.
436
    /// </summary>
437
    /// <param name="headers">The headers to update.</param>
438
    public void UpdateHeaders(List<string> headers)
439
    {
440
        AddHeaders(headers);
×
441
    }
×
442

443
    /// <summary>
444
    /// This method adds a title to the table.
445
    /// </summary>
446
    /// <param name="title">The title to add.</param>
447
    public void AddTitle(string title)
448
    {
449
        _title = title;
×
450
        BuildTable();
×
451
    }
×
452

453
    /// <summary>
454
    /// This method updates the title of the table.
455
    /// </summary>
456
    /// <param name="title">The title to update.</param>
457
    public void UpdateTitle(string title)
458
    {
459
        AddTitle(title);
×
460
    }
×
461

462
    /// <summary>
463
    /// Toggles the rounded corners of the table.
464
    /// </summary>
465
    /// <remarks>Refer to the example project to understand how to implement it available at https://github.com/MorganKryze/ConsoleAppVisuals/blob/main/example/Program.cs </remarks>
466
    public void SetRoundedCorners(bool rounded = true)
467
    {
468
        _roundedCorners = rounded;
×
469
        BuildTable();
×
470
    }
×
471

472
    /// <summary>
473
    /// This property returns the specified line in the table.
474
    /// </summary>
475
    /// <param name="index">The index of the line to return.</param>
476
    /// <returns>The line at the specified index.</returns>
477
    /// <exception cref="ArgumentOutOfRangeException">Is thrown when the index is out of range.</exception>
478
    /// <remarks>Refer to the example project to understand how to implement it available at https://github.com/MorganKryze/ConsoleAppVisuals/blob/main/example/Program.cs </remarks>
479
    public List<T> GetLine(int index)
480
    {
481
        if (index < 0 || index >= _rawLines?.Count)
×
482
        {
483
            throw new ArgumentOutOfRangeException(nameof(index), "The index is out of range.");
×
484
        }
485
        return _rawLines![index];
×
486
    }
487

488
    /// <summary>
489
    /// This method is used to get all the elements from a column given its index.
490
    /// </summary>
491
    /// <param name="index">The index of the column.</param>
492
    /// <returns>The elements of the column.</returns>
493
    /// <exception cref="ArgumentOutOfRangeException">Is thrown when the index is out of range.</exception>
494
    public List<T>? GetColumnData(int index)
495
    {
496
        if (_rawLines is null)
×
497
        {
498
            return null;
×
499
        }
500

501
        if (index < 0 || index >= _rawLines[0].Count)
×
502
        {
503
            throw new ArgumentOutOfRangeException(nameof(index), "Invalid column index.");
×
504
        }
505

506
        List<T>? list = new();
×
507
        for (int i = 0; i < _rawLines.Count; i++)
×
508
        {
509
            list.Add(_rawLines[i][index]);
×
510
        }
511
        return list;
×
512
    }
513

514
    /// <summary>
515
    /// This method is used to get all the elements from a column given its header.
516
    /// </summary>
517
    /// <param name="header">The header of the column.</param>
518
    /// <returns>The elements of the column.</returns>
519
    /// <exception cref="InvalidOperationException">Is thrown when the table is empty.</exception>
520
    /// <exception cref="ArgumentOutOfRangeException">Is thrown when the header is invalid.</exception>
521
    public List<T>? GetColumnData(string header)
522
    {
523
        if (_rawHeaders is null)
×
524
        {
525
            throw new InvalidOperationException("The headers are null.");
×
526
        }
527
        else if (_rawLines is null)
×
528
        {
529
            return null;
×
530
        }
531
        if (!_rawHeaders.Contains(header))
×
532
        {
533
            throw new ArgumentOutOfRangeException(nameof(header), "Invalid column header.");
×
534
        }
535

536
        return GetColumnData(_rawHeaders.IndexOf(header));
×
537
    }
538

539
    /// <summary>
540
    /// This method adds a line to the table.
541
    /// </summary>
542
    /// <param name="line">The line to add.</param>
543
    /// <exception cref="ArgumentException">Is thrown when the number of columns in the table is not consistent with itself or with the headers.</exception>
544
    /// <remarks>Refer to the example project to understand how to implement it available at https://github.com/MorganKryze/ConsoleAppVisuals/blob/main/example/Program.cs </remarks>
545
    public void AddLine(List<T> line)
546
    {
547
        if (_rawLines?.Count > 0 && line.Count != _rawLines[0].Count)
×
548
        {
549
            throw new ArgumentException(
×
550
                "The number of columns in the table is not consistent with other lines."
×
551
            );
×
552
        }
553
        if (_rawHeaders is not null && line.Count != _rawHeaders.Count)
×
554
        {
555
            throw new ArgumentException(
×
556
                "The number of columns in the table is not consistent with the headers."
×
557
            );
×
558
        }
559
        _rawLines ??= new List<List<T>>();
×
560
        _rawLines.Add(line);
×
561
        BuildTable();
×
562
    }
×
563

564
    /// <summary>
565
    /// This method removes a line from the table.
566
    /// </summary>
567
    /// <param name="index">The index of the line to remove.</param>
568
    /// <exception cref="ArgumentOutOfRangeException">Is thrown when the index is out of range.</exception>
569
    /// <remarks>Refer to the example project to understand how to implement it available at https://github.com/MorganKryze/ConsoleAppVisuals/blob/main/example/Program.cs </remarks>
570
    public void RemoveLine(int index)
571
    {
572
        if (_rawLines?.Count > 0 && (index < 0 || index >= _rawLines.Count))
×
573
        {
574
            throw new ArgumentOutOfRangeException(nameof(index), "The index is out of range.");
×
575
        }
576

577
        _rawLines?.RemoveAt(index);
×
578
        BuildTable();
×
579
    }
×
580

581
    /// <summary>
582
    /// This method updates a line in the table.
583
    /// </summary>
584
    /// <param name="index">The index of the line to update.</param>
585
    /// <param name="line">The new line.</param>
586
    /// <exception cref="ArgumentOutOfRangeException">Is thrown when the index is out of range.</exception>
587
    /// <exception cref="ArgumentException">Is thrown when the number of columns in the table is not consistent with itself or with the headers.</exception>
588
    /// <remarks>Refer to the example project to understand how to implement it available at https://github.com/MorganKryze/ConsoleAppVisuals/blob/main/example/Program.cs </remarks>
589
    public void UpdateLine(int index, List<T> line)
590
    {
591
        if (_rawLines?.Count > 0)
×
592
        {
593
            if (index < 0 || index >= _rawLines.Count)
×
594
            {
595
                throw new ArgumentOutOfRangeException(nameof(index), "The index is out of range.");
×
596
            }
597

598
            if (line.Count != _rawHeaders?.Count)
×
599
            {
600
                throw new ArgumentException(
×
601
                    "The number of columns in the table is not consistent."
×
602
                );
×
603
            }
604
        }
605
        _rawLines![index] = line;
×
606
        BuildTable();
×
607
    }
×
608

609
    /// <summary>
610
    /// This method clears the headers of the table.
611
    /// </summary>
612
    public void ClearHeaders()
613
    {
614
        _rawHeaders = null;
×
615
        BuildTable();
×
616
    }
×
617

618
    /// <summary>
619
    /// This method clears the lines of the table.
620
    /// </summary>
621
    public void ClearLines()
622
    {
623
        _rawLines = null;
×
624
        BuildTable();
×
625
    }
×
626

627
    /// <summary>
628
    /// This method clears the table.
629
    /// </summary>
630
    public void Reset()
631
    {
632
        _title = null;
×
633
        _rawHeaders?.Clear();
×
634
        _rawLines?.Clear();
×
635
        _displayArray = null;
×
636
    }
×
637
    #endregion
638

639
    #region Display Methods
640
    /// <summary>
641
    /// This method displays the table without interaction.
642
    /// </summary>
643
    protected override void RenderElementActions()
644
    {
645
        int minIndex = GetMinIndex(_excludeHeader);
×
646
        int maxIndex = GetMaxIndex(_excludeFooter);
×
647
        int index = minIndex;
×
648

649
        while (true)
650
        {
651
            string[] array = new string[_displayArray!.Length];
×
652
            for (int j = 0; j < _displayArray.Length; j++)
×
653
            {
654
                array[j] = _displayArray[j];
×
655
                Core.WritePositionedString(array[j], TextAlignment.Center, false, _line + j);
×
656
                if (j == index)
×
657
                {
658
                    Core.WritePositionedString(
×
659
                        j == _displayArray.Length - 1
×
660
                            ? array[j].InsertString($"┤ {_footerText} ├", Placement.TopCenter)[
×
661
                                2..^2
×
662
                            ]
×
663
                            : array[j][1..^1],
×
664
                        TextAlignment.Center,
×
665
                        true,
×
666
                        _line + j
×
667
                    );
×
668
                }
669
            }
670
            switch (Console.ReadKey(intercept: true).Key)
×
671
            {
672
                case ConsoleKey.UpArrow:
673
                case ConsoleKey.Z:
674
                    index = HandleUpArrowKey(index, minIndex, maxIndex);
×
675
                    break;
×
676
                case ConsoleKey.DownArrow:
677
                case ConsoleKey.S:
678
                    index = HandleDownArrowKey(index, minIndex, maxIndex);
×
679
                    break;
×
680
                case ConsoleKey.Enter:
681
                    SendResponse(
×
682
                        this,
×
683
                        new InteractionEventArgs<int>(Output.Select, ReturnIndex(index))
×
684
                    );
×
685
                    return;
×
686
                case ConsoleKey.Escape:
687
                    SendResponse(this, new InteractionEventArgs<int>(Output.Exit, 0));
×
688
                    return;
×
689
                case ConsoleKey.Backspace:
690
                    SendResponse(
×
691
                        this,
×
692
                        new InteractionEventArgs<int>(Output.Delete, ReturnIndex(index))
×
693
                    );
×
694
                    return;
×
695
            }
696
        }
697
    }
698

699
    int ReturnIndex(int index)
700
    {
701
        return index - GetMinIndex(_excludeHeader);
×
702
    }
703

704
    int GetMinIndex(bool excludeHeader)
705
    {
706
        if (excludeHeader)
×
707
        {
708
            return _rawHeaders is null ? 3 : 5;
×
709
        }
710
        else
711
        {
712
            return 0;
×
713
        }
714
    }
715

716
    int GetMaxIndex(bool excludeFooter)
717
    {
718
        return excludeFooter ? _displayArray!.Length - 2 : _displayArray!.Length - 1;
×
719
    }
720

721
    static int HandleUpArrowKey(int index, int minIndex, int maxIndex)
722
    {
723
        if (index == minIndex)
×
724
        {
725
            return maxIndex;
×
726
        }
727
        else if (index > minIndex)
×
728
        {
729
            return index - 1;
×
730
        }
731
        return index;
×
732
    }
733

734
    static int HandleDownArrowKey(int index, int minIndex, int maxIndex)
735
    {
736
        if (index == maxIndex)
×
737
        {
738
            return minIndex;
×
739
        }
740
        else if (index < maxIndex)
×
741
        {
742
            return index + 1;
×
743
        }
744
        return index;
×
745
    }
746
    #endregion
747
}
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

© 2025 Coveralls, Inc