1
0
mirror of https://github.com/makew0rld/amfora.git synced 2024-06-01 18:31:08 +00:00

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.
This commit is contained in:
mntn 2021-10-16 15:31:52 -04:00
parent e8122fc52d
commit 7fa774b7f7
9 changed files with 316 additions and 61 deletions

View File

@ -142,6 +142,7 @@ Features in *italics* are in the master branch, but not in the latest release.
- So is subscribing to a page, to know when it changes
- [x] Open non-text files in another application
- [x] Ability to stream content instead of downloading it first
- [x] Run custom commands using the current or selected URL as an argument
- [ ] Stream support
- [ ] Table of contents for pages
- [ ] Search in pages with <kbd>Ctrl-F</kbd>

23
command/command.go Normal file
View File

@ -0,0 +1,23 @@
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
} else {
if err := exec.Command(cmdWithUrl).Start(); err != nil {
return "", err
}
return "Ran command " + cmdWithUrl, nil
}
}

View File

@ -203,6 +203,16 @@ func Init() error {
viper.SetDefault("a-general.page_max_size", 2097152)
viper.SetDefault("a-general.page_max_time", 10)
viper.SetDefault("a-general.scrollbar", "auto")
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")
@ -246,6 +256,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"})

View File

@ -90,6 +90,26 @@ scrollbar = "auto"
# "example.com" = 'mycert.key'
[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):
@ -137,6 +157,32 @@ scrollbar = "auto"
# 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

View File

@ -8,33 +8,54 @@ 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], and CmdCommand[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
@ -156,43 +177,63 @@ func parseBinding(cmd Command, binding string) {
// Called by config.Init()
func KeyInit() {
configBindings := map[Command]string{
CmdLink1: "keybindings.bind_link1",
CmdLink2: "keybindings.bind_link2",
CmdLink3: "keybindings.bind_link3",
CmdLink4: "keybindings.bind_link4",
CmdLink5: "keybindings.bind_link5",
CmdLink6: "keybindings.bind_link6",
CmdLink7: "keybindings.bind_link7",
CmdLink8: "keybindings.bind_link8",
CmdLink9: "keybindings.bind_link9",
CmdLink0: "keybindings.bind_link0",
CmdBottom: "keybindings.bind_bottom",
CmdEdit: "keybindings.bind_edit",
CmdHome: "keybindings.bind_home",
CmdBookmarks: "keybindings.bind_bookmarks",
CmdAddBookmark: "keybindings.bind_add_bookmark",
CmdSave: "keybindings.bind_save",
CmdReload: "keybindings.bind_reload",
CmdBack: "keybindings.bind_back",
CmdForward: "keybindings.bind_forward",
CmdMoveUp: "keybindings.bind_moveup",
CmdMoveDown: "keybindings.bind_movedown",
CmdMoveLeft: "keybindings.bind_moveleft",
CmdMoveRight: "keybindings.bind_moveright",
CmdPgup: "keybindings.bind_pgup",
CmdPgdn: "keybindings.bind_pgdn",
CmdNewTab: "keybindings.bind_new_tab",
CmdCloseTab: "keybindings.bind_close_tab",
CmdNextTab: "keybindings.bind_next_tab",
CmdPrevTab: "keybindings.bind_prev_tab",
CmdQuit: "keybindings.bind_quit",
CmdHelp: "keybindings.bind_help",
CmdSub: "keybindings.bind_sub",
CmdAddSub: "keybindings.bind_add_sub",
CmdCopyPageURL: "keybindings.bind_copy_page_url",
CmdCopyTargetURL: "keybindings.bind_copy_target_url",
CmdBeginning: "keybindings.bind_beginning",
CmdEnd: "keybindings.bind_end",
CmdLink1: "keybindings.bind_link1",
CmdLink2: "keybindings.bind_link2",
CmdLink3: "keybindings.bind_link3",
CmdLink4: "keybindings.bind_link4",
CmdLink5: "keybindings.bind_link5",
CmdLink6: "keybindings.bind_link6",
CmdLink7: "keybindings.bind_link7",
CmdLink8: "keybindings.bind_link8",
CmdLink9: "keybindings.bind_link9",
CmdLink0: "keybindings.bind_link0",
CmdBottom: "keybindings.bind_bottom",
CmdEdit: "keybindings.bind_edit",
CmdHome: "keybindings.bind_home",
CmdBookmarks: "keybindings.bind_bookmarks",
CmdAddBookmark: "keybindings.bind_add_bookmark",
CmdSave: "keybindings.bind_save",
CmdReload: "keybindings.bind_reload",
CmdBack: "keybindings.bind_back",
CmdForward: "keybindings.bind_forward",
CmdMoveUp: "keybindings.bind_moveup",
CmdMoveDown: "keybindings.bind_movedown",
CmdMoveLeft: "keybindings.bind_moveleft",
CmdMoveRight: "keybindings.bind_moveright",
CmdPgup: "keybindings.bind_pgup",
CmdPgdn: "keybindings.bind_pgdn",
CmdNewTab: "keybindings.bind_new_tab",
CmdCloseTab: "keybindings.bind_close_tab",
CmdNextTab: "keybindings.bind_next_tab",
CmdPrevTab: "keybindings.bind_prev_tab",
CmdQuit: "keybindings.bind_quit",
CmdHelp: "keybindings.bind_help",
CmdSub: "keybindings.bind_sub",
CmdAddSub: "keybindings.bind_add_sub",
CmdCopyPageURL: "keybindings.bind_copy_page_url",
CmdCopyTargetURL: "keybindings.bind_copy_target_url",
CmdBeginning: "keybindings.bind_beginning",
CmdEnd: "keybindings.bind_end",
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",
}
// 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

View File

@ -87,6 +87,26 @@ scrollbar = "auto"
# "example.com" = 'mycert.key'
[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):
@ -134,6 +154,32 @@ scrollbar = "auto"
# 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
View 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 = num + 1
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 {
Error("Command Error", err.Error())
return
}
Info(msg)
} else {
Error("Command Error", "Command " + strconv.Itoa(num) + " not defined")
return
}
App.Draw()
}

View File

@ -48,6 +48,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\tQuit\n")
var helpTable = cview.NewTextView()
@ -78,6 +82,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),
@ -108,6 +116,8 @@ func helpInit() {
config.GetKeyBinding(config.CmdSave),
config.GetKeyBinding(config.CmdSub),
config.GetKeyBinding(config.CmdAddSub),
commandKeys,
commandTargetKeys,
config.GetKeyBinding(config.CmdQuit),
)

View File

@ -213,6 +213,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-COMMANDTERGET10
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