ref: ae53203b51d8666b4aee0537537450044234c830
dir: /commands.go/
package main
import (
"fmt"
"strings"
mastodon "codeberg.org/penny64/hellclient-go-mastodon"
)
var commands = []string{"examine", "reply", "like", "thread", "open", "prev", "download", "dm", "rt", "hrt", "parent", "children", "rm", "mark", "unmark", "account", "import", "pause", "resume", "url", "fpost", "ufpost", "edit", "notice", "stats", "next", "view", "bookmarks", "follow", "unfollow", "likes", "help", "reload", "attach", "detach", "pinned", "cat", "play", "translate", "read", "version", "local", "public", "block", "unblock", "unlike", "home", "page", "profile"}
func processInput(input string) (command string, arguments string, found bool) {
if input == "" {
command = ""
arguments = ""
return
}
if input[0] != '/' {
command = ""
arguments = input
return
}
inputcommand, _, hasargument := strings.Cut(input[1:], " ")
if !hasargument {
inputcommand = input[1:]
}
for _, choice := range commands {
if strings.HasPrefix(choice, inputcommand) {
command = choice
_, arguments, _ = strings.Cut(input, " ")
found = true
break
}
}
if command == "" {
command = inputcommand
}
return
}
func pullParameter(input string) (parameter string, remainder string) {
if strings.HasPrefix(input, "?") {
parameter, _, _ = strings.Cut(input, " ")
if len(parameter) == len(input) {
remainder = ""
parameter = input
} else {
remainder = input[len(parameter)+1:]
}
} else {
return "", input
}
prefix, _, cut := strings.Cut(parameter, "\"")
if cut {
quote, _, _ := strings.Cut(input[len(prefix)+1:], "\"")
parameter = prefix + quote
if len(parameter)+3 <= len(input) {
remainder = input[len(parameter)+3:]
} else {
remainder = input[len(parameter)+2:]
}
}
return
}
func splitParameter(input string) (parameter []string) {
if len(input) < 2 {
//nothing here
return nil
}
input = input[1:]
key, value, _ := strings.Cut(input, "=")
return []string{key, value}
}
func extractInputParameters(input string) (remainder string, parameters [][]string) {
parameter := " "
remainder = input
for parameter != "" {
parameter, remainder = pullParameter(remainder)
if parameter != " " && parameter != "" {
parameters = append(parameters, splitParameter(parameter))
}
}
return
}
type cmdflag uint8
const (
free cmdflag = 1 << iota
status
account
argument
)
type cmdloader struct {
hc *Hellclient
lastindex string
lastaccount *mastodon.Account
}
// Cases
// Return loaded account if tag was foundor was empty but loaded
// Return loaded account if index was empty
// If there's no last account, load the account by index and return it
// If index is empty or . return last account
func (data *cmddata) lookupAccount(loader *cmdloader) *mastodon.Account {
if data.found_index {
return data.account
}
if data.index == "" && data.account != nil {
return data.account
}
if loader.lastaccount == nil {
account := loader.hc.resolveAccount(data.index)
if account == nil {
return nil
}
}
loader.lastaccount = account
loader.lastindex = ""
return account
}
func (loader *cmdloader) processLine(line string) (*cmddata, error) {
command, arguments, _ := processInput(line)
index, content, _ := strings.Cut(arguments, " ")
fmt.Printf("index: %s\n", index)
// "." refers to most recently acted on status
// but if we have an account set, we don't want to set an index!
var dot_index bool
if index == "." && loader.lastaccount == nil {
dot_index = true
index = loader.lastindex
}
postItem, postOK := loader.hc.homeMap[index]
foundindex := false
//If there's no index selected load the last post we operated on
if postOK {
foundindex = true
loader.lastindex = index
loader.lastaccount = nil
} else {
postItem, postOK = loader.hc.homeMap[loader.lastindex]
}
var reblogger *mastodon.Status
//Okay now see if the post we end up with is a reblog
if postOK {
if postItem.Reblog != nil {
reblogger = postItem
postItem = postItem.Reblog
}
}
cmdctx := &cmddata{
command: command,
content: content,
raw_argument: arguments,
dot_index: dot_index,
found_index: foundindex,
index: index,
}
if loader.lastaccount != nil {
cmdctx.account = loader.lastaccount
}
if postOK {
cmdctx.status = postItem
cmdctx.account = &postItem.Account
cmdctx.reblogger = reblogger
}
return cmdctx, nil
}
type cmddata struct {
status *mastodon.Status
account *mastodon.Account
reblogger *mastodon.Status
raw_argument string
command string
content string
found_index bool
dot_index bool
index string
}
// Cmder interface and post data
type cmd struct {
data *cmddata
cmder cmder
}
type cmder interface {
name() string
flags() cmdflag
result(data *cmddata) string
}
func (cmd *cmd) String() string {
return cmd.cmder.result(cmd.data)
}
// return an error message if cmddata matches cmders flags
func (cmd *cmd) checkReqs() (err error) {
if(cmd.cmder.flags()&free !=0) {
return nil
}
if (cmd.cmder.flags()&status != 0) && (cmd.cmder.flags()&account != 0) {
if cmd.data.status == nil && cmd.data.account == nil {
return fmt.Errorf("%s requires a status or an account", cmd.cmder.name())
}
} else {
if (cmd.cmder.flags()&status != 0) && (cmd.data.status == nil) {
return fmt.Errorf("%s requires a status", cmd.cmder.name())
}
if (cmd.cmder.flags()&account != 0) && (cmd.data.account == nil) {
return fmt.Errorf("%s requires an account", cmd.cmder.name())
}
}
if (cmd.cmder.flags()&argument != 0) && (cmd.data.raw_argument == "") {
return fmt.Errorf("%s requires an argument", cmd.cmder.name())
}
return nil
}
type dmcmd struct {
*Hellclient
}
func (cmd *dmcmd) name() string {
return "dm"
}
func (cmd *dmcmd) flags() cmdflag {
return argument
}
func (cmd *dmcmd) result(data *cmddata) string {
hc := cmd.Hellclient
if data.raw_argument != "" {
hc.dispatchStatus(data.raw_argument, "direct")
return ""
}
hc.page = &Page{}
getter := &BasicStatusGetter{getter: hc.client.GetTimelineDirect}
hc.page.loader = &StatusPages{hc: hc, getter: getter}
fmt.Print(hc.page.String())
hc.pause(true)
return ""
}
type profilecmd struct {
*Hellclient
*cmdloader
}
func (cmd *profilecmd) name() string {
return "profile"
}
func (cmd *profilecmd) flags() cmdflag {
return free
}
func (cmd *profilecmd) result(data *cmddata) string {
hc := cmd.Hellclient
account := data.lookupAccount(cmd.cmdloader)
if account == nil {
return fmt.Sprintf("Account lookup failed.\n")
}
return fmt.Sprint(hc.formatAccount(account))
}