Compare commits
3 Commits
9c1b8298be
...
be53c209ea
| Author | SHA1 | Date | |
|---|---|---|---|
| be53c209ea | |||
| aa2bfa967e | |||
| 2b91b19ef3 |
@@ -116,7 +116,7 @@ class Line:
|
|||||||
# todo there are many other character combinations that should be skipped
|
# todo there are many other character combinations that should be skipped
|
||||||
while i < len(self._line) and unicodedata.category(self._line[i]) == "Mn":
|
while i < len(self._line) and unicodedata.category(self._line[i]) == "Mn":
|
||||||
self._char_to_column_cache[i] = result - 1
|
self._char_to_column_cache[i] = result - 1
|
||||||
if not result in self._column_to_char_cache:
|
if (result - 1) not in self._column_to_char_cache:
|
||||||
self._column_to_char_cache[result - 1] = i
|
self._column_to_char_cache[result - 1] = i
|
||||||
i = i + 1
|
i = i + 1
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ from src.ui.bigtext.highlighting import Highlighting
|
|||||||
from src.ui.bigtext.line import Line
|
from src.ui.bigtext.line import Line
|
||||||
import os
|
import os
|
||||||
from src.settings.settings import Settings
|
from src.settings.settings import Settings
|
||||||
|
from functools import lru_cache
|
||||||
|
|
||||||
|
|
||||||
class LogFileModel:
|
class LogFileModel:
|
||||||
@@ -21,6 +22,8 @@ class LogFileModel:
|
|||||||
range_start = 0
|
range_start = 0
|
||||||
range_end = -1
|
range_end = -1
|
||||||
|
|
||||||
|
_line_cache = {}
|
||||||
|
|
||||||
def __init__(self, file: str, settings: Settings, original_file: str = False):
|
def __init__(self, file: str, settings: Settings, original_file: str = False):
|
||||||
"""
|
"""
|
||||||
:param file:
|
:param file:
|
||||||
@@ -133,6 +136,13 @@ class LogFileModel:
|
|||||||
def _is_word_char(self, char: str) -> bool:
|
def _is_word_char(self, char: str) -> bool:
|
||||||
return re.match(r"\w", char) is not None
|
return re.match(r"\w", char) is not None
|
||||||
|
|
||||||
|
def prune_cache(self, range_start: int, range_end: int):
|
||||||
|
for key in list(self._line_cache.keys()):
|
||||||
|
line = self._line_cache[key]
|
||||||
|
if range_start > line.byte_end() or line.byte_offset() > range_end:
|
||||||
|
del self._line_cache[key]
|
||||||
|
|
||||||
|
|
||||||
def data(self, byte_offset: int, scroll_lines: int, lines: int, range_start: int, range_end: int) -> List[Line]:
|
def data(self, byte_offset: int, scroll_lines: int, lines: int, range_start: int, range_end: int) -> List[Line]:
|
||||||
# print("data(%s, %s, %s)" % (byte_offset, scroll_lines, lines))
|
# print("data(%s, %s, %s)" % (byte_offset, scroll_lines, lines))
|
||||||
lines_before_offset: List[Line] = []
|
lines_before_offset: List[Line] = []
|
||||||
@@ -148,19 +158,36 @@ class LogFileModel:
|
|||||||
offset = max(0,
|
offset = max(0,
|
||||||
max(range_start - self.settings.max_line_length(), offset - self.settings.max_line_length()))
|
max(range_start - self.settings.max_line_length(), offset - self.settings.max_line_length()))
|
||||||
|
|
||||||
|
self.prune_cache(range_start, range_end)
|
||||||
|
|
||||||
|
previous_line_is_complete = False
|
||||||
f.seek(offset)
|
f.seek(offset)
|
||||||
while l := f.readline():
|
while True:
|
||||||
|
line: Line | None = self._line_cache.get(offset)
|
||||||
|
if line is None:
|
||||||
|
line_bytes = f.readline()
|
||||||
|
if not line_bytes:
|
||||||
|
break
|
||||||
new_offset = f.tell()
|
new_offset = f.tell()
|
||||||
if 0 <= range_end < new_offset:
|
if 0 <= range_end < new_offset:
|
||||||
break
|
break
|
||||||
line = Line(offset, new_offset, l.decode("utf8", errors="ignore"))
|
line = Line(offset, new_offset, line_bytes.decode("utf8", errors="ignore"))
|
||||||
|
if previous_line_is_complete: # only cache lines when we know they are complete
|
||||||
|
self._line_cache[offset] = line
|
||||||
|
offset = new_offset
|
||||||
|
previous_line_is_complete = True
|
||||||
|
else:
|
||||||
|
# print(f"loaded cached line at offset {offset}")
|
||||||
|
offset = line.byte_end() # line.byte_end() returns the end byte +1
|
||||||
|
f.seek(offset)
|
||||||
|
previous_line_is_complete = True
|
||||||
|
|
||||||
if line.byte_end() <= byte_offset: # line.byte_end() returns the end byte +1
|
if line.byte_end() <= byte_offset: # line.byte_end() returns the end byte +1
|
||||||
if line.byte_offset() >= range_start: # only add if in range
|
if line.byte_offset() >= range_start: # only add if in range
|
||||||
lines_before_offset.append(line)
|
lines_before_offset.append(line)
|
||||||
else:
|
else:
|
||||||
lines_after_offset.append(line)
|
lines_after_offset.append(line)
|
||||||
offset = f.tell()
|
|
||||||
if len(lines_after_offset) >= lines_to_find:
|
if len(lines_after_offset) >= lines_to_find:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
@@ -31,9 +31,9 @@ class MyTestCase(unittest.TestCase):
|
|||||||
self.assertEqual(9, line.column_to_char(15)) # tab
|
self.assertEqual(9, line.column_to_char(15)) # tab
|
||||||
self.assertEqual(10, line.column_to_char(16)) # g
|
self.assertEqual(10, line.column_to_char(16)) # g
|
||||||
|
|
||||||
def test_column_to_char_ignore_nonspacing_mark_charaters(self):
|
def test_column_to_char_ignore_nonspacing_mark_characters(self):
|
||||||
"""
|
"""
|
||||||
nonspacing mark charaters are those little decorations that are applied to the previous character,
|
nonspacing mark characters are those little decorations that are applied to the previous character,
|
||||||
e.g. x\u0308 to make ẍ
|
e.g. x\u0308 to make ẍ
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
@@ -63,7 +63,7 @@ class MyTestCase(unittest.TestCase):
|
|||||||
|
|
||||||
def test_char_to_column_ignore_nonspacing_mark_charaters(self):
|
def test_char_to_column_ignore_nonspacing_mark_charaters(self):
|
||||||
"""
|
"""
|
||||||
nonspacing mark charaters are those little decorations that are applied to the previous character,
|
nonspacing mark characters are those little decorations that are applied to the previous character,
|
||||||
e.g. x\u0308 to make ẍ
|
e.g. x\u0308 to make ẍ
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
@@ -119,7 +119,7 @@ class MyTestCase(unittest.TestCase):
|
|||||||
for i in range(128):
|
for i in range(128):
|
||||||
if unicodedata.category(chr(i)) == "Cc":
|
if unicodedata.category(chr(i)) == "Cc":
|
||||||
# print(i, " -> ", ord(chr(i)), " --> ", chr(9216 + i))
|
# print(i, " -> ", ord(chr(i)), " --> ", chr(9216 + i))
|
||||||
if not i in [9, 10, 11, 13]:
|
if i not in [9, 10, 11, 13]:
|
||||||
text = text + chr(i)
|
text = text + chr(i)
|
||||||
|
|
||||||
line = Line(byte_offset=byte_offset, byte_end=byte_offset + len(text.encode("utf8")), line=text)
|
line = Line(byte_offset=byte_offset, byte_end=byte_offset + len(text.encode("utf8")), line=text)
|
||||||
|
|||||||
Reference in New Issue
Block a user