Fix highlight color in replace/selection
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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}>'
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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"""
|
||||||
|
|||||||
@@ -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)
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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'>"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
Reference in New Issue
Block a user