Skip to content

Commit 1e72c3c

Browse files
committed
clipdel: add options to delete number of entries
-n will match against the newest entries while -N matches against oldest ones. can be naturally combined with -v also. Closes: #98
1 parent 79dc341 commit 1e72c3c

File tree

2 files changed

+45
-3
lines changed

2 files changed

+45
-3
lines changed

man/clipdel.1

+11
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,17 @@ Real deletion mode. Matching clipboard entries will be removed.
1717
.B \-F
1818
Perform a literal (fixed-string) match instead of interpreting the pattern as a regular expression.
1919
.TP
20+
.B \-N
21+
Interpret PATTERN as the amount of entries to delete starting from the oldest.
22+
E.g
23+
.I "\-N 1"
24+
deletes the oldest entry.
25+
.TP
26+
.B \-n
27+
Same as
28+
.B \-N
29+
but starting from newest.
30+
.TP
2031
.B \-v
2132
Invert the matching condition; entries that do not match the given pattern are selected for deletion.
2233
.TP

src/clipdel.c

+34-3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ enum delete_mode {
2424
enum match_type {
2525
MATCH_REGEX,
2626
MATCH_LITERAL,
27+
MATCH_COUNT_NEWEST,
28+
MATCH_COUNT_OLDEST,
2729
};
2830

2931
/**
@@ -37,6 +39,10 @@ struct clipdel_state {
3739
union {
3840
regex_t rgx;
3941
const char *needle;
42+
struct {
43+
uint64_t current;
44+
uint64_t num_delete;
45+
} count;
4046
};
4147
};
4248

@@ -59,6 +65,15 @@ static enum cs_remove_action _nonnull_ remove_if_match(uint64_t hash _unused_,
5965
expect(ret == 0 || ret == REG_NOMATCH);
6066
matches = ret == 0;
6167
break;
68+
case MATCH_COUNT_NEWEST:
69+
case MATCH_COUNT_OLDEST:
70+
if (state->count.current < state->count.num_delete) {
71+
matches = true;
72+
++state->count.current;
73+
} else {
74+
matches = false;
75+
}
76+
break;
6277
default:
6378
die("unreachable\n");
6479
}
@@ -73,21 +88,27 @@ static enum cs_remove_action _nonnull_ remove_if_match(uint64_t hash _unused_,
7388
}
7489

7590
int main(int argc, char *argv[]) {
76-
const char usage[] = "Usage: clipdel [-d] [-F] [-v] pattern";
91+
const char usage[] = "Usage: clipdel [-d] [-F] [-N] [-n] [-v] pattern";
7792

7893
_drop_(config_free) struct config cfg = setup("clipdel");
7994

8095
struct clipdel_state state = {0};
8196

8297
int opt;
83-
while ((opt = getopt(argc, argv, "dFvh")) != -1) {
98+
while ((opt = getopt(argc, argv, "dFNnvh")) != -1) {
8499
switch (opt) {
85100
case 'd':
86101
state.mode = DELETE_REAL;
87102
break;
88103
case 'F':
89104
state.type = MATCH_LITERAL;
90105
break;
106+
case 'N':
107+
state.type = MATCH_COUNT_OLDEST;
108+
break;
109+
case 'n':
110+
state.type = MATCH_COUNT_NEWEST;
111+
break;
91112
case 'v':
92113
state.invert_match = true;
93114
break;
@@ -109,6 +130,7 @@ int main(int argc, char *argv[]) {
109130
_drop_(cs_destroy) struct clip_store cs;
110131
expect(cs_init(&cs, snip_fd, content_dir_fd) == 0);
111132

133+
enum cs_iter_direction direction = CS_ITER_OLDEST_FIRST;
112134
switch (state.type) {
113135
case MATCH_REGEX:
114136
die_on(regcomp(&state.rgx, argv[optind], REG_EXTENDED | REG_NOSUB),
@@ -117,11 +139,20 @@ int main(int argc, char *argv[]) {
117139
case MATCH_LITERAL:
118140
state.needle = argv[optind];
119141
break;
142+
case MATCH_COUNT_NEWEST:
143+
case MATCH_COUNT_OLDEST:
144+
die_on(str_to_uint64(argv[optind], &state.count.num_delete) < 0,
145+
"Bad argument, expected integer: %s\n", argv[optind]);
146+
state.count.current = 0;
147+
if (state.type == MATCH_COUNT_NEWEST) {
148+
direction = CS_ITER_NEWEST_FIRST;
149+
}
150+
break;
120151
default:
121152
die("unreachable\n");
122153
}
123154

124-
expect(cs_remove(&cs, CS_ITER_OLDEST_FIRST, remove_if_match, &state) == 0);
155+
expect(cs_remove(&cs, direction, remove_if_match, &state) == 0);
125156

126157
if (state.type == MATCH_REGEX) {
127158
regfree(&state.rgx);

0 commit comments

Comments
 (0)