summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2021-01-24 19:27:49 -0500
committerLeo Tenenbaum <pommicket@gmail.com>2021-01-24 19:27:49 -0500
commitf6d49d377ac136fc29457b3b4501f0488b6412e3 (patch)
tree1ff4a6885decabcc4f639a0420b94c836e01940f
parentaccf188e7c84ee627d5e4cfe12c141e929699830 (diff)
copy/cut/paste
-rw-r--r--Untitled6
-rw-r--r--buffer.c90
-rw-r--r--command.c9
-rw-r--r--command.h6
-rw-r--r--main.c1
-rw-r--r--string32.c1
-rw-r--r--ted.cfg3
-rw-r--r--ted.h1
8 files changed, 111 insertions, 6 deletions
diff --git a/Untitled b/Untitled
index 967045d..e988e21 100644
--- a/Untitled
+++ b/Untitled
@@ -1,4 +1,4 @@
1 2 3 4
-t e s t
-he ll o!! !!
-t e s t
+1 4 9 16
+1 8 27 64
+1 16 81 256 \ No newline at end of file
diff --git a/buffer.c b/buffer.c
index cc97e19..422f03c 100644
--- a/buffer.c
+++ b/buffer.c
@@ -1,4 +1,6 @@
// Text buffers - These store the contents of a file.
+// NOTE: All text editing should be done through the two functions
+// buffer_insert_text_at_pos and buffer_delete_chars_at_pos
// this is a macro so we get -Wformat warnings
#define buffer_seterr(buffer, ...) \
@@ -181,7 +183,7 @@ static u64 buffer_checksum(TextBuffer *buffer) {
// Returns the number of characters gotten.
// You can pass NULL for text if you just want to know how many characters *could* be accessed before the
// end of the file.
-static size_t buffer_get_text_at_pos(TextBuffer *buffer, BufferPos pos, char32_t *text, size_t nchars) {
+size_t buffer_get_text_at_pos(TextBuffer *buffer, BufferPos pos, char32_t *text, size_t nchars) {
if (!buffer_pos_valid(buffer, pos)) {
return 0; // invalid position. no chars for you!
}
@@ -213,6 +215,32 @@ static size_t buffer_get_text_at_pos(TextBuffer *buffer, BufferPos pos, char32_t
return nchars - chars_left;
}
+// returns a UTF-32 string of at most `nchars` code points from `buffer` starting at `pos`
+// the string should be str32_free'd.
+String32 buffer_get_str32_text_at_pos(TextBuffer *buffer, BufferPos pos, size_t nchars) {
+ String32 s32 = {0};
+ size_t len = buffer_get_text_at_pos(buffer, pos, NULL, nchars);
+ if (len) {
+ char32_t *str = buffer_calloc(buffer, len, sizeof *str);
+ if (str) {
+ buffer_get_text_at_pos(buffer, pos, str, nchars);
+ s32.str = str;
+ s32.len = len;
+ }
+ }
+ return s32;
+}
+
+// see buffer_get_str32_text_at_pos. returns NULL on failure (out of memory)
+// the returned string should be free'd
+char *buffer_get_utf8_text_at_pos(TextBuffer *buffer, BufferPos pos, size_t nchars) {
+ String32 s32 = buffer_get_str32_text_at_pos(buffer, pos, nchars);
+ char *ret = str32_to_utf8_cstr(s32);
+ if (!ret) buffer_out_of_mem(buffer);
+ str32_free(&s32);
+ return ret;
+}
+
static BufferPos buffer_pos_advance(TextBuffer *buffer, BufferPos pos, size_t nchars) {
buffer_pos_validate(buffer, &pos);
size_t chars_left = nchars;
@@ -619,6 +647,9 @@ bool buffer_save(TextBuffer *buffer) {
}
if (ferror(out)) success = false;
if (fclose(out) != 0) success = false;
+ if (success) {
+ buffer->modified = false;
+ }
return success;
} else {
buffer_seterr(buffer, "Couldn't create file %s.", buffer->filename);
@@ -1280,6 +1311,8 @@ BufferPos buffer_insert_text_at_pos(TextBuffer *buffer, BufferPos pos, String32
// We need to put this after the end so the emptiness-checking is done after the edit is made.
buffer_remove_last_edit_if_empty(buffer);
+ buffer->modified = true;
+
BufferPos b = {.line = line_idx, .index = index};
return b;
}
@@ -1522,6 +1555,8 @@ void buffer_delete_chars_at_pos(TextBuffer *buffer, BufferPos pos, i64 nchars_)
// cursor position could have been invalidated by this edit
buffer_validate_cursor(buffer);
+
+ buffer->modified = true;
}
// Delete characters between the given buffer positions. Returns number of characters deleted.
@@ -1683,6 +1718,49 @@ void buffer_redo(TextBuffer *buffer, i64 ntimes) {
}
}
+void buffer_copy_or_cut(TextBuffer *buffer, bool cut) {
+ if (buffer->selection) {
+ BufferPos pos1 = buffer_pos_min(buffer->selection_pos, buffer->cursor_pos);
+ BufferPos pos2 = buffer_pos_max(buffer->selection_pos, buffer->cursor_pos);
+ i64 selection_len = buffer_pos_diff(buffer, pos1, pos2);
+ char *text = buffer_get_utf8_text_at_pos(buffer, pos1, (size_t)selection_len);
+ if (text) {
+ int err = SDL_SetClipboardText(text);
+ free(text);
+ if (err < 0) {
+ buffer_seterr(buffer, "Couldn't get clipboard contents: %s", SDL_GetError());
+ } else {
+ // text copied successfully
+ if (cut) {
+ buffer_delete_selection(buffer);
+ }
+ }
+ }
+ }
+}
+
+void buffer_copy(TextBuffer *buffer) {
+ buffer_copy_or_cut(buffer, false);
+}
+
+void buffer_cut(TextBuffer *buffer) {
+ buffer_copy_or_cut(buffer, true);
+}
+
+void buffer_paste(TextBuffer *buffer) {
+ if (SDL_HasClipboardText()) {
+ char *text = SDL_GetClipboardText();
+ if (text) {
+ String32 str = str32_from_utf8(text);
+ if (str.len) {
+ buffer_insert_text_at_cursor(buffer, str);
+ str32_free(&str);
+ }
+ SDL_free(text);
+ }
+ }
+}
+
// for debugging
#if DEBUG
static void buffer_pos_check_valid(TextBuffer *buffer, BufferPos p) {
@@ -1752,8 +1830,11 @@ void buffer_render(TextBuffer *buffer, float x1, float y1, float x2, float y2) {
if (!buffer->is_line_buffer) { // header
glColor3f(1,1,1);
float x = x1, y = y1;
- if (buffer->filename)
- text_render_with_state(font, &text_state, buffer->filename, x, y);
+ if (buffer->filename) {
+ char text[256] = {0};
+ strbuf_printf(text, "%s%s%s", buffer->modified ? "*" : "", buffer->filename, buffer->modified ? "*" :"");
+ text_render_with_state(font, &text_state, text, x, y);
+ }
#if DEBUG
// show checksum
char checksum[32] = {0};
@@ -1853,6 +1934,9 @@ void buffer_render(TextBuffer *buffer, float x1, float y1, float x2, float y2) {
.render = true
};
+ // sel_pos >= scrolloff
+ // sel - scroll >= scrolloff
+ // scroll <= sel - scrolloff
text_state.y -= (float)(buffer->scroll_y - start_line) * char_height;
gl_color_rgba(colors[COLOR_TEXT]);
diff --git a/command.c b/command.c
index 74a624a..d90153d 100644
--- a/command.c
+++ b/command.c
@@ -129,6 +129,15 @@ void command_execute(Ted *ted, Command c, i64 argument) {
case CMD_REDO:
if (buffer) buffer_redo(buffer, argument);
break;
+ case CMD_COPY:
+ if (buffer) buffer_copy(buffer);
+ break;
+ case CMD_CUT:
+ if (buffer) buffer_cut(buffer);
+ break;
+ case CMD_PASTE:
+ if (buffer) buffer_paste(buffer);
+ break;
case CMD_TEXT_SIZE_INCREASE: {
i64 new_text_size = settings->text_size + argument;
diff --git a/command.h b/command.h
index 50821b5..2372e37 100644
--- a/command.h
+++ b/command.h
@@ -38,6 +38,9 @@ ENUM_U16 {
CMD_SAVE, // save current buffer
CMD_UNDO,
CMD_REDO,
+ CMD_COPY,
+ CMD_CUT,
+ CMD_PASTE,
CMD_TEXT_SIZE_INCREASE,
CMD_TEXT_SIZE_DECREASE,
@@ -87,6 +90,9 @@ static CommandName const command_names[CMD_COUNT] = {
{"save", CMD_SAVE},
{"undo", CMD_UNDO},
{"redo", CMD_REDO},
+ {"copy", CMD_COPY},
+ {"cut", CMD_CUT},
+ {"paste", CMD_PASTE},
{"increase-text-size", CMD_TEXT_SIZE_INCREASE},
{"decrease-text-size", CMD_TEXT_SIZE_DECREASE},
{"escape", CMD_ESCAPE},
diff --git a/main.c b/main.c
index b7ee115..8895c1f 100644
--- a/main.c
+++ b/main.c
@@ -1,5 +1,6 @@
// @TODO:
// - Windows installation
+// - error bar
#include "base.h"
no_warn_start
#if _WIN32
diff --git a/string32.c b/string32.c
index f678ad1..d7278d2 100644
--- a/string32.c
+++ b/string32.c
@@ -13,6 +13,7 @@ String32 str32_substr(String32 s, size_t from, size_t len) {
return str32(s.str + from, len);
}
+// frees string and sets it to ""
void str32_free(String32 *s) {
free(s->str);
s->str = NULL;
diff --git a/ted.cfg b/ted.cfg
index 623e914..c9608a5 100644
--- a/ted.cfg
+++ b/ted.cfg
@@ -60,6 +60,9 @@ Ctrl+o = :open
Ctrl+s = :save
Ctrl+z = :undo
Ctrl+Shift+z = :redo
+Ctrl+c = :copy
+Ctrl+x = :cut
+Ctrl+v = :paste
Ctrl++ = 3 :increase-text-size
Ctrl+- = 3 :decrease-text-size
diff --git a/ted.h b/ted.h
index 16fb131..8556d36 100644
--- a/ted.h
+++ b/ted.h
@@ -63,6 +63,7 @@ typedef struct {
bool is_line_buffer; // "line buffers" are buffers which can only have one line of text (used for inputs)
bool selection;
bool store_undo_events; // set to false to disable undo events
+ bool modified; // has the buffer been modified since it was loaded/saved?
float x1, y1, x2, y2;
u32 nlines;
u32 lines_capacity;