Making WebStorm Friendlier

There's a few settings I recently tweaked in WebStorm that vastly improved my development experience.
Here's a quick rundown.

Ensure "Show Reformat Code" is disabled

Show "Reformat Code" dialog

Make sure these guys are off to get the popups out of your way. I also remap the commands to Ctrl+K, D and Ctrl+R, S to match my Visual Studio setup.

Tweak code completion popups

This is the setup I use:

Code Completion

The most important one is the Parameter Info popup - I really like having the method signatures there all the time, so making this nice and small makes it much more useful. I'd recommend trying "Insert selected variant by typing dot, space, etc" as well, for more natural completions. Can be annoying, though

Key Bindings

The default key bindings are a little all over the shop. Here's some handy ones:

  • Ctrl+T: Navigate to symbol
  • Ctrl+Shift+T: Navigate to file
  • F2 and Ctrl+R, R: Rename (works for files and symbols)
  • Alt+Enter: Autocomplete
  • Alt+Home: Super types hierarchy
  • Alt+End: Sub types hierarchy
  • Ctrl+R, S: Optimise Imports
  • Ctrl+K, D: Reformat Document

Some of these are muscle memory from my Visual Studio settings at work, but be sure to make them something you use, because they are all VERY useful commands.

Plugins

The best plugin I've seen is Key Promoter. This handy extension shows a popup whenever you do something inefficiently. For example, if I go to Settings via the menu, instead of Alt+F7, it'll show a blocker for 1s that shows the shortcut in an impossible to miss way. Recently, it noticed that I use "Close all documents" a lot, and nagged me to make a shortcut for it. I can now use Ctrl+Shift+W for that purpose, and it will nag me if I don't.

Foray into node.js on Windows 7

I've decided to learn about node.js - it's about time, really. I've used it - but only so much as to run a grunt task to bundle a specific revision of an Angular directive.

I found this neat tutorial for picking up some node.js know-how - looks pretty decent, and I'll give feedback on that in a subsequent post. Meanwhile, here's a rundown of getting the basic environment up for those on Windows who are having issues (as I did)

Installing NodeJS with NPM

I must have had this idea a little while ago, because I thought my first step should be to find out what I've got installed so far - it turns out I have 2 versions installed from Chocolatey, and one from the official installer, all old versions. So I got rid of them all, and discovered from the helpful comments at the package page for nodejs that I should use nodejs.install instead.

c:\Development\node-learning>node -v
v0.10.28

c:\Development\node-learning>npm -v
1.4.9

Woohoo!

NPM issues

Installing express proved difficult - the mime package kept giving me permission errors and this:

npm ERR! Error: ENOENT, chmod 'C:\Users\*****\AppData\Roaming\npm\node_modules\express\node_modules\accepts\node_modules\mime\README.md'

Whatever that means.

I kept going around in circles - the prevailing wisdom seems to be to clean the npm cache or to run as administrator.

I tried these (alongside an npm uninst -g for everything to get a clean start), and it worked a treat. I then removed all the modules again, cleaned my cache, and tried again, to make sure my solution was valid.

npm ERR! EEXIST, mkdir 'C:\Users\*****\AppData\Roaming\npm\node_modules\express\node_modules\send\node_modules\mime'
File exists: C:\Users\*****\AppData\Roaming\npm\node_modules\express\node_modules\send\node_modules\mime
Move it away, and try again.

It wasn't. I've made sure %appdata%/npm-cache is empty as well, to no avail. I sometimes get a few other errors, which seem to cycle around - even though the cache and modules are empty

npm ERR! Error: ENOENT, chmod 'C:\Users\*****\AppData\Roaming\npm\node_modules\express\node_modules\type-is\node_modules\mime\LICENSE'

npm ERR! Error: ENOENT, lstat 'C:\Users\*****\AppData\Roaming\npm\node_modules\express\node_modules\send\node_modules\mime\types\mime.types'

I'm sure I got an EPERM here as well.

I've since learned that ENOENT means "No such file or directory". I'm well into yak-shaving territory at this point.

The light!

In the end, I just kept running npm install express -g until it worked. It's intermittent, which makes me think this stuff installs in parallel or there's a load balancer serving the wrong file or something. Not much of a light, but them's the breaks.

Running npm install for the package had similar issues. As before the "keep on trying" Method works, and works in fewer iterations if you install it package-at-a-time. I couldn't find any documentation about parallel installs, so I've no idea what's going on.

Be sure to let me know if you know what's going on here!

In any case, it was easy sailing from here on out. The tutorial was straight forward, though it reminded me of my PHP days (jam the DB object into the request object? Really?)

Undirect updated to 1.1.1, and some "gotchas"

I've updated Undirect, a Chrome plugin that prevents annoying redirects on the google search page, because it had stopped working. I ran into a few surprises along the way, and some old frustrations cropped up again, here's a rundown to help the next person who tries.

Chrome store feedback

Since I'd released this in 2011, with a small update in 2012 to add RegEx to the pattern, I'd basically stopped checking the store's feedback. I couldn't find a way to get notifications of comments (apparently I'm not the only one) - and checking every few months is something that I probably could have done, but it never crossed my mind.

Now I wish I had, because apparently the plugin hasn't been working since about August 2013 - and I hadn't even noticed. Which is especially concerning, because I use the plugin on all my machines, and so do a lot of friends of mine. Being able to get notifications of reviews would have served me well here, since the average Joe won't exactly raise an issue on GitHub

Manifest JSON

The manifest.json file has been updated to v2, and v1 can no longer be updated on the Web Store. Not a big deal, but there were a few new things about the configuration file which were non-obvious.

  • default_locale is noted as "recommended" field, but without also having a _locales directory with the localisation, you get a confusing error when trying to load it.
  • The documentation page for it looks good for a sample, but it took me a while to realise that the field names are clickable. If you're looking for documentation, click those links!
  • The sample uses comments to mark off sections - but keep in mind this isn't valid JSON! You'll need to take them out before uploading to the store

Isolated world - why it broke

The reason for the extension breaking was a "security" feature they've added to the extension. I put security in quotes, because it's easy to circumvent.

Content scripts now run in an isolated world - which means that while it has access to the page and the DOM and all the jazz, it's a different view than the page. Any scripts or variables that are added by the page are inaccessible from the script - in my case, the onmousedown attribute of the link tags didn't exist from the content script's perspective.

I thought all hope was lost, then came across a neat little workaround, which is basically to add a <script> tag to the head element, causing it to execute in page context. Circumvented!

In my case, I wrote the function I wanted to execute as usually, then added the script to the page by simple calling .toString() on the function. Simple, and I get the full power of my IDE while I'm at it! Here's an example

var fnToRunOnPage = function() {
  // code goes here
};

var fnContents = '(' + fnToRunOnPage.toString() + ')();';

var scriptTag = document.createElement('script');
scriptTag.textContent = executeFnScript;
(document.head || document.documentElement).appendChild(scriptTag);
scriptTag.parentNode.removeChild(scriptTag);

It's the same thing that jQuery does when you add an element with a script tag in it. Works a treat!

The new solution

Previously, my plugin would search all the anchor tags, look for ones that had an onmousedown script with return rwt in it, and remove the value. Every time a DOM element was added or removed, I would run it again.

That's updated now to simply overwrite the rwt function on window to one that does nothing. I (perhaps unnecessarily) future-proofed it against overwrites by making it a property with writeable: false as well. Futile, probably - I'm sure they could get around that simple enough, but I have nothing to lose by doing that.

Static Jekyll Comments

Those of you paying very close attention will have noticed that posts now have a comment section at the bottom. It's currently reading the comments reading in from specially named YAML files in the _data directory of the site, which I have to put in manually.

You can find my comment HTML and YAML on GitHub, hopefully it's pretty straight self-explanatory.

To do it, I had to get a filename-friendly page identifier from the, which I did by replacing slashes with dashes and capturing it in a comment id.

{% capture commentid %}comments{{ page.id | replace: '/','-'}}{% endcapture %}

From here, I read the data from site.data[commentid] and display it on the page. I wanted to allow some formatting in comments, so I pass the content through the | markdownify filter. The comment contents in the YAML have to be multi line as well, ending up with a YAML file with a bunch of entries like so:

- author: Steve
  date: 2014-04-02 10:00 +1000
  contents: |
    I've added comment support to the site now! See [my post](/2014/04/static-jekyll-comments) to see how I went about it.

    You'll note that it has *markdown* support too! I'll moderating it though, so don't try any dirty hacks...

The plan now is to make use of the GitHub API to allow comment submission by creating issues. I think this means that the commenter requires GitHub account, but that's ok. I don't think I'll get enough comments to need more automation than that - I will want to moderate them to ensure there's nothing malicious in the comment anyway, so I don't mind having to copy-paste the markdown from the GitHub issue into a YAML file.

For now, you'll have to create the GitHub issue yourself!

Jekyll Me This

So, I've moved the blog over to Jekyll, a static site generator that's pretty well suited to doing blogs, if you're a tech person, like myself. No, this is not an April fool's joke!

Moving over was a little arduous, not least of all because all the Jekyll tooling (including Ruby) really targets Linux or Mac users more than Windows users.

So, if you're thinking of doing the same, here's a few tips:

  1. Use the guide by juthilo on GitHub on how to run Jekyll on Windows
  2. Pay attention to the version numbers in the article above, as they are written for a reason. When I set mine up, it was Jekyll v1.4.2, but it looks like he's now recommending 1.5.1.
  3. Consider using Javascript code prettifier instead of Pygments if you don't want to install Python.
  4. GitHub pages does NOT support most plugins, only the ones found in the master repository. So either avoid using them, or generate the HTML locally and commit that
  5. While there are a tonne of themes at Jekyll Themes, it's very hard to find a good one - with no search or rating system, it's really a list of the latest submitted ones. A lot of them have hardcoded site names and categories. Avoid the hassle and style it yourself.

I have a GitHub repository for this blog if you want a fairly simple setup or template to base it off. I'm not using Jekyll Bootstrap, so it shows how easy it is to make a very functional blog with vanilla Jekyll.

I still don't know what I want to do with comments, I may simply avoid using them, as I'd have to hand them over to a 3rd party (like Disqus), something I'd rather not do.

If you have any helpful comments or find any problems, let me know by raising an issue or submitting a pull request.