Skip to content

Commit fd43c13

Browse files
committed
feat: support hover tip
1 parent 1fcc091 commit fd43c13

File tree

14 files changed

+5266
-4224
lines changed

14 files changed

+5266
-4224
lines changed

packages/monaco-plugin-ob/example/src/components/App/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,8 @@ export default function () {
104104
'schema2'
105105
]
106106
},
107-
async getTableDDL() {
108-
return `create table aa (
107+
async getTableDDL(tb: string, db: string) {
108+
return `create table ${db}.${tb} (
109109
id int,
110110
uname varchar(20)
111111
);

packages/monaco-plugin-ob/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@oceanbase-odc/monaco-plugin-ob",
3-
"version": "1.3.2",
3+
"version": "1.4.0",
44
"description": "",
55
"main": "dist/index.js",
66
"scripts": {
@@ -50,7 +50,7 @@
5050
"copy-webpack-plugin": "^12.0.2",
5151
"css-loader": "^6.7.1",
5252
"html-webpack-plugin": "^5.5.0",
53-
"monaco-editor": "^0.34.1",
53+
"monaco-editor": "~0.38.0",
5454
"monaco-vim": "^0.3.4",
5555
"react": "^17.0.2",
5656
"react-dom": "^17.0.2",
@@ -63,6 +63,6 @@
6363
"webpack-dev-server": "^4.11.1"
6464
},
6565
"peerDependencies": {
66-
"monaco-editor": "^0.34.1"
66+
"monaco-editor": "~0.38.0"
6767
}
6868
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import * as monaco from 'monaco-editor';
2+
import { PLugin } from '../../Plugin';
3+
import parser from '../worker/parser';
4+
5+
class MonacoHover implements monaco.languages.HoverProvider {
6+
plugin: PLugin | null = null;
7+
constructor(plugin) {
8+
this.plugin = plugin;
9+
}
10+
provideHover(model: monaco.editor.ITextModel, position: monaco.Position, token: monaco.CancellationToken): monaco.languages.ProviderResult<monaco.languages.Hover> {
11+
if (!this.plugin?.modelOptionsMap.get(model.id)?.getTableDDL) {
12+
return;
13+
}
14+
return new Promise(async (resolve, reject) => {
15+
const word = model.getWordAtPosition(position)
16+
if (!word) {
17+
return resolve(null)
18+
}
19+
const delimiter = this.plugin?.modelOptionsMap.get(model.id)?.delimiter || ';';
20+
const offset = model.getOffsetAt(position);
21+
const result = await parser.getOffsetType(model.getValue(), delimiter, offset)
22+
if (!result) {
23+
resolve(null);
24+
return;
25+
}
26+
const { type, name, schema } = result;
27+
if (!name) {
28+
resolve(null);
29+
return;
30+
}
31+
const ddl = await this.plugin?.modelOptionsMap.get(model.id)?.getTableDDL?.(name, schema);
32+
if (!ddl) {
33+
resolve(null);
34+
return;
35+
}
36+
resolve({
37+
contents: [
38+
{
39+
value: '```sql\n '+ddl+' \n```'
40+
}
41+
]
42+
});
43+
})
44+
}
45+
}
46+
47+
48+
49+
export default MonacoHover;

packages/monaco-plugin-ob/src/mysql/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import MonacoAutoComplete from './autoComplete';
55
import { conf, language } from './monarch/mysql';
66
import { DocumentFormattingEditProvider, DocumentRangeFormattingEditProvider } from '../format';
77
import MonacoInlineComplete from '../inlineCompletion';
8+
import MonacoHover from './hover';
89

910
export function setup(plugin: PLugin) {
1011
monaco.languages.register({
@@ -16,5 +17,6 @@ export function setup(plugin: PLugin) {
1617
monaco.languages.registerDocumentFormattingEditProvider(LanguageType.MySQL, new DocumentFormattingEditProvider(plugin, LanguageType.MySQL))
1718
monaco.languages.registerDocumentRangeFormattingEditProvider(LanguageType.MySQL, new DocumentRangeFormattingEditProvider(plugin, LanguageType.MySQL))
1819
monaco.languages.registerInlineCompletionsProvider(LanguageType.MySQL, new MonacoInlineComplete(plugin))
20+
monaco.languages.registerHoverProvider(LanguageType.MySQL, new MonacoHover(plugin))
1921

2022
}

packages/monaco-plugin-ob/src/mysql/worker/parser.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,5 +333,81 @@ export default {
333333

334334
return sqlCompletion(statement, offset - statement.start)
335335

336+
},
337+
getOffsetType(text: string, delimiter: string, offset: number): {
338+
type: 'table';
339+
name: string;
340+
schema?: string;
341+
} | null {
342+
if (!text) {
343+
return null;
344+
}
345+
const sqlDocuments = getSQLDocument(text, delimiter);
346+
let statement = sqlDocuments.statements.find(s => s.start <= (offset - 1) && s.stop >= (offset - 1));
347+
if (!statement) {
348+
return null;
349+
}
350+
const result = statement.parse(offset, () => {});
351+
if (!result){
352+
return null;
353+
}
354+
const queryMap = createFromASTTree(result.result);
355+
let query: Query | undefined;
356+
queryMap.forEach((value, key) => {
357+
const location = value.location;
358+
if (!location) {
359+
return;
360+
}
361+
if (location.range[0] <= offset && location.range[1] >= offset) {
362+
if (!query) {
363+
query = value;
364+
return;
365+
}
366+
if (query.location && query.location.range[0] < location.range[0]) {
367+
query = value;
368+
return;
369+
}
370+
}
371+
})
372+
if (!query) {
373+
return null;
374+
}
375+
const fromTable = query.fromTables.find(fromTable => {
376+
const { location } = fromTable;
377+
return location.range[0] <= offset && location.range[1] >= offset;
378+
})
379+
if (fromTable) {
380+
if (fromTable.query) {
381+
return null;
382+
}
383+
return {
384+
type: 'table',
385+
name: fromTable.tableName || '',
386+
schema: fromTable.schemaName
387+
}
388+
}
389+
/**
390+
* select columns
391+
*/
392+
const selectColumn = query.selectColumns.find(selectColumn => {
393+
const { location } = selectColumn;
394+
return location.range[0] <= offset && location.range[1] >= offset;
395+
})
396+
if (selectColumn) {
397+
if (!selectColumn.columnName || !(selectColumn.columnName instanceof Array) || selectColumn.columnName?.length < 2) {
398+
return null;
399+
}
400+
const tableAlias = selectColumn.columnName[0];
401+
const from = query.fromTables.find(from => from.alias === tableAlias || from.tableName === tableAlias);
402+
if (!from) {
403+
return null;
404+
}
405+
return {
406+
type: 'table',
407+
name: from.tableName || '',
408+
schema: from.schemaName
409+
}
410+
}
411+
return null;
336412
}
337413
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import * as monaco from 'monaco-editor';
2+
import { PLugin } from '../../Plugin';
3+
import parser from '../worker/parser';
4+
5+
class MonacoHover implements monaco.languages.HoverProvider {
6+
plugin: PLugin | null = null;
7+
constructor(plugin) {
8+
this.plugin = plugin;
9+
}
10+
provideHover(model: monaco.editor.ITextModel, position: monaco.Position, token: monaco.CancellationToken): monaco.languages.ProviderResult<monaco.languages.Hover> {
11+
if (!this.plugin?.modelOptionsMap.get(model.id)?.getTableDDL) {
12+
return;
13+
}
14+
return new Promise(async (resolve, reject) => {
15+
const word = model.getWordAtPosition(position)
16+
if (!word) {
17+
return resolve(null)
18+
}
19+
const delimiter = this.plugin?.modelOptionsMap.get(model.id)?.delimiter || ';';
20+
const offset = model.getOffsetAt(position);
21+
const result = await parser.getOffsetType(model.getValue(), delimiter, offset)
22+
if (!result) {
23+
resolve(null);
24+
return;
25+
}
26+
const { type, name, schema } = result;
27+
if (!name) {
28+
resolve(null);
29+
return;
30+
}
31+
const ddl = await this.plugin?.modelOptionsMap.get(model.id)?.getTableDDL?.(name, schema);
32+
if (!ddl) {
33+
resolve(null);
34+
return;
35+
}
36+
resolve({
37+
contents: [
38+
{
39+
value: '```sql\n '+ddl+' \n```'
40+
}
41+
]
42+
});
43+
})
44+
}
45+
}
46+
47+
48+
49+
export default MonacoHover;

packages/monaco-plugin-ob/src/obmysql/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import MonacoAutoComplete from './autoComplete';
55
import { conf, language } from './monarch/obmysql';
66
import { DocumentFormattingEditProvider, DocumentRangeFormattingEditProvider } from '../format';
77
import MonacoInlineComplete from '../inlineCompletion';
8+
import MonacoHover from './hover';
89

910
export function setup(plugin: PLugin) {
1011
monaco.languages.register({
@@ -16,4 +17,5 @@ export function setup(plugin: PLugin) {
1617
monaco.languages.registerDocumentFormattingEditProvider(LanguageType.OB_MySQL, new DocumentFormattingEditProvider(plugin, LanguageType.OB_MySQL))
1718
monaco.languages.registerDocumentRangeFormattingEditProvider(LanguageType.OB_MySQL, new DocumentRangeFormattingEditProvider(plugin, LanguageType.OB_MySQL))
1819
monaco.languages.registerInlineCompletionsProvider(LanguageType.OB_MySQL, new MonacoInlineComplete(plugin))
20+
monaco.languages.registerHoverProvider(LanguageType.OB_MySQL, new MonacoHover(plugin))
1921
}

packages/monaco-plugin-ob/src/obmysql/worker/parser.ts

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { getTableContextFromMap } from '../../model/helper';
88
import { Query, QueryCursorContext } from '../../model/query';
99
import { createFromASTTree } from '../../model/dialect/obmysql';
1010
import { keywords } from '../keywords';
11+
import { ISelectColumn } from '../../model';
1112

1213
const keywordsSet = new Set(keywords)
1314

@@ -332,5 +333,82 @@ export default {
332333

333334
return sqlCompletion(statement, offset - statement.start)
334335

336+
},
337+
338+
getOffsetType(text: string, delimiter: string, offset: number): {
339+
type: 'table';
340+
name: string;
341+
schema?: string;
342+
} | null {
343+
if (!text) {
344+
return null;
345+
}
346+
const sqlDocuments = getSQLDocument(text, delimiter);
347+
let statement = sqlDocuments.statements.find(s => s.start <= (offset - 1) && s.stop >= (offset - 1));
348+
if (!statement) {
349+
return null;
350+
}
351+
const result = statement.parse(offset, () => {});
352+
if (!result){
353+
return null;
354+
}
355+
const queryMap = createFromASTTree(result.result);
356+
let query: Query | undefined;
357+
queryMap.forEach((value, key) => {
358+
const location = value.location;
359+
if (!location) {
360+
return;
361+
}
362+
if (location.range[0] <= offset && location.range[1] >= offset) {
363+
if (!query) {
364+
query = value;
365+
return;
366+
}
367+
if (query.location && query.location.range[0] < location.range[0]) {
368+
query = value;
369+
return;
370+
}
371+
}
372+
})
373+
if (!query) {
374+
return null;
375+
}
376+
const fromTable = query.fromTables.find(fromTable => {
377+
const { location } = fromTable;
378+
return location.range[0] <= offset && location.range[1] >= offset;
379+
})
380+
if (fromTable) {
381+
if (fromTable.query) {
382+
return null;
383+
}
384+
return {
385+
type: 'table',
386+
name: fromTable.tableName || '',
387+
schema: fromTable.schemaName
388+
}
389+
}
390+
/**
391+
* select columns
392+
*/
393+
const selectColumn = query.selectColumns.find(selectColumn => {
394+
const { location } = selectColumn;
395+
return location.range[0] <= offset && location.range[1] >= offset;
396+
})
397+
if (selectColumn) {
398+
if (!selectColumn.columnName || !(selectColumn.columnName instanceof Array) || selectColumn.columnName?.length < 2) {
399+
return null;
400+
}
401+
const tableAlias = selectColumn.columnName[0];
402+
const from = query.fromTables.find(from => from.alias === tableAlias || from.tableName === tableAlias);
403+
if (!from) {
404+
return null;
405+
}
406+
return {
407+
type: 'table',
408+
name: from.tableName || '',
409+
schema: from.schemaName
410+
}
411+
}
412+
return null;
335413
}
336414
}

packages/monaco-plugin-ob/src/oboracle/definition/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import * as monaco from 'monaco-editor';
22
import { PLugin } from '../../Plugin';
3-
import { findTargetVariable } from '../hover/helper';
43
import { IFromTable, ITableVariable } from '../worker/type';
54
import wrapWorker from '../worker/workerInstance';
65

0 commit comments

Comments
 (0)