ts-tex
v0.9.35
Published
**ts-tex** is a document preprocessor that allows you to call predefined typescript functions conveniently from within your latex code (or actually any document). It also provides a language service that wraps the [typescript compiler api](https://github.
Downloads
9
Readme
What is ts-tex
ts-tex is a document preprocessor that allows you to call predefined typescript functions conveniently from within your latex code (or actually any document). It also provides a language service that wraps the typescript compiler api and provides you with diagnostics, auto completions, signature helps etc. ts-tex automatically differentiates between typescript and non-typescript code using a pegjs parser. Therefore you can mix normal LaTeX code and typescript function calls as you wish. I also develope a vscode-extension vscode-ts-tex that integrates the language service into vscode. I also maintain a repository for useful tstex modules that you can use for your documents or as a learning resource.
Why ts-tex
When it comes to typesetting LaTeX produces the best output. Nontheless it's syntax is old, inconsistent and verbose. It's practically impossible to provide modern language services for LaTeX because of the varying syntax. This makes it very hard for beginners to learn. ts-tex provides an interface to wrap the production of underlying LaTeX code in a typescript function that provides a consistent syntax and language services to the writer. In the end, only the module developer must deal with the LaTeX interface. For other users LaTeX is just abstracted away.
Quickstart
The language service operates on one folder as a root. In this folder all /**/.tex DocumentFiles can be loaded into the AST. If non-existant the folder tstex_modules is created. In this folder you can create typescript (.ts) files and add them as CodeFiles to the AST (vscode-ts-tex takes care of all this automatically). Additionally there is an tstex_modules/_api.ts file that should not be edited. This file exposes the api interfaces that you can use to implement functionality that you can call from your DocumentFiles. Please refer to the wiki api page to look at the complete api.
Creating a new module
In any tstex_modules/**/*.ts file you can create a exported class that implements IModule (which is defined in _api.ts). Classes that implement IModule will be instantiated and added as a property to your scope. Example:
// ./tstex_modules/mymodule.ts
import { IModule } from "./_api.ts";
export class MyModule implements IModule
{
*createTable(table: string[][])
{
//... do some stuff
yield result;
}
}
Now from any of your DocumentFiles you can access the functionality of this module by
// ./myLatexDoc.tex
\this.myModule.createTable([["asd"],
["test"]]
);
ts-tex has a custom parser that will differentiate between typescript code and non-typescript code. Just like in latex all function-calls into the typescript domain have to start with "\". Also just like in ts, your statement will be executed in the context of a scope class, so you will have to write "this." to access functions of your scope.
To fit with javascript property naming style the property name of your module instance on your scope object wll be camel-cased if necessary. Note that only special classes that extend _api.ts interfaces such as IModule will be transpiled and instantiated. Other code such as defined functions or classes won't be transpiled or executed at any time and are therefore not callable from your document or your module code. If you define a normal class and try to instantiate it in a module function this will not work, as the code was never evaluated! Please refer to the api for more details.
Build
The result of your function call will be converted to string in a recursive manner and in the built document the function call will be replaced by this string. String conversion happens with these rules:
- value is array: convert all elements to string and join
- value is object: call toString() method
- value is number: convert number to string
- value is boolean: convert boolean to string
- value is string: it stays string
- value is Iterable:, i.e. the function is a generator function -> the generator is iterated over and all results are converted to string and joined
- value is Promise: currently unsupported but I might look into this in the future
Note that by default when building e.g. a file test.tex will result in a built file .build.test.tex file. This is due to filenames with a leading . being ignored by vscode-ts-tex's updates. This makes sense, because we don't want to add the build result to the AST as it is not a ts-tex file.
If a function call takes up more than one line in your document but the evaluation results in less lines, ts-tex will add newlines to the result until it matches the line count of the function call. This is useful when compiling your built document with LaTeX the error lines of the built document will match the lines of your document. Because of this I recommend the convention to always yield single line strings (i.e without any '\n's) out of function calls. This makes sure that your function calls and function results in the built document and working document are always aligned!
Lifecyclehooks
When implementing IModule from your custom module class you can implement the following functions:
init(resolver: IResolver)
: will be called on construction of your module class (everytime you change your module code and save it, your module instance will be re-instantiated). A resolver is passed to you where you can register or resolve dependencies that you might have added in other module files.finalize()
: will be called whenever your module will be unloaded. Note that when you change your module code and save it, this method will be called before the new module will be instantiated.prebuild()
: logic that will be executed before building the documentpostbuild()
: logic that will be executed after building the document
Types
When using functions or lambdas as parameters one could want access global types like @types/node
. The ts-tex language service looks in your global node_modules/@types folder for types. So to use the node types just install @types/node
globally:$ npm install -g @types/node
and you can use the intelli-sense for those types.
Security
ts-tex runs code from your document. Currently no security concept (like vms) has been implemented. Be cautious when running 3rd party modules, as they are programs and have access to your filesystem! If I see that a lot of people use ts-tex maybe I will look into implementing a sandboxing mechanism of modules.
Limitations
- Workspaces with more than one open folder are currently not supported
- Currently only linux file-endings LF are supported, no CRLF. Atm I see no reason to invest effort into implementing this support but if somebody needs it feel free to patch it yourself or text me.
- TS-Comments are not parsed atm as they are not really usefull in documents (you can comment with normal latex comments with % outside of function calls).
- Function chaining such as
this.fn( somethingsomething ).anotherfunction()
is not possible. I think the use-case is not worth the effort here, but if you need it drop me an issue - async functions (returned promises) are not supported. As the whole build process is single threaded, async would not enhance performance but it might make sense to consume async apis more easily. I might look into this one day.
How type-tex works
I will document this as soon
Credits
The following libraries were really helpful for implementing this project