checkpoint: created the printer and began refactoring and redesigning

This commit is contained in:
Dan Anglin 2024-06-16 20:17:07 +01:00
parent f73f1f5872
commit 947b1b8c46
Signed by: dananglin
GPG key ID: 0C1D44CFBEE68638
18 changed files with 424 additions and 222 deletions

View file

@ -11,6 +11,7 @@ import (
"strconv"
"codeflow.dananglin.me.uk/apollo/enbas/internal/executor"
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
)
var (
@ -87,39 +88,52 @@ func run() error {
command := flag.Arg(0)
args := flag.Args()[1:]
enbasPrinter := printer.NewPrinter(
*topLevelFlags.NoColor,
topLevelFlags.Pager,
80,
)
executorMap := map[string]executor.Executor{
executor.CommandAccept: executor.NewAcceptOrRejectExecutor(
topLevelFlags,
enbasPrinter,
topLevelFlags.ConfigDir,
executor.CommandAccept,
executor.CommandSummaryLookup(executor.CommandAccept),
),
executor.CommandAdd: executor.NewAddExecutor(
topLevelFlags,
enbasPrinter,
topLevelFlags.ConfigDir,
executor.CommandAdd,
executor.CommandSummaryLookup(executor.CommandAdd),
),
executor.CommandBlock: executor.NewBlockOrUnblockExecutor(
topLevelFlags,
enbasPrinter,
topLevelFlags.ConfigDir,
executor.CommandBlock,
executor.CommandSummaryLookup(executor.CommandBlock),
),
executor.CommandCreate: executor.NewCreateExecutor(
topLevelFlags,
enbasPrinter,
topLevelFlags.ConfigDir,
executor.CommandCreate,
executor.CommandSummaryLookup(executor.CommandCreate),
),
executor.CommandDelete: executor.NewDeleteExecutor(
topLevelFlags,
enbasPrinter,
topLevelFlags.ConfigDir,
executor.CommandDelete,
executor.CommandSummaryLookup(executor.CommandDelete),
),
executor.CommandEdit: executor.NewEditExecutor(
topLevelFlags,
enbasPrinter,
topLevelFlags.ConfigDir,
executor.CommandEdit,
executor.CommandSummaryLookup(executor.CommandEdit),
),
executor.CommandFollow: executor.NewFollowOrUnfollowExecutor(
topLevelFlags,
enbasPrinter,
topLevelFlags.ConfigDir,
executor.CommandFollow,
executor.CommandSummaryLookup(executor.CommandFollow),
),
@ -129,7 +143,8 @@ func run() error {
executor.CommandSummaryLookup(executor.CommandLogin),
),
executor.CommandReject: executor.NewAcceptOrRejectExecutor(
topLevelFlags,
enbasPrinter,
topLevelFlags.ConfigDir,
executor.CommandReject,
executor.CommandSummaryLookup(executor.CommandReject),
),
@ -139,26 +154,31 @@ func run() error {
executor.CommandSummaryLookup(executor.CommandRemove),
),
executor.CommandSwitch: executor.NewSwitchExecutor(
topLevelFlags,
enbasPrinter,
topLevelFlags.ConfigDir,
executor.CommandSwitch,
executor.CommandSummaryLookup(executor.CommandSwitch),
),
executor.CommandUnfollow: executor.NewFollowOrUnfollowExecutor(
topLevelFlags,
enbasPrinter,
topLevelFlags.ConfigDir,
executor.CommandUnfollow,
executor.CommandSummaryLookup(executor.CommandUnfollow),
),
executor.CommandUnblock: executor.NewBlockOrUnblockExecutor(
topLevelFlags,
enbasPrinter,
topLevelFlags.ConfigDir,
executor.CommandUnblock,
executor.CommandSummaryLookup(executor.CommandUnblock),
),
executor.CommandShow: executor.NewShowExecutor(
topLevelFlags,
enbasPrinter,
topLevelFlags.ConfigDir,
executor.CommandShow,
executor.CommandSummaryLookup(executor.CommandShow),
),
executor.CommandVersion: executor.NewVersionExecutor(
enbasPrinter,
executor.CommandVersion,
executor.CommandSummaryLookup(executor.CommandVersion),
binaryVersion,
@ -167,7 +187,8 @@ func run() error {
gitCommit,
),
executor.CommandWhoami: executor.NewWhoAmIExecutor(
topLevelFlags,
enbasPrinter,
topLevelFlags.ConfigDir,
executor.CommandWhoami,
executor.CommandSummaryLookup(executor.CommandWhoami),
),

View file

@ -17,7 +17,7 @@ const (
listPath string = "/api/v1/lists"
)
func (g *Client) GetAllLists() (model.Lists, error) {
func (g *Client) GetAllLists() ([]model.List, error) {
url := g.Authentication.Instance + listPath
var lists []model.List

View file

@ -9,23 +9,26 @@ import (
"fmt"
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
)
type AcceptOrRejectExecutor struct {
*flag.FlagSet
topLevelFlags TopLevelFlags
resourceType string
accountName string
command string
printer *printer.Printer
configDir string
resourceType string
accountName string
command string
}
func NewAcceptOrRejectExecutor(tlf TopLevelFlags, name, summary string) *AcceptOrRejectExecutor {
func NewAcceptOrRejectExecutor(enbasPrinter *printer.Printer, configDir, name, summary string) *AcceptOrRejectExecutor {
acceptExe := AcceptOrRejectExecutor{
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
topLevelFlags: tlf,
command: name,
printer: enbasPrinter,
configDir: configDir,
command: name,
}
acceptExe.StringVar(&acceptExe.resourceType, flagType, "", "Specify the type of resource to accept or reject")
@ -46,7 +49,7 @@ func (a *AcceptOrRejectExecutor) Execute() error {
return UnsupportedTypeError{resourceType: a.resourceType}
}
gtsClient, err := client.NewClientFromConfig(a.topLevelFlags.ConfigDir)
gtsClient, err := client.NewClientFromConfig(a.configDir)
if err != nil {
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
}
@ -55,7 +58,7 @@ func (a *AcceptOrRejectExecutor) Execute() error {
}
func (a *AcceptOrRejectExecutor) acceptOrRejectFollowRequest(gtsClient *client.Client) error {
accountID, err := getAccountID(gtsClient, false, a.accountName, a.topLevelFlags.ConfigDir)
accountID, err := getAccountID(gtsClient, false, a.accountName, a.configDir)
if err != nil {
return fmt.Errorf("received an error while getting the account ID: %w", err)
}
@ -75,7 +78,7 @@ func (a *AcceptOrRejectExecutor) acceptFollowRequest(gtsClient *client.Client, a
return fmt.Errorf("unable to accept the follow request: %w", err)
}
fmt.Println("Successfully accepted the follow request.")
a.printer.PrintSuccess("Successfully accepted the follow request.")
return nil
}
@ -85,7 +88,7 @@ func (a *AcceptOrRejectExecutor) rejectFollowRequest(gtsClient *client.Client, a
return fmt.Errorf("unable to reject the follow request: %w", err)
}
fmt.Println("Successfully rejected the follow request.")
a.printer.PrintSuccess("Successfully rejected the follow request.")
return nil
}

View file

@ -10,12 +10,14 @@ import (
"fmt"
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
)
type AddExecutor struct {
*flag.FlagSet
topLevelFlags TopLevelFlags
printer *printer.Printer
configDir string
resourceType string
toResourceType string
listID string
@ -26,13 +28,15 @@ type AddExecutor struct {
content string
}
func NewAddExecutor(tlf TopLevelFlags, name, summary string) *AddExecutor {
func NewAddExecutor(printer *printer.Printer, configDir, name, summary string) *AddExecutor {
emptyArr := make([]string, 0, 3)
addExe := AddExecutor{
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
accountNames: MultiStringFlagValue(emptyArr),
topLevelFlags: tlf,
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
printer: printer,
configDir: configDir,
accountNames: MultiStringFlagValue(emptyArr),
}
addExe.StringVar(&addExe.resourceType, flagType, "", "Specify the resource type to add (e.g. account, note)")
@ -67,7 +71,7 @@ func (a *AddExecutor) Execute() error {
return UnsupportedTypeError{resourceType: a.toResourceType}
}
gtsClient, err := client.NewClientFromConfig(a.topLevelFlags.ConfigDir)
gtsClient, err := client.NewClientFromConfig(a.configDir)
if err != nil {
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
}
@ -124,7 +128,7 @@ func (a *AddExecutor) addAccountsToList(gtsClient *client.Client) error {
return fmt.Errorf("unable to add the accounts to the list: %w", err)
}
fmt.Println("Successfully added the account(s) to the list.")
a.printer.PrintSuccess("Successfully added the account(s) to the list.")
return nil
}
@ -150,7 +154,7 @@ func (a *AddExecutor) addNoteToAccount(gtsClient *client.Client) error {
return fmt.Errorf("unexpected number of accounts specified: want 1, got %d", len(a.accountNames))
}
accountID, err := getAccountID(gtsClient, false, a.accountNames[0], a.topLevelFlags.ConfigDir)
accountID, err := getAccountID(gtsClient, false, a.accountNames[0], a.configDir)
if err != nil {
return fmt.Errorf("received an error while getting the account ID: %w", err)
}
@ -166,7 +170,7 @@ func (a *AddExecutor) addNoteToAccount(gtsClient *client.Client) error {
return fmt.Errorf("unable to add the private note to the account: %w", err)
}
fmt.Println("Successfully added the private note to the account.")
a.printer.PrintSuccess("Successfully added the private note to the account.")
return nil
}
@ -196,7 +200,7 @@ func (a *AddExecutor) addStatusToBookmarks(gtsClient *client.Client) error {
return fmt.Errorf("unable to add the status to your bookmarks: %w", err)
}
fmt.Println("Successfully added the status to your bookmarks.")
a.printer.PrintSuccess("Successfully added the status to your bookmarks.")
return nil
}
@ -228,7 +232,7 @@ func (a *AddExecutor) addStarToStatus(gtsClient *client.Client) error {
return fmt.Errorf("unable to add the %s to the status: %w", a.resourceType, err)
}
fmt.Printf("Successfully added a %s to the status.\n", a.resourceType)
a.printer.PrintSuccess("Successfully added a " + a.resourceType + " to the status.\n")
return nil
}
@ -238,7 +242,7 @@ func (a *AddExecutor) addBoostToStatus(gtsClient *client.Client) error {
return fmt.Errorf("unable to add the boost to the status: %w", err)
}
fmt.Println("Successfully added the boost to the status.")
a.printer.PrintSuccess("Successfully added the boost to the status.")
return nil
}
@ -285,7 +289,7 @@ func (a *AddExecutor) addVoteToPoll(gtsClient *client.Client) error {
return fmt.Errorf("unable to add your vote(s) to the poll: %w", err)
}
fmt.Println("Successfully added your vote(s) to the poll.")
a.printer.PrintSuccess("Successfully added your vote(s) to the poll.")
return nil
}

View file

@ -9,23 +9,26 @@ import (
"fmt"
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
)
type BlockOrUnblockExecutor struct {
*flag.FlagSet
topLevelFlags TopLevelFlags
resourceType string
accountName string
command string
printer *printer.Printer
configDir string
resourceType string
accountName string
command string
}
func NewBlockOrUnblockExecutor(tlf TopLevelFlags, name, summary string) *BlockOrUnblockExecutor {
func NewBlockOrUnblockExecutor(printer *printer.Printer, configDir, name, summary string) *BlockOrUnblockExecutor {
blockExe := BlockOrUnblockExecutor{
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
topLevelFlags: tlf,
command: name,
printer: printer,
configDir: configDir,
command: name,
}
blockExe.StringVar(&blockExe.resourceType, flagType, "", "Specify the type of resource to block or unblock")
@ -46,7 +49,7 @@ func (b *BlockOrUnblockExecutor) Execute() error {
return UnsupportedTypeError{resourceType: b.resourceType}
}
gtsClient, err := client.NewClientFromConfig(b.topLevelFlags.ConfigDir)
gtsClient, err := client.NewClientFromConfig(b.configDir)
if err != nil {
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
}
@ -55,7 +58,7 @@ func (b *BlockOrUnblockExecutor) Execute() error {
}
func (b *BlockOrUnblockExecutor) blockOrUnblockAccount(gtsClient *client.Client) error {
accountID, err := getAccountID(gtsClient, false, b.accountName, b.topLevelFlags.ConfigDir)
accountID, err := getAccountID(gtsClient, false, b.accountName, b.configDir)
if err != nil {
return fmt.Errorf("received an error while getting the account ID: %w", err)
}
@ -75,7 +78,7 @@ func (b *BlockOrUnblockExecutor) blockAccount(gtsClient *client.Client, accountI
return fmt.Errorf("unable to block the account: %w", err)
}
fmt.Println("Successfully blocked the account.")
b.printer.PrintSuccess("Successfully blocked the account.")
return nil
}
@ -85,7 +88,7 @@ func (b *BlockOrUnblockExecutor) unblockAccount(gtsClient *client.Client, accoun
return fmt.Errorf("unable to unblock the account: %w", err)
}
fmt.Println("Successfully unblocked the account.")
b.printer.PrintSuccess("Successfully unblocked the account.")
return nil
}

View file

@ -11,39 +11,42 @@ import (
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
)
type CreateExecutor struct {
*flag.FlagSet
topLevelFlags TopLevelFlags
addPoll bool
boostable bool
federated bool
likeable bool
printer *printer.Printer
addPoll bool
boostable bool
federated bool
likeable bool
pollAllowsMultipleChoices bool
pollHidesVoteCounts bool
replyable bool
sensitive *bool
content string
contentType string
fromFile string
language string
resourceType string
listTitle string
listRepliesPolicy string
spoilerText string
visibility string
pollExpiresIn TimeDurationFlagValue
pollOptions MultiStringFlagValue
replyable bool
sensitive *bool
configDir string
content string
contentType string
fromFile string
language string
resourceType string
listTitle string
listRepliesPolicy string
spoilerText string
visibility string
pollExpiresIn TimeDurationFlagValue
pollOptions MultiStringFlagValue
}
func NewCreateExecutor(tlf TopLevelFlags, name, summary string) *CreateExecutor {
func NewCreateExecutor(printer *printer.Printer, configDir, name, summary string) *CreateExecutor {
createExe := CreateExecutor{
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
topLevelFlags: tlf,
printer: printer,
configDir: configDir,
}
createExe.BoolVar(&createExe.boostable, flagEnableReposts, true, "Specify if the status can be reposted/boosted by others")
@ -87,7 +90,7 @@ func (c *CreateExecutor) Execute() error {
return FlagNotSetError{flagText: flagType}
}
gtsClient, err := client.NewClientFromConfig(c.topLevelFlags.ConfigDir)
gtsClient, err := client.NewClientFromConfig(c.configDir)
if err != nil {
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
}
@ -125,8 +128,8 @@ func (c *CreateExecutor) createList(gtsClient *client.Client) error {
return fmt.Errorf("unable to create the list: %w", err)
}
fmt.Println("Successfully created the following list:")
utilities.Display(list, *c.topLevelFlags.NoColor, c.topLevelFlags.Pager)
c.printer.PrintSuccess("Successfully created the following list:")
c.printer.PrintList(list)
return nil
}
@ -217,13 +220,13 @@ func (c *CreateExecutor) createStatus(gtsClient *client.Client) error {
form.Poll = &poll
}
status, err := gtsClient.CreateStatus(form)
_, err = gtsClient.CreateStatus(form)
if err != nil {
return fmt.Errorf("unable to create the status: %w", err)
}
fmt.Println("Successfully created the following status:")
utilities.Display(status, *c.topLevelFlags.NoColor, c.topLevelFlags.Pager)
c.printer.PrintSuccess("Successfully created the following status:")
//utilities.Display(status, *c.topLevelFlags.NoColor, c.topLevelFlags.Pager)
return nil
}

View file

@ -9,20 +9,24 @@ import (
"fmt"
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
)
type DeleteExecutor struct {
*flag.FlagSet
topLevelFlags TopLevelFlags
resourceType string
listID string
printer *printer.Printer
configDir string
resourceType string
listID string
}
func NewDeleteExecutor(tlf TopLevelFlags, name, summary string) *DeleteExecutor {
func NewDeleteExecutor(printer *printer.Printer, configDir, name, summary string) *DeleteExecutor {
deleteExe := DeleteExecutor{
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
topLevelFlags: tlf,
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
printer: printer,
configDir: configDir,
}
deleteExe.StringVar(&deleteExe.resourceType, flagType, "", "Specify the type of resource to delete")
@ -47,7 +51,7 @@ func (d *DeleteExecutor) Execute() error {
return UnsupportedTypeError{resourceType: d.resourceType}
}
gtsClient, err := client.NewClientFromConfig(d.topLevelFlags.ConfigDir)
gtsClient, err := client.NewClientFromConfig(d.configDir)
if err != nil {
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
}
@ -64,7 +68,7 @@ func (d *DeleteExecutor) deleteList(gtsClient *client.Client) error {
return fmt.Errorf("unable to delete the list: %w", err)
}
fmt.Println("The list was successfully deleted.")
d.printer.PrintSuccess("The list was successfully deleted.")
return nil
}

View file

@ -10,23 +10,26 @@ import (
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
)
type EditExecutor struct {
*flag.FlagSet
topLevelFlags TopLevelFlags
printer *printer.Printer
configDir string
resourceType string
listID string
listTitle string
listRepliesPolicy string
}
func NewEditExecutor(tlf TopLevelFlags, name, summary string) *EditExecutor {
func NewEditExecutor(printer *printer.Printer, configDir, name, summary string) *EditExecutor {
editExe := EditExecutor{
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
topLevelFlags: tlf,
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
printer: printer,
configDir: configDir,
}
editExe.StringVar(&editExe.resourceType, flagType, "", "Specify the type of resource to update")
@ -53,7 +56,7 @@ func (e *EditExecutor) Execute() error {
return UnsupportedTypeError{resourceType: e.resourceType}
}
gtsClient, err := client.NewClientFromConfig(e.topLevelFlags.ConfigDir)
gtsClient, err := client.NewClientFromConfig(e.configDir)
if err != nil {
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
}
@ -89,8 +92,8 @@ func (e *EditExecutor) editList(gtsClient *client.Client) error {
return fmt.Errorf("unable to update the list: %w", err)
}
fmt.Println("Successfully updated the list.")
utilities.Display(updatedList, *e.topLevelFlags.NoColor, e.topLevelFlags.Pager)
e.printer.PrintSuccess("Successfully updated the list.")
e.printer.PrintList(updatedList)
return nil
}

View file

@ -9,25 +9,28 @@ import (
"fmt"
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
)
type FollowOrUnfollowExecutor struct {
*flag.FlagSet
topLevelFlags TopLevelFlags
resourceType string
accountName string
showReposts bool
notify bool
action string
printer *printer.Printer
configDir string
resourceType string
accountName string
showReposts bool
notify bool
action string
}
func NewFollowOrUnfollowExecutor(tlf TopLevelFlags, name, summary string) *FollowOrUnfollowExecutor {
func NewFollowOrUnfollowExecutor(printer *printer.Printer, configDir, name, summary string) *FollowOrUnfollowExecutor {
command := FollowOrUnfollowExecutor{
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
topLevelFlags: tlf,
action: name,
printer: printer,
configDir: configDir,
action: name,
}
command.StringVar(&command.resourceType, flagType, "", "Specify the type of resource to follow")
@ -50,7 +53,7 @@ func (f *FollowOrUnfollowExecutor) Execute() error {
return UnsupportedTypeError{resourceType: f.resourceType}
}
gtsClient, err := client.NewClientFromConfig(f.topLevelFlags.ConfigDir)
gtsClient, err := client.NewClientFromConfig(f.configDir)
if err != nil {
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
}
@ -59,7 +62,7 @@ func (f *FollowOrUnfollowExecutor) Execute() error {
}
func (f *FollowOrUnfollowExecutor) followOrUnfollowAccount(gtsClient *client.Client) error {
accountID, err := getAccountID(gtsClient, false, f.accountName, f.topLevelFlags.ConfigDir)
accountID, err := getAccountID(gtsClient, false, f.accountName, f.configDir)
if err != nil {
return fmt.Errorf("received an error while getting the account ID: %w", err)
}
@ -85,7 +88,7 @@ func (f *FollowOrUnfollowExecutor) followAccount(gtsClient *client.Client, accou
return fmt.Errorf("unable to follow the account: %w", err)
}
fmt.Println("The follow request was sent successfully.")
f.printer.PrintSuccess("Successfully sent the follow request.")
return nil
}
@ -95,7 +98,7 @@ func (f *FollowOrUnfollowExecutor) unfollowAccount(gtsClient *client.Client, acc
return fmt.Errorf("unable to unfollow the account: %w", err)
}
fmt.Println("Successfully unfollowed the account.")
f.printer.PrintSuccess("Successfully unfollowed the account.")
return nil
}

View file

@ -10,16 +10,19 @@ import (
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
)
type ShowExecutor struct {
*flag.FlagSet
topLevelFlags TopLevelFlags
printer *printer.Printer
myAccount bool
skipAccountRelationship bool
showUserPreferences bool
showInBrowser bool
configDir string
resourceType string
accountName string
statusID string
@ -30,10 +33,12 @@ type ShowExecutor struct {
limit int
}
func NewShowExecutor(tlf TopLevelFlags, name, summary string) *ShowExecutor {
func NewShowExecutor(printer *printer.Printer, configDir, name, summary string) *ShowExecutor {
showExe := ShowExecutor{
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
topLevelFlags: tlf,
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
printer: printer,
configDir: configDir,
}
showExe.BoolVar(&showExe.myAccount, flagMyAccount, false, "Set to true to lookup your account")
@ -80,7 +85,7 @@ func (s *ShowExecutor) Execute() error {
return UnsupportedTypeError{resourceType: s.resourceType}
}
gtsClient, err := client.NewClientFromConfig(s.topLevelFlags.ConfigDir)
gtsClient, err := client.NewClientFromConfig(s.configDir)
if err != nil {
return fmt.Errorf("unable to create the GoToSocial client: %w", err)
}
@ -94,7 +99,7 @@ func (s *ShowExecutor) showInstance(gtsClient *client.Client) error {
return fmt.Errorf("unable to retrieve the instance details: %w", err)
}
utilities.Display(instance, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
utilities.Display(instance, false, "")
return nil
}
@ -106,7 +111,7 @@ func (s *ShowExecutor) showAccount(gtsClient *client.Client) error {
)
if s.myAccount {
account, err = getMyAccount(gtsClient, s.topLevelFlags.ConfigDir)
account, err = getMyAccount(gtsClient, s.configDir)
if err != nil {
return fmt.Errorf("received an error while getting the account details: %w", err)
}
@ -127,7 +132,7 @@ func (s *ShowExecutor) showAccount(gtsClient *client.Client) error {
return nil
}
utilities.Display(account, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
utilities.Display(account, false, "")
if !s.myAccount && !s.skipAccountRelationship {
relationship, err := gtsClient.GetAccountRelationship(account.ID)
@ -135,7 +140,7 @@ func (s *ShowExecutor) showAccount(gtsClient *client.Client) error {
return fmt.Errorf("unable to retrieve the relationship to this account: %w", err)
}
utilities.Display(relationship, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
utilities.Display(relationship, false, "")
}
if s.myAccount && s.showUserPreferences {
@ -144,7 +149,7 @@ func (s *ShowExecutor) showAccount(gtsClient *client.Client) error {
return fmt.Errorf("unable to retrieve the user preferences: %w", err)
}
utilities.Display(preferences, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
utilities.Display(preferences, false, "")
}
return nil
@ -166,7 +171,7 @@ func (s *ShowExecutor) showStatus(gtsClient *client.Client) error {
return nil
}
utilities.Display(status, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
utilities.Display(status, false, "")
return nil
}
@ -210,12 +215,12 @@ func (s *ShowExecutor) showTimeline(gtsClient *client.Client) error {
}
if len(timeline.Statuses) == 0 {
fmt.Println("There are no statuses in this timeline.")
s.printer.PrintInfo("There are no statuses in this timeline.\n")
return nil
}
utilities.Display(timeline, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
utilities.Display(timeline, false, "")
return nil
}
@ -244,7 +249,7 @@ func (s *ShowExecutor) showList(gtsClient *client.Client) error {
list.Accounts = accountMap
}
utilities.Display(list, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
s.printer.PrintList(list)
return nil
}
@ -256,18 +261,18 @@ func (s *ShowExecutor) showLists(gtsClient *client.Client) error {
}
if len(lists) == 0 {
fmt.Println("You have no lists.")
s.printer.PrintInfo("You have no lists.\n")
return nil
}
utilities.Display(lists, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
s.printer.PrintLists(lists)
return nil
}
func (s *ShowExecutor) showFollowers(gtsClient *client.Client) error {
accountID, err := getAccountID(gtsClient, s.myAccount, s.accountName, s.topLevelFlags.ConfigDir)
accountID, err := getAccountID(gtsClient, s.myAccount, s.accountName, s.configDir)
if err != nil {
return fmt.Errorf("received an error while getting the account ID: %w", err)
}
@ -278,16 +283,16 @@ func (s *ShowExecutor) showFollowers(gtsClient *client.Client) error {
}
if len(followers.Accounts) > 0 {
utilities.Display(followers, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
utilities.Display(followers, false, "")
} else {
fmt.Println("There are no followers for this account or the list is hidden.")
s.printer.PrintInfo("There are no followers for this account (or the list is hidden).\n")
}
return nil
}
func (s *ShowExecutor) showFollowing(gtsClient *client.Client) error {
accountID, err := getAccountID(gtsClient, s.myAccount, s.accountName, s.topLevelFlags.ConfigDir)
accountID, err := getAccountID(gtsClient, s.myAccount, s.accountName, s.configDir)
if err != nil {
return fmt.Errorf("received an error while getting the account ID: %w", err)
}
@ -298,9 +303,9 @@ func (s *ShowExecutor) showFollowing(gtsClient *client.Client) error {
}
if len(following.Accounts) > 0 {
utilities.Display(following, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
utilities.Display(following, false, "")
} else {
fmt.Println("This account is not following anyone or the list is hidden.")
s.printer.PrintInfo("This account is not following anyone or the list is hidden.\n")
}
return nil
@ -313,9 +318,9 @@ func (s *ShowExecutor) showBlocked(gtsClient *client.Client) error {
}
if len(blocked.Accounts) > 0 {
utilities.Display(blocked, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
utilities.Display(blocked, false, "")
} else {
fmt.Println("You have no blocked accounts.")
s.printer.PrintInfo("You have no blocked accounts.\n")
}
return nil
@ -328,9 +333,9 @@ func (s *ShowExecutor) showBookmarks(gtsClient *client.Client) error {
}
if len(bookmarks.Statuses) > 0 {
utilities.Display(bookmarks, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
utilities.Display(bookmarks, false, "")
} else {
fmt.Println("You have no bookmarks.")
s.printer.PrintInfo("You have no bookmarks.\n")
}
return nil
@ -343,9 +348,9 @@ func (s *ShowExecutor) showLiked(gtsClient *client.Client) error {
}
if len(liked.Statuses) > 0 {
utilities.Display(liked, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
utilities.Display(liked, false, "")
} else {
fmt.Printf("You have no %s statuses.\n", s.resourceType)
s.printer.PrintInfo("You have no " + s.resourceType + " statuses.\n")
}
return nil
@ -358,9 +363,9 @@ func (s *ShowExecutor) showFollowRequests(gtsClient *client.Client) error {
}
if len(accounts.Accounts) > 0 {
utilities.Display(accounts, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
utilities.Display(accounts, false, "")
} else {
fmt.Println("You have no follow requests.")
s.printer.PrintInfo("You have no follow requests.\n")
}
return nil
@ -376,7 +381,7 @@ func (s *ShowExecutor) showPoll(gtsClient *client.Client) error {
return fmt.Errorf("unable to retrieve the poll: %w", err)
}
utilities.Display(poll, *s.topLevelFlags.NoColor, s.topLevelFlags.Pager)
utilities.Display(poll, false, "")
return nil
}

View file

@ -9,20 +9,23 @@ import (
"fmt"
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
)
type SwitchExecutor struct {
*flag.FlagSet
topLevelFlags TopLevelFlags
configDir string
toResourceType string
accountName string
printer *printer.Printer
}
func NewSwitchExecutor(tlf TopLevelFlags, name, summary string) *SwitchExecutor {
func NewSwitchExecutor(printer *printer.Printer, configDir, name, summary string) *SwitchExecutor {
switchExe := SwitchExecutor{
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
topLevelFlags: tlf,
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
printer: printer,
configDir: configDir,
}
switchExe.StringVar(&switchExe.toResourceType, flagTo, "", "The account to switch to")
@ -51,11 +54,11 @@ func (s *SwitchExecutor) switchToAccount() error {
return NoAccountSpecifiedError{}
}
if err := config.UpdateCurrentAccount(s.accountName, s.topLevelFlags.ConfigDir); err != nil {
if err := config.UpdateCurrentAccount(s.accountName, s.configDir); err != nil {
return fmt.Errorf("unable to switch account to the account: %w", err)
}
fmt.Printf("The current account is now set to %q.\n", s.accountName)
s.printer.PrintSuccess("The current account is now set to '" + s.accountName + "'.")
return nil
}

View file

@ -6,13 +6,13 @@ package executor
import (
"flag"
"os"
"strings"
"text/tabwriter"
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
)
type VersionExecutor struct {
*flag.FlagSet
printer *printer.Printer
showFullVersion bool
binaryVersion string
buildTime string
@ -20,9 +20,19 @@ type VersionExecutor struct {
gitCommit string
}
func NewVersionExecutor(name, summary, binaryVersion, buildTime, goVersion, gitCommit string) *VersionExecutor {
func NewVersionExecutor(
enbasPrinter *printer.Printer,
name,
summary,
binaryVersion,
buildTime,
goVersion,
gitCommit string,
) *VersionExecutor {
command := VersionExecutor{
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
printer: enbasPrinter,
binaryVersion: binaryVersion,
buildTime: buildTime,
goVersion: goVersion,
@ -38,24 +48,7 @@ func NewVersionExecutor(name, summary, binaryVersion, buildTime, goVersion, gitC
}
func (v *VersionExecutor) Execute() error {
var builder strings.Builder
if v.showFullVersion {
builder.WriteString("Enbas\n")
tableWriter := tabwriter.NewWriter(&builder, 0, 8, 0, '\t', 0)
tableWriter.Write([]byte(" Version:\t" + v.binaryVersion + "\n"))
tableWriter.Write([]byte(" Git commit:\t" + v.gitCommit + "\n"))
tableWriter.Write([]byte(" Go version:\t" + v.goVersion + "\n"))
tableWriter.Write([]byte(" Build date:\t" + v.buildTime + "\n"))
tableWriter.Flush()
} else {
builder.WriteString("Enbas " + v.binaryVersion + "\n")
}
os.Stdout.WriteString(builder.String())
v.printer.PrintVersion(v.showFullVersion, v.binaryVersion, v.buildTime, v.goVersion, v.gitCommit)
return nil
}

View file

@ -9,18 +9,22 @@ import (
"fmt"
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
)
type WhoAmIExecutor struct {
*flag.FlagSet
topLevelFlags TopLevelFlags
printer *printer.Printer
configDir string
}
func NewWhoAmIExecutor(tlf TopLevelFlags, name, summary string) *WhoAmIExecutor {
func NewWhoAmIExecutor(printer *printer.Printer, configDir, name, summary string) *WhoAmIExecutor {
whoExe := WhoAmIExecutor{
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
topLevelFlags: tlf,
FlagSet: flag.NewFlagSet(name, flag.ExitOnError),
printer: printer,
configDir: configDir,
}
whoExe.Usage = commandUsageFunc(name, summary, whoExe.FlagSet)
@ -29,12 +33,12 @@ func NewWhoAmIExecutor(tlf TopLevelFlags, name, summary string) *WhoAmIExecutor
}
func (c *WhoAmIExecutor) Execute() error {
config, err := config.NewCredentialsConfigFromFile(c.topLevelFlags.ConfigDir)
config, err := config.NewCredentialsConfigFromFile(c.configDir)
if err != nil {
return fmt.Errorf("unable to load the credential config: %w", err)
}
fmt.Printf("You are logged in as %q.\n", config.CurrentAccount)
c.printer.PrintInfo("You are logged in as '" + config.CurrentAccount + "'.\n")
return nil
}

View file

@ -7,8 +7,6 @@ package model
import (
"encoding/json"
"fmt"
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
)
type ListRepliesPolicy int
@ -107,53 +105,3 @@ type List struct {
Title string `json:"title"`
Accounts map[string]string
}
func (l List) Display(noColor bool) string {
format := `
%s
%s
%s
%s
%s
%s
%s`
output := fmt.Sprintf(
format,
utilities.HeaderFormat(noColor, "LIST TITLE:"), l.Title,
utilities.HeaderFormat(noColor, "LIST ID:"), l.ID,
utilities.HeaderFormat(noColor, "REPLIES POLICY:"), l.RepliesPolicy,
utilities.HeaderFormat(noColor, "ADDED ACCOUNTS:"),
)
if len(l.Accounts) > 0 {
for acct, name := range l.Accounts {
output += "\n • " + utilities.FullDisplayNameFormat(noColor, name, acct)
}
} else {
output += "\n None"
}
output += "\n"
return output
}
type Lists []List
func (l Lists) Display(noColor bool) string {
output := "\n" + utilities.HeaderFormat(noColor, "LISTS")
for i := range l {
output += fmt.Sprintf(
"\n • %s (%s)",
l[i].Title,
l[i].ID,
)
}
return output
}

View file

@ -0,0 +1 @@
package printer

45
internal/printer/list.go Normal file
View file

@ -0,0 +1,45 @@
package printer
import (
"strings"
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
)
func (p Printer) PrintList(list model.List) {
var builder strings.Builder
builder.WriteString(p.headerFormat("\n" + "LIST TITLE:") + "\n")
builder.WriteString(list.Title + "\n\n")
builder.WriteString(p.headerFormat("LIST ID:") + "\n")
builder.WriteString(list.ID + "\n\n")
builder.WriteString(p.headerFormat("REPLIES POLICY:") + "\n")
builder.WriteString(list.RepliesPolicy.String() + "\n\n")
builder.WriteString(p.headerFormat("ADDED ACCOUNTS:"))
if len(list.Accounts) > 0 {
for acct, name := range list.Accounts {
builder.WriteString("\n" + p.bullet + p.fullDisplayNameFormat(name, acct))
}
} else {
builder.WriteString("\n" + "None")
}
builder.WriteString("\n")
printToStdout(builder.String())
}
func (p Printer) PrintLists(lists []model.List) {
var builder strings.Builder
builder.WriteString("\n" + p.headerFormat("LISTS"))
for i := range lists {
builder.WriteString("\n" + p.bullet + " " + lists[i].Title + " (" + lists[i].ID + ")")
}
builder.WriteString("\n")
printToStdout(builder.String())
}

126
internal/printer/printer.go Normal file
View file

@ -0,0 +1,126 @@
// SPDX-FileCopyrightText: 2024 Dan Anglin <d.n.i.anglin@gmail.com>
//
// SPDX-License-Identifier: GPL-3.0-or-later
package printer
import (
"os"
"regexp"
"strings"
"time"
)
type theme struct {
reset string
boldblue string
boldmagenta string
green string
}
type Printer struct {
theme theme
noColor bool
maxTerminalWidth int
pager string
statusSeparator string
bullet string
pollMeterSymbol string
successSymbol string
failureSymbol string
dateFormat string
dateTimeFormat string
}
func NewPrinter(
noColor bool,
pager string,
maxTerminalWidth int,
) *Printer {
theme := theme{
reset: "\033[0m",
boldblue: "\033[34;1m",
boldmagenta: "\033[35;1m",
green: "\033[32m",
}
return &Printer{
noColor: noColor,
maxTerminalWidth: maxTerminalWidth,
pager: pager,
statusSeparator: strings.Repeat("─", maxTerminalWidth),
bullet: "\u2022",
pollMeterSymbol: "\u2501",
successSymbol: "\u2714",
failureSymbol: "\u2717",
dateFormat: "02 Jan 2006",
dateTimeFormat: "02 Jan 2006, 15:04 (MST)",
theme: theme,
}
}
func (p Printer) PrintSuccess(text string) {
success := p.theme.green + p.successSymbol + p.theme.reset
if p.noColor {
success = p.successSymbol
}
printToStdout(success + " " + text + "\n")
}
func (p Printer) PrintFailure(text string) {
printToStderr(p.failureSymbol + " " + text)
}
func (p Printer) PrintInfo(text string) {
printToStdout(text)
}
func (p Printer) headerFormat(text string) string {
if p.noColor {
return text
}
return p.theme.boldblue + text + p.theme.reset
}
func (p Printer) fieldFormat(text string) string {
if p.noColor {
return text
}
return p.theme.green + text + p.theme.reset
}
func (p Printer) fullDisplayNameFormat(displayName, acct string) string {
// use this pattern to remove all emoji strings
pattern := regexp.MustCompile(`\s:[A-Za-z0-9_]*:`)
var builder strings.Builder
if p.noColor {
builder.WriteString(pattern.ReplaceAllString(displayName, ""))
} else {
builder.WriteString(p.theme.boldmagenta + pattern.ReplaceAllString(displayName, "") + p.theme.reset)
}
builder.WriteString(" (@" + acct + ")")
return builder.String()
}
func (p Printer) formatDate(date time.Time) string {
return date.Local().Format(p.dateFormat)
}
func (p Printer) formatDateTime(date time.Time) string {
return date.Local().Format(p.dateTimeFormat)
}
func printToStdout(text string) {
os.Stdout.WriteString(text)
}
func printToStderr(text string) {
os.Stderr.WriteString(text)
}

View file

@ -0,0 +1,33 @@
// SPDX-FileCopyrightText: 2024 Dan Anglin <d.n.i.anglin@gmail.com>
//
// SPDX-License-Identifier: GPL-3.0-or-later
package printer
import (
"strings"
"text/tabwriter"
)
func (p Printer) PrintVersion(showFullVersion bool, binaryVersion, buildTime, goVersion, gitCommit string) {
if !showFullVersion {
printToStdout("Enbas " + binaryVersion + "\n")
return
}
var builder strings.Builder
builder.WriteString(p.headerFormat("Enbas") + "\n\n")
tableWriter := tabwriter.NewWriter(&builder, 0, 4, 1, ' ', 0)
_, _ = tableWriter.Write([]byte(p.fieldFormat("Version:") + "\t" + binaryVersion + "\n"))
_, _ = tableWriter.Write([]byte(p.fieldFormat("Git commit:") + "\t" + gitCommit + "\n"))
_, _ = tableWriter.Write([]byte(p.fieldFormat("Go version:") + "\t" + goVersion + "\n"))
_, _ = tableWriter.Write([]byte(p.fieldFormat("Build date:") + "\t" + buildTime + "\n"))
tableWriter.Flush()
printToStdout(builder.String())
}