Skip to content

Commit

Permalink
Add basic plumbing for Flutter Outline.
Browse files Browse the repository at this point in the history
See #605.
  • Loading branch information
DanTup committed Mar 5, 2018
1 parent 2a64e21 commit 4fc7050
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 2 deletions.
6 changes: 5 additions & 1 deletion package.json
Expand Up @@ -32,7 +32,6 @@
"icon": "media/icon.png",
"activationEvents": [
"onLanguage:dart",
"onView:dartPackages",
"workspaceContains:**/pubspec.yaml",
"workspaceContains:**/*.dart",
"onCommand:flutter.createProject",
Expand Down Expand Up @@ -348,6 +347,11 @@
},
"views": {
"explorer": [
{
"id": "dartFlutterOutline",
"name": "Flutter Outline",
"when": "dart-code:flutterProjectLoaded && dart-code:showFlutterOutline"
},
{
"id": "dartPackages",
"name": "Dependencies",
Expand Down
1 change: 1 addition & 0 deletions src/analysis/analyzer.ts
Expand Up @@ -21,6 +21,7 @@ class AnalyzerCapabilities {
get supportsDiagnostics() { return versionIsAtLeast(this.version, "1.18.1"); }
get supportsClosingLabels() { return versionIsAtLeast(this.version, "1.18.4"); }
get supportsGetDeclerations() { return versionIsAtLeast(this.version, "1.18.7"); }
get supportsFlutterOutline() { return versionIsAtLeast(this.version, "1.18.7"); }
}

export class Analyzer extends AnalyzerGen {
Expand Down
6 changes: 5 additions & 1 deletion src/extension.ts
Expand Up @@ -41,6 +41,7 @@ import { isFlutterProject } from "./utils";
import { FixCodeActionProvider } from "./providers/fix_code_action_provider";
import { AssistCodeActionProvider } from "./providers/assist_code_action_provider";
import { LegacyDebugConfigProvider } from "./providers/legacy_debug_config_provider";
import { FlutterOutlineProvider } from "./views/flutter_outline_view";

const DART_MODE: vs.DocumentFilter[] = [{ language: "dart", scheme: "file" }];
const HTML_MODE: vs.DocumentFilter[] = [{ language: "html", scheme: "file" }];
Expand Down Expand Up @@ -284,6 +285,9 @@ export function activate(context: vs.ExtensionContext) {
context.subscriptions.push(vs.languages.registerWorkspaceSymbolProvider(new LegacyDartWorkspaceSymbolProvider(analyzer)));
}

if (analyzer.capabilities.supportsFlutterOutline)
context.subscriptions.push(vs.window.registerTreeDataProvider("dartFlutterOutline", new FlutterOutlineProvider(analyzer)));

// Hook open/active file changes so we can set priority files with the analyzer.
const openFileTracker = new OpenFileTracker(analyzer);
context.subscriptions.push(vs.workspace.onDidOpenTextDocument((td) => openFileTracker.updatePriorityFiles()));
Expand Down Expand Up @@ -314,7 +318,7 @@ export function activate(context: vs.ExtensionContext) {
// Register misc commands.
context.subscriptions.push(new TypeHierarchyCommand(context, analyzer));

// Register our view providers.
// Register our dependency tree provider.
const dartPackagesProvider = new DartPackagesProvider();
dartPackagesProvider.setWorkspaces(util.getDartWorkspaceFolders());
context.subscriptions.push(dartPackagesProvider);
Expand Down
8 changes: 8 additions & 0 deletions src/open_file_tracker.ts
Expand Up @@ -56,5 +56,13 @@ export class OpenFileTracker {
},
});
}

if (this.analyzer.capabilities.supportsFlutterOutline) {
this.analyzer.flutterSetSubscriptions({
subscriptions: {
OUTLINE: priorityFiles,
},
});
}
}
}
93 changes: 93 additions & 0 deletions src/views/flutter_outline_view.ts
@@ -0,0 +1,93 @@
"use strict";

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

const DART_SHOW_FLUTTER_OUTLINE = "dart-code:showFlutterOutline";

export class FlutterOutlineProvider implements vs.TreeDataProvider<FlutterWidgetItem>, vs.Disposable {
private subscriptions: vs.Disposable[] = [];
private analyzer: Analyzer;
private activeEditor: vs.TextEditor;
private flutterOutline: as.FlutterOutlineNotification;
private updateTimeout: NodeJS.Timer;
private onDidChangeTreeDataEmitter: vs.EventEmitter<FlutterWidgetItem | undefined> = new vs.EventEmitter<FlutterWidgetItem | undefined>();
public readonly onDidChangeTreeData: vs.Event<FlutterWidgetItem | undefined> = this.onDidChangeTreeDataEmitter.event;

constructor(analyzer: Analyzer) {
this.analyzer = analyzer;

this.analyzer.registerForFlutterOutline((n) => {
if (this.activeEditor && n.file === this.activeEditor.document.fileName) {
this.flutterOutline = n;
// Delay this so if we're getting lots of updates we don't flicker.
clearTimeout(this.updateTimeout);
this.updateTimeout = setTimeout(() => this.update(), 500);
}
});

this.subscriptions.push(vs.window.onDidChangeActiveTextEditor((e) => this.setTrackingFile(e)));
if (vs.window.activeTextEditor)
this.setTrackingFile(vs.window.activeTextEditor);
}

private update() {
if (!this.flutterOutline || !this.activeEditor || this.flutterOutline.file !== this.activeEditor.document.fileName)
return;

FlutterOutlineProvider.showTree();

// Do tree...
}

private setTrackingFile(editor: vs.TextEditor) {
if (editor && isAnalyzable(editor.document)) {
this.activeEditor = editor;
this.flutterOutline = null;

this.analyzer.forceNotificationsFor(editor.document.fileName);
} else {
FlutterOutlineProvider.hideTree();
this.activeEditor = null;
}
}

public refresh(): void {
this.onDidChangeTreeDataEmitter.fire();
}

public getTreeItem(element: FlutterWidgetItem): vs.TreeItem {
return element;
}

public getChildren(element?: FlutterWidgetItem): FlutterWidgetItem[] {
return [];
}

private static setTreeVisible(visible: boolean) {
vs.commands.executeCommand("setContext", DART_SHOW_FLUTTER_OUTLINE, visible);
}

public static showTree() { this.setTreeVisible(true); }
public static hideTree() { this.setTreeVisible(false); }

public dispose() {
this.activeEditor = null;
this.subscriptions.forEach((s) => s.dispose());
}
}

class FlutterWidgetItem extends vs.TreeItem {
constructor(
public readonly label: string,
public readonly depPath: string,
public readonly collapsibleState?: vs.TreeItemCollapsibleState,
public readonly command?: vs.Command,
) {
super(label, collapsibleState);
}

public contextValue = "flutterWidget";
}

0 comments on commit 4fc7050

Please sign in to comment.