简体   繁体   English

html 中可编辑文本区域的语法高亮显示

[英]Syntax Highlighting for editable textarea in html

So I have a project that involves creating an html webapp that's similar to pastebin.所以我有一个项目涉及创建一个类似于 pastebin 的 html webapp。 And I have to add syntax highlighting but we're not allowed to used premade syntax highlighter or plugins.我必须添加语法高亮,但我们不允许使用预制的语法高亮或插件。 We have to do it from scratch.我们必须从头开始。 I know that I have to do it with javascript.我知道我必须用 javascript 来做。 Can anyone give me some insight on how I should create this syntax highlighting?谁能给我一些关于我应该如何创建这种语法突出显示的见解? I've only made some test for syntax highlighting from what I saw on yt, but mostly they are plugins我只是根据我在 yt 上看到的内容对语法高亮进行了一些测试,但它们大多是插件

Here is the code for the test.html这是测试的代码。html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
code {
    display:block;
    white-space: pre-wrap;
    border: 1px solid #000;
    padding: 10px;
    line-height: 1.5em;
    font-family: "Lucida Console", Monaco, monospace;
}
.code-str { color : #090; }
.code-elem{ 
    color: #F90;
}
</style>
<script>
    function syntaxhighlights() {
        var ca = document.getElementsByTagName("code");
        for(var i = 0; i < ca.length; i++ ){
            var data = ca[i].innerHTML;
            data = data.replace (/"(.*?)"/g, '<span class="code-str">&quot;$1&quot;</span>');
            data = data.replace (/&lt;(.*?)&gt;/g, '<span class="code-elem">&lt;$1&gt;</span>');
            ca[i].innerHTML = data;
        }
}
window.addEventListener("load", syntaxhighlights);      
</script>
</head>
<body>
    <h2>Code Example:</h2>
    <code>&lt;h2 id="h21"&gt;Welcome Visitors&lt;/h2&gt;
&lt;p&gt;When in Rome, do as the Romans do.&lt;/p&gt;
    </code> 
</body>

I have created a project involving syntax highlighting.我创建了一个涉及语法高亮的项目。 The best way is to use regex excessively.最好的方法是过度使用正则表达式。 You have to create classes for each token.您必须为每个令牌创建类。 You need a function to take the text and convert it into an html chunk.您需要 function 来获取文本并将其转换为 html 块。 Using String.replace you can format the given text.使用String.replace您可以格式化给定的文本。 Just create a render class.只需创建一个渲染 class。 Mine was something like that(It has been so long since I wrote it. Hope this helps):我的就是这样(我写它已经很久了。希望这会有所帮助):

jsx-parse-engine.js jsx-parse-engine.js

import ReactHtmlParser from 'react-html-parser'
import StyleSheet from '../styles/native/code.module.css'
import React from 'react'
import { insertArray, replaceString, updateArray } from './utility-functions'

// Add String.matchAll polyfill in case it is not implemented
;(() => {
    if (!String.prototype.matchAll) {
        String.prototype.matchAll = function (regex) {
            let match = regex.exec(this)
            const matches = []
            while (match !== null) {
                matches.push(match)
                match = regex.exec(this)
            }
            return matches
        }
    }
    console.log('matchAll polyfill has been configured.')
})()

const createJSXBuilder = (className) => (v) =>
    `<span class="${className}">${v}</span>`

const getMatchArray = (content, pattern, builder) => {
    let matchArray = []
    const results = Array.from(content.matchAll(pattern))
    for (const result of results) {
        const index = result.index
        const match = result[0]
        const length = match.length
        matchArray.push([index, length, match, builder])
    }
    return matchArray
}

const sortMatchArray = (matchArray) => {
    let sortedMatchedArray = []
    let g
    for (const matchItem of matchArray) {
        if (sortedMatchedArray.length === 0) {
            sortedMatchedArray.push(matchItem)
            continue
        }
        g = true
        for (let i = 0; i < sortedMatchedArray.length; i++) {
            if (matchItem[0] < sortedMatchedArray[i][0]) {
                sortedMatchedArray = insertArray(
                    sortedMatchedArray,
                    i,
                    matchItem
                )
                g = false
                break
            }
        }
        if (g) {
            sortedMatchedArray.push(matchItem)
        }
    }
    return sortedMatchedArray
}

const parse = (content, matchArray) => {
    let secretIndex = 0
    for (const match of matchArray) {
        const jsx = match[3](match[2])
        const beginIndex = match[0] + secretIndex
        content = replaceString(content, beginIndex, beginIndex + match[1], jsx)
        secretIndex += jsx.length - match[2].length
    }
    return content
}

export function parseSourceCodeToJSX(content) {
    let matchArray = []
    const newLine = /\n/g
    const tab = /\t/g
    const parserTokenMap = [
        [/@\w+\([\w, ]*\)\n/g, createJSXBuilder(StyleSheet.annotation)],
        [/(?<!(['"@]\w*\(?))[,():+\-*\[\];{}.!](?!\w*['"])/g, createJSXBuilder(StyleSheet.symbol)],
        [/\/\/.*/g, createJSXBuilder(StyleSheet.comment)],
        [/['"].*?['"]/g, createJSXBuilder(StyleSheet.string)],
        [/\b(?<!(['"]|\/\/ )\w*)\d+\.?\d*(?!\w*['"])\b/g, createJSXBuilder(StyleSheet.number)],
        [/(?<=\.)\w+(?=\()/g, createJSXBuilder(StyleSheet.method)],
        [/(?<=\.)\w+(?!\()\b/g, createJSXBuilder(StyleSheet.property)],
        [/\bthis(?=\.)/g, createJSXBuilder(StyleSheet.number)],
        [
            /\b(number|string|boolean|object|instanceof|typeof)\b/g,
            createJSXBuilder(StyleSheet.method),
        ],
        [/(&gt|&lt)/g, createJSXBuilder(StyleSheet.method)],
        [
            /(?<=&lt)\/?(?!number|string|boolean|object|instanceof|typeof)\w*(?=&gt)/g,
            createJSXBuilder(StyleSheet.method),
        ],
        [
            /\b(((?<! )import)|new|true|extends|super|false|from|function|break|case|return|const|=|let|default|((?<! )export)|class)\b/g,
            createJSXBuilder(StyleSheet.keyword),
        ],
    ]
    for (const parserItem of parserTokenMap) {
        matchArray = matchArray.concat(
            getMatchArray(content.slice(), parserItem[0], parserItem[1])
        )
    }
    matchArray = sortMatchArray(matchArray)
    let result = parse(content, matchArray)
    result = result.replace(tab, '<span class="space"></span>')
    result = result.replace(newLine, '<br />')
    return <div dangerouslySetInnerHTML={{ __html: result }} />
}

export function parseTextToJSX(content) {
    const newLine = /\n/g
    return <>{ReactHtmlParser(content.replace(newLine, '<br/>'))}</>
}

utility-functions.js实用功能.js

export function updateArray(arr, index, value) {
    return [...arr.slice(0, index), value, ...arr.slice(index + 1)]
}

export function insertArray(arr, index, value) {
    return [...arr.slice(0, index), value, ...arr.slice(index)]
}

export function replaceString(str, begin, end, value) {
    return str.substring(0, begin) + value + str.substring(end)
}

code.module.css代码.module.css

Contains styles for token classes

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM