Home About me Blog Po polsku

Content AND Presentation

(Note to English-speaking readers: the links entitled Komentarze na tej stronie lead to comment pages.)

2015-02-28 Math examples in TeX, part I

I’m currently coauthoring an introductory book on LaTeX. (Yes, yet another one. But apparently there are not that many of them in Polish!) Of course, one of the must-haves is a chapter on typesetting equations. What I wanted, however, is a way to enter them with preservation of the DRY principle. It’s probably a solved problem, but I quite enjoyed hacking it together myself.

\documentclass{article}
\makeatletter
\def\mathdemo{%
  \bgroup
  \let\do\@makeother\dospecials
  \@mathdemo
}
\def\@mathdemo`#1`{%
  \egroup
  \par\smallskip\noindent
  \makebox[0.48\textwidth]{\texttt{#1}}\hfill
  \framebox[0.48\textwidth]{$\scantokens{#1}$}\par\smallskip
}
\makeatother

\begin{document}
\mathdemo`E=mc^2`
\end{document}

It is probably self-explanatory for more seasoned TeX hackers, but let me explain it for the beginners here. We start with enabling the internal “@-commands” (\makeatletter). With that done, we define the \mathdemo command. It starts a group and makes all special characters no longer special locally in that group. (It does that by making the \do command turn its argument into an “other” category, and firing the \dospecials, which runs \do on all the special characters.) Finally, we start the \@mathdemo internal command.

What it does is that it interprets anything between the backticks as its argument (backtick is rather unlikely to happen in math examples). It starts by ending the group, which is important: now that all the category codes of the characters in the argument are fixed (as “non-specials”), we no longer need that. We start a new, unindented paragraph with a small skip above, put our argument in a fixed-width font in a box, and then the real fun begins. We use eTeX’s \scantokens to reinterpret the argument with the category codes now in effect. (This was something impossible to do in Knuth’s vanilla TeX.) This way, all the special characters (like the caret) get reinterpreted with their usual meaning. Finally, we turn off the “letterness” of the at-sign.

A side-effect of our playing with catcodes, by the way, is the impossibility of putting a space between \mathdemo and the first backtick: when reading the backtick-delimited argument to \@mathdemo, space is no longer of category 10 (a space character), so it is not ignored after a command.

Also, I have to admit that the production code I use is a bit more complicated: it allows for multiline code on the left, for instance, and it has a \dmathdemo variant for demonstrating displayed math. This, however, is another subject for another post.

CategoryEnglish, CategoryBlog, CategoryTeX, CategoryLaTeX

Komentarze na tej stronie

2015-02-21 Lorem ipsum dolor sit Emacs

As many LaTeX users know, sometimes you just need some dummy text so that you can test a font, a layout or something like that. In such cases, the lipsum package (or kantlipsum, if you’re feeling philosophical) is really handy. OTOH, when coding things like Org-mode exporters, a similar thing for Emacs’ Org-mode would be also useful. So I decided to write lipsum.el.

Well, but I didn’t write it after all. I googled first, and it turns out that I was late by more than a decade… Here it is on GitHub: https://github.com/jschaf/emacs-lorem-ipsum. It is not exactly idiomatic Elisp (I’ll come back to this in a moment), and it uses randomization, so I might write my own version some day (LaTeX’s lipsum is fully deterministic, and I prefer that to random sentences each time), but it’s here and it works.

Coming back to the “idiomatic Elisp” part. Don’t get me wrong, I’m not trying to claim that I’m an expert Elisp programmer – I’m not. But while we’re at it, why not study a piece of code from that package, just in case some beginner reads this? So, here it is:

(defun lorem-ipsum-insert-paragraphs (&optional num)
  "Insert lorem ipsum paragraphs into buffer.
If NUM is non-nil, insert NUM paragraphs."
  (interactive "p")
  (if (not num)(setq num 1))
  (if (> num 0)
      (progn
	(insert (concat
		 (mapconcat 'identity
			    (nth (random (length lorem-ipsum-text))
				 lorem-ipsum-text)
			    lorem-ipsum-sentence-separator)
		 lorem-ipsum-paragraph-separator))
	(lorem-ipsum-insert-paragraphs (- num 1)))))

First of all, I really don’t like the (if (not num)(setq num 1)) part; I believe that the common idiom would be to write (setq num (or num 1)).

Then, while I appreciate the mathematical elegance of tail recursion, the bad news is that Elisp is not Scheme, and you can easily run out of stack. (Here’s a trivial way to check this: define

(defun tail-recursion-test (n)
  (when (> n 0)
    (insert (format "Countdown: %s\n" n))
    (tail-recursion-test (1- n))))

and run it with a large parameter.) While that might not be considered Lispy enough, I guess that a simple dotimes would do better here.

Yet another problem I have with this code is the

(if (...)
    (progn ...
           ...))

construct. It is exactly the situation when when should be used – there is no “else” branch, and the “then” branch consists of more than one expression.

Last but not least: while (- num 1) is perfectly fine, I personally would use (1- num) – though I can imagine that someone might prefer the longer version for its ostensible readability.

Anyway: again, this all is not to say that someone did a poor job. All these “problems” are in fact minor ones. It’s just that the (good enough, but arguably not optimal) code is an opportunity to learn.

CategoryEnglish, CategoryBlog, CategoryEmacs, CategoryOrgMode, CategoryTeX

Komentarze na tej stronie

2015-02-14 Counting visible characters

There was a discussion on the ConTeXt mailing list recently about counting visible characters in a PDF file. This is easily reduced (by the pdftotext utility) to the problem of counting visible characters in a text file. Just for fun, I decided to do this in Elisp. I knew this wouldn’t be really a challenge to code it, but it might be a bit challenging to make it optimal. So, here’s the first (and final, as of now) version:

(defun how-many-visible-chars ()
    "Count visible (i.e., other than spaces, tabs and newlines)
characters in the buffer."
  (interactive)
  (let ((count 0))
    (save-excursion
      (goto-char (point-min))
      (while (not (eobp))
	(unless (looking-at-p "[ \t\n]")
	  (setq count (1+ count)))
	(forward-char)))
    (message "%d visible characters" count)))

First of all, note that this is not production-ready code: it works only as an interactive command (i.e., it does not return an integer nor suppress the message when called from a Lisp program), nor does it recognize active region (which IMHO is a must for command like this – though it does, obviously, respect narrowing).

Also, it counts hidden characters, too, e.g. it takes into account all the folded text in Org buffers. I don’t exactly know how to overcome this. (Actually, I can imagine that someone might want to do things like this. For instance, count-lines-region counts invisible lines, too, and sometimes I want to count only the subheadings of the Org entry. There is no built-in way to do it, although it is simple to write a bit of Elisp to perform such a calculation.)

The biggest problem with this – at least I thought so – is performance. The idea of walking through the buffer character by character and using a regex to check whether it is not a blank one seems outrageous (and rightfully so). I was quite surprised to learn that it’s not really that inefficient: I ran it on Emacs’ simple.el (which is more than 300 kB long – quite a feat for a text file), and it took my function one or two seconds to count all the non-blank characters.

I guess it might be an interesting exercise to think about possible optimizations. I guess getting rid of regexen may be a good idea. Another one I could come up with is kind of loop unrolling: since the bulk of most buffers is made up of letters, digits and a few other characters, using skip-chars-forward might help a lot. As a matter of fact, skip-syntax-forward might be even faster; OTOH, in buffers where the syntax property is used a lot, this might not be the best idea.

I have to admit that now having thought and written about this, I can’t wait to try out the Emacs profiler.

CategoryEnglish, CategoryBlog, CategoryEmacs, CategoryOrgMode, CategoryTeX

Komentarze na tej stronie

Więcej...

(Więcej means More in Polish; click it to see older entries.)

CategoryEnglish, CategoryBlog