The following should do what you want (thanks to Ulrike Fischer for her useful comments!). I used (n--p)
style for ranges, but switching to (n-p)
style or something similar if you prefer is trivial (just look at \__cis_output_parnum_range:nn
: this is the function doing the formatting of parnum info; it should be fairly easy to modify for this kind of change).
\documentclass[fontsize=9pt, paper=a5, twoside, numbers=enddot,
headsepline,plainheadsepline]{scrreprt}
\usepackage{zref}
\usepackage{multicol}
\usepackage{blindtext}
\usepackage{lipsum}
\usepackage{marginnote}
\usepackage{etoolbox}
\usepackage{xparse}
\ExplSyntaxOn
% ****************************************************************************
% * LaTeX3 bindings to macros from the zref package *
% ****************************************************************************
% Extract prop #2 recorded for ref cis-parnum-label-#1 (#1 corresponds to a
% parnum)
\cs_new:Npn \cis_extract_prop:nn #1#2
{
% \zref@extract is expandable
\use:c { zref@extract } { cis-parnum-label-#1 } {#2}
}
\cs_generate_variant:Nn \cis_extract_prop:nn { V }
\cs_new_protected:Npn \cis_ref_used:n #1
{
\use:c { zref@refused } { cis-parnum-label-#1 }
}
\cs_generate_variant:Nn \cis_ref_used:n { V }
\prg_new_conditional:Npnn \cis_if_parnum_ref_defined:n #1 { p }
{
% \zref@ifrefundefined is expandable
\use:c { zref@ifrefundefined } { cis-parnum-label-#1 }
{ \prg_return_false: }
{ \prg_return_true: }
}
\prg_generate_conditional_variant:Nnn \cis_if_parnum_ref_defined:n { V } { p }
% ****************************************************************************
% * Main code for generation of parnum ranges *
% ****************************************************************************
% Most important variable: in the \AtBeginDocument hook, we are going to fill
% it to give the parnum range for each page that has at least one parnum. Keys
% in this property list are page numbers (in decimal notation); values have
% the form '{first}{last}' (without quotes). E.g., {2}{5} or {6}{6}. If a page
% contains no parnum at all, the property list will have no key equal to the
% corresponding page number.
\prop_new:N \g_cis_parnums_for_page_prop
\int_new:N \l__cis_fpfep_parnum_int
\int_new:N \l__cis_fpfep_page_in_ref_int
\int_new:N \l__cis_fpfep_last_page_seen_int
\int_new:N \l__cis_fpfep_first_parnum_for_page_int
\int_new:N \l__cis_fpfep_last_parnum_for_page_int
\cs_generate_variant:Nn \int_compare:nNnF { VN }
\cs_generate_variant:Nn \int_compare:nNnF { VNV }
% #1: first labelled parnum in document (if any)
\cs_new_protected:Npn \__cis_find_parnums_for_each_page:n #1
{
\int_set:Nn \l__cis_fpfep_parnum_int {#1} % next parnum to examine
\int_set:Nn \l__cis_fpfep_last_page_seen_int { -1000 } % sentinel value
\bool_while_do:nn
{ \cis_if_parnum_ref_defined_p:V \l__cis_fpfep_parnum_int }
{
% Get the page for parnum \l__cis_fpfep_parnum_int
\int_set:Nn \l__cis_fpfep_page_in_ref_int
{ \cis_extract_prop:Vn \l__cis_fpfep_parnum_int { page } }
\cis_ref_used:V \l__cis_fpfep_parnum_int
\int_compare:VNVF
\l__cis_fpfep_last_page_seen_int = \l__cis_fpfep_page_in_ref_int
{
% The parnum corresponding to the currently examined ref is on a
% different page than the previously-examined parnum, therefore
% we now have all the info for the last seen page -> store it.
\__cis_store_parnums_if_real_page:VVV
\l__cis_fpfep_last_page_seen_int
\l__cis_fpfep_first_parnum_for_page_int
\l__cis_fpfep_last_parnum_for_page_int
\int_set_eq:NN \l__cis_fpfep_first_parnum_for_page_int
\l__cis_fpfep_parnum_int
}
% Will be overwritten if there are more parnums on the same page
\int_set_eq:NN \l__cis_fpfep_last_parnum_for_page_int
\l__cis_fpfep_parnum_int
\int_set_eq:NN \l__cis_fpfep_last_page_seen_int
\l__cis_fpfep_page_in_ref_int
\int_incr:N \l__cis_fpfep_parnum_int
}
% Store info for the last page containing a labelled parnum
\__cis_store_parnums_if_real_page:VVV
\l__cis_fpfep_last_page_seen_int
\l__cis_fpfep_first_parnum_for_page_int
\l__cis_fpfep_last_parnum_for_page_int
}
% #1: page number or sentinel value (-1000) meaning “do nothing”
% #2: first parnum on this page
% #3: last parnum on this page
\cs_new_protected:Npn \__cis_store_parnums_if_real_page:nnn #1#2#3
{
\int_compare:nNnF {#1} = { -1000 }
{
\prop_gput:Nnn \g_cis_parnums_for_page_prop {#1} { {#2} {#3} }
}
}
\cs_generate_variant:Nn \__cis_store_parnums_if_real_page:nnn { VVV }
\cs_generate_variant:Nn \__cis_output_parnum_range:nn { VV }
\tl_new:N \g__cis_oprfp_first_parnum_tl
\tl_new:N \g__cis_oprfp_last_parnum_tl
\cs_new_protected:Npn \cis_output_parnums_range_for_page:n #1
{
\prop_get:NnNTF \g_cis_parnums_for_page_prop {#1} \l_tmpa_tl
{
\seq_set_split:NnV \l_tmpa_seq { } \l_tmpa_tl
\seq_pop_left:NN \l_tmpa_seq \l_tmpa_tl
\seq_pop_left:NN \l_tmpa_seq \l_tmpb_tl
\tl_gset_eq:NN \g__cis_oprfp_first_parnum_tl \l_tmpa_tl
\tl_gset_eq:NN \g__cis_oprfp_last_parnum_tl \l_tmpb_tl
\__cis_output_parnum_range:VV \g__cis_oprfp_first_parnum_tl
\g__cis_oprfp_last_parnum_tl
}
{
% In case there is no parnum at all on a page, the OP wants the page
% header to hold only the last parnum seen (not the last parnum info,
% i.e.: he wants only a number, not a range). Hence "last, last"
% instead of "first, last" here:
\__cis_output_parnum_range:VV \g__cis_oprfp_last_parnum_tl
\g__cis_oprfp_last_parnum_tl
}
}
% Write formatted information for the specified parnum range.
%
% #1: first parnum of range
% #2: last parnum of range
\cs_new_protected:Npn \__cis_output_parnum_range:nn #1#2
{
\tl_if_eq:nnTF {#1} {#2}
{
\tl_if_blank:nF {#1} { (#1) }
}
{
(#1--#2)
}
}
\cs_generate_variant:Nn \cis_output_parnums_range_for_page:n { x }
% Fully expands the argument (which should be a page number)
\NewDocumentCommand \parnumrangeinpage { m }
{
\cis_output_parnums_range_for_page:x {#1}
}
% 1 is the number of the first parnum to consider as possibly existing in the
% document. \__cis_find_parnums_for_each_page:n looks for refs corresponding
% to parnums 1, 2, ... The smallest integer in this scanning process for which
% no ref is found in the .aux file is considered to be one past the last
% parnum.
\AtBeginDocument { \__cis_find_parnums_for_each_page:n { 1 } }
\ExplSyntaxOff
\makeatletter
\zref@newlist{cisparnumlist}
\zref@addprop{cisparnumlist}{page}
% Paragraph numbers. Must be strictly increasing, and the numbering should
% have no holes.
\newcounter{parnumber}
\newcommand*\parnum[1][]{%
\leavevmode
\refstepcounter{parnumber}%
\ifblank{#1}{}{\label{#1}}% regular LaTeX label for the numbered paragraph
\marginnote{%
\theparnumber
% Set our special zref label for parnums. From the set of all such labels,
% we can deduce in the \AtBeginDocument hook the parnum range for each
% page.
\zref@labelbylist{cis-parnum-label-\the\value{parnumber}}%
{cisparnumlist}}%
}
\makeatother
% Allow easy on/off switching of parnum info in headers
\newtoggle{parnumsinheader}
\newcommand*{\parnumsinheaderon}{\toggletrue{parnumsinheader}}
\newcommand*{\parnumsinheaderoff}{\togglefalse{parnumsinheader}}
\parnumsinheaderon % Show parnum info in headers by default
% Set up the page headers
\usepackage[automark]{scrlayer-scrpage}
\ohead*{%
\iftoggle{parnumsinheader}{%
\marginnote{\parnumrangeinpage{\thepage}}% range of parnums
}{}%
\ifstr{\headmark}{}{\rightbotmark}{\headmark}% chapter or section title, etc.
}
\begin{document}
\chapter{Three parnums here}
\parnum[TPy]
Theorem of Pythagoras \par
\parnum
\blindtext \par
Text without parnum.
\parnum Text.
The theorem of Pythagoras corresponds to parnum~\ref{TPy} on
page~\pageref{TPy}.
\chapter{Two parnums here}
\parnum Text.
\parnum[mylabel] Text.
\chapter{Only one parnum here}
\parnum Text.
\newpage % Test repeating of last parnum info when there is no parnum on the
% current page.
\chapter{Test with parnums deeply embedded in \TeX\ lists}
\noindent
{\centering
\begin{minipage}{\linewidth}
\begin{multicols}{2}
\parnum Text.
\lipsum[1-3]
\parnum Text.
\end{multicols}
\end{minipage}
}
\newpage
\lipsum[1-2]
\end{document}






zref
. It's easy to do if you are ready to live without the chapter and section titles in headings (my opinion is that it is naturally a job for marks). If you want to keep them, it seems harder to me—unless there is some way to set additional, independent marks that behave like TeX's\firstmark
and\botmark
.zref
could help. You can get the current value of a property, but I don't see how that would help you to get the first value put on the current page—à la\firstmark
, which you need.zref
-based method technically superior to any method based on marks, except for the fact that it requires two compilation runs like any\label
/\ref
-like thing.