пофиксил баги с переходом в конец/начало длинных строк + удаления длинной строки когда scrollX большой

master
serr 2025-02-04 20:01:25 +03:00
parent 6012c2f690
commit 94bbccde99
3 changed files with 95 additions and 42 deletions

10
main.py
View File

@ -1,13 +1,15 @@
from mvc.models import VimModel 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 Controller, ReturnCode
from mvc.controllers import EditStrategy, CommandStrategy, NormalStrategy from mvc.controllers import EditStrategy, CommandStrategy, NormalStrategy
def main(): def main():
model, view = VimModel(), VimView() adapter = CursesAdapter()
model = VimModel(adapter.lines, adapter.cols)
view = VimView(adapter)
# начальный режим - редактирование # start mode - navigation mode
strategy = NormalStrategy(model, view.curses_adapter) strategy = NormalStrategy(model, adapter)
controller = Controller(strategy) controller = Controller(strategy)
# Загрузка файла для редактирования # Загрузка файла для редактирования

View File

@ -9,7 +9,9 @@ class ReturnCode(Enum):
CONTINUE = -96 CONTINUE = -96
class VimModel: class VimModel:
def __init__(self): def __init__(self, displayLines: int, displayCols: int):
self.displayLines = displayLines
self.displayCols = displayCols
self.displayBuffer = [] # буфер для хранения всех строк self.displayBuffer = [] # буфер для хранения всех строк
self.currentLine = 0 # текущий индекс строки self.currentLine = 0 # текущий индекс строки
self.currentCol = 0 # текущий индекс колонки self.currentCol = 0 # текущий индекс колонки
@ -44,19 +46,59 @@ class VimModel:
self.displayBuffer[self.currentLine].insert(self.currentCol, chr(symbolCode)) self.displayBuffer[self.currentLine].insert(self.currentCol, chr(symbolCode))
self.currentCol += 1 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): def EnterCommand(self):
"""Обработка введенной команды"""
cmd = ''.join(self.commandBuffer) cmd = ''.join(self.commandBuffer)
self.commandBuffer.clear() self.commandBuffer.clear()
match cmd: match cmd:
case "$": case "$":
self.currentCol = len(self.displayBuffer[self.currentLine]) self.MoveToLineEnd() # Перемещение в конец строки
return ReturnCode.GOOD
case "^" | "0":
self.MoveToLineStart() # Перемещение в начало строки
return ReturnCode.GOOD return ReturnCode.GOOD
case "q": case "q":
return ReturnCode.EXIT_CODE return ReturnCode.EXIT_CODE
case "i":
return ReturnCode.SET_EDIT_MODE
case "S": case "S":
self.currentCol = 0 self.MoveToLineStart()
self.displayBuffer[self.currentLine] = [] self.displayBuffer[self.currentLine] = []
return ReturnCode.SET_EDIT_MODE 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: def Enter(self) -> None:
# Разделяем текущую строку на две части # Разделяем текущую строку на две части

View File

@ -1,39 +1,5 @@
import curses 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: class CursesAdapter:
def __init__(self) -> None: def __init__(self) -> None:
self.KEY_LEFT = curses.KEY_LEFT self.KEY_LEFT = curses.KEY_LEFT
@ -79,4 +45,47 @@ class CursesAdapter:
def GetChar(self) -> int: def GetChar(self) -> int:
"""Wait users input""" """Wait users input"""
return self.screen.getch() 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)