diff --git a/example/pubspec.lock b/example/pubspec.lock index 53164fc..af91d09 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -13,18 +13,18 @@ packages: dependency: transitive description: name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.1" collection: dependency: "direct main" description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.1" flutter: dependency: "direct main" description: flutter @@ -66,18 +66,18 @@ packages: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.13.0" meta: dependency: transitive description: name: meta - sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.18.0" path: dependency: transitive description: @@ -92,7 +92,7 @@ packages: path: ".." relative: true source: path - version: "0.9.0" + version: "0.10.0" re_highlight: dependency: "direct main" description: @@ -105,7 +105,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" stream_channel: dependency: transitive description: @@ -118,10 +118,10 @@ packages: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.2.0" sdks: - dart: ">=3.2.0-0 <4.0.0" + dart: ">=3.10.0-0 <4.0.0" flutter: ">=1.17.0" diff --git a/lib/src/_code_field.dart b/lib/src/_code_field.dart index f5d4ff9..934d4ea 100644 --- a/lib/src/_code_field.dart +++ b/lib/src/_code_field.dart @@ -1183,8 +1183,23 @@ class _CodeFieldRender extends RenderBox implements MouseTrackerAnnotation { } void _calculatePreferredLineHeight() { + // Measured with the same strut the paragraphs are laid out with, see + // `_CodeParagraphProvider.updateBaseStyle`. + // + // This number is the grid the editor places lines on, so it has to be the + // height a line actually gets. Measured without the strut it was three + // points taller here, and every line scrolled past added that much to the + // correction the layout applies to the scroll offset. Scrolling up by a + // page then pushed the offset above the top of the document and the + // physics sprang it back — a bounce nobody asked for. final TextPainter painter = TextPainter( textDirection: TextDirection.ltr, + strutStyle: StrutStyle( + fontSize: _textStyle.fontSize, + fontFamily: _textStyle.fontFamily, + height: _textStyle.height, + forceStrutHeight: true, + ), ); painter.text = TextSpan( text: '0', diff --git a/lib/src/_code_paragraph.dart b/lib/src/_code_paragraph.dart index d975fed..bddedb9 100644 --- a/lib/src/_code_paragraph.dart +++ b/lib/src/_code_paragraph.dart @@ -128,7 +128,20 @@ class _ParagraphImpl extends IParagraph { if (range.isCollapsed) { return const []; } - return paragraph.getBoxesForRange(range.start, range.end, boxHeightStyle: ui.BoxHeightStyle.max).map((e) => e.toRect()).toList(); + // Selection boxes span the whole line of the grid rather than the ascent + // and descent of the glyphs. + // + // `BoxHeightStyle.max` measures the runs, and a run is shorter than the + // line it sits on, so adjacent boxes did not touch and a selection dragged + // over several lines looked striped. An empty line made it obvious: the + // branch above returns a box of a full `preferredLineHeight` for it, so + // the gap changed depending on whether a line had any text on it. + return paragraph.getBoxesForRange(range.start, range.end, boxHeightStyle: ui.BoxHeightStyle.max).map((e) { + final Rect rect = e.toRect(); + final int line = max(0, (rect.center.dy / _preferredLineHeight).floor()); + final double top = line * _preferredLineHeight; + return Rect.fromLTRB(rect.left, top, rect.right, top + _preferredLineHeight); + }).toList(); } Offset? _getOffsetDownstream(int position) { @@ -210,19 +223,26 @@ class _CodeParagraphProvider { if (uiStyle == _style) { return; } + // One strut for both the paragraph layout and the line height measured + // below. Measured without the strut, `_preferredLineHeight` is a different + // number than the height a line is actually given: for Consolas 13.09 it + // is 21 against 18. Lines are then placed on a grid that is taller than + // they are, which shows up as a stripe of background between them. + final StrutStyle strutStyle = StrutStyle( + fontSize: style.fontSize, + fontFamily: style.fontFamily, + height: style.height, + forceStrutHeight: true, + ); _paragraphStyle = style.getParagraphStyle( textAlign: TextAlign.left, textDirection: TextDirection.ltr, - strutStyle: StrutStyle( - fontSize: style.fontSize, - fontFamily: style.fontFamily, - height: style.height, - forceStrutHeight: true, - ) + strutStyle: strutStyle ); _style = uiStyle; final TextPainter painter = TextPainter( textDirection: TextDirection.ltr, + strutStyle: strutStyle, ); painter.text = TextSpan( text: '0',