debugger_view.dart 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. import 'package:flutter/material.dart';
  2. import 'package:xterm/src/utils/debugger.dart';
  3. class TerminalDebuggerView extends StatefulWidget {
  4. const TerminalDebuggerView(
  5. this.debugger, {
  6. Key? key,
  7. this.scrollController,
  8. this.onSeek,
  9. }) : super(key: key);
  10. final TerminalDebugger debugger;
  11. final ScrollController? scrollController;
  12. final void Function(int?)? onSeek;
  13. @override
  14. State<TerminalDebuggerView> createState() => _TerminalDebuggerViewState();
  15. }
  16. class _TerminalDebuggerViewState extends State<TerminalDebuggerView> {
  17. int? selectedCommand;
  18. @override
  19. void initState() {
  20. widget.debugger.addListener(_onDebuggerChanged);
  21. super.initState();
  22. }
  23. @override
  24. void didUpdateWidget(covariant TerminalDebuggerView oldWidget) {
  25. if (oldWidget.debugger != widget.debugger) {
  26. oldWidget.debugger.removeListener(_onDebuggerChanged);
  27. widget.debugger.addListener(_onDebuggerChanged);
  28. }
  29. super.didUpdateWidget(oldWidget);
  30. }
  31. @override
  32. void dispose() {
  33. widget.debugger.removeListener(_onDebuggerChanged);
  34. super.dispose();
  35. }
  36. void _onDebuggerChanged() {
  37. setState(() {});
  38. }
  39. @override
  40. Widget build(BuildContext context) {
  41. final commands = widget.debugger.commands;
  42. return ListView.builder(
  43. itemExtent: 20,
  44. controller: widget.scrollController,
  45. itemCount: commands.length,
  46. itemBuilder: (context, index) {
  47. final command = commands[index];
  48. return _CommandItem(
  49. index,
  50. command,
  51. selected: selectedCommand == index,
  52. onTap: () {
  53. if (selectedCommand == index) {
  54. selectedCommand = null;
  55. } else {
  56. setState(() => selectedCommand = index);
  57. }
  58. widget.onSeek?.call(selectedCommand);
  59. },
  60. );
  61. },
  62. );
  63. }
  64. }
  65. class _CommandItem extends StatelessWidget {
  66. const _CommandItem(
  67. this.index,
  68. this.command, {
  69. Key? key,
  70. this.onTap,
  71. this.selected = false,
  72. }) : super(key: key);
  73. final int index;
  74. final TerminalCommand command;
  75. final bool selected;
  76. final void Function()? onTap;
  77. @override
  78. Widget build(BuildContext context) {
  79. return GestureDetector(
  80. onTap: onTap,
  81. child: MouseRegion(
  82. cursor: SystemMouseCursors.click,
  83. onEnter: (event) {
  84. if (event.down) {
  85. onTap?.call();
  86. }
  87. },
  88. child: Container(
  89. decoration: BoxDecoration(
  90. border: Border.all(
  91. color: selected ? Colors.blue : Colors.transparent,
  92. width: 2,
  93. ),
  94. borderRadius: BorderRadius.circular(5),
  95. ),
  96. child: Row(
  97. children: [
  98. Container(
  99. width: 50,
  100. child: Text(
  101. '${index + 1}',
  102. style: TextStyle(
  103. color: selected ? Colors.blue : Colors.black,
  104. fontFamily: 'monospace',
  105. fontFamilyFallback: [
  106. 'Menlo',
  107. 'Monaco',
  108. 'Consolas',
  109. 'Liberation Mono',
  110. 'Courier New',
  111. 'Noto Sans Mono CJK SC',
  112. 'Noto Sans Mono CJK TC',
  113. 'Noto Sans Mono CJK KR',
  114. 'Noto Sans Mono CJK JP',
  115. 'Noto Sans Mono CJK HK',
  116. 'Noto Color Emoji',
  117. 'Noto Sans Symbols',
  118. 'monospace',
  119. 'sans-serif',
  120. ],
  121. ),
  122. textAlign: TextAlign.right,
  123. ),
  124. ),
  125. SizedBox(width: 20),
  126. Container(
  127. width: 100,
  128. child: Text(
  129. command.escapedChars,
  130. style: TextStyle(color: command.error ? Colors.red : null),
  131. ),
  132. ),
  133. Expanded(
  134. child: Container(
  135. child: Text(
  136. command.explanation.join(','),
  137. style: TextStyle(color: command.error ? Colors.red : null),
  138. ),
  139. ),
  140. ),
  141. ],
  142. ),
  143. ),
  144. ),
  145. );
  146. }
  147. }