in all in one view mode show file status (modified/staged/added/deleted/undecided/?)
This commit is contained in:
@@ -66,7 +66,7 @@ Use one method or the other, not both: an unpacked `Packages/vDiff` directory ov
|
|||||||
| `?` | show this key list in a popup |
|
| `?` | show this key list in a popup |
|
||||||
| Esc | close the view |
|
| Esc | close the view |
|
||||||
|
|
||||||
The header links do the same with the mouse. The all-files view shows five context lines around each change by default; configure this with `all_files_context` in `vDiff.sublime-settings`. The same file sets the background of deleted and inserted lines (`deleted_line_background`, `inserted_line_background`) and the colours of the all-files line-number column (`line_numbers_foreground`, `line_numbers_background`); left empty, they follow the colour scheme. The all-files file heading takes its colours from `file_header_background`, `file_header_deleted_foreground` and `file_header_inserted_foreground`.
|
The header links do the same with the mouse. The all-files view shows five context lines around each change by default; configure this with `all_files_context` in `vDiff.sublime-settings`. The same file sets the background of deleted and inserted lines (`deleted_line_background`, `inserted_line_background`) and the colours of the all-files line-number column (`line_numbers_foreground`, `line_numbers_background`); left empty, they follow the colour scheme. Each all-files file heading shows the file's status letter (`s` when anything is staged, else `m`, `d`, `a`, `?` ...) before its -/+ counts, and takes its colours from `file_header_background`, `file_header_status_foreground`, `file_header_deleted_foreground` and `file_header_inserted_foreground`.
|
||||||
|
|
||||||
## The channel
|
## The channel
|
||||||
|
|
||||||
|
|||||||
@@ -722,6 +722,24 @@ def all_files_view():
|
|||||||
return view, st
|
return view, st
|
||||||
|
|
||||||
|
|
||||||
|
def test_all_files_headings_show_the_status_letter_before_the_counts():
|
||||||
|
from vdiff import parse
|
||||||
|
view = sublime.View()
|
||||||
|
st = state.ViewState("/repo")
|
||||||
|
st.all_mode = True
|
||||||
|
st.files = [git.FileChange("a - b.py", "M", True, 1, 0, None), change("m.py"), change("gone.py", "D")]
|
||||||
|
lines = [parse.Line("+", None, 1, "x")]
|
||||||
|
st.all_diffs = {c.path: (lines, parse.change_blocks(lines), False) for c in st.files}
|
||||||
|
commands.render.render_all(view, st)
|
||||||
|
|
||||||
|
headings = [row for row in view.text.split("\n") if row.startswith("▼")]
|
||||||
|
# staged wins over the git letter; a path containing " -" must not confuse the letter's position
|
||||||
|
assert headings == ["▼ a - b.py s -0 +1", "▼ m.py m -0 +1", "▼ gone.py d -0 +1"]
|
||||||
|
regions, scope, _, _ = view.regions[commands.render.KEY_FILE_STATUS]
|
||||||
|
assert scope == commands.render.palette.SCOPE_FILE_STATUS
|
||||||
|
assert [view.text[r.a:r.b] for r in regions] == ["s", "m", "d"]
|
||||||
|
|
||||||
|
|
||||||
def heading_row(st, path):
|
def heading_row(st, path):
|
||||||
return next(i for i, (c, _, section) in enumerate(st.all_rows) if section and c.path == path)
|
return next(i for i, (c, _, section) in enumerate(st.all_rows) if section and c.path == path)
|
||||||
|
|
||||||
|
|||||||
@@ -147,3 +147,13 @@ def test_file_header_colours_come_from_settings(tmp_path, monkeypatch):
|
|||||||
assert rules[palette.SCOPE_FILE_INS_COUNT]["background"] == "#202040"
|
assert rules[palette.SCOPE_FILE_INS_COUNT]["background"] == "#202040"
|
||||||
assert rules[palette.SCOPE_FILE_INS_COUNT]["foreground"] == "#00ff00"
|
assert rules[palette.SCOPE_FILE_INS_COUNT]["foreground"] == "#00ff00"
|
||||||
assert rules[palette.SCOPE_FILE_DEL_COUNT]["foreground"] == palette.FILE_DEL_FOREGROUND
|
assert rules[palette.SCOPE_FILE_DEL_COUNT]["foreground"] == palette.FILE_DEL_FOREGROUND
|
||||||
|
|
||||||
|
|
||||||
|
def test_the_status_letter_is_white_on_the_heading_unless_set(tmp_path, monkeypatch):
|
||||||
|
palette.ensure(sublime.View())
|
||||||
|
rule = by_scope(tmp_path)[palette.SCOPE_FILE_STATUS]
|
||||||
|
assert rule["foreground"] == palette.FILE_STATUS_FOREGROUND == "#ffffff"
|
||||||
|
assert rule["background"] == by_scope(tmp_path)[palette.SCOPE_FILE_HEADER]["background"]
|
||||||
|
colour_option(monkeypatch, "file_header_status_foreground", "#ffff00")
|
||||||
|
palette.ensure(sublime.View())
|
||||||
|
assert by_scope(tmp_path)[palette.SCOPE_FILE_STATUS]["foreground"] == "#ffff00"
|
||||||
|
|||||||
@@ -25,8 +25,9 @@
|
|||||||
"line_numbers_foreground": "",
|
"line_numbers_foreground": "",
|
||||||
"line_numbers_background": "",
|
"line_numbers_background": "",
|
||||||
|
|
||||||
// file heading of the all-files view: its background and the colours of its -/+ counts
|
// file heading of the all-files view: its background and the colours of its status letter and -/+ counts
|
||||||
"file_header_background": "#0000EE",
|
"file_header_background": "#0000EE",
|
||||||
|
"file_header_status_foreground": "#ffffff",
|
||||||
"file_header_deleted_foreground": "#d64646",
|
"file_header_deleted_foreground": "#d64646",
|
||||||
"file_header_inserted_foreground": "#46d646",
|
"file_header_inserted_foreground": "#46d646",
|
||||||
|
|
||||||
|
|||||||
@@ -32,11 +32,13 @@ KINDS: Tuple[str, ...] = TINT_KINDS + ("ctx",)
|
|||||||
KIND_TINT: Dict[str, str] = {"del": SCOPE_DEL, "ins": SCOPE_INS, "del.char": SCOPE_DEL_CHAR, "ins.char": SCOPE_INS_CHAR,
|
KIND_TINT: Dict[str, str] = {"del": SCOPE_DEL, "ins": SCOPE_INS, "del.char": SCOPE_DEL_CHAR, "ins.char": SCOPE_INS_CHAR,
|
||||||
"ctx": SCOPE_CTX}
|
"ctx": SCOPE_CTX}
|
||||||
|
|
||||||
# all-files file heading and its -/+ counts; their colours come from settings, these when one is empty
|
# all-files file heading, its status letter and its -/+ counts; their colours come from settings, these when one is empty
|
||||||
SCOPE_FILE_HEADER = "vdiff.file.header"
|
SCOPE_FILE_HEADER = "vdiff.file.header"
|
||||||
SCOPE_FILE_DEL_COUNT = "vdiff.file.del.count"
|
SCOPE_FILE_DEL_COUNT = "vdiff.file.del.count"
|
||||||
SCOPE_FILE_INS_COUNT = "vdiff.file.ins.count"
|
SCOPE_FILE_INS_COUNT = "vdiff.file.ins.count"
|
||||||
|
SCOPE_FILE_STATUS = "vdiff.file.status"
|
||||||
FILE_HEADER_BACKGROUND = "#0000FF"
|
FILE_HEADER_BACKGROUND = "#0000FF"
|
||||||
|
FILE_STATUS_FOREGROUND = "#ffffff"
|
||||||
# sublime's former markup.deleted / markup.inserted colours
|
# sublime's former markup.deleted / markup.inserted colours
|
||||||
FILE_DEL_FOREGROUND = "#d64646"
|
FILE_DEL_FOREGROUND = "#d64646"
|
||||||
FILE_INS_FOREGROUND = "#46d646"
|
FILE_INS_FOREGROUND = "#46d646"
|
||||||
@@ -45,7 +47,7 @@ FILE_INS_FOREGROUND = "#46d646"
|
|||||||
COLOUR_SETTINGS: Tuple[str, ...] = ("deleted_line_background", "inserted_line_background",
|
COLOUR_SETTINGS: Tuple[str, ...] = ("deleted_line_background", "inserted_line_background",
|
||||||
"line_numbers_foreground", "line_numbers_background",
|
"line_numbers_foreground", "line_numbers_background",
|
||||||
"file_header_background", "file_header_deleted_foreground",
|
"file_header_background", "file_header_deleted_foreground",
|
||||||
"file_header_inserted_foreground")
|
"file_header_inserted_foreground", "file_header_status_foreground")
|
||||||
# the scopes those colours go into: the changed-line tints and the all-files line-number column
|
# the scopes those colours go into: the changed-line tints and the all-files line-number column
|
||||||
SCOPE_LINE_DEL = "vdiff.line.del"
|
SCOPE_LINE_DEL = "vdiff.line.del"
|
||||||
SCOPE_LINE_INS = "vdiff.line.ins"
|
SCOPE_LINE_INS = "vdiff.line.ins"
|
||||||
@@ -311,7 +313,8 @@ def _merge_rules(rules: List[Dict[str, str]], tints: Dict[str, str], colours: Di
|
|||||||
# the all-files file heading and its deletion and insertion counts
|
# the all-files file heading and its deletion and insertion counts
|
||||||
header = user["file_header_background"] or FILE_HEADER_BACKGROUND
|
header = user["file_header_background"] or FILE_HEADER_BACKGROUND
|
||||||
wanted = [{"scope": SCOPE_FILE_HEADER, "background": header}]
|
wanted = [{"scope": SCOPE_FILE_HEADER, "background": header}]
|
||||||
for scope, colour in ((SCOPE_FILE_DEL_COUNT, user["file_header_deleted_foreground"] or FILE_DEL_FOREGROUND),
|
for scope, colour in ((SCOPE_FILE_STATUS, user["file_header_status_foreground"] or FILE_STATUS_FOREGROUND),
|
||||||
|
(SCOPE_FILE_DEL_COUNT, user["file_header_deleted_foreground"] or FILE_DEL_FOREGROUND),
|
||||||
(SCOPE_FILE_INS_COUNT, user["file_header_inserted_foreground"] or FILE_INS_FOREGROUND)):
|
(SCOPE_FILE_INS_COUNT, user["file_header_inserted_foreground"] or FILE_INS_FOREGROUND)):
|
||||||
wanted.append({"scope": scope, "background": header, "foreground": colour, "font_style": "bold"})
|
wanted.append({"scope": scope, "background": header, "foreground": colour, "font_style": "bold"})
|
||||||
# the user's line colours; an unset one keeps any old rule, which render then ignores
|
# the user's line colours; an unset one keeps any old rule, which render then ignores
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ KEY_INS_CHAR = "vdiff.ins.char"
|
|||||||
KEY_FILE_HEADER = "vdiff.file.header"
|
KEY_FILE_HEADER = "vdiff.file.header"
|
||||||
KEY_FILE_DEL_COUNT = palette.SCOPE_FILE_DEL_COUNT
|
KEY_FILE_DEL_COUNT = palette.SCOPE_FILE_DEL_COUNT
|
||||||
KEY_FILE_INS_COUNT = palette.SCOPE_FILE_INS_COUNT
|
KEY_FILE_INS_COUNT = palette.SCOPE_FILE_INS_COUNT
|
||||||
|
KEY_FILE_STATUS = palette.SCOPE_FILE_STATUS
|
||||||
KEY_FILE_PREFIX = "vdiff.file.prefix"
|
KEY_FILE_PREFIX = "vdiff.file.prefix"
|
||||||
REGION_KEYS = (
|
REGION_KEYS = (
|
||||||
KEY_DEL,
|
KEY_DEL,
|
||||||
@@ -36,6 +37,7 @@ REGION_KEYS = (
|
|||||||
KEY_FILE_HEADER,
|
KEY_FILE_HEADER,
|
||||||
KEY_FILE_DEL_COUNT,
|
KEY_FILE_DEL_COUNT,
|
||||||
KEY_FILE_INS_COUNT,
|
KEY_FILE_INS_COUNT,
|
||||||
|
KEY_FILE_STATUS,
|
||||||
KEY_FILE_PREFIX,
|
KEY_FILE_PREFIX,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -318,12 +320,13 @@ def render_all(view: sublime.View, st: ViewState, focus: Union[None, str, Tuple[
|
|||||||
st.all_change_targets.append((change.path, hunk_index))
|
st.all_change_targets.append((change.path, hunk_index))
|
||||||
hunk_index += 1
|
hunk_index += 1
|
||||||
in_change = changed
|
in_change = changed
|
||||||
# the heading: fold marker, path and the file's -/+ counts
|
# the heading: fold marker, path, lowercase status letter (s when anything is staged) and the file's -/+ counts
|
||||||
ins, dele = parse.counts(lines)
|
ins, dele = parse.counts(lines)
|
||||||
marker = "▶" if change.path in st.collapsed else "▼"
|
marker = "▶" if change.path in st.collapsed else "▼"
|
||||||
if change.path == focus:
|
if change.path == focus:
|
||||||
heading = len(rows)
|
heading = len(rows)
|
||||||
rows.append(f"{marker} {change.path} -{dele} +{ins}")
|
letter = "s" if change.staged else change.status.lower()
|
||||||
|
rows.append(f"{marker} {change.path} {letter} -{dele} +{ins}")
|
||||||
metadata.append((change, None, True))
|
metadata.append((change, None, True))
|
||||||
# the diff rows, recording the row where each visible change starts
|
# the diff rows, recording the row where each visible change starts
|
||||||
if change.path not in st.collapsed:
|
if change.path not in st.collapsed:
|
||||||
@@ -351,7 +354,7 @@ def render_all(view: sublime.View, st: ViewState, focus: Union[None, str, Tuple[
|
|||||||
# per-row regions: heading counts, number prefix, tint, token colours
|
# per-row regions: heading counts, number prefix, tint, token colours
|
||||||
starts = _row_starts_for_text(rows)
|
starts = _row_starts_for_text(rows)
|
||||||
del_regions, ins_regions, file_regions, prefix_regions = [], [], [], []
|
del_regions, ins_regions, file_regions, prefix_regions = [], [], [], []
|
||||||
file_del_counts, file_ins_counts = [], []
|
file_del_counts, file_ins_counts, file_statuses = [], [], []
|
||||||
token_groups: Dict[str, List[sublime.Region]] = {}
|
token_groups: Dict[str, List[sublime.Region]] = {}
|
||||||
default_colour = palette.foreground(view, "text.plain")
|
default_colour = palette.foreground(view, "text.plain")
|
||||||
resolved = palette.tokens_resolved(view)
|
resolved = palette.tokens_resolved(view)
|
||||||
@@ -360,9 +363,12 @@ def render_all(view: sublime.View, st: ViewState, focus: Union[None, str, Tuple[
|
|||||||
for i, (change, line, section) in enumerate(metadata):
|
for i, (change, line, section) in enumerate(metadata):
|
||||||
if section:
|
if section:
|
||||||
file_regions.append(sublime.Region(starts[i], starts[i] + len(rows[i])))
|
file_regions.append(sublime.Region(starts[i], starts[i] + len(rows[i])))
|
||||||
# colour just the counts over the heading tint; rfind, as a path may contain " -"
|
# colour just the status letter and counts over the heading tint; rfind, as a path may contain " -"
|
||||||
minus = rows[i].rfind(" -") + 1
|
minus = rows[i].rfind(" -") + 1
|
||||||
plus = rows[i].rfind(" +") + 1
|
plus = rows[i].rfind(" +") + 1
|
||||||
|
if minus >= 2:
|
||||||
|
# the letter sits just before the space before the deletion count
|
||||||
|
file_statuses.append(sublime.Region(starts[i] + minus - 2, starts[i] + minus - 1))
|
||||||
if minus and plus > minus:
|
if minus and plus > minus:
|
||||||
file_del_counts.append(sublime.Region(starts[i] + minus, starts[i] + plus - 1))
|
file_del_counts.append(sublime.Region(starts[i] + minus, starts[i] + plus - 1))
|
||||||
if plus:
|
if plus:
|
||||||
@@ -393,6 +399,7 @@ def render_all(view: sublime.View, st: ViewState, focus: Union[None, str, Tuple[
|
|||||||
view.add_regions(KEY_FILE_HEADER, file_regions, _file_header_scope(view), flags=sublime.DRAW_NO_OUTLINE)
|
view.add_regions(KEY_FILE_HEADER, file_regions, _file_header_scope(view), flags=sublime.DRAW_NO_OUTLINE)
|
||||||
view.add_regions(KEY_FILE_DEL_COUNT, file_del_counts, KEY_FILE_DEL_COUNT, flags=sublime.DRAW_NO_OUTLINE)
|
view.add_regions(KEY_FILE_DEL_COUNT, file_del_counts, KEY_FILE_DEL_COUNT, flags=sublime.DRAW_NO_OUTLINE)
|
||||||
view.add_regions(KEY_FILE_INS_COUNT, file_ins_counts, KEY_FILE_INS_COUNT, flags=sublime.DRAW_NO_OUTLINE)
|
view.add_regions(KEY_FILE_INS_COUNT, file_ins_counts, KEY_FILE_INS_COUNT, flags=sublime.DRAW_NO_OUTLINE)
|
||||||
|
view.add_regions(KEY_FILE_STATUS, file_statuses, KEY_FILE_STATUS, flags=sublime.DRAW_NO_OUTLINE)
|
||||||
view.add_regions(KEY_FILE_PREFIX, prefix_regions, palette.line_numbers_scope(view), flags=sublime.DRAW_NO_OUTLINE)
|
view.add_regions(KEY_FILE_PREFIX, prefix_regions, palette.line_numbers_scope(view), flags=sublime.DRAW_NO_OUTLINE)
|
||||||
for scope, regions in token_groups.items():
|
for scope, regions in token_groups.items():
|
||||||
view.add_regions(palette.token_key(scope), regions, scope, flags=sublime.DRAW_NO_OUTLINE)
|
view.add_regions(palette.token_key(scope), regions, scope, flags=sublime.DRAW_NO_OUTLINE)
|
||||||
|
|||||||
Reference in New Issue
Block a user