Initial commit

This commit is contained in:
admin
2025-12-08 14:39:07 +08:00
commit 9d4f78656b
782 changed files with 66418 additions and 0 deletions

View File

@@ -0,0 +1,26 @@
# highlight
功能:代码块高亮显示
支持平台:
| 微信小程序 | QQ 小程序 | 百度小程序 | 支付宝小程序 | 头条小程序 | uni-app |
|:---:|:---:|:---:|:---:|:---:|:---:|
| √ | √ | √ | √ | √ | √ |
说明:
大小:*≈16KB*
编辑 *plugins/highlight/config.js* 顶部的选项,可以选择是否需要以下功能:
- *copyByLongPress* 是否需要长按代码块时显示复制代码内容菜单(*uni-app nvue* 暂不支持)
- *showLanguageName* 是否在代码块右上角显示语言的名称
- *showLineNumber* 是否在左侧显示行号
> 修改该配置后需要重新生成组件包,在构建后的组件包中修改配置无法生效
引入本插件后,*html* 中符合以下格式的 *pre* 将被高亮处理:
```html
<!-- pre 中内含一个 code并在 pre 或 code 的 class 中设置 language- -->
<pre><code class="language-css">p { color: red }</code></pre>
```
> 与 *editable* 插件共用时,编辑状态下,不会进行高亮,可以直接修改代码文本
> 本插件的高亮功能依赖于 [prismjs](https://prismjs.com/),默认配置中仅支持 *html*、*css*、*c-like*、*javascript* 语言和 *Tomorrow Night* 主题,如果需要更多语言或更换主题请前往 [官网](https://prismjs.com/download.html) 下载对应的 *prism.min.js* 和 *prism.css* 并替换 *plugins/highlight/* 目录下的文件

View File

@@ -0,0 +1,5 @@
module.exports = {
copyByLongPress: false, // 是否需要长按代码块时显示复制代码内容菜单
showLanguageName: false, // 是否在代码块右上角显示语言的名称
showLineNumber: false // 是否显示行号
}

View File

@@ -0,0 +1,96 @@
/**
* @fileoverview highlight 插件
* Include prismjs (https://prismjs.com)
*/
const prism = require('./prism.min')
const config = require('./config')
const Parser = require('../parser')
function Highlight (vm) {
this.vm = vm
}
Highlight.prototype.onParse = function (node, vm) {
if (node.name === 'pre') {
if (vm.options.editable) {
node.attrs.class = (node.attrs.class || '') + ' hl-pre'
return
}
let i
for (i = node.children.length; i--;) {
if (node.children[i].name === 'code') break
}
if (i === -1) return
const code = node.children[i]
let className = code.attrs.class + ' ' + node.attrs.class
i = className.indexOf('language-')
if (i === -1) {
i = className.indexOf('lang-')
if (i === -1) {
className = 'language-text'
i = 9
} else {
i += 5
}
} else {
i += 9
}
let j
for (j = i; j < className.length; j++) {
if (className[j] === ' ') break
}
const lang = className.substring(i, j)
if (code.children.length) {
const text = this.vm.getText(code.children).replace(/&amp;/g, '&')
if (!text) return
if (node.c) {
node.c = undefined
}
if (prism.languages[lang]) {
code.children = (new Parser(this.vm).parse(
// 加一层 pre 保留空白符
'<pre>' + prism.highlight(text, prism.languages[lang], lang).replace(/token /g, 'hl-') + '</pre>'))[0].children
}
node.attrs.class = 'hl-pre'
code.attrs.class = 'hl-code'
if (config.showLanguageName) {
node.children.push({
name: 'div',
attrs: {
class: 'hl-language',
style: 'user-select:none'
},
children: [{
type: 'text',
text: lang
}]
})
}
if (config.copyByLongPress) {
node.attrs.style += (node.attrs.style || '') + ';user-select:none'
node.attrs['data-content'] = text
vm.expose()
}
if (config.showLineNumber) {
const line = text.split('\n').length; const children = []
for (let k = line; k--;) {
children.push({
name: 'span',
attrs: {
class: 'span'
}
})
}
node.children.push({
name: 'span',
attrs: {
class: 'line-numbers-rows'
},
children
})
}
}
}
}
module.exports = Highlight

View File

@@ -0,0 +1,88 @@
const config = require('../config')
const build = {
import: 'prism.css',
handler (file) {
if (file.path.includes('prism.css')) {
// 将标签名选择器和属性选择器转为 class 选择器(组件内仅支持 class 选择器)
file.contents = Buffer.from(file.contents.toString().replace(/pre([[)])/g, '.hl-pre$1').replace(/code/g, '.hl-code').replace(/\[class\*="?language-"?\]/g, '').replace(/:not[^,}]+[,}]*/g, '').replace(/\.token\./g, '.hl-'))
}
}
}
if (config.showLanguageName || config.showLineNumber) {
// pre 内部的 code 进行滚动,避免行号和语言名称跟随滚动
build.style = `.hl-pre {
position: relative;
}
.hl-code {
overflow: auto;
display: block;
}`
}
if (config.copyByLongPress) {
build.template = '<rich-text wx:if="{{n.attrs[\'data-content\']}}" nodes="{{[n]}}" data-content="{{n.attrs[\'data-content\']}}" data-lang="{{n.attrs[\'data-lang\']}}" bindlongpress="copyCode" />'
build.methods = {
copyCode (e) {
wx.showActionSheet({
itemList: ['复制代码'],
success: () =>
wx.setClipboardData({
data: e.currentTarget.dataset.content
})
})
}
}
}
if (config.showLanguageName) {
build.style = (build.style || '') +
`.hl-language {
font-size: 12px;
font-weight: 600;
position: absolute;
right: 8px;
text-align: right;
top: 3px;
}
.hl-pre {
padding-top: 1.5em;
}`
}
if (config.showLineNumber) {
build.style = (build.style || '') +
`.hl-pre {
font-size: 14px;
padding-left: 3.8em;
counter-reset: linenumber;
}
.line-numbers-rows {
position: absolute;
pointer-events: none;
top: ${config.showLanguageName ? 1.5 : 1}em;
font-size: 100%;
left: 0;
width: 3em; /* works for line-numbers below 1000 lines */
letter-spacing: -1px;
border-right: 1px solid #999;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.line-numbers-rows .span {
display: block;
counter-increment: linenumber;
}
.line-numbers-rows .span:before {
content: counter(linenumber);
color: #999;
display: block;
padding-right: 0.8em;
text-align: right;
}`
}
module.exports = build

View File

@@ -0,0 +1,125 @@
/* PrismJS 1.22.0
https://prismjs.com/download.html#themes=prism-tomorrow&languages=markup+css+clike+javascript */
/**
* prism.js tomorrow night eighties for JavaScript, CoffeeScript, CSS and HTML
* Based on https://github.com/chriskempson/tomorrow-theme
* @author Rose Pritchard
*/
code[class*="language-"],
pre[class*="language-"] {
color: #ccc;
background: none;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
font-size: 1em;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre) > code[class*="language-"],
pre[class*="language-"] {
background: #2d2d2d;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.block-comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: #999;
}
.token.punctuation {
color: #ccc;
}
.token.tag,
.token.attr-name,
.token.namespace,
.token.deleted {
color: #e2777a;
}
.token.function-name {
color: #6196cc;
}
.token.boolean,
.token.number,
.token.function {
color: #f08d49;
}
.token.property,
.token.class-name,
.token.constant,
.token.symbol {
color: #f8c555;
}
.token.selector,
.token.important,
.token.atrule,
.token.keyword,
.token.builtin {
color: #cc99cd;
}
.token.string,
.token.char,
.token.attr-value,
.token.regex,
.token.variable {
color: #7ec699;
}
.token.operator,
.token.entity,
.token.url {
color: #67cdcc;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
.token.inserted {
color: green;
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,88 @@
const config = require('../config')
const build = {
import: 'prism.css',
handler (file) {
if (file.path.includes('prism.css')) {
// 将标签名选择器和属性选择器转为 class 选择器(组件内仅支持 class 选择器)
file.contents = Buffer.from(file.contents.toString().replace(/pre([[)])/g, '.hl-pre$1').replace(/code/g, '.hl-code').replace(/\[class\*="?language-"?\]/g, '').replace(/:not[^,}]+[,}]*/g, '').replace(/\.token\./g, '.hl-'))
}
}
}
if (config.showLanguageName || config.showLineNumber) {
// pre 内部的 code 进行滚动,避免行号和语言名称跟随滚动
build.style = `.hl-pre {
position: relative;
}
.hl-code {
overflow: auto;
display: block;
}`
}
if (config.copyByLongPress) {
build.template = '<rich-text v-if="n.attrs&&n.attrs[\'data-content\']" :nodes="[n]" :data-content="n.attrs[\'data-content\']" :data-lang="n.attrs[\'data-lang\']" @longpress="copyCode" />'
build.methods = {
copyCode (e) {
uni.showActionSheet({
itemList: ['复制代码'],
success: () =>
uni.setClipboardData({
data: e.currentTarget.dataset.content
})
})
}
}
}
if (config.showLanguageName) {
build.style = (build.style || '') +
`.hl-language {
font-size: 12px;
font-weight: 600;
position: absolute;
right: 8px;
text-align: right;
top: 3px;
}
.hl-pre {
padding-top: 1.5em;
}`
}
if (config.showLineNumber) {
build.style = (build.style || '') +
`.hl-pre {
font-size: 14px;
padding-left: 3.8em;
counter-reset: linenumber;
}
.line-numbers-rows {
position: absolute;
pointer-events: none;
top: ${config.showLanguageName ? 1.5 : 1}em;
font-size: 100%;
left: 0;
width: 3em; /* works for line-numbers below 1000 lines */
letter-spacing: -1px;
border-right: 1px solid #999;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.line-numbers-rows .span {
display: block;
counter-increment: linenumber;
}
.line-numbers-rows .span:before {
content: counter(linenumber);
color: #999;
display: block;
padding-right: 0.8em;
text-align: right;
}`
}
module.exports = build