From 9d38354a0f53819d2274c8c8c611a72ae9c19b31 Mon Sep 17 00:00:00 2001 From: matryer Date: Fri, 2 Apr 2021 14:11:28 +0100 Subject: [PATCH] added run in terminal feature --- README.md | 23 ++++++++++++++++++++++- app/app.go | 16 ++++++++++++++++ app/menu_parser.go | 2 +- app/settings.go | 24 ++++++++++++++++++++++++ pkg/plugins/plugin.go | 30 ++++++++++++++++++++++++++++++ 5 files changed, 93 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 44f2e999f..d649e1463 100644 --- a/README.md +++ b/README.md @@ -335,7 +335,7 @@ It is possible to control xbar using special `xbar://` URLs: * `xbar://app.xbarapp.com/openPlugin?path=path/to/plugin` - `openPlugin` opens a plugin in the app * `xbar://app.xbarapp.com/refreshPlugin?path=path/to/plugin` - `refreshPlugin` refreshes a specific plugin -### Variables JSON files +### Plugin variable JSON files Variables are stored in JSON files alongside your plugin. The key is the name of the Variable and the name of the environment variable. The values are the user's preferences. @@ -350,6 +350,27 @@ For example, the variables file for the `tail.5s.sh` plugin looks like this: } ``` +### Xbar config + +You can control xbar behaviour by modifying the `/Library/Application Support/xbar/xbar.config.json` file: + +* This file doesn't exist by default, you may need to create it. + +```json +{ + "autoupdate": true, + "terminal": { + "appleScriptTemplate": "" + } +} +``` + +* Change take effect next time xbar starts +* `autoupdate` - (boolean) whether to keep xbar automatically updated or not +* `terminal.appleScriptTemplate` - (string) the AppleScript to use when **Run in terminal** option is used (use `"false"` to turn this feature off) + +You can delete this file and restart xbar to reset to defaults. + ## Thanks * Special thanks to [@leaanthony at https://wails.app](https://wails.app) and [@ianfoo](https://github.com/ianfoo), [@gingerbeardman](https://github.com/gingerbeardman), [@iosdeveloper](https://github.com/iosdeveloper), [@muhqu](https://github.com/muhqu), [@m-cat](https://github.com/m-cat), [@mpicard](https://github.com/mpicard), [@tylerb](https://github.com/tylerb) for their help diff --git a/app/app.go b/app/app.go index 1f0dd9343..760ec882e 100644 --- a/app/app.go +++ b/app/app.go @@ -546,6 +546,22 @@ func (app *app) onRefresh(ctx context.Context, p *plugins.Plugin, _ error) { if pluginMenu == nil { pluginMenu = app.newXbarMenu(p, false) } else { + if app.settings.Terminal.AppleScriptTemplate != "false" { + pluginMenu.Append(menu.Separator()) + pluginMenu.Append(menu.Text("Run in terminal…", keys.Shift("return"), func(_ *menu.CallbackData) { + err := p.RunInTerminal(app.settings.Terminal.AppleScriptTemplate) + if err != nil { + app.runtime.Dialog.Message(&dialog.MessageDialog{ + Type: dialog.ErrorDialog, + Title: "Run in terminal", + Message: err.Error(), + Buttons: []string{"OK"}, + CancelButton: "OK", + }) + return + } + })) + } pluginMenu.Append(menu.Separator()) pluginMenu.Merge(app.newXbarMenu(p, true)) } diff --git a/app/menu_parser.go b/app/menu_parser.go index 8c8725815..5c7354410 100644 --- a/app/menu_parser.go +++ b/app/menu_parser.go @@ -81,7 +81,7 @@ func (m MenuParser) ParseMenuItem(ctx context.Context, item *plugins.Item) *menu menuItem.Disabled = true } if item.Params.Disabled { - // explicity disabled + // explicitly disabled menuItem.Disabled = true } return menuItem diff --git a/app/settings.go b/app/settings.go index 52001e8de..8598db349 100644 --- a/app/settings.go +++ b/app/settings.go @@ -5,16 +5,35 @@ import ( "io/ioutil" "os" "path/filepath" + "sync" "github.com/pkg/errors" ) type settings struct { + sync.Mutex + path string `json:"-"` // AutoUpdate indicates that xbar should automatically // update itself. AutoUpdate bool `json:"autoupdate"` + + Terminal struct { + AppleScriptTemplate string `json:"appleScriptTemplate"` + } `json:"terminal"` +} + +func (s *settings) setDefaults() { + if s.Terminal.AppleScriptTemplate == "" { + s.Terminal.AppleScriptTemplate = `activate application "Terminal" +tell application "Terminal" + if not (exists window 1) then reopen + set quotedScriptName to quoted form of "{{ .Command }}" + do script quotedScriptName +end tell +` + } } func loadSettings(path string) (*settings, error) { @@ -25,6 +44,7 @@ func loadSettings(path string) (*settings, error) { if err != nil { if os.IsNotExist(err) { // file not found - it's ok, just use defaults + s.setDefaults() return s, nil } return nil, errors.Wrap(err, "ReadFile") @@ -33,10 +53,14 @@ func loadSettings(path string) (*settings, error) { if err != nil { return nil, errors.Wrap(err, "Unmarshal") } + s.setDefaults() return s, nil } func (s *settings) save() error { + s.Lock() + defer s.Unlock() + s.setDefaults() b, err := json.MarshalIndent(s, "", "\t") if err != nil { return errors.Wrap(err, "MarshalIndent") diff --git a/pkg/plugins/plugin.go b/pkg/plugins/plugin.go index 2ef1c1c4e..f71833db1 100644 --- a/pkg/plugins/plugin.go +++ b/pkg/plugins/plugin.go @@ -13,6 +13,7 @@ import ( "strings" "sync" "syscall" + "text/template" "time" "github.com/pkg/errors" @@ -278,6 +279,35 @@ func (p *Plugin) CurrentCycleItem() *Item { return p.Items.CycleItems[p.CycleIndex] } +func (p *Plugin) RunInTerminal(terminalAppleScript string) error { + tpl, err := template.New("appleScriptTemplate").Parse(terminalAppleScript) + if err != nil { + return err + } + var renderedScript bytes.Buffer + err = tpl.Execute(&renderedScript, struct { + Command string + }{ + Command: p.Command, + }) + if err != nil { + return err + } + appleScript := renderedScript.String() + log.Println(p.Command, "RunInTerminal", appleScript) + cmd := exec.Command("osascript", "-s", "h", "-e", appleScript) + var stderr bytes.Buffer + cmd.Stderr = &stderr + err = cmd.Run() + if err != nil { + p.Debugf("(ignoring) RunInTerminal failed: %s", err) + } + if cmd.ProcessState != nil && cmd.ProcessState.ExitCode() != 0 { + return errors.Errorf("run in terminal script failed: %s", stderr.String()) + } + return nil +} + // refresh runs the plugin and parses the output, updating the // state of Plugin. func (p *Plugin) refresh(ctx context.Context) error {