diff --git a/README.org b/README.org index e9eeebb..0646596 100644 --- a/README.org +++ b/README.org @@ -29,11 +29,11 @@ * Usage - 1. Start with `/slack register` for instructions on how + 1. Start with =/slack register= for instructions on how to obtain a token, or if you already have a token, use - `/slack register `. + =/slack register =. - 2. Use `/slack connect ` with the name + 2. Use =/slack connect = with the name returned by register * Installing diff --git a/api/slack-api-message.c b/api/slack-api-message.c index 0fd0a04..99f6ac0 100644 --- a/api/slack-api-message.c +++ b/api/slack-api-message.c @@ -107,6 +107,10 @@ int slack_api_message_message_handle(struct t_slack_workspace *workspace, _("%s%s"), slack_user_as_prefix(workspace, ptr_user, NULL), message); + slack_channel_member_speaking_add(channel, ptr_user->profile.display_name, + weechat_string_has_highlight( + message, + ptr_user->profile.display_name)); free(message); ptr_typing = slack_channel_typing_search(ptr_channel, diff --git a/slack-channel.c b/slack-channel.c index d301f20..33efb9e 100644 --- a/slack-channel.c +++ b/slack-channel.c @@ -237,6 +237,8 @@ struct t_slack_channel *slack_channel_new(struct t_slack_workspace *workspace, new_channel->is_user_deleted = 0; new_channel->typing_hook_timer = typing_timer; + new_channel->members_speaking[0] = NULL; + new_channel->members_speaking[1] = NULL; new_channel->typings = NULL; new_channel->last_typing = NULL; new_channel->members = NULL; @@ -255,6 +257,95 @@ struct t_slack_channel *slack_channel_new(struct t_slack_workspace *workspace, return new_channel; } +void slack_channel_member_speaking_add_to_list(struct t_slack_channel *channel, + const char *nick, + int highlight) +{ + int size, to_remove, i; + struct t_weelist_item *ptr_item; + + /* create list if it does not exist */ + if (!channel->members_speaking[highlight]) + channel->members_speaking[highlight] = weechat_list_new(); + + /* remove item if it was already in list */ + ptr_item = weechat_list_casesearch(channel->members_speaking[highlight], nick); + if (ptr_item) + weechat_list_remove(channel->members_speaking[highlight], ptr_item); + + /* add nick in list */ + weechat_list_add(channel->members_speaking[highlight], nick, + WEECHAT_LIST_POS_END, NULL); + + /* reduce list size if it's too big */ + size = weechat_list_size(channel->members_speaking[highlight]); + if (size > SLACK_CHANNEL_MEMBERS_SPEAKING_LIMIT) + { + to_remove = size - SLACK_CHANNEL_MEMBERS_SPEAKING_LIMIT; + for (i = 0; i < to_remove; i++) + { + weechat_list_remove( + channel->members_speaking[highlight], + weechat_list_get(channel->members_speaking[highlight], 0)); + } + } +} + +void slack_channel_member_speaking_add(struct t_slack_channel *channel, + const char *nick, int highlight) +{ + if (highlight < 0) + highlight = 0; + if (highlight > 1) + highlight = 1; + if (highlight) + slack_channel_member_speaking_add_to_list(channel, nick, 1); + + slack_channel_member_speaking_add_to_list(channel, nick, 0); +} + +void slack_channel_member_speaking_rename(struct t_slack_channel *channel, + const char *old_nick, + const char *new_nick) +{ + struct t_weelist_item *ptr_item; + int i; + + for (i = 0; i < 2; i++) + { + if (channel->members_speaking[i]) + { + ptr_item = weechat_list_search(channel->members_speaking[i], old_nick); + if (ptr_item) + weechat_list_set(ptr_item, new_nick); + } + } +} + +void slack_channel_member_speaking_rename_if_present(struct t_slack_workspace *workspace, + struct t_slack_channel *channel, + const char *nick) +{ + struct t_weelist_item *ptr_item; + int i, j, list_size; + + (void) workspace; + + for (i = 0; i < 2; i++) + { + if (channel->members_speaking[i]) + { + list_size = weechat_list_size(channel->members_speaking[i]); + for (j = 0; j < list_size; j++) + { + ptr_item = weechat_list_get (channel->members_speaking[i], j); + if (ptr_item && (strcasecmp(weechat_list_string(ptr_item), nick) == 0)) + weechat_list_set(ptr_item, nick); + } + } + } +} + void slack_channel_typing_free(struct t_slack_channel *channel, struct t_slack_channel_typing *typing) { @@ -473,6 +564,10 @@ void slack_channel_free(struct t_slack_workspace *workspace, free(channel->purpose.creator); if (channel->creator) free(channel->creator); + if (channel->members_speaking[0]) + weechat_list_free(channel->members_speaking[0]); + if (channel->members_speaking[1]) + weechat_list_free(channel->members_speaking[1]); if (channel->buffer_as_string) free(channel->buffer_as_string); diff --git a/slack-channel.h b/slack-channel.h index 23275eb..e5f507e 100644 --- a/slack-channel.h +++ b/slack-channel.h @@ -5,6 +5,8 @@ #ifndef _SLACK_CHANNEL_H_ #define _SLACK_CHANNEL_H_ +#define SLACK_CHANNEL_MEMBERS_SPEAKING_LIMIT 128 + #define SLACK_CHANNEL_NAME_MAX_LEN 22 enum t_slack_channel_type @@ -76,6 +78,7 @@ struct t_slack_channel int is_user_deleted; struct t_hook *typing_hook_timer; + struct t_weelist *members_speaking[2]; struct t_slack_channel_typing *typings; struct t_slack_channel_typing *last_typing; struct t_slack_channel_member *members; @@ -97,6 +100,17 @@ struct t_slack_channel *slack_channel_new(struct t_slack_workspace *workspace, enum t_slack_channel_type type, const char *id, const char *name); +void slack_channel_member_speaking_add(struct t_slack_channel *channel, + const char *nick, int highlight); + +void slack_channel_member_speaking_rename(struct t_slack_channel *channel, + const char *old_nick, + const char *new_nick); + +void slack_channel_member_speaking_rename_if_present(struct t_slack_workspace *workspace, + struct t_slack_channel *channel, + const char *nick); + void slack_channel_typing_free(struct t_slack_channel *channel, struct t_slack_channel_typing *typing); diff --git a/slack-completion.c b/slack-completion.c index 4a71eec..1002e0c 100644 --- a/slack-completion.c +++ b/slack-completion.c @@ -8,11 +8,99 @@ #include "weechat-plugin.h" #include "slack.h" +#include "slack-config.h" #include "slack-emoji.h" #include "slack-workspace.h" #include "slack-channel.h" +#include "slack-user.h" +#include "slack-buffer.h" #include "slack-completion.h" +void slack_completion_channel_nicks_add_speakers(struct t_gui_completion *completion, + struct t_slack_workspace *workspace, + struct t_slack_channel *channel, + int highlight) +{ + struct t_slack_user *user; + const char *member; + int list_size, i; + + if (channel->members_speaking[highlight]) + { + list_size = weechat_list_size(channel->members_speaking[highlight]); + for (i = 0; i < list_size; i++) + { + member = weechat_list_string ( + weechat_list_get(channel->members_speaking[highlight], i)); + if (member) + { + user = slack_user_search(workspace, member); + if (user) + weechat_hook_completion_list_add(completion, + user->profile.display_name, + 1, WEECHAT_LIST_POS_BEGINNING); + } + } + } +} + +int slack_completion_channel_nicks_cb(const void *pointer, void *data, + const char *completion_item, + struct t_gui_buffer *buffer, + struct t_gui_completion *completion) +{ + struct t_slack_workspace *ptr_workspace; + struct t_slack_channel *ptr_channel; + struct t_slack_channel_member *ptr_member; + struct t_slack_user *ptr_user; + + /* make C compiler happy */ + (void) pointer; + (void) data; + (void) completion_item; + + ptr_workspace = NULL; + ptr_channel = NULL; + slack_buffer_get_workspace_and_channel(buffer, &ptr_workspace, &ptr_channel); + + if (ptr_channel) + { + switch (ptr_channel->type) + { + case SLACK_CHANNEL_TYPE_CHANNEL: + case SLACK_CHANNEL_TYPE_GROUP: + case SLACK_CHANNEL_TYPE_MPIM: + case SLACK_CHANNEL_TYPE_IM: + for (ptr_member = ptr_channel->members; ptr_member; + ptr_member = ptr_member->next_member) + { + ptr_user = slack_user_search(ptr_workspace, ptr_member->id); + if (ptr_user) + weechat_hook_completion_list_add(completion, + ptr_user->profile.display_name, + 1, WEECHAT_LIST_POS_SORT); + } + /* add recent speakers on channel */ + if (weechat_config_integer(slack_config_look_nick_completion_smart) == SLACK_CONFIG_NICK_COMPLETION_SMART_SPEAKERS) + { + slack_completion_channel_nicks_add_speakers(completion, ptr_workspace, ptr_channel, 0); + } + /* add members whose make highlights on me recently on this channel */ + if (weechat_config_integer(slack_config_look_nick_completion_smart) == SLACK_CONFIG_NICK_COMPLETION_SMART_SPEAKERS_HIGHLIGHTS) + { + slack_completion_channel_nicks_add_speakers(completion, ptr_workspace, ptr_channel, 1); + } + /* add self member at the end */ + weechat_hook_completion_list_add(completion, + ptr_workspace->nick, + 1, WEECHAT_LIST_POS_END); + break; + } + } + + return WEECHAT_RC_OK; +} + int slack_completion_workspaces_cb(const void *pointer, void *data, const char *completion_item, struct t_gui_buffer *buffer, @@ -40,6 +128,12 @@ void slack_completion_init() { struct t_config_option *option; const char *default_template; + + + weechat_hook_completion ("nick", + N_("nicks of current Slack channel"), + &slack_completion_channel_nicks_cb, + NULL, NULL); weechat_hook_completion("slack_workspace", N_("slack workspaces"), diff --git a/slack-config.c b/slack-config.c index 06a0b94..62d125e 100644 --- a/slack-config.c +++ b/slack-config.c @@ -15,6 +15,8 @@ struct t_config_file *slack_config_file; struct t_config_section *slack_config_section_workspace_default; struct t_config_section *slack_config_section_workspace; +struct t_config_option *slack_config_look_nick_completion_smart; + struct t_config_option *slack_config_workspace_default[SLACK_WORKSPACE_NUM_OPTIONS]; int slack_config_workspace_check_value_cb(const void *pointer, void *data, @@ -243,6 +245,31 @@ int slack_config_init() if(!slack_config_file) return 0; + ptr_section = weechat_config_new_section( + slack_config_file, "look", + 0, 0, + NULL, NULL, NULL, + NULL, NULL, NULL, + NULL, NULL, NULL, + NULL, NULL, NULL, + NULL, NULL, NULL); + + if (!ptr_section) + { + weechat_config_free(slack_config_file); + slack_config_file = NULL; + return 0; + } + + slack_config_look_nick_completion_smart = weechat_config_new_option ( + slack_config_file, ptr_section, + "nick_completion_smart", "integer", + N_("smart completion for nicks (completes first with last speakers): " + "speakers = all speakers (including highlights), " + "speakers_highlights = only speakers with highlight"), + "off|speakers|speakers_highlights", 0, 0, "speakers", NULL, 0, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + ptr_section = weechat_config_new_section( slack_config_file, "workspace_default", 0, 0, diff --git a/slack-config.h b/slack-config.h index c769419..19d10b3 100644 --- a/slack-config.h +++ b/slack-config.h @@ -7,11 +7,20 @@ #define SLACK_CONFIG_NAME "slack" +enum t_slack_config_nick_completion +{ + SLACK_CONFIG_NICK_COMPLETION_SMART_OFF = 0, + SLACK_CONFIG_NICK_COMPLETION_SMART_SPEAKERS, + SLACK_CONFIG_NICK_COMPLETION_SMART_SPEAKERS_HIGHLIGHTS, +}; + extern struct t_config_file *slack_config_file; extern struct t_config_section *slack_config_section_workspace_default; extern struct t_config_section *slack_config_section_workspace; +extern struct t_config_option *slack_config_look_nick_completion_smart; + extern struct t_config_option *slack_config_workspace_default[]; int slack_config_workspace_check_value_cb(const void *pointer, void *data,