debouncing / merging docChanged transactions?

CodeMirror 6 lets you listen for doc changes in the form of transactions, but every change is fired off immediately: if a user types function cakeBaker(type="extreme") at a normal typing rate, that’s 30+ transactions for one letter each, instead of a single transaction for the single stretch of text typed.

Is there a way to set a debounce interval (“keep aggregating changes until there’s no new change for X milliseconds”) or even debounce with explicit “ignore debounce if …” rule (e.g. don’t finalize the current transaction unless the change was a boundary character), or even a way to bundle/merge transactions into one transaction after the fact, so that someone can roll their own debounce logic that lets them send a single object to their OT server ? (e.g. const bundle = Transaction.merge(t1,t2,t3,t4,t5,...)).

You cannot merge transactions, but you can merge change set with ChangeSet.compose. You could set up a thing that accumulates changes and runs some code on the result only after a given period of inactivity.

Sounds good! is there an example or docs page that illustrates how to do that somewhere?

Won’t work for everyone but I get an effect like this by calling code from the linter callback.

import { linter, lintGutter } from "@codemirror/lint";
// other eslint stuff I guess not strictly necessary
// but see https://codemirror.net/examples/lint/
// in extensions:

    linter(
      view => {
        let o = esLint(new eslint.Linter(), config)(view).filter(d => !(d.source == 'eslint:no-undef' && d.message.includes("_in'")));
        if (o.length == 0) {
          update(view); // update is my custom function
        }
        return o;
      }),

I think I read that the linter pass gets skipped if it interferes with editor responsiveness, so not quite a simple debounce, but it might have interesting code to look into.