中文EN

dsh-math-snippets

uinpmMIT

输入框里的 LaTeX 片段展开,触发词表直接取自 Obsidian Latex Suite 的默认片段——138 条打完即出,Tab 依次跳 tabstop,142 条全在一份可编辑的 JSON 里。

下载量 / Downloads
638

安装

dsh plugin --profile web add dsh-math-snippets

沙箱测试

这个插件还没测过。提交测试 →

README

dsh-math-snippets

LaTeX-Suite-style snippet expansion in the DSH web composer. The trigger table is built

from Obsidian LaTeX Suite's own

defaults — the same triggers, the same auto/Tab split, the same tabstop numbering — so the

muscle memory carries over.

$//        →  $\frac{}{}$          no Tab: an auto snippet expands as it is typed
$sum       →  $\sum_{i=1}^{n} $
$ff<Tab>   →  $\frac{}{}$          this plugin's short pair, on Tab or on its own
mk         →  $$                   outside math, caret between the dollars
dm         →  $$⏎⏎$$               display math, caret on the empty line
$@a        →  $\alpha              LaTeX Suite's Greek spelling, also auto
$sr        →  $^{2}                and `_`, `cb`, `rd`, `**`, `->`, `<=`, `!=`, `oo` …

Tab then walks the tabstops, in the order LaTeX Suite numbers them: $ff<Tab>3<Tab>4<Tab>

puts the caret in the numerator, then the denominator, then after the fraction.

Install

dsh plugin --profile <profile> add dsh-math-snippets

Restart the harness afterwards (a profile's bundle list is read at boot), then reload

the GUI page.

<details>

<summary>Installing from a checkout instead</summary>

Add a row to the profile's cordis.patch.yml:

- insert:
    - id: math-snippets
      name: 'file:///path/to/dsh-math-snippets/index.js'

</details>

LaTeX Suite parity

The table is not a hand-written approximation: it is generated from LaTeX Suite's

src/default_snippets.js, keeping every entry that can be expressed as a plain string

snippet. 142 tags, 138 of them auto, 4 left on Tab.

Same · the trigger vocabulary (//, @a, sr, cb, rd, _, , ->, <=, >=, !=, oo, sum, lim, dint, hat, bar, vec, norm, ceil, floor, text, …), which triggers are auto** and which need Tab, w word-boundary flags, and the $0,$1,$2 tabstop order

Same · the ${1:\infty} placeholder syntax parses (the default text is dropped — see below)

Different · the four LaTeX Suite deliberately keeps on <kbd>Tab</kbd> — par, \sum, \prod, \int — stay on Tab here too, which is the point

Different · dm does not prepend the newline LaTeX Suite's does. In a note you always want display math on a line of its own; in a chat composer the common case is that you are already on an empty line, and that newline would leave a blank first paragraph

Different · no conceal/render of formulas while typing, no auto-enlarging brackets, no backwards expansion, no regex/visual/function snippets, and ${1:x} placeholder text is not preselected: the shell publishes no selection seam, so a hole is empty instead

Snippet table

On first start the host half writes an editable table to ~/.dsh/math-snippets.json

containing every built-in trigger, and serves the effective table at

/plugin/math-snippets/table. The browser half re-reads that route once a minute, so

edits take effect without a restart or a page reload.

Each entry is { "body": "...", "auto": true }:

Field · Meaning

body · what the trigger becomes. $0, $1, $2 … are holes and Tab visits them in numeric order; ${1:\infty} is accepted too. A body with no hole leaves the caret after the text.

auto · true expands on the keystroke that completes the trigger, with no Tab. This is the default here, as it is in LaTeX Suite.

open · true allows the trigger outside math (used by mk and dm, which are how you enter math). Everything else only fires inside $…$, $$…$$, \(…\) or \[…\].

word · true also requires a delimiter after the trigger, so dm inside dmx stays a word. Taken from LaTeX Suite's w flag.

desc · free-form note for yourself; unused by the expander.

Example — add your own:

{
  "snippets": {
    "capm": { "body": "$E[R_i]=R_f+\\beta_i(E[R_m]-R_f)$", "auto": true },
    "npv":  { "body": "\\mathrm{NPV}=\\sum_{t=0}^{n}\\frac{CF_t}{(1+r)^t}" },
    "par":  { "body": "\\frac{\\partial $0}{\\partial $1}", "auto": true }
  }
}

A tag in the file overrides the built-in of the same name field by field, so an entry that

only restates a body keeps the built-in's open/auto/word switches — and an explicit

"auto": false turns one off. That last line is the escape hatch: if an auto trigger fires

when you were still typing a word, switch that one tag to Tab.

Two kinds of tag

Tag · Kind · Matched as

ff, sum, alp · bare word · the whole word before the caret (xff is the token xff, not ff)

//, @a, _, sr · literal run · the exact characters before the caret; longest table entry wins

A tag is a bare word when it is all letters, and a literal run otherwise, so //, _, **,

->, @a and :e all work. Two carve-outs keep literal runs out of URLs, mirroring the

shell's own / rules: a slash directly after another slash does not fire (/// is dead), and

a slash pair after a scheme: colon does not either, so https:// never arms the fraction.

How it works

Four seams the shell already publishes, no DOM editing and no fork of the composer:

1. The caret comes from shell.projection, the composer's own projection product

({ detectText, clipboardText, selection, caret }). caret is an offset into

detectText — the same coordinate space the input span uses — so nothing is measured

from the DOM.

2. The replacement is dispatched as the scoped input event the shell installs for its

own input-trigger sources:

actx.bail(actx, "slash/input-insert-text", { text, span }) with

actx = sessions.scope(sessionId) and span = { start, end, draftRev }. The shell

refuses a span whose draftRev no longer matches, so a stale keystroke can never

corrupt the draft.

3. The hole needs no caret API, because the shell always leaves the caret after what

…(truncated)

以上内容来自 npm 上的 README,我们只做格式化,不改内容。

版本

npm 上共发布:4,最后更新 2026-09-30

链接

GitHub · Homepage · npm

同类插件