Skip to content

Add shift range text selection #206

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
144 changes: 144 additions & 0 deletions lib/src/core/buffer/range_shift.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import 'package:xterm/src/core/buffer/cell_offset.dart';
import 'package:xterm/src/core/buffer/range.dart';
import 'package:xterm/src/core/buffer/segment.dart';

/// A range of cells in the buffer that represents a shift selection.
/// This range is used when the user holds the shift key while selecting text.
class BufferRangeShift extends BufferRange {
BufferRangeShift(super.begin, super.end);

@override
bool get isNormalized => true;

@override
bool get isCollapsed => begin == end;

@override
BufferRange get normalized {
if (isNormalized) {
return this;
}
return BufferRangeShift(end, begin);
}

@override
List<BufferSegment> toSegments() {
final isReversed = begin.y > end.y || (begin.y == end.y && begin.x > end.x);
final segmentStart = isReversed ? end : begin;
final segmentEnd = isReversed ? begin : end;

if (segmentStart.y == segmentEnd.y) {
return [
BufferSegment(
this,
segmentStart.y,
segmentStart.x,
segmentEnd.x,
),
];
}

final segments = <BufferSegment>[];
final startLine = segmentStart.y;
final endLine = segmentEnd.y;

segments.add(BufferSegment(
this,
startLine,
segmentStart.x,
null,
));

for (var line = startLine + 1; line < endLine; line++) {
segments.add(BufferSegment(
this,
line,
0,
null,
));
}

segments.add(BufferSegment(
this,
endLine,
0,
segmentEnd.x,
));

return segments;
}

@override
bool contains(CellOffset offset) {
final minY = begin.y < end.y ? begin.y : end.y;
final maxY = begin.y > end.y ? begin.y : end.y;

if (offset.y < minY || offset.y > maxY) {
return false;
}

if (begin.y == end.y) {
final minX = begin.x < end.x ? begin.x : end.x;
final maxX = begin.x > end.x ? begin.x : end.x;
return offset.x >= minX && offset.x <= maxX;
}

if (offset.y == begin.y) {
if (begin.y < end.y) {
return offset.x >= begin.x;
} else {
return offset.x <= begin.x;
}
}

if (offset.y == end.y) {
if (begin.y < end.y) {
return offset.x <= end.x;
} else {
return offset.x >= end.x;
}
}

return true;
}

@override
BufferRange merge(BufferRange other) {
if (other is! BufferRangeShift) {
final normalized = this.normalized;
final otherNormalized = other.normalized;

final newBegin = normalized.begin.isBefore(otherNormalized.begin)
? normalized.begin
: otherNormalized.begin;

final newEnd = normalized.end.isAfter(otherNormalized.end)
? normalized.end
: otherNormalized.end;

return BufferRangeShift(newBegin, newEnd);
}

final normalized = this.normalized;
final otherNormalized = other.normalized;

final newBegin = normalized.begin.isBefore(otherNormalized.begin)
? normalized.begin
: otherNormalized.begin;

final newEnd = normalized.end.isAfter(otherNormalized.end)
? normalized.end
: otherNormalized.end;

return BufferRangeShift(newBegin, newEnd);
}

@override
BufferRange extend(CellOffset newEnd) {
if (begin.y < newEnd.y || (begin.y == newEnd.y && begin.x < newEnd.x)) {
return BufferRangeShift(begin, newEnd);
} else {
return BufferRangeShift(newEnd, begin);
}
}
}
3 changes: 3 additions & 0 deletions lib/src/ui/controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:xterm/src/core/buffer/line.dart';
import 'package:xterm/src/core/buffer/range.dart';
import 'package:xterm/src/core/buffer/range_block.dart';
import 'package:xterm/src/core/buffer/range_line.dart';
import 'package:xterm/src/core/buffer/range_shift.dart';
import 'package:xterm/src/ui/pointer_input.dart';
import 'package:xterm/src/ui/selection_mode.dart';

Expand Down Expand Up @@ -73,6 +74,8 @@ class TerminalController with ChangeNotifier {
return BufferRangeLine(begin, end);
case SelectionMode.block:
return BufferRangeBlock(begin, end);
case SelectionMode.shift:
return BufferRangeShift(begin, end);
}
}

Expand Down
Loading