From bf1c3d1ee1add549d22f75504e64b56fa8d7e77f Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 21 Mar 2020 21:08:43 -0700 Subject: [PATCH] Fix highlight color in replace/selection --- babi/color_manager.py | 11 ++++------- babi/file.py | 9 ++++++++- babi/hl/replace.py | 6 +++--- babi/hl/selection.py | 12 ++++++------ babi/hl/trailing_whitespace.py | 18 +----------------- babi/screen.py | 16 ++++++++-------- tests/file_test.py | 3 ++- tests/hl/syntax_test.py | 13 +++++++++---- 8 files changed, 41 insertions(+), 47 deletions(-) diff --git a/babi/color_manager.py b/babi/color_manager.py index ee252c4..c3ea784 100644 --- a/babi/color_manager.py +++ b/babi/color_manager.py @@ -19,19 +19,16 @@ class ColorManager(NamedTuple): raw_pairs: Dict[Tuple[int, int], int] def init_color(self, color: Color) -> None: - if curses.COLORS < 256: - return - elif curses.can_change_color(): + if curses.can_change_color(): n = min(self.colors.values(), default=256) - 1 self.colors[color] = n curses.init_color(n, *_color_to_curses(color)) - else: + elif curses.COLORS >= 256: self.colors[color] = color_kd.nearest(color, color_kd.make_256()) + else: + self.colors[color] = -1 def color_pair(self, fg: Optional[Color], bg: Optional[Color]) -> int: - if curses.COLORS < 256: - return 0 - fg_i = self.colors[fg] if fg is not None else -1 bg_i = self.colors[bg] if bg is not None else -1 return self.raw_color_pair(fg_i, bg_i) diff --git a/babi/file.py b/babi/file.py index c3b7a8f..94be846 100644 --- a/babi/file.py +++ b/babi/file.py @@ -21,10 +21,12 @@ from typing import TYPE_CHECKING from typing import TypeVar from typing import Union +from babi.color_manager import ColorManager from babi.hl.interface import FileHL from babi.hl.interface import HLFactory from babi.hl.replace import Replace from babi.hl.selection import Selection +from babi.hl.trailing_whitespace import TrailingWhitespace from babi.horizontal_scrolling import line_x from babi.horizontal_scrolling import scrolled_line from babi.list_spy import ListSpy @@ -211,6 +213,7 @@ class File: def __init__( self, filename: Optional[str], + color_manager: ColorManager, hl_factories: Tuple[HLFactory, ...], ) -> None: self.filename = filename @@ -222,6 +225,7 @@ class File: self.undo_stack: List[Action] = [] self.redo_stack: List[Action] = [] self._hl_factories = hl_factories + self._trailing_whitespace = TrailingWhitespace(color_manager) self._replace_hl = Replace() self.selection = Selection() self._file_hls: Tuple[FileHL, ...] = () @@ -260,7 +264,10 @@ class File: file_hls.append(hl) else: file_hls.append(factory.blank_file_highlighter()) - self._file_hls = (*file_hls, self._replace_hl, self.selection) + self._file_hls = ( + *file_hls, + self._trailing_whitespace, self._replace_hl, self.selection, + ) def __repr__(self) -> str: return f'<{type(self).__name__} {self.filename!r}>' diff --git a/babi/hl/replace.py b/babi/hl/replace.py index 8a3177f..27defa2 100644 --- a/babi/hl/replace.py +++ b/babi/hl/replace.py @@ -8,8 +8,6 @@ from babi.hl.interface import HL from babi.hl.interface import HLs from babi.list_spy import SequenceNoSlice -HIGHLIGHT = curses.A_REVERSE | curses.A_DIM - class Replace: include_edge = True @@ -25,7 +23,9 @@ class Replace: @contextlib.contextmanager def region(self, y: int, x: int, end: int) -> Generator[None, None, None]: - self.regions[y] = (HL(x=x, end=end, attr=HIGHLIGHT),) + # XXX: this assumes pair 1 is the background + attr = curses.A_REVERSE | curses.A_DIM | curses.color_pair(1) + self.regions[y] = (HL(x=x, end=end, attr=attr),) try: yield finally: diff --git a/babi/hl/selection.py b/babi/hl/selection.py index 6b69219..d69664f 100644 --- a/babi/hl/selection.py +++ b/babi/hl/selection.py @@ -8,8 +8,6 @@ from babi.hl.interface import HL from babi.hl.interface import HLs from babi.list_spy import SequenceNoSlice -ATTR = curses.A_REVERSE | curses.A_DIM - class Selection: include_edge = True @@ -23,18 +21,20 @@ class Selection: if self.start is None or self.end is None: return + # XXX: this assumes pair 1 is the background + attr = curses.A_REVERSE | curses.A_DIM | curses.color_pair(1) (s_y, s_x), (e_y, e_x) = self.get() if s_y == e_y: - self.regions[s_y] = (HL(x=s_x, end=e_x, attr=ATTR),) + self.regions[s_y] = (HL(x=s_x, end=e_x, attr=attr),) else: self.regions[s_y] = ( - HL(x=s_x, end=len(lines[s_y]) + 1, attr=ATTR), + HL(x=s_x, end=len(lines[s_y]) + 1, attr=attr), ) for l_y in range(s_y + 1, e_y): self.regions[l_y] = ( - HL(x=0, end=len(lines[l_y]) + 1, attr=ATTR), + HL(x=0, end=len(lines[l_y]) + 1, attr=attr), ) - self.regions[e_y] = (HL(x=0, end=e_x, attr=ATTR),) + self.regions[e_y] = (HL(x=0, end=e_x, attr=attr),) def touch(self, lineno: int) -> None: """our highlight regions are populated in other ways""" diff --git a/babi/hl/trailing_whitespace.py b/babi/hl/trailing_whitespace.py index 9c7ed2a..3cd63b4 100644 --- a/babi/hl/trailing_whitespace.py +++ b/babi/hl/trailing_whitespace.py @@ -1,6 +1,5 @@ import curses from typing import List -from typing import NamedTuple from babi.color_manager import ColorManager from babi.hl.interface import HL @@ -8,7 +7,7 @@ from babi.hl.interface import HLs from babi.list_spy import SequenceNoSlice -class FileTrailingWhitespace: +class TrailingWhitespace: include_edge = False def __init__(self, color_manager: ColorManager) -> None: @@ -37,18 +36,3 @@ class FileTrailingWhitespace: def touch(self, lineno: int) -> None: del self.regions[lineno:] - - -class TrailingWhitespace(NamedTuple): - color_manager: ColorManager - - def file_highlighter( - self, - filename: str, - first_line: str, - ) -> FileTrailingWhitespace: - # no file-specific behaviour - return self.blank_file_highlighter() - - def blank_file_highlighter(self) -> FileTrailingWhitespace: - return FileTrailingWhitespace(self.color_manager) diff --git a/babi/screen.py b/babi/screen.py index 1eb9701..b3a86ae 100644 --- a/babi/screen.py +++ b/babi/screen.py @@ -20,7 +20,6 @@ from babi.file import File from babi.file import get_lines from babi.history import History from babi.hl.syntax import Syntax -from babi.hl.trailing_whitespace import TrailingWhitespace from babi.margin import Margin from babi.perf import Perf from babi.prompt import Prompt @@ -77,12 +76,12 @@ class Screen: perf: Perf, ) -> None: self.stdscr = stdscr - color_manager = ColorManager.make() - self.hl_factories = ( - Syntax.from_screen(stdscr, color_manager), - TrailingWhitespace(color_manager), - ) - self.files = [File(f, self.hl_factories) for f in filenames] + self.color_manager = ColorManager.make() + self.hl_factories = (Syntax.from_screen(stdscr, self.color_manager),) + self.files = [ + File(filename, self.color_manager, self.hl_factories) + for filename in filenames + ] self.i = 0 self.history = History() self.perf = perf @@ -459,7 +458,8 @@ class Screen: def open_file(self) -> Optional[EditResult]: response = self.prompt('enter filename', history='open') if response is not PromptResult.CANCELLED: - self.files.append(File(response, self.hl_factories)) + opened = File(response, self.color_manager, self.hl_factories) + self.files.append(opened) return EditResult.OPEN else: return None diff --git a/tests/file_test.py b/tests/file_test.py index 72dbbcb..df1cb8f 100644 --- a/tests/file_test.py +++ b/tests/file_test.py @@ -2,12 +2,13 @@ import io import pytest +from babi.color_manager import ColorManager from babi.file import File from babi.file import get_lines def test_position_repr(): - ret = repr(File('f.txt', ())) + ret = repr(File('f.txt', ColorManager.make(), ())) assert ret == "" diff --git a/tests/hl/syntax_test.py b/tests/hl/syntax_test.py index f483596..2db3604 100644 --- a/tests/hl/syntax_test.py +++ b/tests/hl/syntax_test.py @@ -78,11 +78,16 @@ def syntax(tmpdir): def test_init_screen_low_color(stdscr, syntax): with FakeCurses.patch(n_colors=16, can_change_color=False) as fake_curses: syntax._init_screen(stdscr) - assert syntax.color_manager.colors == {} - assert syntax.color_manager.raw_pairs == {} + assert syntax.color_manager.colors == { + Color.parse('#cccccc'): -1, + Color.parse('#333333'): -1, + Color.parse('#000000'): -1, + Color.parse('#009900'): -1, + } + assert syntax.color_manager.raw_pairs == {(-1, -1): 1} assert fake_curses.colors == {} - assert fake_curses.pairs == {} - assert stdscr.attr == 0 + assert fake_curses.pairs == {1: (-1, -1)} + assert stdscr.attr == 1 << 8 def test_init_screen_256_color(stdscr, syntax):