diff --git a/main.py b/main.py index 9bac2d7..738d100 100644 --- a/main.py +++ b/main.py @@ -9,7 +9,6 @@ def main(): adapter = CursesAdapter() model, view = VimModel(adapter.lines, adapter.cols), VimView(adapter) - # start mode - navigation mode strategy = NormalStrategy(model, view.curses_adapter) controller = Controller(strategy) @@ -18,13 +17,11 @@ def main(): if len(sys.argv) > 1: model.LoadFile(sys.argv[1]) else: model.LoadFile("File not found but i create it"+str(tools.UnixSec())+".txt") + view.SetModel(model) # view subscribe model + while True: - view.Render(model.displayBuffer, - model.currentLine, model.currentCol, - model.scrollX, model.scrollY, - model.ModeBar(), - model.showLineNumbers) + model.notify() symbolCode = view.curses_adapter.GetChar() match controller.HandleInput(symbolCode): diff --git a/mvc/controllers.py b/mvc/controllers.py index 021e4e5..6fd50a4 100644 --- a/mvc/controllers.py +++ b/mvc/controllers.py @@ -23,9 +23,6 @@ class BaseStrategy(ABC): case self.adapter.KEY_CTRL_S: self.model.SaveFile() case _: return ReturnCode.CONTINUE # Не обрабатываем, передаем дальше - self.model.Scroll() - return ReturnCode.GOOD - @abstractmethod def HandleInput(self, symbolCode: int) -> int: pass @@ -95,27 +92,38 @@ class NormalStrategy(BaseStrategy): def HandleInput(self, symbolCode) -> int: """Обработка ввода пользователя""" self.model.UpdateKeyLog(symbolCode) + result = self.handle_common_input(symbolCode) + if result != ReturnCode.CONTINUE: + self.model.Scroll() + return result + match symbolCode: - case self.adapter.KEY_TWO_DOTS: return ReturnCode.SET_COMMAND_MODE - case self.adapter.KEY_LEFT: self.model.MoveLeft() - case self.adapter.KEY_RIGHT: self.model.MoveRight() - case self.adapter.KEY_UP: self.model.MoveUp() - case self.adapter.KEY_DOWN: self.model.MoveDown() - case self.adapter.KEY_CTRL_S: self.model.SaveFile() - case self.adapter.KEY_NULL | self.adapter.KEY_XOR: self.model.ToLineStart() - case self.adapter.KEY_DOLLAR: self.model.ToLineEnd() - case self.adapter.KEY_p: self.model.Paste() + case self.adapter.KEY_TWO_DOTS: + return ReturnCode.SET_COMMAND_MODE + case self.adapter.KEY_NULL | self.adapter.KEY_XOR: + self.model.ToLineStart() + case self.adapter.KEY_DOLLAR: + self.model.ToLineEnd() + case self.adapter.KEY_p: + self.model.Paste() case self.adapter.KEY_w: - if self.model.CombinationCheck("diw", 3): self.model.DeleteWord() - elif self.model.CombinationCheck("yw", 3): self.model.CopyWord() + if self.model.CombinationCheck("diw", 3): + self.model.DeleteWord() + elif self.model.CombinationCheck("yw", 3): + self.model.CopyWord() else: self.model.ToWordEnd() - case self.adapter.KEY_b: self.model.ToWordStart() + case self.adapter.KEY_b: + self.model.ToWordStart() case self.adapter.KEY_d: - if self.model.CombinationCheck("dd", 3): self.model.CutLine() + if self.model.CombinationCheck("dd", 3): + self.model.CutLine() case self.adapter.KEY_y: - if self.model.CombinationCheck("yy", 3): self.model.CopyLine() - case self.adapter.KEY_x: self.model.DeleteNext() - case self.adapter.KEY_U: self.model.RecoverLine() + if self.model.CombinationCheck("yy", 3): + self.model.CopyLine() + case self.adapter.KEY_x: + self.model.DeleteNext() + case self.adapter.KEY_U: + self.model.RecoverLine() case self.adapter.KEY_G: num, ind = tools.ExtracrtNumBeforeLastKey(''.join([chr(item[0]) for item in self.model.keyLog])) if num != None and ind != None: @@ -124,7 +132,10 @@ class NormalStrategy(BaseStrategy): self.model.ToFileEnd() case self.adapter.KEY_g: if self.model.CombinationCheck("gg", 3): self.model.ToFileStart() - case self.adapter.KEY_PG_UP: self.model.PageUp() - case self.adapter.KEY_PG_DOWN: self.model.PageDown() + case self.adapter.KEY_PG_UP: + self.model.PageUp() + case self.adapter.KEY_PG_DOWN: + self.model.PageDown() + self.model.Scroll() return ReturnCode.GOOD \ No newline at end of file diff --git a/mvc/models.py b/mvc/models.py index 96f2f13..2cc08cd 100644 --- a/mvc/models.py +++ b/mvc/models.py @@ -1,4 +1,3 @@ -import re import tools from enum import Enum @@ -12,6 +11,7 @@ class ReturnCode(Enum): class VimModel: def __init__(self, displayLinesCount: int, displayColsCount: int): + self.observers = [] self.displayLinesCount = displayLinesCount self.displayColsCount = displayColsCount self.showLineNumbers = True @@ -29,6 +29,16 @@ class VimModel: self.commandBuffer = [] # буффер для команды self.exchangeBuffer = [] # буффер обмена + def attach(self, observer): + self.observers.append(observer) + + def detach(self, observer): + self.observers.remove(observer) + + def notify(self): + for observer in self.observers: + observer.Update() + def InputAfterCursor(self) -> None: self.inputAfterCursor = not self.inputAfterCursor diff --git a/mvc/views.py b/mvc/views.py index d7cc3b9..74e1250 100644 --- a/mvc/views.py +++ b/mvc/views.py @@ -1,4 +1,6 @@ +from abc import ABC, abstractmethod import curses +import mvc.models class CursesAdapter: def __init__(self) -> None: @@ -32,6 +34,7 @@ class CursesAdapter: self.screen.keypad(True) self.cols = curses.COLS self.lines = curses.LINES + curses.noecho() curses.curs_set(1) # Make cursor visible curses.start_color() curses.init_pair(1, curses.COLOR_BLUE, curses.COLOR_BLACK) # Фиолетовый текст на черном фоне @@ -64,10 +67,30 @@ class CursesAdapter: """Wait users input""" return self.screen.getch() +class Observer: + @abstractmethod + def Update(self): + pass -class VimView: +class VimView(Observer): def __init__(self, adapter: CursesAdapter) -> None: self.curses_adapter = adapter + self.model = None + + def SetModel(self, model: mvc.models.VimModel): + self.model = model + model.attach(self) + + def Update(self): + self.Render( + self.model.displayBuffer, + self.model.currentLine, + self.model.currentCol, + self.model.scrollX, + self.model.scrollY, + self.model.ModeBar(), + self.model.showLineNumbers + ) def Render(self, displayBuffer: list[list[str]],