Skip to content

Instantly share code, notes, and snippets.

@willy-r
Last active May 29, 2020 21:24
Show Gist options
  • Save willy-r/3b263397863e05a44a7912d906a81717 to your computer and use it in GitHub Desktop.
Save willy-r/3b263397863e05a44a7912d906a81717 to your computer and use it in GitHub Desktop.
Build a simple text editor
"""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