Hi again

Long list, thanks. Went through it, item per item.
Current version in git reflects answers.
Comments inline...

On 1/11/25 14:23, Ihor Radchenko wrote:

> Pedro Andres Aranda Gutierrez <[email protected]> writes:

>> So, how do we proceed now?

> The next step is code review.
> Here are the initial comments on ox-latex.el:

> > +(defun string-or-null-p (object)
> > +  "Return non-nil when `object' is a string or nil"
> > +  (or (null object)
> > +      (stringp object)))
>
> Please remove. This is a function from subr.el. I am not sure why you
> need to copy its definition.

Wasn't sure it was there and included it therefore.
Removed.

>> +(defcustom org-latex-multi-lang nil
>> +  "The multi-lingual support package used by the LaTeX backend.
>> +
>> +Possible values are \"polyglossia\",\"babel\" , \"fontspec\" or `nil'.
>> +\"polyglossia\" or \"babel\"  activates new implementations for
>> +                              either LaTeX package,
>> +`t'           activates new font/multi-lingual support,
>> +`nil' means legacy support for babel/polyglossia."
>
>Please add reference to the in-buffer keyword. See how it is done in
>`org-latex-compiler' docstring.

Done

> Also, the text alignment is strange. On other docstrings as well -
> indentation of some lines seem arbitrary.

I hope I fixed it now.

> In addition, here and in other docstrings, please remove quotes from `t'
> and `nil'. By docstring convention, you should leave nil and t as is.

Done for ox-latex.el

>> (defcustom org-latex-fontspec-config nil
>>   "This variable stores the configuration for the fontspec package.
>> By default, this variable is set to `nil' to generate no configuration.
>>
>> Each element is defined as
>> (`font-name' . `font-plist')
>>  where `font-name' is the name in `\\set...font{}'
>>  and `font-plist' is a plist. The keys for this plist are
>>   `:font':     system font name (mandatory)
>>   `:features': string or list of strings with font features.
>>                A potential fallback will be appended.
>>                CAVEAT: features may be overwritten by fallback.
>> `:fallback': an alist of (`script' . `mapping') to map scripts in the buffer
>>                to their fallback font (optional).
>
> Having an example would be useful. You can refer to the manual if you do
> not want to duplicate examples here and there.

An example doesn't hurt... done

>> Place your customization in your Emacs initialisation or in .dir-locals.el"
>
>I do not think that we need to explain this for a defcustom. It is a
>given, and we do not add such explanation to other custom options in Org.

OK. Done

>   :type '(choice (const :tag "No template" nil)
>             (alist :tag "fontspec config"))

I notice that you are using tabs for indentation. Our convention (and
settings in .dir-locals.el) disable indent-tabs-mode.

>> By defauly, this variable is set to `nil' to generate no configuration.
>> *default
> Also, `nil' -> nil

See above.

>> +(defcustom org-latex-babel-languages nil
>> +  "A string with the babel languages.
>> +This is an alternative to adding the package in the LaTeX header"
>> +  :group 'org-export-latex
>> +  :package-version '(Org . "9.8")
>> +  :type '(choice (const :tag "No babel languages" nil)
>> +               (string :tag "babel language list"))
>> +  :safe #'string-or-null-p)
>
>This option is not used anywhere.

Part of our discussions... commented out

> (defun org-latex--get-doc-scripts ()
>   "This function gets the char-scripts used in the current buffer.

Please provide a proper docstring. See D.6 Tips for Documentation Strings
in Elisp manual.

>>    (message "=> Scripts used in document: %s" scripts)
>
>Here and elsewhere, please get rid of the debugging messages. They are
>ok during testing, but not when we merge the branch upstream.

In this case it is not a debugging message. This message helps you,
for example, when you are defining the fallbacks. It is mentioned in
the manual.

>> (defun org-latex--mk-options (opts)
>>   "Return empty string if OPTS is nil or a zero-length string.
>> If OPTS is a non-empty string, enclose it in square brackets.
>> If OPTS is a list of strings, trim each string in the list
>> before concatenating to a comma separated list and
>> returning the list enclosed in square brackets."
>
>The first line of the docstring should describe overall purpose/return
>value of the function. For example,
>
>    Format OPTS as LaTeX option string [opt1,opt2,...] or empty string.

Done

>> (cond ((null opts) "")
>>         ((stringp opts) (if (length= opts 0 ) "" (format "[%s]" opts)))
>>         (t (format "[%s]" (mapconcat #'string-trim opts ","))))
>
>You can use `org-string-nw-p'

I'll keep it like that. The DOCSTRING was written to describe the logic and
I think it is clean enough. ()

>>   "A minimal font code translator.
>> TODO: more languages and possible error conditions."
>
>Please provide a full docstring.
>Also, avoid TODO comments in the docstring. Instead, put them in the
>code, if you think they are necessary and mark them FIXME:, not
>TODO. TODO is way too common in org code as a keyword. FIXME is more distinct.

Done.

> More generally, please review the docstrings to follow the Elisp
> conventions I linked to earlier.

In progress...

>>    (concat "main="
>> ;; (mapconcat #'org-latex--pdflatex-ldf (split-string langs "," t) ",")
>>            (mapconcat #'org-latex--pdflatex-ldf langs ","))))
>
>Please clean up all irrelevant comments from the code.
This one done.

>>  (let ((latex-langs
>> (or (plist-get info :languages) (list org-export-default-language)))
>>        (multi-lang
>> (or (plist-get info :latex-multi-lang) org-latex-multi-lang))
>
>This should not be necessary. Export options should handle their
>default value just fine. You do not need to do double job that is
>supposed to by handled by ox.el API.

So let's trust ox.el :-)

>> (with-temp-buffer
>>       (goto-char (point-min))
>>       (when multi-lang
>>         (insert "%% \\usepackage[utf8]{inputenc}\n")
>> (insert (format "\\usepackage%s{fontenc}\n" (org-latex--fontenc-options latex-langs)))
>>         (when (equal multi-lang "babel")
>> (insert (format "\n\\usepackage%s{babel}" (org-latex--babel-ldf-list latex-langs)))))
>>       (buffer-string))
>
>You can simply use `concat'. (concat "a" nil "b") => "ab"

You may, but this will be easier to remember (IMHO)

>> (compiler (or (plist-get info :compiler)
>>                        org-latex-compiler))
>
> (plist-get info :latex-compiler). Again, you do not need to manually
> check the default value. It is all defined in the :options-alist in the
> export backend definition.

You tell me once and I clean up (hopefully) everywhere. ;-)
>>
>>         (unicode-math-options nil) ;; TODO
>
>What does this TODO mean?

I leave these options FFS

>>         ;; These change inside `with-temp-buffer'
>>         (fontspec-config org-latex-fontspec-config)
>
>You can actually do (org-latex-fontspec-config org-latex-fontspec-config)
>That will make it unnecessary to invent new variable names.

Let's keep this for a second iteration... It doesn't harm, does it?

>>        (warn "polyglossia isn't supported by pdflatex!"))
>*Polyglossia
>Messages in Emacs start from capital letter.

Reworded: Polyglossia with capital P looks strange to me.

>> ;; Insert newline at the beginning to avoid too many empty lines in the export
>>     (cl-loop for lang in polyglossia-list do
>
> This comment does not seem relevant.

Made sense to me while coding...

>              (let* ((lang-list (assoc lang org-latex-language-alist))
>                     (lang-plist (cdr lang-list))

Here, and in other places, see `alist-get'.

>>                (insert (format "\n\\set%slanguage%s{%s}"
>>                                lang-type
>>                                (org-latex--mk-options lang-variant)
>>                                lang))
>>                (setq lang-type "other")))
>
>I suggest moving let-binding of LANG-TYPE variable close to this part of
>the code. It is only used here anyway. AFAIR, you can probably define it
>right inside cl-loop (via let keyword).

I moved the binding to the beginning of the loop. The docs on cl-loop are not
self-evident.

>> (defun org-latex--get-babel-lang (lang &optional default-lang)
>>   (when (equal lang "AUTO")
>
>Please add missing docstrings.

Checking and adding where I find... recheck afterwards, please

>>   (if-let* ((lang-alist (assoc lang org-latex-language-alist))
>>             (lang-plist (cdr lang-alist)))
>>       ;; (message "?? %s -> %s" lang lang-alist)
>>       (let ((babel-lang (plist-get lang-plist :babel))
>>             (babel-ini-only (plist-get lang-plist :babel-ini-only))
>>             (babel-ini-alt (plist-get lang-plist :babel-ini-alt)))
>>         (if babel-ini-alt babel-ini-alt
>>           (or babel-lang babel-ini-only)))
>>     lang))
>
>(let ((lang-plist (alist-get lang org-latex-language-alist nil nil #'equal)))
>  (or (plist-get lang-plist :babel-ini-alt)
>      (plist-get lang-plist :babel)
>      (plist-get lang-plist :babel-ini-only)
>      lang))

Changed.

>> (defun org-latex--babel-langs-as-option(langs)
>
>This function is not used anywhere in the code.

Commented out. (2140)

>>  "This function returns a string with the prelude part for
>> babel on lualatex/xelatex.
>
>You seem to be using a pattern "This function returns ..." in many
>places. Just say "Return ...". It is much shorter and is also Elisp convention.

Replaced (hopefully) everywhere.

>>  (let* ((compiler
>>          (or (plist-get info :latex-compiler) org-latex-compiler))
>>         (latex-babel-langs
>> (or (plist-get info :languages) (list org-export-default-language)))
>
> Again, you do not need to check default value manually. ox API will do
> it for you.

Idem

>> ;; Tracing lost chars: https://tex.stackexchange.com/questions/548901
>>      ;; TODO: do we really need fontspec??
>>      (insert "\\tracinglostchars=2\n%%\\usepackage{fontspec}")
>
> What is this TODO about?

Including fontspec seems sometimes redundant, but I'm still not 100% fine
with not including it because of tracinglostchars.

>> (insert (format"\n\\babelprovide[main,import]{%s}" (org-latex--get-babel-lang (pop latex-babel-langs))))
>
>Please do not use pop. It will modify the list by side effect and might
>modify the actual customization by reference chain.

This is why I 'duplicate' variables in the let binding. Try this:
(setq test-list '("How" "do" "you" "do?"))
(let ((test-copy test-list))
  (message "Inside let, before pop -> %s" test-copy)
  (pop test-copy)
  (message "Inside let, after pop -> %s" test-copy))
(message "Outside let -> %s" test-list)


> >      (cl-loop for bab-lang in latex-babel-langs
>
> Using cl-loop here is an overkill. Just do
>
>        (dolist (babel-lang latex-babel-langs) ...)

AFAIU it will translate into dolist internally. Since I'm also using it

for (cl-loop for (key . val) in alist ...

I was using it to make the function more uniform as for the number of
constructs it uses. It makes it easier to read (for me) and therefore
to program.


> Also, you seem to be shortening the variable names. IMHO, it is not
> desirable as it reduces readability. I prefer to have more readable
> (even if verbose) variable names in the code. This makes reading the
> code easier.

See above. Just being defensive, to avoid potential side effects.
IMvHO readability is marginally affected and the gain is worth it.

>> (let* ((props (alist-get bab-lang doc-babel-font-config nil nil #'string=))
>>        (provide (when props (plist-get props :provide))))
>>                     ;; \\babelprovide needs language and provide
>>                     ;; it doesn't work on the default language
>>                     (unless provide
>>                       (setq provide "import"))
>
> Can just
>
> (let* ((props (alist-get bab-lang doc-babel-font-config nil nil #'string=))
>        (provide (or (plist-get props :provide) "import"))) ...)

What would happen in `props' is nil?

>>   "Returns the font prelude when we are on Lua/XeLaTeX and
>> we are using neither bale nor polyglossia"
>*babel

Thx.

>>  (let ((compiler
>>         (or (plist-get info :latex-compiler) org-latex-compiler))
>
> Again, you do not need to check default value manually.

Done (see above).

>> (cjk-packages nil) ;; will be need the packages to support CJK fonts?
>*we need

Thx

>>      ;;
>>      ;; If we intend to use polyglossia, we can put it here.
>>      ;; Same for babel on lua/xelatex
>>      ;; They will automatically load, among others, fontspec
>>      ;; If none are selected, then use fontspec directly
>>      ;;
>>      (insert "\\usepackage{fontspec}\n")
>>      (insert (format "\\usepackage%s{unicode-math}\n"
>>                      (org-latex--mk-options unicode-math-options)))

Left-over from the devel process

>>      ;; TODO: if we choose polyglossia,
>>      ;;       do we need fallbacks or
>>      ;;       should we warn if fallbacks are defined for polyglossia
>
>These comments make no sense to me.
Left-over. Thx

>      ;; add all fonts with fallback to fallback-alist
That makes sense

>>Why are you talking about using polyglossia in
>    (defun org-latex--lualatex-fontspec-config (info)
>      "Returns the font prelude when we are on Lua/XeLaTeX and
>    we are using neither bale nor polyglossia"
>                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

To stress that it is a fontspec-only. Anyhow, changed...

>>      (when fallback-alist
>>        (unless (equal compiler "lualatex")
>>          (setq fallback-alist nil)
>>          (warn "Fallback fonts only work with lualatex!")))
>
>AFAIU, this warning will be displayed every single time latex export is
>using xelatex, if there are fallback fonts in the fontspec-config. Is it
>really desired? Should be there an option to provide separate fontspec
>configuration to xelatex?

Well, I'd rather keep it. If someone doesn't fully understand this and
keeps trying to use xelatex with fallbacks, he should be warned each
single time.

>> (when-let* ((fallback-check fallback-alist) ;; don't do anything when no fallbacks >> (fallback-fn (alist-get ffamily fallback-alist nil nil #'string=))
>
>The first line is redundant. (alist-get "foo" nil) will return nil and
>won't go into when-let* body.

Cool... wasn't my reading of the function...

>>        ;; TODO: what about xpinyin??
>
>Why would you need xpinyin? It add latex commands to provide pinyin
>spelling of Chinese characters. AFAIU, it does not do anything
>automatically; you need to explicitly put a command. So, it does not
>seem necessary for automatic font configuration.

Not now. But why not let the possibility open and point to a
a possible place in the code to add it in the future?

>>  "Return the font prelude for the current buffer as a string.
>
>You keep using "prelude". I think we refer to what we put before
>\begin{document} as "preamble" elsewhere in ox-latex.

Done the first time you found it. Might have been one of the days
where coding helped me cope with mankind's stupidity.

>>  (let ((compiler
>>         (or (plist-get info :latex-compiler) org-latex-compiler))
>>        (multi-lang
>>         (or (plist-get info :latex-multi-lang) org-latex-multi-lang)))
>
>Again, you do not need to check default value yourself.
see above ...

>> (defun keep-pkg (pkg use-driver)
>>   "This function filters out the font management packages.
>> Keep the package if we are in legacy mode or
>> if it is not a font management package."
>>   (or (null use-driver)
>> (not (member-ignore-case pkg '("fontenc" "fontspec" "inputenc" "unicode-math")))))
>
>This function is (1) inappropriately named; (2) used exactly one.
>I think you can simply inline it.

(1) OK, renamed. (2) affects readability of the function below.

>> (defun org-latex--get-lang (lang)
>>   "Return the long language name for LANG.
>> LANG can be a string, a comma-separated string or a list of languages.
>> When we have multiple languages, take the first."
>>   (when lang
>>     (if (stringp lang)
>>         (setq lang (car (string-split lang "," t " ")))
>>       (setq lang (car lang)))
>>     (let ((plist (cdr (assoc lang org-latex-language-alist))))
>>       ;; (message "%s" plist)
>>       (or (plist-get plist :lang-name) lang))))
>
>Why do we need supporting comma-separated list here? In the manual, we
>explicitly say that the languages should be space-separated and then
>>ox.el handles splitting the value into a list. So, LANG should always be
a list.

Right. Left-over from LANGUAGE to LANGUAGES and back.

>>         (multi-lang (or (plist-get info :latex-multi-lang)
>>                                org-latex-multi-lang)))
>
>Again, you do not need to use default value manually.

N/C... see above

>>    ;;
>> ;; This is just a note for the integration of the new features with main
>>    ;;
>
>What does this comment mean?

Escaped cleanup.



Reply via email to