Introduction
Introduction Statistics Contact Development Disclaimer Help
tStart implementing substitution - ledit - Text editor (WIP)
git clone git://lumidify.org/ledit.git (fast, but not encrypted)
git clone https://lumidify.org/git/ledit.git (encrypted, but very slow)
Log
Files
Refs
README
LICENSE
---
commit 123a3087ad0bc4f772f0cd0a17caf95304092f87
parent 82723082181a863b7bc7c7cbbcc92da5c30caf6d
Author: lumidify <[email protected]>
Date: Wed, 8 Dec 2021 20:56:21 +0100
Start implementing substitution
Diffstat:
M buffer.c | 16 ++++++++++++++++
M buffer.h | 10 ++++++++++
M keys.c | 6 +++++-
M keys_command.c | 121 +++++++++++++++++++++++++++++…
M search.c | 2 +-
M view.c | 14 ++++++++++++++
M view.h | 15 +++++++++++++++
7 files changed, 181 insertions(+), 3 deletions(-)
---
diff --git a/buffer.c b/buffer.c
t@@ -143,6 +143,22 @@ buffer_create(ledit_common *common) {
return buffer;
}
+void
+buffer_lock_all_views_except(ledit_buffer *buffer, ledit_view *view, char *loc…
+ for (size_t i = 0; i < buffer->views_num; i++) {
+ if (buffer->views[i] != view) {
+ view_lock(buffer->views[i], lock_text);
+ }
+ }
+}
+
+void
+buffer_unlock_all_views(ledit_buffer *buffer) {
+ for (size_t i = 0; i < buffer->views_num; i++) {
+ view_unlock(buffer->views[i]);
+ }
+}
+
static void
set_view_hard_line_text(ledit_buffer *buffer, ledit_view *view) {
char *text = buffer->hard_line_based ? "|HL" : "|SL";
diff --git a/buffer.h b/buffer.h
t@@ -49,6 +49,16 @@ struct ledit_buffer {
ledit_buffer *buffer_create(ledit_common *common);
/*
+ * Lock all views except the given view.
+ */
+void buffer_lock_all_views_except(ledit_buffer *buffer, ledit_view *view, char…
+
+/*
+ * Unlock all views.
+ */
+void buffer_unlock_all_views(ledit_buffer *buffer);
+
+/*
* Set the hard line mode of the buffer and update the
* displayed mode in all views.
*/
diff --git a/keys.c b/keys.c
t@@ -27,7 +27,11 @@ get_language_index(char *lang) {
}
/* FIXME: Does this break anything? */
-static unsigned int importantmod = ShiftMask | ControlMask | Mod1Mask | Mod2Ma…
+/*static unsigned int importantmod = ShiftMask | ControlMask | Mod1Mask | Mod2…
+/* FIXME: ShiftMask is currently masked away anyways, so it isn't really impor…
+/* FIXME: The Mod*Masks can be remapped, so it isn't really clear what is what…
+/* most are disabled now to avoid issues with e.g. numlock */
+static unsigned int importantmod = ShiftMask | ControlMask | Mod1Mask;
#define XK_ANY_MOD UINT_MAX
int
diff --git a/keys_command.c b/keys_command.c
t@@ -27,6 +27,18 @@
#include "keys_command.h"
#include "keys_command_config.h"
+static char *last_search = NULL;
+static char *last_replacement = NULL;
+static int last_replacement_global = 0;
+
+static int
+view_locked_error(ledit_view *view) {
+ window_show_message(view->window, view->lock_text, -1);
+ return 0;
+}
+
+#define CHECK_VIEW_LOCKED if (view->lock_text) return view_locked_error(view)
+
/* FIXME: history for search and commands */
static int create_view(ledit_view *view, char *cmd, size_t l1, size_t l2);
t@@ -104,7 +116,107 @@ handle_substitute(ledit_view *view, char *cmd, size_t l1…
(void)cmd;
(void)l1;
(void)l2;
- printf("substitute\n");
+ CHECK_VIEW_LOCKED;
+ cmd++; /* remove 's' at beginning */
+ size_t len = strlen(cmd);
+ if (len == 0) goto error;
+ /* FIXME: utf8 */
+ char sep = cmd[0];
+ cmd++;
+ char *next = strchr(cmd, sep);
+ if (next == NULL) goto error;
+ *next = '\0';
+ next++;
+ char *last = strchr(next, sep);
+ if (last == NULL) goto error;
+ *last = '\0';
+ last++;
+ int confirm = 0, global = 0;
+ char *c = last;
+ while (*c != '\0') {
+ switch (*c) {
+ case 'c':
+ confirm = 1;
+ break;
+ case 'g':
+ global = 1;
+ break;
+ default:
+ goto error;
+ }
+ c++;
+ }
+ free(last_search);
+ free(last_replacement);
+ last_search = ledit_strdup(cmd);
+ last_replacement = ledit_strdup(next);
+ last_replacement_global = global;
+
+ if (confirm) {
+ buffer_lock_all_views_except(view->buffer, view, "Ongoing subs…
+ buffer_unlock_all_views(view->buffer);
+ } else {
+ int num = 0;
+ int start_undo_group = 1;
+ size_t slen = strlen(last_search);
+ size_t rlen = strlen(last_replacement);
+ txtbuf *buf = txtbuf_new(); /* FIXME: don't allocate new every…
+ view_wipe_line_cursor_attrs(view, view->cur_line);
+ for (size_t i = l1 - 1; i < l2; i++) {
+ ledit_line *ll = buffer_get_line(view->buffer, i);
+ buffer_normalize_line(ll);
+ char *pos = strstr(ll->text, last_search);
+ while (pos != NULL) {
+ size_t index = (size_t)(pos - ll->text);
+ ledit_range cur_range, del_range;
+ cur_range.line1 = view->cur_line;
+ cur_range.byte1 = view->cur_line;
+ view_delete_range(
+ view, DELETE_CHAR,
+ i, index,
+ i, index + slen,
+ &view->cur_line, &view->cur_index,
+ &del_range, buf
+ );
+ cur_range.line2 = view->cur_line;
+ cur_range.byte2 = view->cur_index;
+ undo_push_delete(
+ view->buffer->undo, buf, del_range, cur_ra…
+ );
+ start_undo_group = 0;
+ txtbuf ins_buf = {.text = last_replacement, .l…
+ cur_range.line1 = view->cur_line;
+ cur_range.byte1 = view->cur_index;
+ del_range.line1 = i;
+ del_range.byte1 = index;
+ size_t cur_line, cur_index;
+ buffer_insert_text_with_newlines(
+ view->buffer, i, index, last_replacement, …
+ &cur_line, &cur_index
+ );
+ cur_range.line2 = view->cur_line;
+ cur_range.byte2 = view->cur_index;
+ del_range.line2 = cur_line;
+ del_range.byte2 = cur_index;
+ undo_push_insert(
+ view->buffer->undo, &ins_buf, del_range, c…
+ );
+ num++;
+ if (!global) break;
+ buffer_normalize_line(ll); /* just in case */
+ pos = strstr(ll->text + index + rlen, last_sea…
+ }
+ }
+ /* FIXME: show number replaced */
+ /* this doesn't need to be added to the undo stack since it's …
+ view->cur_index = view_get_legal_normal_pos(view, view->cur_li…
+ view_set_line_cursor_attrs(view, view->cur_line, view->cur_ind…
+ view_ensure_cursor_shown(view);
+ txtbuf_destroy(buf);
+ }
+ return 0;
+error:
+ window_show_message(view->window, "Invalid command", -1);
return 0;
}
t@@ -133,6 +245,7 @@ $ last line
*/
/* FIXME: ACTUALLY USE LEN!!! */
+/* FIXME: allow using marks and selection range here */
static int
parse_range(ledit_view *view, char *cmd, size_t len, char **cmd_ret, size_t *l…
(void)len;
t@@ -180,6 +293,7 @@ parse_range(ledit_view *view, char *cmd, size_t len, char …
l1 = 1;
l2 = view->lines_num;
*l1_valid = *l2_valid = 1;
+ c++;
break;
} else {
return 1;
t@@ -204,6 +318,8 @@ parse_range(ledit_view *view, char *cmd, size_t len, char …
}
if ((!*l1_valid || !*l2_valid) && !(s & START_RANGE))
return 1;
+ if ((*l1_valid || *l2_valid) && (l1 == 0 || l2 == 0 || l1 > view->line…
+ return 1; /* FIXME: better error messages */
*cmd_ret = c;
*line1_ret = l1;
*line2_ret = l2;
t@@ -221,6 +337,7 @@ handle_cmd(ledit_view *view, char *cmd, size_t len) {
if (parse_range(view, cmd, len, &c, &l1, &l2, &l1_valid, &l2_valid))
return 0;
int range_given = l1_valid && l2_valid;
+ /* FIXME: mandatory range */
for (size_t i = 0; i < LENGTH(cmds); i++) {
if (!strncmp(cmds[i].cmd, c, strlen(cmds[i].cmd)) &&
(!range_given || cmds[i].type == CMD_OPTIONAL_RANGE)) {
t@@ -335,6 +452,7 @@ search_next(ledit_view *view) {
view_wipe_line_cursor_attrs(view, view->cur_line);
enum ledit_search_state ret = ledit_search_next(view, &view->cur_line,…
view_set_line_cursor_attrs(view, view->cur_line, view->cur_index);
+ view_ensure_cursor_shown(view);
if (ret != SEARCH_NORMAL)
window_show_message(view->window, search_state_to_str(ret), -1…
}
t@@ -344,6 +462,7 @@ search_prev(ledit_view *view) {
view_wipe_line_cursor_attrs(view, view->cur_line);
enum ledit_search_state ret = ledit_search_prev(view, &view->cur_line,…
view_set_line_cursor_attrs(view, view->cur_line, view->cur_index);
+ view_ensure_cursor_shown(view);
if (ret != SEARCH_NORMAL)
window_show_message(view->window, search_state_to_str(ret), -1…
}
diff --git a/search.c b/search.c
t@@ -19,7 +19,7 @@
#include "search.h"
/* FIXME: make sure only whole utf8 chars are matched */
-char *last_search = NULL;
+static char *last_search = NULL;
enum {
FORWARD,
BACKWARD
diff --git a/view.c b/view.c
t@@ -112,6 +112,7 @@ view_create(ledit_buffer *buffer, ledit_theme *theme, enum…
view->window = window_create(buffer->common, theme, mode);
view->theme = theme;
view->cache = cache_create(buffer->common->dpy);
+ view->lock_text = NULL;
view->cur_action = (struct action){ACTION_NONE, NULL};
window_set_scroll_callback(view->window, &view_scroll_handler, view);
window_set_button_callback(view->window, &view_button_handler, view);
t@@ -147,6 +148,18 @@ view_create(ledit_buffer *buffer, ledit_theme *theme, enu…
return view;
}
+void
+view_lock(ledit_view *view, char *lock_text) {
+ free(view->lock_text);
+ view->lock_text = ledit_strdup(lock_text);
+}
+
+void
+view_unlock(ledit_view *view) {
+ free(view->lock_text);
+ view->lock_text = NULL;
+}
+
ledit_view_line *
view_get_line(ledit_view *view, size_t index) {
assert(index < view->lines_num);
t@@ -262,6 +275,7 @@ void
view_destroy(ledit_view *view) {
cache_destroy(view->cache);
window_destroy(view->window);
+ free(view->lock_text);
free(view->lines);
free(view);
}
diff --git a/view.h b/view.h
t@@ -57,6 +57,7 @@ struct ledit_view {
ledit_theme *theme; /* current theme in use */
ledit_cache *cache; /* cache for pixmaps and pango layouts */
ledit_view_line *lines; /* array of lines, stored as gap buffer */
+ char *lock_text; /* text to show if view is locked, i.e. no e…
/* current command type - used by key handler in keys_command.c */
enum ledit_command_type cur_command_type;
struct action cur_action; /* current action to execute on key press */
t@@ -98,6 +99,20 @@ ledit_view *view_create(
);
/*
+ * Lock a view.
+ * Views are locked for instance when substitution with confirmation is
+ * being performed in another view to avoid an inconsistent state.
+ * This currently only sets the lock text - commands using the view need
+ * to make sure to check that it isn't locked.
+ */
+void view_lock(ledit_view *view, char *text);
+
+/*
+ * Unlock a view.
+ */
+void view_unlock(ledit_view *view);
+
+/*
* Get the view line at the given index.
*/
ledit_view_line *view_get_line(ledit_view *view, size_t index);
You are viewing proxied material from lumidify.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.