Last active
May 29, 2020 21:24
-
-
Save willy-r/3b263397863e05a44a7912d906a81717 to your computer and use it in GitHub Desktop.
Build a simple text editor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"""This is a simple script that simulates a text editor.""" | |
import re | |
import os.path | |
from datetime import datetime | |
class TextEditor: | |
"""A tentative of representing a simple text editor. | |
This class is a very simple tentative of representing a text | |
editor, contains some methods for manipulating the text that | |
will be edited. | |
:attr current_text: This is the text that will be edited. | |
:type current_text: str | |
:attr undo_text: The "copy" of the current text that contains the | |
last change made in current_text. | |
:type undo_text: str | |
""" | |
def __init__(self, current_text): | |
self.current_text = current_text | |
self.undo_text = None | |
def __str__(self): | |
"""Returns the string representation of the current_text.""" | |
return self.current_text | |
def append_text(self, text): | |
"""Appends text to the end of the current_text. | |
:param text: The text that will be appended to the end of the | |
current_text. | |
:type text: str | |
""" | |
self.undo_text = self.current_text | |
self.current_text += text | |
def insert_text(self, index, text): | |
"""Inserts text in the index of the current_text. | |
:param index: The index that the text will be inserted. | |
:type index: int | |
:param text: The text that will be inserted in the index of the | |
current_text. | |
:type text: str | |
""" | |
self.undo_text = self.current_text | |
list_current_text = [char for char in self.current_text] | |
list_current_text.insert(index, text) | |
self.current_text = ''.join(list_current_text) | |
def replace_word(self, old, new): | |
"""Replaces a old to a new word of the current_text. | |
If the old word is not in the current_text, the process will be | |
canceled. | |
:param old: The word in current_text that will be | |
replaced by new. | |
:type old: str | |
:param new: The word that will replace the old. | |
:type new: str | |
""" | |
self.undo_text = self.current_text | |
pattern = re.compile(fr'\b{old}\b') | |
if not old or pattern.search(self.current_text) is None: | |
print(f'The word "{old}" is not in the current text.') | |
else: | |
self.current_text = pattern.sub(new, self.current_text, 1) | |
def delete_text(self, num_chars=0): | |
"""Deletes the last num_chars of the current_text. | |
:param num_chars: The number of the last characters that will be | |
deleted (default is 0 (zero), that means "all characters of | |
current_text will be deleted"). | |
:type num_chars: int | |
""" | |
self.undo_text = self.current_text | |
# Denies negative number of characters. | |
num_chars = abs(num_chars) | |
if num_chars == 0: | |
self.current_text = '' | |
else: | |
self.current_text = self.current_text[:-num_chars] | |
def undo_last_change(self): | |
"""Undo the last change made in the current_text. | |
If no change was made in current_text, the process will be | |
canceled. | |
""" | |
if self.undo_text is None: | |
print('No change was made in the current text yet.') | |
else: | |
self.current_text = self.undo_text | |
def save_to_file(self, filename): | |
"""Saves the current_text to a text file. | |
:param filename: The filename with extension (if you want to | |
save the file in another directory, the full path of the | |
file must be passed). | |
:type filename: str | |
""" | |
with open(filename, 'w') as f_obj: | |
f_obj.write(self.current_text) | |
def edit_from_file(self, filename): | |
"""Edits the text from a file. | |
Replaces the current_text with the text from the file. | |
If the file does not exist, the process will be canceled. | |
:param filename: The filename with extension (if the file isn't | |
in the same working directory, the full path of the file | |
must be passed). | |
:type filename: str | |
""" | |
self.undo_text = self.current_text | |
if not os.path.exists(filename): | |
print(f"The file '{filename}' does not exist.") | |
else: | |
with open(filename) as f_obj: | |
text = f_obj.read() | |
self.current_text = text.rstrip() | |
def main(): | |
edit_text = TextEditor('') | |
while True: | |
print(f'\nCurrent text: "{edit_text}"') | |
command = str(input('>>> ')).lower() | |
if command == 'h': | |
print("""\ | |
-> Text Editor Commands <- | |
h -- show this help message | |
a -- append text to the end of the current text | |
i -- insert text in the index of the current text | |
r -- replace a word of the current text | |
d -- delete the last number of characters of the current text | |
s -- save the current text in a text file | |
e -- edit a text from a file | |
u -- undo the last change | |
q -- quit the text editor | |
""".rstrip()) | |
elif command == 'a': | |
text = str(input(f'\n[APPEND] ->{edit_text}')) | |
edit_text.append_text(text) | |
elif command == 'i': | |
try: | |
index = int(input('\n[INSERT] Index for insert: ')) | |
except ValueError: | |
print('ERROR: expected a integer for the index.') | |
else: | |
current_text = edit_text.current_text | |
text = str(input(f'[INSERT] ->{current_text[:index]}')) | |
edit_text.insert_text(index, text) | |
elif command == 'r': | |
old_word = str(input('\n[REPLACE] Old word: ')) | |
new_word = str(input(f'[REPLACE "{old_word}"] New word: ')) | |
edit_text.replace_word(old_word, new_word) | |
elif command == 'd': | |
try: | |
n = int(input('\n[DELETE] N° characters [0 to delete all]: ')) | |
edit_text.delete_text(n) | |
except ValueError: | |
print('ERROR: expected a integer for the n° of characters.') | |
elif command == 's': | |
filename = str(input('\n[SAVE TO FILE] Filename: /')) | |
edit_text.save_to_file(filename) | |
path = os.path.realpath(filename) | |
dt_format = '%b %m %Y, %H:%M:%S' | |
now = datetime.strftime(datetime.now(), dt_format) | |
print(f"Saved on '{path}' - {now}") | |
elif command == 'e': | |
filename = str(input('\n[EDIT FROM FILE] Filename: /')) | |
edit_text.edit_from_file(filename) | |
elif command == 'u': | |
edit_text.undo_last_change() | |
elif command == 'q': | |
print('Exiting the text editor...') | |
break | |
else: | |
print("""\ | |
This is not a valid command. | |
Please enter 'h' to see all available commands. | |
""".rstrip()) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment