171 lines
4.5 KiB
Elixir
171 lines
4.5 KiB
Elixir
defmodule BDS.Scripting.Capabilities.AppShell do
|
|
@moduledoc false
|
|
|
|
import BDS.Scripting.Capabilities.Util
|
|
|
|
alias BDS.Desktop.FolderPicker
|
|
alias BDS.Desktop.MenuBar
|
|
require Logger
|
|
|
|
@compiled_env Application.compile_env(:bds, :current_env, Mix.env())
|
|
|
|
def copy_to_clipboard(text, opts) do
|
|
case Keyword.get(opts, :copy_to_clipboard) do
|
|
callback when is_function(callback, 1) -> callback.(string_or_nil(text) || "")
|
|
_other -> do_copy_to_clipboard(text)
|
|
end
|
|
end
|
|
|
|
defp do_copy_to_clipboard(text) do
|
|
if test_mode?() do
|
|
true
|
|
else
|
|
{executable, args} = clipboard_command()
|
|
pipe_to_clipboard(executable, args, string_or_nil(text) || "")
|
|
end
|
|
rescue
|
|
_error -> false
|
|
end
|
|
|
|
defp clipboard_command do
|
|
case :os.type() do
|
|
{:unix, :darwin} -> {"pbcopy", []}
|
|
{:win32, _other} -> {"cmd", ["/c", "clip"]}
|
|
{:unix, _other} -> {"xclip", ["-selection", "clipboard"]}
|
|
end
|
|
end
|
|
|
|
# System.cmd has no stdin option, so feed the clipboard tool through a Port.
|
|
# Closing the port signals EOF, which is what pbcopy/xclip/clip wait for.
|
|
defp pipe_to_clipboard(executable, args, input) do
|
|
case System.find_executable(executable) do
|
|
nil ->
|
|
false
|
|
|
|
path ->
|
|
port = Port.open({:spawn_executable, path}, [:binary, :use_stdio, args: args])
|
|
Port.command(port, input)
|
|
Port.close(port)
|
|
true
|
|
end
|
|
end
|
|
|
|
def blogmark_bookmarklet(opts \\ []) do
|
|
project_id = Keyword.get(opts, :project_id)
|
|
|
|
# Concatenate as a JS string literal (+'&project_id=...'), not raw text, so
|
|
# the generated bookmarklet stays valid JavaScript when a project is set.
|
|
project_param =
|
|
if is_binary(project_id) and project_id != "" do
|
|
"+'&project_id=" <> URI.encode_www_form(project_id) <> "'"
|
|
else
|
|
""
|
|
end
|
|
|
|
"javascript:(()=>{const t=encodeURIComponent(document.title||'');const u=encodeURIComponent(location.href||'');location.href='bds2://new-post?title='+t+'&url='+u#{project_param};})();"
|
|
end
|
|
|
|
def title_bar_metrics(opts) do
|
|
case Keyword.get(opts, :title_bar_metrics) do
|
|
callback when is_function(callback, 0) -> callback.()
|
|
_other -> do_title_bar_metrics()
|
|
end
|
|
end
|
|
|
|
defp do_title_bar_metrics do
|
|
case :os.type() do
|
|
{:unix, :darwin} -> %{macos_left_inset: 72}
|
|
_other -> nil
|
|
end
|
|
end
|
|
|
|
def notify_renderer_ready(opts) do
|
|
case Keyword.get(opts, :notify_renderer_ready) do
|
|
callback when is_function(callback, 0) -> callback.()
|
|
_other -> true
|
|
end
|
|
end
|
|
|
|
def open_folder(folder_path, opts) do
|
|
case Keyword.get(opts, :open_folder) do
|
|
callback when is_function(callback, 1) -> callback.(string_or_nil(folder_path))
|
|
_other -> do_open_folder(folder_path)
|
|
end
|
|
end
|
|
|
|
defp do_open_folder(folder_path) do
|
|
if test_mode?() do
|
|
""
|
|
else
|
|
case shell_open_system_path(string_or_nil(folder_path)) do
|
|
:ok -> ""
|
|
{:error, reason} -> inspect(reason)
|
|
end
|
|
end
|
|
end
|
|
|
|
def select_folder(title, opts) do
|
|
case Keyword.get(opts, :select_folder) do
|
|
callback when is_function(callback, 1) -> callback.(string_or_nil(title) || "Select Folder")
|
|
_other -> do_select_folder(title)
|
|
end
|
|
end
|
|
|
|
defp do_select_folder(title) do
|
|
if test_mode?() do
|
|
nil
|
|
else
|
|
case FolderPicker.choose_directory(string_or_nil(title) || "Select Folder") do
|
|
{:ok, path} -> path
|
|
:cancel -> nil
|
|
{:error, _reason} -> nil
|
|
end
|
|
end
|
|
end
|
|
|
|
def set_preview_post_target(post_id) do
|
|
:persistent_term.put(
|
|
{BDS.Scripting.Capabilities, :preview_post_target},
|
|
string_or_nil(post_id)
|
|
)
|
|
|
|
true
|
|
end
|
|
|
|
def show_item_in_folder(item_path, opts) do
|
|
callback = Keyword.get(opts, :show_item_in_folder)
|
|
|
|
cond do
|
|
is_function(callback, 1) -> callback.(string_or_nil(item_path))
|
|
test_mode?() -> :ok
|
|
true -> _ = shell_reveal_system_path(string_or_nil(item_path))
|
|
end
|
|
|
|
nil
|
|
end
|
|
|
|
def trigger_menu_action(action, opts) do
|
|
callback = Keyword.get(opts, :trigger_menu_action)
|
|
|
|
cond do
|
|
is_function(callback, 1) -> callback.(string_or_nil(action))
|
|
test_mode?() -> :ok
|
|
true -> _ = MenuBar.handle_event(string_or_nil(action), nil)
|
|
end
|
|
|
|
nil
|
|
rescue
|
|
error ->
|
|
Logger.debug("swallowed app_shell trigger_menu_action error: #{inspect(error)}")
|
|
nil
|
|
end
|
|
|
|
def test_mode? do
|
|
Application.get_env(:bds, :test_mode, false) or current_env() == :test
|
|
end
|
|
|
|
def current_env do
|
|
Application.get_env(:bds, :current_env_override) || @compiled_env
|
|
end
|
|
end
|