Skip to content

Access state from command

Gold Holk edited this page Aug 22, 2022 · 1 revision

Tridactyl store some browser-wide state in state (src/state.ts), including history commands, marks (the markadd command) and jump marks (the jumpprev command). If you are going to define some commands which require a browser-wide storage, the state is a good storage for you.

Write

As the comment in state.ts said, just state.foo = 'bar' is enough. The assignment will propagate to the whole scope (the background script, in fact) asynchronously.

If you want to wait the propagation finishing, you shoud use the postMessage way as the state Proxy.

Read

Althought the state.ts say script can access the values stored in state with State.getAsync, the getAsync is undefined in the :js scope [^1]. In fact, the getAsync function defined in the state.ts use the postMessage to request the background script to return the value if it is called not called in the background, so we can define a function to read the value just like what getAsync do:

tri.stateGetAsync = function (...keys) {
  const values = keys.map(k => browser.runtime.sendMessage({
    type: 'state',
    command: 'stateGet',
    args: [{prop: k}]
  }))
  return Promise.all(values)
}

or define a command:

" In js scope, call this with `const [foo, bar] = await tri.controller.acceptExCmd('state_get foo bar')`
command state_get js -d% const args = JS_ARGS.slice(); if (args[0] == '') args.shift(); Promise.all(args.map(k => browser.runtime.sendMessage({type:'state', command:'stateGet', args: [{prop: k}]}))); % 

[^1]: This is caused by the Typescript bundler; the typescript want the State is the class State in runtime, and the export getAsync become the state_exports.getAsync. Because I don't want to depend on the internal implementation of bundler, I will not use the state_exports object.

With jsb

Another easy but dirty choice is using the jsb function. As the comments in state.ts, the state can be accessed as a normal object in background script. To run code in backscript, you can call the jsb function inside the js; the code will be evaluate and you get the value from the last statement.

Therefore, to read and write:

const foo = await jsb(`state.foo`)
foo += 1
await jsb(`state.foo = ${foo}`)

To take care of the special character you can use the JSON.stringify to encode any value to a valid javascript expression

Some other storage choice

  • tri.* in background script, can access with const foo = await jsb('tri.foo') and await jsb(`tri.foo = ${foo+1}`) in content script (the scope of js). This is never persistent.
  • Tridactyl config, juse call the get and the set commands, or call tri.config.{get,set}. This is always persistent.