yoxterm 4.1.0 copy "yoxterm: ^4.1.0" to clipboard
yoxterm: ^4.1.0 copied to clipboard

High-performance terminal emulator for Flutter — a performance-focused fork of xterm.dart with glyph-atlas rendering, pooled paint ops and parser fast paths. Mobile and desktop supported.

example/lib/main.dart

import 'dart:convert';
import 'dart:io';

import 'package:example/src/platform_menu.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_pty/flutter_pty.dart';
import 'package:yoxterm/xterm.dart';

void main() {
  runApp(MyApp());
}

bool get isDesktop {
  if (kIsWeb) return false;
  return [
    TargetPlatform.windows,
    TargetPlatform.linux,
    TargetPlatform.macOS,
  ].contains(defaultTargetPlatform);
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'xterm.dart demo',
      debugShowCheckedModeBanner: false,
      home: AppPlatformMenu(child: Home()),
    );
  }
}

class Home extends StatefulWidget {
  Home({super.key});

  @override
  HomeState createState() => HomeState();
}

class HomeState extends State<Home> {
  final terminal = Terminal(maxLines: 10000);
  final terminalController = TerminalController();

  late final Pty pty;

  double _scale = 1.0;
  static const double _baseWidth = 800;
  static const double _baseHeight = 600;

  @override
  void initState() {
    super.initState();

    WidgetsBinding.instance.endOfFrame.then(
      (_) {
        if (mounted) _startPty();
      },
    );
  }

  void _startPty() {
    // Print a box-drawing demo before the shell starts.
    terminal.write(
      '\u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E\r\n'
      '\u2502  hello  \u2502\r\n'
      '\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F\r\n'
      '\r\n',
    );

    pty = Pty.start(
      shell,
      columns: terminal.viewWidth,
      rows: terminal.viewHeight,
    );

    pty.output
        .cast<List<int>>()
        .transform(Utf8Decoder())
        .listen(terminal.write);

    pty.exitCode.then((code) {
      terminal.write('the process exited with exit code $code');
    });

    terminal.onOutput = (data) {
      pty.write(const Utf8Encoder().convert(data));
    };

    terminal.onResize = (w, h, pw, ph) {
      pty.resize(h, w);
    };
  }

  void _setScale(double value) {
    setState(() {
      _scale = value;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.transparent,
      body: SafeArea(
        child: Stack(
          children: [
            Center(
              child: Transform.scale(
                scale: _scale,
                alignment: Alignment.topLeft,
                child: SizedBox(
                  width: _baseWidth,
                  height: _baseHeight,
                  child: TerminalView(
                    terminal,
                    controller: terminalController,
                    autofocus: true,
                    backgroundOpacity: 0.7,
                    onSecondaryTapDown: (details, offset) async {
                      final selection = terminalController.selection;
                      if (selection != null) {
                        final text = terminal.buffer.getText(selection);
                        terminalController.clearSelection();
                        await Clipboard.setData(ClipboardData(text: text));
                      } else {
                        final data = await Clipboard.getData('text/plain');
                        final text = data?.text;
                        if (text != null) {
                          terminal.paste(text);
                        }
                      }
                    },
                  ),
                ),
              ),
            ),
            Positioned(
              top: 8,
              left: 8,
              child: Container(
                padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
                decoration: BoxDecoration(
                  color: Colors.black87,
                  borderRadius: BorderRadius.circular(4),
                ),
                child: Text(
                  'Scale: ${_scale.toStringAsFixed(2)}x  |  '
                  'Base: ${_baseWidth.toInt()}x${_baseHeight.toInt()}  |  '
                  'Rendered: ${(_baseWidth * _scale).toInt()}x${(_baseHeight * _scale).toInt()}',
                  style: const TextStyle(
                    color: Colors.white,
                    fontSize: 12,
                    fontFamily: 'monospace',
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
      floatingActionButton: Wrap(
        spacing: 8,
        runSpacing: 8,
        children: [
          for (final s in [0.5, 0.75, 1.0, 1.25, 1.5, 2.0])
            FloatingActionButton.small(
              heroTag: 'scale_$s',
              backgroundColor:
                  _scale == s ? Colors.blue : Colors.grey.shade800,
              onPressed: () => _setScale(s),
              child: Text(
                '${s}x',
                style: const TextStyle(fontSize: 10, color: Colors.white),
              ),
            ),
        ],
      ),
    );
  }
}

String get shell {
  if (Platform.isMacOS || Platform.isLinux) {
    return Platform.environment['SHELL'] ?? 'bash';
  }

  if (Platform.isWindows) {
    return 'cmd.exe';
  }

  return 'sh';
}
0
likes
140
points
180
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

High-performance terminal emulator for Flutter — a performance-focused fork of xterm.dart with glyph-atlas rendering, pooled paint ops and parser fast paths. Mobile and desktop supported.

Repository (GitHub)
View/report issues

Topics

#terminal #xterm #vt100 #ansi #emulator

License

MIT (license)

Dependencies

convert, equatable, flutter, meta, quiver, zmodem

More

Packages that depend on yoxterm