Unverified Commit 866fa64d authored by Zachary Anderson's avatar Zachary Anderson Committed by GitHub

Esarbanis flutter run help (#48314)

* Reword flutter run help screen.

* As per Hixie request, added Efthymios Sarmpanis to the AUTHORS file

* fix test
Co-authored-by: 's avatarEfthymis Sarmpanis <e.sarbanis@gmail.com>
parent 76b21d28
......@@ -49,3 +49,4 @@ Robin Jespersen <info@unitedpartners.de>
Jefferson Quesado <jeff.quesado@gmail.com>
Mark Diener <rpzrpzrpz@gmail.com>
Alek Åström <alek.astrom@gmail.com>
Efthymios Sarpmpanis <e.sarbanis@gmail.com>
// Copyright 2014 The Flutter Authors. 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:math' as math;
import '../globals.dart' as globals;
import 'terminal.dart';
const String fire = '🔥';
const int maxLineWidth = 84;
/// Encapsulates the help text construction and printing
class CommandHelp {
const CommandHelp._(this.key, this.description, [this.inParenthesis = '']);
static const CommandHelp L = CommandHelp._('L', 'Dump layer tree to the console.', 'debugDumpLayerTree');
static const CommandHelp P = CommandHelp._('P', 'Toggle performance overlay.', 'WidgetsApp.showPerformanceOverlay');
static const CommandHelp R = CommandHelp._('R', 'Hot restart.');
static const CommandHelp S = CommandHelp._('S', 'Dump accessibility tree in traversal order.', 'debugDumpSemantics');
static const CommandHelp U = CommandHelp._('U', 'Dump accessibility tree in inverse hit test order.', 'debugDumpSemantics');
static const CommandHelp a = CommandHelp._('a', 'Toggle timeline events for all widget build methods.', 'debugProfileWidgetBuilds');
static const CommandHelp d = CommandHelp._('d', 'Detach (terminate "flutter run" but leave application running).');
static const CommandHelp h = CommandHelp._('h', 'Repeat this help message.');
static const CommandHelp i = CommandHelp._('i', 'Toggle widget inspector.', 'WidgetsApp.showWidgetInspectorOverride');
static const CommandHelp o = CommandHelp._('o', 'Simulate different operating systems.', 'defaultTargetPlatform');
static const CommandHelp p = CommandHelp._('p', 'Toggle the display of construction lines.', 'debugPaintSizeEnabled');
static const CommandHelp q = CommandHelp._('q', 'Quit (terminate the application on the device).');
static const CommandHelp r = CommandHelp._('r', 'Hot reload. $fire$fire$fire');
static const CommandHelp s = CommandHelp._('s', 'Save a screenshot to flutter.png.');
static const CommandHelp t = CommandHelp._('t', 'Dump rendering tree to the console.', 'debugDumpRenderTree');
static const CommandHelp w = CommandHelp._('w', 'Dump widget hierarchy to the console.', 'debugDumpApp');
static const CommandHelp z = CommandHelp._('z', 'Toggle elevation checker.');
/// The key associated with this command
final String key;
/// A description of what this command does
final String description;
/// Text shown in parenthesis to give the context
final String inParenthesis;
bool get _hasTextInParenthesis => inParenthesis != null && inParenthesis.isNotEmpty;
int get _rawMessageLength => key.length + description.length;
@override
String toString() {
final StringBuffer message = StringBuffer();
message.writeAll(<String>[globals.terminal.bolden(key), description], ' ');
if (_hasTextInParenthesis) {
bool wrap = false;
final int maxWidth = math.max(outputPreferences.wrapColumn ?? 0, maxLineWidth);
int width = maxWidth - (globals.platform.stdoutSupportsAnsi ? _rawMessageLength + 1 : message.length);
final String parentheticalText = '($inParenthesis)';
if (width < parentheticalText.length) {
width = maxWidth;
wrap = true;
}
if (wrap) {
message.write('\n');
}
// pad according to the raw text
message.write(''.padLeft(width - parentheticalText.length));
message.write(globals.terminal.color(parentheticalText, TerminalColor.grey));
}
return message.toString();
}
void print() {
globals.printStatus(toString());
}
}
......@@ -9,6 +9,7 @@ import 'package:meta/meta.dart';
import 'application_package.dart';
import 'artifacts.dart';
import 'asset.dart';
import 'base/command_help.dart';
import 'base/common.dart';
import 'base/file_system.dart';
import 'base/io.dart' as io;
......@@ -1003,23 +1004,30 @@ abstract class ResidentRunner {
void printHelp({ @required bool details });
void printHelpDetails() {
if (flutterDevices.any((FlutterDevice d) => d.device.supportsScreenshot)) {
CommandHelp.s.print();
}
if (supportsServiceProtocol) {
globals.printStatus('You can dump the widget hierarchy of the app (debugDumpApp) by pressing "w".');
globals.printStatus('To dump the rendering tree of the app (debugDumpRenderTree), press "t".');
CommandHelp.w.print();
CommandHelp.t.print();
if (isRunningDebug) {
globals.printStatus('For layers (debugDumpLayerTree), use "L"; for accessibility (debugDumpSemantics), use "S" (for traversal order) or "U" (for inverse hit test order).');
globals.printStatus('To toggle the widget inspector (WidgetsApp.showWidgetInspectorOverride), press "i".');
globals.printStatus('To toggle the display of construction lines (debugPaintSizeEnabled), press "p".');
globals.printStatus('To simulate different operating systems, (defaultTargetPlatform), press "o".');
globals.printStatus('To toggle the elevation checker, press "z".');
CommandHelp.L.print();
CommandHelp.S.print();
CommandHelp.U.print();
CommandHelp.i.print();
CommandHelp.p.print();
CommandHelp.o.print();
CommandHelp.z.print();
} else {
globals.printStatus('To dump the accessibility tree (debugDumpSemantics), press "S" (for traversal order) or "U" (for inverse hit test order).');
CommandHelp.S.print();
CommandHelp.U.print();
}
globals.printStatus('To display the performance overlay (WidgetsApp.showPerformanceOverlay), press "P".');
globals.printStatus('To enable timeline events for all widget build methods, (debugProfileWidgetBuilds), press "a"');
// `P` should precede `a`
CommandHelp.P.print();
CommandHelp.a.print();
}
if (flutterDevices.any((FlutterDevice d) => d.device.supportsScreenshot)) {
globals.printStatus('To save a screenshot to flutter.png, press "s".');
CommandHelp.s.print();
}
}
......
......@@ -6,6 +6,7 @@ import 'dart:async';
import 'package:meta/meta.dart';
import 'base/command_help.dart';
import 'base/file_system.dart';
import 'device.dart';
import 'globals.dart' as globals;
......@@ -179,31 +180,23 @@ class ColdRunner extends ResidentRunner {
@override
void printHelp({ @required bool details }) {
bool haveDetails = false;
bool haveAnything = false;
for (final FlutterDevice device in flutterDevices) {
final String dname = device.device.name;
if (device.vmService != null) {
globals.printStatus('An Observatory debugger and profiler on $dname is '
'available at: ${device.vmService .httpAddress}');
}
}
globals.printStatus('Flutter run key commands.');
if (supportsServiceProtocol) {
haveDetails = true;
if (details) {
printHelpDetails();
haveAnything = true;
}
}
final String quitMessage = _didAttach
? 'To detach, press "d"; to quit, press "q".'
: 'To quit, press "q".';
if (haveDetails && !details) {
globals.printStatus('For a more detailed help message, press "h". $quitMessage');
} else if (haveAnything) {
globals.printStatus('To repeat this help message, press "h". $quitMessage');
} else {
globals.printStatus(quitMessage);
CommandHelp.h.print();
if (_didAttach) {
CommandHelp.d.print();
}
CommandHelp.q.print();
for (final FlutterDevice device in flutterDevices) {
final String dname = device.device.name;
if (device.vmService != null) {
globals.printStatus('An Observatory debugger and profiler on $dname is '
'available at: ${device.vmService.httpAddress}');
}
}
}
......
......@@ -9,12 +9,12 @@ import 'package:json_rpc_2/error_code.dart' as rpc_error_code;
import 'package:json_rpc_2/json_rpc_2.dart' as rpc;
import 'package:meta/meta.dart';
import 'package:pool/pool.dart';
import 'base/async_guard.dart';
import 'base/command_help.dart';
import 'base/context.dart';
import 'base/file_system.dart';
import 'base/logger.dart';
import 'base/terminal.dart';
import 'base/utils.dart';
import 'build_info.dart';
import 'compile.dart';
......@@ -1045,29 +1045,23 @@ class HotRunner extends ResidentRunner {
@override
void printHelp({ @required bool details }) {
const String fire = '🔥';
String rawMessage = ' To hot reload changes while running, press "r". ';
globals.printStatus('Flutter run key commands.');
CommandHelp.r.print();
if (canHotRestart) {
rawMessage += 'To hot restart (and rebuild state), press "R".';
CommandHelp.R.print();
}
final String message = globals.terminal.color(
fire + globals.terminal.bolden(rawMessage),
TerminalColor.red,
);
globals.printStatus(message);
for (final FlutterDevice device in flutterDevices) {
final String dname = device.device.name;
globals.printStatus('An Observatory debugger and profiler on $dname is '
'available at: ${device.vmService.httpAddress}');
CommandHelp.h.print();
if (_didAttach) {
CommandHelp.d.print();
}
final String quitMessage = _didAttach
? 'To detach, press "d"; to quit, press "q".'
: 'To quit, press "q".';
CommandHelp.q.print();
if (details) {
printHelpDetails();
globals.printStatus('To repeat this help message, press "h". $quitMessage');
} else {
globals.printStatus('For a more detailed help message, press "h". $quitMessage');
}
for (final FlutterDevice device in flutterDevices) {
final String dname = device.device.name;
globals.printStatus('An Observatory debugger and profiler on $dname is '
'available at:\n${device.vmService.httpAddress}');
}
}
......
......@@ -165,7 +165,10 @@ void main() {
if (message == '[stdout] Lost connection to device.') {
observatoryLogs.add(message);
}
if (message.contains('To hot reload changes while running, press "r". To hot restart (and rebuild state), press "R".')) {
if (message.contains('Hot reload.')) {
observatoryLogs.add(message);
}
if (message.contains('Hot restart.')) {
observatoryLogs.add(message);
}
});
......@@ -203,14 +206,16 @@ void main() {
}));
});
expect(observatoryLogs.length, 7);
expect(observatoryLogs.length, 9);
expect(observatoryLogs[0], '[stdout] Waiting for a connection from Flutter on MockAndroidDevice...');
expect(observatoryLogs[1], '[verbose] Observatory URL on device: http://127.0.0.1:1234');
expect(observatoryLogs[2], '[stdout] Lost connection to device.');
expect(observatoryLogs[3].contains('To hot reload changes while running, press "r". To hot restart (and rebuild state), press "R"'), isTrue);
expect(observatoryLogs[4], '[verbose] Observatory URL on device: http://127.0.0.1:1235');
expect(observatoryLogs[5], '[stdout] Lost connection to device.');
expect(observatoryLogs[6].contains('To hot reload changes while running, press "r". To hot restart (and rebuild state), press "R"'), isTrue);
expect(observatoryLogs[3].contains('Hot reload.'), isTrue);
expect(observatoryLogs[4].contains('Hot restart.'), isTrue);
expect(observatoryLogs[5], '[verbose] Observatory URL on device: http://127.0.0.1:1235');
expect(observatoryLogs[6], '[stdout] Lost connection to device.');
expect(observatoryLogs[7].contains('Hot reload.'), isTrue);
expect(observatoryLogs[8].contains('Hot restart.'), isTrue);
verify(portForwarder.forward(1234, hostPort: anyNamed('hostPort'))).called(1);
verify(portForwarder.forward(1235, hostPort: anyNamed('hostPort'))).called(1);
......
......@@ -6,6 +6,7 @@ import 'dart:async';
import 'package:file/memory.dart';
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/command_help.dart';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/context.dart';
import 'package:flutter_tools/src/base/file_system.dart';
......@@ -365,21 +366,33 @@ void main() {
// supports service protocol
expect(residentRunner.supportsServiceProtocol, true);
expect(testLogger.statusText, contains('"w"'));
expect(testLogger.statusText, contains('"t"'));
expect(testLogger.statusText, contains('"P"'));
expect(testLogger.statusText, contains('"a"'));
// isRunningDebug
expect(residentRunner.isRunningDebug, true);
expect(testLogger.statusText, contains('"L"'));
expect(testLogger.statusText, contains('"S"'));
expect(testLogger.statusText, contains('"U"'));
expect(testLogger.statusText, contains('"i"'));
expect(testLogger.statusText, contains('"p"'));
expect(testLogger.statusText, contains('"o"'));
expect(testLogger.statusText, contains('"z"'));
// screenshot
expect(testLogger.statusText, contains('"s"'));
// commands
expect(testLogger.statusText, equals(
<dynamic>[
'Flutter run key commands.',
CommandHelp.r,
CommandHelp.R,
CommandHelp.h,
CommandHelp.q,
CommandHelp.s,
CommandHelp.w,
CommandHelp.t,
CommandHelp.L,
CommandHelp.S,
CommandHelp.U,
CommandHelp.i,
CommandHelp.p,
CommandHelp.o,
CommandHelp.z,
CommandHelp.P,
CommandHelp.a,
CommandHelp.s,
'An Observatory debugger and profiler on null is available at:\nnull',
''
].join('\n')
));
}));
test('ResidentRunner can take screenshot on debug device', () => testbed.run(() async {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment