Monday, July 14, 2014

Experiments with QML and Vim

This weekend, I've been having a lot of fun playing around with QML, and doing so in Vim (instead of my usual Notepad++). Chances are that you probably haven't heard of QML before (or if you did, your projects at the time wouldn't have really benefited from it, given that it does have limitations when it comes to being able to use standard widgets).

QML is basically a "declarative" language for defining dynamic UI's, built on top of the Qt Framework. It's syntax is like a nicer version of CSS, with the ability to throw snippets of Javascript in when needed to define small bits of custom logic when needed, and (if it's hosted via PyQt) you can even code up any of the more "tricky" or substantial logic in Python, then use the PyQt QObject bindings to make this available to your QML code.

Although it doesn't come with a fully fleshed out widget set that you can use (though apparently, this is only true for the PyQt4/Qt4.x that I'm still using, as they've developed a set of widgets for that purpose in Qt5), it more than makes up for that in terms of what it enables you to do instead.

Basically, if you're looking for a lightweight domain-specific language for defining/prototyping little graphical scenes, complete with dynamic behaviour (i.e. procedural animations, animation effects, and transitions in response to user input), and the ability to compose/package up you creations as reusable assets, look no further. This toolkit is for you!

QML Review
So far, I've been quite impressed with what I've seen (though there have been a few natural growing pains as I've stumbled around trying to figure out how some of these things work). It feels totally natural to be doing things this way:
1) Firstly, it's great to finally have a language where you can clearly express the hierarchical structures that UI code naturally requires/falls into, without having to rely on setting up and maintaining classes to achieve such organisational patterns

2) It's great to be able to specify "relationship expressions" defining how things should be (i.e. property x's value should be calculated using that function over there, or that a certain effect only applies when some condition is true)

3) When building UI's, layout and style are intricately intertwined. IMO, anyone who thinks otherwise is somewhat deluded (Note: Having mulled over this briefly, I think that this still holds when talking about "alternative UI's" - e.g. for the blind - as we really should be optimising those experiences for the demands/needs of those users. That said, I do acknowledge that programmers being the lazy sods that we are probably often never get there, and having to create separate optimised layouts for such cases often doesn't happen).

Specifically, I have been of the opinion from day 1 that trying to build full-blown applications using the web-based frameworks of today is complete and utter bullshit. That whole, "content and presentation (i.e. layout + styling) must be separate" ideology is the culprit IMO. It effectively forces developers to split their UI descriptions into at least two parts, resulting in a rather unholy mess: firstly, by using/abusing the HTML-defined DOM to define the raw text/images/content and some abstract relationships of such items to each other, then riding roughshod over that using house-of-cards CSS to reappropriate all those elements into their actual/intended semantic representations (which are often far removed from the way they're defined - e.g. list elements being reinterpreted as anything from tabs and menus or items in dynamic menus, to some "div" elements becoming buttons while others become background padding). That's also not to mention the sorts of bizarre gymnastics that need to be performed to move elements to various places on screen - e.g. elements may need to be defined in the HTML in places where they have no logical reason/relationship to the stuff nearby, solely because that's the only way you can trick the layout engine into taking note of that element so that it may hopefully place it where you hope it should appear.

HTML was defined as a semantic language for describing documents - content which has a strongly ordered (and even hierarchical) linear format. GUI's by definition are something else entirely: they are highly structured graphical constructs, where there is a close association between structure and representation. We should not be abusing elements with one set of semantic meanings to represent a completely different set of entities!

Therefore, I cannot heap enough praise on the Qt team for their efforts with QML. IMO, they've finally managed to capture what many other attempts in industry so far have failed to achieve, by creating a specialised tool for a very specialised problem. Sometimes, there are limits to what "general-purpose" can do, not to mention whether general-purpose solutions should be used.

4) It's great to be able to easily define animations and transitions between visual/logical states as an integral part of the framework.

The problem for most of our existing frameworks is that animation is almost always an afterthought (since it really was). You see, most widget frameworks (and ways of coding these) are still firmly rooted in the days when machines were far too wimpy to even manage to display and manage the GUI's themselves (drawn in the most basic ways possible to still be understandable). So, it's no wonder that they didn't bother (or actually, didn't have the capacity to even contemplate) to animate anything. Thus, if you need to add animation effects, you end up needing to find ways of rerouting it into each and every piece of code you want animation effects to occur in. Doing so was actually frequently slow and tricky work, that you really didn't want to do...

So, to see this as part of the Qt Quick system (i.e. the whole subsystem build on top of the base Qt framework to support and run QML code) is really reassuring. It also makes things like defining transitions to be applied to large collections of items (e.g. some dynamic view) a much easier/nicer prospect than if you'd have needed to figure out how to do this from scratch (*shudders*). For prototyping novel interfaces containing motion, this just makes sense.

5) I love that you can easily create reusble assets by clobbering together some of the primitives they provide (and really, if you get creative, that basic set is actually enough to take you a very long way - especially if you simply defer any complex graphics/shape rendering problems to being a matter of displaying some pre-defined images or SVG's), along with some custom-defined properties (which you've rigged to set the relevant parameters).

Abstraction + encapsulation mechanisms like these are really powerful tools, and are an essential part of any toolkit which strives to enable and empower its users to create whatever they desire without fear.

6) Another benefit to the QML language is of course that it is dynamically compiled at runtime. Now, especially when working in Python (but also in C++ to a lesser degree), this raises a very interesting (and even more powerful) option for creating complex + reusable assets: If you have a situation where simply reusing assets simply won't cut it (e.g. you need to override/customise a specific aspect further), there's always the code generation approach. Yep, you can simply write some code which will splice together the magical new components necessary to achieve the desired effect, and have this get compiled in the background and loaded up as part of the app without batting an eyelid.

Several anecdotes from our algorithms professor come to mind writing this - firstly, how the code generation approach provides us with a powerful mechanism for having programs tailor-made for solving particular problem scenarios (vs relying on a generic one-size-fits-all approach), and secondly, how as computer scientists, our role in the greater scientific landscape is in creating the tools which create the tools people use (a rather meta/zen statement).

7) Overall, I'm very happy to have finally found the lightweight, dynamic prototyping tool I've been dreaming about for ages. For a while, I'd been trialling using Blender for this. While that exercise has given me some good ideas for some necessary tweaks for aid motion graphics people, and also informed some greater untapped problems (namely the issue of reactive - i.e. actions/animations firing in response to some stimulus/event/change - behaviour, and how we could support this), it's still ultimately a bit too far off in the distance to be useful for the work I need to be doing today.

I've dabbled with Vim on and off for many years now. As with a lot of open source software, I likely first fired it up back during my high school days when I was dabbling with Cygwin on my crappy XP box (which was necessary to run some software I needed/wanted to run at the time, based on top of TeX).

It was only in my 2nd year of uni that I really started to try and seriously learn to use it. The impetus at the time was: 1) I hadn't found any decent text editors on Linux,  2) I was taking a course at the time which was a prerequisite for most other courses (but where I was already quite familiar with half the material), so to inject a bit of a challenge for myself, I aimed to do all the course work for that course using this Vim (to stand a chance of scaling the steep learning curve),  3) yet another course I was taking at the time required writing in a foreign language containing accents (something I didn't have a clue how to do using a US Keyboard under Word, but which I was sure LaTeX would have an ASCII + markup-code solution for), so I ended up clobbering up a script which would generate the LaTeX templates, load up Vim so that I could write the content, and then run LaTeX on the file to generate a submittable PDF.

Sure enough, I did get familiar with a few basics following that ordeal, but it never actually got to the point where I though it offered my workflow anything yet. There are a few reasons why:
1) I almost always only stayed in either Normal or Insert (entered as standard IKEY insert, or new-line OKEY insert) modes. At that stage, I hadn't figure out how to use the visual/select mode - partly since I was using the Windows keybindings then, and those actually remapped quite a lot of the useful stuff for those.

2) At the time, I only knew about exiting modes using the Esc key. This was a bloody pain, as, for such a frequently performed action, I'd end up needing to frequently fling my hand over to stab the Esc key, jump back to type a few characters, then get back up there again. This made the modes feel a lot less efficient than they could be.

3) I quickly learned about the magic "r" commands (i.e. replace the character under the cursor with the next one you type), the "c" commands (specifically "cw" - change the "word" under the cursor, and "cc" to change the whole line), the "x" command (i.e. for deleting the character under the cursor), and the "dd" command (i.e. to deleting the current line)  -- an essential quartet for quickly correcting typos without doing the whole mode-switching dance most of the time. While these were admittedly very nice, on their own they weren't enough of a motivational factor to use Vim for more.

4) It was still a pain to jump around the file. Specifically, to find the definition of a function I was working with, or for simply refinding whatever line I was working on. There were also other features that I'd grown used to in Notepad++ but couldn't find yet (like bookmarking, swapping lines, and similar)

5) And perhaps the most critical: I found that it couldn't be trusted to NOT munge my whitespace. I'm quite a stickler on this matter - if an editor decides that it knows better and develops a mind of its own for randomly deleting my whitespace on "blank" lines, or reformatting the type of indentation used on other lines (i.e. usually meaning, it indents using spaces, and/or tries to convert any other code it touches the same way), or any other hideous whitespace sins - then it isn't usable. Period. If I cannot trust it to no do anything stupid behind my back, it's a dangerous piece of software that's not worth further consideration.

(For reference, SublimeText also fails on the whitespace count; I've had it reporting that all my code was indented perfectly as expected using tabs - after I had manually fixed the bloody default config to not use spaces - and, after committing the code, discover via the commit log mail that in fact, the wrong indentation had been used on one line of code but not any of the ones around it. Thus, it cannot be trusted, so that's why I don't use it, despite what any hype may say.)

A few years later, I occasionally dabbled with it again - this time using it mostly as a quick/light file viewer when my primary text editor would be loaded already. In the intervening years, a number of things had happened, which improved my view of the editor:
1) GMail Shortcuts - The single biggest thing that happened during that time would have been that, after getting sick and tired of scrolling and clicking through a long list of emails in the mornings to delete them after reading, I resolved to learn the keyboard shortcuts. Lo and behold, I quickly developed a "xjxjxj" reflex (for selecting a bunch of emails to delete), Shift-# to delete, or "k k k" to jump to a "newer" message (displayed above the current one in the list). I rarely do these thing using a mouse anymore.

2) Quick-find in Firefox - Sometimes, the Ctrl-F in Firefox feels too "heavyweight" as it has a nasty habit of capturing input but not going away. Simply doing "/" followed by whatever you're searching for was a lot faster

3) Becoming a lot more proficient on the command-line, thanks in part to SSH-ing in to my departmental account to grab stuff and developing techniques (in combination with modifying config files to get easier-to-use defaults like the "case insensitive cyclic tab completion" you have on Windows - seriously, this is instance where I have to disagree with those who say Bash or some Linux shell is superior to Windows, as things like this are a usability nightmare) meant a growing demand for having/being skilled at some text editor I could fire up from a commandline and bash off emergency tweaks from if need be. Vim fit this bill very nicely.

4) Adding a whole lot of stuff to my config files to make Vim more well behaved. Things like making search case insensitive + wrap around, and other similar things. Thus, search was now usable by doing "/<search-text><Enter>" then "n" to jump between matches. (Substitutions though, were still too complex/unreliable to understand, but that didn't matter, as I could now at least get around much easier)

5) Learning about markers (and forgetting every time I didn't use Vim for a few months - it's ma, mb, mc, ... to define, and `a, `b, `c, ... to access), moving between lines (specifically "gg" for the first line, "GG" for the last", and "<x> G" to jump to a specific line - though I almost always forget those three), learning about "xxp" (swapping characters - TBH, I still don't use this one much, as it still seems quite confusing at times), learning about "yyp" (i.e. duplicating lines).

Still, at the end of the day, switching modes was still too clumsy with the Esc key so far out, moving around with hjkl seemed pointless (although it could be done if need be - just "jk" though), and the issues with bad management of whitespace were still blocking issues to taking it seriously.

Perhaps the next watershed occurred last year. I was starting to work mobile a lot more (due simply to the fact that I had a lot of code to write - for 2 high octane projects at once - but not enough time to write it, so I had to multiplex my time to get some coding done while still having a bit of a life/fun-time), so I needed to find ways to work without touching a mouse that much. Vim's appeal for such times was evident, though not all the time.

The turning point though was accidentally learning about the "windows" feature one day. While on previous encounters with it, I'd ended up terrified and having to resort to forcibly closing down the app to get it back to normal, a happy accidental action which resolved the problem, followed by curiosity about what had just happened, and through a half-hour of mucking about (and checking the menu for tips) later, I finally "got" this feature. All of a sudden, it made sense. And, it was quite a neat/nifty setup:
  • Ctrl-W is the "base key" for all operations involving windows. That is, you firstly type, "Ctrl-W" followed by the one-letter key for whatever window operation you want to perform.
  • s = Split the current view, creating 2 views of the current document. This is useful if you want to look at/for the definition of a function without losing your place in the document. Simply keep your actual working code in the bottom pane, and do all the searching in the upper pane.
  • c = Close the active pane. This is useful when you're done with the split-pane to browse for definitions.
  • j/k = Change the active pane to the one below the active (j) and one above the active (k). Just like if you were moving around through text.
Around the same time, I also learned for the first time that Ctrl-[ is the same as pressing Esc. Sure, it's 2 keys vs 1, but doing this required less hand movement, amounting to a huge speed boost. Along with the other things I'd been learning about Vim over the years, and being forced to use it to make Git commits on my office computer for a while (as it was a locked down Linux install which didn't have Git Gui - more in a moment), my Vim productivity could at least be described as "functional" at that stage. Sure I was still clumsy moving between the modes, but it was at least somewhat manageable.

Then, disaster struck. In a hazy-confused rush to commit something, I accidentally issued the wrong sequence of commands to Vim. The result was that a file named ":q" got saved AND added to the repository, then pushed off to my central backup repo. Eek! This quickly resulted in an hour-long struggle to find a way to get rid of that file from the repository, followed by some extra time to document my struggles (so that I had reference for what to do if it happened again). It also convinced me that the situation was untenable, so I fired off a support request to get Git Gui installed for all the department's Linux machines.

Vim was once again banished to the "dangerous and clumsy" software backwaters. At least for doing commits, having Vim as the final step between uncommitted changes and committed changes was far too risky to contemplate any more. Command-line Git usage was thus another casualty; it would be GUI's only for me for most actions (except from cloning repos, when using a preformed query provided by Github or Bitbucket) to prevent another repeat of that whole debacle.

Recently though, Vim has gotten a new look in on my workflow. After getting a bit fed up with Notepad++'s new function list (which not only has a habit of keeping classes collapsed - making it difficult to jump to those functions - but it seems that it randomly decides to collapse classes if and so it chooses to do so when unprovoked) for coding, and being a bit too lazy to set up yet another TexMaker project for my latest WIP paper writing project, Vim seemed like a good option again.

First it was the LaTeX project. This time, I figured that maybe I should try doing this with a TeX plugin installed, along with a spell checker turned on (I hadn't realised this feature existed all these years!). Lo and behold, that combination worked wonders. The extra mechanics of having to work the interface - a slightly clumsy exercise initially (as I'd practically forgotten a lot of things, and had to relearn them again, but this time, much more thoroughly it seems), but later developing into certain sets of rhythms and opportunistic bids to do "clever" command sets (several articles I'd read had finally convinced me of how Vim's interaction model actually encouraged users to learn a new language/vocabulary, which they could then combine in various ways to actually achieve stuff). There was an added benefit to having all that extra mechanics to contend with: it turned out that the effort of figuring out how to achieve stuff using Vim's commands without resort to "bad habits" of repeatedly jabbering the arrow or backspace keys acted as a good distraction from attempts to procrastinate from the writing work; the extra mechanics were keeping the "monkey brain" occupied long enough to let the writing-thinking work actually take place. Yay!

During this time, I learned and mastered a few more things. Stuff like:
  • U = Undo
  • Ctrl-R = Redo
  • w = Jump forward to the next "word"  (Ctrl-RightArrow also does this)
  • b = Jump backwards to the start of the previous "word"  (Ctrl-LeftArrow also does this)
  • "+y  = Copy to windows clipboard   (<---- this is still a bit tricky to remember)
  • "+gP = Paste from windows clipboard  (<--- this is still a bit tricky to remember)
  • Ctrl-O = Allow specifying one command without leaving insert mode
These turned out to be quite useful additions.

Buoyed by this success, and concluding that a syntax highlighting config likely existed (given the enduring popularity of this editor), when I came across QML late on Friday night, I concluded that setting up Vim for coding in it would be a priority.

Over the past two days, I've ended up coding exclusively in Vim, with multiple windows open, and doing some actual development work in a language I didn't know, while getting to grips with a still-newish text editor. It's actually all starting to make sense - in particular, I'm finally starting to appreciate the w and b shortcuts, as well as the hjkl (yep, the full set, not just jk), not to mention rocking the r/c/x/d stuff whenever a quick typo-fix is necessary when iterating. Perhaps this might finally be able to become a more permanent fixture in my coding workflow...

I also finally started making sense of how to best use the "Visual" selection modes:
  • v = Letter by letter mode. Its killer use case is when "cw" doesn't work (and you don't know/understand how to use substitute, or wouldn't anyway as it was too error prone or cumbersome) for replacing part of an identifier. Things like changing "newspaperMouseArea" to "moviesMouseArea". To do this, simply do "v8lc" - (v = enter letter-by-letter select, 8l = advance the cursor 8 times to select all the unwanted part, c = enter "change text" mode to start typing the new value for that part)
  • Shift-V = Entire-line mode. Its killer use case is to copy off a number of lines of code somewhere else in the file. Simply do "Shift-V jjj..." or similar to select all the lines of code to copy, followed by "y" to copy to clipboard, then "o <Esc> p" to paste the copied code to its new home.
  • Ctrl-B = Block mode. This one I'm still getting to terms with, but it seems I should be able to use this for inserting stuff at the start of a bunch of lines, if I enter edit-mode using Shift-I (plain-i doesn't do anything :/)

No comments:

Post a Comment