├── .gitignore
├── LICENSE
├── README.md
├── index.html
├── package.json
├── pnpm-lock.yaml
├── scripts
└── build.mjs
├── src
├── core.ts
├── extensions
│ ├── autocomplete
│ │ ├── css
│ │ │ ├── data.ts
│ │ │ └── index.ts
│ │ ├── filter.ts
│ │ ├── icons.css
│ │ ├── index.ts
│ │ ├── javascript
│ │ │ ├── index.ts
│ │ │ ├── jsdoc.ts
│ │ │ ├── jsx.ts
│ │ │ ├── keywords.ts
│ │ │ ├── reactData.ts
│ │ │ └── snippets.ts
│ │ ├── markup
│ │ │ ├── data.ts
│ │ │ ├── index.ts
│ │ │ └── svgData.ts
│ │ ├── style.css
│ │ ├── tooltip.ts
│ │ ├── types.ts
│ │ └── utils.ts
│ ├── commands.ts
│ ├── copy-button
│ │ ├── copy.css
│ │ └── index.ts
│ ├── cursor.ts
│ ├── folding
│ │ ├── folding.css
│ │ └── index.ts
│ ├── guides.ts
│ ├── match-brackets
│ │ ├── highlight.ts
│ │ └── index.ts
│ ├── match-tags.ts
│ ├── overscroll.ts
│ └── search
│ │ ├── api.ts
│ │ ├── index.ts
│ │ ├── invisibles.css
│ │ ├── invisibles.ts
│ │ ├── replace.ts
│ │ ├── search.css
│ │ ├── search.ts
│ │ ├── selection.ts
│ │ └── widget.ts
├── index.ts
├── languages
│ ├── abap.ts
│ ├── abnf.ts
│ ├── actionscript.ts
│ ├── ada.ts
│ ├── agda.ts
│ ├── al.ts
│ ├── antlr4.ts
│ ├── apacheconf.ts
│ ├── apex.ts
│ ├── apl.ts
│ ├── applescript.ts
│ ├── aql.ts
│ ├── arduino.ts
│ ├── arff.ts
│ ├── arturo.ts
│ ├── asciidoc.ts
│ ├── asm.ts
│ ├── aspnet.ts
│ ├── autohotkey.ts
│ ├── autoit.ts
│ ├── avisynth.ts
│ ├── avro-idl.ts
│ ├── awk.ts
│ ├── bash.ts
│ ├── basic.ts
│ ├── batch.ts
│ ├── bbj.ts
│ ├── bicep.ts
│ ├── birb.ts
│ ├── bison.ts
│ ├── bqn.ts
│ ├── brightscript.ts
│ ├── bro.ts
│ ├── bsl.ts
│ ├── cfscript.ts
│ ├── chaiscript.ts
│ ├── cil.ts
│ ├── cilk.ts
│ ├── clike.ts
│ ├── clojure.ts
│ ├── cmake.ts
│ ├── cobol.ts
│ ├── coffeescript.ts
│ ├── common.ts
│ ├── concurnas.ts
│ ├── cooklang.ts
│ ├── coq.ts
│ ├── cshtml.ts
│ ├── css.ts
│ ├── cue.ts
│ ├── cypher.ts
│ ├── dataweave.ts
│ ├── dax.ts
│ ├── dhall.ts
│ ├── django.ts
│ ├── dns-zone-file.ts
│ ├── docker.ts
│ ├── dot.ts
│ ├── ebnf.ts
│ ├── editorconfig.ts
│ ├── eiffel.ts
│ ├── ejs.ts
│ ├── elixir.ts
│ ├── elm.ts
│ ├── erb.ts
│ ├── erlang.ts
│ ├── etlua.ts
│ ├── excel-formula.ts
│ ├── factor.ts
│ ├── false.ts
│ ├── firestore-security-rules.ts
│ ├── fortran.ts
│ ├── fsharp.ts
│ ├── ftl.ts
│ ├── gap.ts
│ ├── gcode.ts
│ ├── gdscript.ts
│ ├── gettext.ts
│ ├── gherkin.ts
│ ├── git.ts
│ ├── glsl.ts
│ ├── gml.ts
│ ├── gn.ts
│ ├── go-module.ts
│ ├── gradle.ts
│ ├── graphql.ts
│ ├── groovy.ts
│ ├── haml.ts
│ ├── handlebars.ts
│ ├── haskell.ts
│ ├── hcl.ts
│ ├── hoon.ts
│ ├── html.ts
│ ├── ichigojam.ts
│ ├── icon.ts
│ ├── iecst.ts
│ ├── ignore.ts
│ ├── index.ts
│ ├── inform7.ts
│ ├── ini.ts
│ ├── io.ts
│ ├── j.ts
│ ├── jolie.ts
│ ├── jq.ts
│ ├── json.ts
│ ├── jsx.ts
│ ├── julia.ts
│ ├── keepalived.ts
│ ├── keyman.ts
│ ├── kotlin.ts
│ ├── kumir.ts
│ ├── kusto.ts
│ ├── latex.ts
│ ├── latte.ts
│ ├── lilypond.ts
│ ├── linker-script.ts
│ ├── liquid.ts
│ ├── lisp.ts
│ ├── livescript.ts
│ ├── llvm.ts
│ ├── lolcode.ts
│ ├── lua.ts
│ ├── magma.ts
│ ├── makefile.ts
│ ├── mata.ts
│ ├── matlab.ts
│ ├── maxscript.ts
│ ├── mel.ts
│ ├── mermaid.ts
│ ├── metafont.ts
│ ├── mizar.ts
│ ├── mongodb.ts
│ ├── monkey.ts
│ ├── moonscript.ts
│ ├── n1ql.ts
│ ├── n4js.ts
│ ├── nand2tetris-hdl.ts
│ ├── naniscript.ts
│ ├── neon.ts
│ ├── nevod.ts
│ ├── nginx.ts
│ ├── nim.ts
│ ├── nix.ts
│ ├── nsis.ts
│ ├── objectivec.ts
│ ├── ocaml.ts
│ ├── odin.ts
│ ├── opencl.ts
│ ├── openqasm.ts
│ ├── oz.ts
│ ├── parigp.ts
│ ├── parser.ts
│ ├── pascal.ts
│ ├── peoplecode.ts
│ ├── perl.ts
│ ├── php.ts
│ ├── plant-uml.ts
│ ├── powerquery.ts
│ ├── powershell.ts
│ ├── processing.ts
│ ├── prolog.ts
│ ├── promql.ts
│ ├── properties.ts
│ ├── protobuf.ts
│ ├── psl.ts
│ ├── pug.ts
│ ├── puppet.ts
│ ├── pure.ts
│ ├── purebasic.ts
│ ├── python.ts
│ ├── q.ts
│ ├── qml.ts
│ ├── qore.ts
│ ├── qsharp.ts
│ ├── r.ts
│ ├── reason.ts
│ ├── rego.ts
│ ├── rescript.ts
│ ├── rest.ts
│ ├── rip.ts
│ ├── roboconf.ts
│ ├── robotframework.ts
│ ├── ruby.ts
│ ├── rust.ts
│ ├── sas.ts
│ ├── scala.ts
│ ├── scheme.ts
│ ├── shared
│ │ └── index.ts
│ ├── smali.ts
│ ├── smalltalk.ts
│ ├── smarty.ts
│ ├── sml.ts
│ ├── solidity.ts
│ ├── solution-file.ts
│ ├── soy.ts
│ ├── splunk-spl.ts
│ ├── sqf.ts
│ ├── sql.ts
│ ├── squirrel.ts
│ ├── stan.ts
│ ├── stata.ts
│ ├── stylus.ts
│ ├── supercollider.ts
│ ├── swift.ts
│ ├── systemd.ts
│ ├── tcl.ts
│ ├── textile.ts
│ ├── toml.ts
│ ├── tremor.ts
│ ├── tt2.ts
│ ├── turtle.ts
│ ├── twig.ts
│ ├── typoscript.ts
│ ├── unrealscript.ts
│ ├── uorazor.ts
│ ├── v.ts
│ ├── vala.ts
│ ├── vbnet.ts
│ ├── velocity.ts
│ ├── verilog.ts
│ ├── vhdl.ts
│ ├── vim.ts
│ ├── visual-basic.ts
│ ├── warpscript.ts
│ ├── wasm.ts
│ ├── web-idl.ts
│ ├── wgsl.ts
│ ├── wiki.ts
│ ├── wolfram.ts
│ ├── wren.ts
│ ├── xeora.ts
│ ├── xml.ts
│ ├── xojo.ts
│ ├── xquery.ts
│ ├── yaml.ts
│ ├── yang.ts
│ └── zig.ts
├── layout.css
├── prism
│ ├── index.d.ts
│ ├── index.js
│ ├── languages
│ │ ├── abap.ts
│ │ ├── abnf.ts
│ │ ├── actionscript.ts
│ │ ├── ada.ts
│ │ ├── agda.ts
│ │ ├── al.ts
│ │ ├── antlr4.ts
│ │ ├── apacheconf.ts
│ │ ├── apex.ts
│ │ ├── apl.ts
│ │ ├── applescript.ts
│ │ ├── aql.ts
│ │ ├── arduino.ts
│ │ ├── arff.ts
│ │ ├── armasm.ts
│ │ ├── arturo.ts
│ │ ├── asciidoc.ts
│ │ ├── asm6502.ts
│ │ ├── asmatmel.ts
│ │ ├── aspnet.ts
│ │ ├── autohotkey.ts
│ │ ├── autoit.ts
│ │ ├── avisynth.ts
│ │ ├── avro-idl.ts
│ │ ├── awk.ts
│ │ ├── bash.ts
│ │ ├── basic.ts
│ │ ├── batch.ts
│ │ ├── bbcode.ts
│ │ ├── bbj.ts
│ │ ├── bicep.ts
│ │ ├── birb.ts
│ │ ├── bison.ts
│ │ ├── bnf.ts
│ │ ├── bqn.ts
│ │ ├── brainfuck.ts
│ │ ├── brightscript.ts
│ │ ├── bro.ts
│ │ ├── bsl.ts
│ │ ├── c.ts
│ │ ├── cfscript.ts
│ │ ├── chaiscript.ts
│ │ ├── cil.ts
│ │ ├── cilkc.ts
│ │ ├── cilkcpp.ts
│ │ ├── clike.ts
│ │ ├── clojure.ts
│ │ ├── cmake.ts
│ │ ├── cobol.ts
│ │ ├── coffeescript.ts
│ │ ├── common.ts
│ │ ├── concurnas.ts
│ │ ├── cooklang.ts
│ │ ├── coq.ts
│ │ ├── cpp.ts
│ │ ├── crystal.ts
│ │ ├── csharp.ts
│ │ ├── cshtml.ts
│ │ ├── csp.ts
│ │ ├── css-extras.ts
│ │ ├── css.ts
│ │ ├── csv.ts
│ │ ├── cue.ts
│ │ ├── cypher.ts
│ │ ├── d.ts
│ │ ├── dart.ts
│ │ ├── dataweave.ts
│ │ ├── dax.ts
│ │ ├── dhall.ts
│ │ ├── diff.ts
│ │ ├── django.ts
│ │ ├── dns-zone-file.ts
│ │ ├── docker.ts
│ │ ├── dot.ts
│ │ ├── ebnf.ts
│ │ ├── editorconfig.ts
│ │ ├── eiffel.ts
│ │ ├── ejs.ts
│ │ ├── elixir.ts
│ │ ├── elm.ts
│ │ ├── erb.ts
│ │ ├── erlang.ts
│ │ ├── etlua.ts
│ │ ├── excel-formula.ts
│ │ ├── factor.ts
│ │ ├── false.ts
│ │ ├── firestore-security-rules.ts
│ │ ├── flow.ts
│ │ ├── fortran.ts
│ │ ├── fsharp.ts
│ │ ├── ftl.ts
│ │ ├── gap.ts
│ │ ├── gcode.ts
│ │ ├── gdscript.ts
│ │ ├── gedcom.ts
│ │ ├── gettext.ts
│ │ ├── gherkin.ts
│ │ ├── git.ts
│ │ ├── glsl.ts
│ │ ├── gml.ts
│ │ ├── gn.ts
│ │ ├── go-module.ts
│ │ ├── go.ts
│ │ ├── gradle.ts
│ │ ├── graphql.ts
│ │ ├── groovy.ts
│ │ ├── haml.ts
│ │ ├── handlebars.ts
│ │ ├── haskell.ts
│ │ ├── haxe.ts
│ │ ├── hcl.ts
│ │ ├── hlsl.ts
│ │ ├── hoon.ts
│ │ ├── hpkp.ts
│ │ ├── hsts.ts
│ │ ├── http.ts
│ │ ├── ichigojam.ts
│ │ ├── icon.ts
│ │ ├── icu-message-format.ts
│ │ ├── idris.ts
│ │ ├── iecst.ts
│ │ ├── ignore.ts
│ │ ├── index.ts
│ │ ├── inform7.ts
│ │ ├── ini.ts
│ │ ├── io.ts
│ │ ├── j.ts
│ │ ├── java.ts
│ │ ├── javadoc.ts
│ │ ├── javadoclike.ts
│ │ ├── javascript.ts
│ │ ├── javastacktrace.ts
│ │ ├── jexl.ts
│ │ ├── jolie.ts
│ │ ├── jq.ts
│ │ ├── js-templates.ts
│ │ ├── jsdoc.ts
│ │ ├── json.ts
│ │ ├── json5.ts
│ │ ├── jsonp.ts
│ │ ├── jsstacktrace.ts
│ │ ├── jsx.ts
│ │ ├── julia.ts
│ │ ├── keepalived.ts
│ │ ├── keyman.ts
│ │ ├── kotlin.ts
│ │ ├── kumir.ts
│ │ ├── kusto.ts
│ │ ├── latex.ts
│ │ ├── latte.ts
│ │ ├── less.ts
│ │ ├── lilypond.ts
│ │ ├── linker-script.ts
│ │ ├── liquid.ts
│ │ ├── lisp.ts
│ │ ├── livescript.ts
│ │ ├── llvm.ts
│ │ ├── log.ts
│ │ ├── lolcode.ts
│ │ ├── lua.ts
│ │ ├── magma.ts
│ │ ├── makefile.ts
│ │ ├── markdown.ts
│ │ ├── markup.ts
│ │ ├── mata.ts
│ │ ├── matlab.ts
│ │ ├── maxscript.ts
│ │ ├── mel.ts
│ │ ├── mermaid.ts
│ │ ├── metafont.ts
│ │ ├── mizar.ts
│ │ ├── mongodb.ts
│ │ ├── monkey.ts
│ │ ├── moonscript.ts
│ │ ├── n1ql.ts
│ │ ├── n4js.ts
│ │ ├── nand2tetris-hdl.ts
│ │ ├── naniscript.ts
│ │ ├── nasm.ts
│ │ ├── neon.ts
│ │ ├── nevod.ts
│ │ ├── nginx.ts
│ │ ├── nim.ts
│ │ ├── nix.ts
│ │ ├── nsis.ts
│ │ ├── objectivec.ts
│ │ ├── ocaml.ts
│ │ ├── odin.ts
│ │ ├── opencl.ts
│ │ ├── openqasm.ts
│ │ ├── oz.ts
│ │ ├── parigp.ts
│ │ ├── parser.ts
│ │ ├── pascal.ts
│ │ ├── pascaligo.ts
│ │ ├── pcaxis.ts
│ │ ├── peoplecode.ts
│ │ ├── perl.ts
│ │ ├── php-extras.ts
│ │ ├── php.ts
│ │ ├── phpdoc.ts
│ │ ├── plant-uml.ts
│ │ ├── plsql.ts
│ │ ├── powerquery.ts
│ │ ├── powershell.ts
│ │ ├── processing.ts
│ │ ├── prolog.ts
│ │ ├── promql.ts
│ │ ├── properties.ts
│ │ ├── protobuf.ts
│ │ ├── psl.ts
│ │ ├── pug.ts
│ │ ├── puppet.ts
│ │ ├── pure.ts
│ │ ├── purebasic.ts
│ │ ├── purescript.ts
│ │ ├── python.ts
│ │ ├── q.ts
│ │ ├── qml.ts
│ │ ├── qore.ts
│ │ ├── qsharp.ts
│ │ ├── r.ts
│ │ ├── racket.ts
│ │ ├── reason.ts
│ │ ├── regex.ts
│ │ ├── rego.ts
│ │ ├── renpy.ts
│ │ ├── rescript.ts
│ │ ├── rest.ts
│ │ ├── rip.ts
│ │ ├── roboconf.ts
│ │ ├── robotframework.ts
│ │ ├── ruby.ts
│ │ ├── rust.ts
│ │ ├── sas.ts
│ │ ├── sass.ts
│ │ ├── scala.ts
│ │ ├── scheme.ts
│ │ ├── scss.ts
│ │ ├── shell-session.ts
│ │ ├── smali.ts
│ │ ├── smalltalk.ts
│ │ ├── smarty.ts
│ │ ├── sml.ts
│ │ ├── solidity.ts
│ │ ├── solution-file.ts
│ │ ├── soy.ts
│ │ ├── sparql.ts
│ │ ├── splunk-spl.ts
│ │ ├── sqf.ts
│ │ ├── sql.ts
│ │ ├── squirrel.ts
│ │ ├── stan.ts
│ │ ├── stata.ts
│ │ ├── stylus.ts
│ │ ├── supercollider.ts
│ │ ├── swift.ts
│ │ ├── systemd.ts
│ │ ├── t4-cs.ts
│ │ ├── t4-vb.ts
│ │ ├── tap.ts
│ │ ├── tcl.ts
│ │ ├── textile.ts
│ │ ├── toml.ts
│ │ ├── tremor.ts
│ │ ├── tsx.ts
│ │ ├── tt2.ts
│ │ ├── turtle.ts
│ │ ├── twig.ts
│ │ ├── typescript.ts
│ │ ├── typoscript.ts
│ │ ├── unrealscript.ts
│ │ ├── uorazor.ts
│ │ ├── uri.ts
│ │ ├── v.ts
│ │ ├── vala.ts
│ │ ├── vbnet.ts
│ │ ├── velocity.ts
│ │ ├── verilog.ts
│ │ ├── vhdl.ts
│ │ ├── vim.ts
│ │ ├── visual-basic.ts
│ │ ├── warpscript.ts
│ │ ├── wasm.ts
│ │ ├── web-idl.ts
│ │ ├── wgsl.ts
│ │ ├── wiki.ts
│ │ ├── wolfram.ts
│ │ ├── wren.ts
│ │ ├── xeora.ts
│ │ ├── xml-doc.ts
│ │ ├── xml.ts
│ │ ├── xojo.ts
│ │ ├── xquery.ts
│ │ ├── yaml.ts
│ │ ├── yang.ts
│ │ └── zig.ts
│ ├── utils.d.ts
│ └── utils.js
├── rtl-layout.css
├── scrollbar.css
├── setups.ts
├── testsite
│ ├── App.tsx
│ ├── examples.ts
│ ├── index.tsx
│ └── style.css
├── themes
│ ├── atom-one-dark.css
│ ├── dracula.css
│ ├── github-dark-dimmed.css
│ ├── github-dark.css
│ ├── github-light.css
│ ├── index.ts
│ ├── night-owl.css
│ ├── prism-okaidia.css
│ ├── prism-solarized-light.css
│ ├── prism-tomorrow.css
│ ├── prism-twilight.css
│ ├── prism.css
│ ├── vs-code-dark.css
│ └── vs-code-light.css
├── tooltips.tsx
├── types.ts
└── utils
│ ├── index.ts
│ ├── local.ts
│ └── other.ts
├── tsconfig.json
└── vite.config.ts
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 FIameCaster
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Solid prism editor
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "solid-prism-editor",
3 | "version": "1.2.0",
4 | "type": "module",
5 | "description": "Lightweight, extensible code editor component for SolidJS apps",
6 | "main": "./dist/index.js",
7 | "types": "./dist/index.d.ts",
8 | "exports": {
9 | ".": "./dist/index.js",
10 | "./prism": "./dist/prism/index.js",
11 | "./prism/utils": "./dist/prism/utils/index.js",
12 | "./guides": "./dist/extensions/guides.js",
13 | "./copy-button": "./dist/extensions/copy-button/index.js",
14 | "./copy-button.css": "./dist/copy.css",
15 | "./code-folding.css": "./dist/folding.css",
16 | "./scrollbar.css": "./dist/scrollbar.css",
17 | "./autocomplete.css": "./dist/autocomplete.css",
18 | "./autocomplete-icons.css": "./dist/autocomplete-icons.css",
19 | "./utils": "./dist/utils/index.js",
20 | "./layout.css": "./dist/layout.css",
21 | "./rtl-layout.css": "./dist/rtl-layout.css",
22 | "./themes/*.css": "./dist/themes/*.css",
23 | "./themes": "./dist/themes/index.js",
24 | "./languages": "./dist/languages/index.js",
25 | "./languages/*": "./dist/languages/*.js",
26 | "./prism/languages": "./dist/prism/languages/index.js",
27 | "./prism/languages/*": "./dist/prism/languages/*.js",
28 | "./match-brackets": "./dist/extensions/match-brackets/index.js",
29 | "./highlight-brackets": "./dist/extensions/match-brackets/highlight.js",
30 | "./match-tags": "./dist/extensions/match-tags.js",
31 | "./setups": "./dist/setups.js",
32 | "./tooltips": "./dist/tooltips.js",
33 | "./autocomplete": "./dist/extensions/autocomplete/index.js",
34 | "./autocomplete/css": "./dist/extensions/autocomplete/css/index.js",
35 | "./autocomplete/markup": "./dist/extensions/autocomplete/markup/index.js",
36 | "./autocomplete/javascript": "./dist/extensions/autocomplete/javascript/index.js",
37 | "./commands": "./dist/extensions/commands.js",
38 | "./cursor": "./dist/extensions/cursor.js",
39 | "./code-folding": "./dist/extensions/folding/index.js",
40 | "./overscroll": "./dist/extensions/overscroll.js",
41 | "./search": "./dist/extensions/search/index.js",
42 | "./search/api": "./dist/extensions/search/api.js",
43 | "./search.css": "./dist/search.css",
44 | "./invisibles.css": "./dist/invisibles.css"
45 | },
46 | "typesVersions": {
47 | "*": {
48 | "*": [
49 | "./dist/*"
50 | ]
51 | }
52 | },
53 | "files": [
54 | "dist/*"
55 | ],
56 | "scripts": {
57 | "start": "vite",
58 | "dev": "vite",
59 | "build": "vite build && node scripts/build.mjs",
60 | "serve": "vite preview"
61 | },
62 | "license": "MIT",
63 | "devDependencies": {
64 | "@types/node": "^20.12.6",
65 | "prism-code-editor": "^3.4.0",
66 | "solid-devtools": "^0.29.2",
67 | "solid-js": "^1.8.11",
68 | "typescript": "^5.3.3",
69 | "vite": "^5.3.3",
70 | "vite-plugin-dts": "^3.8.1",
71 | "vite-plugin-solid": "^2.8.2"
72 | },
73 | "peerDependencies": {
74 | "solid-js": "*"
75 | },
76 | "keywords": [
77 | "editor",
78 | "code editor",
79 | "textarea",
80 | "solid",
81 | "highlight",
82 | "prismjs"
83 | ],
84 | "author": "FlameCaster",
85 | "repository": {
86 | "type": "git",
87 | "url": "git+https://github.com/FIameCaster/solid-prism-editor.git"
88 | },
89 | "sideEffects": [
90 | "*.css",
91 | "./dist/languages/*",
92 | "./dist/prism/languages/*",
93 | "./dist/jsx-*"
94 | ],
95 | "packageManager": "pnpm@9.0.4+sha1.b198ac6d38244fd829253720f9daafd6a606834d"
96 | }
97 |
--------------------------------------------------------------------------------
/scripts/build.mjs:
--------------------------------------------------------------------------------
1 | import * as fs from "node:fs/promises"
2 |
3 | const themes = [
4 | "atom-one-dark",
5 | "dracula",
6 | "github-dark-dimmed",
7 | "github-dark",
8 | "github-light",
9 | "night-owl",
10 | "prism-okaidia",
11 | "prism-solarized-light",
12 | "prism-twilight",
13 | "prism-tomorrow",
14 | "prism",
15 | "vs-code-dark",
16 | "vs-code-light",
17 | ]
18 |
19 | let themeMod = await fs.readFile("dist/themes/index.js", "utf-8")
20 | const regex = RegExp(`^(${themes.join("|")})(-\\w+)\.js$`)
21 | const entries = await fs.readdir("dist", { withFileTypes: true })
22 |
23 | for (const entry of entries) {
24 | const match = entry.name.match(regex)
25 | if (match) {
26 | themeMod = themeMod.replace(match[2], "")
27 | fs.rename(`dist/${entry.name}`, `dist/${match[1]}.js`)
28 | }
29 | }
30 |
31 | fs.writeFile("dist/themes/index.js", themeMod)
32 |
33 | const dummyModule = `/** Used for autocompletion. This module doesn't have a default export. */
34 | declare const _: never;
35 | export default _;
36 | `
37 |
38 | ;["dist/prism/languages/", "dist/languages/"].forEach(path => {
39 | fs.readdir(path).then(entries =>
40 | entries.forEach(entry => {
41 | if (entry.slice(-2) == "js") {
42 | const name = entry.slice(0, -3)
43 | fs.writeFile(path + name + ".d.ts", dummyModule)
44 | }
45 | }),
46 | )
47 | })
48 |
--------------------------------------------------------------------------------
/src/extensions/autocomplete/filter.ts:
--------------------------------------------------------------------------------
1 | import { CompletionFilter } from "./types"
2 |
3 | /**
4 | * Fuzzy filter that only requires that the option includes all the characters in the
5 | * query string in order with any number of character between each.
6 | *
7 | * Occurrences that result in score penalties:
8 | * - Skipping characters in the option.
9 | * - The case of the characters doesn't match.
10 | * - The match doesn't start at the beginning.
11 | * - The option is longer than the query.
12 | */
13 | const fuzzyFilter: CompletionFilter = (query: string, option: string) => {
14 | const optionLen = option.length
15 | const queryLen = query.length
16 |
17 | if (queryLen > optionLen) return
18 | if (queryLen == 1 || queryLen == optionLen) return strictFilter(query, option)
19 |
20 | const queryLc = query.toLowerCase()
21 | const optionLc = option.toLowerCase()
22 | const matched: number[] = []
23 | const fullMatch = optionLc.indexOf(queryLc)
24 |
25 | let score = 0
26 | let i = 0
27 | let prevPos = 0
28 | let j = 0
29 | for (; i < queryLen; i++) {
30 | const char = queryLc[i]
31 | const pos = fullMatch > -1 ? i + fullMatch : optionLc.indexOf(char, prevPos)
32 | const hasSkipped = pos > prevPos
33 |
34 | if (pos < 0) return
35 | if (hasSkipped) score -= 800
36 | if (hasSkipped || !j) {
37 | matched[j++] = pos
38 | matched[j++] = pos + 1
39 | } else {
40 | matched[j - 1] = pos + 1
41 | }
42 |
43 | // Add a penalty if the query and option had different case
44 | if (((char != query[i])) ^ ((optionLc[pos] != option[pos]))) score -= 100
45 | prevPos = pos + 1
46 | }
47 |
48 | return [score - optionLen - (queryLen < optionLen ? 100 : 0), matched]
49 | }
50 |
51 | /**
52 | * Strict filter that requires the option to start with the query string.
53 | *
54 | * Occurrences that result in score penalties:
55 | * - The case of the query and the start of the option is different.
56 | * - The option is longer than the query.
57 | */
58 | const strictFilter: CompletionFilter = (query: string, option: string) => {
59 | const optionLen = option.length
60 | const queryLen = query.length
61 |
62 | if (queryLen > optionLen) return
63 |
64 | const start = option.slice(0, queryLen)
65 | const score = start == query ? 0 : query.toLowerCase() == start.toLowerCase() ? -200 : null
66 | if (score == null) return
67 |
68 | return [query ? score - optionLen - (queryLen < optionLen ? 100 : 0) : 0, [0, queryLen]]
69 | }
70 |
71 | export { fuzzyFilter, strictFilter }
72 |
--------------------------------------------------------------------------------
/src/extensions/autocomplete/icons.css:
--------------------------------------------------------------------------------
1 | @import "prism-code-editor/autocomplete-icons.css";
2 |
--------------------------------------------------------------------------------
/src/extensions/autocomplete/index.ts:
--------------------------------------------------------------------------------
1 | /** @module autocomplete */
2 |
3 | export { autoComplete, registerCompletions } from "./tooltip"
4 | export { fuzzyFilter, strictFilter } from "./filter"
5 | export { findWords, completeSnippets } from "./utils"
6 | export * from "./types"
7 |
--------------------------------------------------------------------------------
/src/extensions/autocomplete/javascript/jsdoc.ts:
--------------------------------------------------------------------------------
1 | import { getClosestToken } from "../../../utils"
2 | import { Completion, CompletionSource } from "../types"
3 |
4 | const tags: Completion[] =
5 | "abstract,access,alias,argument,async,augments,author,borrows,callback,class,classdesc,constant,constructor,constructs,copyright,default,deprecated,description,emits,enum,event,example,exports,extends,external,field,file,fileoverview,fires,function,generator,global,hideconstructor,host,ignore,implements,import,inheritdoc,inner,instance,interface,kind,lends,license,link,linkcode,linkplain,listens,member,memberof,method,mixes,mixin,module,name,namespace,overload,override,package,param,private,prop,property,protected,public,readonly,requires,returns,satisfies,see,since,static,summary,template,this,throws,todo,tutorial,type,typedef,var,variation,version,virtual,yields"
6 | .split(",")
7 | .map(label => ({ label, icon: "keyword" }))
8 |
9 | const jsDocCompletion: CompletionSource = (context, editor) => {
10 | if (
11 | getClosestToken(editor, ".doc-comment", 0, 0, context.pos) &&
12 | /@[a-z]*$/.test(context.lineBefore)
13 | ) {
14 | return {
15 | from: context.before.lastIndexOf("@") + 1,
16 | options: tags,
17 | }
18 | }
19 | }
20 |
21 | export { jsDocCompletion }
22 |
--------------------------------------------------------------------------------
/src/extensions/autocomplete/javascript/jsx.ts:
--------------------------------------------------------------------------------
1 | import { JSContext } from "./index.js"
2 | import { AttributeConfig, Completion, CompletionSource, TagConfig } from "../types.js"
3 | import { optionsFromKeys } from "../utils.js"
4 |
5 | /**
6 | * Completion source that adds autocompletion for JSX tags.
7 | * @param tags Object mapping tag-names to completable attributes for that tag.
8 | * @param globalAttributes Completable attributes shared by all tags.
9 | * @returns A Completion source. Requires a JavaScript context to work.
10 | */
11 | const jsxTagCompletion = (
12 | tags: TagConfig,
13 | globalAttributes: AttributeConfig,
14 | ): CompletionSource => {
15 | const tagOptions = optionsFromKeys(tags, "property")
16 | const attrOptions = optionsFromKeys(globalAttributes, "enum")
17 |
18 | return ({ tagMatch, explicit }) => {
19 | if (tagMatch && (explicit || !/\s/.test(tagMatch[0].slice(-1)))) {
20 | let [tag, tagName, lastAttr, lastAttrValue] = tagMatch
21 | let start = tagMatch.index
22 | let from = start + 1
23 | let options: Completion[] | undefined | 0 = tagOptions
24 |
25 | if (/[\s/]/.test(tagMatch[0])) {
26 | let tagAttrs = tags[tagName]
27 | from = start + tag.search(/[^\s="'{}]*$/)
28 |
29 | if (lastAttrValue) {
30 | options = (globalAttributes[lastAttr] || tagAttrs?.[lastAttr])?.map(val => ({
31 | label: val,
32 | icon: "unit",
33 | }))
34 | } else {
35 | options =
36 | tag.slice(-1) == "=" || !tagAttrs
37 | ? 0
38 | : attrOptions.concat(optionsFromKeys(tagAttrs, "enum"))
39 | }
40 | }
41 |
42 | if (options) {
43 | return {
44 | from,
45 | options,
46 | }
47 | }
48 | }
49 | }
50 | }
51 |
52 | export { jsxTagCompletion }
53 |
--------------------------------------------------------------------------------
/src/extensions/autocomplete/javascript/keywords.ts:
--------------------------------------------------------------------------------
1 | import { JSContext } from "./index.js"
2 | import { Completion, CompletionSource } from "../types.js"
3 |
4 | const jsKeyWords: Completion[] =
5 | "as,await,break,case,catch,class,const,continue,debugger,default,delete,do,else,export,extends,false,finally,for,function,if,import,in,instanceof,let,new,null,of,package,return,static,super,switch,this,throw,true,try,typeof,undefined,var,void,while,with,yield"
6 | .split(",")
7 | .map(name => ({ label: name, icon: "keyword" }))
8 |
9 | const tsKeywords: Completion[] = jsKeyWords.concat(
10 | "abstract,any,asserts,boolean,declare,enum,infer,interface,is,keyof,module,namespace,never,number,private,protected,public,readonly,string,symbol,type,unknown"
11 | .split(",")
12 | .map(name => ({ label: name, icon: "keyword" })),
13 | )
14 |
15 | /**
16 | * Completion source that adds autocompletion for JS/TS keywords.
17 | */
18 | const completeKeywords: CompletionSource = ({ path, explicit, language, pos }) => {
19 | if (path?.length == 1 && (path[0] || explicit)) {
20 | return {
21 | from: pos - path[0].length,
22 | options: language[0] == "t" ? tsKeywords : jsKeyWords,
23 | }
24 | }
25 | }
26 |
27 | export { completeKeywords }
28 |
--------------------------------------------------------------------------------
/src/extensions/autocomplete/javascript/snippets.ts:
--------------------------------------------------------------------------------
1 | import { Completion } from "../types.js"
2 |
3 | const jsSnipets: Completion[] = [
4 | {
5 | label: "log",
6 | insert: "console.log()\n",
7 | tabStops: [12, 12, 14],
8 | icon: "snippet",
9 | detail: "Log to the console",
10 | },
11 | {
12 | label: "warn",
13 | insert: "console.warn()\n",
14 | tabStops: [13, 13, 15],
15 | icon: "snippet",
16 | detail: "Log warning to the console",
17 | },
18 | {
19 | label: "error",
20 | insert: "console.error()\n",
21 | tabStops: [14, 14, 16],
22 | icon: "snippet",
23 | detail: "Log error to the console",
24 | },
25 | {
26 | label: "import",
27 | insert: 'import { } from "module"\n',
28 | tabStops: [9, 9, 18, 24, 26],
29 | icon: "snippet",
30 | detail: "Import Statement",
31 | },
32 | {
33 | label: "function",
34 | insert: "function name(params) {\n\t\n}",
35 | tabStops: [9, 13, 14, 20, 25],
36 | icon: "snippet",
37 | detail: "Function Statement",
38 | },
39 | {
40 | label: "class",
41 | insert: "class name {\n\tconstructor(params) {\n\t\t\n\t}\n}",
42 | tabStops: [6, 10, 26, 32, 38],
43 | icon: "snippet",
44 | detail: "Class Definition",
45 | },
46 | {
47 | label: "throw",
48 | insert: 'throw new Error("")',
49 | tabStops: [17],
50 | icon: "snippet",
51 | detail: "Throw Exception",
52 | },
53 | {
54 | label: "trycatch",
55 | insert: "try {\n\t\n} catch (error) {\n\t\n}",
56 | tabStops: [7, 7, 17, 22, 27],
57 | icon: "snippet",
58 | detail: "Try-Catch Statement",
59 | },
60 | {
61 | label: "for",
62 | insert: "for (let index = 0; index < array.length; index++) {\n\t\n}",
63 | tabStops: [9, 14, 20, 25, 28, 33, 42, 47, 54],
64 | icon: "snippet",
65 | detail: "For Loop",
66 | },
67 | {
68 | label: "forof",
69 | insert: "for (const item of iterable) {\n\t\n}",
70 | tabStops: [11, 15, 19, 27, 32],
71 | icon: "snippet",
72 | detail: "For-Of Loop",
73 | },
74 | {
75 | label: "forin",
76 | insert: "for (const key in object) {\n\t\n}",
77 | tabStops: [11, 14, 18, 24, 29],
78 | icon: "snippet",
79 | detail: "For-In Loop",
80 | },
81 | {
82 | label: "forawaitof",
83 | insert: "for await (const item of iterable) {\n\t\n}",
84 | tabStops: [17, 21, 25, 33, 38],
85 | icon: "snippet",
86 | detail: "For-Await-Of Loop",
87 | },
88 | {
89 | label: "if",
90 | insert: "if () {\n\t\n}",
91 | tabStops: [4, 4, 9],
92 | icon: "snippet",
93 | detail: "If Statement",
94 | },
95 | {
96 | label: "ifelse",
97 | insert: "if () {\n\t\n} else {\n\t\n}",
98 | tabStops: [4, 4, 9, 9, 20],
99 | icon: "snippet",
100 | detail: "If-Else Statement",
101 | },
102 | {
103 | label: "while",
104 | insert: "while () {\n\t\n}",
105 | tabStops: [7, 7, 12],
106 | icon: "snippet",
107 | detail: "While Statement",
108 | },
109 | {
110 | label: "dowhile",
111 | insert: "do {\n\t\n} while ()",
112 | tabStops: [6, 6, 16],
113 | icon: "snippet",
114 | detail: "Do-While Statement",
115 | },
116 | {
117 | label: "switch",
118 | insert: "switch () {\n\t\n}",
119 | tabStops: [8, 8, 13],
120 | icon: "snippet",
121 | detail: "Switch Statement",
122 | },
123 | ]
124 |
125 | export { jsSnipets }
126 |
--------------------------------------------------------------------------------
/src/extensions/autocomplete/markup/index.ts:
--------------------------------------------------------------------------------
1 | /** @module autocomplete/markup */
2 |
3 | import { PrismEditor } from "../../.."
4 | import { getClosestToken } from "../../../utils"
5 | import {
6 | AttributeConfig,
7 | Completion,
8 | CompletionContext,
9 | CompletionSource,
10 | TagConfig,
11 | } from "../types"
12 | import { optionsFromKeys } from "../utils"
13 |
14 | const tagPattern =
15 | /<$|<(?![!\d])([^\s/=>$<%]+)(?:\s(?:\s*([^\s/"'=>]+)(?:\s*=\s*(?!\s)(?:"[^"]*(?:"|$)|'[^']*(?:'|$)|[^\s"'=>]+(?!\S))?|(?![^\s=])))*\s*)?$/
16 |
17 | /**
18 | * `false` is returned if completion shouldn't happen at the current position.
19 | * `null` is returned if the cursor isn't in a tag.
20 | *
21 | * If completion should happen and the cursor is in a tag, a match array is
22 | * returned. The match has two capturing groups; the tag's name and the last attribute's
23 | * name.
24 | */
25 | const getTagMatch = ({ explicit, before, pos }: CompletionContext, editor: PrismEditor) => {
26 | return getClosestToken(editor, ".comment,.cdata,.prolog,.doctype", 0, 0, pos) ||
27 | (!explicit && /\s/.test(before.slice(-1)))
28 | ? false
29 | : tagPattern.exec(before)
30 | }
31 |
32 | /**
33 | * Completion source that adds auto completion for HTML tags.
34 | * @param tags Object mapping tag-names to completable attributes for that tag.
35 | * @param globalAttributes Completable attributes shared by all tags.
36 | * @returns A Completion source.
37 | */
38 | const markupCompletion = (tags: TagConfig, globalAttributes: AttributeConfig): CompletionSource => {
39 | const tagOptions = optionsFromKeys(tags, "property")
40 | const attrOptions = optionsFromKeys(globalAttributes, "enum")
41 |
42 | return (context, editor) => {
43 | const tagMatch = getTagMatch(context, editor)
44 |
45 | if (tagMatch) {
46 | let [tag, tagName, lastAttr] = tagMatch
47 | let start = tagMatch.index
48 | let from = start + 1
49 | let options: Completion[] | undefined = tagOptions
50 |
51 | if (/\s/.test(tag)) {
52 | let tagAttrs = tags[tagName]
53 | from = start + tag.search(/[^\s"'=]*$/)
54 |
55 | if (/=\s*(?:"[^"]*|'[^']*|[^\s"'=]*)$/.test(tag)) {
56 | options = (globalAttributes[lastAttr] || tagAttrs?.[lastAttr])?.map(val => ({
57 | label: val,
58 | icon: "unit",
59 | }))
60 | } else {
61 | options = tagAttrs ? attrOptions.concat(optionsFromKeys(tagAttrs, "enum")) : attrOptions
62 | }
63 | }
64 |
65 | if (options) {
66 | return {
67 | from,
68 | options,
69 | }
70 | }
71 | }
72 | }
73 | }
74 |
75 | export { htmlTags, globalHtmlAttributes } from "./data.js"
76 | export { svgTags, globalSvgAttributes } from "./svgData.js"
77 | export { markupCompletion, getTagMatch }
78 |
--------------------------------------------------------------------------------
/src/extensions/autocomplete/style.css:
--------------------------------------------------------------------------------
1 | @import "prism-code-editor/autocomplete.css";
2 |
--------------------------------------------------------------------------------
/src/extensions/autocomplete/utils.ts:
--------------------------------------------------------------------------------
1 | import { PrismEditor } from "../.."
2 | import { Token, TokenStream } from "../../prism"
3 | import { matchTemplate } from "../search/search"
4 | import { Completion, CompletionContext, CompletionSource } from "./types"
5 |
6 | const optionsFromKeys = (obj: object, icon?: string): Completion[] =>
7 | Object.keys(obj).map(tag => ({ label: tag, icon }))
8 |
9 | const updateNode = (node: Text, text: string) => {
10 | if (node.data != text) node.data = text
11 | }
12 |
13 | const updateMatched = (container: HTMLElement, matched: number[], text: string) => {
14 | let nodes = container.childNodes
15 | let nodeCount = nodes.length - 1
16 | let pos = 0
17 | let i = 0
18 | let l = matched.length
19 |
20 | for (; i < l; ) {
21 | if (i >= nodeCount) {
22 | nodes[i].before("", matchTemplate())
23 | }
24 | updateNode(nodes[i] as Text, text.slice(pos, (pos = matched[i++])))
25 | updateNode(nodes[i].firstChild as Text, text.slice(pos, (pos = matched[i++])))
26 | }
27 | for (; nodeCount > i; ) {
28 | nodes[--nodeCount].remove()
29 | }
30 | updateNode(nodes[l] as Text, text.slice(pos))
31 | }
32 |
33 | /**
34 | * Completion source that returns a list of snippets if `path` property of the context
35 | * is present and only contains a single string.
36 | * @param snippets Snippets to complete.
37 | */
38 | const completeSnippets = (snippets: Completion[]): CompletionSource<{ path: string[] | null }> => {
39 | return ({ path, explicit, pos }) => {
40 | if (path?.length == 1 && (path[0] || explicit)) {
41 | return {
42 | from: pos - path[0].length,
43 | options: snippets,
44 | }
45 | }
46 | }
47 | }
48 |
49 | /**
50 | * Utility that searches the editor's {@link TokenStream} for strings.
51 | * @param context Current completion context.
52 | * @param editor Editor to search in.
53 | * @param filter Function used to filter tokens you want to search in. Is called with the
54 | * type of the token and its starting position. If the filter returns true, the token
55 | * will be searched.
56 | * @param pattern Pattern used to search for words.
57 | * @param init Words to initialize the result with.
58 | * @param tokensOnly If `true` only the text of tokens whoose `content` is a string will
59 | * be searched. If not any string inside the {@link TokenStream} can be searched.
60 | * @returns An array with found identifers/words.
61 | */
62 | const findWords = (
63 | context: CompletionContext,
64 | editor: PrismEditor,
65 | filter: (type: string, start: number) => boolean,
66 | pattern: RegExp,
67 | init?: Iterable,
68 | tokensOnly?: boolean,
69 | ) => {
70 | const cursorPos = context.pos
71 | const language = context.language
72 | const result = new Set(init)
73 | const search = (tokens: TokenStream, pos: number, isCorrectLang: boolean) => {
74 | let i = 0
75 | let token: string | Token
76 | if (isCorrectLang) {
77 | for (; (token = tokens[i++]); ) {
78 | if (typeof token == "string") {
79 | if (!tokensOnly) match(token, pos)
80 | } else {
81 | const type = token.type
82 | const content = token.content
83 | if ((token.alias || type).slice(0, 9) != "language-" && filter(type, pos)) {
84 | if (Array.isArray(content)) {
85 | search(content, pos, true)
86 | } else match(content, pos)
87 | }
88 | }
89 | pos += token.length
90 | }
91 | } else {
92 | for (; (token = tokens[i++]); ) {
93 | if (typeof token != "string") {
94 | const type = token.type
95 | const content = token.content
96 | if (Array.isArray(content)) {
97 | const aliasType = token.alias || type
98 | search(
99 | content,
100 | pos,
101 | aliasType.slice(0, 9) == "language-" ? aliasType.slice(9) == language : false,
102 | )
103 | }
104 | }
105 | pos += token.length
106 | }
107 | }
108 | }
109 | const match = (token: string, pos: number) => {
110 | let match: RegExpExecArray | null
111 | while ((match = pattern.exec(token))) {
112 | let start = pos + match.index
113 | let str = match[0]
114 | if (start > cursorPos || start + str.length < cursorPos) result.add(str)
115 | }
116 | }
117 |
118 | search(editor.tokens(), 0, language == editor.props.language)
119 |
120 | return [...result]
121 | }
122 |
123 | export { optionsFromKeys, updateMatched, updateNode, findWords, completeSnippets }
124 |
--------------------------------------------------------------------------------
/src/extensions/copy-button/copy.css:
--------------------------------------------------------------------------------
1 | @import "prism-code-editor/copy-button.css";
2 |
--------------------------------------------------------------------------------
/src/extensions/copy-button/index.ts:
--------------------------------------------------------------------------------
1 | import { template as _template } from "solid-js/web"
2 | import { Extension } from "../../types"
3 |
4 | const template = _template(
5 | '