Skip to content

Commit

Permalink
Detect gitlog and gitstash filetypes from first line of buffer
Browse files Browse the repository at this point in the history
This works when opening files, but more importantly it also works when
piping to stdin at startup. For example:

    git log -p HEAD~8..HEAD | dte
    git stash list -p | dte

See also:

* Commit f75e62f
* Commit 03900b6
  • Loading branch information
craigbarnes committed Dec 23, 2024
1 parent 8c6db8e commit 3099ba9
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/filetype.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "util/log.h"
#include "util/path.h"
#include "util/str-util.h"
#include "util/strtonum.h"
#include "util/xmalloc.h"
#include "util/xmemmem.h"

Expand Down
4 changes: 4 additions & 0 deletions src/filetype/names.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ typedef enum {
GETTEXT,
GITCOMMIT,
GITIGNORE,
GITLOG,
GITREBASE,
GITSTASH,
GLSL,
GNUPLOT,
GO,
Expand Down Expand Up @@ -155,7 +157,9 @@ static const char builtin_filetype_names[NR_BUILTIN_FILETYPES][12] = {
[GETTEXT] = "gettext",
[GITCOMMIT] = "gitcommit",
[GITIGNORE] = "gitignore",
[GITLOG] = "gitlog",
[GITREBASE] = "gitrebase",
[GITSTASH] = "gitstash",
[GLSL] = "glsl",
[GNUPLOT] = "gnuplot",
[GO] = "go",
Expand Down
19 changes: 19 additions & 0 deletions src/filetype/signatures.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,21 @@ static FileTypeEnum filetype_from_emacs_var(const StringView line)
return (ft >= 0) ? (FileTypeEnum)ft : NONE;
}

static bool is_gitlog_commit_line(StringView line)
{
if (!strview_remove_matching_prefix(&line, "commit ") || line.length < 40) {
return false;
}

size_t ndigits = ascii_hex_prefix_length(line.data, line.length);
if (ndigits < 40) {
return false;
}

strview_remove_prefix(&line, ndigits);
return line.length == 0 || strview_has_prefix_and_suffix(&line, " (", ")");
}

static FileTypeEnum filetype_from_signature(const StringView line)
{
if (line.length < 5) {
Expand Down Expand Up @@ -95,8 +110,12 @@ static FileTypeEnum filetype_from_signature(const StringView line)
break;
case 'I':
return strview_has_prefix(&line, "ISO-10303-21;") ? STEP : NONE;
case 'c':
return is_gitlog_commit_line(line) ? GITLOG : NONE;
case 'd':
return strview_has_prefix(&line, "diff --git") ? DIFF : NONE;
case 's':
return strview_has_prefix(&line, "stash@{") ? GITSTASH : NONE;
case '/':
case '.':
case ';':
Expand Down
9 changes: 9 additions & 0 deletions src/util/string-view.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,15 @@ static inline bool strview_has_suffix(const StringView *sv, const char *suffix)
return strview_has_strn_suffix(sv, suffix, strlen(suffix));
}

NONNULL_ARGS
static inline bool strview_has_prefix_and_suffix (
const StringView *sv,
const char *prefix,
const char *suffix
) {
return strview_has_prefix(sv, prefix) && strview_has_suffix(sv, suffix);
}

NONNULL_ARGS
static inline bool strview_isblank(const StringView *sv)
{
Expand Down
14 changes: 14 additions & 0 deletions src/util/strtonum.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,20 @@ static inline unsigned int hex_decode(unsigned char c)
return hex_decode_table[c];
}

static inline bool ascii_isxdigit(unsigned char c)
{
return hex_decode(c) <= 0xF;
}

static inline size_t ascii_hex_prefix_length(const char *str, size_t len)
{
size_t i = 0;
while (i < len && ascii_isxdigit(str[i])) {
i++;
}
return i;
}

WARN_UNUSED_RESULT
static inline size_t buf_parse_hex_uint(const char *str, size_t len, unsigned int *valp)
{
Expand Down
6 changes: 6 additions & 0 deletions test/filetype.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,12 @@ static void test_find_ft_firstline(TestContext *ctx)
{"#autoload", "sh"},
{"#compdef dte", "sh"},
{"#compdef", NULL},
{"stash@{0}: WIP on master: ...", "gitstash"},
{"stash@", NULL},
{"commit 8c6db8e8f8fbf055633ffb7a8bb449bb177adf01 (...)", "gitlog"},
{"commit 8c6db8e8f8fbf055633ffb7a8bb449bb177adf01", "gitlog"},
{"commit 8c6db8e8f8fbf055633ffb7a8bb449bb177adf01 ", NULL},
{"commit 8c6db8e8f8fbf055633ffb7a8bb449bb177adf0 (...)", NULL},

// Emacs style file-local variables
{"<!--*-xml-*-->", "xml"},
Expand Down
11 changes: 10 additions & 1 deletion test/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -428,8 +428,8 @@ static void test_ascii(TestContext *ctx)
EXPECT_EQ(ascii_isdigit(i), !!isdigit(i));
EXPECT_EQ(ascii_isblank(i), !!isblank(i));
EXPECT_EQ(ascii_isprint(i), !!isprint(i));
EXPECT_EQ(ascii_isxdigit(i), !!isxdigit(i));
EXPECT_EQ(u_is_ascii_upper(i), !!isupper(i));
EXPECT_EQ(hex_decode(i) <= 0xF, !!isxdigit(i));
EXPECT_EQ(is_alpha_or_underscore(i), !!isalpha(i) || i == '_');
EXPECT_EQ(is_alnum_or_underscore(i), !!isalnum(i) || i == '_');
if (i != '\v' && i != '\f') {
Expand Down Expand Up @@ -1575,6 +1575,14 @@ static void test_u_is_cntrl(TestContext *ctx)
EXPECT_FALSE(u_is_cntrl(0xFF));
}

static void test_u_is_unicode(TestContext *ctx)
{
EXPECT_TRUE(u_is_unicode(0));
EXPECT_TRUE(u_is_unicode(1));
EXPECT_TRUE(u_is_unicode(UNICODE_MAX_VALID_CODEPOINT));
EXPECT_FALSE(u_is_unicode(UNICODE_MAX_VALID_CODEPOINT + 1));
}

static void test_u_is_zero_width(TestContext *ctx)
{
// Default ignorable codepoints:
Expand Down Expand Up @@ -3246,6 +3254,7 @@ static const TestEntry tests[] = {
TEST(test_u_is_upper),
TEST(test_u_is_ascii_upper),
TEST(test_u_is_cntrl),
TEST(test_u_is_unicode),
TEST(test_u_is_zero_width),
TEST(test_u_is_special_whitespace),
TEST(test_u_is_unprintable),
Expand Down

0 comments on commit 3099ba9

Please sign in to comment.