From 4bf5d56f36d33074ef0df9e91a12a9c8082d7a3e Mon Sep 17 00:00:00 2001 From: Allen Downey Date: Thu, 21 Aug 2025 16:54:53 -0400 Subject: [PATCH] Save HeVeA experiments: Makefile cleanup, HeVeA integration attempts, and conditional compilation work --- Makefile | 260 +++++++++++++++++++++++++++++++-------------- README.md | 102 ++++++++++++++++-- ch01.tex | 8 +- ch05.tex | 8 +- hevea/htmlonly.tex | 6 ++ latexonly.tex | 6 +- thinkjava2.tex | 21 ++-- 7 files changed, 307 insertions(+), 104 deletions(-) diff --git a/Makefile b/Makefile index bbd9fc6..807088d 100644 --- a/Makefile +++ b/Makefile @@ -1,99 +1,197 @@ -F=thinkjava2 +# ThinkJava2 Makefile +# Build system for the ThinkJava2 textbook project -all: - pdflatex $(F).tex - pdflatex $(F).tex - pdflatex $(F).tex +# ============================================================================= +# VARIABLES +# ============================================================================= -clean: - rm -f comment.cut $(F).aux $(F).idx $(F).ilg $(F).ind $(F).log $(F).out $(F).toc +# Main project filename +F := thinkjava2 -plastex: - # Before running plastex, we need the current directory in PYTHONPATH - # export PYTHONPATH=$PYTHONPATH:. - latexpand --keep-comments $(F).tex > $(F).expand - python2 preprocess.py $(F).expand > $(F).plastex - plastex --renderer=DocBook --theme=book --image-resolution=300 --filename=$(F).xml $(F).plastex - cd $(F); python2 ../postprocess.py $(F).xml > temp; mv temp $(F).xml - cd $(F); python ../xmlsplit.py $(F).xml +# Directories +BUILD_DIR := build +HEVEA_DIR := heveahtml +TRINKET_DIR := trinkethtml +DIST_DIR := dist +DEST_DIR := /home/downey/public_html/greent/thinkjava7 -xxe: - xmlcopyeditor ~/ThinkJava2/$(F)/$(F).xml & +# Tools +PYTHON := python +PYTHON2 := python2 +PYTHON3 := python3 +LATEX := pdflatex +PLASTEX := plastex +HEVEA := hevea +IMAGEN := imagen +HACHA := hacha +LATEXPAND := latexpand + +# ============================================================================= +# DEFAULT TARGET +# ============================================================================= + +.PHONY: all +all: pdf -lint: - xmllint -noout $(F)/$(F).xml +# Note: 'all' builds only PDF. Use specific targets for other formats: +# make plastex - Build XML version +# make hevea - Build HTML version +# make trinket - Build Trinket HTML version -#oreilly: -# rsync -a $(F)/*.xml atlas/ -# rsync -a figs/*.pdf atlas/figs/ -# rsync -a figs/*.png atlas/figs/ -# rsync -a figs/*.jpg atlas/figs/ -# cd atlas; git add *.xml figs/* -# cd atlas; git commit -m "Automated check in." -# cd atlas; git push +# ============================================================================= +# PDF BUILD +# ============================================================================= -# if a bug (in ocaml?) causes "make hevea" to fail; use "make -i hevea" instead +.PHONY: pdf +pdf: + @echo "Building PDF..." + $(LATEX) $(F).tex + $(LATEX) $(F).tex + $(LATEX) $(F).tex + @echo "PDF build complete: $(F).pdf" + +# ============================================================================= +# XML BUILD (PLASTEX) +# ============================================================================= + +.PHONY: plastex +plastex: + @echo "Building XML with PlasTeX..." + @mkdir -p $(BUILD_DIR) + # Before running plastex, we need the current directory in PYTHONPATH + # export PYTHONPATH=$PYTHONPATH:. + $(LATEXPAND) --keep-comments $(F).tex > $(F).expand + $(PYTHON2) preprocess.py $(F).expand > $(F).plastex + $(PLASTEX) --renderer=DocBook --theme=book --image-resolution=300 --filename=$(F).xml $(F).plastex + cd $(BUILD_DIR); $(PYTHON2) ../postprocess.py $(F).xml > temp && mv temp $(F).xml + cd $(BUILD_DIR); $(PYTHON) ../xmlsplit.py $(F).xml + +# ============================================================================= +# HTML BUILD (HEVEA) +# ============================================================================= +# Note: hevea/ contains source files (htmlonly.tex, templates, scripts) +# heveahtml/ contains generated HTML output (build artifacts) .PHONY: hevea hevea: + @echo "Building HTML with HeVeA..." + @rm -rf $(HEVEA_DIR) + @mkdir -p $(HEVEA_DIR) cp $(F).tex $(F)_.tex - rm -rf heveahtml - mkdir heveahtml - hevea -O -exec xxdate.exe -e latexonly.tex hevea/htmlonly.tex $(F)_ - hevea -O -exec xxdate.exe -e latexonly.tex hevea/htmlonly.tex $(F)_ - imagen -png -pdf $(F)_ - imagen -png -pdf $(F)_ - hacha $(F)_.html - cp hevea/*.png heveahtml + $(HEVEA) -O -exec xxdate.exe -e latexonly.tex hevea/htmlonly.tex $(F)_ + $(HEVEA) -O -exec xxdate.exe -e latexonly.tex hevea/htmlonly.tex $(F)_ + $(IMAGEN) -png -pdf $(F)_ + # $(IMAGEN) -png -pdf $(F)_ + $(HACHA) $(F)_.html + cp hevea/*.png $(HEVEA_DIR) cat custom.css >> $(F)_.css - mv index.html $(F)_?*.html $(F)_*.png $(F)_.css heveahtml - rm *motif.gif $(F)_.* - sed -i 's/\\%/%/g' heveahtml/*.html - sed -i 's/\\{/{/g' heveahtml/*.html - sed -i 's/\\}/}/g' heveahtml/*.html - sed -i 's/\\\\n/\\n/g' heveahtml/*.html - sed -i 's/\\\\t/\\t/g' heveahtml/*.html - python3 hevea/rename.py heveahtml + mv index.html $(F)_?*.html $(F)_*.png $(F)_.css $(HEVEA_DIR) + rm -f *motif.gif $(F)_.* + sed -i 's/\\%/%/g' $(HEVEA_DIR)/*.html + sed -i 's/\\{/{/g' $(HEVEA_DIR)/*.html + sed -i 's/\\}/}/g' $(HEVEA_DIR)/*.html + sed -i 's/\\\\n/\\n/g' $(HEVEA_DIR)/*.html + sed -i 's/\\\\t/\\t/g' $(HEVEA_DIR)/*.html + $(PYTHON3) hevea/rename.py $(HEVEA_DIR) + +# ============================================================================= +# TRINKET BUILD +# ============================================================================= .PHONY: trinket trinket: + @echo "Building Trinket HTML..." + @rm -rf $(TRINKET_DIR) + @mkdir -p $(TRINKET_DIR) cp $(F).tex $(F)_.tex - rm -rf trinkethtml - mkdir trinkethtml - hevea -O -exec xxdate.exe -e latexonly.tex trinket/htmlonly.tex $(F)_ - hevea -O -exec xxdate.exe -e latexonly.tex trinket/htmlonly.tex $(F)_ - imagen -png -pdf $(F)_ - imagen -png -pdf $(F)_ - hacha $(F)_.html - cp trinket/*.css trinket/*.js trinkethtml - mv index.html $(F)_.css $(F)_?*.html $(F)_*.png trinkethtml - rm *motif.gif $(F)_.* - sed -i 's/\\%/%/g' trinkethtml/*.html - sed -i 's/\\{/{/g' trinkethtml/*.html - sed -i 's/\\}/}/g' trinkethtml/*.html - sed -i 's/\\\\n/\\n/g' trinkethtml/*.html - sed -i 's/\\\\t/\\t/g' trinkethtml/*.html - - # perl postprocessing (woot) seems easier than escaping through Latex and Hevea - perl -i -pe 's/\[\[\[\[\s?(\S*?)\s?\]\]\]\]/----{\1}----/g' trinkethtml/*.html - perl -i -pe 's/\\<\/a\>//g' trinkethtml/*.html - perl -0777 -i -pe 's/\//' trinkethtml/*.html - - # produce nunjucks templates for our app - mkdir trinkethtml/nunjucks - python trinket/maketemplates.py - - # gather images for ease of uploading to CDN - mkdir trinkethtml/img - cp trinkethtml/*.png trinkethtml/img - -DEST = /home/downey/public_html/greent/thinkjava7 + $(HEVEA) -O -exec xxdate.exe -e latexonly.tex trinket/htmlonly.tex $(F)_ + $(HEVEA) -O -exec xxdate.exe -e latexonly.tex trinket/htmlonly.tex $(F)_ + $(IMAGEN) -png -pdf $(F)_ + $(IMAGEN) -png -pdf $(F)_ + $(HACHA) $(F)_.html + cp trinket/*.css trinket/*.js $(TRINKET_DIR) + mv index.html $(F)_.css $(F)_?*.html $(F)_*.png $(TRINKET_DIR) + rm -f *motif.gif $(F)_.* + sed -i 's/\\%/%/g' $(TRINKET_DIR)/*.html + sed -i 's/\\{/{/g' $(TRINKET_DIR)/*.html + sed -i 's/\\}/}/g' $(TRINKET_DIR)/*.html + sed -i 's/\\\\n/\\n/g' $(TRINKET_DIR)/*.html + sed -i 's/\\\\t/\\t/g' $(TRINKET_DIR)/*.html + # Perl postprocessing for Trinket-specific formatting + perl -i -pe 's/\[\[\[\[\s?(\S*?)\s?\]\]\]\]/----{\1}----/g' $(TRINKET_DIR)/*.html + perl -i -pe 's/\\<\/a\>//g' $(TRINKET_DIR)/*.html + perl -0777 -i -pe 's/\//' $(TRINKET_DIR)/*.html + + # Produce Nunjucks templates for our app + @mkdir -p $(TRINKET_DIR)/nunjucks + $(PYTHON) trinket/maketemplates.py + + # Gather images for ease of uploading to CDN + @mkdir -p $(TRINKET_DIR)/img + cp $(TRINKET_DIR)/*.png $(TRINKET_DIR)/img + +# ============================================================================= +# UTILITY TARGETS +# ============================================================================= + +.PHONY: clean +clean: + @echo "Cleaning build artifacts..." + rm -f comment.cut $(F).aux $(F).idx $(F).ilg $(F).ind $(F).log $(F).out $(F).toc + rm -f $(F).expand $(F).plastex + rm -rf $(BUILD_DIR) $(HEVEA_DIR) $(TRINKET_DIR) $(DIST_DIR) + +.PHONY: clean-all +clean-all: clean + @echo "Cleaning all generated files..." + rm -f $(F).pdf + +.PHONY: xxe +xxe: + @echo "Opening XML in XML Copy Editor..." + xmlcopyeditor ~/ThinkJava2/$(BUILD_DIR)/$(F).xml & + +.PHONY: lint +lint: $(BUILD_DIR)/$(F).xml + @echo "Validating XML..." + xmllint -noout $(BUILD_DIR)/$(F).xml + +# ============================================================================= +# DISTRIBUTION +# ============================================================================= + +.PHONY: distrib distrib: - rm -rf dist - mkdir dist - rsync -a $(F).pdf dist - rsync -a heveahtml/ dist/html/ - rsync -a dist/* $(DEST) - chmod -R o+r $(DEST)/* - cd $(DEST)/..; sh back + @echo "Creating distribution package..." + rsync -a $(F).pdf $(DIST_DIR) + rsync -a $(HEVEA_DIR)/ $(DIST_DIR)/html/ + rsync -a $(DIST_DIR)/* $(DEST_DIR) + chmod -R o+r $(DEST_DIR)/* + cd $(DEST_DIR)/..; sh back + @echo "Distribution complete: $(DEST_DIR)" + +$(DIST_DIR): + @mkdir -p $(DIST_DIR) + +# ============================================================================= +# HELP +# ============================================================================= + +.PHONY: help +help: + @echo "ThinkJava2 Makefile - Available targets:" + @echo "" + @echo " all/pdf - Build PDF version (default)" + @echo " plastex - Build XML version using PlasTeX" + @echo " hevea - Build HTML version using HeVeA" + @echo " trinket - Build Trinket HTML version" + @echo " distrib - Create distribution package" + @echo "" + @echo " clean - Remove build artifacts" + @echo " clean-all - Remove all generated files" + @echo " lint - Validate XML output" + @echo " xxe - Open XML in XML Copy Editor" + @echo " help - Show this help message" + @echo "" + @echo "Note: If HeVeA fails due to OCaml bugs, use 'make -i hevea'" diff --git a/README.md b/README.md index 69e33f6..8467246 100644 --- a/README.md +++ b/README.md @@ -9,15 +9,101 @@ The illustrations were drawn using xfig (http://www.xfig.org/) and dia (https:// Compiling the LaTeX source has the effect of generating a device-independent representation of the book, which can be converted to other formats and printed. -To compile the PDF version from source: +## Building the Book - pdflatex thinkjava2.tex - pdflatex thinkjava2.tex - pdflatex thinkjava2.tex +### Prerequisites +On Linux, you may need to install: +- `texlive-latex-extra` and `texlive-fonts-recommended` for PDF generation +- `plastex` for XML generation -The source code includes a Makefile that automates this process. On Linux, you may need to install texlive-latex-extra and texlive-fonts-recommended. +#### Installing HeVeA (Required for HTML generation) +HeVeA is available through the OCaml Package Manager (opam): -To build the HTML versions, the hevea package is required. Use the Makefile as follows: +```bash +# 1. Install opam if you don't have it +# Debian/Ubuntu +sudo apt install opam - make hevea # static html - make trinket # interactive +# macOS with Homebrew +brew install opam + +# 2. Initialize opam +opam init + +# 3. Install hevea from opam (latest release from maintainer) +opam install hevea + +# 4. Make sure opam's bin directory is in your PATH +eval $(opam env) + +#### Troubleshooting: LaTeX Can't Find HeVeA Style File +After installing HeVeA, you may see a warning that `hevea.sty` was installed but LaTeX can't find it. This is because the style file is in opam's directory. Here's how to fix it: + +**Solution: Add opam's LaTeX directory to TEXINPUTS** + +```bash +# Add this line to your ~/.bashrc or ~/.zshrc +export TEXINPUTS="$HOME/.opam/default/lib/hevea:$TEXINPUTS" + +# Then reload your shell configuration +source ~/.bashrc # or source ~/.zshrc + +# Verify the file is now found +kpsewhich hevea.sty +``` + +This should return the path to `hevea.sty` if the fix worked. + + + +### Build Options + +#### PDF Version (Default) +```bash +make pdf # or just 'make' +``` +This runs `pdflatex` three times to resolve cross-references. + +#### HTML Versions +```bash +make hevea # Static HTML version +make trinket # Interactive HTML version for Trinket platform +``` + +#### XML Version +```bash +make plastex # DocBook XML output +``` + +#### Other Targets +```bash +make clean # Remove build artifacts +make clean-all # Remove all generated files including PDF +make lint # Validate XML output +make distrib # Create distribution package +``` + +### Manual PDF Build +If you prefer to build manually: + +```bash +pdflatex thinkjava2.tex +pdflatex thinkjava2.tex +pdflatex thinkjava2.tex +``` + +## Project Structure + +- **`*.tex`** - LaTeX source files for each chapter +- **`figs/`** - Source figures (xfig, dia, PNG) +- **`code/`** - Java source code examples +- **`hevea/`** - HTML build configuration and templates +- **`atlas/`** - Publishing workflow files +- **`Makefile`** - Automated build system + +## Notes + +- The default `make` target builds only PDF for faster development cycles +- Use specific targets for other formats when needed +- Build artifacts are placed in separate directories (e.g., `heveahtml/`, `build/`) +- If HeVeA fails due to OCaml bugs, use `make -i hevea` diff --git a/ch01.tex b/ch01.tex index 2d52b0b..f852c08 100644 --- a/ch01.tex +++ b/ch01.tex @@ -40,10 +40,10 @@ \section{What Is a Computer?} \begin{figure}[!ht] \begin{center} %https://commons.wikimedia.org/wiki/File:Intel_80486DX2_top.jpg -\includegraphics[height=11em]{figs/CPU.jpg} +\includegraphics[height=11em,alt="Intel 80486DX2 processor chip"]{figs/CPU.jpg} \hspace{2em} %https://commons.wikimedia.org/wiki/File:Memory_module_DDRAM_20-03-2006.jpg -\includegraphics[height=11em]{figs/RAM.jpg} +\includegraphics[height=11em,alt="DDRAM memory module"]{figs/RAM.jpg} \caption{Example processor and memory hardware.} \label{fig.cpuram} \end{center} @@ -215,7 +215,7 @@ \section{Compiling Java Programs} \begin{figure}[!ht] \begin{center} -\includegraphics{figs/interpreter.pdf} +\includegraphics[alt="Interpreter reading and executing code line by line"]{figs/interpreter.pdf} \caption{How interpreted languages are executed.} \label{fig.interpreter} \end{center} @@ -256,7 +256,7 @@ \section{Compiling Java Programs} \begin{figure}[!ht] \begin{center} -\includegraphics{figs/compiler.pdf} +\includegraphics[alt="Java compilation process from source to bytecode"]{figs/compiler.pdf} \caption{The process of compiling and running a Java program.} \label{fig.compiler} \end{center} diff --git a/ch05.tex b/ch05.tex index eddf7f9..d10440c 100644 --- a/ch05.tex +++ b/ch05.tex @@ -791,17 +791,17 @@ \section{Exercises} \hline \java{True || hello.length() > 0} & \\ \hline -\java{hello.isEmpty() && yes} & \\ +\java{hello.isEmpty() \&\& yes} & \\ \hline -\java{grade <= 100 && !false} & \\ +\java{grade <= 100 \&\& !false} & \\ \hline \java{!yes || no} & \\ \hline \java{grade > 75 > amount} & \\ \hline -\java{amount <= hiVal && amount >= loVal} & \\ +\java{amount <= hiVal \&\& amount >= loVal} & \\ \hline -\java{no && !no || yes && !yes} & \\ +\java{no \&\& !no || yes \&\& !yes} & \\ \hline \end{tabular} \end{center} diff --git a/hevea/htmlonly.tex b/hevea/htmlonly.tex index f007256..e2819cf 100644 --- a/hevea/htmlonly.tex +++ b/hevea/htmlonly.tex @@ -1,6 +1,12 @@ \usepackage{makeidx} \makeindex +% Set HeVeA conditional to true +\newif\ifhevea \heveatrue + +% MathJax for better math rendering and accessibility +\usepackage[auto]{mathjax} + \newcommand{\adjustpage}[1]{} \newcommand{\clearemptydoublepage}{} diff --git a/latexonly.tex b/latexonly.tex index a0ceeca..2600c54 100644 --- a/latexonly.tex +++ b/latexonly.tex @@ -1,3 +1,7 @@ +\usepackage[T1]{fontenc} +\usepackage{lmodern} +\usepackage{textcomp} + \usepackage{geometry} \geometry{ %paperwidth=6.0in, @@ -86,7 +90,6 @@ \definecolor{strings}{HTML}{B20000} % syntax highlighting in code listings -\usepackage{textcomp} \usepackage{listings} \lstset{ language=java, @@ -110,6 +113,7 @@ \lstnewenvironment{code} {\minipage{\linewidth}} {\endminipage} + \lstnewenvironment{stdout} {\lstset{commentstyle=,keywordstyle=,stringstyle=}\minipage{\linewidth}} {\endminipage} diff --git a/thinkjava2.tex b/thinkjava2.tex index 741d5c4..3f9d8d5 100644 --- a/thinkjava2.tex +++ b/thinkjava2.tex @@ -36,6 +36,7 @@ \newif\ifplastex \plastexfalse + %%%% PLASTEX ONLY \ifplastex @@ -73,16 +74,24 @@ %%%% LATEX/HTML ONLY \else -%BEGIN LATEX -\usepackage{comment} -\excludecomment{htmlonly} -\includecomment{latexonly} -%END LATEX +\makeatletter +\@ifundefined{ifhevea}{\newif\ifhevea \heveafalse}{} +\makeatother -\input{latexonly.tex} +\ifhevea + % HeVeA-specific setup + \typeout{DEBUG: HeVeA is running} +\else + % LaTeX/PDF-only setup + \typeout{DEBUG: LaTeX is running} + \usepackage{comment} + \excludecomment{htmlonly} + \includecomment{latexonly} + \input{latexonly.tex} \fi +\fi %%%% END OF PREAMBLE \begin{document}