Merge remote-tracking branch 'origin/master'

This commit is contained in:
Vladimir.Orlov
2015-02-02 16:03:08 +03:00
13 changed files with 280 additions and 23 deletions
+2 -2
View File
@@ -5,6 +5,7 @@
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/scripts" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/restApiDocGenerator/node_modules" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
@@ -35,5 +36,4 @@
<orderEntry type="module" module-name="groovy-jps-plugin" scope="RUNTIME" />
<orderEntry type="module" module-name="groovy_rt" scope="RUNTIME" />
</component>
</module>
</module>
+1
View File
@@ -0,0 +1 @@
node_modules/
+5
View File
@@ -0,0 +1,5 @@
{
"name": "IntelliJ Platform REST API",
"version": "140.2110",
"url" : "http://localhost:63342/rest"
}
+15
View File
@@ -0,0 +1,15 @@
var gulp = require('gulp')
var apidoc = require('gulp-apidoc')
var path = require('path')
var sources = path.normalize("../../platform/platform-impl/src/org/jetbrains/ide")
gulp.task('apidoc', function () {
apidoc.exec({src: sources, dest: (process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE) + "/idea-rest-api"})
})
gulp.task('default', ['apidoc'])
gulp.task('watch', function() {
gulp.watch(sources + "/**/*.{clj,coffee,cs,dart,erl,go,java,js,php,py,rb,ts,pm}", ['apidoc'])
})
+7
View File
@@ -0,0 +1,7 @@
{
"name": "restApiDocGenerator",
"devDependencies": {
"gulp": "^3.8.10",
"gulp-apidoc": "^0.1.2"
}
}
@@ -62,7 +62,10 @@ public class StubTree extends ObjectStubTree<StubElement<?>> {
@NotNull
@Override
public List<StubElement<?>> getPlainListFromAllRoots() {
return ContainerUtil.concat(getRoot().getStubRoots(), new Function<PsiFileStub, Collection<? extends StubElement<?>>>() {
final PsiFileStub[] roots = getRoot().getStubRoots();
if (roots.length == 1) return super.getPlainListFromAllRoots();
return ContainerUtil.concat(roots, new Function<PsiFileStub, Collection<? extends StubElement<?>>>() {
@Override
public Collection<? extends StubElement<?>> fun(PsiFileStub stub) {
final ObjectStubTree existingTree = stub.getUserData(STUB_TO_TREE_REFERENCE);
@@ -219,14 +219,16 @@ public class JBScrollPane extends JScrollPane {
if (hsb != null) container.setComponentZOrder(hsb, 0);
if (extendViewportUnderVScrollbar) {
int x2 = Math.max(vsb.getX() + vsb.getWidth(), viewportBounds.x + viewportBounds.width);
viewportBounds.x = Math.min(viewportBounds.x, vsb.getX());
viewportBounds.width = vsb.getX() + vsb.getWidth() - viewportBounds.x;
viewportBounds.width = x2 - viewportBounds.x;
}
if (extendViewportUnderHScrollbar) {
int y2 = Math.max(hsb.getY() + hsb.getHeight(), viewportBounds.y + viewportBounds.height);
viewportBounds.y = Math.min(viewportBounds.y, hsb.getY());
viewportBounds.height = hsb.getY() + hsb.getHeight() - viewportBounds.y;
viewportBounds.height = y2 - viewportBounds.y;
}
if (extendViewportUnderVScrollbar) {
if (hsb != null) {
Rectangle scrollbarBounds = hsb.getBounds();
@@ -0,0 +1,43 @@
###
@apiDefine SuccessExample
@apiSuccessExample {json} Success-Response:
{
"name": "WebStorm 140.SNAPSHOT",
"productName": "WebStorm",
"baselineVersion": 140
}
###
###
@apiDefine SuccessExampleWithRegisteredFileTypes
@apiSuccessExample {json} Success-Response (with registeredFileTypes):
{
"name": "WebStorm 140.SNAPSHOT",
"productName": "WebStorm",
"baselineVersion": 140,
"registeredFileTypes": [
{
"name": "HTML",
"description": "HTML files",
"isBinary": false
},
{
"name": "XHTML",
"description": "XHTML files",
"isBinary": false
},
{
"name": "DTD",
"description": "XML Document Type Definition",
"isBinary": false
},
{
"name": "XML",
"description": "XML files",
"isBinary": false
}
]
}
###
@@ -0,0 +1,115 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* 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 org.jetbrains.ide;
import com.google.gson.stream.JsonWriter;
import com.intellij.openapi.application.ApplicationInfo;
import com.intellij.openapi.application.ApplicationNamesInfo;
import com.intellij.openapi.application.ex.ApplicationInfoEx;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeRegistry;
import com.intellij.openapi.util.BuildNumber;
import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.util.PlatformUtils;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.io.Responses;
import java.io.IOException;
import java.io.OutputStreamWriter;
/**
* @api {get} /about The application info
* @apiName about
* @apiGroup Platform
*
* @apiParam {Boolean} [registeredFileTypes=false] Whether to include the list of registered file types.
*
* @apiSuccess {String} name The full application name.
* @apiSuccess {String} productName The product name.
* @apiSuccess {String} baselineVersion The baseline version.
* @apiSuccess {String} [buildNumber] The build number.
*
* @apiSuccess {Object[]} registeredFileTypes The list of registered file types.
* @apiSuccess {String} registeredFileTypes.name The name of file type.
* @apiSuccess {String} registeredFileTypes.description The user-readable description of the file type.
* @apiSuccess {Boolean} registeredFileTypes.isBinary Whether files of the specified type contain binary data.
*
* * @apiExample Request-Example:
* /rest/about?registeredFileTypes
*
* @apiUse SuccessExample
* @apiUse SuccessExampleWithRegisteredFileTypes
*/
class AboutHttpService extends RestService {
@NotNull
@Override
protected String getServiceName() {
return "about";
}
@Override
protected boolean isMethodSupported(@NotNull HttpMethod method) {
return method == HttpMethod.GET;
}
@Nullable
@Override
public String execute(@NotNull QueryStringDecoder urlDecoder, @NotNull FullHttpRequest request, @NotNull ChannelHandlerContext context) throws IOException {
BuildNumber build = ApplicationInfo.getInstance().getBuild();
@SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
BufferExposingByteArrayOutputStream byteOut = new BufferExposingByteArrayOutputStream();
JsonWriter writer = new JsonWriter(new OutputStreamWriter(byteOut, CharsetToolkit.UTF8_CHARSET));
writer.beginObject();
String appName = ApplicationInfoEx.getInstanceEx().getFullApplicationName();
if (!PlatformUtils.isIdeaUltimate()) {
String productName = ApplicationNamesInfo.getInstance().getProductName();
appName = appName.replace(productName + " (" + productName + ")", productName);
if (appName.startsWith("JetBrains ")) {
appName = appName.substring("JetBrains ".length());
}
}
writer.name("name").value(appName);
writer.name("productName").value(ApplicationNamesInfo.getInstance().getProductName());
writer.name("baselineVersion").value(build.getBaselineVersion());
if (build.getBuildNumber() != Integer.MAX_VALUE) {
writer.name("buildNumber").value(build.getBuildNumber());
}
if (getBooleanParameter("registeredFileTypes", urlDecoder)) {
writer.name("registeredFileTypes").beginArray();
for (FileType fileType : FileTypeRegistry.getInstance().getRegisteredFileTypes()) {
writer.beginObject();
writer.name("name").value(fileType.getName());
writer.name("description").value(fileType.getDescription());
writer.name("isBinary").value(fileType.isBinary());
writer.endObject();
}
writer.endArray();
}
writer.endObject();
writer.close();
Responses.send(new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(byteOut.getInternalBuffer(), 0, byteOut.size())), context.channel(), request);
return null;
}
}
@@ -0,0 +1,18 @@
###
@apiDefine DiffRequestExample
@apiExample {json} Request-Example:
{
"fileType": "JSON",
"contents": [
{
"title": "Actual",
"content": "foo"
},
{
"title": "Expected",
"content": "bar"
}
]
}
###
@@ -38,34 +38,57 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* @api {post} /diff The differences between contents
* @apiName diff
* @apiGroup Platform
*
* @apiParam (properties) {String} [fileType] The file type name of the contents (see <a href="https://github.com/JetBrains/intellij-community/blob/master/platform/core-api/src/com/intellij/openapi/fileTypes/FileType.java">FileType.getName()</a>).
* You can get registered file types using <a href="#api-Platform-about">/rest/about?registeredFileTypes</a> request.
* @apiParam (properties) {String} [windowTitle=Diff Service] The title of the diff window.
* @apiParam (properties) {Boolean} [focused=true] Whether to focus project window.
*
* @apiParam (properties) {Object[]{2..}} contents The list of the contents to diff.
* @apiParam (properties) {String} [contents.title] The title of the content.
* @apiParam (properties) {String} [contents.fileType] The file type name of the content.
* @apiParam (properties) {String} contents.content The data of the content.
*
* @apiUse DiffRequestExample
*/
final class DiffHttpService extends RestService {
@Override
protected boolean isMethodSupported(@NotNull HttpMethod method) {
return method == HttpMethod.POST;
}
@NotNull
@Override
protected String getServiceName() {
return "diff";
}
@Override
protected boolean isMethodSupported(@NotNull HttpMethod method) {
return method == HttpMethod.POST;
}
@Override
@Nullable
public String execute(@NotNull QueryStringDecoder urlDecoder, @NotNull FullHttpRequest request, @NotNull ChannelHandlerContext context) throws IOException {
final List<DiffContent> contents = new ArrayList<DiffContent>();
final List<String> titles = new ArrayList<String>();
boolean focused = true;
String windowTitle = null;
JsonReader reader = createJsonReader(request);
if (reader.hasNext()) {
String fileType = null;
boolean reformat;
reader.beginObject();
while (reader.hasNext()) {
String name = reader.nextName();
if (name.equals("fileTypeName")) {
if (name.equals("fileType")) {
fileType = reader.nextString();
}
else if (name.equals("focused")) {
focused = reader.nextBoolean();
}
else if (name.equals("windowTitle")) {
windowTitle = StringUtil.nullize(reader.nextString(), true);
}
else if (name.equals("contents")) {
String error = readContent(reader, contents, titles, fileType);
if (error != null) {
@@ -89,6 +112,8 @@ final class DiffHttpService extends RestService {
return "No opened project, please open any project";
}
final boolean finalFocused = focused;
final String finalWindowTitle = windowTitle;
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
@@ -106,21 +131,23 @@ final class DiffHttpService extends RestService {
@Override
public String getWindowTitle() {
return "Diff Service";
return StringUtil.notNullize(finalWindowTitle, "Diff Service");
}
});
ProjectUtil.focusProjectWindow(project, true);
if (finalFocused) {
ProjectUtil.focusProjectWindow(project, true);
}
}
}, project.getDisposed());
return null;
}
@Nullable
private static String readContent(@NotNull JsonReader reader, @NotNull List<DiffContent> contents, @NotNull List<String> titles, @Nullable String defaultFileTypeName) throws IOException {
private static String readContent(@NotNull JsonReader reader, @NotNull List<DiffContent> contents, @NotNull List<String> titles, @Nullable String defaultfileType) throws IOException {
FileTypeRegistry fileTypeRegistry = FileTypeRegistry.getInstance();
FileType defaultFileType = defaultFileTypeName == null ? null : fileTypeRegistry.findFileTypeByName(defaultFileTypeName);
FileType defaultFileType = defaultfileType == null ? null : fileTypeRegistry.findFileTypeByName(defaultfileType);
reader.beginArray();
while (reader.hasNext()) {
String title = null;
@@ -133,7 +160,7 @@ final class DiffHttpService extends RestService {
if (name.equals("title")) {
title = reader.nextString();
}
else if (name.equals("fileTypeName")) {
else if (name.equals("fileType")) {
fileType = reader.nextString();
}
else if (name.equals("content")) {
@@ -145,7 +172,7 @@ final class DiffHttpService extends RestService {
}
reader.endObject();
if (content == null) {;
if (content == null) {
return "content is not specified";
}
@@ -24,6 +24,7 @@ import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.openapi.wm.IdeFrame;
import com.intellij.util.ExceptionUtil;
import com.intellij.util.containers.ContainerUtil;
import io.netty.buffer.ByteBufInputStream;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.*;
@@ -33,7 +34,12 @@ import org.jetbrains.io.Responses;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
/**
* Document your service using <a href="http://apidocjs.com">apiDoc</a>. To extract big example from source code, consider to use *.coffee file near your source file.
* (or Python/Ruby, but coffee recommended because it's plugin is lightweight). See {@link AboutHttpService} for example.
*/
public abstract class RestService extends HttpRequestHandler {
protected static final Logger LOG = Logger.getInstance(RestService.class);
@@ -55,18 +61,21 @@ public abstract class RestService extends HttpRequestHandler {
return true;
}
else {
char c = uri.charAt(minLength + 1);
char c = uri.charAt(minLength);
return c == '/' || c == '?';
}
}
return false;
}
protected abstract boolean isMethodSupported(@NotNull HttpMethod method);
@NotNull
/**
* Use human-readable name or UUID if it is an internal service.
*/
protected abstract String getServiceName();
protected abstract boolean isMethodSupported(@NotNull HttpMethod method);
@Override
public final boolean process(@NotNull QueryStringDecoder urlDecoder, @NotNull FullHttpRequest request, @NotNull ChannelHandlerContext context) throws IOException {
try {
@@ -115,4 +124,15 @@ public abstract class RestService extends HttpRequestHandler {
}
return project;
}
protected static boolean getBooleanParameter(@NotNull String name, @NotNull QueryStringDecoder urlDecoder) {
List<String> values = urlDecoder.parameters().get(name);
if (ContainerUtil.isEmpty(values)) {
return false;
}
String value = values.get(values.size() - 1);
// if just name specified, so, true
return value.isEmpty() || Boolean.parseBoolean(value);
}
}
@@ -341,6 +341,7 @@
<postStartupActivity implementation="org.jetbrains.ide.BuiltInServerManagerImpl$MyPostStartupActivity"/>
<httpRequestHandler implementation="org.jetbrains.ide.DiffHttpService"/>
<httpRequestHandler implementation="org.jetbrains.ide.AboutHttpService"/>
<editorNotificationProvider implementation="com.intellij.openapi.editor.impl.ForcedSoftWrapsNotificationProvider"/>
<editorNotificationProvider implementation="com.intellij.ide.FileChangedNotificationProvider"/>