openURL broken on MAC

SketchUp didn’t call Ruby’s URI.encode, but some other encoding function we have in C++. The problem is that it would take URLs with anchors and query parameters (#, & and & etc) and URL-encode those characters which then prevents the correct URL from being loaded.

In the example above you’d build the string differently if you needed to append fragments (#example) or query params ?foo=bar.

SU 2017
URI.encode(help)

Error: #<NameError: uninitialized constant URI>

In any case, since my help file html is always stored with the plugin rbs, all of my users worked perfectly before 19.3. Now all MAC users who upgrade to 19.3 don’t work.
If I add my own encoding, resubmit my extensions and users update them, will it work for all versions of SU? I have no way to test this.

I’m not MAC aware so maybe I’m wrong, but it seems that encoding is only necessary because Trimble creates folders with names that includes spaces, something us old timers would never do. Do you know of any other software that does this?

This is NOT the way to fix this kind of problem. Backward compatibility is paramount. A new recommended OpenURLunencoded method could have been added for new development WITHOUT removing the old OpenURL method.

Apple does it all the time…

john

Trimble is not entirely to blame. The folders that macOS provides for apps to store user-specific data are inside

~/Library/Application Support/

There’s already a space in there that Trimble can’t do anything about. For better or worse, spaces have long been allowed in file and folder names on macOS. Ordinarily this is not a problem because the OS handles it.

But when one goes through something like openURL(), the request may go out to the web and spaces are not allowed in URLs on the web. There are other unicode characters that are also illegal because the web uses exclusively ASCII character encoding. This could equally be a problem on non-US installations of SketchUp. See for example, this tutorial.. It is the code’s responsibility to create an acceptable URL by URI encoding it.

I suspect the SketchUp developers’ point of view was that Windows coders had been getting away with ignoring this URL requirement because Windows folders and filenames don’t normally embed spaces. That is, the code worked not because it was right but because nothing was detecting that it was wrong! And on Mac, it worked because the C++ library was covering up for the mistake.

I won’t argue that this couldn’t have been done more smoothly. Library changes that break existing code are never a good thing.

If the only issue is embedded spaces (which I have no way to know for your specific files or for specific users) a simple

path.gsub!(" ", "%20") 

will work in all versions of SketchUp because it is basic Ruby independent of what libraries are installed. It’s basically a no-op when there are no spaces (as usual on Windows) and harmless when there are spaces even if the Mac SketchUp’s openURL() processes the encoding again.

URI is from the StdLib, so you would have to require 'uri (I’ll update my example.)

It’s unfortunate that this broke - but there was no way for us to otherwise fix the blocking bug.

You probably have to conditionally avoid encoding for macOS SketchUp users older than SU2019.3. (I will be adding this to the documentation and examples.)

Application Support is from Apple - it’s not unique to us. Also Windows will have spaces in many of their default system names. But it’s not just spaces that can be an issue, plenty of other characters that’s valid filenames needs URL encoding. Filenames has become very liberal since the old days of 8+3 DOS filenames.

I agree that compatibility is key - but in this case the method was already broken. Broken to the point it blocked other usage. Also, the method’s API contract is to open an URL - the fact that opening local files works is a side-effect of implementation details. As I mentioned earlier, I’d like to add a dedicated method that officially support opening local files. Currently the behaviour of UI.openURL is depending on not just our own implementation detail - but also on implementation details of how browsers deal with local files. Just because something undocumented happened to work, doesn’t mean it will continue to work.

Program Files … And often user folder names.

Always best to use dedicated URL encoding functionality than to roll your own partial formatting. You never know when implementation details might change. Suddenly another character appear in a file that you didn’t anticipate earlier.

While I’m generally very much in favor of obeying API contracts I’m wondering if this is the best approach here. Not only because of how widespread use of openURL for local files appears to be but also because using it that way matches how you expect a computer to work: you tell the system to open a path and the system picks its standard browser if it recognized the path as being an URL.

Perhaps the URL for mating can be applied only if the string starts with http:// or http://?

FYI, My examples clearly showed the loading of the URI library in the 4th post above.

I also showed in the 4th post how using the 2nd argument a coder can specify exactly and only what characters to encode.

For example, only space encoding …

path = File.join( __dir__, "help", "help.html#anchor?what=anything" )
url = URI.encode( "file:///#{path}", " " )

… will not encode the hash character, question mark, equals sign, etc.

Uh … sorry Steve, this has never been true.

Windows has always had a mixture or spaced and CamelCase folder names. Some of them necessary system folders such as “Documents and Settings” (now mapped to “Users”,) “Program Files” and “Program Files (x86)”, “Offline Web Pages”, “Downloaded Program Files”, “Application Data” (now mapped to “~/AppData”,) “Local Settings” (now mapped to “~/AppData/Local”,) … etc., etc.

There has been since Win8 a trend more toward both CamelCase and dot separated folder names. (The latter especially in regard to .NET libraries and software SDK folders.)


Anyway, on Windows NT local URLs never had an issue with unencoded spaces. They could be encoded or not. It didn’t seem to matter. Ie …

UI.openURL("file:///C:/Program%20Files/SketchUp/")
#=> true
UI.openURL("file:///C:/Program Files/SketchUp/")
#=> true

both open a File Explorer window into the proper parent directory for SketchUp installs.

Windows NT (being designed for network use with the NTFS,) expects network filepaths and can handle them as well as normal paths. Perhaps not so true for the early FAT based consumer Windows over DOS editions.

We could have considered that if it’s been brought up before SU2019.3 release - but now that ship has sailed. SU2019.3 is out and there won’t be any more SU2019 releases.

Btw, I updated my example earlier up in the thread: openURL broken on MAC - #37 by tt_su

“You probably have to conditionally avoid encoding for macOS SketchUp users older than SU2019.3.”
PROBABLY??? You now want me to add more code that I cannot test.
As I said before, you fix this kind of problem by ADDING a new method and leaving the old method in place. I strongly suggest you do this in the next release.

Example (again) …

  def open_html( subdir = 'help', file = 'index.html' )
    path = File.join( __dir__, subdir, file )
    url  = "file:///#{path}"
    if (Sketchup.platform == :platform_osx rescue false) &&
    Sketchup.version_number > 1920000000
      require 'uri'
      url = URI.encode( url, ' ' )
    end
    UI.openURL(url)
  end

You can also do the conditional method definition at load time thus …

  if (Sketchup.platform == :platform_osx rescue false) &&
  Sketchup.version_number > 1920000000
    require 'uri'
    def open_html( subdir = 'help', file = 'index.html' )
      path = File.join( __dir__, subdir, file )
      url  = URI.encode( "file:///#{path}", ' ' )
      UI.openURL(url)
    end
  else
    def open_html( subdir = 'help', file = 'index.html' )
      path = File.join( __dir__, subdir, file )
      url  = "file:///#{path}"
      UI.openURL(url)
    end
  end

Sorry for being vague in my language - but yes - you need to avoid applying encoding the string in older mac versions. Otherwise you get double encoding. My updated example shows a working example.

Remember that the API contract for this function is to open an URL in a browser - that was broken with no workarounds.

Opening local files was a side-effect of an implementation detail. Fixing bugs in documented API contracts will always trump changing behaviour in undocumented behaviour. Especially when there is no way to not break either one of them.

That being said, opening local files with whatever application is associated for it is a useful and legitimate, but that warrants a dedicated API method. I’ve added that as in internal issue. Meanwhile we’ll update the documentation for UI.openURL with working cross-platform example of how to achieve this in older versions of SketchUp.

And I urge API users to file a feature request if you find yourself using a method in a manner that isn’t documented to work that way. We have no change of keeping track of API usage beyond what the documentation promise.

I concur!

Your response ignores basic facts:

  1. Any non trivial extension should have a locally stored help file.
  2. In practice OpenURL has been the only way to do this.
  3. Probably 99% of all executions of OpenURL in the wild are opening a local file.

Yet you want to make it virtually impossible to safely provide a local help file until some future method may be offered.
IMO this one change makes the SketchUp API a non viable development platform.

I believe openURL should’ve never been there in the first place. Opening a file in the system default program is not something specific to sketchup, but already possible in pure ruby…

Fixing the blocking bug in the documented API contract did not block the undocumented usage. It only meant a behaviour change which is has a practical workaround. One which we will include in the documentation so people know what they can use until we get an official API for this.

Great. Tell me how to do it in ruby. And explain why all the API gurus have been recommending OpenURL way back when I was first learning the API.

Not to offend anyone but few SketchUp Ruby API gurus are Ruby gurus. I wouldn’t call myself a Ruby guru.

Quite questionable software practices are unfortunately quite widespread in the SketchUp developer community, probably because so many of us are self taught. People discover what works and use it, often without questioning why it works, if it is supposed to work or if they can trust it to work in the future. Being self-taught I’ve done this myself for years, and picked up things like openURL from other users myself, but I am getting better at learning best practices all the time.

I believe a few options have already passed the revue in this very same thread.

3 Likes

… much of this was discussed as early as 2016 …