From a7305881e78ea1cdf5536cfc30cd5dd7ed3fb568 Mon Sep 17 00:00:00 2001 From: Rasmus Lindroth Date: Sat, 31 Dec 2022 14:05:23 +0100 Subject: [PATCH] 1.0.32 (#240) * bump version * add ws and bug fix for conversations * fix so autocomplete works with new version of tview * fix poll and url length --- api/feed.go | 7 +++++-- api/instance.go | 45 ++++++++++++++++++++++++++++++++++++++++ api/status.go | 21 ++++++++++++++++--- api/stream.go | 14 ++++++------- api/types.go | 10 +++++---- config.example.ini | 4 ---- config/config.go | 2 -- config/default_config.go | 4 ---- docs/man/tut.1 | 2 +- docs/man/tut.1.md | 4 ++-- docs/man/tut.5 | 10 +-------- docs/man/tut.5.md | 8 ++----- docs/man/tut.7 | 2 +- docs/man/tut.7.md | 4 ++-- feed/feed.go | 26 +++++++++++++++++++++++ go.mod | 7 ++++--- go.sum | 26 ++++++++++++++--------- main.go | 2 +- ui/cmdbar.go | 9 ++++++++ ui/composeview.go | 21 ++++++++++++++++++- ui/input.go | 13 +++++++++--- ui/item_status.go | 28 ++++++++++++++++++------- ui/pollview.go | 13 ++++++++---- ui/tutview.go | 21 ++++++++++++++----- 24 files changed, 222 insertions(+), 81 deletions(-) create mode 100644 api/instance.go diff --git a/api/feed.go b/api/feed.go index ce5a756..79f8eca 100644 --- a/api/feed.go +++ b/api/feed.go @@ -154,6 +154,9 @@ func (ac *AccountClient) GetConversations(pg *mastodon.Pagination) ([]Item, erro return items, err } for _, c := range conversations { + if c.LastStatus == nil { + continue + } item := NewStatusItem(c.LastStatus, false) items = append(items, item) } @@ -165,10 +168,10 @@ func (ac *AccountClient) GetUsers(search string) ([]Item, error) { var users []*mastodon.Account var err error if strings.HasPrefix(search, "@") && len(strings.Split(search, "@")) == 3 { - users, err = ac.Client.AccountsSearch(context.Background(), search, 10, true) + users, err = ac.Client.AccountsSearchResolve(context.Background(), search, 10, true) } if len(users) == 0 || err != nil { - users, err = ac.Client.AccountsSearch(context.Background(), search, 10, false) + users, err = ac.Client.AccountsSearchResolve(context.Background(), search, 10, false) } if err != nil { return items, err diff --git a/api/instance.go b/api/instance.go new file mode 100644 index 0000000..b9414dd --- /dev/null +++ b/api/instance.go @@ -0,0 +1,45 @@ +package api + +func (ac *AccountClient) GetCharLimit() int { + if ac.Instance != nil { + return ac.Instance.Configuration.Statuses.MaxCharacters + } + if ac.InstanceOld == nil || ac.InstanceOld.Configuration == nil || ac.InstanceOld.Configuration.Statuses == nil { + return 500 + } + s := ac.InstanceOld.Configuration.Statuses + if val, ok := (*s)["max_characters"]; ok { + return val + } + return 500 +} + +func (ac *AccountClient) GetLengthURL() int { + if ac.Instance != nil { + return ac.Instance.Configuration.Statuses.CharactersReservedPerURL + } + if ac.InstanceOld == nil || ac.InstanceOld.Configuration == nil || ac.InstanceOld.Configuration.Statuses == nil { + return 23 + } + s := ac.InstanceOld.Configuration.Statuses + if val, ok := (*s)["characters_reserved_per_url"]; ok { + return val + } + return 23 +} + +func (ac *AccountClient) GetPollOptions() (options, chars int) { + if ac.Instance != nil { + return ac.Instance.Configuration.Polls.MaxOptions, ac.Instance.Configuration.Polls.MaxCharactersPerOption + } + if ac.InstanceOld == nil || ac.InstanceOld.Configuration == nil || ac.InstanceOld.Configuration.Polls == nil { + return 4, 50 + } + s := ac.InstanceOld.Configuration.Polls + opts, okOne := (*s)["max_options"] + c, okTwo := (*s)["max_characters_per_option"] + if okOne && okTwo { + return opts, c + } + return 4, 50 +} diff --git a/api/status.go b/api/status.go index 925f5ca..7ca8515 100644 --- a/api/status.go +++ b/api/status.go @@ -39,8 +39,13 @@ func toggleHelper(s *mastodon.Status, comp bool, on, off statusToggleFunc) (*mas } func (ac *AccountClient) BoostToggle(s *mastodon.Status) (*mastodon.Status, error) { + ns := util.StatusOrReblog(s) + reblogged := false + if ns.Reblogged != nil { + reblogged = ns.Reblogged.(bool) + } return toggleHelper(s, - util.StatusOrReblog(s).Reblogged, + reblogged, ac.Boost, ac.Unboost, ) } @@ -54,8 +59,13 @@ func (ac *AccountClient) Unboost(s *mastodon.Status) (*mastodon.Status, error) { } func (ac *AccountClient) FavoriteToogle(s *mastodon.Status) (*mastodon.Status, error) { + ns := util.StatusOrReblog(s) + favorited := false + if ns.Favourited != nil { + favorited = ns.Favourited.(bool) + } return toggleHelper(s, - util.StatusOrReblog(s).Favourited, + favorited, ac.Favorite, ac.Unfavorite, ) } @@ -71,8 +81,13 @@ func (ac *AccountClient) Unfavorite(s *mastodon.Status) (*mastodon.Status, error } func (ac *AccountClient) BookmarkToogle(s *mastodon.Status) (*mastodon.Status, error) { + ns := util.StatusOrReblog(s) + bookmarked := false + if ns.Bookmarked != nil { + bookmarked = ns.Bookmarked.(bool) + } return toggleHelper(s, - util.StatusOrReblog(s).Bookmarked, + bookmarked, ac.Bookmark, ac.Unbookmark, ) } diff --git a/api/stream.go b/api/stream.go index 545f3f0..01e2ecd 100644 --- a/api/stream.go +++ b/api/stream.go @@ -81,7 +81,7 @@ func (s *Stream) RemoveReceiver(r *Receiver) { func (s *Stream) listen() { for e := range s.incoming { switch e.(type) { - case *mastodon.UpdateEvent, *mastodon.NotificationEvent, *mastodon.DeleteEvent, *mastodon.ErrorEvent: + case *mastodon.UpdateEvent, *mastodon.ConversationEvent, *mastodon.NotificationEvent, *mastodon.DeleteEvent, *mastodon.ErrorEvent: for _, r := range s.receivers { go func(rec *Receiver, e mastodon.Event) { rec.mux.Lock() @@ -133,17 +133,17 @@ func (ac *AccountClient) NewGenericStream(st StreamType, data string) (rec *Rece var ch chan mastodon.Event switch st { case HomeStream: - ch, err = ac.Client.StreamingUser(context.Background()) + ch, err = ac.WSClient.StreamingWSUser(context.Background()) case LocalStream: - ch, err = ac.Client.StreamingPublic(context.Background(), true) + ch, err = ac.WSClient.StreamingWSPublic(context.Background(), true) case FederatedStream: - ch, err = ac.Client.StreamingPublic(context.Background(), false) + ch, err = ac.WSClient.StreamingWSPublic(context.Background(), false) case DirectStream: - ch, err = ac.Client.StreamingDirect(context.Background()) + ch, err = ac.WSClient.StreamingWSDirect(context.Background()) case TagStream: - ch, err = ac.Client.StreamingHashtag(context.Background(), data, false) + ch, err = ac.WSClient.StreamingWSHashtag(context.Background(), data, false) case ListStream: - ch, err = ac.Client.StreamingList(context.Background(), mastodon.ID(data)) + ch, err = ac.WSClient.StreamingWSList(context.Background(), mastodon.ID(data)) default: panic("invalid StreamType") } diff --git a/api/types.go b/api/types.go index 0752ab4..a969ff8 100644 --- a/api/types.go +++ b/api/types.go @@ -8,10 +8,12 @@ type RequestData struct { } type AccountClient struct { - Client *mastodon.Client - Streams map[string]*Stream - Me *mastodon.Account - Filters []*mastodon.Filter + Client *mastodon.Client + Streams map[string]*Stream + Me *mastodon.Account + WSClient *mastodon.WSClient + InstanceOld *mastodon.Instance + Instance *mastodon.InstanceV2 } type User struct { diff --git a/config.example.ini b/config.example.ini index 36e892d..96cfb9c 100644 --- a/config.example.ini +++ b/config.example.ini @@ -110,10 +110,6 @@ notifications-to-hide= # default=false quote-reply=false -# If you're on an instance with a custom character limit you can set it here. -# default=500 -char-limit=500 - # If you want to show icons in the list of toots. # default=true show-icons=true diff --git a/config/config.go b/config/config.go index af8ac16..ea08cc6 100644 --- a/config/config.go +++ b/config/config.go @@ -158,7 +158,6 @@ type General struct { MaxWidth int NotificationFeed bool QuoteReply bool - CharLimit int ShortHints bool ShowFilterPhrase bool ListPlacement ListPlacement @@ -848,7 +847,6 @@ func parseGeneral(cfg *ini.File) General { general.NotificationFeed = cfg.Section("general").Key("notification-feed").MustBool(true) general.QuoteReply = cfg.Section("general").Key("quote-reply").MustBool(false) - general.CharLimit = cfg.Section("general").Key("char-limit").MustInt(500) general.MaxWidth = cfg.Section("general").Key("max-width").MustInt(0) general.ShortHints = cfg.Section("general").Key("short-hints").MustBool(false) general.ShowFilterPhrase = cfg.Section("general").Key("show-filter-phrase").MustBool(true) diff --git a/config/default_config.go b/config/default_config.go index 40d586c..88962dc 100644 --- a/config/default_config.go +++ b/config/default_config.go @@ -112,10 +112,6 @@ notifications-to-hide= # default=false quote-reply=false -# If you're on an instance with a custom character limit you can set it here. -# default=500 -char-limit=500 - # If you want to show icons in the list of toots. # default=true show-icons=true diff --git a/docs/man/tut.1 b/docs/man/tut.1 index 011f827..6f3cbda 100644 --- a/docs/man/tut.1 +++ b/docs/man/tut.1 @@ -14,7 +14,7 @@ . ftr VB CB . ftr VBI CBI .\} -.TH "tut" "1" "2022-12-29" "tut 1.0.31" "" +.TH "tut" "1" "2022-12-31" "tut 1.0.32" "" .hy .SH NAME .PP diff --git a/docs/man/tut.1.md b/docs/man/tut.1.md index 826df9e..fae5dcc 100644 --- a/docs/man/tut.1.md +++ b/docs/man/tut.1.md @@ -1,6 +1,6 @@ -% tut(1) tut 1.0.31 +% tut(1) tut 1.0.32 % Rasmus Lindroth -% 2022-12-29 +% 2022-12-31 # NAME tut - a Mastodon TUI diff --git a/docs/man/tut.5 b/docs/man/tut.5 index 6b1a6ec..09da0c7 100644 --- a/docs/man/tut.5 +++ b/docs/man/tut.5 @@ -14,7 +14,7 @@ . ftr VB CB . ftr VBI CBI .\} -.TH "tut" "5" "2022-12-29" "tut 1.0.31" "" +.TH "tut" "5" "2022-12-31" "tut 1.0.32" "" .hy .SH NAME .PP @@ -231,14 +231,6 @@ If you always want to quote original message when replying. .P .PD \f[B]quote-reply\f[R]=\f[I]false\f[R] -.SS char-limit -.PP -If you\[aq]re on an instance with a custom character limit you can set -it here. -.PD 0 -.P -.PD -\f[B]char-limit\f[R]=\f[I]500\f[R] .SS show-icons .PP If you want to show icons in the list of toots. diff --git a/docs/man/tut.5.md b/docs/man/tut.5.md index 64fd54c..1176d8d 100644 --- a/docs/man/tut.5.md +++ b/docs/man/tut.5.md @@ -1,6 +1,6 @@ -% tut(5) tut 1.0.31 +% tut(5) tut 1.0.32 % Rasmus Lindroth -% 2022-12-29 +% 2022-12-31 # NAME tut - configuration for tut(1) @@ -116,10 +116,6 @@ Hide notifications of this type. If you have multiple you separate them with a c If you always want to quote original message when replying. **quote-reply**=*false* -## char-limit -If you\'re on an instance with a custom character limit you can set it here. -**char-limit**=*500* - ## show-icons If you want to show icons in the list of toots. **show-icons**=*true* diff --git a/docs/man/tut.7 b/docs/man/tut.7 index d573f9d..d75664b 100644 --- a/docs/man/tut.7 +++ b/docs/man/tut.7 @@ -14,7 +14,7 @@ . ftr VB CB . ftr VBI CBI .\} -.TH "tut" "7" "2022-12-29" "tut 1.0.31" "" +.TH "tut" "7" "2022-12-31" "tut 1.0.32" "" .hy .SH NAME .PP diff --git a/docs/man/tut.7.md b/docs/man/tut.7.md index 2d69015..5d56bf7 100644 --- a/docs/man/tut.7.md +++ b/docs/man/tut.7.md @@ -1,6 +1,6 @@ -% tut(7) tut 1.0.31 +% tut(7) tut 1.0.32 % Rasmus Lindroth -% 2022-12-29 +% 2022-12-31 # NAME tut - keys and commands inside of tut(1) diff --git a/feed/feed.go b/feed/feed.go index a3a55f7..b83c7ad 100644 --- a/feed/feed.go +++ b/feed/feed.go @@ -694,6 +694,32 @@ func (f *Feed) startStream(rec *api.Receiver, timeline string, err error) { go func() { for e := range rec.Ch { switch t := e.(type) { + case *mastodon.ConversationEvent: + if t.Conversation.LastStatus == nil { + continue + } + s := api.NewStatusItem(t.Conversation.LastStatus, false) + f.itemsMux.Lock() + found := false + if len(f.streams) > 0 { + for _, item := range f.items { + switch v := item.Raw().(type) { + case *mastodon.Status: + if t.Conversation.LastStatus.ID == v.ID { + found = true + break + } + } + } + } + if !found { + f.items = append([]api.Item{s}, f.items...) + f.Updated(DesktopNotificationHolder{ + Type: DesktopNotificationMention, + }) + f.apiData.MinID = t.Conversation.LastStatus.ID + } + f.itemsMux.Unlock() case *mastodon.UpdateEvent: s := api.NewStatusItem(t.Status, false) f.itemsMux.Lock() diff --git a/go.mod b/go.mod index f7bff96..22a4e9f 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/RasmusLindroth/tut go 1.18 require ( - github.com/RasmusLindroth/go-mastodon v0.0.17 + github.com/RasmusLindroth/go-mastodon v0.0.20 github.com/adrg/xdg v0.4.0 github.com/atotto/clipboard v0.1.4 github.com/gdamore/tcell/v2 v2.5.3 @@ -12,12 +12,13 @@ require ( github.com/icza/gox v0.0.0-20221026131554-a08a8cdc726a github.com/microcosm-cc/bluemonday v1.0.21 github.com/pelletier/go-toml/v2 v2.0.6 - github.com/rivo/tview v0.0.0-20221221172820-02e38ea9604c + github.com/rivo/tview v0.0.0-20221229180733-b86a50a5126c github.com/rivo/uniseg v0.4.3 github.com/spf13/pflag v1.0.5 - golang.org/x/exp v0.0.0-20221227203929-1b447090c38c + golang.org/x/exp v0.0.0-20221230185412-738e83a70c30 golang.org/x/net v0.4.0 gopkg.in/ini.v1 v1.67.0 + mvdan.cc/xurls/v2 v2.4.0 ) require ( diff --git a/go.sum b/go.sum index 249a456..985a543 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/RasmusLindroth/go-mastodon v0.0.17 h1:PUR4YS9ORe62ZSabvZVwxROZvrcMuNVC/8Y/D/d6dFQ= -github.com/RasmusLindroth/go-mastodon v0.0.17/go.mod h1:Lr6n8V1U2b+9P89YZKsICkNc+oNeJXkygY7raei9SXE= +github.com/RasmusLindroth/go-mastodon v0.0.20 h1:xnFiSV7DfMCF8VOEn6QVbk94bGXxxAiUlw3Grby6ofw= +github.com/RasmusLindroth/go-mastodon v0.0.20/go.mod h1:Lr6n8V1U2b+9P89YZKsICkNc+oNeJXkygY7raei9SXE= github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls= github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E= github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= @@ -27,6 +27,9 @@ github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWm github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/icza/gox v0.0.0-20221026131554-a08a8cdc726a h1:ctOSka++0Y+9xF7VLtZ8TOJjyXjOGYywzuhbzj3IEHw= github.com/icza/gox v0.0.0-20221026131554-a08a8cdc726a/go.mod h1:VbcN86fRkkUMPX2ufM85Um8zFndLZswoIW1eYtpAcVk= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= @@ -38,15 +41,15 @@ github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/ github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rivo/tview v0.0.0-20221217182043-ccce554c3803 h1:gaknGRzW4g4I+5sGu4X81BZbROJ0j96ap9xnEbcZhXA= -github.com/rivo/tview v0.0.0-20221217182043-ccce554c3803/go.mod h1:YX2wUZOcJGOIycErz2s9KvDaP0jnWwRCirQMPLPpQ+Y= -github.com/rivo/tview v0.0.0-20221221172820-02e38ea9604c h1:Y4GSXEYKYAtguH10lmQmYb7hRkJ7U+m8GvnFHKU2jrk= -github.com/rivo/tview v0.0.0-20221221172820-02e38ea9604c/go.mod h1:lBUy/T5kyMudFzWUH/C2moN+NlU5qF505vzOyINXuUQ= +github.com/rivo/tview v0.0.0-20221229180733-b86a50a5126c h1:Xa0IDAwI/b4D3AQwFOhvOeYB/H0N8Bhhe3XJWSa2vjg= +github.com/rivo/tview v0.0.0-20221229180733-b86a50a5126c/go.mod h1:lBUy/T5kyMudFzWUH/C2moN+NlU5qF505vzOyINXuUQ= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw= github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -61,12 +64,11 @@ github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af h1:6yITBqGTE2lEeTPG0 github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af/go.mod h1:4F09kP5F+am0jAwlQLddpoMDM+iewkxxt6nxUQ5nq5o= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE= -golang.org/x/exp v0.0.0-20221217163422-3c43f8badb15 h1:5oN1Pz/eDhCpbMbLstvIPa0b/BEQo6g6nwV3pLjfM6w= -golang.org/x/exp v0.0.0-20221217163422-3c43f8badb15/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= -golang.org/x/exp v0.0.0-20221227203929-1b447090c38c h1:Govq2W3bnHJimHT2ium65kXcI7ZzTniZHcFATnLJM0Q= -golang.org/x/exp v0.0.0-20221227203929-1b447090c38c/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/exp v0.0.0-20221230185412-738e83a70c30 h1:m9O6OTJ627iFnN2JIWfdqlZCzneRO6EEBsHXI25P8ws= +golang.org/x/exp v0.0.0-20221230185412-738e83a70c30/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220318055525-2edf467146b5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -82,8 +84,12 @@ golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +mvdan.cc/xurls/v2 v2.4.0 h1:tzxjVAj+wSBmDcF6zBB7/myTy3gX9xvi8Tyr28AuQgc= +mvdan.cc/xurls/v2 v2.4.0/go.mod h1:+GEjq9uNjqs8LQfM9nVnM8rff0OQ5Iash5rzX+N1CSg= diff --git a/main.go b/main.go index c9fe4e6..4d98fb7 100644 --- a/main.go +++ b/main.go @@ -8,7 +8,7 @@ import ( "github.com/rivo/tview" ) -const version = "1.0.31" +const version = "1.0.32" func main() { util.SetTerminalTitle("tut") diff --git a/ui/cmdbar.go b/ui/cmdbar.go index 19b17ea..65e7156 100644 --- a/ui/cmdbar.go +++ b/ui/cmdbar.go @@ -19,6 +19,7 @@ func NewCmdBar(tv *TutView) *CmdBar { View: NewInputField(tv.tut.Config), } c.View.SetAutocompleteFunc(c.Autocomplete) + c.View.SetAutocompletedFunc(c.Autocompleted) c.View.SetDoneFunc(c.DoneFunc) return c @@ -313,3 +314,11 @@ func (c *CmdBar) Autocomplete(curr string) []string { } return entries } + +func (c *CmdBar) Autocompleted(text string, index, source int) bool { + if source != tview.AutocompletedNavigate { + c.View.SetText(text) + } + + return source == tview.AutocompletedEnter || source == tview.AutocompletedClick +} diff --git a/ui/composeview.go b/ui/composeview.go index 990870b..fc92dcc 100644 --- a/ui/composeview.go +++ b/ui/composeview.go @@ -15,6 +15,7 @@ import ( "github.com/gdamore/tcell/v2" "github.com/rivo/tview" "github.com/rivo/uniseg" + "mvdan.cc/xurls/v2" ) type msgToot struct { @@ -102,15 +103,33 @@ const ( ComposeMedia ) +func urlsInText(txt string) (count, length int) { + x := xurls.Strict() + matches := x.FindAllString(txt, -1) + count = len(matches) + for _, m := range matches { + length += len(m) + } + return +} + func (cv *ComposeView) msgLength() int { m := cv.msg charCount := uniseg.GraphemeClusterCount(m.Text) spoilerCount := uniseg.GraphemeClusterCount(m.CWText) totalCount := charCount + urlLength := cv.tutView.tut.Client.GetLengthURL() + + urls, length := urlsInText(m.Text) + if urls > 0 { + totalCount = totalCount - length + totalCount = totalCount + (urls * urlLength) + } + if m.Sensitive { totalCount += spoilerCount } - charsLeft := cv.tutView.tut.Config.General.CharLimit - totalCount + charsLeft := cv.tutView.tut.Client.GetCharLimit() - totalCount return charsLeft } diff --git a/ui/input.go b/ui/input.go index 9698b96..caad577 100644 --- a/ui/input.go +++ b/ui/input.go @@ -381,9 +381,16 @@ func (tv *TutView) InputStatus(event *tcell.EventKey, item api.Item, status *mas hasSpoiler := sr.Sensitive isMine := sr.Account.ID == tv.tut.Client.Me.ID - boosted := sr.Reblogged - favorited := sr.Favourited - bookmarked := sr.Bookmarked + boosted, favorited, bookmarked := false, false, false + if sr.Reblogged != nil { + boosted = sr.Reblogged.(bool) + } + if sr.Favourited != nil { + favorited = sr.Favourited.(bool) + } + if sr.Bookmarked != nil { + bookmarked = sr.Bookmarked.(bool) + } if tv.tut.Config.Input.StatusAvatar.Match(event.Key(), event.Rune()) { if nAcc != nil { diff --git a/ui/item_status.go b/ui/item_status.go index 411cdf2..b66e224 100644 --- a/ui/item_status.go +++ b/ui/item_status.go @@ -124,7 +124,10 @@ func drawStatus(tv *TutView, item api.Item, status *mastodon.Status, main *tview toot.AccountDisplayName = tview.Escape(status.Account.DisplayName) toot.Account = tview.Escape(status.Account.Acct) - toot.Bookmarked = status.Bookmarked + toot.Bookmarked = false + if status.Bookmarked != nil { + toot.Bookmarked = status.Bookmarked.(bool) + } toot.Visibility = status.Visibility toot.Spoiler = status.Sensitive toot.Edited = status.CreatedAt.Before(status.EditedAt) @@ -198,14 +201,25 @@ func drawStatus(tv *TutView, item api.Item, status *mastodon.Status, main *tview } var info []Control - if status.Favourited && !isHistory { + statusFavorited, statusBoosted, statusBookmarked := false, false, false + if status.Favourited != nil { + statusFavorited = status.Favourited.(bool) + } + if status.Reblogged != nil { + statusBoosted = status.Reblogged.(bool) + } + if status.Bookmarked != nil { + statusBookmarked = status.Bookmarked.(bool) + } + + if statusFavorited && !isHistory { info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusFavorite, false)) - } else if !status.Favourited && !isHistory { + } else if !statusFavorited && !isHistory { info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusFavorite, true)) } - if status.Reblogged && !isHistory { + if statusBoosted && !isHistory { info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusBoost, false)) - } else if !status.Reblogged && !isHistory { + } else if !statusBoosted && !isHistory { info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusBoost, true)) } if !isHistory { @@ -229,9 +243,9 @@ func drawStatus(tv *TutView, item api.Item, status *mastodon.Status, main *tview info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusDelete, true)) } - if !status.Bookmarked && !isHistory { + if !statusBookmarked && !isHistory { info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusBookmark, true)) - } else if status.Bookmarked && !isHistory { + } else if statusBookmarked && !isHistory { info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusBookmark, false)) } if !isHistory { diff --git a/ui/pollview.go b/ui/pollview.go index 4ad3294..ede9ce8 100644 --- a/ui/pollview.go +++ b/ui/pollview.go @@ -38,9 +38,12 @@ type PollView struct { list *tview.List poll *mastodon.TootPoll scrollSleep *scrollSleep + numOptions int + numChars int } func NewPollView(tv *TutView) *PollView { + options, chars := tv.tut.Client.GetPollOptions() p := &PollView{ tutView: tv, shared: tv.Shared, @@ -48,6 +51,8 @@ func NewPollView(tv *TutView) *PollView { expiration: NewDropDown(tv.tut.Config), controls: NewControlView(tv.tut.Config), list: NewList(tv.tut.Config), + numOptions: options, + numChars: chars, } p.scrollSleep = NewScrollSleep(p.Next, p.Prev) p.Reset() @@ -157,11 +162,11 @@ func (p *PollView) Next() { } func (p *PollView) Add() { - if p.list.GetItemCount() > 3 { - p.tutView.ShowError("You can only have a maximum of 4 options.") + if p.list.GetItemCount() > p.numOptions-1 { + p.tutView.ShowError(fmt.Sprintf("You can only have a maximum of %d options.", p.numOptions)) return } - text, valid, err := OpenEditorLengthLimit(p.tutView, "", 25) + text, valid, err := OpenEditorLengthLimit(p.tutView, "", p.numChars) if err != nil { p.tutView.ShowError( fmt.Sprintf("Couldn't open editor. Error: %v", err), @@ -182,7 +187,7 @@ func (p *PollView) Edit() { return } text, _ := p.list.GetItemText(p.list.GetCurrentItem()) - text, valid, err := OpenEditorLengthLimit(p.tutView, text, 25) + text, valid, err := OpenEditorLengthLimit(p.tutView, text, p.numChars) if err != nil { p.tutView.ShowError( fmt.Sprintf("Couldn't open editor. Error: %v", err), diff --git a/ui/tutview.go b/ui/tutview.go index 3c46e3b..06e390e 100644 --- a/ui/tutview.go +++ b/ui/tutview.go @@ -151,12 +151,23 @@ func (tv *TutView) loggedIn(acc auth.Account) { tv.tut.App.Stop() tv.CleanExit(1) } - filters, _ := client.GetFilters(context.Background()) ac := &api.AccountClient{ - Me: me, - Client: client, - Streams: make(map[string]*api.Stream), - Filters: filters, + Me: me, + Client: client, + Streams: make(map[string]*api.Stream), + WSClient: client.NewWSClient(), + } + inst, err := ac.Client.GetInstanceV2(context.Background()) + if err != nil { + inst, err := ac.Client.GetInstance(context.Background()) + if err != nil { + fmt.Printf("Couldn't get instance. Error %s\n", err) + tv.tut.App.Stop() + tv.CleanExit(1) + } + ac.InstanceOld = inst + } else { + ac.Instance = inst } tv.tut.Client = ac