deploy: current vibn theia state
Made-with: Cursor
This commit is contained in:
10
packages/callhierarchy/.eslintrc.js
Normal file
10
packages/callhierarchy/.eslintrc.js
Normal file
@@ -0,0 +1,10 @@
|
||||
/** @type {import('eslint').Linter.Config} */
|
||||
module.exports = {
|
||||
extends: [
|
||||
'../../configs/build.eslintrc.json'
|
||||
],
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: 'tsconfig.json'
|
||||
}
|
||||
};
|
||||
31
packages/callhierarchy/README.md
Normal file
31
packages/callhierarchy/README.md
Normal file
@@ -0,0 +1,31 @@
|
||||
<div align='center'>
|
||||
|
||||
<br />
|
||||
|
||||
<img src='https://raw.githubusercontent.com/eclipse-theia/theia/master/logo/theia.svg?sanitize=true' alt='theia-ext-logo' width='100px' />
|
||||
|
||||
<h2>ECLIPSE THEIA - CALL HIERARCHY EXTENSION</h2>
|
||||
|
||||
<hr />
|
||||
|
||||
</div>
|
||||
|
||||
## Description
|
||||
|
||||
The `@theia/callhierarchy` extension contributes a `call hierarchy` view which displays the caller hierarchy for a selected callable.
|
||||
|
||||
## Additional Information
|
||||
|
||||
- [API documentation for `@theia/callhierarchy`](https://eclipse-theia.github.io/theia/docs/next/modules/_theia_callhierarchy.html)
|
||||
- [Theia - GitHub](https://github.com/eclipse-theia/theia)
|
||||
- [Theia - Website](https://theia-ide.org/)
|
||||
|
||||
## License
|
||||
|
||||
- [Eclipse Public License 2.0](http://www.eclipse.org/legal/epl-2.0/)
|
||||
- [一 (Secondary) GNU General Public License, version 2 with the GNU Classpath Exception](https://projects.eclipse.org/license/secondary-gpl-2.0-cp)
|
||||
|
||||
## Trademark
|
||||
|
||||
"Theia" is a trademark of the Eclipse Foundation
|
||||
<https://www.eclipse.org/theia>
|
||||
50
packages/callhierarchy/package.json
Normal file
50
packages/callhierarchy/package.json
Normal file
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"name": "@theia/callhierarchy",
|
||||
"version": "1.68.0",
|
||||
"description": "Theia - Call Hierarchy Extension",
|
||||
"dependencies": {
|
||||
"@theia/core": "1.68.0",
|
||||
"@theia/editor": "1.68.0",
|
||||
"ts-md5": "^1.2.2",
|
||||
"tslib": "^2.6.2"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"theiaExtensions": [
|
||||
{
|
||||
"frontend": "lib/browser/callhierarchy-frontend-module"
|
||||
}
|
||||
],
|
||||
"keywords": [
|
||||
"theia-extension"
|
||||
],
|
||||
"license": "EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/eclipse-theia/theia.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/eclipse-theia/theia/issues"
|
||||
},
|
||||
"homepage": "https://github.com/eclipse-theia/theia",
|
||||
"files": [
|
||||
"lib",
|
||||
"src"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "theiaext build",
|
||||
"clean": "theiaext clean",
|
||||
"compile": "theiaext compile",
|
||||
"lint": "theiaext lint",
|
||||
"test": "theiaext test",
|
||||
"watch": "theiaext watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@theia/ext-scripts": "1.68.0"
|
||||
},
|
||||
"nyc": {
|
||||
"extends": "../../configs/nyc.json"
|
||||
},
|
||||
"gitHead": "21358137e41342742707f660b8e222f940a27652"
|
||||
}
|
||||
103
packages/callhierarchy/src/browser/callhierarchy-contribution.ts
Normal file
103
packages/callhierarchy/src/browser/callhierarchy-contribution.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2018 TypeFox and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import { injectable, inject, postConstruct } from '@theia/core/shared/inversify';
|
||||
import { MenuModelRegistry, Command, CommandRegistry } from '@theia/core/lib/common';
|
||||
import { AbstractViewContribution, OpenViewArguments, KeybindingRegistry } from '@theia/core/lib/browser';
|
||||
import { EDITOR_CONTEXT_MENU, CurrentEditorAccess, EditorManager } from '@theia/editor/lib/browser';
|
||||
import { CallHierarchyTreeWidget } from './callhierarchy-tree/callhierarchy-tree-widget';
|
||||
import { CALLHIERARCHY_ID, CALL_HIERARCHY_LABEL, CALL_HIERARCHY_TOGGLE_COMMAND_ID } from './callhierarchy';
|
||||
import { CallHierarchyServiceProvider } from './callhierarchy-service';
|
||||
import URI from '@theia/core/lib/common/uri';
|
||||
import { ContextKey, ContextKeyService } from '@theia/core/lib/browser/context-key-service';
|
||||
export { CALL_HIERARCHY_LABEL, CALL_HIERARCHY_TOGGLE_COMMAND_ID };
|
||||
|
||||
export namespace CallHierarchyCommands {
|
||||
export const OPEN = Command.toLocalizedCommand({
|
||||
id: 'callhierarchy:open',
|
||||
label: 'Open Call Hierarchy'
|
||||
}, 'theia/callhierarchy/open');
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export class CallHierarchyContribution extends AbstractViewContribution<CallHierarchyTreeWidget> {
|
||||
|
||||
@inject(CurrentEditorAccess) protected readonly editorAccess: CurrentEditorAccess;
|
||||
@inject(EditorManager) protected readonly editorManager: EditorManager;
|
||||
@inject(CallHierarchyServiceProvider) protected readonly callHierarchyServiceProvider: CallHierarchyServiceProvider;
|
||||
@inject(ContextKeyService) protected readonly contextKeyService: ContextKeyService;
|
||||
|
||||
protected editorHasCallHierarchyProvider!: ContextKey<boolean>;
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
widgetId: CALLHIERARCHY_ID,
|
||||
widgetName: CALL_HIERARCHY_LABEL,
|
||||
defaultWidgetOptions: {
|
||||
area: 'bottom'
|
||||
},
|
||||
toggleCommandId: CALL_HIERARCHY_TOGGLE_COMMAND_ID,
|
||||
toggleKeybinding: 'ctrlcmd+shift+f1'
|
||||
});
|
||||
}
|
||||
|
||||
@postConstruct()
|
||||
protected init(): void {
|
||||
this.editorHasCallHierarchyProvider = this.contextKeyService.createKey('editorHasCallHierarchyProvider', false);
|
||||
this.editorManager.onCurrentEditorChanged(() => this.editorHasCallHierarchyProvider.set(this.isCallHierarchyAvailable()));
|
||||
this.callHierarchyServiceProvider.onDidChange(() => this.editorHasCallHierarchyProvider.set(this.isCallHierarchyAvailable()));
|
||||
}
|
||||
|
||||
protected isCallHierarchyAvailable(): boolean {
|
||||
const { selection, languageId } = this.editorAccess;
|
||||
return !!selection && !!languageId && !!this.callHierarchyServiceProvider.get(languageId, new URI(selection.uri));
|
||||
}
|
||||
|
||||
override async openView(args?: Partial<OpenViewArguments>): Promise<CallHierarchyTreeWidget> {
|
||||
const widget = await super.openView(args);
|
||||
const { selection, languageId } = this.editorAccess;
|
||||
widget.initializeModel(selection, languageId);
|
||||
return widget;
|
||||
}
|
||||
|
||||
override registerCommands(commands: CommandRegistry): void {
|
||||
commands.registerCommand(CallHierarchyCommands.OPEN, {
|
||||
execute: () => this.openView({
|
||||
toggle: false,
|
||||
activate: true
|
||||
}),
|
||||
isEnabled: this.isCallHierarchyAvailable.bind(this)
|
||||
});
|
||||
super.registerCommands(commands);
|
||||
}
|
||||
|
||||
override registerMenus(menus: MenuModelRegistry): void {
|
||||
const menuPath = [...EDITOR_CONTEXT_MENU, 'navigation'];
|
||||
menus.registerMenuAction(menuPath, {
|
||||
commandId: CallHierarchyCommands.OPEN.id,
|
||||
label: CALL_HIERARCHY_LABEL
|
||||
});
|
||||
super.registerMenus(menus);
|
||||
}
|
||||
|
||||
override registerKeybindings(keybindings: KeybindingRegistry): void {
|
||||
super.registerKeybindings(keybindings);
|
||||
keybindings.registerKeybinding({
|
||||
command: CallHierarchyCommands.OPEN.id,
|
||||
keybinding: 'ctrlcmd+f1'
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2018 TypeFox and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import { CallHierarchyContribution } from './callhierarchy-contribution';
|
||||
import { bindContributionProvider } from '@theia/core/lib/common';
|
||||
import { CallHierarchyService, CallHierarchyServiceProvider } from './callhierarchy-service';
|
||||
import { WidgetFactory, bindViewContribution } from '@theia/core/lib/browser';
|
||||
import { CALLHIERARCHY_ID } from './callhierarchy';
|
||||
import { createHierarchyTreeWidget } from './callhierarchy-tree';
|
||||
import { ContainerModule } from '@theia/core/shared/inversify';
|
||||
|
||||
import '../../src/browser/style/index.css';
|
||||
|
||||
export default new ContainerModule(bind => {
|
||||
bindContributionProvider(bind, CallHierarchyService);
|
||||
bind(CallHierarchyServiceProvider).to(CallHierarchyServiceProvider).inSingletonScope();
|
||||
|
||||
bindViewContribution(bind, CallHierarchyContribution);
|
||||
|
||||
bind(WidgetFactory).toDynamicValue(context => ({
|
||||
id: CALLHIERARCHY_ID,
|
||||
createWidget: () => createHierarchyTreeWidget(context.container)
|
||||
}));
|
||||
});
|
||||
89
packages/callhierarchy/src/browser/callhierarchy-service.ts
Normal file
89
packages/callhierarchy/src/browser/callhierarchy-service.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2018 TypeFox and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import { injectable, inject, named, postConstruct } from '@theia/core/shared/inversify';
|
||||
import { Position, DocumentUri } from '@theia/core/shared/vscode-languageserver-protocol';
|
||||
import { CancellationToken } from '@theia/core';
|
||||
import URI from '@theia/core/lib/common/uri';
|
||||
import { ContributionProvider, Disposable, Emitter, Event } from '@theia/core/lib/common';
|
||||
import { CallHierarchyItem, CallHierarchyIncomingCall, CallHierarchyOutgoingCall } from './callhierarchy';
|
||||
import { LanguageSelector, score } from '@theia/editor/lib/common/language-selector';
|
||||
|
||||
export const CallHierarchyService = Symbol('CallHierarchyService');
|
||||
|
||||
export interface CallHierarchySession {
|
||||
items: CallHierarchyItem[];
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export interface CallHierarchyService {
|
||||
|
||||
readonly selector: LanguageSelector;
|
||||
|
||||
getRootDefinition(uri: DocumentUri, position: Position, cancellationToken: CancellationToken): Promise<CallHierarchySession | undefined>
|
||||
getCallers(definition: CallHierarchyItem, cancellationToken: CancellationToken): Promise<CallHierarchyIncomingCall[] | undefined>
|
||||
getCallees?(definition: CallHierarchyItem, cancellationToken: CancellationToken): Promise<CallHierarchyOutgoingCall[] | undefined>
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export class CallHierarchyServiceProvider {
|
||||
|
||||
@inject(ContributionProvider) @named(CallHierarchyService)
|
||||
protected readonly contributions: ContributionProvider<CallHierarchyService>;
|
||||
|
||||
protected readonly onDidChangeEmitter = new Emitter<void>();
|
||||
get onDidChange(): Event<void> {
|
||||
return this.onDidChangeEmitter.event;
|
||||
}
|
||||
|
||||
private services: CallHierarchyService[] = [];
|
||||
|
||||
@postConstruct()
|
||||
init(): void {
|
||||
this.services = this.services.concat(this.contributions.getContributions());
|
||||
}
|
||||
|
||||
get(languageId: string, uri: URI): CallHierarchyService | undefined {
|
||||
return this.services
|
||||
.filter(service => this.score(service, languageId, uri) > 0)
|
||||
.sort((left, right) => this.score(right, languageId, uri) - this.score(left, languageId, uri))[0];
|
||||
}
|
||||
|
||||
protected score(service: CallHierarchyService, languageId: string, uri: URI): number {
|
||||
return score(service.selector, uri.scheme, uri.path.toString(), languageId, true);
|
||||
}
|
||||
|
||||
add(service: CallHierarchyService): Disposable {
|
||||
this.services.push(service);
|
||||
const that = this;
|
||||
this.onDidChangeEmitter.fire();
|
||||
return {
|
||||
dispose: () => {
|
||||
that.remove(service);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private remove(service: CallHierarchyService): boolean {
|
||||
const length = this.services.length;
|
||||
this.services = this.services.filter(value => value !== service);
|
||||
const serviceWasRemoved = length !== this.services.length;
|
||||
if (serviceWasRemoved) {
|
||||
this.onDidChangeEmitter.fire();
|
||||
}
|
||||
return serviceWasRemoved;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2018 TypeFox and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import { interfaces, Container } from '@theia/core/shared/inversify';
|
||||
import { createTreeContainer } from '@theia/core/lib/browser';
|
||||
import { CallHierarchyTree } from './callhierarchy-tree';
|
||||
import { CallHierarchyTreeModel } from './callhierarchy-tree-model';
|
||||
import { CallHierarchyTreeWidget } from './callhierarchy-tree-widget';
|
||||
|
||||
function createHierarchyTreeContainer(parent: interfaces.Container): Container {
|
||||
const child = createTreeContainer(parent, {
|
||||
tree: CallHierarchyTree,
|
||||
model: CallHierarchyTreeModel,
|
||||
widget: CallHierarchyTreeWidget,
|
||||
});
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
export function createHierarchyTreeWidget(parent: interfaces.Container): CallHierarchyTreeWidget {
|
||||
return createHierarchyTreeContainer(parent).get<CallHierarchyTreeWidget>(CallHierarchyTreeWidget);
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2018 TypeFox and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import { injectable, inject } from '@theia/core/shared/inversify';
|
||||
import { CompositeTreeNode, TreeModelImpl, TreeNode } from '@theia/core/lib/browser';
|
||||
import { CallHierarchyTree, ItemNode } from './callhierarchy-tree';
|
||||
import { CallHierarchyServiceProvider, CallHierarchySession } from '../callhierarchy-service';
|
||||
import { Position } from '@theia/core/shared/vscode-languageserver-protocol';
|
||||
import URI from '@theia/core/lib/common/uri';
|
||||
import { CancellationTokenSource } from '@theia/core/lib/common/cancellation';
|
||||
|
||||
@injectable()
|
||||
export class CallHierarchyTreeModel extends TreeModelImpl {
|
||||
|
||||
protected _languageId: string | undefined;
|
||||
protected currentSession?: CallHierarchySession;
|
||||
|
||||
@inject(CallHierarchyTree) protected override readonly tree: CallHierarchyTree;
|
||||
@inject(CallHierarchyServiceProvider) protected readonly callHierarchyServiceProvider: CallHierarchyServiceProvider;
|
||||
|
||||
getTree(): CallHierarchyTree {
|
||||
return this.tree;
|
||||
}
|
||||
|
||||
get languageId(): string | undefined {
|
||||
return this._languageId;
|
||||
}
|
||||
|
||||
async initializeCallHierarchy(languageId: string | undefined, uri: string | undefined, position: Position | undefined): Promise<void> {
|
||||
this.tree.root = undefined;
|
||||
this.tree.callHierarchyService = undefined;
|
||||
this._languageId = languageId;
|
||||
if (languageId && uri && position) {
|
||||
const callHierarchyService = this.callHierarchyServiceProvider.get(languageId, new URI(uri));
|
||||
if (callHierarchyService) {
|
||||
this.tree.callHierarchyService = callHierarchyService;
|
||||
const cancellationSource = new CancellationTokenSource();
|
||||
const rootDefinition = await callHierarchyService.getRootDefinition(uri, position, cancellationSource.token);
|
||||
if (rootDefinition) {
|
||||
this.currentSession?.dispose();
|
||||
this.currentSession = rootDefinition;
|
||||
const root: CompositeTreeNode = {
|
||||
id: 'call-hierarchy-tree-root',
|
||||
parent: undefined,
|
||||
children: [],
|
||||
visible: false,
|
||||
};
|
||||
rootDefinition.items.forEach(definition => CompositeTreeNode.addChild(root, ItemNode.create(definition, root)));
|
||||
this.tree.root = root;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override doOpenNode(node: TreeNode): void {
|
||||
// do nothing (in particular do not expand the node)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2018 TypeFox and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import { injectable, inject } from '@theia/core/shared/inversify';
|
||||
import {
|
||||
ContextMenuRenderer, TreeWidget, NodeProps, TreeProps, TreeNode,
|
||||
TreeModel, DockPanel, codicon
|
||||
} from '@theia/core/lib/browser';
|
||||
import { LabelProvider } from '@theia/core/lib/browser/label-provider';
|
||||
import { ItemNode, CallerNode } from './callhierarchy-tree';
|
||||
import { CallHierarchyTreeModel } from './callhierarchy-tree-model';
|
||||
import { CALLHIERARCHY_ID, CallHierarchyItem, CallHierarchyIncomingCall, CALL_HIERARCHY_LABEL } from '../callhierarchy';
|
||||
import URI from '@theia/core/lib/common/uri';
|
||||
import { Location, Range, SymbolKind, DocumentUri, SymbolTag } from '@theia/core/shared/vscode-languageserver-protocol';
|
||||
import { EditorManager } from '@theia/editor/lib/browser';
|
||||
import { nls } from '@theia/core/lib/common/nls';
|
||||
import * as React from '@theia/core/shared/react';
|
||||
|
||||
export const HIERARCHY_TREE_CLASS = 'theia-CallHierarchyTree';
|
||||
export const DEFINITION_NODE_CLASS = 'theia-CallHierarchyTreeNode';
|
||||
export const DEFINITION_ICON_CLASS = 'theia-CallHierarchyTreeNodeIcon';
|
||||
|
||||
@injectable()
|
||||
export class CallHierarchyTreeWidget extends TreeWidget {
|
||||
|
||||
constructor(
|
||||
@inject(TreeProps) override readonly props: TreeProps,
|
||||
@inject(CallHierarchyTreeModel) override readonly model: CallHierarchyTreeModel,
|
||||
@inject(ContextMenuRenderer) contextMenuRenderer: ContextMenuRenderer,
|
||||
@inject(LabelProvider) protected override readonly labelProvider: LabelProvider,
|
||||
@inject(EditorManager) readonly editorManager: EditorManager
|
||||
) {
|
||||
super(props, model, contextMenuRenderer);
|
||||
|
||||
this.id = CALLHIERARCHY_ID;
|
||||
this.title.label = CALL_HIERARCHY_LABEL;
|
||||
this.title.caption = CALL_HIERARCHY_LABEL;
|
||||
this.title.iconClass = codicon('references');
|
||||
this.title.closable = true;
|
||||
this.addClass(HIERARCHY_TREE_CLASS);
|
||||
this.toDispose.push(this.model.onSelectionChanged(selection => {
|
||||
const node = selection[0];
|
||||
if (node) {
|
||||
this.openEditor(node, true);
|
||||
}
|
||||
}));
|
||||
this.toDispose.push(this.model.onOpenNode((node: TreeNode) => {
|
||||
this.openEditor(node, false);
|
||||
}));
|
||||
this.toDispose.push(
|
||||
this.labelProvider.onDidChange(() => this.update())
|
||||
);
|
||||
}
|
||||
|
||||
initializeModel(selection: Location | undefined, languageId: string | undefined): void {
|
||||
this.model.initializeCallHierarchy(languageId, selection ? selection.uri : undefined, selection ? selection.range.start : undefined);
|
||||
}
|
||||
|
||||
protected override createNodeClassNames(node: TreeNode, props: NodeProps): string[] {
|
||||
const classNames = super.createNodeClassNames(node, props);
|
||||
if (ItemNode.is(node)) {
|
||||
classNames.push(DEFINITION_NODE_CLASS);
|
||||
}
|
||||
return classNames;
|
||||
}
|
||||
|
||||
protected override createNodeAttributes(node: TreeNode, props: NodeProps): React.Attributes & React.HTMLAttributes<HTMLElement> {
|
||||
const elementAttrs = super.createNodeAttributes(node, props);
|
||||
return {
|
||||
...elementAttrs,
|
||||
};
|
||||
}
|
||||
|
||||
protected override renderTree(model: TreeModel): React.ReactNode {
|
||||
return super.renderTree(model)
|
||||
|| <div className='theia-widget-noInfo'>{nls.localize('theia/callhierarchy/noCallers', 'No callers have been detected.')}</div>;
|
||||
}
|
||||
|
||||
protected override renderCaption(node: TreeNode, props: NodeProps): React.ReactNode {
|
||||
if (ItemNode.is(node)) {
|
||||
return this.decorateDefinitionCaption(node.definition);
|
||||
}
|
||||
if (CallerNode.is(node)) {
|
||||
return this.decorateCallerCaption(node.caller);
|
||||
}
|
||||
return 'caption';
|
||||
}
|
||||
|
||||
protected decorateDefinitionCaption(definition: CallHierarchyItem): React.ReactNode {
|
||||
const symbol = definition.name;
|
||||
const location = this.labelProvider.getName(URI.fromComponents(definition.uri));
|
||||
const container = location;
|
||||
const isDeprecated = definition.tags?.includes(SymbolTag.Deprecated);
|
||||
const classNames = ['definitionNode'];
|
||||
if (isDeprecated) {
|
||||
classNames.push('deprecatedDefinition');
|
||||
}
|
||||
|
||||
return <div className={classNames.join(' ')}>
|
||||
<div className={'symbol-icon-center codicon codicon-symbol-' + this.toIconClass(definition.kind)}></div>
|
||||
<div className='definitionNode-content'>
|
||||
<span className='symbol'>
|
||||
{symbol}
|
||||
</span>
|
||||
<span className='container'>
|
||||
{container}
|
||||
</span>
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
protected decorateCallerCaption(caller: CallHierarchyIncomingCall): React.ReactNode {
|
||||
const definition = caller.from;
|
||||
const symbol = definition.name;
|
||||
const referenceCount = caller.fromRanges.length;
|
||||
const location = this.labelProvider.getName(URI.fromComponents(definition.uri));
|
||||
const container = location;
|
||||
const isDeprecated = definition.tags?.includes(SymbolTag.Deprecated);
|
||||
const classNames = ['definitionNode'];
|
||||
if (isDeprecated) {
|
||||
classNames.push('deprecatedDefinition');
|
||||
}
|
||||
|
||||
return <div className={classNames.join(' ')}>
|
||||
<div className={'symbol-icon-center codicon codicon-symbol-' + this.toIconClass(definition.kind)}></div>
|
||||
<div className='definitionNode-content'>
|
||||
<span className='symbol'>
|
||||
{symbol}
|
||||
</span>
|
||||
<span className='referenceCount'>
|
||||
{(referenceCount > 1) ? `[${referenceCount}]` : ''}
|
||||
</span>
|
||||
<span className='container'>
|
||||
{container}
|
||||
</span>
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
// tslint:disable-next-line:typedef
|
||||
protected toIconClass(symbolKind: number) {
|
||||
switch (symbolKind) {
|
||||
case SymbolKind.File: return 'file';
|
||||
case SymbolKind.Module: return 'module';
|
||||
case SymbolKind.Namespace: return 'namespace';
|
||||
case SymbolKind.Package: return 'package';
|
||||
case SymbolKind.Class: return 'class';
|
||||
case SymbolKind.Method: return 'method';
|
||||
case SymbolKind.Property: return 'property';
|
||||
case SymbolKind.Field: return 'field';
|
||||
case SymbolKind.Constructor: return 'constructor';
|
||||
case SymbolKind.Enum: return 'enum';
|
||||
case SymbolKind.Interface: return 'interface';
|
||||
case SymbolKind.Function: return 'function';
|
||||
case SymbolKind.Variable: return 'variable';
|
||||
case SymbolKind.Constant: return 'constant';
|
||||
case SymbolKind.String: return 'string';
|
||||
case SymbolKind.Number: return 'number';
|
||||
case SymbolKind.Boolean: return 'boolean';
|
||||
case SymbolKind.Array: return 'array';
|
||||
default: return 'unknown';
|
||||
}
|
||||
}
|
||||
|
||||
private openEditor(node: TreeNode, keepFocus: boolean): void {
|
||||
|
||||
if (ItemNode.is(node)) {
|
||||
const def = node.definition;
|
||||
this.doOpenEditor(URI.fromComponents(def.uri).toString(), def.selectionRange ? def.selectionRange : def.range, keepFocus);
|
||||
}
|
||||
if (CallerNode.is(node)) {
|
||||
this.doOpenEditor(URI.fromComponents(node.caller.from.uri).toString(), node.caller.fromRanges[0], keepFocus);
|
||||
}
|
||||
}
|
||||
|
||||
private doOpenEditor(uri: DocumentUri, range: Range, keepFocus: boolean): void {
|
||||
this.editorManager.open(
|
||||
new URI(uri), {
|
||||
mode: keepFocus ? 'reveal' : 'activate',
|
||||
selection: range
|
||||
}
|
||||
).then(editorWidget => {
|
||||
if (editorWidget.parent instanceof DockPanel) {
|
||||
editorWidget.parent.selectWidget(editorWidget);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
override storeState(): object {
|
||||
const callHierarchyService = this.model.getTree().callHierarchyService;
|
||||
if (this.model.root && callHierarchyService) {
|
||||
return {
|
||||
root: this.deflateForStorage(this.model.root),
|
||||
languageId: this.model.languageId,
|
||||
};
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
override restoreState(oldState: object): void {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
if ((oldState as any).root && (oldState as any).languageId) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const root = this.inflateFromStorage((oldState as any).root) as ItemNode;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
this.model.initializeCallHierarchy((oldState as any).languageId, URI.fromComponents(root.definition.uri).toString(), root.definition.range.start);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2018 TypeFox and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import { injectable } from '@theia/core/shared/inversify';
|
||||
import { TreeNode, CompositeTreeNode, SelectableTreeNode, ExpandableTreeNode, TreeImpl } from '@theia/core/lib/browser';
|
||||
import { CallHierarchyItem, CallHierarchyIncomingCall } from '../callhierarchy';
|
||||
import { CallHierarchyService } from '../callhierarchy-service';
|
||||
import { Md5 } from 'ts-md5';
|
||||
import { CancellationTokenSource } from '@theia/core/lib/common/cancellation';
|
||||
|
||||
@injectable()
|
||||
export class CallHierarchyTree extends TreeImpl {
|
||||
|
||||
protected _callHierarchyService: CallHierarchyService | undefined;
|
||||
|
||||
set callHierarchyService(callHierarchyService: CallHierarchyService | undefined) {
|
||||
this._callHierarchyService = callHierarchyService;
|
||||
}
|
||||
|
||||
get callHierarchyService(): CallHierarchyService | undefined {
|
||||
return this._callHierarchyService;
|
||||
}
|
||||
|
||||
override async resolveChildren(parent: CompositeTreeNode): Promise<TreeNode[]> {
|
||||
if (!this.callHierarchyService) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
if (parent.children.length > 0) {
|
||||
return Promise.resolve([...parent.children]);
|
||||
}
|
||||
let definition: CallHierarchyItem | undefined;
|
||||
if (ItemNode.is(parent)) {
|
||||
definition = parent.definition;
|
||||
} else if (CallerNode.is(parent)) {
|
||||
definition = parent.caller.from;
|
||||
}
|
||||
if (definition) {
|
||||
const cancellationSource = new CancellationTokenSource();
|
||||
const callers = await this.callHierarchyService.getCallers(definition, cancellationSource.token);
|
||||
if (!callers) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
return this.toNodes(callers, parent);
|
||||
}
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
protected toNodes(callers: CallHierarchyIncomingCall[], parent: CompositeTreeNode): TreeNode[] {
|
||||
return callers.map(caller => this.toNode(caller, parent));
|
||||
}
|
||||
|
||||
protected toNode(caller: CallHierarchyIncomingCall, parent: CompositeTreeNode | undefined): TreeNode {
|
||||
return CallerNode.create(caller, parent as TreeNode);
|
||||
}
|
||||
}
|
||||
|
||||
export interface ItemNode extends SelectableTreeNode, ExpandableTreeNode {
|
||||
definition: CallHierarchyItem;
|
||||
}
|
||||
|
||||
export namespace ItemNode {
|
||||
export function is(node: TreeNode | undefined): node is ItemNode {
|
||||
return !!node && 'definition' in node;
|
||||
}
|
||||
|
||||
export function create(definition: CallHierarchyItem, parent: TreeNode | undefined): ItemNode {
|
||||
const name = definition.name;
|
||||
const id = createId(definition, parent);
|
||||
return <ItemNode>{
|
||||
id, definition, name, parent,
|
||||
visible: true,
|
||||
children: [],
|
||||
expanded: false,
|
||||
selected: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export interface CallerNode extends SelectableTreeNode, ExpandableTreeNode {
|
||||
caller: CallHierarchyIncomingCall;
|
||||
}
|
||||
|
||||
export namespace CallerNode {
|
||||
export function is(node: TreeNode | undefined): node is CallerNode {
|
||||
return !!node && 'caller' in node;
|
||||
}
|
||||
|
||||
export function create(caller: CallHierarchyIncomingCall, parent: TreeNode | undefined): CallerNode {
|
||||
const callerDefinition = caller.from;
|
||||
const name = callerDefinition.name;
|
||||
const id = createId(callerDefinition, parent);
|
||||
return <CallerNode>{
|
||||
id, caller, name, parent,
|
||||
visible: true,
|
||||
children: [],
|
||||
expanded: false,
|
||||
selected: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function createId(definition: CallHierarchyItem, parent: TreeNode | undefined): string {
|
||||
const idPrefix = (parent) ? parent.id + '/' : '';
|
||||
const id = idPrefix + Md5.hashStr(JSON.stringify(definition));
|
||||
return id;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2018 TypeFox and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
export * from './callhierarchy-tree';
|
||||
export * from './callhierarchy-tree-model';
|
||||
export * from './callhierarchy-tree-widget';
|
||||
export * from './callhierarchy-tree-container';
|
||||
47
packages/callhierarchy/src/browser/callhierarchy.ts
Normal file
47
packages/callhierarchy/src/browser/callhierarchy.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2018 TypeFox and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import { nls } from '@theia/core';
|
||||
import { UriComponents } from '@theia/core/lib/common/uri';
|
||||
import { Range, SymbolKind, SymbolTag } from '@theia/core/shared/vscode-languageserver-protocol';
|
||||
|
||||
export const CALLHIERARCHY_ID = 'callhierarchy';
|
||||
export const CALL_HIERARCHY_TOGGLE_COMMAND_ID = 'callhierarchy:toggle';
|
||||
export const CALL_HIERARCHY_LABEL = nls.localizeByDefault('Call Hierarchy');
|
||||
|
||||
export interface CallHierarchyItem {
|
||||
_sessionId?: string;
|
||||
_itemId?: string;
|
||||
|
||||
kind: SymbolKind;
|
||||
name: string;
|
||||
detail?: string;
|
||||
uri: UriComponents;
|
||||
range: Range;
|
||||
selectionRange: Range;
|
||||
tags?: readonly SymbolTag[];
|
||||
data?: unknown;
|
||||
}
|
||||
|
||||
export interface CallHierarchyIncomingCall {
|
||||
from: CallHierarchyItem;
|
||||
fromRanges: Range[];
|
||||
}
|
||||
|
||||
export interface CallHierarchyOutgoingCall {
|
||||
to: CallHierarchyItem;
|
||||
fromRanges: Range[];
|
||||
}
|
||||
20
packages/callhierarchy/src/browser/index.ts
Normal file
20
packages/callhierarchy/src/browser/index.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2018 TypeFox and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
export * from './callhierarchy';
|
||||
export * from './callhierarchy-contribution';
|
||||
export * from './callhierarchy-frontend-module';
|
||||
export * from './callhierarchy-service';
|
||||
65
packages/callhierarchy/src/browser/style/index.css
Normal file
65
packages/callhierarchy/src/browser/style/index.css
Normal file
@@ -0,0 +1,65 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2018 TypeFox and others.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the Eclipse
|
||||
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
* with the GNU Classpath Exception which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
********************************************************************************/
|
||||
|
||||
.theia-CallHierarchyTree {
|
||||
font-size: var(--theia-ui-font-size1);
|
||||
}
|
||||
|
||||
.theia-CallHierarchyTree .theia-TreeNode {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.theia-CallHierarchyTree .theia-ExpansionToggle {
|
||||
min-width: 9px;
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
.theia-CallHierarchyTree .definitionNode {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.theia-CallHierarchyTree .definitionNode {
|
||||
width: calc(100% - 32px);
|
||||
}
|
||||
|
||||
.theia-CallHierarchyTree .definitionNode div {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.theia-CallHierarchyTree .definitionNode .symbol {
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
.theia-CallHierarchyTree .definitionNode .referenceCount {
|
||||
color: var(--theia-badge-background);
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
.theia-CallHierarchyTree .definitionNode .container {
|
||||
color: var(--theia-descriptionForeground);
|
||||
}
|
||||
|
||||
.theia-CallHierarchyTree .definitionNode-content {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.theia-CallHierarchyTree
|
||||
.definitionNode.deprecatedDefinition
|
||||
.definitionNode-content {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
102
packages/callhierarchy/src/browser/utils.ts
Normal file
102
packages/callhierarchy/src/browser/utils.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2018 TypeFox and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import { Location, Range, Position } from '@theia/core/shared/vscode-languageserver-protocol';
|
||||
|
||||
/**
|
||||
* Test if `otherRange` is in `range`. If the ranges are equal, will return true.
|
||||
*/
|
||||
export function containsRange(range: Range, otherRange: Range): boolean {
|
||||
if (otherRange.start.line < range.start.line || otherRange.end.line < range.start.line) {
|
||||
return false;
|
||||
}
|
||||
if (otherRange.start.line > range.end.line || otherRange.end.line > range.end.line) {
|
||||
return false;
|
||||
}
|
||||
if (otherRange.start.line === range.start.line && otherRange.start.character < range.start.character) {
|
||||
return false;
|
||||
}
|
||||
if (otherRange.end.line === range.end.line && otherRange.end.character > range.end.character) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export function containsPosition(range: Range, position: Position): boolean {
|
||||
return comparePosition(range.start, position) >= 0 && comparePosition(range.end, position) <= 0;
|
||||
}
|
||||
|
||||
function sameStart(a: Range, b: Range): boolean {
|
||||
const pos1 = a.start;
|
||||
const pos2 = b.start;
|
||||
return pos1.line === pos2.line
|
||||
&& pos1.character === pos2.character;
|
||||
}
|
||||
|
||||
export function filterSame(locations: Location[], definition: Location): Location[] {
|
||||
return locations.filter(candidate => candidate.uri !== definition.uri
|
||||
|| !sameStart(candidate.range, definition.range)
|
||||
);
|
||||
}
|
||||
|
||||
export function comparePosition(left: Position, right: Position): number {
|
||||
const diff = right.line - left.line;
|
||||
if (diff !== 0) {
|
||||
return diff;
|
||||
}
|
||||
return right.character - left.character;
|
||||
}
|
||||
|
||||
export function filterUnique(locations: Location[] | null): Location[] {
|
||||
if (!locations) {
|
||||
return [];
|
||||
}
|
||||
const result: Location[] = [];
|
||||
const set = new Set<string>();
|
||||
for (const location of locations) {
|
||||
const json = JSON.stringify(location);
|
||||
if (!set.has(json)) {
|
||||
set.add(json);
|
||||
result.push(location);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function startsAfter(a: Range, b: Range): boolean {
|
||||
if (a.start.line > b.start.line) {
|
||||
return true;
|
||||
}
|
||||
if (a.start.line === b.start.line) {
|
||||
if (a.start.character > b.start.character) {
|
||||
return true;
|
||||
}
|
||||
if (a.start.character === b.start.character) {
|
||||
if (a.end.line > b.end.line) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isSame(a: Location, b: Location): boolean {
|
||||
return a.uri === b.uri
|
||||
&& a.range.start.line === b.range.start.line
|
||||
&& a.range.end.line === b.range.end.line
|
||||
&& a.range.start.character === b.range.start.character
|
||||
&& a.range.end.character === b.range.end.character;
|
||||
}
|
||||
28
packages/callhierarchy/src/package.spec.ts
Normal file
28
packages/callhierarchy/src/package.spec.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2018 TypeFox and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
/* note: this bogus test file is required so that
|
||||
we are able to run mocha unit tests on this
|
||||
package, without having any actual unit tests in it.
|
||||
This way a coverage report will be generated,
|
||||
showing 0% coverage, instead of no report.
|
||||
This file can be removed once we have real unit
|
||||
tests in place. */
|
||||
|
||||
describe('callhierarchy package', () => {
|
||||
|
||||
it('support code coverage statistics', () => true);
|
||||
});
|
||||
19
packages/callhierarchy/tsconfig.json
Normal file
19
packages/callhierarchy/tsconfig.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"extends": "../../configs/base.tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"rootDir": "src",
|
||||
"outDir": "lib"
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "../core"
|
||||
},
|
||||
{
|
||||
"path": "../editor"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user