summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/screen.h3
-rw-r--r--src/selection.c77
-rw-r--r--src/snapshot.c3
3 files changed, 61 insertions, 22 deletions
diff --git a/src/screen.h b/src/screen.h
index 0bd95c0..df464a7 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -18,7 +18,8 @@ void term_screen_insert_chars(struct term *t, int count);
const struct cell *term_screen_view_row(const struct term *t, int y);
uint64_t term_screen_view_row_key(const struct term *t, int y);
/* The selected columns [c0, c1] of each view row; c1 < c0 when none. */
-void term_selection_view_spans(const struct term *t, int *c0, int *c1);
+/* False when memory runs out; c0 and c1 are then not complete. */
+bool term_selection_view_spans(const struct term *t, int *c0, int *c1);
int term_screen_history_rows(const struct term *t);
diff --git a/src/selection.c b/src/selection.c
index 40fb1f1..1d931c9 100644
--- a/src/selection.c
+++ b/src/selection.c
@@ -109,7 +109,9 @@ struct lines {
struct line_pos stack[256];
};
-static void lines_init(struct lines *L, const struct term *t)
+/* False when a screen taller than the stack array needs memory and none is
+ * left. L can still be passed to lines_free(). */
+static bool lines_init(struct lines *L, const struct term *t)
{
L->t = t;
L->cols = t->cols;
@@ -117,14 +119,16 @@ static void lines_init(struct lines *L, const struct term *t)
L->hist_end = L->hist ? hist_end_id(&t->hist) : 0;
L->first = first_retained_line(t);
L->pos = t->rows <= 256 ? L->stack : malloc((size_t)t->rows * sizeof(*L->pos));
- if (!L->pos)
+ if (!L->pos) {
L->pos = L->stack;
- int rows = L->pos == L->stack && t->rows > 256 ? 256 : t->rows;
+ return false;
+ }
struct line_pos p = screen_top_line(t);
- for (int y = 0; y < rows; y++) {
+ for (int y = 0; y < t->rows; y++) {
L->pos[y] = p;
p = line_pos_next(p, screen_get_row(&t->scr, y));
}
+ return true;
}
static void lines_free(struct lines *L)
@@ -135,7 +139,7 @@ static void lines_free(struct lines *L)
static inline int lines_rows(const struct lines *L)
{
- return L->pos == L->stack && L->t->rows > 256 ? 256 : L->t->rows;
+ return L->t->rows;
}
static inline bool in_hist(const struct lines *L, uint64_t id)
@@ -498,27 +502,48 @@ static void select_range(struct term *t, const struct lines *L,
t->selection = true;
}
-void term_select_start(struct term *t, struct term_vector2i cell, bool right_half,
+bool term_select_start(struct term *t, struct term_vector2i cell, bool right_half,
enum term_select_unit unit)
{
- if (!t) return;
+ if (!t) return false;
term_write_begin(t);
struct lines L;
- lines_init(&L, t);
+ if (!lines_init(&L, t)) {
+ lines_free(&L);
+ term_write_end(t);
+ return false;
+ }
+ struct term_sel_point first, last;
+ unit_span(&L, cell.x, cell.y, right_half, unit, &first, &last);
+ lines_free(&L);
+ enum term_select_unit old_unit = t->select_unit;
+ struct term_sel_point old_first = t->sel_anchor_first, old_last = t->sel_anchor_last;
+ bool old_selection = t->selection;
t->select_unit = unit;
- unit_span(&L, cell.x, cell.y, right_half, unit, &t->sel_anchor_first, &t->sel_anchor_last);
+ t->sel_anchor_first = first;
+ t->sel_anchor_last = last;
t->selection = false;
- lines_free(&L);
- term_select_extend(t, cell, right_half);
+ bool ok = term_select_extend(t, cell, right_half);
+ if (!ok) {
+ t->select_unit = old_unit;
+ t->sel_anchor_first = old_first;
+ t->sel_anchor_last = old_last;
+ t->selection = old_selection;
+ }
term_write_end(t);
+ return ok;
}
-void term_select_extend(struct term *t, struct term_vector2i cell, bool right_half)
+bool term_select_extend(struct term *t, struct term_vector2i cell, bool right_half)
{
- if (!t) return;
+ if (!t) return false;
term_write_begin(t);
struct lines L;
- lines_init(&L, t);
+ if (!lines_init(&L, t)) {
+ lines_free(&L);
+ term_write_end(t);
+ return false;
+ }
struct term_sel_point first, last;
unit_span(&L, cell.x, cell.y, right_half, t->select_unit, &first, &last);
if (sel_point_cmp(first, t->sel_anchor_first) > 0) first = t->sel_anchor_first;
@@ -529,6 +554,7 @@ void term_select_extend(struct term *t, struct term_vector2i cell, bool right_ha
select_range(t, &L, first, sel_point_prev(&L, last));
lines_free(&L);
term_write_end(t);
+ return true;
}
bool term_has_selection(const struct term *t)
@@ -541,7 +567,7 @@ bool term_has_selection(const struct term *t)
return has;
}
-void term_selection_view_spans(const struct term *t, int *c0, int *c1)
+bool term_selection_view_spans(const struct term *t, int *c0, int *c1)
{
int rows = t->rows, cols = t->cols;
for (int y = 0; y < rows; y++) {
@@ -549,13 +575,16 @@ void term_selection_view_spans(const struct term *t, int *c0, int *c1)
c1[y] = -1;
}
if (!t->selection)
- return;
+ return true;
struct lines L;
- lines_init(&L, t);
+ if (!lines_init(&L, t)) {
+ lines_free(&L);
+ return false;
+ }
struct term_sel_point start, end;
if (!selection_bounds(&L, &start, &end)) {
lines_free(&L);
- return;
+ return true;
}
uint64_t prev_id = UINT64_MAX;
int prev_seg = -1;
@@ -596,6 +625,7 @@ void term_selection_view_spans(const struct term *t, int *c0, int *c1)
c1[y] = (int)e;
}
lines_free(&L);
+ return true;
}
static bool text_reserve(char **text, size_t *cap, size_t need)
@@ -619,7 +649,10 @@ static char *range_text_inner(const struct term *t,
{
if (!t || (!bounds && !t->selection)) return NULL;
struct lines L;
- lines_init(&L, t);
+ if (!lines_init(&L, t)) {
+ lines_free(&L);
+ return NULL;
+ }
struct term_sel_point start, end;
if (bounds) {
start = bounds[0];
@@ -783,7 +816,11 @@ char *term_history_text(struct term *t, int max_rows)
}
int begin_row = end_row > max_rows ? end_row - max_rows : 0;
struct lines L;
- lines_init(&L, t);
+ if (!lines_init(&L, t)) {
+ lines_free(&L);
+ term_write_end(t);
+ return NULL;
+ }
struct term_sel_point bounds[2] = {0};
int first_seg, last_seg;
char *text = NULL;
diff --git a/src/snapshot.c b/src/snapshot.c
index 8726265..78c66b0 100644
--- a/src/snapshot.c
+++ b/src/snapshot.c
@@ -318,7 +318,8 @@ static bool term_snapshot_update_inner(struct term_snapshot *s, struct term *t)
s->arena_cap = cap;
}
- term_selection_view_spans(t, c0, c1);
+ if (!term_selection_view_spans(t, c0, c1))
+ goto done;
p.all = all;
p.scrolled = scrolled;
apply(s, t, &p);