пофиксил баги с переходом в конец/начало длинных строк + удаления длинной строки когда 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.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)
# Загрузка файла для редактирования

View File

@ -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:
# Разделяем текущую строку на две части

View File

@ -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
@ -80,3 +46,46 @@ class CursesAdapter:
def GetChar(self) -> int:
"""Wait users input"""
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)