Browse Source

1.0.11 (#152)

* fix filters and add sticky

* upgrade packages

* update version

* Input user on original user, not reblog

* update example config

* update readme
pull/156/head 1.0.11
Rasmus Lindroth 4 years ago committed by GitHub
parent
commit
9b7aaa3a35
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 9
      README.md
  2. 52
      api/feed.go
  3. 68
      api/item.go
  4. 10
      config.example.ini
  5. 6
      config/config.go
  6. 10
      config/default_config.go
  7. 34
      feed/feed.go
  8. 6
      go.mod
  9. 12
      go.sum
  10. BIN
      images/preview2.png
  11. 2
      main.go
  12. 2
      ui/cliview.go
  13. 46
      ui/feed.go
  14. 4
      ui/input.go
  15. 11
      ui/item.go
  16. 18
      ui/item_status.go

9
README.md

@ -1,4 +1,9 @@
# Tut - a Mastodon TUI
[![Release](https://badgen.net/github/release/RasmusLindroth/tut)](https://github.com/RasmusLindroth/tut/releases)
[![web](https://badgen.net/badge/web/tut.anv.nu/f92672)](https://tut.anv.nu)
[![tut](https://badgen.net/badge/AUR/tut/08c)](https://aur.archlinux.org/packages/tut)
[![tut-bin](https://badgen.net/badge/AUR/tut-bin/08c)](https://aur.archlinux.org/packages/tut-bin)
[![@tut](https://badgen.net/mastodon/follow/tut@fosstodon.org)](https://fosstodon.org/@tut)
A TUI for Mastodon with vim inspired keys. The program has most of the
features you can find in the web client.
@ -8,6 +13,7 @@ Press `C` to create a new toot and `N` to focus on your notifications.
You can find Linux binaries under [releases](https://github.com/RasmusLindroth/tut/releases).
![Preview](./images/preview.png "Preview")
![Preview 2](./images/preview2.png "Preview 2")
## Table of contents
@ -85,6 +91,7 @@ Head over to https://github.com/RasmusLindroth/tut/releases
You can find it in the Arch User Repository (AUR). I'm the maintainer there.
https://aur.archlinux.org/packages/tut/
https://aur.archlinux.org/packages/tut-bin/
You can also use `tut-mastodon`. Currently `aur/tut` collides with a package
named `tut` if you're running Manjaro ARM. So if you face the same problem you
@ -127,7 +134,7 @@ cd tut
# Build or install
# Install (usally /home/user/go/bin)
# Install (usually /home/user/go/bin)
go install
# Build (same directory i.e. ./ )

52
api/feed.go

@ -15,11 +15,9 @@ func (ac *AccountClient) getStatusSimilar(fn func() ([]*mastodon.Status, error),
return items, err
}
for _, s := range statuses {
item, filtered := NewStatusItem(s, ac.Filters, filter)
if !filtered {
item := NewStatusItem(s, ac.Filters, filter, false)
items = append(items, item)
}
}
return items, nil
}
@ -89,12 +87,10 @@ func (ac *AccountClient) GetNotifications(pg *mastodon.Pagination) ([]Item, erro
for _, n := range notifications {
for _, r := range rel {
if n.Account.ID == r.ID {
item, filtered := NewNotificationItem(n, &User{
item := NewNotificationItem(n, &User{
Data: &n.Account, Relation: r,
}, ac.Filters)
if !filtered {
items = append(items, item)
}
break
}
}
@ -102,29 +98,20 @@ func (ac *AccountClient) GetNotifications(pg *mastodon.Pagination) ([]Item, erro
return items, nil
}
func (ac *AccountClient) GetThread(status *mastodon.Status) ([]Item, int, error) {
func (ac *AccountClient) GetThread(status *mastodon.Status) ([]Item, error) {
var items []Item
statuses, err := ac.Client.GetStatusContext(context.Background(), status.ID)
if err != nil {
return items, 0, err
return items, err
}
for _, s := range statuses.Ancestors {
item, filtered := NewStatusItem(s, ac.Filters, "thread")
if !filtered {
items = append(items, item)
}
}
item, filtered := NewStatusItem(status, ac.Filters, "thread")
if !filtered {
items = append(items, item)
items = append(items, NewStatusItem(s, ac.Filters, "thread", false))
}
items = append(items, NewStatusItem(status, ac.Filters, "thread", false))
for _, s := range statuses.Descendants {
item, filtered := NewStatusItem(s, ac.Filters, "thread")
if !filtered {
items = append(items, item)
}
items = append(items, NewStatusItem(s, ac.Filters, "thread", false))
}
return items, len(statuses.Ancestors), nil
return items, nil
}
func (ac *AccountClient) GetFavorites(pg *mastodon.Pagination) ([]Item, error) {
@ -148,11 +135,9 @@ func (ac *AccountClient) GetConversations(pg *mastodon.Pagination) ([]Item, erro
return items, err
}
for _, c := range conversations {
item, filtered := NewStatusItem(c.LastStatus, ac.Filters, "thread")
if !filtered {
item := NewStatusItem(c.LastStatus, ac.Filters, "thread", false)
items = append(items, item)
}
}
return items, nil
}
@ -240,10 +225,21 @@ func (ac *AccountClient) GetUser(pg *mastodon.Pagination, id mastodon.ID) ([]Ite
return items, err
}
for _, s := range statuses {
item, filtered := NewStatusItem(s, ac.Filters, "account")
if !filtered {
item := NewStatusItem(s, ac.Filters, "account", false)
items = append(items, item)
}
return items, nil
}
func (ac *AccountClient) GetUserPinned(id mastodon.ID) ([]Item, error) {
var items []Item
statuses, err := ac.Client.GetAccountPinnedStatuses(context.Background(), id)
if err != nil {
return items, err
}
for _, s := range statuses {
item := NewStatusItem(s, ac.Filters, "account", true)
items = append(items, item)
}
return items, nil
}
@ -267,11 +263,9 @@ func (ac *AccountClient) GetListStatuses(pg *mastodon.Pagination, id mastodon.ID
return items, err
}
for _, s := range statuses {
item, filtered := NewStatusItem(s, ac.Filters, "home")
if !filtered {
item := NewStatusItem(s, ac.Filters, "home", false)
items = append(items, item)
}
}
return items, nil
}

68
api/item.go

@ -26,12 +26,19 @@ type Item interface {
ShowSpoiler() bool
Raw() interface{}
URLs() ([]util.URL, []mastodon.Mention, []mastodon.Tag, int)
Filtered() (bool, string)
Pinned() bool
}
func NewStatusItem(item *mastodon.Status, filters []*mastodon.Filter, timeline string) (sitem Item, filtered bool) {
filtered = false
type filtered struct {
inUse bool
name string
}
func NewStatusItem(item *mastodon.Status, filters []*mastodon.Filter, timeline string, pinned bool) (sitem Item) {
filtered := filtered{inUse: false}
if item == nil {
return &StatusItem{id: newID(), item: item, showSpoiler: false}, false
return &StatusItem{id: newID(), item: item, showSpoiler: false, filtered: filtered, pinned: pinned}
}
s := util.StatusOrReblog(item)
content := s.Content
@ -67,30 +74,35 @@ func NewStatusItem(item *mastodon.Status, filters []*mastodon.Filter, timeline s
filter := strings.Split(strings.ToLower(f.Phrase), " ")
for i := 0; i+len(filter)-1 < len(stripped); i++ {
if strings.ToLower(f.Phrase) == strings.Join(stripped[i:i+len(filter)], " ") {
filtered = true
filtered.inUse = true
filtered.name = f.Phrase
break
}
}
} else {
if strings.Contains(s.Content, strings.ToLower(f.Phrase)) {
filtered = true
filtered.inUse = true
filtered.name = f.Phrase
}
if strings.Contains(s.SpoilerText, strings.ToLower(f.Phrase)) {
filtered = true
filtered.inUse = true
filtered.name = f.Phrase
}
}
if filtered {
if filtered.inUse {
break
}
}
sitem = &StatusItem{id: newID(), item: item, showSpoiler: false}
return sitem, filtered
sitem = &StatusItem{id: newID(), item: item, showSpoiler: false, filtered: filtered, pinned: pinned}
return sitem
}
type StatusItem struct {
id uint
item *mastodon.Status
showSpoiler bool
filtered filtered
pinned bool
}
func (s *StatusItem) ID() uint {
@ -141,6 +153,14 @@ func (s *StatusItem) URLs() ([]util.URL, []mastodon.Mention, []mastodon.Tag, int
return realUrls, status.Mentions, status.Tags, length
}
func (s *StatusItem) Filtered() (bool, string) {
return s.filtered.inUse, s.filtered.name
}
func (s *StatusItem) Pinned() bool {
return s.pinned
}
func NewUserItem(item *User, profile bool) Item {
return &UserItem{id: newID(), item: item, profile: profile}
}
@ -185,8 +205,16 @@ func (u *UserItem) URLs() ([]util.URL, []mastodon.Mention, []mastodon.Tag, int)
return urls, []mastodon.Mention{}, []mastodon.Tag{}, len(urls)
}
func NewNotificationItem(item *mastodon.Notification, user *User, filters []*mastodon.Filter) (nitem Item, filtred bool) {
status, filtred := NewStatusItem(item.Status, filters, "notifications")
func (s *UserItem) Filtered() (bool, string) {
return false, ""
}
func (u *UserItem) Pinned() bool {
return false
}
func NewNotificationItem(item *mastodon.Notification, user *User, filters []*mastodon.Filter) (nitem Item) {
status := NewStatusItem(item.Status, filters, "notifications", false)
nitem = &NotificationItem{
id: newID(),
item: item,
@ -195,7 +223,7 @@ func NewNotificationItem(item *mastodon.Notification, user *User, filters []*mas
status: status,
}
return nitem, filtred
return nitem
}
type NotificationItem struct {
@ -240,6 +268,14 @@ func (n *NotificationItem) URLs() ([]util.URL, []mastodon.Mention, []mastodon.Ta
return nil, nil, nil, 0
}
func (n *NotificationItem) Filtered() (bool, string) {
return false, ""
}
func (n *NotificationItem) Pinned() bool {
return false
}
func NewListsItem(item *mastodon.List) Item {
return &ListItem{id: newID(), item: item, showSpoiler: true}
}
@ -272,3 +308,11 @@ func (s *ListItem) Raw() interface{} {
func (s *ListItem) URLs() ([]util.URL, []mastodon.Mention, []mastodon.Tag, int) {
return nil, nil, nil, 0
}
func (s *ListItem) Filtered() (bool, string) {
return false, ""
}
func (n *ListItem) Pinned() bool {
return false
}

10
config.example.ini

@ -107,6 +107,10 @@ show-icons=true
# default=false
short-hints=false
# If you want to display the filter that filtered a toot.
# default=true
show-filter-phrase=true
# If you want to show a message in the cmdbar on how to access the help text.
# default=true
show-help=true
@ -132,7 +136,7 @@ leader-key=
leader-timeout=1000
# You set actions for the leader-key with one or more leader-action. It consists
# of two parts first the action then the shortcut. And they're seperated by a
# of two parts first the action then the shortcut. And they're separated by a
# comma.
#
# Available commands: home, direct, local, federated, compose, blocking,
@ -314,7 +318,7 @@ posts=false
#
# You can also use xrdb colors like this xrdb:color1 The program will use colors
# prefixed with an * first then look for URxvt or XTerm if it can't find any
# color prefixed with an asterik. If you don't want tut to guess the prefix you
# color prefixed with an asterisk. If you don't want tut to guess the prefix you
# can set the prefix yourself. If the xrdb color can't be found a preset color
# will be used. You'll have to set theme=none for this to work.
@ -326,7 +330,7 @@ xrdb-prefix=guess
# available on the URL below. If a theme is named "nord.ini" you just write
# theme=nord
#
# https://github.com/RasmusLindroth/tut/tree/master/themes
# https://github.com/RasmusLindroth/tut/tree/master/config/themes
#
# If you want to use your own theme set theme to none then you can create your
# own theme below

6
config/config.go

@ -95,9 +95,9 @@ type General struct {
QuoteReply bool
CharLimit int
ShortHints bool
ShowFilterPhrase bool
ListPlacement ListPlacement
ListSplit ListSplit
HideNotificationText bool
ListProportion int
ContentProportion int
ShowIcons bool
@ -576,7 +576,7 @@ func parseGeneral(cfg *ini.File) General {
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.HideNotificationText = cfg.Section("general").Key("hide-notification-text").MustBool(false)
general.ShowFilterPhrase = cfg.Section("general").Key("show-filter-phrase").MustBool(true)
general.ShowIcons = cfg.Section("general").Key("show-icons").MustBool(true)
general.ShowHelp = cfg.Section("general").Key("show-help").MustBool(true)
general.RedrawUI = cfg.Section("general").Key("redraw-ui").MustBool(true)
@ -630,7 +630,7 @@ func parseGeneral(cfg *ini.File) General {
for _, l := range lactions {
parts := strings.Split(l, ",")
if len(parts) != 2 {
fmt.Printf("leader-action must consist of two parts seperated by a comma. Your value is: %s\n", strings.Join(parts, ","))
fmt.Printf("leader-action must consist of two parts separated by a comma. Your value is: %s\n", strings.Join(parts, ","))
os.Exit(1)
}
for i, p := range parts {

10
config/default_config.go

@ -109,6 +109,10 @@ show-icons=true
# default=false
short-hints=false
# If you want to display the filter that filtered a toot.
# default=true
show-filter-phrase=true
# If you want to show a message in the cmdbar on how to access the help text.
# default=true
show-help=true
@ -134,7 +138,7 @@ leader-key=
leader-timeout=1000
# You set actions for the leader-key with one or more leader-action. It consists
# of two parts first the action then the shortcut. And they're seperated by a
# of two parts first the action then the shortcut. And they're separated by a
# comma.
#
# Available commands: home, direct, local, federated, compose, blocking,
@ -316,7 +320,7 @@ posts=false
#
# You can also use xrdb colors like this xrdb:color1 The program will use colors
# prefixed with an * first then look for URxvt or XTerm if it can't find any
# color prefixed with an asterik. If you don't want tut to guess the prefix you
# color prefixed with an asterisk. If you don't want tut to guess the prefix you
# can set the prefix yourself. If the xrdb color can't be found a preset color
# will be used. You'll have to set theme=none for this to work.
@ -328,7 +332,7 @@ xrdb-prefix=guess
# available on the URL below. If a theme is named "nord.ini" you just write
# theme=nord
#
# https://github.com/RasmusLindroth/tut/tree/master/themes
# https://github.com/RasmusLindroth/tut/tree/master/config/themes
#
# If you want to use your own theme set theme to none then you can create your
# own theme below

34
feed/feed.go

@ -16,7 +16,7 @@ type apiEmptyFunc func() ([]api.Item, error)
type apiIDFunc func(pg *mastodon.Pagination, id mastodon.ID) ([]api.Item, error)
type apiSearchFunc func(search string) ([]api.Item, error)
type apiSearchPGFunc func(pg *mastodon.Pagination, search string) ([]api.Item, error)
type apiThreadFunc func(status *mastodon.Status) ([]api.Item, int, error)
type apiThreadFunc func(status *mastodon.Status) ([]api.Item, error)
type FeedType uint
@ -64,6 +64,7 @@ const (
type Feed struct {
accountClient *api.AccountClient
feedType FeedType
sticky []api.Item
items []api.Item
itemsMux sync.RWMutex
loadingNewer *LoadingLock
@ -85,7 +86,8 @@ func (f *Feed) Type() FeedType {
func (f *Feed) List() []api.Item {
f.itemsMux.RLock()
defer f.itemsMux.RUnlock()
return f.items
r := f.sticky
return append(r, f.items...)
}
func (f *Feed) Delete(id uint) {
@ -167,6 +169,10 @@ func (f *Feed) Name() string {
return f.name
}
func (f *Feed) StickyCount() int {
return len(f.sticky)
}
func (f *Feed) singleNewerSearch(fn apiSearchFunc, search string) {
items, err := fn(search)
if err != nil {
@ -181,7 +187,7 @@ func (f *Feed) singleNewerSearch(fn apiSearchFunc, search string) {
}
func (f *Feed) singleThread(fn apiThreadFunc, status *mastodon.Status) {
items, _, err := fn(status)
items, err := fn(status)
if err != nil {
return
}
@ -322,12 +328,7 @@ func (f *Feed) normalNewerUser(fn apiIDFunc, id mastodon.ID) {
if len(items) > 0 {
item := items[0].Raw().(*mastodon.Status)
f.apiData.MinID = item.ID
newItems := []api.Item{f.items[0]}
newItems = append(newItems, items...)
if len(f.items) > 1 {
newItems = append(newItems, f.items[1:]...)
}
f.items = newItems
f.items = append(items, f.items...)
f.Updated(DekstopNotificationNone)
if f.apiData.MaxID == mastodon.ID("") {
item = items[len(items)-1].Raw().(*mastodon.Status)
@ -538,15 +539,13 @@ func (f *Feed) startStream(rec *api.Receiver, timeline string, err error) {
for e := range f.stream.Ch {
switch t := e.(type) {
case *mastodon.UpdateEvent:
s, filtered := api.NewStatusItem(t.Status, f.accountClient.Filters, timeline)
if !filtered {
s := api.NewStatusItem(t.Status, f.accountClient.Filters, timeline, false)
f.itemsMux.Lock()
f.items = append([]api.Item{s}, f.items...)
f.Updated(DesktopNotificationPost)
f.itemsMux.Unlock()
}
}
}
}()
}
@ -567,12 +566,11 @@ func (f *Feed) startStreamNotification(rec *api.Receiver, timeline string, err e
log.Fatalln(t.Notification.Account.Acct)
continue
}
s, filtered := api.NewNotificationItem(t.Notification,
s := api.NewNotificationItem(t.Notification,
&api.User{
Data: &t.Notification.Account,
Relation: rel[0],
}, f.accountClient.Filters)
if !filtered {
f.itemsMux.Lock()
f.items = append([]api.Item{s}, f.items...)
nft := DekstopNotificationNone
@ -594,13 +592,13 @@ func (f *Feed) startStreamNotification(rec *api.Receiver, timeline string, err e
f.itemsMux.Unlock()
}
}
}
}()
}
func newFeed(ac *api.AccountClient, ft FeedType) *Feed {
return &Feed{
accountClient: ac,
sticky: make([]api.Item, 0),
items: make([]api.Item, 0),
feedType: ft,
loadNewer: func() {},
@ -689,7 +687,11 @@ func NewUserSearch(ac *api.AccountClient, search string) *Feed {
func NewUserProfile(ac *api.AccountClient, user *api.User) *Feed {
feed := newFeed(ac, User)
feed.name = user.Data.Acct
feed.items = append(feed.items, api.NewUserItem(user, true))
feed.sticky = append(feed.sticky, api.NewUserItem(user, true))
pinned, err := ac.GetUserPinned(user.Data.ID)
if err == nil {
feed.sticky = append(feed.sticky, pinned...)
}
feed.loadNewer = func() { feed.normalNewerUser(feed.accountClient.GetUser, user.Data.ID) }
feed.loadOlder = func() { feed.normalOlderUser(feed.accountClient.GetUser, user.Data.ID) }

6
go.mod

@ -3,7 +3,7 @@ module github.com/RasmusLindroth/tut
go 1.17
require (
github.com/RasmusLindroth/go-mastodon v0.0.7
github.com/RasmusLindroth/go-mastodon v0.0.8
github.com/atotto/clipboard v0.1.4
github.com/gdamore/tcell/v2 v2.5.1
github.com/gen2brain/beeep v0.0.0-20220518085355-d7852edf42fc
@ -13,8 +13,8 @@ require (
github.com/pelletier/go-toml/v2 v2.0.1
github.com/rivo/tview v0.0.0-20220307222120-9994674d60a8
github.com/rivo/uniseg v0.2.0
golang.org/x/net v0.0.0-20220526153639-5463443f8c37
gopkg.in/ini.v1 v1.66.4
golang.org/x/net v0.0.0-20220531201128-c960675eff93
gopkg.in/ini.v1 v1.66.6
)
require (

12
go.sum

@ -1,5 +1,5 @@
github.com/RasmusLindroth/go-mastodon v0.0.7 h1:iGgkkvDrPHTiAyACUehLH5zragSHCUSbhcYdQEBIn48=
github.com/RasmusLindroth/go-mastodon v0.0.7/go.mod h1:4L0oyiNwq1tUoiByczzhSikxR9RiANzELtZgexxKpPM=
github.com/RasmusLindroth/go-mastodon v0.0.8 h1:t2rrbdNgS4h0JhmPNsmUOQBByDxmUPawnERGn6oR2eA=
github.com/RasmusLindroth/go-mastodon v0.0.8/go.mod h1:4L0oyiNwq1tUoiByczzhSikxR9RiANzELtZgexxKpPM=
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
@ -49,8 +49,8 @@ github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af/go.mod h1:4F09kP5F+a
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/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220526153639-5463443f8c37 h1:lUkvobShwKsOesNfWWlCS5q7fnbG1MEliIzwu886fn8=
golang.org/x/net v0.0.0-20220526153639-5463443f8c37/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220531201128-c960675eff93 h1:MYimHLfoXEpOhqd/zgoA/uoXzHB86AEky4LAx5ij9xA=
golang.org/x/net v0.0.0-20220531201128-c960675eff93/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -71,7 +71,7 @@ golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
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/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4=
gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.66.6 h1:LATuAqN/shcYAOkv3wl2L4rkaKqkcgTBQjOyYDvcPKI=
gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

BIN
images/preview2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

2
main.go

@ -8,7 +8,7 @@ import (
"github.com/rivo/tview"
)
const version = "1.0.10"
const version = "1.0.11"
func main() {
util.MakeDirs()

2
ui/cliview.go

@ -41,7 +41,7 @@ func CliView(version string) (newUser bool, selectedUser string) {
fmt.Print("\t\tIf two users are named the same. Use full name like tut@fosstodon.org\n\n")
fmt.Print("Configuration:\n")
fmt.Printf("\tThe config is located in XDG_CONFIG_HOME/tut/config.ini which usally equals to ~/.config/tut/config.ini.\n")
fmt.Printf("\tThe config is located in XDG_CONFIG_HOME/tut/config.ini which usually equals to ~/.config/tut/config.ini.\n")
fmt.Printf("\tThe program will generate the file the first time you run tut. The file has comments which exmplains what each configuration option does.\n\n")
fmt.Print("Contact info for issues or questions:\n")

46
ui/feed.go

@ -16,6 +16,7 @@ import (
type FeedList struct {
Text *tview.List
Symbol *tview.List
stickyCount int
}
func (fl *FeedList) InFocus(style config.Style) {
@ -136,7 +137,7 @@ func NewHomeFeed(tv *TutView) *Feed {
tutView: tv,
Data: f,
ListIndex: 0,
List: NewFeedList(tv.tut),
List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut),
}
go fd.update()
@ -151,7 +152,7 @@ func NewFederatedFeed(tv *TutView) *Feed {
tutView: tv,
Data: f,
ListIndex: 0,
List: NewFeedList(tv.tut),
List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut),
}
go fd.update()
@ -166,7 +167,7 @@ func NewLocalFeed(tv *TutView) *Feed {
tutView: tv,
Data: f,
ListIndex: 0,
List: NewFeedList(tv.tut),
List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut),
}
go fd.update()
@ -181,7 +182,7 @@ func NewNotificationFeed(tv *TutView) *Feed {
tutView: tv,
Data: f,
ListIndex: 0,
List: NewFeedList(tv.tut),
List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut),
}
go fd.update()
@ -196,7 +197,7 @@ func NewThreadFeed(tv *TutView, item api.Item) *Feed {
tutView: tv,
Data: f,
ListIndex: 0,
List: NewFeedList(tv.tut),
List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut),
}
for i, s := range f.List() {
@ -218,7 +219,7 @@ func NewConversationsFeed(tv *TutView) *Feed {
tutView: tv,
Data: f,
ListIndex: 0,
List: NewFeedList(tv.tut),
List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut),
}
go fd.update()
@ -237,7 +238,7 @@ func NewUserFeed(tv *TutView, item api.Item) *Feed {
tutView: tv,
Data: f,
ListIndex: 0,
List: NewFeedList(tv.tut),
List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut),
}
go fd.update()
@ -252,7 +253,7 @@ func NewUserSearchFeed(tv *TutView, search string) *Feed {
tutView: tv,
Data: f,
ListIndex: 0,
List: NewFeedList(tv.tut),
List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut),
}
for _, s := range f.List() {
@ -271,7 +272,7 @@ func NewTagFeed(tv *TutView, search string) *Feed {
tutView: tv,
Data: f,
ListIndex: 0,
List: NewFeedList(tv.tut),
List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut),
}
go fd.update()
@ -285,7 +286,7 @@ func NewListsFeed(tv *TutView) *Feed {
tutView: tv,
Data: f,
ListIndex: 0,
List: NewFeedList(tv.tut),
List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut),
}
go fd.update()
@ -300,7 +301,7 @@ func NewListFeed(tv *TutView, l *mastodon.List) *Feed {
tutView: tv,
Data: f,
ListIndex: 0,
List: NewFeedList(tv.tut),
List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut),
}
go fd.update()
@ -315,7 +316,7 @@ func NewFavoritedFeed(tv *TutView) *Feed {
tutView: tv,
Data: f,
ListIndex: 0,
List: NewFeedList(tv.tut),
List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut),
}
@ -330,7 +331,7 @@ func NewBookmarksFeed(tv *TutView) *Feed {
tutView: tv,
Data: f,
ListIndex: 0,
List: NewFeedList(tv.tut),
List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut),
}
go fd.update()
@ -345,7 +346,7 @@ func NewFavoritesStatus(tv *TutView, id mastodon.ID) *Feed {
tutView: tv,
Data: f,
ListIndex: 0,
List: NewFeedList(tv.tut),
List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut),
}
go fd.update()
@ -360,7 +361,7 @@ func NewBoosts(tv *TutView, id mastodon.ID) *Feed {
tutView: tv,
Data: f,
ListIndex: 0,
List: NewFeedList(tv.tut),
List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut),
}
go fd.update()
@ -375,7 +376,7 @@ func NewFollowers(tv *TutView, id mastodon.ID) *Feed {
tutView: tv,
Data: f,
ListIndex: 0,
List: NewFeedList(tv.tut),
List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut),
}
go fd.update()
@ -390,7 +391,7 @@ func NewFollowing(tv *TutView, id mastodon.ID) *Feed {
tutView: tv,
Data: f,
ListIndex: 0,
List: NewFeedList(tv.tut),
List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut),
}
go fd.update()
@ -405,7 +406,7 @@ func NewBlocking(tv *TutView) *Feed {
tutView: tv,
Data: f,
ListIndex: 0,
List: NewFeedList(tv.tut),
List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut),
}
go fd.update()
@ -420,7 +421,7 @@ func NewMuting(tv *TutView) *Feed {
tutView: tv,
Data: f,
ListIndex: 0,
List: NewFeedList(tv.tut),
List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut),
}
go fd.update()
@ -435,7 +436,7 @@ func NewFollowRequests(tv *TutView) *Feed {
tutView: tv,
Data: f,
ListIndex: 0,
List: NewFeedList(tv.tut),
List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut),
}
go fd.update()
@ -443,10 +444,11 @@ func NewFollowRequests(tv *TutView) *Feed {
return fd
}
func NewFeedList(t *Tut) *FeedList {
func NewFeedList(t *Tut, stickyCount int) *FeedList {
fl := &FeedList{
Text: NewList(t.Config),
Symbol: NewList(t.Config),
stickyCount: stickyCount,
}
return fl
}
@ -476,7 +478,7 @@ func (fl *FeedList) Prev() (loadNewer bool) {
}
fl.Text.SetCurrentItem(ni)
fl.Symbol.SetCurrentItem(ni)
return ni < 4
return ni-fl.stickyCount < 4
}
func (fl *FeedList) Clear() {

4
ui/input.go

@ -452,7 +452,7 @@ func (tv *TutView) InputStatus(event *tcell.EventKey, item api.Item, status *mas
return nil
}
if tv.tut.Config.Input.StatusUser.Match(event.Key(), event.Rune()) {
id := status.Account.ID
id := sr.Account.ID
if nAcc != nil {
id = nAcc.ID
}
@ -468,7 +468,7 @@ func (tv *TutView) InputStatus(event *tcell.EventKey, item api.Item, status *mas
return nil
}
if tv.tut.Config.Input.StatusYank.Match(event.Key(), event.Rune()) {
copyToClipboard(status.URL)
copyToClipboard(sr.URL)
return nil
}
if tv.tut.Config.Input.StatusToggleSpoiler.Match(event.Key(), event.Rune()) {

11
ui/item.go

@ -20,13 +20,20 @@ func DrawListItem(cfg *config.Config, item api.Item) (string, string) {
symbol := ""
status := s
if s.Reblog != nil {
status = s
status = s.Reblog
}
if status.RepliesCount > 0 {
symbol = " ⤶ "
}
if item.Pinned() {
symbol = " ! "
}
acc := strings.TrimSpace(s.Account.Acct)
if s.Reblog != nil && cfg.General.ShowIcons {
acc = fmt.Sprintf("♺ %s", acc)
}
d := OutputDate(cfg, s.CreatedAt.Local())
return fmt.Sprintf("%s %s", d, strings.TrimSpace(s.Account.Acct)), symbol
return fmt.Sprintf("%s %s", d, acc), symbol
case api.UserType:
a := item.Raw().(*api.User)
return strings.TrimSpace(a.Data.Acct), ""

18
ui/item_status.go

@ -71,6 +71,24 @@ type DisplayTootData struct {
}
func drawStatus(tut *Tut, item api.Item, status *mastodon.Status, main *tview.TextView, controls *tview.TextView, additional string) {
filtered, phrase := item.Filtered()
if filtered {
var output string
if tut.Config.General.ShowFilterPhrase {
output = fmt.Sprintf("Filtered by phrase: %s", tview.Escape(phrase))
} else {
output = "Filtered."
}
if main != nil {
if additional != "" {
additional = fmt.Sprintf("%s\n\n", config.SublteText(tut.Config, additional))
}
main.SetText(additional + output)
}
controls.SetText("")
return
}
showSensitive := item.ShowSpoiler()
var strippedContent string

Loading…
Cancel
Save