Forráskód Böngészése

Remove vi interface (#376)

Ayyan 2 éve
szülő
commit
c87f3fffc6
7 módosított fájl, 322 hozzáadás és 373 törlés
  1. 11 22
      README.md
  2. 16 20
      cmd/guilds_tree.go
  3. 20 60
      cmd/main_flex.go
  4. 87 78
      cmd/message_input.go
  5. 150 136
      cmd/messages_text.go
  6. 2 2
      internal/config/config.go
  7. 36 55
      internal/config/keys.go

+ 11 - 22
README.md

@@ -51,9 +51,9 @@ go build .
 
 The configuration file allows you to configure and customize the behavior, keybindings, and theme of the application.
 
-- Unix: `$XDG_CONFIG_HOME/discordo/config.yml` or `$HOME/.config/discordo/config.yml`
-- Darwin: `$HOME/Library/Application Support/discordo/config.yml`
-- Windows: `%AppData%/discordo/config.yml`
+- Unix: `$XDG_CONFIG_HOME/discordo/config.toml` or `$HOME/.config/discordo/config.toml`
+- Darwin: `$HOME/Library/Application Support/discordo/config.toml`
+- Windows: `%AppData%/discordo/config.toml`
 
 ```toml
 mouse = true
@@ -62,24 +62,19 @@ timestamps_before_author = false
 messages_limit = 50
 editor = "default"
 
-[keys.normal]
-insert_mode = "Rune[i]"
+[keys]
 focus_guilds_tree = "Ctrl+G"
 focus_messages_text = "Ctrl+T"
 toggle_guild_tree = "Ctrl+B"
-
-[keys.normal.guilds_tree]
-select_current = "Enter"
 select_previous = "Rune[k]"
 select_next = "Rune[j]"
 select_first = "Rune[g]"
 select_last = "Rune[G]"
 
-[keys.normal.messages_text]
-select_previous = "Rune[k]"
-select_next = "Rune[j]"
-select_first = "Rune[g]"
-select_last = "Rune[G]"
+[keys.guilds_tree]
+select_current = "Enter"
+
+[keys.messages_text]
 select_reply = "Rune[s]"
 reply = "Rune[r]"
 reply_mention = "Rune[R]"
@@ -87,12 +82,10 @@ delete = "Rune[d]"
 yank = "Rune[y]"
 open = "Rune[o]"
 
-[keys.insert]
-normal_mode = "Esc"
-
-[keys.insert.message_input]
+[keys.message_input]
 send = "Enter"
 editor = "Ctrl+E"
+cancel = "Esc"
 
 [theme]
 border = true
@@ -104,16 +97,12 @@ background_color = "default"
 [theme.guilds_tree]
 auto_expand_folders = true
 graphics = true
-
+  
 [theme.messages_text]
 author_color = "aqua"
 reply_indicator = "╭ "
 ```
 
-## Documentation
-
-[Here.](./docs)
-
 ## Disclaimer
 
 Automated user accounts or "self-bots" are against Discord's Terms of Service. I am not responsible for any loss caused by using "self-bots" or Discordo.

+ 16 - 20
cmd/guilds_tree.go

@@ -108,22 +108,23 @@ func (gt *GuildsTree) channelToString(c discord.Channel) string {
 	return s
 }
 
-func (gt *GuildsTree) createChannelNode(n *tview.TreeNode, c discord.Channel) {
+func (gt *GuildsTree) createChannelNode(n *tview.TreeNode, c discord.Channel) *tview.TreeNode {
 	if c.Type != discord.DirectMessage && c.Type != discord.GroupDM {
 		ps, err := discordState.Permissions(c.ID, discordState.Ready().User.ID)
 		if err != nil {
 			log.Println(err)
-			return
+			return nil
 		}
 
 		if !ps.Has(discord.PermissionViewChannel) {
-			return
+			return nil
 		}
 	}
 
 	cn := tview.NewTreeNode(gt.channelToString(c))
 	cn.SetReference(c.ID)
 	n.AddChild(cn)
+	return cn
 }
 
 func (gt *GuildsTree) createChannelNodes(n *tview.TreeNode, cs []discord.Channel) {
@@ -219,23 +220,18 @@ func (gt *GuildsTree) onSelected(n *tview.TreeNode) {
 }
 
 func (gt *GuildsTree) onInputCapture(event *tcell.EventKey) *tcell.EventKey {
-	switch mainFlex.mode {
-	case ModeNormal:
-		switch event.Name() {
-		case cfg.Keys.Normal.GuildsTree.SelectCurrent:
-			return tcell.NewEventKey(tcell.KeyEnter, 0, tcell.ModNone)
-		case cfg.Keys.Normal.GuildsTree.SelectPrevious:
-			return tcell.NewEventKey(tcell.KeyUp, 0, tcell.ModNone)
-		case cfg.Keys.Normal.GuildsTree.SelectNext:
-			return tcell.NewEventKey(tcell.KeyDown, 0, tcell.ModNone)
-		case cfg.Keys.Normal.GuildsTree.SelectFirst:
-			return tcell.NewEventKey(tcell.KeyHome, 0, tcell.ModNone)
-		case cfg.Keys.Normal.GuildsTree.SelectLast:
-			return tcell.NewEventKey(tcell.KeyEnd, 0, tcell.ModNone)
-		}
-
-		// do not propagate event to the children in normal mode.
-		return nil
+	switch event.Name() {
+	case cfg.Keys.SelectPrevious:
+		return tcell.NewEventKey(tcell.KeyUp, 0, tcell.ModNone)
+	case cfg.Keys.SelectNext:
+		return tcell.NewEventKey(tcell.KeyDown, 0, tcell.ModNone)
+	case cfg.Keys.SelectFirst:
+		return tcell.NewEventKey(tcell.KeyHome, 0, tcell.ModNone)
+	case cfg.Keys.SelectLast:
+		return tcell.NewEventKey(tcell.KeyEnd, 0, tcell.ModNone)
+
+	case cfg.Keys.GuildsTree.SelectCurrent:
+		return tcell.NewEventKey(tcell.KeyEnter, 0, tcell.ModNone)
 	}
 
 	return event

+ 20 - 60
cmd/main_flex.go

@@ -5,17 +5,9 @@ import (
 	"github.com/rivo/tview"
 )
 
-type Mode uint
-
-const (
-	ModeNormal Mode = iota
-	ModeInsert
-)
-
 type MainFlex struct {
 	*tview.Flex
 
-	mode         Mode
 	guildsTree   *GuildsTree
 	messagesText *MessagesText
 	messageInput *MessageInput
@@ -25,23 +17,11 @@ func newMainFlex() *MainFlex {
 	mf := &MainFlex{
 		Flex: tview.NewFlex(),
 
-		mode:         ModeNormal,
 		guildsTree:   newGuildsTree(),
 		messagesText: newMessagesText(),
 		messageInput: newMessageInput(),
 	}
 
-	app.SetBeforeDrawFunc(func(screen tcell.Screen) bool {
-		switch mf.mode {
-		case ModeNormal:
-			mf.messageInput.SetBorderAttributes(tcell.AttrNone)
-		case ModeInsert:
-			mf.messageInput.SetBorderAttributes(tcell.AttrDim)
-		}
-
-		return false
-	})
-
 	mf.init()
 	mf.SetInputCapture(mf.onInputCapture)
 	return mf
@@ -60,49 +40,29 @@ func (mf *MainFlex) init() {
 }
 
 func (mf *MainFlex) onInputCapture(event *tcell.EventKey) *tcell.EventKey {
-	switch mf.mode {
-	case ModeNormal:
-		switch event.Name() {
-		case cfg.Keys.Normal.InsertMode:
-			mf.mode = ModeInsert
-			app.SetFocus(mf.messageInput)
-			return nil
-
-		case cfg.Keys.Normal.FocusGuildsTree:
-			app.SetFocus(mf.guildsTree)
-			return nil
-		case cfg.Keys.Normal.FocusMessagesText:
-			app.SetFocus(mf.messagesText)
-			return nil
-		case cfg.Keys.Normal.ToggleGuildsTree:
-			// The guilds tree is visible if the numbers of items is two.
-			if mf.GetItemCount() == 2 {
-				mf.RemoveItem(mf.guildsTree)
-				if mf.guildsTree.HasFocus() {
-					app.SetFocus(mf)
-				}
-			} else {
-				mf.init()
-				app.SetFocus(mf.guildsTree)
+	switch event.Name() {
+	case cfg.Keys.FocusGuildsTree:
+		app.SetFocus(mf.guildsTree)
+		return nil
+	case cfg.Keys.FocusMessagesText:
+		app.SetFocus(mf.messagesText)
+		return nil
+	case cfg.Keys.FocusMessageInput:
+		app.SetFocus(mf.messageInput)
+		return nil
+	case cfg.Keys.ToggleGuildsTree:
+		// The guilds tree is visible if the numbers of items is two.
+		if mf.GetItemCount() == 2 {
+			mf.RemoveItem(mf.guildsTree)
+			if mf.guildsTree.HasFocus() {
+				app.SetFocus(mf)
 			}
-
-			return nil
-		}
-
-		// do not propagate event to the children if the message input is focused in normal mode.
-		if mf.messageInput.HasFocus() {
-			return nil
-		}
-	case ModeInsert:
-		switch event.Name() {
-		case cfg.Keys.Insert.NormalMode:
-			mf.mode = ModeNormal
-			return nil
+		} else {
+			mf.init()
+			app.SetFocus(mf.guildsTree)
 		}
 
-		if !mf.messageInput.HasFocus() {
-			return nil
-		}
+		return nil
 	}
 
 	return event

+ 87 - 78
cmd/message_input.go

@@ -49,97 +49,106 @@ func newMessageInput() *MessageInput {
 }
 
 func (mi *MessageInput) reset() {
+	mi.replyMessageIdx = -1
 	mi.SetTitle("")
 	mi.SetText("", true)
 }
 
 func (mi *MessageInput) onInputCapture(event *tcell.EventKey) *tcell.EventKey {
-	switch mainFlex.mode {
-	case ModeInsert:
-		switch event.Name() {
-		case cfg.Keys.Insert.MessageInput.Send:
-			if !mainFlex.guildsTree.selectedChannelID.IsValid() {
-				return nil
-			}
+	switch event.Name() {
+	case cfg.Keys.MessageInput.Send:
+		mi.send()
+		return nil
+	case cfg.Keys.MessageInput.Editor:
+		mi.editor()
+		return nil
+	case cfg.Keys.MessageInput.Cancel:
+		mi.reset()
+		return nil
+	}
 
-			text := strings.TrimSpace(mi.GetText())
-			if text == "" {
-				return nil
-			}
+	return event
+}
 
-			if mi.replyMessageIdx != -1 {
-				ms, err := discordState.Cabinet.Messages(mainFlex.guildsTree.selectedChannelID)
-				if err != nil {
-					log.Println(err)
-					return nil
-				}
-
-				data := api.SendMessageData{
-					Content:         text,
-					Reference:       &discord.MessageReference{MessageID: ms[mi.replyMessageIdx].ID},
-					AllowedMentions: &api.AllowedMentions{RepliedUser: option.False},
-				}
-
-				if strings.HasPrefix(mi.GetTitle(), "[@]") {
-					data.AllowedMentions.RepliedUser = option.True
-				}
-
-				go func() {
-					if _, err := discordState.SendMessageComplex(mainFlex.guildsTree.selectedChannelID, data); err != nil {
-						log.Println("failed to send message:", err)
-					}
-				}()
-			} else {
-				go func() {
-					if _, err := discordState.SendMessage(mainFlex.guildsTree.selectedChannelID, text); err != nil {
-						log.Println("failed to send message:", err)
-					}
-				}()
-			}
+func (mi *MessageInput) send() {
+	if !mainFlex.guildsTree.selectedChannelID.IsValid() {
+		return
+	}
 
-			mi.replyMessageIdx = -1
-			mainFlex.messagesText.Highlight()
-			mi.reset()
-			return nil
-		case cfg.Keys.Insert.MessageInput.Editor:
-			e := cfg.Editor
-			if e == "default" {
-				e = os.Getenv("EDITOR")
-			}
+	text := strings.TrimSpace(mi.GetText())
+	if text == "" {
+		return
+	}
+
+	if mi.replyMessageIdx != -1 {
+		ms, err := discordState.Cabinet.Messages(mainFlex.guildsTree.selectedChannelID)
+		if err != nil {
+			log.Println(err)
+			return
+		}
 
-			f, err := os.CreateTemp("", constants.TmpFilePattern)
-			if err != nil {
-				log.Println(err)
-				return nil
+		data := api.SendMessageData{
+			Content:         text,
+			Reference:       &discord.MessageReference{MessageID: ms[mi.replyMessageIdx].ID},
+			AllowedMentions: &api.AllowedMentions{RepliedUser: option.False},
+		}
+
+		if strings.HasPrefix(mi.GetTitle(), "[@]") {
+			data.AllowedMentions.RepliedUser = option.True
+		}
+
+		go func() {
+			if _, err := discordState.SendMessageComplex(mainFlex.guildsTree.selectedChannelID, data); err != nil {
+				log.Println("failed to send message:", err)
 			}
-			_, _ = f.WriteString(mi.GetText())
-			f.Close()
-
-			defer os.Remove(f.Name())
-
-			cmd := exec.Command(e, f.Name())
-			cmd.Stdin = os.Stdin
-			cmd.Stdout = os.Stdout
-			cmd.Stderr = os.Stderr
-
-			app.Suspend(func() {
-				err := cmd.Run()
-				if err != nil {
-					log.Println(err)
-					return
-				}
-			})
-
-			msg, err := os.ReadFile(f.Name())
-			if err != nil {
-				log.Println(err)
-				return nil
+		}()
+	} else {
+		go func() {
+			if _, err := discordState.SendMessage(mainFlex.guildsTree.selectedChannelID, text); err != nil {
+				log.Println("failed to send message:", err)
 			}
+		}()
+	}
+
+	mi.replyMessageIdx = -1
+	mainFlex.messagesText.Highlight()
+	mi.reset()
+}
 
-			mi.SetText(strings.TrimSpace(string(msg)), true)
-			return nil
+func (mi *MessageInput) editor() {
+	e := cfg.Editor
+	if e == "default" {
+		e = os.Getenv("EDITOR")
+	}
+
+	f, err := os.CreateTemp("", constants.TmpFilePattern)
+	if err != nil {
+		log.Println(err)
+		return
+	}
+	_, _ = f.WriteString(mi.GetText())
+	f.Close()
+
+	defer os.Remove(f.Name())
+
+	cmd := exec.Command(e, f.Name())
+	cmd.Stdin = os.Stdin
+	cmd.Stdout = os.Stdout
+	cmd.Stderr = os.Stderr
+
+	app.Suspend(func() {
+		err := cmd.Run()
+		if err != nil {
+			log.Println(err)
+			return
 		}
+	})
+
+	msg, err := os.ReadFile(f.Name())
+	if err != nil {
+		log.Println(err)
+		return
 	}
 
-	return event
+	mi.SetText(strings.TrimSpace(string(msg)), true)
 }

+ 150 - 136
cmd/messages_text.go

@@ -1,6 +1,7 @@
 package cmd
 
 import (
+	"errors"
 	"fmt"
 	"io"
 	"log"
@@ -149,179 +150,192 @@ func (mt *MessagesText) createFooter(w io.Writer, m discord.Message) {
 	}
 }
 
-func (mt *MessagesText) onInputCapture(event *tcell.EventKey) *tcell.EventKey {
-	switch mainFlex.mode {
-	case ModeNormal:
-		switch event.Name() {
-		case cfg.Keys.Normal.MessagesText.Yank:
-			if mt.selectedMessage == -1 {
-				return nil
-			}
+func (mt *MessagesText) getSelectedMessage() (*discord.Message, error) {
+	if mt.selectedMessage == -1 {
+		return nil, errors.New("no message is currently selected")
+	}
 
-			ms, err := discordState.Cabinet.Messages(mainFlex.guildsTree.selectedChannelID)
-			if err != nil {
-				log.Println(err)
-				return nil
-			}
+	ms, err := discordState.Cabinet.Messages(mainFlex.guildsTree.selectedChannelID)
+	if err != nil {
+		return nil, err
+	}
 
-			err = clipboard.WriteAll(ms[mt.selectedMessage].Content)
-			if err != nil {
-				log.Println("failed to write to clipboard:", err)
-				return nil
-			}
+	return &ms[mt.selectedMessage], nil
+}
 
+func (mt *MessagesText) onInputCapture(event *tcell.EventKey) *tcell.EventKey {
+	switch event.Name() {
+	case cfg.Keys.SelectPrevious, cfg.Keys.SelectNext, cfg.Keys.SelectFirst, cfg.Keys.SelectLast, cfg.Keys.MessagesText.SelectReply:
+		ms, err := discordState.Cabinet.Messages(mainFlex.guildsTree.selectedChannelID)
+		if err != nil {
+			log.Println(err)
 			return nil
+		}
 
-		case cfg.Keys.Normal.MessagesText.SelectFirst, cfg.Keys.Normal.MessagesText.SelectLast, cfg.Keys.Normal.MessagesText.SelectPrevious, cfg.Keys.Normal.MessagesText.SelectNext, cfg.Keys.Normal.MessagesText.SelectReply:
-			ms, err := discordState.Cabinet.Messages(mainFlex.guildsTree.selectedChannelID)
-			if err != nil {
-				log.Println(err)
-				return nil
-			}
-
-			switch event.Name() {
-			case cfg.Keys.Normal.MessagesText.SelectPrevious:
-				// If no message is currently selected, select the latest message.
-				if len(mt.GetHighlights()) == 0 {
-					mt.selectedMessage = 0
-				} else {
-					if mt.selectedMessage < len(ms)-1 {
-						mt.selectedMessage++
-					} else {
-						return nil
-					}
-				}
-			case cfg.Keys.Normal.MessagesText.SelectNext:
-				// If no message is currently selected, select the latest message.
-				if len(mt.GetHighlights()) == 0 {
-					mt.selectedMessage = 0
+		switch event.Name() {
+		case cfg.Keys.SelectPrevious:
+			// If no message is currently selected, select the latest message.
+			if len(mt.GetHighlights()) == 0 {
+				mt.selectedMessage = 0
+			} else {
+				if mt.selectedMessage < len(ms)-1 {
+					mt.selectedMessage++
 				} else {
-					if mt.selectedMessage > 0 {
-						mt.selectedMessage--
-					} else {
-						return nil
-					}
+					return nil
 				}
-			case cfg.Keys.Normal.MessagesText.SelectFirst:
-				mt.selectedMessage = len(ms) - 1
-			case cfg.Keys.Normal.MessagesText.SelectLast:
+			}
+		case cfg.Keys.SelectNext:
+			// If no message is currently selected, select the latest message.
+			if len(mt.GetHighlights()) == 0 {
 				mt.selectedMessage = 0
-			case cfg.Keys.Normal.MessagesText.SelectReply:
-				if mt.selectedMessage == -1 {
+			} else {
+				if mt.selectedMessage > 0 {
+					mt.selectedMessage--
+				} else {
 					return nil
 				}
-
-				if ref := ms[mt.selectedMessage].ReferencedMessage; ref != nil {
-					for i, m := range ms {
-						if ref.ID == m.ID {
-							mt.selectedMessage = i
-						}
-					}
-				}
 			}
-
-			mt.Highlight(ms[mt.selectedMessage].ID.String())
-			mt.ScrollToHighlight()
-			return nil
-		case cfg.Keys.Normal.MessagesText.Open:
+		case cfg.Keys.SelectFirst:
+			mt.selectedMessage = len(ms) - 1
+		case cfg.Keys.SelectLast:
+			mt.selectedMessage = 0
+		case cfg.Keys.MessagesText.SelectReply:
 			if mt.selectedMessage == -1 {
 				return nil
 			}
 
-			ms, err := discordState.Cabinet.Messages(mainFlex.guildsTree.selectedChannelID)
-			if err != nil {
-				log.Println(err)
-				return nil
+			if ref := ms[mt.selectedMessage].ReferencedMessage; ref != nil {
+				for i, m := range ms {
+					if ref.ID == m.ID {
+						mt.selectedMessage = i
+					}
+				}
 			}
+		}
 
-			attachments := ms[mt.selectedMessage].Attachments
-			if len(attachments) == 0 {
-				return nil
-			}
+		mt.Highlight(ms[mt.selectedMessage].ID.String())
+		mt.ScrollToHighlight()
+		return nil
 
-			for _, a := range attachments {
-				go func() {
-					if err := open.Start(a.URL); err != nil {
-						log.Println(err)
-					}
-				}()
-			}
+	case cfg.Keys.MessagesText.Yank:
+		mt.yank()
+		return nil
+	case cfg.Keys.MessagesText.Open:
+		mt.open()
+		return nil
+	case cfg.Keys.MessagesText.Reply:
+		mt.reply(false)
+		return nil
+	case cfg.Keys.MessagesText.ReplyMention:
+		mt.reply(true)
+		return nil
+	case cfg.Keys.MessagesText.Delete:
+		mt.delete()
+		return nil
+	}
 
-			return nil
-		case cfg.Keys.Normal.MessagesText.Reply, cfg.Keys.Normal.MessagesText.ReplyMention:
-			if mt.selectedMessage == -1 {
-				return nil
-			}
+	return event
+}
 
-			var title string
-			if event.Name() == cfg.Keys.Normal.MessagesText.ReplyMention {
-				title += "[@] Replying to "
-			} else {
-				title += "Replying to "
-			}
+func (mt *MessagesText) yank() {
+	msg, err := mt.getSelectedMessage()
+	if err != nil {
+		log.Println(err)
+		return
+	}
 
-			ms, err := discordState.Cabinet.Messages(mainFlex.guildsTree.selectedChannelID)
-			if err != nil {
-				log.Println(err)
-				return nil
-			}
+	err = clipboard.WriteAll(msg.Content)
+	if err != nil {
+		log.Println("failed to write to clipboard:", err)
+		return
+	}
+}
 
-			title += ms[mt.selectedMessage].Author.Tag()
-			mainFlex.messageInput.SetTitle(title)
-			mainFlex.messageInput.replyMessageIdx = mt.selectedMessage
+func (mt *MessagesText) open() {
+	msg, err := mt.getSelectedMessage()
+	if err != nil {
+		log.Println(err)
+		return
+	}
 
-			app.SetFocus(mainFlex.messageInput)
-			return nil
-		case cfg.Keys.Normal.MessagesText.Delete:
-			if mt.selectedMessage == -1 {
-				return nil
-			}
+	attachments := msg.Attachments
+	if len(attachments) == 0 {
+		return
+	}
 
-			ms, err := discordState.Cabinet.Messages(mainFlex.guildsTree.selectedChannelID)
-			if err != nil {
+	for _, a := range attachments {
+		go func() {
+			if err := open.Start(a.URL); err != nil {
 				log.Println(err)
-				return nil
 			}
+		}()
+	}
 
-			m := ms[mt.selectedMessage]
-			clientID := discordState.Ready().User.ID
-
-			ps, err := discordState.Permissions(mainFlex.guildsTree.selectedChannelID, discordState.Ready().User.ID)
-			if err != nil {
-				return nil
-			}
+}
 
-			if m.Author.ID != clientID && !ps.Has(discord.PermissionManageMessages) {
-				return nil
-			}
+func (mt *MessagesText) reply(mention bool) {
+	var title string
+	if mention {
+		title += "[@] Replying to "
+	} else {
+		title += "Replying to "
+	}
 
-			if err := discordState.DeleteMessage(mainFlex.guildsTree.selectedChannelID, m.ID, ""); err != nil {
-				log.Println(err)
-			}
+	msg, err := mt.getSelectedMessage()
+	if err != nil {
+		log.Println(err)
+		return
+	}
 
-			if err := discordState.MessageRemove(mainFlex.guildsTree.selectedChannelID, m.ID); err != nil {
-				log.Println(err)
-			}
+	title += msg.Author.Tag()
+	mainFlex.messageInput.SetTitle(title)
+	mainFlex.messageInput.replyMessageIdx = mt.selectedMessage
+	app.SetFocus(mainFlex.messageInput)
+}
 
-			ms, err = discordState.Cabinet.Messages(mainFlex.guildsTree.selectedChannelID)
-			if err != nil {
-				log.Println(err)
-				return nil
-			}
+func (mt *MessagesText) delete() {
 
-			mt.Clear()
+	msg, err := mt.getSelectedMessage()
+	if err != nil {
+		log.Println(err)
+		return
+	}
 
-			for i := len(ms) - 1; i >= 0; i-- {
-				mainFlex.messagesText.createMessage(ms[i])
-			}
+	clientID := discordState.Ready().User.ID
+	if msg.GuildID.IsValid() {
+		ps, err := discordState.Permissions(mainFlex.guildsTree.selectedChannelID, discordState.Ready().User.ID)
+		if err != nil {
+			return
+		}
 
-			return nil
+		if msg.Author.ID != clientID && !ps.Has(discord.PermissionManageMessages) {
+			return
 		}
+	} else {
+		if msg.Author.ID != clientID {
+			return
+		}
+	}
 
-		// do not propagate event to the children in normal mode.
-		return nil
+	if err := discordState.DeleteMessage(mainFlex.guildsTree.selectedChannelID, msg.ID, ""); err != nil {
+		log.Println(err)
+		return
+	}
 
+	if err := discordState.MessageRemove(mainFlex.guildsTree.selectedChannelID, msg.ID); err != nil {
+		log.Println(err)
+	}
+
+	ms, err := discordState.Cabinet.Messages(mainFlex.guildsTree.selectedChannelID)
+	if err != nil {
+		log.Println(err)
+		return
+	}
+
+	mt.Clear()
+
+	for i := len(ms) - 1; i >= 0; i-- {
+		mainFlex.messagesText.createMessage(ms[i])
 	}
 
-	return event
 }

+ 2 - 2
internal/config/config.go

@@ -22,7 +22,7 @@ type Config struct {
 	Theme Theme `toml:"theme"`
 }
 
-func defaultConfig() Config {
+func DefaultConfig() Config {
 	return Config{
 		Mouse: true,
 
@@ -44,7 +44,7 @@ func Load() (*Config, error) {
 		return nil, err
 	}
 
-	cfg := defaultConfig()
+	cfg := DefaultConfig()
 	path = filepath.Join(path, constants.Name, "config.toml")
 	f, err := os.Open(path)
 	if os.IsNotExist(err) {

+ 36 - 55
internal/config/keys.go

@@ -2,35 +2,27 @@ package config
 
 type (
 	Keys struct {
-		Normal NormalModeKeys `toml:"normal"`
-		Insert InsertModeKeys `toml:"insert"`
-	}
-
-	NormalModeKeys struct {
-		InsertMode        string `toml:"insert_mode"`
 		FocusGuildsTree   string `toml:"focus_guilds_tree"`
 		FocusMessagesText string `toml:"focus_messages_text"`
+		FocusMessageInput string `toml:"focus_message_input"`
 		ToggleGuildsTree  string `toml:"toggle_guild_tree"`
 
-		GuildsTree   GuildsTreeNormalModeKeys   `toml:"guilds_tree"`
-		MessagesText MessagesTextNormalModeKeys `toml:"messages_text"`
-	}
-
-	GuildsTreeNormalModeKeys struct {
-		SelectCurrent  string `toml:"select_current"`
 		SelectPrevious string `toml:"select_previous"`
 		SelectNext     string `toml:"select_next"`
 		SelectFirst    string `toml:"select_first"`
 		SelectLast     string `toml:"select_last"`
+
+		GuildsTree   GuildsTreeKeys   `toml:"guilds_tree"`
+		MessagesText MessagesTextKeys `toml:"messages_text"`
+		MessageInput MessageInputKeys `toml:"message_input"`
 	}
 
-	MessagesTextNormalModeKeys struct {
-		SelectPrevious string `toml:"select_previous"`
-		SelectNext     string `toml:"select_next"`
-		SelectFirst    string `toml:"select_first"`
-		SelectLast     string `toml:"select_last"`
-		SelectReply    string `toml:"select_reply"`
+	GuildsTreeKeys struct {
+		SelectCurrent string `toml:"select_current"`
+	}
 
+	MessagesTextKeys struct {
+		SelectReply  string `toml:"select_reply"`
 		Reply        string `toml:"reply"`
 		ReplyMention string `toml:"reply_mention"`
 
@@ -39,55 +31,44 @@ type (
 		Open   string `toml:"open"`
 	}
 
-	InsertModeKeys struct {
-		NormalMode string `toml:"normal_mode"`
-
-		MessageInput MessageInputInsertModeKeys `toml:"message_input"`
-	}
-
-	MessageInputInsertModeKeys struct {
+	MessageInputKeys struct {
 		Send   string `toml:"send"`
 		Editor string `toml:"editor"`
+		Cancel string `toml:"cancel"`
 	}
 )
 
 func defaultKeys() Keys {
 	return Keys{
-		Normal: NormalModeKeys{
-			InsertMode: "Rune[i]",
+		FocusGuildsTree:   "Ctrl+G",
+		FocusMessagesText: "Ctrl+T",
+		FocusMessageInput: "Ctrl+P",
+		ToggleGuildsTree:  "Ctrl+B",
+
+		SelectPrevious: "Rune[k]",
+		SelectNext:     "Rune[j]",
+		SelectFirst:    "Rune[g]",
+		SelectLast:     "Rune[G]",
 
-			FocusGuildsTree:   "Ctrl+G",
-			FocusMessagesText: "Ctrl+T",
-			ToggleGuildsTree:  "Ctrl+B",
+		GuildsTree: GuildsTreeKeys{
+			SelectCurrent: "Enter",
+		},
 
-			GuildsTree: GuildsTreeNormalModeKeys{
-				SelectCurrent:  "Enter",
-				SelectPrevious: "Rune[k]",
-				SelectNext:     "Rune[j]",
-				SelectFirst:    "Rune[g]",
-				SelectLast:     "Rune[G]",
-			},
-			MessagesText: MessagesTextNormalModeKeys{
-				SelectPrevious: "Rune[k]",
-				SelectNext:     "Rune[j]",
-				SelectFirst:    "Rune[g]",
-				SelectLast:     "Rune[G]",
-				SelectReply:    "Rune[s]",
+		MessagesText: MessagesTextKeys{
+			SelectReply: "Rune[s]",
 
-				Reply:        "Rune[r]",
-				ReplyMention: "Rune[R]",
+			Reply:        "Rune[r]",
+			ReplyMention: "Rune[R]",
 
-				Delete: "Rune[d]",
-				Yank:   "Rune[y]",
-				Open:   "Rune[o]",
-			},
+			Delete: "Rune[d]",
+			Yank:   "Rune[y]",
+			Open:   "Rune[o]",
 		},
-		Insert: InsertModeKeys{
-			NormalMode: "Esc",
-			MessageInput: MessageInputInsertModeKeys{
-				Send:   "Enter",
-				Editor: "Ctrl+E",
-			},
+
+		MessageInput: MessageInputKeys{
+			Send:   "Enter",
+			Editor: "Ctrl+E",
+			Cancel: "Esc",
 		},
 	}
 }