| // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| // 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. |
| |
| // Usage: Add the following to your .gclient file (found in the parent |
| // of the "dart" in a gclient checkout of the Dart repositor). |
| // |
| // hooks = [ |
| // { |
| // "pattern": ".", |
| // "action": [ |
| // "dart/sdk/bin/dart", |
| // # Replace "xcodebuild" with "out" on Linux, and "build" on Windows. |
| // "-pdart/xcodebuild/ReleaseIA32/packages/", |
| // "dart/pkg/compiler/samples/darttags/darttags.dart", |
| // "dart/TAGS", |
| // # Modify the following list to your preferences: |
| // "dart/tests/try/web/incremental_compilation_update_test.dart", |
| // "package:compiler/src/dart2js.dart", |
| // ], |
| // }, |
| // ] |
| // |
| // Modify .emacs to contain: |
| // |
| // (setq tags-table-list |
| // '("DART_LOCATION/dart")) |
| // |
| // Where DART_LOCATION is the gclient directory where you found .gclient. |
| |
| import 'dart:io'; |
| |
| import 'dart:mirrors'; |
| |
| import 'package:sdk_library_metadata/libraries.dart' |
| show LIBRARIES, LibraryInfo; |
| |
| import 'package:compiler/src/mirrors/analyze.dart' |
| show analyze; |
| import 'package:compiler/src/mirrors/dart2js_mirrors.dart' |
| show BackDoor; |
| import 'package:compiler/src/mirrors/mirrors_util.dart' show nameOf; |
| |
| import 'package:compiler/src/filenames.dart'; |
| import 'package:compiler/src/io/source_file.dart'; |
| import 'package:compiler/src/source_file_provider.dart'; |
| import 'package:compiler/src/util/uri_extras.dart'; |
| |
| const DART2JS = 'package:compiler/src/dart2js.dart'; |
| const DART2JS_MIRROR = 'package:compiler/src/mirrors/dart2js_mirrors.dart'; |
| const SDK_ROOT = '../../../../sdk/'; |
| |
| bool isPublicDart2jsLibrary(String name) { |
| return !name.startsWith('_') && LIBRARIES[name].isDart2jsLibrary; |
| } |
| |
| var handler; |
| RandomAccessFile output; |
| Uri outputUri; |
| |
| main(List<String> arguments) { |
| handler = new FormattingDiagnosticHandler() |
| ..throwOnError = true; |
| |
| outputUri = |
| handler.provider.cwd.resolve(nativeToUriPath(arguments.first)); |
| output = new File(arguments.first).openSync(mode: FileMode.WRITE); |
| |
| Uri myLocation = |
| handler.provider.cwd.resolveUri(Platform.script); |
| |
| List<Uri> uris = <Uri>[]; |
| |
| if (arguments.length > 1) { |
| // Compute tags for libraries requested by the user. |
| uris.addAll( |
| arguments.skip(1).map((argument) => Uri.base.resolve(argument))); |
| } else { |
| // Compute tags for dart2js itself. |
| uris.add(myLocation.resolve(DART2JS)); |
| uris.add(myLocation.resolve(DART2JS_MIRROR)); |
| } |
| |
| // Get the names of public dart2js libraries. |
| Iterable<String> names = LIBRARIES.keys.where(isPublicDart2jsLibrary); |
| |
| // Prepend "dart:" to the names. |
| uris.addAll(names.map((String name) => Uri.parse('dart:$name'))); |
| |
| Uri libraryRoot = myLocation.resolve(SDK_ROOT); |
| Uri packageRoot = Uri.base.resolve(Platform.packageRoot); |
| |
| analyze(uris, libraryRoot, packageRoot, handler.provider, handler) |
| .then(processMirrors); |
| } |
| |
| processMirrors(MirrorSystem mirrors) { |
| mirrors.libraries.forEach((_, LibraryMirror library) { |
| BackDoor.compilationUnitsOf(library).forEach(emitTagsForCompilationUnit); |
| }); |
| |
| output.closeSync(); |
| } |
| |
| /** |
| * From http://en.wikipedia.org/wiki/Ctags#Etags_2 |
| * |
| * A section starts with a two line header, one line containing a |
| * single <\x0c> character, followed by a line which consists of: |
| * |
| * {src_file},{size_of_tag_definition_data_in_bytes} |
| * |
| * The header is followed by tag definitions, one definition per line, |
| * with the format: |
| * |
| * {tag_definition_text}<\x7f>{tagname}<\x01>{line_number},{byte_offset} |
| */ |
| emitTagsForCompilationUnit(compilationUnit) { |
| // Certain variables in this method do not follow Dart naming |
| // conventions. This is because the format as written on Wikipedia |
| // looks very similar to Dart string interpolation that the author |
| // felt it would make sense to keep the names. |
| Uri uri = compilationUnit.uri; |
| var buffer = new StringBuffer(); |
| SourceFile file = handler.provider.sourceFiles[uri]; |
| String src_file = relativize(outputUri, uri, false); |
| |
| compilationUnit.declarations.forEach((_, DeclarationMirror mirror) { |
| Definition definition = new Definition.from(mirror, file); |
| String name = nameOf(mirror); |
| definition.writeOn(buffer, name); |
| |
| if (mirror is ClassMirror) { |
| emitTagsForClass(mirror, file, buffer); |
| } |
| }); |
| |
| var tag_definition_data = '$buffer'; |
| var size_of_tag_definition_data_in_bytes = tag_definition_data.length; |
| |
| // The header. |
| output.writeStringSync( |
| '\x0c\n${src_file},${size_of_tag_definition_data_in_bytes}\n'); |
| output.writeStringSync(tag_definition_data); |
| } |
| |
| void emitTagsForClass(ClassMirror cls, SourceFile file, StringBuffer buffer) { |
| String className = nameOf(cls); |
| |
| cls.declarations.forEach((_, DeclarationMirror mirror) { |
| Definition definition = new Definition.from(mirror, file); |
| String name = nameOf(mirror); |
| if (mirror is MethodMirror && mirror.isConstructor) { |
| if (name == '') { |
| name = className; |
| definition.writeOn(buffer, 'new $className'); |
| } else { |
| definition.writeOn(buffer, 'new $className.$name'); |
| } |
| } else { |
| definition.writeOn(buffer, '$className.$name'); |
| } |
| definition.writeOn(buffer, name); |
| }); |
| } |
| |
| class Definition { |
| final int byte_offset; |
| final int line_number; |
| final String tag_definition_text; |
| |
| Definition(this.byte_offset, this.line_number, this.tag_definition_text); |
| |
| factory Definition.from(DeclarationMirror mirror, SourceFile file) { |
| var location = mirror.location; |
| int byte_offset = location.offset; |
| int line_number = file.getLine(byte_offset) + 1; |
| |
| int lineStart = file.lineStarts[line_number - 1]; |
| |
| int lineEnd = file.lineStarts.length > line_number |
| // Subract 1 to remove trailing newline. |
| ? file.lineStarts[line_number] - 1 |
| : null; |
| String tag_definition_text = file.slowText().substring(lineStart, lineEnd); |
| |
| return new Definition(byte_offset, line_number, tag_definition_text); |
| } |
| |
| void writeOn(StringBuffer buffer, String tagname) { |
| buffer.write( |
| '${tag_definition_text}\x7f${tagname}' |
| '\x01${line_number},${byte_offset}\n'); |
| } |
| } |