aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sam.c6
-rw-r--r--vis-core.h3
-rw-r--r--vis-lua.c4
-rw-r--r--vis.c92
-rw-r--r--vis.h2
5 files changed, 77 insertions, 30 deletions
diff --git a/sam.c b/sam.c
index 717b380..0c1ffee 100644
--- a/sam.c
+++ b/sam.c
@@ -1102,10 +1102,8 @@ static bool cmd_write(Vis *vis, Win *win, Command *cmd, const char *argv[], Curs
return false;
}
- if (!file->name) {
- vis_window_name(win, *name);
- file->name = win->file->name;
- }
+ if (!file->name)
+ file_name_set(file, *name);
if (strcmp(file->name, *name) == 0)
file->stat = text_stat(text);
if (vis->event && vis->event->file_save)
diff --git a/vis-core.h b/vis-core.h
index fb34a1b..51c9447 100644
--- a/vis-core.h
+++ b/vis-core.h
@@ -199,4 +199,7 @@ void mode_set(Vis *vis, Mode *new_mode);
void window_selection_save(Win *win);
Win *window_new_file(Vis *vis, File *file);
+const char *file_name_get(File*);
+void file_name_set(File*, const char *name);
+
#endif
diff --git a/vis-lua.c b/vis-lua.c
index 3a4f0dd..5aff161 100644
--- a/vis-lua.c
+++ b/vis-lua.c
@@ -41,7 +41,7 @@ static void window_status_update(Vis *vis, Win *win) {
int width = vis_window_width_get(win);
enum UiOption options = view_options_get(view);
bool focused = vis->win == win;
- const char *filename = file->name;
+ const char *filename = file_name_get(file);
const char *mode = vis->mode->status;
if (focused && mode)
@@ -1066,7 +1066,7 @@ static int file_index(lua_State *L) {
if (lua_isstring(L, 2)) {
const char *key = lua_tostring(L, 2);
if (strcmp(key, "name") == 0) {
- lua_pushstring(L, file->name);
+ lua_pushstring(L, file_name_get(file));
return 1;
}
diff --git a/vis.c b/vis.c
index 6d8febd..3b5e0d0 100644
--- a/vis.c
+++ b/vis.c
@@ -18,6 +18,7 @@
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <pwd.h>
+#include <libgen.h>
#include <termkey.h>
#include "vis.h"
@@ -68,34 +69,68 @@ static File *file_new_text(Vis *vis, Text *text) {
return file;
}
-static File *file_new(Vis *vis, const char *filename) {
- if (filename) {
+static char *absolute_path(const char *name) {
+ if (!name)
+ return NULL;
+ char *copy1 = strdup(name);
+ char *copy2 = strdup(name);
+ char *path_absolute = NULL;
+ char path_normalized[PATH_MAX] = "";
+
+ if (!copy1 || !copy2)
+ goto err;
+
+ char *dir = dirname(copy1);
+ char *base = basename(copy2);
+ if (!(path_absolute = realpath(dir, NULL)))
+ goto err;
+
+ snprintf(path_normalized, sizeof(path_normalized)-1, "%s/%s",
+ path_absolute, base);
+err:
+ free(copy1);
+ free(copy2);
+ free(path_absolute);
+ return path_normalized[0] ? strdup(path_normalized) : NULL;
+}
+
+static File *file_new(Vis *vis, const char *name) {
+ char *name_absolute = NULL;
+ if (name) {
+ if (!(name_absolute = absolute_path(name)))
+ return NULL;
+ File *existing = NULL;
/* try to detect whether the same file is already open in another window
* TODO: do this based on inodes */
for (File *file = vis->files; file; file = file->next) {
- if (file->name && strcmp(file->name, filename) == 0) {
- return file;
+ if (file->name && strcmp(file->name, name_absolute) == 0) {
+ existing = file;
+ break;
}
}
+ if (existing) {
+ free(name_absolute);
+ return existing;
+ }
}
- Text *text = text_load(filename);
- if (!text && filename && errno == ENOENT)
+ File *file = NULL;
+ Text *text = text_load(name);
+ if (!text && name && errno == ENOENT)
text = text_load(NULL);
if (!text)
- return NULL;
-
- File *file = file_new_text(vis, text);
- if (!file) {
- text_free(text);
- return NULL;
- }
-
- if (filename)
- file->name = strdup(filename);
+ goto err;
+ if (!(file = file_new_text(vis, text)))
+ goto err;
+ file->name = name_absolute;
if (!file->internal && vis->event && vis->event->file_open)
vis->event->file_open(vis, file);
return file;
+err:
+ free(name_absolute);
+ text_free(text);
+ file_free(vis, file);
+ return NULL;
}
static File *file_new_internal(Vis *vis, const char *filename) {
@@ -107,12 +142,25 @@ static File *file_new_internal(Vis *vis, const char *filename) {
return file;
}
-void vis_window_name(Win *win, const char *filename) {
- File *file = win->file;
- if (filename != file->name) {
- free((char*)file->name);
- file->name = filename ? strdup(filename) : NULL;
- }
+void file_name_set(File *file, const char *name) {
+ if (name == file->name)
+ return;
+ free((char*)file->name);
+ file->name = absolute_path(name);
+}
+
+const char *file_name_get(File *file) {
+ /* TODO: calculate path relative to working directory, cache result */
+ if (!file->name)
+ return NULL;
+ char cwd[PATH_MAX];
+ if (!getcwd(cwd, sizeof cwd))
+ return file->name;
+ const char *path = strstr(file->name, cwd);
+ if (path != file->name)
+ return file->name;
+ size_t cwdlen = strlen(cwd);
+ return file->name[cwdlen] == '/' ? file->name+cwdlen+1 : file->name;
}
void vis_window_status(Win *win, const char *status) {
diff --git a/vis.h b/vis.h
index d699085..1a2a7d0 100644
--- a/vis.h
+++ b/vis.h
@@ -92,8 +92,6 @@ void vis_window_close(Win*);
/* split the given window. changes to the displayed text will be reflected
* in both windows */
bool vis_window_split(Win*);
-/* change file name associated with this window, affects syntax coloring */
-void vis_window_name(Win*, const char *filename);
/* change status message of this window */
void vis_window_status(Win*, const char *status);
/* focus the next / previous window */