WEML Language Support
Support for WEML (White Estate Markup Language) — an HTML5-compatible
format used for importing and exporting publications — in Visual Studio Code:
the language itself, and three modules on top of it — the WEML view in
the side bar (editing tools, EGW search suggestions, sign-in), a live
preview, and a table of contents. Each module can be turned off.
The language
For .weml files:
- Syntax highlighting based on an extended HTML grammar.
- Autocomplete for tags, attributes and attribute values, respecting
nesting rules.
- Hover tooltips describing tags, attributes and values.
- Structure diagnostics: unknown tags and attributes, required attributes,
allowed enum values, child count and order,
<a href> / id link checks,
duplicate <div id>, required <meta> tags in <head>.
- Document outline by
<w-heading> headings and top-level <div> blocks.
- Formatting into a canonical, normalized WEML form via Format Document
and format-on-save.
- Format cycle (
Alt+Shift+F): toggles the whole document between standard
HTML formatting (readable, indented) and the canonical WEML form on each
press, so you can switch back and forth while editing.
Open any file with the .weml extension — the features activate
automatically.
- Format Document (or format-on-save) rewrites the document into the
canonical, normalized WEML form. Canonical formatting is skipped when tag
structure is invalid, so malformed content is never replaced by a partial or
empty document.
Alt+Shift+F runs WEML: Cycle Format (HTML / Canonical) — press it once
to expand the document into indented, human-readable HTML, and again to
collapse it back into the canonical WEML form. Each press alternates between
the two, and each cursor stays on its <div>. HTML/pretty formatting remains
available while an invalid structure is being repaired. The command is also in
the editor's right-click menu, next to Format Document (which always applies
the canonical form).
Modules
| Module |
Setting (default true) |
What it adds |
| WEML view |
wemlTools.enabled |
the WEML side-bar view, the EGW sign-in, Ctrl+B / Ctrl+I / Ctrl+U |
| Preview |
wemlPreview.enabled |
Open WEML Preview and its keys, buttons and menus |
| Table of contents |
wemlToc.enabled |
Open WEML Table of Contents, its button and menus |
Turning a module off removes everything it adds — commands, buttons, menus,
keys, views, open panels — at once, without a reload; turning it on brings them
back. Every setting has an Edit in settings.json link in its description.
The WEML view
The WEML icon in the Activity Bar opens one 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. 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; Open Preview and Open Table of Contents: the document in
those modules, to the side. A module that is turned off has its button faded
with turned off, and a click offers to turn it on (then opens the view). All
three are in the Command Palette too (WEML Tools: …).
- 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.
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 a webview and only presents: it calls the extension host 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: 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;
- EGW Writings is also a VS Code authentication provider (
egw-oidc): the
account appears in the Accounts menu and can be signed out from there too;
another extension can use it through
vscode.authentication.getSession('egw-oidc', [], …);
- the authorization response is checked against the request (
state) and, per
RFC 9207, against the server (iss) — 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), and the
access token is refreshed before it expires (
offline_access).
Nothing environment-specific is built in. Everything comes from these settings,
which are machine-scoped (user settings only, never a workspace's
.vscode/settings.json):
| 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 |
Redirect URI
After sign-in the server sends the browser back to a redirect URI, and only
to one registered with the OIDC client — the one thing to set up on the server.
Leave wemlTools.auth.redirectUri empty (recommended): the browser comes
back to VS Code itself, through the URI VS Code assigns to this extension. Every
environment you sign in from needs its own entry on the server:
| VS Code |
Redirect URI |
| VS Code (desktop) |
vscode://egwwritings.weml-support/auth-callback |
| VS Code Insiders |
vscode-insiders://egwwritings.weml-support/auth-callback |
| In the browser (vscode.dev, Codespaces, a remote server opened in the browser) |
an https URL of that VS Code, 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. WEML Tools: Copy
Redirect URI (Command Palette, or the view's … menu) copies the exact URI
the current window will send.
Set redirectUri to an http://localhost:<port>/<path> URL only if the
server refuses custom-scheme URIs and accepts loopback ones (RFC 8252); the
extension then listens on that port for the moment of the redirect.
Changing the authority, client id or scopes drops the session, and the view
asks to sign in again.
The preview
A live preview of .weml and .html documents rendered with
weml-stylesheet — the same stylesheet and script web
applications render WEML with — even when the file links no stylesheet or
script.
- Open WEML Preview and … to the Side — the keys, the editor title
button (
Alt+click opens in place) and the editor's right-click menu (with
Open in Browser) in WEML language mode; the tab and Explorer context menus
for any .weml, .html, .htm or .xhtml file.
- Live update while typing; when only
<body> changed, it is swapped in
place — no reload, scroll position kept.
- Theme follows VS Code's (or
light / dark / the OS); the editor's
background, text and scrollbars.
- Scroll sync both ways, by source line; double-click a block to jump to
its line. Toggle WEML Preview Scroll Sync and the title-bar button switch
both directions at once.
- Links:
http(s) and mailto open in the browser, #id scrolls, egw://
is shown with Copy.
- Open in Browser with WEML Styles writes a styled copy to the temp folder.
- Follow / lock: an unlocked preview follows the active WEML editor;
previews are restored after a restart.
| Command |
Windows / Linux |
macOS |
When |
| Open WEML Preview |
Ctrl+Shift+V |
Cmd+Shift+V |
editor in WEML mode |
| Open WEML Preview to the Side |
Ctrl+K V |
Cmd+K V |
editor in WEML mode |
| Open in Browser with WEML Styles |
Ctrl+K W |
Cmd+K W |
WEML mode / WEML preview |
| Show WEML Source |
Ctrl+Shift+V |
Cmd+Shift+V |
WEML preview focused |
These are html-preview's keys, active in WEML language mode only: switch an
.html file to WEML in the status bar and they open this preview.
Settings (wemlPreview.*): theme, followActiveEditor,
scrollPreviewWithEditor, scrollEditorWithPreview,
doubleClickToSwitchToEditor, updateDelay (at least 1000 ms for documents
over 2 MB), removeDocumentScripts, customStyles (extra stylesheets after
weml.css), fontFamily, fontSize, lineHeight.
The table of contents
The tree of the document's <w-heading level> next to the editor, drawn as
VS Code's Outline — the same tree a web editor built on weml-monaco shows
(weml-monaco/toc).
- Open WEML Table of Contents and … to the Side — the editor title button
(
Alt+click opens in place), the editor's right-click menu, the tab and
Explorer context menus for .weml files, the palette, and the WEML view's
Open Table of Contents.
- Headings nest by
level, shown as H1, H2, …; labels are the heading's
text (inline tags and notes left out, entities decoded).
- A click selects the whole
<w-heading> in the editor and centers it; two
headings with the same text are two entries.
- It follows the edits (
wemlToc.updateDelay) and the cursor — the heading the
cursor is under is selected and its section unfolded (wemlToc.followCursor)
— and the active WEML editor unless locked (wemlToc.followActiveEditor).
- The keyboard of a VS Code tree; Collapse All / Expand All, Show WEML
Source, Refresh, Toggle Locking and Settings in the title bar; panels
are restored after a restart.
License
MIT
| |