├── .gitignore ├── README.md ├── tests └── ind_lines.tex ├── algpseudocodex.tex └── algpseudocodex.sty /.gitignore: -------------------------------------------------------------------------------- 1 | *.pdf 2 | *.aux 3 | *.fdb_latexmk 4 | *.fls 5 | *.log 6 | *.synctex.gz 7 | *.out 8 | *.toc 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # algpseudocodex 2 | ## Overview 3 | This package allows typesetting pseudocode in LaTeX. It is based on algpseudocode from the algorithmicx package and uses the same syntax, but adds several new features and improvements. Notable features include customizable indent guide lines and the ability to draw boxes around parts of the code for highlighting differences. This package also has better support for long code lines spanning several lines and improved comments. 4 | 5 | The package documentation can be found in the file algpseudocodex.tex. 6 | 7 | ## Author and Contact 8 | The package is authored and maintained by Christian Matt. For bug reports and other issues please visit the official repository at . 9 | 10 | ## License 11 | This material is subject to the LaTeX Project Public License (LPPL), version 1.3c. 12 | -------------------------------------------------------------------------------- /tests/ind_lines.tex: -------------------------------------------------------------------------------- 1 | %\documentclass[a4paper,twocolumn]{article} 2 | \documentclass[a4paper]{article} 3 | \usepackage{amsmath} 4 | \usepackage{etoolbox} 5 | \usepackage{multicol} 6 | 7 | \newbool{noEnd} 8 | \setbool{noEnd}{true} 9 | %\setbool{noEnd}{false} 10 | 11 | \ifbool{noEnd}{% 12 | \usepackage[noEnd=true]{../algpseudocodex} 13 | }{ 14 | \usepackage[noEnd=false]{../algpseudocodex} 15 | } 16 | 17 | \begin{document} 18 | \section{Test Indent Guide Lines} 19 | \subsection{Basic Tests} 20 | This is some text before the algorithm starts to test how it indents. This is some text before the algorithm starts to test how it indents. 21 | \begin{algorithmic}[1] 22 | \State first line 23 | \If{$X > 0$} no additional line 24 | \EndIf 25 | \While{$x$}\EndWhile 26 | \If{$a_{q_q} > 0$} 27 | \State a 28 | \State a 29 | \State a 30 | \EndIf 31 | \If{$a > 0$} 32 | \State a 33 | \ElsIf{$b > 0$} 34 | \State b 35 | \ElsIf{$c > 0$} 36 | \Else 37 | \State d 38 | \EndIf 39 | \If{There is a really long line in the if condition, then this line is split over two lines} 40 | \State a 41 | \If{$x > 0$} 42 | \State $a_{q_{q_{q_q}}}$ 43 | \EndIf 44 | \EndIf 45 | \Repeat 46 | \State $x \gets x - 1$ 47 | \Until{$x^{2^{2^{2^{2^2}}}} = 0$} 48 | \State some line 49 | \Procedure{AnotherProcedure}{$x, y, S$} 50 | \State This is a really long line that is broken up into two lines within the same line. $q_{q_{q_{q_q}}}$ 51 | \EndProcedure 52 | \Procedure{SomeProcedure}{$x,y$} 53 | \State $x \gets y+1$ 54 | \Repeat 55 | \State $x \gets 2xy$ 56 | \Until{$x > 1000$} 57 | \EndProcedure 58 | \State some line 59 | \Procedure{AnotherProcedure}{$x, y, S$} 60 | \State $x \gets x+y$ 61 | \For{$z \in S$} 62 | \State This is a really long line that is broken up into two lines within the same line. 63 | \EndFor 64 | \EndProcedure 65 | \end{algorithmic} 66 | 67 | \newpage 68 | \subsection{Test Page Breaks} 69 | This is some text before the algorithm starts to test how it indents.\footnote{This is a footnote.} 70 | \begin{algorithmic}[1] 71 | \State first line 72 | \If{$a > 0$} 73 | \State a 74 | \State a 75 | \State a 76 | \State a 77 | \State a 78 | \If{$b > 0$} 79 | \State a 80 | \State a 81 | \State a 82 | \If{$c > 0$} 83 | \State a 84 | \State a 85 | \State a 86 | \State a 87 | \State a 88 | \State a 89 | \State a 90 | \State a 91 | \State a 92 | \State a 93 | \State a 94 | \State a 95 | \State a 96 | \State a 97 | \EndIf 98 | \State a 99 | \State a 100 | \State a 101 | \State a 102 | \State a 103 | \State a 104 | \State a 105 | \State a 106 | \State a 107 | \State a 108 | \State a 109 | \State a 110 | \State a 111 | \State a 112 | \State a 113 | \State a 114 | \ifbool{noEnd}{ 115 | \State a 116 | }{} 117 | \State This is a very long line to test how page break interact with line breaks in lines. 118 | \State $x^{x^{x^2}}$ la la la la la 119 | \State a 120 | \State a 121 | \State a 122 | \State a 123 | \State a 124 | \State a 125 | \State a 126 | \State a 127 | \State a 128 | \State a 129 | \State a 130 | \State a 131 | \State a 132 | \State a 133 | \State a 134 | \State a 135 | \State a 136 | \State a 137 | \State a 138 | \State a 139 | \State a 140 | \State a 141 | \State a 142 | \State a 143 | \State a 144 | \State a 145 | \State a 146 | \State a 147 | \State a 148 | \State a 149 | \State a 150 | \State a 151 | \If{$d > 0$} 152 | \State a 153 | \State a 154 | \State a 155 | \State a 156 | \State a 157 | \State This an extremely long line that does not fit on a single line so it must be broken up. 158 | \State a 159 | \State a 160 | \State a 161 | \ifbool{noEnd}{ 162 | \State a 163 | }{} 164 | \State a 165 | \State $q_{q_{q_q}}$ 166 | \EndIf 167 | \State a 168 | \State $q_{q_{q_q}}$ 169 | \State a 170 | \State a 171 | \State a 172 | \State a 173 | \If{$x > 0$} 174 | \State a 175 | \If{$x > 0$} 176 | \State This an extremely long line that does not fit on a single line so it must be broken up. 177 | \EndIf 178 | \EndIf 179 | \EndIf 180 | \State some line here 181 | \EndIf 182 | %\State last line 183 | \end{algorithmic} 184 | 185 | \newpage 186 | \subsection{Indentation Starts on Last Line} 187 | \begin{algorithmic}[1] 188 | \State first line 189 | \If{$a > 0$} 190 | \State a 191 | \State a 192 | \State a 193 | \State a 194 | \State a 195 | \State a 196 | \State a 197 | \State a 198 | \State a 199 | \State a 200 | \State a 201 | \State a 202 | \State a 203 | \State a 204 | \State a 205 | \State a 206 | \State a 207 | \State a 208 | \State a 209 | \State a 210 | \State a 211 | \State a 212 | \State a 213 | \State a 214 | \State a 215 | \State a 216 | \State a 217 | \State a 218 | \State a 219 | \State a 220 | \State a 221 | \State a 222 | \State a 223 | \State a 224 | \State a 225 | \State a 226 | \State a 227 | \State a 228 | \State a 229 | \State a 230 | \State a 231 | \State a 232 | \State a 233 | \State a 234 | \State a 235 | \If{$b > 0$} 236 | \State a 237 | \State a 238 | \State a 239 | \If{$c > 0$} 240 | \State a 241 | \State a 242 | \State a 243 | \State a 244 | \State a 245 | \EndIf 246 | \EndIf 247 | \EndIf 248 | \end{algorithmic} 249 | 250 | \newpage 251 | \subsection{Indentation Starts on First Line} 252 | \begin{algorithmic}[1] 253 | \State first line 254 | \If{$a > 0$} 255 | \State a 256 | \State a 257 | \State a 258 | \State a 259 | \State a 260 | \State a 261 | \State a 262 | \State a 263 | \State a 264 | \State a 265 | \State a 266 | \State a 267 | \State a 268 | \State a 269 | \State a 270 | \State a 271 | \State a 272 | \State a 273 | \State a 274 | \State a 275 | \State a 276 | \State a 277 | \State a 278 | \State a 279 | \State a 280 | \State a 281 | \State a 282 | \State a 283 | \State a 284 | \State a 285 | \State a 286 | \State a 287 | \State a 288 | \State a 289 | \State a 290 | \State a 291 | \State a 292 | \State a 293 | \State a 294 | \State a 295 | \State a 296 | \State a 297 | \State a 298 | \State a 299 | \State a 300 | \State a 301 | \If{$b > 0$} 302 | \State a 303 | \State a 304 | \State a 305 | \If{$c > 0$} 306 | \State a 307 | \State a 308 | \State a 309 | \State a 310 | \State a 311 | \EndIf 312 | \EndIf 313 | \EndIf 314 | \end{algorithmic} 315 | 316 | \newpage 317 | \subsection{Indentation Ends on First Line} 318 | \begin{algorithmic}[1] 319 | \State first line 320 | \If{$a > 0$} 321 | \State a 322 | \State a 323 | \State a 324 | \State a 325 | \State a 326 | \State a 327 | \State a 328 | \State a 329 | \State a 330 | \State a 331 | \State a 332 | \State a 333 | \State a 334 | \State a 335 | \State a 336 | \State a 337 | \State a 338 | \State a 339 | \State a 340 | \State a 341 | \State a 342 | \State a 343 | \State a 344 | \State a 345 | \State a 346 | \State a 347 | \State a 348 | \State a 349 | \State a 350 | \State a 351 | \State a 352 | \State a 353 | \State a 354 | \State a 355 | \ifbool{noEnd}{ 356 | \State a 357 | }{} 358 | \State a 359 | \State a 360 | \If{$b > 0$} 361 | \State a 362 | \State a 363 | \State a 364 | \If{$c > 0$} 365 | \If{$d > 0$} 366 | \State a 367 | \ElsIf{$e > 0$} 368 | \State a 369 | \State a 370 | \EndIf 371 | \EndIf 372 | \EndIf 373 | \EndIf 374 | \end{algorithmic} 375 | 376 | \newpage 377 | \subsection{Indentation Ends on Last Line} 378 | \begin{algorithmic}[1] 379 | \State first line 380 | \If{$a > 0$} 381 | \State a 382 | \State a 383 | \State a 384 | \State a 385 | \State a 386 | \State a 387 | \State a 388 | \State a 389 | \State a 390 | \State a 391 | \State a 392 | \State a 393 | \State a 394 | \State a 395 | \State a 396 | \State a 397 | \State a 398 | \State a 399 | \State a 400 | \State a 401 | \State a 402 | \State a 403 | \State a 404 | \State a 405 | \State a 406 | \State a 407 | \State a 408 | \State a 409 | \State a 410 | \State a 411 | \State a 412 | \State a 413 | \State a 414 | \State a 415 | \State a 416 | \State a 417 | \State a 418 | \State a 419 | \State a 420 | \State a 421 | \State a 422 | \State a 423 | \State a 424 | \State a 425 | \State a 426 | \State a 427 | \State a 428 | \State a 429 | \State a 430 | \State a 431 | \State a 432 | \State a 433 | \State a 434 | \State a 435 | \State a 436 | \State a 437 | \State a 438 | \State a 439 | \State a 440 | \State a 441 | \State a 442 | \State a 443 | \State a 444 | \State a 445 | \State a 446 | \State a 447 | \State a 448 | \State a 449 | \State a 450 | \State a 451 | \State a 452 | \If{$b > 0$} 453 | \State a 454 | \State a 455 | \State a 456 | \State a 457 | \State a 458 | \State a 459 | \State a 460 | \State a 461 | \State a 462 | \State a 463 | \State a 464 | \State a 465 | \State a 466 | \ifbool{noEnd}{ 467 | \State a 468 | \State a 469 | \State a 470 | }{} 471 | \State a 472 | \State a 473 | \If{$c > 0$} 474 | \State a 475 | \State a 476 | \State a 477 | \State a 478 | \State a 479 | \EndIf 480 | \EndIf 481 | \EndIf 482 | \end{algorithmic} 483 | One line after algorithm. 484 | 485 | \newpage 486 | \subsection{Page Break on EndIf} 487 | \begin{algorithmic}[1] 488 | \State first line 489 | \If{$a > 0$} 490 | \State a 491 | \State a 492 | \State a 493 | \State a 494 | \State a 495 | \State a 496 | \State a 497 | \State a 498 | \State a 499 | \State a 500 | \State a 501 | \State a 502 | \State a 503 | \State a 504 | \State a 505 | \State a 506 | \State a 507 | \State a 508 | \State a 509 | \State a 510 | \State a 511 | \State a 512 | \State a 513 | \State a 514 | \State a 515 | \State a 516 | \State a 517 | \State a 518 | \State a 519 | \State a 520 | \State a 521 | \State a 522 | \State a 523 | \State a 524 | \State a 525 | \State a 526 | \State a 527 | \State a 528 | \State a 529 | \State a 530 | \State a 531 | \State a 532 | \State a 533 | \State a 534 | \State a 535 | \State a 536 | \State a 537 | \State a 538 | \State a 539 | \State a 540 | \State a 541 | \State a 542 | \State a 543 | \State a 544 | \State a 545 | \State a 546 | \State a 547 | \State a 548 | \State a 549 | \State a 550 | \State a 551 | \State a 552 | \State a 553 | \State a 554 | \State a 555 | \State a 556 | \State a 557 | \State a 558 | \State a 559 | \State a 560 | \State a 561 | \State a 562 | \State a 563 | \State a 564 | \State a 565 | \State a 566 | \State a 567 | \State a 568 | \State a 569 | \State a 570 | \State a 571 | \If{$d > 0$} 572 | \State a 573 | \State a 574 | \State a 575 | \State a 576 | \State a 577 | \State a 578 | \State a 579 | \State a 580 | \State a 581 | \State a 582 | \State a 583 | \ifbool{noEnd}{% 584 | \State a 585 | }{}% 586 | \State a 587 | \State q 588 | \EndIf 589 | \State a 590 | \State a 591 | \State a 592 | \State a 593 | \State a 594 | \EndIf 595 | \end{algorithmic} 596 | 597 | \newpage 598 | \subsection{Page Starts with LComment} 599 | \begin{algorithmic}[1] 600 | \State first line 601 | \If{$a > 0$} 602 | \State a 603 | \State a 604 | \State a 605 | \State a 606 | \State a 607 | \State a 608 | \State a 609 | \State a 610 | \State a 611 | \State a 612 | \State a 613 | \State a 614 | \State a 615 | \State a 616 | \State a 617 | \State a 618 | \State a 619 | \State a 620 | \State a 621 | \State a 622 | \State a 623 | \State a 624 | \State a 625 | \State a 626 | \State a 627 | \State a 628 | \State a 629 | \State a 630 | \State a 631 | \State a 632 | \State a 633 | \State a 634 | \State a 635 | \State a 636 | \State a 637 | \State a 638 | \State a 639 | \State a 640 | \State a 641 | \State a 642 | \State a 643 | \State a 644 | \State a 645 | \State a 646 | \State a 647 | \State a 648 | \LComment{This is a comment.} 649 | \State a 650 | \State a 651 | \State a 652 | \State a 653 | \State a 654 | \State a 655 | \State a 656 | \State a 657 | \State a 658 | \State a 659 | \State a 660 | \State a 661 | \State a 662 | \State a 663 | \State a 664 | \State a 665 | \State a 666 | \State a 667 | \State a 668 | \State a 669 | \State a 670 | \State a 671 | \State a 672 | \State a 673 | \State a 674 | \If{$b > 0$} 675 | \State a 676 | \State a 677 | \State a 678 | \State a 679 | \State a 680 | \State a 681 | \State a 682 | \EndIf 683 | \State a 684 | \State a 685 | \State a 686 | \State a 687 | \State a 688 | \EndIf 689 | \end{algorithmic} 690 | 691 | \newpage 692 | \subsection{Multicolumn} 693 | We here test the behavior with page breaks on local multicolumn environments. 694 | \begin{multicols}{3} 695 | \begin{algorithmic}[1] 696 | \State first line 697 | \If{$a > 0$} 698 | \State a 699 | \State a 700 | \State a 701 | \State a 702 | \State a 703 | \State a 704 | \State a 705 | \State a 706 | \State a 707 | \State a 708 | \If{$b > 0$} 709 | \State a 710 | \State a 711 | \State a 712 | \State a 713 | \State a 714 | \State a 715 | \State a 716 | \State a 717 | \State a 718 | \State a 719 | \State a 720 | \State a 721 | \State a 722 | \State a 723 | \State a 724 | \State a 725 | \State a 726 | \State a 727 | \State a 728 | \EndIf 729 | \State a 730 | \State a 731 | \State a 732 | \State a 733 | \State a 734 | \State a 735 | \State a 736 | \EndIf 737 | \end{algorithmic} 738 | \end{multicols} 739 | This was a test to see how the column breaks are handled. 740 | \end{document} -------------------------------------------------------------------------------- /algpseudocodex.tex: -------------------------------------------------------------------------------- 1 | %% algpseudocodex.tex 2 | %% Copyright 2020-2023, 2025 Christian Matt 3 | % 4 | % This work may be distributed and/or modified under the 5 | % conditions of the LaTeX Project Public License, either version 1.3c 6 | % of this license or (at your option) any later version. 7 | % The latest version of this license is in 8 | % http://www.latex-project.org/lppl.txt 9 | % and version 1.3c or later is part of all distributions of LaTeX 10 | % version 2008-05-04 or later. 11 | % 12 | % This work has the LPPL maintenance status `maintained'. 13 | % 14 | % The Current Maintainer of this work is Christian Matt. 15 | % 16 | % This work consists of the files algpseudocodex.sty and algpseudocodex.tex. 17 | 18 | \documentclass[11pt,a4paper,USenglish]{article} 19 | \usepackage[T1]{fontenc} 20 | \usepackage{babel} 21 | \usepackage[utf8]{inputenc} 22 | \usepackage[margin=1.0in]{geometry} 23 | \usepackage{microtype} 24 | \usepackage{xcolor} 25 | \usepackage{algpseudocodex} 26 | 27 | \usepackage[colorlinks,allcolors=blue!70!black]{hyperref} 28 | \usepackage[capitalise,nameinlink,noabbrev,compress]{cleveref} 29 | 30 | \title{\bf{Algpseudocodex Package Documentation}} 31 | \author{Christian Matt \\ \url{https://github.com/chrmatt/algpseudocodex}} 32 | \date{\today\\v1.2.0} 33 | 34 | \begin{document} 35 | 36 | \maketitle 37 | 38 | \begin{abstract} 39 | This package allows typesetting pseudocode in \LaTeX. It is based on \texttt{algpseudocode} from the \texttt{algorithmicx} package and uses the same syntax, but adds several new features and improvements. Notable features include customizable indent guide lines and the ability to draw boxes around parts of the code for highlighting differences. This package also has better support for long code lines spanning several lines and improved comments. 40 | \end{abstract} 41 | 42 | \newpage 43 | 44 | \tableofcontents 45 | 46 | \newpage 47 | 48 | \section{Basic Usage} 49 | To use the package, load it in your preamble: 50 | \begin{verbatim} 51 | \usepackage{algpseudocodex} 52 | \end{verbatim} 53 | 54 | Basic usage is identical to \texttt{algpseudocode} from the \texttt{algorithmicx} package. Pseudocode written for that package should also be compatible with \texttt{algpseudocodex}. 55 | 56 | \subsection{Algorithmic Block} 57 | Pseudocode can be typeset inside a algorithmic blocks: 58 | \begin{verbatim} 59 | \begin{algorithmic}[line numbering] 60 | ... 61 | \end{algorithmic} 62 | \end{verbatim} 63 | The optional argument specifies how lines are numbered. $0$ means no numbering, $n > 0$ means every $n$th line gets a number. The default is $0$, i.e., no line numbers will be typeset if no optional argument is provided. 64 | 65 | \subsection{Simple Statements and Commands} 66 | Statements start with \verb|\State|. The command \verb|\Statex| can be used to start a new line that does not get a new line number. 67 | 68 | The commands \verb|\Return| and \verb|\Output| can be used for return values of functions and outputs. They do not start a new line on their own, so they need to be used together with \verb|\State|. 69 | 70 | The \verb|\Call| command is used for procedure calls. It takes two arguments: The first one is the name of the procedure and the second one are the arguments. 71 | 72 | \subsubsection*{Example} 73 | \begin{minipage}[t]{0.45\textwidth} 74 | \begin{verbatim} 75 | \begin{algorithmic}[1] 76 | \State first line 77 | \Statex continuing first line 78 | \State \Call{Proc}{a1, a2} 79 | \State \Output Hello World! 80 | \end{algorithmic} 81 | \end{verbatim} 82 | \end{minipage} 83 | \hfill 84 | \begin{minipage}[t]{0.45\textwidth} 85 | \begin{algorithmic}[1] 86 | \State first line 87 | \Statex continuing first line 88 | \State \Call{Proc}{a1, a2} 89 | \State \Output Hello World! 90 | \end{algorithmic} 91 | \end{minipage} 92 | 93 | 94 | \subsection{Blocks} 95 | Blocks are used for loops, conditional statements, and functions. Blocks can also be nested within other blocks. 96 | 97 | \subsubsection{While Loop} 98 | \begin{minipage}[t]{0.45\textwidth} 99 | \begin{verbatim} 100 | \While{condition} 101 | \State body 102 | \EndWhile 103 | \end{verbatim} 104 | \end{minipage} 105 | \hfill 106 | \begin{minipage}[t]{0.45\textwidth} 107 | \begin{algorithmic} 108 | \While{condition} 109 | \State body 110 | \EndWhile 111 | \end{algorithmic} 112 | \end{minipage} 113 | 114 | 115 | \subsubsection{For Loop} 116 | \begin{minipage}[t]{0.45\textwidth} 117 | \begin{verbatim} 118 | \For{$n = 1, \dots, 10$} 119 | \State body 120 | \EndFor 121 | \end{verbatim} 122 | \end{minipage} 123 | \hfill 124 | \begin{minipage}[t]{0.45\textwidth} 125 | \begin{algorithmic} 126 | \For{$n = 1, \dots, 10$} 127 | \State body 128 | \EndFor 129 | \end{algorithmic} 130 | \end{minipage} 131 | 132 | \subsubsection{For-All Loop} 133 | \begin{minipage}[t]{0.45\textwidth} 134 | \begin{verbatim} 135 | \ForAll{$n \in \{1, \dots, 10\}$} 136 | \State body 137 | \EndFor 138 | \end{verbatim} 139 | \end{minipage} 140 | \hfill 141 | \begin{minipage}[t]{0.45\textwidth} 142 | \begin{algorithmic} 143 | \ForAll{$n \in \{1, \dots, 10\}$} 144 | \State body 145 | \EndFor 146 | \end{algorithmic} 147 | \end{minipage} 148 | 149 | \subsubsection{Loop} 150 | \begin{minipage}[t]{0.45\textwidth} 151 | \begin{verbatim} 152 | \Loop 153 | \State body 154 | \EndLoop 155 | \end{verbatim} 156 | \end{minipage} 157 | \hfill 158 | \begin{minipage}[t]{0.45\textwidth} 159 | \begin{algorithmic} 160 | \Loop 161 | \State body 162 | \EndLoop 163 | \end{algorithmic} 164 | \end{minipage} 165 | 166 | \subsubsection{Repeat-Until Loop} 167 | \begin{minipage}[t]{0.45\textwidth} 168 | \begin{verbatim} 169 | \Repeat 170 | \State body 171 | \Until{$n > 10$} 172 | \end{verbatim} 173 | \end{minipage} 174 | \hfill 175 | \begin{minipage}[t]{0.45\textwidth} 176 | \begin{algorithmic} 177 | \Repeat 178 | \State body 179 | \Until{$n > 10$} 180 | \end{algorithmic} 181 | \end{minipage} 182 | 183 | \subsubsection{If Statement} 184 | \begin{minipage}[t]{0.45\textwidth} 185 | \begin{verbatim} 186 | \If{condition} 187 | \State body 188 | \ElsIf{condition} 189 | \State body 190 | \Else 191 | \State body 192 | \EndIf 193 | \end{verbatim} 194 | \end{minipage} 195 | \hfill 196 | \begin{minipage}[t]{0.45\textwidth} 197 | \begin{algorithmic} 198 | \If{condition} 199 | \State body 200 | \ElsIf{condition} 201 | \State body 202 | \Else 203 | \State body 204 | \EndIf 205 | \end{algorithmic} 206 | \end{minipage} 207 | 208 | \bigskip 209 | The \verb|\ElsIf| and \verb|\Else| parts are optional. 210 | 211 | 212 | \subsubsection{Procedure} 213 | \begin{minipage}[t]{0.45\textwidth} 214 | \begin{verbatim} 215 | \Procedure{name}{parameters} 216 | \State body 217 | \EndProcedure 218 | \end{verbatim} 219 | \end{minipage} 220 | \hfill 221 | \begin{minipage}[t]{0.45\textwidth} 222 | \begin{algorithmic} 223 | \Procedure{name}{parameters} 224 | \State body 225 | \EndProcedure 226 | \end{algorithmic} 227 | \end{minipage} 228 | 229 | 230 | \subsubsection{Function} 231 | \begin{minipage}[t]{0.45\textwidth} 232 | \begin{verbatim} 233 | \Function{name}{parameters} 234 | \State body 235 | \EndFunction 236 | \end{verbatim} 237 | \end{minipage} 238 | \hfill 239 | \begin{minipage}[t]{0.45\textwidth} 240 | \begin{algorithmic} 241 | \Function{name}{parameters} 242 | \State body 243 | \EndFunction 244 | \end{algorithmic} 245 | \end{minipage} 246 | 247 | \subsubsection{Structure} 248 | \begin{minipage}[t]{0.45\textwidth} 249 | \begin{verbatim} 250 | \Structure{name} 251 | \State body 252 | \EndStructure 253 | \end{verbatim} 254 | \end{minipage} 255 | \hfill 256 | \begin{minipage}[t]{0.45\textwidth} 257 | \begin{algorithmic} 258 | \Structure{name} 259 | \State body 260 | \EndStructure 261 | \end{algorithmic} 262 | \end{minipage} 263 | 264 | \subsubsection{Class} 265 | \begin{minipage}[t]{0.45\textwidth} 266 | \begin{verbatim} 267 | \Class{name} 268 | \State body 269 | \EndClass 270 | \end{verbatim} 271 | \end{minipage} 272 | \hfill 273 | \begin{minipage}[t]{0.45\textwidth} 274 | \begin{algorithmic} 275 | \Class{name} 276 | \State body 277 | \EndClass 278 | \end{algorithmic} 279 | \end{minipage} 280 | 281 | \subsubsection{Properties} 282 | \begin{minipage}[t]{0.45\textwidth} 283 | \begin{verbatim} 284 | \Properties 285 | \State body 286 | \EndProperties 287 | \end{verbatim} 288 | \end{minipage} 289 | \hfill 290 | \begin{minipage}[t]{0.45\textwidth} 291 | \begin{algorithmic} 292 | \Properties 293 | \State body 294 | \EndProperties 295 | \end{algorithmic} 296 | \end{minipage} 297 | 298 | \subsubsection{Methods} 299 | \begin{minipage}[t]{0.45\textwidth} 300 | \begin{verbatim} 301 | \Methods 302 | \State body 303 | \EndMethods 304 | \end{verbatim} 305 | \end{minipage} 306 | \hfill 307 | \begin{minipage}[t]{0.45\textwidth} 308 | \begin{algorithmic} 309 | \Methods 310 | \State body 311 | \EndMethods 312 | \end{algorithmic} 313 | \end{minipage} 314 | 315 | \subsection{Require and Ensure} 316 | To specify conditions on the inputs and outputs of an algorithm, \verb|\Require| and \verb|\Ensure| can be used. 317 | 318 | \subsubsection*{Example} 319 | \begin{minipage}[t]{0.45\textwidth} 320 | \begin{verbatim} 321 | \begin{algorithmic}[1] 322 | \Require $x \in \{0,1\}$ 323 | \Ensure $y \in \{1,2\}$ 324 | \State $y \gets x+1$ 325 | \State \Return $y$ 326 | \end{algorithmic} 327 | \end{verbatim} 328 | \end{minipage} 329 | \hfill 330 | \begin{minipage}[t]{0.45\textwidth} 331 | \begin{algorithmic}[1] 332 | \Require $x \in \{0,1\}$ 333 | \Ensure $y \in \{1,2\}$ 334 | \State $y \gets x+1$ 335 | \State \Return $y$ 336 | \end{algorithmic} 337 | \end{minipage} 338 | 339 | 340 | \subsection{Comments} 341 | There are two ways to typeset code comments: The command \verb|\Comment| can be used to add shorts comments to the end of the current line. The command \verb|\LComment| can be used to typeset long comments that can span multiple lines. Comments with \verb|\LComment| start on a new line. 342 | 343 | \subsubsection*{Example} 344 | \begin{minipage}[t]{0.45\textwidth} 345 | \begin{verbatim} 346 | \begin{algorithmic}[1] 347 | \State $x \gets y^2$ 348 | \LComment{The next two lines 349 | increment both $x$ and $y$.} 350 | \State $x \gets x + 1$ 351 | \Comment{Increment $x$.} 352 | \State $y \gets y + 1$ 353 | \Comment{Increment $y$.} 354 | \end{algorithmic} 355 | \end{verbatim} 356 | \end{minipage} 357 | \hfill 358 | \begin{minipage}[t]{0.45\textwidth} 359 | \begin{algorithmic}[1] 360 | \State $x \gets y^2$ 361 | \LComment{The next two lines 362 | increment both $x$ and $y$.} 363 | \State $x \gets x + 1$ 364 | \Comment{Increment $x$.} 365 | \State $y \gets y + 1$ 366 | \Comment{Increment $y$.} 367 | \end{algorithmic} 368 | \end{minipage} 369 | 370 | 371 | \section{Boxes} 372 | A unique feature of the \texttt{algpseudocodex} package is the ability to draw boxes around pieces of code. There are two different methods to do so: One for drawing boxes around multiple lines of code, and another one for drawing a box around a string on a single line of code. 373 | 374 | \subsection{Boxes Around Multiple Lines of Code} 375 | The command \verb|\BeginBox[style]| is used to set the beginning of the box. The optional argument determines the style of the drawn box. The boxes are drawn using TikZ, so any TikZ style can be used. The default style can be changed as described in \cref{sec:defBoxStyle}. 376 | The command \verb|\EndBox| is used to set the end of the last started box. Boxes can be nested arbitrarily, but every \verb|\BeginBox| needs a matching \verb|\EndBox|. 377 | 378 | \subsubsection*{Example} 379 | \begin{minipage}[t]{0.45\textwidth} 380 | \begin{verbatim} 381 | \begin{algorithmic} 382 | \BeginBox 383 | \State first line 384 | \BeginBox[fill=yellow] 385 | \State second line 386 | \State another line 387 | \EndBox 388 | \EndBox 389 | \BeginBox[draw=blue,dashed] 390 | \State last line 391 | \EndBox 392 | \end{algorithmic} 393 | \end{verbatim} 394 | \end{minipage} 395 | \hfill 396 | \begin{minipage}[t]{0.45\textwidth} 397 | \begin{algorithmic} 398 | \BeginBox 399 | \State first line 400 | \BeginBox[fill=yellow] 401 | \State second line 402 | \State another line 403 | \EndBox 404 | \EndBox 405 | \BeginBox[draw=blue,dashed] 406 | \State last line 407 | \EndBox 408 | \end{algorithmic} 409 | \end{minipage} 410 | 411 | 412 | \subsection{Boxes Inside Single Line} 413 | The command \verb|\BoxedString[style]{text}| is used to typeset text with a box around it. The optional argument determines the style of the box, as in \verb|\BeginBox|. The default style is the same as for \verb|\BeginBox|. 414 | 415 | \subsubsection*{Example} 416 | \begin{minipage}[t]{0.45\textwidth} 417 | \begin{verbatim} 418 | \begin{algorithmic} 419 | \State first line 420 | \State second line with 421 | \BoxedString[fill=yellow]{box} 422 | \State last line 423 | \end{algorithmic} 424 | \end{verbatim} 425 | \end{minipage} 426 | \hfill 427 | \begin{minipage}[t]{0.45\textwidth} 428 | \begin{algorithmic} 429 | \State first line 430 | \State second line with 431 | \BoxedString[fill=yellow]{box} 432 | \State last line 433 | \end{algorithmic} 434 | \end{minipage} 435 | 436 | 437 | \section{Package Options} 438 | When loading \texttt{algpseudocodex} the options describe in this section can be set. They syntax for setting \verb|option1| to \verb|value1| and \verb|option2| to \verb|value2| is: 439 | \begin{verbatim} 440 | \usepackage[option1=value1,option2=value2]{algpseudocodex} 441 | \end{verbatim} 442 | 443 | \subsection{noEnd} 444 | \begin{description} 445 | \item[possible values:] \verb|true|, \verb|false| 446 | \item[default:] \verb|true| 447 | \end{description} 448 | If \verb|false|, the end of blocks are marked with the expression ``end'' followed by the name of the block. 449 | 450 | \subsubsection*{Example} 451 | \begin{minipage}[t]{0.45\textwidth} 452 | \verb|noEnd=false|: 453 | \begin{algorithmic} 454 | % redefine if commands here to handle noEnd = false 455 | \makeatletter 456 | \setbool{algpx@noEnd}{false}% 457 | \let\If\undefined% 458 | \let\EndIf\undefined% 459 | \algdef{SE}[IF]{If}{EndIf}[1]{% 460 | \algpx@startCodeCommand\algpx@startIndent\algorithmicif\ #1\ \algorithmicthen% 461 | }{% 462 | \algpx@startEndBlockCommand\algpx@endIndent\algorithmicend\ \algorithmicif% 463 | } 464 | \pretocmd{\If}{\algpx@endCodeCommand}{}{}% 465 | \pretocmd{\EndIf}{\algpx@endCodeCommand[0]}{}{}% 466 | \makeatother 467 | \If{$x > 0$} 468 | \State $x \gets x - 1$ 469 | \EndIf 470 | \end{algorithmic} 471 | \end{minipage} 472 | \hfill 473 | \begin{minipage}[t]{0.45\textwidth} 474 | \verb|noEnd=true|: 475 | \begin{algorithmic} 476 | \If{$x > 0$} 477 | \State $x \gets x - 1$ 478 | \EndIf 479 | \end{algorithmic} 480 | \end{minipage} 481 | 482 | 483 | \subsection{indLines} 484 | \begin{description} 485 | \item[possible values:] \verb|true|, \verb|false| 486 | \item[default:] \verb|true| 487 | \end{description} 488 | If \verb|true|, indent guide lines are drawn. The style of the lines can be customized as described in \cref{sec:indStyle}. 489 | 490 | \subsubsection*{Example} 491 | \begin{minipage}[t]{0.45\textwidth} 492 | \verb|indLines=false|: 493 | \begin{algorithmic} 494 | \makeatletter 495 | \setbool{algpx@indLines}{false}% 496 | \makeatother 497 | \If{$x > 0$} 498 | \State $x \gets x - 1$ 499 | \EndIf 500 | \end{algorithmic} 501 | \end{minipage} 502 | \hfill 503 | \begin{minipage}[t]{0.45\textwidth} 504 | \verb|indLines=true|: 505 | \begin{algorithmic} 506 | \If{$x > 0$} 507 | \State $x \gets x - 1$ 508 | \EndIf 509 | \end{algorithmic} 510 | \end{minipage} 511 | 512 | 513 | \subsection{spaceRequire} 514 | \begin{description} 515 | \item[possible values:] \verb|true|, \verb|false| 516 | \item[default:] \verb|true| 517 | \end{description} 518 | If \verb|true|, vertical space is added before every \verb|\Require| except the one on the first line. This is useful for specifying different behaviors depending on the provided input. 519 | 520 | \subsubsection*{Example} 521 | \begin{minipage}[t]{0.45\textwidth} 522 | \verb|spaceRequire=false|: 523 | \begin{algorithmic} 524 | \makeatletter 525 | \setbool{algpx@spaceRequire}{false}% 526 | \makeatother 527 | \Require $x \in \{0,1\}$ 528 | \State \Return $x$ 529 | \Require $x \in \{1,2\}$ 530 | \State \Return $x-1$ 531 | \end{algorithmic} 532 | \end{minipage} 533 | \hfill 534 | \begin{minipage}[t]{0.45\textwidth} 535 | \verb|spaceRequire=true|: 536 | \begin{algorithmic} 537 | \Require $x \in \{0,1\}$ 538 | \State \Return $x$ 539 | \Require $x \in \{1,2\}$ 540 | \State \Return $x-1$ 541 | \end{algorithmic} 542 | \end{minipage} 543 | 544 | 545 | \subsection{italicComments} 546 | \begin{description} 547 | \item[possible values:] \verb|true|, \verb|false| 548 | \item[default:] \verb|true| 549 | \end{description} 550 | If \verb|true|, all comments are typeset in italic font. If \verb|false|, comments are typeset in roman font. 551 | 552 | \subsubsection*{Example} 553 | \begin{minipage}[t]{0.45\textwidth} 554 | \verb|italicComments=false|: 555 | \begin{algorithmic} 556 | \makeatletter 557 | \setbool{algpx@italicComments}{false}% 558 | \makeatother 559 | \LComment{Long comment.} 560 | \State $x \gets 0$ \Comment{Short comment.} 561 | \end{algorithmic} 562 | \end{minipage} 563 | \hfill 564 | \begin{minipage}[t]{0.45\textwidth} 565 | \verb|italicComments=true|: 566 | \begin{algorithmic} 567 | \LComment{Long comment.} 568 | \State $x \gets 0$ \Comment{Short comment.} 569 | \end{algorithmic} 570 | \end{minipage} 571 | 572 | 573 | \subsection{rightComments} 574 | \begin{description} 575 | \item[possible values:] \verb|true|, \verb|false| 576 | \item[default:] \verb|true| 577 | \end{description} 578 | If \verb|true|, comments typeset with \verb|\Comment| are right justified on the current line. If a comment does not fit on the current line, no justification is applied. If \verb|false|, all comments are typeset right after the end of the current line. 579 | 580 | Does not affect long comments typeset with \verb|\LComment|. 581 | 582 | \subsubsection*{Example} 583 | \begin{minipage}[t]{0.45\textwidth} 584 | \verb|rightComments=false|: 585 | \begin{algorithmic} 586 | \makeatletter 587 | \setbool{algpx@rightComments}{false}% 588 | \makeatother 589 | \LComment{No effect on long comments.} 590 | \State $x \gets 0$ \Comment{Short comment.} 591 | \State $x \gets x^2$ \Comment{Does not fit on the current line and is thus not justified.} 592 | \end{algorithmic} 593 | \end{minipage} 594 | \hfill 595 | \begin{minipage}[t]{0.45\textwidth} 596 | \verb|rightComments=true|: 597 | \begin{algorithmic} 598 | \LComment{No effect on long comments.} 599 | \State $x \gets 0$ \Comment{Short comment.} 600 | \State $x \gets x^2$ \Comment{Does not fit on the current line and is thus not justified.} 601 | \end{algorithmic} 602 | \end{minipage} 603 | 604 | 605 | \subsection{commentColor} 606 | \begin{description} 607 | \item[possible values:] Any color that can be used in \verb|\textcolor|. 608 | \item[default:] \verb|gray| 609 | \end{description} 610 | Defines the color in which comments are typeset. 611 | 612 | \subsubsection*{Example} 613 | \begin{minipage}[t]{0.45\textwidth} 614 | \verb|commentColor=black|: 615 | \begin{algorithmic} 616 | \makeatletter 617 | \renewcommand{\algpx@commentColor}{black}% 618 | \makeatother 619 | \LComment{Long comment.} 620 | \State $x \gets 0$ \Comment{Short comment.} 621 | \end{algorithmic} 622 | \end{minipage} 623 | \hfill 624 | \begin{minipage}[t]{0.45\textwidth} 625 | \verb|commentColor=blue|: 626 | \begin{algorithmic} 627 | \makeatletter 628 | \renewcommand{\algpx@commentColor}{blue}% 629 | \makeatother 630 | \LComment{Long comment.} 631 | \State $x \gets 0$ \Comment{Short comment.} 632 | \end{algorithmic} 633 | \end{minipage} 634 | 635 | 636 | \subsection{beginComment and endComment} 637 | \begin{description} 638 | \item[possible values:] Any string that can be typeset in text mode. 639 | \item[default:] \verb|$\triangleright$~| and (empty) 640 | \end{description} 641 | Used to indicate the beginning and end of comments typeset with \verb|\Comment|, respectively. 642 | 643 | \subsubsection*{Example} 644 | \begin{minipage}[t]{0.45\textwidth} 645 | \verb|beginComment=//~|: 646 | \begin{algorithmic} 647 | \makeatletter 648 | \renewcommand{\algpx@beginComment}{//~}% 649 | \makeatother 650 | \LComment{Long comment.} 651 | \State $x \gets 0$ \Comment{Short comment.} 652 | \end{algorithmic} 653 | \end{minipage} 654 | \hfill 655 | \begin{minipage}[t]{0.45\textwidth} 656 | \verb|beginComment=/*~|, \verb|endComment=~*/|: 657 | \begin{algorithmic} 658 | \makeatletter 659 | \renewcommand{\algpx@beginComment}{/*~}% 660 | \renewcommand{\algpx@endComment}{~*/}% 661 | \makeatother 662 | \LComment{Long comment.} 663 | \State $x \gets 0$ \Comment{Short comment.} 664 | \end{algorithmic} 665 | \end{minipage} 666 | 667 | \subsection{beginLComment and endLComment} 668 | \begin{description} 669 | \item[possible values:] Any string that can be typeset in text mode. 670 | \item[default:] \verb|$\triangleright$~| and \verb|~$\triangleleft$| 671 | \end{description} 672 | Used to indicate the beginning and end of long comments typeset with \verb|\LComment|, respectively. 673 | \subsubsection*{Example} 674 | \begin{minipage}[t]{0.45\textwidth} 675 | \verb|beginLComment=/*~|, \verb|endLComment=~*/|: 676 | \begin{algorithmic} 677 | \makeatletter 678 | \renewcommand{\algpx@beginLComment}{/*~}% 679 | \renewcommand{\algpx@endLComment}{~*/}% 680 | \makeatother 681 | \LComment{Long comment.} 682 | \State $x \gets 0$ \Comment{Short comment.} 683 | \end{algorithmic} 684 | \end{minipage} 685 | 686 | 687 | \section{Customization} 688 | \subsection{Style of Indent Guide Lines}\label{sec:indStyle} 689 | Indent guide lines are drawn using TikZ and consequently any TikZ style can be used. To set the style, use: 690 | \begin{verbatim} 691 | \tikzset{algpxIndentLine/.style={style}} 692 | \end{verbatim} 693 | The default style is \verb|draw=gray,very thin|. 694 | 695 | \subsubsection*{Example} 696 | \verb|algpxIndentLine/.style={draw=blue,dashed}|: 697 | \begin{algorithmic} 698 | \tikzset{algpxIndentLine/.style={draw=blue,dashed}} 699 | \If{$x > 0$} 700 | \State $x \gets x - 1$ 701 | \EndIf 702 | \end{algorithmic} 703 | 704 | 705 | \subsection{Default Style of Boxes}\label{sec:defBoxStyle} 706 | Boxes are drawn using TikZ and consequently any TikZ style can be used. To set the default style, use: 707 | \begin{verbatim} 708 | \tikzset{algpxDefaultBox/.style={style}} 709 | \end{verbatim} 710 | The default style is \verb|draw|. 711 | 712 | 713 | \subsection{Changing Keywords} 714 | As in the \texttt{algorithmicx} package, keywords can be renamed using the syntax: 715 | \begin{verbatim} 716 | \algrenewcommand\keyword{new name} 717 | \end{verbatim} 718 | The following keywords can be customized: 719 | \begin{itemize} 720 | \item \verb|\algorithmicend| 721 | \hfill Default: \verb|\textbf{end}| 722 | \item \verb|\algorithmicdo| 723 | \hfill Default: \verb|\textbf{do}| 724 | \item \verb|\algorithmicwhile| 725 | \hfill Default: \verb|\textbf{while}| 726 | \item \verb|\algorithmicfor| 727 | \hfill Default: \verb|\textbf{for}| 728 | \item \verb|\algorithmicforall| 729 | \hfill Default: \verb|\textbf{for all}| 730 | \item \verb|\algorithmicloop| 731 | \hfill Default: \verb|\textbf{loop}| 732 | \item \verb|\algorithmicrepeat| 733 | \hfill Default: \verb|\textbf{repeat}| 734 | \item \verb|\algorithmicuntil| 735 | \hfill Default: \verb|\textbf{until}| 736 | \item \verb|\algorithmicprocedure| 737 | \hfill Default: \verb|\textbf{procedure}| 738 | \item \verb|\algorithmicfunction| 739 | \hfill Default: \verb|\textbf{function}| 740 | \item \verb|\algorithmicif| 741 | \hfill Default: \verb|\textbf{if}| 742 | \item \verb|\algorithmicthen| 743 | \hfill Default: \verb|\textbf{then}| 744 | \item \verb|\algorithmicelse| 745 | \hfill Default: \verb|\textbf{else}| 746 | \item \verb|\algorithmicrequire| 747 | \hfill Default: \verb|\textbf{Require:}| 748 | \item \verb|\algorithmicensure| 749 | \hfill Default: \verb|\textbf{Ensure:}| 750 | \item \verb|\algorithmicreturn| 751 | \hfill Default: \verb|\textbf{return}| 752 | \item \verb|\algorithmicoutput| 753 | \hfill Default: \verb|\textbf{output}| 754 | \item \verb|\algorithmicstructure| 755 | \hfill Default: \verb|\textbf{structure}| 756 | \item \verb|\algorithmicclass| 757 | \hfill Default: \verb|\textbf{class}| 758 | \item \verb|\algorithmicproperties| 759 | \hfill Default: \verb|\textbf{properties}| 760 | \item \verb|\algorithmicmethods| 761 | \hfill Default: \verb|\textbf{methods}| 762 | \end{itemize} 763 | 764 | \section{Revision History} 765 | 766 | \subsection*{v1.2.0 (2025-04-16)} 767 | \begin{itemize} 768 | \item Added support for classes, structures, properties, and methods. 769 | \end{itemize} 770 | 771 | \subsection*{v1.1.2 (2023-04-17)} 772 | \begin{itemize} 773 | \item Fixed issue with resetting value of lineskiplimit. 774 | \end{itemize} 775 | 776 | \subsection*{v1.1.1 (2023-04-16)} 777 | \begin{itemize} 778 | \item Fixed issue with resetting value of lineskip. 779 | \end{itemize} 780 | 781 | \subsection*{v1.1.0 (2023-02-17)} 782 | \begin{itemize} 783 | \item Added support for indent guide lines spanning multiple pages. 784 | \end{itemize} 785 | 786 | \subsection*{v1.0.2 (2022-10-07)} 787 | \begin{itemize} 788 | \item Fixed bug with incorrectly ended indent block for nested statements. 789 | \end{itemize} 790 | 791 | \subsection*{v1.0.1 (2021-12-05)} 792 | \begin{itemize} 793 | \item Fixed bug regarding alignment of comments after end if, end for etc. 794 | \end{itemize} 795 | 796 | \subsection*{v1.0 (2020-08-16)} 797 | \begin{itemize} 798 | \item Initial release. 799 | \end{itemize} 800 | 801 | \end{document} 802 | -------------------------------------------------------------------------------- /algpseudocodex.sty: -------------------------------------------------------------------------------- 1 | %% algpseudocodex.sty 2 | %% Copyright 2017, 2020-2023, 2025 Christian Matt 3 | % 4 | % This work may be distributed and/or modified under the 5 | % conditions of the LaTeX Project Public License, either version 1.3c 6 | % of this license or (at your option) any later version. 7 | % The latest version of this license is in 8 | % http://www.latex-project.org/lppl.txt 9 | % and version 1.3c or later is part of all distributions of LaTeX 10 | % version 2008-05-04 or later. 11 | % 12 | % This work has the LPPL maintenance status `maintained'. 13 | % 14 | % The Current Maintainer of this work is Christian Matt. 15 | % 16 | % This work consists of the files algpseudocodex.sty and algpseudocodex.tex. 17 | 18 | 19 | % Pseudocodex algorithmic style 20 | % Based on Szasz Janos' algpseudocode.sty 21 | 22 | \NeedsTeXFormat{LaTeX2e} 23 | \ProvidesPackage{algpseudocodex}[2025-04-16 v1.2.0 pseudocode typesetting] 24 | \RequirePackage{kvoptions} 25 | \RequirePackage{algorithmicx} 26 | \RequirePackage{etoolbox} 27 | \RequirePackage{fifo-stack} 28 | \RequirePackage{varwidth} 29 | \RequirePackage{tabto} 30 | \RequirePackage{totcount} 31 | \RequirePackage{tikz} 32 | \usetikzlibrary{calc,fit,tikzmark} 33 | 34 | 35 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 36 | % Package options 37 | % 38 | \SetupKeyvalOptions{% 39 | family=algpx,% 40 | prefix=algpx@% 41 | } 42 | 43 | \DeclareBoolOption[true]{noEnd}% don't print end if etc. 44 | \DeclareBoolOption[true]{indLines}% show indent guide lines 45 | \DeclareBoolOption[true]{spaceRequire}% adds vertical space before \Require if not in first line 46 | \DeclareBoolOption[true]{italicComments}% italicise comments 47 | \DeclareBoolOption[true]{rightComments}% right justify comments 48 | \DeclareStringOption[gray]{commentColor}% color of comments 49 | \DeclareStringOption[$\triangleright$~]{beginComment}% print at beginning of comment 50 | \DeclareStringOption[]{endComment}% print at end of comment 51 | \DeclareStringOption[$\triangleright$~]{beginLComment}% print at beginning of long comment 52 | \DeclareStringOption[~$\triangleleft$]{endLComment}% print at end of long comment 53 | \ProcessLocalKeyvalOptions* 54 | 55 | 56 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 57 | % Styles 58 | % 59 | \tikzset{% 60 | algpxDefaultBox/.style={draw},% 61 | algpxIndentLine/.style={draw=gray,very thin}% 62 | } 63 | 64 | 65 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 66 | % Declarations 67 | % 68 | \algnewlanguage{pseudocodex} 69 | \alglanguage{pseudocodex} 70 | 71 | % \tikzmark is only available on next compilation; the following command immediately after using it 72 | \newcommand{\@tikzmarkNow}[2][]{\tikz[overlay,remember picture] \node[#1] (#2) {};} 73 | 74 | \long\def\@ifnodedefined#1#2#3{% 75 | \@ifundefined{pgf@sh@ns@#1}{#3}{#2}% 76 | } 77 | 78 | \newlength{\algpx@codeBoxInnerSep}% distance between box and its content 79 | \newlength{\algpx@codeBoxSep}% distance between nested boxes 80 | \newlength{\algpx@codeBoxOuterSep}% additional space before and after box 81 | 82 | % the following lengths related to indent lines are set when opening an algorithmic environment to reflect to current font size 83 | \newlength{\algpx@indShiftX}% indent line shifted right by that amount from beginning of line 84 | \newlength{\algpx@indStartShiftY}% start of indent line shifted up by that amount from beginning of line 85 | \newlength{\algpx@indEndShiftY}% end of indent line shifted up by that amount from beginning of line (only if noEnd=false, otherwise no shift) 86 | \newlength{\algpx@indXLineLength}% length of horizonal line drawn at end when noEnd=true 87 | \newlength{\algpx@minIndDist}% minimum distance between start and end of indent line to draw line 88 | \newlength{\algpx@oldPos} 89 | \newlength{\algpx@newPos} 90 | \newlength{\algpx@tmpLen}% length to be used for various things 91 | \newlength{\algpx@currentLineskiplimit}% used to restore lineskiplimit in varwidth 92 | \newlength{\algpx@currentLineskip}% used to restore lineskip in varwidth 93 | \newlength{\algpx@indStartY} 94 | \newlength{\algpx@indEndY} 95 | \newlength{\algpx@indStartX}% x coordinate of indent line 96 | \newlength{\algpx@extraShiftX}% current line is shifted by this amount right 97 | \newlength{\algpx@minTopPageHeight}% minimum for setting height of first line on page (used, e.g., to draw indent lines on page break) 98 | \newlength{\algpx@minBotPageDepth}% minimum for setting depth of last line on page (used, e.g., to draw indent lines on page break) 99 | 100 | \setlength{\algpx@codeBoxInnerSep}{2pt} 101 | \setlength{\algpx@codeBoxSep}{3pt} 102 | \setlength{\algpx@codeBoxOuterSep}{1pt} 103 | \settoheight{\algpx@minTopPageHeight}{\footnotesize9}% account for line numbers, which use \footnotesize 104 | \settodepth{\algpx@minBotPageDepth}{\footnotesize9}% account for line numbers, which use \footnotesize 105 | 106 | \newbool{algpx@firstLine} 107 | \newbool{algpx@setNorth}% whether codeBoxNorth should be set 108 | \newbool{algpx@executeEndVarwidth} 109 | \newbool{algpx@adjustHeight} 110 | \newbool{algpx@restorePrevdepth} 111 | \newbool{algpx@hasCheckedPageBreak}% whether checkPageBreak has been executed in current environment 112 | \newbool{algpx@indJustEnded}% true after end with noend 113 | \newbool{algpx@pageJustBroken}% 114 | 115 | \newcounter{algpx@codeBoxCount}% number of already created code boxes. Used to fill algpx@startNewCodeBoxQueue 116 | \newcounter{algpx@nestedCBoxCount} 117 | \newcounter{algpx@startedBoxesCount} 118 | \newcounter{algpx@endedBoxesCount} 119 | \newcounter{algpx@nestedBoxedStringCount} 120 | \newcounter{algpx@nestedBoxedStringMaxCount} 121 | \newcounter{algpx@indentCount} 122 | \newcounter{algpx@lastIndentEnded} 123 | \newcounter{algpx@pageCount}% counter of "pages" (columns in multi column format); incremented when page break is detected 124 | \newcounter{algpx@tmpCount}% temporary counter 125 | 126 | \FSCreate{algpx@startNewCodeBoxQueue}{0}% queue of code boxes to be created on next \State, \If etc. Only stores index of box (0 is value of top if empty; should not be relevant) 127 | \FSCreate{algpx@codeBoxStack}{0} 128 | \FSCreate{algpx@codeBoxStackTmp}{0} 129 | \FSCreate{algpx@indentStack}{0} 130 | \FSCreate{algpx@indentStackTmp}{0} 131 | 132 | \newsavebox{\algpx@boxedStringBox} 133 | 134 | 135 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 136 | % Macros for boxes around code 137 | % 138 | % Draw a box. First parameter is style, others are coordinates (north, west, east, south) 139 | \newcommand{\algpx@drawCodeBox}[5]{% 140 | \tikz[overlay,remember picture]{% 141 | \node[inner sep=\algpx@codeBoxInnerSep,#1,fit={(pic cs:#2) (pic cs:#3) (pic cs:#4) (pic cs:#5)}] {};% 142 | }% 143 | } 144 | 145 | % execute after \State, \If etc. 146 | \newcommand{\algpx@startCodeCommand}{% 147 | \algpx@startCodeCommandX{}{}% 148 | } 149 | 150 | % execute before printing end if etc. 151 | \newcommand{\algpx@startEndBlockCommand}{% 152 | % add space for indentation because of how ALG@nested is computed 153 | \algpx@startCodeCommandX[1]{}{\hspace*{\algorithmicindent}}% 154 | } 155 | 156 | % extended version of \algpx@startCodeCommand 157 | % first argument 1 if executed in \algpx@startEndBlockCommand 158 | % second argument is printed before content 159 | % third argument is used to reserve space after contents (for end symbol of long comments) 160 | \newcommand{\algpx@startCodeCommandX}[3][0]{% 161 | \setbool{algpx@indJustEnded}{false}% 162 | \setcounter{algpx@startedBoxesCount}{0}% 163 | \setcounter{algpx@endedBoxesCount}{0}% 164 | \setcounter{algpx@nestedBoxedStringMaxCount}{0}% 165 | \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@startNewCodeBoxQueue}}}}{% 166 | \FSPush{algpx@codeBoxStack}{\FSTop{algpx@startNewCodeBoxQueue}}% 167 | \algpx@drawCodeBox{algpx@codeBoxStyle-\FSTop{algpx@startNewCodeBoxQueue}}{algpx@codeBoxNorth-\FSTop{algpx@startNewCodeBoxQueue}}{algpx@codeBoxWest-\FSTop{algpx@startNewCodeBoxQueue}}{algpx@codeBoxEast-\FSTop{algpx@startNewCodeBoxQueue}}{algpx@codeBoxSouth-\FSTop{algpx@startNewCodeBoxQueue}}% 168 | \FSPop{algpx@startNewCodeBoxQueue}% 169 | \setbool{algpx@setNorth}{true}% 170 | \stepcounter{algpx@startedBoxesCount}% 171 | }% 172 | \algpx@setCodeBoxWest% 173 | % check for page break only if indent line is open because page breaks are only used for this 174 | \ifboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@indentStack}}}}{% 175 | \algpx@checkPageBreak[#1]% 176 | }{}% 177 | \setbool{algpx@firstLine}{false}% 178 | \setbool{algpx@executeEndVarwidth}{true}% 179 | #2% 180 | % create box from here to end of line, leaving space for #3 181 | \settowidth{\algpx@extraShiftX}{#2}% remember that line actually starts further right than last box 182 | \settowidth{\algpx@tmpLen}{#3}% 183 | \setlength{\algpx@currentLineskiplimit}{\lineskiplimit}% remember value of lineskiplimit 184 | \setlength{\algpx@currentLineskip}{\lineskip}% remember value of lineskip 185 | \begin{varwidth}[t]{\dimexpr \linewidth - \algpx@extraShiftX - \algpx@tmpLen - \algorithmicindent * \numexpr \value{ALG@nested} - 1 \relax \relax}% 186 | \setlength{\lineskiplimit}{\algpx@currentLineskiplimit}% restore lineskiplimit value 187 | \setlength{\lineskip}{\algpx@currentLineskip}% restore lineskip value 188 | } 189 | 190 | % executed before \State, \If etc., i.e., at end of previous line 191 | % first argument 1 if after \EndIf etc. and noend 192 | \newcommand{\algpx@endCodeCommand}[1][0]{% 193 | \ifbool{algpx@executeEndVarwidth}{% 194 | \par\xdef\algpx@pdtemp{\the\prevdepth}% see https://tex.stackexchange.com/a/34982 195 | \end{varwidth}\setbox0=\lastbox\usebox0% 196 | \setbool{algpx@executeEndVarwidth}{false}% 197 | \setbool{algpx@adjustHeight}{true}% 198 | \setbool{algpx@restorePrevdepth}{true}% 199 | }{}% 200 | \ifbool{algpx@setNorth}{% 201 | % todo: north should not be set again if highest element in current line is BoxedString 202 | \algpx@setCodeBoxNorth{\the\ht0}% set north here shifted by height of current line 203 | \setbool{algpx@setNorth}{false}% 204 | }{}% 205 | \algpx@setCodeBoxEast% 206 | % remember position of ending line and possibly set north of page 207 | % not necessary if no indent lines are open or just ended (because EndIf with noEnd cannot break page) 208 | \ifboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@indentStack}}} and not bool{algpx@indJustEnded}}{% 209 | \algpx@setLineEndPos% 210 | }{}% 211 | \ifbool{algpx@adjustHeight}{% 212 | % todo: if highest or deepest element in current line is BoxedString, \ht0 or \dp0 should be adjusted for different sep values 213 | \algpx@addBoxSpacing{\value{algpx@startedBoxesCount}}{\the\ht0}{\value{algpx@endedBoxesCount}}{\the\dp0}% 214 | \setbool{algpx@adjustHeight}{false}% 215 | }{}% 216 | \ifboolexpr{bool{algpx@restorePrevdepth} and test{\ifstrequal{#1}{0}}}{% 217 | \par\prevdepth\algpx@pdtemp% 218 | \setbool{algpx@restorePrevdepth}{false}% 219 | }{}% 220 | } 221 | 222 | % Checks whether current line starts on new page (or column) by comparing y position with previous line. 223 | % If so, draws indent lines neither starting nor ending on this page. 224 | % Optional argument is 1 if executed on end block with noEnd=false. 225 | % 226 | % Note: We do not rely on \iftikzmarkonpage because, e.g., in double-column format, lines can be on the same page, 227 | % but we want to consider them to be on different pages. 228 | \newcommand{\algpx@checkPageBreak}[1][0]{% 229 | \ifbool{algpx@hasCheckedPageBreak}{% first line of code cannot be on new page 230 | % extract y positions of previous line 231 | \tikz[overlay,remember picture]{% 232 | \pgfextracty{\algpx@oldPos}{\pgfpointanchor{algpx@currentStartYPos}{center}}% 233 | \global\algpx@oldPos=\algpx@oldPos% 234 | }% 235 | % current pos is 0, so if last pos is less than that, we are on new page 236 | \ifdimcomp{\algpx@oldPos}{<}{0ex}{% 237 | % set south of previous page to y pos last saved in \algpx@setLineEndPos 238 | \tikz[overlay,remember picture]{% 239 | \tikzmark{algpx@pageSouth-\thealgpx@pageCount}{(algpx@currentEndYPos)}% 240 | }% 241 | \stepcounter{algpx@pageCount}% 242 | \setbool{algpx@pageJustBroken}{true}% 243 | % all currently open indent lines have started on earlier page. 244 | % Draw full line from top to bottom for all of those not ending on this page either 245 | \algpx@drawIndentLinesOnPageBreak[#1]% 246 | }{% 247 | \tikz[overlay,remember picture]{}% dummy to keep in sync 248 | \tikz[overlay,remember picture]{}% dummy to keep in sync (inside drawIndentLinesOnPageBreak) 249 | }% 250 | }{}% 251 | \@tikzmarkNow{algpx@currentStartYPos}% save y position of current line to compare next time 252 | \setbool{algpx@hasCheckedPageBreak}{true}% 253 | } 254 | 255 | % Remember current position as south of page and set north of current page if page was just broken. 256 | \newcommand{\algpx@setLineEndPos}{% 257 | % save y position of current line shifted down the depth of current line to later use for pageSouth coordinate in \algpx@checkPageBreak 258 | % shift down at least by \algpx@minBotPageDepth 259 | \ifdimcomp{\the\dp0}{<}{\algpx@minBotPageDepth}{% 260 | \@tikzmarkNow[yshift=-\algpx@minBotPageDepth]{algpx@currentEndYPos}% 261 | }{% 262 | \@tikzmarkNow[yshift=-\the\dp0]{algpx@currentEndYPos}% 263 | }% 264 | % right after pagebreak, set north of current page 265 | \ifbool{algpx@pageJustBroken}{% 266 | % shift to beginning of line and also shift up by height of current line, but last least \algpx@minTopPageHeight 267 | % also shift to left by \wd0 (width of last box, i.e., of line in varwidth) + \algpx@extraShiftX to get x position at beginning of line 268 | \tikz[overlay,remember picture]{% 269 | \ifdimcomp{\the\ht0}{<}{\algpx@minTopPageHeight}{% 270 | \coordinate (algpx@pageNorth) at (-\wd0 - \algpx@extraShiftX,\algpx@minTopPageHeight);% 271 | }{% 272 | \coordinate (algpx@pageNorth) at (-\wd0 - \algpx@extraShiftX,\the\ht0);% 273 | }% 274 | \tikzmark{algpx@pageNorth-\thealgpx@pageCount}{(algpx@pageNorth)}% 275 | }% 276 | \setbool{algpx@pageJustBroken}{false}% 277 | }{% 278 | \tikz[overlay,remember picture]{}% dummy to keep in sync 279 | }% 280 | } 281 | 282 | % set algpx@codeBoxNorthMax of current box and all ancestors; argument is amount to shift up from current baseline 283 | \newcommand{\algpx@setCodeBoxNorth}[1]{% 284 | \setcounter{algpx@nestedCBoxCount}{0}% 285 | \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@codeBoxStack}}}}{% 286 | \FSPush{algpx@codeBoxStackTmp}{\FSTop{algpx@codeBoxStack}}% copy stack to tmp 287 | \@ifnodedefined{algpx@codeBoxNorthMax-\FSTop{algpx@codeBoxStack}}{% 288 | % get current position; shift according to nest-level to ensure nested boxes don't collide 289 | \@tikzmarkNow[yshift=\dimexpr #1 + \algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxNorthHere}% 290 | % extract y-coordinate of previously stored north 291 | \tikz[overlay,remember picture]{% 292 | \pgfextracty{\algpx@oldPos}{\pgfpointanchor{algpx@codeBoxNorthMax-\FSTop{algpx@codeBoxStack}}{center}}% 293 | \pgfextracty{\algpx@newPos}{\pgfpointanchor{algpx@codeBoxNorthHere}{center}}% 294 | \global\algpx@oldPos=\algpx@oldPos% 295 | \global\algpx@newPos=\algpx@newPos% 296 | }% 297 | \ifdimcomp{\algpx@oldPos}{<}{\algpx@newPos}{% 298 | % new y is greater than old one, so set it 299 | \@tikzmarkNow[yshift=\dimexpr #1 + \algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxNorthMax-\FSTop{algpx@codeBoxStack}}% 300 | }{% 301 | \@tikzmarkNow{algpx@codeBoxNorthDummy}% set something to keep in sync 302 | }% 303 | }{% 304 | \@tikzmarkNow[yshift=\dimexpr #1 + \algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxNorthMax-\FSTop{algpx@codeBoxStack}}% 305 | }% 306 | \FSPop{algpx@codeBoxStack}% 307 | \stepcounter{algpx@nestedCBoxCount}% 308 | }% 309 | % restore stack from tmp 310 | \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@codeBoxStackTmp}}}}{% 311 | \FSPush{algpx@codeBoxStack}{\FSTop{algpx@codeBoxStackTmp}}% 312 | \FSPop{algpx@codeBoxStackTmp}% 313 | }% 314 | } 315 | 316 | 317 | % set algpx@codeBoxSouthMax of current box and all ancestors; argument is amount to shift down from current baseline 318 | \newcommand{\algpx@setCodeBoxSouth}[1]{% 319 | \setcounter{algpx@nestedCBoxCount}{0}% 320 | \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@codeBoxStack}}}}{% 321 | \FSPush{algpx@codeBoxStackTmp}{\FSTop{algpx@codeBoxStack}}% copy stack to tmp 322 | \@ifnodedefined{algpx@codeBoxSouthMax-\FSTop{algpx@codeBoxStack}}{% 323 | % get current position; shift according to nest-level to ensure nested boxes don't collide 324 | \@tikzmarkNow[yshift=\dimexpr -#1 -\algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxSouthHere}% 325 | % extract y-coordinate of previously stored south 326 | \tikz[overlay,remember picture]{% 327 | \pgfextracty{\algpx@oldPos}{\pgfpointanchor{algpx@codeBoxSouthMax-\FSTop{algpx@codeBoxStack}}{center}}% 328 | \pgfextracty{\algpx@newPos}{\pgfpointanchor{algpx@codeBoxSouthHere}{center}}% 329 | \global\algpx@oldPos=\algpx@oldPos% 330 | \global\algpx@newPos=\algpx@newPos% 331 | }% 332 | \ifdimcomp{\algpx@oldPos}{>}{\algpx@newPos}{% 333 | % new y is less than old one, so set it 334 | \@tikzmarkNow[yshift=\dimexpr -#1 -\algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxSouthMax-\FSTop{algpx@codeBoxStack}}% 335 | }{% 336 | \@tikzmarkNow{algpx@codeBoxSouthDummy}% set something to keep in sync 337 | }% 338 | }{% 339 | \@tikzmarkNow[yshift=\dimexpr -#1 -\algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxSouthMax-\FSTop{algpx@codeBoxStack}}% 340 | }% 341 | \FSPop{algpx@codeBoxStack}% 342 | \stepcounter{algpx@nestedCBoxCount}% 343 | }% 344 | % restore stack from tmp 345 | \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@codeBoxStackTmp}}}}{% 346 | \FSPush{algpx@codeBoxStack}{\FSTop{algpx@codeBoxStackTmp}}% 347 | \FSPop{algpx@codeBoxStackTmp}% 348 | }% 349 | } 350 | 351 | % set algpx@codeBoxWestMax of current box and all ancestors; argument is amount to shift left from current position 352 | \newcommand{\algpx@setCodeBoxWest}[1][0pt]{% 353 | \setcounter{algpx@nestedCBoxCount}{0}% 354 | \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@codeBoxStack}}}}{% 355 | \FSPush{algpx@codeBoxStackTmp}{\FSTop{algpx@codeBoxStack}}% copy stack to tmp 356 | \@ifnodedefined{algpx@codeBoxWestMax-\FSTop{algpx@codeBoxStack}}{% 357 | % get current position; shift according to nest-level to ensure nested boxes don't collide 358 | \@tikzmarkNow[xshift=\dimexpr -#1 -\algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxWestHere}% 359 | % extract x-coordinate of previously stored west 360 | \tikz[overlay,remember picture]{% 361 | \pgfextractx{\algpx@oldPos}{\pgfpointanchor{algpx@codeBoxWestMax-\FSTop{algpx@codeBoxStack}}{center}}% 362 | \pgfextractx{\algpx@newPos}{\pgfpointanchor{algpx@codeBoxWestHere}{center}}% 363 | \global\algpx@oldPos=\algpx@oldPos% 364 | \global\algpx@newPos=\algpx@newPos% 365 | }% 366 | \ifdimcomp{\algpx@oldPos}{>}{\algpx@newPos}{% 367 | % new x is smaller than old one, so set it 368 | \@tikzmarkNow[xshift=\dimexpr -#1 -\algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxWestMax-\FSTop{algpx@codeBoxStack}}% 369 | }{% 370 | \@tikzmarkNow{algpx@codeBoxWestDummy}% set something to keep in sync 371 | }% 372 | }{% 373 | \@tikzmarkNow[xshift=\dimexpr -#1 -\algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxWestMax-\FSTop{algpx@codeBoxStack}}% 374 | }% 375 | \FSPop{algpx@codeBoxStack}% 376 | \stepcounter{algpx@nestedCBoxCount}% 377 | }% 378 | % restore stack from tmp 379 | \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@codeBoxStackTmp}}}}{% 380 | \FSPush{algpx@codeBoxStack}{\FSTop{algpx@codeBoxStackTmp}}% 381 | \FSPop{algpx@codeBoxStackTmp}% 382 | }% 383 | } 384 | 385 | % set algpx@codeBoxEastMax of current box and all ancestors 386 | \newcommand{\algpx@setCodeBoxEast}{% 387 | \setcounter{algpx@nestedCBoxCount}{0}% 388 | \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@codeBoxStack}}}}{% 389 | \FSPush{algpx@codeBoxStackTmp}{\FSTop{algpx@codeBoxStack}}% copy stack to tmp 390 | \@ifnodedefined{algpx@codeBoxEastMax-\FSTop{algpx@codeBoxStack}}{% 391 | % get current position; shift according to nest-level to ensure nested boxes don't collide 392 | \@tikzmarkNow[xshift=\dimexpr \algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxEastHere}% 393 | % extract x-coordinate of previously stored east 394 | \tikz[overlay,remember picture]{% 395 | \pgfextractx{\algpx@oldPos}{\pgfpointanchor{algpx@codeBoxEastMax-\FSTop{algpx@codeBoxStack}}{center}}% 396 | \pgfextractx{\algpx@newPos}{\pgfpointanchor{algpx@codeBoxEastHere}{center}}% 397 | \global\algpx@oldPos=\algpx@oldPos% 398 | \global\algpx@newPos=\algpx@newPos% 399 | }% 400 | \ifdimcomp{\algpx@oldPos}{<}{\algpx@newPos}{% 401 | % new x is greater than old one, so set it 402 | \@tikzmarkNow[xshift=\dimexpr \algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxEastMax-\FSTop{algpx@codeBoxStack}}% 403 | }{% 404 | \@tikzmarkNow{algpx@codeBoxEastDummy}% set something to keep in sync 405 | }% 406 | }{% 407 | \@tikzmarkNow[xshift=\dimexpr \algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxEastMax-\FSTop{algpx@codeBoxStack}}% 408 | }% 409 | \FSPop{algpx@codeBoxStack}% 410 | \stepcounter{algpx@nestedCBoxCount}% 411 | }% 412 | % restore stack from tmp 413 | \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@codeBoxStackTmp}}}}{% 414 | \FSPush{algpx@codeBoxStack}{\FSTop{algpx@codeBoxStackTmp}}% 415 | \FSPop{algpx@codeBoxStackTmp}% 416 | }% 417 | } 418 | 419 | % Set coordinates of box on top of algpx@codeBoxStack to maximal reported values. 420 | % This ensures, e.g., that the right edge of the box is after the longest line inside. 421 | \newcommand{\algpx@setBoxesToStoredMax}{% 422 | \tikz[overlay,remember picture]{% 423 | \tikzmark{algpx@codeBoxNorth-\FSTop{algpx@codeBoxStack}}{(algpx@codeBoxNorthMax-\FSTop{algpx@codeBoxStack})}% 424 | \tikzmark{algpx@codeBoxSouth-\FSTop{algpx@codeBoxStack}}{(algpx@codeBoxSouthMax-\FSTop{algpx@codeBoxStack})}% 425 | \tikzmark{algpx@codeBoxWest-\FSTop{algpx@codeBoxStack}}{(algpx@codeBoxWestMax-\FSTop{algpx@codeBoxStack})}% 426 | \tikzmark{algpx@codeBoxEast-\FSTop{algpx@codeBoxStack}}{(algpx@codeBoxEastMax-\FSTop{algpx@codeBoxStack})}% 427 | }% 428 | } 429 | 430 | % add some space above and below box; more if several boxes are nested 431 | % first argument: number of boxes above 432 | % second argument: height of content 433 | % third argument: number of boxes below 434 | % fourth argument: depth of content 435 | \newcommand{\algpx@addBoxSpacing}[4]{% 436 | \ifnumcomp{0}{<}{#1}{% 437 | \rule{0pt}{\dimexpr #2 + \algpx@codeBoxInnerSep + \algpx@codeBoxOuterSep + (\algpx@codeBoxSep * (#1 - 1))\relax}% 438 | }{}% 439 | \ifnumcomp{0}{<}{#3}{% 440 | \rule[\dimexpr -#4 - \algpx@codeBoxInnerSep - \algpx@codeBoxOuterSep - (\algpx@codeBoxSep * (#3 - 1))\relax]{0pt}{\dimexpr #4 + \algpx@codeBoxInnerSep + \algpx@codeBoxOuterSep + (\algpx@codeBoxSep * (#3 - 1))\relax}% negative offset equal to height to draw line down from baseline 441 | }{}% 442 | } 443 | 444 | % Begin a new code box here. 445 | % Must be followed by \State, \If, \For etc. 446 | % (optional) argument is style of box 447 | \newcommand{\BeginBox}[1][algpxDefaultBox]{% 448 | \ignorespaces% 449 | \FSUnshift{algpx@startNewCodeBoxQueue}{\thealgpx@codeBoxCount}% add to queue; processed by \algpx@startCodeCommand 450 | %globally set tikz style (https://tex.stackexchange.com/a/47918) 451 | \begingroup% 452 | \globaldefs=1\relax% 453 | \pgfqkeys{/tikz}{algpx@codeBoxStyle-\thealgpx@codeBoxCount/.style={#1}}% 454 | \endgroup% 455 | \stepcounter{algpx@codeBoxCount}% 456 | \ignorespaces% 457 | } 458 | 459 | % End one open code box. Fails if no box open (i.e., if algpx@codeBoxStack is empty). 460 | \newcommand{\EndBox}{% 461 | \ignorespaces% 462 | \ifnumcomp{0}{<}{\FSSize{algpx@startNewCodeBoxQueue}}{% 463 | \PackageError{algpseudocodex}{BeginBox must be followed by State, If, For, etc. Use BoxedString instead}{}% 464 | \FSClear{algpx@startNewCodeBoxQueue}% 465 | }{% 466 | \ifnumcomp{0}{<}{\FSSize{algpx@codeBoxStack}}{% 467 | \unskip% 468 | \ifbool{algpx@executeEndVarwidth}{% 469 | \par\xdef\algpx@pdtemp{\the\prevdepth}% see https://tex.stackexchange.com/a/34982 470 | \end{varwidth}\setbox0=\lastbox\usebox0% 471 | \setbool{algpx@executeEndVarwidth}{false}% 472 | \setbool{algpx@adjustHeight}{true}% 473 | \setbool{algpx@restorePrevdepth}{true}% 474 | }{}% 475 | \ifbool{algpx@setNorth}{% 476 | \algpx@setCodeBoxNorth{\the\ht0}% set north here shifted by height of current line 477 | \setbool{algpx@setNorth}{false}% 478 | }{}% 479 | \algpx@setCodeBoxEast% 480 | \ifbool{algpx@indJustEnded}{% 481 | \algpx@setCodeBoxSouth{0pt}% set south here, don't shift after end with noEnd 482 | % add space after boxes. Otherwise done by endCodeCommand, but this is not executed after End with noEnd 483 | \algpx@addBoxSpacing{\value{algpx@startedBoxesCount}}{0pt}{\numexpr \value{algpx@endedBoxesCount} + 1 \relax}{0pt}% 484 | }{% 485 | \algpx@setCodeBoxSouth{\the\dp0}% set south here shifted by depth of current line 486 | }% 487 | %adjust stored prevdepth for ended boxes 488 | \ifnumcomp{0}{<}{\value{algpx@endedBoxesCount}}{% 489 | \edef\algpx@pdtemp{\dimexpr \algpx@pdtemp + \algpx@codeBoxSep \relax}% 490 | }{% 491 | \edef\algpx@pdtemp{\dimexpr \algpx@pdtemp + \algpx@codeBoxInnerSep + \algpx@codeBoxOuterSep \relax}% 492 | }% 493 | \algpx@setBoxesToStoredMax% 494 | \FSPop{algpx@codeBoxStack}% 495 | \stepcounter{algpx@endedBoxesCount}% 496 | }{% 497 | \PackageError{algpseudocodex}{No box to end}{}% 498 | }% 499 | }% 500 | \ignorespaces% 501 | } 502 | 503 | % Draw box within a single line of code. 504 | % (Optional) first argument is style of the box. 505 | % Second argument is the string to print inside the box. 506 | \newcommand{\BoxedString}[2][algpxDefaultBox]{% 507 | \ifnumcomp{\value{algpx@nestedBoxedStringCount}}{=}{0}{% 508 | \setcounter{algpx@nestedBoxedStringMaxCount}{0}% reset max count for new boxes 509 | }{}% 510 | \stepcounter{algpx@nestedBoxedStringCount}% 511 | \ifnumcomp{\value{algpx@nestedBoxedStringMaxCount}}{<}{\value{algpx@nestedBoxedStringCount}}{% 512 | \setcounter{algpx@nestedBoxedStringMaxCount}{\value{algpx@nestedBoxedStringCount}}% 513 | }{}% 514 | \algpx@drawCodeBox{#1}{algpx@codeBoxNorth-\thealgpx@codeBoxCount}{algpx@codeBoxWest-\thealgpx@codeBoxCount}{algpx@codeBoxEast-\thealgpx@codeBoxCount}{algpx@codeBoxSouth-\thealgpx@codeBoxCount}% 515 | \FSPush{algpx@codeBoxStack}{\thealgpx@codeBoxCount}% 516 | \stepcounter{algpx@codeBoxCount}% 517 | \algpx@setCodeBoxWest% 518 | \ifmmode% 519 | % This works in equation but not in align / displaystyle etc. gets lost 520 | \savebox{\algpx@boxedStringBox}{$\m@th#2$}% 521 | \usebox{\algpx@boxedStringBox}% 522 | \else% 523 | \savebox{\algpx@boxedStringBox}{#2}% 524 | \usebox{\algpx@boxedStringBox}% 525 | \fi% 526 | \algpx@setCodeBoxEast% 527 | \algpx@setCodeBoxNorth{\the\ht\algpx@boxedStringBox}% 528 | \algpx@setCodeBoxSouth{\the\dp\algpx@boxedStringBox}% 529 | \algpx@setBoxesToStoredMax% 530 | \FSPop{algpx@codeBoxStack}% 531 | \addtocounter{algpx@nestedBoxedStringCount}{-1}% BoxedString ends here 532 | \ifnumcomp{\value{algpx@nestedBoxedStringCount}}{=}{0}{% 533 | \algpx@addBoxSpacing{\value{algpx@nestedBoxedStringMaxCount}}{\the\ht\algpx@boxedStringBox}{\value{algpx@nestedBoxedStringMaxCount}}{\the\dp\algpx@boxedStringBox}% 534 | }{}% 535 | } 536 | 537 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 538 | % Macros for indentation lines 539 | % 540 | % start indented block 541 | \newcommand{\algpx@startIndent}{% 542 | \ifbool{algpx@indLines}{% 543 | % Define counter for the page on which this indent line ends. 544 | % The use of totcount ensures the last value is preserved during compilations and thus can be used before setting it. 545 | % expansion is needed because name contains variable, see 546 | % https://tex.stackexchange.com/questions/517559/why-cant-the-name-of-a-totcounter-be-defined-with-a-variable 547 | \expanded{\noexpand\newtotcounter{algpx@indentEndPage-\thealgpx@indentCount}}% 548 | % set start coordinate here and draw indent line 549 | % Note: Draw already here because endIndent could already be called on next page if end is at last line of page. 550 | \tikz[overlay,remember picture]{% 551 | \coordinate (startPos) at (\algpx@indShiftX,\algpx@indStartShiftY); 552 | \algpx@drawIndentLine{\thealgpx@indentCount}{startPos}% 553 | }% 554 | \FSPush{algpx@indentStack}{\thealgpx@indentCount}% 555 | \stepcounter{algpx@indentCount}% 556 | }{}% 557 | } 558 | 559 | % end of indented block 560 | % optional argument 1 means that only interrupted by else, 2 means ended with until 561 | \newcommand{\algpx@endIndent}[1][0]{% 562 | \ifbool{algpx@indLines}{% 563 | % remember on which page indent line ends (remembered through compiliations because we use totcount) 564 | \setcounter{algpx@indentEndPage-\FSTop{algpx@indentStack}}{\value{algpx@pageCount}}% 565 | \tikz[overlay,remember picture]{% 566 | \ifboolexpr{bool{algpx@indJustEnded} and test{\ifstrequal{#1}{0}}}{% 567 | % if another line has just ended, use same coordinates as for previous end 568 | % to this end, remember index of previous end to use 569 | \expanded{\noexpand\newtotcounter{algpx@indentEndCoordIndex-\FSTop{algpx@indentStack}}}% 570 | \setcounter{algpx@indentEndCoordIndex-\FSTop{algpx@indentStack}}{\thealgpx@lastIndentEnded}% 571 | }{% 572 | % if not just ended, use current position (0,0) as end 573 | \ifboolexpr{bool{algpx@noEnd} and test{\ifstrequal{#1}{0}}}{% 574 | % Draw additional line to right if noend and line is not interrupted and move down by current line depth. 575 | % Note: we are now at the end of the line, so the x position is too far right. 576 | % We solve this in \algpx@drawIndentLine by going at most \algpx@indShiftX to the right. 577 | % Adjusting here would require access to the start position and thus an additional compilation. 578 | \coordinate (algpx@indentEndCoord) at (\algpx@indShiftX+\algpx@indXLineLength,-\the\dp0);% 579 | }{% 580 | % if using end or interrupted by else etc., use current position shifted by default values 581 | \coordinate (algpx@indentEndCoord) at (\algpx@indShiftX,\algpx@indEndShiftY);% 582 | }% 583 | % remember end position using \tikzmark so it can be accessed by \algpx@startIndent before 584 | \tikzmark{algpx@indentEnd-\FSTop{algpx@indentStack}}{(algpx@indentEndCoord)}% 585 | }% 586 | }% 587 | }{}% 588 | % set indJustEnded even if indLines are not drawn; also used for EndBox 589 | \ifboolexpr{not bool{algpx@indJustEnded} and bool{algpx@noEnd} and test{\ifstrequal{#1}{0}}}{% 590 | \setbool{algpx@indJustEnded}{true}% 591 | \ifbool{algpx@indLines}{% 592 | \setcounter{algpx@lastIndentEnded}{\FSTop{algpx@indentStack}}% 593 | }{}% 594 | }{}% 595 | \ifbool{algpx@indLines}{% 596 | \FSPop{algpx@indentStack}% 597 | \ifstrequal{#1}{1}{% 598 | \algpx@startIndent% start new line if only interrupted 599 | }{}% 600 | }{}% 601 | } 602 | 603 | % Draw indent line with index #1 and start coordinate (#2). 604 | % To be called inside a TikZ picture. 605 | \newcommand{\algpx@drawIndentLine}[2]{% 606 | \ifnumcomp{\totvalue{algpx@indentEndPage-#1}}{>}{\value{algpx@pageCount}}{% 607 | % if indentation does not end on the same page, draw line to end of page with x position of start 608 | \coordinate (algpx@indentEndCoord) at (#2 |- {pic cs:algpx@pageSouth-\thealgpx@pageCount});% 609 | }{% 610 | % otherwise, indentation ends on same page 611 | \@ifundefined{c@algpx@indentEndCoordIndex-#1@totc}{% 612 | % if no indentEndCoordIndex is stored, just use stored end position 613 | \coordinate (algpx@indentEndCoord) at (pic cs:algpx@indentEnd-#1);% 614 | }{% 615 | % if indentEndCoordIndex is defined, another line has just ended and we use the same y coordinates as for previous end 616 | \coordinate (algpx@indentEndCoord) at (pic cs:algpx@indentEnd-\the\totvalue{algpx@indentEndCoordIndex-#1});% 617 | }% 618 | }{}% 619 | % Only draw if there is minimum distance between start and end 620 | \pgfextracty{\algpx@indStartY}{\pgfpointanchor{#2}{center}}% 621 | \pgfextracty{\algpx@indEndY}{\pgfpointanchor{algpx@indentEndCoord}{center}}% 622 | \ifdimcomp{\algpx@indStartY - \algpx@indEndY}{>}{\algpx@minIndDist}{% 623 | % draw in straight lines from start position (#2) to end coordinate, but with x position at most start + \algpx@indXLineLength since end position is set at end of line in \algpx@endIndent 624 | \draw[algpxIndentLine] let \p1=(#2), \p2=(algpx@indentEndCoord) in (#2) |- ({min(\x2, \x1 + \algpx@indXLineLength)}, \y2);% 625 | }{}% 626 | } 627 | 628 | % For all open indent lines not ending on current page, draw from top to bottom of page 629 | % Optional argument is 1 if executed on end block with noEnd=false. 630 | \newcommand{\algpx@drawIndentLinesOnPageBreak}[1][0]{% 631 | \tikz[overlay,remember picture]{% 632 | % iterate over all open indent lines 633 | \ifstrequal{#1}{0}{% 634 | \setcounter{algpx@tmpCount}{0}% tmp counter to count interations 635 | }{% 636 | % if ending block here, the last indentation has already ended and line won't be drawn 637 | % start counting at -1 to get correct indentation of later ending lines. 638 | \setcounter{algpx@tmpCount}{-1}% 639 | }% 640 | \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@indentStack}}}}{% 641 | \FSPush{algpx@indentStackTmp}{\FSTop{algpx@indentStack}}% copy stack to tmp 642 | \stepcounter{algpx@tmpCount}% 643 | % draw line to bottom of page 644 | % set beginning of line to north of page (with x set to beginning of line, see \algpx@checkPageBreak) 645 | % shifted by the number indentations 646 | \coordinate (startPos) at ($(pic cs:algpx@pageNorth-\thealgpx@pageCount) - (\dimexpr \algorithmicindent * \value{algpx@tmpCount} - \algpx@indShiftX \relax, 0ex)$);% 647 | \algpx@drawIndentLine{\FSTop{algpx@indentStack}}{startPos}% 648 | % finally remove top element 649 | \FSPop{algpx@indentStack}% 650 | }% 651 | % restore stack from tmp 652 | \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@indentStackTmp}}}}{% 653 | \FSPush{algpx@indentStack}{\FSTop{algpx@indentStackTmp}}% 654 | \FSPop{algpx@indentStackTmp}% 655 | }% 656 | }% 657 | } 658 | 659 | 660 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 661 | % Keywords 662 | % 663 | \algnewcommand\algorithmicend{\textbf{end}} 664 | \algnewcommand\algorithmicdo{\textbf{do}} 665 | \algnewcommand\algorithmicwhile{\textbf{while}} 666 | \algnewcommand\algorithmicfor{\textbf{for}} 667 | \algnewcommand\algorithmicforall{\textbf{for all}} 668 | \algnewcommand\algorithmicloop{\textbf{loop}} 669 | \algnewcommand\algorithmicrepeat{\textbf{repeat}} 670 | \algnewcommand\algorithmicuntil{\textbf{until}} 671 | \algnewcommand\algorithmicprocedure{\textbf{procedure}} 672 | \algnewcommand\algorithmicfunction{\textbf{function}} 673 | \algnewcommand\algorithmicif{\textbf{if}} 674 | \algnewcommand\algorithmicthen{\textbf{then}} 675 | \algnewcommand\algorithmicelse{\textbf{else}} 676 | \algnewcommand\algorithmicrequire{\textbf{Require:}} 677 | \algnewcommand\algorithmicensure{\textbf{Ensure:}} 678 | \algnewcommand\algorithmicreturn{\textbf{return}} 679 | \algnewcommand\algorithmicoutput{\textbf{output}} 680 | \algnewcommand\algorithmicstructure{\textbf{structure}} 681 | \algnewcommand\algorithmicclass{\textbf{class}} 682 | \algnewcommand\algorithmicproperties{\textbf{properties}} 683 | \algnewcommand\algorithmicmethods{\textbf{methods}} 684 | \algnewcommand\textproc{\textsc}% font for procedure/function names 685 | \algnewcommand\textstruc{\textsc}% font for structure and class names 686 | 687 | 688 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 689 | % Loops, conditional statements, and functions 690 | % 691 | \algdef{SE}[WHILE]{While}{EndWhile}[1]{% 692 | \algpx@startCodeCommand\algpx@startIndent\algorithmicwhile\ #1\ \algorithmicdo% 693 | }{% 694 | \algpx@startEndBlockCommand\algpx@endIndent\algorithmicend\ \algorithmicwhile% 695 | } 696 | \algdef{SE}[FOR]{For}{EndFor}[1]{% 697 | \algpx@startCodeCommand\algpx@startIndent\algorithmicfor\ #1\ \algorithmicdo% 698 | }{% 699 | \algpx@startEndBlockCommand\algpx@endIndent\algorithmicend\ \algorithmicfor% 700 | } 701 | \algdef{S}[FOR]{ForAll}[1]{% 702 | \algpx@startCodeCommand\algpx@startIndent\algorithmicforall\ #1\ \algorithmicdo% 703 | } 704 | \algdef{SE}[LOOP]{Loop}{EndLoop}{% 705 | \algpx@startCodeCommand\algpx@startIndent\algorithmicloop% 706 | }{% 707 | \algpx@startEndBlockCommand\algpx@endIndent\algorithmicend\ \algorithmicloop% 708 | } 709 | \algdef{SE}[REPEAT]{Repeat}{Until}{% 710 | \algpx@startCodeCommand\algpx@startIndent\algorithmicrepeat% 711 | }[1]{% 712 | \algpx@startEndBlockCommand\algpx@endIndent[2]\algorithmicuntil\ #1% 713 | } 714 | \algdef{SE}[IF]{If}{EndIf}[1]{% 715 | \algpx@startCodeCommand\algpx@startIndent\algorithmicif\ #1\ \algorithmicthen% 716 | }{% 717 | \algpx@startEndBlockCommand\algpx@endIndent\algorithmicend\ \algorithmicif% 718 | } 719 | \algdef{C}[IF]{IF}{ElsIf}[1]{% 720 | \algpx@startCodeCommand\algpx@endIndent[1]\algorithmicelse\ \algorithmicif\ #1\ \algorithmicthen% 721 | } 722 | \algdef{Ce}[ELSE]{IF}{Else}{EndIf}{% 723 | \algpx@startCodeCommand\algpx@endIndent[1]\algorithmicelse% 724 | } 725 | \algdef{SE}[PROCEDURE]{Procedure}{EndProcedure}[2]{% 726 | \algpx@startCodeCommand\algpx@startIndent\algorithmicprocedure\ \textproc{#1}\ifstrempty{#2}{}{(#2)}% 727 | }{% 728 | \algpx@startEndBlockCommand\algpx@endIndent\algorithmicend\ \algorithmicprocedure% 729 | } 730 | \algdef{SE}[FUNCTION]{Function}{EndFunction}[2]{% 731 | \algpx@startCodeCommand\algpx@startIndent\algorithmicfunction\ \textproc{#1}\ifstrempty{#2}{}{(#2)}% 732 | }{% 733 | \algpx@startEndBlockCommand\algpx@endIndent\algorithmicend\ \algorithmicfunction% 734 | } 735 | \algdef{SE}[STRUCTURE]{Structure}{EndStructure}[1]{% 736 | \algpx@startCodeCommand\algpx@startIndent\algorithmicstructure\ \textstruc{#1}% 737 | }{% 738 | \algpx@startEndBlockCommand\algpx@endIndent\algorithmicend\ \algorithmicstructure% 739 | } 740 | \algdef{SE}[CLASS]{Class}{EndClass}[1]{% 741 | \algpx@startCodeCommand\algpx@startIndent\algorithmicclass\ \textstruc{#1}% 742 | }{% 743 | \algpx@startEndBlockCommand\algpx@endIndent\algorithmicend\ \algorithmicclass% 744 | } 745 | \algdef{SE}[PROPERTIES]{Properties}{EndProperties}{% 746 | \algpx@startCodeCommand\algpx@startIndent\algorithmicproperties% 747 | }{% 748 | \algpx@startEndBlockCommand\algpx@endIndent\algorithmicend\ \algorithmicproperties% 749 | } 750 | \algdef{SE}[METHODS]{Methods}{EndMethods}{% 751 | \algpx@startCodeCommand\algpx@startIndent\algorithmicmethods% 752 | }{% 753 | \algpx@startEndBlockCommand\algpx@endIndent\algorithmicend\ \algorithmicmethods% 754 | } 755 | 756 | \ifbool{algpx@noEnd}{% 757 | \algtext*{EndWhile}% 758 | \algtext*{EndFor}% 759 | \algtext*{EndLoop}% 760 | \algtext*{EndIf}% 761 | \algtext*{EndProcedure}% 762 | \algtext*{EndFunction}% 763 | \algtext*{EndStructure}% 764 | \algtext*{EndClass}% 765 | \algtext*{EndProperties}% 766 | \algtext*{EndMethods}% 767 | % 768 | % end indent line before end command 769 | \pretocmd{\EndWhile}{\algpx@endIndent}{}{}% 770 | \pretocmd{\EndFor}{\algpx@endIndent}{}{}% 771 | \pretocmd{\EndLoop}{\algpx@endIndent}{}{}% 772 | \pretocmd{\EndIf}{\algpx@endIndent}{}{}% 773 | \pretocmd{\EndProcedure}{\algpx@endIndent}{}{}% 774 | \pretocmd{\EndFunction}{\algpx@endIndent}{}{}% 775 | \pretocmd{\EndStructure}{\algpx@endIndent}{}{}% 776 | \pretocmd{\EndClass}{\algpx@endIndent}{}{}% 777 | \pretocmd{\EndProperties}{\algpx@endIndent}{}{}% 778 | \pretocmd{\EndMethods}{\algpx@endIndent}{}{}% 779 | }{}% 780 | 781 | % execute \algpx@endCodeCommand before \State, \If etc. 782 | \pretocmd{\State}{\algpx@endCodeCommand}{}{} 783 | \pretocmd{\While}{\algpx@endCodeCommand}{}{} 784 | \pretocmd{\For}{\algpx@endCodeCommand}{}{} 785 | \pretocmd{\ForAll}{\algpx@endCodeCommand}{}{} 786 | \pretocmd{\Loop}{\algpx@endCodeCommand}{}{} 787 | \pretocmd{\Repeat}{\algpx@endCodeCommand}{}{} 788 | \pretocmd{\Until}{\algpx@endCodeCommand}{}{} 789 | \pretocmd{\If}{\algpx@endCodeCommand}{}{} 790 | \pretocmd{\ElsIf}{\algpx@endCodeCommand}{}{} 791 | \pretocmd{\Else}{\algpx@endCodeCommand}{}{} 792 | \pretocmd{\Procedure}{\algpx@endCodeCommand}{}{} 793 | \pretocmd{\Function}{\algpx@endCodeCommand}{}{} 794 | \pretocmd{\Structure}{\algpx@endCodeCommand}{}{} 795 | \pretocmd{\Class}{\algpx@endCodeCommand}{}{} 796 | \pretocmd{\Properties}{\algpx@endCodeCommand}{}{} 797 | \pretocmd{\Methods}{\algpx@endCodeCommand}{}{} 798 | 799 | % for end commands that may not be printed, tell endCodeCommand whether we are using noEnd 800 | \ifbool{algpx@noEnd}{% 801 | \pretocmd{\EndWhile}{\algpx@endCodeCommand[1]}{}{}% 802 | \pretocmd{\EndFor}{\algpx@endCodeCommand[1]}{}{}% 803 | \pretocmd{\EndLoop}{\algpx@endCodeCommand[1]}{}{}% 804 | \pretocmd{\EndIf}{\algpx@endCodeCommand[1]}{}{}% 805 | \pretocmd{\EndProcedure}{\algpx@endCodeCommand[1]}{}{}% 806 | \pretocmd{\EndFunction}{\algpx@endCodeCommand[1]}{}{}% 807 | \pretocmd{\EndStructure}{\algpx@endCodeCommand[1]}{}{}% 808 | \pretocmd{\EndClass}{\algpx@endCodeCommand[1]}{}{}% 809 | \pretocmd{\EndProperties}{\algpx@endCodeCommand[1]}{}{}% 810 | \pretocmd{\EndMethods}{\algpx@endCodeCommand[1]}{}{}% 811 | }{% 812 | \pretocmd{\EndWhile}{\algpx@endCodeCommand[0]}{}{}% 813 | \pretocmd{\EndFor}{\algpx@endCodeCommand[0]}{}{}% 814 | \pretocmd{\EndLoop}{\algpx@endCodeCommand[0]}{}{}% 815 | \pretocmd{\EndIf}{\algpx@endCodeCommand[0]}{}{}% 816 | \pretocmd{\EndProcedure}{\algpx@endCodeCommand[0]}{}{}% 817 | \pretocmd{\EndFunction}{\algpx@endCodeCommand[0]}{}{}% 818 | \pretocmd{\EndStructure}{\algpx@endCodeCommand[0]}{}{}% 819 | \pretocmd{\EndClass}{\algpx@endCodeCommand[0]}{}{}% 820 | \pretocmd{\EndProperties}{\algpx@endCodeCommand[0]}{}{}% 821 | \pretocmd{\EndMethods}{\algpx@endCodeCommand[0]}{}{}% 822 | }% 823 | 824 | % execute \algpx@startCodeCommand after \State (this is done for loops etc. inside the definitions above) 825 | \apptocmd{\State}{\algpx@startCodeCommand}{}{} 826 | 827 | 828 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 829 | % Other declarations 830 | % 831 | 832 | % dirty hack: execute drawing in argument of item and rest of \algpx@startCodeCommand outside 833 | % argument: text in item[.] 834 | \newcommand{\algpx@drawInItem}[1]{% 835 | \item[% 836 | \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@startNewCodeBoxQueue}}}}{% 837 | \FSPush{algpx@codeBoxStack}{\FSTop{algpx@startNewCodeBoxQueue}}% 838 | \algpx@drawCodeBox{algpx@codeBoxStyle-\FSTop{algpx@startNewCodeBoxQueue}}{algpx@codeBoxNorth-\FSTop{algpx@startNewCodeBoxQueue}}{algpx@codeBoxWest-\FSTop{algpx@startNewCodeBoxQueue}}{algpx@codeBoxEast-\FSTop{algpx@startNewCodeBoxQueue}}{algpx@codeBoxSouth-\FSTop{algpx@startNewCodeBoxQueue}}% 839 | \FSPop{algpx@startNewCodeBoxQueue}% 840 | \stepcounter{algpx@startedBoxesCount}% 841 | }% 842 | #1% 843 | ]% 844 | \setbool{algpx@indJustEnded}{false}% 845 | \setcounter{algpx@startedBoxesCount}{0}% 846 | \setcounter{algpx@endedBoxesCount}{0}% 847 | \setcounter{algpx@nestedBoxedStringMaxCount}{0}% 848 | \settowidth{\algpx@tmpLen}{#1}% 849 | \algpx@setCodeBoxWest[\dimexpr \labelsep + \algpx@tmpLen \relax]% 850 | \setbool{algpx@firstLine}{false}% 851 | \setbool{algpx@executeEndVarwidth}{true}% 852 | \setlength{\algpx@currentLineskiplimit}{\lineskiplimit}% remember value of lineskiplimit 853 | \setlength{\algpx@currentLineskip}{\lineskip}% remember value of lineskip 854 | \begin{varwidth}[t]{\dimexpr \linewidth - \labelsep - \algpx@tmpLen + \leftmargin \relax}% 855 | \setlength{\lineskiplimit}{\algpx@currentLineskiplimit}% restore lineskiplimit value 856 | \setlength{\lineskip}{\algpx@currentLineskip}% restore lineskip value 857 | \settoheight{\algpx@tmpLen}{#1}% 858 | \rule{0pt}{\algpx@tmpLen}% 859 | } 860 | 861 | \algnewcommand\Require{% 862 | \algpx@endCodeCommand% 863 | \ifnumcomp{0}{<}{\FSSize{algpx@startNewCodeBoxQueue}}{\setbool{algpx@setNorth}{true}}{}% 864 | \ifboolexpr{bool{algpx@spaceRequire} and not bool{algpx@firstLine}}{% 865 | \medskip% 866 | }{}% 867 | \algpx@drawInItem{\algorithmicrequire}% 868 | } 869 | 870 | \algnewcommand\Ensure{% 871 | \algpx@endCodeCommand% 872 | \ifnumcomp{0}{<}{\FSSize{algpx@startNewCodeBoxQueue}}{\setbool{algpx@setNorth}{true}}{}% 873 | \algpx@drawInItem{\algorithmicensure}% 874 | } 875 | 876 | \algnewcommand\Return{\algorithmicreturn{} } 877 | \algnewcommand\Output{\algorithmicoutput{} } 878 | \algnewcommand\Call[2]{\textproc{#1}\ifstrempty{#2}{}{(#2)}} 879 | 880 | %% internal methods to format comment 881 | % format according to comment format 882 | \newcommand{\algpx@commentFormat}[1]{% 883 | \ifbool{algpx@italicComments}{% 884 | \textit{\textcolor{\algpx@commentColor}{#1}}% 885 | }{% 886 | \textcolor{\algpx@commentColor}{#1}% 887 | }% 888 | } 889 | 890 | % get string for inline comment including begin and end markers 891 | \newcommand{\algpx@commentString}[1]{% 892 | \algpx@commentFormat{\algpx@beginComment#1\algpx@endComment}% 893 | } 894 | 895 | % redefine \Comment 896 | \algrenewcomment[1]{% 897 | \ifbool{algpx@rightComments}{% 898 | \settowidth{\algpx@tmpLen}{\algpx@commentString{#1}}% set temp variable to width of comment 899 | \tabto{\CurrentLineWidth}% this saves current position in \TabPrevPos and fixes spacing up to here 900 | \ifdimcomp{\algpx@tmpLen}{<}{\dimexpr \linewidth - \TabPrevPos \relax}{% check whether comment fits on line 901 | \tabto{\dimexpr \linewidth - \algpx@tmpLen \relax}% move position to right justify text 902 | \algpx@commentString{#1}% print comment 903 | }{% 904 | \algpx@commentString{#1}% if it doesn't fit, just print normally, allowing line break 905 | }% 906 | }{% 907 | \algpx@commentString{#1}% just print normally if not right justified 908 | }% 909 | \ignorespaces% 910 | }% 911 | 912 | % Long comment starting on new line. 913 | % Can span several lines and in contrast to \Comment, never right justified. 914 | \algdef{SL}[LCOMMENT]{LComment}{0}[1]{% 915 | \algpx@startCodeCommandX{\algpx@commentFormat{\algpx@beginLComment}}{\algpx@commentFormat{\algpx@endLComment}}% 916 | \algpx@commentFormat{#1}% print actual comment 917 | \tabto{\CurrentLineWidth}% this saves current position in \TabPrevPos and fixes spacing up to here 918 | \setlength{\algpx@tmpLen}{\dimexpr \linewidth - \TabPrevPos \relax}% set to remaining space on line 919 | \makebox[0pt][l]{% start box here that takes no space (otherwise impacts spacing of text before) 920 | \rule{\algpx@tmpLen}{0pt}% draw invisible rule from beginning of line until end of comment text 921 | \algpx@commentFormat{\algpx@endLComment}% print end comment at the end 922 | \algpx@setCodeBoxEast% since this takes 0 space, we have to set east of code box here explicitly 923 | }% 924 | }% 925 | 926 | \pretocmd{\LComment}{\algpx@endCodeCommand}{}{} 927 | 928 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 929 | % Execute at beginning and end of algorithmic environment 930 | % 931 | \AtBeginEnvironment{algorithmic}{% 932 | \setbool{algpx@firstLine}{true}% 933 | \setbool{algpx@setNorth}{false}% 934 | \setbool{algpx@executeEndVarwidth}{false}% 935 | \setbool{algpx@adjustHeight}{false}% 936 | \setbool{algpx@restorePrevdepth}{false}% 937 | \setbool{algpx@hasCheckedPageBreak}{false}% 938 | \setbool{algpx@pageJustBroken}{false}% 939 | \setcounter{algpx@startedBoxesCount}{0}% 940 | \setcounter{algpx@endedBoxesCount}{0}% 941 | % 942 | % Set lengths here to use correct font sizes 943 | \setlength{\algpx@indShiftX}{0.12em}% 944 | \setlength{\algpx@indStartShiftY}{-0.8ex}% 945 | \setlength{\algpx@indEndShiftY}{2.0ex}% 946 | \setlength{\algpx@indXLineLength}{0.5em}% 947 | \setlength{\algpx@minIndDist}{0.7ex}% 948 | } 949 | 950 | \AtEndEnvironment{algorithmic}{% 951 | \algpx@endCodeCommand% 952 | % Error checking 953 | \ifboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@codeBoxStack}}} or test {\ifnumcomp{0}{<}{\FSSize{algpx@startNewCodeBoxQueue}}}}{% 954 | \PackageError{algpseudocodex}{Some boxes have not ended}{}% 955 | }{}% 956 | } 957 | --------------------------------------------------------------------------------