From dae4e214e7b5d3899b853febd26458eb3dcc6603 Mon Sep 17 00:00:00 2001 From: Tom de Geus Date: Tue, 14 Mar 2023 08:32:43 +0100 Subject: [PATCH] Taking indentation into own hands (#54) --- .pre-commit-config.yaml | 2 +- environment.yaml | 2 - tests/test_classify.py | 8 +- tests/test_find_command.py | 115 ++ tests/test_indent.py | 850 ++++++++++++- tests/test_indent_long.py | 2405 ++++++++++++++++++++++++++++++++++++ tests/test_placeholders.py | 73 +- tests/test_simple.py | 46 +- texplain/__init__.py | 1544 +++++++++++++++-------- 9 files changed, 4447 insertions(+), 598 deletions(-) create mode 100644 tests/test_find_command.py create mode 100644 tests/test_indent_long.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a48fbbb..5bcc217 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -34,7 +34,7 @@ repos: rev: 6.0.0 hooks: - id: flake8 - args: [--max-line-length=100] + args: [--max-line-length=100, --ignore=E203, --per-file-ignore=tests/test_one_sentence_per_line.py:E501, --per-file-ignore=tests/test_indent_long.py:E501] - repo: https://github.com/asottile/setup-cfg-fmt rev: v2.2.0 hooks: diff --git a/environment.yaml b/environment.yaml index 7276156..a8bfe52 100644 --- a/environment.yaml +++ b/environment.yaml @@ -3,10 +3,8 @@ channels: dependencies: - click - furo -- latexindent.pl - numpy - python -- pyyaml - setuptools_scm - sphinx - sphinx-argparse diff --git a/tests/test_classify.py b/tests/test_classify.py index e0eae6a..0ae293e 100644 --- a/tests/test_classify.py +++ b/tests/test_classify.py @@ -20,7 +20,7 @@ def test_equation(self): tex = texplain.TeX(text) tex.format_labels() - self.assertEqual(tex.get(), text) + self.assertEqual(str(tex).strip(), text.strip()) # -- @@ -34,7 +34,7 @@ def test_equation(self): tex = texplain.TeX(text) tex.format_labels() - self.assertEqual(tex.get(), text) + self.assertEqual(str(tex).strip(), text.strip()) def test_section(self): text = r""" @@ -46,7 +46,7 @@ def test_section(self): tex = texplain.TeX(text) tex.format_labels() - self.assertEqual(tex.get(), text) + self.assertEqual(str(tex).strip(), text.strip()) def test_figure(self): text = r""" @@ -60,7 +60,7 @@ def test_figure(self): tex = texplain.TeX(text) tex.format_labels() - self.assertEqual(tex.get(), text) + self.assertEqual(str(tex).strip(), text.strip()) if __name__ == "__main__": diff --git a/tests/test_find_command.py b/tests/test_find_command.py new file mode 100644 index 0000000..efbd22c --- /dev/null +++ b/tests/test_find_command.py @@ -0,0 +1,115 @@ +import unittest + +import texplain + + +class MyTests(unittest.TestCase): + """ + Tests + """ + + def test_basic(self): + text = r"This is some \foo \bar" + ret = texplain.find_command(text) + + self.assertEqual(r"\foo", text[ret[0][0][0] : ret[0][0][1]]) + + def test_argument(self): + text = r"This is some \foo{fooarg} \bar{[bararg} {bararg2}" + ret = texplain.find_command(text) + + self.assertEqual(text[ret[0][0][0] : ret[0][0][1]], r"\foo") + self.assertEqual(text[ret[0][1][0] : ret[0][1][1]], r"{fooarg}") + + self.assertEqual(text[ret[1][0][0] : ret[1][0][1]], r"\bar") + self.assertEqual(text[ret[1][1][0] : ret[1][1][1]], r"{[bararg}") + self.assertEqual(text[ret[1][2][0] : ret[1][2][1]], r"{bararg2}") + + def test_argument_comment(self): + text = r"This is some \foo{fooarg} \bar{[bararg} {bararg2} % some } nonsense" + ret = texplain.find_command(text) + + self.assertEqual(text[ret[0][0][0] : ret[0][0][1]], r"\foo") + self.assertEqual(text[ret[0][1][0] : ret[0][1][1]], r"{fooarg}") + + self.assertEqual(text[ret[1][0][0] : ret[1][0][1]], r"\bar") + self.assertEqual(text[ret[1][1][0] : ret[1][1][1]], r"{[bararg}") + self.assertEqual(text[ret[1][2][0] : ret[1][2][1]], r"{bararg2}") + + def test_argument_comment_a(self): + text = r""" + This is a text with a \command% + % first comment + [ + option1 + ]% + % second comment + { + argument1 + } + + \bar + [ + option2 + ] + % comment + { + argument2 + } + """ + ret = texplain.find_command(text) + + self.assertEqual(text[ret[0][0][0] : ret[0][0][1]], r"\command") + self.assertEqual( + text[ret[0][1][0] : ret[0][1][1]].replace(" ", "").replace("\n", ""), r"[option1]" + ) + self.assertEqual( + text[ret[0][2][0] : ret[0][2][1]].replace(" ", "").replace("\n", ""), r"{argument1}" + ) + + self.assertEqual(text[ret[1][0][0] : ret[1][0][1]], r"\bar") + self.assertEqual( + text[ret[1][1][0] : ret[1][1][1]].replace(" ", "").replace("\n", ""), r"[option2]" + ) + self.assertEqual( + text[ret[1][2][0] : ret[1][2][1]].replace(" ", "").replace("\n", ""), r"{argument2}" + ) + + def test_option_argument(self): + text = r"This is some \foo[fooopt]{fooarg} \bar [baropt] [{baropt2}] {[bararg} {bararg2}" + ret = texplain.find_command(text) + + self.assertEqual(text[ret[0][0][0] : ret[0][0][1]], r"\foo") + self.assertEqual(text[ret[0][1][0] : ret[0][1][1]], r"[fooopt]") + self.assertEqual(text[ret[0][2][0] : ret[0][2][1]], r"{fooarg}") + + self.assertEqual(text[ret[1][0][0] : ret[1][0][1]], r"\bar") + self.assertEqual(text[ret[1][1][0] : ret[1][1][1]], r"[baropt]") + self.assertEqual(text[ret[1][2][0] : ret[1][2][1]], r"[{baropt2}]") + self.assertEqual(text[ret[1][3][0] : ret[1][3][1]], r"{[bararg}") + self.assertEqual(text[ret[1][4][0] : ret[1][4][1]], r"{bararg2}") + + def test_nested_command(self): + text = r""" +\begin{figure} + \subfloat{\label{fig:foo}} +\end{figure} + """ + + ret = texplain.find_command(text) + + self.assertEqual(text[ret[0][0][0] : ret[0][0][1]], r"\begin") + self.assertEqual(text[ret[0][1][0] : ret[0][1][1]], r"{figure}") + + self.assertEqual(text[ret[1][0][0] : ret[1][0][1]], r"\subfloat") + self.assertEqual(text[ret[1][1][0] : ret[1][1][1]], r"{\label{fig:foo}}") + + self.assertEqual(text[ret[2][0][0] : ret[2][0][1]], r"\label") + self.assertEqual(text[ret[2][1][0] : ret[2][1][1]], r"{fig:foo}") + + self.assertEqual(text[ret[3][0][0] : ret[3][0][1]], r"\end") + self.assertEqual(text[ret[3][1][0] : ret[3][1][1]], r"{figure}") + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_indent.py b/tests/test_indent.py index 8564067..fcbe88c 100644 --- a/tests/test_indent.py +++ b/tests/test_indent.py @@ -3,16 +3,358 @@ import texplain -class TestIndent(unittest.TestCase): - """ - Tests - """ +class TestComment(unittest.TestCase): + def test_comment_a(self): + text = r"This is a % comment" - def test_command_punctuation(self): + ret = texplain.indent(text) + self.assertEqual(ret.strip(), text.strip()) + + def test_comment_b(self): + text = r"This is a. % comment" + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), text.strip()) + + def test_comment_c(self): + text = "This is a. % comment a\nAnd another. % comment b" + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), text.strip()) + + def test_comment_d(self): + text = r""" +% a +% b + % c +% d + %% e + % f +%% g + """ + + formatted = r""" +% a +% b +% c +% d +%% e +% f +%% g + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_comment_indent(self): + text = r""" +% a +% b + % c +% d +\begin{figure}[htbp] + %% e + % f +\end{figure} +%% g + """ + + formatted = r""" +% a +% b +% c +% d +\begin{figure}[htbp] + %% e + % f +\end{figure} +%% g + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + +class TestNoindent(unittest.TestCase): + def test_verbatim(self): + text = r""" +Some text \begin{verbatim} a = b \end{verbatim} some more text. + """ + + formatted = r""" +Some text \begin{verbatim} a = b \end{verbatim} some more text. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_verbatim_a(self): + text = r""" +Some text + + +\begin{verbatim} a = b \end{verbatim} + + +some more text. + """ + + formatted = r""" +Some text + +\begin{verbatim} a = b \end{verbatim} + +some more text. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_noindent(self): + text = r""" +Some text +% \begin{noindent} +should be ignored +% \end{noindent} + some more text. + """ + + formatted = r""" +Some text +% \begin{noindent} +should be ignored +% \end{noindent} +some more text. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_noindent_a(self): + text = r""" +Some text + + +% \begin{noindent} +should be ignored +% \end{noindent} + + + some more text. + """ + + formatted = r""" +Some text + +% \begin{noindent} +should be ignored +% \end{noindent} + +some more text. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + +class TestIndentEnvironment(unittest.TestCase): + def test_environment(self): + text = r""" +Some text \begin{equation} a = b \end{equation} some more text. + """ + + formatted = r""" +Some text +\begin{equation} + a = b +\end{equation} +some more text. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_environment_a(self): + text = r""" +Some text \begin{equation}a = b\end{equation} some more text. + """ + + formatted = r""" +Some text +\begin{equation} + a = b +\end{equation} +some more text. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_environment_b(self): + text = r""" +Some text \begin{equation}[0, 1)\end{equation} some more text on interval $[0, 1)$. + """ + + formatted = r""" +Some text +\begin{equation} + [0, 1) +\end{equation} +some more text on interval $[0, 1)$. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_environment_c(self): + text = r""" +Some text \begin{equation} +[0, 1) +(2, 3) +\end{equation} some more text on interval $[0, 1)$. + """ + + formatted = r""" +Some text +\begin{equation} + [0, 1) + (2, 3) +\end{equation} +some more text on interval $[0, 1)$. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_environment_nested_a(self): + text = r""" +Some text \begin{equation} \begin{split} a = b \end{split} \end{equation} some more text. + """ + + formatted = r""" +Some text +\begin{equation} + \begin{split} + a = b + \end{split} +\end{equation} +some more text. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_environment_nested_b(self): + text = r""" +Some text \begin{equation} \begin{equation} a = b \end{equation} \end{equation} some more text. + """ + + formatted = r""" +Some text +\begin{equation} + \begin{equation} + a = b + \end{equation} +\end{equation} +some more text. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_environment_nested_c(self): + text = r""" +Some text +\begin{equation} +\begin{equation} +\begin{equation} +\begin{equation} +a = b +\end{equation} +\end{equation} +\end{equation} +\end{equation} +some more text. + """ + + formatted = r""" +Some text +\begin{equation} + \begin{equation} + \begin{equation} + \begin{equation} + a = b + \end{equation} + \end{equation} + \end{equation} +\end{equation} +some more text. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_environment_multiline_a(self): + text = r""" +Some text \begin{figure} + \foo + \bar \end{figure} some more text. """ - Keep exact indentation of command. + + formatted = r""" +Some text +\begin{figure} + \foo + \bar +\end{figure} +some more text. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_environment_multiline_b(self): + text = r""" +Some text \begin{figure} + \foo + \bar \end{figure} \begin{equation} a = b \end{equation} some more text. + """ + + formatted = r""" +Some text +\begin{figure} + \foo + \bar +\end{figure} +\begin{equation} + a = b +\end{equation} +some more text. """ + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_environment_comment(self): + text = r""" +Some text \begin{equation} % some comment +a = b \end{equation} some more text. + """ + + formatted = r""" +Some text +\begin{equation} % some comment + a = b +\end{equation} +some more text. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + +class TestIndentCommand(unittest.TestCase): + def test_command_punctuation(self): text = r""" A start\footnote{ This is a footnote @@ -20,12 +362,10 @@ def test_command_punctuation(self): A new sentence. """ - config = texplain.texindent_default_config() - ret = texplain.texindent(text, config) + ret = texplain.indent(text) self.assertEqual(ret.strip(), text.strip()) - # ----- - + def test_command_punctuation_a(self): text = r""" A start\footnote{ This is a footnote @@ -33,26 +373,117 @@ def test_command_punctuation(self): a continued sentence. """ - config = texplain.texindent_default_config() - ret = texplain.texindent(text, config) + ret = texplain.indent(text) self.assertEqual(ret.strip(), text.strip()) - # ----- - + def test_command_punctuation_b(self): text = r""" -\section{My section} +\section{My? section} \label{sec:a} """ - config = texplain.texindent_default_config() - ret = texplain.texindent(text, config) + ret = texplain.indent(text) self.assertEqual(ret.strip(), text.strip()) - def test_force_comment(self): + def test_label_equation(self): + text = r""" +\begin{equation} + \label{eq:a} + a = b +\end{equation} """ - Keep comments exactly as they are. + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), text.strip()) + + def test_nested_command(self): + text = r""" +\begin{figure} + \subfloat{\label{fig:foo}} +\end{figure} """ + ret = texplain.indent(text) + self.assertEqual(ret.strip(), text.strip()) + + +class TestOneSentencePerLine(unittest.TestCase): + def test_quote(self): + text = r""" +This a ``sentence!'' And another. + """ + + formatted = r""" +This a ``sentence!'' And another. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_full_quote(self): + text = r""" +``This a sentence!'' And +another. + """ + + formatted = r""" +``This a sentence!'' And another. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_brace(self): + text = r""" +This a sentence. And another +(etc.). + """ + + formatted = r""" +This a sentence. +And another (etc.). + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_full_brace(self): + text = r""" +(This a sentence.) (This a second sentence.) And another. And one more (?). + """ + + formatted = r""" +(This a sentence.) (This a second sentence.) And another. +And one more (?). + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_comment_a(self): + text = r""" +This is % some comment +a sentence. +And +here +is +another. +With a % another comment +final statement. + """ + + formatted = r""" +This is % some comment +a sentence. +And here is another. +With a % another comment +final statement. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_comment_b(self): text = r""" This is a text% with a comment that ends here. @@ -66,40 +497,385 @@ def test_force_comment(self): But this is not a comment. """ - config = texplain.texindent_default_config() - ret = texplain.texindent(text, config) + ret = texplain.indent(text) self.assertEqual(ret.strip(), formatted.strip()) - def test_label_equation(self): + def test_block(self): + text = r""" +This is the +first sentence. + +And the +second sentence. """ - Keep label where it is in an equation. + + formatted = r""" +This is the first sentence. + +And the second sentence. """ + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_environment(self): text = r""" -\begin{equation} - \label{eq:a} +This is the +first sentence. + +And the +\begin{foo} + With some + sub sentence. +\end{foo} +second sentence. + """ + + formatted = r""" +This is the first sentence. + +And the +\begin{foo} + With some sub sentence. +\end{foo} +second sentence. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_command_ignore(self): + text = r""" +This is the +first sentence. + +And \TG{?}{and some}{.} the +second sentence. + """ + + formatted = r""" +This is the first sentence. + +And \TG{?}{and some}{.} the second sentence. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_command_newline(self): + text = r""" +This is the +first sentence. + +And \footnote{ +A text with a +footnote. +} the +second sentence. + """ + + formatted = r""" +This is the first sentence. + +And \footnote{ + A text with a footnote. +} the second sentence. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_command_newline_a(self): + text = r""" +A start\footnote{This is a footnote. With + some poor formatting. +}. +A new sentence. + """ + + formatted = r""" +A start\footnote{ + This is a footnote. + With some poor formatting. +}. +A new sentence. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_command_newline_b(self): + text = r""" +A start\footnote[Some option]{This is a footnote. With + some poor formatting. +}. +A new sentence. + """ + + formatted = r""" +A start\footnote[Some option]{ + This is a footnote. + With some poor formatting. +}. +A new sentence. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_command_newline_comment(self): + text = r""" +A start\footnote{ % + This is a footnote. With + some poor formatting. +}. +A new sentence. + """ + + formatted = r""" +A start\footnote{ % + This is a footnote. + With some poor formatting. +}. +A new sentence. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_command_newline_comment_a(self): + text = r""" +% my comment +A start\footnote{ % + This is a footnote. With + some poor formatting. +} % + """ + + formatted = r""" +% my comment +A start\footnote{ % + This is a footnote. + With some poor formatting. +} % + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_command_newline_nested_a(self): + text = r""" +This is the +first sentence. + +And \footnote{ +A text with a \TG{ % some comment + A note in + a note. +} +footnote. +} the +second sentence. + """ + + formatted = r""" +This is the first sentence. + +And \footnote{ + A text with a \TG{ % some comment + A note in a note. + } + footnote. +} the second sentence. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_command_newline_nested_b(self): + text = r""" +This is the +first sentence. + +% some header +And \footnote{ +A text with a \TG{ % some comment + A note in + a note. +} +footnote. +} the +second sentence. + """ + + formatted = r""" +This is the first sentence. + +% some header +And \footnote{ + A text with a \TG{ % some comment + A note in a note. + } + footnote. +} the second sentence. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_command_multi_nested(self): + text = r""" +This is the +first sentence. + +% some header +\TG{ This is +a sentence. +} % +{ And another +sentence. +\TG{with +some} +{ +more +formatting +to +do +} +} + """ + + formatted = r""" +This is the first sentence. + +% some header +\TG{ + This is a sentence. +} % +{ + And another sentence. + \TG{ + with some + } + { + more formatting to do + } +} + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_nested_environment(self): + text = r""" +\some{ +\mycommand{ +\begin{something} +Some text \emph{with some highlighting}. And two sentences. +\end{something} +} +} + """ + + formatted = r""" +\some{ + \mycommand{ + \begin{something} + Some text \emph{with some highlighting}. + And two sentences. + \end{something} + } +} + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + +class TestIndentMath(unittest.TestCase): + def test_environment_a(self): + text = r""" +Some text \[ a = b \] \[c = d\] some more text. + """ + + formatted = r""" +Some text +\[ a = b -\end{equation} +\] +\[ + c = d +\] +some more text. """ - config = texplain.texindent_default_config() - ret = texplain.texindent(text, config) - self.assertEqual(ret.strip(), text.strip()) + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) - def test_nested_command(self): + +class TestCode(unittest.TestCase): + def test_code(self): + text = r""" +% a comment +\if foo \else bar \fi """ - Do nothing against nested commands. + + formatted = r""" +% a comment +\if + foo +\else + bar +\fi """ + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_code_a(self): text = r""" -\begin{figure} - \subfloat{\label{fig:foo}} -\end{figure} +% a comment +some text \if@namecite foo \else bar \fi """ - config = texplain.texindent_default_config() - ret = texplain.texindent(text, config) - self.assertEqual(ret.strip(), text.strip()) + formatted = r""" +% a comment +some text +\if@namecite + foo +\else + bar +\fi + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + @unittest.SkipTest # TODO + def test_code_b(self): + text = r""" +\newif\if@namecite +\let\if@namecite\iffalse +\DeclareOption{namecite}{\let\if@namecite\iftrue} + +some text \if@namecite foo \else bar \fi + """ + + formatted = r""" +\newif\if@namecite +\let\if@namecite\iffalse +\DeclareOption{namecite}{\let\if@namecite\iftrue} + +some text +\if@namecite + foo +\else + bar +\fi + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) if __name__ == "__main__": diff --git a/tests/test_indent_long.py b/tests/test_indent_long.py new file mode 100644 index 0000000..7e79c2e --- /dev/null +++ b/tests/test_indent_long.py @@ -0,0 +1,2405 @@ +import unittest + +import texplain + + +class TestLatexIndent(unittest.TestCase): + """ + From https://github.com/cmhughes/latexindent.pl/tree/main/test-cases/oneSentencePerLine + """ + + def test_dbmrq(self): + """ + Important difference: whitespace before and after commands is preserved. + """ + + text = r""" +A distinção entre conteúdo \emph{real} e conteúdo \emph{intencional} está +relacionada, ainda, à distinção entre o conceito husserliano de +\emph{experiência} e o uso popular desse termo. No sentido comum, +o \term{experimentado} é um complexo de eventos exteriores, +e o \term{experimentar} consiste em percepções (além de julgamentos e outros +atos) nas quais tais eventos aparecem como objetos, e objetos frequentemente +relacionados ao ego empírico. Nesse sentido, diz-se, por exemplo, que se +\term{experimentou} uma guerra. No sentido fenomenológico, no entanto, +é evidente que os eventos ou objetos externos não estão dentro do ego que os +experimenta, nem são seu conteúdo ou suas partes constituintes +\cite[5.][3]{lu}. Experimentar eventos exteriores, nesse sentido, significa +direcionar certos atos de percepção a tais eventos, de modo que certos +conteúdos constituem, então, uma unidade de consciência no fluxo unificado de +um ego empírico. Nesse caso, temos um todo \emph{real} do qual se pode dizer +que cada parte é de fato \emph{experimentada}. Enquanto no primeiro sentido há +uma distinção entre o conteúdo da consciência e aquilo que é experimentado +(e.g.\, entre a sensação e aquilo que é sentido), nesse último sentido aquilo +que o ego ou a consciência experimenta \emph{é} seu conteúdo. + """ + + formatted = r""" +A distinção entre conteúdo \emph{real} e conteúdo \emph{intencional} está relacionada, ainda, à distinção entre o conceito husserliano de +\emph{experiência} e o uso popular desse termo. +No sentido comum, o \term{experimentado} é um complexo de eventos exteriores, e o \term{experimentar} consiste em percepções (além de julgamentos e outros atos) nas quais tais eventos aparecem como objetos, e objetos frequentemente relacionados ao ego empírico. +Nesse sentido, diz-se, por exemplo, que se +\term{experimentou} uma guerra. +No sentido fenomenológico, no entanto, é evidente que os eventos ou objetos externos não estão dentro do ego que os experimenta, nem são seu conteúdo ou suas partes constituintes +\cite[5.][3]{lu}. +Experimentar eventos exteriores, nesse sentido, significa direcionar certos atos de percepção a tais eventos, de modo que certos conteúdos constituem, então, uma unidade de consciência no fluxo unificado de um ego empírico. +Nesse caso, temos um todo \emph{real} do qual se pode dizer que cada parte é de fato \emph{experimentada}. +Enquanto no primeiro sentido há uma distinção entre o conteúdo da consciência e aquilo que é experimentado (e.g.\, entre a sensação e aquilo que é sentido), nesse último sentido aquilo que o ego ou a consciência experimenta \emph{é} seu conteúdo. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_dbmrq3(self): + """ + Important difference: whitespace before and after commands is preserved. + """ + + text = r""" +\some{ +\mycommand{ +\begin{something} +A distinção entre conteúdo \emph{real} e conteúdo \emph{intencional} está +relacionada, ainda, à distinção entre o conceito husserliano de +\emph{experiência} e o uso popular desse termo. No sentido comum, +o \term{experimentado} é um complexo de eventos exteriores, +e o \term{experimentar} consiste em percepções (além de julgamentos e outros +atos) nas quais tais eventos aparecem como objetos, e objetos frequentemente +relacionados ao ego empírico. Nesse sentido, diz-se, por exemplo, que se +\term{experimentou} uma guerra. No sentido fenomenológico, no entanto, +é evidente que os eventos ou objetos externos não estão dentro do ego que os +experimenta, nem são seu conteúdo ou suas partes constituintes +\cite[5.][3]{lu}. Experimentar eventos exteriores, nesse sentido, significa +direcionar certos atos de percepção a tais eventos, de modo que certos +conteúdos constituem, então, uma unidade de consciência no fluxo unificado de +um ego empírico. Nesse caso, temos um todo \emph{real} do qual se pode dizer +que cada parte é de fato \emph{experimentada}. Enquanto no primeiro sentido há +uma distinção entre o conteúdo da consciência e aquilo que é experimentado +(e.g.\, entre a sensação e aquilo que é sentido), nesse último sentido aquilo +que o ego ou a consciência experimenta \emph{é} seu conteúdo. +\end{something} +} +} + """ + + formatted = r""" +\some{ + \mycommand{ + \begin{something} + A distinção entre conteúdo \emph{real} e conteúdo \emph{intencional} está relacionada, ainda, à distinção entre o conceito husserliano de + \emph{experiência} e o uso popular desse termo. + No sentido comum, o \term{experimentado} é um complexo de eventos exteriores, e o \term{experimentar} consiste em percepções (além de julgamentos e outros atos) nas quais tais eventos aparecem como objetos, e objetos frequentemente relacionados ao ego empírico. + Nesse sentido, diz-se, por exemplo, que se + \term{experimentou} uma guerra. + No sentido fenomenológico, no entanto, é evidente que os eventos ou objetos externos não estão dentro do ego que os experimenta, nem são seu conteúdo ou suas partes constituintes + \cite[5.][3]{lu}. + Experimentar eventos exteriores, nesse sentido, significa direcionar certos atos de percepção a tais eventos, de modo que certos conteúdos constituem, então, uma unidade de consciência no fluxo unificado de um ego empírico. + Nesse caso, temos um todo \emph{real} do qual se pode dizer que cada parte é de fato \emph{experimentada}. + Enquanto no primeiro sentido há uma distinção entre o conteúdo da consciência e aquilo que é experimentado (e.g.\, entre a sensação e aquilo que é sentido), nesse último sentido aquilo que o ego ou a consciência experimenta \emph{é} seu conteúdo. + \end{something} + } +} + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_dot_followed_by_tilde(self): + text = r""" +Here is a sentence (Fig.~\ref{dummy18}). Here is another sentence (Fig.~\ref{dummy19}). + """ + + formatted = r""" +Here is a sentence (Fig.~\ref{dummy18}). +Here is another sentence (Fig.~\ref{dummy19}). + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_issue_321(self): + text = r""" +\documentclass{article} + +\begin{document} + +I.e.\ it is a finite constant. + +\end{document} + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), text.strip()) + + def test_issue_355(self): + text = r""" +This is a very long sentence that I would like to be cut at the set line width which is however currently not done. +Sentences are put on different lines. +This is a very long sentence that is formatted like it should and it +should therefore not be touched by the formatter. + """ + + formatted = r""" +This is a very long sentence that I would like to be cut at the set line width which is however currently not done. +Sentences are put on different lines. +This is a very long sentence that is formatted like it should and it should therefore not be touched by the formatter. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_issue_376(self): + text = r""" +For a slip event at interface $s$, we have $\Delta R_s > 0$ and $\Delta R_i = 0$ for $i \neq s$, inducing +\begin{equation} + \label{eq:delta_fi} + \Delta f_i = K\Delta R_s \,\, \mathrm{for} \,\, i \geq s ; \quad \Delta f_i=0 \,\, \mathrm{otherwise}. +\end{equation} +We can then deduce that +\begin{equation} + \label{eq:DR_DF_multi} + \Delta F = \frac{h K}{H} \Delta R_s \sum\limits_{i=s}^n i \, = \frac{h K}{H}\Delta R_s (n+s)(n-s+1) / 2. +\end{equation} +which we verify in \cref{fig:2c}. + """ + + formatted = r""" +For a slip event at interface $s$, we have $\Delta R_s > 0$ and $\Delta R_i = 0$ for $i \neq s$, inducing +\begin{equation} + \label{eq:delta_fi} + \Delta f_i = K\Delta R_s \,\, \mathrm{for} \,\, i \geq s ; \quad \Delta f_i=0 \,\, \mathrm{otherwise}. +\end{equation} +We can then deduce that +\begin{equation} + \label{eq:DR_DF_multi} + \Delta F = \frac{h K}{H} \Delta R_s \sum\limits_{i=s}^n i \, = \frac{h K}{H}\Delta R_s (n+s)(n-s+1) / 2. +\end{equation} +which we verify in \cref{fig:2c}. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_issue_392(self): + r""" + Difference with ``latexindent.pl``: abbrivations not automatically recognized. + Instead use ``"~"`` or ``"\ "`` to have a space after the abbreviation. + """ + + text = r""" +\section{e.G. example} +some text with. e.G.~A sentence. + +\section{E.G. example} +some text with. e.G.\ A sentence. + +\subsection{Ph.D. example} +other text. Ph.D.\ With sentences. + """ + + formatted = r""" +\section{e.G. example} +some text with. +e.G.~A sentence. + +\section{E.G. example} +some text with. +e.G.\ A sentence. + +\subsection{Ph.D. example} +other text. +Ph.D.\ With sentences. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_kiryph1(self): + """ + Difference: comment left in place. + """ + + text = r""" +Xx xxxxxxxx, xxx xxxxxxxx xxxxxxxxxx, xxxxxxxxxx xxxxxxxxxxx xxxxxxxx xx x + xxxxxxxx xx xxxx xx xxxxxxx \enquote{xxxxxx xxxx xxxxxxxxx}% + \cite{XxxxxXxXx:xxxx}. + Xxxx x xxxxxxxx xx xxxxxx \emph{xxxxxxx} \cite{XxxxxXxXx:xxxx} xxx xx + xxxxxxxx xxxxxxxxxxxxx xx x xxxxxxxx \emp{Xxxxxxx'x xxxxx}. + """ + + formatted = r""" +Xx xxxxxxxx, xxx xxxxxxxx xxxxxxxxxx, xxxxxxxxxx xxxxxxxxxxx xxxxxxxx xx x xxxxxxxx xx xxxx xx xxxxxxx \enquote{xxxxxx xxxx xxxxxxxxx}% +\cite{XxxxxXxXx:xxxx}. +Xxxx x xxxxxxxx xx xxxxxx \emph{xxxxxxx} \cite{XxxxxXxXx:xxxx} xxx xx xxxxxxxx xxxxxxxxxxxxx xx x xxxxxxxx \emp{Xxxxxxx'x xxxxx}. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_konfect(self): + text = r""" +The filter does different things depending on the file format; + in most cases + it is determined on the output of the "file" command [2], [6], that recognizes + lots of formats. + +C'est bon; à six +heures on y va. + """ + + formatted = r""" +The filter does different things depending on the file format; in most cases it is determined on the output of the "file" command [2], [6], that recognizes lots of formats. + +C'est bon; à six heures on y va. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_mlep(self): + r""" + Difference with ``latexindent.pl``: abbrivations not automatically recognized. + Instead use ``"~"`` or ``"\ "`` to have a space after the abbreviation. + """ + + text = r""" +This is an example (i.e.~a test). The unit is $\rm kg.m^{-2}.s^{-1}$. Values goes from 0.02 to 0.74 Pa. Here some space needed \hspace{0.5cm}. The value is $\lambda=3.67$. The URL is \url{www.scilab.org}. + """ + + formatted = r""" +This is an example (i.e.~a test). +The unit is $\rm kg.m^{-2}.s^{-1}$. +Values goes from 0.02 to 0.74 Pa. +Here some space needed \hspace{0.5cm}. +The value is $\lambda=3.67$. +The URL is \url{www.scilab.org}. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_mlep2(self): + text = r""" +The names (Smith, Doe, etc.) are inherited. + +Two items are used: +\begin{itemize} + \item Item 1. + \item Item 2. +\end{itemize} + +The energy is defined as +\begin{equation} + E=m c^2 +\end{equation} +where m is the mass. + +\begin{table}[htbp] + \caption{\label{tab1} Here is the legend.} + \begin{tabular}{cc} + 1 & 1 \\ + \end{tabular} +\end{table} + +This is a sentence. + +\begin{table}[htbp] + \caption{\label{tab1} Here is the legend.} + \begin{tabular}{cc} + 1 & 1 \\ + \end{tabular} +\end{table} + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), text.strip()) + + def test_more_code_blocks(self): + text = r""" +\section*{Executive Summary} +Sonifications are non-verbal representation of plots or graphs. +This report details the results of an eSTEeM-funded project +to investigate the efficacy of sonifications when presented to +participants in study-like activities. We are grateful to eSTEeM +for their support and funding throughout the project. + +\tableofcontents +\section{Introduction} +The depiction of numerical data using graphs and charts play a vital part in many STEM modules. As Tufte says in a key text about the design of plots and charts ``at their best graphics are instruments for reasoning about quantitative measurement'' \cite{Tufte1983}. In this report we will focus on static images, such as graphs and plots in printed materials. Dynamic images in which the user can change +features of the diagram or graph are not considered. In order to meet the OU's mission of being open to [all] people, such plots and graphs need to be accessible to \emph{all} students, as some students may otherwise be disadvantaged in their study. + +The Equality Act 2010 \cite{ehrcequalityact} requires universities to avoid discrimination against people with protected characteristics, +including disability, and to do so by making `reasonable adjustments'. The Equality and Human Rights Commission offers guidance +for Higher Education providers \cite{ehrcprovidersguidance}. The Act created the Public Sector Equality Duty \cite{ehrcpublicsector}, which +requires universities to promote equality of opportunity by removing disadvantage and meet the needs of protected groups. +In the context of The Open University, this means that the authors of module materials should ensure that plots and charts (or alternate versions of them) are accessible to all students with visual impairments, including those students with no vision at all. + +Individuals who are blind have often had limited access to mathematics and science \cite{advisorycommission}, +especially in distance learning courses \cite{educause}; in part this is because of the highly visual nature of the representations of numerical relationships. Methods commonly used to accommodate learners who are blind or have low vision include: use of sighted assistants who can describe graphics verbally; provision of text-based descriptions of graphics that can be read with text-to-speech applications (for example JAWS \cite{jaws}, Dolphin \cite{dolphin}); accessed as Braille, either as hard copy or via refreshable display, or through provision of tactile graphics for visual representations. + +Desirable features of an accessible graph include the following \cite{Summers2012}: +\begin{itemize} + \item Perceptual precision: the representation allows the user to interpret the plot with an appropriate amount of detail. + \item First-hand access: the representation allows the user to directly interpret the data and is not reliant on subject interpretation by others (bias). + \item Works on affordable, mainstream hardware. + \item Born-accessible: the creator of the plot would not have to put extra effort into creating the accessible version. +\end{itemize} + +\begin{figure}[!htb] + \centering + \figureDescription{Screenshot of participant S7 interacting with the ferris wheel example.} + \includegraphics[width=.5\textwidth]{p7-ferris-wheel} + \caption{Visualisation of the sonification from S7.} + \label{fig:partipants-ferris-wheel} +\end{figure} + """ + + formatted = r""" +\section*{Executive Summary} +Sonifications are non-verbal representation of plots or graphs. +This report details the results of an eSTEeM-funded project to investigate the efficacy of sonifications when presented to participants in study-like activities. +We are grateful to eSTEeM for their support and funding throughout the project. + +\tableofcontents +\section{Introduction} +The depiction of numerical data using graphs and charts play a vital part in many STEM modules. +As Tufte says in a key text about the design of plots and charts ``at their best graphics are instruments for reasoning about quantitative measurement'' \cite{Tufte1983}. +In this report we will focus on static images, such as graphs and plots in printed materials. +Dynamic images in which the user can change features of the diagram or graph are not considered. +In order to meet the OU's mission of being open to [all] people, such plots and graphs need to be accessible to \emph{all} students, as some students may otherwise be disadvantaged in their study. + +The Equality Act 2010 \cite{ehrcequalityact} requires universities to avoid discrimination against people with protected characteristics, including disability, and to do so by making `reasonable adjustments'. +The Equality and Human Rights Commission offers guidance for Higher Education providers \cite{ehrcprovidersguidance}. +The Act created the Public Sector Equality Duty \cite{ehrcpublicsector}, which requires universities to promote equality of opportunity by removing disadvantage and meet the needs of protected groups. +In the context of The Open University, this means that the authors of module materials should ensure that plots and charts (or alternate versions of them) are accessible to all students with visual impairments, including those students with no vision at all. + +Individuals who are blind have often had limited access to mathematics and science \cite{advisorycommission}, especially in distance learning courses \cite{educause}; in part this is because of the highly visual nature of the representations of numerical relationships. +Methods commonly used to accommodate learners who are blind or have low vision include: use of sighted assistants who can describe graphics verbally; provision of text-based descriptions of graphics that can be read with text-to-speech applications (for example JAWS \cite{jaws}, Dolphin \cite{dolphin}); accessed as Braille, either as hard copy or via refreshable display, or through provision of tactile graphics for visual representations. + +Desirable features of an accessible graph include the following \cite{Summers2012}: +\begin{itemize} + \item Perceptual precision: the representation allows the user to interpret the plot with an appropriate amount of detail. + \item First-hand access: the representation allows the user to directly interpret the data and is not reliant on subject interpretation by others (bias). + \item Works on affordable, mainstream hardware. + \item Born-accessible: the creator of the plot would not have to put extra effort into creating the accessible version. +\end{itemize} + +\begin{figure}[!htb] + \centering + \figureDescription{Screenshot of participant S7 interacting with the ferris wheel example.} + \includegraphics[width=.5\textwidth]{p7-ferris-wheel} + \caption{Visualisation of the sonification from S7.} + \label{fig:partipants-ferris-wheel} +\end{figure} + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_multiple_sentences9(self): + text = r""" +This paragraph% first comment +has line breaks throughout its paragraph;% second comment +we would like to combine% third comment +the textwrapping% fourth comment +and paragraph removal routine. % fifth comment + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), text.strip()) + + def test_other_begins(self): + text = r""" +This is the first +sentence. 7 is the second +sentence. This is the +third sentence. + +This is the fourth +sentence! This is the fifth sentence? This is the +sixth sentence. $a$ is often +referred to as +an integer. furthermore +we have that. + """ + + formatted = r""" +This is the first sentence. +7 is the second sentence. +This is the third sentence. + +This is the fourth sentence! +This is the fifth sentence? +This is the sixth sentence. +$a$ is often referred to as an integer. +furthermore we have that. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_pcc_program_review1(self): + text = r""" +% arara: pdflatex: {files: [MathSACpr2014]} +% !arara: indent: {overwrite: yes} +\chapter{Facilities and Support} +\begin{flushright} + \includegraphics[width=8cm]{xkcd-806-tech_support-punchline}\\ + \url{http://xkcd.com} +\end{flushright} +\section[Space, technology, and equipment]{Describe how classroom space, classroom technology, laboratory space +and equipment impact student success.} + +Over the past few years, efforts by the college to create classrooms containing +the same basic equipment has helped tremendously with consistency issues. The +nearly universal presence of classroom podiums with attendant Audio Visual (AV) devices is +considerably useful. For example, many instructors use computer-based +calculator emulators when instructing their students on calculator use---this +allows explicit keystroking examples to be demonstrated that were not possible +before the podiums appeared; the document cameras found in most classrooms are +also used by most mathematics instructors. Having an instructor computer with +internet access has been a great help as instructors have access to a wide +variety of tools to engage students, as well as a source for quick answers when +unusual questions arise. + +Several classrooms on the Sylvania campus have Starboards or Smart Boards +integrated with their AV systems. Many mathematics instructors use these tools +as their primary presentation vehicles; documents can be preloaded into the +software and the screens allow instructors to write their work directly onto +the document. Among other things, this makes it easy to save the work into pdf +files that can be accessed by students outside of class. This equipment is not +used as much on the other campuses, but there are instructors on other campuses +that say they would use them if they were widely available on their campus. + +A few instructors have begun creating lessons with LiveScribe technology. The +technology allows the instructor to make an audio/visual record of their +lecture without a computer or third person recording device; instructors can +post a `live copy' of their actual class lecture online. The students do not +simply see a static copy of the +notes that were written; the students see the notes emerge as they were being +written and they hear the words that were spoken while they were written. The +use of LiveScribe technology is strongly supported by Disability Services, and +for that reason alone continued experimentation with its use is strongly +encouraged. + +Despite all of the improvements that have been made in classrooms over the past +few years, there still are some serious issues. + +Rooms are assigned randomly, which often leads to mathematics classes being +scheduled in rooms that are not appropriate for a math class. For example, +scheduling a math class in a room with individual student desks creates a lot +of problems; many instructors have students take notes, refer to their text, +and use their calculator all at the same time and there simply is not enough +room on the individual desktops to keep all of that material in place. More +significantly, this furniture is especially ill-suited for group work. Not +only does the movement of desks and sharing of work exacerbate the materials +issue (materials frequently falling off the desks), students simply cannot +share their work in the efficient way that work can be shared when they are +gathered about tables. It would be helpful if all non-computer-based math +classes could be scheduled in rooms with tables. + +Another problem relates to an inadequate number of computerized classrooms and +insufficient space in many of the existing computerized classroom; both of +these shortages have greatly increased due to Bond-related construction. +Several sections of MTH 243 and MTH 244 (statistics courses), which are +normally taught in computerized classrooms, \emph{have} been scheduled in regular +classrooms. Many of the statistics courses that were scheduled in +computerized classrooms have been scheduled in rooms that seat only 28, 24, or +even 20 students. When possible, we generally limit our class capacities at 34 +or 35. Needless to say, running multiple sections of classes in rooms well +below those capacities creates many problems. This is especially problematic +for student success, as it hinders students' ability to register due to +undersized classrooms. + +Finally, the computerized classrooms could be configured in such a way that +maximizes potential for meaningful student engagement and minimizes potential +for students to get off course due to internet access. We believe that all +computerized classrooms need to come equipped with software that allows the +instructor control of the student computers such as LanSchool Classroom +Management Software. The need for this technology is dire; it will reduce or +eliminate students being off task when using computers, and it will allow +another avenue to facilitate instruction as the instructor will be able to +`see' any student computer and `interact' with any student computer. It can +also be used to solicit student feedback in an anonymous manner. The gathering +of anonymous feedback can frequently provide a better gauge of the general +level of understanding than activities such as the traditional showing of +hands. + +\recommendation[Scheduling]{All mathematics classes should be scheduled in rooms that are either + computerized (upon request) or have multi-person tables (as opposed to +individual desks).} + +\recommendation[Scheduling, Deans of Instruction, PCC Cabinet]{All computerized classrooms + should have at least 30, if not 34, individual work +stations.} + +\recommendation[Multimedia Services, Deans of Instruction, PCC Cabinet]{An adequate number of classrooms on all campuses should be equipped with + Smartboards so that all instructors who want access to the technology can teach +every one of their classes in rooms equipped with the technology.} + +\recommendation[Multimedia Services, TSS]{The disk image for all computerized classrooms should include software that + allows the podium computer direct access to each student +computer. } + +\section[Library and other outside-the-classroom information +resources]{Describe how students are using the library or other +outside-the-classroom information resources. } +We researched this topic by conducting a stratified sampling method +survey of 976 on-campus students and 291 online students; the participants were +chosen in a random manner. We gave scantron surveys to the on-campus students +and used SurveyMonkey for the online students. We found that students are +generally knowledgeable about library resources and other outside-the-classroom +resources. The complete survey, together with its results, is given in +\vref{app:sec:resourcesurvey}; we have summarized our comments to some of the +more interesting questions below. + +\begin{enumerate}[label=Q\arabic*.,font=\bf] + \item Not surprisingly, library resources and other campus-based resources + are used more frequently by our on-campus students than by our online + students. This could be due to less frequent visits to campus for online + students and/or online students already having similar resources available + to them via the internet. + \item We found that nearly 70\% of instructors include resource information + in their syllabi. This figure was consistent regardless of the level of + the class (DE/transfer level) or the employment status of the instructor + (full/part-time). + + We found that a majority of our instructors are using online resources to + connect with students. Online communication between students and + instructors is conducted across many platforms such as instructor websites, + Desire2Learn, MyPCC, online graphing applications, and online homework + platforms. + + We found that students are using external educational websites such as + \href{https://www.khanacademy.org/}{Khan Academy}, + \href{http://patrickjmt.com/}{PatrickJMT}, + \href{http://www.purplemath.com/}{PurpleMath}, and + \href{http://www.youtube.com/}{YouTube}. The data suggest online + students use these services more than on-campus students. + \item The use of online homework (such as WeBWorK, MyMathLab, MyStatLab, and + ALEKS) has grown significantly over the past few years. However, the data + suggests that significantly more full-time instructors than part-time + instructors are directing their students towards these tools (as either a + required or optional component of the course). Additionally, there is a + general trend that online homework programs are being used more frequently + in online classes than in on-campus classes. Both of these discrepancies + may reflect the need to distribute more information to faculty about these + software resources. + \item The Math SAC needs to address whether or not we should be requiring + students to use online resources that impose additional costs upon the + students and, if so, what would constitute a reasonable cost to the + student. To that end, our survey asked if students would be willing to pay + up to \$35 to access online homework and other resources. We found that + online students were more willing to pay an extra fee than those enrolled + in on-campus classes. + \setcounter{enumi}{6} + \item The PCC mathematics website offers a wealth of materials that are + frequently accessed by students. These include course-specific supplements, + calculator manuals, and the required Calculus I lab manual; all of these + materials were written by PCC mathematics faculty. Students may print + these materials for free from any PCC computer lab. The website also links + to PCC-specific information relevant to mathematics students (such as + tutoring resources) as well as outside resources (such as the Texas + Instruments website). + \setcounter{enumi}{8} + \item In addition to the previously mentioned resources we also encourage + students to use resources offered at PCC such as on-campus Student Learning + Centers, online tutoring, Collaborate, and/or Elluminate. A significant + number of students registered in on-campus sections are using these + resources whereas students enrolled in online sections generally are not. + This is not especially surprising since on-campus students are, well, on + campus whereas many online students rarely visit a campus. +\end{enumerate} + +\recommendation[Math SAC]{The majority of our data suggests that students are using a variety of + resources to further their knowledge. We recommend that instructors continue to + educate students about both PCC resources and non-PCC resources. We need to + uniformly encourage students to use resources such as online tutoring, Student + Learning Centers, Collaborate, and/or Elluminate; this includes resource +citations in each and every course syllabus.} + +\recommendation[Faculty Department Chairs]{A broader education campaign should be engaged to distribute information to + part-time faculty regarding online homework such as WeBWorK, MyMathLab, +MyStatLab, and ALEKS. } + +\recommendation[Math SAC]{Instructors should consider quality, accessibility and cost to students when +requiring specific curriculum materials. } + +\section[Clerical, technical, administrative and/or tutoring support]{Provide +information on clerical, technical, administrative and/or tutoring support.} + +The Math SAC has a sizable presence on each of PCC's three campuses and at Southeast Center (soon to be +a campus in its own right). Each campus houses a math department within a +division of that campus. The clerical, technical, administrative, and tutoring +support systems are best described on location-by-location basis. + +\subsection{Clerical, technical, and administrative support} + +Across the district, our SAC has an excellent and very involved administrative +liaison, Dr. Alyson Lighthart. We would like to thank her for her countless +hours of support in attending our SAC meetings and being available to the SAC +Co-Chairs. She provides us with thoughtful feedback and insightful perspectives +that help us gather our thoughts and make sound decisions. + +\subsubsection{Cascade} +The Cascade math department belongs to the Math, Sciences, Health and PE +division. The math department is located on the third floor of the student +services building, sharing a floor with the ROOTS office. The math department +also shares space with allied health support staff, medical professions +faculty, medical assisting faculty and the Cascade academic intervention +specialists (one of whom is also a math part-time faculty). Part-time math +faculty share 11 cubicles, each with a computer. Our 7 full-time instructors +are paired in offices that open up to the part-time cubicles. We have space in +our offices for another full time faculty member as we lost a temporary +full-time position at the start of the 2013 academic year. In Winter 2014, a +collective 42 faculty share one high speed Ricoh printer and one copy machine. +Our division offices are located in another building. We have a dedicated +administrative assistant at the front desk who helps students and faculty most +days from 8 {\sc a.m.--5 p.m.} + +\subsubsection{Rock Creek} +The Rock Creek math department is located in the same floor as the division it +belongs to (Mathematics, Aviation, and Industrial Technology) and it is shared +with Computer Science. Part-time faculty share fourteen cubicles, each with a +computer, located in the same office as full-time instructors, that are used to +prepare and meet with students. The sixty-five plus faculty share two high +speed printers that can collate, staple and allow double sided printing, and +one high speed scanner. Currently we have reached space capacity and we will +have to re-think the current office configuration in order to add one more +full-time faculty member next Fall. Two years ago the Rock Creek math +department added a dedicated administrative assistant, which has helped with +scheduling needs, coordinating part-time faculty needs, and providing better +service to the students. + +\subsubsection{Southeast} +The clerical and administrative setup at Southeast has changed, as of Winter +2014. There was a recent restructuring of divisions. What used to be the +Liberal Arts and Sciences Division split into two divisions: the Liberal Arts +and CTE Division (which is in the first floor of Scott Hall, Room 103, where +the Liberal Arts and Sciences used to be) and the Math and Science Division +(which is on the \nth{2} floor of the new Student Commons Building, Room 214). +All of the math and science faculty are now in this new space, including the +part-time instructors (everybody was scattered before, so this is a welcome +change). + +All of the department chairs have their own offices (with doors), while the +rest of the faculty (full-time and part-time) occupy cubicle spaces +(approximately 20 cubicles in the space, shared by 4--5 faculty per cubicle). +There are two administrative assistants, one of whom is with the math and +science faculty and the other of whom is in charge of the STEM program. There +is also one clerical staff member. + +There is one Ricoh printer in the space, along with a fax machine. Any and all +supplies (markers, erasers, etc.) are located across the hall in a designated +staff room. + +\subsubsection{Sylvania} +The Sylvania math department belongs to the Math and Industrial Technology +division, which is located in the neighboring automotive building. The math +department is currently located in two separate areas of adjacent buildings as +of Fall 2013, when the developmental math faculty officially merged with the +math department. This separation will soon be remedied by construction of the +new math department area, scheduled to be completed during Spring 2014. This +new location will be next door to the Engineering department, and will share a +conference room, copy machine room, and kitchen. The math department will +include two department chair offices, seventeen full-time instructor cubicles, +six additional cubicles shared by part-time faculty, and two flex-space rooms. +Each of the cubicles will have a computer, and there will be two shared laser +printers plus one color scanner in the department office. + +Our two administrative assistants work an overlapped schedule, which provides +dual coverage during the busy midday times and allows the office to remain +open to students and visitors for eleven hours. These assistants do an +incredible job serving both student and faculty needs, including: scheduling +assistance, interfacing with technical support regarding office and classroom +equipment, maintaining supplies inventory, arranging for substitute +instructors, securing signatures and processing department paperwork, guiding +students to campus resources, and organizing syllabi and schedules from +approximately 70 math instructors. + +Our math department has frequent interaction with both Audio-Visual and +Technology Solution Services. Responses by AV to instructor needs in the +classroom are extremely prompt--typically within minutes of the notification of +a problem. Since the math department is very technology-oriented, we have many +needs that require the assistance of TSS. Work orders for computer equipment +and operational issues that arise on individual faculty computers can take +quite a long time to be implemented or to be resolved. This may be due to the +sheer volume of requests that they are processing, but more information during +the process, especially notes of any delays, would be welcomed. + +\subsection{Tutoring support} +PCC has a Student Learning Center (SLC) on each campus. It is a +testament to PCC's commitment to student success that the four SLCs exist. +However, discrepancies such as unequal distribution of resources, inconsistency +in the number and nature of tutors (including faculty `donating time' to the +centers), and disparate hours +of operation present challenges to students trying to navigate their way +through different centers. + +\recommendation[PCC Cabinet, Deans of Students, Deans of Instructions, Student Learning Centers]{The college should strive for more + consistency with its Student Learning Centers. We feel that the centers would + be an even greater resource if they were more consistent in structure, resource +availability, physical space, and faculty support.} + +Over the last five years the general environment of PCC has been greatly +impacted by historically-unmatched enrollment growth (see +\vref{fig:sec3:DLenrollments,fig:sec3:F2Fenrollments}). PCC's four Student +Learning Centers have been greatly affected by this (see \vref{app:sec:tutoringhours}). +Most notably, the number of students seeking math tutoring has +increased dramatically. Unfortunately, this increase in student need has not +been met by increase in tutors or tutoring resources. As a result the +amount of attention an individual student receives has decreased in a +substantive way, leaving students often frustrated and without the help they +needed. Consequently, the numbers of students dropped again as students stopped +even trying. While some of this growth has been (or will be) accommodated +by increasing the physical space available for tutoring (i.e., by the +construction of new facilities at Rock Creek and Southeast), +that is still not enough since personnel resources were not increased at the +same rate and work-study awards have been decreased significantly. A +comprehensive plan needs to be developed and implemented that will ensure each +and every student receives high-quality tutoring in a consistent and +consistently accessible manner. + +As it now stands, the operation of the SLCs is completely campus driven. As +such, reporting on the current status needs to be done on a campus-by-campus +basis. + +\subsubsection{Cascade} +Averaging over non-summer terms from Fall 2008 to Spring 2013, the Cascade SLC has served about +680 math students with 3900 individual visits and 8 hours per student per term. +(See \vref{app:tut:tab:SLC} for a full accounting.) + +The Cascade SLC has increased its operating hours in response to student +demand. Statistics tutoring is now offered at most times and the introduction of +online homework has led to `Hybrid Tutoring', where students receive tutoring +while working on their online homework. + +At the Cascade Campus, all full-time mathematics instructors and many part-time +mathematics instructors volunteer 1--4 hours per week in the SLC to help with +student demand. To help ensure usage throughout the SLC's operational hours, +instructors are notified by email of slow-traffic times; this allows the +instructors to direct students who need extra help to take advantage of those +times. Other communications such as announcements, ads, and newsletters are +sent out regularly. + +Full-time faculty have constructed a `First week lecture series' that they +conduct on the first Friday of every term (except summer). It is designed to +review basic skills from MTH 20 through MTH 111. It is run in 50-minute +segments throughout the day with a 10-minute break between each segment. The +first offering of this series began in Winter 2012 with 100 students in +attendance; the attendance has since grown steadily and was up to +approximately 300 students by Fall 2013. + +The Cascade SLC has formalized both the hiring process and the training process +for casual tutors. The department chairs interview potential tutors, determine +which levels they are qualified to tutor, and give guidance as to tutoring +strategies and rules. During their first term, each new tutor is always +scheduled in the learning center at the same time as a math instructor, and is +encouraged to seek math +and tutoring advice from that instructor. + +\subsubsection{Rock Creek} +Averaging over non-summer terms from Fall 2008 to Spring 2013, the Rock Creek SLC has served about +690 math students with 3300 individual visits and 10 hours per student per term. (See \vref{app:tut:tab:SLC} for a full accounting.) + +Everyone who works and learns in the Rock Creek SLC is looking forward to +moving into the newly-built space in Building 7 by Spring 2014. The new space +will bring the SLC closer to the library and into the same building as the WRC, +MC, and TLC. Students seek tutoring largely in math and science, but +increasingly for accounting, computer basics, and also college reading. +Mathematics full-time faculty hold two of the required five office hours at the +tutoring center. + +Motivated by the high levels of student demand for math tutoring, in 2012/13 +the SLC piloted math tutoring by appointment two days per week. On each of the +two days a tutor leads thirty-minute individual sessions or one-hour group +tutoring sessions by appointment for most math levels. After some tweaking of +days and times, we have settled on Tuesdays and Wednesdays. Students who are +seeking a longer, more personalized or intensive tutoring session seem to +highly appreciate this new service. + +Finally, the Rock Creek SLC has benefited over the last three years from collaboration +with advisors, counselors, librarians, the WRC, MC, and the Career Resource +Center in offering a wide variety of workshops as well as resource fairs to +support student learning. + +\subsubsection{Southeast} +Averaging over non-summer terms from Fall 2008 to Spring 2013, the Southeast SLC has served about +280 math students with 1200 individual visits and 5 hours per student per term. (See \vref{app:tut:tab:SLC} for a full accounting.) + +The SE SLC staff is looking forward to its move into the new tutoring center +facilities when the new buildings are completed. In the meantime, it has +expanded the math tutoring area by moving the writing tutoring to the back room +of the tutoring center. + +Since the SE Tutoring Center opened in 2004, it has gone from serving an +average of 200 students per term (including math and other subjects) to serving +an average of 350 students per term in math alone. With this increase in +students +seeking assistance, the staff has also grown; the SE SLC now has several faculty +members who work part time in the tutoring center. + +Many SE math faculty members donate time to the tutoring center. We have +developed a service learning project where calculus students volunteer their +time in the tutoring center; this practice has been a great help to +students who utilize the tutoring center as well as a great opportunity for +calculus students to cement their own mathematical skills. + +\subsubsection{Sylvania} +Averaging over non-summer terms from Fall 2008 to Spring 2013, the Sylvania SLC has served about +1100 math students with 6200 individual visits and 7 hours per student per +term. (See \vref{app:tut:tab:SLC} for a full accounting.) + +The Sylvania SLC moved into a new location in Fall 2012; it is now in +the Library building, together with the Student Computing Center. The creation +of a learning commons is working out well and students are taking advantage of +having these different study resources in one place. Unfortunately, the new SLC +has less space available for math tutoring than the prior Student Success Center +which has been addressed by restructuring the space. Since enrollment remains high, having enough space +for all students seeking help remains a challenge. + +PCC's incredible growth in enrollment created an attendant need for a dramatic +increase in the number of tutors available to students. This increased need has +been partially addressed by an increase in the budget set aside for paid tutors +as well as a heightened solicitation for volunteer tutors. Many +instructors (both full-time and part-time) have helped by volunteering in the +Sylvania SLC; for several years, the center was also able to recruit up to 10 +work-study tutors per academic year, but with recent Federal changes to +Financial Aid, the Math Center is now only allowed two work-study tutors per +year; this restriction has led to a decrease of up to 50 tutoring hours per +week. + +In addition to tutoring, the Sylvania SLC hosts the self-paced ALC math +classes, provides study material, and offers resources and workshops for +students to prepare for the Compass placement test. Efforts are also underway +to modernize a vast library of paper-based materials by putting them online and +making them available in alternate formats. + + +\section[Student services]{Provide information on how Advising, Counseling, +Disability Services and other student services impact students. } + +Perhaps more than ever, the Math SAC appreciates and values the role of student +services in fostering success for our +students. In our development of an NSF-IUSE proposal (see +\vref{over:subsub:nsfiuse}), discussions and +planning returned again and again to student services such as advising, +placement testing, and counseling. As we look ahead hopefully toward a +realization of the structure that we envisioned, we will keep these services as +essential partners in serving our students. The current status of these +services follows. + +\subsection{Advising and counseling} +The advising and counseling departments play a vital role in creating pathways +for student success; this is especially important when it comes to helping +students successfully navigate their mathematics courses. Historically there +have been incidents of miscommunication between various math departments and +their campus counterparts in advising, but over the past few years a much more +deliberate effort to build strong communication links between the two has +resulted in far fewer of these incidents. + +The advising departments have been very responsive to requests made by the +mathematics departments and have been clear that there are +policies in place that prevent them from implementing some of the changes we +would like. + +For example, in the past many advisers would make placement decisions based +upon criteria that the Math SAC felt weren't sufficient to support the +decision. One example of this was placing students into classes based upon a +university's prerequisite structure rather than PCC's prerequisite structure. +When the advisers were made aware that this frequently led to students +enrolling in courses for which they were not prepared for success, the advising +department instituted an ironclad policy not to give any student permission to +register for a course unless there was documented evidence that the student had +passed a class that could be transcribed to PCC as the PCC prerequisite for +the course. Any student who wants permission without a satisfied prerequisite +or adequate Compass score is now directed to a math faculty chair or to the +instructor of the specific section in which the student wishes to enroll. + +On the downside, there are things we would like the advisers to do that we +have come to learn they cannot do. For example, for several years the policy +of the Math SAC has been that prerequisites that were satisfied at other +colleges or universities would only be `automatically' accepted if they were +less than three years old. Many instructors in the math department were under +the impression that this policy was in place in the advising department, but it +was discovered in 2012 that not only is this policy \emph{not} in place but the +policy in fact cannot be enforced by anyone +(including math faculty). Apparently such a policy is enforceable only if +explicit prerequisite time-limits are written into the CCOGs. + +The advising department had been aware of the prerequisite issue for six or +seven years, but somehow the word had not been passed along to the general math +faculty. This serves as an example that both advising supervisors and the math +department chairs need to make every effort possible to inform all relevant +parties of policy changes in a clear and timely manner. Towards that end, the +math department at Sylvania Campus has now been assigned an official liaison in +the Sylvania advising department. and we believe that similar connections +should be created on the other campuses as well. + +With the college's new focus on student completion, the relationship between +the math departments and advising departments needs to become much stronger. +Initial placement plays a critical role in completion, as do other things such +as enrollment into necessary study skills classes and consecutive term-to-term +enrollment through a sequence of courses. We need to make sure that the +advisers have all of the tools necessary to help students make the best choices +and the advisers need to help us understand their perspective on the needs of +students enrolling in mathematics courses. To help establish this +collaborative environment, a Math SAC ad hoc committee has been formed to +investigate and address advising issues, placement issues, and study +skills issues; the committee is going to ask several people involved in +advising and counseling to join the committee. It has been speculated that +perhaps such a committee should not be under the direct purview of the Math +SAC; if the administration decides to create a similar committee under +someone else's direction we ask that any such committee have a large contingent +of math faculty. + +\recommendation[PCC Cabinet, Deans of Students, Advising]{All four campuses should have an + official advising liaison and the + four liaisons should themselves have an established relationship. Ideally we + would like to have one adviser at each campus dedicated solely to math advising +issues.} + +\recommendation[Math SAC, Advising, ROOTS]{ A committee consisting of advisers, + math faculty, and other relevant parties + (e.g.\ ROOTS representation) should be formed to investigate and establish + policies related to student success in mathematics courses. The issues to + investigate include, but are not limited to, placement, study skills, and +other college success skills as they relate to mathematics courses.} + +\subsection{Testing centers} +At the time we wrote our last program review there were very uneven procedures +at the various testing centers which caused a lot of problems; the +inconsistencies were especially problematic for online instructors and their +students---see \cite{mathprogramreview2003}, page 26 . We are pleased that the testing centers recognized that +inconsistency as a problem and they addressed the issue in a forthright way. +The testing centers now have uniform policies and they have made great strides +in making their services easily accessible to students and instructors alike. +For example, the ability to make testing arrangements online has been a +tremendous help as has the increase in the number of options by which a +completed exam can be returned to the instructor. + +A limited number of hours of operation remains a problem at each of the testing +centers; evening and weekend hours are not offered and testing times during +the remaining time are limited; for example, the Cascade Testing Center +offers only four start times for make up exams exam week. It appears to us that the size of the +facilities and the number of personnel have not increased in equal parts with +the dramatic increase in enrollment. It also appears that the testing centers +have not been given adequate funding to offer hours that accommodate students +who can only come to campus during the evening or on a weekend. + +This lack of access can be especially problematic for students registered in +math courses. The majority of the math courses at PCC are taught by part-time +faculty and these faculty members do not have the same flexibility in their +schedule as full-time faculty to proctor their own exams; as such they are +especially dependent on the testing centers for make-up testing. This +dependency is all the more problematic since many part-time faculty teach +evening or Saturday classes and many of the students in those classes find it +difficult to come to campus during `normal business hours.' Additionally, the +Sylvania math department simply does not have the space required to +administer make-up testing in the office, so 100\% of its faculty are dependent +upon the testing centers for make-up testing; we realize this puts a strain +on the testing centers. + +\recommendation[PCC Cabinet]{We recommend that the space and staffing in the +testing centers be increased.} + +\recommendation[PCC Cabinet, Deans of Students, Testing Centers]{We recommend that make-up + testing be available as late as 9:00 {\sc p.m.}\ at least two days per week, +and that make-up testing hours be available every Saturday.} + +As discussed on \cpageref{other:page:disabilityservices,needs:page:disabilityservices}, +the Math SAC has a very positive and productive relationship with disability +services. For example, disability services was very responsive when some +instructors began to question accommodation requests that contradicted specific +evaluation criteria mandated in CCOGs (e.g.~testing certain material without +student access to a calculator). Kaela Parks came to the SAC and assured us +that any such accommodation request is something an instructor need only +consider; i.e., those type of accommodation requests are not mandates on the +part of disability services. The speed with which we received clarity about +this issue is indicative of the strong connection that has been forged between +the mathematics departments and disability services. + +Beginning in the 2012/13 AY, all communication regarding student accommodations +(both general and testing-specific) has been done online. +Because of issues such as notifications being filtered to spam files, not all +accommodation requests were being read by faculty. At the mathematics faculty +department chairs' request, Kaela Parks created a spaces page that allow the +faculty chairs monitor which instructors have one or more students with +accommodation needs and highlights in red any instructor who has an outstanding +issue (such as pending exam) that needs immediate attention. This resource has +greatly diminished the number of incidents where a student has an +accommodation need that is not addressed in a timely manner. + +\section[Patterns of scheduling]{Describe current patterns of scheduling (such + as modality, class size, duration, DC times, location, or other), address the +pedagogy of the program/discipline and the needs of students.} +%\section[Patterns of scheduling]{Describe current patterns of scheduling (such as such as modality, class size, duration, times, location, or other). How do these relate to the pedagogy of the program/discipline and/or the needs of students?} %new version of the question, from Kendra +\label{facilities:sec:scheduling} +The math departments schedule classes that start as early as 7:00 {\sc a.m.}\ and +others that run as late as 9:50 {\sc p.m.} About 80\% of our math classes are offered +in a two-day-a week format, meeting either Monday-Wednesday or +Tuesday-Thursday. Some sections are offered in a three-day-a-week format and a +few in a four-day-a-week format; sections are offered in these formats to +accommodate students who find it helpful to be introduced to less content in +any one class session. + +We also schedule classes that meet only once a week; some of those classes are +scheduled on Saturdays. While once-weekly meetings are not an ideal format for +teaching mathematics, having such sections creates options for students who +cannot attend college more than one day a week. + +We offer several courses online, the enrollment in which has jumped +dramatically over the past five years (see \vref{fig:sec3:F2Fenrollments} and the discussion +surrounding it). We also offer classes in both a web/TV hybrid and an online/on-campus hybrid format. + +On-campus class sizes generally range from 20 to 35 students; that number is +typically dependent on the room that is assigned for the class (see \cpageref{needs:page:classsize} and +\vref{app:sec:classsize}). This has led +to some inconsistencies among campuses as distribution of classroom capacities +is not consistent from one campus to the next. + +Teaching online presents unique obstacles for faculty and students alike. +Faculty members, like students, have different methods of addressing these +obstacles. The SAC has a recommended capacity limit of twenty-five for each +section on its DL course offerings. This recommendation was based upon a +determination that twenty-five is a reasonable class size given the extra +duties associated with teaching online. Because the attrition rates in online +courses can be higher than that in on-campus courses, many DL instructors ask +that their class capacity be set at, say, thirty to accommodate for first week +attrition. + +In addition to increased class sizes that account for anticipated attrition, +some faculty members choose to allow additional students when their workload +allows for the attendant extra work. In fact, during Winter 2014, only fifteen +out of a total of forty-one DL sections are limited to twenty-five students. +Of the remaining DL sections, seven are capped between twenty-five and thirty, +twelve are capped in the mid-to-low thirties, and seven are capped at greater +than forty-five. Further information about scheduling patterns, broken down +by campus, can be found in \vref{sec:app:courseschedule}. + +There is no specific pedagogical dictates in most of our courses. Class +activities can range from lecture to class-discussion to group-work to +student-board-work. Some instructors provide their students with pre-printed +lecture notes and examples, others write notes on the board; some instructors +have their students work mostly on computer-based activities, and yet others +mostly work problems from the textbook. The frequency with which each +instructor uses each approach is almost entirely up to him/her. Many +instructors have a required online homework component, while others do not. + +This diversity of classroom experience has both positive and negative +consequences. On the positive side, it provides an environment that has the +potential to address a wide-range of learning styles. On the negative side, it +can lead to very inconsistent experiences for students as they work their way +through a sequence. The inconsistency is probably most prevalent and, +unfortunately, most problematic at the DE level of instruction. +As the Math SAC looks for ways to increase completion rates for students who +place into developmental mathematics courses, serious attention will be given +to plans that increase the consistency of classroom experience for students; +consistency that is built upon evidence-based best practices. + """ + + formatted = r""" +% arara: pdflatex: {files: [MathSACpr2014]} +% !arara: indent: {overwrite: yes} +\chapter{Facilities and Support} +\begin{flushright} + \includegraphics[width=8cm]{xkcd-806-tech_support-punchline}\\ + \url{http://xkcd.com} +\end{flushright} +\section[Space, technology, and equipment]{ + Describe how classroom space, classroom technology, laboratory space and equipment impact student success. +} + +Over the past few years, efforts by the college to create classrooms containing the same basic equipment has helped tremendously with consistency issues. +The nearly universal presence of classroom podiums with attendant Audio Visual (AV) devices is considerably useful. +For example, many instructors use computer-based calculator emulators when instructing their students on calculator use---this allows explicit keystroking examples to be demonstrated that were not possible before the podiums appeared; the document cameras found in most classrooms are also used by most mathematics instructors. +Having an instructor computer with internet access has been a great help as instructors have access to a wide variety of tools to engage students, as well as a source for quick answers when unusual questions arise. + +Several classrooms on the Sylvania campus have Starboards or Smart Boards integrated with their AV systems. +Many mathematics instructors use these tools as their primary presentation vehicles; documents can be preloaded into the software and the screens allow instructors to write their work directly onto the document. +Among other things, this makes it easy to save the work into pdf files that can be accessed by students outside of class. +This equipment is not used as much on the other campuses, but there are instructors on other campuses that say they would use them if they were widely available on their campus. + +A few instructors have begun creating lessons with LiveScribe technology. +The technology allows the instructor to make an audio/visual record of their lecture without a computer or third person recording device; instructors can post a `live copy' of their actual class lecture online. +The students do not simply see a static copy of the notes that were written; the students see the notes emerge as they were being written and they hear the words that were spoken while they were written. +The use of LiveScribe technology is strongly supported by Disability Services, and for that reason alone continued experimentation with its use is strongly encouraged. + +Despite all of the improvements that have been made in classrooms over the past few years, there still are some serious issues. + +Rooms are assigned randomly, which often leads to mathematics classes being scheduled in rooms that are not appropriate for a math class. +For example, scheduling a math class in a room with individual student desks creates a lot of problems; many instructors have students take notes, refer to their text, and use their calculator all at the same time and there simply is not enough room on the individual desktops to keep all of that material in place. +More significantly, this furniture is especially ill-suited for group work. +Not only does the movement of desks and sharing of work exacerbate the materials issue (materials frequently falling off the desks), students simply cannot share their work in the efficient way that work can be shared when they are gathered about tables. +It would be helpful if all non-computer-based math classes could be scheduled in rooms with tables. + +Another problem relates to an inadequate number of computerized classrooms and insufficient space in many of the existing computerized classroom; both of these shortages have greatly increased due to Bond-related construction. +Several sections of MTH 243 and MTH 244 (statistics courses), which are normally taught in computerized classrooms, \emph{have} been scheduled in regular classrooms. +Many of the statistics courses that were scheduled in computerized classrooms have been scheduled in rooms that seat only 28, 24, or even 20 students. +When possible, we generally limit our class capacities at 34 or 35. +Needless to say, running multiple sections of classes in rooms well below those capacities creates many problems. +This is especially problematic for student success, as it hinders students' ability to register due to undersized classrooms. + +Finally, the computerized classrooms could be configured in such a way that maximizes potential for meaningful student engagement and minimizes potential for students to get off course due to internet access. +We believe that all computerized classrooms need to come equipped with software that allows the instructor control of the student computers such as LanSchool Classroom Management Software. +The need for this technology is dire; it will reduce or eliminate students being off task when using computers, and it will allow another avenue to facilitate instruction as the instructor will be able to `see' any student computer and `interact' with any student computer. +It can also be used to solicit student feedback in an anonymous manner. +The gathering of anonymous feedback can frequently provide a better gauge of the general level of understanding than activities such as the traditional showing of hands. + +\recommendation[Scheduling]{ + All mathematics classes should be scheduled in rooms that are either computerized (upon request) or have multi-person tables (as opposed to individual desks). +} + +\recommendation[Scheduling, Deans of Instruction, PCC Cabinet]{ + All computerized classrooms should have at least 30, if not 34, individual work stations. +} + +\recommendation[Multimedia Services, Deans of Instruction, PCC Cabinet]{ + An adequate number of classrooms on all campuses should be equipped with Smartboards so that all instructors who want access to the technology can teach every one of their classes in rooms equipped with the technology. +} + +\recommendation[Multimedia Services, TSS]{ + The disk image for all computerized classrooms should include software that allows the podium computer direct access to each student computer. +} + +\section[ + Library and other outside-the-classroom information resources +]{ + Describe how students are using the library or other outside-the-classroom information resources. +} +We researched this topic by conducting a stratified sampling method survey of 976 on-campus students and 291 online students; the participants were chosen in a random manner. +We gave scantron surveys to the on-campus students and used SurveyMonkey for the online students. +We found that students are generally knowledgeable about library resources and other outside-the-classroom resources. +The complete survey, together with its results, is given in +\vref{app:sec:resourcesurvey}; we have summarized our comments to some of the more interesting questions below. + +\begin{enumerate}[label=Q\arabic*.,font=\bf] + \item Not surprisingly, library resources and other campus-based resources are used more frequently by our on-campus students than by our online students. + This could be due to less frequent visits to campus for online students and/or online students already having similar resources available to them via the internet. + \item We found that nearly 70\% of instructors include resource information in their syllabi. + This figure was consistent regardless of the level of the class (DE/transfer level) or the employment status of the instructor (full/part-time). + + We found that a majority of our instructors are using online resources to connect with students. + Online communication between students and instructors is conducted across many platforms such as instructor websites, Desire2Learn, MyPCC, online graphing applications, and online homework platforms. + + We found that students are using external educational websites such as + \href{https://www.khanacademy.org/}{Khan Academy}, + \href{http://patrickjmt.com/}{PatrickJMT}, + \href{http://www.purplemath.com/}{PurpleMath}, and + \href{http://www.youtube.com/}{YouTube}. + The data suggest online students use these services more than on-campus students. + \item The use of online homework (such as WeBWorK, MyMathLab, MyStatLab, and ALEKS) has grown significantly over the past few years. + However, the data suggests that significantly more full-time instructors than part-time instructors are directing their students towards these tools (as either a required or optional component of the course). + Additionally, there is a general trend that online homework programs are being used more frequently in online classes than in on-campus classes. + Both of these discrepancies may reflect the need to distribute more information to faculty about these software resources. + \item The Math SAC needs to address whether or not we should be requiring students to use online resources that impose additional costs upon the students and, if so, what would constitute a reasonable cost to the student. + To that end, our survey asked if students would be willing to pay up to \$35 to access online homework and other resources. + We found that online students were more willing to pay an extra fee than those enrolled in on-campus classes. + \setcounter{enumi}{6} + \item The PCC mathematics website offers a wealth of materials that are frequently accessed by students. + These include course-specific supplements, calculator manuals, and the required Calculus I lab manual; all of these materials were written by PCC mathematics faculty. + Students may print these materials for free from any PCC computer lab. + The website also links to PCC-specific information relevant to mathematics students (such as tutoring resources) as well as outside resources (such as the Texas Instruments website). + \setcounter{enumi}{8} + \item In addition to the previously mentioned resources we also encourage students to use resources offered at PCC such as on-campus Student Learning Centers, online tutoring, Collaborate, and/or Elluminate. + A significant number of students registered in on-campus sections are using these resources whereas students enrolled in online sections generally are not. + This is not especially surprising since on-campus students are, well, on campus whereas many online students rarely visit a campus. +\end{enumerate} + +\recommendation[Math SAC]{ + The majority of our data suggests that students are using a variety of resources to further their knowledge. + We recommend that instructors continue to educate students about both PCC resources and non-PCC resources. + We need to uniformly encourage students to use resources such as online tutoring, Student Learning Centers, Collaborate, and/or Elluminate; this includes resource citations in each and every course syllabus. +} + +\recommendation[Faculty Department Chairs]{ + A broader education campaign should be engaged to distribute information to part-time faculty regarding online homework such as WeBWorK, MyMathLab, MyStatLab, and ALEKS. +} + +\recommendation[Math SAC]{ + Instructors should consider quality, accessibility and cost to students when requiring specific curriculum materials. +} + +\section[Clerical, technical, administrative and/or tutoring support]{ + Provide information on clerical, technical, administrative and/or tutoring support. +} + +The Math SAC has a sizable presence on each of PCC's three campuses and at Southeast Center (soon to be a campus in its own right). +Each campus houses a math department within a division of that campus. +The clerical, technical, administrative, and tutoring support systems are best described on location-by-location basis. + +\subsection{Clerical, technical, and administrative support} + +Across the district, our SAC has an excellent and very involved administrative liaison, Dr. +Alyson Lighthart. +We would like to thank her for her countless hours of support in attending our SAC meetings and being available to the SAC Co-Chairs. +She provides us with thoughtful feedback and insightful perspectives that help us gather our thoughts and make sound decisions. + +\subsubsection{Cascade} +The Cascade math department belongs to the Math, Sciences, Health and PE division. +The math department is located on the third floor of the student services building, sharing a floor with the ROOTS office. +The math department also shares space with allied health support staff, medical professions faculty, medical assisting faculty and the Cascade academic intervention specialists (one of whom is also a math part-time faculty). +Part-time math faculty share 11 cubicles, each with a computer. +Our 7 full-time instructors are paired in offices that open up to the part-time cubicles. +We have space in our offices for another full time faculty member as we lost a temporary full-time position at the start of the 2013 academic year. +In Winter 2014, a collective 42 faculty share one high speed Ricoh printer and one copy machine. +Our division offices are located in another building. +We have a dedicated administrative assistant at the front desk who helps students and faculty most days from 8 {\sc a.m.--5 p.m.} + +\subsubsection{Rock Creek} +The Rock Creek math department is located in the same floor as the division it belongs to (Mathematics, Aviation, and Industrial Technology) and it is shared with Computer Science. +Part-time faculty share fourteen cubicles, each with a computer, located in the same office as full-time instructors, that are used to prepare and meet with students. +The sixty-five plus faculty share two high speed printers that can collate, staple and allow double sided printing, and one high speed scanner. +Currently we have reached space capacity and we will have to re-think the current office configuration in order to add one more full-time faculty member next Fall. +Two years ago the Rock Creek math department added a dedicated administrative assistant, which has helped with scheduling needs, coordinating part-time faculty needs, and providing better service to the students. + +\subsubsection{Southeast} +The clerical and administrative setup at Southeast has changed, as of Winter 2014. +There was a recent restructuring of divisions. +What used to be the Liberal Arts and Sciences Division split into two divisions: the Liberal Arts and CTE Division (which is in the first floor of Scott Hall, Room 103, where the Liberal Arts and Sciences used to be) and the Math and Science Division (which is on the \nth{2} floor of the new Student Commons Building, Room 214). +All of the math and science faculty are now in this new space, including the part-time instructors (everybody was scattered before, so this is a welcome change). + +All of the department chairs have their own offices (with doors), while the rest of the faculty (full-time and part-time) occupy cubicle spaces (approximately 20 cubicles in the space, shared by 4--5 faculty per cubicle). +There are two administrative assistants, one of whom is with the math and science faculty and the other of whom is in charge of the STEM program. +There is also one clerical staff member. + +There is one Ricoh printer in the space, along with a fax machine. +Any and all supplies (markers, erasers, etc.) are located across the hall in a designated staff room. + +\subsubsection{Sylvania} +The Sylvania math department belongs to the Math and Industrial Technology division, which is located in the neighboring automotive building. +The math department is currently located in two separate areas of adjacent buildings as of Fall 2013, when the developmental math faculty officially merged with the math department. +This separation will soon be remedied by construction of the new math department area, scheduled to be completed during Spring 2014. +This new location will be next door to the Engineering department, and will share a conference room, copy machine room, and kitchen. +The math department will include two department chair offices, seventeen full-time instructor cubicles, six additional cubicles shared by part-time faculty, and two flex-space rooms. +Each of the cubicles will have a computer, and there will be two shared laser printers plus one color scanner in the department office. + +Our two administrative assistants work an overlapped schedule, which provides dual coverage during the busy midday times and allows the office to remain open to students and visitors for eleven hours. +These assistants do an incredible job serving both student and faculty needs, including: scheduling assistance, interfacing with technical support regarding office and classroom equipment, maintaining supplies inventory, arranging for substitute instructors, securing signatures and processing department paperwork, guiding students to campus resources, and organizing syllabi and schedules from approximately 70 math instructors. + +Our math department has frequent interaction with both Audio-Visual and Technology Solution Services. +Responses by AV to instructor needs in the classroom are extremely prompt--typically within minutes of the notification of a problem. +Since the math department is very technology-oriented, we have many needs that require the assistance of TSS. +Work orders for computer equipment and operational issues that arise on individual faculty computers can take quite a long time to be implemented or to be resolved. +This may be due to the sheer volume of requests that they are processing, but more information during the process, especially notes of any delays, would be welcomed. + +\subsection{Tutoring support} +PCC has a Student Learning Center (SLC) on each campus. +It is a testament to PCC's commitment to student success that the four SLCs exist. +However, discrepancies such as unequal distribution of resources, inconsistency in the number and nature of tutors (including faculty `donating time' to the centers), and disparate hours of operation present challenges to students trying to navigate their way through different centers. + +\recommendation[PCC Cabinet, Deans of Students, Deans of Instructions, Student Learning Centers]{ + The college should strive for more consistency with its Student Learning Centers. + We feel that the centers would be an even greater resource if they were more consistent in structure, resource availability, physical space, and faculty support. +} + +Over the last five years the general environment of PCC has been greatly impacted by historically-unmatched enrollment growth (see +\vref{fig:sec3:DLenrollments,fig:sec3:F2Fenrollments}). +PCC's four Student Learning Centers have been greatly affected by this (see \vref{app:sec:tutoringhours}). +Most notably, the number of students seeking math tutoring has increased dramatically. +Unfortunately, this increase in student need has not been met by increase in tutors or tutoring resources. +As a result the amount of attention an individual student receives has decreased in a substantive way, leaving students often frustrated and without the help they needed. +Consequently, the numbers of students dropped again as students stopped even trying. +While some of this growth has been (or will be) accommodated by increasing the physical space available for tutoring (i.e., by the construction of new facilities at Rock Creek and Southeast), that is still not enough since personnel resources were not increased at the same rate and work-study awards have been decreased significantly. +A comprehensive plan needs to be developed and implemented that will ensure each and every student receives high-quality tutoring in a consistent and consistently accessible manner. + +As it now stands, the operation of the SLCs is completely campus driven. +As such, reporting on the current status needs to be done on a campus-by-campus basis. + +\subsubsection{Cascade} +Averaging over non-summer terms from Fall 2008 to Spring 2013, the Cascade SLC has served about 680 math students with 3900 individual visits and 8 hours per student per term. +(See \vref{app:tut:tab:SLC} for a full accounting.) + +The Cascade SLC has increased its operating hours in response to student demand. +Statistics tutoring is now offered at most times and the introduction of online homework has led to `Hybrid Tutoring', where students receive tutoring while working on their online homework. + +At the Cascade Campus, all full-time mathematics instructors and many part-time mathematics instructors volunteer 1--4 hours per week in the SLC to help with student demand. +To help ensure usage throughout the SLC's operational hours, instructors are notified by email of slow-traffic times; this allows the instructors to direct students who need extra help to take advantage of those times. +Other communications such as announcements, ads, and newsletters are sent out regularly. + +Full-time faculty have constructed a `First week lecture series' that they conduct on the first Friday of every term (except summer). +It is designed to review basic skills from MTH 20 through MTH 111. +It is run in 50-minute segments throughout the day with a 10-minute break between each segment. +The first offering of this series began in Winter 2012 with 100 students in attendance; the attendance has since grown steadily and was up to approximately 300 students by Fall 2013. + +The Cascade SLC has formalized both the hiring process and the training process for casual tutors. +The department chairs interview potential tutors, determine which levels they are qualified to tutor, and give guidance as to tutoring strategies and rules. +During their first term, each new tutor is always scheduled in the learning center at the same time as a math instructor, and is encouraged to seek math and tutoring advice from that instructor. + +\subsubsection{Rock Creek} +Averaging over non-summer terms from Fall 2008 to Spring 2013, the Rock Creek SLC has served about 690 math students with 3300 individual visits and 10 hours per student per term. +(See \vref{app:tut:tab:SLC} for a full accounting.) + +Everyone who works and learns in the Rock Creek SLC is looking forward to moving into the newly-built space in Building 7 by Spring 2014. +The new space will bring the SLC closer to the library and into the same building as the WRC, MC, and TLC. +Students seek tutoring largely in math and science, but increasingly for accounting, computer basics, and also college reading. +Mathematics full-time faculty hold two of the required five office hours at the tutoring center. + +Motivated by the high levels of student demand for math tutoring, in 2012/13 the SLC piloted math tutoring by appointment two days per week. +On each of the two days a tutor leads thirty-minute individual sessions or one-hour group tutoring sessions by appointment for most math levels. +After some tweaking of days and times, we have settled on Tuesdays and Wednesdays. +Students who are seeking a longer, more personalized or intensive tutoring session seem to highly appreciate this new service. + +Finally, the Rock Creek SLC has benefited over the last three years from collaboration with advisors, counselors, librarians, the WRC, MC, and the Career Resource Center in offering a wide variety of workshops as well as resource fairs to support student learning. + +\subsubsection{Southeast} +Averaging over non-summer terms from Fall 2008 to Spring 2013, the Southeast SLC has served about 280 math students with 1200 individual visits and 5 hours per student per term. +(See \vref{app:tut:tab:SLC} for a full accounting.) + +The SE SLC staff is looking forward to its move into the new tutoring center facilities when the new buildings are completed. +In the meantime, it has expanded the math tutoring area by moving the writing tutoring to the back room of the tutoring center. + +Since the SE Tutoring Center opened in 2004, it has gone from serving an average of 200 students per term (including math and other subjects) to serving an average of 350 students per term in math alone. +With this increase in students seeking assistance, the staff has also grown; the SE SLC now has several faculty members who work part time in the tutoring center. + +Many SE math faculty members donate time to the tutoring center. +We have developed a service learning project where calculus students volunteer their time in the tutoring center; this practice has been a great help to students who utilize the tutoring center as well as a great opportunity for calculus students to cement their own mathematical skills. + +\subsubsection{Sylvania} +Averaging over non-summer terms from Fall 2008 to Spring 2013, the Sylvania SLC has served about 1100 math students with 6200 individual visits and 7 hours per student per term. +(See \vref{app:tut:tab:SLC} for a full accounting.) + +The Sylvania SLC moved into a new location in Fall 2012; it is now in the Library building, together with the Student Computing Center. +The creation of a learning commons is working out well and students are taking advantage of having these different study resources in one place. +Unfortunately, the new SLC has less space available for math tutoring than the prior Student Success Center which has been addressed by restructuring the space. +Since enrollment remains high, having enough space for all students seeking help remains a challenge. + +PCC's incredible growth in enrollment created an attendant need for a dramatic increase in the number of tutors available to students. +This increased need has been partially addressed by an increase in the budget set aside for paid tutors as well as a heightened solicitation for volunteer tutors. +Many instructors (both full-time and part-time) have helped by volunteering in the Sylvania SLC; for several years, the center was also able to recruit up to 10 work-study tutors per academic year, but with recent Federal changes to Financial Aid, the Math Center is now only allowed two work-study tutors per year; this restriction has led to a decrease of up to 50 tutoring hours per week. + +In addition to tutoring, the Sylvania SLC hosts the self-paced ALC math classes, provides study material, and offers resources and workshops for students to prepare for the Compass placement test. +Efforts are also underway to modernize a vast library of paper-based materials by putting them online and making them available in alternate formats. + +\section[Student services]{ + Provide information on how Advising, Counseling, Disability Services and other student services impact students. +} + +Perhaps more than ever, the Math SAC appreciates and values the role of student services in fostering success for our students. +In our development of an NSF-IUSE proposal (see +\vref{over:subsub:nsfiuse}), discussions and planning returned again and again to student services such as advising, placement testing, and counseling. +As we look ahead hopefully toward a realization of the structure that we envisioned, we will keep these services as essential partners in serving our students. +The current status of these services follows. + +\subsection{Advising and counseling} +The advising and counseling departments play a vital role in creating pathways for student success; this is especially important when it comes to helping students successfully navigate their mathematics courses. +Historically there have been incidents of miscommunication between various math departments and their campus counterparts in advising, but over the past few years a much more deliberate effort to build strong communication links between the two has resulted in far fewer of these incidents. + +The advising departments have been very responsive to requests made by the mathematics departments and have been clear that there are policies in place that prevent them from implementing some of the changes we would like. + +For example, in the past many advisers would make placement decisions based upon criteria that the Math SAC felt weren't sufficient to support the decision. +One example of this was placing students into classes based upon a university's prerequisite structure rather than PCC's prerequisite structure. +When the advisers were made aware that this frequently led to students enrolling in courses for which they were not prepared for success, the advising department instituted an ironclad policy not to give any student permission to register for a course unless there was documented evidence that the student had passed a class that could be transcribed to PCC as the PCC prerequisite for the course. +Any student who wants permission without a satisfied prerequisite or adequate Compass score is now directed to a math faculty chair or to the instructor of the specific section in which the student wishes to enroll. + +On the downside, there are things we would like the advisers to do that we have come to learn they cannot do. +For example, for several years the policy of the Math SAC has been that prerequisites that were satisfied at other colleges or universities would only be `automatically' accepted if they were less than three years old. +Many instructors in the math department were under the impression that this policy was in place in the advising department, but it was discovered in 2012 that not only is this policy \emph{not} in place but the policy in fact cannot be enforced by anyone (including math faculty). +Apparently such a policy is enforceable only if explicit prerequisite time-limits are written into the CCOGs. + +The advising department had been aware of the prerequisite issue for six or seven years, but somehow the word had not been passed along to the general math faculty. +This serves as an example that both advising supervisors and the math department chairs need to make every effort possible to inform all relevant parties of policy changes in a clear and timely manner. +Towards that end, the math department at Sylvania Campus has now been assigned an official liaison in the Sylvania advising department. +and we believe that similar connections should be created on the other campuses as well. + +With the college's new focus on student completion, the relationship between the math departments and advising departments needs to become much stronger. +Initial placement plays a critical role in completion, as do other things such as enrollment into necessary study skills classes and consecutive term-to-term enrollment through a sequence of courses. +We need to make sure that the advisers have all of the tools necessary to help students make the best choices and the advisers need to help us understand their perspective on the needs of students enrolling in mathematics courses. +To help establish this collaborative environment, a Math SAC ad hoc committee has been formed to investigate and address advising issues, placement issues, and study skills issues; the committee is going to ask several people involved in advising and counseling to join the committee. +It has been speculated that perhaps such a committee should not be under the direct purview of the Math SAC; if the administration decides to create a similar committee under someone else's direction we ask that any such committee have a large contingent of math faculty. + +\recommendation[PCC Cabinet, Deans of Students, Advising]{ + All four campuses should have an official advising liaison and the four liaisons should themselves have an established relationship. + Ideally we would like to have one adviser at each campus dedicated solely to math advising issues. +} + +\recommendation[Math SAC, Advising, ROOTS]{ + A committee consisting of advisers, math faculty, and other relevant parties (e.g.\ ROOTS representation) should be formed to investigate and establish policies related to student success in mathematics courses. + The issues to investigate include, but are not limited to, placement, study skills, and other college success skills as they relate to mathematics courses. +} + +\subsection{Testing centers} +At the time we wrote our last program review there were very uneven procedures at the various testing centers which caused a lot of problems; the inconsistencies were especially problematic for online instructors and their students---see \cite{mathprogramreview2003}, page 26 . +We are pleased that the testing centers recognized that inconsistency as a problem and they addressed the issue in a forthright way. +The testing centers now have uniform policies and they have made great strides in making their services easily accessible to students and instructors alike. +For example, the ability to make testing arrangements online has been a tremendous help as has the increase in the number of options by which a completed exam can be returned to the instructor. + +A limited number of hours of operation remains a problem at each of the testing centers; evening and weekend hours are not offered and testing times during the remaining time are limited; for example, the Cascade Testing Center offers only four start times for make up exams exam week. +It appears to us that the size of the facilities and the number of personnel have not increased in equal parts with the dramatic increase in enrollment. +It also appears that the testing centers have not been given adequate funding to offer hours that accommodate students who can only come to campus during the evening or on a weekend. + +This lack of access can be especially problematic for students registered in math courses. +The majority of the math courses at PCC are taught by part-time faculty and these faculty members do not have the same flexibility in their schedule as full-time faculty to proctor their own exams; as such they are especially dependent on the testing centers for make-up testing. +This dependency is all the more problematic since many part-time faculty teach evening or Saturday classes and many of the students in those classes find it difficult to come to campus during `normal business hours.' Additionally, the Sylvania math department simply does not have the space required to administer make-up testing in the office, so 100\% of its faculty are dependent upon the testing centers for make-up testing; we realize this puts a strain on the testing centers. + +\recommendation[PCC Cabinet]{ + We recommend that the space and staffing in the testing centers be increased. +} + +\recommendation[PCC Cabinet, Deans of Students, Testing Centers]{ + We recommend that make-up testing be available as late as 9:00 {\sc p.m.}\ at least two days per week, and that make-up testing hours be available every Saturday. +} + +As discussed on \cpageref{other:page:disabilityservices,needs:page:disabilityservices}, the Math SAC has a very positive and productive relationship with disability services. +For example, disability services was very responsive when some instructors began to question accommodation requests that contradicted specific evaluation criteria mandated in CCOGs (e.g.~testing certain material without student access to a calculator). +Kaela Parks came to the SAC and assured us that any such accommodation request is something an instructor need only consider; i.e., those type of accommodation requests are not mandates on the part of disability services. +The speed with which we received clarity about this issue is indicative of the strong connection that has been forged between the mathematics departments and disability services. + +Beginning in the 2012/13 AY, all communication regarding student accommodations (both general and testing-specific) has been done online. +Because of issues such as notifications being filtered to spam files, not all accommodation requests were being read by faculty. +At the mathematics faculty department chairs' request, Kaela Parks created a spaces page that allow the faculty chairs monitor which instructors have one or more students with accommodation needs and highlights in red any instructor who has an outstanding issue (such as pending exam) that needs immediate attention. +This resource has greatly diminished the number of incidents where a student has an accommodation need that is not addressed in a timely manner. + +\section[Patterns of scheduling]{ + Describe current patterns of scheduling (such as modality, class size, duration, DC times, location, or other), address the pedagogy of the program/discipline and the needs of students. +} +%\section[Patterns of scheduling]{Describe current patterns of scheduling (such as such as modality, class size, duration, times, location, or other). How do these relate to the pedagogy of the program/discipline and/or the needs of students?} %new version of the question, from Kendra +\label{facilities:sec:scheduling} +The math departments schedule classes that start as early as 7:00 {\sc a.m.}\ and others that run as late as 9:50 {\sc p.m.} About 80\% of our math classes are offered in a two-day-a week format, meeting either Monday-Wednesday or Tuesday-Thursday. +Some sections are offered in a three-day-a-week format and a few in a four-day-a-week format; sections are offered in these formats to accommodate students who find it helpful to be introduced to less content in any one class session. + +We also schedule classes that meet only once a week; some of those classes are scheduled on Saturdays. +While once-weekly meetings are not an ideal format for teaching mathematics, having such sections creates options for students who cannot attend college more than one day a week. + +We offer several courses online, the enrollment in which has jumped dramatically over the past five years (see \vref{fig:sec3:F2Fenrollments} and the discussion surrounding it). +We also offer classes in both a web/TV hybrid and an online/on-campus hybrid format. + +On-campus class sizes generally range from 20 to 35 students; that number is typically dependent on the room that is assigned for the class (see \cpageref{needs:page:classsize} and +\vref{app:sec:classsize}). +This has led to some inconsistencies among campuses as distribution of classroom capacities is not consistent from one campus to the next. + +Teaching online presents unique obstacles for faculty and students alike. +Faculty members, like students, have different methods of addressing these obstacles. +The SAC has a recommended capacity limit of twenty-five for each section on its DL course offerings. +This recommendation was based upon a determination that twenty-five is a reasonable class size given the extra duties associated with teaching online. +Because the attrition rates in online courses can be higher than that in on-campus courses, many DL instructors ask that their class capacity be set at, say, thirty to accommodate for first week attrition. + +In addition to increased class sizes that account for anticipated attrition, some faculty members choose to allow additional students when their workload allows for the attendant extra work. +In fact, during Winter 2014, only fifteen out of a total of forty-one DL sections are limited to twenty-five students. +Of the remaining DL sections, seven are capped between twenty-five and thirty, twelve are capped in the mid-to-low thirties, and seven are capped at greater than forty-five. +Further information about scheduling patterns, broken down by campus, can be found in \vref{sec:app:courseschedule}. + +There is no specific pedagogical dictates in most of our courses. +Class activities can range from lecture to class-discussion to group-work to student-board-work. +Some instructors provide their students with pre-printed lecture notes and examples, others write notes on the board; some instructors have their students work mostly on computer-based activities, and yet others mostly work problems from the textbook. +The frequency with which each instructor uses each approach is almost entirely up to him/her. +Many instructors have a required online homework component, while others do not. + +This diversity of classroom experience has both positive and negative consequences. +On the positive side, it provides an environment that has the potential to address a wide-range of learning styles. +On the negative side, it can lead to very inconsistent experiences for students as they work their way through a sequence. +The inconsistency is probably most prevalent and, unfortunately, most problematic at the DE level of instruction. +As the Math SAC looks for ways to increase completion rates for students who place into developmental mathematics courses, serious attention will be given to plans that increase the consistency of classroom experience for students; consistency that is built upon evidence-based best practices. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_pcc_program_review2(self): + text = r""" +% arara: pdflatex: {files: [MathSACpr2014]} +% !arara: indent: {overwrite: yes} +\chapter[Faculty composition and qualifications]{Faculty: reflect on the +composition, qualifications and development of the faculty} +\epigraph{ % + I want to tell you what went through my head as I saw the D on my \nth{3} exam in + Calc II: ``f\#\$king a\&\$hole!'' That D changed my life. The feeling of + failure, not from my incompetence but rather my laziness. + I want to let you know that every single success in my life now is due in part + to your teachings. I can't thank you enough \& I hope that if for nothing + else, you have made a great influence on me.}{PCC Mathematics +Student, December 2013} + +\section[Faculty composition]{Provide information on each of the following:} +\subsection[Quantity and quality of the faculty]{Quantity and quality of the faculty needed to meet the needs of the +program or discipline.} +The total number of full-time faculty at all campuses between 2011 and 2013 +varied between 36 to 41 and the +part-time faculty varied between 143 to 158 on any given term, not including +Summer. The percent of \emph{all} courses (pre-college and college level) +taught by full-time instructors during this time period varied from a low of +22\% at Rock Creek to a high of 29\% at Sylvania (see +\cref{app:tab:analysisPTFT}). + +From the academic year 2008/09 to 2012/13 there was a significant increase in the +number of students taking math courses at all campuses as shown +\cref{reflect:tab:enrollment}. +\begin{table}[!htb] + \centering + \caption{Enrollment Difference from AY 08/09 to AY 12/13} + \label{reflect:tab:enrollment} + \begin{tabular}{lrr} + \toprule + Campus & Enrollment Difference & \% increase \\ + \midrule + SY & 5277 & 48.59\% \\ + CA & 3666 & 64.82\% \\ + RC & 5333 & 55.87\% \\ + ELC & 3171 & 103.09\% \\ + \bottomrule + \end{tabular} +\end{table} + +\Cref{app:tab:analysisPTFT} summarizes the breakdown of courses taught by +full-time and part-time faculty from Summer 2011--Spring 2013; breakdowns +by \emph{term} are given in \vref{app:sec:analysisPTFT}. + +\begin{table}[!htb] + \centering + \caption{Summary of sections taught (by campus) from Summer 2011--Spring 2013} + \label{app:tab:analysisPTFT} + % summary + % summary + % summary + \pgfplotstableread[col sep=comma]{./data/sectionsTaughtPTFT/sectionsTaughtPTFT2011-2013.csv}\sectionsTaughtSummary + \pgfplotstabletypeset[sectionFTPT]{\sectionsTaughtSummary} +\end{table} + + +In reference to ``quality of the faculty needed to meet the needs of the +discipline,'' it is insufficient to look at degree or experience +qualifications alone. Even a short list of what we expect from our mathematics +faculty would include, but not be limited to that she/he: +\begin{itemize} + \item possess an understanding of effective mathematics teaching + methodologies and strategies, and be able to adjust in response to + student needs; + \item teach the course content as outlined in CCOGs and with the appropriate mathematical rigor; + \item show genuine commitment to students' success; + \item identify problems when students encounter difficulties learning; + \item demonstrate an ongoing intellectual curiosity about the relationship + between teaching and learning; + \item manage classroom learning environments and effectively handle student + discipline problems; + \item demonstrate technological literacy needed in the teaching of mathematics; + \item participate in professional organizations; + \item develop, evaluate and revise the mathematics curricula; + \item serve and contribute to the PCC community as a whole through campus and + district wide committees and activities. +\end{itemize} +In addition, with the enormous enrollment increases of the past several years, +there are more students than ever needing both remediation in mathematics and +guidance in general about what it takes to be a successful college student. + +Addressing this section heading directly, the `quantity' of full-time faculty +needed to achieve the `quality' goals noted above is currently inadequate. It +is primarily the full-time faculty that has the time, resources and +institutional support to fully realize the expectations noted above. Part-time +faculty are dedicated, but the expectations are different given the +many of the challenges they face (discussed below). To increase the probability that a student moves successfully +through our mathematics courses without sacrificing quality, having a larger +full-time faculty presence than currently exists is needed. + +In recognizing the need for more full-time faculty, we do not want to downplay +the skills and talents of our part-time faculty. We have approximately 150 +part-time instructors that serve our students each term, many of whom have +teaching experience from other colleges and universities; they bring additional +experiences from industry, other sciences, high school and middle school +education, and so much more. Since they teach such a high percentage of our +classes, their success is crucial to our students' success. + +Given the importance of part-time faculty, efforts needs to be made to minimize +the many challenges that are unique to them. Many of these challenges are +created by the fact that part-timers frequently work on more than one campus or +have a second (or third) job beyond their work for PCC. Many of the problems +are created by the institution itself. The challenges include limited office +space, limited access to office computers and other resources, limited +opportunities to attend meetings, limited opportunities to engage in +professional development activities, limited opportunities for peer-to-peer +discourse. + +\recommendation[Office of Academic and Student Affairs]{The college should + continue to add new full-time math positions so that at each campus full-timers + at least 40\% of all sections at both the DE and transfer level.} + +\recommendation[Math SAC, PCC Cabinet, ACCEPT, PCCFFAP]{Given the heavy + reliance on part-time faculty for staffing our courses, there is little chance + that we can institutionalize significant changes in our DE courses without an + empowered part-time work force. As such, we recommend that the college take + action to support professional development for part-time faculty, provide + adequate office space and tools for part-time faculty, and any recommendations +put forth by ACCEPT.} + +\recommendation[PCC Cabinet, Human Resources]{The college should allow mathematics + departments, at the discretion of each campus's faculty, to hire full-time + faculty who meet the approved instructor qualifications for teaching at the + pre-100 level but not the approved instructor qualifications for teaching at + the post-100 level. A large majority of our courses are at the DE level, and + the needs of students enrolled in those courses are frequently different than + the needs of students enrolled in undergraduate level courses. Having a robust + assortment of full-time faculty educational experience can only help in our +pursuit of increased student success and completion.} + + +\subsection[Faculty turnover]{Extent of faculty turnover and changes anticipated in the next five +years.} +Since 2011, ten full-time instructors have been hired and seven full-time +instructors have left campuses across the district (this includes full-time +temporary positions). Of the seven full-time +instructors who left, five retired, one left to pursue other job opportunities, +and one returned to another teaching job after her temporary full-time position +terminated. Three of the retirements occurred at Sylvania and one each at Rock +Creek and Cascade. In addition to those that left the college, four full-time +instructors transferred from one campus to another. Given no unexpected +events, we anticipate that these demographics will roughly be repeated over the +next five years. + + +Since 2011, 53 part-time instructors have been hired and 35 part-time +instructors have left campuses across the district. Of the three campuses, +Rock Creek has the most part-time faculty turnover, followed by Cascade and +Sylvania. Reasons for leaving varied, but at least eight of the part-time +instructors who left campuses simply moved to another campus in the district +(see \vref{app:sec:facultyDegrees}). + +\subsection[Part-time faculty]{Extent of the reliance upon part-time faculty and how they compare +with full-time faculty in terms of educational and experiential backgrounds.} +Across the district, the mathematics departments rely heavily upon part-time +faculty to teach the majority of the math classes offered. Between 2011 and +2013, 75.1\% of the classes at Cascade were taught by part-time instructors, +71.8\% at Rock Creek, 72.7\% at Southeast, and 59\% at Sylvania. This reliance +on part-time faculty to teach classes has been a challenge to the departments +in a number of ways: +\begin{itemize} + \item the turnover of part-time faculty is higher and + thus there is a need to orient new employees more frequently and provide + mentoring and guidance to them as well; + \item many part-time faculty are on + campus only to teach their courses, and thus often do not attend meetings and + keep up with current SAC discussions on curriculum. +\end{itemize} +For these reasons, classes have a higher probability to be taught with less consistency than the +mathematics SAC would like. Increasing the number of full-time faculty (and +thus decreasing the dependence on part-time faculty) would mitigate much of +this inconsistency; complete details are given in \vref{app:sec:analysisPTFT}. + +Part-time faculty educational backgrounds vary much more than the full-time +faculty backgrounds. Full-time instructors have master's or doctorate degrees +in mathematics or related fields with extensive math graduate credits. About a +quarter of the part-time instructors have bachelor's degrees and the rest have +either a master's or doctorate degree. The part-time instructors come from a +variety of employment backgrounds and have different reasons for working +part-time. They may be high school instructors (active or retired), may come +from a household in which only one member is working full time while the other +teaches part time, may be recently graduated MS or MAT students seeking full +time employment, may be working full time elsewhere in a non-educational field, +or may be retired from a non-educational field (see +\vref{app:sec:facultyDegrees}). +% Is it true that a quarter of our PT faculty only have BS degrees? How did +% this happen? I don't see room for that in the IQs. How did you get this +% data? + +\subsection[Faculty diversity]{How the faculty composition reflects the diversity and cultural +competency goals of the institution.} +The mathematics SAC is deeply committed to fostering an inclusive campus +climate at each location that respects all individuals regardless of race, +color, religion, ethnicity, use of native language, national origin, sex, +marital status, height/weight ratio, disability, veteran status, age, or sexual +orientation. Many of these human characteristics noted above are not +measurable nor necessarily discernible. However, PCC does gather data on +gender and race/ethnicity, as detailed in \cref{reflect:tab:racialethnicmakeup} +(see also the extensive demographic data displayed in +\vref{app:sec:demographicdata}). + +\begin{table}[!htb] + \centering + \caption{Racial/Ethnic Make-up of PCC Faculty and Students} + \label{reflect:tab:racialethnicmakeup} + \begin{tabular}{rrrr} + \toprule + & PT Faculty & FT Faculty & Students \\ + \midrule + Male & 54.1\% & 53.2\% & 55\% \\ + Female & 45.9\% & 47\% & 45\% \\ + Asian /Pacific Islander & 7.7\% & 6.4\% & 8\% \\ + Black or African American & 1.1\% & 0.0\% & 6\% \\ + Hispanic/Latino & 2.2\% & 4.3\% & 11\% \\ + Multiracial & 1.1\% & 0.0\% & 3\% \\ + Native American & 0.0\% & 0.0\% & 1\% \\ + Unknown/International & 12.2\% & 4.3\% & 3\% \\ + Caucasian & 75.7\% & 85.1\% & 68\% \\ + \bottomrule + \end{tabular} +\end{table} + +Our SAC will continue to strive toward keeping our faculty body ethnically +diverse and culturally competent, but it is an area where improvement is +needed. In terms of hiring, there is a shortage of minorities in the Science, Technology, Engineering +and Mathematics (STEM) undergraduate and graduate programs, which makes our +recruitment of minority faculty difficult. \label{reflect:page:stem} + +\recommendation[Math SAC, Division Deans]{Math chairs and deans should + strongly recommend that full- and part-time faculty +attend workshops related to diversity and cultural competency issues.} + +\recommendation[PCCFFAP, Division Deans]{Part-time faculty should be allowed + to attend diversity/cultural awareness workshops in lieu of contractually +mandated quarterly meetings.} + +\recommendation[Math SAC, Division Deans, Human Resources]{Hiring committees need to work with HR to identify + and aggressively target mathematics graduate programs in the Northwest with +minority students who are seeking teaching positions in community colleges.} + +\recommendation[Division Deans, Faculty Department Chairs]{Departments on all campuses should increase efforts to find candidates + for the Faculty Diversity Internship Program \cite{affirmativeaction}.} + +\section[Changes to instructor qualifications]{Report any changes the SAC has + made to instructor qualifications since +the last review and the reason for the changes.} +In Spring 2011, prompted by the transfer of MTH 20 from Developmental +Education (DE) to the Mathematics SAC, the math instructor qualifications were +changed. MTH 20 had been the only remaining mathematics course in the DE SAC. + +The transfer included transitioning three full-time DE math instructors at +Sylvania into the Math Department at Sylvania. At this time, instructor +qualifications for math faculty were examined and changed to reflect the +inclusion of DE math faculty. It was determined that separate qualifications +should be written for pre-college and college level courses. These +qualifications were written so that all of the full-time DE math faculty +transitioning into the math department (as well as any new DE math faculty +hired) were qualified to teach the pre-college level courses and any new math +faculty were qualified to teach all of the math courses. + +For instance, a masters degree in mathematics education (instead of just +mathematics) was included as an optional qualification for full-time +instructors teaching pre-college level courses. Also a masters degree in +mathematics education became an option for part-time instructors teaching MTH +211--213 (the sequence for elementary education math teachers). Additionally, +at the request of the administration, the terms `part-time' and `full-time' +were removed from instructor qualifications in order to satisfy accreditation +requirements. Instead of labeling what had traditionally been part-time +qualifications as `part-time,' these qualifications were labeled `Criteria for +Provisional Instructors.' + +In Winter 2013, the math instructor qualifications were again changed at the +request of the math department chairs. The `provisional' labeling +from the last revision had required math department chairs to regularly +re-certify part-time (`provisional') instructors. In order to avoid this +unnecessary paperwork, the SAC adopted a three-tiered qualification structure +based on full-time, part-time, and provisionally-approved part-time instructors +(mainly graduate students currently working on graduate degrees). The +part-time (non-provisional) tier was labeled `Demonstrated Competency.' +Complete details of instructor qualifications are given in \vref{app:sec:instructorquals}. + + +\section[Professional development activities]{How have professional development + activities of the faculty contributed to the strength of the + program/discipline? If such activities have resulted in instructional or +curricular changes, please describe.} + +The members of the mathematics SAC, full-time and part-time alike, are very +committed to professional development. As with members of any academic +discipline, the faculty in the Math SAC pursue professional development in a +variety of manners. Traditionally these activities have been categorized in +ways such as `membership in professional organizations' or `presentations at +conferences'. The members of the Math SAC do not in any way devalue the +engagement in such organizations or activities, and in fact a summative list of +such things can be found in \vref{app:sec:memberships}. + +Nor do the members in any way diminish individual pursuit of professional +development. In an attempt to acknowledge such pursuits, each member of the +full-time faculty was asked to submit one or two highlights of their +professional development activities over the past five years. Those +submissions can be found in \vref{app:sec:professionaldevelop}. + +It should be noted that the list of organizations and activities found in these +appendices are not exhaustive; they are merely a representative sample of +the types of professional development pursuits engaged in by members of the +Math SAC. + +The members of the Math SAC realize that if there is going to be +institutional-level change that results in increased success and completion +rates for students enrolled in DE mathematics courses, there are going to have +to be targeted and on-going professional development activities with that goal +in mind and that all mathematics faculty, full-time and part-time, are going to +have to take advantage of those opportunities. This is especially important +since many of our faculty members are not specialists in working with +developmental mathematics students. We look forward to working with the broader +PCC community as we pursue our common goal of increased student success and +completion, and we look forward to the college's support in providing +professional development opportunities that promote attainment of this goal. + +\recommendation[PCC Cabinet]{The college should provide funds and other necessary resources + that allow the SAC members to engage in targeted, on-going professional + development geared toward realization of district-wide goals. This should + include, for example, support for activities such as annual two-day workshops + focusing on goals such as universal adoption of evidence-based best +practices.} + +\recommendation[Division Deans, Faculty Department Chairs, PCCFFAP, Completion Investment Council]{Each math department should create structures and policies that + promote sustained professional development. Institutionalization of practices + such as faculty-inquiry-groups and peer-to-peer classroom visitations are +necessary components of sustained professional development.} + +\recommendation[Math SAC, PCC Cabinet]{The college should continue to provide funds for activities + such as conference attendance, professional organization membership, etc. At + the same time, procedures should be put into place that allow for maximal + dissemination of ``good ideas'' and maximum probability that said ideas grow into +sustained practices.} + +\recommendation[Division Deans, Faculty Department Chairs, PCCFFAP]{Formalized procedures for mentoring new faculty, full-time and + part-time alike, should be adopted and strictly observed. Beginning a new job + is a unique opportunity for rapid professional development, and we need to make + sure that we provide as supportive and directed an opportunity for new faculty + as possible so that the development happens in a positive and long-lasting +way.} + """ + + formatted = r""" +% arara: pdflatex: {files: [MathSACpr2014]} +% !arara: indent: {overwrite: yes} +\chapter[Faculty composition and qualifications]{ + Faculty: reflect on the composition, qualifications and development of the faculty +} +\epigraph{ % + I want to tell you what went through my head as I saw the D on my \nth{3} exam in Calc II: ``f\#\$king a\&\$hole!'' That D changed my life. + The feeling of failure, not from my incompetence but rather my laziness. + I want to let you know that every single success in my life now is due in part to your teachings. + I can't thank you enough \& I hope that if for nothing else, you have made a great influence on me. +}{ + PCC Mathematics Student, December 2013 +} + +\section[Faculty composition]{Provide information on each of the following:} +\subsection[Quantity and quality of the faculty]{ + Quantity and quality of the faculty needed to meet the needs of the program or discipline. +} +The total number of full-time faculty at all campuses between 2011 and 2013 varied between 36 to 41 and the part-time faculty varied between 143 to 158 on any given term, not including Summer. +The percent of \emph{all} courses (pre-college and college level) taught by full-time instructors during this time period varied from a low of 22\% at Rock Creek to a high of 29\% at Sylvania (see +\cref{app:tab:analysisPTFT}). + +From the academic year 2008/09 to 2012/13 there was a significant increase in the number of students taking math courses at all campuses as shown +\cref{reflect:tab:enrollment}. +\begin{table}[!htb] + \centering + \caption{Enrollment Difference from AY 08/09 to AY 12/13} + \label{reflect:tab:enrollment} + \begin{tabular}{lrr} + \toprule + Campus & Enrollment Difference & \% increase \\ + \midrule + SY & 5277 & 48.59\% \\ + CA & 3666 & 64.82\% \\ + RC & 5333 & 55.87\% \\ + ELC & 3171 & 103.09\% \\ + \bottomrule + \end{tabular} +\end{table} + +\Cref{app:tab:analysisPTFT} summarizes the breakdown of courses taught by full-time and part-time faculty from Summer 2011--Spring 2013; breakdowns by \emph{term} are given in \vref{app:sec:analysisPTFT}. + +\begin{table}[!htb] + \centering + \caption{Summary of sections taught (by campus) from Summer 2011--Spring 2013} + \label{app:tab:analysisPTFT} + % summary + % summary + % summary + \pgfplotstableread[col sep=comma]{./data/sectionsTaughtPTFT/sectionsTaughtPTFT2011-2013.csv}\sectionsTaughtSummary + \pgfplotstabletypeset[sectionFTPT]{\sectionsTaughtSummary} +\end{table} + +In reference to ``quality of the faculty needed to meet the needs of the discipline,'' it is insufficient to look at degree or experience qualifications alone. +Even a short list of what we expect from our mathematics faculty would include, but not be limited to that she/he: +\begin{itemize} + \item possess an understanding of effective mathematics teaching methodologies and strategies, and be able to adjust in response to student needs; + \item teach the course content as outlined in CCOGs and with the appropriate mathematical rigor; + \item show genuine commitment to students' success; + \item identify problems when students encounter difficulties learning; + \item demonstrate an ongoing intellectual curiosity about the relationship between teaching and learning; + \item manage classroom learning environments and effectively handle student discipline problems; + \item demonstrate technological literacy needed in the teaching of mathematics; + \item participate in professional organizations; + \item develop, evaluate and revise the mathematics curricula; + \item serve and contribute to the PCC community as a whole through campus and district wide committees and activities. +\end{itemize} +In addition, with the enormous enrollment increases of the past several years, there are more students than ever needing both remediation in mathematics and guidance in general about what it takes to be a successful college student. + +Addressing this section heading directly, the `quantity' of full-time faculty needed to achieve the `quality' goals noted above is currently inadequate. +It is primarily the full-time faculty that has the time, resources and institutional support to fully realize the expectations noted above. +Part-time faculty are dedicated, but the expectations are different given the many of the challenges they face (discussed below). +To increase the probability that a student moves successfully through our mathematics courses without sacrificing quality, having a larger full-time faculty presence than currently exists is needed. + +In recognizing the need for more full-time faculty, we do not want to downplay the skills and talents of our part-time faculty. +We have approximately 150 part-time instructors that serve our students each term, many of whom have teaching experience from other colleges and universities; they bring additional experiences from industry, other sciences, high school and middle school education, and so much more. +Since they teach such a high percentage of our classes, their success is crucial to our students' success. + +Given the importance of part-time faculty, efforts needs to be made to minimize the many challenges that are unique to them. +Many of these challenges are created by the fact that part-timers frequently work on more than one campus or have a second (or third) job beyond their work for PCC. +Many of the problems are created by the institution itself. +The challenges include limited office space, limited access to office computers and other resources, limited opportunities to attend meetings, limited opportunities to engage in professional development activities, limited opportunities for peer-to-peer discourse. + +\recommendation[Office of Academic and Student Affairs]{ + The college should continue to add new full-time math positions so that at each campus full-timers at least 40\% of all sections at both the DE and transfer level. +} + +\recommendation[Math SAC, PCC Cabinet, ACCEPT, PCCFFAP]{ + Given the heavy reliance on part-time faculty for staffing our courses, there is little chance that we can institutionalize significant changes in our DE courses without an empowered part-time work force. + As such, we recommend that the college take action to support professional development for part-time faculty, provide adequate office space and tools for part-time faculty, and any recommendations put forth by ACCEPT. +} + +\recommendation[PCC Cabinet, Human Resources]{ + The college should allow mathematics departments, at the discretion of each campus's faculty, to hire full-time faculty who meet the approved instructor qualifications for teaching at the pre-100 level but not the approved instructor qualifications for teaching at the post-100 level. + A large majority of our courses are at the DE level, and the needs of students enrolled in those courses are frequently different than the needs of students enrolled in undergraduate level courses. + Having a robust assortment of full-time faculty educational experience can only help in our pursuit of increased student success and completion. +} + +\subsection[Faculty turnover]{ + Extent of faculty turnover and changes anticipated in the next five years. +} +Since 2011, ten full-time instructors have been hired and seven full-time instructors have left campuses across the district (this includes full-time temporary positions). +Of the seven full-time instructors who left, five retired, one left to pursue other job opportunities, and one returned to another teaching job after her temporary full-time position terminated. +Three of the retirements occurred at Sylvania and one each at Rock Creek and Cascade. +In addition to those that left the college, four full-time instructors transferred from one campus to another. +Given no unexpected events, we anticipate that these demographics will roughly be repeated over the next five years. + +Since 2011, 53 part-time instructors have been hired and 35 part-time instructors have left campuses across the district. +Of the three campuses, Rock Creek has the most part-time faculty turnover, followed by Cascade and Sylvania. +Reasons for leaving varied, but at least eight of the part-time instructors who left campuses simply moved to another campus in the district (see \vref{app:sec:facultyDegrees}). + +\subsection[Part-time faculty]{ + Extent of the reliance upon part-time faculty and how they compare with full-time faculty in terms of educational and experiential backgrounds. +} +Across the district, the mathematics departments rely heavily upon part-time faculty to teach the majority of the math classes offered. +Between 2011 and 2013, 75.1\% of the classes at Cascade were taught by part-time instructors, 71.8\% at Rock Creek, 72.7\% at Southeast, and 59\% at Sylvania. +This reliance on part-time faculty to teach classes has been a challenge to the departments in a number of ways: +\begin{itemize} + \item the turnover of part-time faculty is higher and thus there is a need to orient new employees more frequently and provide mentoring and guidance to them as well; + \item many part-time faculty are on campus only to teach their courses, and thus often do not attend meetings and keep up with current SAC discussions on curriculum. +\end{itemize} +For these reasons, classes have a higher probability to be taught with less consistency than the mathematics SAC would like. +Increasing the number of full-time faculty (and thus decreasing the dependence on part-time faculty) would mitigate much of this inconsistency; complete details are given in \vref{app:sec:analysisPTFT}. + +Part-time faculty educational backgrounds vary much more than the full-time faculty backgrounds. +Full-time instructors have master's or doctorate degrees in mathematics or related fields with extensive math graduate credits. +About a quarter of the part-time instructors have bachelor's degrees and the rest have either a master's or doctorate degree. +The part-time instructors come from a variety of employment backgrounds and have different reasons for working part-time. +They may be high school instructors (active or retired), may come from a household in which only one member is working full time while the other teaches part time, may be recently graduated MS or MAT students seeking full time employment, may be working full time elsewhere in a non-educational field, or may be retired from a non-educational field (see +\vref{app:sec:facultyDegrees}). +% Is it true that a quarter of our PT faculty only have BS degrees? How did +% this happen? I don't see room for that in the IQs. How did you get this +% data? + +\subsection[Faculty diversity]{ + How the faculty composition reflects the diversity and cultural competency goals of the institution. +} +The mathematics SAC is deeply committed to fostering an inclusive campus climate at each location that respects all individuals regardless of race, color, religion, ethnicity, use of native language, national origin, sex, marital status, height/weight ratio, disability, veteran status, age, or sexual orientation. +Many of these human characteristics noted above are not measurable nor necessarily discernible. +However, PCC does gather data on gender and race/ethnicity, as detailed in \cref{reflect:tab:racialethnicmakeup} +(see also the extensive demographic data displayed in +\vref{app:sec:demographicdata}). + +\begin{table}[!htb] + \centering + \caption{Racial/Ethnic Make-up of PCC Faculty and Students} + \label{reflect:tab:racialethnicmakeup} + \begin{tabular}{rrrr} + \toprule + & PT Faculty & FT Faculty & Students \\ + \midrule + Male & 54.1\% & 53.2\% & 55\% \\ + Female & 45.9\% & 47\% & 45\% \\ + Asian /Pacific Islander & 7.7\% & 6.4\% & 8\% \\ + Black or African American & 1.1\% & 0.0\% & 6\% \\ + Hispanic/Latino & 2.2\% & 4.3\% & 11\% \\ + Multiracial & 1.1\% & 0.0\% & 3\% \\ + Native American & 0.0\% & 0.0\% & 1\% \\ + Unknown/International & 12.2\% & 4.3\% & 3\% \\ + Caucasian & 75.7\% & 85.1\% & 68\% \\ + \bottomrule + \end{tabular} +\end{table} + +Our SAC will continue to strive toward keeping our faculty body ethnically diverse and culturally competent, but it is an area where improvement is needed. +In terms of hiring, there is a shortage of minorities in the Science, Technology, Engineering and Mathematics (STEM) undergraduate and graduate programs, which makes our recruitment of minority faculty difficult. \label{reflect:page:stem} + +\recommendation[Math SAC, Division Deans]{ + Math chairs and deans should strongly recommend that full- and part-time faculty attend workshops related to diversity and cultural competency issues. +} + +\recommendation[PCCFFAP, Division Deans]{ + Part-time faculty should be allowed to attend diversity/cultural awareness workshops in lieu of contractually mandated quarterly meetings. +} + +\recommendation[Math SAC, Division Deans, Human Resources]{ + Hiring committees need to work with HR to identify and aggressively target mathematics graduate programs in the Northwest with minority students who are seeking teaching positions in community colleges. +} + +\recommendation[Division Deans, Faculty Department Chairs]{ + Departments on all campuses should increase efforts to find candidates for the Faculty Diversity Internship Program \cite{affirmativeaction}. +} + +\section[Changes to instructor qualifications]{ + Report any changes the SAC has made to instructor qualifications since the last review and the reason for the changes. +} +In Spring 2011, prompted by the transfer of MTH 20 from Developmental Education (DE) to the Mathematics SAC, the math instructor qualifications were changed. +MTH 20 had been the only remaining mathematics course in the DE SAC. + +The transfer included transitioning three full-time DE math instructors at Sylvania into the Math Department at Sylvania. +At this time, instructor qualifications for math faculty were examined and changed to reflect the inclusion of DE math faculty. +It was determined that separate qualifications should be written for pre-college and college level courses. +These qualifications were written so that all of the full-time DE math faculty transitioning into the math department (as well as any new DE math faculty hired) were qualified to teach the pre-college level courses and any new math faculty were qualified to teach all of the math courses. + +For instance, a masters degree in mathematics education (instead of just mathematics) was included as an optional qualification for full-time instructors teaching pre-college level courses. +Also a masters degree in mathematics education became an option for part-time instructors teaching MTH 211--213 (the sequence for elementary education math teachers). +Additionally, at the request of the administration, the terms `part-time' and `full-time' were removed from instructor qualifications in order to satisfy accreditation requirements. +Instead of labeling what had traditionally been part-time qualifications as `part-time,' these qualifications were labeled `Criteria for Provisional Instructors.' + +In Winter 2013, the math instructor qualifications were again changed at the request of the math department chairs. +The `provisional' labeling from the last revision had required math department chairs to regularly re-certify part-time (`provisional') instructors. +In order to avoid this unnecessary paperwork, the SAC adopted a three-tiered qualification structure based on full-time, part-time, and provisionally-approved part-time instructors (mainly graduate students currently working on graduate degrees). +The part-time (non-provisional) tier was labeled `Demonstrated Competency.' Complete details of instructor qualifications are given in \vref{app:sec:instructorquals}. + +\section[Professional development activities]{ + How have professional development activities of the faculty contributed to the strength of the program/discipline? + If such activities have resulted in instructional or curricular changes, please describe. +} + +The members of the mathematics SAC, full-time and part-time alike, are very committed to professional development. +As with members of any academic discipline, the faculty in the Math SAC pursue professional development in a variety of manners. +Traditionally these activities have been categorized in ways such as `membership in professional organizations' or `presentations at conferences'. +The members of the Math SAC do not in any way devalue the engagement in such organizations or activities, and in fact a summative list of such things can be found in \vref{app:sec:memberships}. + +Nor do the members in any way diminish individual pursuit of professional development. +In an attempt to acknowledge such pursuits, each member of the full-time faculty was asked to submit one or two highlights of their professional development activities over the past five years. +Those submissions can be found in \vref{app:sec:professionaldevelop}. + +It should be noted that the list of organizations and activities found in these appendices are not exhaustive; they are merely a representative sample of the types of professional development pursuits engaged in by members of the Math SAC. + +The members of the Math SAC realize that if there is going to be institutional-level change that results in increased success and completion rates for students enrolled in DE mathematics courses, there are going to have to be targeted and on-going professional development activities with that goal in mind and that all mathematics faculty, full-time and part-time, are going to have to take advantage of those opportunities. +This is especially important since many of our faculty members are not specialists in working with developmental mathematics students. +We look forward to working with the broader PCC community as we pursue our common goal of increased student success and completion, and we look forward to the college's support in providing professional development opportunities that promote attainment of this goal. + +\recommendation[PCC Cabinet]{ + The college should provide funds and other necessary resources that allow the SAC members to engage in targeted, on-going professional development geared toward realization of district-wide goals. + This should include, for example, support for activities such as annual two-day workshops focusing on goals such as universal adoption of evidence-based best practices. +} + +\recommendation[Division Deans, Faculty Department Chairs, PCCFFAP, Completion Investment Council]{ + Each math department should create structures and policies that promote sustained professional development. + Institutionalization of practices such as faculty-inquiry-groups and peer-to-peer classroom visitations are necessary components of sustained professional development. +} + +\recommendation[Math SAC, PCC Cabinet]{ + The college should continue to provide funds for activities such as conference attendance, professional organization membership, etc. + At the same time, procedures should be put into place that allow for maximal dissemination of ``good ideas'' and maximum probability that said ideas grow into sustained practices. +} + +\recommendation[Division Deans, Faculty Department Chairs, PCCFFAP]{ + Formalized procedures for mentoring new faculty, full-time and part-time alike, should be adopted and strictly observed. + Beginning a new job is a unique opportunity for rapid professional development, and we need to make sure that we provide as supportive and directed an opportunity for new faculty as possible so that the development happens in a positive and long-lasting way. +} + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_sentence_across_blocks(self): + text = r""" +This sentence stretches +\[ + x^2 + \] +across lines. + +As does +\begin{tabular}{cc} + 1 & 2\\ +3&4\end{tabular} +this one. + """ + + formatted = r""" +This sentence stretches +\[ + x^2 +\] +across lines. + +As does +\begin{tabular}{cc} + 1 & 2\\ + 3&4 +\end{tabular} +this one. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_six_sentences_mutl_blank(self): + text = r""" +This is the first +sentence. This is the second sentence. This is the +third sentence. + + + +This is the fourth +sentence! + + + +This is the fifth +sentence. This is the +sixth sentence. + + +This is the seventh +sentence! This is the +eighth sentence. + +This is the ninth +sentence? This is the +tenth sentence. +\par +This is +the eleventh +sentence. + """ + + formatted = r""" +This is the first sentence. +This is the second sentence. +This is the third sentence. + +This is the fourth sentence! + +This is the fifth sentence. +This is the sixth sentence. + +This is the seventh sentence! +This is the eighth sentence. + +This is the ninth sentence? +This is the tenth sentence. +\par +This is the eleventh sentence. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_textbook_snippet(self): + """ + Difference: the double dollar signs have been removed. + """ + + text = r""" +% https://tex.stackexchange.com/questions/325505/best-practices-for-source-file-line-lengths/325511 +This manual is intended for people who have never used \TeX\ before, as +well as for experienced \TeX\ hackers. In other words, it's supposed to +be a panacea that satisfies everybody, at the risk of satisfying nobody. +Everything you need to know about \TeX\ is explained +here somewhere, and so are a lot of things that most users don't care about. +If you are preparing a simple manuscript, you won't need to +learn much about \TeX\ at all; on the other hand, some +things that go into the printing of technical books are inherently +difficult, and if you wish to achieve more complex effects you +will want to penetrate some of \TeX's darker corners. In order +to make it possible for many types of users to read this manual +effectively, a special sign is used to designate material that is +for wizards only: When the symbol +\vbox{\hbox{\dbend}\vskip 11pt} +appears at the beginning of a paragraph, it warns of a ``^{dangerous bend}'' +in the train of thought; don't read the paragraph unless you need to. +Brave and experienced drivers at the controls of \TeX\ will gradually enter +more and more of these hazardous areas, but for most applications the +details won't matter. + """ + + formatted = r""" +% https://tex.stackexchange.com/questions/325505/best-practices-for-source-file-line-lengths/325511 +This manual is intended for people who have never used \TeX\ before, as well as for experienced \TeX\ hackers. +In other words, it's supposed to be a panacea that satisfies everybody, at the risk of satisfying nobody. +Everything you need to know about \TeX\ is explained here somewhere, and so are a lot of things that most users don't care about. +If you are preparing a simple manuscript, you won't need to learn much about \TeX\ at all; on the other hand, some things that go into the printing of technical books are inherently difficult, and if you wish to achieve more complex effects you will want to penetrate some of \TeX's darker corners. +In order to make it possible for many types of users to read this manual effectively, a special sign is used to designate material that is for wizards only: When the symbol +\vbox{\hbox{\dbend}\vskip 11pt} +appears at the beginning of a paragraph, it warns of a ``^{dangerous bend}'' in the train of thought; don't read the paragraph unless you need to. +Brave and experienced drivers at the controls of \TeX\ will gradually enter more and more of these hazardous areas, but for most applications the details won't matter. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_three_sentences_trailing_comments(self): + text = r""" +%This is the first +%sentence. This is the second sentence. This is the +%third sentence. + +This is the fourth +sentence! This is the fifth sentence? This is the +sixth sentence. + """ + + formatted = r""" +%This is the first +%sentence. This is the second sentence. This is the +%third sentence. + +This is the fourth sentence! +This is the fifth sentence? +This is the sixth sentence. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_trailing_comments(self): + text = r""" +This is %1st comment +the first% 2nd comment +sentence.% 3rd comment + +This is the second sentence. % ?! 4th comment +This is the % 5th comment +third sentence. + +This is the fourth +sentence! This is the fifth sentence? This is the +sixth sentence. + """ + + formatted = r""" +This is %1st comment +the first% 2nd comment +sentence.% 3rd comment + +This is the second sentence. % ?! 4th comment +This is the % 5th comment +third sentence. + +This is the fourth sentence! +This is the fifth sentence? +This is the sixth sentence. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_two_sentences(self): + text = r""" +This is the +first sentence. + +This is the second +sentence! + """ + + formatted = r""" +This is the first sentence. + +This is the second sentence! + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + def test_verbatim_test(self): + text = r""" +This is the fourth +sentence! This is the fifth sentence? This is the +sixth sentence, and runs across +\begin{verbatim} + This is the fourth + sentence! This is the fifth sentence? This is the + sixth sentence. +\end{verbatim} +a verbatim environment; +and beyond! + +This is the fourth +sentence! This is the fifth sentence? This is the +sixth sentence. + """ + + formatted = r""" +This is the fourth sentence! +This is the fifth sentence? +This is the sixth sentence, and runs across +\begin{verbatim} + This is the fourth + sentence! This is the fifth sentence? This is the + sixth sentence. +\end{verbatim} +a verbatim environment; and beyond! + +This is the fourth sentence! +This is the fifth sentence? +This is the sixth sentence. + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + +class TestCode(unittest.TestCase): + def test_code(self): + text = r""" +\if@namecite + \RequirePackage{natbib} + \let\oldbibliography\bibliography + \renewcommand{\bibliography}[1]{% + \setlength{\bibsep}{3pt plus 0.3ex} + \def\bibfont{\scriptsize} + \if@twocolumnbib + \begin{multicols}{2}\raggedright\oldbibliography{#1}\justifying\end{multicols} + \else + \raggedright\oldbibliography{#1}\justifying + \fi + } +\else + \RequirePackage[square,sort&compress,numbers,comma]{natbib} + \let\oldbibliography\bibliography + \renewcommand{\bibliography}[1]{% + \setlength{\bibsep}{3pt plus 0.3ex} + \def\bibfont{\scriptsize} + \if@twocolumnbib + \begin{multicols}{2}\raggedright\oldbibliography{#1}\justifying\end{multicols} + \else + \raggedright\oldbibliography{#1}\justifying + \fi + } +\fi + """ + + formatted = r""" +\if@namecite + \RequirePackage{natbib} + \let\oldbibliography\bibliography + \renewcommand{\bibliography}[1]{% + \setlength{\bibsep}{3pt plus 0.3ex} + \def\bibfont{\scriptsize} + \if@twocolumnbib + \begin{multicols}{2} + \raggedright\oldbibliography{#1}\justifying + \end{multicols} + \else + \raggedright\oldbibliography{#1}\justifying + \fi + } +\else + \RequirePackage[square,sort&compress,numbers,comma]{natbib} + \let\oldbibliography\bibliography + \renewcommand{\bibliography}[1]{% + \setlength{\bibsep}{3pt plus 0.3ex} + \def\bibfont{\scriptsize} + \if@twocolumnbib + \begin{multicols}{2} + \raggedright\oldbibliography{#1}\justifying + \end{multicols} + \else + \raggedright\oldbibliography{#1}\justifying + \fi + } +\fi + """ + + ret = texplain.indent(text) + self.assertEqual(ret.strip(), formatted.strip()) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_placeholders.py b/tests/test_placeholders.py index 6af51da..4be965d 100644 --- a/tests/test_placeholders.py +++ b/tests/test_placeholders.py @@ -52,37 +52,37 @@ def test_noindent(self): """ text = r""" - This is a text - %\begin{noindent} - should be ignored - %\end{noindent} - More text. +This is a text +%\begin{noindent} +should be ignored +%\end{noindent} +More text. - Bla bla bla. - % \begin{noindent} - should also be ignored - % \end{noindent} - A last sentence. +Bla bla bla. +% \begin{noindent} +should also be ignored +% \end{noindent} +A last sentence. """ expect = r""" - This is a text - -TEXINDENT-NOINDENT-1- - More text. +This is a text +-TEXINDENT-NOINDENT-1- +More text. - Bla bla bla. - -TEXINDENT-NOINDENT-2- - A last sentence. +Bla bla bla. +-TEXINDENT-NOINDENT-2- +A last sentence. """ change_indent = r""" - This is a text -TEXINDENT-NOINDENT-1- More text. +This is a text -TEXINDENT-NOINDENT-1- More text. - Bla bla bla. -TEXINDENT-NOINDENT-2- A last sentence. +Bla bla bla. -TEXINDENT-NOINDENT-2- A last sentence. """ ret, placeholders = texplain.text_to_placeholders( - text, [texplain.PlacholderType.noindent_block] + text, [texplain.PlaceholderType.noindent_block] ) self.assertEqual(ret, expect) self.assertEqual(text, texplain.text_from_placeholders(ret, placeholders)) @@ -100,12 +100,14 @@ def test_comments(self): """ expect = """ - This is a text-TEXINDENT-COMMENT-1- + This is a text-TEXINDENT-INLINE-COMMENT-1- More text. - -TEXINDENT-COMMENT-2- + -TEXINDENT-COMMENT-1- """ - ret, placeholders = texplain.text_to_placeholders(text, [texplain.PlacholderType.comment]) + ret, placeholders = texplain.text_to_placeholders( + text, [texplain.PlaceholderType.comment, texplain.PlaceholderType.inline_comment] + ) self.assertEqual(ret, expect) self.assertEqual(text, texplain.text_from_placeholders(ret, placeholders)) @@ -148,7 +150,7 @@ def test_environment(self): """ ret, placeholders = texplain.text_to_placeholders( - text, [texplain.PlacholderType.environment] + text, [texplain.PlaceholderType.environment] ) self.assertEqual(ret, expect) self.assertEqual(text, texplain.text_from_placeholders(ret, placeholders)) @@ -168,18 +170,18 @@ def test_math(self): expect = """ This is a text - -TEXINDENT-MATH-1-. + -TEXINDENT-INLINEMATH-1-. More text. - -TEXINDENT-MATH-2-. + -TEXINDENT-INLINEMATH-2-. Even more text. - -TEXINDENT-MATH-3-. + -TEXINDENT-INLINEMATH-3-. Bla bla bla. - -TEXINDENT-MATH-4-. + -TEXINDENT-INLINEMATH-4-. A last sentence. """ ret, placeholders = texplain.text_to_placeholders( - text, [texplain.PlacholderType.inline_math] + text, [texplain.PlaceholderType.inline_math] ) self.assertEqual(ret, expect) self.assertEqual(text, texplain.text_from_placeholders(ret, placeholders)) @@ -203,7 +205,20 @@ def test_command(self): some -TEXINDENT-COMMAND-4- """ - ret, placeholders = texplain.text_to_placeholders(text, [texplain.PlacholderType.command]) + ret, placeholders = texplain.text_to_placeholders(text, [texplain.PlaceholderType.command]) + self.assertEqual(ret, expect) + self.assertEqual(text, texplain.text_from_placeholders(ret, placeholders)) + + def test_command_a(self): + text = r""" + \section*{Foo} bar + """ + + expect = """ + -TEXINDENT-COMMAND-1- bar + """ + + ret, placeholders = texplain.text_to_placeholders(text, [texplain.PlaceholderType.command]) self.assertEqual(ret, expect) self.assertEqual(text, texplain.text_from_placeholders(ret, placeholders)) diff --git a/tests/test_simple.py b/tests/test_simple.py index 186ce39..d6322a2 100644 --- a/tests/test_simple.py +++ b/tests/test_simple.py @@ -150,7 +150,7 @@ def test_format_labels(self): "sec:lc", ], ) - self.assertEqual(formatted, tex.get()) + self.assertEqual(formatted.strip(), str(tex).strip()) def test_format_labels_prefix(self): text = r""" @@ -267,7 +267,7 @@ def test_format_labels_prefix(self): "sec:SI:lc", ], ) - self.assertEqual(formatted, tex.get()) + self.assertEqual(formatted.strip(), str(tex).strip()) def test_remove_commentlines(self): text = r""" @@ -284,7 +284,7 @@ def test_remove_commentlines(self): tex = texplain.TeX(text=text) tex.remove_commentlines() - self.assertEqual(formatted, tex.get()) + self.assertEqual(formatted.strip(), str(tex).strip()) def test_use_cleveref(self): text = r""" @@ -303,88 +303,88 @@ def test_use_cleveref(self): tex = texplain.TeX(text=text) tex.use_cleveref() - self.assertEqual(formatted, tex.get()) + self.assertEqual(formatted.strip(), str(tex).strip()) def test_replace_command_simple(self): source = r"This is a \TG{I would replace this} text." expect = r"This is a text." tex = texplain.TeX(text=source) tex.replace_command(r"{\TG}[1]", "") - self.assertEqual(expect, tex.get()) + self.assertEqual(expect.strip(), str(tex).strip()) tex = texplain.TeX(text=source) tex.replace_command(r"{\TG}", "") - self.assertEqual(expect, tex.get()) + self.assertEqual(expect.strip(), str(tex).strip()) tex = texplain.TeX(text=source) tex.replace_command(r"\TG", "") - self.assertEqual(expect, tex.get()) + self.assertEqual(expect.strip(), str(tex).strip()) tex = texplain.TeX(text=source) tex.replace_command(r"{\TG}", "{}") - self.assertEqual(expect, tex.get()) + self.assertEqual(expect.strip(), str(tex).strip()) source = r"This is a \TG{text}{foo}{test}." expect = r"This is a test." tex = texplain.TeX(text=source) tex.replace_command(r"{\TG}[3]", "#3") - self.assertEqual(expect, tex.get()) + self.assertEqual(expect.strip(), str(tex).strip()) source = r"This is a \TG{text}{foo}{test}." expect = r"This is a test." tex = texplain.TeX(text=source) tex.replace_command(r"{\TG}[3]", "{#3}") - self.assertEqual(expect, tex.get()) + self.assertEqual(expect.strip(), str(tex).strip()) source = r"This is a \TG{text}{test}." expect = r"This is a \mycomment{text}{test}." tex = texplain.TeX(text=source) tex.replace_command(r"{\TG}[2]", r"\mycomment{#1}{#2}") - self.assertEqual(expect, tex.get()) + self.assertEqual(expect.strip(), str(tex).strip()) def test_replace_command_recursive(self): source = r"This is a \TG{I would replace this\TG{reasons...}} text. \TG{And this too}Foo" expect = r"This is a text. Foo" tex = texplain.TeX(text=source) tex.replace_command(r"{\TG}[1]", "") - self.assertEqual(expect, tex.get()) + self.assertEqual(expect.strip(), str(tex).strip()) source = r"This is a \TG{Foo\TG{my}{Bar}}{Bar} text. \TG{And this too}{Bar}" expect = r"This is a Bar text. Bar" tex = texplain.TeX(text=source) tex.replace_command(r"{\TG}[2]", "#2") - self.assertEqual(expect, tex.get()) + self.assertEqual(expect.strip(), str(tex).strip()) source = r"This is a \TG{Foo}{\TG{my}{Bar}} text. \TG{And this too}{Bar}" expect = r"This is a Bar text. Bar" tex = texplain.TeX(text=source) tex.replace_command(r"{\TG}[2]", "#2") - self.assertEqual(expect, tex.get()) + self.assertEqual(expect.strip(), str(tex).strip()) source = r"This is a \TG{Foo}{\TG{my}{Bar}} text. \TG{And this too}{Bar}" expect = r"This is a \AB{\AB{Bar}{my}}{Foo} text. \AB{Bar}{And this too}" tex = texplain.TeX(text=source) tex.replace_command(r"{\TG}[2]", r"\AB{#2}{#1}") - self.assertEqual(expect, tex.get()) + self.assertEqual(expect.strip(), str(tex).strip()) def test_remove_comments(self): source = r"This is a %, text with comments" expect = r"This is a " tex = texplain.TeX(text=source) tex.remove_comments() - self.assertEqual(expect, tex.get()) + self.assertEqual(expect.strip(), str(tex).strip()) source = "This is a %, text with comments\nAnd some more" expect = "This is a \nAnd some more" tex = texplain.TeX(text=source) tex.remove_comments() - self.assertEqual(expect, tex.get()) + self.assertEqual(expect.strip(), str(tex).strip()) source = r"Here, 10 \% of water was removed % after cheating" expect = r"Here, 10 \% of water was removed " tex = texplain.TeX(text=source) tex.remove_comments() - self.assertEqual(expect, tex.get()) + self.assertEqual(expect.strip(), str(tex).strip()) def test_remove_comments_external(self): source = r""" @@ -401,7 +401,7 @@ def test_remove_comments_external(self): tex = texplain.TeX(text=source) tex.remove_commentlines() tex.remove_comments() - self.assertEqual(expect, tex.get()) + self.assertEqual(expect.strip(), str(tex).strip()) def test_remove_command_a(self): """ @@ -413,7 +413,7 @@ def test_remove_command_a(self): tex = texplain.TeX(text=source) tex.replace_command(r"{\TG}[1]", "#1") - self.assertEqual(expect, tex.get()) + self.assertEqual(expect.strip(), str(tex).strip()) def test_remove_command_b(self): """ @@ -425,7 +425,7 @@ def test_remove_command_b(self): tex = texplain.TeX(text=source) tex.replace_command(r"{\TG}[1]", "#1") - self.assertEqual(expect, tex.get()) + self.assertEqual(expect.strip(), str(tex).strip()) def test_remove_command_c(self): """ @@ -437,7 +437,7 @@ def test_remove_command_c(self): tex = texplain.TeX(text=source) tex.replace_command(r"{\TG}[1]", "#1", ignore_commented=True) - self.assertEqual(expect, tex.get()) + self.assertEqual(expect.strip(), str(tex).strip()) def test_remove_command_d(self): """ @@ -449,7 +449,7 @@ def test_remove_command_d(self): tex = texplain.TeX(text=source) tex.replace_command(r"{\TG}[1]", "#1", ignore_commented=True) - self.assertEqual(expect, tex.get()) + self.assertEqual(expect.strip(), str(tex).strip()) if __name__ == "__main__": diff --git a/texplain/__init__.py b/texplain/__init__.py index a413673..1f6aacb 100644 --- a/texplain/__init__.py +++ b/texplain/__init__.py @@ -1,20 +1,15 @@ import argparse -import copy import enum import itertools import os import pathlib import re -import subprocess import sys -import tempfile import textwrap -from collections.abc import Callable from copy import deepcopy from shutil import copyfile import numpy as np -import yaml from numpy.typing import ArrayLike from numpy.typing import NDArray @@ -22,6 +17,23 @@ from ._version import version_tuple # noqa: F401 +class PlaceholderType(enum.Enum): + """ + Type of placeholder. + """ + + inline_comment = enum.auto() + comment = enum.auto() + tabular = enum.auto() + math = enum.auto() + inline_math = enum.auto() + math_line = enum.auto() + environment = enum.auto() + command = enum.auto() + noindent_block = enum.auto() + verbatim = enum.auto() + + def find_opening( text: str, opening: str, @@ -69,7 +81,7 @@ def find_commented(text: str) -> list[list[int]]: return ret -def is_commented(text: str) -> NDArray[bool]: +def is_commented(text: str) -> NDArray[np.bool_]: """ Return array that lists per character if it corresponds to commented text. @@ -106,7 +118,7 @@ def find_matching( :param escape: If ``True``, ``opening`` and ``closing`` are escaped. :param opening_match: Select index of begin (``0``) or end (``1``) of opening bracket match. :param closing_match: Select index of begin (``0``) or end (``1``) of closing bracket match. - :param return_array: If ``True``, return array of indices instead of dictionary. + :param return_array: If ``True``, return NumPy-array of indices instead of dictionary. :return: Dictionary with ``{index_opening: index_closing}`` """ @@ -122,6 +134,8 @@ def find_matching( b = [-1 * i.span()[closing_match] for i in re.finditer(closing, text)] if len(a) == 0 and len(b) == 0: + if return_array: + return np.zeros((0, 2), dtype=int) return {} if ignore_commented: @@ -132,7 +146,7 @@ def find_matching( b = list(-b[~is_comment[b]]) if len(a) != len(b): - raise OSError(f"Unmatching {opening}...{closing} found") + raise IndexError(f"Unmatching {opening}...{closing} found") brackets = sorted(a + b, key=lambda i: abs(i)) @@ -144,31 +158,197 @@ def find_matching( stack.append(i) else: if len(stack) == 0: - raise IndexError(f"No closing {closing} at: {i:d}") + raise IndexError(f"No closing {closing} at: {text[i - 20 : i + 20]}") j = stack.pop() ret[j] = -1 * i if len(stack) > 0: - raise IndexError(f"No opening {opening} at {stack.pop():d}") + i = stack.pop() + raise IndexError(f"No opening {opening} at: {text[i - 20 : i + 20]}") if return_array: - return _indices2array(ret) + return np.array(list(ret.items()), dtype=int).reshape(-1, 2) return ret -def _indices2array(indices: dict[int]): +def _detail_find_option( + character: NDArray[np.bool_], index: int, braces: ArrayLike, ret: list[tuple[int]] +) -> list[tuple[int]]: + """ + Find the matching brace. + This function is recursively called until the closing brace is followed by any character + that is not a space (or a comment). + + :param character: + Per character, ``True`` if the character is not a space (nor a comment). + + :param index: + Index from where to start searching. + May be the index of the opening brace or any space (or comment) before it. + + :param braces: + Sorted list of indices of the opening and closing braces. + The closing braces are indicated by a negative index. + + :param ret: + List of tuples of the indices of the opening and closing braces. + """ + + if len(braces) == 0: + return ret + + if braces[0] < 0: + return ret + + if np.any(character[index : braces[0]]) and braces[0] - index > 1: + return ret + + stack = [] + + for i, trial in enumerate(braces): + trial = braces[i] + if trial >= 0: + stack.append(trial) + else: + if len(stack) == 0: + raise IndexError(f"No closing closing bracket at for {index:d}") + open = stack.pop() + if len(stack) == 0: + closing = -1 * trial + break + + return _detail_find_option(character, closing + 1, braces[i + 1 :], ret + [(open, closing + 1)]) + + +def _find_option( + character: NDArray[np.bool_], index: int, opening: ArrayLike, closing: ArrayLike +) -> list[int]: """ - Convert indices for :py:func:`find_matching` to array. + Find indices of command options/arguments. + + :param character: + Per character, ``True`` if the character is not a space (nor a comment). - :param indices: Dictionary of indices ``{a: b, ...}`` - :return: Array of indices ``[[a, b], ...]`` + :param index: + Index from where to start searching. + May be the index of the opening brace or any space (or comment) before it. + + :param opening: Index of all relevant opening brackets. + :param closing: Index of all relevant closing brackets. + + :return: List of tuples with indices of opening and closing brackets of the options. """ - ret = np.zeros((len(indices), 2), dtype=int) - for i, opening in enumerate(indices): - ret[i, 0] = opening - ret[i, 1] = indices[opening] + if len(opening) == 0: + return [] + + braces = np.concatenate((opening, -np.array(closing))) + braces = braces[np.argsort(np.abs(braces))] + return _detail_find_option(character, index, braces, []) + + +def find_command( + text: str, + name: str = None, + regex: str = r"(? list[list[tuple[int]]]: + """ + Find indices of commands, and their options, and arguments. + + :param text: Text. + :param name: Name of command without backslash (e.g. ``"textbf"``). + :param regex: Regex to match search the command name. + :param is_comment: + Per character of ``text``, ``True`` if the character is part of a comment. + Default: search for comments using :py:func:`is_commented`. + + :return: List of indices of commands and their arguments: + ``[[(name_start, name_end), (arg1_start, arg1_end), ...], ...]`` + Note the definition is such that one can extract the ``j``-th component of the ``i``-th + command as follows: ``text[cmd[i][j][0]:cmd[i][j][1]]``. + """ + + if name is not None: + regex = r"(? 0: + square_open = square_open[~is_comment[square_open]] + if square_closing.size > 0: + square_closing = square_closing[~is_comment[square_closing]] + if curly_open.size > 0: + curly_open = curly_open[~is_comment[curly_open]] + if curly_closing.size > 0: + curly_closing = curly_closing[~is_comment[curly_closing]] + + # search to what commands brackets might belong + cmd_square_open = np.searchsorted(cmd_end, square_open, side="right") - 1 + cmd_square_closing = np.searchsorted(cmd_end, square_closing, side="right") - 1 + cmd_curly_open = np.searchsorted(cmd_end, curly_open, side="right") - 1 + cmd_curly_closing = np.searchsorted(cmd_end, curly_closing, side="right") - 1 + + ret = [] + whitespace = np.logical_or(is_comment, [i == " " or i == "\n" for i in text] + [False]) + character = ~whitespace # any non-whitespace and non-comment character + + for icmd in range(len(cmd_end)): + i_square_open = square_open[cmd_square_open >= icmd] + i_square_closing = square_closing[cmd_square_closing >= icmd] + i_curly_open = curly_open[cmd_curly_open >= icmd] + i_curly_closing = curly_closing[cmd_curly_closing >= icmd] + + item = [(cmd_start[icmd], cmd_end[icmd])] + index = cmd_end[icmd] + might_have_opt = True + + if len(i_square_open) == 0: + might_have_opt = False + else: + if len(i_curly_open) > 0: + if i_curly_open[0] < i_square_open[0]: + might_have_opt = False + + if might_have_opt: + opts = _find_option(character, index, i_square_open, i_square_closing) + + if len(opts) > 0: + index = opts[-1][1] + item += opts + i_curly_open = i_curly_open[i_curly_open >= index] + i_curly_closing = i_curly_closing[i_curly_closing >= index] + + args = _find_option(character, index, i_curly_open, i_curly_closing) + + if len(args) > 0: + item += args + + ret += [item] + return ret @@ -179,7 +359,7 @@ def remove_comments(text: str) -> str: :param text: The string to consider. :return: The string without comments. """ - text = text.split("\n") + text = text.splitlines() for i in range(len(text)): text[i] = re.sub(r"([^%]*)(? list[str]: return list(set(ret)) -class PlacholderType(enum.Enum): - """ - Type of placeholder. - """ - - comment = enum.auto() - inline_math = enum.auto() - environment = enum.auto() - command = enum.auto() - noindent_block = enum.auto() - special_indent = enum.auto() - - class Placeholder: """ Placeholder for text. @@ -226,6 +393,9 @@ class Placeholder: :param space_front: The whitespace before the placeholder. :param space_back: The whitespace after the placeholder. :param ptype: The type of placeholder. + :param search_placeholder: + The regex used to search for the placeholder + (optional, but speeds up greatly for batch searches). """ def __init__( @@ -234,17 +404,25 @@ def __init__( content: str, space_front: str = None, space_back: str = None, - ptype: PlacholderType = None, + ptype: PlaceholderType = None, + search_placeholder: str = None, ): self.placeholder = placeholder self.content = content self.space_front = space_front self.space_back = space_back self.ptype = ptype + self.search_placeholder = search_placeholder @classmethod def from_text( - self, placeholder: str, text: str, start: int, end: int, ptype: PlacholderType = None + self, + placeholder: str, + text: str, + start: int, + end: int, + ptype: PlaceholderType = None, + search_placeholder: str = None, ): """ Replace text with placeholder. @@ -259,14 +437,22 @@ def from_text( :param start: The start index of ``text`` to be replaced by the placeholder. :param end: The end index of ``text`` to be replaced by the placeholder. :param ptype: The type of placeholder. + :param search_placeholder: The regex used to search the placeholder. :return: ``(Placeholder, text)`` where in ``text`` the placeholder is inserted. """ pre = text[:start][::-1] post = text[end:] front = re.search(r"\s*", pre).end() - back = re.search(r"\s*", post).end() + back = re.search(r"\ *\n?", post).end() return ( - Placeholder(placeholder, text[start:end], pre[:front][::-1], post[:back], ptype), + Placeholder( + placeholder, + text[start:end], + pre[:front][::-1], + post[:back], + ptype, + search_placeholder, + ), text[:start] + placeholder + text[end:], ) @@ -287,9 +473,11 @@ def to_text(self, text: str, index: int = None) -> str: if self.space_front is not None: front = re.search(r"\s*", pre).end() pre = pre[front:][::-1] + self.space_front + else: + pre = pre[::-1] if self.space_back is not None: - back = re.search(r"\s*", post).end() + back = re.search(r"\ *\n?", post).end() post = self.space_back + post[back:] return pre + self.content + post @@ -326,23 +514,45 @@ def __call__(self): self.i += 1 return f"-{self.base}-{self.name}-{self.i:d}-" + @property + def search_placeholder(self) -> str: + """ + Return the regex that can be used to search for the placeholder. + """ + return f"-{self.base}-{self.name}-\\d+-" + + +def _filter_nested(indices: ArrayLike) -> ArrayLike: + indices = indices[np.argsort(indices[:, 0])] + keep = np.ones(len(indices), dtype=bool) + + last = 0 + for i in range(len(indices)): + if indices[i, 0] < last: + keep[i] = False + else: + last = indices[i, 1] + + return indices[keep] + def _apply_placeholders( text: str, - indices: ArrayLike, + indices: NDArray[np.int_] | list[tuple[int, int]], base: str, name: str, - ptype: PlacholderType, + ptype: PlaceholderType, + filter_nested: bool = True, ) -> tuple[str, list[Placeholder]]: """ Replace text with placeholders. - Note: nested placeholders are skipped. - :param text: The text to consider. + :param text: Text to consider. :param indices: A list of start and end indices of the text to be replaced by a placeholder. :param base: The base of the placeholder, see :py:class:`GeneratePlaceholder`. :param name: The name of the placeholder, see :py:class:`GeneratePlaceholder`. - :param ptype: The type of placeholder, see :py:class:`PlacholderType`. + :param ptype: The type of placeholder, see :py:class:`PlaceholderType`. + :param filter_nested: If ``True``, nested placeholders are skipped. :return: ``(text, placeholders)`` where: - ``text`` is the text with the placeholders. @@ -355,37 +565,177 @@ def _apply_placeholders( if len(indices) == 0: return text, [] - # filter nested - i = np.argsort(indices[:, 0]) - indices = indices[i] - keep = np.ones(len(indices), dtype=bool) - i = 0 - while i < len(indices) - 2: - while indices[i + 1, 0] < indices[i, 1]: - keep[i + 1] = False - i += 1 - i += 1 - indices = indices[keep] + indices = np.array(indices, dtype=int).reshape(-1, 2) + + if filter_nested: + indices = _filter_nested(indices) - # replacement - ret = [] gen = GeneratePlaceholder(base, name) + search_placeholder = gen.search_placeholder + assert re.match(search_placeholder, text) is None + + ret = [] for i in range(indices.shape[0]): - placeholder, text = Placeholder.from_text(gen(), text, indices[i, 0], indices[i, 1], ptype) + placeholder, text = Placeholder.from_text( + gen(), text, indices[i, 0], indices[i, 1], ptype, search_placeholder + ) ret += [placeholder] indices -= len(placeholder.content) - len(placeholder.placeholder) return text, ret +def _detail_text_to_placholders( + text: str, ptype: PlaceholderType, base: str, placeholders_comments +) -> tuple[str, list[Placeholder]]: + """ + Replace text with a specific placeholder type. + + :param text: Text to consider. + :param ptype: The type of placeholder, see :py:class:`PlaceholderType`. + :param base: The base of the placeholder, see :py:class:`GeneratePlaceholder`. + :param placeholders_comments: A list comment placeholders. + :return: + ``(text, placeholders)`` where: + - ``text`` is the text with the placeholders. + - ``placeholders`` is a list of the placeholders that includes their original content. + """ + + if ptype == PlaceholderType.noindent_block: + indices = find_matching( + text, + r"%\s*\\begin{noindent}", + r"%\s*\\end{noindent}", + escape=False, + closing_match=1, + return_array=True, + ) + return _apply_placeholders(text, indices, base, "noindent".upper(), ptype) + + if ptype == PlaceholderType.verbatim: + indices = find_matching( + text, + r"\\begin{verbatim}", + r"\\end{verbatim}", + escape=False, + closing_match=1, + return_array=True, + ) + return _apply_placeholders(text, indices, base, "verbatim".upper(), ptype) + + if ptype == PlaceholderType.tabular: + indices = find_matching( + text, + r"\\begin{tabular}", + r"\\end{tabular}", + escape=False, + closing_match=1, + return_array=True, + ) + return _apply_placeholders(text, indices, base, "tabular".upper(), ptype) + + if ptype == PlaceholderType.inline_comment: + indices = [i.span(2) for i in re.finditer(r"([^\ ][\ ]*)(? tuple[str, list[Placeholder]]: r""" Replace text with placeholders. The following placeholders are supported: - - :py:class:`PlacholderType.noindent_block`: + - :py:class:`PlaceholderType.noindent_block`: .. code-block:: latex @@ -393,20 +743,99 @@ def text_to_placeholders( ... % \end{noindent} + is replaced with + + .. code-block:: latex + + -BASE-NOINDENT-1- + + - :py:class:`PlaceholderType.verbatim`: + + .. code-block:: latex + + \begin{verbatim} + ... + \end{verbatim} + + is replaced with + + .. code-block:: latex + + -BASE-VERBATIM-1- - - :py:class:`PlacholderType.comment`: + - :py:class:`PlaceholderType.comment`: + + A comment on a line that contains no other text. .. code-block:: latex % ... - - :py:class:`PlacholderType.inline_math`: + is replaced with + + .. code-block:: latex + + -BASE-COMMENT-1- + + - :py:class:`PlaceholderType.inline_comment`: + + A comment following some other text on the same line. + + .. code-block:: latex + + xxx % ... + + is replaced with + + .. code-block:: latex + + xxx -BASE-INLINE-COMMENT-1- + + - :py:class:`PlaceholderType.inline_math`: .. code-block:: latex $...$ - - :py:class:`PlacholderType.environment`: + (and other inline math environments) is replaced with + + .. code-block:: latex + + -BASE-INLINE-MATH-1- + + - :py:class:`PlaceholderType.math`: + + .. code-block:: latex + + \begin{equation} + ... + \end{equation} + + (and other math environments) is replaced with + + .. code-block:: latex + + -BASE-MATH-1- + + - :py:class:`PlaceholderType.math_line`: + + .. code-block:: latex + + \begin{equation} + ... + ... + \end{equation} + + (and other math environments) is replaced with + + .. code-block:: latex + + \begin{equation} + -BASE-MATH-LINE-1- + -BASE-MATH-LINE-2- + \end{equation} + + - :py:class:`PlaceholderType.environment`: .. code-block:: latex @@ -414,113 +843,53 @@ def text_to_placeholders( ... \end{...} - - :py:class:`PlacholderType.special_indent`: + is replaced with - - ``-PLACEHOLDER-)`` <- ``.)``, ``?)``, or ``!)`` - - ``text-PLACEHOLDER-\n`` <- ``text:\n`` - """ + .. code-block:: latex - ret = [] + -BASE-ENVIRONMENT-1- - for ptype in ptypes: - if ptype == PlacholderType.noindent_block: - indices = find_matching( - text, - r"%\s*\\begin{noindent}", - r"%\s*\\end{noindent}", - escape=False, - closing_match=1, - return_array=True, - ) - text, placeholders = _apply_placeholders( - text, indices, base, "noindent".upper(), PlacholderType.noindent_block - ) - ret += placeholders + - :py:class:`PlaceholderType.tabular`: - elif ptype == PlacholderType.comment: - indices = np.array([i.span() for i in re.finditer(r"(? str: """ Replace placeholders with original text. + The whitespace before and after the placeholder is modified to the match + :py:attr:`Placeholder.space_front` and :py:attr:`Placeholder.space_back`. + + :param text: Text with placeholders. + :param placeholders: List of placeholders. + :return: Text with content of the placeholders. """ if len(placeholders) == 0: return text - if default_naming and len(placeholders) > 1: - placeholders = {i.placeholder: i for i in placeholders} - while True: - indices = [ - (text[i.span()[0] : i.span()[1]], i.span()[0]) # noqa: E203 - for i in re.finditer("-" + prefix + r"-\w*-[0-9]*-", text) - ] - if len(indices) == 0: + search_placeholder = [] + + if len(placeholders) > 1: + search_placeholder = list(set(list({i.search_placeholder for i in placeholders}))) + + placeholders = {i.placeholder: i for i in placeholders} + + for search in search_placeholder: + if search is None: + continue + indices = {text[i.span()[0] : i.span()[1]]: i.span()[0] for i in re.finditer(search, text)} + offset = 0 + for key, index in indices.items(): + placeholder = placeholders.pop(key, None) + if placeholder is None: + continue + n = len(text) + text = placeholder.to_text(text, index + offset) + offset += len(text) - n + if len(placeholders) == 0: return text - offset = 0 - for name, index in indices: - placeholder = placeholders[name] - n = len(text) - text = placeholder.to_text(text, index + offset) - offset += len(text) - n - - for placeholder in placeholders: + + for key in placeholders: + placeholder = placeholders[key] n = len(text) text = placeholder.to_text(text) return text +def _rstrip_lines(text: str) -> str: + """ + ``.rstrip()`` for each line. + + :param text: Text. + :return: Formatted text. + """ + return "\n".join([line.rstrip() for line in text.splitlines()]) + + +def _lstrip_lines(text: str) -> str: + """ + ``.rstrip()`` for each line. + + :param text: Text. + :return: Formatted text. + """ + return "\n".join([line.lstrip() for line in text.splitlines()]) + + +def _dedent(text: str, partial: list[PlaceholderType]) -> str: + """ + Remove indentation. + + :param text: Text. + :param partial: + List of :py:class:`PlaceholderType` to dedent partially. + If the number of lines is less than 3, ``textwrap.dedent`` is applied to all lines. + Otherwise, ``textwrap.dedent`` is applied to ``lines[1:-1]``; + the first and last lines are stripped. + + :return: Formatted text. + """ + + text, placholders = text_to_placeholders(text, partial, base="TEXDEDENT") + + text = _lstrip_lines(text) + + # keep common indentation table + # TODO: make more clever + for placeholder in placholders: + tmp = placeholder.content.splitlines() + if len(tmp) <= 2: + placeholder.content = "\n".join(textwrap.dedent(tmp)) + else: + placeholder.content = "\n".join( + [tmp[0].lstrip(), textwrap.dedent("\n".join(tmp[1:-1])), tmp[-1].lstrip()] + ) + placeholder.space_front = "\n" + + text = text_from_placeholders(text, placholders) + + return text + + +def _squashspaces(text: str, skip: list[PlaceholderType]) -> str: + """ + Squash spaces. + + :param text: Text. + :param skip: List of :py:class:`PlaceholderType` to skip. + :return: Formatted text. + """ + + text, placholders = text_to_placeholders(text, skip, base="TEXSQUASH") + text = re.sub(r"(\ +)", r" ", text) + text = text_from_placeholders(text, placholders) + return text + + +def _is_placeholder(text: str, placeholders: list[Placeholder]) -> list[bool]: + """ + Check per character if it is a placeholder. + + :param text: Text. + :param placeholders: List of placeholders. + :return: List of booleans. + """ + + search_placeholder = list(set(list({i.search_placeholder for i in placeholders}))) + + ret = {} + + for search in search_placeholder: + if search is None: + continue + indices = {text[i.span()[0] : i.span()[1]]: i.span()[0] for i in re.finditer(search, text)} + ret.update(indices) + + names = [i.placeholder for i in placeholders] + ret = {key: value for key, value in ret.items() if key in names} + + is_comment = np.zeros(len(text), dtype=bool) + for i in ret: + is_comment[ret[i] : ret[i] + len(i)] = True + + return is_comment + + +def _begin_end_one_separate_line(text: str, comment_placeholders: list[Placeholder]) -> str: + r""" + Put : + - ``\begin{...}`` and ``\\end{...}`` + - ``\[`` and ``\]`` + - ``\if`` and ``\else`` and ``\fi`` + on separate lines. + + :param text: Text. + :param comment_placeholder: + List of :py:class:`Placeholder` for comments. + Assumes that all comments are replaced by placeholders. + + :return: Formatted text. + """ + + # begin all ``\begin{...}``and ``\end{...}`` on newline + text = re.sub(r"(\n?\ *)(? str: + """ + Indent text. + + :param text: The text to indent. + :param indent: The indentation to use. + :return: The indented text. + """ + + if len(text) == 0: + return text + + # known limitation + if re.match(r"(? str: + """ + Split text into sentences. + + :param text: Text. + :return: Formatted text. + + TODO: optional split characters such as ``;`` and ``:`` + """ + + text = re.split(r"(?<=[\.\!\?])\s+", text) + + for i in range(len(text)): + text[i] = re.sub("(\n[\\ \t]*)([\\w\\$\\(\\[\\`])", r" \2", text[i]) + + return "\n".join(text) + + +def _one_sentence_per_line( + text: str, + fold: list[PlaceholderType] = [], + base: str = "TEXONEPERLINE", +) -> str: + """ + Split text into sentences. + + TODO: describe formatting rules + + :param text: Text. + :param fold: List of placeholder types to fold before formatting (and restore after). + :param base: Base name for placeholders. + :return: Formatted text. + """ + + text, placeholders = text_to_placeholders(text, fold, base=base) + + # format in blocks separated by blocks between ``(start, end)`` in ``skip`` + skip = [] + + # \begin{...} + skip += [i.span() for i in re.finditer(r"(? str: + """ + Format a command. + This function loops over all options and arguments and places them on a separate line if + they contain at least one ``\n``. + In that case :py:func:`_one_sentence_per_line` is applied to the option/argument. + + For example:: + + \foo[bar]{This is + sentence.} + + becomes:: + + \foo[bar]{ + This is sentence. + } + + :param text: Text. + :param placeholders_comments: List of placeholders for comments. + :param level: Level of nestedness, used to define unique placeholder names. + :return: Formatted text. + """ + if not re.match(r".*\n.*", text): + return text + + is_comment = _is_placeholder(text, placeholders_comments) + commands = find_command(text, is_comment=is_comment) + commands = [i for i in commands if len(i) > 1] + + if len(commands) == 0: + return text + + braces = [] + for i in commands: + for j in i[1:]: + braces += [j] + + braces = list(_filter_nested(np.array(braces))) + [[None, None]] + + parts = [text[: braces[0][0]]] + for i in range(len(braces) - 1): + o, c = braces[i] + parts += [text[o:c], text[c : braces[i + 1][0]]] + + for i, part in enumerate(parts): + if i % 2 == 1: + if not re.match(r".*\n.*", part): + continue + body = part[1:-1].strip() + body, placeholders = text_to_placeholders( + body, [PlaceholderType.command], f"TEXONEPERLINENESTED{level}" + ) + body = _one_sentence_per_line(body, []) + for placeholder in placeholders: + placeholder.content = _format_command( + placeholder.content, placeholders_comments, level + 1 + ) + body = text_from_placeholders(body, placeholders) + parts[i] = "\n".join([parts[i][0], body, parts[i][-1]]) + + return "".join(parts) + + def _classify_for_label(text: str) -> tuple[list[str], NDArray[np.int_]]: """ Classify characters to identify to which environment a label belongs. @@ -764,7 +1605,23 @@ def get(self): """ Return document. """ - return self.preamble + self.start + self.main + self.postamble + ret = "\n\n".join( + list( + filter( + None, + [ + self.preamble.strip(), + self.start.strip(), + self.main.strip(), + self.postamble.strip(), + ], + ) + ) + ) + return ret + "\n" + + def __str__(self): + return self.get() def changed(self): """ @@ -905,7 +1762,7 @@ def remove_commentlines(self): Remove lines that are entirely a comment. """ - tmp = self.main.split("\n") + tmp = self.main.splitlines() tmp = list(itertools.filterfalse(re.compile(r"^\s*%.*$").match, tmp)) self.main = "\n".join(tmp) @@ -1391,7 +2248,7 @@ def texcleanup(args: list[str]): if tex.changed(): with open(file, "w") as file: - file.write(tex.get()) + file.write(str(tex)) def _texcleanup_cli(): @@ -1489,283 +2346,13 @@ def texplain(args: list[str]): output = os.path.join(new.dirname, new.filename) with open(output, "w") as file: - file.write(new.get()) + file.write(str(new)) def _texplain_cli(): texplain(sys.argv[1:]) -def _texindent_latexindent( - config: dict, text: str, tempdir: pathlib.Path, generate_filename: Callable -) -> str: - """ - Run ``latexindent.pl`` on text. - - :param config: Configuration of ``latexindent.pl``. - :param text: Text to format. - :param tempdir: Temporary directory to write files to. - :param generate_filename: Generator of filenames for temporary files ``tempdir / filename``. - :return: Formatted text. - """ - - with open(tempdir / ".latexindent.yaml", "w") as f: - yaml.dump(config, f) - - if generate_filename is not None: - filename = generate_filename() - else: - filename = "main.tex" - - (tempdir / filename).write_text(text) - - subprocess.check_output( - ["latexindent.pl", "-s", "-wd", "-l", "-m", "-r", filename], cwd=tempdir - ) - - return (tempdir / filename).read_text() - - -def _texindent_default( - config: dict, text: str, tempdir: pathlib.Path, generate_filename: Callable -) -> str: - """ - Run ``latexindent.pl`` with in addition to the user configuration the following settings: - - .. code-block:: yaml - - modifyLineBreaks: - oneSentencePerLine: - manipulateSentences: 0 - removeSentenceLineBreaks: 0 - - :param config: Configuration of ``latexindent.pl``. - :param text: Text to format. - :param tempdir: Temporary directory to write files to. - :param generate_filename: Generator of filenames for temporary files ``tempdir / filename``. - :return: Formatted text. - """ - - rules = copy.deepcopy(config) - - if "modifyLineBreaks" in rules: - if "oneSentencePerLine" in rules["modifyLineBreaks"]: - rules["modifyLineBreaks"]["oneSentencePerLine"]["manipulateSentences"] = 0 - rules["modifyLineBreaks"]["oneSentencePerLine"]["removeSentenceLineBreaks"] = 0 - - return _texindent_latexindent(rules, text, tempdir, generate_filename) - - -def _texindent_sentence( - config: dict, text: str, tempdir: pathlib.Path, generate_filename: Callable -) -> str: - """ - Run ``latexindent.pl`` if the following settings are present - - .. code-block:: yaml - - modifyLineBreaks: - oneSentencePerLine: - manipulateSentences: 0/1 - removeSentenceLineBreaks: 0/1 - - Comments, math, environments, and commands are replaced with placeholders to make formatting - a lot less aggressive. - - :param config: Configuration of ``latexindent.pl``. - :param text: Text to format. - :param tempdir: Temporary directory to write files to. - :param generate_filename: Generator of filenames for temporary files ``tempdir / filename``. - :return: Formatted text. - """ - - if "modifyLineBreaks" not in config: - return text - - if "oneSentencePerLine" not in config["modifyLineBreaks"]: - return text - - if ( - "manipulateSentences" not in config["modifyLineBreaks"]["oneSentencePerLine"] - and "removeSentenceLineBreaks" not in config["modifyLineBreaks"]["oneSentencePerLine"] - ): - return text - - ret = TeX(text) - - format, placeholders = text_to_placeholders( - ret.main, - [ - PlacholderType.noindent_block, - PlacholderType.comment, - PlacholderType.inline_math, - PlacholderType.special_indent, - PlacholderType.command, - PlacholderType.environment, - ], - ) - format = _texindent_latexindent(config, format, tempdir, generate_filename) - - for placeholder in placeholders: - if placeholder.ptype == PlacholderType.command: - if re.match(r"([^\{]*\{\n)(.*)", placeholder.content): - if placeholder.content[-1] != "}": - continue - content = re.split( - r"([^\{]*\{\n)(\s*)(.*)", placeholder.content[:-1].rstrip(), re.MULTILINE - ) - command = content[1] - indent = content[2] - content = textwrap.dedent("".join(content[2:])) - content, pl = text_to_placeholders(content, [PlacholderType.command], "SUBINDENT") - content = _texindent_latexindent(config, content, tempdir, generate_filename) - content = text_from_placeholders( - content, pl, default_naming=True, prefix="SUBINDENT" - ) - if content[-1] != "\n": - content += "\n" - placeholder.content = command + textwrap.indent(content + "}", indent) - - ret.main = "\n" + text_from_placeholders(format, placeholders) - - return ret.get() - - -def _detail_texindent(text: str, config: dict, tempdir: pathlib.Path, generate_filename: Callable): - """ - See :py:func:`texindent`. - """ - - if generate_filename is not None: - (tempdir / generate_filename()).write_text(text) - - # "latexindent.pl" formatting with configuration augmented by - # - modifyLineBreaks/oneSentencePerLine/manipulateSentences = 0 - # - modifyLineBreaks/oneSentencePerLine/removeSentenceLineBreaks = 0 - text = _texindent_default(config, text, tempdir, generate_filename) - - # if set, formatting with - # - modifyLineBreaks/oneSentencePerLine/manipulateSentences - # - modifyLineBreaks/oneSentencePerLine/removeSentenceLineBreaks - text = _texindent_sentence(config, text, tempdir, generate_filename) - - # "latexindent.pl" formatting with configuration augmented by - # - modifyLineBreaks/oneSentencePerLine/manipulateSentences = 0 - # - modifyLineBreaks/oneSentencePerLine/removeSentenceLineBreaks = 0 - text = _texindent_default(config, text, tempdir, generate_filename) - - # remove trailing whitespaces - text = "\n".join([line.rstrip() for line in text.splitlines()]) + "\n" - - return text - - -def texindent_default_config() -> dict: - r""" - Default configuration of ``latexindent.pl``. - - .. code-block:: yaml - - defaultIndent: ' ' - removeTrailingWhitespace: 1 - - lookForAlignDelims: - align: - alignDoubleBackSlash: 0 - split: - alignDoubleBackSlash: 0 - - modifyLineBreaks: - oneSentencePerLine: - manipulateSentences: 1 - removeSentenceLineBreaks: 1 - multipleSpacesToSingle: 1 - items: - ItemFinishesWithLineBreak: 1 - environments: - BeginStartsOnOwnLine: 1 - BodyStartsOnOwnLine: 1 - EndStartsOnOwnLine: 1 - EndFinishesWithLineBreak: 1 - DBSFinishesWithLineBreak: 1 - - indentRules: - item: ' ' - - fineTuning: - namedGroupingBracesBrackets: - # https://github.com/cmhughes/latexindent.pl/issues/330 - name: '[0-9\.a-zA-Z@\*><_]+?' - arguments: - # https://github.com/cmhughes/latexindent.pl/issues/416 - between: _|\^|\*|\| - """ - - text = texindent_default_config.__doc__ - text = textwrap.dedent(text.split(".. code-block:: yaml")[1]) - return yaml.load(text, Loader=yaml.FullLoader) - - -def texindent( - text: str, config: dict, tempdir: pathlib.Path = None, generate_filename: Callable = None -) -> str: - r""" - Format text with ``latexindent.pl``. - Augmented rules: - - - A command and inline math inside a sentence is considered as a neutral placeholder. - - - The whitespace before and after any command, environment, and comment are exactly preserved. - - - The linebreaks of sentences inside commands are only changed if the command if formatted: - - .. code-block:: latex - - ... \mycommand{ - This is a - sentence. - } - - which is formatted to - - .. code-block:: latex - - ... \mycommand{ - This is a sentence. - } - - Instead, the following formatting does not change the linebreaks inside the command: - - .. code-block:: latex - - ... \mycommand{This is a - sentence.} - - :param text: Text to format. - - :param config: Configuration of ``latexindent.pl``, e.g. :py:func:`texindent_default_config`. - - :param tempdir: - Temporary directory to write files to. - If ``None`` a temporary directory is created, and removed after use. - - :param generate_filename: - Generator of filenames for temporary files ``tempdir / filename``. - If ```None`` a single filename is used. - That file is overwritten on each call. - - :return: Formatted text. - """ - - if tempdir is None: - assert generate_filename is None - with tempfile.TemporaryDirectory() as tempdir: - tempdir = pathlib.Path(tempdir) - return _detail_texindent(text, config, tempdir, None) - - return _detail_texindent(text, config, tempdir, generate_filename) - - def _texindent_parser(): """ Return parser for :py:func:`texindent`. @@ -1774,44 +2361,12 @@ def _texindent_parser(): desc = "Wrapper around ``latexindent.pl`` with some additional rules. ``texplain.texindent``." parser = argparse.ArgumentParser(description=desc) - parser.add_argument("-c", "--config", type=str, help="Configuration file") - parser.add_argument("-t", "--tempdir", type=str, help="Temporary directory") - parser.add_argument("-v", "--version", action="version", version=version) parser.add_argument("files", nargs="+", type=str, help="TeX file") return parser -def _detail_texindent_cli( - filepath: str, config: dict, tempdir: pathlib.Path, generate_filename: Callable -): - """ - See :py:func:`texindent_cli`. - """ - - filepath = pathlib.Path(filepath) - orig = filepath.read_text() - formatted = texindent(orig, config, tempdir, generate_filename) - - # copy back if modified - if formatted != orig: - filepath.write_text(formatted) - - -class _FilenameGenerator: - """ - Class to generate filenames. - """ - - def __init__(self): - self.i = 0 - - def __call__(self): - self.i += 1 - return f"texindent-stage-{self.i:03d}.tex" - - def texindent_cli(args: list[str]): """ Wrapper around latexindent.pl, see ``--help``. @@ -1821,33 +2376,18 @@ def texindent_cli(args: list[str]): args = parser.parse_args(args) assert all([os.path.isfile(file) for file in args.files]) - if args.config is None: - if os.path.isfile(".texindent.yaml"): - args.config = ".texindent.yaml" - elif os.path.isfile(".texindent.yml"): - args.config = ".texindent.yml" - elif os.path.isfile(".latexindent.yaml"): - args.config = ".latexindent.yaml" - elif os.path.isfile(".latexindent.yml"): - args.config = ".latexindent.yml" - else: - config = texindent_default_config() - else: - assert os.path.isfile(args.config) - - if args.config is not None: - with open(args.config) as file: - config = yaml.load(file.read(), Loader=yaml.FullLoader) + for filepath in args.files: + filepath = pathlib.Path(filepath) + orig = filepath.read_text() - if args.tempdir is not None: - assert len(args.files) == 1 - gen = _FilenameGenerator() - return _detail_texindent_cli(args.files[0], config, pathlib.Path(args.tempdir), gen) + tex = TeX(orig) + tex.preamble = indent(tex.preamble) + tex.main = indent(tex.main) + tex.postamble = indent(tex.postamble) + formatted = str(tex) - with tempfile.TemporaryDirectory() as tempdir: - tempdir = pathlib.Path(tempdir) - for filepath in args.files: - _detail_texindent_cli(filepath, config, tempdir, None) + if formatted != orig: + filepath.write_text(formatted) def _texindent_cli():