~eskin/clp

a7736668ca20860b0665c3f8539b86183be6048f — Jon Eskin 7 months ago 8b7069b
namespace cleanup, bugfixes

handle bad opts, better error messages, fix regression where text after line highlight is not displayed
5 files changed, 116 insertions(+), 86 deletions(-)

M cli.c
M clp.c
M clp.h
M lua/clp.lua
M tests/tests.c
M cli.c => cli.c +16 -21
@@ 7,9 7,10 @@
// maybe we should make the opts set some flags in an options struct
// and pass it to a func that sets up the lua accordingly
int
main(int argc, char *argv[]) {
    struct app app;
    init_app(&app);
main(int argc, char *argv[])
{
    struct clp_ctx ctx;
    clp_init(&ctx);
    struct optparse_long longopts[] = {
        {"highlight-line", 'h', OPTPARSE_REQUIRED},
        {"override-filetype", 't', OPTPARSE_REQUIRED},


@@ 24,17 25,20 @@ main(int argc, char *argv[]) {
    while ((option = optparse_long(&options, longopts, NULL)) != -1) {
        switch (option) {
        case 'l':
            app.program_opts.print_available_overrides = true;
            return 0;
            ctx.program_opts.print_available_overrides = true;
            break;
        case 't':
            app.program_opts.filetype_override = options.optarg;
            ctx.program_opts.filetype_override = options.optarg;
            break;
        case 'h':
            app.program_opts.highlight_line = atoi(options.optarg);
            ctx.program_opts.highlight_line = atoi(options.optarg);
            break;
        case 's':
            app.program_opts.color_theme_override = options.optarg;
            ctx.program_opts.color_theme_override = options.optarg;
            break;
        default:
            usage();
            exit(1);
        }
    }



@@ 42,21 46,12 @@ main(int argc, char *argv[]) {

    struct stat buf;

    if (stat(filename, &buf) == -1) {
        /* stat failed, file does not exist or is inaccessible */
        perror("stat");
        return 1;
    }

    if (!S_ISREG(buf.st_mode)) {
        /* file exists but is not a regular file */
        printf("%s is not a regular file\n", argv[1]);
    if (!ctx.program_opts.print_available_overrides &&
        clp_open_file(&ctx, &buf, filename)) {
        return 1;
    }

    // copy filename to app.filename
    strcpy(app.filename, filename);
    run_lua(&app);
    lua_close(app.L);
    clp_run(&ctx);
    clp_cleanup(&ctx);
    return 0;
}

M clp.c => clp.c +87 -56
@@ 9,6 9,16 @@ bail(lua_State *L, char *msg)
    exit(1);
}

void
usage()
{
    printf("usage: clp <filename>\n\
        [--highlight-line <line number>]\n\
        [--override-filetype <filetype>]\n\
        [--list-overrides]\n\
        [--override-colortheme <colortheme>]\n");
}

int
print_lua_path(lua_State *L)
{


@@ 73,24 83,27 @@ package_exists(lua_State *L, const char *name)
}

int
lua_init(struct app *app)
lua_init(struct clp_ctx *ctx)
{
    app->L = luaL_newstate();
    luaL_openlibs(app->L);
    ctx->L = luaL_newstate();
    luaL_openlibs(ctx->L);

    return 0;
}

int
init_app(struct app *app)
clp_init(struct clp_ctx *ctx)
{
    lua_init(app);
    if (!(app->L)) {
    // should there be more initialization here? filename and stuff? does that
    // belong in cli main? where does initialization actually take place in
    // other programs?
    lua_init(ctx);
    if (!(ctx->L)) {
        return -1;
    }
    lua_path_add(app->L, CLP_PATH);
    lua_path_add(ctx->L, CLP_PATH);
    if (strcmp(SRC_LUA_PATH, "") != 0) {
        lua_path_add(app->L, SRC_LUA_PATH);
        lua_path_add(ctx->L, SRC_LUA_PATH);
    }

    char *home = getenv("HOME");


@@ 109,83 122,101 @@ init_app(struct app *app)
            return 1;
        }

        app->program_opts.highlight_line = -1;
        app->program_opts.filetype_override = NULL;
        app->program_opts.color_theme_override = NULL;
        app->program_opts.print_available_overrides = false;
        ctx->program_opts.highlight_line = -1;
        ctx->program_opts.filetype_override = NULL;
        ctx->program_opts.color_theme_override = NULL;
        ctx->program_opts.print_available_overrides = false;
    }

    const char *xdg_config = getenv("XDG_CONFIG_HOME");
    if (xdg_config) {
        snprintf(app->path, sizeof app->path, "%s/clp", xdg_config);
        lua_path_add(app->L, app->path);
        snprintf(ctx->path, sizeof ctx->path, "%s/clp", xdg_config);
        lua_path_add(ctx->L, ctx->path);
    } else if (home && *home) {
        snprintf(app->path, sizeof app->path, "%s/.config/clp", home);
        lua_path_add(app->L, app->path);
        snprintf(ctx->path, sizeof ctx->path, "%s/.config/clp", home);
        lua_path_add(ctx->L, ctx->path);
    }
    return 0;
}

int
run_lua(struct app *app)
clp_open_file(struct clp_ctx *ctx, struct stat *buf, char *filename)
{
    int ret = 0;
    if (app->program_opts.print_available_overrides) {
        printf("in overrides\n");
        lua_getglobal(app->L, "print_available_overrides");
        ret = lua_pcall(app->L, 0, 0, 0);
        if (ret != 0) {
            fprintf(stderr, "%s\n", lua_tostring(app->L, -1));
            return 1;
        }
        app_cleanup(app);
    if (stat(filename, buf) == -1) {
        fprintf(stderr, "Unable to stat %s: ", filename);
        perror(0);
        fprintf(stderr, "Did you provide a valid file?");
        return 1;
    }

    if (!S_ISREG(buf->st_mode)) {
        fprintf(stderr, "%s exists but is not a regular file\n", filename);
        return 1;
    }
    strcpy(ctx->filename, filename);
    return 0;
}

int
clp_run(struct clp_ctx *ctx)
{
    int ret = 0;

    int status = 0;
    if (!package_exists(app->L, "clp")) {
    if (!package_exists(ctx->L, "clp")) {
        fprintf(stderr, "ERROR: failed to load clp.lua\n");
        exit(1);
    }

    lua_getglobal(app->L, "require");
    lua_pushstring(app->L, "clp");
    status = lua_pcall(app->L, 1, 1, 0);
    lua_getglobal(ctx->L, "require");
    lua_pushstring(ctx->L, "clp");
    status = lua_pcall(ctx->L, 1, 1, 0);
    if (status != 0)
        fprintf(stderr, "%s\n", lua_tostring(app->L, -1));
        fprintf(stderr, "%s\n", lua_tostring(ctx->L, -1));

    if (ctx->program_opts.print_available_overrides) {
        lua_getglobal(ctx->L, "print_available_overrides");
        ret = lua_pcall(ctx->L, 0, 0, 0);
        if (ret != 0) {
            fprintf(stderr, "error printing overrides: %s\n",
                    lua_tostring(ctx->L, -1));
            return 1;
        }
        return 0;
    }

    lua_getglobal(app->L, "write");
    lua_newtable(app->L);
    lua_getglobal(ctx->L, "write");
    lua_newtable(ctx->L);

    if (app->program_opts.filetype_override) {
        lua_pushliteral(app->L, "filetype_override");
        lua_pushstring(app->L, app->program_opts.filetype_override);
        lua_settable(app->L, -3);
    if (ctx->program_opts.filetype_override) {
        printf("in ft override, see %s\n", ctx->program_opts.filetype_override);
        lua_pushliteral(ctx->L, "filetype_override");
        lua_pushstring(ctx->L, ctx->program_opts.filetype_override);
        lua_settable(ctx->L, -3);
    }
    if (app->program_opts.highlight_line >= 0) {
        lua_pushliteral(app->L, "highlight_line");
        lua_pushinteger(app->L, app->program_opts.highlight_line);
        lua_settable(app->L, -3);
    if (ctx->program_opts.highlight_line >= 0) {
        lua_pushliteral(ctx->L, "highlight_line");
        lua_pushinteger(ctx->L, ctx->program_opts.highlight_line);
        lua_settable(ctx->L, -3);
    }
    if (app->program_opts.color_theme_override) {
        lua_pushliteral(app->L, "color_theme_override");
        lua_pushstring(app->L, app->program_opts.color_theme_override);
        lua_settable(app->L, -3);
    if (ctx->program_opts.color_theme_override) {
        lua_pushliteral(ctx->L, "color_theme_override");
        lua_pushstring(ctx->L, ctx->program_opts.color_theme_override);
        lua_settable(ctx->L, -3);
    }
    lua_pushliteral(app->L, "filename");
    lua_pushstring(app->L, app->filename);
    lua_settable(app->L, -3);
    ret = lua_pcall(app->L, 1, 0, 0);
    lua_pushliteral(ctx->L, "filename");
    lua_pushstring(ctx->L, ctx->filename);
    lua_settable(ctx->L, -3);
    ret = lua_pcall(ctx->L, 1, 0, 0);
    if (ret != 0) {
        fprintf(stderr, "%s\n", lua_tostring(app->L, -1));
        fprintf(stderr, "%s\n", lua_tostring(ctx->L, -1));
        return 1;
    }
    lua_pushliteral(app->L, "filename");
    lua_pushstring(app->L, app->filename);
    lua_settable(app->L, -3);
    return ret;
}

void
app_cleanup(struct app *app)
clp_cleanup(struct clp_ctx *ctx)
{
    lua_close(app->L);
    lua_close(ctx->L);
}

M clp.h => clp.h +9 -5
@@ 27,7 27,7 @@
#define SRC_LUA_PATH ""
#endif

struct app {
struct clp_ctx {
    lua_State *L;
    char path[PATHMAX];
    struct {


@@ 41,18 41,22 @@ struct app {

void bail(lua_State *L, char *msg);

void usage();

int print_lua_path(lua_State *L);

bool lua_path_add(lua_State *L, const char *path);

bool lua_paths_get(lua_State *L, char **lpath, char **cpath);

int lua_init(struct app *app);
int lua_init(struct clp_ctx *ctx);

int clp_init(struct clp_ctx *ctx);

int init_app(struct app *app);
int clp_open_file(struct clp_ctx *ctx, struct stat *buf, char *filename);

int run_lua(struct app *app);
int clp_run(struct clp_ctx *ctx);

void app_cleanup(struct app *app);
void clp_cleanup(struct clp_ctx *ctx);

#endif /* CLP_H */

M lua/clp.lua => lua/clp.lua +1 -1
@@ 110,7 110,7 @@ function write_hl(text, lexer, hl_line_start, hl_line_end, lang_theme)
        io.write(ansi_codes.begin_line_hl_ansi .. hl ..
                     ansi_codes.end_line_hl_ansi)
    end

    if (post_hl ~= nil) then write_styled(post_hl, lexer, lang_theme) end
end

-- https://github.com/martanne/vis/issues/601#issuecomment-327018674

M tests/tests.c => tests/tests.c +3 -3
@@ 69,9 69,9 @@ run_tests(const char *filename, const char *highlighted[],
        close(pipefd[0]);               // Close unused read end
        dup2(pipefd[1], STDOUT_FILENO); // Redirect stdout to pipe
        struct app app;
        init_app(&app);
        clp_init(&app);
        strcpy(app.filename, filename);
        run_lua(&app);
        clp_run(&app);

        close(pipefd[1]); // Close the write end of the pipe
    } else {


@@ 111,7 111,7 @@ run_tests(const char *filename, const char *highlighted[],
    }
    return 0;
}
// include headers with lua_init and run_lua defs
// include headers with lua_init and clp_run defs
int
main(int argc, char *argv[])
{