Skip to content

Commit 3a7c7c1

Browse files
author
jialan
committed
feat: snippets demo
1 parent 3e78633 commit 3a7c7c1

13 files changed

+508
-29
lines changed

Diff for: .gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@
77
.history
88
/docs/
99
.DS_Store
10-
*.tgz
10+
#*.tgz

Diff for: dt-sql-parser-4.0.2.tgz

1.84 MB
Binary file not shown.

Diff for: package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
}
6262
},
6363
"dependencies": {
64-
"dt-sql-parser": "4.0.2"
64+
"dt-sql-parser": "file:./dt-sql-parser-4.0.2.tgz"
6565
},
6666
"peerDependencies": {
6767
"monaco-editor": ">=0.31.0"

Diff for: pnpm-lock.yaml

+14-11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: src/baseSQLWorker.ts

+47-3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,18 @@ export interface ICreateData {
77
languageId: string;
88
}
99

10+
export type SnippetToken = {
11+
line: number;
12+
column: number;
13+
text: string | null;
14+
start: number;
15+
stop: number;
16+
type: number;
17+
isWhiteSpace: boolean;
18+
isIdentify: boolean;
19+
isStringLiteral: boolean;
20+
};
21+
1022
export abstract class BaseSQLWorker {
1123
protected abstract _ctx: worker.IWorkerContext;
1224
protected abstract parser: BasicSQL;
@@ -45,17 +57,49 @@ export abstract class BaseSQLWorker {
4557
async doCompletionWithEntities(
4658
code: string,
4759
position: Position
48-
): Promise<[Suggestions | null, EntityContext[] | null]> {
60+
): Promise<{
61+
suggestions: Suggestions | null;
62+
allEntities: EntityContext[] | null;
63+
context?: any;
64+
}> {
4965
code = code || this.getTextDocument();
5066
if (code) {
5167
const suggestions = this.parser.getSuggestionAtCaretPosition(code, position);
5268
let allEntities = null;
5369
if (suggestions?.syntax?.length) {
5470
allEntities = this.parser.getAllEntities(code, position);
5571
}
56-
return Promise.resolve([suggestions, allEntities]);
72+
const contextType = this.parser.getContextTypeAtCaretPosition(code, position);
73+
74+
return Promise.resolve({
75+
suggestions,
76+
allEntities,
77+
context: contextType
78+
});
5779
}
58-
return Promise.resolve([null, null]);
80+
81+
return Promise.resolve({
82+
suggestions: null,
83+
allEntities: null,
84+
context: null
85+
});
86+
}
87+
88+
async getAllTokens(code: string): Promise<SnippetToken[]> {
89+
code = code || this.getTextDocument();
90+
const tokens: SnippetToken[] = this.parser.getAllTokens(code).map((item) => ({
91+
line: item.line,
92+
column: item.column,
93+
text: item.text,
94+
start: item.start,
95+
stop: item.stop,
96+
type: item.type,
97+
// todo replace
98+
isWhiteSpace: item.type === 434,
99+
isIdentify: item.type === 432,
100+
isStringLiteral: item.type === 426
101+
}));
102+
return Promise.resolve(tokens);
59103
}
60104

61105
async getAllEntities(code: string, position?: Position): Promise<EntityContext[] | null> {

Diff for: src/languageFeatures.ts

+86-4
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ import {
99
CancellationToken
1010
} from './fillers/monaco-editor-core';
1111
import { debounce } from './common/utils';
12-
import { BaseSQLWorker } from './baseSQLWorker';
12+
import { BaseSQLWorker, SnippetToken } from './baseSQLWorker';
1313
import type { ParseError } from 'dt-sql-parser';
14-
import type { LanguageServiceDefaults } from './monaco.contribution';
14+
import type { CompletionSnippet, LanguageServiceDefaults } from './monaco.contribution';
1515

1616
export interface WorkerAccessor<T extends BaseSQLWorker> {
1717
(...uris: Uri[]): Promise<T>;
@@ -130,6 +130,25 @@ function toDiagnostics(_resource: Uri, diag: ParseError): editor.IMarkerData {
130130
};
131131
}
132132

133+
function mininumCode(model: editor.IModel, position: Position) {
134+
const codeBeforePosition = model.getValueInRange(
135+
new Range(0, 0, position.lineNumber, position.column)
136+
);
137+
const separatorIndex = codeBeforePosition.lastIndexOf(';');
138+
return separatorIndex === -1
139+
? codeBeforePosition
140+
: codeBeforePosition.slice(separatorIndex + 1);
141+
}
142+
143+
// async function getSQLSnippets(languageId: string) {
144+
// switch (languageId) {
145+
// case 'hivesql':
146+
// return import('./languages/hive/hive.snippet');
147+
// default:
148+
// return Promise.resolve({snippets: []})
149+
// }
150+
// }
151+
133152
export class CompletionAdapter<T extends BaseSQLWorker>
134153
implements languages.CompletionItemProvider
135154
{
@@ -159,13 +178,22 @@ export class CompletionAdapter<T extends BaseSQLWorker>
159178
}
160179
return worker.doCompletionWithEntities(code, position);
161180
})
162-
.then(([suggestions, allEntities]) => {
181+
.then(async ({ suggestions, allEntities, context: sqlContext }) => {
182+
let snippets: CompletionSnippet[] = [];
183+
if (sqlContext?.newStatement) {
184+
snippets = this._defaults.completionSnippets.map((item) => ({
185+
...item,
186+
insertText: typeof item.body === 'string' ? item.body : item.body.join('\n')
187+
}));
188+
}
189+
163190
return this._defaults.completionService(
164191
model,
165192
position,
166193
context,
167194
suggestions,
168-
allEntities
195+
allEntities,
196+
snippets
169197
);
170198
})
171199
.then((completions) => {
@@ -197,3 +225,57 @@ export class CompletionAdapter<T extends BaseSQLWorker>
197225
});
198226
}
199227
}
228+
229+
export class InlineCompletionAdapter<T extends BaseSQLWorker>
230+
implements languages.InlineCompletionsProvider
231+
{
232+
constructor(
233+
private readonly _worker: WorkerAccessor<T>,
234+
private readonly _defaults: LanguageServiceDefaults
235+
) {
236+
console.log('模板列表', _defaults.inlineCompletionSnippets);
237+
}
238+
239+
private allSnippetsTokens: { tokens: SnippetToken[]; snippetText: string }[] = [];
240+
241+
provideInlineCompletions(
242+
model: editor.ITextModel,
243+
position: Position
244+
): languages.ProviderResult<languages.InlineCompletions<languages.InlineCompletion>> {
245+
const resource = model.uri;
246+
return this._worker(resource)
247+
.then(async (worker) => {
248+
let code = mininumCode(model, position);
249+
if (typeof this._defaults.preprocessCode === 'function') {
250+
code = this._defaults.preprocessCode(code);
251+
}
252+
253+
if (!this.allSnippetsTokens?.length) {
254+
const allSnippetsTokens = [];
255+
for (const snippet of this._defaults.inlineCompletionSnippets) {
256+
const tokens = await worker.getAllTokens(snippet);
257+
allSnippetsTokens.push({ tokens, snippetText: snippet });
258+
}
259+
this.allSnippetsTokens = allSnippetsTokens;
260+
}
261+
262+
const currentCodeTokens = await worker.getAllTokens(code);
263+
264+
return {
265+
code,
266+
codeTokens: currentCodeTokens,
267+
allSnippetsTokens: this.allSnippetsTokens
268+
};
269+
})
270+
.then(({ code, codeTokens, allSnippetsTokens }) => {
271+
return this._defaults.inlineCompletionService(
272+
model,
273+
position,
274+
code,
275+
codeTokens,
276+
allSnippetsTokens
277+
) as any;
278+
});
279+
}
280+
freeInlineCompletions(_completions: any) {}
281+
}

Diff for: src/languages/hive/hive.snippet.ts

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
export const snippets = [
2+
{
3+
prefix: 'INSERT',
4+
label: 'INSERT 默认模板',
5+
body: ['insert', 'into', ' `${1:table1}`', 'values', ' (`$2`);', '${3}']
6+
},
7+
{
8+
prefix: 'SELECT',
9+
label: 'SELECT 默认模板',
10+
body: ['select', ' ${1:id}', 'from', ' ${2:table1};', '${3}']
11+
}
12+
];

Diff for: src/monaco.contribution.ts

+49-1
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,19 @@ export type CompletionService = (
3131
position: Position,
3232
completionContext: languages.CompletionContext,
3333
suggestions: Suggestions | null,
34-
entities: EntityContext[] | null
34+
entities: EntityContext[] | null,
35+
snippets?: CompletionSnippet[],
36+
identifiers?: any[]
3537
) => Promise<ICompletionItem[] | ICompletionList>;
3638

39+
export type InlineCompletionService = (
40+
model: editor.IReadOnlyModel,
41+
position: Position,
42+
code: string,
43+
tokens: any[],
44+
allSnippetsTokens: any[]
45+
) => Promise<languages.InlineCompletions<languages.InlineCompletion> | null | undefined>;
46+
3747
export interface CompletionOptions {
3848
enable: boolean;
3949
/**
@@ -42,6 +52,21 @@ export interface CompletionOptions {
4252
*/
4353
completionService: CompletionService;
4454
triggerCharacters: string[];
55+
snippets: CompletionSnippet[];
56+
}
57+
58+
export interface InlineCompletionOptions {
59+
enable: boolean;
60+
completionService: InlineCompletionService;
61+
inlineSnippets: string[];
62+
}
63+
64+
export interface CompletionSnippet {
65+
prefix: string;
66+
label: string;
67+
body: string | string[];
68+
// generated by body
69+
insertText?: string;
4570
}
4671

4772
export interface ModeConfiguration {
@@ -51,6 +76,8 @@ export interface ModeConfiguration {
5176
*/
5277
readonly completionItems: CompletionOptions;
5378

79+
readonly inlineCompletionItems: any;
80+
5481
/**
5582
* Defines whether the built-in diagnostic provider is enabled.
5683
*/
@@ -90,6 +117,9 @@ export interface LanguageServiceDefaults {
90117
readonly modeConfiguration: ModeConfiguration;
91118
preprocessCode: PreprocessCode | null;
92119
completionService: CompletionService;
120+
inlineCompletionService: any;
121+
completionSnippets: CompletionSnippet[];
122+
inlineCompletionSnippets: string[];
93123
triggerCharacters: string[];
94124
setModeConfiguration(modeConfiguration: ModeConfiguration): void;
95125
}
@@ -126,6 +156,18 @@ export class LanguageServiceDefaultsImpl implements LanguageServiceDefaults {
126156
return this._modeConfiguration.completionItems.completionService;
127157
}
128158

159+
get inlineCompletionService(): any {
160+
return this._modeConfiguration.inlineCompletionItems.completionService;
161+
}
162+
163+
get completionSnippets(): CompletionSnippet[] {
164+
return this._modeConfiguration.completionItems.snippets;
165+
}
166+
167+
get inlineCompletionSnippets(): string[] {
168+
return this._modeConfiguration.inlineCompletionItems.inlineSnippets;
169+
}
170+
129171
get triggerCharacters(): string[] {
130172
return this._modeConfiguration.completionItems.triggerCharacters;
131173
}
@@ -167,6 +209,12 @@ export const defaultCompletionService: CompletionService = function (
167209

168210
export const modeConfigurationDefault: Required<ModeConfiguration> = {
169211
completionItems: {
212+
enable: true,
213+
completionService: defaultCompletionService,
214+
triggerCharacters: ['.', ' '],
215+
snippets: []
216+
},
217+
inlineCompletionItems: {
170218
enable: true,
171219
completionService: defaultCompletionService,
172220
triggerCharacters: ['.', ' ']

0 commit comments

Comments
 (0)