commit - 633bf6d87d247b0fddf6259b176f491c3f736318
commit + eb2ed626f304f3f1e00711c20d76ecfd8dcc5ce7
blob - 18eb35022c9575129ab163d736402e4e0dff5bfb
blob + 75f3482e4c2a078554ed59ba188c66b6d06af796
--- README.md
+++ README.md
## User files
-Telescope stores user files in `~/.telescope`. The usage and contents
-of these files are described in [the man page](telescope.1), under
-"FILES". There's no support yet for XDG-style directories.
+Telescope stores user files according to the
+[XDG Base Directory Specification][xdg]. The usage and contents of these files
+are described in [the man page](telescope.1), under "FILES".
Only one instance of Telescope can be running at time per user.
[unicode-license]: https://www.unicode.org/license.html
+[xdg]: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
blob - e46a362c97d9a10cb14ba7d4679a8c1e6e47497b
blob + 2c6daa4565ce45e2f7eb957d4e0a447c58baf4e6
--- contrib/README.md
+++ contrib/README.md
- `brutalist.config`: a brutalist theme
- `light.config`: an opinionated theme for light terminals. Load it
with `telescope -c contrib/light.config` or copy it to
- `~/.telescope/config`
+ `~/.config/telescope/config`
- `dark.config`: an opinionated theme for dark terminals. Load it
with `telescope -c contrib/dark.config` or copy it to
- `~/.telecsope/config`
+ `~/.config/telescope/config`
blob - /dev/null
blob + 79a734da3fd082f4e974a0d403a049261db88678 (mode 755)
--- /dev/null
+++ contrib/xdg-migrate.sh
+#!/bin/sh
+
+old_path="$HOME/.telescope"
+
+Die() {
+ printf 'error: %s\n' "$1" 1>&2
+ exit 1
+}
+
+[ -e "$old_path" ] || Die "$old_path does not exist."
+[ -d "$old_path" ] || Die "$old_path is not a directory."
+
+xdg_config="${XDG_CONFIG_HOME:-$HOME/.config}/telescope"
+xdg_data="${XDG_DATA_HOME:-$HOME/.local/share}/telescope"
+xdg_cache="${XDG_CACHE_HOME:-$HOME/.cache}/telescope"
+
+mkdir -p "$xdg_config" "$xdg_data" "$xdg_cache"
+
+for filepath in \
+ "$xdg_config/config" \
+ "$xdg_config/pages" \
+ "$xdg_data/bookmarks.gmi" \
+ "$xdg_data/known_hosts"
+do
+ old_file="$old_path/${filepath##*/}"
+ [ -e "$old_file" ] && cp -R "$old_file" "filepath"
+done
+
+printf "\
+WARNING: the old ~/.telescope directory will be removed.
+
+Every file/directory other than the followings has not been copyied:
+ - config
+ - bookmarks.gmi
+ - known_hosts
+ - pages/
+
+Are you sure? [Y/n] "
+
+read -r reply
+case $reply in
+ [yY]) rm -r "$old_path" && printf 'done\n' ;;
+esac
blob - 0a10064c4146364f37a288587015018ce0c4b532
blob + fe5290ef682562a940933715bda1bf34554c84d7
--- fs.c
+++ fs.c
*/
/*
- * Handles the data in ~/.telescope
+ * Handles config and runtime files
*/
#include "compat.h"
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
+#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include "fs.h"
#include "pages.h"
#include "telescope.h"
static void handle_session_end(struct imsg*, size_t);
static void handle_dispatch_imsg(int, short, void*);
static int fs_send_ui(int, uint32_t, int, const void *, uint16_t);
+static size_t join_path(char*, const char*, const char*, size_t);
+static void getenv_default(char*, const char*, const char*, size_t);
+static void mkdirs(const char*, mode_t);
+static void xdg_init(void);
static struct imsgev *iev_ui;
static FILE *session;
-static char base_path[PATH_MAX];
+/* WARNING: xdg_*_base variables are not initialized if ~/.telescope exists */
+static char xdg_config_base[PATH_MAX];
+static char xdg_data_base[PATH_MAX];
+static char xdg_cache_base[PATH_MAX];
+
+/* *_path_base variables are all equal to $HOME/.telescope if it exists */
+static char config_path_base[PATH_MAX];
+static char data_path_base[PATH_MAX];
+static char cache_path_base[PATH_MAX];
+
+char config_path[PATH_MAX];
static char lockfile_path[PATH_MAX];
static char bookmark_file[PATH_MAX];
static char known_hosts_file[PATH_MAX], known_hosts_tmp[PATH_MAX];
if (page == NULL)
goto notfound;
- strlcpy(path, base_path, sizeof(path));
+ strlcpy(path, config_path_base, sizeof(path));
strlcat(path, "/", sizeof(path));
if (page->path != NULL)
strlcat(path, page->path, sizeof(path));
if (dispatch_imsg(iev, ev, handlers, sizeof(handlers)) == -1) {
/*
- * This should leave a ~/.telescope/crashed file to
+ * This should leave a ~/.cache/telescope/crashed file to
* trigger about:crash on next run. Unfortunately, if
* the main process dies the fs sticks around and
* doesn't notice that the fd was closed. Why EV_READ
data, datalen);
}
-int
-fs_init(void)
+static size_t
+join_path(char *buf, const char *lhs, const char *rhs, size_t buflen)
{
- strlcpy(base_path, getenv("HOME"), sizeof(base_path));
- strlcat(base_path, "/.telescope", sizeof(base_path));
- mkdir(base_path, 0700);
+ strlcpy(buf, lhs, buflen);
+ return strlcat(buf, rhs, buflen);
+}
- strlcpy(lockfile_path, base_path, sizeof(lockfile_path));
- strlcat(lockfile_path, "/lock", sizeof(lockfile_path));
-
- strlcpy(bookmark_file, base_path, sizeof(bookmark_file));
- strlcat(bookmark_file, "/bookmarks.gmi", sizeof(bookmark_file));
+static void
+getenv_default(char *buf, const char *name, const char *def, size_t buflen)
+{
+ size_t ret;
+ char *home, *env;
- strlcpy(known_hosts_file, base_path, sizeof(known_hosts_file));
- strlcat(known_hosts_file, "/known_hosts", sizeof(known_hosts_file));
+ if ((home = getenv("HOME")) == NULL)
+ errx(1, "HOME is not defined");
- strlcpy(known_hosts_tmp, base_path, sizeof(known_hosts_tmp));
- strlcat(known_hosts_tmp, "/known_hosts.tmp.XXXXXXXXXX",
- sizeof(known_hosts_file));
+ if ((env = getenv(name)) != NULL)
+ ret = strlcpy(buf, env, buflen);
+ else
+ ret = join_path(buf, home, def, buflen);
- strlcpy(session_file, base_path, sizeof(session_file));
- strlcat(session_file, "/session", sizeof(session_file));
+ if (ret >= buflen)
+ errx(1, "buffer too small for %s", name);
+}
- strlcpy(crashed_file, base_path, sizeof(crashed_file));
- strlcat(crashed_file, "/crashed", sizeof(crashed_file));
+static void
+mkdirs(const char *path, mode_t mode)
+{
+ char copy[PATH_MAX+1], *parent;
+ strlcpy(copy, path, sizeof(copy));
+ parent = dirname(copy);
+ if (!strcmp(parent, "/"))
+ return;
+ mkdirs(parent, mode);
+
+ if (mkdir(path, mode) != 0) {
+ if (errno == EEXIST)
+ return;
+ err(1, "can't mkdir %s", path);
+ }
+}
+
+static void
+xdg_init(void)
+{
+ char *home, old_path[PATH_MAX];
+ struct stat info;
+
+ /* old path */
+ if ((home = getenv("HOME")) == NULL)
+ errx(1, "HOME is not defined");
+ join_path(old_path, home, "/.telescope", sizeof(old_path));
+
+ /* if ~/.telescope exists, use that instead of xdg dirs */
+ if (stat(old_path, &info) == 0 && S_ISDIR(info.st_mode)) {
+ join_path(config_path_base, home, "/.telescope",
+ sizeof(config_path_base));
+ join_path(data_path_base, home, "/.telescope",
+ sizeof(data_path_base));
+ join_path(cache_path_base, home, "/.telescope",
+ sizeof(cache_path_base));
+ return;
+ }
+
+ /* xdg paths */
+ getenv_default(xdg_config_base, "XDG_CONFIG_HOME", "/.config",
+ sizeof(xdg_config_base));
+ getenv_default(xdg_data_base, "XDG_DATA_HOME", "/.local/share",
+ sizeof(xdg_data_base));
+ getenv_default(xdg_cache_base, "XDG_CACHE_HOME", "/.cache",
+ sizeof(xdg_cache_base));
+
+ join_path(config_path_base, xdg_config_base, "/telescope",
+ sizeof(config_path_base));
+ join_path(data_path_base, xdg_data_base, "/telescope",
+ sizeof(data_path_base));
+ join_path(cache_path_base, xdg_cache_base, "/telescope",
+ sizeof(cache_path_base));
+
+ mkdirs(xdg_config_base, S_IRWXU);
+ mkdirs(xdg_data_base, S_IRWXU);
+ mkdirs(xdg_cache_base, S_IRWXU);
+
+ mkdirs(config_path_base, S_IRWXU);
+ mkdirs(data_path_base, S_IRWXU);
+ mkdirs(cache_path_base, S_IRWXU);
+}
+
+int
+fs_init(void)
+{
+ xdg_init();
+
+ join_path(config_path, config_path_base, "/config",
+ sizeof(config_path));
+ join_path(lockfile_path, cache_path_base, "/lock",
+ sizeof(lockfile_path));
+ join_path(bookmark_file, data_path_base, "/bookmarks.gmi",
+ sizeof(bookmark_file));
+ join_path(known_hosts_file, data_path_base, "/known_hosts",
+ sizeof(known_hosts_file));
+ join_path(known_hosts_tmp, cache_path_base,
+ "/known_hosts.tmp.XXXXXXXXXX", sizeof(known_hosts_tmp));
+ join_path(session_file, cache_path_base, "/session",
+ sizeof(session_file));
+ join_path(crashed_file, cache_path_base, "/crashed",
+ sizeof(crashed_file));
+
return 1;
}
blob - /dev/null
blob + d7b6931d477c232dd73707897491781aa4150416 (mode 644)
--- /dev/null
+++ fs.h
+/*
+ * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef FS_H
+#define FS_H
+
+#include <limits.h>
+
+extern char config_path[PATH_MAX];
+
+#endif
blob - 7af4b34ab6e3ceb2b2293fad3d137a3d6463f0c0
blob + b29b85415704dfea07ae512b66885e20f79ea08e
--- pages/about_help.gmi
+++ pages/about_help.gmi
Telescope is fully customizable. The configuration file is
-> ~/.telescope/config
+> ~/.config/telescope/config
By default Telescope doesn’t use colours too much in order to adapt to both light and dark-themed terminals. This doesn’t mean that Telescope cannot use colours though! See for example contrib/light.config and contrib/dark.config.
All the ‘about:*’ pages can be locally overridden. For example, to customise about:new create:
-> ~/.telescope/pages/about_new.gmi
+> ~/.config/telescope/pages/about_new.gmi
about:bookmarks is the only page that doesn’t follow this pattern; it’s located at
-> ~/.telescope/bookmarks.gmi
+> ~/.local/share/telescope/bookmarks.gmi
## Protocol Proxies
blob - b7d11fff56505b844c2b07147aa9b9b5982456eb
blob + 9dd8771c3768e5133f73b60628a815f3eb6d4f01
--- pages/bookmarks.gmi
+++ pages/bookmarks.gmi
No bookmarks yet!
-Create ~/.telescope/bookmarks.gmi or use ‘bookmark-page’.
+Create ~/.local/share/telescope/bookmarks.gmi or use ‘bookmark-page’.
blob - 4e30e954ab7655bb3ef4d8d6513b644df781192b
blob + 1546d7a1499832c05dec9700952b543cff9fd5d9
--- telescope.1
+++ telescope.1
.It Fl c Pa config
Specify an alternative configuration file.
By default
-.Pa $HOME/.telescope/config
+.Pa $HOME/.config/telescope/config
is loaded.
.It Fl h , Fl -help
Display version and usage.
During the startup,
.Nm
reads the configuration file at
-.Pa ~/.telescope/config
+.Pa ~/.config/telescope/config
or the one given with the
.Fl c
flag.
.El
.Sh FILES
.Bl -tag -width Ds -compact
-.It Pa ~/.telescope/bookmarks.gmi
-Bookmarks file.
-.It Pa ~/.telescope/config
+.It Pa ~/.config/telescope/config
Default configuration file.
-.It Pa ~/.telescope/known_hosts
+.It Pa ~/.config/telescope/pages/about_*.gmi
+Overrides for built-in about: pages.
+.It Pa ~/.local/share/telescope/bookmarks.gmi
+Bookmarks file.
+.It Pa ~/.local/share/telescope/known_hosts
Hash of the certificates for all the known hosts.
Each line contains three fields: hostname with optional port number,
hash of the certificate and a numeric flag.
-.It Pa ~/.telescope/lock
+.It Pa ~/.cache/telescope/lock
Lock file used to prevent multiple instance of
.Nm
from running at the same time.
-.It Pa ~/.telescope/pages/about_*.gmi
-Overrides for built-in about: pages.
-.It Pa ~/.telescope/session
+.It Pa ~/.cache/telescope/session
The list of tabs from the last session.
Every line identifies a tab and contains three space-separated fields:
the full URL, a comma-separated list of attributes and the cached
.Dq the small web
.Pq i.e. simple websites
by using programs like the duckling-proxy by defining a proxy in
-.Pa ~/.telescope/config :
+.Pa ~/.config/telescope/config :
.Bd -literal -offset indent
proxy http via "gemini://127.0.0.1:1965"
proxy https via "gemini://127.0.0.1:1965"
blob - bee474089af045b48224937ec8bd34bc6ca4793e
blob + 31a077546609381a7b422b13497c50095ac2e693
--- telescope.c
+++ telescope.c
#include <unistd.h>
#include "defaults.h"
+#include "fs.h"
#include "minibuffer.h"
#include "parser.h"
#include "session.h"
int proc = -1;
int sessionfd = -1;
int status;
- char path[PATH_MAX], url[GEMINI_URL_LEN+1];
+ char url[GEMINI_URL_LEN+1];
const char *argv0;
argv0 = argv[0];
if (getenv("NO_COLOR") != NULL)
enable_colors = 0;
- strlcpy(path, getenv("HOME"), sizeof(path));
- strlcat(path, "/.telescope/config", sizeof(path));
+ fs_init();
while ((ch = getopt_long(argc, argv, opts, longopts, NULL)) != -1) {
switch (ch) {
exit(ui_print_colors());
case 'c':
fail = 1;
- strlcpy(path, optarg, sizeof(path));
+ strlcpy(config_path, optarg, sizeof(config_path));
break;
case 'n':
configtest = 1;
TAILQ_INIT(&minibuffer_map.m);
config_init();
- parseconfig(path, fail);
+ parseconfig(config_path, fail);
if (configtest) {
puts("config OK");
exit(0);
(download_path = strdup("/tmp/")) == NULL)
errx(1, "strdup");
- fs_init();
if (!safe_mode && (sessionfd = lock_session()) == -1)
errx(1, "can't lock session, is another instance of "
"telescope already running?");