() {
@Override
public DefaultMutableTreeNode fun(final VcsError error) {
diff --git a/platform/indexing-impl/src/com/intellij/psi/impl/PersistentIntList.java b/platform/indexing-impl/src/com/intellij/psi/impl/PersistentIntList.java
index aa5998364db4..8306cda2bfe1 100644
--- a/platform/indexing-impl/src/com/intellij/psi/impl/PersistentIntList.java
+++ b/platform/indexing-impl/src/com/intellij/psi/impl/PersistentIntList.java
@@ -16,371 +16,286 @@
package com.intellij.psi.impl;
import com.intellij.openapi.Disposable;
-import com.intellij.openapi.util.Ref;
-import com.intellij.openapi.util.io.FileUtil;
import com.intellij.util.ArrayUtil;
-import com.intellij.util.io.Bits;
-import com.intellij.util.io.IntToIntBtree;
-import com.intellij.util.io.PagedFileStorage;
-import com.intellij.util.io.RandomAccessDataFile;
import gnu.trove.TIntHashSet;
-import gnu.trove.TIntIntHashMap;
-import gnu.trove.TIntIntProcedure;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+import java.nio.channels.FileChannel;
import java.util.Arrays;
/**
- * the (int -> int[]) map which is persisted to the specified file.
+ * the (int -> int[]) map which is persisted to the specified file.
+ * File layout:
+ *
+ *
(to edit the diagram go to www.draw.io, "Import from", this PersistentIntList.png)
*/
public class PersistentIntList implements Disposable {
public static final int MAX_DATA_BYTES = 500000000;
- public static final int MAX_LIST_LENGTH = 100000;
- private final IntToIntBtree index;
- private RandomAccessDataFile data;
+ public static final int MAX_LIST_LENGTH = 10000000;
+ private final FileChannel data;
public int gap; // bytes lost due to fragmentation
- private final int dataStart; // offset of real data; the bytes before are reserved for 'index' meta information, see persistsVarsTo()
+ private IntArray pointers;
- public PersistentIntList(@NotNull File indexFile, @NotNull File dataFile, boolean initial) throws IOException {
- if (initial) {
- FileUtil.writeToFile(dataFile, ArrayUtil.EMPTY_BYTE_ARRAY);
+ public PersistentIntList(@NotNull File dataFile, int initialSize) throws IOException {
+ data = new RandomAccessFile(dataFile, "rw").getChannel();
+ int pointersBase;
+ int initialCapacity = initialSize + 256;
+ if (initialSize != 0) {
+ writeInt(data, 0, 4); // base of the pointers array
+ writeInt(data, 4, initialSize);
+ writeInt(data, 8, initialCapacity);
+ fillWithZeros(data, 4 + 8, initialCapacity *4);
+ pointersBase = 4;
}
- PagedFileStorage.StorageLockContext context = new PagedFileStorage.StorageLockContext(true);
- context.lock();
- try {
- data = new RandomAccessDataFile(dataFile);
- index = new IntToIntBtree(4096, indexFile, context, initial);
- dataStart = persistsVarsTo(data, initial);
+ else {
+ pointersBase = readInt(data, 0);
}
- finally {
- context.unlock();
+ pointers = new IntArray(data, pointersBase);
+ if (initialSize != 0) {
+ assert pointers.size == initialSize;
+ assert pointers.capacity == initialCapacity;
+ assert pointers.base == 4;
+ }
+ EMPTY = new Empty(data);
+ }
+
+ public synchronized int getSize() {
+ return pointers.size;
+ }
+
+ private static void fillWithZeros(FileChannel data, int from, int length) throws IOException {
+ ByteBuffer zeros = ByteBuffer.allocateDirect(Math.min(8192, length));
+
+ while (length > 0) {
+ ByteBuffer toWrite = length < zeros.limit() ? ByteBuffer.allocateDirect(length) : zeros;
+ toWrite.position(0);
+ int written = data.write(toWrite, from);
+ length -= written;
+ from += written;
}
}
- private int persistsVarsTo(@NotNull final RandomAccessDataFile data, boolean toDisk) {
- return index.persistVars(new IntToIntBtree.BtreeDataStorage() {
- @Override
- public int persistInt(int offset, int value, boolean toDisk) {
- if (toDisk) {
- data.putInt(offset, value);
- return value;
+ private static void writeInt(FileChannel data, int off, int value) throws IOException {
+ ByteBuffer b = ByteBuffer.allocate(4);
+ b.putInt(0,value);
+ data.write(b, off);
+ }
+ private static int readInt(FileChannel data, int off) throws IOException {
+ ByteBuffer b = ByteBuffer.allocate(4);
+ int read = data.read(b, off);
+ if (read != 4) throw new IOException(read + " bytes instead of 4");
+ return b.getInt(0);
+ }
+
+ private static class Empty extends IntArray{
+ public Empty(FileChannel data) {
+ super(data);
+ }
+
+ @Override
+ public int[] toArray() {
+ return ArrayUtil.EMPTY_INT_ARRAY;
+ }
+
+ @Override
+ void assertListLength() {
+ }
+ }
+
+ private final Empty EMPTY;
+
+ private static class IntArray {
+ private final FileChannel data;
+ private final int base;
+ private int size;
+ private final int capacity;
+
+ public IntArray(FileChannel data, int base) throws IOException {
+ this.data = data;
+ this.base = base;
+ size = readInt(data, base);
+ capacity = readInt(data, base + 4);
+ assertListLength();
+ }
+
+ private IntArray(FileChannel data) {
+ this.data = data;
+ base = 0;
+ size = 0;
+ capacity = 0;
+ }
+
+ public int get(int i) throws IOException {
+ if (i < 0 || i >= size) throw new IndexOutOfBoundsException("i="+i+"; size="+size);
+ return readInt(data, base + 8 + i*4);
+ }
+
+ public void put(int i, int value) throws IOException {
+ if (i < 0 || i >= size) throw new IndexOutOfBoundsException("i="+i+"; size="+size);
+ writeInt(data, base + 8 + i * 4, value);
+ }
+
+ public IntArray addAll(int[] values) throws IOException {
+ int[] old = toArray();
+ assertSorted(old);
+ assertListLength();
+
+ ByteBuffer mergedBytes = ByteBuffer.allocateDirect(size*4 + values.length * 4);
+ int i = 0;
+ int j = 0;
+ while (i < size || j < values.length) {
+ int stored = i < size ? old[i] : Integer.MAX_VALUE;
+ int value = j < values.length ? values[j] : Integer.MAX_VALUE;
+ if (stored < value) {
+ mergedBytes.putInt(stored);
+ i++;
+ }
+ else if (stored > value) {
+ mergedBytes.putInt(value);
+ j++;
}
else {
- return data.getInt(offset);
+ mergedBytes.putInt(value);
+ j++;
+ i++;
}
}
- }, toDisk);
+ mergedBytes.limit(mergedBytes.position());
+ mergedBytes.position(0);
+
+ int[] mergedInts = fromBytes(mergedBytes);
+ assertSorted(mergedInts);
+
+ int newSize = mergedInts.length;
+ if (newSize > capacity) {
+ IntArray realloc = reallocWith(mergedBytes, newSize);
+ assert realloc.size == newSize;
+ return realloc;
+ }
+ data.write(mergedBytes, base + 8);
+ writeInt(data, base, newSize);
+ size = newSize;
+ assertListLength();
+
+ return null;
+ }
+
+ private IntArray reallocWith(ByteBuffer bytes, int maxSize) throws IOException {
+ assert maxSize > 0 && maxSize < MAX_LIST_LENGTH : maxSize;
+ int newSize = Math.max(maxSize, bytes.limit() / 4);
+ int newCapacity = newSize < 10 ? (newSize + 1) * 2 : newSize * 3 / 2;
+ int newBase = (int)data.size();
+ writeInt(data, newBase, newSize);
+ writeInt(data, newBase + 4, newCapacity);
+ bytes.position(0);
+ data.write(bytes, newBase + 8);
+ fillWithZeros(data, newBase + 8 + newSize * 4, (newCapacity - newSize) * 4);
+ IntArray array = new IntArray(data, newBase);
+ assert array.size == newSize;
+ assert array.capacity == newCapacity;
+ assert array.base == newBase;
+ array.assertListLength();
+ return array;
+ }
+
+
+ public int[] toArray() throws IOException {
+ return fromBytes(toBuffer());
+ }
+
+ private ByteBuffer toBuffer() throws IOException {
+ assertListLength();
+ int listLength = size;
+ ByteBuffer bytes = ByteBuffer.allocateDirect(listLength * 4);
+ int read = data.read(bytes, base+8);
+ if (read != listLength*4) throw new IOException(read +" instead of "+listLength*4);
+ bytes.position(0);
+ assert bytes.limit() == listLength * 4;
+ return bytes;
+ }
+
+ void assertListLength() {
+ int listLength = size;
+ assert 0 <= listLength && listLength <= MAX_LIST_LENGTH : "size = "+listLength + ", capacity=" + capacity;
+ assert 0 < capacity && capacity <= MAX_LIST_LENGTH : "size = "+listLength + ", capacity=" + capacity;
+ assert capacity >= listLength : "size = "+listLength + ", capacity=" + capacity;
+ assert listLength == 0 || capacity <= (listLength+1)*2 : "size = "+listLength + ", capacity=" + capacity;
+ }
}
@Override
public void dispose() {
- index.withStorageLock(new Runnable() {
- @Override
- public void run() {
- try {
- persistsVarsTo(data, true);
- index.doClose();
- }
- catch (IOException e) {
- throw new RuntimeException(e);
- }
- data.dispose();
- }
- });
+ try {
+ data.close();
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
}
@NotNull
- public int[] get(final int id) {
- final Ref res = new Ref();
-
- index.withStorageLock(new Runnable() {
- @Override
- public void run() {
- final int[] ptrPtr = new int[1];
- boolean exists = index.get(id, ptrPtr);
- if (!exists) {
- ptrPtr[0] = 0;
- }
- int pointer = ptrPtr[0];
- if (pointer == 0) {
- res.set(ArrayUtil.EMPTY_INT_ARRAY);
- }
- else {
- assertPointer(pointer);
- int listLength = data.getInt(pointer);
- int capacity = data.getInt(pointer + 4);
- assertListLength(listLength, capacity);
- int[] result = new int[listLength];
- byte[] bytes = new byte[listLength * 4];
- data.get(pointer + 8, bytes, 0, bytes.length);
- for (int i = 0; i < listLength; i++) {
- result[i] = Bits.getInt(bytes, i*4);
- }
- res.set(result);
- }
- }
- });
- return res.get();
+ public synchronized int[] get(final int id) {
+ assertPointer(id);
+ try {
+ int arrayBase = pointers.get(id);
+ IntArray array = arrayBase == 0 ? EMPTY : new IntArray(data, arrayBase);
+ return array.toArray();
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
}
- // return true if was added
- public boolean add(final int id, final int value) {
- assert value > 0;
- assert id > 0;
- final boolean[] added = new boolean[1];
- index.withStorageLock(new Runnable() {
- @Override
- public void run() {
- int[] ptrPtr = new int[1];
- index.get(id, ptrPtr);
- final int pointer = ptrPtr[0];
- int[] stored;
- int capacity;
- final int listLength;
- if (pointer == 0) {
- stored = ArrayUtil.EMPTY_INT_ARRAY;
- listLength = 0;
- capacity = 2;
- }
- else {
- assertPointer(pointer);
- listLength = data.getInt(pointer);
- capacity = data.getInt(pointer+4);
- assertListLength(listLength,capacity);
- stored = new int[listLength];
- for (int i = 0; i < listLength; i++) {
- int v = data.getInt(pointer + (i + 2) * 4);
- stored[i] = v;
- if (v == value) return;
- }
- // append
- if (capacity > listLength /*|| data.length() == pointer + 4 + 4 + 4*capacity*/) {
- data.putInt(pointer + (listLength + 2) * 4, value);
- data.putInt(pointer, listLength + 1);
- if (capacity <= listLength) {
- data.putInt(pointer+4, capacity + 1);
- }
- added[0] = true;
- return;
- }
- // reallocate
- gap += 4 + 4 + 4 * capacity;
- }
-
- int storePointer = (int)data.length();
- data.putInt(storePointer, stored.length + 1);
- int newCapacity = capacity < 10 ? capacity * 2 : (int)(capacity * 1.5);
- assert newCapacity > stored.length + 1;
- data.putInt(storePointer+4, newCapacity);
- for (int i = 0; i < stored.length; i++) {
- int v = stored[i];
- data.putInt(storePointer + (i+2)*4, v);
- }
- data.putInt(storePointer + (stored.length+2)*4, value);
- for (int i = stored.length + 1; i < newCapacity; i++) {
- data.putInt(storePointer + (i+2)*4, 0); // gap
- }
- index.put(id, storePointer);
- if (storePointer > 10000000) {
- int i = 0;
- }
- added[0] = true;
- }
- });
-
- return added[0];
- }
-
- private static void assertListLength(int listLength, int capacity) {
- assert 0 < listLength && listLength <= MAX_LIST_LENGTH : listLength;
- assert 0 < capacity && capacity <= MAX_LIST_LENGTH : capacity;
- assert capacity >= listLength : listLength + ", " + capacity;
- assert capacity <= (listLength+1)*2 : listLength + ", " + capacity;
- }
-
- public void addAll(final int id, @NotNull final int[] values) {
- assertListLength(values.length, values.length);
+ public synchronized void addAll(final int id, @NotNull final int[] values) {
+ assert 0 < values.length && values.length <= MAX_LIST_LENGTH : values.length;
assert id > 0;
Arrays.sort(values);
-
- index.withStorageLock(new Runnable() {
- @Override
- public void run() {
- int[] ptrPtr = new int[1];
- index.get(id, ptrPtr);
- final int pointer = ptrPtr[0];
- int capacity;
- final int newListLength;
- byte[] mergedBytes;
-
- if (pointer == 0) {
- mergedBytes = toBytes(values);
- newListLength = values.length;
- capacity = 0;
- }
- else {
- int[] oldIds = get(id);
- checkSorted(oldIds);
-
- assertPointer(pointer);
- int storedListLength = data.getInt(pointer);
- capacity = data.getInt(pointer + 4);
- assertListLength(storedListLength, capacity);
- // try to merge inplace and if failed, reallocate at the end
- byte[] storedBytes = new byte[storedListLength * 4];
- data.get(pointer + 8, storedBytes, 0, storedListLength * 4);
-
- mergedBytes = new byte[storedBytes.length + values.length * 4];
- int outPtr = 0;
- int i = 0;
- int j = 0;
- while (i < storedListLength || j < values.length) {
- int stored = i < storedListLength ? Bits.getInt(storedBytes, i * 4) : Integer.MAX_VALUE;
- int value = j < values.length ? values[j] : Integer.MAX_VALUE;
- if (stored < value) {
- Bits.putInt(mergedBytes, outPtr, stored);
- outPtr += 4;
- i++;
- }
- else if (stored > value) {
- Bits.putInt(mergedBytes, outPtr, value);
- outPtr += 4;
- j++;
- }
- else {
- Bits.putInt(mergedBytes, outPtr, value);
- outPtr += 4;
- j++;
- i++;
- }
- }
- int[] mergedInts = fromBytes(mergedBytes, outPtr);
- checkSorted(mergedInts);
-
- newListLength = outPtr / 4;
- assertListLength(newListLength, newListLength);
- if (newListLength <= capacity) {
- storeArray(data, pointer, newListLength, capacity, mergedBytes);
- return;
- }
- gap += capacity * 4 + 8;
- }
- // reallocate at the end
-
- int storePointer = (int)data.length();
- assertPointer(storePointer);
- int oldCapacity = Math.max(capacity, newListLength);
- int newCapacity = oldCapacity < 10 ? (oldCapacity + 1) * 2 : (int)(oldCapacity * 1.5);
- assert newCapacity > newListLength + 1;
- storeArray(data, storePointer, newListLength, newCapacity, mergedBytes);
- index.put(id, storePointer);
+ try {
+ if (id >= pointers.size) {
+ pointers = pointers.reallocWith(pointers.toBuffer(), id+1);
+ writeInt(data, 0, pointers.base);
+ assert pointers.size > id : id + " > " + pointers.size;
}
- });
+ int arrayBase = pointers.get(id);
+ IntArray array = arrayBase == 0 ? EMPTY : new IntArray(data, arrayBase);
+ IntArray newArray = array.addAll(values);
+ if (newArray != null) {
+ pointers.put(id, newArray.base);
+ }
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
int[] ids = get(id);
- checkSorted(ids);
+ assertSorted(ids);
TIntHashSet set = new TIntHashSet(ids);
assert set.containsAll(values): "ids: "+Arrays.toString(ids)+";\n values:"+Arrays.toString(values);
}
- private static void checkSorted(int[] oldIds) {
+ private static void assertSorted(int[] oldIds) {
for (int i = 1; i < oldIds.length; i++) {
assert oldIds[i - 1] < oldIds[i] : oldIds[i-1] + ", " + oldIds[i];
}
}
- private static byte[] toBytes(@NotNull int[] values) {
- byte[] mergedBytes = new byte[4 * values.length];
- for (int i = 0; i < values.length; i++) {
- int value = values[i];
- Bits.putInt(mergedBytes, i * 4, value);
- }
- return mergedBytes;
- }
-
- private static int[] fromBytes(@NotNull byte[] bytes, int length) {
- assert length % 4 == 0;
- int[] ints = new int[length/4];
- for (int i = 0; i < length; i+=4) {
- int value = Bits.getInt(bytes, i);
- ints[i/4] = value;
- }
- return ints;
- }
-
- private static void storeArray(@NotNull RandomAccessDataFile data,
- int storePointer,
- int newListLength,
- int newCapacity,
- @NotNull byte[] mergedBytes) {
- assertListLength(newListLength, newCapacity);
- data.putInt(storePointer, newListLength);
- data.putInt(storePointer + 4, newCapacity);
- data.put(storePointer + 8, mergedBytes, 0, newListLength * 4);
- byte[] fill = new byte[(newCapacity - newListLength) * 4];
- Arrays.fill(fill, (byte)-1);
- data.put(storePointer + 8 + newListLength * 4, fill, 0, fill.length);
+ private static int[] fromBytes(@NotNull ByteBuffer bytes) {
+ IntBuffer intBuffer = bytes.asIntBuffer();
+ int[] result = new int[intBuffer.limit()];
+ intBuffer.get(result);
+ return result;
}
private static void assertPointer(int pointer) {
assert 0 < pointer && pointer <= MAX_DATA_BYTES : pointer;
}
- public void flush() {
- index.withStorageLock(new Runnable() {
- @Override
- public void run() {
- persistsVarsTo(data, true);
- index.doFlush();
- data.sync();
- //data.force();
- }
- });
- }
-
- private void compactIfNecessary() {
- if (gap < data.length() / 2) return;
- index.withStorageLock(new Runnable() {
- @Override
- public void run() {
- persistsVarsTo(data, true);
- index.doFlush();
- data.sync();
-
- try {
- final RandomAccessDataFile newData = new RandomAccessDataFile(new File(data.getFile().getParentFile(), "newData"));
- persistsVarsTo(newData, true);
- final TIntIntHashMap map = new TIntIntHashMap();
- index.processMappings(new IntToIntBtree.KeyValueProcessor() {
- @Override
- public boolean process(int key, int value) throws IOException {
- map.put(key, value);
- return true;
- }
- });
- map.forEachEntry(new TIntIntProcedure() {
- @Override
- public boolean execute(int key, int value) {
- int[] ids = get(key);
- int pointer = (int)newData.length();
- byte[] bytes = toBytes(ids);
- storeArray(newData, pointer, ids.length, (int)(ids.length * 1.3), bytes);
- index.put(key, pointer);
- return true;
- }
- });
-
- data.dispose();
- data = newData;
- gap = 0;
- flush();
- }
- catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- });
+ public synchronized void flush() throws IOException {
+ data.force(true);
}
}
diff --git a/platform/indexing-impl/src/com/intellij/psi/impl/PersistentIntList.png b/platform/indexing-impl/src/com/intellij/psi/impl/PersistentIntList.png
new file mode 100644
index 000000000000..954b8410c1a6
Binary files /dev/null and b/platform/indexing-impl/src/com/intellij/psi/impl/PersistentIntList.png differ
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java
index 450b684d2980..5b5ae579d0ae 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 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.
@@ -42,6 +42,7 @@ import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ex.WindowManagerEx;
import com.intellij.pom.Navigatable;
import com.intellij.psi.PsiElement;
@@ -54,6 +55,7 @@ import com.intellij.ui.components.JBLayeredPane;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.util.Consumer;
import com.intellij.util.containers.HashMap;
+import com.intellij.util.io.URLUtil;
import com.intellij.util.ui.GraphicsUtil;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NonNls;
@@ -66,8 +68,11 @@ import javax.swing.event.ChangeListener;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.text.*;
+import javax.swing.text.html.HTMLDocument;
+import javax.swing.text.html.HTMLEditorKit;
import java.awt.*;
import java.awt.event.*;
+import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;
import java.util.List;
@@ -155,6 +160,11 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr
myIsShown = false;
myEditorPane = new JEditorPane(UIUtil.HTML_MIME, "") {
+ @Override
+ public EditorKit getEditorKit() {
+ return new HTMLEditorKit();
+ }
+
@Override
public Dimension getPreferredScrollableViewportSize() {
if (getWidth() == 0 || getHeight() == 0) {
@@ -529,7 +539,6 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr
}
private void setDataInternal(SmartPsiElementPointer element, String text, final Rectangle viewRect, boolean skip) {
-
myElement = element;
boolean justShown = false;
@@ -549,6 +558,21 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr
myText = text;
}
+ Document document = myEditorPane.getDocument();
+ if (document instanceof HTMLDocument && element != null) {
+ // set base URL for this javadoc to resolve relative images correctly
+ VirtualFile virtualFile = element.getVirtualFile();
+ VirtualFile directory = virtualFile == null ? null : virtualFile.getParent();
+ String path = directory == null ? "" : directory.getPath()+"/";
+
+ try {
+ URL url = new URL(URLUtil.FILE_PROTOCOL, null, path);
+ ((HTMLDocument)document).setBase(url);
+ }
+ catch (MalformedURLException ignored) {
+ }
+ }
+
//noinspection SSBasedInspection
SwingUtilities.invokeLater(new Runnable() {
@Override
diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/UrlUtil.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/UrlUtil.java
index 400620fc4644..7eb88034c6e3 100644
--- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/UrlUtil.java
+++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/UrlUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2011 JetBrains s.r.o.
+ * Copyright 2000-2014 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.
@@ -36,9 +36,9 @@ import java.util.zip.ZipFile;
* Date: 3/25/11
*/
public class UrlUtil {
- private static final String JAR_SEPARATOR = "!/";
+ private static final String JAR_SEPARATOR = URLUtil.JAR_SEPARATOR;
private static final String URL_PATH_SEPARATOR = "/";
- private static final String FILE_PROTOCOL = "file";
+ private static final String FILE_PROTOCOL = URLUtil.FILE_PROTOCOL;
private static final String FILE_PROTOCOL_PREFIX = FILE_PROTOCOL + ":";
public static String loadText(URL url) throws IOException {
@@ -56,7 +56,7 @@ public class UrlUtil {
if ("jar".equalsIgnoreCase(protocol)) {
return getChildPathsFromJar(root);
}
- if ("file".equalsIgnoreCase(protocol)){
+ if (FILE_PROTOCOL.equalsIgnoreCase(protocol)){
return getChildPathsFromFile(root);
}
return Collections.emptyList();
diff --git a/platform/lang-impl/src/com/intellij/openapi/editor/actions/ToggleShowImportPopupsAction.java b/platform/lang-impl/src/com/intellij/openapi/editor/actions/ToggleShowImportPopupsAction.java
index b4be4d7ab4ac..64ce70e972e2 100644
--- a/platform/lang-impl/src/com/intellij/openapi/editor/actions/ToggleShowImportPopupsAction.java
+++ b/platform/lang-impl/src/com/intellij/openapi/editor/actions/ToggleShowImportPopupsAction.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2014 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.
@@ -16,46 +16,39 @@
package com.intellij.openapi.editor.actions;
+import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
-import com.intellij.openapi.actionSystem.LangDataKeys;
-import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.actionSystem.ToggleAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiFile;
-import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author Dmitry Avdeev
*/
public class ToggleShowImportPopupsAction extends ToggleAction {
-
@Override
public boolean isSelected(AnActionEvent e) {
- return getAnalyzer(e).isImportHintsEnabled(getFile(e));
+ PsiFile file = getFile(e);
+ return file != null && DaemonCodeAnalyzer.getInstance(file.getProject()).isImportHintsEnabled(file);
}
@Override
public void setSelected(AnActionEvent e, boolean state) {
- getAnalyzer(e).setImportHintsEnabled(getFile(e), state);
+ PsiFile file = getFile(e);
+ if (file != null) {
+ DaemonCodeAnalyzer.getInstance(file.getProject()).setImportHintsEnabled(file, state);
+ }
}
@Override
- public void update(AnActionEvent e) {
- if (getFile(e) == null) {
- e.getPresentation().setEnabled(false);
- e.getPresentation().setVisible(false);
- }
- else {
- e.getPresentation().setEnabled(true);
- e.getPresentation().setVisible(true);
- super.update(e);
- }
- }
-
- private DaemonCodeAnalyzer getAnalyzer(AnActionEvent e) {
- return DaemonCodeAnalyzer.getInstance(e.getData(CommonDataKeys.PROJECT));
+ public void update(@NotNull AnActionEvent e) {
+ boolean works = getFile(e) != null;
+ e.getPresentation().setEnabled(works);
+ e.getPresentation().setVisible(works);
+ super.update(e);
}
@Nullable
diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/ToggleAction.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/ToggleAction.java
index d82ad10626b2..ac53e4038b64 100644
--- a/platform/platform-api/src/com/intellij/openapi/actionSystem/ToggleAction.java
+++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/ToggleAction.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2014 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.
@@ -15,6 +15,7 @@
*/
package com.intellij.openapi.actionSystem;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
@@ -23,8 +24,8 @@ import javax.swing.*;
* An action which has a selected state, and which toggles its selected state when performed.
* Can be used to represent a menu item with a checkbox, or a toolbar button which keeps its pressed state.
*/
+@SuppressWarnings("StaticInheritance")
public abstract class ToggleAction extends AnAction implements Toggleable {
-
public ToggleAction(){
}
@@ -37,7 +38,7 @@ public abstract class ToggleAction extends AnAction implements Toggleable {
}
@Override
- public final void actionPerformed(final AnActionEvent e){
+ public final void actionPerformed(@NotNull final AnActionEvent e){
final boolean state = !isSelected(e);
setSelected(e, state);
final Boolean selected = state ? Boolean.TRUE : Boolean.FALSE;
@@ -60,8 +61,8 @@ public abstract class ToggleAction extends AnAction implements Toggleable {
public abstract void setSelected(AnActionEvent e, boolean state);
@Override
- public void update(final AnActionEvent e){
- final Boolean selected = isSelected(e) ? Boolean.TRUE : Boolean.FALSE;
+ public void update(@NotNull final AnActionEvent e){
+ boolean selected = isSelected(e);
final Presentation presentation = e.getPresentation();
presentation.putClientProperty(SELECTED_PROPERTY, selected);
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java
index 17c37d822fe2..b65a147fa0ef 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java
@@ -76,7 +76,6 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
private static final int FREE_PAINTERS_AREA_WIDTH = 5;
private static final int GAP_BETWEEN_ICONS = 3;
private static final TooltipGroup GUTTER_TOOLTIP_GROUP = new TooltipGroup("GUTTER_TOOLTIP_GROUP", 0);
- private static final Color COLOR_F0F0 = new Color(0xF0F0F0);
public static final TIntFunction ID = new TIntFunction() {
@Override
public int execute(int value) {
@@ -96,7 +95,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
private TIntArrayList myTextAnnotationGutterSizes = new TIntArrayList();
private ArrayList myTextAnnotationGutters = new ArrayList();
private final Map myProviderToListener = new HashMap();
- private static final int GAP_BETWEEN_ANNOTATIONS = 6;
+ private static final int GAP_BETWEEN_ANNOTATIONS = 5;
private Color myBackgroundColor = null;
private String myLastGutterToolTip = null;
private int myLastPreferredHeight = -1;
@@ -227,7 +226,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
private void paintEditorBackgrounds(Graphics g, Rectangle clip, int firstVisibleOffset, int lastVisibleOffset) {
Color defaultBackgroundColor = myEditor.getBackgroundColor();
- int startX = getWhitespaceSeparatorOffset() + 1;
+ int startX = getWhitespaceSeparatorOffset() + (isFoldingOutlineShown() ? 1 : 0);
IterationState state = new IterationState(myEditor, firstVisibleOffset, lastVisibleOffset, false, true);
while (!state.atEnd()) {
VisualPosition visualStart = myEditor.offsetToVisualPosition(state.getStartOffset());
@@ -329,19 +328,12 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
x += myTextAnnotationGutterSizes.get(i);
}
-
- if (!myEditor.isInDistractionFreeMode()) {
- UIUtil.drawVDottedLine((Graphics2D)g, getAnnotationsAreaOffset() + w - 1, clip.y, clip.y + clip.height, null, getOutlineColor(false));
- }
}
private void paintFoldingTree(Graphics g, Rectangle clip, int firstVisibleOffset, int lastVisibleOffset) {
if (isFoldingOutlineShown()) {
doPaintFoldingTree((Graphics2D)g, clip, firstVisibleOffset, lastVisibleOffset);
}
- else {
- UIUtil.drawVDottedLine((Graphics2D)g, clip.x + clip.width - 1, clip.y, clip.y + clip.height, null, getOutlineColor(false));
- }
}
private void paintLineMarkers(Graphics g, Rectangle clip, int firstVisibleOffset, int lastVisibleOffset) {
@@ -378,8 +370,6 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
private void paintLineNumbers(Graphics g, Rectangle clip) {
if (isLineNumbersShown()) {
- int x = getLineNumberAreaOffset() + getLineNumberAreaWidth() - 2;
- UIUtil.drawVDottedLine((Graphics2D)g, x, clip.y, clip.y + clip.height, null, getOutlineColor(false));
doPaintLineNumbers(g, clip);
}
}
@@ -396,7 +386,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
EditorColorsScheme colorsScheme = myEditor.getColorsScheme();
boolean distractionMode = myEditor.isInDistractionFreeMode();
Color color = distractionMode ? colorsScheme.getDefaultBackground() : colorsScheme.getColor(EditorColors.GUTTER_BACKGROUND);
- myBackgroundColor = color == null ? COLOR_F0F0 : color;
+ myBackgroundColor = color == null ? EditorColors.GUTTER_BACKGROUND.getDefaultColor() : color;
}
return myBackgroundColor;
}
@@ -648,9 +638,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
}
});
- myLineMarkerAreaWidth = myIconsAreaWidth + FREE_PAINTERS_AREA_WIDTH +
- // if folding outline is shown, there will be enough place for change markers, otherwise add place for it.
- (isFoldingOutlineShown() ? 0 : getFoldingAnchorWidth() / 2);
+ myLineMarkerAreaWidth = myIconsAreaWidth + FREE_PAINTERS_AREA_WIDTH;
}
private void paintGutterRenderers(final Graphics g, int firstVisibleOffset, int lastVisibleOffset) {
@@ -739,7 +727,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
int height = endY - startY;
int w = FREE_PAINTERS_AREA_WIDTH;
- int x = getLineMarkerAreaOffset() + myIconsAreaWidth;
+ int x = getLineMarkerAreaOffset() + myIconsAreaWidth - 1;
return new Rectangle(x, startY, w, height);
}
@@ -770,7 +758,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
final int leftSize = x - getLineMarkerAreaOffset();
- x = getLineMarkerAreaOffset() + myIconsAreaWidth;
+ x = getLineMarkerAreaOffset() + myIconsAreaWidth - 2; // because of 2px LineMarkerRenderers
for (GutterMark r : row) {
if (((GutterIconRenderer)r).getAlignment() == GutterIconRenderer.Alignment.RIGHT) {
Icon icon = r.getIcon();
@@ -780,7 +768,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
}
}
- int rightSize = myIconsAreaWidth + getLineMarkerAreaOffset() - x;
+ int rightSize = myIconsAreaWidth + getLineMarkerAreaOffset() - x + 1;
if (middleCount > 0) {
middleSize -= GAP_BETWEEN_ICONS;
@@ -845,7 +833,9 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
private void paintFoldingLines(final Graphics2D g, final Rectangle clip) {
if (!isFoldingOutlineShown()) return;
- UIUtil.drawVDottedLine(g, getWhitespaceSeparatorOffset(), clip.y, clip.y + clip.height, null, getOutlineColor(false));
+ g.setColor(getOutlineColor(false));
+ int x = getWhitespaceSeparatorOffset();
+ UIUtil.drawLine(g, x, clip.y, x, clip.y + clip.height);
final int anchorX = getFoldingAreaOffset();
final int width = getFoldingAnchorWidth();
@@ -981,14 +971,11 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
}
public int getFoldingAreaOffset() {
- return getLineMarkerAreaOffset() +
- getLineMarkerAreaWidth();
+ return getLineMarkerAreaOffset() + getLineMarkerAreaWidth();
}
public int getFoldingAreaWidth() {
- return isFoldingOutlineShown()
- ? getFoldingAnchorWidth() + 2
- : 0;
+ return getFoldingAnchorWidth() + (isFoldingOutlineShown() ? 2 : 0);
}
@Override
@@ -1347,7 +1334,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
}
@Override
- public void actionPerformed(AnActionEvent e) {
+ public void actionPerformed(@NotNull AnActionEvent e) {
closeAllAnnotations();
}
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java
index 5179512af245..484191e67b07 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java
@@ -303,7 +303,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
private final TIntFunction myLineNumberAreaWidthFunction = new TIntFunction() {
@Override
public int execute(int lineNumber) {
- return getFontMetrics(Font.PLAIN).stringWidth(Integer.toString(lineNumber + 1)) + 6;
+ return getFontMetrics(Font.PLAIN).stringWidth(Integer.toString(lineNumber + 1)) + 5;
}
};
@@ -6771,10 +6771,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
g.setColor(ButtonlessScrollBarUI.getTrackBackground());
g.fillRect(0, 0, width, height);
- int shortner = 0;
- if (myGutterComponent.isFoldingOutlineShown()) {
- shortner = myGutterComponent.getFoldingAreaWidth() / 2;
- }
+ int shortner = myGutterComponent.getFoldingAreaWidth() / 2;
g.setColor(myGutterComponent.getBackground());
g.fillRect(0, 0, width - shortner, height);
diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorComposite.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorComposite.java
index d8a704d891bf..87668ba25ea0 100644
--- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorComposite.java
+++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorComposite.java
@@ -36,7 +36,6 @@ import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.FocusWatcher;
import com.intellij.ui.PrevNextActionsDescriptor;
-import com.intellij.ui.SideBorder;
import com.intellij.ui.TabbedPaneWrapper;
import com.intellij.ui.tabs.UiDecorator;
import com.intellij.util.SmartList;
@@ -351,7 +350,7 @@ public abstract class EditorComposite implements Disposable {
if (remove) {
container.remove(component.getParent());
} else {
- container.add(new TopBottomComponentWrapper(component, top));
+ container.add(new TopBottomComponentWrapper(component));
}
container.revalidate();
}
@@ -474,19 +473,10 @@ public abstract class EditorComposite implements Disposable {
private static class TopBottomComponentWrapper extends JPanel {
private final JComponent myWrappee;
- public TopBottomComponentWrapper(JComponent component, boolean top) {
+ public TopBottomComponentWrapper(JComponent component) {
super(new BorderLayout());
myWrappee = component;
setOpaque(false);
-
- setBorder(new SideBorder(null, top ? SideBorder.BOTTOM : SideBorder.TOP, true) {
- @Override
- public Color getLineColor() {
- Color result = EditorColorsManager.getInstance().getGlobalScheme().getColor(EditorColors.TEARLINE_COLOR);
- return result == null ? Color.black : result;
- }
- });
-
add(component);
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/ToolWindowsWidget.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/ToolWindowsWidget.java
index 4609acf0fd4b..dac743069bd0 100644
--- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/ToolWindowsWidget.java
+++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/ToolWindowsWidget.java
@@ -59,7 +59,7 @@ class ToolWindowsWidget extends JLabel implements CustomStatusBarWidget, StatusB
private JBPopup popup;
private boolean wasExited = false;
- ToolWindowsWidget(Disposable parent) {
+ ToolWindowsWidget(@NotNull Disposable parent) {
new BaseButtonBehavior(this, TimedDeadzone.NULL) {
@Override
protected void execute(MouseEvent e) {
diff --git a/platform/platform-resources/src/DefaultColorSchemesManager.xml b/platform/platform-resources/src/DefaultColorSchemesManager.xml
index 42ab4dcb3abc..ad7511a69f82 100644
--- a/platform/platform-resources/src/DefaultColorSchemesManager.xml
+++ b/platform/platform-resources/src/DefaultColorSchemesManager.xml
@@ -18,10 +18,10 @@
-
+
-
-
+
+
diff --git a/platform/platform-resources/src/META-INF/PlatformLangPlugin.xml b/platform/platform-resources/src/META-INF/PlatformLangPlugin.xml
index ffeeeef7871b..44ef7698cac6 100644
--- a/platform/platform-resources/src/META-INF/PlatformLangPlugin.xml
+++ b/platform/platform-resources/src/META-INF/PlatformLangPlugin.xml
@@ -82,7 +82,7 @@
-
+
diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java
index a433ccadd30a..f188bfd0c207 100644
--- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java
+++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java
@@ -407,7 +407,7 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig
@Override
public long checkHighlighting(final boolean checkWarnings, final boolean checkInfos, final boolean checkWeakWarnings, boolean ignoreExtraHighlighting) {
try {
- return collectAndCheckHighlighting(checkWarnings, checkInfos, checkWeakWarnings);
+ return collectAndCheckHighlighting(checkWarnings, checkInfos, checkWeakWarnings, ignoreExtraHighlighting);
}
catch (Exception e) {
throw new RuntimeException(e);
@@ -1501,8 +1501,7 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig
private long collectAndCheckHighlighting(boolean checkWarnings, boolean checkInfos, boolean checkWeakWarnings,
boolean ignoreExtraHighlighting) throws Exception {
ExpectedHighlightingData data = new ExpectedHighlightingData(myEditor.getDocument(),
- checkWarnings, checkWeakWarnings, ignoreExtraHighlighting,
- checkInfos, getHostFile());
+ checkWarnings, checkWeakWarnings, checkInfos, ignoreExtraHighlighting, getHostFile());
data.init();
return collectAndCheckHighlighting(data);
}
diff --git a/platform/util/src/com/intellij/util/text/ImmutableText.java b/platform/util/src/com/intellij/util/text/ImmutableText.java
index 2dde3eb60293..3c487e81f1c2 100644
--- a/platform/util/src/com/intellij/util/text/ImmutableText.java
+++ b/platform/util/src/com/intellij/util/text/ImmutableText.java
@@ -50,9 +50,8 @@ import org.jetbrains.annotations.NotNull;
* @author Wilfried Middleton
* @version 5.3, January 10, 2007
*/
-@SuppressWarnings("AssignmentToForLoopParameter")
+@SuppressWarnings({"AssignmentToForLoopParameter","UnnecessaryThis"})
public final class ImmutableText extends ImmutableCharSequence implements CharArrayExternalizable {
-
/**
* Holds the default size for primitive blocks of characters.
*/
@@ -82,18 +81,39 @@ public final class ImmutableText extends ImmutableCharSequence implements CharAr
}
private static ImmutableText valueOf(@NotNull CharSequence str) {
- return new ImmutableText(new LeafNode(CharArrayUtil.fromSequence(str, 0, str.length())));
+ return new ImmutableText(createLeafNode(CharArrayUtil.fromSequence(str, 0, str.length())));
}
/**
- * Returns the text that contains the characters from the specified
+ * Returns the text that contains the characters from the specified
* array.
*
* @param chars the array source of the characters.
* @return the corresponding instance.
*/
public static ImmutableText valueOf(@NotNull char[] chars) {
- return new ImmutableText(new LeafNode(chars));
+ return new ImmutableText(createLeafNode(chars));
+ }
+
+ private static LeafNode createLeafNode(@NotNull char[] chars) {
+ if (chars.length == 0) {
+ return EMPTY_NODE;
+ }
+
+ byte[] packed = new byte[chars.length];
+ boolean success = true;
+ for (int i=0; i= 256) {
+ success = false;
+ break;
+ }
+ packed[i] = (byte)c;
+ }
+ if (success) {
+ return new Leaf8BitNode(packed);
+ }
+ return new WideLeafNode(chars);
}
/**
@@ -105,26 +125,20 @@ public final class ImmutableText extends ImmutableCharSequence implements CharAr
*/
public ImmutableText ensureChunked() {
if (length() > BLOCK_SIZE && myNode instanceof LeafNode) {
- return new ImmutableText(nodeOf(((LeafNode)myNode)._data, 0, length()));
+ return new ImmutableText(nodeOf((LeafNode)myNode, 0, length()));
}
return this;
}
- private static Node nodeOf(@NotNull char[] chars, int offset, int length) {
+ private static Node nodeOf(@NotNull LeafNode node, int offset, int length) {
if (length <= BLOCK_SIZE) {
- if (offset == 0 && length == chars.length) {
- return new LeafNode(chars);
- }
- char[] subArray = new char[length];
- System.arraycopy(chars, offset, subArray, 0, length);
- return new LeafNode(subArray);
- } else { // Splits on a block boundary.
- int half = ((length + BLOCK_SIZE) >> 1) & BLOCK_MASK;
- return new CompositeNode(nodeOf(chars, offset, half), nodeOf(chars, offset + half, length - half));
+ return node.subNode(offset, offset+length);
}
+ // Splits on a block boundary.
+ int half = ((length + BLOCK_SIZE) >> 1) & BLOCK_MASK;
+ return new CompositeNode(nodeOf(node, offset, half), nodeOf(node, offset + half, length - half));
}
-
/**
* Returns the text representation of the boolean argument.
*
@@ -141,13 +155,15 @@ public final class ImmutableText extends ImmutableCharSequence implements CharAr
private static final ImmutableText FALSE = valueOf("false");
- private static final ImmutableText EMPTY = valueOf("");
+ private static final LeafNode EMPTY_NODE = new Leaf8BitNode(new byte[0]);
+ private static final ImmutableText EMPTY = new ImmutableText(EMPTY_NODE);
/**
* Returns the length of this text.
*
* @return the number of characters (16-bits Unicode) composing this text.
*/
+ @Override
public int length() {
return myNode.nodeLength();
}
@@ -162,7 +178,7 @@ public final class ImmutableText extends ImmutableCharSequence implements CharAr
* @return this + that
*/
public ImmutableText concat(ImmutableText that) {
- return that.length() == 0 ? this : new ImmutableText(ensureChunked().myNode.concatNodes(that.ensureChunked().myNode));
+ return that.length() == 0 ? this : new ImmutableText(concatNodes(ensureChunked().myNode, that.ensureChunked().myNode));
}
/**
@@ -206,28 +222,35 @@ public final class ImmutableText extends ImmutableCharSequence implements CharAr
*/
public ImmutableText delete(int start, int end) {
if (start == end) return this;
- if (start > end)
+ if (start > end) {
throw new IndexOutOfBoundsException();
+ }
return ensureChunked().subtext(0, start).concat(subtext(end));
}
+ @Override
public CharSequence subSequence(final int start, final int end) {
if (start == 0 && end == length()) return this;
return new CharSequenceSubSequence(this, start, end);
}
+ @Override
public boolean equals(Object obj) {
- if (this == obj)
+ if (this == obj) {
return true;
- if (!(obj instanceof ImmutableText))
+ }
+ if (!(obj instanceof ImmutableText)) {
return false;
- final ImmutableText that = (ImmutableText) obj;
+ }
+ final ImmutableText that = (ImmutableText)obj;
int len = this.length();
- if (len != that.length())
+ if (len != that.length()) {
return false;
- for (int i = 0; i < len;) {
- if (this.charAt(i) != that.charAt(i++))
+ }
+ for (int i = 0; i < len; ) {
+ if (this.charAt(i) != that.charAt(i++)) {
return false;
+ }
}
return true;
}
@@ -237,6 +260,7 @@ public final class ImmutableText extends ImmutableCharSequence implements CharAr
*
* @return the hash code value.
*/
+ @Override
public int hashCode() {
int h = 0;
final int length = this.length();
@@ -246,16 +270,17 @@ public final class ImmutableText extends ImmutableCharSequence implements CharAr
return h;
}
+ @Override
public char charAt(int index) {
if (myNode instanceof LeafNode) {
- return ((LeafNode)myNode)._data[index];
+ return ((LeafNode)myNode).charAt(index);
}
InnerLeaf leaf = myLastLeaf;
if (leaf == null || index < leaf.offset || index >= leaf.offset + leaf.leafNode.nodeLength()) {
myLastLeaf = leaf = findLeaf(index, 0);
}
- return leaf.leafNode._data[index - leaf.offset];
+ return leaf.leafNode.charAt(index - leaf.offset);
}
private volatile InnerLeaf myLastLeaf;
@@ -271,7 +296,8 @@ public final class ImmutableText extends ImmutableCharSequence implements CharAr
CompositeNode composite = (CompositeNode)node;
if (index < composite._head.nodeLength()) {
node = composite._head;
- } else {
+ }
+ else {
offset += composite._head.nodeLength();
index -= composite._head.nodeLength();
node = composite._tail;
@@ -283,7 +309,7 @@ public final class ImmutableText extends ImmutableCharSequence implements CharAr
final LeafNode leafNode;
final int offset;
- private InnerLeaf(LeafNode leafNode, int offset) {
+ private InnerLeaf(@NotNull LeafNode leafNode, int offset) {
this.leafNode = leafNode;
this.offset = offset;
}
@@ -300,12 +326,15 @@ public final class ImmutableText extends ImmutableCharSequence implements CharAr
* (start > end) || (end > this.length())
*/
public ImmutableText subtext(int start, int end) {
- if ((start < 0) || (start > end) || (end > length()))
+ if ((start < 0) || (start > end) || (end > length())) {
throw new IndexOutOfBoundsException();
- if ((start == 0) && (end == length()))
+ }
+ if ((start == 0) && (end == length())) {
return this;
- if (start == end)
+ }
+ if (start == end) {
return EMPTY;
+ }
return new ImmutableText(myNode.subNode(start, end));
}
@@ -321,6 +350,7 @@ public final class ImmutableText extends ImmutableCharSequence implements CharAr
* @throws IndexOutOfBoundsException if (start < 0) || (end < 0) ||
* (start > end) || (end > this.length())
*/
+ @Override
public void getChars(int start, int end, @NotNull char[] dest, int destPos) {
myNode.getChars(start, end, dest, destPos);
}
@@ -330,68 +360,69 @@ public final class ImmutableText extends ImmutableCharSequence implements CharAr
*
* @return the java.lang.String for this text.
*/
+ @Override
@NotNull
public String toString() {
- if (myNode instanceof LeafNode) { // Primitive.
- return new String(((LeafNode)myNode)._data, 0, length());
- } else { // Composite.
- int len = length();
- char[] data = new char[len];
- this.getChars(0, len, data, 0);
- return new String(data, 0, len);
- }
+ return myNode.toString();
}
- private static abstract class Node {
-
+ private abstract static class Node {
abstract int nodeLength();
-
- Node concatNodes(Node that) {
- // All Text instances are maintained balanced:
- // (head < tail * 2) & (tail < head * 2)
-
- final int length = this.nodeLength() + that.nodeLength();
- if (length <= BLOCK_SIZE) { // Merges to primitive.
- char[] chars = new char[length];
- this.getChars(0, this.nodeLength(), chars, 0);
- that.getChars(0, that.nodeLength(), chars, this.nodeLength());
- return new LeafNode(chars);
- } else { // Returns a composite.
- Node head = this;
- Node tail = that;
-
- if (((head.nodeLength() << 1) < tail.nodeLength()) && tail instanceof CompositeNode) {
- // head too small, returns (head + tail/2) + (tail/2)
- if (((CompositeNode)tail)._head.nodeLength() > ((CompositeNode)tail)._tail.nodeLength()) {
- // Rotates to concatenate with smaller part.
- tail = ((CompositeNode)tail).rightRotation();
- }
- head = head.concatNodes(((CompositeNode)tail)._head);
- tail = ((CompositeNode)tail)._tail;
-
- } else if (((tail.nodeLength() << 1) < head.nodeLength()) && head instanceof CompositeNode) {
- // tail too small, returns (head/2) + (head/2 concat tail)
- if (((CompositeNode)head)._tail.nodeLength() > ((CompositeNode)head)._head.nodeLength()) {
- // Rotates to concatenate with smaller part.
- head = ((CompositeNode)head).leftRotation();
- }
- tail = ((CompositeNode)head)._tail.concatNodes(tail);
- head = ((CompositeNode)head)._head;
- }
- return new CompositeNode(head, tail);
- }
- }
-
abstract void getChars(int start, int end, @NotNull char[] dest, int destPos);
-
abstract Node subNode(int start, int end);
-
+ @Override
+ public String toString() {
+ int len = nodeLength();
+ char[] data = new char[len];
+ getChars(0, len, data, 0);
+ return StringFactory.createShared(data);
+ }
+ }
+ private abstract static class LeafNode extends Node {
+ public abstract char charAt(int index);
}
- private static class LeafNode extends Node {
- final char[] _data;
+ @NotNull
+ private static Node concatNodes(@NotNull Node node1, @NotNull Node node2) {
+ // All Text instances are maintained balanced:
+ // (head < tail * 2) & (tail < head * 2)
+ final int length = node1.nodeLength() + node2.nodeLength();
+ if (length <= BLOCK_SIZE) { // Merges to primitive.
+ char[] chars = new char[length];
+ node1.getChars(0, node1.nodeLength(), chars, 0);
+ node2.getChars(0, node2.nodeLength(), chars, node1.nodeLength());
+ return createLeafNode(chars);
+ }
+ else { // Returns a composite.
+ Node head = node1;
+ Node tail = node2;
- LeafNode(char[] _data) {
+ if (((head.nodeLength() << 1) < tail.nodeLength()) && tail instanceof CompositeNode) {
+ // head too small, returns (head + tail/2) + (tail/2)
+ if (((CompositeNode)tail)._head.nodeLength() > ((CompositeNode)tail)._tail.nodeLength()) {
+ // Rotates to concatenate with smaller part.
+ tail = ((CompositeNode)tail).rightRotation();
+ }
+ head = concatNodes(head, ((CompositeNode)tail)._head);
+ tail = ((CompositeNode)tail)._tail;
+ }
+ else if (((tail.nodeLength() << 1) < head.nodeLength()) && head instanceof CompositeNode) {
+ // tail too small, returns (head/2) + (head/2 concat tail)
+ if (((CompositeNode)head)._tail.nodeLength() > ((CompositeNode)head)._head.nodeLength()) {
+ // Rotates to concatenate with smaller part.
+ head = ((CompositeNode)head).leftRotation();
+ }
+ tail = concatNodes(((CompositeNode)head)._tail, tail);
+ head = ((CompositeNode)head)._head;
+ }
+ return new CompositeNode(head, tail);
+ }
+ }
+
+ private static class WideLeafNode extends LeafNode {
+ private final char[] _data;
+
+ WideLeafNode(@NotNull char[] _data) {
this._data = _data;
}
@@ -402,8 +433,9 @@ public final class ImmutableText extends ImmutableCharSequence implements CharAr
@Override
void getChars(int start, int end, @NotNull char[] dest, int destPos) {
- if ((start < 0) || (end > nodeLength()) || (start > end))
+ if ((start < 0) || (end > nodeLength()) || (start > end)) {
throw new IndexOutOfBoundsException();
+ }
System.arraycopy(_data, start, dest, destPos, end - start);
}
@@ -415,7 +447,56 @@ public final class ImmutableText extends ImmutableCharSequence implements CharAr
int length = end - start;
char[] chars = new char[length];
System.arraycopy(_data, start, chars, 0, length);
- return new LeafNode(chars);
+ return createLeafNode(chars);
+ }
+
+ @Override
+ public String toString() {
+ return StringFactory.createShared(_data);
+ }
+
+ @Override
+ public char charAt(int index) {
+ return _data[index];
+ }
+ }
+
+ private static class Leaf8BitNode extends LeafNode {
+ private final byte[] data;
+ Leaf8BitNode(@NotNull byte[] data) {
+ this.data = data;
+ }
+
+ @Override
+ int nodeLength() {
+ return data.length;
+ }
+
+ @Override
+ void getChars(int start, int end, @NotNull char[] dest, int destPos) {
+ if ((start < 0) || (end > nodeLength()) || (start > end)) {
+ throw new IndexOutOfBoundsException();
+ }
+ for (int i=start;i= cesure) {
+ }
+ else if (start >= cesure) {
_tail.getChars(start - cesure, end - cesure, dest, destPos);
- } else { // Overlaps head and tail.
+ }
+ else { // Overlaps head and tail.
_head.getChars(start, cesure, dest, destPos);
_tail.getChars(0, end - cesure, dest, destPos + cesure - start);
}
@@ -473,14 +558,17 @@ public final class ImmutableText extends ImmutableCharSequence implements CharAr
@Override
Node subNode(int start, int end) {
final int cesure = _head.nodeLength();
- if (end <= cesure)
+ if (end <= cesure) {
return _head.subNode(start, end);
- if (start >= cesure)
+ }
+ if (start >= cesure) {
return _tail.subNode(start - cesure, end - cesure);
- if ((start == 0) && (end == _count))
+ }
+ if ((start == 0) && (end == _count)) {
return this;
+ }
// Overlaps head and tail.
- return _head.subNode(start, cesure).concatNodes(_tail.subNode(0, end - cesure));
+ return concatNodes(_head.subNode(start, cesure), _tail.subNode(0, end - cesure));
}
}
}
\ No newline at end of file
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java
index 9c769e7434b0..ccf0a1560c8c 100644
--- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java
@@ -72,19 +72,18 @@ public class LineStatusTrackerDrawing {
final EditorGutterComponentEx gutter = ((EditorEx)editor).getGutterComponentEx();
Color stripeColor = getDiffGutterColor(range);
- boolean foldingOutlineShown = ((EditorEx)editor).getGutterComponentEx().isFoldingOutlineShown();
int triangle = 4;
if (range.getInnerRanges() == null) { // actual painter
g.setColor(stripeColor);
final int endX = gutter.getWhitespaceSeparatorOffset();
- final int x = r.x + r.width - 4;
+ final int x = r.x + r.width - 3;
final int width = endX - x;
if (r.height > 0) {
- g.fillRect(x, r.y, width, r.height); // todo: intersection with dotted gutter outline
+ g.fillRect(x, r.y, width, r.height);
}
else {
- final int[] xPoints = new int[]{x, x, endX - (foldingOutlineShown ? -1 : triangle + 1)};
+ final int[] xPoints = new int[]{x, x, endX};
final int[] yPoints = new int[]{r.y - triangle, r.y + triangle, r.y};
g.fillPolygon(xPoints, yPoints, 3);
}
@@ -97,7 +96,7 @@ public class LineStatusTrackerDrawing {
if (range.getType() == Range.DELETED) {
final int y = lineToY(editor, range.getLine1());
- final int[] xPoints = new int[]{x, x, endX - (foldingOutlineShown ? 0 : triangle + 1)};
+ final int[] xPoints = new int[]{x, x, endX + 1};
final int[] yPoints = new int[]{y - triangle, y + triangle, y};
g.setColor(stripeColor);
@@ -215,7 +214,7 @@ public class LineStatusTrackerDrawing {
toolbar.setBackground(background);
toolbar
- .setBorder(new ColoredSideBorder(foreground, foreground, (range.getType() != Range.INSERTED) ? null : foreground, foreground, 1));
+ .setBorder(new ColoredSideBorder(foreground, foreground, range.getType() != Range.INSERTED ? null : foreground, foreground, 1));
final JPanel component = new JPanel(new BorderLayout());
component.setOpaque(false);
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushOptionsPanel.java b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushOptionsPanel.java
index 32d22730e560..470bf925aa2b 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushOptionsPanel.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushOptionsPanel.java
@@ -16,31 +16,24 @@
package org.zmlx.hg4idea.push;
import com.intellij.dvcs.push.VcsPushOptionsPanel;
-import com.intellij.openapi.ui.ComboBox;
-import org.jetbrains.annotations.NotNull;
+import com.intellij.ui.components.JBCheckBox;
+import org.jetbrains.annotations.Nullable;
-import javax.swing.*;
import java.awt.*;
public class HgPushOptionsPanel extends VcsPushOptionsPanel {
- private final ComboBox myReferenceStrategyCombobox;
+ private final JBCheckBox myPushBookmarkCheckBox;
public HgPushOptionsPanel() {
setLayout(new BorderLayout());
- myReferenceStrategyCombobox = new ComboBox();
- HgVcsPushOptionValue[] values = HgVcsPushOptionValue.values();
- DefaultComboBoxModel comboModel = new DefaultComboBoxModel(values);
- myReferenceStrategyCombobox.setModel(comboModel);
- JLabel referenceStrategyLabel = new JLabel("Export Bookmarks: ");
- add(referenceStrategyLabel, BorderLayout.WEST);
- add(myReferenceStrategyCombobox, BorderLayout.CENTER);
+ myPushBookmarkCheckBox = new JBCheckBox("Export Active Bookmarks");
+ add(myPushBookmarkCheckBox, BorderLayout.WEST);
}
@Override
- @NotNull
+ @Nullable
public HgVcsPushOptionValue getValue() {
- return (HgVcsPushOptionValue)myReferenceStrategyCombobox.getSelectedItem();
+ return myPushBookmarkCheckBox.isSelected() ? HgVcsPushOptionValue.Current : null;
}
-
}
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/StudyTaskManager.java b/python/edu/learn-python/src/com/jetbrains/python/edu/StudyTaskManager.java
index f37adf0b19f6..365aa25afd23 100644
--- a/python/edu/learn-python/src/com/jetbrains/python/edu/StudyTaskManager.java
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/StudyTaskManager.java
@@ -217,14 +217,14 @@ public class StudyTaskManager implements ProjectComponent, PersistentStateCompon
}
});
}
- addShortcut(StudyNextWindowAction.SHORTCUT, StudyNextWindowAction.ACTION_ID);
- addShortcut(StudyPrevWindowAction.SHORTCUT, StudyPrevWindowAction.ACTION_ID);
- addShortcut(StudyShowHintAction.SHORTCUT, StudyShowHintAction.ACTION_ID);
- addShortcut(StudyNextWindowAction.SHORTCUT2, StudyNextWindowAction.ACTION_ID);
- addShortcut(StudyCheckAction.SHORTCUT, StudyCheckAction.ACTION_ID);
- addShortcut(StudyNextStudyTaskAction.SHORTCUT, StudyNextStudyTaskAction.ACTION_ID);
- addShortcut(StudyPreviousStudyTaskAction.SHORTCUT, StudyPreviousStudyTaskAction.ACTION_ID);
- addShortcut(StudyRefreshTaskFileAction.SHORTCUT, StudyRefreshTaskFileAction.ACTION_ID);
+ addShortcut(StudyNextWindowAction.SHORTCUT, StudyNextWindowAction.ACTION_ID, false);
+ addShortcut(StudyPrevWindowAction.SHORTCUT, StudyPrevWindowAction.ACTION_ID, false);
+ addShortcut(StudyShowHintAction.SHORTCUT, StudyShowHintAction.ACTION_ID, false);
+ addShortcut(StudyNextWindowAction.SHORTCUT2, StudyNextWindowAction.ACTION_ID, true);
+ addShortcut(StudyCheckAction.SHORTCUT, StudyCheckAction.ACTION_ID, false);
+ addShortcut(StudyNextStudyTaskAction.SHORTCUT, StudyNextStudyTaskAction.ACTION_ID, false);
+ addShortcut(StudyPreviousStudyTaskAction.SHORTCUT, StudyPreviousStudyTaskAction.ACTION_ID, false);
+ addShortcut(StudyRefreshTaskFileAction.SHORTCUT, StudyRefreshTaskFileAction.ACTION_ID, false);
}
}
});
@@ -233,10 +233,10 @@ public class StudyTaskManager implements ProjectComponent, PersistentStateCompon
}
- private static void addShortcut(@NotNull final String shortcutString, @NotNull final String actionIdString) {
+ private static void addShortcut(@NotNull final String shortcutString, @NotNull final String actionIdString, boolean isAdditional) {
Keymap keymap = KeymapManager.getInstance().getActiveKeymap();
Shortcut[] shortcuts = keymap.getShortcuts(actionIdString);
- if (shortcuts.length > 0) {
+ if (shortcuts.length > 0 && !isAdditional) {
return;
}
Shortcut studyActionShortcut = new KeyboardShortcut(KeyStroke.getKeyStroke(shortcutString), null);
diff --git a/python/src/com/jetbrains/python/codeInsight/regexp/PythonRegexpParserDefinition.java b/python/src/com/jetbrains/python/codeInsight/regexp/PythonRegexpParserDefinition.java
index 25cc6495e1f4..a28460c6ca0c 100644
--- a/python/src/com/jetbrains/python/codeInsight/regexp/PythonRegexpParserDefinition.java
+++ b/python/src/com/jetbrains/python/codeInsight/regexp/PythonRegexpParserDefinition.java
@@ -33,8 +33,7 @@ public class PythonRegexpParserDefinition extends RegExpParserDefinition {
public static final IFileElementType PYTHON_REGEXP_FILE = new IFileElementType("PYTHON_REGEXP_FILE", PythonRegexpLanguage.INSTANCE);
protected final EnumSet CAPABILITIES = EnumSet.of(RegExpCapability.DANGLING_METACHARACTERS,
RegExpCapability.OCTAL_NO_LEADING_ZERO,
- RegExpCapability.OMIT_NUMBERS_IN_QUANTIFIERS,
- RegExpCapability.ALLOW_EMPTY_CHARACTER_CLASS);
+ RegExpCapability.OMIT_NUMBERS_IN_QUANTIFIERS);
@NotNull
public Lexer createLexer(Project project) {
diff --git a/python/src/com/jetbrains/python/inspections/quickfix/AddEncodingQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/AddEncodingQuickFix.java
index 82f61cfb1b57..3e3e55028abe 100644
--- a/python/src/com/jetbrains/python/inspections/quickfix/AddEncodingQuickFix.java
+++ b/python/src/com/jetbrains/python/inspections/quickfix/AddEncodingQuickFix.java
@@ -25,9 +25,9 @@ import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.TextEditor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiComment;
-import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiWhiteSpace;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.inspections.PyEncodingUtil;
import com.jetbrains.python.psi.LanguageLevel;
@@ -71,20 +71,20 @@ public class AddEncodingQuickFix implements LocalQuickFix {
if (firstLine instanceof PsiComment && firstLine.getText().startsWith("#!")) {
firstLine = firstLine.getNextSibling();
}
+ final LanguageLevel languageLevel = LanguageLevel.forElement(file);
final String commentText = String.format(PyEncodingUtil.ENCODING_FORMAT_PATTERN[myEncodingFormatIndex], myDefaultEncoding);
final PyElementGenerator elementGenerator = PyElementGenerator.getInstance(project);
- PsiComment encodingComment = elementGenerator.createFromText(LanguageLevel.forElement(file), PsiComment.class, commentText);
+ PsiComment encodingComment = elementGenerator.createFromText(languageLevel, PsiComment.class, commentText);
encodingComment = (PsiComment)file.addBefore(encodingComment, firstLine);
final FileEditor fileEditor = FileEditorManager.getInstance(project).getSelectedEditor(element.getContainingFile().getVirtualFile());
if (fileEditor instanceof TextEditor) {
+ if (encodingComment.getNextSibling() == null || !encodingComment.getNextSibling().textContains('\n')) {
+ file.addAfter(elementGenerator.createFromText(languageLevel, PsiWhiteSpace.class, "\n"), encodingComment);
+ }
final Editor editor = ((TextEditor)fileEditor).getEditor();
final Document document = editor.getDocument();
final int insertedLineNumber = document.getLineNumber(encodingComment.getTextOffset());
- if (insertedLineNumber == document.getLineCount() - 1) {
- PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(document);
- document.insertString(document.getLineEndOffset(insertedLineNumber), "\n");
- }
editor.getCaretModel().moveToLogicalPosition(new LogicalPosition(insertedLineNumber + 1, 0));
}
}
diff --git a/python/testData/inspections/AddEncodingInEmptyFile.py b/python/testData/inspections/AddEncodingAtLastLine.py
similarity index 74%
rename from python/testData/inspections/AddEncodingInEmptyFile.py
rename to python/testData/inspections/AddEncodingAtLastLine.py
index 376db9193fc4..a7868cf286f9 100644
--- a/python/testData/inspections/AddEncodingInEmptyFile.py
+++ b/python/testData/inspections/AddEncodingAtLastLine.py
@@ -1 +1 @@
-
+#!/usr/bin/env python
\ No newline at end of file
diff --git a/python/testData/inspections/AddEncodingInEmptyFile_after.py b/python/testData/inspections/AddEncodingAtLastLine_after.py
similarity index 50%
rename from python/testData/inspections/AddEncodingInEmptyFile_after.py
rename to python/testData/inspections/AddEncodingAtLastLine_after.py
index 76ea4ea7c759..5e9beaa6da1d 100644
--- a/python/testData/inspections/AddEncodingInEmptyFile_after.py
+++ b/python/testData/inspections/AddEncodingAtLastLine_after.py
@@ -1,2 +1,3 @@
+#!/usr/bin/env python
# coding=utf-8
\ No newline at end of file
diff --git a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java
index c7e8d138aa83..6cc2e578fb30 100644
--- a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java
+++ b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java
@@ -356,8 +356,8 @@ public class PyQuickFixTest extends PyTestCase {
}
// PY-13297
- public void testAddEncodingInEmptyFile() {
- doInspectionTest("AddEncodingInEmptyFile.py", PyMandatoryEncodingInspection.class,
+ public void testAddEncodingAtLastLine() {
+ doInspectionTest("AddEncodingAtLastLine.py", PyMandatoryEncodingInspection.class,
PyBundle.message("QFIX.add.encoding"), true, true);
}
diff --git a/xml/impl/src/com/intellij/codeInsight/editorActions/EnterBetweenXmlTagsHandler.java b/xml/impl/src/com/intellij/codeInsight/editorActions/EnterBetweenXmlTagsHandler.java
index 96309e2bdb34..a2465be776f2 100644
--- a/xml/impl/src/com/intellij/codeInsight/editorActions/EnterBetweenXmlTagsHandler.java
+++ b/xml/impl/src/com/intellij/codeInsight/editorActions/EnterBetweenXmlTagsHandler.java
@@ -28,6 +28,7 @@ import com.intellij.openapi.util.Ref;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
+import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
@@ -41,7 +42,10 @@ public class EnterBetweenXmlTagsHandler extends EnterHandlerDelegateAdapter {
final Project project = CommonDataKeys.PROJECT.getData(dataContext);
if (file instanceof XmlFile && isBetweenXmlTags(project, editor, file, caretOffset.get().intValue())) {
- originalHandler.execute(editor, dataContext);
+ editor.getDocument().insertString(caretOffset.get(), "\n");
+ if (project != null) {
+ CodeStyleManager.getInstance(project).adjustLineIndent(editor.getDocument(), caretOffset.get() + 1);
+ }
return Result.DefaultForceIndent;
}
return Result.Continue;
diff --git a/xml/impl/src/com/intellij/codeInsight/template/emmet/EmmetPreviewHint.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/EmmetPreviewHint.java
index 01c809e6a459..626582db1113 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/emmet/EmmetPreviewHint.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/EmmetPreviewHint.java
@@ -89,13 +89,13 @@ public class EmmetPreviewHint extends LightweightHint implements Disposable {
JRootPane pane = myParentEditor.getComponent().getRootPane();
JComponent layeredPane = pane != null ? pane.getLayeredPane() : myParentEditor.getComponent();
HintHint hintHint = new HintHint(layeredPane, position.first)
- .setAwtTooltip(true)
- .setContentActive(true)
- .setExplicitClose(true)
- .setShowImmediately(true)
- .setPreferredPosition(position.second == HintManager.ABOVE ? Balloon.Position.above : Balloon.Position.below)
- .setTextBg(myParentEditor.getColorsScheme().getDefaultBackground())
- .setBorderInsets(new Insets(1, 1, 1, 1));
+ .setAwtTooltip(true)
+ .setContentActive(true)
+ .setExplicitClose(true)
+ .setShowImmediately(true)
+ .setPreferredPosition(position.second == HintManager.ABOVE ? Balloon.Position.above : Balloon.Position.below)
+ .setTextBg(myParentEditor.getColorsScheme().getDefaultBackground())
+ .setBorderInsets(new Insets(1, 1, 1, 1));
int hintFlags = HintManager.HIDE_BY_OTHER_HINT | HintManager.HIDE_BY_ESCAPE | HintManager.UPDATE_BY_SCROLLING;
HintManagerImpl.getInstanceImpl().showEditorHint(this, myParentEditor, position.first, hintFlags, 0, false, hintHint);
@@ -123,7 +123,7 @@ public class EmmetPreviewHint extends LightweightHint implements Disposable {
}
}, 100);
}
-
+
@TestOnly
@NotNull
public String getContent() {
@@ -143,7 +143,9 @@ public class EmmetPreviewHint extends LightweightHint implements Disposable {
}
@NotNull
- public static EmmetPreviewHint createHint(@NotNull final EditorEx parentEditor, @NotNull String templateText, @NotNull FileType fileType) {
+ public static EmmetPreviewHint createHint(@NotNull final EditorEx parentEditor,
+ @NotNull String templateText,
+ @NotNull FileType fileType) {
EditorFactory editorFactory = EditorFactory.getInstance();
Document document = editorFactory.createDocument(templateText);
final EditorEx previewEditor = (EditorEx)editorFactory.createEditor(document, parentEditor.getProject(), fileType, true);
@@ -172,9 +174,9 @@ public class EmmetPreviewHint extends LightweightHint implements Disposable {
Dimension parentEditorSize = parentEditor.getScrollPane().getSize();
int maxWidth = (int)parentEditorSize.getWidth() / 3;
int maxHeight = (int)parentEditorSize.getHeight() / 2;
- Dimension contentSize = previewEditor.getContentSize();
- return new Dimension(maxWidth > contentSize.getWidth() && !settings.isUseSoftWraps() ? (int)size.getWidth() : maxWidth,
- maxHeight > contentSize.getHeight() ? (int)size.getHeight() : maxHeight);
+ final int width = settings.isUseSoftWraps() ? maxWidth : Math.min((int)size.getWidth(), maxWidth);
+ final int height = Math.min((int)size.getHeight(), maxHeight);
+ return new Dimension(width, height);
}
@NotNull
diff --git a/xml/tests/src/com/intellij/codeInsight/completion/XmlTypedHandlersTest.java b/xml/tests/src/com/intellij/codeInsight/completion/XmlTypedHandlersTest.java
index 41e64aad87e9..d3e5e941cb07 100644
--- a/xml/tests/src/com/intellij/codeInsight/completion/XmlTypedHandlersTest.java
+++ b/xml/tests/src/com/intellij/codeInsight/completion/XmlTypedHandlersTest.java
@@ -105,6 +105,20 @@ public class XmlTypedHandlersTest extends LightPlatformCodeInsightFixtureTestCas
"");
}
+ public void testWeb13982() throws Exception {
+ doTest(
+ "",
+
+ '\n',
+
+ "\n" +
+ " \n" +
+ ""
+ );
+ }
+
private void doTest(String text, char c, String result) {
myFixture.configureByText(XmlFileType.INSTANCE, text);
myFixture.type(c);
diff --git a/xml/xml-analysis-impl/src/com/intellij/xml/util/CheckTagEmptyBodyInspection.java b/xml/xml-analysis-impl/src/com/intellij/xml/util/CheckTagEmptyBodyInspection.java
index fdc14937782f..968ef3e34e26 100644
--- a/xml/xml-analysis-impl/src/com/intellij/xml/util/CheckTagEmptyBodyInspection.java
+++ b/xml/xml-analysis-impl/src/com/intellij/xml/util/CheckTagEmptyBodyInspection.java
@@ -59,7 +59,7 @@ public class CheckTagEmptyBodyInspection extends XmlSuppressableInspectionTool {
if (node != null &&
node.getElementType() == XmlTokenType.XML_END_TAG_START) {
- final LocalQuickFix localQuickFix = new ReplaceEmptyTagBodyByEmptyEndFix();
+ final LocalQuickFix localQuickFix = new Fix();
holder.registerProblem(
tag,
XmlBundle.message("xml.inspections.tag.empty.body"),
@@ -98,7 +98,7 @@ public class CheckTagEmptyBodyInspection extends XmlSuppressableInspectionTool {
return "CheckTagEmptyBody";
}
- private static class ReplaceEmptyTagBodyByEmptyEndFix implements LocalQuickFix {
+ public static class Fix implements LocalQuickFix {
@Override
@NotNull
public String getName() {
diff --git a/xml/xml-psi-api/src/com/intellij/codeInspection/XmlSuppressableInspectionTool.java b/xml/xml-psi-api/src/com/intellij/codeInspection/XmlSuppressableInspectionTool.java
index 3e1052f3c939..7d588ce38897 100644
--- a/xml/xml-psi-api/src/com/intellij/codeInspection/XmlSuppressableInspectionTool.java
+++ b/xml/xml-psi-api/src/com/intellij/codeInspection/XmlSuppressableInspectionTool.java
@@ -35,7 +35,9 @@ public abstract class XmlSuppressableInspectionTool extends LocalInspectionTool
@NotNull
public static SuppressQuickFix[] getSuppressFixes(@NotNull String shortName, @NotNull XmlSuppressionProvider provider) {
- final String id = HighlightDisplayKey.find(shortName).getID();
+ HighlightDisplayKey key = HighlightDisplayKey.find(shortName);
+ if (key == null) return SuppressQuickFix.EMPTY_ARRAY;
+ final String id = key.getID();
return new SuppressQuickFix[]{new SuppressTagStatic(id, provider), new SuppressForFile(id, provider), new SuppressAllForFile(provider)};
}