Fix highlight color in replace/selection

This commit is contained in:
Anthony Sottile
2020-03-21 21:08:43 -07:00
parent f1772ec829
commit bf1c3d1ee1
8 changed files with 41 additions and 47 deletions

View File

@@ -19,19 +19,16 @@ class ColorManager(NamedTuple):
raw_pairs: Dict[Tuple[int, int], int] raw_pairs: Dict[Tuple[int, int], int]
def init_color(self, color: Color) -> None: def init_color(self, color: Color) -> None:
if curses.COLORS < 256: if curses.can_change_color():
return
elif curses.can_change_color():
n = min(self.colors.values(), default=256) - 1 n = min(self.colors.values(), default=256) - 1
self.colors[color] = n self.colors[color] = n
curses.init_color(n, *_color_to_curses(color)) curses.init_color(n, *_color_to_curses(color))
else: elif curses.COLORS >= 256:
self.colors[color] = color_kd.nearest(color, color_kd.make_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: 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 fg_i = self.colors[fg] if fg is not None else -1
bg_i = self.colors[bg] if bg 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) return self.raw_color_pair(fg_i, bg_i)

View File

@@ -21,10 +21,12 @@ from typing import TYPE_CHECKING
from typing import TypeVar from typing import TypeVar
from typing import Union from typing import Union
from babi.color_manager import ColorManager
from babi.hl.interface import FileHL from babi.hl.interface import FileHL
from babi.hl.interface import HLFactory from babi.hl.interface import HLFactory
from babi.hl.replace import Replace from babi.hl.replace import Replace
from babi.hl.selection import Selection 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 line_x
from babi.horizontal_scrolling import scrolled_line from babi.horizontal_scrolling import scrolled_line
from babi.list_spy import ListSpy from babi.list_spy import ListSpy
@@ -211,6 +213,7 @@ class File:
def __init__( def __init__(
self, self,
filename: Optional[str], filename: Optional[str],
color_manager: ColorManager,
hl_factories: Tuple[HLFactory, ...], hl_factories: Tuple[HLFactory, ...],
) -> None: ) -> None:
self.filename = filename self.filename = filename
@@ -222,6 +225,7 @@ class File:
self.undo_stack: List[Action] = [] self.undo_stack: List[Action] = []
self.redo_stack: List[Action] = [] self.redo_stack: List[Action] = []
self._hl_factories = hl_factories self._hl_factories = hl_factories
self._trailing_whitespace = TrailingWhitespace(color_manager)
self._replace_hl = Replace() self._replace_hl = Replace()
self.selection = Selection() self.selection = Selection()
self._file_hls: Tuple[FileHL, ...] = () self._file_hls: Tuple[FileHL, ...] = ()
@@ -260,7 +264,10 @@ class File:
file_hls.append(hl) file_hls.append(hl)
else: else:
file_hls.append(factory.blank_file_highlighter()) 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: def __repr__(self) -> str:
return f'<{type(self).__name__} {self.filename!r}>' return f'<{type(self).__name__} {self.filename!r}>'

View File

@@ -8,8 +8,6 @@ from babi.hl.interface import HL
from babi.hl.interface import HLs from babi.hl.interface import HLs
from babi.list_spy import SequenceNoSlice from babi.list_spy import SequenceNoSlice
HIGHLIGHT = curses.A_REVERSE | curses.A_DIM
class Replace: class Replace:
include_edge = True include_edge = True
@@ -25,7 +23,9 @@ class Replace:
@contextlib.contextmanager @contextlib.contextmanager
def region(self, y: int, x: int, end: int) -> Generator[None, None, None]: 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: try:
yield yield
finally: finally:

View File

@@ -8,8 +8,6 @@ from babi.hl.interface import HL
from babi.hl.interface import HLs from babi.hl.interface import HLs
from babi.list_spy import SequenceNoSlice from babi.list_spy import SequenceNoSlice
ATTR = curses.A_REVERSE | curses.A_DIM
class Selection: class Selection:
include_edge = True include_edge = True
@@ -23,18 +21,20 @@ class Selection:
if self.start is None or self.end is None: if self.start is None or self.end is None:
return 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() (s_y, s_x), (e_y, e_x) = self.get()
if s_y == e_y: 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: else:
self.regions[s_y] = ( 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): for l_y in range(s_y + 1, e_y):
self.regions[l_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: def touch(self, lineno: int) -> None:
"""our highlight regions are populated in other ways""" """our highlight regions are populated in other ways"""

View File

@@ -1,6 +1,5 @@
import curses import curses
from typing import List from typing import List
from typing import NamedTuple
from babi.color_manager import ColorManager from babi.color_manager import ColorManager
from babi.hl.interface import HL from babi.hl.interface import HL
@@ -8,7 +7,7 @@ from babi.hl.interface import HLs
from babi.list_spy import SequenceNoSlice from babi.list_spy import SequenceNoSlice
class FileTrailingWhitespace: class TrailingWhitespace:
include_edge = False include_edge = False
def __init__(self, color_manager: ColorManager) -> None: def __init__(self, color_manager: ColorManager) -> None:
@@ -37,18 +36,3 @@ class FileTrailingWhitespace:
def touch(self, lineno: int) -> None: def touch(self, lineno: int) -> None:
del self.regions[lineno:] 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)

View File

@@ -20,7 +20,6 @@ from babi.file import File
from babi.file import get_lines from babi.file import get_lines
from babi.history import History from babi.history import History
from babi.hl.syntax import Syntax from babi.hl.syntax import Syntax
from babi.hl.trailing_whitespace import TrailingWhitespace
from babi.margin import Margin from babi.margin import Margin
from babi.perf import Perf from babi.perf import Perf
from babi.prompt import Prompt from babi.prompt import Prompt
@@ -77,12 +76,12 @@ class Screen:
perf: Perf, perf: Perf,
) -> None: ) -> None:
self.stdscr = stdscr self.stdscr = stdscr
color_manager = ColorManager.make() self.color_manager = ColorManager.make()
self.hl_factories = ( self.hl_factories = (Syntax.from_screen(stdscr, self.color_manager),)
Syntax.from_screen(stdscr, color_manager), self.files = [
TrailingWhitespace(color_manager), File(filename, self.color_manager, self.hl_factories)
) for filename in filenames
self.files = [File(f, self.hl_factories) for f in filenames] ]
self.i = 0 self.i = 0
self.history = History() self.history = History()
self.perf = perf self.perf = perf
@@ -459,7 +458,8 @@ class Screen:
def open_file(self) -> Optional[EditResult]: def open_file(self) -> Optional[EditResult]:
response = self.prompt('enter filename', history='open') response = self.prompt('enter filename', history='open')
if response is not PromptResult.CANCELLED: 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 return EditResult.OPEN
else: else:
return None return None

View File

@@ -2,12 +2,13 @@ import io
import pytest import pytest
from babi.color_manager import ColorManager
from babi.file import File from babi.file import File
from babi.file import get_lines from babi.file import get_lines
def test_position_repr(): def test_position_repr():
ret = repr(File('f.txt', ())) ret = repr(File('f.txt', ColorManager.make(), ()))
assert ret == "<File 'f.txt'>" assert ret == "<File 'f.txt'>"

View File

@@ -78,11 +78,16 @@ def syntax(tmpdir):
def test_init_screen_low_color(stdscr, syntax): def test_init_screen_low_color(stdscr, syntax):
with FakeCurses.patch(n_colors=16, can_change_color=False) as fake_curses: with FakeCurses.patch(n_colors=16, can_change_color=False) as fake_curses:
syntax._init_screen(stdscr) syntax._init_screen(stdscr)
assert syntax.color_manager.colors == {} assert syntax.color_manager.colors == {
assert syntax.color_manager.raw_pairs == {} 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.colors == {}
assert fake_curses.pairs == {} assert fake_curses.pairs == {1: (-1, -1)}
assert stdscr.attr == 0 assert stdscr.attr == 1 << 8
def test_init_screen_256_color(stdscr, syntax): def test_init_screen_256_color(stdscr, syntax):