Skip to content

Commit f759bb1

Browse files
committed
Merge branch 'v0.2.2'
2 parents 6fdaaba + 8440d01 commit f759bb1

File tree

9 files changed

+1903
-64
lines changed

9 files changed

+1903
-64
lines changed

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,16 @@ Getting started
5959
"C-8": "backspace",
6060
"<delete>": "delete",
6161
"<space>": "space"
62+
},
63+
"search": {
64+
"<left>": "cursor-left",
65+
"<right>": "cursor-right",
66+
"<escape>": "clear-input",
67+
"<enter>": "clear-input",
68+
"<backspace>": "backspace",
69+
"C-8": "backspace",
70+
"<delete>": "delete",
71+
"<space>": "space"
6272
}
6373
}
6474
}
@@ -79,6 +89,7 @@ Default Key Mapping
7989
| mode | key | action |
8090
|---------|-----------|----------------------------|
8191
| command | `i` | insert mode |
92+
| command | `/` | search mode |
8293
| command | `k` | move channel cursor up |
8394
| command | `j` | move channel cursor down |
8495
| command | `g` | move channel cursor top |
@@ -95,3 +106,5 @@ Default Key Mapping
95106
| insert | `right` | move input cursor right |
96107
| insert | `enter` | send message |
97108
| insert | `esc` | command mode |
109+
| search | `esc` | command mode |
110+
| search | `enter` | command mode |

components/channels.go

Lines changed: 139 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,18 @@ import (
99
"github.com/erroneousboat/slack-term/service"
1010
)
1111

12+
const (
13+
IconOnline = "●"
14+
IconOffline = "○"
15+
IconChannel = "#"
16+
IconGroup = "☰"
17+
IconIM = "●"
18+
IconNotification = "🞷"
19+
20+
PresenceAway = "away"
21+
PresenceActive = "active"
22+
)
23+
1224
// Channels is the definition of a Channels component
1325
type Channels struct {
1426
List *termui.List
@@ -31,6 +43,7 @@ func CreateChannels(svc *service.SlackService, inputHeight int) *Channels {
3143
channels.CursorPosition = channels.List.InnerBounds().Min.Y
3244

3345
channels.GetChannels(svc)
46+
channels.SetPresenceForIMChannels(svc)
3447

3548
return channels
3649
}
@@ -115,7 +128,23 @@ func (c *Channels) SetY(y int) {
115128
// GetChannels will get all available channels from the SlackService
116129
func (c *Channels) GetChannels(svc *service.SlackService) {
117130
for _, slackChan := range svc.GetChannels() {
118-
c.List.Items = append(c.List.Items, fmt.Sprintf(" %s", slackChan.Name))
131+
label := setChannelLabel(slackChan, false)
132+
c.List.Items = append(c.List.Items, label)
133+
134+
}
135+
}
136+
137+
// SetPresenceForIMChannels this will set the correct icon for
138+
// IM channels for when they're online of away
139+
func (c *Channels) SetPresenceForIMChannels(svc *service.SlackService) {
140+
for _, slackChan := range svc.GetChannels() {
141+
if slackChan.Type == service.ChannelTypeIM {
142+
presence, err := svc.GetUserPresence(slackChan.UserID)
143+
if err != nil {
144+
continue
145+
}
146+
c.SetPresence(svc, slackChan.UserID, presence)
147+
}
119148
}
120149
}
121150

@@ -166,6 +195,7 @@ func (c *Channels) MoveCursorBottom() {
166195

167196
// ScrollUp enables us to scroll through the channel list when it overflows
168197
func (c *Channels) ScrollUp() {
198+
// Is cursor at the top of the channel view?
169199
if c.CursorPosition == c.List.InnerBounds().Min.Y {
170200
if c.Offset > 0 {
171201
c.Offset--
@@ -177,6 +207,7 @@ func (c *Channels) ScrollUp() {
177207

178208
// ScrollDown enables us to scroll through the channel list when it overflows
179209
func (c *Channels) ScrollDown() {
210+
// Is the cursor at the bottom of the channel view?
180211
if c.CursorPosition == c.List.InnerBounds().Max.Y-1 {
181212
if c.Offset < len(c.List.Items)-1 {
182213
c.Offset++
@@ -186,41 +217,138 @@ func (c *Channels) ScrollDown() {
186217
}
187218
}
188219

189-
// NewMessage will be called when a new message arrives and will
190-
// render an asterisk in front of the channel name
191-
func (c *Channels) NewMessage(svc *service.SlackService, channelID string) {
192-
var index int
220+
// Search will search through the channels to find a channel,
221+
// when a match has been found the selected channel will then
222+
// be the channel that has been found
223+
func (c *Channels) Search(term string) {
224+
for i, item := range c.List.Items {
225+
if strings.Contains(item, term) {
226+
227+
// The new position
228+
newPos := i
229+
230+
// Is the new position in range of the current view?
231+
minRange := c.Offset
232+
maxRange := c.Offset + (c.List.InnerBounds().Max.Y - 2)
233+
234+
if newPos < minRange {
235+
// newPos is above, we need to scroll up.
236+
c.SetSelectedChannel(i)
237+
238+
// How much do we need to scroll to get it into range?
239+
c.Offset = c.Offset - (minRange - newPos)
240+
} else if newPos > maxRange {
241+
// newPos is below, we need to scroll down
242+
c.SetSelectedChannel(i)
243+
244+
// How much do we need to scroll to get it into range?
245+
c.Offset = c.Offset + (newPos - maxRange)
246+
} else {
247+
// newPos is inside range
248+
c.SetSelectedChannel(i)
249+
}
250+
251+
// Set cursor to correct position
252+
c.CursorPosition = (newPos - c.Offset) + 1
253+
254+
break
255+
}
256+
}
257+
}
193258

259+
// SetNotification will be called when a new message arrives and will
260+
// render an notification icon in front of the channel name
261+
func (c *Channels) SetNotification(svc *service.SlackService, channelID string) {
194262
// Get the correct Channel from svc.Channels
263+
var index int
195264
for i, channel := range svc.Channels {
196265
if channelID == channel.ID {
197266
index = i
198267
break
199268
}
200269
}
201270

202-
if !strings.Contains(c.List.Items[index], "*") {
271+
if !strings.Contains(c.List.Items[index], IconNotification) {
203272
// The order of svc.Channels relates to the order of
204273
// List.Items, index will be the index of the channel
205-
c.List.Items[index] = fmt.Sprintf("* %s", strings.TrimSpace(c.List.Items[index]))
274+
c.List.Items[index] = fmt.Sprintf(
275+
"%s %s", IconNotification, strings.TrimSpace(c.List.Items[index]),
276+
)
206277
}
207278

208279
// Play terminal bell sound
209280
fmt.Print("\a")
210281
}
211282

212-
// ClearNewMessageIndicator will remove the asterisk in front of a channel that
213-
// received a new message. This will happen as one will move up or down the
214-
// cursor for Channels
283+
// ClearNewMessageIndicator will remove the notification icon in front of
284+
// a channel that received a new message. This will happen as one will
285+
// move up or down the cursor for Channels
215286
func (c *Channels) ClearNewMessageIndicator() {
216-
channelName := strings.Split(c.List.Items[c.SelectedChannel], "* ")
287+
channelName := strings.Split(
288+
c.List.Items[c.SelectedChannel],
289+
fmt.Sprintf("%s ", IconNotification),
290+
)
291+
217292
if len(channelName) > 1 {
218293
c.List.Items[c.SelectedChannel] = fmt.Sprintf(" %s", channelName[1])
219294
} else {
220295
c.List.Items[c.SelectedChannel] = channelName[0]
221296
}
222297
}
223298

299+
// SetReadMark will send the ReadMark event on the service
224300
func (c *Channels) SetReadMark(svc *service.SlackService) {
225301
svc.SetChannelReadMark(svc.SlackChannels[c.SelectedChannel])
226302
}
303+
304+
// SetPresence will set the correct icon for a IM Channel
305+
func (c *Channels) SetPresence(svc *service.SlackService, userID string, presence string) {
306+
// Get the correct Channel from svc.Channels
307+
var index int
308+
for i, channel := range svc.Channels {
309+
if userID == channel.UserID {
310+
index = i
311+
break
312+
}
313+
}
314+
315+
switch presence {
316+
case PresenceActive:
317+
c.List.Items[index] = strings.Replace(
318+
c.List.Items[index], IconOffline, IconOnline, 1,
319+
)
320+
case PresenceAway:
321+
c.List.Items[index] = strings.Replace(
322+
c.List.Items[index], IconOnline, IconOffline, 1,
323+
)
324+
default:
325+
c.List.Items[index] = strings.Replace(
326+
c.List.Items[index], IconOnline, IconOffline, 1,
327+
)
328+
}
329+
330+
}
331+
332+
// setChannelLabel will set the label of the channel, meaning, how it
333+
// is displayed on screen. Based on the type, different icons are
334+
// shown, as well as an optional notification icon.
335+
func setChannelLabel(channel service.Channel, notification bool) string {
336+
var prefix string
337+
if notification {
338+
prefix = IconNotification
339+
} else {
340+
prefix = " "
341+
}
342+
343+
var label string
344+
switch channel.Type {
345+
case service.ChannelTypeChannel:
346+
label = fmt.Sprintf("%s %s %s", prefix, IconChannel, channel.Name)
347+
case service.ChannelTypeGroup:
348+
label = fmt.Sprintf("%s %s %s", prefix, IconGroup, channel.Name)
349+
case service.ChannelTypeIM:
350+
label = fmt.Sprintf("%s %s %s", prefix, IconIM, channel.Name)
351+
}
352+
353+
return label
354+
}

config/config.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ func NewConfig(filepath string) (*Config, error) {
2828
KeyMap: map[string]keyMapping{
2929
"command": {
3030
"i": "mode-insert",
31+
"/": "mode-search",
3132
"k": "channel-up",
3233
"j": "channel-down",
3334
"g": "channel-top",
@@ -51,6 +52,16 @@ func NewConfig(filepath string) (*Config, error) {
5152
"<delete>": "delete",
5253
"<space>": "space",
5354
},
55+
"search": {
56+
"<left>": "cursor-left",
57+
"<right>": "cursor-right",
58+
"<escape>": "clear-input",
59+
"<enter>": "clear-input",
60+
"<backspace>": "backspace",
61+
"C-8": "backspace",
62+
"<delete>": "delete",
63+
"<space>": "space",
64+
},
5465
},
5566
}
5667

0 commit comments

Comments
 (0)