Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
6c94490
chore(libghostty): sync ghostty source and terminal bindings
elias8 Aug 7, 2026
0181671
feat(libghostty): expose terminal mode and continuation options
elias8 Aug 7, 2026
b8e2ebc
feat(libghostty): expose terminal options and continuation (#140)
elias8 Aug 7, 2026
2b915a5
ci(deps): bump dorny/paths-filter from 4.0.2 to 4.0.3
dependabot[bot] Aug 10, 2026
63658e9
ci(deps): bump dorny/paths-filter from 4.0.2 to 4.0.3 (#141)
elias8 Aug 10, 2026
2dca542
fix: support Flutter 3.47 analyzer changes
elias8 Aug 13, 2026
c426091
fix: support Flutter 3.47 (#142)
elias8 Aug 13, 2026
bf6ea62
refactor(flterm): establish controller view boundary
elias8 Aug 13, 2026
e4f31cf
refactor(flterm): separate controller and view responsibilities (#143)
elias8 Aug 14, 2026
6deaece
refactor(flterm): align internal component names with domain boundaries
elias8 Aug 14, 2026
611cf21
refactor(flterm): align internal component names with domain boundari…
elias8 Aug 14, 2026
1ce5943
refactor(libghostty): reorganize public API and bindings
elias8 Aug 17, 2026
e4bbd7a
ci(libghostty): run shared Wasm tests
elias8 Aug 17, 2026
451f4b0
docs(libghostty): document public API refactor
elias8 Aug 17, 2026
e6b7230
refactor(libghostty): restructure and harden native and Wasm C ABI bi…
elias8 Aug 17, 2026
d572a47
feat(libghostty): sync latest Ghostty C API
elias8 Aug 17, 2026
6a72e70
perf(libghostty): optimize render traversal
elias8 Aug 17, 2026
a588555
docs: update changelogs for Ghostty sync
elias8 Aug 17, 2026
4c5d972
feat(libghostty): sync latest Ghostty C API (#147)
elias8 Aug 17, 2026
a1bf77c
ci(deps): bump dawidd6/action-download-artifact from 21 to 23
dependabot[bot] Aug 18, 2026
991cbb0
ci(deps): bump dawidd6/action-download-artifact from 21 to 23 (#148)
elias8 Aug 18, 2026
307f876
perf(libghostty): support reusable Kitty pixel buffers
elias8 Aug 18, 2026
840bb51
fix(flterm): stabilize Kitty image and placement rendering
elias8 Aug 18, 2026
2a4f5bd
docs: update changelogs for Kitty graphics
elias8 Aug 18, 2026
fbc5a7b
fix(flterm): stabilize Kitty graphics rendering (#149)
elias8 Aug 18, 2026
cb03a4b
ci(deps): bump browser-actions/setup-chrome from 2.1.2 to 2.2.0
dependabot[bot] Aug 19, 2026
1d81c7e
ci(deps): bump browser-actions/setup-chrome from 2.1.2 to 2.2.0 (#150)
elias8 Aug 19, 2026
f831ba0
fix(flterm): align Nerd Font symbol rendering
elias8 Aug 18, 2026
8b2c87f
fix(flterm): stabilize operator ligature shaping
elias8 Aug 19, 2026
5c04700
fix(flterm): stabilize kitty image replacement frames
elias8 Aug 19, 2026
65a9d22
docs(flterm): update changelog for rendering fixes
elias8 Aug 20, 2026
7993603
fix(flterm): correct glyph and Kitty image rendering (#151)
elias8 Aug 20, 2026
bc2c524
fix(flterm): recover text input when a delta desyncs from the sentinel
jacobaraujo7 Aug 15, 2026
fb81609
Merge branch 'cockpit/upstream-sync-2026-08-22' — sync with elias8/li…
pretodev Aug 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
ptyx: ${{ steps.filter.outputs.ptyx }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: dorny/paths-filter@7b450fff21473bca461d4b92ce414b9d0420d706 # v4.0.2
- uses: dorny/paths-filter@ceb8a2b8f2d89434be7ff52d3de7ec3738c5cc9d # v4.0.3
id: filter
with:
filters: |
Expand Down
7 changes: 3 additions & 4 deletions .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
ptyx: ${{ steps.filter.outputs.ptyx }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: dorny/paths-filter@7b450fff21473bca461d4b92ce414b9d0420d706 # v4.0.2
- uses: dorny/paths-filter@ceb8a2b8f2d89434be7ff52d3de7ec3738c5cc9d # v4.0.3
id: filter
with:
filters: |
Expand Down Expand Up @@ -220,7 +220,7 @@ jobs:
- uses: mlugg/setup-zig@d1434d08867e3ee9daa34448df10607b98908d29 # v2.2.1
with:
version: ${{ env.ZIG_VERSION }}
- uses: browser-actions/setup-chrome@2e1d749697dd1612b833dba4a722266286fbefcd # v2.1.2
- uses: browser-actions/setup-chrome@48ad923757ca74d66703209fe939badbdf80f2f4 # v2.2.0
- uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.pub-cache
Expand All @@ -246,13 +246,12 @@ jobs:
- name: isolate from repo git
run: touch ghostty/.git
- run: flutter pub get
- run: dart pub global activate very_good_cli
- name: build wasm
working-directory: packages/libghostty
run: dart run tool/build_wasm.dart
- name: run wasm tests
working-directory: packages/libghostty
run: very_good test --platform=chrome test/wasm
run: dart test --platform=chrome test --exclude-tags=ffi

test-flterm-golden:
name: test-flterm-linux-golden
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: download artifacts from main
uses: dawidd6/action-download-artifact@b6e2e70617bc3265edd6dab6c906732b2f1ae151 # v21
uses: dawidd6/action-download-artifact@57aa996fc1713cc1579039614f4645a7f4841fd4 # v23
with:
workflow: build.yml
branch: main
Expand Down
16 changes: 15 additions & 1 deletion all_lint_rules.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ linter:
- always_use_package_imports
- annotate_overrides
- annotate_redeclares
- async_return_with_no_await
- avoid_annotating_with_dynamic
- avoid_bool_literals_in_conditional_expressions
- avoid_catches_without_on_clauses
Expand Down Expand Up @@ -77,15 +78,18 @@ linter:
- document_ignores
- empty_catches
- empty_constructor_bodies
- empty_container_bodies
- empty_statements
- eol_at_end_of_file
- exhaustive_cases
- file_names
- flutter_style_todos
- future_sync_value
- hash_and_equals
- implementation_imports
- implicit_call_tearoffs
- implicit_reopen
- initialize_in_field_declaration
- invalid_case_patterns
- invalid_runtime_check_with_js_interop_types
- join_return_with_assignment
Expand All @@ -97,16 +101,19 @@ linter:
- lines_longer_than_80_chars
- literal_only_boolean_expressions
- matching_super_parameters
- migrate_design_widgets
- missing_code_block_language_in_doc_comment
- missing_whitespace_between_adjacent_strings
- no_adjacent_strings_in_list
- no_default_cases
- no_duplicate_case_values
- no_dynamic_casts
- no_leading_underscores_for_library_prefixes
- no_leading_underscores_for_local_identifiers
- no_literal_bool_comparisons
- no_logic_in_create_state
- no_runtimeType_toString
- no_raw_types
- no_runtimetype_tostring
- no_self_assignments
- no_wildcard_variable_uses
- non_constant_identifier_names
Expand Down Expand Up @@ -167,6 +174,7 @@ linter:
- remove_deprecations_in_breaking_versions
- require_trailing_commas
- secure_pubspec_urls
- simple_directive_paths
- simplify_variable_pattern
- sized_box_for_whitespace
- sized_box_shrink_expand
Expand All @@ -192,6 +200,7 @@ linter:
- unnecessary_brace_in_string_interps
- unnecessary_breaks
- unnecessary_const
- unnecessary_const_in_enum_constructor
- unnecessary_constructor_name
- unnecessary_final
- unnecessary_getters_setters
Expand All @@ -208,19 +217,23 @@ linter:
- unnecessary_nullable_for_final_variable_declarations
- unnecessary_overrides
- unnecessary_parenthesis
- unnecessary_primary_constructor_body
- unnecessary_raw_strings
- unnecessary_statements
- unnecessary_string_escapes
- unnecessary_string_interpolations
- unnecessary_this
- unnecessary_this_alias
- unnecessary_to_list_in_spreads
- unnecessary_type_name_in_constructor
- unnecessary_unawaited
- unnecessary_underscores
- unreachable_from_main
- unrelated_type_equality_checks
- unsafe_variance
- use_build_context_synchronously
- use_colored_box
- use_declaring_parameters
- use_decorated_box
- use_enums
- use_full_hex_values_for_flutter_colors
Expand All @@ -241,4 +254,5 @@ linter:
- use_to_and_as_if_applicable
- use_truncating_division
- valid_regexps
- var_with_no_type_annotation
- void_checks
50 changes: 31 additions & 19 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,26 @@ analyzer:
strict-raw-types: true

errors:
# The shared rule list includes mutually exclusive rules and rules that
# may not be recognized by every supported SDK.
included_file_warning: ignore

# Correctness
avoid_slow_async_io: error
avoid_type_to_string: error
avoid_web_libraries_in_flutter: error
cancel_subscriptions: error
close_sinks: error
collection_methods_unrelated_type: error
conditional_uri_does_not_exist: error
depend_on_referenced_packages: error
hash_and_equals: error
literal_only_boolean_expressions: error
missing_required_param: error
missing_return: error
no_duplicate_case_values: error
no_self_assignments: error
only_throw_errors: error
throw_in_finally: error
unrelated_type_equality_checks: error
unsafe_variance: error
Expand All @@ -31,35 +38,41 @@ analyzer:
use_build_context_synchronously: error

exclude:
# Generated and platform-specific build output is outside package source.
- "**/*.g.dart"
- "**/*.gr.dart"
- "**/*.freezed.dart"
- "**/*.config.dart"
- "**/*.gen.dart"
- "**/*.mocks.dart"
- "**/l10n/app_localizations*.dart"
- "**/generated/**"
- build/**
- android/**
- ios/**
- web/**
- windows/**
- macos/**
- linux/**

linter:
rules:
# Conflicting rules — disable the losing side of each pair.
always_specify_types: false # conflicts with omit_local_variable_types, omit_obvious_*
type_annotate_public_apis: false # conflicts with omit_obvious_property_types
always_use_package_imports: false # conflicts with prefer_relative_imports
prefer_double_quotes: false # conflicts with prefer_single_quotes
prefer_final_parameters: false # conflicts with avoid_final_parameters
unnecessary_final: false # conflicts with prefer_final_locals

# Too strict or noisy for a Flutter app.
# Allow the workspace's existing inferred-type declaration style.
always_specify_types: false
omit_local_variable_types: false
specify_nonobvious_property_types: false
specify_nonobvious_local_variable_types: false
type_annotate_public_apis: false

# Use relative internal imports and single-quoted strings across packages.
always_use_package_imports: false
prefer_double_quotes: false

# Keep final-variable and parameter choices consistent across packages.
prefer_final_parameters: false
unnecessary_final: false

# These rules are too noisy or too narrow for a reusable package workspace.
always_put_control_body_on_new_line: false
always_put_required_named_parameters_first: false
avoid_classes_with_only_static_members: false
avoid_setters_without_getters: false
cascade_invocations: false
comment_references: false
diagnostic_describe_all_properties: false
document_ignores: false
flutter_style_todos: false
one_member_abstracts: false
prefer_expression_function_bodies: false
Expand All @@ -68,5 +81,4 @@ linter:
prefer_mixin: false
public_member_api_docs: false
sort_constructors_first: false
avoid_setters_without_getters: false
document_ignores: false
specify_nonobvious_property_types: false
39 changes: 39 additions & 0 deletions packages/flterm/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,50 @@

## Unreleased

### Breaking

- **Renderer-neutral controller**: focus and soft-keyboard APIs move from
`TerminalController` to `TerminalView`. Pass a `FocusNode` for imperative
focus control and configure soft-keyboard access with `showKeyboard`.
- **Controller contract**: `TerminalController` supports one attached
`TerminalView`. A second concurrent attachment throws `StateError`.
- **Callback configuration**: `onBell`, `onOutput`, `onPwdChanged`, `onResize`,
and `onTitleChanged` are setter-only. Retain callback references if their
identity is needed elsewhere.
- **Removed public types**: `KeyboardState` and `TerminalScrollPosition` are no
longer exported. Use `FocusNode`, `TerminalView.showKeyboard`, and the
standard `ScrollPosition` interface.

### Changed

- **Incremental rendering**: frame building uses libghostty's dirty-row
iteration and bulk cleanup to reduce row scans and binding calls.
- **Resize lifecycle**: `onResize` reports only after `TerminalView` commits a
measured grid; assigning it later immediately reports that grid.
Cell-pixel-only changes skip the callback, and in-band output is emitted
first.

### Fixed

- **Cursor viewport state**: cursor and IME preedit rendering honor whether
the cursor has a valid viewport position and use its reported visual style.
- **Text input recovery**: terminal clients reconnect when another input client
takes the platform text input connection, including while composition is
active.
- **Keyboard and IME input**: AltGr printable input no longer emits synthetic
Control or Alt bytes, Kitty keyboard reports include Caps Lock and Num Lock,
and newline/deletion deduplication no longer duplicates or suppresses input.
- **Pointer input**: mouse and stylus button changes remain accurate during a
gesture, stylus drags select text, and a gesture no longer switches between
selection and terminal mouse reporting.
- **View updates**: controller swaps transfer terminal focus correctly, and
changing `TerminalView.fontData` refreshes cell metrics.
- **Terminal glyph rendering**: Nerd Font symbols use common fallback families,
fit their cell without distortion, and preserve adjacent spacing. Operator
ligatures remain stable across complete runs.
- **Kitty graphics rendering**: unchanged and replacing images remain drawable,
decode pressure is bounded, replacement pixels and geometry publish
atomically, and placement geometry refreshes during layout and resizing.

## 0.0.5

Expand Down
7 changes: 6 additions & 1 deletion packages/flterm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ libghostty-vt engine.
keyboard on mobile, both on web.
- `TerminalController` owns the terminal and connects to a backend
(PTY, SSH, socket) via output/resize/bell/title callbacks. Helpers
for I/O, selection, focus, scrolling, paste, and mode toggling.
for I/O, selection, scrolling, paste, and mode toggling.
- Drag, double-click, triple-click, and Alt+drag selection over wide
characters (CJK, emoji, VS16, combining marks) with cell-snapped
boundaries.
Expand Down Expand Up @@ -72,6 +72,11 @@ TerminalView(
);
```

Attach a controller to only one `TerminalView` at a time. The view does not
dispose it; remove the view, dispose any formatters created by the controller,
then dispose the controller when the terminal session ends. Resize callbacks
begin after the view has measured and committed its first grid.

The same controller drives the terminal programmatically:

```dart
Expand Down
Binary file not shown.
2 changes: 1 addition & 1 deletion packages/flterm/example/lib/demo_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import 'dart:convert';
import 'dart:typed_data';

import 'package:flterm/flterm.dart';
import 'package:flutter/material.dart';
import 'package:material_ui/material_ui.dart';

class DemoPage extends StatefulWidget {
final TerminalTheme? theme;
Expand Down
2 changes: 1 addition & 1 deletion packages/flterm/example/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'package:flterm/flterm.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:material_ui/material_ui.dart';

import 'demo_page.dart';
import 'themes.dart';
Expand Down
5 changes: 3 additions & 2 deletions packages/flterm/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ resolution: workspace
publish_to: none

environment:
sdk: ^3.10.0
flutter: ">=3.32.0"
sdk: ^3.12.0
flutter: ">=3.44.0"

dependencies:
flterm:
path: ..
flutter:
sdk: flutter
material_ui: ^1.0.0

dev_dependencies:
flutter_test:
Expand Down
13 changes: 6 additions & 7 deletions packages/flterm/lib/flterm.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@ export 'package:libghostty/libghostty.dart'
UnderlineStyle,
initializeForWeb;

export 'src/foundation/callbacks.dart' show OnResize;
export 'src/controller/terminal_controller.dart'
show OnResize, TerminalController;
export 'src/foundation/cell_range.dart' show CellRange;
export 'src/foundation/color_palette.dart' show ColorPalette;
export 'src/foundation/dynamic_color.dart' show DynamicColor;
export 'src/foundation/input_types.dart' show KeyboardState, MouseAutoHide;
export 'src/foundation/input_types.dart' show MouseAutoHide;
export 'src/foundation/terminal_config.dart'
show ScrollToBottom, TerminalConfig;
export 'src/foundation/terminal_gesture_settings.dart'
Expand All @@ -62,8 +63,6 @@ export 'src/links/link_settings.dart'
LinkSettings,
LinkType,
LinkedFile;
export 'src/widgets/terminal_controller.dart' show TerminalController;
export 'src/widgets/terminal_scope.dart' show TerminalScope;
export 'src/widgets/terminal_scroll_controller.dart'
show TerminalScrollController, TerminalScrollPosition;
export 'src/widgets/terminal_view.dart' show TerminalView;
export 'src/view/terminal_scope.dart' show TerminalScope;
export 'src/view/terminal_scroll_controller.dart' show TerminalScrollController;
export 'src/view/terminal_view.dart' show TerminalView;
26 changes: 26 additions & 0 deletions packages/flterm/lib/src/controller/kitty_png_decoder.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import 'dart:typed_data';

import 'package:image/image.dart' show decodePng;
import 'package:libghostty/libghostty.dart';

var _installed = false;

/// Installs flterm's default PNG decoder for Kitty graphics.
///
/// Installation is idempotent across terminal sessions.
void installDefaultKittyPngDecoder() {
if (_installed) return;
_installed = true;
LibGhostty.setPngDecoder(_decodePng);
}

DecodedImage? _decodePng(Uint8List bytes) {
final decoded = decodePng(bytes);
if (decoded == null) return null;
final rgba = decoded.convert(format: .uint8, numChannels: 4);
return DecodedImage(
width: rgba.width,
height: rgba.height,
rgba: rgba.toUint8List(),
);
}
Loading
Loading