diff --git a/Documentation/licenses.txt b/Documentation/licenses.txt index eec1931e6e..cfb2ec2367 100644 --- a/Documentation/licenses.txt +++ b/Documentation/licenses.txt @@ -36,7 +36,7 @@ OpenXRI <> Neko HTML <> Ehcache <> mime-util <> -Jetty <>, or link:http://www.eclipse.org/legal/epl-v10.html[EPL] +Jetty <>, or link:http://www.eclipse.org/legal/epl-v10.html[EPL] Google Code Prettify <> Java Servlet API <> ICU4J <> @@ -49,6 +49,8 @@ ANTLR <> args4j <> SLF4J <> Clippy <> +Mozilla Rhino <> +juniversalchardet <> ----------------------------------------------------------- Cryptography Notice @@ -644,6 +646,484 @@ All trademarks and registered trademarks mentioned herein are the property of their respective owners. ---- +[[mpl1_1]] +Mozilla Public License 1.1 +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* link:http://www.mozilla.org/MPL/MPL-1.1.html + +---- + MOZILLA PUBLIC LICENSE + Version 1.1 + + --------------- + +1. Definitions. + + 1.0.1. "Commercial Use" means distribution or otherwise making the + Covered Code available to a third party. + + 1.1. "Contributor" means each entity that creates or contributes to + the creation of Modifications. + + 1.2. "Contributor Version" means the combination of the Original + Code, prior Modifications used by a Contributor, and the Modifications + made by that particular Contributor. + + 1.3. "Covered Code" means the Original Code or Modifications or the + combination of the Original Code and Modifications, in each case + including portions thereof. + + 1.4. "Electronic Distribution Mechanism" means a mechanism generally + accepted in the software development community for the electronic + transfer of data. + + 1.5. "Executable" means Covered Code in any form other than Source + Code. + + 1.6. "Initial Developer" means the individual or entity identified + as the Initial Developer in the Source Code notice required by Exhibit + A. + + 1.7. "Larger Work" means a work which combines Covered Code or + portions thereof with code not governed by the terms of this License. + + 1.8. "License" means this document. + + 1.8.1. "Licensable" means having the right to grant, to the maximum + extent possible, whether at the time of the initial grant or + subsequently acquired, any and all of the rights conveyed herein. + + 1.9. "Modifications" means any addition to or deletion from the + substance or structure of either the Original Code or any previous + Modifications. When Covered Code is released as a series of files, a + Modification is: + A. Any addition to or deletion from the contents of a file + containing Original Code or previous Modifications. + + B. Any new file that contains any part of the Original Code or + previous Modifications. + + 1.10. "Original Code" means Source Code of computer software code + which is described in the Source Code notice required by Exhibit A as + Original Code, and which, at the time of its release under this + License is not already Covered Code governed by this License. + + 1.10.1. "Patent Claims" means any patent claim(s), now owned or + hereafter acquired, including without limitation, method, process, + and apparatus claims, in any patent Licensable by grantor. + + 1.11. "Source Code" means the preferred form of the Covered Code for + making modifications to it, including all modules it contains, plus + any associated interface definition files, scripts used to control + compilation and installation of an Executable, or source code + differential comparisons against either the Original Code or another + well known, available Covered Code of the Contributor's choice. The + Source Code can be in a compressed or archival form, provided the + appropriate decompression or de-archiving software is widely available + for no charge. + + 1.12. "You" (or "Your") means an individual or a legal entity + exercising rights under, and complying with all of the terms of, this + License or a future version of this License issued under Section 6.1. + For legal entities, "You" includes any entity which controls, is + controlled by, or is under common control with You. For purposes of + this definition, "control" means (a) the power, direct or indirect, + to cause the direction or management of such entity, whether by + contract or otherwise, or (b) ownership of more than fifty percent + (50%) of the outstanding shares or beneficial ownership of such + entity. + +2. Source Code License. + + 2.1. The Initial Developer Grant. + The Initial Developer hereby grants You a world-wide, royalty-free, + non-exclusive license, subject to third party intellectual property + claims: + (a) under intellectual property rights (other than patent or + trademark) Licensable by Initial Developer to use, reproduce, + modify, display, perform, sublicense and distribute the Original + Code (or portions thereof) with or without Modifications, and/or + as part of a Larger Work; and + + (b) under Patents Claims infringed by the making, using or + selling of Original Code, to make, have made, use, practice, + sell, and offer for sale, and/or otherwise dispose of the + Original Code (or portions thereof). + + (c) the licenses granted in this Section 2.1(a) and (b) are + effective on the date Initial Developer first distributes + Original Code under the terms of this License. + + (d) Notwithstanding Section 2.1(b) above, no patent license is + granted: 1) for code that You delete from the Original Code; 2) + separate from the Original Code; or 3) for infringements caused + by: i) the modification of the Original Code or ii) the + combination of the Original Code with other software or devices. + + 2.2. Contributor Grant. + Subject to third party intellectual property claims, each Contributor + hereby grants You a world-wide, royalty-free, non-exclusive license + + (a) under intellectual property rights (other than patent or + trademark) Licensable by Contributor, to use, reproduce, modify, + display, perform, sublicense and distribute the Modifications + created by such Contributor (or portions thereof) either on an + unmodified basis, with other Modifications, as Covered Code + and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using, or + selling of Modifications made by that Contributor either alone + and/or in combination with its Contributor Version (or portions + of such combination), to make, use, sell, offer for sale, have + made, and/or otherwise dispose of: 1) Modifications made by that + Contributor (or portions thereof); and 2) the combination of + Modifications made by that Contributor with its Contributor + Version (or portions of such combination). + + (c) the licenses granted in Sections 2.2(a) and 2.2(b) are + effective on the date Contributor first makes Commercial Use of + the Covered Code. + + (d) Notwithstanding Section 2.2(b) above, no patent license is + granted: 1) for any code that Contributor has deleted from the + Contributor Version; 2) separate from the Contributor Version; + 3) for infringements caused by: i) third party modifications of + Contributor Version or ii) the combination of Modifications made + by that Contributor with other software (except as part of the + Contributor Version) or other devices; or 4) under Patent Claims + infringed by Covered Code in the absence of Modifications made by + that Contributor. + +3. Distribution Obligations. + + 3.1. Application of License. + The Modifications which You create or to which You contribute are + governed by the terms of this License, including without limitation + Section 2.2. The Source Code version of Covered Code may be + distributed only under the terms of this License or a future version + of this License released under Section 6.1, and You must include a + copy of this License with every copy of the Source Code You + distribute. You may not offer or impose any terms on any Source Code + version that alters or restricts the applicable version of this + License or the recipients' rights hereunder. However, You may include + an additional document offering the additional rights described in + Section 3.5. + + 3.2. Availability of Source Code. + Any Modification which You create or to which You contribute must be + made available in Source Code form under the terms of this License + either on the same media as an Executable version or via an accepted + Electronic Distribution Mechanism to anyone to whom you made an + Executable version available; and if made available via Electronic + Distribution Mechanism, must remain available for at least twelve (12) + months after the date it initially became available, or at least six + (6) months after a subsequent version of that particular Modification + has been made available to such recipients. You are responsible for + ensuring that the Source Code version remains available even if the + Electronic Distribution Mechanism is maintained by a third party. + + 3.3. Description of Modifications. + You must cause all Covered Code to which You contribute to contain a + file documenting the changes You made to create that Covered Code and + the date of any change. You must include a prominent statement that + the Modification is derived, directly or indirectly, from Original + Code provided by the Initial Developer and including the name of the + Initial Developer in (a) the Source Code, and (b) in any notice in an + Executable version or related documentation in which You describe the + origin or ownership of the Covered Code. + + 3.4. Intellectual Property Matters + (a) Third Party Claims. + If Contributor has knowledge that a license under a third party's + intellectual property rights is required to exercise the rights + granted by such Contributor under Sections 2.1 or 2.2, + Contributor must include a text file with the Source Code + distribution titled "LEGAL" which describes the claim and the + party making the claim in sufficient detail that a recipient will + know whom to contact. If Contributor obtains such knowledge after + the Modification is made available as described in Section 3.2, + Contributor shall promptly modify the LEGAL file in all copies + Contributor makes available thereafter and shall take other steps + (such as notifying appropriate mailing lists or newsgroups) + reasonably calculated to inform those who received the Covered + Code that new knowledge has been obtained. + + (b) Contributor APIs. + If Contributor's Modifications include an application programming + interface and Contributor has knowledge of patent licenses which + are reasonably necessary to implement that API, Contributor must + also include this information in the LEGAL file. + + (c) Representations. + Contributor represents that, except as disclosed pursuant to + Section 3.4(a) above, Contributor believes that Contributor's + Modifications are Contributor's original creation(s) and/or + Contributor has sufficient rights to grant the rights conveyed by + this License. + + 3.5. Required Notices. + You must duplicate the notice in Exhibit A in each file of the Source + Code. If it is not possible to put such notice in a particular Source + Code file due to its structure, then You must include such notice in a + location (such as a relevant directory) where a user would be likely + to look for such a notice. If You created one or more Modification(s) + You may add your name as a Contributor to the notice described in + Exhibit A. You must also duplicate this License in any documentation + for the Source Code where You describe recipients' rights or ownership + rights relating to Covered Code. You may choose to offer, and to + charge a fee for, warranty, support, indemnity or liability + obligations to one or more recipients of Covered Code. However, You + may do so only on Your own behalf, and not on behalf of the Initial + Developer or any Contributor. You must make it absolutely clear than + any such warranty, support, indemnity or liability obligation is + offered by You alone, and You hereby agree to indemnify the Initial + Developer and every Contributor for any liability incurred by the + Initial Developer or such Contributor as a result of warranty, + support, indemnity or liability terms You offer. + + 3.6. Distribution of Executable Versions. + You may distribute Covered Code in Executable form only if the + requirements of Section 3.1-3.5 have been met for that Covered Code, + and if You include a notice stating that the Source Code version of + the Covered Code is available under the terms of this License, + including a description of how and where You have fulfilled the + obligations of Section 3.2. The notice must be conspicuously included + in any notice in an Executable version, related documentation or + collateral in which You describe recipients' rights relating to the + Covered Code. You may distribute the Executable version of Covered + Code or ownership rights under a license of Your choice, which may + contain terms different from this License, provided that You are in + compliance with the terms of this License and that the license for the + Executable version does not attempt to limit or alter the recipient's + rights in the Source Code version from the rights set forth in this + License. If You distribute the Executable version under a different + license You must make it absolutely clear that any terms which differ + from this License are offered by You alone, not by the Initial + Developer or any Contributor. You hereby agree to indemnify the + Initial Developer and every Contributor for any liability incurred by + the Initial Developer or such Contributor as a result of any such + terms You offer. + + 3.7. Larger Works. + You may create a Larger Work by combining Covered Code with other code + not governed by the terms of this License and distribute the Larger + Work as a single product. In such a case, You must make sure the + requirements of this License are fulfilled for the Covered Code. + +4. Inability to Comply Due to Statute or Regulation. + + If it is impossible for You to comply with any of the terms of this + License with respect to some or all of the Covered Code due to + statute, judicial order, or regulation then You must: (a) comply with + the terms of this License to the maximum extent possible; and (b) + describe the limitations and the code they affect. Such description + must be included in the LEGAL file described in Section 3.4 and must + be included with all distributions of the Source Code. Except to the + extent prohibited by statute or regulation, such description must be + sufficiently detailed for a recipient of ordinary skill to be able to + understand it. + +5. Application of this License. + + This License applies to code to which the Initial Developer has + attached the notice in Exhibit A and to related Covered Code. + +6. Versions of the License. + + 6.1. New Versions. + Netscape Communications Corporation ("Netscape") may publish revised + and/or new versions of the License from time to time. Each version + will be given a distinguishing version number. + + 6.2. Effect of New Versions. + Once Covered Code has been published under a particular version of the + License, You may always continue to use it under the terms of that + version. You may also choose to use such Covered Code under the terms + of any subsequent version of the License published by Netscape. No one + other than Netscape has the right to modify the terms applicable to + Covered Code created under this License. + + 6.3. Derivative Works. + If You create or use a modified version of this License (which you may + only do in order to apply it to code which is not already Covered Code + governed by this License), You must (a) rename Your license so that + the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", + "MPL", "NPL" or any confusingly similar phrase do not appear in your + license (except to note that your license differs from this License) + and (b) otherwise make it clear that Your version of the license + contains terms which differ from the Mozilla Public License and + Netscape Public License. (Filling in the name of the Initial + Developer, Original Code or Contributor in the notice described in + Exhibit A shall not of themselves be deemed to be modifications of + this License.) + +7. DISCLAIMER OF WARRANTY. + + COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF + DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. + THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE + IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, + YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE + COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER + OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF + ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. + +8. TERMINATION. + + 8.1. This License and the rights granted hereunder will terminate + automatically if You fail to comply with terms herein and fail to cure + such breach within 30 days of becoming aware of the breach. All + sublicenses to the Covered Code which are properly granted shall + survive any termination of this License. Provisions which, by their + nature, must remain in effect beyond the termination of this License + shall survive. + + 8.2. If You initiate litigation by asserting a patent infringement + claim (excluding declatory judgment actions) against Initial Developer + or a Contributor (the Initial Developer or Contributor against whom + You file such action is referred to as "Participant") alleging that: + + (a) such Participant's Contributor Version directly or indirectly + infringes any patent, then any and all rights granted by such + Participant to You under Sections 2.1 and/or 2.2 of this License + shall, upon 60 days notice from Participant terminate prospectively, + unless if within 60 days after receipt of notice You either: (i) + agree in writing to pay Participant a mutually agreeable reasonable + royalty for Your past and future use of Modifications made by such + Participant, or (ii) withdraw Your litigation claim with respect to + the Contributor Version against such Participant. If within 60 days + of notice, a reasonable royalty and payment arrangement are not + mutually agreed upon in writing by the parties or the litigation claim + is not withdrawn, the rights granted by Participant to You under + Sections 2.1 and/or 2.2 automatically terminate at the expiration of + the 60 day notice period specified above. + + (b) any software, hardware, or device, other than such Participant's + Contributor Version, directly or indirectly infringes any patent, then + any rights granted to You by such Participant under Sections 2.1(b) + and 2.2(b) are revoked effective as of the date You first made, used, + sold, distributed, or had made, Modifications made by that + Participant. + + 8.3. If You assert a patent infringement claim against Participant + alleging that such Participant's Contributor Version directly or + indirectly infringes any patent where such claim is resolved (such as + by license or settlement) prior to the initiation of patent + infringement litigation, then the reasonable value of the licenses + granted by such Participant under Sections 2.1 or 2.2 shall be taken + into account in determining the amount or value of any payment or + license. + + 8.4. In the event of termination under Sections 8.1 or 8.2 above, + all end user license agreements (excluding distributors and resellers) + which have been validly granted by You or any distributor hereunder + prior to termination shall survive termination. + +9. LIMITATION OF LIABILITY. + + UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT + (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL + DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, + OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR + ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY + CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, + WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER + COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN + INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF + LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY + RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW + PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE + EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO + THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. + +10. U.S. GOVERNMENT END USERS. + + The Covered Code is a "commercial item," as that term is defined in + 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer + software" and "commercial computer software documentation," as such + terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 + C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), + all U.S. Government End Users acquire Covered Code with only those + rights set forth herein. + +11. MISCELLANEOUS. + + This License represents the complete agreement concerning subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. This License shall be governed by + California law provisions (except to the extent applicable law, if + any, provides otherwise), excluding its conflict-of-law provisions. + With respect to disputes in which at least one party is a citizen of, + or an entity chartered or registered to do business in the United + States of America, any litigation relating to this License shall be + subject to the jurisdiction of the Federal Courts of the Northern + District of California, with venue lying in Santa Clara County, + California, with the losing party responsible for costs, including + without limitation, court costs and reasonable attorneys' fees and + expenses. The application of the United Nations Convention on + Contracts for the International Sale of Goods is expressly excluded. + Any law or regulation which provides that the language of a contract + shall be construed against the drafter shall not apply to this + License. + +12. RESPONSIBILITY FOR CLAIMS. + + As between Initial Developer and the Contributors, each party is + responsible for claims and damages arising, directly or indirectly, + out of its utilization of rights under this License and You agree to + work with Initial Developer and Contributors to distribute such + responsibility on an equitable basis. Nothing herein is intended or + shall be deemed to constitute any admission of liability. + +13. MULTIPLE-LICENSED CODE. + + Initial Developer may designate portions of the Covered Code as + "Multiple-Licensed". "Multiple-Licensed" means that the Initial + Developer permits you to utilize portions of the Covered Code under + Your choice of the NPL or the alternative licenses, if any, specified + by the Initial Developer in the file described in Exhibit A. + +EXHIBIT A -Mozilla Public License. + + ``The contents of this file are subject to the Mozilla Public License + Version 1.1 (the "License"); you may not use this file except in + compliance with the License. You may obtain a copy of the License at + http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + License for the specific language governing rights and limitations + under the License. + + The Original Code is ______________________________________. + + The Initial Developer of the Original Code is ________________________. + Portions created by ______________________ are Copyright (C) ______ + _______________________. All Rights Reserved. + + Contributor(s): ______________________________________. + + Alternatively, the contents of this file may be used under the terms + of the _____ license (the "[___] License"), in which case the + provisions of [______] License are applicable instead of those + above. If you wish to allow use of your version of this file only + under the terms of the [____] License and not to allow others to use + your version of this file under the MPL, indicate your decision by + deleting the provisions above and replace them with the notice and + other provisions required by the [___] License. If you do not delete + the provisions above, a recipient may use your version of this file + under either the MPL or the [___] License." + + [NOTE: The text of this Exhibit A may differ slightly from the text of + the notices in the Source Code files of the Original Code. You should + use the text of this Exhibit A rather than the text found in the + Original Code Source Code for Your Modifications.] +---- + GERRIT ------ Part of link:index.html[Gerrit Code Review] diff --git a/gerrit-common/pom.xml b/gerrit-common/pom.xml index eda8e830f4..af03191364 100644 --- a/gerrit-common/pom.xml +++ b/gerrit-common/pom.xml @@ -50,6 +50,12 @@ limitations under the License. ${project.version} + + com.google.gerrit + gerrit-prettify + ${project.version} + + com.google.gerrit gerrit-patch-jgit diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchScriptSettings.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchScriptSettings.java index 019ecdf490..cd43ba41e6 100644 --- a/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchScriptSettings.java +++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchScriptSettings.java @@ -14,6 +14,7 @@ package com.google.gerrit.common.data; +import com.google.gerrit.prettify.common.PrettySettings; import com.google.gerrit.reviewdb.AccountGeneralPreferences; import com.google.gerrit.reviewdb.CodedEnum; @@ -37,15 +38,26 @@ public class PatchScriptSettings { protected int context; protected Whitespace whitespace; + protected PrettySettings pretty; public PatchScriptSettings() { context = AccountGeneralPreferences.DEFAULT_CONTEXT; whitespace = Whitespace.IGNORE_NONE; + pretty = new PrettySettings(); } public PatchScriptSettings(final PatchScriptSettings s) { context = s.context; whitespace = s.whitespace; + pretty = new PrettySettings(s.pretty); + } + + public PrettySettings getPrettySettings() { + return pretty; + } + + public void setPrettySettings(PrettySettings s) { + pretty = s; } public int getContext() { diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/SparseFileContent.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/SparseFileContent.java index 99913c61f8..24f07478af 100644 --- a/gerrit-common/src/main/java/com/google/gerrit/common/data/SparseFileContent.java +++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/SparseFileContent.java @@ -14,6 +14,8 @@ package com.google.gerrit.common.data; +import com.google.gwtexpui.safehtml.client.SafeHtml; + import java.util.ArrayList; import java.util.List; @@ -44,12 +46,12 @@ public class SparseFileContent { missingNewlineAtEnd = missing; } - public String get(final int idx) { + public SafeHtml get(final int idx) { final String line = getLine(idx); if (line == null) { throw new ArrayIndexOutOfBoundsException(idx); } - return line; + return SafeHtml.asis(line); } public boolean contains(final int idx) { @@ -93,6 +95,10 @@ public class SparseFileContent { return null; } + public void addLine(final int i, final SafeHtml content) { + addLine(i, content.asString()); + } + public void addLine(final int i, final String content) { final Range r; if (!ranges.isEmpty() && i == last().end()) { diff --git a/gerrit-gwtui/pom.xml b/gerrit-gwtui/pom.xml index ad62160c98..c09a4243ec 100644 --- a/gerrit-gwtui/pom.xml +++ b/gerrit-gwtui/pom.xml @@ -125,12 +125,12 @@ limitations under the License. com.google.gerrit - gerrit-patch-gwtexpui + gerrit-prettify ${project.version} com.google.gerrit - gerrit-patch-gwtexpui + gerrit-prettify ${project.version} sources jar diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/GerritGwtUI.gwt.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/GerritGwtUI.gwt.xml index a9099d48e8..ec0f74fcb6 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/GerritGwtUI.gwt.xml +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/GerritGwtUI.gwt.xml @@ -23,7 +23,7 @@ - + diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java index a2726b0cbb..f379ef1b87 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java @@ -32,6 +32,8 @@ import com.google.gerrit.common.data.PatchScript; import com.google.gerrit.common.data.PatchScriptSettings; import com.google.gerrit.common.data.PatchSetDetail; import com.google.gerrit.common.data.PatchScriptSettings.Whitespace; +import com.google.gerrit.prettify.client.ClientSideFormatter; +import com.google.gerrit.prettify.common.PrettyFactory; import com.google.gerrit.reviewdb.AccountGeneralPreferences; import com.google.gerrit.reviewdb.Change; import com.google.gerrit.reviewdb.Patch; @@ -63,6 +65,8 @@ import com.google.gwtexpui.safehtml.client.SafeHtml; import com.google.gwtjsonrpc.client.VoidResult; public abstract class PatchScreen extends Screen { + static final PrettyFactory PRETTY = ClientSideFormatter.FACTORY; + public static class SideBySide extends PatchScreen { public SideBySide(final Patch.Key id, final int patchIndex, final PatchTable patchTable) { diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/SideBySideTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/SideBySideTable.java index dd86bb542b..dc3d84849a 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/SideBySideTable.java +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/SideBySideTable.java @@ -28,7 +28,6 @@ import com.google.gerrit.reviewdb.Patch; import com.google.gerrit.reviewdb.PatchLineComment; import com.google.gwt.core.client.GWT; import com.google.gwt.user.client.ui.HTMLTable.CellFormatter; -import com.google.gwtexpui.safehtml.client.PrettyFormatter; import com.google.gwtexpui.safehtml.client.SafeHtml; import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder; import com.google.gwtorm.client.KeyUtil; @@ -70,12 +69,9 @@ public class SideBySideTable extends AbstractPatchContentTable { protected void render(final PatchScript script) { final SparseFileContent a = script.getA(); final SparseFileContent b = script.getB(); - final PrettyFormatter fmtA = PrettyFormatter.newFormatter(formatLanguage); - final PrettyFormatter fmtB = PrettyFormatter.newFormatter(formatLanguage); final ArrayList lines = new ArrayList(); final SafeHtmlBuilder nc = new SafeHtmlBuilder(); - fmtB.setShowWhiteSpaceErrors(true); appendHeader(script, nc); lines.add(null); @@ -90,10 +86,10 @@ public class SideBySideTable extends AbstractPatchContentTable { while (hunk.next()) { if (hunk.isContextLine()) { openLine(nc); - final SafeHtml ctx = fmtA.format(a.get(hunk.getCurA())); + final SafeHtml ctx = a.get(hunk.getCurA()); appendLineText(nc, hunk.getCurA(), CONTEXT, ctx); if (ignoreWS && b.contains(hunk.getCurB())) { - appendLineText(nc, hunk.getCurB(), CONTEXT, b, hunk.getCurB(), fmtB); + appendLineText(nc, hunk.getCurB(), CONTEXT, b, hunk.getCurB()); } else { appendLineText(nc, hunk.getCurB(), CONTEXT, ctx); } @@ -107,14 +103,14 @@ public class SideBySideTable extends AbstractPatchContentTable { openLine(nc); if (del) { - appendLineText(nc, hunk.getCurA(), DELETE, a, hunk.getCurA(), fmtA); + appendLineText(nc, hunk.getCurA(), DELETE, a, hunk.getCurA()); hunk.incA(); } else { appendLineNone(nc); } if (ins) { - appendLineText(nc, hunk.getCurB(), INSERT, b, hunk.getCurB(), fmtB); + appendLineText(nc, hunk.getCurB(), INSERT, b, hunk.getCurB()); hunk.incB(); } else { appendLineNone(nc); @@ -275,12 +271,10 @@ public class SideBySideTable extends AbstractPatchContentTable { m.closeTd(); } - private SafeHtml appendLineText(final SafeHtmlBuilder m, + private void appendLineText(final SafeHtmlBuilder m, final int lineNumberMinusOne, final PatchLine.Type type, - final SparseFileContent src, final int i, final PrettyFormatter dst) { - final SafeHtml lineHtml = dst.format(src.get(i)); - appendLineText(m, lineNumberMinusOne, type, lineHtml); - return lineHtml; + final SparseFileContent src, final int i) { + appendLineText(m, lineNumberMinusOne, type, src.get(i)); } private void appendLineText(final SafeHtmlBuilder m, diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UnifiedDiffTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UnifiedDiffTable.java index 2d4ec6f166..d904837344 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UnifiedDiffTable.java +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UnifiedDiffTable.java @@ -29,7 +29,7 @@ import com.google.gerrit.reviewdb.Patch; import com.google.gerrit.reviewdb.PatchLineComment; import com.google.gwt.core.client.GWT; import com.google.gwt.user.client.ui.HTMLTable.CellFormatter; -import com.google.gwtexpui.safehtml.client.PrettyFormatter; +import com.google.gwtexpui.safehtml.client.SafeHtml; import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder; import com.google.gwtorm.client.KeyUtil; @@ -89,10 +89,6 @@ public class UnifiedDiffTable extends AbstractPatchContentTable { final SparseFileContent a = script.getA(); final SparseFileContent b = script.getB(); final SafeHtmlBuilder nc = new SafeHtmlBuilder(); - final PrettyFormatter fmtA = PrettyFormatter.newFormatter(formatLanguage); - final PrettyFormatter fmtB = PrettyFormatter.newFormatter(formatLanguage); - - fmtB.setShowWhiteSpaceErrors(true); // Display the patch header for (final String line : script.getPatchHeader()) { @@ -144,7 +140,7 @@ public class UnifiedDiffTable extends AbstractPatchContentTable { openLine(nc); appendLineNumber(nc, hunk.getCurA()); appendLineNumber(nc, hunk.getCurB()); - appendLineText(nc, CONTEXT, a, hunk.getCurA(), fmtA, fmtB); + appendLineText(nc, CONTEXT, a, hunk.getCurA()); closeLine(nc); hunk.incBoth(); lines.add(new PatchLine(CONTEXT, hunk.getCurA(), hunk.getCurB())); @@ -153,7 +149,7 @@ public class UnifiedDiffTable extends AbstractPatchContentTable { openLine(nc); appendLineNumber(nc, hunk.getCurA()); padLineNumber(nc); - appendLineText(nc, DELETE, a, hunk.getCurA(), fmtA, fmtB); + appendLineText(nc, DELETE, a, hunk.getCurA()); closeLine(nc); hunk.incA(); lines.add(new PatchLine(DELETE, hunk.getCurA(), 0)); @@ -164,7 +160,7 @@ public class UnifiedDiffTable extends AbstractPatchContentTable { openLine(nc); padLineNumber(nc); appendLineNumber(nc, hunk.getCurB()); - appendLineText(nc, INSERT, b, hunk.getCurB(), fmtA, fmtB); + appendLineText(nc, INSERT, b, hunk.getCurB()); closeLine(nc); hunk.incB(); lines.add(new PatchLine(INSERT, 0, hunk.getCurB())); @@ -308,27 +304,25 @@ public class UnifiedDiffTable extends AbstractPatchContentTable { } private void appendLineText(final SafeHtmlBuilder m, - final PatchLine.Type type, final SparseFileContent src, final int i, - final PrettyFormatter fmtA, final PrettyFormatter fmtB) { - final String text = src.get(i); + final PatchLine.Type type, final SparseFileContent src, final int i) { + final SafeHtml text = src.get(i); m.openTd(); m.addStyleName(Gerrit.RESOURCES.css().diffText()); switch (type) { case CONTEXT: m.addStyleName(Gerrit.RESOURCES.css().diffTextCONTEXT()); m.nbsp(); - m.append(fmtA.format(text)); - fmtB.update(text); + m.append(text); break; case DELETE: m.addStyleName(Gerrit.RESOURCES.css().diffTextDELETE()); m.append("-"); - m.append(fmtA.format(text)); + m.append(text); break; case INSERT: m.addStyleName(Gerrit.RESOURCES.css().diffTextINSERT()); m.append("+"); - m.append(fmtB.format(text)); + m.append(text); break; } m.closeTd(); diff --git a/gerrit-httpd/pom.xml b/gerrit-httpd/pom.xml index 40198b585a..6696ab3818 100644 --- a/gerrit-httpd/pom.xml +++ b/gerrit-httpd/pom.xml @@ -79,5 +79,11 @@ limitations under the License. gerrit-server ${project.version} + + + com.google.gerrit + gerrit-prettify + ${project.version} + diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebModule.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebModule.java index cec4be3029..76571f485a 100644 --- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebModule.java +++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebModule.java @@ -23,6 +23,7 @@ import com.google.gerrit.httpd.auth.ldap.LdapAuthModule; import com.google.gerrit.httpd.auth.openid.OpenIdModule; import com.google.gerrit.httpd.gitweb.GitWebModule; import com.google.gerrit.httpd.rpc.UiRpcModule; +import com.google.gerrit.prettify.server.PrettifyModule; import com.google.gerrit.reviewdb.AuthType; import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.IdentifiedUser; @@ -121,6 +122,7 @@ public class WebModule extends FactoryModule { install(new UiRpcModule()); install(new GerritRequestModule()); install(new ProjectServlet.Module()); + install(new PrettifyModule()); bind(SshInfo.class).toProvider(sshInfoProvider); bind(SshKeyCache.class).toProvider(sshKeyCacheProvider); diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchModule.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchModule.java index 0b58702561..14bf951e96 100644 --- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchModule.java +++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchModule.java @@ -34,6 +34,7 @@ public class PatchModule extends RpcServletModule { factory(SaveDraft.Factory.class); } }); + bind(PatchScriptBuilder.class); rpc(PatchDetailServiceImpl.class); } } diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchScriptBuilder.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchScriptBuilder.java index 673ef0faa4..753c6fcba9 100644 --- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchScriptBuilder.java +++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchScriptBuilder.java @@ -20,12 +20,16 @@ import com.google.gerrit.common.data.PatchScript; import com.google.gerrit.common.data.PatchScriptSettings; import com.google.gerrit.common.data.SparseFileContent; import com.google.gerrit.common.data.PatchScript.DisplayMethod; +import com.google.gerrit.prettify.common.PrettyFactory; +import com.google.gerrit.prettify.common.PrettyFormatter; +import com.google.gerrit.prettify.common.PrettySettings; import com.google.gerrit.reviewdb.Change; import com.google.gerrit.reviewdb.PatchLineComment; import com.google.gerrit.reviewdb.Patch.PatchType; import com.google.gerrit.server.FileTypeRegistry; import com.google.gerrit.server.patch.PatchListEntry; import com.google.gerrit.server.patch.Text; +import com.google.inject.Inject; import eu.medsea.mimeutil.MimeType; import eu.medsea.mimeutil.MimeUtil2; @@ -61,6 +65,7 @@ class PatchScriptBuilder { }; private final List header; + private final PrettyFactory prettyFactory; private Repository db; private Change change; private PatchScriptSettings settings; @@ -73,8 +78,10 @@ class PatchScriptBuilder { private List edits; private final FileTypeRegistry registry; - PatchScriptBuilder(final FileTypeRegistry ftr) { + @Inject + PatchScriptBuilder(final FileTypeRegistry ftr, final PrettyFactory pf) { header = new ArrayList(); + prettyFactory = pf; a = new Side(); b = new Side(); registry = ftr; @@ -125,19 +132,19 @@ class PatchScriptBuilder { if (a.mode == FileMode.GITLINK || b.mode == FileMode.GITLINK) { - } else if (a.src == b.src && a.src.size() <= context() + } else if (a.src == b.src && a.size() <= context() && contentAct.getEdits().isEmpty()) { // Odd special case; the files are identical (100% rename or copy) // and the user has asked for context that is larger than the file. // Send them the entire file, with an empty edit after the last line. // - for (int i = 0; i < a.src.size(); i++) { - a.src.addLineTo(a.dst, i); + for (int i = 0; i < a.size(); i++) { + a.addLine(i); } edits = new ArrayList(1); - edits.add(new Edit(a.src.size(), a.src.size())); + edits.add(new Edit(a.size(), a.size())); } else { - if (BIG_FILE < Math.max(a.src.size(), b.src.size()) && 25 < context()) { + if (BIG_FILE < Math.max(a.size(), b.size()) && 25 < context()) { settings.setContext(25); } packContent(); @@ -298,19 +305,19 @@ class PatchScriptBuilder { } private void packContent() { - EditList list = new EditList(edits, context(), a.src.size(), b.src.size()); + EditList list = new EditList(edits, context(), a.size(), b.size()); for (final EditList.Hunk hunk : list.getHunks()) { while (hunk.next()) { if (hunk.isContextLine()) { - a.src.addLineTo(a.dst, hunk.getCurA()); + a.addLine(hunk.getCurA()); hunk.incBoth(); } else if (hunk.isDeletedA()) { - a.src.addLineTo(a.dst, hunk.getCurA()); + a.addLine(hunk.getCurA()); hunk.incA(); } else if (hunk.isInsertedB()) { - b.src.addLineTo(b.dst, hunk.getCurB()); + b.addLine(hunk.getCurB()); hunk.incB(); } } @@ -321,11 +328,20 @@ class PatchScriptBuilder { String path; ObjectId id; FileMode mode; - Text src; + byte[] srcContent; + PrettyFormatter src; MimeType mimeType = MimeUtil2.UNKNOWN_MIME_TYPE; DisplayMethod displayMethod = DisplayMethod.DIFF; final SparseFileContent dst = new SparseFileContent(); + int size() { + return src != null ? src.size() : 0; + } + + void addLine(int line) { + dst.addLine(line, src.getLine(line)); + } + void resolve(final Side other, final ObjectId within) throws IOException { try { final TreeWalk tw = find(within); @@ -337,29 +353,29 @@ class PatchScriptBuilder { other != null && other.id.equals(id) && other.mode == mode; if (reuse) { - src = other.src; + srcContent = other.srcContent; } else if (mode.getObjectType() == Constants.OBJ_BLOB) { final ObjectLoader ldr = db.openObject(id); if (ldr == null) { throw new MissingObjectException(id, Constants.TYPE_BLOB); } - final byte[] data = ldr.getCachedBytes(); + srcContent = ldr.getCachedBytes(); if (ldr.getType() != Constants.OBJ_BLOB) { throw new IncorrectObjectTypeException(id, Constants.TYPE_BLOB); } - src = new Text(data); } else { - src = Text.EMPTY; + srcContent = Text.NO_BYTES; } if (reuse) { mimeType = other.mimeType; displayMethod = other.displayMethod; + src = other.src; - } else if (src.getContent().length > 0 && FileMode.SYMLINK != mode) { - mimeType = registry.getMimeType(path, src.getContent()); + } else if (srcContent.length > 0 && FileMode.SYMLINK != mode) { + mimeType = registry.getMimeType(path, srcContent); if ("image".equals(mimeType.getMediaType()) && registry.isSafeInline(mimeType)) { displayMethod = DisplayMethod.IMG; @@ -370,8 +386,19 @@ class PatchScriptBuilder { displayMethod = DisplayMethod.NONE; } - dst.setMissingNewlineAtEnd(src.isMissingNewlineAtEnd()); - dst.setSize(src.size()); + if (displayMethod == DisplayMethod.DIFF) { + PrettySettings s = new PrettySettings(settings.getPrettySettings()); + s.setFileName(path); + s.setShowWhiteSpaceErrors(other != null /* side B */); + + src = prettyFactory.get(); + src.format(s, Text.asString(srcContent, null)); + } + + if (srcContent.length > 0 && srcContent[srcContent.length - 1] != '\n') { + dst.setMissingNewlineAtEnd(true); + } + dst.setSize(size()); } catch (IOException err) { throw new IOException("Cannot read " + within.name() + ":" + path, err); } diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchScriptFactory.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchScriptFactory.java index 6f856e955b..13a96a5f17 100644 --- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchScriptFactory.java +++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchScriptFactory.java @@ -26,7 +26,6 @@ import com.google.gerrit.reviewdb.PatchLineComment; import com.google.gerrit.reviewdb.PatchSet; import com.google.gerrit.reviewdb.Project; import com.google.gerrit.reviewdb.ReviewDb; -import com.google.gerrit.server.FileTypeRegistry; import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.patch.PatchList; @@ -37,6 +36,7 @@ import com.google.gerrit.server.project.ChangeControl; import com.google.gerrit.server.project.NoSuchChangeException; import com.google.gwtorm.client.OrmException; import com.google.inject.Inject; +import com.google.inject.Provider; import com.google.inject.assistedinject.Assisted; import org.eclipse.jgit.errors.RepositoryNotFoundException; @@ -62,7 +62,7 @@ class PatchScriptFactory extends Handler { LoggerFactory.getLogger(PatchScriptFactory.class); private final GitRepositoryManager repoManager; - private final FileTypeRegistry registry; + private final Provider builderFactory; private final PatchListCache patchListCache; private final ReviewDb db; private final ChangeControl.Factory changeControlFactory; @@ -88,7 +88,8 @@ class PatchScriptFactory extends Handler { private ObjectId bId; @Inject - PatchScriptFactory(final GitRepositoryManager grm, final FileTypeRegistry ftr, + PatchScriptFactory(final GitRepositoryManager grm, + Provider builderFactory, final PatchListCache patchListCache, final ReviewDb db, final ChangeControl.Factory changeControlFactory, @Assisted final Patch.Key patchKey, @@ -96,7 +97,7 @@ class PatchScriptFactory extends Handler { @Assisted("patchSetB") final PatchSet.Id patchSetB, @Assisted final PatchScriptSettings settings) { this.repoManager = grm; - this.registry = ftr; + this.builderFactory = builderFactory; this.patchListCache = patchListCache; this.db = db; this.changeControlFactory = changeControlFactory; @@ -182,7 +183,7 @@ class PatchScriptFactory extends Handler { else throw new NoSuchChangeException(changeId); - final PatchScriptBuilder b = new PatchScriptBuilder(registry); + final PatchScriptBuilder b = builderFactory.get(); b.setRepository(git); b.setChange(change); b.setSettings(s); diff --git a/gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/MultiLineStyle.java b/gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/MultiLineStyle.java deleted file mode 100644 index e8bec8f70c..0000000000 --- a/gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/MultiLineStyle.java +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (C) 2009 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package com.google.gwtexpui.safehtml.client; - - -public abstract class MultiLineStyle { - public MultiLineStyle isStart(String line) { - return null; - } - - public boolean isEnd(String line) { - return false; - } - - public String restart(String line) { - return line; - } - - public String unrestart(String line) { - return line; - } - - static class Simple extends MultiLineStyle { - private final String begin; - private final String end; - - Simple(String b, String e) { - begin = b; - end = e; - } - - @Override - public MultiLineStyle isStart(String line) { - final int lastBegin = line.lastIndexOf(begin); - if (lastBegin < 0) { - return null; - } - - final int lastEnd = line.lastIndexOf(end); - return lastBegin > lastEnd ? this : null; - } - - @Override - public boolean isEnd(String line) { - final int firstEnd = line.indexOf(end); - if (firstEnd < 0) { - return false; - } - - final int lastBegin = line.lastIndexOf(begin); - return lastBegin < firstEnd; - } - - @Override - public String restart(String line) { - return begin + "\n" + line; - } - - @Override - public String unrestart(String formattedHtml) { - final int beginPos = formattedHtml.indexOf(begin); - final String lineBegin = formattedHtml.substring(0, beginPos); - String lineEnd = formattedHtml.substring(beginPos + begin.length()); - if (lineEnd.startsWith("') + 1); - } - return lineBegin + lineEnd; - } - } -} diff --git a/gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/PrettyFormatter.java b/gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/PrettyFormatter.java deleted file mode 100644 index 808439009b..0000000000 --- a/gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/PrettyFormatter.java +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright (C) 2009 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package com.google.gwtexpui.safehtml.client; - -import com.google.gwt.resources.client.TextResource; -import com.google.gwtexpui.safehtml.client.prettify.Resources; - -import java.util.HashMap; -import java.util.Map; - -public abstract class PrettyFormatter { - private static final Map STYLES; - private static final MultiLineStyle DEFAULT_STYLE = new MultiLineStyle() {}; - static { - STYLES = new HashMap(); - - MultiLineStyle c = new MultiLineStyle.Simple("/*", "*/"); - STYLES.put("h", c); - STYLES.put("c", c); - STYLES.put("cc", c); - STYLES.put("cpp", c); - STYLES.put("cxx", c); - STYLES.put("cyc", c); - STYLES.put("m", c); - STYLES.put("cs", c); - STYLES.put("java", c); - STYLES.put("js", c); - STYLES.put("css", c); - STYLES.put("scala", c); - - MultiLineStyle xml = new MultiLineStyle.Simple(""); - STYLES.put("xml", xml); - STYLES.put("html", xml); - STYLES.put("sgml", xml); - } - - private static MultiLineStyle getCommentStyle(final String lang) { - MultiLineStyle style = STYLES.get(lang); - return style != null ? style : DEFAULT_STYLE; - } - - public static PrettyFormatter newFormatter(String lang) { - return new Pretty(lang); - } - - private boolean showWhiteSpaceErrors; - private int lineLength = 100; - - public void setShowWhiteSpaceErrors(final boolean show) { - showWhiteSpaceErrors = show; - } - - public void setLineLength(final int len) { - lineLength = len; - } - - public SafeHtml format(String line) { - SafeHtml html = new SafeHtmlBuilder().append(wrapLines(line)); - if (showWhiteSpaceErrors) { - html = showTabAfterSpace(html); - html = showTrailingWhitespace(html); - } - html = prettify(html); - return html; - } - - public void update(String line) { - } - - private String wrapLines(final String src) { - if (lineLength <= 0) { - // Caller didn't request for line wrapping; use it unmodified. - // - return src; - } - if (src.length() < lineLength && src.indexOf('\t') < 0) { - // We're too short and there are no horizontal tabs, line is fine - // as-is so bypass the longer line wrapping code below. - return src; - } - - final StringBuilder r = new StringBuilder(); - int lineLen = 0; - for (int i = 0; i < src.length(); i++) { - final char c = src.charAt(i); - final int cLen = c == '\t' ? 8 : 1; - if (lineLen >= lineLength) { - r.append('\n'); - lineLen = 0; - } - r.append(c); - lineLen += cLen; - } - return r.toString(); - } - - - private static SafeHtml showTabAfterSpace(SafeHtml src) { - return src.replaceFirst("^( *\t)", "$1"); - } - - private static SafeHtml showTrailingWhitespace(SafeHtml src) { - return src.replaceFirst("([ \t][ \t]*)(\r?\n?)$", "$1$2"); - } - - protected SafeHtml prettify(SafeHtml line) { - return line; - } - - private static class Pretty extends PrettyFormatter { - static { - Resources.I.prettify_css().ensureInjected(); - Resources.I.css().ensureInjected(); - - eval(Resources.I.core()); - eval(Resources.I.lang_css()); - eval(Resources.I.lang_hs()); - eval(Resources.I.lang_lisp()); - eval(Resources.I.lang_lua()); - eval(Resources.I.lang_ml()); - eval(Resources.I.lang_proto()); - eval(Resources.I.lang_sql()); - eval(Resources.I.lang_vb()); - eval(Resources.I.lang_wiki()); - } - - private static void eval(final TextResource core) { - eval(core.getText()); - } - - private static native void eval(String js) - /*-{ eval(js); }-*/; - - private final String srcType; - private final MultiLineStyle commentStyle; - private MultiLineStyle currentStyle; - - Pretty(final String lang) { - srcType = lang; - commentStyle = getCommentStyle(lang); - } - - @Override - protected SafeHtml prettify(final SafeHtml src) { - String line = src.asString().replaceAll("'", "'"); - - if (currentStyle != null) { - final boolean isEnd = currentStyle.isEnd(line); - - line = currentStyle.restart(line); - line = prettifyNative(line, srcType); - line = currentStyle.unrestart(line); - - if (isEnd) { - currentStyle = null; - } - } else { - currentStyle = commentStyle.isStart(line); - line = prettifyNative(line, srcType); - } - - return SafeHtml.asis(line); - } - - @Override - public void update(String line) { - if (currentStyle != null) { - if (currentStyle.isEnd(line)) { - currentStyle = null; - } - } else { - currentStyle = commentStyle.isStart(line); - } - } - - private static native String prettifyNative(String srcText, String srcType) - /*-{ return prettyPrintOne(srcText, srcType); }-*/; - } -} diff --git a/gerrit-patch-gwtexpui/.gitignore b/gerrit-prettify/.gitignore similarity index 100% rename from gerrit-patch-gwtexpui/.gitignore rename to gerrit-prettify/.gitignore diff --git a/gerrit-patch-gwtexpui/.settings/org.eclipse.core.resources.prefs b/gerrit-prettify/.settings/org.eclipse.core.resources.prefs similarity index 100% rename from gerrit-patch-gwtexpui/.settings/org.eclipse.core.resources.prefs rename to gerrit-prettify/.settings/org.eclipse.core.resources.prefs diff --git a/gerrit-patch-gwtexpui/.settings/org.eclipse.core.runtime.prefs b/gerrit-prettify/.settings/org.eclipse.core.runtime.prefs similarity index 100% rename from gerrit-patch-gwtexpui/.settings/org.eclipse.core.runtime.prefs rename to gerrit-prettify/.settings/org.eclipse.core.runtime.prefs diff --git a/gerrit-patch-gwtexpui/.settings/org.eclipse.jdt.core.prefs b/gerrit-prettify/.settings/org.eclipse.jdt.core.prefs similarity index 100% rename from gerrit-patch-gwtexpui/.settings/org.eclipse.jdt.core.prefs rename to gerrit-prettify/.settings/org.eclipse.jdt.core.prefs diff --git a/gerrit-patch-gwtexpui/.settings/org.eclipse.jdt.ui.prefs b/gerrit-prettify/.settings/org.eclipse.jdt.ui.prefs similarity index 100% rename from gerrit-patch-gwtexpui/.settings/org.eclipse.jdt.ui.prefs rename to gerrit-prettify/.settings/org.eclipse.jdt.ui.prefs diff --git a/gerrit-patch-gwtexpui/pom.xml b/gerrit-prettify/pom.xml similarity index 79% rename from gerrit-patch-gwtexpui/pom.xml rename to gerrit-prettify/pom.xml index 59163a7c7c..f7afc3893a 100644 --- a/gerrit-patch-gwtexpui/pom.xml +++ b/gerrit-prettify/pom.xml @@ -25,11 +25,11 @@ limitations under the License. 2.1-SNAPSHOT - gerrit-patch-gwtexpui - Gerrit Code Review - Patch gwtexpui + gerrit-prettify + Gerrit Code Review - Prettify - Hacks to expose package-private data from gwtexpui to Gerrit + Prettify based syntax highlighting @@ -38,6 +38,16 @@ limitations under the License. gwtexpui + + com.google.code.guice + guice + + + + rhino + js + + com.google.gwt gwt-user diff --git a/gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/PrettyFormatter.gwt.xml b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/PrettyFormatter.gwt.xml similarity index 93% rename from gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/PrettyFormatter.gwt.xml rename to gerrit-prettify/src/main/java/com/google/gerrit/prettify/PrettyFormatter.gwt.xml index 7c8a85aae3..93ce272151 100644 --- a/gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/PrettyFormatter.gwt.xml +++ b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/PrettyFormatter.gwt.xml @@ -16,4 +16,6 @@ + + diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/ClientSideFormatter.java b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/ClientSideFormatter.java new file mode 100644 index 0000000000..cf712d2a8c --- /dev/null +++ b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/ClientSideFormatter.java @@ -0,0 +1,63 @@ +// Copyright (C) 2010 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.prettify.client; + +import com.google.gerrit.prettify.common.PrettyFactory; +import com.google.gerrit.prettify.common.PrettyFormatter; +import com.google.gwt.resources.client.TextResource; + +/** Evaluates prettify using the host browser's JavaScript engine. */ +public class ClientSideFormatter extends PrettyFormatter { + public static final PrettyFactory FACTORY = new PrettyFactory() { + @Override + public PrettyFormatter get() { + return new ClientSideFormatter(); + } + }; + + static { + Resources.I.prettify_css().ensureInjected(); + Resources.I.gerrit_css().ensureInjected(); + + compile(Resources.I.core()); + compile(Resources.I.lang_css()); + compile(Resources.I.lang_hs()); + compile(Resources.I.lang_lisp()); + compile(Resources.I.lang_lua()); + compile(Resources.I.lang_ml()); + compile(Resources.I.lang_proto()); + compile(Resources.I.lang_sql()); + compile(Resources.I.lang_vb()); + compile(Resources.I.lang_wiki()); + } + + private static void compile(TextResource core) { + eval(core.getText()); + } + + private static native void eval(String js) + /*-{ eval(js); }-*/; + + @Override + protected String prettify(String html) { + return go(html, settings.getFilename(), settings.getTabSize()); + } + + private static native String go(String srcText, String srcType, int tabSize) + /*-{ + window['PR_TAB_WIDTH'] = tabSize; + return window.prettyPrintOne(srcText, srcType); + }-*/; +} diff --git a/gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/Resources.java b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/Resources.java similarity index 86% rename from gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/Resources.java rename to gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/Resources.java index ec0e2d6058..745c921d35 100644 --- a/gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/Resources.java +++ b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/Resources.java @@ -12,21 +12,22 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.google.gwtexpui.safehtml.client.prettify; +package com.google.gerrit.prettify.client; import com.google.gwt.core.client.GWT; import com.google.gwt.resources.client.ClientBundle; import com.google.gwt.resources.client.CssResource; import com.google.gwt.resources.client.TextResource; -public interface Resources extends ClientBundle { - public static final Resources I = GWT.create(Resources.class); +/** Loads the minimized form of prettify into the client. */ +interface Resources extends ClientBundle { + static final Resources I = GWT.create(Resources.class); @Source("prettify.css") CssResource prettify_css(); @Source("gerrit.css") - PrettyCss css(); + CssResource gerrit_css(); @Source("prettify.js") TextResource core(); diff --git a/gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/PrettyCss.java b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/PrettyFactory.java similarity index 68% rename from gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/PrettyCss.java rename to gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/PrettyFactory.java index ed9dd7787e..364789f34f 100644 --- a/gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/PrettyCss.java +++ b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/PrettyFactory.java @@ -1,4 +1,4 @@ -// Copyright (C) 2009 The Android Open Source Project +// Copyright (C) 2010 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,11 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.google.gwtexpui.safehtml.client.prettify; +package com.google.gerrit.prettify.common; -import com.google.gwt.resources.client.CssResource; - -public interface PrettyCss extends CssResource { - String visualtab(); - String whitespaceerror(); +/** Creates a new PrettyFormatter instance for one formatting run. */ +public interface PrettyFactory { + PrettyFormatter get(); } diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/PrettyFormatter.java b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/PrettyFormatter.java new file mode 100644 index 0000000000..97a63da07f --- /dev/null +++ b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/PrettyFormatter.java @@ -0,0 +1,251 @@ +// Copyright (C) 2010 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.prettify.common; + +import com.google.gwtexpui.safehtml.client.SafeHtml; +import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public abstract class PrettyFormatter { + protected List lines = Collections.emptyList(); + protected PrettySettings settings; + + /** @return the line of formatted HTML. */ + public SafeHtml getLine(int lineNo) { + return SafeHtml.asis(lines.get(lineNo)); + } + + /** @return the number of lines in this formatter. */ + public int size() { + return lines.size(); + } + + /** + * Parse and format a complete source code file. + * + * @param how the settings to apply to the formatter. + * @param srcText raw content of the file to format. The string will be HTML + * escaped before processing, so it must be the raw text. + */ + public void format(PrettySettings how, String srcText) { + settings = how; + lines = new ArrayList(); + + String html = prettify(toHTML(srcText)); + int pos = 0; + int textChunkStart = 0; + int col = 0; + Tag lastTag = Tag.NULL; + + StringBuilder buf = new StringBuilder(); + while (pos <= html.length()) { + int tagStart = html.indexOf('<', pos); + + if (tagStart < 0) { + // No more tags remaining. What's left is plain text. + // + assert lastTag == Tag.NULL; + pos = html.length(); + if (textChunkStart < pos) { + col = htmlText(col, buf, html.substring(textChunkStart, pos)); + } + if (0 < buf.length()) { + lines.add(buf.toString()); + } + break; + } + + // Assume no attribute contains '>' and that all tags + // within the HTML will be well-formed. + // + int tagEnd = html.indexOf('>', tagStart); + assert tagStart < tagEnd; + pos = tagEnd + 1; + + // Handle any text between the end of the last tag, + // and the start of this tag. + // + if (textChunkStart < tagStart) { + lastTag.open(buf, html); + col = htmlText(col, buf, html.substring(textChunkStart, tagStart)); + } + textChunkStart = pos; + + if (isBR(html, tagStart, tagEnd)) { + lastTag.close(buf, html); + lines.add(buf.toString()); + buf = new StringBuilder(); + col = 0; + + } else if (html.charAt(tagStart + 1) == '/') { + lastTag = lastTag.pop(buf, html); + + } else if (html.charAt(tagEnd - 1) != '/') { + lastTag = new Tag(lastTag, tagStart, tagEnd); + } + } + } + + private int htmlText(int col, StringBuilder buf, String txt) { + int pos = 0; + + while (pos < txt.length()) { + int start = txt.indexOf('&', pos); + if (start < 0) { + break; + } + + col = cleanText(col, buf, txt, pos, start); + pos = txt.indexOf(';', start + 1) + 1; + + if (settings.getLineLength() <= col) { + buf.append("
"); + col = 0; + } + + buf.append(txt.substring(start, pos)); + col++; + } + + return cleanText(col, buf, txt, pos, txt.length()); + } + + private int cleanText(int col, StringBuilder buf, String txt, int pos, int end) { + while (pos < end) { + int free = settings.getLineLength() - col; + if (free <= 0) { + // The current line is full. Throw an explicit line break + // onto the end, and we'll continue on the next line. + // + buf.append("
"); + col = 0; + free = settings.getLineLength(); + } + + int n = Math.min(end - pos, free); + buf.append(txt.substring(pos, pos + n)); + col += n; + pos += n; + } + return col; + } + + /** Run the prettify engine over the text and return the result. */ + protected abstract String prettify(String html); + + private static boolean isBR(String html, int tagStart, int tagEnd) { + return tagEnd - tagStart == 5 // + && html.charAt(tagStart + 1) == 'b' // + && html.charAt(tagStart + 2) == 'r' // + && html.charAt(tagStart + 3) == ' '; + } + + private static class Tag { + static final Tag NULL = new Tag(null, 0, 0) { + @Override + void open(StringBuilder buf, String html) { + } + + @Override + void close(StringBuilder buf, String html) { + } + + @Override + Tag pop(StringBuilder buf, String html) { + return this; + } + }; + + final Tag parent; + final int start; + final int end; + boolean open; + + Tag(Tag p, int s, int e) { + parent = p; + start = s; + end = e; + } + + void open(StringBuilder buf, String html) { + if (!open) { + parent.open(buf, html); + buf.append(html.substring(start, end + 1)); + open = true; + } + } + + void close(StringBuilder buf, String html) { + pop(buf, html); + parent.close(buf, html); + } + + Tag pop(StringBuilder buf, String html) { + if (open) { + int sp = html.indexOf(' ', start + 1); + if (sp < 0 || end < sp) { + sp = end; + } + + buf.append("'); + open = false; + } + return parent; + } + } + + private String toHTML(String src) { + SafeHtml html = new SafeHtmlBuilder().append(src); + + // The prettify parsers don't like ' as an entity for the + // single quote character. Replace them all out so we don't + // confuse the parser. + // + html = html.replaceAll("'", "'"); + + if (settings.isShowWhiteSpaceErrors()) { + // We need to do whitespace errors before showing tabs, because + // these patterns rely on \t as a literal, before it expands. + // + html = showTabAfterSpace(html); + html = showTrailingWhitespace(html); + } + + if (settings.isShowTabs()) { + String t = 1 < settings.getTabSize() ? "\t" : ""; + html = html.replaceAll("\t", " " + t); + } + + return html.asString(); + } + + private SafeHtml showTabAfterSpace(SafeHtml src) { + src = src.replaceFirst("^( *\t)", "$1"); + src = src.replaceAll("\n( *\t)", "\n$1"); + return src; + } + + private SafeHtml showTrailingWhitespace(SafeHtml src) { + final String r = "$1$2"; + src = src.replaceAll("([ \t][ \t]*)(\r?\n)", r); + src = src.replaceFirst("([ \t][ \t]*)(\r?\n?)$", r); + return src; + } +} diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/PrettySettings.java b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/PrettySettings.java new file mode 100644 index 0000000000..f9e8c32d30 --- /dev/null +++ b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/PrettySettings.java @@ -0,0 +1,84 @@ +// Copyright (C) 2010 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.prettify.common; + +/** Settings to configure a {@link PrettyFormatter}. */ +public class PrettySettings { + protected String fileName; + protected boolean showWhiteSpaceErrors; + protected int lineLength; + protected int tabSize; + protected boolean showTabs; + + public PrettySettings() { + showWhiteSpaceErrors = false; + lineLength = 100; + tabSize = 2; + showTabs = true; + } + + public PrettySettings(PrettySettings pretty) { + fileName = pretty.fileName; + showWhiteSpaceErrors = pretty.showWhiteSpaceErrors; + lineLength = pretty.lineLength; + tabSize = pretty.tabSize; + showTabs = pretty.showTabs; + } + + public String getFilename() { + return fileName; + } + + public PrettySettings setFileName(final String name) { + fileName = name; + return this; + } + + public boolean isShowWhiteSpaceErrors() { + return showWhiteSpaceErrors; + } + + public PrettySettings setShowWhiteSpaceErrors(final boolean show) { + showWhiteSpaceErrors = show; + return this; + } + + public int getLineLength() { + return lineLength; + } + + public PrettySettings setLineLength(final int len) { + lineLength = len; + return this; + } + + public int getTabSize() { + return tabSize; + } + + public PrettySettings setTabSize(final int len) { + tabSize = len; + return this; + } + + public boolean isShowTabs() { + return showTabs; + } + + public PrettySettings setShowTabs(final boolean show) { + showTabs = show; + return this; + } +} diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/server/PrettifyModule.java b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/server/PrettifyModule.java new file mode 100644 index 0000000000..b4ffc73c50 --- /dev/null +++ b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/server/PrettifyModule.java @@ -0,0 +1,28 @@ +// Copyright (C) 2010 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.prettify.server; + +import com.google.gerrit.prettify.common.PrettyFactory; +import com.google.gerrit.prettify.common.PrettyFormatter; +import com.google.inject.AbstractModule; + +public class PrettifyModule extends AbstractModule { + @Override + protected void configure() { + bind(ServerPrettyFactory.class); + bind(PrettyFactory.class).to(ServerPrettyFactory.class); + bind(PrettyFormatter.class).toProvider(ServerPrettyFactory.class); + } +} diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/server/ServerPrettyFactory.java b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/server/ServerPrettyFactory.java new file mode 100644 index 0000000000..3f6f5474a6 --- /dev/null +++ b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/server/ServerPrettyFactory.java @@ -0,0 +1,142 @@ +// Copyright (C) 2010 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.prettify.server; + +import com.google.gerrit.prettify.common.PrettyFactory; +import com.google.gerrit.prettify.common.PrettyFormatter; +import com.google.gerrit.prettify.common.PrettySettings; +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.google.inject.Singleton; + +import org.mozilla.javascript.Context; +import org.mozilla.javascript.ContextFactory; +import org.mozilla.javascript.Scriptable; +import org.mozilla.javascript.ScriptableObject; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; + +/** Runs prettify via Mozilla Rhino JavaScript engine. */ +@Singleton +class ServerPrettyFactory implements PrettyFactory, Provider { + private final ContextFactory contextFactory; + private final ScriptableObject sharedScope; + private final Scriptable sharedWindow; + + @Inject + ServerPrettyFactory() { + contextFactory = new ContextFactory() { + @Override + protected boolean hasFeature(Context cx, int featureIndex) { + if (featureIndex == Context.FEATURE_DYNAMIC_SCOPE) { + return true; + } + return super.hasFeature(cx, featureIndex); + } + }; + + Context cx = contextFactory.enterContext(); + try { + cx.setOptimizationLevel(9); + + sharedScope = cx.initStandardObjects(null, true); + sharedWindow = cx.newObject(sharedScope); + sharedScope.put("window", sharedScope, sharedWindow); + + compile(cx, "prettify.js"); + compile(cx, "server-env.js"); + + compile(cx, "lang-apollo.js"); + compile(cx, "lang-css.js"); + compile(cx, "lang-hs.js"); + compile(cx, "lang-lisp.js"); + compile(cx, "lang-lua.js"); + compile(cx, "lang-ml.js"); + compile(cx, "lang-proto.js"); + compile(cx, "lang-sql.js"); + compile(cx, "lang-vb.js"); + compile(cx, "lang-wiki.js"); + } finally { + Context.exit(); + } + } + + @Override + public PrettyFormatter get() { + return new PrettyFormatter() { + @Override + protected String prettify(String html) { + return prettyPrintOne(html, settings); + } + }; + } + + private String prettyPrintOne(String srcText, PrettySettings how) { + String srcType = how.getFilename(); + int dot = srcType.lastIndexOf('.'); + if (0 < dot) { + srcType = srcType.substring(dot + 1); + } + + Context cx = contextFactory.enterContext(); + try { + Scriptable callScope = cx.newObject(sharedScope); + callScope.setPrototype(sharedScope); + callScope.setParentScope(null); + + // We have to clone and shadow the window object, so we can + // set a per-call window.PR_TAB_WIDTH value. Above we ensured + // we compiled our code in a dynamic scope so the window object + // resolution will happen to our shadowed value. + // + Scriptable callWindow = cx.newObject(callScope); + callWindow.setPrototype(sharedWindow); + callWindow.put("PR_TAB_WIDTH", callWindow, how.getTabSize()); + + callScope.put("window", callScope, callWindow); + callScope.put("srcText", callScope, srcText); + callScope.put("srcType", callScope, srcType); + String call = "prettyPrintOne(srcText, srcType)"; + + return cx.evaluateString(callScope, call, "", 1, null).toString(); + } finally { + Context.exit(); + } + } + + private void compile(Context cx, String name) { + name = "com/google/gerrit/prettify/client/" + name; + + InputStream in = getClass().getClassLoader().getResourceAsStream(name); + if (in == null) { + throw new RuntimeException("Cannot find " + name); + } + try { + final InputStreamReader r = new InputStreamReader(in, "UTF-8"); + try { + cx.compileReader(r, name, 1, null).exec(cx, sharedScope); + } finally { + r.close(); + } + } catch (UnsupportedEncodingException e) { + throw new RuntimeException("Cannot compile " + name, e); + } catch (IOException e) { + throw new RuntimeException("Cannot compile " + name, e); + } + } +} diff --git a/gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/gerrit.css b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/gerrit.css similarity index 83% rename from gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/gerrit.css rename to gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/gerrit.css index 531050638f..bbf0d190af 100644 --- a/gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/gerrit.css +++ b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/gerrit.css @@ -13,10 +13,17 @@ * limitations under the License. */ -.visualtab { - border: 1px dotted red; -} +@external .wse; +@external .vt; -.whitespaceerror { +.wse { background: red; } + +.vt { + border-left: 1px dotted red; +} + +.wse .vt { + border-left: 2px dotted black; +} diff --git a/gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/lang-apollo.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-apollo.js similarity index 100% rename from gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/lang-apollo.js rename to gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-apollo.js diff --git a/gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/lang-css.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-css.js similarity index 100% rename from gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/lang-css.js rename to gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-css.js diff --git a/gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/lang-hs.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-hs.js similarity index 100% rename from gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/lang-hs.js rename to gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-hs.js diff --git a/gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/lang-lisp.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-lisp.js similarity index 100% rename from gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/lang-lisp.js rename to gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-lisp.js diff --git a/gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/lang-lua.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-lua.js similarity index 100% rename from gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/lang-lua.js rename to gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-lua.js diff --git a/gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/lang-ml.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-ml.js similarity index 100% rename from gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/lang-ml.js rename to gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-ml.js diff --git a/gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/lang-proto.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-proto.js similarity index 100% rename from gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/lang-proto.js rename to gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-proto.js diff --git a/gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/lang-sql.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-sql.js similarity index 100% rename from gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/lang-sql.js rename to gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-sql.js diff --git a/gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/lang-vb.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-vb.js similarity index 100% rename from gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/lang-vb.js rename to gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-vb.js diff --git a/gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/lang-wiki.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-wiki.js similarity index 100% rename from gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/lang-wiki.js rename to gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-wiki.js diff --git a/gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/prettify.css b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/prettify.css similarity index 100% rename from gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/prettify.css rename to gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/prettify.css diff --git a/gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/prettify.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/prettify.js similarity index 100% rename from gerrit-patch-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/prettify/prettify.js rename to gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/prettify.js diff --git a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/server-env.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/server-env.js new file mode 100644 index 0000000000..28d49c07cb --- /dev/null +++ b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/server-env.js @@ -0,0 +1,22 @@ +// Copyright (C) 2010 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Mozilla Rhino is not IE 6. +// +window._pr_isIE6 = function () { return false; }; + +// Expose the function at the top level to simplify calls. +// +prettyPrintOne = window.prettyPrintOne; +PR = window.PR; diff --git a/gerrit-server/pom.xml b/gerrit-server/pom.xml index b99c982cd7..bf32075f31 100644 --- a/gerrit-server/pom.xml +++ b/gerrit-server/pom.xml @@ -128,6 +128,11 @@ limitations under the License. com.google.code.findbugs jsr305
+ + + com.google.gerrit + juniversalchardet + diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/Text.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/Text.java index 4ce13338ab..20d37a99d0 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/Text.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/Text.java @@ -14,14 +14,30 @@ package com.google.gerrit.server.patch; -import com.google.gerrit.common.data.SparseFileContent; - import org.eclipse.jgit.diff.RawText; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.util.RawParseUtils; +import org.mozilla.universalchardet.UniversalDetector; + +import java.io.UnsupportedEncodingException; public class Text extends RawText { - public static final Text EMPTY = new Text(new byte[0]); + public static final byte[] NO_BYTES = {}; + public static final Text EMPTY = new Text(NO_BYTES); + + public static String asString(byte[] content, String encoding) + throws UnsupportedEncodingException { + if (encoding == null) { + UniversalDetector d = new UniversalDetector(null); + d.handleData(content, 0, content.length); + d.dataEnd(); + encoding = d.getDetectedCharset(); + } + if (encoding == null) { + encoding = "ISO-8859-1"; + } + return new String(content, encoding); + } public Text(final byte[] r) { super(r); @@ -39,8 +55,4 @@ public class Text extends RawText { } return RawParseUtils.decode(Constants.CHARSET, content, s, e); } - - public void addLineTo(final SparseFileContent out, final int i) { - out.addLine(i, getLine(i)); - } } diff --git a/pom.xml b/pom.xml index ce42daf53d..b0bcab45e5 100644 --- a/pom.xml +++ b/pom.xml @@ -49,7 +49,7 @@ limitations under the License. 0.5.1.140-g660fd39 1.1.4-SNAPSHOT 1.2.1 - 1.2.0 + 1.2.1-SNAPSHOT 2.0.0 1.5.8 2.0 @@ -68,7 +68,6 @@ limitations under the License. gerrit-patch-commonsnet - gerrit-patch-gwtexpui gerrit-patch-jgit gerrit-util-cli @@ -79,6 +78,7 @@ limitations under the License. gerrit-launcher gerrit-main gerrit-pgm + gerrit-prettify gerrit-reviewdb gerrit-server gerrit-sshd @@ -703,6 +703,18 @@ limitations under the License. jsr305 1.3.9 + + + rhino + js + 1.7R2 + + + + com.google.gerrit + juniversalchardet + 1.0.3 + diff --git a/tools/gwtui_dbg.launch b/tools/gwtui_dbg.launch index 347ff8a48f..e1b671619d 100644 --- a/tools/gwtui_dbg.launch +++ b/tools/gwtui_dbg.launch @@ -9,13 +9,13 @@ - + - +