Add bare mode and fix terminal resize bug. Fixes #48
This commit is contained in:
parent
4849ef08b8
commit
14903e0cdc
@ -43,5 +43,6 @@ type MatrixContainer interface {
|
|||||||
GetRoom(roomID string) *rooms.Room
|
GetRoom(roomID string) *rooms.Room
|
||||||
|
|
||||||
Download(mxcURL string) ([]byte, string, string, error)
|
Download(mxcURL string) ([]byte, string, string, error)
|
||||||
|
GetDownloadURL(homeserver, fileID string) string
|
||||||
GetCachePath(homeserver, fileID string) string
|
GetCachePath(homeserver, fileID string) string
|
||||||
}
|
}
|
||||||
|
@ -579,12 +579,15 @@ func (c *Container) Download(mxcURL string) (data []byte, hs, id string, err err
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Container) download(hs, id, cacheFile string) (data []byte, err error) {
|
func (c *Container) GetDownloadURL(hs, id string) string {
|
||||||
dlURL, _ := url.Parse(c.client.HomeserverURL.String())
|
dlURL, _ := url.Parse(c.client.HomeserverURL.String())
|
||||||
dlURL.Path = path.Join(dlURL.Path, "/_matrix/media/v1/download", hs, id)
|
dlURL.Path = path.Join(dlURL.Path, "/_matrix/media/v1/download", hs, id)
|
||||||
|
return dlURL.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Container) download(hs, id, cacheFile string) (data []byte, err error) {
|
||||||
var resp *http.Response
|
var resp *http.Response
|
||||||
resp, err = c.client.Client.Get(dlURL.String())
|
resp, err = c.client.Client.Get(c.GetDownloadURL(hs, id))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,7 @@ type MessageView struct {
|
|||||||
prevWidth int
|
prevWidth int
|
||||||
prevHeight int
|
prevHeight int
|
||||||
prevMsgCount int
|
prevMsgCount int
|
||||||
|
prevBareMode bool
|
||||||
|
|
||||||
messageIDs map[string]messages.UIMessage
|
messageIDs map[string]messages.UIMessage
|
||||||
messages []messages.UIMessage
|
messages []messages.UIMessage
|
||||||
@ -76,6 +77,7 @@ func NewMessageView(parent *RoomView) *MessageView {
|
|||||||
prevWidth: -1,
|
prevWidth: -1,
|
||||||
prevHeight: -1,
|
prevHeight: -1,
|
||||||
prevMsgCount: -1,
|
prevMsgCount: -1,
|
||||||
|
prevBareMode: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,9 +170,12 @@ func (view *MessageView) AddMessage(ifcMessage ifc.Message, direction ifc.Messag
|
|||||||
|
|
||||||
view.updateWidestSender(message.Sender())
|
view.updateWidestSender(message.Sender())
|
||||||
|
|
||||||
_, _, width, _ := view.GetInnerRect()
|
_, _, width, _ := view.GetRect()
|
||||||
|
bare := view.parent.parent.bareDisplay
|
||||||
|
if !bare {
|
||||||
width -= view.TimestampWidth + TimestampSenderGap + view.widestSender + SenderMessageGap
|
width -= view.TimestampWidth + TimestampSenderGap + view.widestSender + SenderMessageGap
|
||||||
message.CalculateBuffer(width)
|
}
|
||||||
|
message.CalculateBuffer(bare, width)
|
||||||
|
|
||||||
if direction == ifc.AppendMessage {
|
if direction == ifc.AppendMessage {
|
||||||
if view.ScrollOffset > 0 {
|
if view.ScrollOffset > 0 {
|
||||||
@ -258,11 +263,13 @@ func (view *MessageView) replaceBuffer(original messages.UIMessage, new messages
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (view *MessageView) recalculateBuffers() {
|
func (view *MessageView) recalculateBuffers() {
|
||||||
_, _, width, height := view.GetInnerRect()
|
_, _, width, height := view.GetRect()
|
||||||
|
bareMode := view.parent.parent.bareDisplay
|
||||||
|
if !bareMode {
|
||||||
width -= view.TimestampWidth + TimestampSenderGap + view.widestSender + SenderMessageGap
|
width -= view.TimestampWidth + TimestampSenderGap + view.widestSender + SenderMessageGap
|
||||||
recalculateMessageBuffers := width != view.prevWidth
|
}
|
||||||
if height != view.prevHeight || recalculateMessageBuffers || len(view.messages) != view.prevMsgCount {
|
recalculateMessageBuffers := width != view.prevWidth || bareMode != view.prevBareMode
|
||||||
|
if recalculateMessageBuffers || len(view.messages) != view.prevMsgCount {
|
||||||
view.textBuffer = []tstring.TString{}
|
view.textBuffer = []tstring.TString{}
|
||||||
view.metaBuffer = []ifc.MessageMeta{}
|
view.metaBuffer = []ifc.MessageMeta{}
|
||||||
view.prevMsgCount = 0
|
view.prevMsgCount = 0
|
||||||
@ -272,13 +279,14 @@ func (view *MessageView) recalculateBuffers() {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
if recalculateMessageBuffers {
|
if recalculateMessageBuffers {
|
||||||
message.CalculateBuffer(width)
|
message.CalculateBuffer(bareMode, width)
|
||||||
}
|
}
|
||||||
view.appendBuffer(message)
|
view.appendBuffer(message)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
view.prevHeight = height
|
view.prevHeight = height
|
||||||
view.prevWidth = width
|
view.prevWidth = width
|
||||||
}
|
view.prevBareMode = bareMode
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *MessageView) handleMessageClick(message ifc.MessageMeta) bool {
|
func (view *MessageView) handleMessageClick(message ifc.MessageMeta) bool {
|
||||||
@ -362,7 +370,7 @@ func (view *MessageView) HandleClick(x, y int, button tcell.ButtonMask) bool {
|
|||||||
const PaddingAtTop = 5
|
const PaddingAtTop = 5
|
||||||
|
|
||||||
func (view *MessageView) AddScrollOffset(diff int) {
|
func (view *MessageView) AddScrollOffset(diff int) {
|
||||||
_, _, _, height := view.GetInnerRect()
|
_, _, _, height := view.GetRect()
|
||||||
|
|
||||||
totalHeight := view.TotalHeight()
|
totalHeight := view.TotalHeight()
|
||||||
if diff >= 0 && view.ScrollOffset+diff >= totalHeight-height+PaddingAtTop {
|
if diff >= 0 && view.ScrollOffset+diff >= totalHeight-height+PaddingAtTop {
|
||||||
@ -380,7 +388,7 @@ func (view *MessageView) AddScrollOffset(diff int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (view *MessageView) Height() int {
|
func (view *MessageView) Height() int {
|
||||||
_, _, _, height := view.GetInnerRect()
|
_, _, _, height := view.GetRect()
|
||||||
return height
|
return height
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -389,7 +397,7 @@ func (view *MessageView) TotalHeight() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (view *MessageView) IsAtTop() bool {
|
func (view *MessageView) IsAtTop() bool {
|
||||||
_, _, _, height := view.GetInnerRect()
|
_, _, _, height := view.GetRect()
|
||||||
totalHeight := len(view.textBuffer)
|
totalHeight := len(view.textBuffer)
|
||||||
return view.ScrollOffset >= totalHeight-height+PaddingAtTop
|
return view.ScrollOffset >= totalHeight-height+PaddingAtTop
|
||||||
}
|
}
|
||||||
@ -442,14 +450,14 @@ func (view *MessageView) getIndexOffset(screen tcell.Screen, height, messageX in
|
|||||||
if view.LoadingMessages {
|
if view.LoadingMessages {
|
||||||
message = "Loading more messages..."
|
message = "Loading more messages..."
|
||||||
}
|
}
|
||||||
_, y, _, _ := view.GetInnerRect()
|
_, y, _, _ := view.GetRect()
|
||||||
widget.WriteLineSimpleColor(screen, message, messageX, y, tcell.ColorGreen)
|
widget.WriteLineSimpleColor(screen, message, messageX, y, tcell.ColorGreen)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *MessageView) Draw(screen tcell.Screen) {
|
func (view *MessageView) Draw(screen tcell.Screen) {
|
||||||
x, y, _, height := view.GetInnerRect()
|
x, y, _, height := view.GetRect()
|
||||||
view.recalculateBuffers()
|
view.recalculateBuffers()
|
||||||
|
|
||||||
if view.TotalHeight() == 0 {
|
if view.TotalHeight() == 0 {
|
||||||
@ -461,6 +469,11 @@ func (view *MessageView) Draw(screen tcell.Screen) {
|
|||||||
messageX := usernameX + view.widestSender + SenderMessageGap
|
messageX := usernameX + view.widestSender + SenderMessageGap
|
||||||
separatorX := usernameX + view.widestSender + SenderSeparatorGap
|
separatorX := usernameX + view.widestSender + SenderSeparatorGap
|
||||||
|
|
||||||
|
bareMode := view.parent.parent.bareDisplay
|
||||||
|
if bareMode {
|
||||||
|
messageX = 0
|
||||||
|
}
|
||||||
|
|
||||||
indexOffset := view.getIndexOffset(screen, height, messageX)
|
indexOffset := view.getIndexOffset(screen, height, messageX)
|
||||||
|
|
||||||
if len(view.textBuffer) != len(view.metaBuffer) {
|
if len(view.textBuffer) != len(view.metaBuffer) {
|
||||||
@ -491,14 +504,16 @@ func (view *MessageView) Draw(screen tcell.Screen) {
|
|||||||
|
|
||||||
firstLine = false
|
firstLine = false
|
||||||
|
|
||||||
|
if !bareMode {
|
||||||
screen.SetContent(separatorX, y+line, borderChar, nil, borderStyle)
|
screen.SetContent(separatorX, y+line, borderChar, nil, borderStyle)
|
||||||
|
}
|
||||||
|
|
||||||
text, meta := view.textBuffer[index], view.metaBuffer[index]
|
text, meta := view.textBuffer[index], view.metaBuffer[index]
|
||||||
if meta != prevMeta {
|
if meta != prevMeta {
|
||||||
if len(meta.FormatTime()) > 0 {
|
if len(meta.FormatTime()) > 0 {
|
||||||
widget.WriteLineSimpleColor(screen, meta.FormatTime(), x, y+line, meta.TimestampColor())
|
widget.WriteLineSimpleColor(screen, meta.FormatTime(), x, y+line, meta.TimestampColor())
|
||||||
}
|
}
|
||||||
if prevMeta == nil || meta.Sender() != prevMeta.Sender() {
|
if !bareMode && (prevMeta == nil || meta.Sender() != prevMeta.Sender()) {
|
||||||
widget.WriteLineColor(
|
widget.WriteLineColor(
|
||||||
screen, tview.AlignRight, meta.Sender(),
|
screen, tview.AlignRight, meta.Sender(),
|
||||||
usernameX, y+line, view.widestSender,
|
usernameX, y+line, view.widestSender,
|
||||||
|
@ -41,7 +41,9 @@ type BaseMessage struct {
|
|||||||
MsgIsHighlight bool
|
MsgIsHighlight bool
|
||||||
MsgIsService bool
|
MsgIsService bool
|
||||||
buffer []tstring.TString
|
buffer []tstring.TString
|
||||||
|
plainBuffer []tstring.TString
|
||||||
prevBufferWidth int
|
prevBufferWidth int
|
||||||
|
prevBareMode bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func newBaseMessage(id, sender, displayname, msgtype string, timestamp time.Time) BaseMessage {
|
func newBaseMessage(id, sender, displayname, msgtype string, timestamp time.Time) BaseMessage {
|
||||||
@ -53,6 +55,7 @@ func newBaseMessage(id, sender, displayname, msgtype string, timestamp time.Time
|
|||||||
MsgType: msgtype,
|
MsgType: msgtype,
|
||||||
MsgID: id,
|
MsgID: id,
|
||||||
prevBufferWidth: 0,
|
prevBufferWidth: 0,
|
||||||
|
prevBareMode: false,
|
||||||
MsgState: ifc.MessageStateDefault,
|
MsgState: ifc.MessageStateDefault,
|
||||||
MsgIsHighlight: false,
|
MsgIsHighlight: false,
|
||||||
MsgIsService: false,
|
MsgIsService: false,
|
||||||
|
@ -28,14 +28,14 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ExpandedTextMessage struct {
|
type ExpandedTextMessage struct {
|
||||||
BaseTextMessage
|
BaseMessage
|
||||||
MsgText tstring.TString
|
MsgText tstring.TString
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewExpandedTextMessage creates a new ExpandedTextMessage object with the provided values and the default state.
|
// NewExpandedTextMessage creates a new ExpandedTextMessage object with the provided values and the default state.
|
||||||
func NewExpandedTextMessage(id, sender, displayname, msgtype string, text tstring.TString, timestamp time.Time) UIMessage {
|
func NewExpandedTextMessage(id, sender, displayname, msgtype string, text tstring.TString, timestamp time.Time) UIMessage {
|
||||||
return &ExpandedTextMessage{
|
return &ExpandedTextMessage{
|
||||||
BaseTextMessage: newBaseTextMessage(id, sender, displayname, msgtype, timestamp),
|
BaseMessage: newBaseMessage(id, sender, displayname, msgtype, timestamp),
|
||||||
MsgText: text,
|
MsgText: text,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -48,11 +48,15 @@ func (msg *ExpandedTextMessage) NotificationContent() string {
|
|||||||
return msg.MsgText.String()
|
return msg.MsgText.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (msg *ExpandedTextMessage) CalculateBuffer(width int) {
|
func (msg *ExpandedTextMessage) PlainText() string {
|
||||||
msg.BaseTextMessage.calculateBufferWithText(msg.MsgText, width)
|
return msg.MsgText.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *ExpandedTextMessage) CalculateBuffer(bare bool, width int) {
|
||||||
|
msg.calculateBufferWithText(bare, msg.MsgText, width)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RecalculateBuffer calculates the buffer again with the previously provided width.
|
// RecalculateBuffer calculates the buffer again with the previously provided width.
|
||||||
func (msg *ExpandedTextMessage) RecalculateBuffer() {
|
func (msg *ExpandedTextMessage) RecalculateBuffer() {
|
||||||
msg.CalculateBuffer(msg.prevBufferWidth)
|
msg.CalculateBuffer(msg.prevBareMode, msg.prevBufferWidth)
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,7 @@ func init() {
|
|||||||
|
|
||||||
type ImageMessage struct {
|
type ImageMessage struct {
|
||||||
BaseMessage
|
BaseMessage
|
||||||
|
Body string
|
||||||
Homeserver string
|
Homeserver string
|
||||||
FileID string
|
FileID string
|
||||||
data []byte
|
data []byte
|
||||||
@ -45,9 +46,10 @@ type ImageMessage struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewImageMessage creates a new ImageMessage object with the provided values and the default state.
|
// NewImageMessage creates a new ImageMessage object with the provided values and the default state.
|
||||||
func NewImageMessage(matrix ifc.MatrixContainer, id, sender, displayname, msgtype, homeserver, fileID string, data []byte, timestamp time.Time) UIMessage {
|
func NewImageMessage(matrix ifc.MatrixContainer, id, sender, displayname, msgtype, body, homeserver, fileID string, data []byte, timestamp time.Time) UIMessage {
|
||||||
return &ImageMessage{
|
return &ImageMessage{
|
||||||
newBaseMessage(id, sender, displayname, msgtype, timestamp),
|
newBaseMessage(id, sender, displayname, msgtype, timestamp),
|
||||||
|
body,
|
||||||
homeserver,
|
homeserver,
|
||||||
fileID,
|
fileID,
|
||||||
data,
|
data,
|
||||||
@ -67,6 +69,10 @@ func (msg *ImageMessage) NotificationContent() string {
|
|||||||
return "Sent an image"
|
return "Sent an image"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (msg *ImageMessage) PlainText() string {
|
||||||
|
return fmt.Sprintf("%s: %s", msg.Body, msg.matrix.GetDownloadURL(msg.Homeserver, msg.FileID))
|
||||||
|
}
|
||||||
|
|
||||||
func (msg *ImageMessage) updateData() {
|
func (msg *ImageMessage) updateData() {
|
||||||
defer debug.Recover()
|
defer debug.Recover()
|
||||||
debug.Print("Loading image:", msg.Homeserver, msg.FileID)
|
debug.Print("Loading image:", msg.Homeserver, msg.FileID)
|
||||||
@ -86,11 +92,16 @@ func (msg *ImageMessage) Path() string {
|
|||||||
// CalculateBuffer generates the internal buffer for this message that consists
|
// CalculateBuffer generates the internal buffer for this message that consists
|
||||||
// of the text of this message split into lines at most as wide as the width
|
// of the text of this message split into lines at most as wide as the width
|
||||||
// parameter.
|
// parameter.
|
||||||
func (msg *ImageMessage) CalculateBuffer(width int) {
|
func (msg *ImageMessage) CalculateBuffer(bare bool, width int) {
|
||||||
if width < 2 {
|
if width < 2 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if bare {
|
||||||
|
msg.calculateBufferWithText(bare, tstring.NewTString(msg.PlainText()), width)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
image, err := ansimage.NewScaledFromReader(bytes.NewReader(msg.data), 0, width, color.Black)
|
image, err := ansimage.NewScaledFromReader(bytes.NewReader(msg.data), 0, width, color.Black)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msg.buffer = []tstring.TString{tstring.NewColorTString("Failed to display image", tcell.ColorRed)}
|
msg.buffer = []tstring.TString{tstring.NewColorTString("Failed to display image", tcell.ColorRed)}
|
||||||
@ -100,9 +111,10 @@ func (msg *ImageMessage) CalculateBuffer(width int) {
|
|||||||
|
|
||||||
msg.buffer = image.Render()
|
msg.buffer = image.Render()
|
||||||
msg.prevBufferWidth = width
|
msg.prevBufferWidth = width
|
||||||
|
msg.prevBareMode = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// RecalculateBuffer calculates the buffer again with the previously provided width.
|
// RecalculateBuffer calculates the buffer again with the previously provided width.
|
||||||
func (msg *ImageMessage) RecalculateBuffer() {
|
func (msg *ImageMessage) RecalculateBuffer() {
|
||||||
msg.CalculateBuffer(msg.prevBufferWidth)
|
msg.CalculateBuffer(msg.prevBareMode, msg.prevBufferWidth)
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ import (
|
|||||||
type UIMessage interface {
|
type UIMessage interface {
|
||||||
ifc.Message
|
ifc.Message
|
||||||
|
|
||||||
CalculateBuffer(width int)
|
CalculateBuffer(bare bool, width int)
|
||||||
RecalculateBuffer()
|
RecalculateBuffer()
|
||||||
Buffer() []tstring.TString
|
Buffer() []tstring.TString
|
||||||
Height() int
|
Height() int
|
||||||
|
@ -56,6 +56,7 @@ func ParseMessage(matrix ifc.MatrixContainer, room *rooms.Room, evt *gomatrix.Ev
|
|||||||
displayname = member.DisplayName
|
displayname = member.DisplayName
|
||||||
}
|
}
|
||||||
msgtype, _ := evt.Content["msgtype"].(string)
|
msgtype, _ := evt.Content["msgtype"].(string)
|
||||||
|
text, _ := evt.Content["body"].(string)
|
||||||
ts := unixToTime(evt.Timestamp)
|
ts := unixToTime(evt.Timestamp)
|
||||||
switch msgtype {
|
switch msgtype {
|
||||||
case "m.text", "m.notice", "m.emote":
|
case "m.text", "m.notice", "m.emote":
|
||||||
@ -64,7 +65,6 @@ func ParseMessage(matrix ifc.MatrixContainer, room *rooms.Room, evt *gomatrix.Ev
|
|||||||
text := ParseHTMLMessage(room, evt, displayname)
|
text := ParseHTMLMessage(room, evt, displayname)
|
||||||
return messages.NewExpandedTextMessage(evt.ID, evt.Sender, displayname, msgtype, text, ts)
|
return messages.NewExpandedTextMessage(evt.ID, evt.Sender, displayname, msgtype, text, ts)
|
||||||
}
|
}
|
||||||
text, _ := evt.Content["body"].(string)
|
|
||||||
text = strings.Replace(text, "\t", " ", -1)
|
text = strings.Replace(text, "\t", " ", -1)
|
||||||
return messages.NewTextMessage(evt.ID, evt.Sender, displayname, msgtype, text, ts)
|
return messages.NewTextMessage(evt.ID, evt.Sender, displayname, msgtype, text, ts)
|
||||||
case "m.image":
|
case "m.image":
|
||||||
@ -73,7 +73,7 @@ func ParseMessage(matrix ifc.MatrixContainer, room *rooms.Room, evt *gomatrix.Ev
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
debug.Printf("Failed to download %s: %v", url, err)
|
debug.Printf("Failed to download %s: %v", url, err)
|
||||||
}
|
}
|
||||||
return messages.NewImageMessage(matrix, evt.ID, evt.Sender, displayname, msgtype, hs, id, data, ts)
|
return messages.NewImageMessage(matrix, evt.ID, evt.Sender, displayname, msgtype, text, hs, id, data, ts)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -17,35 +17,26 @@
|
|||||||
package messages
|
package messages
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/gob"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"time"
|
|
||||||
|
|
||||||
"maunium.net/go/gomuks/ui/messages/tstring"
|
"maunium.net/go/gomuks/ui/messages/tstring"
|
||||||
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
|
||||||
gob.Register(BaseTextMessage{})
|
|
||||||
}
|
|
||||||
|
|
||||||
type BaseTextMessage struct {
|
|
||||||
BaseMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
func newBaseTextMessage(id, sender, displayname, msgtype string, timestamp time.Time) BaseTextMessage {
|
|
||||||
return BaseTextMessage{newBaseMessage(id, sender, displayname, msgtype, timestamp)}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Regular expressions used to split lines when calculating the buffer.
|
// Regular expressions used to split lines when calculating the buffer.
|
||||||
//
|
//
|
||||||
// From tview/textview.go
|
// From tview/textview.go
|
||||||
var (
|
var (
|
||||||
boundaryPattern = regexp.MustCompile("([[:punct:]]\\s*|\\s+)")
|
boundaryPattern = regexp.MustCompile(`([[:punct:]]\s*|\s+)`)
|
||||||
|
bareBoundaryPattern = regexp.MustCompile(`(\s+)`)
|
||||||
spacePattern = regexp.MustCompile(`\s+`)
|
spacePattern = regexp.MustCompile(`\s+`)
|
||||||
)
|
)
|
||||||
|
|
||||||
func matchBoundaryPattern(extract tstring.TString) tstring.TString {
|
func matchBoundaryPattern(bare bool, extract tstring.TString) tstring.TString {
|
||||||
matches := boundaryPattern.FindAllStringIndex(extract.String(), -1)
|
regex := boundaryPattern
|
||||||
|
if bare {
|
||||||
|
regex = bareBoundaryPattern
|
||||||
|
}
|
||||||
|
matches := regex.FindAllStringIndex(extract.String(), -1)
|
||||||
if len(matches) > 0 {
|
if len(matches) > 0 {
|
||||||
if match := matches[len(matches)-1]; len(match) >= 2 {
|
if match := matches[len(matches)-1]; len(match) >= 2 {
|
||||||
if until := match[1]; until < len(extract) {
|
if until := match[1]; until < len(extract) {
|
||||||
@ -59,13 +50,20 @@ func matchBoundaryPattern(extract tstring.TString) tstring.TString {
|
|||||||
// CalculateBuffer generates the internal buffer for this message that consists
|
// CalculateBuffer generates the internal buffer for this message that consists
|
||||||
// of the text of this message split into lines at most as wide as the width
|
// of the text of this message split into lines at most as wide as the width
|
||||||
// parameter.
|
// parameter.
|
||||||
func (msg *BaseTextMessage) calculateBufferWithText(text tstring.TString, width int) {
|
func (msg *BaseMessage) calculateBufferWithText(bare bool, text tstring.TString, width int) {
|
||||||
if width < 2 {
|
if width < 2 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
msg.buffer = []tstring.TString{}
|
msg.buffer = []tstring.TString{}
|
||||||
|
|
||||||
|
if bare {
|
||||||
|
text = tstring.
|
||||||
|
NewTString(msg.FormatTime()).
|
||||||
|
AppendTString(tstring.NewColorTString(fmt.Sprintf(" <%s> ", msg.Sender()), msg.SenderColor())).
|
||||||
|
AppendTString(text)
|
||||||
|
}
|
||||||
|
|
||||||
forcedLinebreaks := text.Split('\n')
|
forcedLinebreaks := text.Split('\n')
|
||||||
newlines := 0
|
newlines := 0
|
||||||
for _, str := range forcedLinebreaks {
|
for _, str := range forcedLinebreaks {
|
||||||
@ -82,11 +80,12 @@ func (msg *BaseTextMessage) calculateBufferWithText(text tstring.TString, width
|
|||||||
if spaces := spacePattern.FindStringIndex(str[len(extract):].String()); spaces != nil && spaces[0] == 0 {
|
if spaces := spacePattern.FindStringIndex(str[len(extract):].String()); spaces != nil && spaces[0] == 0 {
|
||||||
extract = str[:len(extract)+spaces[1]]
|
extract = str[:len(extract)+spaces[1]]
|
||||||
}
|
}
|
||||||
extract = matchBoundaryPattern(extract)
|
extract = matchBoundaryPattern(bare, extract)
|
||||||
}
|
}
|
||||||
msg.buffer = append(msg.buffer, extract)
|
msg.buffer = append(msg.buffer, extract)
|
||||||
str = str[len(extract):]
|
str = str[len(extract):]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
msg.prevBufferWidth = width
|
msg.prevBufferWidth = width
|
||||||
|
msg.prevBareMode = bare
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TextMessage struct {
|
type TextMessage struct {
|
||||||
BaseTextMessage
|
BaseMessage
|
||||||
cache tstring.TString
|
cache tstring.TString
|
||||||
MsgText string
|
MsgText string
|
||||||
}
|
}
|
||||||
@ -38,7 +38,7 @@ type TextMessage struct {
|
|||||||
// NewTextMessage creates a new UITextMessage object with the provided values and the default state.
|
// NewTextMessage creates a new UITextMessage object with the provided values and the default state.
|
||||||
func NewTextMessage(id, sender, displayname, msgtype, text string, timestamp time.Time) UIMessage {
|
func NewTextMessage(id, sender, displayname, msgtype, text string, timestamp time.Time) UIMessage {
|
||||||
return &TextMessage{
|
return &TextMessage{
|
||||||
BaseTextMessage: newBaseTextMessage(id, sender, displayname, msgtype, timestamp),
|
BaseMessage: newBaseMessage(id, sender, displayname, msgtype, timestamp),
|
||||||
MsgText: text,
|
MsgText: text,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -57,22 +57,22 @@ func (msg *TextMessage) getCache() tstring.TString {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (msg *TextMessage) SetType(msgtype string) {
|
func (msg *TextMessage) SetType(msgtype string) {
|
||||||
msg.BaseTextMessage.SetType(msgtype)
|
msg.BaseMessage.SetType(msgtype)
|
||||||
msg.cache = nil
|
msg.cache = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (msg *TextMessage) SetState(state ifc.MessageState) {
|
func (msg *TextMessage) SetState(state ifc.MessageState) {
|
||||||
msg.BaseTextMessage.SetState(state)
|
msg.BaseMessage.SetState(state)
|
||||||
msg.cache = nil
|
msg.cache = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (msg *TextMessage) SetIsHighlight(isHighlight bool) {
|
func (msg *TextMessage) SetIsHighlight(isHighlight bool) {
|
||||||
msg.BaseTextMessage.SetIsHighlight(isHighlight)
|
msg.BaseMessage.SetIsHighlight(isHighlight)
|
||||||
msg.cache = nil
|
msg.cache = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (msg *TextMessage) SetIsService(isService bool) {
|
func (msg *TextMessage) SetIsService(isService bool) {
|
||||||
msg.BaseTextMessage.SetIsService(isService)
|
msg.BaseMessage.SetIsService(isService)
|
||||||
msg.cache = nil
|
msg.cache = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,11 +80,15 @@ func (msg *TextMessage) NotificationContent() string {
|
|||||||
return msg.MsgText
|
return msg.MsgText
|
||||||
}
|
}
|
||||||
|
|
||||||
func (msg *TextMessage) CalculateBuffer(width int) {
|
func (msg *TextMessage) PlainText() string {
|
||||||
msg.BaseTextMessage.calculateBufferWithText(msg.getCache(), width)
|
return msg.MsgText
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *TextMessage) CalculateBuffer(bare bool, width int) {
|
||||||
|
msg.calculateBufferWithText(bare, msg.getCache(), width)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RecalculateBuffer calculates the buffer again with the previously provided width.
|
// RecalculateBuffer calculates the buffer again with the previously provided width.
|
||||||
func (msg *TextMessage) RecalculateBuffer() {
|
func (msg *TextMessage) RecalculateBuffer() {
|
||||||
msg.CalculateBuffer(msg.prevBufferWidth)
|
msg.CalculateBuffer(msg.prevBareMode, msg.prevBufferWidth)
|
||||||
}
|
}
|
||||||
|
@ -426,7 +426,7 @@ func (list *RoomList) GetTagDisplayName(tag string) string {
|
|||||||
func (list *RoomList) Draw(screen tcell.Screen) {
|
func (list *RoomList) Draw(screen tcell.Screen) {
|
||||||
list.Box.Draw(screen)
|
list.Box.Draw(screen)
|
||||||
|
|
||||||
x, y, width, height := list.GetInnerRect()
|
x, y, width, height := list.GetRect()
|
||||||
yLimit := y + height
|
yLimit := y + height
|
||||||
y -= list.scrollOffset
|
y -= list.scrollOffset
|
||||||
|
|
||||||
|
@ -147,18 +147,6 @@ func (view *RoomView) Focus(delegate func(p tview.Primitive)) {
|
|||||||
delegate(view.input)
|
delegate(view.input)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constants defining the size of the room view grid.
|
|
||||||
const (
|
|
||||||
UserListBorderWidth = 1
|
|
||||||
UserListWidth = 20
|
|
||||||
StaticHorizontalSpace = UserListBorderWidth + UserListWidth
|
|
||||||
|
|
||||||
TopicBarHeight = 1
|
|
||||||
StatusBarHeight = 1
|
|
||||||
InputBarHeight = 1
|
|
||||||
StaticVerticalSpace = TopicBarHeight + StatusBarHeight + InputBarHeight
|
|
||||||
)
|
|
||||||
|
|
||||||
func (view *RoomView) GetStatus() string {
|
func (view *RoomView) GetStatus() string {
|
||||||
var buf strings.Builder
|
var buf strings.Builder
|
||||||
|
|
||||||
@ -184,11 +172,23 @@ func (view *RoomView) GetStatus() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (view *RoomView) Draw(screen tcell.Screen) {
|
func (view *RoomView) Draw(screen tcell.Screen) {
|
||||||
x, y, width, height := view.GetInnerRect()
|
x, y, width, height := view.GetRect()
|
||||||
if width <= 0 || height <= 0 {
|
if width <= 0 || height <= 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Constants defining the size of the room view grid.
|
||||||
|
const (
|
||||||
|
UserListBorderWidth = 1
|
||||||
|
UserListWidth = 20
|
||||||
|
StaticHorizontalSpace = UserListBorderWidth + UserListWidth
|
||||||
|
|
||||||
|
TopicBarHeight = 1
|
||||||
|
StatusBarHeight = 1
|
||||||
|
InputBarHeight = 1
|
||||||
|
StaticVerticalSpace = TopicBarHeight + StatusBarHeight + InputBarHeight
|
||||||
|
)
|
||||||
|
|
||||||
// Calculate actual grid based on view rectangle and constants defined above.
|
// Calculate actual grid based on view rectangle and constants defined above.
|
||||||
var (
|
var (
|
||||||
contentHeight = height - StaticVerticalSpace
|
contentHeight = height - StaticVerticalSpace
|
||||||
@ -202,12 +202,15 @@ func (view *RoomView) Draw(screen tcell.Screen) {
|
|||||||
statusRow = contentRow + contentHeight
|
statusRow = contentRow + contentHeight
|
||||||
inputRow = statusRow + StatusBarHeight
|
inputRow = statusRow + StatusBarHeight
|
||||||
)
|
)
|
||||||
|
if !view.parent.ShowUserList() {
|
||||||
|
contentWidth = width
|
||||||
|
}
|
||||||
|
|
||||||
// Update the rectangles of all the children.
|
// Update the rectangles of all the children.
|
||||||
view.topic.SetRect(x, topicRow, width, TopicBarHeight)
|
view.topic.SetRect(x, topicRow, width, TopicBarHeight)
|
||||||
view.content.SetRect(x, contentRow, contentWidth, contentHeight)
|
view.content.SetRect(x, contentRow, contentWidth, contentHeight)
|
||||||
view.status.SetRect(x, statusRow, width, StatusBarHeight)
|
view.status.SetRect(x, statusRow, width, StatusBarHeight)
|
||||||
if userListColumn > x {
|
if view.parent.ShowUserList() && userListColumn > x {
|
||||||
view.userList.SetRect(userListColumn, contentRow, UserListWidth, contentHeight)
|
view.userList.SetRect(userListColumn, contentRow, UserListWidth, contentHeight)
|
||||||
view.ulBorder.SetRect(userListBorderColumn, contentRow, UserListBorderWidth, contentHeight)
|
view.ulBorder.SetRect(userListBorderColumn, contentRow, UserListBorderWidth, contentHeight)
|
||||||
}
|
}
|
||||||
@ -220,9 +223,11 @@ func (view *RoomView) Draw(screen tcell.Screen) {
|
|||||||
view.status.SetText(view.GetStatus())
|
view.status.SetText(view.GetStatus())
|
||||||
view.status.Draw(screen)
|
view.status.Draw(screen)
|
||||||
view.input.Draw(screen)
|
view.input.Draw(screen)
|
||||||
|
if view.parent.ShowUserList() {
|
||||||
view.ulBorder.Draw(screen)
|
view.ulBorder.Draw(screen)
|
||||||
view.userList.Draw(screen)
|
view.userList.Draw(screen)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (view *RoomView) SetCompletions(completions []string) {
|
func (view *RoomView) SetCompletions(completions []string) {
|
||||||
view.completions.list = completions
|
view.completions.list = completions
|
||||||
|
@ -48,6 +48,18 @@ type MainView struct {
|
|||||||
gmx ifc.Gomuks
|
gmx ifc.Gomuks
|
||||||
config *config.Config
|
config *config.Config
|
||||||
parent *GomuksUI
|
parent *GomuksUI
|
||||||
|
|
||||||
|
hideUserList bool
|
||||||
|
hideRoomList bool
|
||||||
|
bareDisplay bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (view *MainView) ShowRoomList() bool {
|
||||||
|
return !view.bareDisplay && !view.hideRoomList
|
||||||
|
}
|
||||||
|
|
||||||
|
func (view *MainView) ShowUserList() bool {
|
||||||
|
return !view.bareDisplay && !view.hideUserList
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ui *GomuksUI) NewMainView() tview.Primitive {
|
func (ui *GomuksUI) NewMainView() tview.Primitive {
|
||||||
@ -63,10 +75,11 @@ func (ui *GomuksUI) NewMainView() tview.Primitive {
|
|||||||
parent: ui,
|
parent: ui,
|
||||||
}
|
}
|
||||||
|
|
||||||
mainView.SetDirection(tview.FlexColumn)
|
mainView.
|
||||||
mainView.AddItem(mainView.roomList, 25, 0, false)
|
SetDirection(tview.FlexColumn).
|
||||||
mainView.AddItem(widget.NewBorder(), 1, 0, false)
|
AddItem(mainView.roomList, 25, 0, false).
|
||||||
mainView.AddItem(mainView.roomView, 0, 1, true)
|
AddItem(widget.NewBorder(), 1, 0, false).
|
||||||
|
AddItem(mainView.roomView, 0, 1, true)
|
||||||
mainView.BumpFocus(nil)
|
mainView.BumpFocus(nil)
|
||||||
|
|
||||||
ui.mainView = mainView
|
ui.mainView = mainView
|
||||||
@ -74,6 +87,15 @@ func (ui *GomuksUI) NewMainView() tview.Primitive {
|
|||||||
return mainView
|
return mainView
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (view *MainView) Draw(screen tcell.Screen) {
|
||||||
|
if !view.ShowRoomList() {
|
||||||
|
view.roomView.SetRect(view.GetRect())
|
||||||
|
view.roomView.Draw(screen)
|
||||||
|
} else {
|
||||||
|
view.Flex.Draw(screen)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (view *MainView) BumpFocus(roomView *RoomView) {
|
func (view *MainView) BumpFocus(roomView *RoomView) {
|
||||||
view.lastFocusTime = time.Now()
|
view.lastFocusTime = time.Now()
|
||||||
view.MarkRead(roomView)
|
view.MarkRead(roomView)
|
||||||
@ -195,16 +217,20 @@ func (view *MainView) KeyEventHandler(roomView *RoomView, key *tcell.EventKey) *
|
|||||||
view.BumpFocus(roomView)
|
view.BumpFocus(roomView)
|
||||||
|
|
||||||
k := key.Key()
|
k := key.Key()
|
||||||
|
c := key.Rune()
|
||||||
if key.Modifiers() == tcell.ModCtrl || key.Modifiers() == tcell.ModAlt {
|
if key.Modifiers() == tcell.ModCtrl || key.Modifiers() == tcell.ModAlt {
|
||||||
switch k {
|
switch {
|
||||||
case tcell.KeyDown:
|
case k == tcell.KeyDown:
|
||||||
view.SwitchRoom(view.roomList.Next())
|
view.SwitchRoom(view.roomList.Next())
|
||||||
case tcell.KeyUp:
|
case k == tcell.KeyUp:
|
||||||
view.SwitchRoom(view.roomList.Previous())
|
view.SwitchRoom(view.roomList.Previous())
|
||||||
case tcell.KeyEnter:
|
case k == tcell.KeyEnter:
|
||||||
searchModal := NewFuzzySearchModal(view, 42, 12)
|
searchModal := NewFuzzySearchModal(view, 42, 12)
|
||||||
view.parent.views.AddPage("fuzzy-search-modal", searchModal, true, true)
|
view.parent.views.AddPage("fuzzy-search-modal", searchModal, true, true)
|
||||||
view.parent.app.SetFocus(searchModal)
|
view.parent.app.SetFocus(searchModal)
|
||||||
|
case c == 'l':
|
||||||
|
view.bareDisplay = !view.bareDisplay
|
||||||
|
view.parent.Render()
|
||||||
default:
|
default:
|
||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user