From 94bbccde992aad5356e5e4c2a0f16364a45f3e93 Mon Sep 17 00:00:00 2001 From: serr Date: Tue, 4 Feb 2025 20:01:25 +0300 Subject: [PATCH] =?UTF-8?q?=D0=BF=D0=BE=D1=84=D0=B8=D0=BA=D1=81=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B1=D0=B0=D0=B3=D0=B8=20=D1=81=20=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D0=B5=D1=85=D0=BE=D0=B4=D0=BE=D0=BC=20=D0=B2=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=BD=D0=B5=D1=86/=D0=BD=D0=B0=D1=87=D0=B0=D0=BB=D0=BE=20?= =?UTF-8?q?=D0=B4=D0=BB=D0=B8=D0=BD=D0=BD=D1=8B=D1=85=20=D1=81=D1=82=D1=80?= =?UTF-8?q?=D0=BE=D0=BA=20+=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=B4=D0=BB=D0=B8=D0=BD=D0=BD=D0=BE=D0=B9=20=D1=81?= =?UTF-8?q?=D1=82=D1=80=D0=BE=D0=BA=D0=B8=20=D0=BA=D0=BE=D0=B3=D0=B4=D0=B0?= =?UTF-8?q?=20scrollX=20=D0=B1=D0=BE=D0=BB=D1=8C=D1=88=D0=BE=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.py | 10 ++++--- mvc/models.py | 48 +++++++++++++++++++++++++++++-- mvc/views.py | 79 ++++++++++++++++++++++++++++----------------------- 3 files changed, 95 insertions(+), 42 deletions(-) diff --git a/main.py b/main.py index b3ebcbd..a21b4da 100644 --- a/main.py +++ b/main.py @@ -1,13 +1,15 @@ from mvc.models import VimModel -from mvc.views import VimView +from mvc.views import VimView, CursesAdapter from mvc.controllers import Controller, ReturnCode from mvc.controllers import EditStrategy, CommandStrategy, NormalStrategy def main(): - model, view = VimModel(), VimView() + adapter = CursesAdapter() + model = VimModel(adapter.lines, adapter.cols) + view = VimView(adapter) - # начальный режим - редактирование - strategy = NormalStrategy(model, view.curses_adapter) + # start mode - navigation mode + strategy = NormalStrategy(model, adapter) controller = Controller(strategy) # Загрузка файла для редактирования diff --git a/mvc/models.py b/mvc/models.py index f47b2f6..088288e 100644 --- a/mvc/models.py +++ b/mvc/models.py @@ -9,7 +9,9 @@ class ReturnCode(Enum): CONTINUE = -96 class VimModel: - def __init__(self): + def __init__(self, displayLines: int, displayCols: int): + self.displayLines = displayLines + self.displayCols = displayCols self.displayBuffer = [] # буфер для хранения всех строк self.currentLine = 0 # текущий индекс строки self.currentCol = 0 # текущий индекс колонки @@ -44,19 +46,59 @@ class VimModel: self.displayBuffer[self.currentLine].insert(self.currentCol, chr(symbolCode)) self.currentCol += 1 + def MoveToLineStart(self) -> None: + """Переместить курсор в начало строки и сбросить прокрутку""" + self.currentCol = 0 + self.scrollX = 0 # Сброс горизонтальной прокрутки + + def MoveToLineEnd(self) -> None: + """Переместить курсор в конец строки с учетом прокрутки""" + line_length = len(self.displayBuffer[self.currentLine]) + self.currentCol = line_length + + # Если строка длиннее экрана, корректируем прокрутку + if line_length > self.displayCols: + self.scrollX = max(0, line_length - self.displayCols + 1) + def EnterCommand(self): + """Обработка введенной команды""" cmd = ''.join(self.commandBuffer) self.commandBuffer.clear() match cmd: case "$": - self.currentCol = len(self.displayBuffer[self.currentLine]) + self.MoveToLineEnd() # Перемещение в конец строки + return ReturnCode.GOOD + case "^" | "0": + self.MoveToLineStart() # Перемещение в начало строки return ReturnCode.GOOD case "q": return ReturnCode.EXIT_CODE + case "i": + return ReturnCode.SET_EDIT_MODE case "S": - self.currentCol = 0 + self.MoveToLineStart() self.displayBuffer[self.currentLine] = [] return ReturnCode.SET_EDIT_MODE + case "RIGHT": + if self.currentCol < len(self.displayBuffer[self.currentLine]): + self.currentCol += 1 + return ReturnCode.GOOD + case "LEFT": + if self.currentCol > 0: + self.currentCol -= 1 + return ReturnCode.GOOD + case "UP": + if self.currentLine > 0: + self.currentLine -= 1 + if self.currentCol > len(self.displayBuffer[self.currentLine]): + self.currentCol = len(self.displayBuffer[self.currentLine]) + return ReturnCode.GOOD + case "DOWN": + if self.currentLine < len(self.displayBuffer) - 1: + self.currentLine += 1 + if self.currentCol > len(self.displayBuffer[self.currentLine]): + self.currentCol = len(self.displayBuffer[self.currentLine]) + return ReturnCode.GOOD def Enter(self) -> None: # Разделяем текущую строку на две части diff --git a/mvc/views.py b/mvc/views.py index 00bb3fb..a876847 100644 --- a/mvc/views.py +++ b/mvc/views.py @@ -1,39 +1,5 @@ import curses -class VimView: - def __init__(self) -> None: - self.curses_adapter = CursesAdapter() - - def Render(self, - displayBuffer: list[list[str]], - currentLine: int, currentCol: int, - scrollX: int, scrollY: int, - modeBarData: str): - """Отрисовка текущего состояния""" - - self.curses_adapter.screen.clear() - - # display visible part of text - for i in range(self.curses_adapter.lines - 1): - if i + scrollY < len(displayBuffer): - line = ''.join(displayBuffer[i + scrollY]) - if scrollX < len(line): - self.curses_adapter.SetString(i, 0, line[scrollX:scrollX + self.curses_adapter.cols]) - else: - self.curses_adapter.SetString(i, 0, '') - else: - self.curses_adapter.SetString(i, 0, '') - - # update mode bar - self.SetModeBar(modeBarData) - # update cursor - self.curses_adapter.SetCursor(currentLine - scrollY, currentCol - scrollX) - self.curses_adapter.Refresh() - - def SetModeBar(self, modeBarData: str): - """Print edit mode information panel""" - self.curses_adapter.SetString(self.curses_adapter.lines - 1, 0, modeBarData) - class CursesAdapter: def __init__(self) -> None: self.KEY_LEFT = curses.KEY_LEFT @@ -79,4 +45,47 @@ class CursesAdapter: def GetChar(self) -> int: """Wait users input""" - return self.screen.getch() \ No newline at end of file + return self.screen.getch() + + +class VimView: + def __init__(self, adapter: CursesAdapter) -> None: + self.curses_adapter = adapter + + + def Render(self, + displayBuffer: list[list[str]], + currentLine: int, currentCol: int, + scrollX: int, scrollY: int, + modeBarData: str): + """Отрисовка текущего состояния""" + + self.curses_adapter.screen.clear() + + # Отображение видимой части текста + for i in range(self.curses_adapter.lines - 1): + if i + scrollY < len(displayBuffer): + line = ''.join(displayBuffer[i + scrollY]) + if scrollX < len(line): + self.curses_adapter.SetString(i, 0, line[scrollX:scrollX + self.curses_adapter.cols]) + else: + self.curses_adapter.SetString(i, 0, '') + else: + self.curses_adapter.SetString(i, 0, '') + + # Обновление панели режима + self.SetModeBar(modeBarData) + + # Установка курсора с учетом прокрутки + cursor_x = currentLine - scrollY + cursor_y = currentCol - scrollX + + # Проверка, чтобы курсор не вышел за пределы экрана + if 0 <= cursor_x < self.curses_adapter.lines - 1 and 0 <= cursor_y < self.curses_adapter.cols: + self.curses_adapter.SetCursor(cursor_x, cursor_y) + + self.curses_adapter.Refresh() + + def SetModeBar(self, modeBarData: str): + """Print edit mode information panel""" + self.curses_adapter.SetString(self.curses_adapter.lines - 1, 0, modeBarData)