summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2023-08-13 12:05:54 -0300
committerpommicket <pommicket@gmail.com>2023-08-13 12:05:54 -0300
commit598d72c0674bb059c0f38f03c4851bcc61e5852d (patch)
treeae01311a6bdf872120b9787d44746ab9cd95db14
parentdbf441cdc74245c5a5f567ae0165146cd74c3b92 (diff)
various little changes, remove calls to change_directory
-rw-r--r--CMakeLists.txt2
-rw-r--r--buffer.c7
-rw-r--r--build.c57
-rw-r--r--command.c2
-rw-r--r--control2
-rw-r--r--development.md6
-rw-r--r--ide-usages.c4
-rw-r--r--main.c2
-rw-r--r--menu.c2
-rw-r--r--tags.c70
-rw-r--r--ted-internal.h2
-rw-r--r--ted.h56
12 files changed, 125 insertions, 87 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3641e65..652f407 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.1)
+cmake_minimum_required(VERSION 3.5)
project(ted)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
set(SOURCES buffer.c build.c colors.c command.c config.c find.c gl.c ide-autocomplete.c
diff --git a/buffer.c b/buffer.c
index 3f94cf1..a33cfad 100644
--- a/buffer.c
+++ b/buffer.c
@@ -229,6 +229,8 @@ u32 buffer_last_line_on_screen(TextBuffer *buffer) {
void buffer_set_undo_enabled(TextBuffer *buffer, bool enabled) {
buffer->store_undo_events = enabled;
+ if (!enabled)
+ buffer_clear_undo_redo(buffer);
}
Rect buffer_rect(TextBuffer *buffer) {
@@ -2234,10 +2236,11 @@ bool buffer_change_number_at_pos(TextBuffer *buffer, BufferPos *ppos, i64 by) {
return ret;
}
-void buffer_change_number_at_cursor(TextBuffer *buffer, i64 by) {
+bool buffer_change_number_at_cursor(TextBuffer *buffer, i64 by) {
buffer_start_edit_chain(buffer);
- buffer_change_number_at_pos(buffer, &buffer->cursor_pos, by);
+ bool ret = buffer_change_number_at_pos(buffer, &buffer->cursor_pos, by);
buffer_end_edit_chain(buffer);
+ return ret;
}
// decrease the number of lines in the buffer.
diff --git a/build.c b/build.c
index 771fd6d..df8f36f 100644
--- a/build.c
+++ b/build.c
@@ -50,11 +50,12 @@ static bool build_run_next_command_in_queue(Ted *ted) {
return false;
assert(!ted->build_process);
assert(*ted->build_dir);
- change_directory(ted->build_dir);
char *command = ted->build_queue[0];
arr_remove(ted->build_queue, 0);
if (ted_save_all(ted)) {
- ted->build_process = process_run(command);
+ ProcessSettings settings = {0};
+ settings.working_directory = ted->build_dir;
+ ted->build_process = process_run_ex(command, &settings);
const char *error = process_geterr(ted->build_process);
if (!error) {
ted->building = true;
@@ -90,6 +91,11 @@ void build_queue_finish(Ted *ted) {
build_run_next_command_in_queue(ted); // run the first command
}
+void build_set_working_directory(Ted *ted, const char *dir) {
+ assert(strlen(dir) < TED_PATH_MAX - 1);
+ strbuf_cpy(ted->build_dir, dir);
+}
+
void build_start_with_command(Ted *ted, const char *command) {
build_queue_start(ted);
build_queue_command(ted, command);
@@ -98,27 +104,39 @@ void build_start_with_command(Ted *ted, const char *command) {
void build_start(Ted *ted) {
Settings *settings = ted_active_settings(ted);
- char *command = settings->build_command;
- char *root = ted_get_root_dir(ted);
- strbuf_cpy(ted->build_dir, root);
+ const char *command = settings->build_command;
+
+ {
+ char *root = ted_get_root_dir(ted);
+ build_set_working_directory(ted, root);
+ free(root);
+ }
+
if (*command == 0) {
command = settings->build_default_command;
- change_directory(root);
-
- #if _WIN32
- if (fs_file_exists("make.bat")) {
- command = "make.bat";
- } else
- #endif
- if (fs_file_exists("Cargo.toml")) {
- command = "cargo build";
- } else if (fs_file_exists("Makefile")) {
- command = "make -j16";
- } else if (fs_file_exists("go.mod")) {
- command = "go build";
+ typedef struct {
+ const char *filename;
+ const char *command;
+ } Assoc;
+
+ Assoc associations[] = {
+ #if _WIN32
+ {"make.bat", "make.bat"},
+ #endif
+ {"Cargo.toml", "cargo build"},
+ {"Makefile", "make -j16"},
+ {"go.mod", "go build"},
+ };
+ for (size_t i = 0; i < arr_count(associations); ++i) {
+ Assoc *assoc = &associations[i];
+ char path[TED_PATH_MAX];
+ path_full(ted->build_dir, assoc->filename, path, sizeof path);
+ if (fs_file_exists(path)) {
+ command = assoc->command;
+ break;
+ }
}
}
- free(root);
if (*command)
build_start_with_command(ted, command);
}
@@ -209,7 +227,6 @@ static bool is_source_path(char32_t c) {
|| strchr(allowed_ascii_symbols_in_path, (char)c);
}
-// make sure you set ted->build_dir before running this!
void build_check_for_errors(Ted *ted) {
const Settings *settings = ted_active_settings(ted);
diff --git a/command.c b/command.c
index 05b36cc..b5d2f5d 100644
--- a/command.c
+++ b/command.c
@@ -653,7 +653,7 @@ void command_execute_ex(Ted *ted, Command c, const CommandArgument *full_argumen
case CMD_SHELL: {
const char *str = argument_str;
if (str) {
- strbuf_cpy(ted->build_dir, ted->cwd);
+ build_set_working_directory(ted, ted->cwd);
build_start_with_command(ted, str);
} else {
menu_open(ted, MENU_SHELL);
diff --git a/control b/control
index 380315f..3d0b1ce 100644
--- a/control
+++ b/control
@@ -1,5 +1,5 @@
Package: ted
-Version: 2.4.3
+Version: 3.0
Section: text
Priority: optional
Architecture: amd64
diff --git a/development.md b/development.md
index c633885..086b46a 100644
--- a/development.md
+++ b/development.md
@@ -106,6 +106,12 @@ At the top of `syntax.c` there are a bunch of `SYNTAX_STATE_*` constants.
Create a new enum for your language, and add any state that needs to be remembered across lines.
Then implement the `syntax_highlight_<language>` function similar to the other ones.
+## Glossary
+
+- **buffer** - a text document
+- **column** - one space width
+- **line buffer** - a single-line buffer, e.g. the file name input in the "open file" menu
+
## Releasing
When releasing a new version of `ted`:
diff --git a/ide-usages.c b/ide-usages.c
index 4caa644..9ae31e4 100644
--- a/ide-usages.c
+++ b/ide-usages.c
@@ -124,10 +124,10 @@ void usages_process_lsp_response(Ted *ted, const LSPResponse *response) {
fclose(last_file);
buffer_set_view_only(buffer, true);
- // the build_dir doesn't really matter since we're using absolute paths
+ // the build directory doesn't really matter since we're using absolute paths
// but might as well set it to something reasonable.
char *root = ted_get_root_dir(ted);
- strbuf_cpy(ted->build_dir, root);
+ build_set_working_directory(ted, root);
free(root);
build_check_for_errors(ted);
diff --git a/main.c b/main.c
index bfaf506..6c9b88f 100644
--- a/main.c
+++ b/main.c
@@ -3,9 +3,11 @@ TODO:
- fix find
- public Node API
- public Selector/FileSelector API
+- public Settings API
FUTURE FEATURES:
- autodetect indentation (tabs vs spaces)
+- custom file/build command associations
- config variables
- bind key to series of commands
- convert macro to command list
diff --git a/menu.c b/menu.c
index 67b1fba..1df07ea 100644
--- a/menu.c
+++ b/menu.c
@@ -514,7 +514,7 @@ static void shell_menu_update(Ted *ted) {
arr_add(ted->shell_history, command);
}
menu_close(ted);
- strbuf_cpy(ted->build_dir, ted->cwd);
+ build_set_working_directory(ted, ted->cwd);
build_start_with_command(ted, command);
}
}
diff --git a/tags.c b/tags.c
index 5ada805..2851b17 100644
--- a/tags.c
+++ b/tags.c
@@ -3,24 +3,23 @@
#include "ted-internal.h"
#include "pcre-inc.h"
-static const char *tags_filename(Ted *ted, bool error_if_does_not_exist) {
- change_directory(ted->cwd);
- const char *filename = "tags";
- ted_path_full(ted, ".", ted->tags_dir, sizeof ted->tags_dir);
- if (!fs_file_exists(filename)) {
- filename = "../tags";
- ted_path_full(ted, "..", ted->tags_dir, sizeof ted->tags_dir);
- if (!fs_file_exists(filename)) {
- filename = "../../tags";
- ted_path_full(ted, "../..", ted->tags_dir, sizeof ted->tags_dir);
- if (!fs_file_exists(filename)) {
- if (error_if_does_not_exist)
- ted_error(ted, "No tags file. Try running ctags.");
- filename = NULL;
- }
- }
+static bool get_tags_dir(Ted *ted, bool error_if_does_not_exist) {
+ char prev_dir[TED_PATH_MAX];
+ *prev_dir = '\0';
+ strbuf_cpy(ted->tags_dir, ted->cwd);
+ while (!streq(prev_dir, ted->tags_dir)) {
+ strbuf_cpy(prev_dir, ted->tags_dir);
+ char path[TED_PATH_MAX];
+ path_full(ted->tags_dir, "tags", path, sizeof path);
+ if (fs_file_exists(path))
+ return true;
+
+ path_full(ted->tags_dir, "..", path, sizeof path);
+ strbuf_cpy(ted->tags_dir, path);
}
- return filename;
+ if (error_if_does_not_exist)
+ ted_error(ted, "No tags file. Try running ctags.");
+ return false;
}
// is this a file we can generate tags for?
@@ -99,19 +98,22 @@ static void tags_generate_at_dir(Ted *ted, bool run_in_build_window, const char
// generate/re-generate tags.
void tags_generate(Ted *ted, bool run_in_build_window) {
- const char *filename = tags_filename(ted, false);
- if (!filename) {
+ if (!get_tags_dir(ted, false)) {
char *root = ted_get_root_dir(ted);
strcpy(ted->tags_dir, root);
free(root);
}
- change_directory(ted->tags_dir);
- strcpy(ted->build_dir, ted->tags_dir);
- remove("tags"); // delete old tags file
+ build_set_working_directory(ted, ted->tags_dir);
+
+ {
+ char path[TED_PATH_MAX];
+ path_full(ted->tags_dir, "tags", path, sizeof path);
+ remove(path); // delete old tags file
+ }
+
if (run_in_build_window) build_queue_start(ted);
tags_generate_at_dir(ted, run_in_build_window, ted->tags_dir, 0);
if (run_in_build_window) build_queue_finish(ted);
- change_directory(ted->cwd);
}
static int tag_try(FILE *fp, const char *tag) {
@@ -140,8 +142,10 @@ static int tag_try(FILE *fp, const char *tag) {
size_t tags_beginning_with(Ted *ted, const char *prefix, char **out, size_t out_size, bool error_if_tags_does_not_exist) {
assert(out_size);
- const char *tags_name = tags_filename(ted, error_if_tags_does_not_exist);
- if (!tags_name) return 0;
+ if (!get_tags_dir(ted, error_if_tags_does_not_exist))
+ return 0;
+ char tags_name[TED_PATH_MAX];
+ path_full(ted->tags_dir, "tags", tags_name, sizeof tags_name);
FILE *file = fopen(tags_name, "rb");
if (!file) return 0;
@@ -200,13 +204,14 @@ size_t tags_beginning_with(Ted *ted, const char *prefix, char **out, size_t out_
// returns true if the tag exists.
bool tag_goto(Ted *ted, const char *tag) {
- bool already_regenerated_tags;
- already_regenerated_tags = false;
+ bool already_regenerated_tags = false;
top:;
const Settings *settings = ted_active_settings(ted);
+ if (!get_tags_dir(ted, true))
+ return false;
+ char tags_name[TED_PATH_MAX];
+ path_full(ted->tags_dir, "tags", tags_name, sizeof tags_name);
- const char *tags_name = tags_filename(ted, true);
- if (!tags_name) return false;
FILE *file = fopen(tags_name, "rb");
if (!file) return false;
@@ -370,9 +375,10 @@ top:;
SymbolInfo *tags_get_symbols(Ted *ted) {
// read tags file and extract tag names
- const char *filename = tags_filename(ted, true);
- if (!filename) return NULL;
- FILE *file = fopen(filename, "rb");
+ if (!get_tags_dir(ted, true)) return NULL;
+ char tags_name[TED_PATH_MAX];
+ path_full(ted->tags_dir, "tags", tags_name, sizeof tags_name);
+ FILE *file = fopen(tags_name, "rb");
if (!file) return NULL;
SymbolInfo *infos = NULL;
diff --git a/ted-internal.h b/ted-internal.h
index 6de2cfd..64b3b6e 100644
--- a/ted-internal.h
+++ b/ted-internal.h
@@ -513,6 +513,8 @@ bool buffer_handle_click(Ted *ted, TextBuffer *buffer, vec2 click, u8 times);
/// currently needed to avoid bad positioning when a buffer is created
/// and buffer_center_cursor is called immediately after
void buffer_center_cursor_next_frame(TextBuffer *buffer);
+/// perform a series of checks to make sure the buffer doesn't have any invalid values
+void buffer_check_valid(TextBuffer *buffer);
// === build.c ===
void build_frame(Ted *ted, float x1, float y1, float x2, float y2);
diff --git a/ted.h b/ted.h
index a670566..c8aaf71 100644
--- a/ted.h
+++ b/ted.h
@@ -22,15 +22,12 @@ extern "C" {
#include "command.h"
/// Version number
-#define TED_VERSION "2.4.3"
+#define TED_VERSION "3.0"
/// Maximum path size ted handles.
#define TED_PATH_MAX 1024
/// Config filename
#define TED_CFG "ted.cfg"
-
-// If you are adding new languages, DO NOT change the constant values
-// of the previous languages. It will mess up config files which use :set-language!
enum {
/// avoid using this and use LANG_TEXT instead.
LANG_NONE = 0,
@@ -87,7 +84,6 @@ typedef u32 SyntaxState;
/// types of syntax highlighting
enum SyntaxCharType {
- // do not change these numbers as it will break backwards compatibility with plugins
SYNTAX_NORMAL = 0,
SYNTAX_KEYWORD = 1,
SYNTAX_BUILTIN = 2,
@@ -143,8 +139,6 @@ typedef struct {
/// line number (0-indexed)
u32 line;
/// UTF-32 index of character in line
- ///
- /// (not the same as column, since a tab is `settings->tab_width` columns)
u32 index;
} BufferPos;
@@ -155,9 +149,9 @@ enum {
};
/// see \ref KEY_COMBO
enum {
- KEY_MODIFIER_CTRL_BIT,
- KEY_MODIFIER_SHIFT_BIT,
- KEY_MODIFIER_ALT_BIT
+ KEY_MODIFIER_CTRL_BIT = 0,
+ KEY_MODIFIER_SHIFT_BIT = 1,
+ KEY_MODIFIER_ALT_BIT = 2,
};
/// see \ref KEY_COMBO
#define KEY_MODIFIER_CTRL ((u32)1<<KEY_MODIFIER_CTRL_BIT)
@@ -193,15 +187,15 @@ enum {
/// determines which thing associated with a symbol to go to
typedef enum {
- GOTO_DECLARATION,
- GOTO_DEFINITION,
- GOTO_IMPLEMENTATION,
- GOTO_TYPE_DEFINITION,
+ GOTO_DECLARATION = 0,
+ GOTO_DEFINITION = 1,
+ GOTO_IMPLEMENTATION = 2,
+ GOTO_TYPE_DEFINITION = 3,
} GotoType;
/// options for a pop-up menu
typedef enum {
- POPUP_NONE,
+ POPUP_NONE = 0,
/// "Yes" button
POPUP_YES = 1<<1,
/// "No" button
@@ -345,9 +339,11 @@ bool buffer_selection_pos(TextBuffer *buffer, BufferPos *pos);
///
/// This string can be freed if the buffer is saved under a different name or closed, so don't keep it around for long.
const char *buffer_get_path(TextBuffer *buffer);
-/// clear undo and redo history
+/// clear undo/redo history
void buffer_clear_undo_redo(TextBuffer *buffer);
/// set whether undo history should be kept
+///
+/// if `enabled` is false, any previous undo/redo history will be cleared.
void buffer_set_undo_enabled(TextBuffer *buffer, bool enabled);
/// set manual language override for buffer.
///
@@ -375,11 +371,11 @@ bool buffer_is_line_buffer(TextBuffer *buffer);
bool line_buffer_is_submitted(TextBuffer *buffer);
/// clear submission status of line buffer.
void line_buffer_clear_submitted(TextBuffer *buffer);
-/// returns the character after position pos, or 0 if pos is invalid
+/// returns the character after position `pos`, or 0 if `pos` is invalid or at the end of a line
char32_t buffer_char_at_pos(TextBuffer *buffer, BufferPos pos);
-/// returns the character after the cursor
+/// returns the character after the cursor, or 0 if the cursor is at the end of a line
char32_t buffer_char_at_cursor(TextBuffer *buffer);
-/// returns the character before position pos, or 0 if pos is invalid or at the start of a line
+/// returns the character before position `pos`, or 0 if pos is invalid or at the start of a line
char32_t buffer_char_before_pos(TextBuffer *buffer, BufferPos pos);
/// returns the character to the left of the cursor, or 0 if the cursor at the start of the line.
char32_t buffer_char_before_cursor(TextBuffer *buffer);
@@ -431,17 +427,18 @@ size_t buffer_get_text_at_pos(TextBuffer *buffer, BufferPos pos, char32_t *text,
/// the string should be passed to str32_free.
String32 buffer_get_str32_text_at_pos(TextBuffer *buffer, BufferPos pos, size_t nchars);
/// get UTF-8 string at position, up to `nchars` code points (NOT bytes).
+///
/// the resulting string should be freed.
char *buffer_get_utf8_text_at_pos(TextBuffer *buffer, BufferPos pos, size_t nchars);
/// Puts a UTF-8 string containing the contents of the buffer into out.
+///
/// Returns the number of bytes, including a null terminator.
/// To use this function, first pass NULL for out to get the number of bytes you need to allocate.
size_t buffer_contents_utf8(TextBuffer *buffer, char *out);
/// Returns a UTF-8 string containing the contents of `buffer`.
-/// The return value should be freed..
+///
+/// The return value should be freed.
char *buffer_contents_utf8_alloc(TextBuffer *buffer);
-/// perform a series of checks to make sure the buffer doesn't have any invalid values
-void buffer_check_valid(TextBuffer *buffer);
/// clear contents, undo history, etc. of a buffer
void buffer_clear(TextBuffer *buffer);
/// returns the length of the `line_number`th line (0-indexed),
@@ -454,7 +451,7 @@ void buffer_text_dimensions(TextBuffer *buffer, u32 *lines, u32 *columns);
float buffer_display_lines(TextBuffer *buffer);
/// returns the number of columns of text that can fit in the buffer
float buffer_display_cols(TextBuffer *buffer);
-/// scroll by deltas
+/// scroll by deltas (measured in lines and columns)
void buffer_scroll(TextBuffer *buffer, double dx, double dy);
/// returns the screen position of the character at the given position in the buffer.
vec2 buffer_pos_to_pixels(TextBuffer *buffer, BufferPos pos);
@@ -527,7 +524,7 @@ char *buffer_word_at_cursor_utf8(TextBuffer *buffer);
/// returns false if there was no number at `*ppos`.
bool buffer_change_number_at_pos(TextBuffer *buffer, BufferPos *ppos, i64 by);
/// Used for \ref CMD_INCREMENT_NUMBER and \ref CMD_DECREMENT_NUMBER
-void buffer_change_number_at_cursor(TextBuffer *buffer, i64 argument);
+bool buffer_change_number_at_cursor(TextBuffer *buffer, i64 argument);
/// Buffer position corresponding to the start of line `line` (0-indexed).
BufferPos buffer_pos_start_of_line(TextBuffer *buffer, u32 line);
/// Buffer position corresponding to the end of line `line` (0-indexed).
@@ -592,7 +589,8 @@ void buffer_select_page_down(TextBuffer *buffer, i64 npages);
/// Delete `nchars` characters starting from `pos`.
void buffer_delete_chars_at_pos(TextBuffer *buffer, BufferPos pos, i64 nchars);
/// Delete characters between the two positions.
-/// The order of `p1` and `p2` is irrelevant.
+///
+/// The order of `p1` and `p2` doesn't matter.
i64 buffer_delete_chars_between(TextBuffer *buffer, BufferPos p1, BufferPos p2);
/// Delete current selection.
i64 buffer_delete_selection(TextBuffer *buffer);
@@ -712,12 +710,16 @@ void build_queue_start(Ted *ted);
/// add a command to the build queue. call \ref build_queue_start before this.
void build_queue_command(Ted *ted, const char *command);
/// call this after calling \ref build_queue_start, \ref build_queue_command.
-/// make sure you set `ted->build_dir` before running this!
+///
+/// make sure you call \ref build_set_working_directory before calling this!
void build_queue_finish(Ted *ted);
/// set up the build output buffer.
void build_setup_buffer(Ted *ted);
+/// set directory for build commands.
+void build_set_working_directory(Ted *ted, const char *dir);
/// run a single command in the build window.
-/// make sure you set `ted->build_dir` before running this!
+///
+/// make sure you call \ref build_set_working_directory before calling this!
void build_start_with_command(Ted *ted, const char *command);
/// figure out which build command to run, and run it.
void build_start(Ted *ted);