aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc André Tanner <mat@brain-dump.org>2016-03-30 13:05:50 +0200
committerMarc André Tanner <mat@brain-dump.org>2016-03-30 14:03:12 +0200
commit1cd15a982a47cf9c7a2beade17987f8303df85bf (patch)
treeb6b0690270fd8454d12181584df4fda0fb098b71
parent8bd6650245d050e455cd4d26f6e59e7dd9b80392 (diff)
downloadvis-1cd15a982a47cf9c7a2beade17987f8303df85bf.tar.gz
vis-1cd15a982a47cf9c7a2beade17987f8303df85bf.tar.xz
view: change internal representation of selections
We place the end mark inside the selection as opposted to on the character immediately following it. This is better when selections are touching each other. Previously for two seletions [a][b] the end mark for selection a would be at the same location as the start mark of selection b. Thus when for example the content of selection b is deleted it would also destroy selection a, because the end mark would no longer be valid.
-rw-r--r--view.c50
1 files changed, 27 insertions, 23 deletions
diff --git a/view.c b/view.c
index 0dd185a..bfee827 100644
--- a/view.c
+++ b/view.c
@@ -26,6 +26,21 @@ enum {
SYNTAX_SYMBOL_LAST,
};
+/* A selection is made up of two marks named cursor and anchor.
+ * While the anchor remains fixed the cursor mark follows cursor motions.
+ * For a selection (indicated by []), the marks (^) are placed as follows:
+ *
+ * [some text] [!]
+ * ^ ^ ^
+ * ^
+ *
+ * That is the marks point to the *start* of the first and last character
+ * of the selection. In particular for a single character selection (as
+ * depicted on the right above) both marks point to the same location.
+ *
+ * The view_selections_{get,set} functions take care of adding/removing
+ * the necessary offset for the last character.
+ */
struct Selection {
Mark anchor; /* position where the selection was created */
Mark cursor; /* other selection endpoint where it changes */
@@ -432,20 +447,6 @@ static void cursor_to(Cursor *c, size_t pos) {
c->lastcol = 0;
c->pos = pos;
if (c->sel) {
- size_t anchor = text_mark_get(txt, c->sel->anchor);
- size_t cursor = text_mark_get(txt, c->sel->cursor);
- /* do we have to change the orientation of the selection? */
- if (pos < anchor && anchor < cursor) {
- /* right extend -> left extend */
- anchor = text_char_next(txt, anchor);
- c->sel->anchor = text_mark_set(txt, anchor);
- } else if (cursor < anchor && anchor <= pos) {
- /* left extend -> right extend */
- anchor = text_char_prev(txt, anchor);
- c->sel->anchor = text_mark_set(txt, anchor);
- }
- if (anchor <= pos)
- pos = text_char_next(txt, pos);
c->sel->cursor = text_mark_set(txt, pos);
}
if (!view_coord_get(c->view, pos, &c->line, &c->row, &c->col)) {
@@ -1297,7 +1298,7 @@ void view_cursors_selection_start(Cursor *c) {
return;
Text *txt = c->view->text;
c->sel->anchor = text_mark_set(txt, pos);
- c->sel->cursor = text_mark_set(txt, text_char_next(txt, pos));
+ c->sel->cursor = c->sel->anchor;
view_draw(c->view);
}
@@ -1311,6 +1312,7 @@ void view_cursors_selection_restore(Cursor *c) {
);
if (!text_range_valid(&sel))
return;
+ sel.end = text_char_next(txt, sel.end);
if (!(c->sel = view_selections_new(c->view)))
return;
view_selections_set(c->sel, &sel);
@@ -1338,11 +1340,7 @@ void view_cursors_selection_sync(Cursor *c) {
if (!c->sel)
return;
Text *txt = c->view->text;
- size_t anchor = text_mark_get(txt, c->sel->anchor);
size_t cursor = text_mark_get(txt, c->sel->cursor);
- bool right_extending = anchor < cursor;
- if (right_extending)
- cursor = text_char_prev(txt, cursor);
view_cursors_to(c, cursor);
}
@@ -1439,7 +1437,10 @@ Filerange view_selections_get(Selection *s) {
Text *txt = s->view->text;
size_t anchor = text_mark_get(txt, s->anchor);
size_t cursor = text_mark_get(txt, s->cursor);
- return text_range_new(anchor, cursor);
+ Filerange sel = text_range_new(anchor, cursor);
+ if (text_range_valid(&sel))
+ sel.end = text_char_next(txt, sel.end);
+ return sel;
}
void view_selections_set(Selection *s, Filerange *r) {
@@ -1448,13 +1449,16 @@ void view_selections_set(Selection *s, Filerange *r) {
Text *txt = s->view->text;
size_t anchor = text_mark_get(txt, s->anchor);
size_t cursor = text_mark_get(txt, s->cursor);
- bool left_extending = anchor > cursor;
+ bool left_extending = anchor != EPOS && anchor > cursor;
+ size_t end = r->end;
+ if (r->start != end)
+ end = text_char_prev(txt, end);
if (left_extending) {
- s->anchor = text_mark_set(txt, r->end);
+ s->anchor = text_mark_set(txt, end);
s->cursor = text_mark_set(txt, r->start);
} else {
s->anchor = text_mark_set(txt, r->start);
- s->cursor = text_mark_set(txt, r->end);
+ s->cursor = text_mark_set(txt, end);
}
view_draw(s->view);
}