diff options
| author | tslil <tslil@posteo.de> | 2026-03-05 13:07:07 +0000 |
|---|---|---|
| committer | tslil <tslil@posteo.de> | 2026-03-05 13:07:17 +0000 |
| commit | 0d734cd4095c57be5c6a527adf49504ca1d14863 (patch) | |
| tree | ba0ee668bd21b84d660d3a9123ebf5f70be4692d /python/src/types | |
| parent | 00e03d8fb65119e736dae4db8335e1ac67aac23e (diff) | |
Remove old python prototype
Diffstat (limited to 'python/src/types')
| -rw-r--r-- | python/src/types/buffer.py | 16 | ||||
| -rw-r--r-- | python/src/types/monad.py | 80 | ||||
| -rw-r--r-- | python/src/types/selection.py | 153 | ||||
| -rw-r--r-- | python/src/types/state.py | 93 |
4 files changed, 0 insertions, 342 deletions
diff --git a/python/src/types/buffer.py b/python/src/types/buffer.py deleted file mode 100644 index 04e1def..0000000 --- a/python/src/types/buffer.py +++ /dev/null @@ -1,16 +0,0 @@ -from dataclasses import dataclass - -@dataclass -class Buffer: - content: str - - @property - def min_pos(self) -> int: - return 0 - - @property - def max_pos(self) -> int: - return len(self.content) - - def valid_pos(self, pos : int) -> bool: - return self.min_pos <= pos < self.max_pos diff --git a/python/src/types/monad.py b/python/src/types/monad.py deleted file mode 100644 index f09ff33..0000000 --- a/python/src/types/monad.py +++ /dev/null @@ -1,80 +0,0 @@ -from functools import wraps -from typing import Callable - -from .selection import Selection -from .state import EditorState, Result, StateChange - - -class StateMonad: - def __init__(self, run_fn: Callable[[EditorState], Result]): - self._run_fn = run_fn - - def run(self, state: EditorState) -> Result: - return self._run_fn(state) - - def commit(self, state: EditorState) -> tuple[Selection, EditorState]: - sel, changes = self.run(state) - state.commit_changes(changes) - return (sel, state) - - def bind(self, f: Callable[[Selection], "StateMonad"]) -> "StateMonad": - def run_bound(state: EditorState) -> Result: - sel1, changes1 = self.run(state) - expr2 = f(sel1) - sel2, changes2 = expr2.run(state) - return (sel2, changes1 + changes2) - - return StateMonad(run_bound) - - @staticmethod - def pure(selection: Selection) -> "StateMonad": - def run_pure(_: EditorState) -> Result: - return (selection, []) - - return StateMonad(run_pure) - - def modify(change: StateChange, selection: Selection) -> "StateMonad": - def run_modify(_: EditorState) -> Result: - return (selection, [change]) - - return StateMonad(run_modify) - - -def monadic( - func: Callable[[Selection, EditorState], Result], -) -> Callable[[Selection | StateMonad], StateMonad]: - def make_monad(sel: Selection) -> StateMonad: - def run_fn(state: EditorState) -> Result: - return func(sel, state) - - return StateMonad(run_fn) - - @wraps(func) - def wrapper(arg: Selection | StateMonad) -> StateMonad: - if isinstance(arg, StateMonad): - return arg.bind(make_monad) - else: - return make_monad(arg) - - return wrapper - - -def group(*exprs: StateMonad) -> StateMonad: - def run_grouped(state: EditorState) -> Result: - all_selections = [] - all_changes = [] - - for expr in exprs: - sel, changes = expr.run(state) - all_selections.append(sel) - all_changes.extend(changes) - - # TODO: Check for any overlapping changes - # TODO: Merge selections into union - - return ( - all_selections[0] if all_selections else state.current_selection, - all_changes, - ) - - return StateMonad(run_grouped) diff --git a/python/src/types/selection.py b/python/src/types/selection.py deleted file mode 100644 index d75c9f0..0000000 --- a/python/src/types/selection.py +++ /dev/null @@ -1,153 +0,0 @@ -from dataclasses import dataclass, field -from typing import Callable - -from .buffer import Buffer - - -@dataclass -class Position: - pos: int - - -@dataclass -class Range: - start: Position - end: Position - - -@dataclass -class Ranges: - ranges: list[Range] - - -@dataclass -class MultiRanges: - multi_ranges: dict[Buffer, Ranges] - - -@dataclass -class Selection: - selection: Position | Range | Ranges | MultiRanges - buffers: set[Buffer] = field(default_factory=set) - - def __post_init__(self): - if type(self.selection) is MultiRanges: - self.buffers = set(self.selection.multi_ranges) - else: - assert len(self.buffers) == 1 - - @classmethod - def empty(cls) -> "Selection": - return cls(selection=Ranges(ranges=[]), buffers=set()) - - def promote(self, to_rank: int) -> "Selection": - if to_rank < 0 or to_rank > 3: - raise ValueError(f"Invalid rank: {to_rank}") - if self.rank > to_rank: - raise ValueError(f"Cannot coerce selection of rank {self.rank} to rank {to_rank}") - if self.rank == to_rank: - return self - match self.selection: - case Position(_): - as_range = Range( - start=Position(self.selection.pos), - end=Position(self.selection.pos + 1), - ) - as_ranges = Ranges(ranges=[as_range]) - if to_rank == 1: - return Selection(selection=as_range, buffers=self.buffers) - if to_rank == 2: - return Selection(selection=as_ranges, buffers=self.buffers) - if to_rank == 3: - return Selection(MultiRanges({buffer: as_ranges for buffer in self.buffers})) - case Range(_, _): - as_ranges = Ranges(ranges=[self.selection]) - if to_rank == 2: - return Selection(selection=as_ranges, buffers=self.buffers) - if to_rank == 3: - return Selection(MultiRanges({buffer: as_ranges for buffer in self.buffers})) - case Ranges(_): - return Selection(MultiRanges({buffer: self.selection for buffer in self.buffers})) - - raise RuntimeError("Unexpected promotion issue") - - @classmethod - def union(cls, *selections: "Selection") -> "Selection": - if not selections: - return cls.empty() - - all_buffers = set.union(*[s.buffers for s in selections]) - - if len(all_buffers) == 0: - return cls.empty() - - if len(all_buffers) > 1: - max_rank = 3 - else: - max_rank = max(s.rank for s in selections) - if max_rank < 2: - max_rank = 2 - - promoted = [s.promote(max_rank) for s in selections] - - if max_rank == 2: - all_ranges = [] - for sel in promoted: - if type(sel.selection) is not Ranges: - raise ValueError( - f"Selection of rank {sel.rank} is not a range. Should have been promoted to rank 2." - ) - all_ranges.extend(sel.selection.ranges) - return cls(selection=Ranges(all_ranges), buffers=all_buffers) - - if max_rank == 3: - buffer_ranges: dict[Buffer, list[Range]] = {buf: [] for buf in all_buffers} - for sel in promoted: - if type(sel.selection) is not MultiRanges: - raise ValueError( - f"Selection of rank {sel.rank} is not a multi-range. Should have been promoted to rank 3." - ) - for buffer, ranges in sel.selection.multi_ranges.items(): - buffer_ranges[buffer].extend(ranges.ranges) - - multi = MultiRanges( - {buffer: Ranges(ranges) for buffer, ranges in buffer_ranges.items()} - ) - return cls(selection=multi) - - raise RuntimeError("Unexpected union issue") - - @property - def rank(self) -> int: - match self.selection: - case Position(_): - return 0 - case Range(_, _): - return 1 - case Ranges(_): - return 2 - case MultiRanges(_): - return 3 - - def broadcast( - self, - rank_zero: Callable[[Position, Buffer], "Selection"], - rank_one: Callable[[Range, Buffer], "Selection"], - ) -> "Selection": - match self.selection: - case Position(_): - return rank_zero(self.selection, list(self.buffers)[0]) - - case Range(_, _) as r: - return rank_one(r, list(self.buffers)[0]) - - case Ranges(ranges): - buffer = list(self.buffers)[0] - return Selection.union(*[rank_one(r, buffer) for r in ranges]) - - case MultiRanges(multi): - all_results = [] - for buffer, ranges in multi.items(): - for r in ranges.ranges: - all_results.append(rank_one(r, buffer)) - return Selection.union(*all_results) diff --git a/python/src/types/state.py b/python/src/types/state.py deleted file mode 100644 index ca048aa..0000000 --- a/python/src/types/state.py +++ /dev/null @@ -1,93 +0,0 @@ -from dataclasses import dataclass -from pathlib import Path - -from .buffer import Buffer -from .selection import Selection - - -class StateChange: - def invert(self) -> "StateChange" | None: - return None - - -@dataclass -class SetCurrentSelection(StateChange): - old_selection: Selection - new_selection: Selection - - def invert(self) -> "SetCurrentSelection": - return SetCurrentSelection( - old_selection=self.new_selection, - new_selection=self.old_selection, - ) - - -@dataclass -class SetCurrentBuffer(StateChange): - old_buffer: Buffer - new_buffer: Buffer - - def invert(self) -> "SetCurrentBuffer": - return SetCurrentBuffer( - old_buffer=self.new_buffer, - new_buffer=self.old_buffer, - ) - - -@dataclass -class ModifyBuffer(StateChange): - buffer: Buffer - old_start: int - old_end: int - old_content: str - new_content: str - - def invert(self) -> None: - # TODO: implement - return None - - -@dataclass -class CreateBuffer(StateChange): - buffer: Buffer - file: Path | None - - -@dataclass -class DeleteBuffer(StateChange): - buffer: Buffer - - -@dataclass -class EditorState: - current_buffer: Buffer - current_selection: Selection - buffer_to_file: dict[Buffer, Path | None] - history: list[StateChange] - - def commit(self, change: StateChange) -> "EditorState": - match change: - case SetCurrentSelection(_, new_selection): - self.current_selection = new_selection - case SetCurrentBuffer(_, new_buffer): - self.current_buffer = new_buffer - case ModifyBuffer(buffer, old_start, old_end, _, new_content): - self.current_buffer.content = ( - self.current_buffer.content[:old_start] - + new_content - + self.current_buffer.content[old_end:] - ) - case CreateBuffer(buffer, file): - self.buffer_to_file[buffer] = file - case DeleteBuffer(buffer): - del self.buffer_to_file[buffer] - self.history.append(change) - return self - - def commit_changes(self, changes: list[StateChange]) -> "EditorState": - for change in changes: - self.commit(change) - return self - - -Result = tuple[Selection, list[StateChange]] |
