0

I'm writing a lot of LaTeX-files and to improve the process I'm trying to give each environment a background tinge. So I wrote a list of tuples of environment types and faces, daselt-latex-colored-env-list, and I wrote a function font-lock should use to match an environment:

(defun daselt-latex-match-environment (env end)
  "This function matches the first LaTeX environment of type env between beg and end."
  (let ((match (re-search-forward (format "\\\\begin{%s}\\(\n[ ]*\\\\label{.*}\n\\)?" env) end t))
        (env0 (match-end 0)))
    (if env0 (progn (condition-case noend (LaTeX-find-matching-end)
                      (error nil))
                    (beginning-of-line)
                    (backward-char)
                    (set-match-data (list env0 (point)))
                    match))))

Now I'd like to automatically add this function with its matching face to font-lock-keywords using font-lock-add-keywords and wrote a function that should do that:

(defun daselt-latex-font-lock-add-env-colors ()
  "This function adds the environment-color pairs in daselt-latex-colored-env-list to font-lock-keywords."
  (interactive)
  (mapcar (lambda (envtuple)
            (font-lock-add-keywords 'LaTeX-mode
                                    (list (cons
                                           (lambda (end)
                                             (daselt-latex-match-environment (car envtuple) end))
                                           (list '2 (nth 1 envtuple) t t)))))
          daselt-latex-colored-env-list))

The trouble is, when I try this out, the function doesn't add, daselt-latex-match-environmentwith first argument fixed to one value, like "align", but it adds ((daselt-latex-match-environment (car envtuple) end)), so that I get an error because envtuple is undefined.

Since this wasn't working I went back to the manual and read that the MATCHER in an entry of font-lock-keywords should be the name of a function, not a function itself. Since I never got that far I'm not sure whether this would have been a problem, but I tried to write a function that automatically generates all functions I need as named functions:

(mapcar (lambda (envtuple)
          (let (env (car envtuple))
            (defun (intern (format "daselt-latex-font-lock-match-%s" env)) (beg end)
              (format "Function to match environments of type %n for font-lock." env)
              (lambda (beg end) (daselt-latex-match-environment env beg end)))))
        daselt-latex-colored-env-list)

But this doesn't work either because it doesn't evaluate (intern (format "daselt-latex-font-lock-match-%s" env)), so I get an error message because defun wants a symbol as its first argument. Though those two approaches are different, the core problem is roughly the same which is that macros don't expand their arguments, so how do I use them to create new functions by fixing an argument of a base function?

1 Answer 1

0

I found the answer here, and admittedly it seems pretty simple in hindsight: write a macro around the macro that should define, say, a function, and use that macro to provide the inner macro with its right arguments. Even better, use backquote and commas to precisely define which parts of the macro are to be evaluated and which not. After some trying around, I came up with this, which seems to work:

(defmacro colored-latex-envs-construct-matching-functions (envlist)
  "This macro constructs the functions matching the internals of the environments in envlist, where envlist is a list of pairs of LaTeX-environments env and their corresponding themes, by calling colored-latex-envs-match-environment with env as its first argument."
  (prog2 (mapcar (lambda (envtuple)
                   (eval `(defun ,(intern (concat "colored-latex-envs-match-"
                                                  (car envtuple))) (end)
                            (interactive)
                            (eval (colored-latex-envs-match-environment ,(car envtuple) end)))))
                 (symbol-value envlist))
      nil))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.