Skip to content

Commit

Permalink
implement a type hierarchy command
Browse files Browse the repository at this point in the history
  • Loading branch information
devoncarew committed Oct 9, 2016
1 parent 73d12e3 commit 768601b
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 0 deletions.
6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@
"key": "ctrl+alt+o",
"mac": "cmd+alt+o",
"when": "editorLangId == dart"
},
{
"command": "dart.showTypeHierarchy",
"key": "f4",
"mac": "f4",
"when": "editorLangId == dart"
}
],
"menus": {
Expand Down
131 changes: 131 additions & 0 deletions src/commands/type_hierarchy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
"use strict";

import * as editors from "../editors";
import * as vs from "vscode";
import * as as from "../analysis/analysis_server_types";
import { Analyzer } from "../analysis/analyzer";
import { toRange } from "../utils";

export class TypeHierarchyCommand implements vs.Disposable {
private context: vs.ExtensionContext;
private analyzer: Analyzer;
private commands: Array<vs.Disposable> = [];

constructor(context: vs.ExtensionContext, analyzer: Analyzer) {
this.context = context;
this.analyzer = analyzer;

this.commands.push(
vs.commands.registerTextEditorCommand("dart.showTypeHierarchy", this.showTypeHierarchy, this)
);
}

private showTypeHierarchy(editor: vs.TextEditor, editBuilder: vs.TextEditorEdit) {
if (!editors.hasActiveDartEditor()) {
vs.window.showWarningMessage("No active Dart editor.");
return;
}

let document = editor.document;

this.analyzer.searchGetTypeHierarchy({
file: document.fileName,
offset: document.offsetAt(editor.selection.active)
}).then(response => {
let items = response.hierarchyItems;
if (!items) {
vs.window.showInformationMessage('Type hierarchy not available.');
return;
}

let options = { placeHolder: name(items, 0) };

// TODO: How / where to show implements?
// TODO: How / where to show mixins?
let tree = [];
let startItem = items[0];

tree.push(startItem);
addParents(items, tree, startItem);
addChildren(items, tree, startItem);

vs.window.showQuickPick(tree.map(item => itemToPick(item, items)), options).then(result => {
if (result) {
let location: as.Location = result['location'];
vs.workspace.openTextDocument(location.file).then(document => {
vs.window.showTextDocument(document).then(editor => {
let range = toRange(location);
editor.revealRange(range, vs.TextEditorRevealType.InCenterIfOutsideViewport);
editor.selection = new vs.Selection(range.end, range.start);
});
});
}
});
});
}

dispose(): any {
for (let command of this.commands)
command.dispose();
}
}

function addParents(items: as.TypeHierarchyItem[], tree: as.TypeHierarchyItem[], item: as.TypeHierarchyItem) {
if (item.superclass) {
let parent = items[item.superclass];
tree.unshift(parent);
addParents(items, tree, parent);
}
}

function addChildren(items: as.TypeHierarchyItem[], tree: as.TypeHierarchyItem[], item: as.TypeHierarchyItem) {
// Handle direct children.
for (let index of item.subclasses) {
let child = items[index];
tree.push(child);
}

// Handle grandchildren.
for (let index of item.subclasses) {
let child = items[index];
if (child.subclasses.length > 0)
addChildren(items, tree, child);
}
}

function itemToPick(item: as.TypeHierarchyItem, items: as.TypeHierarchyItem[]): vs.QuickPickItem {
let desc = '';

// extends
if (item.superclass !== undefined && name(items, item.superclass) != 'Object')
desc += `extends ${name(items, item.superclass)}`;

// implements
if (item.interfaces.length > 0) {
if (desc.length > 0)
desc += ', ';
desc += `implements ${item.interfaces.map(i => name(items, i)).join(', ')}`;
}

// with
if (item.mixins.length > 0) {
if (desc.length > 0)
desc += ', ';
desc += `with ${item.mixins.map(i => name(items, i)).join(', ')}`;
}

// TODO: Show the library location in the details (dart:core, ...) (share code
// with dart_workspace_symbol_provider.ts).

let result = {
label: item.classElement.name,
description: desc,
location: item.classElement.location
};

return result;
}

function name(items: as.TypeHierarchyItem[], index: number) {
return items[index].classElement.name;
}
4 changes: 4 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { DartRenameProvider } from "./providers/dart_rename_provider";
import { FileChangeHandler } from "./file_change_handler";
import { OpenFileTracker } from "./open_file_tracker";
import { SdkCommands } from "./commands/sdk";
import { TypeHierarchyCommand } from "./commands/type_hierarchy";
import { ServerStatusNotification } from "./analysis/analysis_server_types";

const DART_MODE: vs.DocumentFilter = { language: "dart", scheme: "file" };
Expand Down Expand Up @@ -132,6 +133,9 @@ export function activate(context: vs.ExtensionContext) {

// Set up commands for Dart editors.
context.subscriptions.push(new EditCommands(context, analyzer));

// Register misc commands.
context.subscriptions.push(new TypeHierarchyCommand(context, analyzer));
}

function handleConfigurationChange() {
Expand Down

0 comments on commit 768601b

Please sign in to comment.