Snippets code from my daily experience

April 12, 2009

Should Komodo macros have to support auto update? (Sunday Thought)

Filed under: komodo,macro,sunday_thought — dafi @ 1:00 am
Tags: , , , , ,

The Komodo macro ecosystem grows quickly and many state-of-art macros born every day.

I’ve already said in the past that Komodo macro environment is powerful like Microsoft VBA although it has many lacks (like UI creation).

I would have a similar environment on every Mozilla based application something like a KoMonkey or GreaseModo ūüėõ (Komodo macros plus GreaseMonkey).

Macros become more complex and the authors release many revisions thanks to community feedback but today it is difficult to stay tuned when new versions are published.

Adding an update checker to KPZ files is possible but not easy, many technical aspects must be considered.

Today the best approach consists to pack macros like extensions (XPI files) but developers need deeper knowledge and this should be frustrating.

I’m sure the Komodo macros are at the beginning of a radical evolution

April 1, 2009

Colored file tabs for Komodo

Filed under: extension,komodo,macro,openkomodo,xul — dafi @ 1:37 pm

A couple of months ago I wrote a Komodo macro allowing the editor view tabs to be colored based on user defined color schemes, when the macro became stable I published it on Komodo community forum.

Amazingly the macro received more feedback so I decided to ‘convert’ it to an XUL extension.

Komodo macros are fantastic but they don’t allow to create complex UIs so moving them to XPI become a necessary step.

Now ColorTab is ready and can be downloaded from here.

The original name was KolorTab, the ‘K’ letter used to remember Komodo but I’ve decided to use a more tradictional name ūüėõ

ColorTab look&feel

ColorTab look&feel

January 20, 2009

Posting syntax highlighted code on wordpress.com using Komodo macro

This post is superseded, now it is possible to use native tag also on wordpress.com, more details can be found here

Soon or later any blogger talking about software development will post some snippet of code.

To make code more cool and attractive he/she will use syntax highlight.

There are many alternatives for many blog platforms like Pygments, GeSHI, CodeHighlighter, WP-Syntax and so on.

This blog is hosted on the free version of WordPress.com, it doesn’t allow to use any plugin or user-defined CSS so adding sexy code is very difficult.

Komodo has the ability to print to HTML files code with the syntax highlighted, this feature is fully accessible from APIs so I’ve written a macro that

  • make CSS style inline replacing HTML class with corresponding style attributes
  • copy to clipboard (using the new Komodo 5 clipboard helper library) in HTML format so user can paste directly on Visual WordPress mode

Below you find the macro source code obviously highlighted by itself ūüėõ

How to get the selected text (or the whole Komodo view) converted to HTML

The variable str at end contains the converted HTML

var view = ko.views.manager.currentView;

var tmpFileSvc = Components.classes["@activestate.com/koFileService;1"]
                 .getService(Components.interfaces.koIFileService)
fname = tmpFileSvc.makeTempName(".html");

var lang = view.document.languageObj;
var forceColor = true;
var selectionOnly = view.selection != "";
var schemeService = Components.classes['@activestate.com/koScintillaSchemeService;1'].getService();
schemeService.convertToHTMLFile(view.scimoz,
                                view.document.displayPath,
                                view.document.language,
                                lang.styleBits,
                                view.document.encoding.python_encoding_name,
                                fname,
                                selectionOnly,
                                forceColor);

var file = Components.classes["@activestate.com/koFileEx;1"]
        .createInstance(Components.interfaces.koIFileEx)
file.URI = ko.uriparse.localPathToURI(fname);
file.open('rb');
var str = file.readfile();
file.close();

Applying the replace to str

Nothing really interesting, simply the replace method is called many times to make CSS style inline inside span tags

Copy to clipboard in HTML format

Komodo 5 allows to interact with clipboard wrapping XPCOM services, these APIs allow to copy in the so called HTML flavor so content preserves styles and colors.

xtk.include("clipboard");

var transferable = xtk.clipboard.addTextDataFlavor("text/html", str);
transferable = xtk.clipboard.addTextDataFlavor("text/unicode", str, transferable);
xtk.clipboard.copyFromTransferable(transferable);

That’s all folks

After running this macro on a Komodo view you can paste directly on WordPress Visual editor and obtain your beautiful code.

Using HTML flavor you can paste into any application able to accept Special Formats like Microsoft Word or OpenOffice Writer.

The full macro source code can be found on Macro SVN repository

December 22, 2008

Downloading protected resources using nsIChannel and friends

Filed under: babelzilla,extension,komodo,macro,nsIChannel,nsIStreamListener — dafi @ 2:35 pm

A couple of days ago I needed to automate file downloading from a service, a very trivial task in every programming language (or using wget).

The little complication was represented by the web based authentication mechanism (userid/password) needed to access to files.
Determining which files to download and their usage (unzipping and picking files) required some specific business logic, nothing really complicated but very annoying.

After a while I realized this job can be done using Javascript and XPCOM and here I would share the solution based on nsIChannel.

What is does

  • the service uses userid and password to login
  • login to the service using HTTP POST method, it simulates an HTML <form/> submission
  • store the cookies sent from server. They contains credentials login data, cookies usage is a prerequisite in our scenario
  • reuse login data to download protected resources

Example usage

Suppose you want to automate download of extensions stored on AMO‘s sandbox, you must login first so this use-case is perfect for us.
Someone can consider this approach ugly, web services or Remora API are better but here I only want to demonstrate how to use nsIChannel.

Let’s start…

You can write the Javascript code shown below to download my extension RichFeedButton (dropped on sandbox an year ago)

var amoUsername = "dafi@localhost";
var amoPassword = "my_secret_code";
downloadProtectedResource(
   "https://addons.mozilla.org/it/firefox/users/login",

   "data[Login][email]=" + amoUsername + "&data[Login][password]" + amoPassword,

   "https://addons.mozilla.org/en-US/firefox/downloads/file/33926/richfeedbutton-0.0.21-fx.xpi",

   "/tmp/richfeedbutton-0.0.21-fx.xpi");

where our downloadProtectedResource function signature is shown below

function downloadProtectedResource(loginUrl, postData, resourceUrl, destPathName) { ... }

Nothing special, simply we need to know the HTML input names used for userid and password (ie data[Login][email] and data[Login][password]) and pass them in postData argument.

The downloadProtectedResource interacts with nsIChannel (nsIHttpChannel) and other XPCOM object

function downloadProtectedResource(loginUrl, postData, resourceUrl, destPathName) {
   var httpChannel = makeHttpChannel(loginUrl); // create an object nsIHttpChannel
   var stream = makeStringStream(postData); // create an object nsIStringInputStream
   setChannelPostData(httpChannel, stream); // fill data using nsIUploadChannel

   // downloader saves data on disk
   var downloader = new Downloader(resourceUrl, destPathName);
   // make a login then passes cookies to downloader object
   var cookieListener = new CookieRetrieverListener(downloader);

   // start authentication and download
   httpChannel.asyncOpen(cookieListener, null);
}

The object Downloader and CookieRetrieverListener implement the nsIStreamListener interface.

The cookieListener after obtaining cookies aborts the operation because we don’t need all server output, then it calls the downloader.

function CookieRetrieverListener(downloader) {
   this.downloader = downloader;
   this.cookies = "";
}

CookieRetrieverListener.prototype = {
   onStartRequest: function(request, ctx) {
         var channel = request.QueryInterface(Components.interfaces.nsIHttpChannel);
         this.cookies = channel.getRequestHeader("Cookie");

         // no need more data
         throw Components.results.NS_ERROR_ABORT;
   },

   onDataAvailable : function(request, context, inputStream, offset, count) {
   },

   onStopRequest: function(request, ctx, status) {
      this.downloader.cookies = this.cookies;
      this.downloader.start();
   }
}

Another way to use this code consists to download localizations from BabelZilla as shown below.
BabelZilla requires many parameters on query string ūüėē


var bzUsername = "dafi_duck";
var bzPassword = "my_secret_code";
var bzItemId = "88";
var bzExtId = "4432";
downloadProtectedResource("http://www.babelzilla.org/index.php",
                 "op2=login&lang=english&message=0"
                        + "&option=ipblogin&task=login&0b14737c5ade1f7697a8f81b33b0bacf=1"
                        + "&option=com_frontpage&Itemid=1"
                        + "&username=" + bzUsername
                        + "&passwd=" + bzPassword,
                 "http://www.babelzilla.org/index.php?option=com_wts&type=downloadtar"
                        + "&Itemid=" + bzItemId
                        + "&extension=" + bzExtId,
                 "/tmp/vsw.tar.gz");

nsIChannel.asyncOpen

Accessing to cookies received from server requires to use nsIStreamListener available only in asynchronous open calls.

This needs to start the download only when cookies are surely retrieved, this is achieved using the nsIRequestObserver.onStopRequest, any better idea is very appreciated.

Complete code

The complete code contains a few of helper functions (reading binary stream, saving file) and is available on SVN, it’s ready to be executed as Komodo macro simply setting userid and password.

October 20, 2008

Adding Komodo macros to context menu

Filed under: context menu,komodo,macro,onpopupshowing,xul — dafi @ 6:37 pm

Komodo macros allow to add new features to the editor, they are like little XUL extensions embedded into application.

I’ve written dozen of macros and many of them are strictly related to cursor position or selected text so it sounds reasonable to access them using the context menu but at this time Komodo doesn’t allow this.

Adding macros to context menu is easy, it can be done also using a ‘Trojan’ macro ūüėÄ triggered at Komodo startup but the best results are achieved using an extension containing configuration dialogs and other whistle and bells.

I’m lazy so I use one mega wrapper extension where I put any new code, a very quick and dirty practice.

Here I want to share the snippets necessary to add macros to context menu and running them selecting the corresponding menuitem.

For the sake of example the code shown below adds all macros found on toolbox, this can produce a very long (and unusable) menu.

It is necessary to install the onpopupshowing event handler so we can add/remove menu items dynamically.



onLoad : function() {
    var ctx = document.getElementById("editorContextMenu");
    ctx.addEventListener("popupshowing", this.onPopupShowing, false);
}

the onPopupShowing function accesses to toolbox and populates the context menu



onPopupShowing : function(event) {
    var arr = {};
    var count = {};

    // get all macros, very ugly but easy to customize
    ko.toolboxes.user.toolbox.getChildrenByType("macro", true, arr, count);

    // remove menu items
    var i = 0;
    var mi;
    for (var i = 0; mi = document.getElementById("macro2ctx" + i); i++) {
        mi.parentNode.removeChild(mi);
    }

    var ctx = document.getElementById("editorContextMenu");
    for (var i = 0; i < count.value; i++) {
        var mi = document.createElement("menuitem");
        var file = arr.value[i].getFile();
        mi.setAttribute("id", "macro2ctx" + i);
        mi.setAttribute("label", file.leafName);
        mi.setAttribute("oncommand", "macro2Ctx.onRunMacro('" + file.displayPath + "')");
        ctx.appendChild(mi);
    }
}

Finally the onRunMacro function executes the macro found starting from its URL

onRunMacro : function(url) {
var item = ko.toolboxes.user.toolbox.getChildByURL(url);
ko.projects.executeMacro(item);
}

That’s all Folks

I hope to move all code on a separated extension and publish it…

but before

  • Macros to add to context menu must be choosen by user
  • Macros must be removed easily
  • Choose the context menu to use (tab context menu or editor context menu)
  • Allow to show macro only if it matches some criteria (like isCommandEnabled)
  • Better error handling

Blog at WordPress.com.