diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..1c29f5b --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 J.P.H. Bruins Slot + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile index 2d6744a..0b95b6f 100644 --- a/Makefile +++ b/Makefile @@ -36,6 +36,14 @@ test: build: CGO_ENABLED=0 go build -a -installsuffix cgo -o ./bin/slack-term ./src/ +# Cross-compile +# http://dave.cheney.net/2015/08/22/cross-compilation-with-go-1-5 +build-linux: + GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -a -installsuffix cgo -o ./bin/slack-term-linux-amd64 ./src/ + +build-mac: + GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -a -installsuffix cgo -o ./bin/slack-term-darwin-amd64 ./src/ + run: build ./bin/slack-term diff --git a/README.md b/README.md index d6ee04a..c291882 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,37 @@ Slack-Term ========== + +A [Slack](https://slack.com) client for your terminal. + +*This project is still in development*, but you can test it by downloading one +of the binaries for your system from the `bin` folder. Rename the file for +convenience into `slack-term` and create a `slack-term.json` file with +the following contents in your home folder. + +``` +{ + "slack_token": "yourslacktokenhere" +} +``` + +Run `slack-term`: + +```bash +$ ./slack-term +``` + +Usage +----- + +| key | action | +|-----------|--------------------------| +| `i` | insert mode | +| `left` | move input cursor left | +| `right` | move input cursor right | +| `esc` | normal mode | +| `k` | move channel cursor up | +| `j` | move channel cursor down | +| `pg-up` | scroll up chat pane | +| `pg-down` | scroll down chat pane | +| `q` | quit | + diff --git a/TODO.md b/TODO.md index 51c0f50..55eb29c 100644 --- a/TODO.md +++ b/TODO.md @@ -12,15 +12,16 @@ Bugs: through RTM in the selected channel - [x] uncovering usernames takes too long, should find a better way test without uncovering, if that is the problem +- [x] GetMessages for a channel can result in `json: cannot unmarshal number + into Go value of type string` https://github.com/nlopes/slack/issues/92 +- [x] set channelname on start +- [x] incoming message event.go probably need a type switch - [ ] GetMessages for a channel doesn't have to load messages based on height of chat pane (y). Because message will sometimes span more than one line and we're able to scroll. Only figure out how many messages you want to load. -- [x] GetMessages for a channel can result in `json: cannot unmarshal number - into Go value of type string` https://github.com/nlopes/slack/issues/92 -- [x] set channelname on start +- [ ] implement the other keys - [ ] docs at exported functions -- [ ] incoming message event.go probably need a type switch Features: @@ -29,5 +30,6 @@ Features: - [x] scrolling in chat pane - [x] group channels, im channels - [x] scrolling in channel pane -- [ ] command mode center text +- [x] command mode center text - [ ] remove unsubscribed or closed channels/groups/im +- [ ] remapping of keys diff --git a/src/components/channels.go b/src/components/channels.go index 168d03b..5c14063 100644 --- a/src/components/channels.go +++ b/src/components/channels.go @@ -133,6 +133,7 @@ func (c *Channels) MoveCursorDown() { } } +// ScrollUp enables us to scroll through the channel list when it overflows func (c *Channels) ScrollUp() { if c.CursorPosition == c.List.InnerBounds().Min.Y { if c.Offset > 0 { @@ -143,6 +144,7 @@ func (c *Channels) ScrollUp() { } } +// ScrollDown enables us to scroll through the channel list when it overflows func (c *Channels) ScrollDown() { if c.CursorPosition == c.List.InnerBounds().Max.Y-1 { if c.Offset < len(c.List.Items)-1 { diff --git a/src/components/input.go b/src/components/input.go index 49c058f..11f052c 100644 --- a/src/components/input.go +++ b/src/components/input.go @@ -63,6 +63,7 @@ func (i *Input) SetY(y int) { i.Par.SetY(y) } +// SendMessage send the input text through the SlackService func (i *Input) SendMessage(svc *service.SlackService, channel string, message string) { svc.SendMessage(channel, message) } diff --git a/src/config/config.go b/src/config/config.go index 39d7d26..d0eca33 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -5,10 +5,12 @@ import ( "os" ) +// Config is the definition of a Config struct type Config struct { SlackToken string `json:"slack_token"` } +// NewConfig loads the config file and returns a Config struct func NewConfig(filepath string) (*Config, error) { var cfg Config diff --git a/src/context/context.go b/src/context/context.go index 820d3a5..0a75b37 100644 --- a/src/context/context.go +++ b/src/context/context.go @@ -23,6 +23,8 @@ type AppContext struct { Mode string } +// CreateAppContext creates an application context which can be passed +// and referenced througout the application func CreateAppContext(flgConfig string) *AppContext { // Load config config, err := config.NewConfig(flgConfig) diff --git a/src/handlers/event.go b/src/handlers/event.go index 93b87fd..4edb20c 100644 --- a/src/handlers/event.go +++ b/src/handlers/event.go @@ -11,7 +11,6 @@ import ( func RegisterEventHandlers(ctx *context.AppContext) { termui.Handle("/sys/kbd/", anyKeyHandler(ctx)) termui.Handle("/sys/wnd/resize", resizeHandler(ctx)) - termui.Handle("/timer/1s", timeHandler(ctx)) incomingMessageHandler(ctx) } @@ -23,16 +22,12 @@ func anyKeyHandler(ctx *context.AppContext) func(termui.Event) { switch key { case "q": actionQuit() - return case "j": actionMoveCursorDownChannels(ctx) - return case "k": actionMoveCursorUpChannels(ctx) - return case "i": actionInsertMode(ctx) - return case "": actionScrollUpChat(ctx) case "": @@ -42,13 +37,10 @@ func anyKeyHandler(ctx *context.AppContext) func(termui.Event) { switch key { case "": actionCommandMode(ctx) - return case "": actionSend(ctx) - return case "": actionInput(ctx.View, " ") - return case "": actionBackSpace(ctx.View) case "C-8": @@ -59,11 +51,8 @@ func anyKeyHandler(ctx *context.AppContext) func(termui.Event) { actionMoveCursorLeft(ctx.View) default: actionInput(ctx.View, key) - return } - } - } } @@ -73,11 +62,6 @@ func resizeHandler(ctx *context.AppContext) func(termui.Event) { } } -func timeHandler(ctx *context.AppContext) func(termui.Event) { - return func(e termui.Event) { - } -} - func incomingMessageHandler(ctx *context.AppContext) { go func() { for { diff --git a/src/service/slack.go b/src/service/slack.go index 129cb62..4b77248 100644 --- a/src/service/slack.go +++ b/src/service/slack.go @@ -22,6 +22,8 @@ type Channel struct { Name string } +// NewSlackService is the constructor for the SlackService and will initialize +// the RTM and a Client func NewSlackService(token string) *SlackService { svc := &SlackService{ Client: slack.New(token), @@ -32,6 +34,8 @@ func NewSlackService(token string) *SlackService { go svc.RTM.ManageConnection() + // Creation of user cache this speeds up + // the uncovering of usernames of messages users, _ := svc.Client.GetUsers() for _, user := range users { svc.UserCache[user.ID] = user.Name @@ -40,6 +44,10 @@ func NewSlackService(token string) *SlackService { return svc } +// GetChannels will retrieve all available channels, groups, and im channels. +// Because the channels are of different types, we will append them to +// an []interface as well as to a []Channel which will give us easy access +// to the id and name of the Channel. func (s *SlackService) GetChannels() []Channel { var chans []Channel @@ -53,7 +61,6 @@ func (s *SlackService) GetChannels() []Channel { chans = append(chans, Channel{chn.ID, chn.Name}) } - // TODO: json: cannot unmarshal number into Go value of type string, GetMessages // Groups slackGroups, err := s.Client.GetGroups(true) if err != nil { @@ -174,10 +181,6 @@ func (s *SlackService) GetMessagesForChannel(channel string, count int) []string return messagesReversed } -func (s *SlackService) GetMessageForGroup() { - -} - // CreateMessage will create a string formatted message that can be rendered // in the Chat pane. //