LINUX.ORG.RU

Latex: можно ли запретить оставлять на странице первые 2-3 строки verbatim блока?

 


2

2

Для обычных абзацев это нормально: оставить на предыдущей странице первые две строки, а остальной текст перенести на следующую. В случае же кусков кода и прочего, для чего использую Verbatim, это выглядит плохо. Можно как-нибудь запретить? Чтобы, например, оставалось не меньше 4 строк. А если не получается, то пусть переносит блок на следующую страницу целиком, оставляя на предыдущей пустое место.

Видел у fancyvrb опцию samepage, но она не подходит — сама возможность разорвать блок мне нужна (плюс, некоторые блоки просто не поместятся на одну страницу).

★★
Ответ на: комментарий от bookman900

\vspace{}

Ага, делал так. Но текста много, и повторять работу после каждого изменения очень не хочется.

fffgh ★★
() автор топика

verbatim формирует абзац, поэтому запрещать надо разрывать страницу для абзаца. Для сколько-нибудь современных движков TeXа это можно сделать так:

\clubpenalties 5 10000 10000 10000 10000 0

В абзацах после такой команды после первых 4-х строк будут вставлены штрафы 10000, запрещающие разрыв страницы, а после остальных строк — нулевые штрафы, то есть разрывать строку станет возможно. Чтобы на обычные абзацы это не влияло, можно, скажем, заключать абзацы с verbatim в группы.

TeopeTuK ★★★★★
()
Ответ на: комментарий от TeopeTuK

Для сколько-нибудь современных движков TeXа

pdflatex и xelatex из TeX Live 2013 достаточно современные?

\documentclass{article}

\clubpenalties 5 10000 10000 10000 10000 0

\begin{document}
.\vspace{180mm}

\begin{verbatim}
1
2
3
4
5
6
7 
\end{verbatim}
\end{document}

На первой странице остаётся одна строка.

В абзацах после такой команды после первых 4-х строк будут вставлены штрафы 10000

С обычным текстом это сработало, да. Но не с verbatim.

fffgh ★★
() автор топика
Ответ на: комментарий от fffgh

Значит я неправильно понимаю, как устроен verbatim. Надо почитать инструкцию.

TeopeTuK ★★★★★
()
Ответ на: комментарий от fffgh

Да, я неправильную идею предложил. Внутри verbatim каждая строка — это абзац. Так что надо между абзацами что-то придумывать. Вот, нахакал такое безобразие, подсмотрев в доке пакета verbatim (несколько тяп-ляп, зато быстро):

\documentclass{article}
\usepackage{verbatim}
\makeatletter
\newcounter{VerbatimLineNo}
\addto@hook\every@verbatim{\setcounter{VerbatimLineNo}{0}}
\def\verbatim@processline{%
\addtocounter{VerbatimLineNo}{1}%
\ifnum\c@VerbatimLineNo<4\interlinepenalty=10000\else\interlinepenalty=0\fi%
\leavevmode\the\verbatim@line\par}
\makeatother
\begin{document}
.\vspace{176mm}

\begin{verbatim}
1
2
3
4
5
6
7 
\end{verbatim}
\end{document}

Вот эти вот \ifnum\c@VerbatimLineNo<4 означают, что разрывы страницы разрешены только после 4-й строки verbatim.

TeopeTuK ★★★★★
()
Ответ на: комментарий от TeopeTuK

Вот, нахакал такое безобразие

Шикарно!

fffgh ★★
() автор топика

хм, а поступить также как с таблицей и картинкой разве нельзя? Обернуть все в figure и это уже будет неделимый блок

Silerus ★★★★
()
Ответ на: комментарий от Silerus

Так мне надо, чтобы блок делился, только не в самом начале.

fffgh ★★
() автор топика
Ответ на: комментарий от fffgh

Вот как-то так получилось. Еще хуже с точки зрения вменяемости кода. Но что-то в fancyvrb я вообще не нашел способа штатно влезть между строк.

\documentclass{article}
\usepackage{fancyvrb}
\makeatletter
\newcounter{VerbatimLineNo}
\FV@AddToHook\FV@CatCodesHook{\setcounter{VerbatimLineNo}{-1}}
\renewcommand{\FancyVerbFormatLine}[1]{%
\addtocounter{VerbatimLineNo}{1}%
\ifnum\c@VerbatimLineNo<4\global\interlinepenalty=10000\else\global\interlinepenalty=0\fi%
\leavevmode#1}
\makeatother

\begin{document}
.\vspace{173mm}

\begin{Verbatim}
1
2
3
4
5
6
7 
\end{Verbatim}
\end{document}

О! И теперь еще придется как-то восстанавливать \interlinepenalty после коротких Verbatim (присваивание-то глобальное стало).

TeopeTuK ★★★★★
()
Ответ на: комментарий от TeopeTuK

Спасибо.

\documentclass{article}
\usepackage{fancyvrb}

\makeatletter
\def\FV@Scan{
 \FV@CatCodes
 \VerbatimEnvironment
 \FV@DefineCheckEnd
 \interlinepenalty=10000
 \FV@BeginScanning}
\makeatother

\renewcommand{\FancyVerbFormatLine}[1]{
  \ifnum\value{FancyVerbLine}>4
    \global\interlinepenalty=0{#1}
  \else#1
  \fi
}

\begin{document}
% .\vspace{175mm} % 3
.\vspace{170mm} % 4

\interlinepenalty=10000
\begin{Verbatim}
1
2
3
4
5
6
7 
\end{Verbatim}
\end{document}

Разрешает оставлять от 4 строк. После коротких блоков Verbatim \interlinepenalty восстанавливать не нужно.

Или так, вместо ковыряния в FV@Scan:

\interlinepenalty=10000
\begin{Verbatim}
1
2
\end{Verbatim}
\interlinepenalty=0

Не сложно организовать автозаменой/скриптами.

fffgh ★★
() автор топика
Ответ на: комментарий от fffgh

Да, у тебя лучше получилось. Можно еще вот так (пропатчить парочку макросов с помощью etoolbox):

\documentclass{article}
\usepackage{fancyvrb}
\usepackage{etoolbox}
\makeatletter
\apptocmd{\FV@List}{\interlinepenalty=\@M}{}{}
\apptocmd{\FV@ListProcessLine}{%
  \ifnum\value{FancyVerbLine}>4%
    \global\interlinepenalty=0%
  \fi}{}{}
\makeatother

\begin{document}
.\vspace{173mm}

\begin{Verbatim}
1
2
3
4
5
6
7 
\end{Verbatim}
\end{document}

TeopeTuK ★★★★★
()
Ответ на: комментарий от fffgh
\documentclass{article}

...

\interlinepenalty=10000
\begin{Verbatim}
...

В этом листинге команда «\interlinepenalty=10000», лишняя. Случайно скопировал.

fffgh ★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.