├── .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 | '