mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 02:51:36 -05:00
Merge from vscode 591842cc4b71958c81947b254924a215fe3edcbd (#4886)
This commit is contained in:
@@ -1001,11 +1001,16 @@ export interface ILink {
|
||||
range: IRange;
|
||||
url?: URI | string;
|
||||
}
|
||||
|
||||
export interface ILinksList {
|
||||
links: ILink[];
|
||||
dispose?(): void;
|
||||
}
|
||||
/**
|
||||
* A provider of links.
|
||||
*/
|
||||
export interface LinkProvider {
|
||||
provideLinks(model: model.ITextModel, token: CancellationToken): ProviderResult<ILink[]>;
|
||||
provideLinks(model: model.ITextModel, token: CancellationToken): ProviderResult<ILinksList>;
|
||||
resolveLink?: (link: ILink, token: CancellationToken) => ProviderResult<ILink>;
|
||||
}
|
||||
|
||||
|
||||
@@ -58,12 +58,14 @@ export class EditorWorkerServiceImpl extends Disposable implements IEditorWorker
|
||||
this._workerManager = this._register(new WorkerManager(this._modelService));
|
||||
|
||||
// todo@joh make sure this happens only once
|
||||
this._register(modes.LinkProviderRegistry.register('*', <modes.LinkProvider>{
|
||||
this._register(modes.LinkProviderRegistry.register('*', {
|
||||
provideLinks: (model, token) => {
|
||||
if (!canSyncModel(this._modelService, model.uri)) {
|
||||
return Promise.resolve([]); // File too large
|
||||
return Promise.resolve({ links: [] }); // File too large
|
||||
}
|
||||
return this._workerManager.withWorker().then(client => client.computeLinks(model.uri));
|
||||
return this._workerManager.withWorker().then(client => client.computeLinks(model.uri)).then(links => {
|
||||
return links && { links };
|
||||
});
|
||||
}
|
||||
}));
|
||||
this._register(modes.CompletionProviderRegistry.register('*', new WordBasedCompletionItemProvider(this._workerManager, configurationService, this._modelService)));
|
||||
|
||||
@@ -32,7 +32,7 @@ export class CodeActionSet {
|
||||
}
|
||||
}
|
||||
|
||||
public readonly actions: ReadonlyArray<CodeAction>;
|
||||
public readonly actions: readonly CodeAction[];
|
||||
|
||||
public constructor(actions: CodeAction[]) {
|
||||
this.actions = mergeSort(actions, CodeActionSet.codeActionsComparator);
|
||||
|
||||
@@ -8,9 +8,11 @@ import { onUnexpectedExternalError } from 'vs/base/common/errors';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { ILink, LinkProvider, LinkProviderRegistry } from 'vs/editor/common/modes';
|
||||
import { ILink, LinkProvider, LinkProviderRegistry, ILinksList } from 'vs/editor/common/modes';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { isDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { coalesce } from 'vs/base/common/arrays';
|
||||
|
||||
export class Link implements ILink {
|
||||
|
||||
@@ -66,77 +68,99 @@ export class Link implements ILink {
|
||||
}
|
||||
}
|
||||
|
||||
export function getLinks(model: ITextModel, token: CancellationToken): Promise<Link[]> {
|
||||
export class LinksList extends Disposable {
|
||||
|
||||
let links: Link[] = [];
|
||||
readonly links: Link[];
|
||||
|
||||
constructor(tuples: [ILinksList, LinkProvider][]) {
|
||||
super();
|
||||
let links: Link[] = [];
|
||||
for (const [list, provider] of tuples) {
|
||||
// merge all links
|
||||
const newLinks = list.links.map(link => new Link(link, provider));
|
||||
links = LinksList._union(links, newLinks);
|
||||
// register disposables
|
||||
if (isDisposable(provider)) {
|
||||
this._register(provider);
|
||||
}
|
||||
}
|
||||
this.links = links;
|
||||
}
|
||||
|
||||
private static _union(oldLinks: Link[], newLinks: Link[]): Link[] {
|
||||
// reunite oldLinks with newLinks and remove duplicates
|
||||
let result: Link[] = [];
|
||||
let oldIndex: number;
|
||||
let oldLen: number;
|
||||
let newIndex: number;
|
||||
let newLen: number;
|
||||
|
||||
for (oldIndex = 0, newIndex = 0, oldLen = oldLinks.length, newLen = newLinks.length; oldIndex < oldLen && newIndex < newLen;) {
|
||||
const oldLink = oldLinks[oldIndex];
|
||||
const newLink = newLinks[newIndex];
|
||||
|
||||
if (Range.areIntersectingOrTouching(oldLink.range, newLink.range)) {
|
||||
// Remove the oldLink
|
||||
oldIndex++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const comparisonResult = Range.compareRangesUsingStarts(oldLink.range, newLink.range);
|
||||
|
||||
if (comparisonResult < 0) {
|
||||
// oldLink is before
|
||||
result.push(oldLink);
|
||||
oldIndex++;
|
||||
} else {
|
||||
// newLink is before
|
||||
result.push(newLink);
|
||||
newIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
for (; oldIndex < oldLen; oldIndex++) {
|
||||
result.push(oldLinks[oldIndex]);
|
||||
}
|
||||
for (; newIndex < newLen; newIndex++) {
|
||||
result.push(newLinks[newIndex]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export function getLinks(model: ITextModel, token: CancellationToken): Promise<LinksList> {
|
||||
|
||||
const lists: [ILinksList, LinkProvider][] = [];
|
||||
|
||||
// ask all providers for links in parallel
|
||||
const promises = LinkProviderRegistry.ordered(model).reverse().map(provider => {
|
||||
const promises = LinkProviderRegistry.ordered(model).reverse().map((provider, i) => {
|
||||
return Promise.resolve(provider.provideLinks(model, token)).then(result => {
|
||||
if (Array.isArray(result)) {
|
||||
const newLinks = result.map(link => new Link(link, provider));
|
||||
links = union(links, newLinks);
|
||||
if (result) {
|
||||
lists[i] = [result, provider];
|
||||
}
|
||||
}, onUnexpectedExternalError);
|
||||
});
|
||||
|
||||
return Promise.all(promises).then(() => {
|
||||
return links;
|
||||
});
|
||||
return Promise.all(promises).then(() => new LinksList(coalesce(lists)));
|
||||
}
|
||||
|
||||
function union(oldLinks: Link[], newLinks: Link[]): Link[] {
|
||||
// reunite oldLinks with newLinks and remove duplicates
|
||||
let result: Link[] = [];
|
||||
let oldIndex: number;
|
||||
let oldLen: number;
|
||||
let newIndex: number;
|
||||
let newLen: number;
|
||||
|
||||
for (oldIndex = 0, newIndex = 0, oldLen = oldLinks.length, newLen = newLinks.length; oldIndex < oldLen && newIndex < newLen;) {
|
||||
const oldLink = oldLinks[oldIndex];
|
||||
const newLink = newLinks[newIndex];
|
||||
|
||||
if (Range.areIntersectingOrTouching(oldLink.range, newLink.range)) {
|
||||
// Remove the oldLink
|
||||
oldIndex++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const comparisonResult = Range.compareRangesUsingStarts(oldLink.range, newLink.range);
|
||||
|
||||
if (comparisonResult < 0) {
|
||||
// oldLink is before
|
||||
result.push(oldLink);
|
||||
oldIndex++;
|
||||
} else {
|
||||
// newLink is before
|
||||
result.push(newLink);
|
||||
newIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
for (; oldIndex < oldLen; oldIndex++) {
|
||||
result.push(oldLinks[oldIndex]);
|
||||
}
|
||||
for (; newIndex < newLen; newIndex++) {
|
||||
result.push(newLinks[newIndex]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
CommandsRegistry.registerCommand('_executeLinkProvider', (accessor, ...args) => {
|
||||
|
||||
CommandsRegistry.registerCommand('_executeLinkProvider', async (accessor, ...args): Promise<ILink[]> => {
|
||||
const [uri] = args;
|
||||
if (!(uri instanceof URI)) {
|
||||
return undefined;
|
||||
return [];
|
||||
}
|
||||
|
||||
const model = accessor.get(IModelService).getModel(uri);
|
||||
if (!model) {
|
||||
return undefined;
|
||||
return [];
|
||||
}
|
||||
|
||||
return getLinks(model, CancellationToken.None);
|
||||
const list = await getLinks(model, CancellationToken.None);
|
||||
if (!list) {
|
||||
return [];
|
||||
}
|
||||
const result = list.links.slice(0);
|
||||
list.dispose();
|
||||
return result;
|
||||
});
|
||||
|
||||
@@ -19,7 +19,7 @@ import { IModelDecorationsChangeAccessor, IModelDeltaDecoration, TrackedRangeSti
|
||||
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
|
||||
import { LinkProviderRegistry } from 'vs/editor/common/modes';
|
||||
import { ClickLinkGesture, ClickLinkKeyboardEvent, ClickLinkMouseEvent } from 'vs/editor/contrib/goToDefinition/clickLinkGesture';
|
||||
import { Link, getLinks } from 'vs/editor/contrib/links/getLinks';
|
||||
import { Link, getLinks, LinksList } from 'vs/editor/contrib/links/getLinks';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { editorActiveLinkForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
@@ -157,7 +157,8 @@ class LinkDetector implements editorCommon.IEditorContribution {
|
||||
private enabled: boolean;
|
||||
private listenersToRemove: IDisposable[];
|
||||
private readonly timeout: async.TimeoutTimer;
|
||||
private computePromise: async.CancelablePromise<Link[]> | null;
|
||||
private computePromise: async.CancelablePromise<LinksList> | null;
|
||||
private activeLinksList: LinksList | null;
|
||||
private activeLinkDecorationId: string | null;
|
||||
private readonly openerService: IOpenerService;
|
||||
private readonly notificationService: INotificationService;
|
||||
@@ -210,6 +211,7 @@ class LinkDetector implements editorCommon.IEditorContribution {
|
||||
|
||||
this.timeout = new async.TimeoutTimer();
|
||||
this.computePromise = null;
|
||||
this.activeLinksList = null;
|
||||
this.currentOccurrences = {};
|
||||
this.activeLinkDecorationId = null;
|
||||
this.beginCompute();
|
||||
@@ -246,10 +248,15 @@ class LinkDetector implements editorCommon.IEditorContribution {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.activeLinksList) {
|
||||
this.activeLinksList.dispose();
|
||||
this.activeLinksList = null;
|
||||
}
|
||||
|
||||
this.computePromise = async.createCancelablePromise(token => getLinks(model, token));
|
||||
try {
|
||||
const links = await this.computePromise;
|
||||
this.updateDecorations(links);
|
||||
this.activeLinksList = await this.computePromise;
|
||||
this.updateDecorations(this.activeLinksList.links);
|
||||
} catch (err) {
|
||||
onUnexpectedError(err);
|
||||
} finally {
|
||||
@@ -380,6 +387,9 @@ class LinkDetector implements editorCommon.IEditorContribution {
|
||||
|
||||
private stop(): void {
|
||||
this.timeout.cancel();
|
||||
if (this.activeLinksList) {
|
||||
this.activeLinksList.dispose();
|
||||
}
|
||||
if (this.computePromise) {
|
||||
this.computePromise.cancel();
|
||||
this.computePromise = null;
|
||||
|
||||
Reference in New Issue
Block a user