1 /**
2 * Copyright (c) 2014 Roy Lu <roymercadian@gmail.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19
20 #ifdef __GNUG__
21 #pragma implementation "editor.h"
22 #endif
23
24 #include "mainframe.h"
25
26 #include "editor.h"
27 #include <algorithm> // for std::replace
28 #include <fstream>
29
30 #define RECV_BUF_SIZE (4097)
31
32
33 typedef struct {
34 CTermData* pTermData;
35 string* text;
36 int lines;
37 const char* eol;
38 } ReadStatus;
39
CEditor(CTelnetView * tView,CSite & SiteInfo)40 CEditor::CEditor(CTelnetView* tView, CSite& SiteInfo)
41 : CTelnetCon(tView, SiteInfo)
42 {
43 m_Site.m_CRLF = 1; // \n
44 m_Site.m_ESCConv = "\x1b";
45 }
46
~CEditor()47 CEditor::~CEditor()
48 {
49 // do nothing.
50 }
51
InitAnsiEditor()52 void CEditor::InitAnsiEditor()
53 {
54 m_EditorText.resize(1);
55
56 m_AnsiBright = false;
57 m_AnsiBlink = false;
58 m_AnsiFg = 37;
59 m_AnsiBg = 40;
60
61 m_DisplayStart = m_DisplayEnd = 0;
62
63 m_SelectStartRow = m_SelectStartCol = m_SelectEndRow = m_SelectEndCol = 0;
64
65 string str = "\x1b[m";
66 for(int r = 0; r < 24; ++r){
67 m_EditorText.push_back(str);
68 }
69
70 SetDisplayFrame();
71 }
72
73 /**
74 * @brief Deal with user input. Store the text in TermData.
75 */
Send(void * buf,int length)76 int CEditor::Send( void* buf, int length )
77 {
78 // save text into data
79 string text = (char*)buf;
80 DoInsertText(m_EditorText[m_DisplayStart + m_CaretPos.y], text, m_CaretPos.x);
81
82 GetEditorView()->GetParentFrame()->GetCurEditorView()->UpdateEditor();
83
84 SetTextColor(m_CaretPos.y, m_CaretPos.x, m_CaretPos.x + length - 1);
85
86 //save back to vector
87 string newText = GetLineText(m_CaretPos.y, false);
88 m_EditorText[m_DisplayStart + m_CaretPos.y] = newText;
89
90 m_Sel->Unselect();
91
92 // Move caret to next position
93 m_CaretPos.x += length;
94 if(m_CaretPos.x >= m_ColsPerPage - 1){
95 m_CaretPos.x = m_ColsPerPage - 1;
96 }
97
98 GetEditorView()->GetParentFrame()->GetCurEditorView()->UpdateEditor();
99
100 return 0;
101 }
102
DeleteText()103 void CEditor::DeleteText()
104 {
105
106 DoDeleteText( m_EditorText[m_DisplayStart + m_CaretPos.y], m_CaretPos.x);
107
108 GetEditorView()->GetParentFrame()->GetCurEditorView()->UpdateEditor();
109 }
110
BackspaceText()111 void CEditor::BackspaceText()
112 {
113 DoBackspaceText();
114
115 GetEditorView()->GetParentFrame()->GetCurEditorView()->UpdateEditor();
116 }
117
DoBackspaceText()118 void CEditor::DoBackspaceText()
119 {
120 if(m_CaretPos.x < 0){
121 return;
122 }
123
124 if(m_CaretPos.x == 0){
125 if(m_DisplayStart + m_CaretPos.y > 0){
126 MoveUp();
127 MoveToEnd();
128 //append current line text to end of previous line
129 stringstream ss;
130 ss << m_EditorText[m_DisplayStart + m_CaretPos.y];
131 ss << m_EditorText[m_DisplayStart + m_CaretPos.y + 1];
132
133 m_EditorText[m_DisplayStart + m_CaretPos.y] = ss.str();
134
135 //remove (m_DisplayStart + m_CaretPos.y + 1)
136 vector<string>::iterator itor = m_EditorText.begin();
137
138 m_EditorText.erase(itor + m_DisplayStart + m_CaretPos.y + 1);
139
140 SetDisplayFrame();
141 }
142 return;
143 }
144
145 //move caret to left.
146 MoveLeft();
147
148 DoDeleteText( m_EditorText[m_DisplayStart + m_CaretPos.y], m_CaretPos.x);
149 }
150
151 /**
152 * @brief delete char from text of ansi editor.
153 */
DoDeleteText(string & line,int col)154 void CEditor::DoDeleteText(string &line, int col)
155 {
156 int pos = ParseToRawPos(line, col);
157 if(pos >= static_cast<int>(line.length()) || pos < 0){
158 return; //do nothing
159 }
160
161 stringstream ss;
162 // Deal with DBCS
163 if(line[pos] < 0){ //it's a DBCS
164 ss << line.substr(0, pos);
165 ss << line.substr(pos + 2, -1);
166 }else{
167 ss << line.substr(0, pos);
168 ss << line.substr(pos + 1, -1);
169 }
170 line = ss.str();
171
172 if(line.length() == 0)
173 line = " ";
174 }
175
LoadEditorText()176 void CEditor::LoadEditorText()
177 {
178 //load text block from data to screem
179 stringstream ss;
180 for(int r = m_DisplayStart; r <= m_DisplayEnd; ++r){
181 ss.clear();
182 ss << m_EditorText[r];
183 if(r < m_DisplayEnd) // Don't add \r\n at last row
184 ss << "\r\n";
185 }
186
187 static unsigned char recv_buf[RECV_BUF_SIZE];
188 strcpy( (char *)recv_buf, ss.str().c_str());
189 m_pRecvBuf = recv_buf;
190 gsize rlen = ss.str().size();
191
192 m_pRecvBuf[rlen] = '\0';
193 m_pBuf = m_pRecvBuf;
194 m_pLastByte = m_pRecvBuf + rlen;
195
196 ParseReceivedData();
197
198 UpdateDisplay();
199 //GetView()->UpdateEditor();
200 }
201
202
EditorActions(int action,string arg)203 void CEditor::EditorActions(int action, string arg)
204 {
205 switch (action)
206 {
207 case Init_Ansi_Editor:
208 InitAnsiEditor();
209 break;
210 case Move_Up:
211 MoveUp();
212 break;
213 case Move_Down:
214 MoveDown();
215 break;
216 case Move_Left:
217 MoveLeft();
218 break;
219 case Move_Right:
220 MoveRight();
221 break;
222 case Move_To_Home:
223 MoveToHome();
224 break;
225 case Move_To_End:
226 MoveToEnd();
227 break;
228 case Move_To_Prev_Page:
229 MoveToPrevPage();
230 break;
231 case Move_To_Next_Page:
232 MoveToNextPage();
233 break;
234 case New_Line:
235 NewLine();
236 break;
237 case Delete_Text:
238 DeleteText();
239 break;
240 case Backspace_Text:
241 BackspaceText();
242 break;
243 case Set_Display_Frame_Plus:
244 SetDisplayFrame(1);
245 break;
246 case Set_Display_Frame_Minus:
247 SetDisplayFrame(-1);
248 break;
249 case Set_Caret_Pos_X:
250 SetCaretPosX();
251 break;
252 case Set_Caret_Pos_Y:
253 SetCaretPosY();
254 break;
255 case Load_Editor_Text:
256 LoadEditorText();
257 break;
258 case Load_Ansi_File:
259 LoadAnsiFile(arg);
260 break;
261 case Save_Ansi_File:
262 SaveAnsiFile(arg);
263 break;
264 case Paste_To_Editor:
265 PasteToEditor(arg);
266 break;
267 case Clear_Screen:
268 ClearScreen();
269 break;
270 default:
271 cout << "error: EditorActions" << endl;
272 break;
273 }
274 }
275
MoveUp()276 void CEditor::MoveUp()
277 {
278 if(m_DisplayStart + m_CaretPos.y <= 0){
279 return;
280 }
281
282 m_CaretPos.y--;
283
284 // Move display frame up if m_CaretPos.y < 0
285 if(m_CaretPos.y < 0){
286 m_CaretPos.y = 0;
287 SetDisplayFrame(-1);
288
289 }
290
291 // Detect dbcs and set caret position X
292 SetCaretPosX();
293
294 GetEditorView()->GetParentFrame()->GetCurEditorView()->UpdateEditor();
295 }
296
MoveDown()297 void CEditor::MoveDown()
298 {
299 if( (m_DisplayStart + m_CaretPos.y) >= static_cast<int>(m_EditorText.size()) - 1){
300 //already in the last line, do nothing
301 return;
302 }
303
304 m_CaretPos.y++;
305
306 // Move screen pointers down if m_CaretPos.y > (m_RowsPerPage - 1)
307 if( m_CaretPos.y > (m_RowsPerPage - 1) ){
308 m_CaretPos.y = m_RowsPerPage - 1;
309 SetDisplayFrame(1);
310 }
311
312 //detect dbcs and set caret position X
313 SetCaretPosX();
314
315 GetEditorView()->GetParentFrame()->GetCurEditorView()->UpdateEditor();
316 }
317
MoveLeft()318 void CEditor::MoveLeft()
319 {
320 CTermCharAttr* pAttr = GetLineAttr( m_Screen[m_CaretPos.y] );
321 int x = m_CaretPos.x;
322
323 if(DetectDBChar() && x > 0 && pAttr[x - 1].GetCharSet() == CTermCharAttr::CS_MBCS2){
324 m_CaretPos.x -= 2; //move 2 chars
325 }else{
326 m_CaretPos.x--; //move 1 char
327 }
328
329 if(m_CaretPos.x < 0)
330 m_CaretPos.x = 0;
331
332 GetEditorView()->GetParentFrame()->GetCurEditorView()->UpdateEditorCaretPos();
333 }
334
MoveRight()335 void CEditor::MoveRight()
336 {
337 CTermCharAttr* pAttr = GetLineAttr( m_Screen[m_CaretPos.y] );
338 int x = m_CaretPos.x;
339
340
341 if(DetectDBChar() && pAttr[x].GetCharSet() == CTermCharAttr::CS_MBCS1){
342 m_CaretPos.x += 2; //move 2 chars
343 }else{
344 m_CaretPos.x++; //move 1 char
345 }
346
347 if(m_CaretPos.x > m_ColsPerPage - 1){
348 m_CaretPos.x = m_ColsPerPage - 1;
349 }
350
351 GetEditorView()->GetParentFrame()->GetCurEditorView()->UpdateEditorCaretPos();
352 }
353
MoveToHome()354 void CEditor::MoveToHome()
355 {
356 m_CaretPos.x = 0;
357
358 GetEditorView()->GetParentFrame()->GetCurEditorView()->UpdateEditor();
359 }
360
MoveToEnd()361 void CEditor::MoveToEnd()
362 {
363 m_CaretPos.x = GetTextCharCount( m_EditorText[m_DisplayStart + m_CaretPos.y]);
364
365 if(m_CaretPos.x > m_ColsPerPage - 1)
366 m_CaretPos.x = m_ColsPerPage -1;
367
368 GetEditorView()->GetParentFrame()->GetCurEditorView()->UpdateEditor();
369 }
370
MoveToPrevPage()371 void CEditor::MoveToPrevPage()
372 {
373 SetDisplayFrame(-m_RowsPerPage);
374
375 //bound check
376 if(m_DisplayStart + m_CaretPos.y < 0){
377 m_CaretPos.y = 0;
378 }
379
380 GetEditorView()->GetParentFrame()->GetCurEditorView()->UpdateEditor();
381
382 //detect dbcs and set caret position x
383 CTermCharAttr* pAttr = GetLineAttr( m_Screen[m_CaretPos.y] );
384 int x = m_CaretPos.x;
385
386 if(DetectDBChar() && pAttr[x].GetCharSet() == CTermCharAttr::CS_MBCS2){
387 m_CaretPos.x--;
388 }
389
390 GetEditorView()->GetParentFrame()->GetCurEditorView()->UpdateEditor();
391 }
392
MoveToNextPage()393 void CEditor::MoveToNextPage()
394 {
395 SetDisplayFrame(m_RowsPerPage);
396
397 //bound check
398 if(m_DisplayStart + m_CaretPos.y >= static_cast<int>(m_EditorText.size())){
399 m_CaretPos.y = m_EditorText.size() - 1;
400 if(m_CaretPos.y > m_RowsPerPage - 1)
401 m_CaretPos.y = m_RowsPerPage - 1;
402 }
403
404 GetEditorView()->GetParentFrame()->GetCurEditorView()->UpdateEditor(); //update screen first time
405
406 //detect dbcs
407 CTermCharAttr* pAttr = GetLineAttr( m_Screen[m_CaretPos.y] );
408 int x = m_CaretPos.x;
409
410 if(DetectDBChar() && pAttr[x].GetCharSet() == CTermCharAttr::CS_MBCS2){
411 m_CaretPos.x--;
412 }
413
414 GetEditorView()->GetParentFrame()->GetCurEditorView()->UpdateEditor(); //update screen second time
415 }
416
417 /**
418 * @brief every time when user press enter-key, the m_EditorText add a new string data.
419 */
NewLine()420 void CEditor::NewLine()
421 {
422 //partition the string behind cursor to the next line
423 string str0, str1;
424 int pos = ParseToRawPos(m_EditorText[m_DisplayStart + m_CaretPos.y], m_CaretPos.x);
425 if(pos < static_cast<int>(m_EditorText[m_DisplayStart + m_CaretPos.y].size())){
426 str0 = m_EditorText[m_DisplayStart + m_CaretPos.y].substr(0, pos);
427 str1 = m_EditorText[m_DisplayStart + m_CaretPos.y].substr(pos, -1);
428 if(str0.size() == 0)
429 str0 = "\0";
430 if(str1.size() == 0)
431 str1 = "\0";
432 }else{
433 str0 = m_EditorText[m_DisplayStart + m_CaretPos.y];
434 str1 = "\0";
435 }
436
437 m_EditorText[m_DisplayStart + m_CaretPos.y] = str0;
438
439 if(m_DisplayStart + m_CaretPos.y < static_cast<int>(m_EditorText.size()) - 1){
440 vector<string>::iterator itor = m_EditorText.begin();
441 m_EditorText.insert(itor + m_DisplayStart + m_CaretPos.y + 1, str1);
442 }else{
443 m_EditorText.push_back(str1);
444 }
445
446 //set new caret position
447 m_CaretPos.x = 0;
448
449 if(m_CaretPos.y == m_RowsPerPage - 1){
450 SetDisplayFrame(1);
451 }else{
452 m_CaretPos.y++;
453 SetDisplayFrame();
454 }
455 SetCaretPosX();
456
457 GetEditorView()->GetParentFrame()->GetCurEditorView()->UpdateEditor();
458 }
459
GetTextCharCount(const string & str)460 int CEditor::GetTextCharCount(const string &str)
461 {
462 int count = 0;
463 int i = 0;
464 while(i < static_cast<int>(str.length())){
465 if(str[i] == '\x1b'){
466 while(str[i] != 'm') ++i;
467 ++i;
468 continue;
469 }
470 if(str[i] < 0){ //it's a DBCS
471 i += 2;
472 count += 2;
473 }else{ //SBCS
474 i++;
475 count++;
476 }
477 }
478 return count;
479 }
480
ApplyAnsiColor(int bright,int blink,int fg,int bg)481 void CEditor::ApplyAnsiColor(int bright, int blink, int fg, int bg)
482 {
483 SetAnsiColor(bright, blink, fg, bg);
484
485 SetSelection();
486
487 if(m_SelectStartRow < 0 || m_SelectEndRow < 0){
488 return;
489 }
490
491 SetColorToSelection(bright, blink, fg, bg); // method of parent class CTermData
492
493 GetEditorView()->GetParentFrame()->GetCurEditorView()->UpdateEditor();
494 }
495
LoadAnsiFile(string filename)496 void CEditor::LoadAnsiFile(string filename)
497 {
498 m_EditorText.clear();
499 fstream fs;
500 fs.open(filename.c_str());
501 if(fs.is_open()){
502 string line;
503 while(std::getline(fs, line)){
504 // Remove carriage return
505 std::replace(line.begin(), line.end(), '\r', ' ');
506 m_EditorText.push_back(line);
507 }
508
509 SetDisplayFrame();
510
511 fs.close();
512 }else{
513 printf("fail to open file.\n");
514 }
515 }
516
SaveAnsiFile(string filename)517 void CEditor::SaveAnsiFile(string filename)
518 {
519 stringstream ss;
520 ss << filename << ".ans";
521 filename = ss.str();
522
523 ofstream fs(filename.c_str());
524 if(fs.is_open()){
525
526 for(unsigned int i = 0; i < m_EditorText.size(); ++i){
527 fs << m_EditorText[i] << "\r\n";
528 }
529
530 fs.close();
531 }else{
532 printf("fail to save file.\n");
533 }
534 }
535
SetSelection()536 void CEditor::SetSelection()
537 {
538 m_Sel->GetCanonicalMarks(m_SelectStartRow, m_SelectStartCol, m_SelectEndRow, m_SelectEndCol);
539
540 //check range
541 if(m_EditorText.size() > m_RowsPerPage){
542 //return;
543 }else{
544 if(m_SelectEndRow > static_cast<int>(m_EditorText.size()) - 1){
545 m_SelectEndRow = m_EditorText.size() - 1;
546 m_SelectEndCol = m_ColsPerPage - 1;
547 }
548 }
549 }
550
SetDisplayFrame(int offset)551 void CEditor::SetDisplayFrame(int offset)
552 {
553 if(m_EditorText.size() <= m_RowsPerPage){
554 m_DisplayStart = 0;
555 m_DisplayEnd = m_EditorText.size() - 1;
556 }else{
557 m_DisplayStart += offset;
558
559 if(m_DisplayStart < 0){
560 m_DisplayStart = 0;
561 m_DisplayEnd = m_RowsPerPage - 1;
562 }else{
563 m_DisplayEnd = m_DisplayStart + m_RowsPerPage - 1;
564
565 if(m_DisplayEnd > static_cast<int>(m_EditorText.size()) - 1){
566 m_DisplayEnd = m_EditorText.size() - 1;
567 m_DisplayStart = m_DisplayEnd - m_RowsPerPage + 1;
568 }
569 }
570 }
571 }
572
SetCaretPosX()573 void CEditor::SetCaretPosX()
574 {
575 CTermCharAttr* pAttr = GetLineAttr( m_Screen[m_CaretPos.y] );
576
577 //DetectDBChar() should be added here.
578 if( DetectDBChar() && pAttr[m_CaretPos.x].GetCharSet() == CTermCharAttr::CS_MBCS2){
579 m_CaretPos.x--;
580 }
581 }
582
SetCaretPosY()583 void CEditor::SetCaretPosY()
584 {
585 int lineCount = m_DisplayEnd - m_DisplayStart + 1;
586
587 if(m_CaretPos.y >= lineCount){
588 m_CaretPos.y = lineCount - 1;
589 }
590 }
591
592 /**
593 * Paste text to AnsiEditor.
594 */
PasteToEditor(const string & text)595 void CEditor::PasteToEditor(const string &text)
596 {
597 string temp = text;
598 int lineCount = 0;
599 int found = -1;
600 do{
601 lineCount++;
602 found = temp.find("\n");
603
604 string line = temp.substr(0, found);
605
606 if(lineCount == 1){
607 int insertPos = ParseToRawPos(m_EditorText[m_DisplayStart + m_CaretPos.y], m_CaretPos.x);
608 int length = m_EditorText[m_DisplayStart + m_CaretPos.y].length();
609 if( insertPos > length){
610 int spaceCount = insertPos - length;
611 for(int i = 0; i < spaceCount; ++i){
612 m_EditorText[m_DisplayStart + m_CaretPos.y] += " ";
613 }
614 m_EditorText[m_DisplayStart + m_CaretPos.y] += line;
615 }else{
616 string result = m_EditorText[m_DisplayStart + m_CaretPos.y].substr(0, insertPos);
617 result += line;
618 result += m_EditorText[m_DisplayStart + m_CaretPos.y].substr(insertPos, -1);
619 m_EditorText[m_DisplayStart + m_CaretPos.y] = result;
620 }
621 }else{
622 vector<string>::iterator itor;
623 itor = m_EditorText.begin();
624 m_EditorText.insert(itor + m_DisplayStart + m_CaretPos.y + lineCount -1, line);
625 }
626
627 if(found != static_cast<int>(string::npos))
628 temp = temp.substr(found + 1, -1);
629 }while(found != static_cast<int>(string::npos));
630 }
631
ParseToRawPos(const string & text,int col,bool checkDBCS)632 int CEditor::ParseToRawPos(const string &text, int col, bool checkDBCS)
633 {
634 if(col == -1) return -1;
635
636 int t = 0; //index
637 int i = 0;
638 while(i < static_cast<int>(text.length())){
639 if(text[i] == '\x1b'){
640 while(text[i] != 'm') ++i;
641 ++i;
642 continue;
643 }
644 if(t == col){
645 return i;
646 }
647
648 if(checkDBCS){
649 if(text[i] < 0){ //it's a DBCS
650 i += 2;
651 t += 2;
652 }else{ //it's a SBCS
653 i++;
654 t++;
655 }
656 }else{
657 i++;
658 t++;
659 }
660 }
661
662 while(t != col){
663 ++i;
664 ++t;
665 }
666 return i;
667 }
668
669 /**
670 * @brief Insert string into text at insertCol position.
671 * @param insertPos -1: insert to the end of text.
672 */
DoInsertText(string & text,const string & newText,int insertCol)673 void CEditor::DoInsertText(string &text, const string &newText, int insertCol)
674 {
675 int insertPos = ParseToRawPos(text, insertCol);
676
677 stringstream ss("");
678 if(insertPos < static_cast<int>(text.length())){
679 if(insertPos == -1){ //insert newText to the end of text
680 ss << text << newText;
681 }else{
682 ss << text.substr(0, insertPos);
683 ss << newText;
684 ss << text.substr(insertPos, -1);
685 }
686 }else{
687 //need to add spaces
688 ss << text;
689 int spaceCount = insertPos - text.length();
690 for(int i = 0; i < spaceCount; ++i){
691 ss << " ";
692 }
693 ss << newText;
694 }
695
696 text = ss.str();
697 }
698
SetAnsiColor(int bright,int blink,int fg,int bg)699 void CEditor::SetAnsiColor(int bright, int blink, int fg, int bg)
700 {
701 if(bright == 0 || bright == 1)
702 m_AnsiBright = bright;
703
704 if(blink == 0 || blink == 1)
705 m_AnsiBlink = blink;
706
707 if (fg >= 0 && fg <= 7)
708 m_AnsiFg = fg;
709
710 if (bg >= 0 && bg <= 7)
711 m_AnsiBg = bg;
712 }
713
SetTextColor(int row,int startCol,int endCol)714 void CEditor::SetTextColor(int row, int startCol, int endCol)
715 {
716 SetTextColor(row, startCol, endCol, m_AnsiBright, m_AnsiBlink, m_AnsiFg, m_AnsiBg);
717 }
718
719 /**
720 * Set color attributes for each char between [row, startCol] and [row, endCol]
721 */
SetTextColor(int row,int startCol,int endCol,int bright,int blink,int fg,int bg)722 void CEditor::SetTextColor(int row, int startCol, int endCol, int bright, int blink, int fg, int bg)
723 {
724 CTermCharAttr *pAttr = GetLineAttr( m_Screen[row] );
725 for(int c = startCol; c <= endCol; ++c){
726 if(bright != -1)
727 pAttr[c].SetBright(bright);
728
729 if(blink != -1)
730 pAttr[c].SetBlink(blink);
731
732 if(fg != -1)
733 pAttr[c].SetForeground(fg);
734
735 if(bg != -1)
736 pAttr[c].SetBackground(bg);
737
738 pAttr[c].SetNeedUpdate(true);
739 }
740 }
741
742 /**
743 * Set ANSI Color to current selection.
744 */
SetColorToSelection(int bright,int blink,int fg,int bg)745 void CEditor::SetColorToSelection(int bright, int blink, int fg, int bg)
746 {
747 if(m_SelectStartRow == m_SelectEndRow && m_SelectStartCol > m_SelectEndCol){
748 return;
749 }
750
751 for(int row = m_SelectStartRow; row <= m_SelectEndRow; ++row){
752 int textStart = (row == m_SelectStartRow)? m_SelectStartCol: 0;
753 int textEnd = (row == m_SelectEndRow)? m_SelectEndCol: m_ColsPerPage - 1;
754
755 int rawEnd = ParseToRawPos(m_EditorText[m_DisplayStart + row], textEnd, false);
756
757 // add space if rawEnd >= m_EditorText[m_DisplayStart + row].length()
758 if(rawEnd >= static_cast<int>(m_EditorText[m_DisplayStart + row].length())){
759 int spaceCount = rawEnd - m_EditorText[m_DisplayStart + row].length() + 1;
760 for(int i = 0; i < spaceCount; ++i){
761 m_EditorText[m_DisplayStart + row] += " ";
762 }
763 }
764 SetTextColor(row, textStart, textEnd, bright, blink, fg, bg);
765
766 //save back to vector
767 m_Sel->m_Start.row = row;
768 m_Sel->m_Start.col = 0;
769 m_Sel->m_End.row = row;
770 m_Sel->m_End.col = m_ColsPerPage - 1;
771
772 m_EditorText[m_DisplayStart + row] = GetLineText(row, false);
773
774 m_Sel->Unselect();
775 }
776 }
777
778
779 /**
780 * Get text with Ansi color codes.
781 */
GetLineText(int row,bool trim)782 string CEditor::GetLineText(int row, bool trim)
783 {
784 m_Sel->m_Start.row = row;
785 m_Sel->m_Start.col = 0;
786 m_Sel->m_Start.left = true;
787 m_Sel->m_End.row = row;
788 m_Sel->m_End.col = m_ColsPerPage;
789 m_Sel->m_End.left = true;
790 string text = GetSelectedTextWithColor(trim);
791 return text;
792 }
793
ClearScreen()794 void CEditor::ClearScreen()
795 {
796 m_EditorText.clear();
797 m_EditorText.resize(1);
798 m_DisplayStart = m_DisplayEnd = 0;
799 m_SelectStartRow = m_SelectStartCol = m_SelectEndRow = m_SelectEndCol = 0;
800
801 string str = "\x1b[m";
802 for(int r = 0; r < 24; ++r){
803 m_EditorText.push_back(str);
804 }
805
806 SetDisplayFrame();
807 }
808