From 50595ba6f649bd9b7d0ab87bb383957853ec7ec4 Mon Sep 17 00:00:00 2001 From: serr Date: Tue, 4 Feb 2025 13:16:23 +0300 Subject: [PATCH] =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B2=D0=B8=D1=87=D0=BD?= =?UTF-8?q?=D0=BE=D0=B5=20=D1=80=D0=B0=D0=B7=D0=B1=D0=B8=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20=D0=BD=D0=B0=20MVC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 - controllers.py | 105 ++++++++++++++++++++++++++++++ main.py | 23 +++++++ models.py | 28 ++++++++ test.py | 173 ------------------------------------------------- views.py | 48 ++++++++++++++ 6 files changed, 204 insertions(+), 174 deletions(-) create mode 100644 controllers.py create mode 100644 main.py create mode 100644 models.py delete mode 100644 test.py create mode 100644 views.py diff --git a/.gitignore b/.gitignore index dd6d44a..36f274b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ example.txt boost_python312-vc143-mt-x64-1_87.dll mystring.pyd -views.py __pycache__ \ No newline at end of file diff --git a/controllers.py b/controllers.py new file mode 100644 index 0000000..65ca942 --- /dev/null +++ b/controllers.py @@ -0,0 +1,105 @@ +import curses + +class EditController: + def __init__(self, model, view): + self.model = model + self.view = view + + def handle_input(self, symbolCode): + """Обработка ввода пользователя""" + if symbolCode == 27: # EXIT + return False + + elif symbolCode == curses.KEY_LEFT: + if self.model.currentCol > 0: + self.model.currentCol -= 1 + elif self.model.currentLine > 0: + self.model.currentLine -= 1 + self.model.currentCol = len(self.model.displayBuffer[self.model.currentLine]) + + elif symbolCode == curses.KEY_RIGHT: + if self.model.currentCol < len(self.model.displayBuffer[self.model.currentLine]): + self.model.currentCol += 1 + elif self.model.currentLine < len(self.model.displayBuffer) - 1: + self.model.currentLine += 1 + self.model.currentCol = 0 + + elif symbolCode == curses.KEY_UP: + if self.model.currentLine > 0: + self.model.currentLine -= 1 + self.model.currentCol = min(self.model.currentCol, len(self.model.displayBuffer[self.model.currentLine])) + + elif symbolCode == curses.KEY_DOWN: + if self.model.currentLine < len(self.model.displayBuffer) - 1: + self.model.currentLine += 1 + self.model.currentCol = min(self.model.currentCol, len(self.model.displayBuffer[self.model.currentLine])) + + # BACKSPACE + elif symbolCode in (127, 8): # Backspace + if self.model.currentCol > 0: # Если символ существует в текущей строке + self.model.currentCol -= 1 + del self.model.displayBuffer[self.model.currentLine][self.model.currentCol] # Удаляем символ + elif self.model.currentLine > 0: # Если текущая строка не первая + # Объединяем текущую строку с предыдущей + prev_line_length = len(self.model.displayBuffer[self.model.currentLine - 1]) + self.model.displayBuffer[self.model.currentLine - 1].extend(self.model.displayBuffer[self.model.currentLine]) + del self.model.displayBuffer[self.model.currentLine] + self.model.currentLine -= 1 + self.model.currentCol = prev_line_length # Переходим в конец предыдущей строки + + # ENTER + elif symbolCode == 10: # Enter + # Разделяем текущую строку на две части + new_line = self.model.displayBuffer[self.model.currentLine][self.model.currentCol:] + self.model.displayBuffer[self.model.currentLine] = self.model.displayBuffer[self.model.currentLine][:self.model.currentCol] + self.model.currentLine += 1 # Переходим на следующую строку + self.model.displayBuffer.insert(self.model.currentLine, new_line) # Вставляем новую строку + self.model.currentCol = 0 # Сбрасываем индекс колонки + + # Сохранение файла (Ctrl+S) + elif symbolCode == 19: # Ctrl+S + result = self.model.save_file() + if result is True: + self.view.screen.addstr(self.view.lines - 1, 0, f"File {self.model.file_path} saved successfully.") + else: + self.view.screen.addstr(self.view.lines - 1, 0, f"Error saving file: {result}") + + else: + if self.model.currentCol <= len(self.model.displayBuffer[self.model.currentLine]): # проверяем, не превышает ли индекс колонки длину строки + self.model.displayBuffer[self.model.currentLine].insert(self.model.currentCol, chr(symbolCode)) + self.model.currentCol += 1 + + # Прокрутка экрана + if self.model.currentLine < self.model.scrollY: + self.model.scrollY = self.model.currentLine + elif self.model.currentLine >= self.model.scrollY + self.view.lines - 1: + self.model.scrollY = self.model.currentLine - self.view.lines + 2 + + if self.model.currentCol < self.model.scrollX: + self.model.scrollX = self.model.currentCol + elif self.model.currentCol >= self.model.scrollX + self.view.cols: + self.model.scrollX = self.model.currentCol - self.view.cols + 1 + + return True + + def render(self): + """Отрисовка текущего состояния""" + self.view.screen.clear() + + # Отображение видимой части текста + for i in range(self.view.lines - 1): + if i + self.model.scrollY < len(self.model.displayBuffer): + line = ''.join(self.model.displayBuffer[i + self.model.scrollY]) + if self.model.scrollX < len(line): + self.view.SetString(i, 0, line[self.model.scrollX:self.model.scrollX + self.view.cols]) + else: + self.view.SetString(i, 0, '') + else: + self.view.SetString(i, 0, '') + + # Отображение панели режима + self.view.EditModeBar(self.model.currentLine, len(self.model.displayBuffer), self.model.file_path) + + # Установка курсора + self.view.SetCursor(self.model.currentLine - self.model.scrollY, self.model.currentCol - self.model.scrollX) + self.view.Refresh() \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..be6a109 --- /dev/null +++ b/main.py @@ -0,0 +1,23 @@ +from models import VimModel +from views import CursesAdapter +from controllers import EditController + +def main(): + model = VimModel() + view = CursesAdapter() + controller = EditController(model, view) + + # Загрузка файла для редактирования + file_path = "example.txt" # Укажите путь к файлу + model.load_file(file_path) + + while True: + controller.render() + symbolCode = view.GetChar() + if not controller.handle_input(symbolCode): + break + + view.Cleanup() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/models.py b/models.py new file mode 100644 index 0000000..4194714 --- /dev/null +++ b/models.py @@ -0,0 +1,28 @@ +class VimModel: + def __init__(self): + self.displayBuffer = [] # буфер для хранения всех строк + self.currentLine = 0 # текущий индекс строки + self.currentCol = 0 # текущий индекс колонки + self.scrollY = 0 # вертикальная прокрутка + self.scrollX = 0 # горизонтальная прокрутка + self.file_path = "" # путь к файлу + + def load_file(self, file_path): + """Загрузка файла для редактирования""" + self.file_path = file_path + try: + with open(file_path, "r") as file: + self.displayBuffer = [list(line.rstrip('\n')) for line in file.readlines()] + except FileNotFoundError: + print(f"File {file_path} not found. Starting with empty buffer.") + self.displayBuffer = [] + + def save_file(self): + """Сохранение файла""" + try: + with open(self.file_path, "w") as file: + for line in self.displayBuffer: + file.write(''.join(line) + '\n') + return True + except Exception as e: + return str(e) \ No newline at end of file diff --git a/test.py b/test.py deleted file mode 100644 index b2c5b17..0000000 --- a/test.py +++ /dev/null @@ -1,173 +0,0 @@ -import curses - -class CursesAdapter: - def __init__(self) -> None: - self.screen = curses.initscr() - self.screen.keypad(True) - self.cols = curses.COLS - self.lines = curses.LINES - # init color system - curses.start_color() - # green color pair - curses.init_pair(1, curses.COLOR_MAGENTA, curses.COLOR_BLACK) - curses.curs_set(1) # Make cursor visible - - def Refresh(self) -> None: - """Apply changes""" - self.screen.refresh() - - def Cleanup(self) -> None: - curses.endwin() - - def SetCursor(self, x: int, y: int): - """set cursor position (x, y)""" - self.screen.move(x, y) - - def SetChar(self, x: int, y: int, code: int): - """set char position (x, y)""" - self.screen.addch(x, y, code) - - def SetString(self, x: int, y: int, data: str): - """set string begin position (x, y)""" - self.screen.addstr(x, y, data) - - def GetChar(self) -> int: - """Wait users input""" - return self.screen.getch() - - def EditModeBar(self, currentLine, totalLines, fileName): - """Print edit mode information panel""" - self.screen.addstr(self.lines - 1, 0, ' ' * (self.cols - 1)) # Очистка строки - self.screen.addstr(self.lines - 1, 0, "FILE: ") - self.screen.addstr(fileName, curses.color_pair(1)) # Имя файла - self.screen.addstr(" | MODE:") - self.screen.addstr(" EDIT", curses.color_pair(1)) - self.screen.addstr(" | LINE: ") - self.screen.addstr(str(currentLine + 1), curses.color_pair(1)) - self.screen.addstr("/") - self.screen.addstr(str(totalLines), curses.color_pair(1)) # Общее количество строк - -def main(): - adapter = CursesAdapter() - - currentCol = 0 # текущий индекс колонки - currentLine = 0 # текущий индекс строки - scrollY = 0 # вертикальная прокрутка - scrollX = 0 # горизонтальная прокрутка - displayBuffer = [] # буфер для хранения всех строк - - mode = "EDIT" - - # Загрузка файла для редактирования - file_path = "example.txt" # Укажите путь к файлу - try: - with open(file_path, "r") as file: - displayBuffer = [list(line.rstrip('\n')) for line in file.readlines()] - except FileNotFoundError: - print(f"File {file_path} not found. Starting with empty buffer.") - - while True: - # Очистка экрана - adapter.screen.clear() - - # Отображение видимой части текста - for i in range(adapter.lines - 1): - if i + scrollY < len(displayBuffer): - line = ''.join(displayBuffer[i + scrollY]) - if scrollX < len(line): - adapter.SetString(i, 0, line[scrollX:scrollX + adapter.cols]) - else: - adapter.SetString(i, 0, '') - else: - adapter.SetString(i, 0, '') - - # Отображение панели режима - adapter.EditModeBar(currentLine, len(displayBuffer), file_path) - - # Установка курсора - adapter.SetCursor(currentLine - scrollY, currentCol - scrollX) - adapter.Refresh() - - # Ожидание ввода - if mode == "EDIT": - symbolCode = adapter.GetChar() - - if symbolCode == 27: # EXIT - break - - elif symbolCode == curses.KEY_LEFT: - if currentCol > 0: - currentCol -= 1 - elif currentLine > 0: - currentLine -= 1 - currentCol = len(displayBuffer[currentLine]) - - elif symbolCode == curses.KEY_RIGHT: - if currentCol < len(displayBuffer[currentLine]): - currentCol += 1 - elif currentLine < len(displayBuffer) - 1: - currentLine += 1 - currentCol = 0 - - elif symbolCode == curses.KEY_UP: - if currentLine > 0: - currentLine -= 1 - currentCol = min(currentCol, len(displayBuffer[currentLine])) - - elif symbolCode == curses.KEY_DOWN: - if currentLine < len(displayBuffer) - 1: - currentLine += 1 - currentCol = min(currentCol, len(displayBuffer[currentLine])) - - # BACKSPACE - elif symbolCode in (127, 8): # Backspace - if currentCol > 0: # Если символ существует в текущей строке - currentCol -= 1 - del displayBuffer[currentLine][currentCol] # Удаляем символ - elif currentLine > 0: # Если текущая строка не первая - # Объединяем текущую строку с предыдущей - prev_line_length = len(displayBuffer[currentLine - 1]) - displayBuffer[currentLine - 1].extend(displayBuffer[currentLine]) - del displayBuffer[currentLine] - currentLine -= 1 - currentCol = prev_line_length # Переходим в конец предыдущей строки - - # ENTER - elif symbolCode == 10: # Enter - # Разделяем текущую строку на две части - new_line = displayBuffer[currentLine][currentCol:] - displayBuffer[currentLine] = displayBuffer[currentLine][:currentCol] - currentLine += 1 # Переходим на следующую строку - displayBuffer.insert(currentLine, new_line) # Вставляем новую строку - currentCol = 0 # Сбрасываем индекс колонки - - # Сохранение файла (Ctrl+S) - elif symbolCode == 19: # Ctrl+S - try: - with open(file_path, "w") as file: - for line in displayBuffer: - file.write(''.join(line) + '\n') - adapter.screen.addstr(adapter.lines - 1, 0, f"File {file_path} saved successfully.") - except Exception as e: - adapter.screen.addstr(adapter.lines - 1, 0, f"Error saving file: {e}") - - else: - if currentCol <= len(displayBuffer[currentLine]): # проверяем, не превышает ли индекс колонки длину строки - displayBuffer[currentLine].insert(currentCol, chr(symbolCode)) - currentCol += 1 - - # Прокрутка экрана - if currentLine < scrollY: - scrollY = currentLine - elif currentLine >= scrollY + adapter.lines - 1: - scrollY = currentLine - adapter.lines + 2 - - if currentCol < scrollX: - scrollX = currentCol - elif currentCol >= scrollX + adapter.cols: - scrollX = currentCol - adapter.cols + 1 - - adapter.Cleanup() - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/views.py b/views.py new file mode 100644 index 0000000..ebdb28c --- /dev/null +++ b/views.py @@ -0,0 +1,48 @@ +import curses + +class CursesAdapter: + def __init__(self) -> None: + self.screen = curses.initscr() + self.screen.keypad(True) + self.cols = curses.COLS + self.lines = curses.LINES + # init color system + curses.start_color() + # green color pair + curses.init_pair(1, curses.COLOR_MAGENTA, curses.COLOR_BLACK) + curses.curs_set(1) # Make cursor visible + + def Refresh(self) -> None: + """Apply changes""" + self.screen.refresh() + + def Cleanup(self) -> None: + curses.endwin() + + def SetCursor(self, x: int, y: int): + """set cursor position (x, y)""" + self.screen.move(x, y) + + def SetChar(self, x: int, y: int, code: int): + """set char position (x, y)""" + self.screen.addch(x, y, code) + + def SetString(self, x: int, y: int, data: str): + """set string begin position (x, y)""" + self.screen.addstr(x, y, data) + + def GetChar(self) -> int: + """Wait users input""" + return self.screen.getch() + + def EditModeBar(self, currentLine, totalLines, fileName): + """Print edit mode information panel""" + self.screen.addstr(self.lines - 1, 0, ' ' * (self.cols - 1)) # Очистка строки + self.screen.addstr(self.lines - 1, 0, "FILE: ") + self.screen.addstr(fileName, curses.color_pair(1)) # Имя файла + self.screen.addstr(" | MODE:") + self.screen.addstr(" EDIT", curses.color_pair(1)) + self.screen.addstr(" | LINE: ") + self.screen.addstr(str(currentLine + 1), curses.color_pair(1)) + self.screen.addstr("/") + self.screen.addstr(str(totalLines), curses.color_pair(1)) # Общее количество строк \ No newline at end of file