├── README.md └── Text_Editor.cpp /README.md: -------------------------------------------------------------------------------- 1 | # Text-Editor 2 | This program implements a text editor using Linked List and Stack data structures. 3 | 4 | Each line of text is saved into a linked list node, which consists of a data portion holding the text and a pointer to the next node of the linked list, which is the next line of the text. The program makes use of Stack data structure to implement the Undo function. 5 | 6 | ## Features: 7 | 8 | - Open an existing file and parse every line to a linked list. 9 | 10 | - Save into a file 11 | 12 | - Insert text into line n (user given line number and text) 13 | 14 | - Delete line n (user given line number) 15 | 16 | - Move line n to line m (interchanging two user given lines) 17 | 18 | - Replace text in line n (user given line number and text) 19 | 20 | - Next page 21 | 22 | - Previous page 23 | 24 | - Undo (Implemented using Stack data structure) (Slightly buggy) 25 | -------------------------------------------------------------------------------- /Text_Editor.cpp: -------------------------------------------------------------------------------- 1 | //Blin Qipa 2019 - Yeditepe University 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | using namespace std; 9 | using namespace std::this_thread; 10 | using namespace std::chrono; 11 | 12 | struct undoCmd{ 13 | int lineNumber; 14 | string text; 15 | int commandNumber; 16 | int mLine; 17 | int nLine; 18 | }; 19 | 20 | struct node{ 21 | string data; 22 | struct node *next; 23 | }; 24 | 25 | class linked_list 26 | { 27 | private: 28 | node *head; 29 | node *tail; 30 | int numOfLines = 0; 31 | int next = 1; 32 | stack undoStack; 33 | public: 34 | std::ofstream outfile; 35 | linked_list(){ 36 | int choice = -1; 37 | head = NULL; 38 | tail = NULL; 39 | int prevPagePrinted = 1; 40 | while(choice != 0){ 41 | cout<<"====TEXT EDITOR====\n"<>choice; 46 | cout<> lineGiven; 53 | cout<<"Enter text : "; 54 | cin.ignore(1); 55 | getline(cin,dataGiven); 56 | dataGiven+="\n"; 57 | if (lineGiven == 1) 58 | { 59 | addToHead(dataGiven); 60 | } 61 | else if (lineGiven > numOfLines) 62 | { 63 | insertFurtherAway(dataGiven,lineGiven); 64 | } 65 | else if (lineGiven < numOfLines) 66 | { 67 | insertTextInBetween(dataGiven,lineGiven); 68 | } 69 | else if (lineGiven == numOfLines) 70 | { 71 | int selection; 72 | cout<<"Enter 1 to replace the last line, enter 2 to insert a new line"; 73 | cin>>selection; 74 | if (selection == 1) 75 | { 76 | replaceTextInLine(dataGiven,lineGiven); 77 | } 78 | else if (selection == 2) 79 | { 80 | addToTail(dataGiven); 81 | } 82 | } 83 | } 84 | else if (choice == 2) //Deletion of a line, any line, works fine 85 | { 86 | int lineGiven; 87 | cout<<"Enter the line you want to delete : "; 88 | cin>>lineGiven; 89 | deleteLine(lineGiven); 90 | } 91 | else if (choice == 3) //Interchanging two lines, any two line, works fine 92 | { 93 | int lineGiven1; 94 | int lineGiven2; 95 | cout<<"Enter line 1 you want to swap : "; 96 | cin>>lineGiven1; 97 | cout<<"Enter line 2 you want to swap : "; 98 | cin>>lineGiven2; 99 | moveNtoM(lineGiven1, lineGiven2); 100 | } 101 | else if (choice == 4) 102 | { 103 | int lineGiven; 104 | string dataGiven; 105 | cout<<"Enter line you want to change the content of : "; 106 | cin>>lineGiven; 107 | if (lineGiven > numOfLines) 108 | { 109 | cout<<"The line you entered exceeds the existing number of lines..."<>dataGiven; 114 | dataGiven+="\n"; 115 | replaceTextInLine(dataGiven, lineGiven); 116 | } 117 | } 118 | else if (choice == 5) //Printing the whole list, works fine 119 | { 120 | printall(); 121 | sleep_for(nanoseconds(1000)); 122 | sleep_until(system_clock::now() + 1s); 123 | } 124 | else if (choice == 6) //Saving the list into a txt file, works fine 125 | { 126 | saveAll(); 127 | } 128 | else if (choice == 7) 129 | { 130 | if (undoStack.empty()) 131 | { 132 | cout<<"No command."<next; 150 | free(current); 151 | current = next; 152 | } 153 | head = NULL; 154 | openFile(); 155 | } 156 | else if (choice == 9) //Printing the next page 157 | { 158 | if (prevPagePrinted*10 > numOfLines) 159 | { 160 | // cout<<"No more page left to print."<data = dataGiven; 210 | temp->next = NULL; 211 | head = temp; 212 | tail = head; 213 | numOfLines++; 214 | } 215 | else //one or more than one node 216 | { 217 | node *temp; 218 | temp = new node; 219 | temp->data = dataGiven; 220 | temp->next = NULL; 221 | temp->next = head; 222 | head = temp; 223 | numOfLines++; 224 | } 225 | undoCmd adddedToHead; 226 | adddedToHead.lineNumber = 1; 227 | adddedToHead.commandNumber = 1; 228 | undoStack.push(adddedToHead); 229 | } 230 | 231 | void whateverAddToTail(string dataGiven){ //an extra function used to add to tail, had to implement to make Undo function work, ignore this one please 232 | if (head == NULL) //no node, empty linked list 233 | { 234 | node *temp; 235 | temp = new node; 236 | temp->data = dataGiven; 237 | temp->next = NULL; 238 | head = temp; 239 | tail = head; 240 | numOfLines++; 241 | } 242 | else //one or more than one node 243 | { 244 | node *temp; 245 | temp = new node; 246 | temp->data = dataGiven; 247 | temp->next = NULL; 248 | tail->next = temp; 249 | tail = temp; 250 | numOfLines++; 251 | } 252 | } 253 | 254 | void whateverDeleteTail(){ //an extra function used to delete from tail, had to implement to make Undo function work,ignore this one please 255 | node *temp = head; 256 | if (head == NULL) 257 | { 258 | cout<<"Nothing to be deleted."<data; 264 | delete(temp); 265 | head = NULL; 266 | tail = NULL; 267 | numOfLines--; 268 | } 269 | else 270 | { 271 | while (temp->next != NULL && temp->next->next != NULL) 272 | { 273 | temp = temp->next; 274 | } 275 | tail = temp; 276 | delete temp->next; 277 | temp->next = NULL; 278 | numOfLines--; 279 | } 280 | } 281 | 282 | void addToTail(string dataGiven){ //this function will add to Tail 283 | if (head == NULL) //no node, empty linked list 284 | { 285 | node *temp; 286 | temp = new node; 287 | temp->data = dataGiven; 288 | temp->next = NULL; 289 | head = temp; 290 | tail = head; 291 | numOfLines++; 292 | } 293 | else //one or more than one node 294 | { 295 | node *temp; 296 | temp = new node; 297 | temp->data = dataGiven; 298 | temp->next = NULL; 299 | tail->next = temp; 300 | tail = temp; 301 | numOfLines++; 302 | } 303 | undoCmd addedToTail; 304 | addedToTail.lineNumber = 1; 305 | addedToTail.commandNumber = 8; 306 | undoStack.push(addedToTail); 307 | } 308 | 309 | void deleteHead(){ //function used to delete the very first element, and update the head 310 | string backup = head->data; 311 | node *temp = head; 312 | node *nextNode = head->next; 313 | head = nextNode; 314 | delete(temp); 315 | numOfLines--; 316 | undoCmd deletedHead; 317 | deletedHead.text = backup; 318 | deletedHead.lineNumber = 1; 319 | deletedHead.commandNumber = 3; 320 | undoStack.push(deletedHead); 321 | } 322 | 323 | void deleteTail(){ //function used to delete the very last element, and update the tail 324 | node *temp = head; 325 | if (head == NULL) 326 | { 327 | cout<<"Nothing to be deleted."<data; 333 | delete(temp); 334 | head = NULL; 335 | tail = NULL; 336 | numOfLines--; 337 | undoCmd deletedTail; 338 | deletedTail.text = backup; 339 | deletedTail.lineNumber = 1; 340 | deletedTail.commandNumber = 7; 341 | undoStack.push(deletedTail); 342 | } 343 | else 344 | { 345 | while (temp->next != NULL && temp->next->next != NULL) 346 | { 347 | temp = temp->next; 348 | } 349 | tail = temp; 350 | string backup = temp->next->data; 351 | delete temp->next; 352 | temp->next = NULL; 353 | numOfLines--; 354 | undoCmd deletedTail; 355 | deletedTail.text = backup; 356 | deletedTail.lineNumber = 1; 357 | deletedTail.commandNumber = 7; 358 | undoStack.push(deletedTail); 359 | } 360 | } 361 | 362 | void insertTextInBetween(string dataGiven, int lineGiven){ //this function will insert text in the given line, and will push all the other lines 363 | if (lineGiven == 0) 364 | { 365 | cout<<"There's no line 0, did you mean 1 (cough...Google suggestions...cough)"<data = dataGiven; 374 | temp->next = NULL; 375 | head = temp; 376 | tail = head; 377 | numOfLines++; 378 | } 379 | else //one or more than one node 380 | { 381 | node *temp; 382 | temp = new node; 383 | temp->data = dataGiven; 384 | temp->next = NULL; 385 | temp->next = head; 386 | head = temp; 387 | numOfLines++; 388 | } 389 | //May be unnecessary, dunno 390 | undoCmd insertedToHead; 391 | insertedToHead.lineNumber = 1; 392 | insertedToHead.commandNumber = 5; 393 | undoStack.push(insertedToHead); 394 | // addToHead(dataGiven); 395 | // numOfLines++; 396 | } 397 | else{ 398 | node *prevNode = head; 399 | node *nextNode = head; 400 | node *temp = new node(); 401 | temp->data = dataGiven; 402 | temp->next = NULL; 403 | int iterator = 2; 404 | while(iterator < lineGiven) 405 | { 406 | prevNode = prevNode->next; 407 | nextNode = nextNode->next; 408 | iterator++; 409 | } 410 | nextNode = nextNode->next; 411 | prevNode->next = temp; 412 | temp->next = nextNode; 413 | numOfLines++; 414 | undoCmd insertedInBetween; 415 | insertedInBetween.lineNumber = lineGiven; 416 | insertedInBetween.commandNumber = 6; 417 | undoStack.push(insertedInBetween); 418 | } 419 | } 420 | 421 | void replaceTextInLine(string dataGiven,int lineGiven){ //this function will overwrite anything written in the given line 422 | undoCmd replacedLine; 423 | if (numOfLines < lineGiven) 424 | { 425 | cout<<"The line you entered exceeds the existing number of lines..."<= lineGiven ) 432 | { 433 | node *temp = head; 434 | int goToLine = 1; 435 | while(goToLine < lineGiven) 436 | { 437 | temp = temp->next; 438 | goToLine++; 439 | } 440 | string backup = temp->data; 441 | temp->data = dataGiven; //change what is inside the node number that has been given as line parameter 442 | replacedLine.lineNumber = lineGiven; 443 | replacedLine.text = backup; 444 | replacedLine.commandNumber = 4; 445 | undoStack.push(replacedLine); 446 | } 447 | } 448 | 449 | void deleteLine(int lineGiven){ //this function should delete anything in the given line, also decreases the numOfLines 450 | if (head == NULL) 451 | { 452 | cout<<"There is no line to be deleted/removed."<data; 466 | node *temp = head; 467 | node *nextNode = head->next; 468 | head = nextNode; 469 | delete(temp); 470 | numOfLines--; 471 | undoCmd headRemoved; 472 | headRemoved.text = backup; 473 | headRemoved.lineNumber = 1; 474 | headRemoved.commandNumber = 12; 475 | undoStack.push(headRemoved); 476 | } 477 | else if(lineGiven == numOfLines){ 478 | node *temp = head; 479 | undoCmd deletedLine; 480 | deletedLine.commandNumber = 11; 481 | while (temp->next != NULL && temp->next->next != NULL) 482 | { 483 | temp = temp->next; 484 | } 485 | tail = temp; 486 | string backup = temp->next->data; 487 | delete temp->next; 488 | temp->next = NULL; 489 | numOfLines--; 490 | deletedLine.text = backup; 491 | deletedLine.lineNumber = lineGiven; 492 | undoStack.push(deletedLine); 493 | 494 | } 495 | else if (lineGiven > numOfLines) 496 | { 497 | cout<<"Entered line is larger than existing lines..."<next; 510 | nextNode = nextNode->next; 511 | iterator++; 512 | } 513 | nextNode = nextNode->next; 514 | temp = nextNode; 515 | nextNode = nextNode->next; 516 | prevNode->next = nextNode; 517 | string backup = temp->data; 518 | delete(temp); 519 | numOfLines--; 520 | deletedLine.text = backup; 521 | deletedLine.lineNumber = lineGiven; 522 | undoStack.push(deletedLine); 523 | } 524 | } 525 | 526 | void insertFurtherAway(string dataGiven, int lineGiven){ //will print /n lines if given line is larger than numOfLines 527 | undoCmd insertedFurtherAway; 528 | insertedFurtherAway.lineNumber = 0; 529 | insertedFurtherAway.commandNumber = 9; 530 | if (head == NULL) 531 | { 532 | while(numOfLines < lineGiven-1) 533 | { 534 | whateverAddToTail("\n"); 535 | insertedFurtherAway.lineNumber++; 536 | } 537 | // insertedFurtherAway.lineNumber++; 538 | whateverAddToTail(dataGiven); 539 | } 540 | else{ 541 | while(numOfLines < lineGiven-1) 542 | { 543 | whateverAddToTail("\n"); 544 | insertedFurtherAway.lineNumber++; 545 | } 546 | whateverAddToTail(dataGiven); 547 | } 548 | undoStack.push(insertedFurtherAway); 549 | } 550 | 551 | void moveNtoM(int nLineGiven, int mLineGiven){ //function used to Move line N into line M 552 | if (nLineGiven == 1) 553 | { 554 | string headText = head->data; 555 | deleteHead(); 556 | insertTextInBetween(headText,mLineGiven); 557 | } 558 | else 559 | { 560 | node *temp = head; 561 | int iterator = 1; 562 | while(iterator < nLineGiven) 563 | { 564 | temp = temp -> next; 565 | iterator++; 566 | } 567 | string dataSaved = temp->data; 568 | deleteLine(nLineGiven); 569 | insertTextInBetween(dataSaved,mLineGiven); 570 | } 571 | undoCmd moveHeadToM; 572 | moveHeadToM.commandNumber = 2; 573 | moveHeadToM.nLine = nLineGiven; 574 | moveHeadToM.mLine= mLineGiven; 575 | undoStack.push(moveHeadToM); 576 | } 577 | 578 | void printOnePage(int pageGiven){ //function used to print only one page, only 10 or if there are less than 10 lines, it'll print only those lines 579 | node *temp = head; 580 | if (numOfLines < pageGiven*10) 581 | { 582 | int iterator = 1; 583 | while(iterator < (pageGiven*10)-9){ 584 | temp = temp->next; 585 | iterator++; 586 | } 587 | for (int start = (pageGiven*10)-9 ; start <= numOfLines; start++) 588 | { 589 | cout<data<next; 591 | } 592 | cout<<"-------------------Page "<= pageGiven * 10) 595 | { 596 | int iterator = 1; 597 | while(iterator < (pageGiven*10)-9){ 598 | temp = temp->next; 599 | iterator++; 600 | } 601 | for (int start = (pageGiven*10)-9 ; start <= pageGiven*10; start++) 602 | { 603 | cout<data<next; 605 | } 606 | cout<<"-------------------Page "< numOfLines) 609 | { 610 | cout<<"WHOOSH, you want to print an inexisting page, collect yourself!"<>fileName; 618 | fileName+=".txt"; 619 | ifstream myfile; 620 | myfile.open(fileName); 621 | string s; 622 | while(getline(myfile,s)) 623 | { 624 | addToTail(s); 625 | } 626 | myfile.close(); 627 | } 628 | 629 | void undo(){ //function used to undo the last action taken 630 | undoCmd temp = undoStack.top(); 631 | if (temp.commandNumber == 1) 632 | { 633 | cout<<"Added To head, removing from head..."<= 0){ 683 | whateverDeleteTail(); 684 | whatever--; 685 | } 686 | undoStack.pop(); 687 | } 688 | else if (temp.commandNumber == 10) 689 | { 690 | cout<<"Line deleted, inserting again..."<data<next; 732 | linePrinted++; 733 | } 734 | } 735 | } 736 | 737 | void saveAll(){ 738 | node *temp = head; 739 | int linePrinted = 1; 740 | int pagePrinted = 2; 741 | string fileName; 742 | cout<<"Enter the file name : "; 743 | cin>>fileName; 744 | fileName+=".txt"; 745 | outfile.open(fileName, ios_base::app); 746 | while(temp!=NULL) 747 | { 748 | outfile<data; 749 | temp = temp->next; 750 | linePrinted++; 751 | } 752 | outfile.flush(); 753 | outfile.close(); 754 | } 755 | 756 | // void numOfLinesp(){ //Will print the numOfLines, used for debugging 757 | // cout<