mirror of
https://git.sr.ht/~sircmpwn/gmni
synced 2024-05-04 15:06:01 +02:00
Implement bookmarks
This commit is contained in:
parent
852bc7198f
commit
601f900886
|
@ -16,7 +16,8 @@ gmnlm() {
|
|||
src/escape.c \
|
||||
src/gmnlm.c \
|
||||
src/parser.c \
|
||||
src/url.c
|
||||
src/url.c \
|
||||
src/util.c
|
||||
}
|
||||
|
||||
all="gmni gmnlm"
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef GEMINI_UTIL_H
|
||||
#define GEMINI_UTIL_H
|
||||
|
||||
struct pathspec {
|
||||
const char *var;
|
||||
const char *path;
|
||||
};
|
||||
|
||||
char *getpath(const struct pathspec *paths, size_t npaths);
|
||||
int mkdirs(char *path, mode_t mode);
|
||||
|
||||
#endif
|
83
src/gmnlm.c
83
src/gmnlm.c
|
@ -12,6 +12,7 @@
|
|||
#include <unistd.h>
|
||||
#include "gmni.h"
|
||||
#include "url.h"
|
||||
#include "util.h"
|
||||
|
||||
struct link {
|
||||
char *url;
|
||||
|
@ -29,6 +30,7 @@ struct browser {
|
|||
|
||||
FILE *tty;
|
||||
char *plain_url;
|
||||
char *page_title;
|
||||
struct Curl_URL *url;
|
||||
struct link *links;
|
||||
struct history *history;
|
||||
|
@ -52,6 +54,8 @@ const char *help_msg =
|
|||
"N\tFollow Nth link (where N is a number)\n"
|
||||
"b\tBack (in the page history)\n"
|
||||
"f\tForward (in the page history)\n"
|
||||
"m\tSave bookmark\n"
|
||||
"M\tBrowse bookmarks\n"
|
||||
"\n"
|
||||
"Other commands include:\n\n"
|
||||
"<Enter>\tread more lines\n"
|
||||
|
@ -98,6 +102,63 @@ set_url(struct browser *browser, char *new_url, struct history **history)
|
|||
return true;
|
||||
}
|
||||
|
||||
static char *
|
||||
get_data_pathfmt()
|
||||
{
|
||||
const struct pathspec paths[] = {
|
||||
{.var = "GMNIDATA", .path = "/%s"},
|
||||
{.var = "XDG_DATA_HOME", .path = "/gmni/%s"},
|
||||
{.var = "HOME", .path = "/.local/share/gmni/%s"}
|
||||
};
|
||||
return getpath(paths, sizeof(paths) / sizeof(paths[0]));
|
||||
}
|
||||
|
||||
static char *
|
||||
trim_ws(char *in)
|
||||
{
|
||||
while (*in && isspace(*in)) ++in;
|
||||
return in;
|
||||
}
|
||||
|
||||
static void
|
||||
save_bookmark(struct browser *browser)
|
||||
{
|
||||
const char *path_fmt = get_data_pathfmt();
|
||||
static char path[PATH_MAX+1];
|
||||
snprintf(path, sizeof(path), path_fmt, "bookmarks.gmi");
|
||||
mkdirs(path, 0755);
|
||||
|
||||
FILE *f = fopen(path, "a");
|
||||
if (!f) {
|
||||
fprintf(stderr, "Error opening %s for writing: %s\n",
|
||||
path, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
char *title = browser->page_title;
|
||||
if (title) {
|
||||
title = trim_ws(browser->page_title);
|
||||
}
|
||||
|
||||
fprintf(f, "=> %s%s%s\n", browser->plain_url,
|
||||
title ? " " : "", title ? title : "");
|
||||
fclose(f);
|
||||
|
||||
fprintf(browser->tty, "Bookmark saved: %s\n",
|
||||
title ? title : browser->plain_url);
|
||||
}
|
||||
|
||||
static void
|
||||
open_bookmarks(struct browser *browser)
|
||||
{
|
||||
const char *path_fmt = get_data_pathfmt();
|
||||
static char path[PATH_MAX+1];
|
||||
snprintf(path, sizeof(path), path_fmt, "bookmarks.gmi");
|
||||
static char url[PATH_MAX+1+7];
|
||||
snprintf(url, sizeof(url), "file://%s", path);
|
||||
set_url(browser, url, &browser->history);
|
||||
}
|
||||
|
||||
static enum prompt_result
|
||||
do_prompts(const char *prompt, struct browser *browser)
|
||||
{
|
||||
|
@ -134,6 +195,16 @@ do_prompts(const char *prompt, struct browser *browser)
|
|||
set_url(browser, browser->history->url, NULL);
|
||||
result = PROMPT_ANSWERED;
|
||||
goto exit;
|
||||
case 'm':
|
||||
if (in[1]) break;
|
||||
save_bookmark(browser);
|
||||
result = PROMPT_AGAIN;
|
||||
goto exit;
|
||||
case 'M':
|
||||
if (in[1]) break;
|
||||
open_bookmarks(browser);
|
||||
result = PROMPT_ANSWERED;
|
||||
goto exit;
|
||||
case 'f':
|
||||
if (in[1]) break;
|
||||
if (!browser->history->next) {
|
||||
|
@ -205,13 +276,6 @@ exit_re:
|
|||
return result;
|
||||
}
|
||||
|
||||
static char *
|
||||
trim_ws(char *in)
|
||||
{
|
||||
while (*in && isspace(*in)) ++in;
|
||||
return in;
|
||||
}
|
||||
|
||||
static int
|
||||
wrap(FILE *f, char *s, struct winsize *ws, int *row, int *col)
|
||||
{
|
||||
|
@ -258,6 +322,8 @@ display_gemini(struct browser *browser, struct gemini_response *resp)
|
|||
int nlinks = 0;
|
||||
struct gemini_parser p;
|
||||
gemini_parser_init(&p, resp->bio);
|
||||
free(browser->page_title);
|
||||
browser->page_title = NULL;
|
||||
|
||||
struct winsize ws;
|
||||
ioctl(fileno(browser->tty), TIOCGWINSZ, &ws);
|
||||
|
@ -302,6 +368,9 @@ repeat:
|
|||
}
|
||||
break;
|
||||
case GEMINI_HEADING:
|
||||
if (!browser->page_title) {
|
||||
browser->page_title = strdup(tok.heading.title);
|
||||
}
|
||||
if (text == NULL) {
|
||||
for (int n = tok.heading.level; n; --n) {
|
||||
col += fprintf(out, "#");
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include "util.h"
|
||||
|
||||
static void
|
||||
posix_dirname(char *path, char *dname)
|
||||
{
|
||||
char p[PATH_MAX+1];
|
||||
char *t;
|
||||
|
||||
assert(strlen(path) <= PATH_MAX);
|
||||
|
||||
strcpy(p, path);
|
||||
t = dirname(path);
|
||||
memmove(dname, t, strlen(t) + 1);
|
||||
|
||||
/* restore the path if dirname worked in-place */
|
||||
if (t == path && path != dname) {
|
||||
strcpy(path, p);
|
||||
}
|
||||
}
|
||||
|
||||
/** Make directory and all of its parents */
|
||||
int
|
||||
mkdirs(char *path, mode_t mode)
|
||||
{
|
||||
char dname[PATH_MAX + 1];
|
||||
posix_dirname(path, dname);
|
||||
if (strcmp(dname, "/") == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (mkdirs(dname, mode) != 0) {
|
||||
return -1;
|
||||
}
|
||||
if (mkdir(path, mode) != 0 && errno != EEXIST) {
|
||||
return -1;
|
||||
}
|
||||
errno = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *
|
||||
getpath(const struct pathspec *paths, size_t npaths) {
|
||||
for (size_t i = 0; i < npaths; i++) {
|
||||
const char *var = "";
|
||||
if (paths[i].var) {
|
||||
var = getenv(paths[i].var);
|
||||
}
|
||||
if (var) {
|
||||
char *out = calloc(1,
|
||||
strlen(var) + strlen(paths[i].path) + 1);
|
||||
strcat(strcat(out, var), paths[i].path);
|
||||
return out;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
Loading…
Reference in New Issue