diff --git a/src/languageFeatures.ts b/src/languageFeatures.ts index 2a9a869e..47f0f2fb 100644 --- a/src/languageFeatures.ts +++ b/src/languageFeatures.ts @@ -1,16 +1,22 @@ +import type { ParseError } from 'dt-sql-parser'; import { + EntityContext, +} from 'dt-sql-parser/dist/parser/common/entityCollector'; +import { WordPosition } from 'dt-sql-parser/dist/parser/common/textAndWord'; +import * as monaco from 'monaco-editor'; + +import { BaseSQLWorker } from './baseSQLWorker'; +import { debounce } from './common/utils'; +import { + CancellationToken, editor, - Uri, IDisposable, - MarkerSeverity, - Range, languages, + MarkerSeverity, Position, - CancellationToken + Range, + Uri, } from './fillers/monaco-editor-core'; -import { debounce } from './common/utils'; -import { BaseSQLWorker } from './baseSQLWorker'; -import type { ParseError } from 'dt-sql-parser'; import type { LanguageServiceDefaults } from './monaco.contribution'; export interface WorkerAccessor { @@ -197,3 +203,101 @@ export class CompletionAdapter }); } } + +export class DefinitionAdapter implements languages.DefinitionProvider { + constructor( + private readonly _worker: WorkerAccessor, + private readonly _defaults: LanguageServiceDefaults) {} + provideDefinition( + model: editor.IReadOnlyModel, + position: Position, + _token: CancellationToken + ): languages.ProviderResult { + const resource = model.uri; + const lineContent = model.getLineContent(position.lineNumber); + if (lineContent.startsWith('--')) return null; + return this._worker(resource) + .then((worker) => { + let code = model?.getValue() || ''; + if (typeof this._defaults.preprocessCode === 'function') { + code = this._defaults.preprocessCode(code); + } + return worker.getAllEntities(code); + }) + .then((entities) => { + const word = model.getWordAtPosition(position); + let pos: WordPosition = { + line: -1, + startIndex: -1, + endIndex: -1, + startColumn: -1, + endColumn: -1 + }; + entities?.forEach((entity: EntityContext) => { + if ( + entity.entityContextType.includes('Create') && + word?.word && + entity.text === word?.word + ) { + pos = entity.position; + } + }); + if (pos && pos.line !== -1) { + return { + uri: model.uri, + range: new monaco.Range( + pos?.line, + pos?.startColumn, + pos?.line, + pos?.endColumn + ) + }; + } + }); + } +} + +export class ReferenceAdapter implements languages.ReferenceProvider { + constructor( + private readonly _worker: WorkerAccessor, + private readonly _defaults: LanguageServiceDefaults + ) {} + provideReferences( + model: editor.IReadOnlyModel, + position: Position, + _context: languages.ReferenceContext, + _token: CancellationToken + ): languages.ProviderResult { + const resource = model.uri; + const lineContent = model.getLineContent(position.lineNumber); + if (!lineContent.startsWith('CREATE')) return; + return this._worker(resource) + .then((worker) => { + let code = model?.getValue() || ''; + if (typeof this._defaults.preprocessCode === 'function') { + code = this._defaults.preprocessCode(code); + } + return worker.getAllEntities(model?.getValue()); + }) + .then((entities) => { + const word = model.getWordAtPosition(position); + const arr: languages.Location[] = []; + entities?.forEach((entity) => { + if (word?.word && entity.text === word?.word) { + let pos: WordPosition | null = null; + pos = entity.position; + arr.push({ + uri: model.uri, + range: new monaco.Range( + pos?.line, + pos?.startColumn, + pos?.line, + pos?.endColumn + ) + }); + } + }); + return arr; + }); + } +} diff --git a/src/languages/flink/flink.contribution.ts b/src/languages/flink/flink.contribution.ts index 5efc8c86..fa1462fd 100644 --- a/src/languages/flink/flink.contribution.ts +++ b/src/languages/flink/flink.contribution.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { registerLanguage } from '../../_.contribution'; -import { setupLanguageFeatures } from '../../setupLanguageFeatures'; import { LanguageIdEnum } from '../../common/constants'; +import { setupLanguageFeatures } from '../../setupLanguageFeatures'; registerLanguage({ id: LanguageIdEnum.FLINK, @@ -16,5 +16,7 @@ registerLanguage({ setupLanguageFeatures(LanguageIdEnum.FLINK, { completionItems: true, - diagnostics: true + diagnostics: true, + references: true, + definitions: true, }); diff --git a/src/languages/hive/hive.contribution.ts b/src/languages/hive/hive.contribution.ts index 1ec7650b..9becbd54 100644 --- a/src/languages/hive/hive.contribution.ts +++ b/src/languages/hive/hive.contribution.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { registerLanguage } from '../../_.contribution'; -import { setupLanguageFeatures } from '../../setupLanguageFeatures'; import { LanguageIdEnum } from '../../common/constants'; +import { setupLanguageFeatures } from '../../setupLanguageFeatures'; registerLanguage({ id: LanguageIdEnum.HIVE, @@ -16,5 +16,7 @@ registerLanguage({ setupLanguageFeatures(LanguageIdEnum.HIVE, { completionItems: true, - diagnostics: true + diagnostics: true, + references: true, + definitions: true, }); diff --git a/src/languages/impala/impala.contribution.ts b/src/languages/impala/impala.contribution.ts index 35a6b6f0..6167a6de 100644 --- a/src/languages/impala/impala.contribution.ts +++ b/src/languages/impala/impala.contribution.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { registerLanguage } from '../../_.contribution'; -import { setupLanguageFeatures } from '../../setupLanguageFeatures'; import { LanguageIdEnum } from '../../common/constants'; +import { setupLanguageFeatures } from '../../setupLanguageFeatures'; registerLanguage({ id: LanguageIdEnum.IMPALA, @@ -16,5 +16,7 @@ registerLanguage({ setupLanguageFeatures(LanguageIdEnum.IMPALA, { completionItems: true, - diagnostics: true + diagnostics: true, + references: true, + definitions: true, }); diff --git a/src/languages/mysql/mysql.contribution.ts b/src/languages/mysql/mysql.contribution.ts index bd4c8be1..964b2040 100644 --- a/src/languages/mysql/mysql.contribution.ts +++ b/src/languages/mysql/mysql.contribution.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { registerLanguage } from '../../_.contribution'; -import { setupLanguageFeatures } from '../../setupLanguageFeatures'; import { LanguageIdEnum } from '../../common/constants'; +import { setupLanguageFeatures } from '../../setupLanguageFeatures'; registerLanguage({ id: LanguageIdEnum.MYSQL, @@ -16,5 +16,7 @@ registerLanguage({ setupLanguageFeatures(LanguageIdEnum.MYSQL, { completionItems: true, - diagnostics: true + diagnostics: true, + references: true, + definitions: true, }); diff --git a/src/languages/pgsql/pgsql.contribution.ts b/src/languages/pgsql/pgsql.contribution.ts index 6d6adc56..51e6b7ec 100644 --- a/src/languages/pgsql/pgsql.contribution.ts +++ b/src/languages/pgsql/pgsql.contribution.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { registerLanguage } from '../../_.contribution'; -import { setupLanguageFeatures } from '../../setupLanguageFeatures'; import { LanguageIdEnum } from '../../common/constants'; +import { setupLanguageFeatures } from '../../setupLanguageFeatures'; registerLanguage({ id: LanguageIdEnum.PG, @@ -16,5 +16,7 @@ registerLanguage({ setupLanguageFeatures(LanguageIdEnum.PG, { completionItems: true, - diagnostics: true + diagnostics: true, + references: true, + definitions: true, }); diff --git a/src/languages/spark/spark.contribution.ts b/src/languages/spark/spark.contribution.ts index 18c67757..db0c112d 100644 --- a/src/languages/spark/spark.contribution.ts +++ b/src/languages/spark/spark.contribution.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { registerLanguage } from '../../_.contribution'; -import { setupLanguageFeatures } from '../../setupLanguageFeatures'; import { LanguageIdEnum } from '../../common/constants'; +import { setupLanguageFeatures } from '../../setupLanguageFeatures'; registerLanguage({ id: LanguageIdEnum.SPARK, @@ -16,5 +16,7 @@ registerLanguage({ setupLanguageFeatures(LanguageIdEnum.SPARK, { completionItems: true, - diagnostics: true + diagnostics: true, + references: true, + definitions: true, }); diff --git a/src/languages/trino/trino.contribution.ts b/src/languages/trino/trino.contribution.ts index c8971197..a7aa8b42 100644 --- a/src/languages/trino/trino.contribution.ts +++ b/src/languages/trino/trino.contribution.ts @@ -1,6 +1,6 @@ import { registerLanguage } from '../../_.contribution'; -import { setupLanguageFeatures } from '../../setupLanguageFeatures'; import { LanguageIdEnum } from '../../common/constants'; +import { setupLanguageFeatures } from '../../setupLanguageFeatures'; registerLanguage({ id: LanguageIdEnum.TRINO, @@ -11,5 +11,7 @@ registerLanguage({ setupLanguageFeatures(LanguageIdEnum.TRINO, { completionItems: true, - diagnostics: true + diagnostics: true, + references: true, + definitions: true, }); diff --git a/src/monaco.contribution.ts b/src/monaco.contribution.ts index e655fc54..03cce1dd 100644 --- a/src/monaco.contribution.ts +++ b/src/monaco.contribution.ts @@ -1,5 +1,16 @@ -import { languages, Emitter, IEvent, editor, Position, IRange } from './fillers/monaco-editor-core'; -import { EntityContext, Suggestions } from 'dt-sql-parser'; +import { + EntityContext, + Suggestions, +} from 'dt-sql-parser'; + +import { + editor, + Emitter, + IEvent, + IRange, + languages, + Position, +} from './fillers/monaco-editor-core'; /** * A completion item. @@ -65,7 +76,7 @@ export interface ModeConfiguration { /** * Defines whether the built-in definitions provider is enabled. */ - // readonly definitions?: boolean; + readonly definitions?: boolean; /** * Defines whether the built-in rename provider is enabled. @@ -75,7 +86,7 @@ export interface ModeConfiguration { /** * Defines whether the built-in references provider is enabled. */ - // readonly references?: boolean; + readonly references?: boolean; } /** @@ -171,5 +182,7 @@ export const modeConfigurationDefault: Required = { completionService: defaultCompletionService, triggerCharacters: ['.', ' '] }, - diagnostics: true + diagnostics: true, + definitions: true, + references: true }; diff --git a/src/setupLanguageFeatures.ts b/src/setupLanguageFeatures.ts index bdaeb0f6..66bfdab2 100644 --- a/src/setupLanguageFeatures.ts +++ b/src/setupLanguageFeatures.ts @@ -1,13 +1,16 @@ +import { LanguageIdEnum } from './common/constants'; import { - PreprocessCode, + IDisposable, + languages, +} from './fillers/monaco-editor-core'; +import { + CompletionOptions, LanguageServiceDefaults, LanguageServiceDefaultsImpl, - modeConfigurationDefault, ModeConfiguration, - CompletionOptions + modeConfigurationDefault, + PreprocessCode, } from './monaco.contribution'; -import { languages, IDisposable } from './fillers/monaco-editor-core'; -import { LanguageIdEnum } from './common/constants'; export interface FeatureConfiguration { /** @@ -20,6 +23,14 @@ export interface FeatureConfiguration { * Defaults to true. */ diagnostics?: boolean; + /** + * Defines whether the built-in definitions provider is enabled. + */ + definitions?: boolean; + /** + * Defines whether the built-in references provider is enabled. + */ + references?: boolean; /** * Define a function to preprocess code. * By default, do not something. @@ -110,6 +121,14 @@ function processConfiguration( ? configuration.completionItems!.triggerCharacters : (defaults?.modeConfiguration.completionItems.triggerCharacters ?? modeConfigurationDefault.completionItems.triggerCharacters); + const references = + typeof configuration.references === 'boolean' + ? configuration.references + : (defaults?.modeConfiguration.references ?? modeConfigurationDefault.references); + const definitions = + typeof configuration.definitions === 'boolean' + ? configuration.definitions + : (defaults?.modeConfiguration.definitions ?? modeConfigurationDefault.definitions); return { diagnostics, @@ -117,6 +136,8 @@ function processConfiguration( enable: completionEnable, completionService, triggerCharacters - } + }, + references, + definitions, }; } diff --git a/src/setupLanguageMode.ts b/src/setupLanguageMode.ts index 03a13d8b..77e96aa1 100644 --- a/src/setupLanguageMode.ts +++ b/src/setupLanguageMode.ts @@ -1,8 +1,12 @@ -import { WorkerManager } from './workerManager'; -import { LanguageServiceDefaults } from './monaco.contribution'; -import * as languageFeatures from './languageFeatures'; -import { Uri, IDisposable, languages } from './fillers/monaco-editor-core'; import type { BaseSQLWorker } from './baseSQLWorker'; +import { + IDisposable, + languages, + Uri, +} from './fillers/monaco-editor-core'; +import * as languageFeatures from './languageFeatures'; +import { LanguageServiceDefaults } from './monaco.contribution'; +import { WorkerManager } from './workerManager'; export function setupLanguageMode( defaults: LanguageServiceDefaults @@ -19,7 +23,6 @@ export function setupLanguageMode( function registerProviders(): void { const { languageId, modeConfiguration } = defaults; - disposeAll(providers); if (modeConfiguration.diagnostics) { @@ -34,6 +37,24 @@ export function setupLanguageMode( ) ); } + + if (modeConfiguration.references) { + providers.push( + languages.registerReferenceProvider( + languageId, + new languageFeatures.ReferenceAdapter(worker, defaults) + ) + ); + } + + if (modeConfiguration.definitions) { + providers.push( + languages.registerDefinitionProvider( + languageId, + new languageFeatures.DefinitionAdapter(worker, defaults) + ) + ); + } } registerProviders();