Wednesday, January 19, 2011

Open URL

A useful library in Python is the webbrowser module: it allows you to open a URL in your web browser. When I was writing Reddit "Top", this was something I wanted but couldn't find in Factor. It would be great to have cross-platform "open URL" functionality, so I thought I would show how to build it.


Mac OS X comes with a command-line utility called open. It will open files or directories as if you had double-clicked them in the Finder. If you pass it a URL, it will open that URL in the default web browser. We can use the io.launcher vocabulary to run this command in a new process:

USING: formatting io.launcher urls.encoding ;

: open-url ( url -- )
    url-encode "open \"%s\"" sprintf try-process ;

Alternatively, you could use Applescript (via the osascript command) and the "open location" feature. This is how you might do it, if you want to target a specific browser ("tell application... activate OpenURL..."), indicate that it should open in a new window ("...toWindow..."), or open several URLs at the same time.

USING: formatting io.encodings.ascii io.launcher urls.encoding ;

: open-url ( url -- )
    "osascript" ascii [
        url-encode "open location \"%s\"" printf
    ] with-process-writer ;


On Linux, the situation is a little more complicated. Using Gnome, you can run the gnome-open command. Using KDE, you could run the kfmclient command. On other systems, maybe you could use mimeopen, or maybe write your own. For this example, we will assume you are running Gnome -- but you could support other methods and/or detect which method is appropriate to use:

USING: formatting io.launcher urls.encoding ;

: open-url ( url -- )
    url-encode "gnome-open \"%s\"" sprintf try-process ;


On Windows, we can use the ShellExecute function from Shell32.dll. In Factor, this is defined in the windows.shell32 vocabulary.

USING: urls.encoding windows.shell32 windows.user32 ;

: open-url ( url -- )
    url-encode [ f "open" ] dip f f SW_SHOWNORMAL ShellExecute drop ;

Try it

Once you have the appropriate open-url word loaded into your Factor VM, you should be able to try it out:

( scratchpad ) "" open-url

The code for this (designed as a cross-platform webbrowser vocabulary supporting open-url) is on my Github.

Note: It would be nice if clicking on URLs in the Factor browser and presentations would open them in your web browser, but I haven't yet figured out how to get that to work.


shaurz said...

Another option on Linux is xdg-open.

tgkuo said...

nice work.

I found a similar word $url which was used as a help markup element to show url, but currently, the url printed is not clickable to open the url in the webrowser.
can we enhance this word to make the url it printed in the browser clickable like $link does ( when clicking the element, will go to the topic in browser by default ) ?

mrjbq7 said...

You should be able to modify $url to display urls in help markup in such a way that the can have "operations" defined.

For example, I made a change that allows "URL" objects to support right-click to "Open URL". You can see the commit which essentially boils down to:

[ url? ] \ open-url H{ } define-operation

tgkuo said...
This comment has been removed by the author.
tgkuo said...

I created the words:

USING: help.markup help.stylesheet urls present help.markup.private ;

: ($linkurl) ( str url -- ) [ write-link ] ($span) ;

: $linkurl ( element -- ) dup first swap second >url ($linkurl) ;

now, I can use { $linkurl "website" "" } in the doc file to show linkable url element in the browser.

is it ok to do so ?

mrjbq7 said...

Yes, exactly!

It's a bit cleaner if you define $linkurl like this:

: $linkurl ( element -- ) first2 >url ($linkurl) ;

Also, I might call it a $url-link, to match $vocab-link and some of the other conventions in help.markup.