vue2 monoca-editor使用SQL:自动补全、自定义颜色、格式化代码、标记错误
一、安装(注意webpack-plugin对应版本,否则不能运行)
yarn add monaco-editor@0.29.1
yarn add monaco-editor-webpack-plugin@5.0.0 -D
二、配置vue.config.js
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin')
module.exports = {
configureWebpack: {
plugins: [
new MonacoWebpackPlugin({
language: ['sql']
})
]
}
}
三、使用
1.导入
// 全局导入
import * as monaco from 'monaco-editor'
// 局部导入需要的功能和依赖
import * as monaco from 'monaco-editor/esm/vs/editor/edcore.main'
import 'monaco-editor/esm/vs/basic-languages/sql/sql.contribution'
2.封装组件
<template>
<div id="code"></div>
</template>
<script>
import Vue from 'vue'
import {Component} from 'vue-property-decorator'
import * as monaco from 'monaco-editor/esm/vs/editor/edcore.main'
import 'monaco-editor/esm/vs/basic-languages/sql/sql.contribution'
// import { language } from 'monaco-editor/esm/vs/basic-languages/sql/sql'
// language.keywords插件自带关键词的不全,网上找了一份自己维护
import sqlKeywords from './sqlKeywords.js'
@Component({
props: {
database: String
}
})
export default class SqlEditor extends Vue {
editor = null
color = null
suggestion = null
formatProvider = null
mounted () {
this.initEditor()
}
// 父组件获取值
getValue() {
return this.editor.getValue()
}
// 父组件设置值
setValue(content) {
this.editor.setValue(content)
}
initEditor () {
this.editor = monaco.editor.create(document.getElementById('code'), {
//初始化配置
value: '',
theme: 'vs-dark',
autoIndex: true,
language: 'sql', // 语言类型
tabCompletion: 'on',
cursorSmoothCaretAnimation: true,
formatOnPaste: true,
mouseWheelZoom: true,
folding: true, //代码折叠
autoClosingBrackets: 'always',
autoClosingOvertype: 'always',
autoClosingQuotes: 'always',
automaticLayout: 'always'
})
}
}
</script>
自定义提示
databaseData = {
a: ['group', 'area'],
b: ['user', 'client']
}
tableData = {
user: ['age', 'gender'],
group: ['id', 'name']
}
// 关键字
getSQLSuggest () {
return sqlKeywords.map((key) => ({
label: key,
kind: monaco.languages.CompletionItemKind.Keyword,
insertText: key,
detail: 'keyword'
}))
}
// 表名
getTableSuggest (dbName) {
const tableNames = this.databaseData[dbName]
if (!tableNames) {
return []
}
return tableNames.map((name) => ({
label: name,
kind: monaco.languages.CompletionItemKind.Constant,
insertText: name,
detail: dbName
}))
}
// 字段名
getParamSuggest (tableName) {
const params = this.tableData[tableName]
if (!params) {
return []
}
return params.map((name) => ({
label: name,
kind: monaco.languages.CompletionItemKind.Constant,
insertText: name,
detail: 'param'
}))
}
// 数据库名
getDBSuggest () {
return Object.keys(this.databaseData).map((key) => ({
label: key,
kind: monaco.languages.CompletionItemKind.Enum,
insertText: key,
detail: 'database'
}))
}
initEditor () {
// 自动补全提示
this.suggestion = monaco.languages.registerCompletionItemProvider('sql', {
// 触发条件,也可以不写,不写的话只要输入满足配置的label就会提示;仅支持单字符
triggerCharacters: ['.', ' '],
provideCompletionItems: (model, position) => {
let suggestions = []
const { lineNumber, column } = position
const textBeforePointer = model.getValueInRange({
startLineNumber: lineNumber,
startColumn: 0,
endLineNumber: lineNumber,
endColumn: column,
})
const tokens = textBeforePointer.toLocaleLowerCase().trim().split(/\s+/)
const lastToken = tokens[tokens.length - 1] // 获取最后一段非空字符串
if (lastToken.endsWith('.')) {
// 提示该数据库下的表名
const tokenNoDot = lastToken.slice(0, lastToken.length - 1)
if (Object.keys(this.databaseData).includes(tokenNoDot)) {
suggestions = [...this.getTableSuggest(tokenNoDot)]
}
} else if (lastToken === '.') {
suggestions = []
} else if (textBeforePointer.endsWith(' ')) {
if (textBeforePointer.endsWith('select * from ')) {
// select * from 提示指定数据库的表名
suggestions = this.getTableSuggest(this.database)
} else if (lastToken === 'where') {
const lastToken2 = tokens[tokens.length - 2]
const lastToken3 = tokens[tokens.length - 3]
const lastToken4 = tokens[tokens.length - 4]
const lastToken5 = tokens[tokens.length - 5]
if (lastToken5 + lastToken4 + lastToken3 === 'select*from') {
// select * from tableName where 提示指定表的字段名
suggestions = [...this.getParamSuggest(lastToken2)]
} else {
suggestions = []
}
}else {
suggestions = []
}
} else {
// 提示数据库名和关键词
suggestions = [...this.getDBSuggest(), ...this.getSQLSuggest()]
}
return {
suggestions,
}
}
})
}
自定义文本颜色,自带也有
initEditor() {
//自定义文本颜色,也可以不设置,自带也有颜色区分
let reg = '/'
sqlKeywords.forEach((keyword) => {
reg += `${keyword}|`
})
reg += '/'
this.color = monaco.languages.setMonarchTokensProvider('sql', {
ignoreCase: true,
tokenizer: {
root: [
[
reg,
{ token: 'keyword' },
], //蓝色
[
/[+]|[-]|[*]|[/]|[%]|[>]|[<]|[=]|[!]|[:]|[&&]|[||]/,
{ token: 'string' },
], //红色
[/'.*?'|".*?"/, { token: 'string.escape' }], //橙色
[/#--.*?\--#/, { token: 'comment' }], //绿色
[/null/, { token: 'regexp' }], //粉色
[/[{]|[}]/, { token: 'type' }], //青色
[/[\u4e00-\u9fa5]/, { token: 'predefined' }],//亮粉色
[/''/, { token: 'invalid' }],//红色
[/[\u4e00-\u9fa5]/, { token: 'number.binary' }],//浅绿
[/(?!.*[a-zA-Z])[0-9]/, { token: 'number.hex' }], //浅绿
[/[(]|[)]/, { token: 'number.octal' }], //浅绿
[/[\u4e00-\u9fa5]/, { token: 'number.float' }],//浅绿
]
}
})
}
格式化代码&标记错误
yarn add sql-formatter@10.7.2 -D
import { format } from 'sql-formatter'
initEditor() {
// 改写插件自带格式化功能
const self = this
this.formatProvider = monaco.languages.registerDocumentFormattingEditProvider('sql', {
provideDocumentFormattingEdits(model) {
return [{
text: self.formatSql(1),
range: model.getFullModelRange()
}]
}
})
}
// 格式化代码
formatSql(needValue) {
this.clearMistake()
try {
this.setValue(format((this.editor).getValue()))
} catch (e) {
const {message} = e
const list = message.split(' ')
const line = list.indexOf('line')
const column = list.indexOf('column')
this.markMistake({
startLineNumber: Number(list[line + 1]),
endLineNumber: Number(list[line + 1]),
startColumn: Number(list[column + 1]),
endColumn: Number(list[column + 1])
}, 'Error', message)
}
if (needValue) {
return this.editor.getValue()
}
}
// 标记错误信息
markMistake(range, type, message) {
const {startLineNumber, endLineNumber, startColumn, endColumn} = range
monaco.editor.setModelMarkers(
this.editor.getModel(),
'eslint',
[{
startLineNumber,
endLineNumber,
startColumn,
endColumn,
severity: monaco.MarkerSeverity[type], // type可以是Error,Warning,Info
message
}]
)
}
// 清除错误信息
clearMistake() {
monaco.editor.setModelMarkers(
this.editor.getModel(),
'eslint',
[]
)
}
监听值变化
initEditor() {
this.editor.onDidChangeModelContent(() => {
console.log('value', this.editor.getValue())
})
}
销毁编辑器及其配置,防止自定义提示数据重复
beforeDestroy () {
if (this.editor) {
this.clearMistake()
this.editor.dispose()
this.color.dispose()
this.suggestion.dispose()
this.formatProvider.dispose()
}
}
更新:附上SqlKeywords.js
// SqlKeywords.js
export default [
'ACCESSIBLE',
'ACCOUNT',
'ACTION',
'ADD',
'AFTER',
'AGAINST',
'AGGREGATE',
'ALGORITHM',
'ALL',
'ALTER',
'ALWAYS',
'ANALYSE',
'ANALYZE',
'AND',
'ANY',
'AS',
'ASC',
'ASCII',
'ASENSITIVE',
'AT',
'AUTOEXTEND_SIZE',
'AUTO_INCREMENT',
'AVG',
'AVG_ROW_LENGTH',
'BACKUP',
'BEFORE',
'BEGIN',
'BETWEEN',
'BIGINT',
'BINARY',
'BINLOG',
'BIT',
'BLOB',
'BLOCK',
'BOOL',
'BOOLEAN',
'BOTH',
'BTREE',
'BY',
'BYTE',
'CACHE',
'CALL',
'CASCADE',
'CASCADED',
'CASE',
'CATALOG_NAME',
'CHAIN',
'CHANGE',
'CHANGED',
'CHANNEL',
'CHAR',
'CHARACTER',
'CHARSET',
'CHECK',
'CHECKSUM',
'CIPHER',
'CLASS_ORIGIN',
'CLIENT',
'CLOSE',
'COALESCE',
'CODE',
'COLLATE',
'COLLATION',
'COLUMN',
'COLUMNS',
'COLUMN_FORMAT',
'COLUMN_NAME',
'COMMENT',
'COMMIT',
'COMMITTED',
'COMPACT',
'COMPLETION',
'COMPRESSED',
'COMPRESSION',
'CONCURRENT',
'CONDITION',
'CONNECTION',
'CONSISTENT',
'CONSTRAINT',
'CONSTRAINT_CATALOG',
'CONSTRAINT_NAME',
'CONSTRAINT_SCHEMA',
'CONTAINS',
'CONTEXT',
'CONTINUE',
'CONVERT',
'CPU',
'CREATE',
'CROSS',
'CUBE',
'CURRENT',
'CURRENT_DATE',
'CURRENT_TIME',
'CURRENT_TIMESTAMP',
'CURRENT_USER',
'CURSOR',
'CURSOR_NAME',
'DATA',
'DATABASE',
'DATABASES',
'DATAFILE',
'DATE',
'DATETIME',
'DAY',
'DAY_HOUR',
'DAY_MICROSECOND',
'DAY_MINUTE',
'DAY_SECOND',
'DEALLOCATE',
'DEC',
'DECIMAL',
'DECLARE',
'DEFAULT',
'DEFAULT_AUTH',
'DEFINER',
'DELAYED',
'DELAY_KEY_WRITE',
'DELETE',
'DESC',
'DESCRIBE',
'DES_KEY_FILE',
'DETERMINISTIC',
'DIAGNOSTICS',
'DIRECTORY',
'DISABLE',
'DISCARD',
'DISK',
'DISTINCT',
'DISTINCTROW',
'DIV',
'DO',
'DOUBLE',
'DROP',
'DUAL',
'DUMPFILE',
'DUPLICATE',
'DYNAMIC',
'EACH',
'ELSE',
'ELSEIF',
'ENABLE',
'ENCLOSED',
'ENCRYPTION',
'END',
'ENDS',
'ENGINE',
'ENGINES',
'ENUM',
'ERROR',
'ERRORS',
'ESCAPE',
'ESCAPED',
'EVENT',
'EVENTS',
'EVERY',
'EXCHANGE',
'EXECUTE',
'EXISTS',
'EXIT',
'EXPANSION',
'EXPIRE',
'EXPLAIN',
'EXPORT',
'EXTENDED',
'EXTENT_SIZE',
'FALSE',
'FAST',
'FAULTS',
'FETCH',
'FIELDS',
'FILE',
'FILE_BLOCK_SIZE',
'FILTER',
'FIRST',
'FIXED',
'FLOAT',
'FLOAT4',
'FLOAT8',
'FLUSH',
'FOLLOWS',
'FOR',
'FORCE',
'FOREIGN',
'FORMAT',
'FOUND',
'FROM',
'FULL',
'FULLTEXT',
'FUNCTION',
'GENERAL',
'GENERATED',
'GEOMETRY',
'GEOMETRYCOLLECTION',
'GET',
'GET_FORMAT',
'GLOBAL',
'GRANT',
'GRANTS',
'GROUP',
'GROUP_REPLICATION',
'HANDLER',
'HASH',
'HAVING',
'HELP',
'HIGH_PRIORITY',
'HOST',
'HOSTS',
'HOUR',
'HOUR_MICROSECOND',
'HOUR_MINUTE',
'HOUR_SECOND',
'IDENTIFIED',
'IF',
'IGNORE',
'IGNORE_SERVER_IDS',
'IMPORT',
'IN',
'INDEX',
'INDEXES',
'INFILE',
'INITIAL_SIZE',
'INNER',
'INOUT',
'INSENSITIVE',
'INSERT',
'INSERT_METHOD',
'INSTALL',
'INSTANCE',
'INT',
'INT1',
'INT2',
'INT3',
'INT4',
'INT8',
'INTEGER',
'INTERVAL',
'INTO',
'INVOKER',
'IO',
'IO_AFTER_GTIDS',
'IO_BEFORE_GTIDS',
'IO_THREAD',
'IPC',
'IS',
'ISOLATION',
'ISSUER',
'ITERATE',
'JOIN',
'JSON',
'KEY',
'KEYS',
'KEY_BLOCK_SIZE',
'KILL',
'LANGUAGE',
'LAST',
'LEADING',
'LEAVE',
'LEAVES',
'LEFT',
'LESS',
'LEVEL',
'LIKE',
'LIMIT',
'LINEAR',
'LINES',
'LINESTRING',
'LIST',
'LOAD',
'LOCAL',
'LOCALTIME',
'LOCALTIMESTAMP',
'LOCK',
'LOCKS',
'LOGFILE',
'LOGS',
'LONG',
'LONGBLOB',
'LONGTEXT',
'LOOP',
'LOW_PRIORITY',
'MASTER',
'MASTER_AUTO_POSITION',
'MASTER_BIND',
'MASTER_CONNECT_RETRY',
'MASTER_DELAY',
'MASTER_HEARTBEAT_PERIOD',
'MASTER_HOST',
'MASTER_LOG_FILE',
'MASTER_LOG_POS',
'MASTER_PASSWORD',
'MASTER_PORT',
'MASTER_RETRY_COUNT',
'MASTER_SERVER_ID',
'MASTER_SSL',
'MASTER_SSL_CA',
'MASTER_SSL_CAPATH',
'MASTER_SSL_CERT',
'MASTER_SSL_CIPHER',
'MASTER_SSL_CRL',
'MASTER_SSL_CRLPATH',
'MASTER_SSL_KEY',
'MASTER_SSL_VERIFY_SERVER_CERT',
'MASTER_TLS_VERSION',
'MASTER_USER',
'MATCH',
'MAXVALUE',
'MAX_CONNECTIONS_PER_HOUR',
'MAX_QUERIES_PER_HOUR',
'MAX_ROWS',
'MAX_SIZE',
'MAX_STATEMENT_TIME',
'MAX_UPDATES_PER_HOUR',
'MAX_USER_CONNECTIONS',
'MEDIUM',
'MEDIUMBLOB',
'MEDIUMINT',
'MEDIUMTEXT',
'MEMORY',
'MERGE',
'MESSAGE_TEXT',
'MICROSECOND',
'MIDDLEINT',
'MIGRATE',
'MINUTE',
'MINUTE_MICROSECOND',
'MINUTE_SECOND',
'MIN_ROWS',
'MOD',
'MODE',
'MODIFIES',
'MODIFY',
'MONTH',
'MULTILINESTRING',
'MULTIPOINT',
'MULTIPOLYGON',
'MUTEX',
'MYSQL_ERRNO',
'NAME',
'NAMES',
'NATIONAL',
'NATURAL',
'NCHAR',
'NDB',
'NDBCLUSTER',
'NEVER',
'NEW',
'NEXT',
'NO',
'NODEGROUP',
'NONBLOCKING',
'NONE',
'NOT',
'NO_WAIT',
'NO_WRITE_TO_BINLOG',
'NULL',
'NUMBER',
'NUMERIC',
'NVARCHAR',
'OFFSET',
'OLD_PASSWORD',
'ON',
'ONE',
'ONLY',
'OPEN',
'OPTIMIZE',
'OPTIMIZER_COSTS',
'OPTION',
'OPTIONALLY',
'OPTIONS',
'OR',
'ORDER',
'OUT',
'OUTER',
'OUTFILE',
'OWNER',
'PACK_KEYS',
'PAGE',
'PARSER',
'PARSE_GCOL_EXPR',
'PARTIAL',
'PARTITION',
'PARTITIONING',
'PARTITIONS',
'PASSWORD',
'PHASE',
'PLUGIN',
'PLUGINS',
'PLUGIN_DIR',
'POINT',
'POLYGON',
'PORT',
'PRECEDES',
'PRECISION',
'PREPARE',
'PRESERVE',
'PREV',
'PRIMARY',
'PRIVILEGES',
'PROCEDURE',
'PROCESSLIST',
'PROFILE',
'PROFILES',
'PROXY',
'PURGE',
'QUARTER',
'QUERY',
'QUICK',
'RANGE',
'READ',
'READS',
'READ_ONLY',
'READ_WRITE',
'REAL',
'REBUILD',
'RECOVER',
'REDOFILE',
'REDO_BUFFER_SIZE',
'REDUNDANT',
'REFERENCES',
'REGEXP',
'RELAY',
'RELAYLOG',
'RELAY_LOG_FILE',
'RELAY_LOG_POS',
'RELAY_THREAD',
'RELEASE',
'RELOAD',
'REMOVE',
'RENAME',
'REORGANIZE',
'REPAIR',
'REPEAT',
'REPEATABLE',
'REPLACE',
'REPLICATE_DO_DB',
'REPLICATE_DO_TABLE',
'REPLICATE_IGNORE_DB',
'REPLICATE_IGNORE_TABLE',
'REPLICATE_REWRITE_DB',
'REPLICATE_WILD_DO_TABLE',
'REPLICATE_WILD_IGNORE_TABLE',
'REPLICATION',
'REQUIRE',
'RESET',
'RESIGNAL',
'RESTORE',
'RESTRICT',
'RESUME',
'RETURN',
'RETURNED_SQLSTATE',
'RETURNS',
'REVERSE',
'REVOKE',
'RIGHT',
'RLIKE',
'ROLLBACK',
'ROLLUP',
'ROTATE',
'ROUTINE',
'ROW',
'ROWS',
'ROW_COUNT',
'ROW_FORMAT',
'RTREE',
'SAVEPOINT',
'SCHEDULE',
'SCHEMA',
'SCHEMAS',
'SCHEMA_NAME',
'SECOND',
'SECOND_MICROSECOND',
'SECURITY',
'SELECT',
'SENSITIVE',
'SEPARATOR',
'SERIAL',
'SERIALIZABLE',
'SERVER',
'SESSION',
'SET',
'SHARE',
'SHOW',
'SHUTDOWN',
'SIGNAL',
'SIGNED',
'SIMPLE',
'SLAVE',
'SLOW',
'SMALLINT',
'SNAPSHOT',
'SOCKET',
'SOME',
'SONAME',
'SOUNDS',
'SOURCE',
'SPATIAL',
'SPECIFIC',
'SQL',
'SQLEXCEPTION',
'SQLSTATE',
'SQLWARNING',
'SQL_AFTER_GTIDS',
'SQL_AFTER_MTS_GAPS',
'SQL_BEFORE_GTIDS',
'SQL_BIG_RESULT',
'SQL_BUFFER_RESULT',
'SQL_CACHE',
'SQL_CALC_FOUND_ROWS',
'SQL_NO_CACHE',
'SQL_SMALL_RESULT',
'SQL_THREAD',
'SQL_TSI_DAY',
'SQL_TSI_HOUR',
'SQL_TSI_MINUTE',
'SQL_TSI_MONTH',
'SQL_TSI_QUARTER',
'SQL_TSI_SECOND',
'SQL_TSI_WEEK',
'SQL_TSI_YEAR',
'SSL',
'STACKED',
'START',
'STARTING',
'STARTS',
'STATS_AUTO_RECALC',
'STATS_PERSISTENT',
'STATS_SAMPLE_PAGES',
'STATUS',
'STOP',
'STORAGE',
'STORED',
'STRAIGHT_JOIN',
'STRING',
'SUBCLASS_ORIGIN',
'SUBJECT',
'SUBPARTITION',
'SUBPARTITIONS',
'SUPER',
'SUSPEND',
'SWAPS',
'SWITCHES',
'TABLE',
'TABLES',
'TABLESPACE',
'TABLE_CHECKSUM',
'TABLE_NAME',
'TEMPORARY',
'TEMPTABLE',
'TERMINATED',
'TEXT',
'THAN',
'THEN',
'TIME',
'TIMESTAMP',
'TIMESTAMPADD',
'TIMESTAMPDIFF',
'TINYBLOB',
'TINYINT',
'TINYTEXT',
'TO',
'TRAILING',
'TRANSACTION',
'TRIGGER',
'TRIGGERS',
'TRUE',
'TRUNCATE',
'TYPE',
'TYPES',
'UNCOMMITTED',
'UNDEFINED',
'UNDO',
'UNDOFILE',
'UNDO_BUFFER_SIZE',
'UNICODE',
'UNINSTALL',
'UNION',
'UNIQUE',
'UNKNOWN',
'UNLOCK',
'UNSIGNED',
'UNTIL',
'UPDATE',
'UPGRADE',
'USAGE',
'USE',
'USER',
'USER_RESOURCES',
'USE_FRM',
'USING',
'UTC_DATE',
'UTC_TIME',
'UTC_TIMESTAMP',
'VALIDATION',
'VALUE',
'VALUES',
'VARBINARY',
'VARCHAR',
'VARCHARACTER',
'VARIABLES',
'VARYING',
'VIEW',
'VIRTUAL',
'WAIT',
'WARNINGS',
'WEEK',
'WEIGHT_STRING',
'WHEN',
'WHERE',
'WHILE',
'WITH',
'WITHOUT',
'WORK',
'WRAPPER',
'WRITE',
'X509',
'XA',
'XID',
'XML',
'XOR',
'YEAR',
'YEAR_MONTH',
'ZEROFILL'
]