Skip to content

Commit

Permalink
Version 0.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
FIameCaster committed Aug 18, 2023
1 parent 98fa3a4 commit 2a4d284
Show file tree
Hide file tree
Showing 25 changed files with 416 additions and 148 deletions.
3 changes: 2 additions & 1 deletion package/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "prism-code-editor",
"version": "0.0.6",
"version": "0.1.0",
"type": "module",
"description": "Lightweight, extensible code editor for the web using Prism",
"main": "./dist/index.js",
Expand All @@ -24,6 +24,7 @@
"./languages/python": "./dist/languages/python.js",
"./languages/xml": "./dist/languages/xml.js",
"./match-brackets": "./dist/extensions/matchBrackets.js",
"./match-tags": "./dist/extensions/matchTags.js",
"./commands": "./dist/extensions/commands.js",
"./cursor": "./dist/extensions/cursor.js",
"./prism-core": "./dist/prismCore.js",
Expand Down
8 changes: 6 additions & 2 deletions package/src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ const createEditor = (
value = "",
activeLineNumber: number,
removed = false,
handleSelecionChange = true
handleSelecionChange = true,
tokens: (Prism.Token | string)[] = []

const scrollContainer = <HTMLDivElement>editorTemplate.cloneNode(true),
wrapper = <HTMLDivElement>scrollContainer.firstChild,
Expand Down Expand Up @@ -92,7 +93,7 @@ const createEditor = (
closingTags = "",
env = <TokenizeEnv>{ language, code, grammar }
Prism.hooks.run("before-tokenize", env)
const tokens = (env.tokens = Prism.tokenize(env.code, env.grammar))
tokens = (env.tokens = Prism.tokenize(env.code, env.grammar))
Prism.hooks.run("after-tokenize", env)
dispatchEvent("tokenize", env)

Expand Down Expand Up @@ -219,6 +220,9 @@ const createEditor = (
get removed() {
return removed
},
get tokens() {
return tokens
},
inputCommandMap,
keyCommandMap,
setOptions,
Expand Down
42 changes: 22 additions & 20 deletions package/src/extensions/guides.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@ import { createTemplate } from "../core"
import { Extension, PrismEditor } from "../types"

const template = createTemplate(
'<style>.guide-indents div{width:1px;position:absolute;background:var(--bg-guide-indent)}.guide-indents .active{background:var(--bg-guide-indent-active)}</style><div class="guide-indents" style="position:relative;"> </div>',
'<div class="guide-indents" style="position:relative;display:inline-block"> </div>',
"left:var(--padding-left)",
)

const indentTemplate = createTemplate(
"",
"width:1px;position:absolute;background:var(--bg-guide-indent)",
)

export interface IndentGuides extends Extension {
/** Collection of all the guide lines. */
readonly lines: HTMLCollectionOf<HTMLDivElement>
Expand All @@ -15,12 +20,11 @@ export interface IndentGuides extends Extension {

/** Adds indent guides to an editor. Does not work with word wrap. */
export const indentGuides = (): IndentGuides => {
let currentTabSize: number,
let tabSize: number,
prevLength = 0,
lineIndentMap: number[],
active = -1,
currentEditor: PrismEditor,
currentWrap: boolean
currentEditor: PrismEditor

const lines: HTMLDivElement[] = [],
indents: number[][] = [],
Expand All @@ -34,15 +38,15 @@ export const indentGuides = (): IndentGuides => {
l = newIndents.length

for (let i = 0, prev: number[] = [], next = newIndents[0]; next; i++) {
const { style } = lines[i] || (lines[i] = document.createElement("div")),
const { style } = lines[i] || (lines[i] = <HTMLDivElement>indentTemplate.cloneNode()),
[top, height, left] = next,
old = indents[i]

next = newIndents[i + 1]

if (top != old?.[0]) style.top = top + "00%"
if (height != old?.[1]) style.height = height + "00%"
if (left != old?.[2]) style.left = left + "ch"
if (left != old?.[2]) style.left = left + "00%"

const isSingleIndent = prev[0] != top && next?.[0] != top,
isSingleOutdent = prev[0] + prev[1] != top + height && next?.[0] + next?.[1] != top + height
Expand Down Expand Up @@ -87,7 +91,7 @@ export const indentGuides = (): IndentGuides => {
results[p++] = stack[j] = [
emptyPos == -1 || j > prevIndent ? i : emptyPos,
0,
j++ * currentTabSize,
j++ * tabSize,
]
}
emptyPos = -1
Expand All @@ -104,28 +108,26 @@ export const indentGuides = (): IndentGuides => {
result = 0
if (l == -1) return -1
for (let i = 0; i < l; ) {
result += text[i++] == "\t" ? currentTabSize - (result % currentTabSize) : 1
result += text[i++] == "\t" ? tabSize - (result % tabSize) : 1
}
return Math.ceil(result / currentTabSize)
return Math.ceil(result / tabSize)
}

return {
lines: <HTMLCollectionOf<HTMLDivElement>>guideHeight.children,
get indentLevels() {
return indentLevels
},
update(editor, { wordWrap = false, tabSize }) {
let wrapChanged = currentWrap != (currentWrap = wordWrap),
tabChanged = currentTabSize != (currentTabSize = tabSize || 2)

if (currentEditor != (currentEditor = editor) || wrapChanged) {
wordWrap ? container.remove() : editor.overlays.append(container)

const listener = wordWrap ? editor.removeListener : editor.addListener
listener("update", update)
listener("selectionChange", updateActive)
update(editor, options) {
if (!currentEditor) {
currentEditor = editor
editor.overlays.append(container)
editor.addListener("update", update)
editor.addListener("selectionChange", updateActive)
}
if (!wordWrap && (wrapChanged || tabChanged)) update(editor.value), updateActive()
container.style.display = options.wordWrap ? "none" : ""

if (tabSize != (tabSize = options.tabSize || 2)) update(editor.value), updateActive()
},
}
}
118 changes: 54 additions & 64 deletions package/src/extensions/matchBrackets.ts
Original file line number Diff line number Diff line change
@@ -1,65 +1,4 @@
import { Extension, PrismEditor, TokenizeEnv } from ".."

const pairBrackets = (
tokens: (Prism.Token | string)[],
openingRegex: RegExp,
closingRegex: RegExp,
pairRegex: RegExp,
) => {
let position = 0
const stack: [number, Prism.Token][] = []
const positions: number[][] = []
const add = (token: Prism.Token, classes: string) => {
let alias = token.alias
token.alias = (alias ? (Array.isArray(alias) ? alias.join(" ") : alias) + " " : "") + classes
}
const matchPairs = (tokens: (Prism.Token | string)[]) => {
for (let i = 0, l = tokens.length; i < l; i++) {
const token = tokens[i]
if (typeof token != "string") {
const { content, type } = token

if (Array.isArray(content)) {
matchPairs(content)
continue
}
if (
typeof content == "string" &&
(type == "punctuation" || token.alias == "punctuation") &&
type != "regex"
) {
if (openingRegex.test(content)) stack.push([position, token])
else if (closingRegex.test(content)) {
let i = stack.length,
found: boolean

while (i) {
const [position1, token1] = stack[--i]
if (pairRegex.test(token1.content + content)) {
for (let arr = stack.splice(i), j = 1; j < arr.length; )
add(arr[j++][1], "bracket-error")
if (position - position1 == 1) {
token1.content += content
token.content = ""
}
positions.push([position1, position])
add(token1, "bracket-open bracket-level-" + (i % 12))
add(token, "bracket-close bracket-level-" + (i % 12))
found = true
break
}
}
found! || add(token, "bracket-error")
}
}
}
position += token.length
}
}
matchPairs(tokens)
stack.forEach(item => add(item[1], "bracket-error"))
return positions
}
import { Extension, PrismEditor } from ".."

export interface BracketMatcher extends Extension {
/** Array of the positions of all the brackets. */
Expand Down Expand Up @@ -126,11 +65,62 @@ export const matchBrackets = (
add("blur", selectionChange)
add("focus", selectionChange)
addListener("selectionChange", selectionChange)
addListener("tokenize", (env: TokenizeEnv) => {
addListener("tokenize", env => {
if (env.language != "regex") {
toggleBrackets(activeID, false)
activeID = -1
pairs = pairBrackets(env.tokens, openingRegex, closingRegex, pairRegex)
pairs = []
let position = 0
let stack: [number, Prism.Token][] = []
let add = (token: Prism.Token, classes: string) => {
let alias = token.alias
token.alias = (alias ? (Array.isArray(alias) ? alias.join(" ") : alias) + " " : "") + classes
}
let matchPairs = (tokens: (Prism.Token | string)[]) => {
for (let i = 0, l = tokens.length; i < l; i++) {
const token = tokens[i]
if (typeof token != "string") {
const { content, type } = token

if (Array.isArray(content)) {
matchPairs(content)
continue
}
if (
typeof content == "string" &&
(type == "punctuation" || token.alias == "punctuation") &&
type != "regex"
) {
if (openingRegex.test(content)) stack.push([position, token])
else if (closingRegex.test(content)) {
let i = stack.length,
found: boolean

while (i) {
const [position1, token1] = stack[--i]
if (pairRegex.test(token1.content + content)) {
for (let arr = stack.splice(i), j = 1; j < arr.length; )
add(arr[j++][1], "bracket-error")
if (position - position1 == 1) {
token1.content += content
token.content = ""
}
pairs.push([position1, position])
add(token1, "bracket-open bracket-level-" + (i % 12))
add(token, "bracket-close bracket-level-" + (i % 12))
found = true
break
}
}
found! || add(token, "bracket-error")
}
}
}
position += token.length
}
}
matchPairs(env.tokens)
stack.forEach(item => add(item[1], "bracket-error"))
secondOrder = pairs.slice().sort((a, b) => a[0] - b[0])
}
})
Expand Down
Loading

0 comments on commit 2a4d284

Please sign in to comment.