Skip to content
| Marketplace
Sign in
Visual Studio Code>Other>WEML ToolsNew to Visual Studio Code? Get it now.
WEML Tools

WEML Tools

EGW Writings

|
2 installs
| (0) | Free
Editing tools for WEML (White Estate Markup Language) documents in the side bar: wrap the selection, insert snippets, renumber <div> ids, and EGW search suggestions with sign-in.
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

WEML Tools

Editing tools for WEML (White Estate Markup Language) documents in the side bar (the WEML icon in the Activity Bar): one WEML view made of panes that behave like the Explorer's Outline and Timeline: each collapses from its header, each open one scrolls on its own, the sash between two open panes resizes them (double-click it to share the height evenly again), and collapsed panes and sizes are remembered.

Tools — everything that edits the document:

  • Wrap or insert — one searchable list of tags, grouped as the WEML docs are (Containers, Blocks, Inlines): type to filter, ↑ ↓ and Enter (or a click) to choose, then the button in the field applies it — again as often as needed. An inline — w-format (each text-formatting value), w-color, w-lang, w-non-egw, w-entity, w-sent, a (link) — wraps the selection (required attributes become tab stops); every container (w-para, w-heading, w-para-group, w-toc, and a new div section with any of them or with a w-page page break), block (w-text-block, table, w-list, figure, hr) and empty inline (w-note, w-page, br, the a id anchor) inserts a snippet at the cursor. The chosen tag is remembered;
  • Document — Renumber div ids (1…n): every <div> id becomes its position in document order (also WEML Tools: Renumber <div> ids in the Command Palette);
  • Hotkeys in .weml editors — Ctrl+B / Ctrl+I / Ctrl+U wrap the selection in <w-format type="bold|italic|underline">;

Search Suggestions — EGW search: a query and a language, then per result its ParaId and BookCode (copyable), its title and, for a paragraph, a ready <a href="egw://book|bible/…"> that can be copied or inserted in place of the selection (the selection becomes its label; # without one). Needs sign-in: until then — or until the settings are filled in — this section offers that instead of the search.

The tools act on the active WEML editor — the last text editor in WEML language mode, or the only visible one. Clicking in the side bar does not lose it.

It is one view on purpose. VS Code merges a container's only view into the container's title bar, so the view's buttons — the account button, and Copy Redirect URI and Settings in the … menu — sit in the WEML header itself; extensions have no other way there (viewContainer/title is proposed API). A feature to come is one more pane in this view, not a view of its own, so it shares that header and the account.

The view's content is the shared WEML panel (weml-monaco/panel) — the same Tools and Search Suggestions a web editor built on weml-monaco shows. Here it runs in the webview (webview-src/main.ts, bundled into dist/webview/panel.js) and only presents: it calls the extension host (src/views/protocol.ts, wemlView.ts) for every edit and every search, so the sign-in, the token and the requests never leave the extension.

Sign-in

Sign-in is OpenID Connect — authorization code with PKCE, optionally through the server's own login page — on VS Code's own machinery:

  • the account button in the WEML header, just before the … — one account for the whole extension and every group in it. It signs in when signed out; signed in, it opens the account menu: the Gravatar with the name and email, Open Account Page (only when wemlTools.auth.accountPageUrl is set), Sign Out, Copy Redirect URI and Settings. VS Code only draws codicons in a title bar, so the Gravatar is in the menu rather than on the button, and the menu is a QuickPick, which always has a filter box. Signing out also clears the search results found under the old session;
  • EGW Writings is also a VS Code authentication provider: the account appears in the Accounts menu (bottom of the Activity Bar) and can be signed out from there too;
  • the authorization response is checked against the request (state) and, per RFC 9207, against the server (iss must equal the discovered issuer; a server that advertises authorization_response_iss_parameter_supported must send it) — a mix-up attack through another server is refused before any code is exchanged;
  • tokens are kept in VS Code's SecretStorage (the OS keychain), shared by all windows, and the access token is refreshed with the refresh token before it expires (offline_access);
  • the browser comes back to VS Code through its URI handler (see Redirect URI below), or through a one-shot local listener when the server only allows an http://localhost redirect.

Every setting's description ends with an Edit in settings.json link.

Nothing environment-specific is built in. Everything comes from the settings below, which are machine-scoped: they can be set in the user settings only (Ctrl+, → User, or settings.json), never in a workspace's .vscode/settings.json, so they cannot be committed.

Setting Notes
wemlTools.auth.authority OIDC issuer; discovery is read from it
wemlTools.auth.clientId must allow the redirect URI
wemlTools.auth.scopes include offline_access, and search for suggestions
wemlTools.auth.loginPageUrl optional; the authorize request is passed to it as next
wemlTools.auth.redirectUri empty (VS Code's URI, see below) or http://localhost:…
wemlTools.auth.accountPageUrl optional full URL of the user's page; shows Open Account Page
wemlTools.search.apiUrl GET <apiUrl>/search/suggestions?query=&lang=
wemlTools.search.defaultLanguage en by default
// User settings.json
"wemlTools.auth.authority": "https://…",
"wemlTools.auth.clientId": "…",
"wemlTools.auth.scopes": "openid offline_access … search",
"wemlTools.auth.loginPageUrl": "https://…",
"wemlTools.search.apiUrl": "https://…"

The browser tab of the sign-in stays open afterwards: a page may only close a tab its own script opened, and this one was opened by the OS and went through several pages. With a vscode:// redirect the tab is left on the server's last page; with an http://localhost one the extension's own page tries window.close() and otherwise says the tab can be closed. VS Code's built-in GitHub and Microsoft sign-ins leave theirs open the same way.

Redirect URI

After sign-in the server sends the browser back to a redirect URI, and it only does so to a URI registered with the OIDC client — so this is the one thing to set up on the server.

Leave wemlTools.auth.redirectUri empty (recommended). The browser then comes back to VS Code itself, through the URI VS Code assigns to this extension. That URI depends on where VS Code runs, and every environment you sign in from needs its own entry on the server:

VS Code Redirect URI
VS Code (desktop) vscode://egwwritings.weml-tools/auth-callback
VS Code Insiders vscode-insiders://egwwritings.weml-tools/auth-callback
In the browser: vscode.dev, Codespaces, a remote server opened in the browser an https URL of that VS Code (e.g. https://vscode.dev/callback?…), produced by vscode.env.asExternalUri

Register the URI exactly as shown — all lower case, no query: servers such as OpenIddict compare redirect URIs character by character, so vscode://EGWWritings.weml-tools/… or …/auth-callback?windowId=1 is a different URI to them. That is also why the desktop URI is not taken from vscode.env.asExternalUri, which appends ?windowId=…; the callback then goes to the last active VS Code window — the one signing in.

The scheme is VS Code's own (vscode.env.uriScheme), so a fork of VS Code has its own one too. Rather than working it out, run WEML Tools: Copy Redirect URI (Command Palette, or the view's … menu): it copies the exact URI the current window will send, ready to register. In a browser-based VS Code check that URI before registering it — it may carry query parameters a server that matches redirect URIs exactly will not accept.

Set redirectUri to an http://localhost:<port>/<path> URL only if the server refuses custom-scheme URIs like vscode:// and accepts loopback ones (RFC 8252). The extension then listens on that port for the moment of the redirect, so the port must be free while signing in. The same URL works in VS Code and Insiders alike, but not in a browser-based VS Code.

Changing the authority, client id or scopes drops the session — the token was issued for the old ones — and the view asks to sign in again.

For features to come

Sign-in is not part of the search: it is a shared layer every feature uses, and nothing else touches tokens.

  • In this extension, a feature takes the EgwApi (src/auth/egwApi.ts) and calls api.fetch(url, init): it adds Authorization: Bearer …, refreshes the token before it expires, and on a 401 refreshes once more and retries. Signed out, it throws NotSignedInError without sending anything. The feature's API base URL is its own setting, wemlTools.<feature>.apiUrl, machine-scoped like the others; a scope it needs is added to wemlTools.auth.scopes.

  • The other extensions of the WEML set (WEML Language Support, WEML Preview — none of them signs in yet) get the same object as this extension's exported API, once they list EGWWritings.weml-tools in their extensionDependencies:

    const egw = await vscode.extensions.getExtension('EGWWritings.weml-tools')?.activate();
    const response = await egw.fetch(`${apiUrl}/…`);
    egw.onDidChangeSession(() => …);
    

    or, without depending on this extension's code, through VS Code itself: vscode.authentication.getSession('egw-oidc', [], { createIfNone: true }).

Requires

WEML Language Support (EGWWritings.weml-support), which owns the weml language mode; it is declared in extensionDependencies.

Relation to WEML Language Support

This is the toolbar that WEML Language Support used to have in the bottom panel (the WEML tab), moved to the side bar together with the rest of the editing tools — Renumber div ids and the Ctrl+B / Ctrl+I / Ctrl+U hotkeys. WEML Language Support keeps the language features and formatting (Format Document, Alt+Shift+F).

Shared code

The language logic comes from the workspace package weml-language-core (bundled in): the schema, structure rules and snippets, wrap / divRenumber, the tool model — the tags this view's picker offers, the same ones weml-monaco's toolbar and the web editor offer — and the EGW search client with the egw:// link builder (src/search/ there; its suggestionLinks.ts holds the list of Bible book ids that decides between egw://bible/… and egw://book/…). This extension keeps what is VS Code's: the sign-in, the token, and the search request made with it.

Developing

npm install            # at the repository root (npm workspaces)
npm run build          # dist/extension.js + dist/webview/ (the panel, from weml-monaco's sources)
npm run watch
npm run check-types    # the extension and the webview script
npm run package        # vsce package --no-dependencies

The sign-in protocol (PKCE, the authorize URL, the RFC 9207 check, the token requests) is weml-language-core's auth/oidc.ts, tested there; this extension keeps the VS Code side of it (the authentication provider, SecretStorage, the redirect callbacks).

F5 (Run WEML Tools, with this folder open) starts an Extension Development Host on ../../samples.

The Activity Bar icon media/weml.svg is the WEML Editor's logo (weml-storybook/src/modules/WemlEditor/icons/vscLogoIconJson.ts) as a plain currentColor SVG.

License

MIT

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
  • Your Privacy Choices
  • Consumer Health Privacy
© 2026 Microsoft