Custom title page style / loading .scm module with relative path

Hello,
This is a question I asked on the mailing list, you can see the discussion here: http://lists.texmacs.org/wws/arc/texmacs-users/2021-04/msg00029.html
I would like to create a custom style for the title page, by defining new elements (like an illustration image for instance) and the layout in which they appear.
A solution was given by Giovanni Piredda to control the layout, which is to create a module in $TEXMACS_HOME_PATH/progs/styles/custom-title.scm with the following code:

(texmacs-module (styles custom-title))
(tm-define (doc-data-main t)
  `(document
     ,@(with authors (select t '(doc-author))
         (if (<= (length authors) 1) authors
            (list `(doc-authors ,@authors))))
     (line (point "0par" "0") (point "1par" "0")) 
     ,@(select t '(doc-title))
     ,@(select t '(doc-subtitle))
     ,@(select t '(doc-imgs))
     ,@(select t '(doc-date))
     ,@(select t '(doc-misc))
     ,@(select t '(doc-inactive))))

I found I can add a new tag by adding ,@(select t '(doc-img)), then add the following to the scm file (so that TeXmacs lets me input the new tag):

(menu-bind focus-title-menu
  (former)
  ("Images" (make-doc-data-element 'doc-imgs)))

Then I define the tag in TeXmacs:

<drd-props|doc-img|border|no>
<assign|doc-img|<macro|x|<arg|x>>>

However, this requires to make a module in ~/.TeXmacs whereas I’d like to load the style from the same directory as the document so that I can share it, would that be possible?

2 Likes

You can try to put the scheme code in an \extern tag in the preamble of the document. Is not very nice and you should make sure that it is run only once. For example you can define an additional flag and then check if it is defined before running your code. This is because you want avoid do redefine doc-data-main and execute the menu-bind macro every time the document is re-typeset…

Alternatively you can try to put in the \exern tag the scheme command (use-modules (custom-title)) and put the scheme file custom-title.scm (without styles in the name) in the current directory of the buffer. But I’m not sure TeXmacs will look there to find it…

1 Like

After re-thinking and reading your answer, I did a quick test and

<extern|(lambda () (use-modules (custom-book-title)))>

did not work for me, while

<extern|(lambda () (load "./custom-book-title.scm"))>

worked.
In "custom-book-title.scm" in this case one does not need the initial module declaration. I tested it only with the doc-data-main function, not with the menu-bind and with the TeXmacs tags of @Pycpp’s post.

I tested this on Linux only, and I remember vaguely that on Windows, inTeXmacs extern relative paths inside load do not work, so if this way works, it might work only for Linux and possibly Mac OS.

Of course putting all of the code inside the extern tag works.

It might even be worth investigating whether one can put the code inside an executable fold environment, where one can type the code more comfortably than inside the extern tag, where I do not know how to put line breaks; the disadvantage that I see is that once you have activated it, you can’t see anymore that it is there.

1 Like

Thank you it works! However I had to change the security option to “accept all scripts”, for some reason it doesn’t show a prompt when it’s on “prompt on script”.
I have another question: when the script is loaded, if I create a new document with another style, the script messes with that style; is it possible to link it to a style so that it only works when the style is active?

Happy that it works.
Following up on the post of @mgubi, I would put all of your definitions inside an if controlled by a variable that you define after running them once, so that you don’t define them multiple times.

For making the definition conditional on the style file, I pass the word to @mgubi, who could have the answer ready. I would have to look through the documentation, but the first idea that comes to my mind is to define new tags for your document that control the title (copying their definitions from the current ones), and make them depend on your “new implementation” of doc-data-main, which would also take a new name: there may be a more straightforward way.

Also for “accept all scripts” perhaps we can do a bit better; please try to experiment adding a (:secure #t) declaration as first form of your definitions. If you get that, you could reset the security setting to the default.

Also, I just noticed that the path in load is relative to where TeXmacs is run and not to the file. If I launch TeXmacs then open the file it doesn’t work.

Uhmm … sorry then … I expect that neither my solution nor the one of @mgubi with external files would work.

You have to include all of the code in the document itself or in a style file that accompanies the document (the style file as far as I know does not make it easier to add Scheme code). You can do that inside the extern tag (you have to wrap everything inside a lambda, as extern take only functions). It is unwieldy because of the lack of basic editing facilities/constructs there.

There might be a way of placing your definitions inside a Scheme session, hidden in your document and automatically executed at the opening of the document (or loading of the style file), but I would have to figure out whether it is possible. Once more, @mgubi, what do you think? It would be convenient to be able to include Scheme code in a style file without asking users to place a file in a separate directory.

You can try with something like

 (load (url-concretize (url-append (url-head (current-buffer-url))   "custom-book-title.scm"))))

but again, put it into a conditional block, so something like

 (unless (defined? 'custom-book-title-flag) (begin 
    (tm-define (custom-book-title-flag) #t)  
    (load (url-concretize (url-append (url-head (current-buffer-url))  
                      "custom-book-title.scm")))))))

You can put it in your style file, so that it is loaded only when the style file is. (maybe)

Yes this works. But when the script is loaded it changes the definition for all styles.

There is a Scheme function, (get-style-list), which I just tested and returns the name of the style you are using.
If that always returns the name of one single style file (which I don’t know, but it is sensible), then you could use it to put a condition in front of your redefinitions; you would have to copy the book style file to a new file with a new name (say custom-book.ts), set the style file of your document to that and in this way in your document the new definitions would be valid but not in other style files.

I am under the impression that there must be a more “principled” way of changing the style of the title for one style only, though :slight_smile:, but I do not see it at the moment.

One would have to make your redefinition conditional on the current style. Useful pointers is to look in the TeXmacs scheme files for (:require ...) statements within tm-defines. Also consider that in the scheme file you can do

(texmacs-modes
    (in-custom-title-style% (style-has? "custom-title-style"))

for example, then you will be able to do

(tm-define (doc-data-main t)
 (:require (in-custom-title-style?))
  `(document
     ,@(with authors (select t '(doc-author))
         (if (<= (length authors) 1) authors
            (list `(doc-authors ,@authors))))
     (line (point "0par" "0") (point "1par" "0")) 
     ,@(select t '(doc-title))
     ,@(select t '(doc-subtitle))
     ,@(select t '(doc-imgs))
     ,@(select t '(doc-date))
     ,@(select t '(doc-misc))
     ,@(select t '(doc-inactive))))

And maybe also

(menu-bind focus-title-menu
  (former)
  (if (in-custom-title-style?) ("Images" (make-doc-data-element 'doc-imgs))))

I never did this kind of things before, maybe check around in the TeXmacs/prog directory how similar in-xxxx-style? declaration are used, both for tm-defines and for UI elements.

It would be also useful if you would like to share what you wrote, so that other people could use it too and maybe it could be of general interest enough to make it into the core.

When I load the script from a style I have to open the style, make a modification and save it, otherwise the script isn’t run (I have to do this every time I launch TeXmacs). With :require the script doesn’t run at all.
Here’s what I wrote:

custom-title.scm

(unless (defined? 'custom-title-flag)
  (begin
    (tm-define custom-title-flag #t)

    (texmacs-modes
     (in-custom-style% (style-has? "custom-style")))

    (tm-define (doc-data-main t)
      ;;(:require (in-custom-style?))
      `(document
        ,@(with authors (select t '(doc-author))
         (if (<= (length authors) 1) authors
             (list `(doc-authors ,@authors))))
        (line (point "0par" "0") (point "1par" "0")) 
        ,@(select t '(doc-title))
        ,@(select t '(doc-subtitle))
        ,@(select t '(doc-img))
        ,@(select t '(doc-date))
        ,@(select t '(doc-misc))
        ,@(select t '(doc-inactive))))

    (menu-bind focus-title-menu
      (former)
      ;;(if (in-custom-style?)
      ("Image" (make-doc-data-element 'doc-img))
      ;;)
      )))

custom-style.ts

<TeXmacs|1.99.19>

<style|<tuple|source|british>>

<\body>
  <extern| (lambda () (load (url-concretize (url-append (url-head
  (current-buffer-url)) "custom-title.scm"))))>

  <drd-props|doc-img|border|no>

  <assign|doc-img|<macro|x|<arg|x>>>
</body>

<\initial>
  <\collection>
    <associate|page-medium|paper>
    <associate|preamble|true>
    <associate|src-special|normal>
  </collection>
</initial>

document.tm

<TeXmacs|1.99.19>

<style|<tuple|tmarticle|british|custom-style>>

<\body>
  <doc-data|<doc-title|This is the title>|<doc-subtitle|subtitle>|<doc-img|image
  here>|<doc-author|<author-data|<author-name|Author name>>>>
</body>

<\initial>
  <\collection>
    <associate|page-medium|paper>
    <associate|preamble|false>
  </collection>
</initial>
1 Like

I have been able to get the script to run with :require, there was a step which I did not expect—explanation follows. I renamed the style file and that may be relevant although in case it is the pattern of the renaming and of the :require check which is important, not the name itself.

At the beginning the style was named custom-book-style.ts and the check that was failing was

(style-has? "custom-book-style")

which was returning #f (testing Scheme functions is done conveniently in a Scheme session inside your document).
Then I realized that checks for other styles were done in the TeXmacs codes with e.g. (in TeXmacs/progs/kernel/texmacs/tm-modes.scm)

 (in-tmdoc% (style-has? "tmdoc-style"))

but a style named tmdoc-style does not exist, while a style named tmdoc exists.
So I changed the name of the style file to custom-book.ts, but this was not yet enough to get #t.

Then I added the header, copying it from the “generic” style file and modifying it:

<\active*>
  <\src-title>
    <src-style-file|custom-book|1.0>

    <\src-purpose>
      A custom book style.
    </src-purpose>

    <\src-copyright|1998--2004>
      Pycpp
    </src-copyright>

    <\src-license>
      \;
    </src-license>
  </src-title>
</active*>

(I am leaving the filling of the license field to you :slight_smile: )
And now it worked. I did not test what happens with the same header and a different file name (this is why I do not know whether it is the renaming to be important or the header!).
I think this makes it so that only your style file modifies the book title page, and in fact I have been able to go back and forth between book and custom-book and see the title page change.

Now there is the issue of forcing the loading of the Scheme file together with the loading of the style file, and I do not know what to do there.

This is the custom-book.ts I used

<\active*>
  <\src-title>
    <src-style-file|custom-book|1.0>

    <\src-purpose>
      A custom book style.
    </src-purpose>

    <\src-copyright|1998--2004>
      Pycpp
    </src-copyright>

    <\src-license>
      \;
    </src-license>
  </src-title>
</active*>

<use-package|std|env|title-book|header-book|section-book>

<extern| (lambda () (load (url-concretize (url-append (url-head
(current-buffer-url)) "custom-style.scm"))))>

<drd-props|doc-img|border|no>

<assign|doc-img|<macro|x|<arg|x>>>

<\initial>
  <\collection>
    <associate|page-medium|paper>
    <associate|preamble|true>
    <associate|src-special|normal>
  </collection>
</initial>

\;

and this is the Scheme file

(unless (defined? 'custom-title-flag)
  (begin
    (tm-define custom-title-flag #t)

    (texmacs-modes
     (in-custom-style% (style-has? "custom-book-style")))

    (tm-define (doc-data-main t)
      (:require (in-custom-style?))
      `(document
        ,@(with authors (select t '(doc-author))
         (if (<= (length authors) 1) authors
             (list `(doc-authors ,@authors))))
        (line (point "0par" "0") (point "1par" "0")) 
        ,@(select t '(doc-title))
        ,@(select t '(doc-subtitle))
        ,@(select t '(doc-img))
        ,@(select t '(doc-date))
        ,@(select t '(doc-misc))
        ,@(select t '(doc-inactive))))

    (menu-bind focus-title-menu
      (former)
      ;;(if (in-custom-style?)
      ("Image" (make-doc-data-element 'doc-img))
      ;;)
      )))

2 Likes

This seems to work, in the style file:

<assign|load-scheme|<macro|<extern| (lambda () (load (url-concretize
(url-append (url-head (current-buffer-url)) "custom-style.scm"))))>>>

together with an invocation of load-scheme in the preamble of the document.
It feels like a hack: I wonder if there is a more “principled” way.