summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/hereapplies/hereapplies.sty
blob: 29db09d1636924c232ae55c586637dadba64c6c3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
%  -*- Mode: latex; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*-

%
% hereapplies.sty
%
% A LaTeX package for cross-linking applications of concepts
%
% https://github.com/madmurphy/hereapplies.sty
%
% Version 0.2.0
%
% Copyright (c) 2022 madmurphy <madmurphy333@gmail.com>
%
% **Here Applies** is free software: you can redistribute it and/or modify it
% under the terms of the GNU Affero General Public License as published by the
% Free Software Foundation, either version 3 of the License, or (at your
% option) any later version.
%
% **Here Applies** is distributed in the hope that it will be useful, but
% WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
% FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
% for more details.
%
% You should have received a copy of the GNU Affero General Public License
% along with this program. If not, see <http://www.gnu.org/licenses/>.
%
%
%
% Example usage:
%
%     \documentclass{article}
%
%     \usepackage{hereapplies}
%
%     \begin{document}
%
%     \title{Some title}
%     \author{Some author}
%
%     \maketitle
%
%     This is concept one. To see this concept applied, please
%     see \whereapplies{conceptone}.
%
%     This is concept four. To see this concept applied, please
%     see \whereapplies{conceptfour}.
%
%     \newpage
%
%     \hereapplies{conceptone}This is page \thepage. As you can see, ``concept
%     one'' applies here.\newpage
%
%     \hereapplies{conceptfour}This is page \thepage. As you can see,
%     ``concept four'' applies here.\newpage
%
%     \hereapplies{conceptone}This is page \thepage. As you can see, ``concept
%     one'' applies here.\newpage
%
%     \hereapplies{conceptfour}This is page \thepage. As you can see,
%     ``concept four'' applies here.\newpage
%
%     \hereapplies[myref]{conceptone}This is page \thepage. As you can
%     see, ``concept one'' applies here. This point in the document is
%     labeled \texttt{appl:conceptone:myref}.
%
%     \end{document}
%
%
\ProvidesPackage{hereapplies}
\RequirePackage{hyperref}
%
%
%
%         PRIVATE ENVIRONMENT
%         ===================
%
%
% Assign a unique number to each applicable concept
\newcounter{@ha@concept@counter}
%
%
% Macro `\@ha@newapplicable{concept_name}`
% *****************************************************************************
%
% Initialize a new applicable concept
%
% Thie macro is for internal purposes only. When invoked it sets up the helper
% macros, counters and auxiliary files needed for keeping track of a concept.
% If the concept was already initialized this macro will be no op.
%
\newcommand{\@ha@newapplicable}[1]{%
	% Was this concept already initialized?
	\expandafter\ifx\csname @ha@concept@#1@cursor\endcsname\relax%
		% The concept was never initialized
		% Move the counter to the current id
		\stepcounter{@ha@concept@counter}%
		% Count the unnamed occurrences
		\newcounter{@ha@concept@#1@unnamed@counter}%
		% The content of this macro will be saved in the .haN file
		\expandafter\def\csname @ha@concept@#1@output\endcsname{\textbf{??}}%
		% The last page that applies
		\expandafter\def\csname @ha@concept@#1@cursor\endcsname{-1}%
		% Store the id of the current concept
		\expandafter\edef\csname @ha@concept@#1@id\endcsname{\arabic{@ha@concept@counter}}%
		% Initialize the .haN file
		% The previous solution generated unwanted whitespaces:
		%\@starttoc{ha\csname @ha@concept@#1@id\endcsname}%
		% I am thankful to David Carlisle for the following line:
		{\endlinechar=\m@ne\@starttoc{ha\csname @ha@concept@#1@id\endcsname}}%
		% Store all the occurrences when the document reaches the end
		\AtEndDocument{%
			% Set the .haN file as output
			\addtocontents{ha\csname @ha@concept@#1@id\endcsname}{%
				% Check that there are occurrences
				\expandafter\ifcsname @ha@concept@#1@cache\endcsname%
					% There are occurrences - write "p./pp. ..." to the output
					\gdef\expandafter\protect\csname @ha@concept@#1@output\endcsname{%
						\csname @ha@concept@#1@preamble\endcsname\csname @ha@concept@#1@cache\endcsname%
					}%
				\else%
					% There are no occurrences - write "??" to the output
					\gdef\expandafter\protect\csname @ha@concept@#1@output\endcsname{%
						\textbf{??}%
					}%
				\fi%
			}%
		}%
	\fi%
}
%
%
% Macro: `\starred@hereapplies[occurrence_name]{concept_name}`
% *****************************************************************************
%
% Equivalent to `\hereapplies*`
%
% Thie macro is for internal purposes - but nothing forbids invoking it
% directly.
%
\newcommand{\starred@hereapplies}[2][]{%
	% Make sure that the concept has been initialized
	\@ha@newapplicable{#2}%
	\ifx&#1&%
		% The macro has been called with only one argument
		% Assign a unique number to the unnamed occurrence
		\stepcounter{@ha@concept@#2@unnamed@counter}%
		% Call `\starred@hereapplies` again (recursion), but this time with 2 arguments
		\edef\tmp{\noexpand\starred@hereapplies[__unnamed\arabic{@ha@concept@#2@unnamed@counter}__]{#2}}\tmp%
	\else%
		% The macro has been called with two arguments
		% Assign a label to this occurrence
		\label{appl:#2:#1}%
		% If the cursor already points to the current page do nothing
		\unless\ifnum\csname @ha@concept@#2@cursor\endcsname=\thepage%
			% Make the cursor point to the current page
			\expandafter\edef\csname @ha@concept@#2@cursor\endcsname{\thepage}%
			% Is this the first occurrence?
			\expandafter\ifcsname @ha@concept@#2@cache\endcsname%
				% This is *not* the first occurrence
				% Use "pp." for the preamble when there are multiple occurrences
				\expandafter\def\csname @ha@concept@#2@preamble\endcsname{pp.~}%
				% Populate the cache
				\expandafter\g@addto@macro\csname @ha@concept@#2@cache\endcsname{, \pageref{appl:#2:#1}}%
			\else%
				% This is the first occurrence
				% Use "p." for the preamble when there is only one occurrence
				\expandafter\def\csname @ha@concept@#2@preamble\endcsname{p.~}%
				% Initialize the cache
				\expandafter\def\csname @ha@concept@#2@cache\endcsname{\pageref{appl:#2:#1}}%
			\fi%
		\fi%
	\fi%
}
%
%
%
%         PUBLIC ENVIRONMENT
%         ===================
%
%
% Macro: `\hereapplies[occurrence_name]{concept_name}`
% *****************************************************************************
%
% Notify the document that here a particular concept applies
%
% If the `occurrence_name` argument is passed, a new label will be created in
% the form `appl:[concept_name]:[occurrence_name]`. Without passing the
% `occurrence_name` argument, an opaque name will be assigned to the label.
%
% The starred version of this macro (`\hereapplies*`) will not invoke the
% `\phantomsection` directive before generating the label.
%
\newcommand{\hereapplies}{%
	% Check if a star is present in the invocation of the command
	\@ifstar{\starred@hereapplies}{\phantomsection\relax\starred@hereapplies}%
}
%
%
% Macro: `\whereapplies{concept_name}`
% *****************************************************************************
%
% Print all the applications of a concept in the form "p./pp. ..."
%
\newcommand{\whereapplies}[1]{%
	% Make sure that the applicable concept is initialized
	\@ha@newapplicable{#1}%
	% Print all the applications of the concept
	\csname @ha@concept@#1@output\endcsname%
}