Skip to content

Commit 4b9461f

Browse files
authored
Merge pull request #228 from DTStack/next
Sync next to main
2 parents 7231989 + cdaa17c commit 4b9461f

18 files changed

Lines changed: 1157 additions & 38 deletions

README-zh_CN.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,45 @@ npm install monaco-sql-languages
205205

206206
<br/>
207207

208+
## 运行语句按钮
209+
210+
在每条 SQL 语句前显示 gutter 运行图标。创建编辑器后调用 `createRunStatementButton`,编辑器销毁时调用 `dispose()`
211+
212+
```typescript
213+
import {
214+
LanguageIdEnum,
215+
createRunStatementButton,
216+
getStatementRangesByLanguage
217+
} from 'monaco-sql-languages';
218+
219+
const controller = createRunStatementButton({
220+
editor,
221+
languageId: LanguageIdEnum.FLINK,
222+
glyphMarginHoverMessage: '运行此语句',
223+
preprocessCode: (code) => code,
224+
onRun: ({ statement, editor, model }) => {
225+
console.log(statement.text);
226+
}
227+
});
228+
229+
// controller.refresh(); // 需要时手动刷新图标
230+
// controller.dispose(); // 编辑器卸载时调用
231+
```
232+
233+
**说明**
234+
235+
- 建议显式传入 `languageId`,以便内置拆分器使用正确的 parser
236+
- 自定义 `getStatementRanges` 只需提供准确的 `startLineNumber``text``executableLineNumber` 会自动归一化。
237+
- 编辑器只读时不显示图标,且忽略点击。
238+
- 若只需内置拆分逻辑,可单独使用 `getStatementRangesByLanguage(code, languageId, preprocessCode)`
239+
- `preprocessCode` 必须与编辑器 model 保持行号对齐(不要增删行导致行号偏移);装饰是打在原始 model 上的。
240+
- 默认情况下,仅空白或仅分号的片段(如 `;;;`)不显示运行图标。
241+
- `executableLineNumber` 会跳过 leading 注释,但不解析字符串字面量;若 leading 字符串内含 `/*``--` 可能误判(实际场景较少见)。
242+
- 多条语句的 `executableLineNumber` 相同时会输出 console 警告,gutter 点击以最后一条为准。
243+
- 编辑器销毁时请调用 `controller.dispose()`(每个编辑器实例对应一个 controller)。
244+
245+
<br/>
246+
208247
## 代码片段
209248
我们为每种SQL语言内置了一部分代码片段, 帮助我们快速编写SQL
210249

README.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,45 @@ npm install monaco-sql-languages
205205

206206
<br/>
207207

208+
## Run Statement Button
209+
210+
Add a gutter run icon before each SQL statement. Call `createRunStatementButton` after creating the editor and dispose the controller when the editor is destroyed.
211+
212+
```typescript
213+
import {
214+
LanguageIdEnum,
215+
createRunStatementButton,
216+
getStatementRangesByLanguage
217+
} from 'monaco-sql-languages';
218+
219+
const controller = createRunStatementButton({
220+
editor,
221+
languageId: LanguageIdEnum.FLINK,
222+
glyphMarginHoverMessage: 'Run this statement',
223+
preprocessCode: (code) => code,
224+
onRun: ({ statement, editor, model }) => {
225+
console.log(statement.text);
226+
}
227+
});
228+
229+
// controller.refresh(); // recompute icons manually when needed
230+
// controller.dispose(); // on editor unmount
231+
```
232+
233+
**Notes**
234+
235+
- Pass `languageId` explicitly so the built-in splitter uses the correct parser.
236+
- Custom `getStatementRanges` only needs accurate `startLineNumber` and `text`; `executableLineNumber` is normalized automatically.
237+
- Icons are hidden and clicks are ignored when the editor is read-only.
238+
- Use `getStatementRangesByLanguage(code, languageId, preprocessCode)` if you need the built-in splitter outside the button.
239+
- `preprocessCode` must keep the same line mapping as the editor model (no insert/delete that shifts lines); decorations are applied to the original model.
240+
- By default, blank or semicolon-only fragments (e.g. `;;;`) do not show a run icon.
241+
- `executableLineNumber` detection skips leading comments but does not parse string literals; a leading string that contains `/*` or `--` may be misidentified (rare in practice).
242+
- When multiple statements share the same `executableLineNumber`, a console warning is emitted and the last one wins for gutter clicks.
243+
- Call `controller.dispose()` when the editor is destroyed (one controller per editor instance).
244+
245+
<br/>
246+
208247
## SQL Snippets
209248

210249
We provide some built-in SQL snippets for each SQL language, which helps us to write SQL quickly.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,6 @@
104104
]
105105
},
106106
"dependencies": {
107-
"dt-sql-parser": "4.5.0"
107+
"dt-sql-parser": "4.5.1"
108108
}
109109
}

pnpm-lock.yaml

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/common/utils.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
1+
export interface DebouncedFunction<T extends (...args: unknown[]) => unknown> {
2+
(...args: Parameters<T>): unknown;
3+
cancel: () => void;
4+
}
5+
16
export function debounce<T extends (...args: unknown[]) => unknown>(
27
func: T,
38
timeout: number,
49
immediate?: boolean
5-
): (...args: Parameters<T>) => unknown {
10+
): DebouncedFunction<T> {
611
let timer: NodeJS.Timeout | null = null;
7-
return (...args) => {
12+
13+
const debounced = (...args: Parameters<T>) => {
814
if (timer) {
915
clearTimeout(timer);
1016
}
@@ -18,4 +24,13 @@ export function debounce<T extends (...args: unknown[]) => unknown>(
1824
func?.(...args);
1925
}, timeout);
2026
};
27+
28+
debounced.cancel = () => {
29+
if (timer) {
30+
clearTimeout(timer);
31+
timer = null;
32+
}
33+
};
34+
35+
return debounced;
2136
}

src/languageFeatures.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,33 @@ function toDiagnostics(_resource: Uri, diag: ParseError): editor.IMarkerData {
145145
};
146146
}
147147

148+
interface TokenizationTextModel {
149+
tokenization?: {
150+
tokenizeLinesAt?: (
151+
lineNumber: number,
152+
lines: string[]
153+
) => Array<{
154+
findTokenIndexAtOffset: (offset: number) => number;
155+
getStandardTokenType: (tokenIndex: number) => number;
156+
}> | null;
157+
};
158+
}
159+
160+
function isPositionInComment(model: editor.IReadOnlyModel, position: Position): boolean {
161+
const lineContent = model.getLineContent(position.lineNumber);
162+
const tokenizationModel = model as editor.IReadOnlyModel & TokenizationTextModel;
163+
// 在光标处追加哨兵字符,避免将刚结束的块注释误判为仍在注释中
164+
const tokenizedLine = tokenizationModel.tokenization?.tokenizeLinesAt?.(position.lineNumber, [
165+
`${lineContent.slice(0, position.column - 1)}x`
166+
])?.[0];
167+
if (!tokenizedLine) {
168+
return false;
169+
}
170+
171+
const tokenIndex = tokenizedLine.findTokenIndexAtOffset(position.column - 1);
172+
return tokenizedLine.getStandardTokenType(tokenIndex) === 1;
173+
}
174+
148175
export class CompletionAdapter<T extends BaseSQLWorker>
149176
implements languages.CompletionItemProvider
150177
{
@@ -165,6 +192,10 @@ export class CompletionAdapter<T extends BaseSQLWorker>
165192
context: languages.CompletionContext,
166193
_token: CancellationToken
167194
): Promise<languages.CompletionList> {
195+
if (isPositionInComment(model, position)) {
196+
return Promise.resolve({ suggestions: [] });
197+
}
198+
168199
const resource = model.uri;
169200
return this._worker(resource)
170201
.then((worker) => {

src/main.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export * from './setupLanguageFeatures';
55
export * from './common/constants';
66
export * from './theme';
77
export * as snippets from './snippets';
8+
export * from './runStatementButton';
89

910
export { EntityContextType, StmtContextType } from 'dt-sql-parser';
1011

0 commit comments

Comments
 (0)