NumeRe v1.1.4
NumeRe: Framework für Numerische Rechnungen
TextManager.cpp
Go to the documentation of this file.
1/*****************************************************************************
2 NumeRe: Framework fuer Numerische Rechnungen
3 Copyright (C) 2018 Erik Haenel et al.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17******************************************************************************/
18
19
20#include "TextManager.h"
21
22#include <iostream>
23#include <stdlib.h>
24#include <wx/wx.h>
25#include <wx/file.h>
26#include <wx/dcmemory.h>
27#include <wx/image.h>
28#include "gterm.hpp"
29
30using namespace std;
31
46TextManager::TextManager(GenericTerminal* parent, int width, int height, int maxWidth, int maxHeight /* = 50 */)
47 : m_parent(parent), m_viewportWidth(width), m_viewportHeight(height), m_maxWidth(maxWidth), m_maxHeight(maxHeight), m_virtualCursor(0)
48{
49 if (m_parent != nullptr)
50 {
51 Reset();
52 }
53
54}
55
56
61{
62 Reset();
63}
64
65
76void TextManager::printOutput(const string& sLine)
77{
78 // Create a new line if the buffer is empty
79 if (!m_managedText.size())
80 newLine();
81
82 // Copy the line and determine, whether the current line
83 // contains the error signature (character #15)
84 string _sLine = sLine;
85 bool isErrorLine = _sLine.find((char)15) != string::npos;
86
87 // Remove the error signature
88 while (_sLine.find((char)15) != string::npos)
89 _sLine.erase(_sLine.find((char)15), 1);
90
91 // Append the line to the current line
92 m_managedText.back() += CharacterVector(_sLine, KERNEL_TEXT);
93
94 // Synchronize the rendered layout by deleting the
95 // current line
97
98 // Update the colors and render the layout
99 updateColors(isErrorLine);
100 renderLayout();
101}
102
103
115void TextManager::insertInput(const string& sLine, size_t logicalpos /*= string::npos*/)
116{
117 // Ensure that the logical position is a valid position
118 if (logicalpos == string::npos)
119 logicalpos = m_managedText.back().length();
120
121 // Insert the text at the desired position
122 m_managedText.back().insert(logicalpos, sLine, EDITABLE_TEXT);
123
124 // Synchronize the rendered layout by deleting the
125 // current line
127
128 // Update colors and render the layout
129 updateColors();
130 renderLayout();
131}
132
133
145{
146 // Ensure that the cursor is valid
147 if (!logCursor)
148 return ViewCursor();
149
150 // Find the logical cursor in the rendered layout
151 // Start at the line of the logical cursor, because this is the first
152 // possible line in the rendered layout
153 for (size_t i = logCursor.line; i < m_renderedBlock.size(); i++)
154 {
155 if (!m_renderedBlock[i].coords.size())
156 break;
157
158 // Ensure that the first coordinate in the line is valid
159 if (m_renderedBlock[i].coords[0] && m_renderedBlock[i].coords[0].line == logCursor.line)
160 {
161 for (size_t j = 0; j < m_renderedBlock[i].coords.size(); j++)
162 {
163 if (m_renderedBlock[i].coords[j].pos == logCursor.pos)
164 {
165 return ViewCursor(j, i - (m_topLine - m_numLinesScrolledUp));
166 }
167 }
168 }
169
170 // If it is not valid, it probably is a hanging indent
171 if (!m_renderedBlock[i].coords[0] && m_renderedBlock[i].coords[m_indentDepth].line == logCursor.line)
172 {
173 for (size_t j = m_indentDepth; j < m_renderedBlock[i].coords.size(); j++)
174 {
175 if (m_renderedBlock[i].coords[j].pos == logCursor.pos)
176 {
177 return ViewCursor(j, i - (m_topLine - m_numLinesScrolledUp));
178 }
179 }
180
181 }
182 }
183
184 // return an invalid cursor, if nothing was found
185 return ViewCursor();
186}
187
188
199{
200 // If the text was not rendered yet, return an invalid cursor
201 if (!m_renderedBlock.size())
202 return ViewCursor();
203
204 // return the converted logical cursor
206}
207
208
220{
221 // Go to the corresponding x and y positions in the rendered layout
222 // block and return the contained coordinates
223 if (viewCursor && m_renderedBlock.size() > m_topLine - m_numLinesScrolledUp + viewCursor.y)
224 {
225 // Ensure that the current line is long enough
226 if (m_renderedBlock[m_topLine - m_numLinesScrolledUp + viewCursor.y].coords.size() > viewCursor.x)
227 return m_renderedBlock[m_topLine - m_numLinesScrolledUp + viewCursor.y].coords[viewCursor.x];
228 }
229
230 // Return an invalid cursor, if the corresponding position may not be found
231 return LogicalCursor();
232}
233
234
246{
247 // Ensure that there's text in the buffer
248 if (!m_managedText.size())
249 return LogicalCursor();
250
251 // Construct a valid cursor with the dimensions of the
252 // text buffer
253 return LogicalCursor(m_managedText.back().length(), m_managedText.size()-1);
254}
255
256
268string TextManager::getRenderedString(size_t viewLine) const
269{
270 // Return an empty line, if the line is not valid
271 if (viewLine + m_topLine - m_numLinesScrolledUp >= m_renderedBlock.size() || viewLine > (size_t)m_viewportHeight)
272 return "";
273
274 return m_renderedBlock[m_topLine - m_numLinesScrolledUp + viewLine].sLine;
275}
276
277
289vector<unsigned short> TextManager::getRenderedColors(size_t viewLine) const
290{
291 // Return an empty vector, if the line is not valid
292 if (viewLine + m_topLine - m_numLinesScrolledUp >= m_renderedBlock.size() || viewLine > (size_t)m_viewportHeight)
293 return vector<unsigned short>();
294
295 // Copy the current color line
296 vector<unsigned short> colors = m_renderedBlock[m_topLine - m_numLinesScrolledUp + viewLine].colors;
297
298 // Copy, whether there is a part of the current line is selected
299 for (size_t i = 0; i < m_renderedBlock[m_topLine - m_numLinesScrolledUp + viewLine].coords.size(); i++)
300 {
301 LogicalCursor coords = m_renderedBlock[m_topLine - m_numLinesScrolledUp + viewLine].coords[i];
302
303 if (m_managedText[coords.line].size() > coords.pos && m_managedText[coords.line][coords.pos].isSelected())
304 colors[i] |= GenericTerminal::SELECTED;
305 }
306
307 // return the colors
308 return colors;
309}
310
311
321int TextManager::calc_color( int fg, int bg, int flags )
322{
323 return (flags & 15) | (fg << 4) | (bg << 8);
324}
325
326
337void TextManager::updateColors(bool isErrorLine /*= false*/)
338{
339 // Get a pointer to the current syntax lexer
340 NumeReSyntax* syntax = m_parent->getSyntax();
341 string sColors;
342
343 // If the current line shall be an error line, highlight it
344 // correspondingly. Otherwise style it with the usual
345 // lexer function
346 if (isErrorLine)
347 sColors = syntax->highlightError(m_managedText.back().toString());
348 else
349 sColors = syntax->highlightLine(m_managedText.back().toString());
350
351 // Convert the string characters to the correct color codes
352 for (size_t i = 0; i < sColors.length(); i++)
353 {
354 if ((int)(sColors[i] - '0') == NumeReSyntax::SYNTAX_COMMAND)
355 m_managedText.back()[i].setColor(calc_color((int)(sColors[i] - '0'), 0, GenericTerminal::BOLD | GenericTerminal::UNDERLINE));
356 else if ((int)(sColors[i] - '0') == NumeReSyntax::SYNTAX_FUNCTION
357 || (int)(sColors[i] - '0') == NumeReSyntax::SYNTAX_CONSTANT
358 || (int)(sColors[i] - '0') == NumeReSyntax::SYNTAX_SPECIALVAL
359 || (int)(sColors[i] - '0') == NumeReSyntax::SYNTAX_METHODS
360 || (int)(sColors[i] - '0') == NumeReSyntax::SYNTAX_PROCEDURE)
361 m_managedText.back()[i].setColor(calc_color((int)(sColors[i] - '0'), 0, GenericTerminal::BOLD));
362 else if ((int)(sColors[i] - '0') == NumeReSyntax::SYNTAX_COMMENT)
363 m_managedText.back()[i].setColor(calc_color((int)(sColors[i] - '0'), 0, GenericTerminal::BOLD));
364 else
365 m_managedText.back()[i].setColor(calc_color((int)(sColors[i] - '0'), 0, 0));
366 }
367}
368
369
382{
383 size_t lastRenderedLine = 0;
384
385 // Get the last rendered line of the current rendered
386 // block
387 if (m_renderedBlock.size())
388 lastRenderedLine = m_renderedBlock.back().coords.back().line + 1;
389
390 // If the last rendered line is larger than the current
391 // available managed text, clear it completely and
392 // render a new layout
393 if (lastRenderedLine >= m_managedText.size())
394 {
395 lastRenderedLine = 0;
396 m_renderedBlock.clear();
397 }
398
399 // Go through the complete container
400 for (size_t i = lastRenderedLine; i < m_managedText.size(); i++)
401 {
402 size_t lastbreakpos = 0;
403 bool firstline = true;
404 LogicalCursor cursor(0, i);
405
406 // Break the text lines at reasonable locations
407 do
408 {
409 RenderedLine rLine;
410
411 // If the last break position is non-zero, this is not a first line
412 if (lastbreakpos)
413 firstline = false;
414
415 // Get the new break position
416 size_t breakpos = findNextLinebreak(m_managedText[i].toString(), lastbreakpos);
417
418 // If it's not the first line, add the indent here
419 if (!firstline)
420 {
421 rLine.sLine = "| ";
422 rLine.colors.assign(m_indentDepth, calc_color(7, 0, 0));
423 rLine.coords.assign(m_indentDepth, LogicalCursor());
424 }
425
426 // Assign text and colors
427 rLine.sLine += m_managedText[i].substr(lastbreakpos, breakpos - lastbreakpos);
428 vector<unsigned short> colors = m_managedText[i].subcolors(lastbreakpos, breakpos - lastbreakpos);
429 rLine.colors.insert(rLine.colors.end(), colors.begin(), colors.end());
430
431 // The last line has an additional white space character,
432 // which is used as input location (to ensure that the cursor is valid)
433 if (i + 1 == m_managedText.size())
434 {
435 rLine.sLine += " ";
436 rLine.colors.push_back(calc_color(7, 0, 0));
437 }
438
439 // Assign the logical cursors
440 for (size_t j = 0; j < rLine.sLine.length() - m_indentDepth*(!firstline); j++)
441 {
442 cursor.pos = j + lastbreakpos;
443 rLine.coords.push_back(cursor);
444 }
445
446 lastbreakpos = breakpos;
447
448 // Store the rendered line
449 m_renderedBlock.push_back(rLine);
450 }
451 while (lastbreakpos < m_managedText[i].length());
452 }
453
454 // Calculate new topline, because it depends on the size of the rendered block
456
457 if (m_topLine < 0)
458 m_topLine = 0;
459}
460
461
475{
476 if (m_renderedBlock.size() && linesToDelete)
477 {
478 // If the number of lines are larger than the
479 // available lines, simply clear the whole block
480 if (m_renderedBlock.size() <= abs(linesToDelete))
481 {
482 m_renderedBlock.clear();
483 return;
484 }
485
486 if (linesToDelete > 0)
487 {
488 // Delete lines from the front
489 while (m_renderedBlock.size() && (!m_renderedBlock.front().coords.size() || m_renderedBlock.front().coords.back().line < (size_t)linesToDelete))
490 {
491 m_renderedBlock.pop_front();
492 }
493
494 // Update the line numbers in the coords field,
495 // because the leading lines have been removed and
496 // the algorithm requires that the line numbering
497 // starts from zero
498 for (size_t i = 0; i < m_renderedBlock.size(); i++)
499 {
500 for (size_t j = 0; j < m_renderedBlock[i].coords.size(); j++)
501 {
502 if (m_renderedBlock[i].coords[j].isValid)
503 m_renderedBlock[i].coords[j].line -= linesToDelete;
504 }
505 }
506 }
507 else
508 {
509 // Delete lines from the back
510 //
511 // Find the corresponding line from the back
512 linesToDelete = (int)m_renderedBlock.back().coords.back().line + linesToDelete;
513
514 while (m_renderedBlock.size() && (!m_renderedBlock.back().coords.size() || m_renderedBlock.back().coords.back().line > (size_t)linesToDelete))
515 {
516 m_renderedBlock.pop_back();
517 }
518 }
519 }
520}
521
522
534size_t TextManager::findNextLinebreak(const string& currentLine, size_t currentLinebreak) const
535{
536 // If the current line is shorter than the current viewport width,
537 // return the length of the current line as next break position
538 if (m_viewportWidth + currentLinebreak - m_indentDepth * (bool)currentLinebreak > currentLine.length())
539 return currentLine.length();
540
541 // Store the valid line break characters
542 static string sValidLinebreaks = "+- ,;.*/<>=!";
543
544 // Find the next possible break position
545 for (int i = currentLinebreak + m_viewportWidth - 1 - m_indentDepth * (bool)currentLinebreak; i >= (int)currentLinebreak; i--)
546 {
547 // If the current character marks a valid line break position,
548 // return the character after it
549 if (sValidLinebreaks.find(currentLine[i]) != string::npos)
550 return i+1;
551 }
552
553 // The fall back solution, if no valid position is found
554 return currentLinebreak + m_viewportWidth - m_indentDepth * (bool)currentLinebreak;
555}
556
557
565{
566 // If the buffer is empty add an empty line first
567 if (!m_managedText.size())
568 newLine();
569
570 // Get the length of the current input line
571 size_t currentPos = m_managedText.back().length();
572
573 // Determine the length of the current tab, which is
574 // between 1 and m_tabLength
575 size_t tabLength = m_tabLength - (currentPos % m_tabLength);
576
577 // Append the length of the tab as
578 // whitespaces to the text buffer
579 m_managedText.back().append(tabLength, ' ');
580
581 // Synchronize the rendered layout by deleting the
582 // current line
584
585 // Return the calculated tab length
586 return tabLength;
587}
588
589
601{
602 // Add a new line to all buffers and fill it with a reasonable value
604
605 // Ensure that the buffer is not larger than the desired history length
606 while (m_managedText.size() > (size_t)m_maxHeight)
607 {
608 m_managedText.pop_front();
609
610 // Synchronize the rendered layout by deleting the
611 // first line
613 }
614
615 // Remove the last line due to the additional input character
617
618 // render layout, get new top line and reset the virtual cursor line
619 renderLayout();
621}
622
623
637{
638 // Ensure that the cursor is valid
639 if (!logCursor)
640 return;
641
642 // Apply a backspace
643 if (logCursor.pos)
644 {
645 // In the current line
646 m_managedText[logCursor.line].erase(m_managedText[logCursor.line].begin() + logCursor.pos - 1);
647 }
648 else
649 {
650 // go to the previous line
651 m_managedText[logCursor.line - 1].pop_back();
652 }
653
654 // Synchronize the rendered layout by deleting the
655 // current line
657
658 // Update the colors and render the layout
659 updateColors();
660 renderLayout();
661}
662
663
675{
676 // Do nothing if the buffer is empty
677 if (!m_managedText.size())
678 return;
679
680 // Clear the lines and fill them with a
681 // reasonable default content (just like in
682 // the new line function)
683 m_managedText.back().clear();
684
685 // Synchronize the rendered layout by deleting the
686 // current line
688
689 // Render the layout
690 renderLayout();
691}
692
693
706bool TextManager::clearRange(const ViewCursor& cursor1, const ViewCursor& cursor2)
707{
708 // Transform the view cursors to logical cursors
709 LogicalCursor logCursor1 = toLogicalCursor(cursor1);
710 LogicalCursor logCursor2 = toLogicalCursor(cursor2);
711
712 // Ensure that the cursors are both valid
713 if (!logCursor1 || !logCursor2)
714 return false;
715
716 // Ensure that their order is correct
717 if (logCursor1 > logCursor2)
718 {
719 LogicalCursor temp = logCursor1;
720 logCursor1 = logCursor2;
721 logCursor2 = temp;
722 }
723
724 // Synchronize the rendered layout by deleting the
725 // current line
726 synchronizeRenderedBlock(min(logCursor1.line, logCursor2.line) - m_managedText.size() - 1);
727
728 // As long as the second cursor is at a larger position than the first character
729 while (logCursor2 > logCursor1)
730 {
731 if (logCursor1.line != logCursor2.line)
732 {
733 // The cursors are in different lines
734 // Erase all from the first to the cursor's position
735 m_managedText[logCursor2.line].erase(m_managedText[logCursor2].begin(), m_managedText[logCursor2].begin()+logCursor2.pos);
736
737 // If the text buffer of the current line is empty,
738 // erase the overall line from all three buffers
739 if (!m_managedText[logCursor2.line].length())
740 {
741 m_managedText.erase(m_managedText.begin()+logCursor2.line);
742 }
743
744 // set the cursor to the last position of the previous line
745 logCursor2.line--;
746 logCursor2.pos = m_managedText[logCursor2.line].length();
747 }
748 else
749 {
750 // The cursors are in the same line
751 m_managedText[logCursor2.line].erase(m_managedText[logCursor2.line].begin() + logCursor1.pos, m_managedText[logCursor2.line].begin() + logCursor2.pos);
752 break;
753 }
754 }
755
756 // Update colors and render the layout
757 updateColors();
758 renderLayout();
759
760 return true;
761}
762
763
775void TextManager::selectText(const ViewCursor& viewCursor, bool bSelect /*= true*/)
776{
777 // Convert the view cursor to a logical cursor
778 LogicalCursor cursor = toLogicalCursor(viewCursor);
779
780 // Ensure that the cursor is valid
781 if (!cursor)
782 return;
783
784 // Select or deselect the pointer character
785 if (bSelect)
786 m_managedText[cursor.line][cursor.pos].select();
787 else
788 m_managedText[cursor.line][cursor.pos].unselect();
789}
790
791
799{
800 for (size_t i = 0; i < m_managedText.size(); i++)
801 {
802 for (size_t j = 0; j < m_managedText[i].length(); j++)
803 {
804 m_managedText[i][j].unselect();
805 }
806 }
807}
808
809
819bool TextManager::isSelected(const ViewCursor& viewCursor) const
820{
821 // Convert the view cursor into a logical cursor and
822 // check for selection
823 return isSelectedLogical(toLogicalCursor(viewCursor));
824}
825
826
836{
837 // Ensure that the cursor is valid
838 if (!cursor)
839 return false;
840
841 // Return true, if the color line at the current contains the SELECTED flag
842 return m_managedText[cursor.line][cursor.pos].isSelected();
843}
844
845
853{
854 string sText;
855
856 // Find every selected character in the text buffer
857 for (size_t i = 0; i < m_managedText.size(); i++)
858 {
859 for (size_t j = 0; j < m_managedText[i].size(); j++)
860 {
861 if (m_managedText[i][j].isSelected())
862 {
863 sText += m_managedText[i][j].m_char;
864 }
865 }
866
867 // Append a new line character after each new line
868 if (sText.length() && sText.back() != '\n')
869 sText += '\n';
870 }
871
872 // Remove all trailing new line characters
873 while (sText.back() == '\n')
874 sText.pop_back();
875
876 // return the selected text
877 return sText;
878}
879
880
890{
891 // Ensure that the buffer is available and that there's user text
892 if (!m_managedText.size() || !m_managedText.back().back().editable())
893 return "";
894
895 string sInput;
896
897 // Find the beginning of the user text
898 for (int i = m_managedText.back().size()-1; i >= 0; i--)
899 {
900 if (!m_managedText.back()[i].editable())
901 {
902 sInput = m_managedText.back().substr(i+1);
903 break;
904 }
905 }
906
907 return sInput;
908}
909
910
920{
921 // Ensure that the buffer is available and that there's user text
922 if (m_managedText.size() < 2)
923 return "";
924
925 return m_managedText[m_managedText.size()-2].toString();
926}
927
928
938{
939 m_managedText.clear();
940 m_renderedBlock.clear();
941
945
946 m_linesReceived = 1;
947
948 m_tabLength = 8;
949 m_indentDepth = 4;
950}
951
952
964{
965 return getRenderedString(index);
966}
967
968
980bool TextManager::Scroll(int numLines, bool scrollUp)
981{
982 int actualLinesToScroll = numLines;
983
984 if (scrollUp)
985 {
986 // skip out if we're scrolled all the way up
988 {
989 return false;
990 }
991
992 // If one wants to scrol more lines than available,
993 // then restrict them
994 if (m_topLine < actualLinesToScroll)
995 {
996 actualLinesToScroll = m_topLine;
997 }
998
999 // This is the maximal possible distance
1000 int limiter = m_topLine - m_numLinesScrolledUp;
1001 if (actualLinesToScroll > limiter)
1002 {
1003 actualLinesToScroll = limiter;
1004 }
1005
1006 // scroll up
1007 m_numLinesScrolledUp += actualLinesToScroll;
1008 }
1009 else
1010 {
1011 // Ignore, if we're completely scrolled down
1012 if (m_numLinesScrolledUp <= 0)
1013 {
1014 return false;
1015 }
1016
1017 // These are the possible lines to scroll down
1018 int linesBelow = m_renderedBlock.size() - (m_topLine + m_viewportHeight - m_numLinesScrolledUp);
1019
1020 // Limit the lines to scroll down
1021 if ( linesBelow < actualLinesToScroll)
1022 {
1023 actualLinesToScroll = linesBelow;
1024 }
1025
1026 // scroll down
1027 m_numLinesScrolledUp -= actualLinesToScroll;
1028
1029 // Ensure that we're not negatively scrolled
1030 if (m_numLinesScrolledUp < 0)
1031 {
1033 }
1034 }
1035 return true;
1036}
1037
1038
1048{
1049 return m_managedText.size();
1050}
1051
1052
1064void TextManager::Resize(int width, int height)
1065{
1066 // Get the current top line
1067 // We've to explicitly create a ViewCursor with (0,0),
1068 // because otherwise the cursor won't be valid
1070
1071 // Store the new dimensions
1072 m_viewportHeight = height;
1073 m_viewportWidth = width;
1074
1075 // Clear the current layout and render
1076 // the layout completely new
1077 m_renderedBlock.clear();
1078 renderLayout();
1079
1080 // If the terminal is scrolled up, get the corresponding top line
1081 // and use it to determine the new number of scrolled lines
1082 int nNewTopLine = 0;
1083 if (m_numLinesScrolledUp > 0)
1084 {
1085 for (size_t i = 0; i < m_renderedBlock.size(); i++)
1086 {
1087 if (m_renderedBlock[i].coords.size() && m_renderedBlock[i].coords[0].line == cursor.line)
1088 {
1089 for (size_t j = 0; j < m_renderedBlock[i].coords.size(); j++)
1090 {
1091 if (m_renderedBlock[i].coords[j].pos == cursor.pos)
1092 {
1093 // If we found the current position, we break the loop
1094 nNewTopLine = i;
1095 break;
1096 }
1097 }
1098 }
1099 // Break if the variable is non-zero
1100 if (nNewTopLine)
1101 break;
1102 }
1103 }
1104
1105 // If a top line was found, calculate the new number
1106 // of scrolled lines
1107 if (nNewTopLine)
1108 {
1109 m_numLinesScrolledUp = nNewTopLine - m_topLine;
1110 if (m_numLinesScrolledUp < 0)
1112 }
1113}
1114
1115
1125string TextManager::GetInputHistory(bool vcursorup)
1126{
1127 if (vcursorup)
1128 {
1129 // scroll up
1130 // decrement the virtual cursor
1132
1133 if (m_virtualCursor >= (int)m_managedText.size())
1134 m_virtualCursor = m_managedText.size() - 1;
1135
1136 // While the virtual cursor is non-zero
1137 while (m_virtualCursor)
1138 {
1139 // find the next user text and return it
1140 for (size_t i = 0; i < m_managedText[m_virtualCursor].size(); i++)
1141 {
1142 if (m_managedText[m_virtualCursor][i].userText())
1143 {
1144 for (size_t j = i; j < m_managedText[m_virtualCursor].size(); j++)
1145 {
1146 if (!m_managedText[m_virtualCursor][j].userText())
1147 {
1148 return m_managedText[m_virtualCursor].substr(i, j - i - 1);
1149 }
1150 }
1151 return m_managedText[m_virtualCursor].substr(i);
1152 }
1153 }
1154
1155 // decrement the virtual cursor
1157 }
1158
1159 // Fallback
1161 }
1162 else
1163 {
1164 // Return an empty string, if the virtual cursor is the lowest possible line
1165 if (m_virtualCursor + 1 >= (int)m_managedText.size())
1166 return "";
1167
1168 // increment the virtual cursor
1170
1171 // While the virtual cursor is smaller than the number of lines in the text buffer
1172 while (m_virtualCursor < (int)m_managedText.size())
1173 {
1174 // find the next user text and return it
1175 for (size_t i = 0; i < m_managedText[m_virtualCursor].size(); i++)
1176 {
1177 if (m_managedText[m_virtualCursor][i].userText())
1178 {
1179 for (size_t j = i; j < m_managedText[m_virtualCursor].size(); j++)
1180 {
1181 if (!m_managedText[m_virtualCursor][j].userText())
1182 {
1183 return m_managedText[m_virtualCursor].substr(i, j - i - 1);
1184 }
1185 }
1186 return m_managedText[m_virtualCursor].substr(i);
1187 }
1188 }
1189
1190 // Increment the virtual cursor
1192 }
1193
1194 // Return an empty string, if the virtual cursor is the lowest possible line
1195 if (m_virtualCursor + 1u >= m_managedText.size())
1196 return "";
1197 }
1198
1199 // Fallback
1200 return "";
1201}
1202
1203
1213string TextManager::GetTextRange(int y, int x0, int x1) const
1214{
1215 // Convert the coordinates to a logical cursor
1216 LogicalCursor cursor = toLogicalCursor(ViewCursor(x0, y));
1217
1218 // ensure that the cursor is valid
1219 if (!cursor)
1220 return "";
1221
1222 // Return the extracted string
1223 return m_managedText[cursor.line].substr(cursor.pos, x1 - x0);
1224}
1225
1226
1237string TextManager::GetWordAt(int y, int x) const
1238{
1239 // Convert the coordinates to a logical cursor
1241
1242 // ensure that the cursor is valid
1243 if (!cursor)
1244 return "";
1245
1246 // Get the text at the corresponnding line
1247 string sWord = m_managedText[cursor.line].toString();
1248
1249 // Find the start of the word and erase everything in front of it
1250 for (int pos = cursor.pos; pos >= 0; pos--)
1251 {
1252 if (isalnum(sWord[pos]) || sWord[pos] == '_')
1253 continue;
1254 sWord.erase(0, pos + 1);
1255 break;
1256 }
1257
1258 // Find the end of the word and return it as a new string
1259 for (size_t pos = 0; pos < sWord.length(); pos++)
1260 {
1261 if (isalnum(sWord[pos]) || sWord[pos] == '_')
1262 continue;
1263 return sWord.substr(0, pos);
1264 }
1265
1266 // Fallback
1267 return "";
1268}
1269
1270
1281string TextManager::GetWordStartAt(int y, int x) const
1282{
1283 // Convert the coordinates to a logical cursor
1285
1286 // Ensure that the cursor is valid
1287 if (!cursor)
1288 return "";
1289
1290 // Get the line until the position
1291 string sWord = m_managedText[cursor.line].substr(0, cursor.pos);
1292
1293 // Find the start of the word and return it as a new string
1294 for (int pos = cursor.pos - 1; pos >= 0; pos--)
1295 {
1296 if (isalnum(sWord[pos]) || sWord[pos] == '_')
1297 continue;
1298 return sWord.substr(pos + 1);
1299 }
1300
1301 // Fallback
1302 return "";
1303}
1304
1305
1317char TextManager::GetCharAdjusted(int y, int x) const
1318{
1320 return GetCharLogical(cursor);
1321}
1322
1323
1332{
1333 if (!cursor)
1334 return ' ';
1335 if (cursor.pos >= m_managedText[cursor.line].size())
1336 return ' '; // default color
1337 return m_managedText[cursor.line][cursor.pos].m_char;
1338}
1339
1340
1349bool TextManager::IsUserText(int y, int x) const
1350{
1352
1353 if (!cursor)
1354 return false;
1355
1356 if (cursor.pos == m_managedText[cursor.line].size())
1357 return true;
1358 if (cursor.pos > m_managedText[cursor.line].size())
1359 return false;
1360 return m_managedText[cursor.line][cursor.pos].userText();
1361}
1362
1363
1372bool TextManager::IsEditable(int y, int x) const
1373{
1375
1376 if (!cursor)
1377 return false;
1378
1379 if (cursor.pos == m_managedText[cursor.line].size())
1380 return true;
1381 if (cursor.pos > m_managedText[cursor.line].size())
1382 return false;
1383 return m_managedText[cursor.line][cursor.pos].editable();
1384}
1385
1386
1395{
1396 if (!logCursor)
1397 return false;
1398
1399 if (logCursor.pos == m_managedText[logCursor.line].size())
1400 return true;
1401 if (logCursor.pos > m_managedText[logCursor.line].size())
1402 return false;
1403 return m_managedText[logCursor.line][logCursor.pos].editable();
1404}
1405
1406
1418unsigned short TextManager::GetColor(int y, int x) const
1419{
1420 return m_managedText[y][x].getColor();
1421}
1422
1423
1435unsigned short TextManager::GetColorAdjusted(int y, int x) const
1436{
1438
1439 if (!cursor)
1440 return 112;
1441
1442 if (cursor.pos >= m_managedText[cursor.line].size())
1443 return 112; // default color
1444 return m_managedText[cursor.line][cursor.pos].getColor();
1445}
1446
1447
1460void TextManager::SetColorAdjusted(int y, int x, unsigned short value)
1461{
1463
1464 if (!cursor)
1465 return;
1466
1467 if (cursor.pos >= m_managedText[cursor.line].size())
1468 return;
1469 m_managedText[cursor.line][cursor.pos].setColor(value);
1470}
1471
1472
1482{
1483 for (size_t i = 0; i < m_managedText.size(); i++)
1484 {
1485 for (size_t j = 0; j < m_managedText[i].size(); j++)
1486 if (m_managedText[i][j].editable())
1487 m_managedText[i][j].makeUserText();
1488 }
1489}
1490
1491
1502int TextManager::AdjustIndex(int index) const
1503{
1504 int adjustedIndex = m_topLine + index - m_numLinesScrolledUp;
1505 return adjustedIndex;
1506}
1507
1508
1518{
1519 return m_numLinesScrolledUp;
1520}
1521
1522
1534{
1535 if (newSize < m_viewportHeight || newSize == m_maxHeight)
1536 {
1537 return;
1538 }
1539
1540 if (m_managedText.size())
1541 {
1542 if (newSize < m_maxHeight)
1543 {
1544 int linesToPitch = m_maxHeight - newSize;
1545
1546 for (int i = 0; i < linesToPitch; i++)
1547 {
1548 if (!m_managedText.size())
1549 break;
1550
1551 m_managedText.pop_front();
1552 }
1553 }
1554 }
1555
1556 m_maxHeight = newSize;
1559
1562
1565
1566 // Clear the rendered block
1567 m_renderedBlock.clear();
1568}
1569
1570
1580{
1581 return m_renderedBlock.size();
1582}
1583
1584
1592{
1593 return m_maxHeight;
1594}
1595
This class resembles an extended string class, which contains the extended character class.
Definition: TextManager.h:319
An implementation of a generic terminal, which has to be specialized in the child classes.
Definition: gterm.hpp:42
NumeReSyntax * getSyntax()
Definition: gterm.hpp:145
This class contains all needed keywords to highlight their occurences correspondingly....
Definition: syntax.hpp:55
std::string highlightLine(const std::string &sCommandLine)
This function applies the highlighting colors to the command line (only used in the terminal).
Definition: syntax.cpp:363
@ SYNTAX_FUNCTION
Definition: syntax.hpp:93
@ SYNTAX_METHODS
Definition: syntax.hpp:102
@ SYNTAX_PROCEDURE
Definition: syntax.hpp:99
@ SYNTAX_COMMENT
Definition: syntax.hpp:103
@ SYNTAX_CONSTANT
Definition: syntax.hpp:94
@ SYNTAX_COMMAND
Definition: syntax.hpp:91
@ SYNTAX_SPECIALVAL
Definition: syntax.hpp:95
std::string highlightError(const std::string &sCommandLine)
Highlight an error message. We simply use the color of the operators (which is red as default).
Definition: syntax.cpp:636
bool clearRange(const ViewCursor &cursor1, const ViewCursor &cursor2)
Clears the range between two view cursors.
std::string getSelectedText() const
This member function returns the selected text.
void synchronizeRenderedBlock(int linesToDelete)
Removes parts of the already rendered block.
bool IsUserText(int y, int x) const
Determines, whether the character at (x,y) is a user text.
int AdjustIndex(int index) const
void printOutput(const std::string &sLine)
This is the read-only print function.
Definition: TextManager.cpp:76
std::deque< CharacterVector > m_managedText
Definition: TextManager.h:566
int m_bottomLine
Definition: TextManager.h:554
unsigned short GetColorAdjusted(int y, int x) const
std::string getRenderedString(size_t viewLine) const
Return the rendered line for the current viewport setting.
std::string operator[](int index)
void SetColorAdjusted(int y, int x, unsigned short value)
size_t tab()
Insert a tab character at the current position.
size_t m_tabLength
Definition: TextManager.h:563
void renderLayout()
This function renders the layout.
void insertInput(const std::string &sLine, size_t logicalpos=std::string::npos)
This is the user input function.
bool Scroll(int numLines, bool scrollUp)
void newLine()
Adds a new line to the current managed text.
int calc_color(int fg, int bg, int flags)
Helper function for converting the colors into a single int.
int m_viewportHeight
Definition: TextManager.h:557
void backspace(const LogicalCursor &logCursor)
Performs a backspace operation.
ViewCursor toViewCursor(const LogicalCursor &logCursor) const
Convert a logical cursor to a view cursor.
std::string getPreviousLine() const
This member function returns the contents of the line before the current input line.
size_t findNextLinebreak(const std::string &currentLine, size_t currentLinebreak) const
Find the next linebreak position.
TextManager(GenericTerminal *parent=nullptr, int width=80, int height=24, int maxWidth=160, int maxHeight=300)
Definition: TextManager.cpp:46
int m_linesReceived
Definition: TextManager.h:558
void Resize(int width, int height)
std::vector< unsigned short > getRenderedColors(size_t viewLine) const
Return the rendered colors for the selected viewport line.
size_t m_indentDepth
Definition: TextManager.h:564
void updateColors(bool isErrorLine=false)
Update the colors for the current line.
~TextManager()
Destructor will reset the internal buffer.
Definition: TextManager.cpp:60
char GetCharAdjusted(int y, int x) const
bool IsEditableLogical(const LogicalCursor &logCursor) const
Determines, whether the character at the logical position is editable text.
char GetCharLogical(const LogicalCursor &cursor) const
Returns the character at the logical position.
std::string GetInputHistory(bool vcursorup=true)
Get the next history line.
int m_numLinesScrolledUp
Definition: TextManager.h:555
void selectText(const ViewCursor &viewCursor, bool bSelect=true)
Selects the text at the view cursor position.
void SetMaxSize(int newSize)
void eraseLine()
Erase the current line.
ViewCursor getCurrentViewPos() const
Returns the current cursor position as view cursor.
bool IsEditable(int y, int x) const
Determines, whether the character at (x,y) is editable text.
std::string GetTextRange(int y, int x0, int x1) const
Extracts the text between the positions.
void ResetVirtualCursorLine()
Definition: TextManager.h:536
bool isSelected(const ViewCursor &viewCursor) const
Determines, whether the pointed character is selected.
std::string GetWordStartAt(int y, int x) const
Returns the word start at the passed position.
void ChangeEditableState()
Removes the editable flag from the managed text.
LogicalCursor toLogicalCursor(const ViewCursor &viewCursor) const
Convert a view cursor into a logical cursor.
unsigned short GetColor(int y, int x) const
int m_virtualCursor
Definition: TextManager.h:561
LogicalCursor getCurrentLogicalPos() const
Returns the current cursor position as logical cursor.
int GetLinesReceived() const
std::string getCurrentInputLine() const
Returns the contents of the input line.
void unselectAll()
This member function unselects the whole text at once.
int m_viewportWidth
Definition: TextManager.h:556
int GetNumLinesScrolled() const
int GetSize() const
GenericTerminal * m_parent
Definition: TextManager.h:551
std::string GetWordAt(int y, int x) const
Returns the word at the passed position.
std::deque< RenderedLine > m_renderedBlock
Definition: TextManager.h:567
bool isSelectedLogical(const LogicalCursor &cursor) const
Determines, whether the pointed character is selected.
int GetMaxSize() const
Returns the buffer size of the terminal.
CONSTCD11 std::chrono::duration< Rep, Period > abs(std::chrono::duration< Rep, Period > d)
Definition: date.h:1317
#define min(a, b)
Definition: resampler.cpp:34
Cursor, which is used in the TextManager to identify the actual line and position in the m_text varia...
Definition: TextManager.h:38
This structure combines the rendered line with its colors and its coordinates.
Definition: TextManager.h:197
std::vector< unsigned short > colors
Definition: TextManager.h:199
std::string sLine
Definition: TextManager.h:198
std::vector< LogicalCursor > coords
Definition: TextManager.h:200
Cursor, which is used in the terminal. The TextManager is able to convert this cursor into a LogicalC...
Definition: TextManager.h:124
size_t y
Definition: TextManager.h:126
size_t x
Definition: TextManager.h:125
std::string toString(int)
Converts an integer to a string without the Settings bloat.