mirror of
https://github.com/makew0rld/amfora.git
synced 2025-02-02 15:07:34 -05:00
Adds support for custom commands (#265)
* Adds support for custom commands Supports up to 10 custom commands, defined in the configuration file. The current or selected URL can be passed to the command by placing ${url} in the command string. Default hotkeys are Alt-1 through Alt-0 for triggering the command with the selected link URL as a parameter, or Alt-Shift-1 through Alt-Shift-0 for triggering the command with the current page URL as a parameter. This follows the convention set by the copy page URL (C) and copy selected URL (c) defaults. Custom commands must be available in the $PATH or use absolute paths. Relative paths are not supported, neither are pipes or shell redirections. * Fix linting issues * Fix typo * Further clarify comment * Use goroutines for Error/Info calls * Run go fmt to fix issue from merge --------- Co-authored-by: makeworld <makeworld@protonmail.com>
This commit is contained in:
parent
b5c921cf11
commit
fd8f122ec0
@ -143,6 +143,7 @@ Features in *italics* are in the master branch, but not in the latest release.
|
||||
- Ability to stream content instead of downloading it first
|
||||
- Highlighting of preformatted code blocks that list a language in the alt text
|
||||
- *Search in pages with <kbd>Ctrl-F</kbd>*
|
||||
- *Run custom commands using the current or selected URL as an argument*
|
||||
|
||||
|
||||
## Usage & Configuration
|
||||
|
22
command/command.go
Normal file
22
command/command.go
Normal file
@ -0,0 +1,22 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// RunCommand runs `command`, replacing the string "${url}" with `url`.
|
||||
func RunCommand(command string, url string) (string, error) {
|
||||
cmdWithURL := strings.ReplaceAll(command, "${url}", url)
|
||||
cmdSplit := strings.SplitN(cmdWithURL, " ", 2)
|
||||
if len(cmdSplit) > 1 {
|
||||
if err := exec.Command(cmdSplit[0], cmdSplit[1]).Start(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return "Ran command " + cmdSplit[0] + " with args " + cmdSplit[1], nil
|
||||
}
|
||||
if err := exec.Command(cmdWithURL).Start(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return "Ran command " + cmdWithURL, nil
|
||||
}
|
@ -207,6 +207,16 @@ func Init() error {
|
||||
viper.SetDefault("a-general.page_max_time", 10)
|
||||
viper.SetDefault("a-general.scrollbar", "auto")
|
||||
viper.SetDefault("a-general.underline", true)
|
||||
viper.SetDefault("commands.command1", "")
|
||||
viper.SetDefault("commands.command2", "")
|
||||
viper.SetDefault("commands.command3", "")
|
||||
viper.SetDefault("commands.command4", "")
|
||||
viper.SetDefault("commands.command5", "")
|
||||
viper.SetDefault("commands.command6", "")
|
||||
viper.SetDefault("commands.command7", "")
|
||||
viper.SetDefault("commands.command8", "")
|
||||
viper.SetDefault("commands.command9", "")
|
||||
viper.SetDefault("commands.command0", "")
|
||||
viper.SetDefault("keybindings.bind_reload", []string{"R", "Ctrl-R"})
|
||||
viper.SetDefault("keybindings.bind_home", "Backspace")
|
||||
viper.SetDefault("keybindings.bind_bookmarks", "Ctrl-B")
|
||||
@ -250,6 +260,26 @@ func Init() error {
|
||||
viper.SetDefault("keybindings.bind_tab8", "*")
|
||||
viper.SetDefault("keybindings.bind_tab9", "(")
|
||||
viper.SetDefault("keybindings.bind_tab0", ")")
|
||||
viper.SetDefault("keybindings.bind_command1", "Alt-!")
|
||||
viper.SetDefault("keybindings.bind_command2", "Alt-@")
|
||||
viper.SetDefault("keybindings.bind_command3", "Alt-#")
|
||||
viper.SetDefault("keybindings.bind_command4", "Alt-$")
|
||||
viper.SetDefault("keybindings.bind_command5", "Alt-%")
|
||||
viper.SetDefault("keybindings.bind_command6", "Alt-^")
|
||||
viper.SetDefault("keybindings.bind_command7", "Alt-&")
|
||||
viper.SetDefault("keybindings.bind_command8", "Alt-*")
|
||||
viper.SetDefault("keybindings.bind_command9", "Alt-(")
|
||||
viper.SetDefault("keybindings.bind_command0", "Alt-)")
|
||||
viper.SetDefault("keybindings.bind_command_target1", "Alt-1")
|
||||
viper.SetDefault("keybindings.bind_command_target2", "Alt-2")
|
||||
viper.SetDefault("keybindings.bind_command_target3", "Alt-3")
|
||||
viper.SetDefault("keybindings.bind_command_target4", "Alt-4")
|
||||
viper.SetDefault("keybindings.bind_command_target5", "Alt-5")
|
||||
viper.SetDefault("keybindings.bind_command_target6", "Alt-6")
|
||||
viper.SetDefault("keybindings.bind_command_target7", "Alt-7")
|
||||
viper.SetDefault("keybindings.bind_command_target8", "Alt-8")
|
||||
viper.SetDefault("keybindings.bind_command_target9", "Alt-9")
|
||||
viper.SetDefault("keybindings.bind_command_target0", "Alt-0")
|
||||
viper.SetDefault("keybindings.bind_copy_page_url", "C")
|
||||
viper.SetDefault("keybindings.bind_copy_target_url", "c")
|
||||
viper.SetDefault("keybindings.bind_beginning", []string{"Home", "g"})
|
||||
|
@ -112,6 +112,26 @@ underline = true
|
||||
# Same as [auth.certs] but the path is to the client key file.
|
||||
|
||||
|
||||
[commands]
|
||||
# Define up to 10 custom commands to execute on the corresponding hotkey press.
|
||||
# Commands are run in a new process and will not terminate when Amfora is closed.
|
||||
# If you need your command to accept additional input, it is recommended to open
|
||||
# a GUI or use a terminal multiplexer like screen or tmux. The string ${url} will
|
||||
# be replaced with the current or selected URL. Note that pipes and redirections
|
||||
# are not allowed, if these are needed then you should set up a script. Use only
|
||||
# absolute paths and/or reference executables in your $PATH.
|
||||
# command1 = "my-script -a -b -c ${url}"
|
||||
# command2 = ""
|
||||
# command3 = ""
|
||||
# command4 = ""
|
||||
# command5 = ""
|
||||
# command6 = ""
|
||||
# command7 = ""
|
||||
# command8 = ""
|
||||
# command9 = ""
|
||||
# command0 = ""
|
||||
|
||||
|
||||
[keybindings]
|
||||
# If you have a non-US keyboard, use bind_tab1 through bind_tab0 to
|
||||
# setup the shift-number bindings: Eg, for US keyboards (the default):
|
||||
@ -159,6 +179,32 @@ underline = true
|
||||
# bind_link9 = "9"
|
||||
# bind_link0 = "0"
|
||||
|
||||
# The bind_command[0-9] options are for the command hotkeys. This will pass the URL of the
|
||||
# current tab as an argument.
|
||||
# bind_command1 = "Alt-!"
|
||||
# bind_command2 = "Alt-@"
|
||||
# bind_command3 = "Alt-#"
|
||||
# bind_command4 = "Alt-$"
|
||||
# bind_command5 = "Alt-%"
|
||||
# bind_command6 = "Alt-^"
|
||||
# bind_command7 = "Alt-&"
|
||||
# bind_command8 = "Alt-*"
|
||||
# bind_command9 = "Alt-("
|
||||
# bind_command0 = "Alt-)"
|
||||
|
||||
# The bind_commandtarget[0-9] options are for command hotkeys that operate on the currently
|
||||
# highlighted link. This will pass the URL of the highlighted link as an argument.
|
||||
# bind_command_target1 = "Alt-1"
|
||||
# bind_command_target2 = "Alt-2"
|
||||
# bind_command_target3 = "Alt-3"
|
||||
# bind_command_target4 = "Alt-4"
|
||||
# bind_command_target5 = "Alt-5"
|
||||
# bind_command_target6 = "Alt-6"
|
||||
# bind_command_target7 = "Alt-7"
|
||||
# bind_command_target8 = "Alt-8"
|
||||
# bind_command_target9 = "Alt-9"
|
||||
# bind_command_target0 = "Alt-0"
|
||||
|
||||
# All keybindings:
|
||||
#
|
||||
# bind_bottom
|
||||
|
@ -8,33 +8,55 @@ import (
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
// NOTE: CmdLink[1-90] and CmdTab[1-90] need to be in-order and consecutive
|
||||
// This property is used to simplify key handling in display/display.go
|
||||
// NOTE: CmdLink[1-90], CmdTab[1-90], CmdCommand[1-90], and
|
||||
// CmdCommandTarget[1-90] need to be in-order and consecutive. This
|
||||
// property is used to simplify key handling in display/display.go
|
||||
// and display/tab.go
|
||||
type Command int
|
||||
|
||||
const (
|
||||
CmdInvalid Command = 0
|
||||
CmdLink1 = 1
|
||||
CmdLink2 = 2
|
||||
CmdLink3 = 3
|
||||
CmdLink4 = 4
|
||||
CmdLink5 = 5
|
||||
CmdLink6 = 6
|
||||
CmdLink7 = 7
|
||||
CmdLink8 = 8
|
||||
CmdLink9 = 9
|
||||
CmdLink0 = 10
|
||||
CmdTab1 = 11
|
||||
CmdTab2 = 12
|
||||
CmdTab3 = 13
|
||||
CmdTab4 = 14
|
||||
CmdTab5 = 15
|
||||
CmdTab6 = 16
|
||||
CmdTab7 = 17
|
||||
CmdTab8 = 18
|
||||
CmdTab9 = 19
|
||||
CmdTab0 = 20
|
||||
CmdBottom = iota
|
||||
CmdInvalid Command = 0
|
||||
CmdLink1 = 1
|
||||
CmdLink2 = 2
|
||||
CmdLink3 = 3
|
||||
CmdLink4 = 4
|
||||
CmdLink5 = 5
|
||||
CmdLink6 = 6
|
||||
CmdLink7 = 7
|
||||
CmdLink8 = 8
|
||||
CmdLink9 = 9
|
||||
CmdLink0 = 10
|
||||
CmdTab1 = 11
|
||||
CmdTab2 = 12
|
||||
CmdTab3 = 13
|
||||
CmdTab4 = 14
|
||||
CmdTab5 = 15
|
||||
CmdTab6 = 16
|
||||
CmdTab7 = 17
|
||||
CmdTab8 = 18
|
||||
CmdTab9 = 19
|
||||
CmdTab0 = 20
|
||||
CmdCommand1 = 21
|
||||
CmdCommand2 = 22
|
||||
CmdCommand3 = 23
|
||||
CmdCommand4 = 24
|
||||
CmdCommand5 = 25
|
||||
CmdCommand6 = 26
|
||||
CmdCommand7 = 27
|
||||
CmdCommand8 = 28
|
||||
CmdCommand9 = 29
|
||||
CmdCommand0 = 30
|
||||
CmdCommandTarget1 = 31
|
||||
CmdCommandTarget2 = 32
|
||||
CmdCommandTarget3 = 33
|
||||
CmdCommandTarget4 = 34
|
||||
CmdCommandTarget5 = 35
|
||||
CmdCommandTarget6 = 36
|
||||
CmdCommandTarget7 = 37
|
||||
CmdCommandTarget8 = 38
|
||||
CmdCommandTarget9 = 39
|
||||
CmdCommandTarget0 = 40
|
||||
CmdBottom = iota
|
||||
CmdEdit
|
||||
CmdHome
|
||||
CmdBookmarks
|
||||
@ -203,9 +225,29 @@ func KeyInit() {
|
||||
CmdBeginning: "keybindings.bind_beginning",
|
||||
CmdEnd: "keybindings.bind_end",
|
||||
CmdURLHandlerOpen: "keybindings.bind_url_handler_open",
|
||||
CmdSearch: "keybindings.bind_search",
|
||||
CmdNextMatch: "keybindings.bind_next_match",
|
||||
CmdPrevMatch: "keybindings.bind_prev_match",
|
||||
CmdCommand1: "keybindings.bind_command1",
|
||||
CmdCommand2: "keybindings.bind_command2",
|
||||
CmdCommand3: "keybindings.bind_command3",
|
||||
CmdCommand4: "keybindings.bind_command4",
|
||||
CmdCommand5: "keybindings.bind_command5",
|
||||
CmdCommand6: "keybindings.bind_command6",
|
||||
CmdCommand7: "keybindings.bind_command7",
|
||||
CmdCommand8: "keybindings.bind_command8",
|
||||
CmdCommand9: "keybindings.bind_command9",
|
||||
CmdCommand0: "keybindings.bind_command0",
|
||||
CmdCommandTarget1: "keybindings.bind_command_target1",
|
||||
CmdCommandTarget2: "keybindings.bind_command_target2",
|
||||
CmdCommandTarget3: "keybindings.bind_command_target3",
|
||||
CmdCommandTarget4: "keybindings.bind_command_target4",
|
||||
CmdCommandTarget5: "keybindings.bind_command_target5",
|
||||
CmdCommandTarget6: "keybindings.bind_command_target6",
|
||||
CmdCommandTarget7: "keybindings.bind_command_target7",
|
||||
CmdCommandTarget8: "keybindings.bind_command_target8",
|
||||
CmdCommandTarget9: "keybindings.bind_command_target9",
|
||||
CmdCommandTarget0: "keybindings.bind_command_target0",
|
||||
CmdSearch: "keybindings.bind_search",
|
||||
CmdNextMatch: "keybindings.bind_next_match",
|
||||
CmdPrevMatch: "keybindings.bind_prev_match",
|
||||
}
|
||||
// This is split off to allow shift_numbers to override bind_tab[1-90]
|
||||
// (This is needed for older configs so that the default bind_tab values
|
||||
|
@ -109,6 +109,26 @@ underline = true
|
||||
# Same as [auth.certs] but the path is to the client key file.
|
||||
|
||||
|
||||
[commands]
|
||||
# Define up to 10 custom commands to execute on the corresponding hotkey press.
|
||||
# Commands are run in a new process and will not terminate when Amfora is closed.
|
||||
# If you need your command to accept additional input, it is recommended to open
|
||||
# a GUI or use a terminal multiplexer like screen or tmux. The string ${url} will
|
||||
# be replaced with the current or selected URL. Note that pipes and redirections
|
||||
# are not allowed, if these are needed then you should set up a script. Use only
|
||||
# absolute paths and/or reference executables in your $PATH.
|
||||
# command1 = "my-script -a -b -c ${url}"
|
||||
# command2 = ""
|
||||
# command3 = ""
|
||||
# command4 = ""
|
||||
# command5 = ""
|
||||
# command6 = ""
|
||||
# command7 = ""
|
||||
# command8 = ""
|
||||
# command9 = ""
|
||||
# command0 = ""
|
||||
|
||||
|
||||
[keybindings]
|
||||
# If you have a non-US keyboard, use bind_tab1 through bind_tab0 to
|
||||
# setup the shift-number bindings: Eg, for US keyboards (the default):
|
||||
@ -156,6 +176,32 @@ underline = true
|
||||
# bind_link9 = "9"
|
||||
# bind_link0 = "0"
|
||||
|
||||
# The bind_command[0-9] options are for the command hotkeys. This will pass the URL of the
|
||||
# current tab as an argument.
|
||||
# bind_command1 = "Alt-!"
|
||||
# bind_command2 = "Alt-@"
|
||||
# bind_command3 = "Alt-#"
|
||||
# bind_command4 = "Alt-$"
|
||||
# bind_command5 = "Alt-%"
|
||||
# bind_command6 = "Alt-^"
|
||||
# bind_command7 = "Alt-&"
|
||||
# bind_command8 = "Alt-*"
|
||||
# bind_command9 = "Alt-("
|
||||
# bind_command0 = "Alt-)"
|
||||
|
||||
# The bind_commandtarget[0-9] options are for command hotkeys that operate on the currently
|
||||
# highlighted link. This will pass the URL of the highlighted link as an argument.
|
||||
# bind_command_target1 = "Alt-1"
|
||||
# bind_command_target2 = "Alt-2"
|
||||
# bind_command_target3 = "Alt-3"
|
||||
# bind_command_target4 = "Alt-4"
|
||||
# bind_command_target5 = "Alt-5"
|
||||
# bind_command_target6 = "Alt-6"
|
||||
# bind_command_target7 = "Alt-7"
|
||||
# bind_command_target8 = "Alt-8"
|
||||
# bind_command_target9 = "Alt-9"
|
||||
# bind_command_target0 = "Alt-0"
|
||||
|
||||
# All keybindings:
|
||||
#
|
||||
# bind_bottom
|
||||
|
35
display/command.go
Normal file
35
display/command.go
Normal file
@ -0,0 +1,35 @@
|
||||
package display
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/makeworld-the-better-one/amfora/command"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
// CustomCommand runs custom commands as defined in the app configuration.
|
||||
// Commands are zero-indexed, so 0 is command1 and 9 is command0 (10).
|
||||
func CustomCommand(num int, url string) {
|
||||
if num < 0 {
|
||||
num = 0
|
||||
}
|
||||
num++
|
||||
if num > 9 {
|
||||
num = 0
|
||||
}
|
||||
|
||||
cmd := viper.GetString("commands.command" + strconv.Itoa(num))
|
||||
if len(cmd) > 0 {
|
||||
msg, err := command.RunCommand(cmd, url)
|
||||
if err != nil {
|
||||
go Error("Command Error", err.Error())
|
||||
return
|
||||
}
|
||||
go Info(msg)
|
||||
} else {
|
||||
go Error("Command Error", "Command "+strconv.Itoa(num)+" not defined")
|
||||
return
|
||||
}
|
||||
|
||||
App.Draw()
|
||||
}
|
@ -49,6 +49,10 @@ var helpCells = strings.TrimSpace(
|
||||
"%s\tSave the current page to your downloads.\n" +
|
||||
"%s\tView subscriptions\n" +
|
||||
"%s\tAdd or update a subscription\n" +
|
||||
"%s\tExecute a custom command using the current page URL as an argument.\n" +
|
||||
"\t(Default: Alt-Shift-NUMBER)\n" +
|
||||
"%s\tExecute a custom command using the selected URL as an argument.\n" +
|
||||
"\t(Default: Alt-NUMBER)\n" +
|
||||
"%s\tSearch the page content for a string\n" +
|
||||
"%s\tFind next search match\n" +
|
||||
"%s\tFind previous search match\n" +
|
||||
@ -82,6 +86,10 @@ func helpInit() {
|
||||
strings.Split(config.GetKeyBinding(config.CmdTab9), ",")[0])
|
||||
linkKeys := fmt.Sprintf("%s to %s", strings.Split(config.GetKeyBinding(config.CmdLink1), ",")[0],
|
||||
strings.Split(config.GetKeyBinding(config.CmdLink0), ",")[0])
|
||||
commandKeys := fmt.Sprintf("%s to %s", strings.Split(config.GetKeyBinding(config.CmdCommand1), ",")[0],
|
||||
strings.Split(config.GetKeyBinding(config.CmdCommand0), ",")[0])
|
||||
commandTargetKeys := fmt.Sprintf("%s to %s", strings.Split(config.GetKeyBinding(config.CmdCommandTarget1), ",")[0],
|
||||
strings.Split(config.GetKeyBinding(config.CmdCommandTarget0), ",")[0])
|
||||
|
||||
helpCells = fmt.Sprintf(helpCells,
|
||||
config.GetKeyBinding(config.CmdMoveLeft),
|
||||
@ -113,6 +121,8 @@ func helpInit() {
|
||||
config.GetKeyBinding(config.CmdSave),
|
||||
config.GetKeyBinding(config.CmdSub),
|
||||
config.GetKeyBinding(config.CmdAddSub),
|
||||
commandKeys,
|
||||
commandTargetKeys,
|
||||
config.GetKeyBinding(config.CmdSearch),
|
||||
config.GetKeyBinding(config.CmdNextMatch),
|
||||
config.GetKeyBinding(config.CmdPrevMatch),
|
||||
|
@ -241,6 +241,29 @@ func makeNewTab() *tab {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
// Command key: 1-9, 0, COMMAND1
|
||||
if cmd >= config.CmdCommand1 && cmd <= config.CmdCommand0 {
|
||||
commandNum := int(cmd - config.CmdCommand1)
|
||||
tabURL := tabs[curTab].page.URL
|
||||
CustomCommand(commandNum, tabURL)
|
||||
return nil
|
||||
}
|
||||
// Target link command key: 1-9, 0, COMMANDTARGET1-COMMANDTARGET10
|
||||
if cmd >= config.CmdCommandTarget1 && cmd <= config.CmdCommandTarget0 {
|
||||
commandNum := int(cmd - config.CmdCommandTarget1)
|
||||
currentURL := t.page.URL
|
||||
selectedURL := t.highlightedURL()
|
||||
|
||||
if selectedURL == "" {
|
||||
return nil
|
||||
}
|
||||
u, _ := url.Parse(currentURL)
|
||||
parsedURL, err := u.Parse(selectedURL)
|
||||
if err == nil {
|
||||
CustomCommand(commandNum, parsedURL.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Scrolling stuff
|
||||
// Copied in scrollTo
|
||||
|
Loading…
x
Reference in New Issue
Block a user