Monthly Archives: March 2010

C++ AutoComplete feature in VIM

I really needed a context-sensitive C++ autocomplete feature for Vim, which would allow me to do crazy things like autocompleting class member names.  As it turns out, there is a way to do that, and it works pretty well.  I decided to write up how I set things up myself, in hopes that this will help others as well.

Here is what you need in order to set things up:

So, you need to install Vim and Ctags (which is platform dependent, and I leave it to you to figure out how to do that in your own platform).  Once you get those set up, grab the OmniCppComplete plugin, and extract it to the .vim directory under your home directory (create it if it doesn’t exist).  After that, you want to put the following inside your ~/.vimrc:

" omnicppcomplete options
map  :!ctags -R --c++-kinds=+p --fields=+iaS --extra=+q -f ~/.vim/commontags /usr/include /usr/local/include ~/moz/obj-ff-dbg/dist/include
set tags+=~/.vim/commontags

" --- OmniCppComplete ---
" -- required --
set nocp " non vi compatible mode
filetype plugin on " enable plugins

" -- optional --
" auto close options when exiting insert mode or moving away
autocmd CursorMovedI * if pumvisible() == 0|pclose|endif
autocmd InsertLeave * if pumvisible() == 0|pclose|endif
set completeopt=menu,menuone

" -- configs --
let OmniCpp_MayCompleteDot = 1 " autocomplete with .
let OmniCpp_MayCompleteArrow = 1 " autocomplete with ->
let OmniCpp_MayCompleteScope = 1 " autocomplete with ::
let OmniCpp_SelectFirstItem = 2 " select first item (but don't insert)
let OmniCpp_NamespaceSearch = 2 " search namespaces in this and included files
let OmniCpp_ShowPrototypeInAbbr = 1 " show function prototype (i.e. parameters) in popup window
let OmniCpp_LocalSearchDecl = 1 " don't require special style of function opening braces

" -- ctags --
" map +F12 to generate ctags for current folder:
map  :!ctags -R --c++-kinds=+p --fields=+iaS --extra=+q .
" add current directory's generated tags file to available tags
set tags+=./tags

" Setup the tab key to do autocompletion
function! CompleteTab()
  let prec = strpart( getline('.'), 0, col('.')-1 )
  if prec =~ '^\s*$' || prec =~ '\s$'
    return "\"
  else
    return "\\"
  endif
endfunction

inoremap  =CompleteTab()

You can of course customize this however you like, but the only part that you really need to customize is the second line.  You would probably want to leave /usr/include and /usr/local/include there, but you can replace ~/moz/obj-ff-dbg/dist/include to whatever project specific directory which contains header files which contain definitions which you want to include in the C++ autocompletion.  ~/moz/obj-ff-dbg/dist/include is a path on my system which contains all header files we use in Mozilla.

The autocompletion functionality is based on the ctags database.  This is a list of all symbols found in header files.  With this setup, you have two separate ctags databases, one is for your system-wide headers (which should change rarely), and the other is for your project-specific symbols.  The former is stored in ~/.vim/commontags, and the latter is stored as a file named tags in your current directory.  To update the system-wide ctags database, you can use Ctrl+X, Ctrl+X, Ctrl+T.  To update the local ctags database (which is created from the contents of the current directory, recursively), you can use Ctrl+X Ctrl+T.  You would usually update the local ctags database from time to time to make sure that the latest changes in your source files are reflected in the ctags database.

Now, open a C++ file inside Vim.  Let’s say you type the beginning of a symbol, and then press Tab.  A list of symbols matching what you have types appear on the screen, like this:

Autocompletion using tab

Also, if you type ., -> or ::, you will be presented with a list of autocomplete options as well.

Autocompletion after .Autocompletion after ->Autocompletion after ::

And that’s it! If you feel adventurous, you can type :help omnicpp in Vim and start exploring what else you can do, but this setup is working perfectly fine for me.

Posted in Blog Tagged with: ,

Thoughts on the future of web-based HTML editors

The ability of editing HTML content on the web is nothing new, we’ve all used it to write emails in Web-based email clients, post content on our blogs, adding content to web sites, etc.  Web sites usually do this using the execCommand API, with either iframes put into designMode, or contentEditable elements, and occasionally utilize things such as the DOM Range API and Selection API.

Things sound great, but in practice, they’re not.  If you’re a web developer, you know that almost nobody tries to use the above APIs directly, and instead everyone resorts to one of the web editor widgets.  The reason for that in my opinion is that there are numerous problems with how browsers implement HTML editing, and these problems cause real pain for web developers, and make it extremely tricky, if possible at all, to get a cross browser and interoperable HTML editing experience.  So, let’s see where the problem lies.

  • Problems with the API.  The execCommand API was first added to IE 5.5 by Microsoft.  This API is very different to all other web APIs, and is in fact an adaptation of the IOleCommandTarget API in MSCOM.  This API is very hard to use, because:
    • It is unintuitive: you just issue commands, and you can’t even control where the commands are going to end up affecting directly.
    • It is not extensible: you don’t have any way to add your own editing commands in a seamless way.  You can’t even query the browser to determine which sets of commands it supports.
    • It is not customizable: some of the commands might show a user interface component provided by the browser, and there is no way to disable that UI or change how it looks.
    • It is not comprehensive: some very important editing functions (like undo/redo lists and spell-checking) are not exposed via the API at all, so there is no way to integrate them into your web application.  You can’t even be sure that those built-in facilities will even work if you’re not careful enough (example: modifying the editable DOM tree in some browsers disables undo/redo functionality.)
  • Lack of specification.  Because web based editing was first added as a proprietary feature to IE, there is no specification defining how it should work.  Other browsers tried to come up with a compatible set of APIs, but that’s unfortunately not even possible, because nobody really knows how IE works in every aspect, so nobody can aim to emulate its behavior correctly.  The lack of specification has created several real-world problems for both web developers and users:
    • Nobody knows what should happen after a command.  For example, when you issue a bold command, some browsers choose to wrap the selected text in a <b> tag, some use a <strong> tag, and some use CSS styles on a <span> element (and there are many more cases for what can happen when a bold command is issued.  This means that if you issue a set of editing commands in different browsers, the HTML markup generated can vary greatly.
    • Nobody knows how (and if) interoperability should happen.  Let’s take the example of the bold command here.  Because different browsers tend to use different methods to make text bold, they usually have difficulty removing the bold style from some piece of text.  This is really frustrating for users, and there is no easy solution to this problem.
    • Nobody knows how keyboard commands should affect the editable area.  Pressing a key can have multiple results based on the position of selection/caret.  For example, pressing Enter can lead to text being deleted, injected, elements being deleted, injected, and it can modify the caret position in unexpected ways.
    • The default behavior of keyboard shortcuts are not specified.   For example, web browsers may choose to tie Ctrl/Cmd+B to the Bold command, but it’s not possible for web pages to determine what these keyboard shortcuts do, and if they are even available (they might not be on localized versions of browsers, for example.)
    • Nobody knows how the browser should handle HTML data from external sources (such as pasting something inside the editor, or setting the innerHTML attribute.)
  • Poor quality of implementation.  Implementing an HTML editor can be extremely complex.  And it turns out that you can actually find bugs with all of the major browsers by just playing with a content editable element for a few minutes!

As you can see, the situation is not very good here.  We have some API which has a lot of problems in its own, and every browser has tried to implement it to some extent, but the behavior of each browser is different, and there is no specification which determines how a browser should implement this functionality.  What this means in practice for web developers is that getting a cross-browser web application which uses these APIs directly is extremely difficult to achieve, and that is why web developers prefer to use web editor widgets which have tried to abstract away as much of these problems as possible.

There have been some attempts at trying to add a common denominator of what different browsers do today into the HTML5 specification, but we need more comprehensive specification to be able to address all of the existing issues.

Mozilla has recently launched a mailing list for people interested in the current state and future of HTML editing in web browsers.  The list is called htmlediting-community.  We are looking for web developers, engineers working on browser engines, people interested in web based APIs and the future of HTML editing to join to this list, so that we can discuss the current issues with HTML editing in web browsers, and where we should be headed in terms of improvements to the web-based HTML editing experience for both users and developers.  Subscribe to this list here!

I’ve recently started to work on Mozilla’s HTML editor implementation (which is called Midas).  I have some plans on how to attack the above problems from different aspects.  Some of the plans are laid out as the following.

  • Fixing some problems which are relatively easy to fix in the near future.  I think we should have both a short and long term plan, and we should try to make some improvements, especially those which can help web developers and users a lot.  I’m looking for feedback from web developers on what those issues are, so that I can come up with a list of things to fix hopefully for the next release of Firefox.
  • Trying to create a comprehensive specification which can be used to implement HTML editing consistently across browsers and platforms.  This specification should address the currently existing APIs and user interactions, and should also propose a new set of APIs which don’t suffer from the basic problems I described above.  The new APIs should be extensible, customizable, intuitive and comprehensive.
  • Trying to write a set of cross-browser unit tests which can be used to test the implementation of both the existing and new APIs in different browsers.  The very important thing here is for the tests to work on multiple browsers, because I want the result of this work to be useful for other browser engines as well, so that we can all help move the web forward by providing a better HTML editing experience across browsers.  I’ve decided that I would try to extend the current BrowserScope RichText tests, so that we can use that work inside Mozilla and hopefully other browsers.
  • Trying to look into the best approach to move the HTML editor component for Mozilla forward.  At this point, I believe that rewriting the HTML editing support in JavaScript might be the best path to take here, because the existing code is extremely complex and fragile, and is not very well understood.  Also, implement this in JavaScript could have a few advantages, like making the less likely to cause crashes, more readable, and cleaner.  And maybe at some point we can actually consider taking the Mozilla-specific code and rewriting it for other web engines so that we can make the same code work in other browsers!

I’m still trying to figure out what needs to be done exactly in each part, and how to best tackle the problems.  I’d very much like to hear what the web has to say here.  If you’re a web developer, web browser engineer, or even a simple user, please leave comments and share what you think.  I will be writing more about this topic as I give it more thoughts, so you can keep an eye on the related posts in the future.  Oh, and participation on the htmlediting-community mailing list is very much appreciated as well!

Posted in Blog Tagged with: , ,