From 66deb574d751a5104abfbc1b0d8fecfc9f39b94d Mon Sep 17 00:00:00 2001 From: David Champion Date: Sat, 28 Jan 2017 18:47:57 -0800 Subject: [PATCH] Adds label completion. A global label hash is added, to which labels are added as they're parsed from a mailbox file or edited manually by the user. Reference counts are kept in the hash table so that unused labels are removed from available completions. Completion is available in the label editor only, but it may be feasible to add for search expressions if the preceding text ends with '~y'. --- doc/manual.xml.head | 3 +++ enter.c | 46 ++++++++++++++++++++------------------------- headers.c | 45 +++++++++++++++++++++++++++++++++++++++++++- init.c | 9 ++++----- main.c | 5 +++-- protos.h | 1 + 6 files changed, 75 insertions(+), 34 deletions(-) diff --git a/doc/manual.xml.head b/doc/manual.xml.head index dcf92a1d0..4e4b75621 100644 --- a/doc/manual.xml.head +++ b/doc/manual.xml.head @@ -6989,6 +6989,9 @@ field. When set to yes, the You can change or delete the X-Label: field within Mutt using the edit-label command, bound to the y key by default. This works for tagged messages, too. +While in the edit-label function, pressing the <complete> +binding (TAB, by default) will perform completion against all labels +currently in use. diff --git a/enter.c b/enter.c index 7a806ddcd..1917c75d6 100644 --- a/enter.c +++ b/enter.c @@ -583,32 +583,26 @@ int _mutt_enter_string (char *buf, size_t buflen, int col, } break; } - else if (flags & MUTT_PATTERN && ch == OP_EDITOR_COMPLETE) - { - char *p; - for (i = state->curpos; i && state->wbuf[i-1] != ',' && - state->wbuf[i-1] != ':'; i--) - ; - for (; i < state->lastchar && state->wbuf[i] == ' '; i++) - ; - my_wcstombs (buf, buflen, state->wbuf + i, state->curpos - i); - p = &buf[i]; - while (p > buf && *(p-1) != '~') - p--; - if (*p == '~' && *(p+1) == 'y') - { - r = mutt_label_complete (buf, buflen, i, state->tabs); - replace_part (state, i, buf); - if (!r) - { - rv = 1; - goto bye; - } - } - else - goto self_insert; - break; - } + else if (flags & MUTT_PATTERN && ch == OP_EDITOR_COMPLETE) + { + for (i = state->curpos; i && state->wbuf[i-1] != '~'; i--) + ; + if (i && i < state->curpos && state->wbuf[i-1] == '~' && state->wbuf[i] == 'y') + { + i++; + my_wcstombs (buf, buflen, state->wbuf + i, state->curpos - i); + r = mutt_label_complete (buf, buflen, i, state->tabs); + replace_part (state, i, buf); + if (!r) + { + rv = 1; + goto bye; + } + } + else + goto self_insert; + break; + } else if (flags & MUTT_ALIAS && ch == OP_EDITOR_COMPLETE_QUERY) { /* invoke the query-menu to get more addresses */ diff --git a/headers.c b/headers.c index c6c2e7b8b..481c9995d 100644 --- a/headers.c +++ b/headers.c @@ -215,6 +215,31 @@ void mutt_edit_headers (const char *editor, } } +static void label_ref_dec(char *label) +{ + uintptr_t count; + + count = (uintptr_t)hash_find(Labels, label); + if (count) + { + hash_delete(Labels, label, NULL, NULL); + count--; + if (count > 0) + hash_insert(Labels, label, (void *)count, 0); + } +} + +static void label_ref_inc(char *label) +{ + uintptr_t count; + + count = (uintptr_t)hash_find(Labels, label); + if (count) + hash_delete(Labels, label, NULL, NULL); + count++; /* was zero if not found */ + hash_insert(Labels, label, (void *)count, 0); +} + /* * add an X-Label: field. */ @@ -224,7 +249,11 @@ static int label_message(HEADER *hdr, char *new) return 0; if (mutt_strcmp (hdr->env->x_label, new) == 0) return 0; + if (hdr->env->x_label != NULL) + label_ref_dec(hdr->env->x_label); mutt_str_replace (&hdr->env->x_label, new); + if (hdr->env->x_label != NULL) + label_ref_inc(hdr->env->x_label); return hdr->changed = hdr->xlabel_changed = 1; } @@ -239,7 +268,7 @@ int mutt_label_message(HEADER *hdr) strncpy(buf, hdr->env->x_label, LONG_STRING); } - if (mutt_get_field("Label: ", buf, sizeof(buf), 0 /* | MUTT_CLEAR */) != 0) + if (mutt_get_field("Label: ", buf, sizeof(buf), MUTT_LABEL /* | MUTT_CLEAR */) != 0) return 0; new = buf; @@ -264,3 +293,17 @@ int mutt_label_message(HEADER *hdr) return changed; } + +/* scan a context (mailbox) and hash all labels we find */ +void mutt_scan_labels(CONTEXT *ctx) +{ + int i; + + if (!ctx) + return; + + for (i = 0; i < ctx->msgcount; i++) + if (ctx->hdrs[i]->env->x_label) + label_ref_inc(ctx->hdrs[i]->env->x_label); +} + diff --git a/init.c b/init.c index 2ee2fd882..b7dacf036 100644 --- a/init.c +++ b/init.c @@ -4147,14 +4147,13 @@ int mutt_label_complete (char *buffer, size_t len, int pos, int numtabs) { char *pt = buffer; int spaces; /* keep track of the number of leading spaces on the line */ - int prefix; SKIPWS (buffer); spaces = buffer - pt; - for (pt = buffer; pt && *pt && *(pt+1); pt++); - for (; pt > buffer && !isspace(*(pt-1)); pt--); - prefix = pt - buffer; + pt = buffer + pos - spaces; + while ((pt > buffer) && !isspace ((unsigned char) *pt)) + pt--; /* first TAB. Collect all the matches */ if (numtabs == 1) @@ -4192,7 +4191,7 @@ int mutt_label_complete (char *buffer, size_t len, int pos, int numtabs) Matches[(numtabs - 2) % Num_matched]); /* return the completed label */ - strncpy (&buffer[prefix], Completed, len - spaces); + strncpy (buffer, Completed, len - spaces); return 1; } diff --git a/main.c b/main.c index 81ae6fea4..a0cb3c71f 100644 --- a/main.c +++ b/main.c @@ -895,15 +895,16 @@ int main (int argc, char **argv, char **environ) if((Context = mx_open_mailbox (folder, ((flags & MUTT_RO) || option (OPTREADONLY)) ? MUTT_READONLY : 0, NULL)) || !explicit_folder) { + Labels = hash_create (131, 0); + mutt_scan_labels(Context); #ifdef USE_SIDEBAR mutt_sb_set_open_buffy (); #endif - Labels = hash_create (131, 0); mutt_index_menu (); if (Context) FREE (&Context); if (Labels) - hash_destroy(&Labels, NULL); + hash_destroy(&Labels, NULL); } #ifdef USE_IMAP imap_logout_all (); diff --git a/protos.h b/protos.h index 1304e4035..d6063fe4b 100644 --- a/protos.h +++ b/protos.h @@ -200,6 +200,7 @@ int mutt_label_message (HEADER *); void mutt_make_label_hash (CONTEXT *); void mutt_label_hash_add (CONTEXT *ctx, HEADER *hdr); void mutt_label_hash_remove (CONTEXT *ctx, HEADER *hdr); +void mutt_scan_labels (CONTEXT *); int mutt_label_complete (char *, size_t, int, int); void mutt_curses_error (const char *, ...); void mutt_curses_message (const char *, ...); -- 2.40.0