diff --git a/md2gost/handlers/inline.py b/md2gost/handlers/inline.py index fbf51c6..8016ab4 100644 --- a/md2gost/handlers/inline.py +++ b/md2gost/handlers/inline.py @@ -6,6 +6,7 @@ from __future__ import annotations +import re import sys from markdown_it.token import Token @@ -32,9 +33,25 @@ def escape_latex(text: str) -> str: return text.translate(_LATEX_SPECIAL) +# Инициалы не должны отрываться друг от друга и от фамилии переносом строки: +# «/ И.» на одной строке и «В. Гилев» на следующей — ошибка оформления списка +# источников. Связывается одиночная заглавная буква с точкой и следующее слово, +# начинающееся с заглавной. +_INITIALS_RE = re.compile(r"(? str: + """Заменить пробел после инициала на неразрывный.""" + previous = None + while previous != text: + previous = text + text = _INITIALS_RE.sub(r"\1~", text) + return text + + @inline("text") def _text(tok: Token) -> str: - return escape_latex(tok.content) + return bind_initials(escape_latex(tok.content)) @inline("strong_open") diff --git a/md2gost/latex/preamble.py b/md2gost/latex/preamble.py index 793ea74..f07bb5d 100644 --- a/md2gost/latex/preamble.py +++ b/md2gost/latex/preamble.py @@ -58,7 +58,7 @@ PREAMBLE = r"""\documentclass[a4paper, 14pt]{extarticle} % комментарий распадался бы на прямые русские и курсивные латинские слова. commentstyle=\color{lstcomment}, stringstyle=\color{lststring}, - numberstyle=\tiny\color{lstlineno}, + numberstyle=\scriptsize\color{lstlineno}, identifierstyle=, breakatwhitespace=false, breaklines=true, @@ -67,7 +67,10 @@ PREAMBLE = r"""\documentclass[a4paper, 14pt]{extarticle} frame=single, keepspaces=true, numbers=left, - numbersep=5pt, + numbersep=7pt, + aboveskip=0.7\baselineskip, + belowskip=0.4\baselineskip, + postbreak=\mbox{\textcolor{lstlineno}{$\hookrightarrow$}\space}, xleftmargin=25pt, xrightmargin=25pt, showspaces=false, @@ -91,9 +94,9 @@ PREAMBLE = r"""\documentclass[a4paper, 14pt]{extarticle} \titleformat{\section}{\fontsize{14pt}{18pt}\selectfont\bfseries}{}{0em}{\thesection. } \titleformat{\subsection}{\fontsize{14pt}{18pt}\selectfont\bfseries}{}{0em}{\thesubsection. } \titleformat{\subsubsection}{\fontsize{14pt}{18pt}\selectfont\bfseries}{}{0em}{\thesubsubsection. } -\titlespacing*{\section}{1.25cm}{0.5ex plus 0.2ex minus 0.2ex}{0.3ex plus 0.1ex minus 0.1ex} -\titlespacing*{\subsection}{1.25cm}{0.5ex plus 0.2ex minus 0.2ex}{0.3ex plus 0.1ex minus 0.1ex} -\titlespacing*{\subsubsection}{1.25cm}{0.5ex plus 0.2ex minus 0.2ex}{0.3ex plus 0.1ex minus 0.1ex} +\titlespacing*{\section}{1.25cm}{1ex plus 0.3ex minus 0.2ex}{0.6ex plus 0.2ex minus 0.1ex} +\titlespacing*{\subsection}{1.25cm}{1ex plus 0.3ex minus 0.2ex}{0.6ex plus 0.2ex minus 0.1ex} +\titlespacing*{\subsubsection}{1.25cm}{1ex plus 0.3ex minus 0.2ex}{0.6ex plus 0.2ex minus 0.1ex} \usepackage{tocloft} \addto\captionsrussian{% \renewcommand{\contentsname}{СОДЕРЖАНИЕ}% diff --git a/tests/test_render.py b/tests/test_render.py index 4641823..d6107a0 100644 --- a/tests/test_render.py +++ b/tests/test_render.py @@ -498,3 +498,14 @@ def test_bare_listing_does_not_float() -> None: """Фрагмент без подписи — часть абзаца, ему плавать незачем.""" tex = body(render("```cpp\nint x;\n```\n")) assert "float=" not in tex + + +def test_initials_are_not_split_across_lines() -> None: + """«/ И.» на одной строке и «В. Гилев» на следующей — ошибка оформления.""" + tex = body(render("Гилев, И. В. Использование технологии SDR.\n")) + assert "И.~В.~Использование" in tex + + +def test_lowercase_abbreviation_is_left_alone() -> None: + tex = body(render("В 3 т., Воронеж, 2025.\n")) + assert "т.~Воронеж" not in tex