Index: pkg/analysis_server/lib/src/status/diagnostics.dart |
diff --git a/pkg/analysis_server/lib/src/status/diagnostics.dart b/pkg/analysis_server/lib/src/status/diagnostics.dart |
index ee8db5020004b475145a39158dde98b1f122fcd1..93524c644688bb1a8eef83f17fb45bd4d79d98f3 100644 |
--- a/pkg/analysis_server/lib/src/status/diagnostics.dart |
+++ b/pkg/analysis_server/lib/src/status/diagnostics.dart |
@@ -2,6 +2,7 @@ |
// for details. All rights reserved. Use of this source code is governed by a |
// BSD-style license that can be found in the LICENSE file. |
+import 'dart:async'; |
import 'dart:convert'; |
import 'dart:io'; |
@@ -14,6 +15,8 @@ import 'package:analysis_server/src/plugin/plugin_manager.dart'; |
import 'package:analysis_server/src/server/http_server.dart'; |
import 'package:analysis_server/src/services/completion/completion_performance.dart'; |
import 'package:analysis_server/src/socket_server.dart'; |
+import 'package:analysis_server/src/status/ast_writer.dart'; |
+import 'package:analysis_server/src/status/element_writer.dart'; |
import 'package:analysis_server/src/status/pages.dart'; |
import 'package:analysis_server/src/utilities/profiling.dart'; |
import 'package:analyzer/file_system/file_system.dart'; |
@@ -24,7 +27,7 @@ import 'package:analyzer/src/context/source.dart'; |
import 'package:analyzer/src/dart/analysis/driver.dart'; |
import 'package:analyzer/src/dart/analysis/file_state.dart'; |
import 'package:analyzer/src/dart/sdk/sdk.dart'; |
-import 'package:analyzer/src/generated/engine.dart'; |
+import 'package:analyzer/src/generated/engine.dart' hide AnalysisResult; |
import 'package:analyzer/src/generated/sdk.dart'; |
import 'package:analyzer/src/generated/source.dart'; |
import 'package:analyzer/src/generated/utilities_general.dart'; |
@@ -128,6 +131,49 @@ td.pre { |
} |
'''; |
+class AstPage extends DiagnosticPageWithNav { |
+ String _description; |
+ |
+ AstPage(DiagnosticsSite site) |
+ : super(site, 'ast', 'AST', description: 'The AST for a file'); |
devoncarew
2017/06/11 06:13:30
We should end this in a period - the other descrip
Brian Wilkerson
2017/06/11 16:45:25
Done
|
+ |
+ @override |
+ String get description => _description ?? super.description; |
+ |
+ @override |
+ Future<Null> generatePage(Map<String, String> params) async { |
+ try { |
+ String path = params['file'] ?? 'unspecified file'; |
+ _description = 'The AST for $path'; |
devoncarew
2017/06/11 06:13:30
Same re: ending in a period.
If the file is unspe
Brian Wilkerson
2017/06/11 16:45:24
Done
|
+ await super.generatePage(params); |
+ } finally { |
+ _description = null; |
+ } |
+ } |
+ |
+ @override |
+ Future<Null> generateContent(Map<String, String> params) async { |
+ String path = params['file']; |
+ if (path == null) { |
+ blankslate('No file path provided.'); |
devoncarew
2017/06/11 06:13:30
I'd suggest something like:
p('No file path provi
Brian Wilkerson
2017/06/11 16:45:24
Done
|
+ return; |
+ } |
+ AnalysisDriver driver = server.getAnalysisDriver(path); |
+ if (driver == null) { |
+ blankslate('The file "$path" is not being analyzed.'); |
devoncarew
2017/06/11 06:13:30
Same, I'd recommend a p() element instead of blank
Brian Wilkerson
2017/06/11 16:45:24
Done
|
+ return; |
+ } |
+ AnalysisResult result = await driver.getResult(path); |
+ if (result == null) { |
+ blankslate('An AST could not be produced for the file "$path".'); |
devoncarew
2017/06/11 06:13:30
p()?
Brian Wilkerson
2017/06/11 16:45:24
Done
|
+ return; |
+ } |
+ |
+ AstWriter writer = new AstWriter(buf); |
+ result.unit.accept(writer); |
+ } |
+} |
+ |
class DiagnosticsSite extends Site implements AbstractGetHandler { |
/// An object that can handle either a WebSocket connection or a connection |
/// to the client over stdio. |
@@ -161,6 +207,9 @@ class DiagnosticsSite extends Site implements AbstractGetHandler { |
// Add non-nav pages. |
pages.add(new FeedbackPage(this)); |
+ |
+ secondaryPages.add(new AstPage(this)); |
devoncarew
2017/06/11 06:13:30
I don't have a strong opinion here, but another wa
Brian Wilkerson
2017/06/11 16:45:24
I think I'll leave it for now, because it's workin
|
+ secondaryPages.add(new ElementModelPage(this)); |
} |
String get customCss => kCustomCss; |
@@ -182,7 +231,7 @@ abstract class DiagnosticPage extends Page { |
AnalysisServer get server => |
(site as DiagnosticsSite).socketServer.analysisServer; |
- void generatePage(Map<String, String> params) { |
+ Future<Null> generatePage(Map<String, String> params) async { |
buf.writeln('<!DOCTYPE html><html lang="en">'); |
buf.write('<head>'); |
buf.write('<meta charset="utf-8">'); |
@@ -201,7 +250,7 @@ abstract class DiagnosticPage extends Page { |
buf.writeln('<body>'); |
generateHeader(); |
buf.writeln('<div class="container">'); |
- generateContainer(params); |
+ await generateContainer(params); |
generateFooter(); |
buf.writeln('</div>'); // div.container |
buf.writeln('</body>'); |
@@ -228,13 +277,13 @@ abstract class DiagnosticPage extends Page { |
'''); |
} |
- void generateContainer(Map<String, String> params) { |
+ Future<Null> generateContainer(Map<String, String> params) async { |
buf.writeln('<div class="columns docs-layout">'); |
buf.writeln('<div class="three-fourths column markdown-body">'); |
h1(title, classes: 'page-title'); |
- div(() { |
+ await asyncDiv(() async { |
p(description); |
- generateContent(params); |
+ await generateContent(params); |
}, classes: 'markdown-body'); |
buf.writeln('</div>'); |
buf.writeln('</div>'); |
@@ -258,7 +307,7 @@ abstract class DiagnosticPageWithNav extends DiagnosticPage { |
{String description}) |
: super(site, id, title, description: description); |
- void generateContainer(Map<String, String> params) { |
+ Future<Null> generateContainer(Map<String, String> params) async { |
buf.writeln('<div class="columns docs-layout">'); |
buf.writeln('<div class="one-fifth column">'); |
@@ -277,9 +326,9 @@ abstract class DiagnosticPageWithNav extends DiagnosticPage { |
buf.writeln('<div class="four-fifths column markdown-body">'); |
h1(title, classes: 'page-title'); |
- div(() { |
+ await asyncDiv(() async { |
p(description); |
- generateContent(params); |
+ await generateContent(params); |
}, classes: 'markdown-body'); |
buf.writeln('</div>'); |
@@ -291,6 +340,51 @@ abstract class DiagnosticPageWithNav extends DiagnosticPage { |
bool get isNavPage => true; |
} |
+class ElementModelPage extends DiagnosticPageWithNav { |
+ String _description; |
+ |
+ ElementModelPage(DiagnosticsSite site) |
+ : super(site, 'element', 'Element model', |
+ description: 'The element model for a file'); |
devoncarew
2017/06/11 06:13:30
nit: end in period
Brian Wilkerson
2017/06/11 16:45:24
Done
|
+ |
+ @override |
+ String get description => _description ?? super.description; |
+ |
+ @override |
+ Future<Null> generatePage(Map<String, String> params) async { |
+ try { |
+ String path = params['file'] ?? 'unspecified file'; |
devoncarew
2017/06/11 06:13:30
when unspecified, null out _description?
Brian Wilkerson
2017/06/11 16:45:24
Done
|
+ _description = 'The element model for $path'; |
+ await super.generatePage(params); |
+ } finally { |
+ _description = null; |
+ } |
+ } |
+ |
+ @override |
+ Future<Null> generateContent(Map<String, String> params) async { |
+ String path = params['file']; |
+ if (path == null) { |
+ blankslate('No file path provided.'); |
+ return; |
+ } |
+ AnalysisDriver driver = server.getAnalysisDriver(path); |
+ if (driver == null) { |
+ blankslate('The file "$path" is not being analyzed.'); |
+ return; |
+ } |
+ AnalysisResult result = await driver.getResult(path); |
+ if (result == null) { |
+ blankslate( |
+ 'An element model could not be produced for the file "$path".'); |
+ return; |
+ } |
+ |
+ ElementWriter writer = new ElementWriter(buf); |
+ result.unit.element.accept(writer); |
+ } |
+} |
+ |
class NotFoundPage extends DiagnosticPage { |
final String path; |
@@ -538,11 +632,14 @@ class ContextsPage extends DiagnosticPageWithNav { |
} |
String contextPath = params['context']; |
- Folder folder = driverMap.keys |
- .firstWhere((f) => f.path == contextPath, orElse: () => null); |
+ List<Folder> folders = driverMap.keys.toList(); |
+ folders |
+ .sort((first, second) => first.shortName.compareTo(second.shortName)); |
+ Folder folder = |
+ folders.firstWhere((f) => f.path == contextPath, orElse: () => null); |
if (folder == null) { |
- folder = driverMap.keys.first; |
+ folder = folders.first; |
contextPath = folder.path; |
} |
@@ -550,7 +647,7 @@ class ContextsPage extends DiagnosticPageWithNav { |
buf.writeln('<div class="tabnav">'); |
buf.writeln('<nav class="tabnav-tabs">'); |
- for (Folder f in driverMap.keys) { |
+ for (Folder f in folders) { |
if (f == folder) { |
buf.writeln( |
'<a class="tabnav-tab selected">${escape(f.shortName)}</a>'); |
@@ -614,14 +711,26 @@ class ContextsPage extends DiagnosticPageWithNav { |
h3('Context files'); |
+ void writeFile(String file) { |
+ String astPath = '/ast?file=${Uri.encodeQueryComponent(file)}'; |
+ String elementPath = '/element?file=${Uri.encodeQueryComponent(file)}'; |
+ |
+ buf.write(file); |
+ buf.write(' ('); |
+ buf.writeln('<a href="$astPath">ast</a>'); |
+ buf.write(' '); |
+ buf.writeln('<a href="$elementPath">element</a>'); |
+ buf.write(')'); |
+ } |
+ |
h4('Priority files ${lenCounter(priorityFiles)}', raw: true); |
- ul(priorityFiles, (file) => buf.write(file), classes: 'scroll-table'); |
+ ul(priorityFiles, writeFile, classes: 'scroll-table'); |
h4('Added files ${lenCounter(addedFiles)}', raw: true); |
- ul(addedFiles, (file) => buf.write(file), classes: 'scroll-table'); |
+ ul(addedFiles, writeFile, classes: 'scroll-table'); |
h4('ImplicitFiles files ${lenCounter(implicitFiles)}', raw: true); |
- ul(implicitFiles, (file) => buf.write(file), classes: 'scroll-table'); |
+ ul(implicitFiles, writeFile, classes: 'scroll-table'); |
SourceFactory sourceFactory = driver.sourceFactory; |
if (sourceFactory is SourceFactoryImpl) { |