Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file b0_web_browser.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234(*---------------------------------------------------------------------------
Copyright (c) 2018 The b0 programmers. All rights reserved.
SPDX-License-Identifier: ISC
---------------------------------------------------------------------------*)openB0_stdopenResult.Syntax(* macOS JavaScript automation *)letmacos_jxa?search()=Os.Cmd.find?search(Cmd.tool"osascript")letmacos_jxa_runjxascriptargs=letcmd=Cmd.(jxa%"-l"%"JavaScript"%"-"%%args)inOs.Cmd.run_out~stdin:(Os.Cmd.in_stringscript)~trim:truecmdletmacos_jxa_default_browser_appidjxa=Result.map_error(fune->Fmt.str"default lookup: %s"e)@@macos_jxa_runjxa{|
ObjC.import('CoreServices');
var h = $.LSCopyDefaultHandlerForURLScheme($('http'));
$.CFStringGetCStringPtr (h, 0);
|}Cmd.empty(* Finding a browser *)moduleEnv=structletbrowser="BROWSER"endtypet=|CmdofCmd.t|Macos_chromeofCmd.t(* this is osascript *)|Macos_safariofCmd.t(* this is osascript *)|Macos_openofCmd.t*stringoptionletbrowser_env_fallbackbrowser=matchbrowserwith|Some_asb->Okb|None->Os.Env.var'~empty_is_none:trueCmd.of_stringEnv.browserletfind_browser_cmd?searchcmd=matchOs.Cmd.find?searchcmdwith|None->None|Somec->Some(Cmdc)letfind_macos_open?search~appid()=matchOs.Cmd.find?search(Cmd.tool"open")with|None->None|Sometool->Some(Macos_open(tool,appid))letfind_with_macos_jxa?search~browserjxa=matchbrowserwith|Somecmd->Result.ok@@beginmatchCmd.is_singletoncmdwith|false->find_browser_cmd?searchcmd|true->beginmatchString.Ascii.lowercase@@List.hd(Cmd.to_listcmd)with|"chrome"->Some(Macos_chromejxa)|"firefox"->find_macos_open?search~appid:(Some"org.mozilla.firefox")()|"open"->find_macos_open?search~appid:None()|"safari"->Some(Macos_safarijxa)|_->find_browser_cmd?searchcmdendend|None->let*appid=macos_jxa_default_browser_appidjxainResult.ok@@matchString.Ascii.lowercaseappidwith|""->find_macos_open?search~appid:None()|"com.apple.safari"->Some(Macos_safarijxa)|"com.google.chrome"->Some(Macos_chromejxa)|appid->find_macos_open?search~appid:(Someappid)()letfind?search?cmd()=Result.map_error(fune->Fmt.str"find browser: %s"e)@@let*result=let*browser=browser_env_fallbackcmdinmatchmacos_jxa?search()with|Somejxa->find_with_macos_jxa?search~browserjxa|None->matchbrowserwith|Somecmd->Ok(find_browser_cmdcmd)|None->matchOs.Cmd.findCmd.(arg"xdg-open")with|None->OkNone|Somexdg->Ok(Some(Cmdxdg))inmatchresultwith|Someb->Okb|None->Fmt.error"No browser found. Set the %a environment variable."Fmt.codeEnv.browser(* Show *)letshow_cmd~background~prefixcmdurl=Os.Cmd.runCmd.(cmd%url)letshow_macos_open~background~prefix:_open_tool~appidurl=letappid=matchappidwith|None->Cmd.empty|Someappid->Cmd.(arg"-b"%appid)inletcmd=Cmd.(open_tool%%if'background(arg"-g")%%appid)inOs.Cmd.runCmd.(cmd%url)letshow_macos_jxaname~background~prefixjxaurlscript=letbool=string_of_boolinletargs=Cmd.(arg(boolbackground)%%arg(boolprefix)%url)inmatchmacos_jxa_runjxascriptargswith|Ok_->Ok()|Errore->Fmt.error"%s jxa: %s"nameeletshow_macos_chrome~background~prefixjxaurl=(* It seems we no longer mange to bring the window to front.
using win.index = 1 doesn't work. Maybe we should only consider
windows[0]. *)show_macos_jxa"chrome"~background~prefixjxaurl{|
function is_equal (s0, s1) { return s0 === s1; }
function is_prefix (p, s) { return s && s.lastIndexOf (p, 0) === 0; }
function run(argv) {
var background = (argv[0] == 'true');
var pred = (argv[1] == 'true') ? is_prefix : is_equal;
var uri = argv[2];
var app = Application ('com.google.chrome');
if (!background) app.activate ();
for (var w = 0; w < app.windows.length; w++) {
var win = app.windows[w];
var tab = win.activeTab;
if (pred (uri, tab.url ())) { app.reload (tab); return; }
for (var t = 0; t < win.tabs.length; t++) {
tab = win.tabs[t];
if (pred (uri, tab.url ())) {
app.reload (tab); win.activeTabIndex = t + 1; return;
}
}
}
if (app.windows.length == 0) { app.Window().make(); }
if (app.windows[0].activeTab.url () === 'chrome://newtab/')
{ app.windows[0].activeTab.url = uri; }
else { app.windows[0].tabs.push(app.Tab ({ url : uri })); }
}|}letshow_macos_safari~background~prefixjxaurl=(* win.index = 1 also (see chrome) doesn't work here and sadly opening
a directory file URL opens the finder. *)show_macos_jxa"safari"~background~prefixjxaurl{|
function is_equal (s0, s1) { return s0 === s1; }
function is_prefix (p, s) { return s && s.lastIndexOf (p, 0) === 0; }
function run(argv) {
var background = (argv[0] == 'true');
var pred = (argv[1] == 'true') ? is_prefix : is_equal;
var uri = argv[2];
var app = Application ('com.apple.safari');
if (!background) app.activate ();
for (var w = 0; w < app.windows.length; w++) {
var win = app.windows[w];
var tab = win.currentTab;
if (pred (uri, tab.url ())) { tab.url = tab.url(); return; }
for (var t = 0; t < win.tabs.length; t++) {
tab = win.tabs[t];
if (pred (uri, tab.url ()))
{ tab.url = tab.url(); win.currentTab = tab; return; }
}
}
if (app.windows.length == 0) { app.Document().make(); }
if (app.windows[0].currentTab.url () === null)
{ app.windows[0].currentTab.url = uri; }
else { app.windows[0].tabs.push(app.Tab ({ url : uri }));
app.windows[0].currentTab =
app.windows[0].tabs[app.windows[0].tabs.length-1]; }
}|}letshow~background~prefixbrowserurl=Result.map_error(fune->Fmt.str"show url %s: %s"urle)@@matchbrowserwith|Cmdcmd->show_cmd~background~prefixcmdurl|Macos_chromejxa->show_macos_chrome~background~prefixjxaurl|Macos_safarijxa->show_macos_safari~background~prefixjxaurl|Macos_open(open_tool,appid)->show_macos_open~background~prefixopen_tool~appidurl(* Cli interaction *)openCmdlinerletbrowser?docs?(opts=["b";"browser"])()=letenv=Cmd.Env.infoEnv.browserinletdoc="The WWW browser command $(docv) to use. The value may be interpreted \
and massaged depending on the OS. On macOS: the names $(b,firefox), \
$(b,chrome) and $(b,safari) are interpreted specially; use $(b,open) \
if you would like to use $(b,open\\(2\\)); if absent the application that \
handles the $(b,http) URL scheme is used. On other platforms if
$(b,xdg-open\\(1\\)) is found in $(b,PATH) this is the program used by
default."inletabsent="OS dependent fallback"inletcmd=Arg.conv'~docv:"CMD"(B0_std.Cmd.of_string,B0_std.Cmd.pp_dump)inArg.(value&opt(Arg.somecmd)None&infoopts~absent~env~doc?docs~docv:"CMD")letprefix?docs~default()=letdefault_str=" (default)"inletprefix=letopts=["prefix"]inletopts=ifnotdefaultthen"p"::optselseoptsinletdoc=Fmt.str"Reload first tab which has the URL as a prefix or create new tab%s. \
See also $(b,--exact). \
Platform and browser support for this feature is severly limited."(ifdefaultthendefault_strelse"")intrue,Arg.infoopts~doc?docsinletexact=letopts=["exact"]inletdoc=Fmt.str"Reload first tab which has the exact URL or create new tab%s. \
See also $(b,--prefix)."(ifdefaultthen""elsedefault_str)infalse,Arg.infoopts~doc?docsinArg.(value&vflagdefault[prefix;exact])letbackground?docs?(opts=["g";"background"])()=letdoc="Keep launched applications in the background. Platform support for \
this feature is limited."inArg.(value&flag&infoopts~doc?docs)letman_best_effort_reload=[`P"Up to severe platform and browser limitation, $(cmd) tries to limit \
the creation of new tabs by reloading existing ones which have the \
same URL or are prefixed by the URL (see $(b,--prefix))."]