|
11 | 11 | if typing.TYPE_CHECKING: |
12 | 12 | from collections.abc import Callable, Iterator |
13 | 13 | from pathlib import Path |
14 | | - from typing import IO |
| 14 | + from typing import IO, Any |
15 | 15 |
|
16 | 16 | from tugboat.analyze import AugmentedDiagnosis |
17 | 17 |
|
@@ -73,9 +73,12 @@ def report_diagnosis(echo: Callable, file: Path, diagnosis: AugmentedDiagnosis): |
73 | 73 | # default to the column number, but if the input is present, use that instead |
74 | 74 | indent_before_caret = " " * max(diagnosis["column"] - 1, 0) |
75 | 75 |
|
76 | | - if diagnosis["input"] is not None and str(diagnosis["input"]) in line: |
77 | | - col_start = line.index(str(diagnosis["input"])) |
78 | | - col_end = col_start + len(str(diagnosis["input"])) |
| 76 | + if range_ := _calc_highlight_range( |
| 77 | + line=line, |
| 78 | + offset=diagnosis["column"] - 1, |
| 79 | + input_=diagnosis["input"], |
| 80 | + ): |
| 81 | + col_start, col_end = range_ |
79 | 82 | indent_before_caret = " " * col_start |
80 | 83 |
|
81 | 84 | # print the underline |
@@ -116,11 +119,31 @@ def report_diagnosis(echo: Callable, file: Path, diagnosis: AugmentedDiagnosis): |
116 | 119 | def get_content_near(file: Path, target_line: int) -> Iterator[tuple[int, str]]: |
117 | 120 | target_line -= 1 # 1-based to 0-based |
118 | 121 | content = read_file(file).splitlines() |
119 | | - start = max(0, target_line - LINES_BEHIND) |
120 | | - end = min(len(content), target_line + LINES_AHEAD) |
121 | | - yield from enumerate(content[start:end], start + 1) |
| 122 | + start = max(0, target_line - LINES_AHEAD) |
| 123 | + end = min(len(content), target_line + LINES_BEHIND) |
| 124 | + yield from enumerate(content[start : end + 1], start + 1) |
122 | 125 |
|
123 | 126 |
|
124 | 127 | @functools.lru_cache(1) |
125 | 128 | def read_file(path: Path) -> str: |
126 | 129 | return path.read_text() |
| 130 | + |
| 131 | + |
| 132 | +def _calc_highlight_range(line: str, offset: int, input_: Any): |
| 133 | + """ |
| 134 | + Calculate the range to highlight in the line. |
| 135 | + """ |
| 136 | + if input_ is None: |
| 137 | + return # early escape if no value is provided |
| 138 | + |
| 139 | + value = str(input_) |
| 140 | + if not value.strip(): |
| 141 | + return # prevent highlighting empty strings |
| 142 | + |
| 143 | + try: |
| 144 | + col_start = line.index(value, offset) |
| 145 | + except ValueError: |
| 146 | + return |
| 147 | + |
| 148 | + col_end = col_start + len(value) |
| 149 | + return col_start, col_end |
0 commit comments