[FIX] длинные токены в таблицах переносятся, а не налезают на соседнюю колонку
This commit is contained in:
@@ -33,6 +33,13 @@ from md2gost.registry import block, pattern
|
||||
|
||||
_CAPTION_RE = re.compile(r"^\s*Таблица\s+\d+\s*[—–-]+\s*(.+?)\s*$")
|
||||
|
||||
# Длина слова, начиная с которой ему нужны точки разрыва. Идентификаторы вроде
|
||||
# HackRFTestingServer:идентификатор не содержат пробелов и дефисов, поэтому в
|
||||
# узкой колонке LaTeX не может их перенести: строка уезжает за границу колонки
|
||||
# и печатается поверх соседней.
|
||||
_LONG_WORD = 18
|
||||
_BREAK_AFTER = ":/_.-"
|
||||
|
||||
_ALIGN_BY_STYLE = {
|
||||
"text-align:left": "l",
|
||||
"text-align:center": "c",
|
||||
@@ -40,6 +47,26 @@ _ALIGN_BY_STYLE = {
|
||||
}
|
||||
|
||||
|
||||
def _breakable(cell: str) -> str:
|
||||
"""Расставить точки переноса внутри длинных слов ячейки.
|
||||
|
||||
Ячейка уже отрендерена в LaTeX, поэтому слова с обратной косой чертой или
|
||||
фигурными скобками пропускаются: вставка внутрь имени команды сломала бы её.
|
||||
"""
|
||||
words = []
|
||||
for word in cell.split(" "):
|
||||
if len(word) < _LONG_WORD or any(ch in word for ch in "\\{}"):
|
||||
words.append(word)
|
||||
continue
|
||||
out = []
|
||||
for ch in word:
|
||||
out.append(ch)
|
||||
if ch in _BREAK_AFTER:
|
||||
out.append("\\allowbreak ")
|
||||
words.append("".join(out))
|
||||
return " ".join(words)
|
||||
|
||||
|
||||
def _cell_align(tok: Token) -> str:
|
||||
style = str(tok.attrGet("style") or "").replace(" ", "")
|
||||
return _ALIGN_BY_STYLE.get(style, "l")
|
||||
@@ -69,7 +96,7 @@ def _collect_rows(
|
||||
pos += 1
|
||||
break
|
||||
if ctok.type in ("th_open", "td_open"):
|
||||
row.append(render_inline(tokens[pos + 1]))
|
||||
row.append(_breakable(render_inline(tokens[pos + 1])))
|
||||
row_aligns.append(_cell_align(ctok))
|
||||
pos += 3
|
||||
else:
|
||||
|
||||
@@ -16,6 +16,7 @@ PREAMBLE = r"""\documentclass[a4paper, 14pt]{extarticle}
|
||||
\usepackage{float}
|
||||
\usepackage{wrapfig}
|
||||
\sloppy
|
||||
\setlength{\emergencystretch}{2em}
|
||||
\clubpenalty=10000
|
||||
\widowpenalty=10000
|
||||
\usepackage{enumitem}
|
||||
|
||||
@@ -410,3 +410,33 @@ def test_table_without_left_columns_stays_plain_tabular() -> None:
|
||||
tex = body(render("| a | b |\n| :---: | :---: |\n| 1 | 2 |\n"))
|
||||
assert "\\begin{tabular}{|c|c|}" in tex
|
||||
assert "\\begin{tabularx}" not in tex
|
||||
|
||||
|
||||
LONG_TOKEN_TABLE_MD = (
|
||||
"| Направление | Формат | Назначение |\n"
|
||||
"| :--- | :--- | :--- |\n"
|
||||
"| сервер | HackRFTestingServer:идентификатор | Приветствие, подтверждает |\n"
|
||||
)
|
||||
|
||||
|
||||
def test_long_token_in_cell_gets_break_points() -> None:
|
||||
"""Иначе токен не переносится и печатается поверх соседней колонки."""
|
||||
tex = body(render(LONG_TOKEN_TABLE_MD))
|
||||
assert "HackRFTestingServer:\\allowbreak" in tex
|
||||
|
||||
|
||||
def test_short_cells_are_left_alone() -> None:
|
||||
tex = body(render("| a | b |\n| :--- | :--- |\n| ping | сервер |\n"))
|
||||
assert "\\allowbreak" not in tex
|
||||
|
||||
|
||||
def test_break_points_do_not_touch_latex_commands() -> None:
|
||||
"""В ячейке с разметкой есть команды; ломать их вставками нельзя."""
|
||||
tex = body(
|
||||
render(
|
||||
"| Поле | Значение |\n| :--- | :--- |\n"
|
||||
"| **оченьдлинноежирноеслово_подчёркивание** | x |\n"
|
||||
)
|
||||
)
|
||||
assert "\\textbf{" in tex
|
||||
assert "\\textbf\\allowbreak" not in tex
|
||||
|
||||
Reference in New Issue
Block a user