toolkit/devtools/server/actors/gcli.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/toolkit/devtools/server/actors/gcli.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,219 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +"use strict";
     1.9 +
    1.10 +var Cu = require('chrome').Cu;
    1.11 +var XPCOMUtils = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {}).XPCOMUtils;
    1.12 +
    1.13 +XPCOMUtils.defineLazyModuleGetter(this, "console",
    1.14 +                                  "resource://gre/modules/devtools/Console.jsm");
    1.15 +XPCOMUtils.defineLazyModuleGetter(this, "CommandUtils",
    1.16 +                                  "resource:///modules/devtools/DeveloperToolbar.jsm");
    1.17 +
    1.18 +XPCOMUtils.defineLazyGetter(this, "Requisition", function() {
    1.19 +  return require("gcli/cli").Requisition;
    1.20 +});
    1.21 +
    1.22 +XPCOMUtils.defineLazyGetter(this, "centralCanon", function() {
    1.23 +  return require("gcli/commands/commands").centralCanon;
    1.24 +});
    1.25 +
    1.26 +var util = require('gcli/util/util');
    1.27 +
    1.28 +var protocol = require("devtools/server/protocol");
    1.29 +var method = protocol.method;
    1.30 +var Arg = protocol.Arg;
    1.31 +var Option = protocol.Option;
    1.32 +var RetVal = protocol.RetVal;
    1.33 +
    1.34 +/**
    1.35 + * Manage remote connections that want to talk to GCLI
    1.36 + */
    1.37 +var GcliActor = protocol.ActorClass({
    1.38 +  typeName: "gcli",
    1.39 +
    1.40 +  initialize: function(conn, tabActor) {
    1.41 +    protocol.Actor.prototype.initialize.call(this, conn);
    1.42 +    this.tabActor = tabActor;
    1.43 +    let browser = tabActor.browser;
    1.44 +
    1.45 +    let environment = {
    1.46 +      chromeWindow: browser.ownerGlobal,
    1.47 +      chromeDocument: browser.ownerDocument,
    1.48 +      window: browser.contentWindow,
    1.49 +      document: browser.contentDocument
    1.50 +    };
    1.51 +
    1.52 +    this.requisition = new Requisition({ environment: env });
    1.53 +  },
    1.54 +
    1.55 +  /**
    1.56 +   * Retrieve a list of the remotely executable commands
    1.57 +   */
    1.58 +  specs: method(function() {
    1.59 +    return this.requisition.canon.getCommandSpecs();
    1.60 +  }, {
    1.61 +    request: {},
    1.62 +    response: RetVal("json")
    1.63 +  }),
    1.64 +
    1.65 +  /**
    1.66 +   * Execute a GCLI command
    1.67 +   * @return a promise of an object with the following properties:
    1.68 +   * - data: The output of the command
    1.69 +   * - type: The type of the data to allow selection of a converter
    1.70 +   * - error: True if the output was considered an error
    1.71 +   */
    1.72 +  execute: method(function(typed) {
    1.73 +    return this.requisition.updateExec(typed).then(function(output) {
    1.74 +      return output.toJson();
    1.75 +    });
    1.76 +  }, {
    1.77 +    request: {
    1.78 +      typed: Arg(0, "string") // The command string
    1.79 +    },
    1.80 +    response: RetVal("json")
    1.81 +  }),
    1.82 +
    1.83 +  /**
    1.84 +   * Get the state of an input string. i.e. requisition.getStateData()
    1.85 +   */
    1.86 +  state: method(function(typed, start, rank) {
    1.87 +    return this.requisition.update(typed).then(function() {
    1.88 +      return this.requisition.getStateData(start, rank);
    1.89 +    }.bind(this));
    1.90 +  }, {
    1.91 +    request: {
    1.92 +      typed: Arg(0, "string"), // The command string
    1.93 +      start: Arg(1, "number"), // Cursor start position
    1.94 +      rank: Arg(2, "number") // The prediction offset (# times UP/DOWN pressed)
    1.95 +    },
    1.96 +    response: RetVal("json")
    1.97 +  }),
    1.98 +
    1.99 +  /**
   1.100 +   * Call type.parse to check validity. Used by the remote type
   1.101 +   * @return a promise of an object with the following properties:
   1.102 +   * - status: Of of the following strings: VALID|INCOMPLETE|ERROR
   1.103 +   * - message: The message to display to the user
   1.104 +   * - predictions: An array of suggested values for the given parameter
   1.105 +   */
   1.106 +  typeparse: method(function(typed, param) {
   1.107 +    return this.requisition.update(typed).then(function() {
   1.108 +      var assignment = this.requisition.getAssignment(param);
   1.109 +
   1.110 +      return promise.resolve(assignment.predictions).then(function(predictions) {
   1.111 +        return {
   1.112 +          status: assignment.getStatus().toString(),
   1.113 +          message: assignment.message,
   1.114 +          predictions: predictions
   1.115 +        };
   1.116 +      });
   1.117 +    });
   1.118 +  }, {
   1.119 +    request: {
   1.120 +      typed: Arg(0, "string"), // The command string
   1.121 +      param: Arg(1, "string") // The name of the parameter to parse
   1.122 +    },
   1.123 +    response: RetVal("json")
   1.124 +  }),
   1.125 +
   1.126 +  /**
   1.127 +   * Get the incremented value of some type
   1.128 +   * @return a promise of a string containing the new argument text
   1.129 +   */
   1.130 +  typeincrement: method(function(typed, param) {
   1.131 +    return this.requisition.update(typed).then(function() {
   1.132 +      var assignment = this.requisition.getAssignment(param);
   1.133 +      return this.requisition.increment(assignment).then(function() {
   1.134 +        return assignment.arg == null ? undefined : assignment.arg.text;
   1.135 +      });
   1.136 +    });
   1.137 +  }, {
   1.138 +    request: {
   1.139 +      typed: Arg(0, "string"), // The command string
   1.140 +      param: Arg(1, "string") // The name of the parameter to parse
   1.141 +    },
   1.142 +    response: RetVal("string")
   1.143 +  }),
   1.144 +
   1.145 +  /**
   1.146 +   * See typeincrement
   1.147 +   */
   1.148 +  typedecrement: method(function(typed, param) {
   1.149 +    return this.requisition.update(typed).then(function() {
   1.150 +      var assignment = this.requisition.getAssignment(param);
   1.151 +      return this.requisition.decrement(assignment).then(function() {
   1.152 +        return assignment.arg == null ? undefined : assignment.arg.text;
   1.153 +      });
   1.154 +    });
   1.155 +  }, {
   1.156 +    request: {
   1.157 +      typed: Arg(0, "string"), // The command string
   1.158 +      param: Arg(1, "string") // The name of the parameter to parse
   1.159 +    },
   1.160 +    response: RetVal("string")
   1.161 +  }),
   1.162 +
   1.163 +  /**
   1.164 +   * Perform a lookup on a selection type to get the allowed values
   1.165 +   */
   1.166 +  selectioninfo: method(function(commandName, paramName, action) {
   1.167 +    var command = this.requisition.canon.getCommand(commandName);
   1.168 +    if (command == null) {
   1.169 +      throw new Error('No command called \'' + commandName + '\'');
   1.170 +    }
   1.171 +
   1.172 +    var type;
   1.173 +    command.params.forEach(function(param) {
   1.174 +      if (param.name === paramName) {
   1.175 +        type = param.type;
   1.176 +      }
   1.177 +    });
   1.178 +    if (type == null) {
   1.179 +      throw new Error('No parameter called \'' + paramName + '\' in \'' +
   1.180 +                      commandName + '\'');
   1.181 +    }
   1.182 +
   1.183 +    switch (action) {
   1.184 +      case 'lookup':
   1.185 +        return type.lookup(context);
   1.186 +      case 'data':
   1.187 +        return type.data(context);
   1.188 +      default:
   1.189 +        throw new Error('Action must be either \'lookup\' or \'data\'');
   1.190 +    }
   1.191 +  }, {
   1.192 +    request: {
   1.193 +      typed: Arg(0, "string"), // The command containing the parameter in question
   1.194 +      param: Arg(1, "string"), // The name of the parameter
   1.195 +      action: Arg(1, "string") // 'lookup' or 'data' depending on the function to call
   1.196 +    },
   1.197 +    response: RetVal("json")
   1.198 +  })
   1.199 +});
   1.200 +
   1.201 +exports.GcliFront = protocol.FrontClass(GcliActor, {
   1.202 +  initialize: function(client, tabForm) {
   1.203 +    protocol.Front.prototype.initialize.call(this, client);
   1.204 +    this.actorID = tabForm.gcliActor;
   1.205 +
   1.206 +    // XXX: This is the first actor type in its hierarchy to use the protocol
   1.207 +    // library, so we're going to self-own on the client side for now.
   1.208 +    client.addActorPool(this);
   1.209 +    this.manage(this);
   1.210 +  },
   1.211 +});
   1.212 +
   1.213 +/**
   1.214 + * Called the framework on DebuggerServer.registerModule()
   1.215 + */
   1.216 +exports.register = function(handle) {
   1.217 +  handle.addTabActor(GcliActor, "gcliActor");
   1.218 +};
   1.219 +
   1.220 +exports.unregister = function(handle) {
   1.221 +  handle.removeTabActor(GcliActor);
   1.222 +};

mercurial