michael@0: michael@0: # Developing GCLI michael@0: michael@0: ## About the code michael@0: michael@0: The majority of the GCLI source is stored in the ``lib`` directory. michael@0: michael@0: The ``docs`` directory contains documentation. michael@0: The ``scripts`` directory contains RequireJS that GCLI uses. michael@0: The ``build`` directory contains files used when creating builds. michael@0: The ``mozilla`` directory contains the mercurial patch queue of patches to apply michael@0: to mozilla-central. michael@0: The ``selenium-tests`` directory contains selenium web-page integration tests. michael@0: michael@0: The source in the ``lib`` directory is split into 4 sections: michael@0: michael@0: - ``lib/demo`` contains commands used in the demo page. It is not needed except michael@0: for demo purposes. michael@0: - ``lib/test`` contains a small test harness for testing GCLI. michael@0: - ``lib/gclitest`` contains tests that run in the test harness michael@0: - ``lib/gcli`` contains the actual meat michael@0: michael@0: GCLI is split into a UI portion and a Model/Controller portion. michael@0: michael@0: michael@0: ## The GCLI Model michael@0: michael@0: The heart of GCLI is a ``Requisition``, which is an AST for the input. A michael@0: ``Requisition`` is a command that we'd like to execute, and we're filling out michael@0: all the inputs required to execute the command. michael@0: michael@0: A ``Requisition`` has a ``Command`` that is to be executed. Each Command has a michael@0: number of ``Parameter``s, each of which has a name and a type as detailed michael@0: above. michael@0: michael@0: As you type, your input is split into ``Argument``s, which are then assigned to michael@0: ``Parameter``s using ``Assignment``s. Each ``Assignment`` has a ``Conversion`` michael@0: which stores the input argument along with the value that is was converted into michael@0: according to the type of the parameter. michael@0: michael@0: There are special assignments called ``CommandAssignment`` which the michael@0: ``Requisition`` uses to link to the command to execute, and michael@0: ``UnassignedAssignment``used to store arguments that do not have a parameter michael@0: to be assigned to. michael@0: michael@0: michael@0: ## The GCLI UI michael@0: michael@0: There are several components of the GCLI UI. Each can have a script portion, michael@0: some template HTML and a CSS file. The template HTML is processed by michael@0: ``domtemplate`` before use. michael@0: michael@0: DomTemplate is fully documented in [it's own repository] michael@0: (https://github.com/joewalker/domtemplate). michael@0: michael@0: The components are: michael@0: michael@0: - ``Inputter`` controls the input field, processing special keyboard events and michael@0: making sure that it stays in sync with the Requisition. michael@0: - ``Completer`` updates a div that is located behind the input field and used michael@0: to display completion advice and hint highlights. It is stored in michael@0: completer.js. michael@0: - ``Display`` is responsible for containing the popup hints that are displayed michael@0: above the command line. Typically Display contains a Hinter and a RequestsView michael@0: although these are not both required. Display itself is optional, and isn't michael@0: planned for use in the first release of GCLI in Firefox. michael@0: - ``Hinter`` Is used to display input hints. It shows either a Menu or an michael@0: ArgFetch component depending on the state of the Requisition michael@0: - ``Menu`` is used initially to select the command to be executed. It can act michael@0: somewhat like the Start menu on windows. michael@0: - ``ArgFetch`` Once the command to be executed has been selected, ArgFetch michael@0: shows a 'dialog' allowing the user to enter the parameters to the selected michael@0: command. michael@0: - ``RequestsView`` Contains a set of ``RequestView`` components, each of which michael@0: displays a command that has been invoked. RequestsView is a poor name, and michael@0: should better be called ReportView michael@0: michael@0: ArgFetch displays a number of Fields. There are fields for most of the Types michael@0: discussed earlier. See 'Writing Fields' above for more information. michael@0: michael@0: michael@0: ## Testing michael@0: michael@0: GCLI contains 2 test suites: michael@0: michael@0: - JS level testing is run with the ``test`` command. The tests are located in michael@0: ``lib/gclitest`` and they use the test runner in ``lib/test``. This is fairly michael@0: comprehensive, however it does not do UI level testing. michael@0: If writing a new test it needs to be registered in ``lib/gclitest/index``. michael@0: For an example of how to write tests, see ``lib/gclitest/testSplit.js``. michael@0: The test functions are implemented in ``lib/test/assert``. michael@0: - Browser integration tests are included in ``browser_webconsole_gcli_*.js``, michael@0: in ``toolkit/components/console/hudservice/tests/browser``. These are michael@0: run with the rest of the Mozilla test suite. michael@0: michael@0: michael@0: ## Coding Conventions michael@0: michael@0: The coding conventions for the GCLI project come from the Bespin/Skywriter and michael@0: Ace projects. They are roughly [Crockford] michael@0: (http://javascript.crockford.com/code.html) with a few exceptions and michael@0: additions: michael@0: michael@0: * ``var`` does not need to be at the top of each function, we'd like to move michael@0: to ``let`` when it's generally available, and ``let`` doesn't have the same michael@0: semantic twists as ``var``. michael@0: michael@0: * Strings are generally enclosed in single quotes. michael@0: michael@0: * ``eval`` is to be avoided, but we don't declare it evil. michael@0: michael@0: The [Google JavaScript conventions] michael@0: (https://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml) are michael@0: more detailed, we tend to deviate in: michael@0: michael@0: * Custom exceptions: We generally just use ``throw new Error('message');`` michael@0: michael@0: * Multi-level prototype hierarchies: Allowed; we don't have ``goog.inherits()`` michael@0: michael@0: * ``else`` begins on a line by itself: michael@0: michael@0: if (thing) { michael@0: doThis(); michael@0: } michael@0: else { michael@0: doThat(); michael@0: } michael@0: michael@0: michael@0: ## Startup michael@0: michael@0: Internally GCLI modules have ``startup()``/``shutdown()`` functions which are michael@0: called on module init from the top level ``index.js`` of that 'package'. michael@0: michael@0: In order to initialize a package all that is needed is to require the package michael@0: index (e.g. ``require('package/index')``). michael@0: michael@0: The ``shutdown()`` function was useful when GCLI was used in Bespin as part of michael@0: dynamic registration/de-registration. It is not known if this feature will be michael@0: useful in the future. So it has not been entirely removed, it may be at some michael@0: future date. michael@0: michael@0: michael@0: ## Running the Unit Tests michael@0: michael@0: Start the GCLI static server: michael@0: michael@0: cd path/to/gcli michael@0: node gcli.js michael@0: michael@0: Now point your browser to http://localhost:9999/localtest.html. When the page michael@0: loads the tests will be automatically run outputting to the console, or you can michael@0: enter the ``test`` command to run the unit tests. michael@0: michael@0: michael@0: ## Contributing Code michael@0: michael@0: Please could you do the following to help minimize the amount of rework that we michael@0: do: michael@0: michael@0: 1. Check the unit tests run correctly (see **Running the Unit Tests** above) michael@0: 2. Check the code follows the style guide. At a minimum it should look like the michael@0: code around it. For more detailed notes, see **Coding Conventions** above michael@0: 3. Help me review your work by using good commit comments. Which means 2 things michael@0: * Well formatted messages, i.e. 50 char summary including bug tag, followed michael@0: by a blank line followed by a more in-depth message wrapped to 72 chars michael@0: per line. This is basically the format used by the Linux Kernel. See the michael@0: [commit log](https://github.com/joewalker/gcli/commits/master) for michael@0: examples. The be extra helpful, please use the "shortdesc-BUGNUM: " if michael@0: possible which also helps in reviews. michael@0: * Commit your changes as a story. Make it easy for me to understand the michael@0: changes that you've made. michael@0: 4. Sign your work. To improve tracking of who did what, we follow the sign-off michael@0: procedure used in the Linux Kernel. michael@0: The sign-off is a simple line at the end of the explanation for the michael@0: patch, which certifies that you wrote it or otherwise have the right to michael@0: pass it on as an open-source patch. The rules are pretty simple: if you michael@0: can certify the below: michael@0: michael@0: Developer's Certificate of Origin 1.1 michael@0: michael@0: By making a contribution to this project, I certify that: michael@0: michael@0: (a) The contribution was created in whole or in part by me and I michael@0: have the right to submit it under the open source license michael@0: indicated in the file; or michael@0: michael@0: (b) The contribution is based upon previous work that, to the best michael@0: of my knowledge, is covered under an appropriate open source michael@0: license and I have the right under that license to submit that michael@0: work with modifications, whether created in whole or in part michael@0: by me, under the same open source license (unless I am michael@0: permitted to submit under a different license), as indicated michael@0: in the file; or michael@0: michael@0: (c) The contribution was provided directly to me by some other michael@0: person who certified (a), (b) or (c) and I have not modified michael@0: it. michael@0: michael@0: (d) I understand and agree that this project and the contribution michael@0: are public and that a record of the contribution (including all michael@0: personal information I submit with it, including my sign-off) is michael@0: maintained indefinitely and may be redistributed consistent with michael@0: this project or the open source license(s) involved. michael@0: michael@0: then you just add a line saying michael@0: michael@0: Signed-off-by: Random J Developer michael@0: michael@0: using your real name (sorry, no pseudonyms or anonymous contributions.) michael@0: michael@0: Thanks for wanting to contribute code. michael@0: