@pentoshi/clai 3.6.0 → 3.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/compaction-summary.d.ts +17 -0
- package/dist/agent/compaction-summary.js +64 -0
- package/dist/agent/compaction-summary.js.map +1 -0
- package/dist/agent/confirm-port.d.ts +3 -1
- package/dist/agent/confirm-port.js +5 -1
- package/dist/agent/confirm-port.js.map +1 -1
- package/dist/agent/context-manager.js +45 -22
- package/dist/agent/context-manager.js.map +1 -1
- package/dist/agent/events.d.ts +6 -0
- package/dist/agent/evidence-governor.d.ts +37 -0
- package/dist/agent/evidence-governor.js +70 -0
- package/dist/agent/evidence-governor.js.map +1 -0
- package/dist/agent/loop-guard.d.ts +29 -11
- package/dist/agent/loop-guard.js +93 -39
- package/dist/agent/loop-guard.js.map +1 -1
- package/dist/agent/must-continue.d.ts +56 -0
- package/dist/agent/must-continue.js +240 -0
- package/dist/agent/must-continue.js.map +1 -0
- package/dist/agent/outcomes.d.ts +101 -0
- package/dist/agent/outcomes.js +359 -0
- package/dist/agent/outcomes.js.map +1 -0
- package/dist/agent/plan-decision.d.ts +33 -0
- package/dist/agent/plan-decision.js +104 -0
- package/dist/agent/plan-decision.js.map +1 -0
- package/dist/agent/plan-tool.d.ts +12 -0
- package/dist/agent/plan-tool.js +312 -104
- package/dist/agent/plan-tool.js.map +1 -1
- package/dist/agent/project-root.js +3 -0
- package/dist/agent/project-root.js.map +1 -1
- package/dist/agent/prompt-composer.d.ts +21 -0
- package/dist/agent/prompt-composer.js +46 -0
- package/dist/agent/prompt-composer.js.map +1 -0
- package/dist/agent/runner.d.ts +11 -1
- package/dist/agent/runner.js +1226 -971
- package/dist/agent/runner.js.map +1 -1
- package/dist/agent/scope-context.d.ts +3 -0
- package/dist/agent/scope-context.js +24 -0
- package/dist/agent/scope-context.js.map +1 -0
- package/dist/agent/scratch-write.d.ts +4 -0
- package/dist/agent/scratch-write.js +54 -0
- package/dist/agent/scratch-write.js.map +1 -0
- package/dist/agent/session-policy.d.ts +7 -0
- package/dist/agent/session-policy.js +61 -0
- package/dist/agent/session-policy.js.map +1 -1
- package/dist/agent/session-state.d.ts +41 -0
- package/dist/agent/session-state.js +107 -0
- package/dist/agent/session-state.js.map +1 -0
- package/dist/agent/step-budget.d.ts +14 -0
- package/dist/agent/step-budget.js +26 -0
- package/dist/agent/step-budget.js.map +1 -0
- package/dist/agent/task-analyzer.d.ts +12 -3
- package/dist/agent/task-analyzer.js +263 -23
- package/dist/agent/task-analyzer.js.map +1 -1
- package/dist/agent/task-evidence.d.ts +111 -29
- package/dist/agent/task-evidence.js +519 -91
- package/dist/agent/task-evidence.js.map +1 -1
- package/dist/agent/task-plan.d.ts +57 -0
- package/dist/agent/task-plan.js +147 -1
- package/dist/agent/task-plan.js.map +1 -1
- package/dist/agent/tool-call-parser.d.ts +4 -12
- package/dist/agent/tool-call-parser.js +34 -67
- package/dist/agent/tool-call-parser.js.map +1 -1
- package/dist/agent/tool-history.d.ts +7 -0
- package/dist/agent/tool-history.js +50 -0
- package/dist/agent/tool-history.js.map +1 -1
- package/dist/agent/tool-output-formatting.d.ts +13 -1
- package/dist/agent/tool-output-formatting.js +75 -22
- package/dist/agent/tool-output-formatting.js.map +1 -1
- package/dist/agent/turn-outcome.d.ts +11 -0
- package/dist/agent/turn-outcome.js +17 -0
- package/dist/agent/turn-outcome.js.map +1 -0
- package/dist/agent/turn-state.d.ts +11 -0
- package/dist/agent/turn-state.js +28 -0
- package/dist/agent/turn-state.js.map +1 -0
- package/dist/agent/workspace-orient.d.ts +11 -0
- package/dist/agent/workspace-orient.js +103 -12
- package/dist/agent/workspace-orient.js.map +1 -1
- package/dist/app/adapters/agent-event-adapter.d.ts +2 -13
- package/dist/app/adapters/agent-event-adapter.js +63 -25
- package/dist/app/adapters/agent-event-adapter.js.map +1 -1
- package/dist/app/adapters/current-agent-adapter.d.ts +0 -5
- package/dist/app/adapters/current-agent-adapter.js +4 -7
- package/dist/app/adapters/current-agent-adapter.js.map +1 -1
- package/dist/app/adapters/current-jobs-adapter.js +1 -0
- package/dist/app/adapters/current-jobs-adapter.js.map +1 -1
- package/dist/app/adapters/current-terminal-adapter.d.ts +0 -7
- package/dist/app/adapters/current-terminal-adapter.js +0 -7
- package/dist/app/adapters/current-terminal-adapter.js.map +1 -1
- package/dist/app/adapters/current-updates-adapter.d.ts +0 -5
- package/dist/app/adapters/current-updates-adapter.js +0 -5
- package/dist/app/adapters/current-updates-adapter.js.map +1 -1
- package/dist/app/adapters/in-memory-clipboard-adapter.d.ts +0 -5
- package/dist/app/adapters/in-memory-clipboard-adapter.js +0 -5
- package/dist/app/adapters/in-memory-clipboard-adapter.js.map +1 -1
- package/dist/app/commands/command.d.ts +0 -5
- package/dist/app/commands/command.js.map +1 -1
- package/dist/app/commands/registry.d.ts +0 -14
- package/dist/app/commands/registry.js +0 -20
- package/dist/app/commands/registry.js.map +1 -1
- package/dist/app/controllers/disposable.d.ts +0 -5
- package/dist/app/controllers/disposable.js +0 -5
- package/dist/app/controllers/disposable.js.map +1 -1
- package/dist/app/controllers/job-controller.d.ts +1 -5
- package/dist/app/controllers/job-controller.js +0 -4
- package/dist/app/controllers/job-controller.js.map +1 -1
- package/dist/app/controllers/plan-controller.d.ts +5 -8
- package/dist/app/controllers/plan-controller.js +30 -12
- package/dist/app/controllers/plan-controller.js.map +1 -1
- package/dist/app/controllers/session-controller.d.ts +17 -32
- package/dist/app/controllers/session-controller.js +56 -35
- package/dist/app/controllers/session-controller.js.map +1 -1
- package/dist/app/controllers/turn-controller.d.ts +2 -6
- package/dist/app/controllers/turn-controller.js +8 -8
- package/dist/app/controllers/turn-controller.js.map +1 -1
- package/dist/app/events/app-event.d.ts +4 -7
- package/dist/app/events/app-event.js +0 -6
- package/dist/app/events/app-event.js.map +1 -1
- package/dist/app/events/event-buffer.d.ts +6 -17
- package/dist/app/events/event-buffer.js +27 -24
- package/dist/app/events/event-buffer.js.map +1 -1
- package/dist/app/events/sequencer.d.ts +0 -9
- package/dist/app/events/sequencer.js +0 -4
- package/dist/app/events/sequencer.js.map +1 -1
- package/dist/app/ports/agent-port.d.ts +13 -3
- package/dist/app/ports/clipboard-port.d.ts +0 -5
- package/dist/app/ports/confirm-port.d.ts +0 -7
- package/dist/app/ports/jobs-port.d.ts +2 -5
- package/dist/app/ports/persistence-port.d.ts +0 -4
- package/dist/app/ports/secret-port.d.ts +0 -5
- package/dist/app/ports/terminal-port.d.ts +0 -6
- package/dist/app/ports/updates-port.d.ts +0 -4
- package/dist/attachments/service.d.ts +29 -0
- package/dist/attachments/service.js +47 -0
- package/dist/attachments/service.js.map +1 -0
- package/dist/commands/providers.js +0 -3
- package/dist/commands/providers.js.map +1 -1
- package/dist/commands/search-providers.d.ts +0 -33
- package/dist/commands/search-providers.js +0 -33
- package/dist/commands/search-providers.js.map +1 -1
- package/dist/commands/update.js +1 -9
- package/dist/commands/update.js.map +1 -1
- package/dist/index.js +22 -42
- package/dist/index.js.map +1 -1
- package/dist/llm/adapters/ollama-tools.d.ts +0 -4
- package/dist/llm/adapters/ollama-tools.js +0 -4
- package/dist/llm/adapters/ollama-tools.js.map +1 -1
- package/dist/llm/capabilities.d.ts +10 -10
- package/dist/llm/capabilities.js +43 -17
- package/dist/llm/capabilities.js.map +1 -1
- package/dist/llm/groq.js +0 -6
- package/dist/llm/groq.js.map +1 -1
- package/dist/llm/http.d.ts +0 -17
- package/dist/llm/http.js +0 -45
- package/dist/llm/http.js.map +1 -1
- package/dist/llm/router.d.ts +0 -6
- package/dist/llm/router.js +0 -15
- package/dist/llm/router.js.map +1 -1
- package/dist/llm/tool-protocol.d.ts +0 -6
- package/dist/llm/tool-protocol.js +3 -7
- package/dist/llm/tool-protocol.js.map +1 -1
- package/dist/modes/agent.d.ts +2 -1
- package/dist/modes/agent.js +4 -2
- package/dist/modes/agent.js.map +1 -1
- package/dist/modes/ask.d.ts +0 -18
- package/dist/modes/ask.js +0 -49
- package/dist/modes/ask.js.map +1 -1
- package/dist/os/cwd.d.ts +0 -21
- package/dist/os/cwd.js +0 -24
- package/dist/os/cwd.js.map +1 -1
- package/dist/os/pkgmgr.js +0 -6
- package/dist/os/pkgmgr.js.map +1 -1
- package/dist/prompts/embedded.d.ts +1 -0
- package/dist/prompts/embedded.js +9 -0
- package/dist/prompts/embedded.js.map +1 -0
- package/dist/prompts/index.d.ts +6 -18
- package/dist/prompts/index.js +104 -293
- package/dist/prompts/index.js.map +1 -1
- package/dist/prompts/system.agent.md +228 -0
- package/dist/prompts/system.ask.md +56 -0
- package/dist/repl/prompt-line.js +0 -36
- package/dist/repl/prompt-line.js.map +1 -1
- package/dist/repl/slash-commands.d.ts +0 -9
- package/dist/repl/slash-commands.js +2 -23
- package/dist/repl/slash-commands.js.map +1 -1
- package/dist/repl.d.ts +5 -0
- package/dist/repl.js +169 -55
- package/dist/repl.js.map +1 -1
- package/dist/safety/classifier.js +17 -9
- package/dist/safety/classifier.js.map +1 -1
- package/dist/safety/engagement-policy.d.ts +46 -0
- package/dist/safety/engagement-policy.js +198 -0
- package/dist/safety/engagement-policy.js.map +1 -0
- package/dist/store/engagement.d.ts +115 -0
- package/dist/store/engagement.js +278 -0
- package/dist/store/engagement.js.map +1 -0
- package/dist/store/logs.d.ts +5 -0
- package/dist/store/logs.js +52 -2
- package/dist/store/logs.js.map +1 -1
- package/dist/store/plan.d.ts +57 -5
- package/dist/store/plan.js +182 -8
- package/dist/store/plan.js.map +1 -1
- package/dist/store/scope.d.ts +4 -1
- package/dist/store/scope.js +2 -2
- package/dist/store/scope.js.map +1 -1
- package/dist/tools/definitions.js +70 -1
- package/dist/tools/definitions.js.map +1 -1
- package/dist/tools/elevated-shell.d.ts +60 -0
- package/dist/tools/elevated-shell.js +233 -0
- package/dist/tools/elevated-shell.js.map +1 -0
- package/dist/tools/file-diff.d.ts +125 -0
- package/dist/tools/file-diff.js +495 -0
- package/dist/tools/file-diff.js.map +1 -0
- package/dist/tools/fs.d.ts +11 -13
- package/dist/tools/fs.js +269 -78
- package/dist/tools/fs.js.map +1 -1
- package/dist/tools/http.d.ts +15 -0
- package/dist/tools/http.js +202 -61
- package/dist/tools/http.js.map +1 -1
- package/dist/tools/jobs.d.ts +71 -10
- package/dist/tools/jobs.js +403 -124
- package/dist/tools/jobs.js.map +1 -1
- package/dist/tools/nmap-runner.d.ts +11 -0
- package/dist/tools/nmap-runner.js +115 -74
- package/dist/tools/nmap-runner.js.map +1 -1
- package/dist/tools/pentest-workflows.d.ts +8 -0
- package/dist/tools/pentest-workflows.js +71 -0
- package/dist/tools/pentest-workflows.js.map +1 -0
- package/dist/tools/registry.d.ts +9 -0
- package/dist/tools/registry.js +244 -57
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/shell.d.ts +3 -0
- package/dist/tools/shell.js +35 -13
- package/dist/tools/shell.js.map +1 -1
- package/dist/tools/tool-types.d.ts +11 -0
- package/dist/tools/web/fetch-core.d.ts +7 -0
- package/dist/tools/web/fetch-core.js +40 -1
- package/dist/tools/web/fetch-core.js.map +1 -1
- package/dist/tools/web/fetch.js +8 -1
- package/dist/tools/web/fetch.js.map +1 -1
- package/dist/tui-v2/app/App.js +34 -41
- package/dist/tui-v2/app/App.js.map +1 -1
- package/dist/tui-v2/app/command-handlers.js +20 -1
- package/dist/tui-v2/app/command-handlers.js.map +1 -1
- package/dist/tui-v2/app/commands/picker-commands.js +3 -0
- package/dist/tui-v2/app/commands/picker-commands.js.map +1 -1
- package/dist/tui-v2/app/commands/session-commands.js +5 -0
- package/dist/tui-v2/app/commands/session-commands.js.map +1 -1
- package/dist/tui-v2/app/plan-lifecycle.d.ts +25 -3
- package/dist/tui-v2/app/plan-lifecycle.js +87 -24
- package/dist/tui-v2/app/plan-lifecycle.js.map +1 -1
- package/dist/tui-v2/bootstrap/patch-opentui-text.d.ts +6 -0
- package/dist/tui-v2/bootstrap/patch-opentui-text.js +53 -0
- package/dist/tui-v2/bootstrap/patch-opentui-text.js.map +1 -0
- package/dist/tui-v2/bootstrap/start-tui-v2.js +7 -0
- package/dist/tui-v2/bootstrap/start-tui-v2.js.map +1 -1
- package/dist/tui-v2/components/jobs/jobs-panel.js +23 -14
- package/dist/tui-v2/components/jobs/jobs-panel.js.map +1 -1
- package/dist/tui-v2/components/modal/confirm-modal.d.ts +1 -1
- package/dist/tui-v2/components/modal/confirm-modal.js +18 -7
- package/dist/tui-v2/components/modal/confirm-modal.js.map +1 -1
- package/dist/tui-v2/components/overlay/overlay-host.js +1 -1
- package/dist/tui-v2/components/overlay/overlay-host.js.map +1 -1
- package/dist/tui-v2/components/pager/pager.d.ts +6 -0
- package/dist/tui-v2/components/pager/pager.js +313 -67
- package/dist/tui-v2/components/pager/pager.js.map +1 -1
- package/dist/tui-v2/components/status/status-line.d.ts +9 -0
- package/dist/tui-v2/components/status/status-line.js +17 -3
- package/dist/tui-v2/components/status/status-line.js.map +1 -1
- package/dist/tui-v2/components/transcript/assistant-message.js +1 -1
- package/dist/tui-v2/components/transcript/assistant-message.js.map +1 -1
- package/dist/tui-v2/components/transcript/compacted-row.js +1 -1
- package/dist/tui-v2/components/transcript/compacted-row.js.map +1 -1
- package/dist/tui-v2/components/transcript/tool-card.d.ts +9 -1
- package/dist/tui-v2/components/transcript/tool-card.js +114 -9
- package/dist/tui-v2/components/transcript/tool-card.js.map +1 -1
- package/dist/tui-v2/components/transcript/transcript-row.js +2 -2
- package/dist/tui-v2/components/transcript/transcript-row.js.map +1 -1
- package/dist/tui-v2/composer/composer-editor.js +16 -0
- package/dist/tui-v2/composer/composer-editor.js.map +1 -1
- package/dist/tui-v2/controllers/overlay-controller.d.ts +16 -2
- package/dist/tui-v2/controllers/overlay-controller.js +92 -12
- package/dist/tui-v2/controllers/overlay-controller.js.map +1 -1
- package/dist/tui-v2/rendering/artifact-pager-source.d.ts +19 -0
- package/dist/tui-v2/rendering/artifact-pager-source.js +103 -0
- package/dist/tui-v2/rendering/artifact-pager-source.js.map +1 -0
- package/dist/tui-v2/rendering/file-diff-view.d.ts +63 -0
- package/dist/tui-v2/rendering/file-diff-view.js +263 -0
- package/dist/tui-v2/rendering/file-diff-view.js.map +1 -0
- package/dist/tui-v2/rendering/open-tool-output.d.ts +9 -1
- package/dist/tui-v2/rendering/open-tool-output.js +65 -12
- package/dist/tui-v2/rendering/open-tool-output.js.map +1 -1
- package/dist/tui-v2/rendering/pager-chrome.d.ts +12 -0
- package/dist/tui-v2/rendering/pager-chrome.js +56 -0
- package/dist/tui-v2/rendering/pager-chrome.js.map +1 -0
- package/dist/tui-v2/rendering/plan-view.js +1 -1
- package/dist/tui-v2/rendering/plan-view.js.map +1 -1
- package/dist/tui-v2/rendering/syntax-highlight.d.ts +37 -0
- package/dist/tui-v2/rendering/syntax-highlight.js +1303 -0
- package/dist/tui-v2/rendering/syntax-highlight.js.map +1 -0
- package/dist/tui-v2/rendering/theme.d.ts +28 -0
- package/dist/tui-v2/rendering/theme.js +28 -0
- package/dist/tui-v2/rendering/theme.js.map +1 -1
- package/dist/tui-v2/rendering/tool-presenter.d.ts +5 -0
- package/dist/tui-v2/rendering/tool-presenter.js +35 -3
- package/dist/tui-v2/rendering/tool-presenter.js.map +1 -1
- package/dist/tui-v2/state/transcript-hydrate.js +5 -0
- package/dist/tui-v2/state/transcript-hydrate.js.map +1 -1
- package/dist/tui-v2/state/transcript-reducer.js +12 -2
- package/dist/tui-v2/state/transcript-reducer.js.map +1 -1
- package/dist/tui-v2/state/transcript-store.d.ts +7 -0
- package/dist/tui-v2/state/transcript-store.js +46 -0
- package/dist/tui-v2/state/transcript-store.js.map +1 -1
- package/dist/tui-v2/state/transcript-types.d.ts +12 -0
- package/dist/tui-v2/state/transcript-types.js +9 -0
- package/dist/tui-v2/state/transcript-types.js.map +1 -1
- package/dist/types.d.ts +17 -1
- package/dist/ui/mentions.d.ts +6 -0
- package/dist/ui/mentions.js +50 -12
- package/dist/ui/mentions.js.map +1 -1
- package/dist/ui/plan-pane.js +1 -1
- package/dist/ui/plan-pane.js.map +1 -1
- package/package.json +18 -12
|
@@ -0,0 +1,1303 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight terminal syntax highlighter for file-diff cards / pager.
|
|
3
|
+
*
|
|
4
|
+
* Goal: work for **any** common source language without shiki/tree-sitter.
|
|
5
|
+
* Strategy:
|
|
6
|
+
* - Map hundreds of extensions → language families
|
|
7
|
+
* - Per-family keyword sets + comment/string rules
|
|
8
|
+
* - Unknown extensions still get a **generic** highlighter (strings, comments,
|
|
9
|
+
* numbers, punctuation) so every file type gets useful coloring
|
|
10
|
+
*/
|
|
11
|
+
export function emptyCarry() {
|
|
12
|
+
return { inBlockComment: false, inTripleString: false };
|
|
13
|
+
}
|
|
14
|
+
// ─── Keyword sets ───────────────────────────────────────────────────────────
|
|
15
|
+
const KW = {
|
|
16
|
+
js: words(`
|
|
17
|
+
as async await break case catch class const continue debugger default delete do else
|
|
18
|
+
enum export extends false finally for from function get if implements import in
|
|
19
|
+
instanceof interface let new null of package private protected public return set static
|
|
20
|
+
super switch this throw true try typeof undefined var void while with yield type keyof
|
|
21
|
+
readonly infer never unknown any boolean number string symbol bigint satisfies asserts
|
|
22
|
+
is namespace module declare abstract override
|
|
23
|
+
`),
|
|
24
|
+
py: words(`
|
|
25
|
+
and as assert async await break class continue def del elif else except False finally
|
|
26
|
+
for from global if import in is lambda None nonlocal not or pass raise return True try
|
|
27
|
+
while with yield match case type
|
|
28
|
+
`),
|
|
29
|
+
go: words(`
|
|
30
|
+
break case chan const continue default defer else fallthrough for func go goto if
|
|
31
|
+
import interface map package range return select struct switch type var true false nil iota
|
|
32
|
+
`),
|
|
33
|
+
rs: words(`
|
|
34
|
+
as async await break const continue crate dyn else enum extern false fn for if impl in
|
|
35
|
+
let loop match mod move mut pub ref return self Self static struct super trait true type
|
|
36
|
+
unsafe use where while async await dyn
|
|
37
|
+
`),
|
|
38
|
+
c: words(`
|
|
39
|
+
auto break case char const continue default do double else enum extern float for goto
|
|
40
|
+
if inline int long register restrict return short signed sizeof static struct switch
|
|
41
|
+
typedef union unsigned void volatile while _Bool _Complex _Imaginary true false NULL
|
|
42
|
+
class public private protected virtual template typename namespace using new delete this
|
|
43
|
+
try catch throw const_cast static_cast dynamic_cast reinterpret_cast constexpr noexcept
|
|
44
|
+
override final nullptr bool wchar_t
|
|
45
|
+
`),
|
|
46
|
+
csharp: words(`
|
|
47
|
+
abstract as base bool break byte case catch char checked class const continue decimal
|
|
48
|
+
default delegate do double else enum event explicit extern false finally fixed float for
|
|
49
|
+
foreach goto if implicit in int interface internal is lock long namespace new null object
|
|
50
|
+
operator out override params private protected public readonly ref return sbyte sealed
|
|
51
|
+
short sizeof stackalloc static string struct switch this throw true try typeof uint ulong
|
|
52
|
+
unchecked unsafe ushort using var virtual void volatile while async await nameof record
|
|
53
|
+
init required nint nuint
|
|
54
|
+
`),
|
|
55
|
+
java: words(`
|
|
56
|
+
abstract assert boolean break byte case catch char class const continue default do double
|
|
57
|
+
else enum extends final finally float for goto if implements import instanceof int
|
|
58
|
+
interface long native new package private protected public return short static strictfp
|
|
59
|
+
super switch synchronized this throw throws transient try void volatile while true false
|
|
60
|
+
null var record sealed permits yields yield non-sealed
|
|
61
|
+
`),
|
|
62
|
+
kotlin: words(`
|
|
63
|
+
as as? break class continue do else false for fun if in !in interface is !is null object
|
|
64
|
+
package return super this throw true try typealias typeof val var when while by catch
|
|
65
|
+
constructor delegate dynamic field file finally get import init param property receiver
|
|
66
|
+
set setparam where actual abstract annotation companion const crossinline data enum
|
|
67
|
+
expect external final infix inline inner internal lateinit noinline open operator out
|
|
68
|
+
override private protected public reified sealed suspend tailrec vararg
|
|
69
|
+
`),
|
|
70
|
+
swift: words(`
|
|
71
|
+
associatedtype class deinit enum extension fileprivate func import init inout internal let
|
|
72
|
+
open operator private protocol public rethrows static struct subscript typealias var break
|
|
73
|
+
case continue default defer do else fallthrough for guard if in repeat return switch where
|
|
74
|
+
while as Any catch false is nil super self Self throw true try async await actor some
|
|
75
|
+
`),
|
|
76
|
+
ruby: words(`
|
|
77
|
+
BEGIN END alias and begin break case class def defined? do else elsif end ensure false
|
|
78
|
+
for if in module next nil not or redo rescue retry return self super then true undef
|
|
79
|
+
unless until when while yield
|
|
80
|
+
`),
|
|
81
|
+
php: words(`
|
|
82
|
+
abstract and array as break callable case catch class clone const continue declare default
|
|
83
|
+
do echo else elseif empty enddeclare endfor endforeach endif endswitch endwhile eval exit
|
|
84
|
+
extends final finally fn for foreach function global goto if implements include include_once
|
|
85
|
+
instanceof insteadof interface isset list match namespace new or print private protected
|
|
86
|
+
public readonly require require_once return static switch throw trait try unset use var
|
|
87
|
+
while xor yield true false null
|
|
88
|
+
`),
|
|
89
|
+
sql: words(`
|
|
90
|
+
select from where insert into values update set delete create table drop alter index view
|
|
91
|
+
join left right inner outer on and or not null as order by group having limit offset union
|
|
92
|
+
all distinct case when then else end exists in between like is primary key foreign
|
|
93
|
+
references constraint default unique check cascade grant revoke commit rollback transaction
|
|
94
|
+
begin true false with recursive
|
|
95
|
+
`),
|
|
96
|
+
lua: words(`
|
|
97
|
+
and break do else elseif end false for function goto if in local nil not or repeat return
|
|
98
|
+
then true until while
|
|
99
|
+
`),
|
|
100
|
+
perl: words(`
|
|
101
|
+
__DATA__ __END__ __FILE__ __LINE__ __PACKAGE__ and cmp continue do else elsif eq exp for
|
|
102
|
+
foreach ge gt if le lock lt m ne next no or package qq qr qw qx redo require return sub
|
|
103
|
+
tr unless until while xor y my our use local
|
|
104
|
+
`),
|
|
105
|
+
r: words(`
|
|
106
|
+
if else repeat while function for in next break TRUE FALSE NULL Inf NaN NA NA_integer_
|
|
107
|
+
NA_real_ NA_complex_ NA_character_ ... ..1
|
|
108
|
+
`),
|
|
109
|
+
haskell: words(`
|
|
110
|
+
case class data default deriving do else foreign if import in infix infixl infixr instance
|
|
111
|
+
let module newtype of then type where _
|
|
112
|
+
`),
|
|
113
|
+
erlang: words(`
|
|
114
|
+
after and andalso band begin bnot bor bsl bsr bxor case catch cond div end fun if let not
|
|
115
|
+
of or orelse receive rem try when xor
|
|
116
|
+
`),
|
|
117
|
+
fortran: words(`
|
|
118
|
+
assign backspace block call close common continue data dimension do else elseif end endfile
|
|
119
|
+
endif enddo entry equivalence external format function goto if implicit inquire integer
|
|
120
|
+
intrinsic open parameter pause print program read real return rewind save stop subroutine
|
|
121
|
+
then write allocate allocatable allocate deallocate module use contains interface pure
|
|
122
|
+
elemental recursive
|
|
123
|
+
`),
|
|
124
|
+
sh: words(`
|
|
125
|
+
if then else elif fi for while until do done case esac in function select time coproc
|
|
126
|
+
true false return exit export local readonly declare typeset alias unalias set unset
|
|
127
|
+
shift break continue source eval exec
|
|
128
|
+
`),
|
|
129
|
+
css: words(`
|
|
130
|
+
important and or not only from to
|
|
131
|
+
`),
|
|
132
|
+
};
|
|
133
|
+
function words(s) {
|
|
134
|
+
return new Set(s.split(/\s+/).filter(Boolean));
|
|
135
|
+
}
|
|
136
|
+
/** extension (no dot) → family */
|
|
137
|
+
const EXT_FAMILY = {
|
|
138
|
+
// JS / TS
|
|
139
|
+
js: "js",
|
|
140
|
+
mjs: "js",
|
|
141
|
+
cjs: "js",
|
|
142
|
+
jsx: "js",
|
|
143
|
+
ts: "js",
|
|
144
|
+
mts: "js",
|
|
145
|
+
cts: "js",
|
|
146
|
+
tsx: "js",
|
|
147
|
+
vue: "html",
|
|
148
|
+
svelte: "html",
|
|
149
|
+
astro: "html",
|
|
150
|
+
// web
|
|
151
|
+
css: "css",
|
|
152
|
+
scss: "css",
|
|
153
|
+
sass: "css",
|
|
154
|
+
less: "css",
|
|
155
|
+
styl: "css",
|
|
156
|
+
stylus: "css",
|
|
157
|
+
html: "html",
|
|
158
|
+
htm: "html",
|
|
159
|
+
xhtml: "html",
|
|
160
|
+
xml: "html",
|
|
161
|
+
xsl: "html",
|
|
162
|
+
xslt: "html",
|
|
163
|
+
svg: "html",
|
|
164
|
+
jsp: "html",
|
|
165
|
+
asp: "html",
|
|
166
|
+
aspx: "html",
|
|
167
|
+
// data
|
|
168
|
+
json: "json",
|
|
169
|
+
jsonc: "json",
|
|
170
|
+
json5: "json",
|
|
171
|
+
jsonl: "json",
|
|
172
|
+
ndjson: "json",
|
|
173
|
+
yaml: "yaml",
|
|
174
|
+
yml: "yaml",
|
|
175
|
+
toml: "toml",
|
|
176
|
+
ini: "ini",
|
|
177
|
+
cfg: "ini",
|
|
178
|
+
conf: "ini",
|
|
179
|
+
env: "ini",
|
|
180
|
+
properties: "ini",
|
|
181
|
+
// docs
|
|
182
|
+
md: "md",
|
|
183
|
+
mdx: "md",
|
|
184
|
+
markdown: "md",
|
|
185
|
+
rst: "md",
|
|
186
|
+
txt: "generic",
|
|
187
|
+
// shell
|
|
188
|
+
sh: "sh",
|
|
189
|
+
bash: "sh",
|
|
190
|
+
zsh: "sh",
|
|
191
|
+
fish: "sh",
|
|
192
|
+
ksh: "sh",
|
|
193
|
+
csh: "sh",
|
|
194
|
+
tcsh: "sh",
|
|
195
|
+
ps1: "sh",
|
|
196
|
+
psm1: "sh",
|
|
197
|
+
bat: "sh",
|
|
198
|
+
cmd: "sh",
|
|
199
|
+
// python
|
|
200
|
+
py: "py",
|
|
201
|
+
pyw: "py",
|
|
202
|
+
pyi: "py",
|
|
203
|
+
pyx: "py",
|
|
204
|
+
pxd: "py",
|
|
205
|
+
ipynb: "json",
|
|
206
|
+
// ruby
|
|
207
|
+
rb: "ruby",
|
|
208
|
+
rake: "ruby",
|
|
209
|
+
gemspec: "ruby",
|
|
210
|
+
// php
|
|
211
|
+
php: "php",
|
|
212
|
+
phtml: "php",
|
|
213
|
+
// go / rust
|
|
214
|
+
go: "clike",
|
|
215
|
+
rs: "clike",
|
|
216
|
+
// C family
|
|
217
|
+
c: "clike",
|
|
218
|
+
h: "clike",
|
|
219
|
+
cc: "clike",
|
|
220
|
+
cpp: "clike",
|
|
221
|
+
cxx: "clike",
|
|
222
|
+
hpp: "clike",
|
|
223
|
+
hxx: "clike",
|
|
224
|
+
hh: "clike",
|
|
225
|
+
m: "clike",
|
|
226
|
+
mm: "clike",
|
|
227
|
+
cs: "clike",
|
|
228
|
+
java: "clike",
|
|
229
|
+
kt: "clike",
|
|
230
|
+
kts: "clike",
|
|
231
|
+
scala: "clike",
|
|
232
|
+
sc: "clike",
|
|
233
|
+
groovy: "clike",
|
|
234
|
+
gradle: "clike",
|
|
235
|
+
swift: "clike",
|
|
236
|
+
dart: "clike",
|
|
237
|
+
// JVM etc
|
|
238
|
+
clj: "lisp",
|
|
239
|
+
cljs: "lisp",
|
|
240
|
+
cljc: "lisp",
|
|
241
|
+
edn: "lisp",
|
|
242
|
+
lisp: "lisp",
|
|
243
|
+
el: "lisp",
|
|
244
|
+
scm: "lisp",
|
|
245
|
+
ss: "lisp",
|
|
246
|
+
racket: "lisp",
|
|
247
|
+
// functional
|
|
248
|
+
hs: "haskell",
|
|
249
|
+
lhs: "haskell",
|
|
250
|
+
elm: "haskell",
|
|
251
|
+
ml: "clike",
|
|
252
|
+
mli: "clike",
|
|
253
|
+
fs: "clike",
|
|
254
|
+
fsi: "clike",
|
|
255
|
+
fsx: "clike",
|
|
256
|
+
erl: "erlang",
|
|
257
|
+
hrl: "erlang",
|
|
258
|
+
ex: "ruby", // Elixir ~ Ruby-ish # comments
|
|
259
|
+
exs: "ruby",
|
|
260
|
+
// scripting
|
|
261
|
+
pl: "perl",
|
|
262
|
+
pm: "perl",
|
|
263
|
+
t: "perl",
|
|
264
|
+
lua: "lua",
|
|
265
|
+
r: "r",
|
|
266
|
+
R: "r",
|
|
267
|
+
jl: "py", // Julia: # comments like python-ish
|
|
268
|
+
// systems
|
|
269
|
+
zig: "clike",
|
|
270
|
+
nim: "py", // # comments
|
|
271
|
+
v: "clike",
|
|
272
|
+
d: "clike",
|
|
273
|
+
pas: "clike",
|
|
274
|
+
pp: "clike",
|
|
275
|
+
// data / query
|
|
276
|
+
sql: "sql",
|
|
277
|
+
mysql: "sql",
|
|
278
|
+
pgsql: "sql",
|
|
279
|
+
psql: "sql",
|
|
280
|
+
hql: "sql",
|
|
281
|
+
graphql: "js",
|
|
282
|
+
gql: "js",
|
|
283
|
+
prisma: "js",
|
|
284
|
+
// config / devops
|
|
285
|
+
dockerfile: "sh",
|
|
286
|
+
tf: "clike",
|
|
287
|
+
hcl: "clike",
|
|
288
|
+
nix: "clike",
|
|
289
|
+
makefile: "sh",
|
|
290
|
+
mk: "sh",
|
|
291
|
+
cmake: "sh",
|
|
292
|
+
// diff
|
|
293
|
+
diff: "diff",
|
|
294
|
+
patch: "diff",
|
|
295
|
+
// others often in repos
|
|
296
|
+
proto: "clike",
|
|
297
|
+
thrift: "clike",
|
|
298
|
+
avdl: "clike",
|
|
299
|
+
sol: "clike",
|
|
300
|
+
move: "clike",
|
|
301
|
+
wgsl: "clike",
|
|
302
|
+
glsl: "clike",
|
|
303
|
+
vert: "clike",
|
|
304
|
+
frag: "clike",
|
|
305
|
+
hlsl: "clike",
|
|
306
|
+
metal: "clike",
|
|
307
|
+
asm: "generic",
|
|
308
|
+
s: "generic",
|
|
309
|
+
S: "generic",
|
|
310
|
+
f: "fortran",
|
|
311
|
+
f90: "fortran",
|
|
312
|
+
f95: "fortran",
|
|
313
|
+
for: "fortran",
|
|
314
|
+
cob: "generic",
|
|
315
|
+
cbl: "generic",
|
|
316
|
+
vb: "clike",
|
|
317
|
+
vbs: "generic",
|
|
318
|
+
coffee: "js",
|
|
319
|
+
litcoffee: "js",
|
|
320
|
+
ls: "js",
|
|
321
|
+
purescript: "haskell",
|
|
322
|
+
purs: "haskell",
|
|
323
|
+
res: "clike",
|
|
324
|
+
resi: "clike",
|
|
325
|
+
re: "clike",
|
|
326
|
+
rei: "clike",
|
|
327
|
+
mlapp: "generic",
|
|
328
|
+
mat: "generic",
|
|
329
|
+
sas: "generic",
|
|
330
|
+
sparql: "sql",
|
|
331
|
+
rq: "sql",
|
|
332
|
+
turtle: "generic",
|
|
333
|
+
ttl: "generic",
|
|
334
|
+
nq: "generic",
|
|
335
|
+
wasm: "generic",
|
|
336
|
+
wat: "generic",
|
|
337
|
+
csv: "generic",
|
|
338
|
+
tsv: "generic",
|
|
339
|
+
log: "generic",
|
|
340
|
+
lock: "json",
|
|
341
|
+
};
|
|
342
|
+
const BASENAME_FAMILY = {
|
|
343
|
+
dockerfile: "sh",
|
|
344
|
+
containerfile: "sh",
|
|
345
|
+
makefile: "sh",
|
|
346
|
+
gnumakefile: "sh",
|
|
347
|
+
"cmakelists.txt": "sh",
|
|
348
|
+
"cargo.toml": "toml",
|
|
349
|
+
"pyproject.toml": "toml",
|
|
350
|
+
"package.json": "json",
|
|
351
|
+
"tsconfig.json": "json",
|
|
352
|
+
"jsconfig.json": "json",
|
|
353
|
+
"composer.json": "json",
|
|
354
|
+
gemfile: "ruby",
|
|
355
|
+
rakefile: "ruby",
|
|
356
|
+
podfile: "ruby",
|
|
357
|
+
brewfile: "ruby",
|
|
358
|
+
vagrantfile: "ruby",
|
|
359
|
+
procfile: "sh",
|
|
360
|
+
justfile: "sh",
|
|
361
|
+
"go.mod": "clike",
|
|
362
|
+
"go.sum": "generic",
|
|
363
|
+
".gitignore": "ini",
|
|
364
|
+
".dockerignore": "ini",
|
|
365
|
+
".npmrc": "ini",
|
|
366
|
+
".env": "ini",
|
|
367
|
+
".env.local": "ini",
|
|
368
|
+
".env.development": "ini",
|
|
369
|
+
".env.production": "ini",
|
|
370
|
+
".eslintrc": "json",
|
|
371
|
+
".prettierrc": "json",
|
|
372
|
+
".babelrc": "json",
|
|
373
|
+
};
|
|
374
|
+
function keywordSetFor(pathOrExt, family) {
|
|
375
|
+
const ext = (pathOrExt.split(".").pop() ?? "").toLowerCase();
|
|
376
|
+
if (family === "js")
|
|
377
|
+
return KW.js;
|
|
378
|
+
if (family === "py")
|
|
379
|
+
return KW.py;
|
|
380
|
+
if (family === "ruby")
|
|
381
|
+
return KW.ruby;
|
|
382
|
+
if (family === "php")
|
|
383
|
+
return KW.php;
|
|
384
|
+
if (family === "sql")
|
|
385
|
+
return KW.sql;
|
|
386
|
+
if (family === "lua")
|
|
387
|
+
return KW.lua;
|
|
388
|
+
if (family === "perl")
|
|
389
|
+
return KW.perl;
|
|
390
|
+
if (family === "r")
|
|
391
|
+
return KW.r;
|
|
392
|
+
if (family === "haskell")
|
|
393
|
+
return KW.haskell;
|
|
394
|
+
if (family === "erlang")
|
|
395
|
+
return KW.erlang;
|
|
396
|
+
if (family === "fortran")
|
|
397
|
+
return KW.fortran;
|
|
398
|
+
if (family === "sh")
|
|
399
|
+
return KW.sh;
|
|
400
|
+
if (family === "css")
|
|
401
|
+
return KW.css;
|
|
402
|
+
if (family === "clike") {
|
|
403
|
+
if (ext === "go")
|
|
404
|
+
return KW.go;
|
|
405
|
+
if (ext === "rs")
|
|
406
|
+
return KW.rs;
|
|
407
|
+
if (ext === "cs")
|
|
408
|
+
return KW.csharp;
|
|
409
|
+
if (ext === "java")
|
|
410
|
+
return KW.java;
|
|
411
|
+
if (ext === "kt" || ext === "kts")
|
|
412
|
+
return KW.kotlin;
|
|
413
|
+
if (ext === "swift")
|
|
414
|
+
return KW.swift;
|
|
415
|
+
if (ext === "dart")
|
|
416
|
+
return KW.js; // close enough
|
|
417
|
+
return KW.c;
|
|
418
|
+
}
|
|
419
|
+
return new Set();
|
|
420
|
+
}
|
|
421
|
+
export function languageFromPath(path) {
|
|
422
|
+
const base = (path.split(/[/\\]/).pop() ?? path).toLowerCase();
|
|
423
|
+
if (BASENAME_FAMILY[base])
|
|
424
|
+
return BASENAME_FAMILY[base];
|
|
425
|
+
// multi-dot basenames
|
|
426
|
+
for (const [name, fam] of Object.entries(BASENAME_FAMILY)) {
|
|
427
|
+
if (base === name || base.endsWith(name))
|
|
428
|
+
return fam;
|
|
429
|
+
}
|
|
430
|
+
const dot = base.lastIndexOf(".");
|
|
431
|
+
if (dot < 0) {
|
|
432
|
+
// shebang-less scripts / Makefile already handled
|
|
433
|
+
return "generic";
|
|
434
|
+
}
|
|
435
|
+
// handle .d.ts, .test.ts etc — use last extension
|
|
436
|
+
const ext = base.slice(dot + 1);
|
|
437
|
+
// double extensions like .d.ts
|
|
438
|
+
if (base.endsWith(".d.ts") || base.endsWith(".d.mts") || base.endsWith(".d.cts")) {
|
|
439
|
+
return "js";
|
|
440
|
+
}
|
|
441
|
+
if (base.endsWith(".test.ts") || base.endsWith(".spec.ts") || base.endsWith(".test.tsx")) {
|
|
442
|
+
return "js";
|
|
443
|
+
}
|
|
444
|
+
return EXT_FAMILY[ext] ?? "generic";
|
|
445
|
+
}
|
|
446
|
+
/** @deprecated use languageFromPath */
|
|
447
|
+
export function languageFromPathLegacy(path) {
|
|
448
|
+
return languageFromPath(path);
|
|
449
|
+
}
|
|
450
|
+
// ─── Core helpers ───────────────────────────────────────────────────────────
|
|
451
|
+
function push(spans, kind, text) {
|
|
452
|
+
if (!text)
|
|
453
|
+
return;
|
|
454
|
+
const last = spans[spans.length - 1];
|
|
455
|
+
if (last && last.kind === kind) {
|
|
456
|
+
spans[spans.length - 1] = { kind, text: last.text + text };
|
|
457
|
+
}
|
|
458
|
+
else {
|
|
459
|
+
spans.push({ kind, text });
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
function isIdentStart(ch) {
|
|
463
|
+
return /[A-Za-z_$\u00a0-\uffff]/.test(ch);
|
|
464
|
+
}
|
|
465
|
+
function isIdentCont(ch) {
|
|
466
|
+
return /[A-Za-z0-9_$\u00a0-\uffff]/.test(ch);
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Highlight one line for any path/language. Unknown types use generic rules.
|
|
470
|
+
*/
|
|
471
|
+
export function highlightLine(line, langOrPath, carry = emptyCarry()) {
|
|
472
|
+
const family = typeof langOrPath === "string" &&
|
|
473
|
+
![
|
|
474
|
+
"clike",
|
|
475
|
+
"js",
|
|
476
|
+
"css",
|
|
477
|
+
"json",
|
|
478
|
+
"html",
|
|
479
|
+
"md",
|
|
480
|
+
"sh",
|
|
481
|
+
"py",
|
|
482
|
+
"ruby",
|
|
483
|
+
"php",
|
|
484
|
+
"sql",
|
|
485
|
+
"lua",
|
|
486
|
+
"perl",
|
|
487
|
+
"r",
|
|
488
|
+
"haskell",
|
|
489
|
+
"lisp",
|
|
490
|
+
"erlang",
|
|
491
|
+
"fortran",
|
|
492
|
+
"yaml",
|
|
493
|
+
"toml",
|
|
494
|
+
"ini",
|
|
495
|
+
"diff",
|
|
496
|
+
"generic",
|
|
497
|
+
].includes(langOrPath)
|
|
498
|
+
? languageFromPath(langOrPath)
|
|
499
|
+
: langOrPath;
|
|
500
|
+
switch (family) {
|
|
501
|
+
case "md":
|
|
502
|
+
return highlightMarkdown(line);
|
|
503
|
+
case "json":
|
|
504
|
+
return highlightJsonLike(line);
|
|
505
|
+
case "css":
|
|
506
|
+
return highlightClike(line, KW.css, carry, { regex: false, hashNumber: true });
|
|
507
|
+
case "html":
|
|
508
|
+
return highlightHtml(line, carry);
|
|
509
|
+
case "yaml":
|
|
510
|
+
return highlightYaml(line);
|
|
511
|
+
case "toml":
|
|
512
|
+
case "ini":
|
|
513
|
+
return highlightIniToml(line);
|
|
514
|
+
case "diff":
|
|
515
|
+
return highlightDiff(line);
|
|
516
|
+
case "sh":
|
|
517
|
+
return highlightLineCommentLang(line, "#", KW.sh, carry);
|
|
518
|
+
case "py":
|
|
519
|
+
return highlightPython(line, carry);
|
|
520
|
+
case "ruby":
|
|
521
|
+
return highlightLineCommentLang(line, "#", KW.ruby, carry);
|
|
522
|
+
case "php":
|
|
523
|
+
return highlightPhp(line, carry);
|
|
524
|
+
case "sql":
|
|
525
|
+
return highlightClike(line, KW.sql, carry, {
|
|
526
|
+
lineComment: "--",
|
|
527
|
+
caseInsensitiveKeywords: true,
|
|
528
|
+
});
|
|
529
|
+
case "lua":
|
|
530
|
+
return highlightLua(line, carry);
|
|
531
|
+
case "perl":
|
|
532
|
+
return highlightLineCommentLang(line, "#", KW.perl, carry);
|
|
533
|
+
case "r":
|
|
534
|
+
return highlightLineCommentLang(line, "#", KW.r, carry);
|
|
535
|
+
case "haskell":
|
|
536
|
+
return highlightHaskell(line, carry);
|
|
537
|
+
case "lisp":
|
|
538
|
+
return highlightLisp(line);
|
|
539
|
+
case "erlang":
|
|
540
|
+
return highlightLineCommentLang(line, "%", KW.erlang, carry);
|
|
541
|
+
case "fortran":
|
|
542
|
+
return highlightLineCommentLang(line, "!", KW.fortran, carry, {
|
|
543
|
+
caseInsensitiveKeywords: true,
|
|
544
|
+
});
|
|
545
|
+
case "js":
|
|
546
|
+
return highlightClike(line, KW.js, carry, { regex: true });
|
|
547
|
+
case "clike":
|
|
548
|
+
return highlightClike(line, keywordSetFor("", "clike"), carry, { regex: false });
|
|
549
|
+
case "generic":
|
|
550
|
+
default:
|
|
551
|
+
return highlightGeneric(line, carry);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
export function highlightLineForPath(line, path, carry = emptyCarry()) {
|
|
555
|
+
const family = languageFromPath(path);
|
|
556
|
+
// re-resolve keywords with extension for clike
|
|
557
|
+
if (family === "clike") {
|
|
558
|
+
return highlightClike(line, keywordSetFor(path, "clike"), carry, { regex: false });
|
|
559
|
+
}
|
|
560
|
+
return highlightLine(line, family, carry);
|
|
561
|
+
}
|
|
562
|
+
export function highlightLines(lines, langOrPath) {
|
|
563
|
+
const carry = emptyCarry();
|
|
564
|
+
const isPath = typeof langOrPath === "string" &&
|
|
565
|
+
(langOrPath.includes("/") || langOrPath.includes(".") || langOrPath.includes("\\"));
|
|
566
|
+
return lines.map((line) => isPath
|
|
567
|
+
? highlightLineForPath(line, langOrPath, carry)
|
|
568
|
+
: highlightLine(line, langOrPath, carry));
|
|
569
|
+
}
|
|
570
|
+
export function clipSpans(spans, maxChars) {
|
|
571
|
+
if (maxChars <= 0)
|
|
572
|
+
return [];
|
|
573
|
+
const out = [];
|
|
574
|
+
let used = 0;
|
|
575
|
+
for (const s of spans) {
|
|
576
|
+
if (used >= maxChars)
|
|
577
|
+
break;
|
|
578
|
+
const room = maxChars - used;
|
|
579
|
+
if (s.text.length <= room) {
|
|
580
|
+
out.push(s);
|
|
581
|
+
used += s.text.length;
|
|
582
|
+
}
|
|
583
|
+
else {
|
|
584
|
+
out.push({ kind: s.kind, text: s.text.slice(0, Math.max(0, room - 1)) + "…" });
|
|
585
|
+
break;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
return out;
|
|
589
|
+
}
|
|
590
|
+
function highlightClike(line, keys, carry, opts = {}) {
|
|
591
|
+
const spans = [];
|
|
592
|
+
const n = line.length;
|
|
593
|
+
let i = 0;
|
|
594
|
+
const lineComment = opts.lineComment ?? "//";
|
|
595
|
+
while (i < n) {
|
|
596
|
+
if (carry.inBlockComment) {
|
|
597
|
+
const end = line.indexOf("*/", i);
|
|
598
|
+
if (end < 0) {
|
|
599
|
+
push(spans, "comment", line.slice(i));
|
|
600
|
+
return spans;
|
|
601
|
+
}
|
|
602
|
+
push(spans, "comment", line.slice(i, end + 2));
|
|
603
|
+
carry.inBlockComment = false;
|
|
604
|
+
i = end + 2;
|
|
605
|
+
continue;
|
|
606
|
+
}
|
|
607
|
+
const ch = line[i];
|
|
608
|
+
const next = line[i + 1];
|
|
609
|
+
// line comment
|
|
610
|
+
if (line.startsWith(lineComment, i)) {
|
|
611
|
+
push(spans, "comment", line.slice(i));
|
|
612
|
+
return spans;
|
|
613
|
+
}
|
|
614
|
+
// block comment
|
|
615
|
+
if (ch === "/" && next === "*") {
|
|
616
|
+
const end = line.indexOf("*/", i + 2);
|
|
617
|
+
if (end < 0) {
|
|
618
|
+
push(spans, "comment", line.slice(i));
|
|
619
|
+
carry.inBlockComment = true;
|
|
620
|
+
return spans;
|
|
621
|
+
}
|
|
622
|
+
push(spans, "comment", line.slice(i, end + 2));
|
|
623
|
+
i = end + 2;
|
|
624
|
+
continue;
|
|
625
|
+
}
|
|
626
|
+
// strings
|
|
627
|
+
if (ch === '"' || ch === "'" || ch === "`") {
|
|
628
|
+
i = readString(line, i, ch, spans);
|
|
629
|
+
continue;
|
|
630
|
+
}
|
|
631
|
+
// regex
|
|
632
|
+
if (opts.regex && ch === "/" && next && next !== "/" && next !== "*") {
|
|
633
|
+
const prev = spans.length ? spans[spans.length - 1].text.trimEnd().slice(-1) : "";
|
|
634
|
+
if (!prev || /[=(:,[\!&|?{;]/.test(prev)) {
|
|
635
|
+
const j = readRegex(line, i);
|
|
636
|
+
if (j > i) {
|
|
637
|
+
push(spans, "regex", line.slice(i, j));
|
|
638
|
+
i = j;
|
|
639
|
+
continue;
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
// #hex colors in css
|
|
644
|
+
if (opts.hashNumber && ch === "#" && next && /[0-9a-fA-F]/.test(next)) {
|
|
645
|
+
let j = i + 1;
|
|
646
|
+
while (j < n && /[0-9a-fA-F]/.test(line[j]))
|
|
647
|
+
j += 1;
|
|
648
|
+
push(spans, "number", line.slice(i, j));
|
|
649
|
+
i = j;
|
|
650
|
+
continue;
|
|
651
|
+
}
|
|
652
|
+
// numbers
|
|
653
|
+
if (/\d/.test(ch) || (ch === "." && next && /\d/.test(next))) {
|
|
654
|
+
let j = i;
|
|
655
|
+
while (j < n && /[\d._xXa-fA-FeEpP+-]/.test(line[j]))
|
|
656
|
+
j += 1;
|
|
657
|
+
push(spans, "number", line.slice(i, j));
|
|
658
|
+
i = j;
|
|
659
|
+
continue;
|
|
660
|
+
}
|
|
661
|
+
// identifiers
|
|
662
|
+
if (isIdentStart(ch)) {
|
|
663
|
+
let j = i + 1;
|
|
664
|
+
while (j < n && isIdentCont(line[j]))
|
|
665
|
+
j += 1;
|
|
666
|
+
const word = line.slice(i, j);
|
|
667
|
+
let k = j;
|
|
668
|
+
while (k < n && (line[k] === " " || line[k] === "\t"))
|
|
669
|
+
k += 1;
|
|
670
|
+
const after = line[k];
|
|
671
|
+
const keyLookup = opts.caseInsensitiveKeywords ? word.toLowerCase() : word;
|
|
672
|
+
const keyHit = opts.caseInsensitiveKeywords
|
|
673
|
+
? [...keys].some((kw) => kw.toLowerCase() === keyLookup)
|
|
674
|
+
: keys.has(word);
|
|
675
|
+
if (keyHit)
|
|
676
|
+
push(spans, "keyword", word);
|
|
677
|
+
else if (after === "(")
|
|
678
|
+
push(spans, "function", word);
|
|
679
|
+
else if (/^[A-Z]/.test(word))
|
|
680
|
+
push(spans, "type", word);
|
|
681
|
+
else if (spans[spans.length - 1]?.text.endsWith("."))
|
|
682
|
+
push(spans, "property", word);
|
|
683
|
+
else
|
|
684
|
+
push(spans, "plain", word);
|
|
685
|
+
i = j;
|
|
686
|
+
continue;
|
|
687
|
+
}
|
|
688
|
+
if (/[{}()\[\];,.]/.test(ch)) {
|
|
689
|
+
push(spans, "punctuation", ch);
|
|
690
|
+
i += 1;
|
|
691
|
+
continue;
|
|
692
|
+
}
|
|
693
|
+
if (/[+\-*/%=<>!&|^~?:@]/.test(ch)) {
|
|
694
|
+
let j = i + 1;
|
|
695
|
+
while (j < n && /[+\-*/%=<>!&|^~?:@]/.test(line[j]))
|
|
696
|
+
j += 1;
|
|
697
|
+
push(spans, "operator", line.slice(i, j));
|
|
698
|
+
i = j;
|
|
699
|
+
continue;
|
|
700
|
+
}
|
|
701
|
+
push(spans, "plain", ch);
|
|
702
|
+
i += 1;
|
|
703
|
+
}
|
|
704
|
+
return spans;
|
|
705
|
+
}
|
|
706
|
+
function readString(line, start, quote, spans) {
|
|
707
|
+
const n = line.length;
|
|
708
|
+
let j = start + 1;
|
|
709
|
+
while (j < n) {
|
|
710
|
+
if (line[j] === "\\") {
|
|
711
|
+
j += 2;
|
|
712
|
+
continue;
|
|
713
|
+
}
|
|
714
|
+
if (line[j] === quote) {
|
|
715
|
+
j += 1;
|
|
716
|
+
break;
|
|
717
|
+
}
|
|
718
|
+
// template ${ } — keep as string for simplicity
|
|
719
|
+
j += 1;
|
|
720
|
+
}
|
|
721
|
+
push(spans, "string", line.slice(start, j));
|
|
722
|
+
return j;
|
|
723
|
+
}
|
|
724
|
+
function readRegex(line, start) {
|
|
725
|
+
const n = line.length;
|
|
726
|
+
let j = start + 1;
|
|
727
|
+
let closed = false;
|
|
728
|
+
while (j < n) {
|
|
729
|
+
if (line[j] === "\\") {
|
|
730
|
+
j += 2;
|
|
731
|
+
continue;
|
|
732
|
+
}
|
|
733
|
+
if (line[j] === "/") {
|
|
734
|
+
j += 1;
|
|
735
|
+
closed = true;
|
|
736
|
+
break;
|
|
737
|
+
}
|
|
738
|
+
if (line[j] === "\n")
|
|
739
|
+
break;
|
|
740
|
+
j += 1;
|
|
741
|
+
}
|
|
742
|
+
if (!closed)
|
|
743
|
+
return start;
|
|
744
|
+
while (j < n && /[gimsuy]/.test(line[j]))
|
|
745
|
+
j += 1;
|
|
746
|
+
return j;
|
|
747
|
+
}
|
|
748
|
+
/** Generic: strings, line/block comments, numbers — any unmapped extension. */
|
|
749
|
+
function highlightGeneric(line, carry) {
|
|
750
|
+
const t = line.trimStart();
|
|
751
|
+
// Prefer # line comments for shell-like / config files when whole-line-ish
|
|
752
|
+
if (t.startsWith("#") && !/^#[0-9a-fA-F]{3,8}\b/.test(t)) {
|
|
753
|
+
return [{ kind: "comment", text: line }];
|
|
754
|
+
}
|
|
755
|
+
return highlightClike(line, new Set(), carry, { regex: false });
|
|
756
|
+
}
|
|
757
|
+
function highlightLineCommentLang(line, commentChar, keys, carry, opts = {}) {
|
|
758
|
+
const caseIns = opts.caseInsensitiveKeywords === true;
|
|
759
|
+
// Reuse clike but with custom line comment by pre-check
|
|
760
|
+
const t = line.trimStart();
|
|
761
|
+
if (t.startsWith(commentChar) && commentChar !== "//") {
|
|
762
|
+
return [{ kind: "comment", text: line }];
|
|
763
|
+
}
|
|
764
|
+
// map # comments: temporarily convert? better custom loop
|
|
765
|
+
if (commentChar === "#") {
|
|
766
|
+
return highlightHashCommentLang(line, keys, caseIns);
|
|
767
|
+
}
|
|
768
|
+
if (commentChar === "%" || commentChar === "!") {
|
|
769
|
+
return highlightHashCommentLang(line, keys, caseIns, commentChar);
|
|
770
|
+
}
|
|
771
|
+
return highlightClike(line, keys, carry, {
|
|
772
|
+
caseInsensitiveKeywords: caseIns,
|
|
773
|
+
});
|
|
774
|
+
}
|
|
775
|
+
function highlightHashCommentLang(line, keys, caseInsensitive = false, commentChar = "#") {
|
|
776
|
+
const spans = [];
|
|
777
|
+
let i = 0;
|
|
778
|
+
const n = line.length;
|
|
779
|
+
while (i < n) {
|
|
780
|
+
if (line[i] === commentChar) {
|
|
781
|
+
push(spans, "comment", line.slice(i));
|
|
782
|
+
return spans;
|
|
783
|
+
}
|
|
784
|
+
if (line[i] === '"' || line[i] === "'" || line[i] === "`") {
|
|
785
|
+
i = readString(line, i, line[i], spans);
|
|
786
|
+
continue;
|
|
787
|
+
}
|
|
788
|
+
if (/\d/.test(line[i])) {
|
|
789
|
+
let j = i;
|
|
790
|
+
while (j < n && /[\d._]/.test(line[j]))
|
|
791
|
+
j += 1;
|
|
792
|
+
push(spans, "number", line.slice(i, j));
|
|
793
|
+
i = j;
|
|
794
|
+
continue;
|
|
795
|
+
}
|
|
796
|
+
if (isIdentStart(line[i])) {
|
|
797
|
+
let j = i + 1;
|
|
798
|
+
while (j < n && isIdentCont(line[j]))
|
|
799
|
+
j += 1;
|
|
800
|
+
const word = line.slice(i, j);
|
|
801
|
+
let k = j;
|
|
802
|
+
while (k < n && /\s/.test(line[k]))
|
|
803
|
+
k += 1;
|
|
804
|
+
const hit = caseInsensitive
|
|
805
|
+
? [...keys].some((kw) => kw.toLowerCase() === word.toLowerCase())
|
|
806
|
+
: keys.has(word);
|
|
807
|
+
if (hit)
|
|
808
|
+
push(spans, "keyword", word);
|
|
809
|
+
else if (line[k] === "(")
|
|
810
|
+
push(spans, "function", word);
|
|
811
|
+
else
|
|
812
|
+
push(spans, "plain", word);
|
|
813
|
+
i = j;
|
|
814
|
+
continue;
|
|
815
|
+
}
|
|
816
|
+
if (/[{}()\[\];,.]/.test(line[i])) {
|
|
817
|
+
push(spans, "punctuation", line[i]);
|
|
818
|
+
i += 1;
|
|
819
|
+
continue;
|
|
820
|
+
}
|
|
821
|
+
push(spans, "plain", line[i]);
|
|
822
|
+
i += 1;
|
|
823
|
+
}
|
|
824
|
+
return spans;
|
|
825
|
+
}
|
|
826
|
+
function highlightPython(line, carry) {
|
|
827
|
+
if (carry.inTripleString) {
|
|
828
|
+
const q = carry.tripleQuote ?? '"""';
|
|
829
|
+
const end = line.indexOf(q);
|
|
830
|
+
if (end < 0)
|
|
831
|
+
return [{ kind: "string", text: line }];
|
|
832
|
+
carry.inTripleString = false;
|
|
833
|
+
carry.tripleQuote = undefined;
|
|
834
|
+
const spans = [{ kind: "string", text: line.slice(0, end + q.length) }];
|
|
835
|
+
if (end + q.length < line.length) {
|
|
836
|
+
spans.push(...highlightPython(line.slice(end + q.length), carry));
|
|
837
|
+
}
|
|
838
|
+
return spans;
|
|
839
|
+
}
|
|
840
|
+
if (line.includes('"""') || line.includes("'''")) {
|
|
841
|
+
const spans = [];
|
|
842
|
+
let i = 0;
|
|
843
|
+
const n = line.length;
|
|
844
|
+
while (i < n) {
|
|
845
|
+
if (line.startsWith('"""', i) || line.startsWith("'''", i)) {
|
|
846
|
+
const q = line.slice(i, i + 3);
|
|
847
|
+
const end = line.indexOf(q, i + 3);
|
|
848
|
+
if (end < 0) {
|
|
849
|
+
push(spans, "string", line.slice(i));
|
|
850
|
+
carry.inTripleString = true;
|
|
851
|
+
carry.tripleQuote = q;
|
|
852
|
+
return spans;
|
|
853
|
+
}
|
|
854
|
+
push(spans, "string", line.slice(i, end + 3));
|
|
855
|
+
i = end + 3;
|
|
856
|
+
continue;
|
|
857
|
+
}
|
|
858
|
+
if (line[i] === "#") {
|
|
859
|
+
push(spans, "comment", line.slice(i));
|
|
860
|
+
return spans;
|
|
861
|
+
}
|
|
862
|
+
// fall through one char via rest of hash highlighter
|
|
863
|
+
const rest = highlightHashCommentLang(line.slice(i), KW.py);
|
|
864
|
+
// only take until we'd re-enter — simpler: process char by char for non-triple
|
|
865
|
+
const sub = rest[0];
|
|
866
|
+
if (!sub) {
|
|
867
|
+
i += 1;
|
|
868
|
+
continue;
|
|
869
|
+
}
|
|
870
|
+
// process rest of line with hash highlighter but need to stop at triple
|
|
871
|
+
const piece = line.slice(i);
|
|
872
|
+
const triple = piece.search(/"""|'''/);
|
|
873
|
+
if (triple < 0) {
|
|
874
|
+
spans.push(...highlightHashCommentLang(piece, KW.py));
|
|
875
|
+
return spans;
|
|
876
|
+
}
|
|
877
|
+
if (triple > 0)
|
|
878
|
+
spans.push(...highlightHashCommentLang(piece.slice(0, triple), KW.py));
|
|
879
|
+
i += triple;
|
|
880
|
+
}
|
|
881
|
+
return spans;
|
|
882
|
+
}
|
|
883
|
+
return highlightHashCommentLang(line, KW.py);
|
|
884
|
+
}
|
|
885
|
+
function highlightPhp(line, carry) {
|
|
886
|
+
// PHP uses // /* # and $variables
|
|
887
|
+
const spans = highlightClike(line, KW.php, carry, { regex: false });
|
|
888
|
+
// color $ident as property
|
|
889
|
+
const out = [];
|
|
890
|
+
for (const s of spans) {
|
|
891
|
+
if (s.kind !== "plain") {
|
|
892
|
+
out.push(s);
|
|
893
|
+
continue;
|
|
894
|
+
}
|
|
895
|
+
const re = /(\$[A-Za-z_][A-Za-z0-9_]*)/g;
|
|
896
|
+
let last = 0;
|
|
897
|
+
let m;
|
|
898
|
+
let any = false;
|
|
899
|
+
while ((m = re.exec(s.text))) {
|
|
900
|
+
any = true;
|
|
901
|
+
if (m.index > last)
|
|
902
|
+
push(out, "plain", s.text.slice(last, m.index));
|
|
903
|
+
push(out, "property", m[1]);
|
|
904
|
+
last = m.index + m[1].length;
|
|
905
|
+
}
|
|
906
|
+
if (any) {
|
|
907
|
+
if (last < s.text.length)
|
|
908
|
+
push(out, "plain", s.text.slice(last));
|
|
909
|
+
}
|
|
910
|
+
else {
|
|
911
|
+
out.push(s);
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
return out;
|
|
915
|
+
}
|
|
916
|
+
function highlightLua(line, carry) {
|
|
917
|
+
// -- line comments, --[[ block ]]
|
|
918
|
+
if (carry.inBlockComment) {
|
|
919
|
+
const end = line.indexOf("]]");
|
|
920
|
+
if (end < 0)
|
|
921
|
+
return [{ kind: "comment", text: line }];
|
|
922
|
+
carry.inBlockComment = false;
|
|
923
|
+
const spans = [{ kind: "comment", text: line.slice(0, end + 2) }];
|
|
924
|
+
if (end + 2 < line.length)
|
|
925
|
+
spans.push(...highlightLua(line.slice(end + 2), carry));
|
|
926
|
+
return spans;
|
|
927
|
+
}
|
|
928
|
+
if (line.includes("--[[")) {
|
|
929
|
+
const start = line.indexOf("--[[");
|
|
930
|
+
const spans = [];
|
|
931
|
+
if (start > 0)
|
|
932
|
+
spans.push(...highlightHashCommentLang(line.slice(0, start), KW.lua));
|
|
933
|
+
// abuse hash with --
|
|
934
|
+
const end = line.indexOf("]]", start + 4);
|
|
935
|
+
if (end < 0) {
|
|
936
|
+
carry.inBlockComment = true;
|
|
937
|
+
spans.push({ kind: "comment", text: line.slice(start) });
|
|
938
|
+
return spans;
|
|
939
|
+
}
|
|
940
|
+
spans.push({ kind: "comment", text: line.slice(start, end + 2) });
|
|
941
|
+
if (end + 2 < line.length)
|
|
942
|
+
spans.push(...highlightLua(line.slice(end + 2), carry));
|
|
943
|
+
return spans;
|
|
944
|
+
}
|
|
945
|
+
// line --
|
|
946
|
+
const idx = line.indexOf("--");
|
|
947
|
+
if (idx >= 0) {
|
|
948
|
+
const before = line.slice(0, idx);
|
|
949
|
+
const spans = before ? highlightHashCommentLang(before, KW.lua) : [];
|
|
950
|
+
spans.push({ kind: "comment", text: line.slice(idx) });
|
|
951
|
+
return spans;
|
|
952
|
+
}
|
|
953
|
+
return highlightHashCommentLang(line, KW.lua);
|
|
954
|
+
}
|
|
955
|
+
function highlightHaskell(line, carry) {
|
|
956
|
+
if (carry.inBlockComment) {
|
|
957
|
+
const end = line.indexOf("-}");
|
|
958
|
+
if (end < 0)
|
|
959
|
+
return [{ kind: "comment", text: line }];
|
|
960
|
+
carry.inBlockComment = false;
|
|
961
|
+
const spans = [{ kind: "comment", text: line.slice(0, end + 2) }];
|
|
962
|
+
if (end + 2 < line.length)
|
|
963
|
+
spans.push(...highlightHaskell(line.slice(end + 2), carry));
|
|
964
|
+
return spans;
|
|
965
|
+
}
|
|
966
|
+
if (line.includes("{-")) {
|
|
967
|
+
const start = line.indexOf("{-");
|
|
968
|
+
const spans = [];
|
|
969
|
+
if (start > 0) {
|
|
970
|
+
// -- style via custom
|
|
971
|
+
const before = line.slice(0, start);
|
|
972
|
+
spans.push(...highlightHaskellLine(before));
|
|
973
|
+
}
|
|
974
|
+
const end = line.indexOf("-}", start + 2);
|
|
975
|
+
if (end < 0) {
|
|
976
|
+
carry.inBlockComment = true;
|
|
977
|
+
spans.push({ kind: "comment", text: line.slice(start) });
|
|
978
|
+
return spans;
|
|
979
|
+
}
|
|
980
|
+
spans.push({ kind: "comment", text: line.slice(start, end + 2) });
|
|
981
|
+
if (end + 2 < line.length)
|
|
982
|
+
spans.push(...highlightHaskell(line.slice(end + 2), carry));
|
|
983
|
+
return spans;
|
|
984
|
+
}
|
|
985
|
+
return highlightHaskellLine(line);
|
|
986
|
+
}
|
|
987
|
+
function highlightHaskellLine(line) {
|
|
988
|
+
const idx = line.indexOf("--");
|
|
989
|
+
if (idx >= 0) {
|
|
990
|
+
const spans = idx > 0 ? highlightHashCommentLang(line.slice(0, idx), KW.haskell) : [];
|
|
991
|
+
// wrong comment char — use plain keyword pass
|
|
992
|
+
spans.push({ kind: "comment", text: line.slice(idx) });
|
|
993
|
+
return spans;
|
|
994
|
+
}
|
|
995
|
+
return highlightHashCommentLang(line, KW.haskell);
|
|
996
|
+
}
|
|
997
|
+
function highlightLisp(line) {
|
|
998
|
+
const t = line.trimStart();
|
|
999
|
+
if (t.startsWith(";"))
|
|
1000
|
+
return [{ kind: "comment", text: line }];
|
|
1001
|
+
const spans = [];
|
|
1002
|
+
let i = 0;
|
|
1003
|
+
const n = line.length;
|
|
1004
|
+
while (i < n) {
|
|
1005
|
+
if (line[i] === ";") {
|
|
1006
|
+
push(spans, "comment", line.slice(i));
|
|
1007
|
+
return spans;
|
|
1008
|
+
}
|
|
1009
|
+
if (line[i] === '"') {
|
|
1010
|
+
i = readString(line, i, '"', spans);
|
|
1011
|
+
continue;
|
|
1012
|
+
}
|
|
1013
|
+
if (line[i] === "(" || line[i] === ")" || line[i] === "[" || line[i] === "]") {
|
|
1014
|
+
push(spans, "punctuation", line[i]);
|
|
1015
|
+
i += 1;
|
|
1016
|
+
continue;
|
|
1017
|
+
}
|
|
1018
|
+
if (isIdentStart(line[i]) || line[i] === ":" || line[i] === "*") {
|
|
1019
|
+
let j = i + 1;
|
|
1020
|
+
while (j < n && /[^\s()\[\]";]/.test(line[j]))
|
|
1021
|
+
j += 1;
|
|
1022
|
+
const word = line.slice(i, j);
|
|
1023
|
+
// first symbol after ( is function-ish
|
|
1024
|
+
const prev = spans[spans.length - 1]?.text;
|
|
1025
|
+
if (prev === "(")
|
|
1026
|
+
push(spans, "function", word);
|
|
1027
|
+
else if (word.startsWith(":"))
|
|
1028
|
+
push(spans, "property", word);
|
|
1029
|
+
else
|
|
1030
|
+
push(spans, "plain", word);
|
|
1031
|
+
i = j;
|
|
1032
|
+
continue;
|
|
1033
|
+
}
|
|
1034
|
+
if (/\d/.test(line[i])) {
|
|
1035
|
+
let j = i;
|
|
1036
|
+
while (j < n && /[\d./]/.test(line[j]))
|
|
1037
|
+
j += 1;
|
|
1038
|
+
push(spans, "number", line.slice(i, j));
|
|
1039
|
+
i = j;
|
|
1040
|
+
continue;
|
|
1041
|
+
}
|
|
1042
|
+
push(spans, "plain", line[i]);
|
|
1043
|
+
i += 1;
|
|
1044
|
+
}
|
|
1045
|
+
return spans;
|
|
1046
|
+
}
|
|
1047
|
+
function highlightMarkdown(line) {
|
|
1048
|
+
const t = line.trimStart();
|
|
1049
|
+
if (t.startsWith("#")) {
|
|
1050
|
+
return [{ kind: "keyword", text: line }];
|
|
1051
|
+
}
|
|
1052
|
+
if (t.startsWith("```") || t.startsWith("~~~")) {
|
|
1053
|
+
return [{ kind: "punctuation", text: line }];
|
|
1054
|
+
}
|
|
1055
|
+
if (t.startsWith(">")) {
|
|
1056
|
+
return [{ kind: "comment", text: line }];
|
|
1057
|
+
}
|
|
1058
|
+
if (t.startsWith("- ") || t.startsWith("* ") || /^\d+\.\s/.test(t)) {
|
|
1059
|
+
const spans = [];
|
|
1060
|
+
const indent = line.length - t.length;
|
|
1061
|
+
if (indent)
|
|
1062
|
+
push(spans, "plain", line.slice(0, indent));
|
|
1063
|
+
const m = t.match(/^([-*]|\d+\.)\s/);
|
|
1064
|
+
if (m) {
|
|
1065
|
+
push(spans, "keyword", m[0]);
|
|
1066
|
+
push(spans, "plain", t.slice(m[0].length));
|
|
1067
|
+
}
|
|
1068
|
+
else {
|
|
1069
|
+
push(spans, "plain", t);
|
|
1070
|
+
}
|
|
1071
|
+
return spans;
|
|
1072
|
+
}
|
|
1073
|
+
// inline `code` and **bold** lightly
|
|
1074
|
+
const spans = [];
|
|
1075
|
+
let i = 0;
|
|
1076
|
+
const n = line.length;
|
|
1077
|
+
while (i < n) {
|
|
1078
|
+
if (line[i] === "`") {
|
|
1079
|
+
const end = line.indexOf("`", i + 1);
|
|
1080
|
+
if (end > i) {
|
|
1081
|
+
push(spans, "string", line.slice(i, end + 1));
|
|
1082
|
+
i = end + 1;
|
|
1083
|
+
continue;
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
if (line.startsWith("**", i)) {
|
|
1087
|
+
const end = line.indexOf("**", i + 2);
|
|
1088
|
+
if (end > i) {
|
|
1089
|
+
push(spans, "keyword", line.slice(i, end + 2));
|
|
1090
|
+
i = end + 2;
|
|
1091
|
+
continue;
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
if (line[i] === "[") {
|
|
1095
|
+
const end = line.indexOf(")", i);
|
|
1096
|
+
if (end > i && line.includes("](", i)) {
|
|
1097
|
+
push(spans, "property", line.slice(i, end + 1));
|
|
1098
|
+
i = end + 1;
|
|
1099
|
+
continue;
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
push(spans, "plain", line[i]);
|
|
1103
|
+
i += 1;
|
|
1104
|
+
}
|
|
1105
|
+
return spans;
|
|
1106
|
+
}
|
|
1107
|
+
function highlightJsonLike(line) {
|
|
1108
|
+
const spans = [];
|
|
1109
|
+
let i = 0;
|
|
1110
|
+
const n = line.length;
|
|
1111
|
+
while (i < n) {
|
|
1112
|
+
const ch = line[i];
|
|
1113
|
+
if (ch === '"') {
|
|
1114
|
+
let j = i + 1;
|
|
1115
|
+
while (j < n) {
|
|
1116
|
+
if (line[j] === "\\") {
|
|
1117
|
+
j += 2;
|
|
1118
|
+
continue;
|
|
1119
|
+
}
|
|
1120
|
+
if (line[j] === '"') {
|
|
1121
|
+
j += 1;
|
|
1122
|
+
break;
|
|
1123
|
+
}
|
|
1124
|
+
j += 1;
|
|
1125
|
+
}
|
|
1126
|
+
let k = j;
|
|
1127
|
+
while (k < n && /\s/.test(line[k]))
|
|
1128
|
+
k += 1;
|
|
1129
|
+
push(spans, line[k] === ":" ? "property" : "string", line.slice(i, j));
|
|
1130
|
+
i = j;
|
|
1131
|
+
continue;
|
|
1132
|
+
}
|
|
1133
|
+
if (/\d/.test(ch) || (ch === "-" && line[i + 1] && /\d/.test(line[i + 1]))) {
|
|
1134
|
+
let j = i + 1;
|
|
1135
|
+
while (j < n && /[\d.eE+-]/.test(line[j]))
|
|
1136
|
+
j += 1;
|
|
1137
|
+
push(spans, "number", line.slice(i, j));
|
|
1138
|
+
i = j;
|
|
1139
|
+
continue;
|
|
1140
|
+
}
|
|
1141
|
+
if (line.startsWith("true", i) || line.startsWith("false", i) || line.startsWith("null", i)) {
|
|
1142
|
+
const w = line.startsWith("false", i) ? "false" : line.startsWith("true", i) ? "true" : "null";
|
|
1143
|
+
push(spans, "keyword", w);
|
|
1144
|
+
i += w.length;
|
|
1145
|
+
continue;
|
|
1146
|
+
}
|
|
1147
|
+
if (/[{}\[\]:,]/.test(ch)) {
|
|
1148
|
+
push(spans, "punctuation", ch);
|
|
1149
|
+
i += 1;
|
|
1150
|
+
continue;
|
|
1151
|
+
}
|
|
1152
|
+
push(spans, "plain", ch);
|
|
1153
|
+
i += 1;
|
|
1154
|
+
}
|
|
1155
|
+
return spans;
|
|
1156
|
+
}
|
|
1157
|
+
function highlightHtml(line, carry) {
|
|
1158
|
+
if (carry.inBlockComment || line.includes("<!--")) {
|
|
1159
|
+
if (carry.inBlockComment) {
|
|
1160
|
+
const end = line.indexOf("-->");
|
|
1161
|
+
if (end < 0)
|
|
1162
|
+
return [{ kind: "comment", text: line }];
|
|
1163
|
+
carry.inBlockComment = false;
|
|
1164
|
+
const spans = [{ kind: "comment", text: line.slice(0, end + 3) }];
|
|
1165
|
+
if (end + 3 < line.length)
|
|
1166
|
+
spans.push(...highlightHtml(line.slice(end + 3), carry));
|
|
1167
|
+
return spans;
|
|
1168
|
+
}
|
|
1169
|
+
const start = line.indexOf("<!--");
|
|
1170
|
+
if (start >= 0) {
|
|
1171
|
+
const spans = [];
|
|
1172
|
+
if (start > 0)
|
|
1173
|
+
spans.push(...highlightHtml(line.slice(0, start), carry));
|
|
1174
|
+
const end = line.indexOf("-->", start + 4);
|
|
1175
|
+
if (end < 0) {
|
|
1176
|
+
carry.inBlockComment = true;
|
|
1177
|
+
spans.push({ kind: "comment", text: line.slice(start) });
|
|
1178
|
+
return spans;
|
|
1179
|
+
}
|
|
1180
|
+
spans.push({ kind: "comment", text: line.slice(start, end + 3) });
|
|
1181
|
+
if (end + 3 < line.length)
|
|
1182
|
+
spans.push(...highlightHtml(line.slice(end + 3), carry));
|
|
1183
|
+
return spans;
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
const spans = [];
|
|
1187
|
+
let i = 0;
|
|
1188
|
+
const n = line.length;
|
|
1189
|
+
while (i < n) {
|
|
1190
|
+
if (line[i] === "<") {
|
|
1191
|
+
const close = line.indexOf(">", i);
|
|
1192
|
+
const end = close < 0 ? n : close + 1;
|
|
1193
|
+
spans.push(...highlightTag(line.slice(i, end)));
|
|
1194
|
+
i = end;
|
|
1195
|
+
continue;
|
|
1196
|
+
}
|
|
1197
|
+
let j = i + 1;
|
|
1198
|
+
while (j < n && line[j] !== "<")
|
|
1199
|
+
j += 1;
|
|
1200
|
+
push(spans, "plain", line.slice(i, j));
|
|
1201
|
+
i = j;
|
|
1202
|
+
}
|
|
1203
|
+
return spans;
|
|
1204
|
+
}
|
|
1205
|
+
function highlightTag(tag) {
|
|
1206
|
+
const spans = [];
|
|
1207
|
+
let i = 0;
|
|
1208
|
+
const n = tag.length;
|
|
1209
|
+
while (i < n) {
|
|
1210
|
+
const ch = tag[i];
|
|
1211
|
+
if (ch === "<" || ch === ">" || ch === "/") {
|
|
1212
|
+
push(spans, "punctuation", ch);
|
|
1213
|
+
i += 1;
|
|
1214
|
+
continue;
|
|
1215
|
+
}
|
|
1216
|
+
if (ch === '"' || ch === "'") {
|
|
1217
|
+
i = readString(tag, i, ch, spans);
|
|
1218
|
+
continue;
|
|
1219
|
+
}
|
|
1220
|
+
if (isIdentStart(ch)) {
|
|
1221
|
+
let j = i + 1;
|
|
1222
|
+
while (j < n && /[A-Za-z0-9_:-]/.test(tag[j]))
|
|
1223
|
+
j += 1;
|
|
1224
|
+
const word = tag.slice(i, j);
|
|
1225
|
+
const prev = spans[spans.length - 1]?.text;
|
|
1226
|
+
if (prev === "<" || prev === "/")
|
|
1227
|
+
push(spans, "keyword", word);
|
|
1228
|
+
else
|
|
1229
|
+
push(spans, "property", word);
|
|
1230
|
+
i = j;
|
|
1231
|
+
continue;
|
|
1232
|
+
}
|
|
1233
|
+
push(spans, "plain", ch);
|
|
1234
|
+
i += 1;
|
|
1235
|
+
}
|
|
1236
|
+
return spans;
|
|
1237
|
+
}
|
|
1238
|
+
function highlightYaml(line) {
|
|
1239
|
+
const trimmed = line.trimStart();
|
|
1240
|
+
if (trimmed.startsWith("#"))
|
|
1241
|
+
return [{ kind: "comment", text: line }];
|
|
1242
|
+
const spans = [];
|
|
1243
|
+
const indent = line.length - trimmed.length;
|
|
1244
|
+
if (indent)
|
|
1245
|
+
push(spans, "plain", line.slice(0, indent));
|
|
1246
|
+
if (trimmed.startsWith("- ")) {
|
|
1247
|
+
push(spans, "punctuation", "-");
|
|
1248
|
+
push(spans, "plain", " ");
|
|
1249
|
+
spans.push(...highlightYaml(trimmed.slice(2)));
|
|
1250
|
+
// fix indent double — simpler:
|
|
1251
|
+
return [
|
|
1252
|
+
...(indent ? [{ kind: "plain", text: line.slice(0, indent) }] : []),
|
|
1253
|
+
{ kind: "punctuation", text: "-" },
|
|
1254
|
+
{ kind: "plain", text: " " },
|
|
1255
|
+
...highlightJsonLike(trimmed.slice(2)),
|
|
1256
|
+
];
|
|
1257
|
+
}
|
|
1258
|
+
const colon = trimmed.indexOf(":");
|
|
1259
|
+
if (colon > 0) {
|
|
1260
|
+
push(spans, "property", trimmed.slice(0, colon));
|
|
1261
|
+
push(spans, "punctuation", ":");
|
|
1262
|
+
const rest = trimmed.slice(colon + 1);
|
|
1263
|
+
if (rest)
|
|
1264
|
+
spans.push(...highlightJsonLike(rest));
|
|
1265
|
+
return spans;
|
|
1266
|
+
}
|
|
1267
|
+
spans.push(...highlightJsonLike(trimmed));
|
|
1268
|
+
return spans;
|
|
1269
|
+
}
|
|
1270
|
+
function highlightIniToml(line) {
|
|
1271
|
+
const t = line.trimStart();
|
|
1272
|
+
if (t.startsWith("#") || t.startsWith(";"))
|
|
1273
|
+
return [{ kind: "comment", text: line }];
|
|
1274
|
+
if (t.startsWith("[") && t.includes("]")) {
|
|
1275
|
+
return [{ kind: "keyword", text: line }];
|
|
1276
|
+
}
|
|
1277
|
+
const eq = line.indexOf("=");
|
|
1278
|
+
if (eq > 0) {
|
|
1279
|
+
return [
|
|
1280
|
+
{ kind: "property", text: line.slice(0, eq) },
|
|
1281
|
+
{ kind: "operator", text: "=" },
|
|
1282
|
+
...highlightJsonLike(line.slice(eq + 1)),
|
|
1283
|
+
];
|
|
1284
|
+
}
|
|
1285
|
+
return highlightJsonLike(line);
|
|
1286
|
+
}
|
|
1287
|
+
function highlightDiff(line) {
|
|
1288
|
+
if (line.startsWith("+++") || line.startsWith("---") || line.startsWith("diff ") || line.startsWith("index ")) {
|
|
1289
|
+
return [{ kind: "keyword", text: line }];
|
|
1290
|
+
}
|
|
1291
|
+
if (line.startsWith("@@"))
|
|
1292
|
+
return [{ kind: "function", text: line }];
|
|
1293
|
+
if (line.startsWith("+"))
|
|
1294
|
+
return [{ kind: "string", text: line }];
|
|
1295
|
+
if (line.startsWith("-"))
|
|
1296
|
+
return [{ kind: "regex", text: line }];
|
|
1297
|
+
return [{ kind: "plain", text: line }];
|
|
1298
|
+
}
|
|
1299
|
+
/** List of extensions we explicitly map (for tests / docs). */
|
|
1300
|
+
export function supportedExtensions() {
|
|
1301
|
+
return Object.keys(EXT_FAMILY).sort();
|
|
1302
|
+
}
|
|
1303
|
+
//# sourceMappingURL=syntax-highlight.js.map
|