Make project public
This commit is contained in:
parent
190b049f76
commit
241d4bbf3e
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -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.
|
8
Makefile
8
Makefile
@ -36,6 +36,14 @@ test:
|
|||||||
build:
|
build:
|
||||||
CGO_ENABLED=0 go build -a -installsuffix cgo -o ./bin/slack-term ./src/
|
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
|
run: build
|
||||||
./bin/slack-term
|
./bin/slack-term
|
||||||
|
|
||||||
|
35
README.md
35
README.md
@ -1,2 +1,37 @@
|
|||||||
Slack-Term
|
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 |
|
||||||
|
|
||||||
|
12
TODO.md
12
TODO.md
@ -12,15 +12,16 @@ Bugs:
|
|||||||
through RTM in the selected channel
|
through RTM in the selected channel
|
||||||
- [x] uncovering usernames takes too long, should find a better way
|
- [x] uncovering usernames takes too long, should find a better way
|
||||||
test without uncovering, if that is the problem
|
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
|
- [ ] 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
|
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
|
line and we're able to scroll. Only figure out how many messages you
|
||||||
want to load.
|
want to load.
|
||||||
- [x] GetMessages for a channel can result in `json: cannot unmarshal number
|
- [ ] implement the other keys
|
||||||
into Go value of type string` https://github.com/nlopes/slack/issues/92
|
|
||||||
- [x] set channelname on start
|
|
||||||
- [ ] docs at exported functions
|
- [ ] docs at exported functions
|
||||||
- [ ] incoming message event.go probably need a type switch
|
|
||||||
|
|
||||||
Features:
|
Features:
|
||||||
|
|
||||||
@ -29,5 +30,6 @@ Features:
|
|||||||
- [x] scrolling in chat pane
|
- [x] scrolling in chat pane
|
||||||
- [x] group channels, im channels
|
- [x] group channels, im channels
|
||||||
- [x] scrolling in channel pane
|
- [x] scrolling in channel pane
|
||||||
- [ ] command mode center text
|
- [x] command mode center text
|
||||||
- [ ] remove unsubscribed or closed channels/groups/im
|
- [ ] remove unsubscribed or closed channels/groups/im
|
||||||
|
- [ ] remapping of keys
|
||||||
|
@ -133,6 +133,7 @@ func (c *Channels) MoveCursorDown() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ScrollUp enables us to scroll through the channel list when it overflows
|
||||||
func (c *Channels) ScrollUp() {
|
func (c *Channels) ScrollUp() {
|
||||||
if c.CursorPosition == c.List.InnerBounds().Min.Y {
|
if c.CursorPosition == c.List.InnerBounds().Min.Y {
|
||||||
if c.Offset > 0 {
|
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() {
|
func (c *Channels) ScrollDown() {
|
||||||
if c.CursorPosition == c.List.InnerBounds().Max.Y-1 {
|
if c.CursorPosition == c.List.InnerBounds().Max.Y-1 {
|
||||||
if c.Offset < len(c.List.Items)-1 {
|
if c.Offset < len(c.List.Items)-1 {
|
||||||
|
@ -63,6 +63,7 @@ func (i *Input) SetY(y int) {
|
|||||||
i.Par.SetY(y)
|
i.Par.SetY(y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SendMessage send the input text through the SlackService
|
||||||
func (i *Input) SendMessage(svc *service.SlackService, channel string, message string) {
|
func (i *Input) SendMessage(svc *service.SlackService, channel string, message string) {
|
||||||
svc.SendMessage(channel, message)
|
svc.SendMessage(channel, message)
|
||||||
}
|
}
|
||||||
|
@ -5,10 +5,12 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Config is the definition of a Config struct
|
||||||
type Config struct {
|
type Config struct {
|
||||||
SlackToken string `json:"slack_token"`
|
SlackToken string `json:"slack_token"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewConfig loads the config file and returns a Config struct
|
||||||
func NewConfig(filepath string) (*Config, error) {
|
func NewConfig(filepath string) (*Config, error) {
|
||||||
var cfg Config
|
var cfg Config
|
||||||
|
|
||||||
|
@ -23,6 +23,8 @@ type AppContext struct {
|
|||||||
Mode string
|
Mode string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateAppContext creates an application context which can be passed
|
||||||
|
// and referenced througout the application
|
||||||
func CreateAppContext(flgConfig string) *AppContext {
|
func CreateAppContext(flgConfig string) *AppContext {
|
||||||
// Load config
|
// Load config
|
||||||
config, err := config.NewConfig(flgConfig)
|
config, err := config.NewConfig(flgConfig)
|
||||||
|
@ -11,7 +11,6 @@ import (
|
|||||||
func RegisterEventHandlers(ctx *context.AppContext) {
|
func RegisterEventHandlers(ctx *context.AppContext) {
|
||||||
termui.Handle("/sys/kbd/", anyKeyHandler(ctx))
|
termui.Handle("/sys/kbd/", anyKeyHandler(ctx))
|
||||||
termui.Handle("/sys/wnd/resize", resizeHandler(ctx))
|
termui.Handle("/sys/wnd/resize", resizeHandler(ctx))
|
||||||
termui.Handle("/timer/1s", timeHandler(ctx))
|
|
||||||
incomingMessageHandler(ctx)
|
incomingMessageHandler(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,16 +22,12 @@ func anyKeyHandler(ctx *context.AppContext) func(termui.Event) {
|
|||||||
switch key {
|
switch key {
|
||||||
case "q":
|
case "q":
|
||||||
actionQuit()
|
actionQuit()
|
||||||
return
|
|
||||||
case "j":
|
case "j":
|
||||||
actionMoveCursorDownChannels(ctx)
|
actionMoveCursorDownChannels(ctx)
|
||||||
return
|
|
||||||
case "k":
|
case "k":
|
||||||
actionMoveCursorUpChannels(ctx)
|
actionMoveCursorUpChannels(ctx)
|
||||||
return
|
|
||||||
case "i":
|
case "i":
|
||||||
actionInsertMode(ctx)
|
actionInsertMode(ctx)
|
||||||
return
|
|
||||||
case "<previous>":
|
case "<previous>":
|
||||||
actionScrollUpChat(ctx)
|
actionScrollUpChat(ctx)
|
||||||
case "<next>":
|
case "<next>":
|
||||||
@ -42,13 +37,10 @@ func anyKeyHandler(ctx *context.AppContext) func(termui.Event) {
|
|||||||
switch key {
|
switch key {
|
||||||
case "<escape>":
|
case "<escape>":
|
||||||
actionCommandMode(ctx)
|
actionCommandMode(ctx)
|
||||||
return
|
|
||||||
case "<enter>":
|
case "<enter>":
|
||||||
actionSend(ctx)
|
actionSend(ctx)
|
||||||
return
|
|
||||||
case "<space>":
|
case "<space>":
|
||||||
actionInput(ctx.View, " ")
|
actionInput(ctx.View, " ")
|
||||||
return
|
|
||||||
case "<backspace>":
|
case "<backspace>":
|
||||||
actionBackSpace(ctx.View)
|
actionBackSpace(ctx.View)
|
||||||
case "C-8":
|
case "C-8":
|
||||||
@ -59,11 +51,8 @@ func anyKeyHandler(ctx *context.AppContext) func(termui.Event) {
|
|||||||
actionMoveCursorLeft(ctx.View)
|
actionMoveCursorLeft(ctx.View)
|
||||||
default:
|
default:
|
||||||
actionInput(ctx.View, key)
|
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) {
|
func incomingMessageHandler(ctx *context.AppContext) {
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
|
@ -22,6 +22,8 @@ type Channel struct {
|
|||||||
Name string
|
Name string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewSlackService is the constructor for the SlackService and will initialize
|
||||||
|
// the RTM and a Client
|
||||||
func NewSlackService(token string) *SlackService {
|
func NewSlackService(token string) *SlackService {
|
||||||
svc := &SlackService{
|
svc := &SlackService{
|
||||||
Client: slack.New(token),
|
Client: slack.New(token),
|
||||||
@ -32,6 +34,8 @@ func NewSlackService(token string) *SlackService {
|
|||||||
|
|
||||||
go svc.RTM.ManageConnection()
|
go svc.RTM.ManageConnection()
|
||||||
|
|
||||||
|
// Creation of user cache this speeds up
|
||||||
|
// the uncovering of usernames of messages
|
||||||
users, _ := svc.Client.GetUsers()
|
users, _ := svc.Client.GetUsers()
|
||||||
for _, user := range users {
|
for _, user := range users {
|
||||||
svc.UserCache[user.ID] = user.Name
|
svc.UserCache[user.ID] = user.Name
|
||||||
@ -40,6 +44,10 @@ func NewSlackService(token string) *SlackService {
|
|||||||
return svc
|
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 {
|
func (s *SlackService) GetChannels() []Channel {
|
||||||
var chans []Channel
|
var chans []Channel
|
||||||
|
|
||||||
@ -53,7 +61,6 @@ func (s *SlackService) GetChannels() []Channel {
|
|||||||
chans = append(chans, Channel{chn.ID, chn.Name})
|
chans = append(chans, Channel{chn.ID, chn.Name})
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: json: cannot unmarshal number into Go value of type string, GetMessages
|
|
||||||
// Groups
|
// Groups
|
||||||
slackGroups, err := s.Client.GetGroups(true)
|
slackGroups, err := s.Client.GetGroups(true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -174,10 +181,6 @@ func (s *SlackService) GetMessagesForChannel(channel string, count int) []string
|
|||||||
return messagesReversed
|
return messagesReversed
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SlackService) GetMessageForGroup() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateMessage will create a string formatted message that can be rendered
|
// CreateMessage will create a string formatted message that can be rendered
|
||||||
// in the Chat pane.
|
// in the Chat pane.
|
||||||
//
|
//
|
||||||
|
Loading…
Reference in New Issue
Block a user