Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,20 @@

Daf (Hebrew `דף` — "sheet/page") is a simple console text editor written in C.

## Planned Features
## Themes

Theming, and similar features are planned for future versions.
Three built-in 256-color themes: `dark` (default), `light`, and `mono` (the
original reverse-video/underline look, for terminals or tastes that don't
want real colors). Resolved in this order:

1. `--theme=NAME` on the command line
2. the `DAF_THEME` environment variable
3. `theme=NAME` in the config file (`$XDG_CONFIG_HOME/daf/config`, or
`~/.config/daf/config`) — `#` starts a comment
4. the build-time default (`meson configure -Ddefault_theme=NAME`)

The config file's own location can be changed at build time too, with
`meson configure -Dconfig_subpath=...`.

## Building

Expand Down
5 changes: 5 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ project(
)

add_project_arguments('-D_POSIX_C_SOURCE=200809L', language: 'c')
add_project_arguments(
'-DDAF_DEFAULT_THEME="' + get_option('default_theme') + '"',
'-DDAF_CONFIG_SUBPATH="' + get_option('config_subpath') + '"',
language: 'c',
)

subdir('src')
subdir('tests')
14 changes: 14 additions & 0 deletions meson_options.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
option(
'default_theme',
type: 'combo',
choices: ['dark', 'light', 'mono'],
value: 'dark',
description: 'Theme used when nothing else (flag, env var, config file) picks one',
)

option(
'config_subpath',
type: 'string',
value: 'daf/config',
description: 'Path to the user config file, relative to $XDG_CONFIG_HOME (or $HOME/.config)',
)
89 changes: 89 additions & 0 deletions src/config.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/* SPDX-FileCopyrightText: AnmiTaliDev <anmitalidev@nuros.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*/

#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifndef DAF_CONFIG_SUBPATH
#define DAF_CONFIG_SUBPATH "daf/config"
#endif

static void build_config_path(char *out, size_t out_size)
{
const char *xdg = getenv("XDG_CONFIG_HOME");
if (xdg != NULL && xdg[0] != '\0') {
snprintf(out, out_size, "%s/%s", xdg, DAF_CONFIG_SUBPATH);
return;
}

const char *home = getenv("HOME");
if (home != NULL && home[0] != '\0') {
snprintf(out, out_size, "%s/.config/%s", home, DAF_CONFIG_SUBPATH);
return;
}

out[0] = '\0';
}

static char *trim(char *s)
{
while (*s == ' ' || *s == '\t') {
s++;
}
size_t len = strlen(s);
while (len > 0 &&
(s[len - 1] == ' ' || s[len - 1] == '\t' || s[len - 1] == '\n' || s[len - 1] == '\r')) {
s[--len] = '\0';
}
return s;
}

static void apply_line(daf_config_t *out, char *line)
{
char *s = trim(line);
if (s[0] == '\0' || s[0] == '#') {
return;
}

char *eq = strchr(s, '=');
if (eq == NULL) {
return;
}
*eq = '\0';
char *key = trim(s);
char *value = trim(eq + 1);

if (strcmp(key, "theme") == 0) {
snprintf(out->theme_name, sizeof(out->theme_name), "%s", value);
}
}

void config_load(daf_config_t *out)
{
char path[512];
build_config_path(path, sizeof(path));
if (path[0] == '\0') {
return;
}

FILE *fp = fopen(path, "r");
if (fp == NULL) {
return;
}

char line[256];
while (fgets(line, sizeof(line), fp) != NULL) {
apply_line(out, line);
}

fclose(fp);
}

const char *config_subpath(void)
{
return DAF_CONFIG_SUBPATH;
}
21 changes: 21 additions & 0 deletions src/config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/* SPDX-FileCopyrightText: AnmiTaliDev <anmitalidev@nuros.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*/

#ifndef DAF_CONFIG_H
#define DAF_CONFIG_H

typedef struct {
char theme_name[64]; /* empty if the config file didn't set one */
} daf_config_t;

/* Reads the user config file (key=value lines, '#' comments) if it exists.
* `out` must be zero-initialized by the caller; a missing file, or one that
* doesn't set a given key, simply leaves the matching field untouched. */
void config_load(daf_config_t *out);

/* Path to the config file, relative to $XDG_CONFIG_HOME (or $HOME/.config),
* baked in at build time via `meson configure -Dconfig_subpath=...`. */
const char *config_subpath(void);

#endif /* DAF_CONFIG_H */
4 changes: 4 additions & 0 deletions src/editor.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,10 @@ void editor_init(editor_t *ed, int screen_rows, int screen_cols)
ed->screen_cols = screen_cols;
ed->mode = MODE_EDIT;
ed->filetype = "Plain Text";
ed->theme = theme_find(theme_build_default_name());
if (ed->theme == NULL) {
ed->theme = theme_find("dark");
}
editor_set_status(ed, "daf %s | Ctrl-S save Ctrl-Q quit Ctrl-F find Ctrl-G go to line", DAF_VERSION);
}

Expand Down
2 changes: 2 additions & 0 deletions src/editor.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include "buffer.h"
#include "search.h"
#include "theme.h"

typedef enum {
MODE_EDIT,
Expand Down Expand Up @@ -61,6 +62,7 @@ typedef struct {

char status_msg[256];
const char *filetype;
const theme_t *theme;

edit_record_t *undo_stack;
size_t undo_count;
Expand Down
50 changes: 45 additions & 5 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,65 @@

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "config.h"
#include "editor.h"
#include "input.h"
#include "render.h"
#include "terminal.h"
#include "theme.h"

static int text_rows_for(int terminal_rows)
{
int text_rows = terminal_rows - 2;
return text_rows < 1 ? 1 : text_rows;
}

static const theme_t *resolve_theme(const char *cli_theme_name)
{
daf_config_t config;
memset(&config, 0, sizeof(config));
config_load(&config);

const char *name = cli_theme_name;
if (name == NULL) {
name = getenv("DAF_THEME");
}
if (name == NULL && config.theme_name[0] != '\0') {
name = config.theme_name;
}
if (name == NULL) {
name = theme_build_default_name();
}

const theme_t *theme = theme_find(name);
if (theme == NULL) {
fprintf(stderr, "daf: unknown theme \"%s\", falling back to \"dark\"\n", name);
theme = theme_find("dark");
}
return theme;
}

int main(int argc, char **argv)
{
if (argc > 2) {
fprintf(stderr, "usage: daf [file]\n");
return EXIT_FAILURE;
const char *cli_theme_name = NULL;
const char *filename = NULL;

for (int i = 1; i < argc; i++) {
if (strncmp(argv[i], "--theme=", 8) == 0) {
cli_theme_name = argv[i] + 8;
} else if (filename == NULL) {
filename = argv[i];
} else {
fprintf(stderr, "usage: daf [--theme=name] [file]\n");
return EXIT_FAILURE;
}
}

const theme_t *theme = resolve_theme(cli_theme_name);

terminal_enable_raw_mode();

int rows;
Expand All @@ -35,9 +74,10 @@ int main(int argc, char **argv)

editor_t ed;
editor_init(&ed, text_rows_for(rows), cols);
ed.theme = theme;

if (argc == 2) {
editor_open(&ed, argv[1]);
if (filename != NULL) {
editor_open(&ed, filename);
}

while (!ed.should_quit) {
Expand Down
2 changes: 2 additions & 0 deletions src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ daf_lib_sources = files(
'terminal.c',
'encoding.c',
'filetype.c',
'theme.c',
'config.c',
'buffer.c',
'search.c',
'render.c',
Expand Down
Loading
Loading