Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mapping Between Typst Source and Output #524

Open
winstonewert opened this issue Apr 30, 2024 · 5 comments
Open

Mapping Between Typst Source and Output #524

winstonewert opened this issue Apr 30, 2024 · 5 comments

Comments

@winstonewert
Copy link
Contributor

Is there a feature/code that enables mapping between the typst source and positions in the output? It'd be nice to be able to map from a position in the source to the page and position on that page, and back again.

I'm using typst.ts on the browser client.

@Myriad-Dreamin
Copy link
Owner

The feature is already at the rust side (for typst-preview) but not exposed in the JS library.

@winstonewert
Copy link
Contributor Author

For my own purposes, I've implemented a getMapping function which produces a javascript object allowing mapping between source and output positions. You can see it here.

Basically, I go through all of the glyphs on all of the elements of all the frames on all the pages of the document, and produce a collection of parallel arrays given page number, x, y, source file, offset. Then I can read through the array in javascript to map source to output and back again.

I'd like to contribute what I've done back, but I figured there would probably be some questions about design that would need to be hashed out before I try to put it in an actuall pull request. So I thought I'd get your thoughts here.

@Myriad-Dreamin
Copy link
Owner

It will be very expensive to export entire span mapping from rust side to js side, especially when document keeps changing. It seems you're building some editor and this will become a bottleneck on big documents.

Two aspect:

@winstonewert
Copy link
Contributor Author

So far, I appear to be getting away with exporting the whole mapping. My theory was that since I'm exporting a whole pdf anyways, it wouldn't be a big deal to export a mapping of it alongside that. But I did figure I'd likely need to optimize eventually. Exporting the mapping does have the advantage of being very fast to lookup new locations.

The actual mapping logic behind the code you pointed to appears to live here: (

pub async fn resolve_src_to_doc_jump(
), and I built my code as an adaption of that.

Can you explain how IncrServer is intended to work? I looked at it previously, but I wasn't sure how to do anything useful with that api.

@Myriad-Dreamin
Copy link
Owner

So far, I appear to be getting away with exporting the whole mapping. My theory was that since I'm exporting a whole pdf anyways, it wouldn't be a big deal to export a mapping of it alongside that. But I did figure I'd likely need to optimize eventually. Exporting the mapping does have the advantage of being very fast to lookup new locations.

Sounds great.

Can you explain how IncrServer is intended to work? I looked at it previously, but I wasn't sure how to do anything useful with that api.

Alright, it is in experiment state currently and doesn't get mentioned in the documentation, as I'm not sure how to expose it correctly. The usage of IncrServer is simple though. You can pass an additional IncrServer object to the compile API, so that typst.ts can store state/cache at rust side. Specifically, it stores the state/cache in the IncrServer object.

The goal of IncrServer is to ensure correct lifetime of these state/cache in rust. When IncrServer is destroyed, all related data are dropped at the same time. To avoid using the raw free function from the wasm-bindgen crate directly, I make a promise that destroys the IncrServer after resolved.

typstPlugin.withIncrementalServer(
  (srv: IncrementalServer) => {
    return new Promise((dispose) => {
      const updateDoc = () => {
        const v = await typstPlugin.compile({
          mainFilePath,
          incrementalServer: srv,
        });

        typstDoc.addChangement(["diff-v1", v]);
      };
      
      callback({ updateDoc, dispose })
    });
  }
);

You can see the experiment code here: https://github.com/mitex-rs/mitex/blob/c5e9f9bf2c5ef9a0f7be1c981f11026a0d732137/packages/mitex-web/src/tools/underleaf.ts#L103-L111

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants