mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master' into eldar/cidr-debugger
# Conflicts: # CIDR/cidr-debugger/resources/META-INF/CidrDebuggerPlugin.xml GitOrigin-RevId: de8e0298bef122544fd1af40c209050903b3d263
This commit is contained in:
committed by
intellij-monorepo-bot
parent
1120c30a56
commit
18962d3d42
@@ -20,7 +20,7 @@
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<lang.documentationProvider language="RegExp" implementationClass="org.intellij.lang.regexp.RegExpDocumentationProvider"/>
|
||||
<completion.contributor language="RegExp" implementationClass="org.intellij.lang.regexp.RegExpCompletionContributor"/>
|
||||
<fileTypeFactory implementation="org.intellij.lang.regexp.RegExpSupportLoader" />
|
||||
<fileType name="RegExp" implementationClass="org.intellij.lang.regexp.RegExpFileType" extensions="regexp" fieldName="INSTANCE" language="RegExp"/>
|
||||
<annotator language="RegExp" implementationClass="org.intellij.lang.regexp.validation.RegExpAnnotator"/>
|
||||
<lang.parserDefinition language="RegExp" implementationClass="org.intellij.lang.regexp.RegExpParserDefinition"/>
|
||||
<lang.syntaxHighlighterFactory language="RegExp" implementationClass="org.intellij.lang.regexp.RegExpSyntaxHighlighterFactory"/>
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006 Sascha Weinreuter
|
||||
*
|
||||
* 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.intellij.lang.regexp;
|
||||
|
||||
import com.intellij.openapi.fileTypes.FileTypeConsumer;
|
||||
import com.intellij.openapi.fileTypes.FileTypeFactory;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class RegExpSupportLoader extends FileTypeFactory {
|
||||
public static final RegExpLanguage LANGUAGE = RegExpLanguage.INSTANCE;
|
||||
public static final RegExpFileType FILE_TYPE = RegExpFileType.INSTANCE;
|
||||
|
||||
@Override
|
||||
public void createFileTypes(final @NotNull FileTypeConsumer consumer) {
|
||||
consumer.consume(FILE_TYPE, FILE_TYPE.getDefaultExtension());
|
||||
}
|
||||
}
|
||||
@@ -5,5 +5,5 @@ jetSignBuild=42.30
|
||||
secondJreVersion=11
|
||||
secondJreBuild=11_0_3b304.2
|
||||
bundledMavenVersion=3.6.1
|
||||
jdkBuild=u212b1586.2
|
||||
jdkBuild=u212b1586.4
|
||||
gradleApiVersion=5.2.1
|
||||
|
||||
+6
-1
@@ -19,7 +19,12 @@
|
||||
</and>
|
||||
</condition>
|
||||
<condition property="gradle.args" value="${intellij.gradle.jdk.build.parameters}" else="--stacktrace">
|
||||
<isset property="intellij.gradle.jdk.build.parameters"/>
|
||||
<and>
|
||||
<isset property="intellij.gradle.jdk.build.parameters"/>
|
||||
<not>
|
||||
<equals arg1="${intellij.gradle.jdk.build.parameters}" arg2=""/>
|
||||
</not>
|
||||
</and>
|
||||
</condition>
|
||||
<condition property="gradlew" value="gradlew.bat" else="gradlew">
|
||||
<os family="windows"/>
|
||||
|
||||
+7
-3
@@ -55,8 +55,8 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
private LanguageLevel myLanguageLevel;
|
||||
private JavaSdkVersion myJavaSdkVersion;
|
||||
|
||||
@SuppressWarnings("StatefulEp") private PsiFile myFile;
|
||||
@SuppressWarnings("StatefulEp") private PsiJavaModule myJavaModule;
|
||||
private PsiFile myFile;
|
||||
private PsiJavaModule myJavaModule;
|
||||
|
||||
// map codeBlock->List of PsiReferenceExpression of uninitialized final variables
|
||||
private final Map<PsiElement, Collection<PsiReferenceExpression>> myUninitializedVarProblems = new THashMap<>();
|
||||
@@ -814,8 +814,12 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
public void visitLiteralExpression(PsiLiteralExpression expression) {
|
||||
super.visitLiteralExpression(expression);
|
||||
if (myHolder.hasErrorResults()) return;
|
||||
|
||||
myHolder.add(HighlightUtil.checkLiteralExpressionParsingError(expression, myLanguageLevel,myFile));
|
||||
if (myRefCountHolder != null && !myHolder.hasErrorResults()) registerReferencesFromInjectedFragments(expression);
|
||||
|
||||
if (myRefCountHolder != null && !myHolder.hasErrorResults()) {
|
||||
registerReferencesFromInjectedFragments(expression);
|
||||
}
|
||||
|
||||
if (myRefCountHolder != null && !myHolder.hasErrorResults()) {
|
||||
for (PsiReference reference : expression.getReferences()) {
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@ class JavaPredefinedConfigurations {
|
||||
// Class based
|
||||
createSearchTemplateInfo(
|
||||
SSRBundle.message("predefined.configuration.methods.of.the.class"),
|
||||
"'_ReturnType '_Method('_ParameterType '_Parameter*);",
|
||||
"'_ReturnType? '_Method('_ParameterType '_Parameter*);",
|
||||
CLASS_TYPE
|
||||
),
|
||||
createSearchTemplateInfo(
|
||||
|
||||
+4
-4
@@ -288,7 +288,7 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile {
|
||||
@NotNull PatternTreeContext context,
|
||||
@NotNull LanguageFileType fileType,
|
||||
@NotNull Language language,
|
||||
String contextName,
|
||||
String contextId,
|
||||
@NotNull Project project,
|
||||
boolean physical) {
|
||||
if (physical) {
|
||||
@@ -311,7 +311,7 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile {
|
||||
if (shouldTryExpressionPattern(result)) {
|
||||
try {
|
||||
final PsiElement[] expressionPattern =
|
||||
createPatternTree(text, PatternTreeContext.Expression, fileType, language, contextName, project, false);
|
||||
createPatternTree(text, PatternTreeContext.Expression, fileType, language, contextId, project, false);
|
||||
if (expressionPattern.length == 1) {
|
||||
return expressionPattern;
|
||||
}
|
||||
@@ -319,7 +319,7 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile {
|
||||
}
|
||||
else if (shouldTryClassPattern(result)) {
|
||||
final PsiElement[] classPattern =
|
||||
createPatternTree(text, PatternTreeContext.Class, fileType, language, contextName, project, false);
|
||||
createPatternTree(text, PatternTreeContext.Class, fileType, language, contextId, project, false);
|
||||
if (classPattern.length <= result.size()) {
|
||||
return classPattern;
|
||||
}
|
||||
@@ -416,7 +416,7 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiCodeFragment createCodeFragment(Project project, String text) {
|
||||
public PsiCodeFragment createCodeFragment(Project project, String text, String contextId) {
|
||||
return JavaCodeFragmentFactory.getInstance(project).createCodeBlockCodeFragment(text, null, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
import {Item} from "@/state/data"
|
||||
import {ChartManager} from "./ChartManager"
|
||||
|
||||
export interface ActivityChartDescriptor {
|
||||
readonly label: string
|
||||
readonly id: string
|
||||
|
||||
readonly isInfoChart?: boolean
|
||||
|
||||
readonly sourceNames?: Array<string>
|
||||
|
||||
readonly rotatedLabels?: boolean
|
||||
readonly groupByThread?: boolean
|
||||
readonly sourceHasPluginInformation?: boolean
|
||||
|
||||
readonly chartManagerProducer?: (container: HTMLElement, sourceNames: Array<string>, descriptor: ActivityChartDescriptor) => Promise<ChartManager>
|
||||
readonly shortNameProducer?: (item: Item) => string
|
||||
}
|
||||
|
||||
@@ -27,6 +31,7 @@ export const chartDescriptors: Array<ActivityChartDescriptor> = [
|
||||
id: "components",
|
||||
sourceNames: ["appComponents", "projectComponents", "moduleComponents"],
|
||||
shortNameProducer: getShortName,
|
||||
chartManagerProducer: async (container, sourceNames, descriptor) => new (await import(/* webpackMode: "eager" */ "./ComponentChartManager")).ComponentChartManager(container, sourceNames!!, descriptor)
|
||||
},
|
||||
{
|
||||
label: "Services",
|
||||
@@ -67,4 +72,18 @@ export const chartDescriptors: Array<ActivityChartDescriptor> = [
|
||||
id: "GCs",
|
||||
rotatedLabels: false,
|
||||
},
|
||||
{
|
||||
label: "Time Distribution",
|
||||
isInfoChart: true,
|
||||
id: "timeDistribution",
|
||||
sourceNames: [],
|
||||
chartManagerProducer: async (container, _sourceNames, _descriptor) => new (await import(/* webpackMode: "eager" */ "./TreeMapChartManager")).TreeMapChartManager(container),
|
||||
},
|
||||
{
|
||||
label: "Plugin Classes",
|
||||
isInfoChart: true,
|
||||
id: "pluginClassCount",
|
||||
sourceNames: [],
|
||||
chartManagerProducer: async (container, _sourceNames, _descriptor) => new (await import(/* webpackMode: "eager" */ "./PluginClassCountTreeMapChartManager")).PluginClassCountTreeMapChartManager(container),
|
||||
},
|
||||
]
|
||||
|
||||
@@ -113,11 +113,7 @@ export class ActivityChartManager extends XYChartManager {
|
||||
|
||||
let getItemListBySourceName: (name: string) => Array<Item> | null | undefined = name => {
|
||||
// @ts-ignore
|
||||
const result: Array<Item> | null = data.data[name]
|
||||
if (result != null) {
|
||||
return result.filter(it => it.duration >= 10)
|
||||
}
|
||||
return result
|
||||
return data.data[name]
|
||||
}
|
||||
|
||||
let sourceNameToLegendName: (sourceName: string, itemCount: number) => string = this.sourceNameToLegendName.bind(this)
|
||||
|
||||
@@ -3,6 +3,7 @@ import {Component, Vue, Watch} from "vue-property-decorator"
|
||||
import {AppState, mainModuleName} from "@/state/StateStorageManager"
|
||||
import {DataManager} from "@/state/DataManager"
|
||||
import {ChartManager} from "@/charts/ChartManager"
|
||||
import {Notification} from "element-ui"
|
||||
|
||||
// @ts-ignore
|
||||
@Component
|
||||
@@ -18,7 +19,7 @@ export abstract class BaseChartComponent<T extends ChartManager> extends Vue {
|
||||
this.renderDataIfAvailable()
|
||||
}
|
||||
|
||||
protected abstract createChartManager(): T
|
||||
protected abstract createChartManager(): Promise<T>
|
||||
|
||||
@Watch("measurementData")
|
||||
/** @final */
|
||||
@@ -31,10 +32,19 @@ export abstract class BaseChartComponent<T extends ChartManager> extends Vue {
|
||||
|
||||
let chartManager = this.chartManager
|
||||
if (chartManager == null) {
|
||||
chartManager = this.createChartManager()
|
||||
this.chartManager = chartManager
|
||||
this.createChartManager()
|
||||
.then(chartManager => {
|
||||
this.chartManager = chartManager
|
||||
chartManager.render(data)
|
||||
})
|
||||
.catch(e => {
|
||||
console.log(e)
|
||||
Notification.error(e)
|
||||
})
|
||||
}
|
||||
else {
|
||||
chartManager.render(data)
|
||||
}
|
||||
chartManager.render(data)
|
||||
}
|
||||
|
||||
beforeDestroy() {
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
import {BaseChartManager, configureCursor} from "@/charts/ChartManager"
|
||||
import * as am4charts from "@amcharts/amcharts4/charts"
|
||||
import * as am4core from "@amcharts/amcharts4/core"
|
||||
|
||||
export abstract class BaseTreeMapChartManager extends BaseChartManager<am4charts.TreeMap> {
|
||||
protected constructor(container: HTMLElement) {
|
||||
super(am4core.create(container, am4charts.TreeMap))
|
||||
|
||||
configureCursor(this.chart)
|
||||
|
||||
// cursor tooltip is distracting (cannot be in BaseChartManager because only TreeMap creates axis as part of chart creation, for other charts axis is created customly)
|
||||
this.chart.xAxis.cursorTooltipEnabled = false
|
||||
this.chart.yAxis.cursorTooltipEnabled = false
|
||||
}
|
||||
|
||||
protected enableZoom() {
|
||||
const chart = this.chart
|
||||
chart.mouseWheelBehavior = "zoomX"
|
||||
chart.scrollbarX = new am4core.Scrollbar()
|
||||
chart.mouseWheelBehavior = "zoomXY"
|
||||
}
|
||||
|
||||
protected configureLabelBullet(bullet: am4charts.LabelBullet) {
|
||||
bullet.locationY = 0.5
|
||||
bullet.locationX = 0.5
|
||||
bullet.label.fill = am4core.color("#fff")
|
||||
}
|
||||
}
|
||||
@@ -9,10 +9,14 @@ export interface ChartManager {
|
||||
dispose(): void
|
||||
}
|
||||
|
||||
function configureCommonChartSettings(chart: am4charts.XYChart) {
|
||||
export function configureCommonChartSettings(chart: am4charts.XYChart) {
|
||||
chart.mouseWheelBehavior = "zoomX"
|
||||
chart.scrollbarX = new am4core.Scrollbar()
|
||||
|
||||
configureCursor(chart)
|
||||
}
|
||||
|
||||
export function configureCursor(chart: am4charts.XYChart) {
|
||||
const cursor = new am4charts.XYCursor()
|
||||
cursor.lineY.disabled = true
|
||||
cursor.lineX.disabled = true
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
import * as am4charts from "@amcharts/amcharts4/charts"
|
||||
import {DataManager} from "@/state/DataManager"
|
||||
import {BaseTreeMapChartManager} from "@/charts/BaseTreeMapChartManager"
|
||||
|
||||
export class PluginClassCountTreeMapChartManager extends BaseTreeMapChartManager {
|
||||
constructor(container: HTMLElement) {
|
||||
super(container)
|
||||
|
||||
const chart = this.chart
|
||||
chart.dataFields.value = "count"
|
||||
chart.dataFields.name = "name"
|
||||
|
||||
this.enableZoom()
|
||||
|
||||
const level1 = chart.seriesTemplates.create("0")
|
||||
const level1Bullet = level1.bullets.push(new am4charts.LabelBullet())
|
||||
this.configureLabelBullet(level1Bullet)
|
||||
level1Bullet.label.text = "{abbreviatedName} ({count})"
|
||||
}
|
||||
|
||||
render(data: DataManager): void {
|
||||
const items: Array<any> = []
|
||||
|
||||
const loadedClasses = data.data.stats.loadedClasses
|
||||
if (loadedClasses != null) {
|
||||
for (const name of Object.keys(loadedClasses)) {
|
||||
items.push({
|
||||
name,
|
||||
abbreviatedName: getAbbreviatedName(name),
|
||||
count: loadedClasses[name],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
this.chart.data = items
|
||||
}
|
||||
}
|
||||
|
||||
function getAbbreviatedName(name: string): string {
|
||||
if (!name.includes(".")) {
|
||||
return name
|
||||
}
|
||||
|
||||
let abbreviatedName = ""
|
||||
const names = name.split(".")
|
||||
for (let i = 0; i < names.length; i++) {
|
||||
const unqualifiedName = names[i]
|
||||
if (i == (names.length - 1)) {
|
||||
abbreviatedName += unqualifiedName
|
||||
} else {
|
||||
abbreviatedName += unqualifiedName.substring(0, 1) + "."
|
||||
}
|
||||
}
|
||||
return abbreviatedName
|
||||
}
|
||||
@@ -1,14 +1,15 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
import {BaseChartManager} from "@/charts/ChartManager"
|
||||
import * as am4charts from "@amcharts/amcharts4/charts"
|
||||
import * as am4core from "@amcharts/amcharts4/core"
|
||||
import {DataManager} from "@/state/DataManager"
|
||||
import {IconData, Item} from "@/state/data"
|
||||
import {getShortName} from "@/charts/ActivityChartDescriptor"
|
||||
import {BaseTreeMapChartManager} from "@/charts/BaseTreeMapChartManager"
|
||||
|
||||
export class TreeMapChartManager extends BaseChartManager<am4charts.TreeMap> {
|
||||
export class TreeMapChartManager extends BaseTreeMapChartManager {
|
||||
constructor(container: HTMLElement) {
|
||||
super(am4core.create(container, am4charts.TreeMap))
|
||||
super(container)
|
||||
|
||||
// enableZoom is not called because for this chart it doesn't work correctly and not really required
|
||||
|
||||
const chart = this.chart
|
||||
chart.dataFields.value = "duration"
|
||||
@@ -35,12 +36,6 @@ export class TreeMapChartManager extends BaseChartManager<am4charts.TreeMap> {
|
||||
chart.seriesTemplates.create("3").bullets.push(level2Bullet)
|
||||
}
|
||||
|
||||
private configureLabelBullet(bullet: am4charts.LabelBullet) {
|
||||
bullet.locationY = 0.5
|
||||
bullet.locationX = 0.5
|
||||
bullet.label.fill = am4core.color("#fff")
|
||||
}
|
||||
|
||||
render(data: DataManager): void {
|
||||
const items: Array<any> = []
|
||||
|
||||
@@ -114,10 +109,6 @@ export class TreeMapChartManager extends BaseChartManager<am4charts.TreeMap> {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.chart.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
function toTreeMapItem(items: Array<Item> | null | undefined) {
|
||||
|
||||
@@ -3,9 +3,7 @@ import Vue from "vue"
|
||||
import Router, {RouteConfig} from "vue-router"
|
||||
import {Notification} from "element-ui"
|
||||
import Main from "@/views/Main.vue"
|
||||
import ItemChart from "@/charts/ActivityChart.vue"
|
||||
import {chartDescriptors} from "@/charts/ActivityChartDescriptor"
|
||||
import TimelineChart from "@/timeline/TimelineChart.vue"
|
||||
|
||||
Vue.use(Router)
|
||||
|
||||
@@ -14,7 +12,7 @@ const chartComponentRoutes: Array<RouteConfig> = chartDescriptors.map(it => {
|
||||
return {
|
||||
path: `/${it.id}`,
|
||||
name: it.label,
|
||||
component: ItemChart,
|
||||
component: () => import(/* webpackMode: "eager" */ "@/views/ActivityChart.vue"),
|
||||
props: {type: it.id},
|
||||
}
|
||||
})
|
||||
@@ -27,7 +25,7 @@ const routes: Array<RouteConfig> = [
|
||||
{
|
||||
path: `/timeline`,
|
||||
name: "Timeline",
|
||||
component: TimelineChart,
|
||||
component: () => import(/* webpackMode: "eager" */ "@/timeline/TimelineChart.vue"),
|
||||
},
|
||||
{
|
||||
path: "*",
|
||||
|
||||
@@ -49,6 +49,8 @@ export interface Stats {
|
||||
|
||||
readonly component: StatItem
|
||||
readonly service: StatItem
|
||||
|
||||
readonly loadedClasses: { [key: string]: number; }
|
||||
}
|
||||
|
||||
export interface StatItem {
|
||||
|
||||
@@ -7,10 +7,11 @@
|
||||
import {Component} from "vue-property-decorator"
|
||||
import {TimelineChartManager} from "./TimeLineChartManager"
|
||||
import {BaseChartComponent} from "@/charts/BaseChartComponent"
|
||||
import {ChartManager} from "@/charts/ChartManager"
|
||||
|
||||
@Component
|
||||
export default class TimelineChart extends BaseChartComponent<TimelineChartManager> {
|
||||
createChartManager(): TimelineChartManager {
|
||||
export default class TimelineChart extends BaseChartComponent<ChartManager> {
|
||||
async createChartManager() {
|
||||
return new TimelineChartManager(this.$refs.chartContainer as HTMLElement)
|
||||
}
|
||||
}
|
||||
|
||||
+10
-8
@@ -5,11 +5,10 @@
|
||||
|
||||
<script lang="ts">
|
||||
import {Component, Prop, Watch} from "vue-property-decorator"
|
||||
import {ActivityChartManager} from "./ActivityChartManager"
|
||||
import {chartDescriptors} from "@/charts/ActivityChartDescriptor"
|
||||
import {BaseChartComponent} from "@/charts/BaseChartComponent"
|
||||
import {ComponentChartManager} from "@/charts/ComponentChartManager"
|
||||
import {ChartManager} from "@/charts/ChartManager"
|
||||
import {Notification} from "element-ui"
|
||||
|
||||
@Component
|
||||
export default class ActivityChart extends BaseChartComponent<ChartManager> {
|
||||
@@ -24,25 +23,28 @@
|
||||
this.chartManager = null
|
||||
}
|
||||
|
||||
this.chartManager = this.createChartManager()
|
||||
this.renderDataIfAvailable()
|
||||
}
|
||||
|
||||
/** @override */
|
||||
protected createChartManager(): ChartManager {
|
||||
protected async createChartManager(): Promise<ChartManager> {
|
||||
const chartContainer = this.$refs.chartContainer as HTMLElement
|
||||
const type = this.type
|
||||
const descriptor = chartDescriptors.find(it => it.id === type)
|
||||
if (descriptor == null) {
|
||||
throw new Error(`Unknown chart type: ${type}`)
|
||||
const message = `Unknown chart type: ${type}`
|
||||
Notification.error(message)
|
||||
throw new Error(message)
|
||||
}
|
||||
|
||||
const sourceNames = descriptor.sourceNames
|
||||
if (type === "components") {
|
||||
return new ComponentChartManager(chartContainer, sourceNames!!, descriptor)
|
||||
if (descriptor.chartManagerProducer != null) {
|
||||
// noinspection ES6RedundantAwait
|
||||
return await descriptor.chartManagerProducer(chartContainer, sourceNames!!, descriptor)
|
||||
}
|
||||
else {
|
||||
return new ActivityChartManager(chartContainer, sourceNames == null ? [type] : sourceNames, descriptor)
|
||||
// noinspection ES6RedundantAwait
|
||||
return new (await import(/* webpackMode: "eager" */ "@/charts/ActivityChartManager")).ActivityChartManager(chartContainer, sourceNames == null ? [type] : sourceNames, descriptor)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
@Component
|
||||
export default class StatsChart extends BaseChartComponent<StatsChartManager> {
|
||||
createChartManager(): StatsChartManager {
|
||||
async createChartManager() {
|
||||
return new StatsChartManager(this.$refs.chartContainer as HTMLElement)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
|
||||
<script lang="ts">
|
||||
import {Component, Vue, Watch} from "vue-property-decorator"
|
||||
import ActivityChart from "@/charts/ActivityChart.vue"
|
||||
import ActivityChart from "@/views/ActivityChart.vue"
|
||||
import {Location} from "vue-router"
|
||||
import {chartDescriptors} from "@/charts/ActivityChartDescriptor"
|
||||
|
||||
@Component({components: {ActivityChart}})
|
||||
export default class TabbedCharts extends Vue {
|
||||
charts = chartDescriptors
|
||||
charts = chartDescriptors.filter(it => it.isInfoChart !== true)
|
||||
|
||||
activeName: string = chartDescriptors[0].id
|
||||
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
<TimelineChart/>
|
||||
</keep-alive>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="Time Distribution" name="treeMap" lazy>
|
||||
<!-- use v-once because `charts` is not going to be changed -->
|
||||
<el-tab-pane v-once v-for="item in charts" :key="item.name" :label="item.label" :name="item.id" lazy>
|
||||
<keep-alive>
|
||||
<TreeMapChart/>
|
||||
<ActivityChart :type="item.id"/>
|
||||
</keep-alive>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="Stats" name="stats" lazy>
|
||||
@@ -24,14 +25,17 @@
|
||||
import {Location} from "vue-router"
|
||||
import TimelineChart from "@/timeline/TimelineChart.vue"
|
||||
import StatsChart from "@/views/StatsChart.vue"
|
||||
import TreeMapChart from "@/views/TreeMapChart.vue"
|
||||
import ActivityChart from "@/views/ActivityChart.vue"
|
||||
import {chartDescriptors} from "@/charts/ActivityChartDescriptor"
|
||||
|
||||
const DEFAULT_ACTIVE_TAB = "timeline"
|
||||
|
||||
@Component({components: {TimelineChart, TreeMapChart, StatsChart}})
|
||||
@Component({components: {TimelineChart, ActivityChart, StatsChart}})
|
||||
export default class TabbedInfoCharts extends Vue {
|
||||
activeName: string = DEFAULT_ACTIVE_TAB
|
||||
|
||||
charts = chartDescriptors.filter(it => it.isInfoChart === true)
|
||||
|
||||
created() {
|
||||
this.updateLocation(this.$route)
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
<!-- Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
||||
<template>
|
||||
<!-- <el-row>-->
|
||||
<!-- <el-col>-->
|
||||
<!-- <small>-->
|
||||
<!-- Component-->
|
||||
<!-- </small>-->
|
||||
<!-- </el-col>-->
|
||||
<!-- </el-row>-->
|
||||
<div class="activityChart" ref="chartContainer"></div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {Component} from "vue-property-decorator"
|
||||
import {BaseChartComponent} from "@/charts/BaseChartComponent"
|
||||
import {TreeMapChartManager} from "@/charts/TreeMapChartManager"
|
||||
|
||||
@Component
|
||||
export default class TreeMapChart extends BaseChartComponent<TreeMapChartManager> {
|
||||
createChartManager(): TreeMapChartManager {
|
||||
return new TreeMapChartManager(this.$refs.chartContainer as HTMLElement)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -2262,9 +2262,9 @@ ejs@^2.6.1:
|
||||
integrity sha512-0xy4A/twfrRCnkhfk8ErDi5DqdAsAqeGxht4xkCUrsvhhbQNs7E+4jV0CN7+NKIY0aHE72+XvqtBIXzD31ZbXQ==
|
||||
|
||||
electron-to-chromium@^1.3.150:
|
||||
version "1.3.152"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.152.tgz#8f1c08e101d58fe2ef72655481bbf8c83f9450fa"
|
||||
integrity sha512-Ah10cGMWIXYD8aUTH2Y7lGRhaOFQLyWuxvXmCPCZCbUIGJ4swnNmT6P4aA8RTgUmNw9kmcDL6SoU8TZC4YuZGg==
|
||||
version "1.3.154"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.154.tgz#e5b73beecd4db9f024d807ba1faad93fe1fb98aa"
|
||||
integrity sha512-r3jVJRWvQIKDdjAbtmvJ7NihBFNUpU4VJKsslAzruv9dnYde3v8U2T7J62Vap3c6l6Ku4J56kxlciIO/E93cQg==
|
||||
|
||||
element-ui@^2.9.1:
|
||||
version "2.9.1"
|
||||
@@ -4908,25 +4908,24 @@ pbkdf2@^3.0.3:
|
||||
safe-buffer "^5.0.1"
|
||||
sha.js "^2.4.8"
|
||||
|
||||
pdfkit@^0.9.1:
|
||||
version "0.9.1"
|
||||
resolved "https://registry.yarnpkg.com/pdfkit/-/pdfkit-0.9.1.tgz#f07a66eebc64855f8345dccfd313f2d8f880f10f"
|
||||
integrity sha512-45X/NjaynHVNd/866ETK9KmblL8Sqwmah1RPz04IzmZoEO+cvPid2UvkVfZQcS4Jeq/uWY+99qAq04NoigzWSA==
|
||||
pdfkit@^0.10.0:
|
||||
version "0.10.0"
|
||||
resolved "https://registry.yarnpkg.com/pdfkit/-/pdfkit-0.10.0.tgz#88f2aa8e3cf9e1cc2caff6447b68dd4e435cb284"
|
||||
integrity sha512-mRJ6iuDzpIQ4ftKp5GvijLXNVRK86xjnyIPBraYSPrUPubNqWM5/oYmc7FZKUWz3wusRTj3PLR9HJ1X5ooqfsg==
|
||||
dependencies:
|
||||
crypto-js "^3.1.9-1"
|
||||
fontkit "^1.0.0"
|
||||
linebreak "^0.3.0"
|
||||
png-js ">=0.1.0"
|
||||
saslprep "1.0.1"
|
||||
|
||||
pdfmake@^0.1.36:
|
||||
version "0.1.56"
|
||||
resolved "https://registry.yarnpkg.com/pdfmake/-/pdfmake-0.1.56.tgz#a4fcabe25fa5f04c07cb6e861c0abbf9ca5b33e9"
|
||||
integrity sha512-c5fSj16VTQCrmTw02Mc+Oj3boRG+PGJuu7cGXAXXljI3bMNDifwmUs+3opEwRZbTWu9WhFKYbrs2Iq136UN/NQ==
|
||||
version "0.1.57"
|
||||
resolved "https://registry.yarnpkg.com/pdfmake/-/pdfmake-0.1.57.tgz#408e9853777fb851eeb700aaa221905e135917a0"
|
||||
integrity sha512-s6Bs71Ylh06yNgJfP61xicHZSEvFrwo8lvI/BOU4+6eDddO8lwOZi5A42RA0V8zQr6hrI1XYxtLkk/7oJ+5w+w==
|
||||
dependencies:
|
||||
iconv-lite "^0.4.24"
|
||||
linebreak "^0.3.0"
|
||||
pdfkit "^0.9.1"
|
||||
pdfkit "^0.10.0"
|
||||
|
||||
performance-now@^2.1.0:
|
||||
version "2.1.0"
|
||||
@@ -5840,11 +5839,6 @@ safe-regex@^1.1.0:
|
||||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||
|
||||
saslprep@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/saslprep/-/saslprep-1.0.1.tgz#b644e0ba25b156b652f3cb90df7542f896049ba6"
|
||||
integrity sha512-ntN6SbE3hRqd45PKKadRPgA+xHPWg5lPSj2JWJdJvjTwXDDfkPVtXWvP8jJojvnm+rAsZ2b299C5NwZqq818EA==
|
||||
|
||||
sax@^1.1.4, sax@^1.2.4, sax@~1.2.4:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
||||
|
||||
@@ -57,7 +57,7 @@ open class FileBasedStorage(file: Path,
|
||||
|
||||
protected open val isUseXmlProlog = false
|
||||
|
||||
final override val isUseVfsForWrite: Boolean
|
||||
override val isUseVfsForWrite: Boolean
|
||||
get() = configuration.isUseVfsForWrite
|
||||
|
||||
private val isUseUnixLineSeparator: Boolean
|
||||
|
||||
@@ -4,12 +4,14 @@ package com.intellij.configurationStore
|
||||
import com.intellij.ide.highlighter.ProjectFileType
|
||||
import com.intellij.ide.highlighter.WorkspaceFileType
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.PathManager
|
||||
import com.intellij.openapi.application.appSystemDir
|
||||
import com.intellij.openapi.components.*
|
||||
import com.intellij.openapi.components.impl.stores.IProjectStore
|
||||
import com.intellij.openapi.diagnostic.runAndLogException
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.ProjectCoreUtil
|
||||
import com.intellij.openapi.project.getProjectCachePath
|
||||
import com.intellij.openapi.project.getProjectCacheFileName
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.util.io.FileUtilRt
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
@@ -144,7 +146,9 @@ abstract class ProjectStoreBase(final override val project: Project) : Component
|
||||
}
|
||||
}
|
||||
|
||||
storageManager.addMacro(StoragePathMacros.CACHE_FILE, project.getProjectCachePath(cacheDirName = "workspace", extensionWithDot = ".xml").systemIndependentPath)
|
||||
val cacheFileName = project.getProjectCacheFileName(extensionWithDot = ".xml")
|
||||
storageManager.addMacro(StoragePathMacros.CACHE_FILE, appSystemDir.resolve("workspace").resolve(cacheFileName).systemIndependentPath)
|
||||
storageManager.addMacro(StoragePathMacros.PRODUCT_WORKSPACE_FILE, "${FileUtil.toSystemIndependentName(PathManager.getConfigPath())}/workspace/$cacheFileName")
|
||||
}
|
||||
|
||||
override fun <T> getStorageSpecs(component: PersistentStateComponent<T>, stateSpec: State, operation: StateStorageOperation): List<Storage> {
|
||||
@@ -180,7 +184,7 @@ abstract class ProjectStoreBase(final override val project: Project) : Component
|
||||
|
||||
// if we create project from default, component state written not to own storage file, but to project file,
|
||||
// we don't have time to fix it properly, so, ancient hack restored
|
||||
if (result.first().path != StoragePathMacros.CACHE_FILE) {
|
||||
if (!isSpecialStorage(result.first())) {
|
||||
result.add(DEPRECATED_PROJECT_FILE_STORAGE_ANNOTATION)
|
||||
}
|
||||
return result
|
||||
@@ -192,7 +196,7 @@ abstract class ProjectStoreBase(final override val project: Project) : Component
|
||||
var hasOnlyDeprecatedStorages = true
|
||||
for (storage in storages) {
|
||||
@Suppress("DEPRECATION")
|
||||
if (storage.path == PROJECT_FILE || storage.path == StoragePathMacros.WORKSPACE_FILE || storage.path == StoragePathMacros.CACHE_FILE) {
|
||||
if (storage.path == PROJECT_FILE || storage.path == StoragePathMacros.WORKSPACE_FILE || isSpecialStorage(storage)) {
|
||||
if (result == null) {
|
||||
result = SmartList()
|
||||
}
|
||||
@@ -243,4 +247,10 @@ abstract class ProjectStoreBase(final override val project: Project) : Component
|
||||
}
|
||||
}
|
||||
|
||||
private fun composeFileBasedProjectWorkSpacePath(filePath: String) = "${FileUtilRt.getNameWithoutExtension(filePath)}${WorkspaceFileType.DOT_DEFAULT_EXTENSION}"
|
||||
private fun composeFileBasedProjectWorkSpacePath(filePath: String) = "${FileUtilRt.getNameWithoutExtension(filePath)}${WorkspaceFileType.DOT_DEFAULT_EXTENSION}"
|
||||
|
||||
private fun isSpecialStorage(storage: Storage) = isSpecialStorage(storage.path)
|
||||
|
||||
internal fun isSpecialStorage(collapsedPath: String): Boolean {
|
||||
return collapsedPath == StoragePathMacros.CACHE_FILE || collapsedPath == StoragePathMacros.PRODUCT_WORKSPACE_FILE
|
||||
}
|
||||
@@ -305,7 +305,10 @@ open class StateStorageManagerImpl(private val rootTagName: String,
|
||||
roamingType,
|
||||
provider), StorageVirtualFileTracker.TrackedStorage {
|
||||
override val isUseXmlProlog: Boolean
|
||||
get() = rootElementName != null && storageManager.isUseXmlProlog
|
||||
get() = rootElementName != null && storageManager.isUseXmlProlog && !isSpecialStorage(fileSpec)
|
||||
|
||||
override val isUseVfsForWrite: Boolean
|
||||
get() = super.isUseVfsForWrite && !isSpecialStorage(fileSpec)
|
||||
|
||||
override val configuration: FileBasedStorageConfiguration
|
||||
get() = storageManager
|
||||
@@ -450,7 +453,7 @@ internal val Storage.path: String
|
||||
get() = if (value.isEmpty()) file else value
|
||||
|
||||
internal fun getEffectiveRoamingType(roamingType: RoamingType, collapsedPath: String): RoamingType {
|
||||
if (roamingType != RoamingType.DISABLED && (collapsedPath == StoragePathMacros.WORKSPACE_FILE || collapsedPath == StoragePathMacros.NON_ROAMABLE_FILE || collapsedPath == StoragePathMacros.CACHE_FILE)) {
|
||||
if (roamingType != RoamingType.DISABLED && (collapsedPath == StoragePathMacros.WORKSPACE_FILE || collapsedPath == StoragePathMacros.NON_ROAMABLE_FILE || isSpecialStorage(collapsedPath))) {
|
||||
return RoamingType.DISABLED
|
||||
}
|
||||
else {
|
||||
|
||||
+39
-15
@@ -6,17 +6,19 @@ import com.intellij.internal.statistic.eventLog.EventLogGroup
|
||||
import com.intellij.internal.statistic.eventLog.fus.FeatureUsageLogger
|
||||
import com.intellij.internal.statistic.utils.getPluginInfo
|
||||
import com.intellij.internal.statistic.utils.getProjectId
|
||||
import com.intellij.openapi.components.ReportValue
|
||||
import com.intellij.openapi.components.State
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.util.concurrency.NonUrgentExecutor
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import com.intellij.serialization.MutableAccessor
|
||||
import com.intellij.util.xmlb.BeanBinding
|
||||
import org.jdom.Element
|
||||
import java.util.*
|
||||
|
||||
private val LOG = Logger.getInstance("com.intellij.configurationStore.statistic.eventLog.FeatureUsageSettingsEventPrinter")
|
||||
private val GROUP = EventLogGroup("settings", 3)
|
||||
private val GROUP = EventLogGroup("settings", 4)
|
||||
|
||||
private val recordedComponents: MutableSet<String> = ContainerUtil.newConcurrentSet()
|
||||
private val recordedOptionNames: MutableSet<String> = ContainerUtil.newConcurrentSet()
|
||||
@@ -91,20 +93,15 @@ open class FeatureUsageSettingsEventPrinter(private val recordDefault: Boolean)
|
||||
for (accessor in accessors) {
|
||||
val type = accessor.genericType
|
||||
if (type === Boolean::class.javaPrimitiveType) {
|
||||
val value = accessor.readUnsafe(state)
|
||||
val isDefault = !jdomSerializer.getDefaultSerializationFilter().accepts(accessor, state)
|
||||
if (!isDefault || recordDefault) {
|
||||
recordedOptionNames.add(accessor.name)
|
||||
val content = HashMap<String, Any>()
|
||||
content["component"] = componentName
|
||||
content["name"] = accessor.name
|
||||
content["value"] = value
|
||||
if (recordDefault) {
|
||||
content["default"] = isDefault
|
||||
}
|
||||
addProjectOptions(content, isDefaultProject, hash)
|
||||
logConfig(GROUP, eventId, content)
|
||||
}
|
||||
logConfigValue(accessor, state, "bool", eventId, isDefaultProject, true, hash, componentName)
|
||||
}
|
||||
else if (type === Int::class.javaPrimitiveType || type === Long::class.javaPrimitiveType) {
|
||||
val reportValue = accessor.getAnnotation(ReportValue::class.java) != null
|
||||
logConfigValue(accessor, state, "int", eventId, isDefaultProject, reportValue, hash, componentName)
|
||||
}
|
||||
else if (type === Float::class.javaPrimitiveType || type === Double::class.javaPrimitiveType) {
|
||||
val reportValue = accessor.getAnnotation(ReportValue::class.java) != null
|
||||
logConfigValue(accessor, state, "float", eventId, isDefaultProject, reportValue, hash, componentName)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,6 +110,33 @@ open class FeatureUsageSettingsEventPrinter(private val recordDefault: Boolean)
|
||||
}
|
||||
}
|
||||
|
||||
private fun logConfigValue(accessor: MutableAccessor,
|
||||
state: Any,
|
||||
type: String,
|
||||
eventId: String,
|
||||
isDefaultProject: Boolean,
|
||||
reportValue: Boolean,
|
||||
hash: String?,
|
||||
componentName: String) {
|
||||
val value = accessor.readUnsafe(state)
|
||||
val isDefault = !jdomSerializer.getDefaultSerializationFilter().accepts(accessor, state)
|
||||
if (!isDefault || recordDefault) {
|
||||
recordedOptionNames.add(accessor.name)
|
||||
val content = HashMap<String, Any>()
|
||||
content["type"] = type
|
||||
content["component"] = componentName
|
||||
content["name"] = accessor.name
|
||||
if (reportValue) {
|
||||
content["value"] = value
|
||||
}
|
||||
if (recordDefault) {
|
||||
content["default"] = isDefault
|
||||
}
|
||||
addProjectOptions(content, isDefaultProject, hash)
|
||||
logConfig(GROUP, eventId, content)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addProjectOptions(content: HashMap<String, Any>,
|
||||
isDefaultProject: Boolean,
|
||||
projectHash: String?) {
|
||||
|
||||
+136
-17
@@ -5,11 +5,13 @@ import com.intellij.configurationStore.getStateSpec
|
||||
import com.intellij.configurationStore.statistic.eventLog.FeatureUsageSettingsEventPrinter
|
||||
import com.intellij.internal.statistic.eventLog.EventLogGroup
|
||||
import com.intellij.openapi.components.PersistentStateComponent
|
||||
import com.intellij.openapi.components.ReportValue
|
||||
import com.intellij.openapi.components.State
|
||||
import com.intellij.openapi.project.ProjectManager
|
||||
import com.intellij.testFramework.ProjectRule
|
||||
import com.intellij.testFramework.assertions.Assertions.assertThat
|
||||
import com.intellij.util.xmlb.annotations.Attribute
|
||||
import org.junit.Assert
|
||||
import org.junit.ClassRule
|
||||
import org.junit.Test
|
||||
|
||||
@@ -116,8 +118,8 @@ class FeatureUsageSettingsEventsTest {
|
||||
val withProject = true
|
||||
val defaultProject = false
|
||||
assertThat(printer.result).hasSize(2)
|
||||
assertDefaultState(printer.getOptionByName("boolOption"), "boolOption", false, withProject, defaultProject)
|
||||
assertDefaultState(printer.getOptionByName("secondBoolOption"), "secondBoolOption", true, withProject, defaultProject)
|
||||
assertDefaultState(printer.getOptionByName("boolOption"), "boolOption", false, "bool", withProject, defaultProject)
|
||||
assertDefaultState(printer.getOptionByName("secondBoolOption"), "secondBoolOption", true, "bool", withProject, defaultProject)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -174,7 +176,7 @@ class FeatureUsageSettingsEventsTest {
|
||||
val defaultProject = false
|
||||
assertThat(printer.result).hasSize(2)
|
||||
assertInvokedRecorded(printer.getInvokedEvent(), withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("boolOption"), "boolOption", true, withRecordDefault, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("boolOption"), "boolOption", true, "bool", withRecordDefault, withProject, defaultProject)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -200,7 +202,7 @@ class FeatureUsageSettingsEventsTest {
|
||||
val defaultProject = false
|
||||
assertThat(printer.result).hasSize(2)
|
||||
assertInvokedRecorded(printer.getInvokedEvent(), withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("boolOption"), "boolOption", true, withRecordDefault, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("boolOption"), "boolOption", true, "bool", withRecordDefault, withProject, defaultProject)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -215,8 +217,8 @@ class FeatureUsageSettingsEventsTest {
|
||||
val withProject = true
|
||||
val defaultProject = false
|
||||
assertThat(printer.result).hasSize(2)
|
||||
assertNotDefaultState(printer.getOptionByName("boolOption"), "boolOption", true, withRecordDefault, withProject, defaultProject)
|
||||
assertDefaultState(printer.getOptionByName("secondBoolOption"), "secondBoolOption", true, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("boolOption"), "boolOption", true, "bool", withRecordDefault, withProject, defaultProject)
|
||||
assertDefaultState(printer.getOptionByName("secondBoolOption"), "secondBoolOption", true, "bool", withProject, defaultProject)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -232,7 +234,7 @@ class FeatureUsageSettingsEventsTest {
|
||||
val defaultProject = false
|
||||
assertThat(printer.result).hasSize(2)
|
||||
assertInvokedRecorded(printer.getInvokedEvent(), withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("boolOption"), "boolOption", true, withRecordDefault, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("boolOption"), "boolOption", true, "bool", withRecordDefault, withProject, defaultProject)
|
||||
}
|
||||
|
||||
@Suppress("SameParameterValue")
|
||||
@@ -248,8 +250,8 @@ class FeatureUsageSettingsEventsTest {
|
||||
val withProject = true
|
||||
val defaultProject = false
|
||||
assertThat(printer.result).hasSize(2)
|
||||
assertNotDefaultState(printer.getOptionByName("boolOption"), "boolOption", true, withRecordDefault, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("secondBoolOption"), "secondBoolOption", false, withRecordDefault, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("boolOption"), "boolOption", true, "bool", withRecordDefault, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("secondBoolOption"), "secondBoolOption", false, "bool", withRecordDefault, withProject, defaultProject)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -265,8 +267,76 @@ class FeatureUsageSettingsEventsTest {
|
||||
val defaultProject = false
|
||||
assertThat(printer.result).hasSize(3)
|
||||
assertInvokedRecorded(printer.getInvokedEvent(), withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("boolOption"), "boolOption", true, withRecordDefault, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("secondBoolOption"), "secondBoolOption", false, withRecordDefault, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("boolOption"), "boolOption", true, "bool", withRecordDefault, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("secondBoolOption"), "secondBoolOption", false, "bool", withRecordDefault, withProject, defaultProject)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `record default numerical fields in application component`() {
|
||||
val component = TestComponent()
|
||||
component.loadState(ComponentStateWithNumerical())
|
||||
val spec = getStateSpec(component)
|
||||
val printer = TestFeatureUsageSettingsEventsPrinter(false)
|
||||
printer.logConfigurationState(spec.name, component.state, null)
|
||||
|
||||
val withProject = false
|
||||
val defaultProject = false
|
||||
Assert.assertEquals(1, printer.result.size)
|
||||
assertInvokedRecorded(printer.getInvokedEvent(), withProject, defaultProject)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `record not default numerical fields in application component`() {
|
||||
val component = TestComponent()
|
||||
component.loadState(ComponentStateWithNumerical(intOpt = 10, longOpt = 15, floatOpt = 5.5F, doubleOpt = 3.4))
|
||||
val spec = getStateSpec(component)
|
||||
val printer = TestFeatureUsageSettingsEventsPrinter(false)
|
||||
printer.logConfigurationState(spec.name, component.state, null)
|
||||
|
||||
val withProject = false
|
||||
val defaultProject = false
|
||||
Assert.assertEquals(5, printer.result.size)
|
||||
assertInvokedRecorded(printer.getInvokedEvent(), withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("integerOption"), "integerOption", null, "int", false, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("longOption"), "longOption", null, "int", false, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("floatOption"), "floatOption", null, "float", false, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("doubleOption"), "doubleOption", null, "float", false, withProject, defaultProject)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `record not default numerical fields with absolute value in application component`() {
|
||||
val component = TestComponent()
|
||||
component.loadState(ComponentStateWithNumerical(absIntOpt = 10, absLongOpt = 15, absFloatOpt = 5.5F, absDoubleOpt = 3.4))
|
||||
val spec = getStateSpec(component)
|
||||
val printer = TestFeatureUsageSettingsEventsPrinter(false)
|
||||
printer.logConfigurationState(spec.name, component.state, null)
|
||||
|
||||
val withProject = false
|
||||
val defaultProject = false
|
||||
Assert.assertEquals(5, printer.result.size)
|
||||
assertInvokedRecorded(printer.getInvokedEvent(), withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("absIntegerOption"), "absIntegerOption", 10, "int", false, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("absLongOption"), "absLongOption", 15L, "int", false, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("absFloatOption"), "absFloatOption", 5.5f, "float", false, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("absDoubleOption"), "absDoubleOption", 3.4, "float", false, withProject, defaultProject)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `record all not default numerical fields with absolute value in application component`() {
|
||||
val component = TestComponent()
|
||||
component.loadState(ComponentStateWithNumerical(absIntOpt = 10, absLongOpt = 15, absFloatOpt = 5.5F, absDoubleOpt = 3.4))
|
||||
val spec = getStateSpec(component)
|
||||
val printer = TestFeatureUsageSettingsEventsPrinter(false)
|
||||
printer.logConfigurationState(spec.name, component.state, null)
|
||||
|
||||
val withProject = false
|
||||
val defaultProject = false
|
||||
Assert.assertEquals(5, printer.result.size)
|
||||
assertInvokedRecorded(printer.getInvokedEvent(), withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("absIntegerOption"), "absIntegerOption", 10, "int", false, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("absLongOption"), "absLongOption", 15L, "int", false, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("absFloatOption"), "absFloatOption", 5.5f, "float", false, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("absDoubleOption"), "absDoubleOption", 3.4, "float", false, withProject, defaultProject)
|
||||
}
|
||||
|
||||
private fun assertDefaultWithoutDefaultRecording(printer: TestFeatureUsageSettingsEventsPrinter,
|
||||
@@ -276,14 +346,16 @@ class FeatureUsageSettingsEventsTest {
|
||||
assertInvokedRecorded(printer.result[0], withProject, defaultProject)
|
||||
}
|
||||
|
||||
private fun assertNotDefaultState(printer: TestFeatureUsageSettingsEventsPrinter, withRecordDefault: Boolean, withProject: Boolean, defaultProject: Boolean) {
|
||||
@Suppress("SameParameterValue")
|
||||
private fun assertNotDefaultState(printer: TestFeatureUsageSettingsEventsPrinter,withRecordDefault: Boolean, withProject: Boolean, defaultProject: Boolean) {
|
||||
assertThat(printer.result).hasSize(1)
|
||||
assertNotDefaultState(printer.result[0], "boolOption", true, withRecordDefault, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.result[0], "boolOption", true, "bool", withRecordDefault, withProject, defaultProject)
|
||||
}
|
||||
|
||||
private fun assertNotDefaultState(event: LoggedComponentStateEvents,
|
||||
name: String,
|
||||
value: Any,
|
||||
value: Any?,
|
||||
type: String,
|
||||
withDefaultRecorded: Boolean,
|
||||
withProject: Boolean,
|
||||
defaultProject: Boolean) {
|
||||
@@ -292,14 +364,18 @@ class FeatureUsageSettingsEventsTest {
|
||||
assertThat(event.id).isEqualTo(if (withDefaultRecorded) "option" else "not.default")
|
||||
|
||||
var size = 3
|
||||
if (value != null) size++
|
||||
if (withDefaultRecorded) size++
|
||||
if (withProject) size++
|
||||
if (defaultProject) size++
|
||||
|
||||
assertThat(event.data).hasSize(size)
|
||||
assertThat(event.data["component"]).isEqualTo("MyTestComponent")
|
||||
assertThat(event.data["type"]).isEqualTo(type)
|
||||
assertThat(event.data["name"]).isEqualTo(name)
|
||||
assertThat(event.data["value"]).isEqualTo(value)
|
||||
if (value != null) {
|
||||
assertThat(event.data["value"]).isEqualTo(value)
|
||||
}
|
||||
if (withDefaultRecorded) {
|
||||
assertThat(event.data["default"]).isEqualTo(false)
|
||||
}
|
||||
@@ -313,24 +389,26 @@ class FeatureUsageSettingsEventsTest {
|
||||
|
||||
private fun assertDefaultState(printer: TestFeatureUsageSettingsEventsPrinter, withProject: Boolean, defaultProject: Boolean) {
|
||||
assertThat(printer.result).hasSize(1)
|
||||
assertDefaultState(printer.result[0], "boolOption", false, withProject, defaultProject)
|
||||
assertDefaultState(printer.result[0], "boolOption", false, "bool", withProject, defaultProject)
|
||||
}
|
||||
|
||||
private fun assertDefaultState(event: LoggedComponentStateEvents,
|
||||
name: String,
|
||||
value: Any,
|
||||
type: String,
|
||||
withProject: Boolean,
|
||||
defaultProject: Boolean) {
|
||||
assertThat(event.group.id).isEqualTo("settings")
|
||||
assertThat(event.group.version).isGreaterThan(0)
|
||||
assertThat(event.id).isEqualTo("option")
|
||||
|
||||
var size = 4
|
||||
var size = 5
|
||||
if (withProject) size++
|
||||
if (defaultProject) size++
|
||||
|
||||
assertThat(event.data).hasSize(size)
|
||||
assertThat(event.data["component"]).isEqualTo("MyTestComponent")
|
||||
assertThat(event.data["type"]).isEqualTo(type)
|
||||
assertThat(event.data["name"]).isEqualTo(name)
|
||||
assertThat(event.data["value"]).isEqualTo(value)
|
||||
assertThat(event.data["default"]).isEqualTo(true)
|
||||
@@ -422,4 +500,45 @@ class FeatureUsageSettingsEventsTest {
|
||||
@Attribute("second-bool-value")
|
||||
val secondBoolOption: Boolean = secondBool
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
private class ComponentStateWithNumerical(intOpt: Int = 0,
|
||||
longOpt: Long = 0,
|
||||
floatOpt: Float = 0.0F,
|
||||
doubleOpt: Double = 0.0,
|
||||
absIntOpt: Int = 0,
|
||||
absLongOpt: Long = 0,
|
||||
absFloatOpt: Float = 0.0F,
|
||||
absDoubleOpt: Double = 0.0,
|
||||
bool: Boolean = false,
|
||||
str: String = "string-option",
|
||||
list: List<Int> = ArrayList()) : ComponentState(bool, str, list) {
|
||||
@Attribute("int-option")
|
||||
val integerOption: Int = intOpt
|
||||
|
||||
@Attribute("long-option")
|
||||
val longOption: Long = longOpt
|
||||
|
||||
@Attribute("float-option")
|
||||
val floatOption: Float = floatOpt
|
||||
|
||||
@Attribute("double-option")
|
||||
val doubleOption: Double = doubleOpt
|
||||
|
||||
@Attribute("abs-int-option")
|
||||
@field:ReportValue
|
||||
val absIntegerOption: Int = absIntOpt
|
||||
|
||||
@Attribute("abs-long-option")
|
||||
@field:ReportValue
|
||||
val absLongOption: Long = absLongOpt
|
||||
|
||||
@Attribute("abs-float-option")
|
||||
@field:ReportValue
|
||||
val absFloatOption: Float = absFloatOpt
|
||||
|
||||
@Attribute("abs-double-option")
|
||||
@field:ReportValue
|
||||
val absDoubleOption: Double = absDoubleOpt
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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 com.intellij.ide.plugins;
|
||||
|
||||
import com.intellij.openapi.extensions.PluginId;
|
||||
import gnu.trove.TObjectIntHashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
class PluginClassCache {
|
||||
private static final Object ourLock = new Object();
|
||||
private final TObjectIntHashMap<PluginId> myClassCounts = new TObjectIntHashMap<>();
|
||||
|
||||
void addPluginClass(@NotNull PluginId pluginId) {
|
||||
synchronized(ourLock) {
|
||||
myClassCounts.put(pluginId, myClassCounts.get(pluginId) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void dumpPluginClassStatistics() {
|
||||
if (!Boolean.valueOf(System.getProperty("idea.is.internal")).booleanValue()) return;
|
||||
|
||||
List<PluginId> counters;
|
||||
synchronized (ourLock) {
|
||||
//noinspection unchecked
|
||||
counters = new ArrayList(Arrays.asList(myClassCounts.keys()));
|
||||
}
|
||||
|
||||
counters.sort((o1, o2) -> myClassCounts.get(o2) - myClassCounts.get(o1));
|
||||
for (PluginId id : counters) {
|
||||
PluginManagerCore.getLogger().info(id + " loaded " + myClassCounts.get(id) + " classes");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,7 +77,6 @@ public class PluginManagerCore {
|
||||
private static final TObjectIntHashMap<PluginId> ourId2Index = new TObjectIntHashMap<>();
|
||||
private static final String MODULE_DEPENDENCY_PREFIX = "com.intellij.module";
|
||||
private static final Map<String, IdeaPluginDescriptorImpl> ourModulesToContainingPlugins = new THashMap<>();
|
||||
private static final PluginClassCache ourPluginClasses = new PluginClassCache();
|
||||
private static final String SPECIAL_IDEA_PLUGIN = "IDEA CORE";
|
||||
private static final String PROPERTY_PLUGIN_PATH = "plugin.path";
|
||||
|
||||
@@ -119,7 +118,7 @@ public class PluginManagerCore {
|
||||
private static final List<Runnable> ourDisabledPluginsListeners = new CopyOnWriteArrayList<>();
|
||||
|
||||
/**
|
||||
* Returns list of all available plugin descriptors (bundled and custom, include disabled ones). Use {@link #getLoadedPlugins(StartupProgress)}
|
||||
* Returns list of all available plugin descriptors (bundled and custom, include disabled ones). Use {@link #getLoadedPlugins()}
|
||||
* if you need to get loaded plugins only.
|
||||
*
|
||||
* <p>
|
||||
@@ -386,10 +385,6 @@ public class PluginManagerCore {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void addPluginClass(@NotNull PluginId pluginId) {
|
||||
ourPluginClasses.addPluginClass(pluginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is an internal method, use {@link PluginException#createByClass(String, Throwable, Class)} instead.
|
||||
*/
|
||||
@@ -437,10 +432,6 @@ public class PluginManagerCore {
|
||||
}
|
||||
}
|
||||
|
||||
public static void dumpPluginClassStatistics() {
|
||||
ourPluginClasses.dumpPluginClassStatistics();
|
||||
}
|
||||
|
||||
private static boolean isDependent(@NotNull IdeaPluginDescriptor descriptor,
|
||||
@NotNull PluginId on,
|
||||
@NotNull Map<PluginId, IdeaPluginDescriptor> map,
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.intellij.ide.plugins.cl;
|
||||
|
||||
import com.intellij.diagnostic.PluginException;
|
||||
import com.intellij.diagnostic.StartUpMeasurer;
|
||||
import com.intellij.ide.plugins.PluginManagerCore;
|
||||
import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.extensions.PluginId;
|
||||
@@ -20,6 +19,7 @@ import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
@@ -38,6 +38,8 @@ public final class PluginClassLoader extends UrlClassLoader {
|
||||
private final AtomicLong edtTime = new AtomicLong();
|
||||
private final AtomicLong backgroundTime = new AtomicLong();
|
||||
|
||||
private final AtomicInteger loadedClassCounter = new AtomicInteger();
|
||||
|
||||
public PluginClassLoader(@NotNull List<URL> urls,
|
||||
@NotNull ClassLoader[] parents,
|
||||
PluginId pluginId,
|
||||
@@ -62,6 +64,10 @@ public final class PluginClassLoader extends UrlClassLoader {
|
||||
return backgroundTime.get();
|
||||
}
|
||||
|
||||
public long getLoadedClassCount() {
|
||||
return loadedClassCounter.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class loadClass(@NotNull String name, boolean resolve) throws ClassNotFoundException {
|
||||
Class c = tryLoadingClass(name, resolve, null);
|
||||
@@ -214,7 +220,7 @@ public final class PluginClassLoader extends UrlClassLoader {
|
||||
throw new PluginException("While loading class " + name + ": " + e.getMessage(), e, myPluginId);
|
||||
}
|
||||
if (c != null) {
|
||||
PluginManagerCore.addPluginClass(myPluginId);
|
||||
loadedClassCounter.incrementAndGet();
|
||||
}
|
||||
|
||||
return c;
|
||||
|
||||
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.openapi.application.ex;
|
||||
|
||||
import com.intellij.openapi.application.Application;
|
||||
@@ -26,10 +12,7 @@ import com.intellij.util.ExceptionUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.ide.PooledThreadExecutor;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
public class ApplicationUtil {
|
||||
// throws exception if can't grab read action right now
|
||||
@@ -74,16 +57,19 @@ public class ApplicationUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for {@code future} to be complete, or the current thread's indicator to be canceled
|
||||
* Note that {@code future} will not be cancelled by this method
|
||||
* Waits for {@code future} to be complete, or the current thread's indicator to be canceled.
|
||||
* Note that {@code future} will not be cancelled by this method.
|
||||
*/
|
||||
public static void runWithCheckCanceled(@NotNull Future<?> future, @NotNull final ProgressIndicator indicator) throws Exception {
|
||||
public static <T> T runWithCheckCanceled(@NotNull Future<T> future,
|
||||
@NotNull final ProgressIndicator indicator) throws ExecutionException {
|
||||
while (true) {
|
||||
indicator.checkCanceled();
|
||||
|
||||
try {
|
||||
future.get(25, TimeUnit.MILLISECONDS);
|
||||
break;
|
||||
return future.get(25, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
throw new ProcessCanceledException(e);
|
||||
}
|
||||
catch (TimeoutException ignored) { }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.openapi.editor.ex.util;
|
||||
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* An experiment API for providing custom way of storing lexer-based highlighting data.
|
||||
* <p>
|
||||
* By default a highlighting lexer uses {@link ShortBasedStorage} implementation which
|
||||
* serializes information about element type to be highlighted with their indices ({@link IElementType#getIndex()})
|
||||
* and deserializes ids back to {@link IElementType} using
|
||||
* element types registry {@link IElementType#find(short)}.
|
||||
* <p>
|
||||
* If you need to store more information during syntax highlighting or
|
||||
* if your element types cannot be restored from {@link IElementType#getIndex()},
|
||||
* you can implement you own storage and make your highlighting lexer implement {@link DataStorageFactory}
|
||||
* that will create the custom storage.
|
||||
* <p>
|
||||
* As an example, see {@link org.jetbrains.plugins.textmate.language.syntax.lexer.TextMateHighlightingLexer},
|
||||
* that lexes files with unregistered (whitout index) element types and
|
||||
* its data storage ({@link org.jetbrains.plugins.textmate.language.syntax.lexer.TextMateLexerDataStorage}
|
||||
* serializes/deserializes them to/from strings.
|
||||
*
|
||||
* @see com.intellij.openapi.editor.ex.util.LexerEditorHighlighter
|
||||
* @see SegmentArrayWithData
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
public interface DataStorageFactory {
|
||||
@NotNull
|
||||
DataStorage createDataStorage();
|
||||
}
|
||||
@@ -13,13 +13,13 @@ import static com.intellij.openapi.editor.ex.util.SegmentArray.calcCapacity;
|
||||
* {@link IElementType} index and and restartability of the state (positive values are for initial state).
|
||||
*/
|
||||
public class ShortBasedStorage implements DataStorage {
|
||||
short[] myData;
|
||||
protected short[] myData;
|
||||
|
||||
public ShortBasedStorage() {
|
||||
myData = new short[INITIAL_SIZE];
|
||||
}
|
||||
|
||||
private ShortBasedStorage(short[] data) {
|
||||
protected ShortBasedStorage(short[] data) {
|
||||
myData = data;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
package com.intellij.ide.ui
|
||||
|
||||
import com.intellij.openapi.components.BaseState
|
||||
import com.intellij.openapi.components.ReportValue
|
||||
import com.intellij.openapi.util.SystemInfo
|
||||
import com.intellij.ui.scale.JBUIScale
|
||||
import com.intellij.util.PlatformUtils
|
||||
@@ -34,9 +35,11 @@ class UISettingsState : BaseState() {
|
||||
@Deprecated("", replaceWith = ReplaceWith("NotRoamableUiOptions.fontScale"))
|
||||
var fontScale by property(0f)
|
||||
|
||||
@get:ReportValue
|
||||
@get:OptionTag("RECENT_FILES_LIMIT")
|
||||
var recentFilesLimit by property(50)
|
||||
|
||||
@get:ReportValue
|
||||
@get:OptionTag("RECENT_LOCATIONS_LIMIT")
|
||||
var recentLocationsLimit by property(25)
|
||||
|
||||
@@ -47,6 +50,7 @@ class UISettingsState : BaseState() {
|
||||
@get:OptionTag("CONSOLE_CYCLE_BUFFER_SIZE_KB")
|
||||
var consoleCycleBufferSizeKb by property(1024)
|
||||
|
||||
@get:ReportValue
|
||||
@get:OptionTag("EDITOR_TAB_LIMIT")
|
||||
var editorTabLimit by property(10)
|
||||
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.openapi.editor.ex.util;
|
||||
|
||||
import com.intellij.lexer.FlexAdapter;
|
||||
@@ -61,7 +61,7 @@ public class LexerEditorHighlighter implements EditorHighlighter, PrioritizedDoc
|
||||
|
||||
@NotNull
|
||||
protected SegmentArrayWithData createSegments() {
|
||||
return new SegmentArrayWithData(myLexer instanceof RestartableLexer ? new IntBasedStorage() : new ShortBasedStorage());
|
||||
return new SegmentArrayWithData(myLexer instanceof DataStorageFactory ? ((DataStorageFactory)myLexer).createDataStorage() : new ShortBasedStorage());
|
||||
}
|
||||
|
||||
public boolean isPlain() {
|
||||
|
||||
+19
-80
@@ -4,7 +4,6 @@ package com.intellij.openapi.externalSystem.model;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.UserDataHolderBase;
|
||||
import com.intellij.openapi.util.UserDataHolderEx;
|
||||
import com.intellij.util.ArrayUtilRt;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -21,8 +20,6 @@ import java.util.function.Function;
|
||||
* enhance any project. For example, particular framework can add facet settings as one more 'project' node's child.
|
||||
* <p/>
|
||||
* Not thread-safe.
|
||||
*
|
||||
* {@link #serializeData} must be called before serialization.
|
||||
*/
|
||||
public class DataNode<T> implements UserDataHolderEx {
|
||||
private static final Logger LOG = Logger.getInstance(DataNode.class);
|
||||
@@ -33,14 +30,12 @@ public class DataNode<T> implements UserDataHolderEx {
|
||||
@NotNull
|
||||
private final transient UserDataHolderBase userData = new UserDataHolderBase();
|
||||
|
||||
private transient T data;
|
||||
|
||||
// Key data type class cannot be used because can specify interface class and not actual data class
|
||||
private String dataClassName;
|
||||
private byte[] rawData;
|
||||
private T data;
|
||||
|
||||
private boolean ignored;
|
||||
|
||||
private transient volatile boolean ready;
|
||||
|
||||
@Nullable
|
||||
private DataNode<?> parent;
|
||||
|
||||
@@ -56,6 +51,10 @@ public class DataNode<T> implements UserDataHolderEx {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public boolean isReady() {
|
||||
return ready;
|
||||
}
|
||||
|
||||
// deserialization, data decoded on demand
|
||||
@SuppressWarnings("unused")
|
||||
private DataNode() {
|
||||
@@ -80,9 +79,6 @@ public class DataNode<T> implements UserDataHolderEx {
|
||||
|
||||
@NotNull
|
||||
public T getData() {
|
||||
if (data == null) {
|
||||
deserializeData(Arrays.asList(getClass().getClassLoader(), Thread.currentThread().getContextClassLoader()));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -94,47 +90,6 @@ public class DataNode<T> implements UserDataHolderEx {
|
||||
this.ignored = ignored;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is a generic holder for any kind of project data. That project data might originate from different locations, e.g.
|
||||
* core ide plugins, non-core ide plugins, third-party plugins etc. That means that when a service from a core plugin needs to
|
||||
* unmarshall {@link DataNode} object, its content should not be unmarshalled as well because its class might be unavailable here.
|
||||
* <p/>
|
||||
* That's why the content is delivered as a raw byte array and this method allows to build actual java object from it using
|
||||
* the right class loader.
|
||||
* <p/>
|
||||
* This method is a no-op if the content is already built.
|
||||
*
|
||||
* @param classLoaders class loaders which are assumed to be able to build object of the target content class
|
||||
*/
|
||||
public void deserializeData(@NotNull Collection<? extends ClassLoader> classLoaders) {
|
||||
if (data != null) {
|
||||
return;
|
||||
}
|
||||
if (rawData == null) {
|
||||
throw new IllegalStateException(String.format("Data node of key '%s' does not contain raw or prepared data", key));
|
||||
}
|
||||
if (rawData.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
String className = dataClassName;
|
||||
if (className == null) {
|
||||
className = key.getDataType();
|
||||
}
|
||||
|
||||
try {
|
||||
MultiLoaderWrapper classLoader = new MultiLoaderWrapper(getClass().getClassLoader(), classLoaders);
|
||||
//noinspection unchecked
|
||||
data = SerializationKt.readDataNodeData(((Class<T>)classLoader.findClass(className)), rawData, classLoader);
|
||||
clearRawData();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalStateException("Can't deserialize target data of key '" + key + "'. " +
|
||||
"Given class loaders: " + classLoaders, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to replace or modify data. If function returns null, data is left unchanged
|
||||
* @param visitor visitor. Must accept argument of type T and return value of type T
|
||||
@@ -147,16 +102,9 @@ public class DataNode<T> implements UserDataHolderEx {
|
||||
T newData = (T) visitor.apply(getData());
|
||||
if (newData != null) {
|
||||
data = newData;
|
||||
clearRawData();
|
||||
dataClassName = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void clearRawData() {
|
||||
rawData = null;
|
||||
dataClassName = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to retrieve data stored for the given key at the current node or any of its parents.
|
||||
*
|
||||
@@ -221,24 +169,6 @@ public class DataNode<T> implements UserDataHolderEx {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void serializeData(@NotNull WriteAndCompressSession buffer) {
|
||||
if (rawData != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (data == null) {
|
||||
dataClassName = null;
|
||||
rawData = ArrayUtilRt.EMPTY_BYTE_ARRAY;
|
||||
}
|
||||
else {
|
||||
dataClassName = data.getClass().getName();
|
||||
if (dataClassName.equals(key.getDataType())) {
|
||||
dataClassName = null;
|
||||
}
|
||||
rawData = SerializationKt.serializeDataNodeData(data, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
// We can't use myChildren.hashCode() because it iterates whole subtree. This should not produce many collisions because 'getData()'
|
||||
@@ -284,7 +214,6 @@ public class DataNode<T> implements UserDataHolderEx {
|
||||
}
|
||||
}
|
||||
parent = null;
|
||||
clearRawData();
|
||||
children.clear();
|
||||
}
|
||||
|
||||
@@ -332,12 +261,22 @@ public class DataNode<T> implements UserDataHolderEx {
|
||||
return userData.getCopyableUserData(key);
|
||||
}
|
||||
|
||||
public boolean validateData() {
|
||||
if (data == null) {
|
||||
ready = false;
|
||||
clear(true);
|
||||
}
|
||||
else {
|
||||
ready = true;
|
||||
}
|
||||
return ready;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static <T> DataNode<T> nodeCopy(@NotNull DataNode<T> dataNode) {
|
||||
DataNode<T> copy = new DataNode<>(dataNode.key, dataNode.data, null);
|
||||
copy.dataClassName = dataNode.dataClassName;
|
||||
copy.rawData = dataNode.rawData;
|
||||
copy.ignored = dataNode.ignored;
|
||||
copy.ready = dataNode.ready;
|
||||
dataNode.userData.copyCopyableDataTo(copy.userData);
|
||||
return copy;
|
||||
}
|
||||
|
||||
+2
-1
@@ -81,7 +81,8 @@ public final class ProjectSystemId implements Serializable {
|
||||
ProjectSystemId cached = ourExistingIds.get(id);
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
+44
-55
@@ -1,67 +1,56 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.openapi.externalSystem.model
|
||||
|
||||
import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream
|
||||
import com.intellij.serialization.*
|
||||
import net.jpountz.lz4.LZ4CompressorWithLength
|
||||
import net.jpountz.lz4.LZ4DecompressorWithLength
|
||||
import net.jpountz.lz4.LZ4Factory
|
||||
import java.io.OutputStream
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.externalSystem.service.project.ProjectDataManager
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
|
||||
import com.intellij.serialization.ReadConfiguration
|
||||
import com.intellij.serialization.WriteConfiguration
|
||||
|
||||
val externalSystemBeanConstructed: BeanConstructed = {
|
||||
if (it is ProjectSystemId) {
|
||||
it.intern()
|
||||
}
|
||||
else {
|
||||
it
|
||||
}
|
||||
}
|
||||
// do not use SkipNullAndEmptySerializationFilter for now because can lead to issues
|
||||
fun createCacheWriteConfiguration() = WriteConfiguration(allowAnySubTypes = true)
|
||||
|
||||
fun createDataNodeReadConfiguration(classLoader: ClassLoader): ReadConfiguration {
|
||||
return ReadConfiguration(allowAnySubTypes = true, classLoader = classLoader, beanConstructed = externalSystemBeanConstructed)
|
||||
}
|
||||
fun createCacheReadConfiguration(log: Logger): ReadConfiguration {
|
||||
val projectDataManager = ProjectDataManager.getInstance()
|
||||
val defaultClassLoader = DataNode::class.java.classLoader
|
||||
|
||||
fun <T : Any> readDataNodeData(dataClass: Class<T>, data: ByteArray, classLoader: ClassLoader): T {
|
||||
val decompressor = LZ4DecompressorWithLength(LZ4Factory.fastestInstance().fastDecompressor())
|
||||
return ObjectSerializer.instance.read(dataClass, decompressor.decompress(data), createDataNodeReadConfiguration(classLoader))
|
||||
}
|
||||
|
||||
fun serializeDataNodeData(data: Any, buffer: WriteAndCompressSession): ByteArray {
|
||||
ObjectSerializer.instance.write(data, buffer.resetAndGetOutputStream(), WriteConfiguration(allowAnySubTypes = true, filter = SkipNullAndEmptySerializationFilter))
|
||||
return buffer.compress()
|
||||
}
|
||||
|
||||
/**
|
||||
* To write and compress a lot of elements sequentially into separate byte arrays.
|
||||
* Reuses input and output byte arrays.
|
||||
*/
|
||||
class WriteAndCompressSession {
|
||||
private val compressor = LZ4CompressorWithLength(LZ4Factory.fastestInstance().fastCompressor())
|
||||
private val buffer = BufferExposingByteArrayOutputStream()
|
||||
|
||||
private var lastByteArray: ByteArray? = null
|
||||
|
||||
fun compress(): ByteArray {
|
||||
val maxCompressedLength = compressor.maxCompressedLength(buffer.size())
|
||||
|
||||
var compressed = lastByteArray
|
||||
if (compressed == null || compressed.size < maxCompressedLength) {
|
||||
compressed = ByteArray(maxCompressedLength)
|
||||
val allManagers = ExternalSystemApiUtil.getAllManagers()
|
||||
return createDataNodeReadConfiguration(fun(name: String, hostObject: Any): Class<*>? {
|
||||
if (hostObject !is DataNode<*>) {
|
||||
return defaultClassLoader.loadClass(name)
|
||||
}
|
||||
|
||||
val compressedLength = compressor.compress(buffer.internalBuffer, 0, buffer.size(), compressed, 0, maxCompressedLength)
|
||||
if (compressedLength == compressed.size) {
|
||||
lastByteArray = null
|
||||
return compressed
|
||||
val services = projectDataManager.findService(hostObject.key)
|
||||
if (services != null) {
|
||||
for (dataService in services) {
|
||||
try {
|
||||
return dataService.javaClass.classLoader.loadClass(name)
|
||||
}
|
||||
catch (e: ClassNotFoundException) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (manager in allManagers) {
|
||||
try {
|
||||
return manager.javaClass.classLoader.loadClass(name)
|
||||
}
|
||||
catch (e: ClassNotFoundException) {
|
||||
}
|
||||
}
|
||||
|
||||
log.warn("Cannot find class `$name`")
|
||||
return null
|
||||
})
|
||||
}
|
||||
|
||||
fun createDataNodeReadConfiguration(loadClass: ((name: String, hostObject: Any) -> Class<*>?)): ReadConfiguration {
|
||||
return ReadConfiguration(allowAnySubTypes = true, loadClass = loadClass, beanConstructed = {
|
||||
if (it is ProjectSystemId) {
|
||||
it.intern()
|
||||
}
|
||||
else {
|
||||
lastByteArray = compressed
|
||||
return compressed.copyOf(compressedLength)
|
||||
it
|
||||
}
|
||||
}
|
||||
|
||||
fun resetAndGetOutputStream(): OutputStream {
|
||||
buffer.reset()
|
||||
return buffer
|
||||
}
|
||||
})
|
||||
}
|
||||
+5
-15
@@ -1,23 +1,10 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.
|
||||
*/
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.openapi.externalSystem.service.project;
|
||||
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.externalSystem.model.DataNode;
|
||||
import com.intellij.openapi.externalSystem.model.ExternalProjectInfo;
|
||||
import com.intellij.openapi.externalSystem.model.Key;
|
||||
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
|
||||
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataService;
|
||||
import com.intellij.openapi.project.Project;
|
||||
@@ -25,6 +12,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Aggregates all {@link ProjectDataService#EP_NAME registered data services}
|
||||
@@ -53,6 +41,8 @@ public interface ProjectDataManager {
|
||||
@NotNull Project project,
|
||||
boolean synchronous);
|
||||
|
||||
List<ProjectDataService<?, ?>> findService(@NotNull Key<?> key);
|
||||
|
||||
void ensureTheDataIsReadyToUse(@Nullable DataNode dataNode);
|
||||
|
||||
@Nullable
|
||||
|
||||
+1
-2
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.openapi.externalSystem.service.project.manage
|
||||
|
||||
import com.intellij.openapi.externalSystem.model.Key
|
||||
@@ -12,7 +12,6 @@ import com.intellij.util.containers.Interner
|
||||
import java.util.function.Function
|
||||
|
||||
class DeduplicateVisitorsSupplier {
|
||||
|
||||
private val myModuleData: Interner<ModuleData> = HashSetInterner()
|
||||
private val myLibraryData: Interner<LibraryData> = HashSetInterner()
|
||||
|
||||
|
||||
+3
-16
@@ -339,28 +339,15 @@ public class ExternalProjectsDataStorage implements SettingsSavingComponentJavaA
|
||||
return projectDataNode;
|
||||
}
|
||||
|
||||
private static void doSave(@NotNull Project project, @NotNull Collection<InternalExternalProjectInfo> externalProjects)
|
||||
throws IOException {
|
||||
private static void doSave(@NotNull Project project, @NotNull Collection<InternalExternalProjectInfo> externalProjects) throws IOException {
|
||||
for (Iterator<InternalExternalProjectInfo> iterator = externalProjects.iterator(); iterator.hasNext(); ) {
|
||||
InternalExternalProjectInfo externalProject = iterator.next();
|
||||
if (!validate(externalProject)) {
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
WriteAndCompressSession buffer = new WriteAndCompressSession();
|
||||
ExternalSystemApiUtil.visit(externalProject.getExternalProjectStructure(), dataNode -> {
|
||||
try {
|
||||
dataNode.serializeData(buffer);
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.warn(e);
|
||||
dataNode.clear(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getCacheFile(project).writeList(externalProjects, InternalExternalProjectInfo.class);
|
||||
getCacheFile(project).writeList(externalProjects, InternalExternalProjectInfo.class, SerializationKt.createCacheWriteConfiguration());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -388,7 +375,7 @@ public class ExternalProjectsDataStorage implements SettingsSavingComponentJavaA
|
||||
LOG.debug("External projects data storage was invalidated");
|
||||
return null;
|
||||
}
|
||||
return cacheFile.readList(InternalExternalProjectInfo.class, SerializationKt.getExternalSystemBeanConstructed());
|
||||
return cacheFile.readList(InternalExternalProjectInfo.class, SerializationKt.createCacheReadConfiguration(LOG));
|
||||
}
|
||||
|
||||
private static boolean isInvalidated(@NotNull Path configurationFile, @NotNull BasicFileAttributes fileAttributes) throws IOException {
|
||||
|
||||
+1
-1
@@ -148,7 +148,7 @@ public class ExternalSystemKeymapExtension implements KeymapExtension {
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void updateActions(Project project, Collection<? extends DataNode<TaskData>> taskData) {
|
||||
public static void updateActions(Project project, @NotNull Collection<? extends DataNode<TaskData>> taskData) {
|
||||
clearActions(project, taskData);
|
||||
createActions(project, taskData);
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.openapi.externalSystem.service.project.manage;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
@@ -103,7 +103,7 @@ public class ExternalSystemShortcutsManager implements Disposable {
|
||||
void shortcutsUpdated();
|
||||
}
|
||||
|
||||
void scheduleKeymapUpdate(Collection<? extends DataNode<TaskData>> taskData) {
|
||||
void scheduleKeymapUpdate(@NotNull Collection<? extends DataNode<TaskData>> taskData) {
|
||||
ExternalSystemKeymapExtension.updateActions(myProject, taskData);
|
||||
}
|
||||
|
||||
|
||||
+1
-16
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.
|
||||
*/
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.openapi.externalSystem.service.project.manage;
|
||||
|
||||
import com.intellij.openapi.externalSystem.model.DataNode;
|
||||
@@ -32,7 +18,6 @@ import java.util.Collection;
|
||||
*/
|
||||
@Deprecated
|
||||
public class ProjectDataManager extends ProjectDataManagerImpl {
|
||||
|
||||
public static ProjectDataManager getInstance() {
|
||||
return new ProjectDataManager(ProjectDataManagerImpl.getInstance());
|
||||
}
|
||||
|
||||
+9
-30
@@ -5,7 +5,6 @@ import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.components.impl.ComponentManagerImpl;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.externalSystem.ExternalSystemManager;
|
||||
import com.intellij.openapi.externalSystem.model.*;
|
||||
import com.intellij.openapi.externalSystem.model.project.ModuleData;
|
||||
import com.intellij.openapi.externalSystem.model.project.ProjectData;
|
||||
@@ -39,8 +38,6 @@ import java.util.function.Supplier;
|
||||
public class ProjectDataManagerImpl implements ProjectDataManager {
|
||||
|
||||
private static final Logger LOG = Logger.getInstance(ProjectDataManagerImpl.class);
|
||||
private static final com.intellij.openapi.util.Key<Boolean> DATA_READY =
|
||||
com.intellij.openapi.util.Key.create("externalSystem.data.ready");
|
||||
|
||||
@NotNull private final NotNullLazyValue<Map<Key<?>, List<ProjectDataService<?, ?>>>> myServices;
|
||||
|
||||
@@ -53,6 +50,12 @@ public class ProjectDataManagerImpl implements ProjectDataManager {
|
||||
this(() -> ProjectDataService.EP_NAME.getExtensions());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public List<ProjectDataService<?, ?>> findService(@NotNull Key<?> key) {
|
||||
return myServices.getValue().get(key);
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
ProjectDataManagerImpl(ProjectDataService... dataServices) {
|
||||
this(() -> dataServices);
|
||||
@@ -343,15 +346,14 @@ public class ProjectDataManagerImpl implements ProjectDataManager {
|
||||
|
||||
@Override
|
||||
public void ensureTheDataIsReadyToUse(@Nullable DataNode startNode) {
|
||||
if (startNode == null || Boolean.TRUE.equals(startNode.getUserData(DATA_READY))) {
|
||||
if (startNode == null || startNode.isReady()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DeduplicateVisitorsSupplier supplier = new DeduplicateVisitorsSupplier();
|
||||
((DataNode<?>)startNode).visit(dataNode -> {
|
||||
if (prepareDataToUse(dataNode)) {
|
||||
if (dataNode.validateData()) {
|
||||
dataNode.visitData(supplier.getVisitor(dataNode.getKey()));
|
||||
dataNode.putUserData(DATA_READY, Boolean.TRUE);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -379,7 +381,7 @@ public class ProjectDataManagerImpl implements ProjectDataManager {
|
||||
}
|
||||
catch (Throwable t) {
|
||||
dispose(modelsProvider, project, synchronous);
|
||||
ExceptionUtil.rethrowAllAsUnchecked(t);
|
||||
ExceptionUtil.rethrow(t);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -423,29 +425,6 @@ public class ProjectDataManagerImpl implements ProjectDataManager {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean prepareDataToUse(@NotNull DataNode dataNode) {
|
||||
final Map<Key<?>, List<ProjectDataService<?, ?>>> servicesByKey = myServices.getValue();
|
||||
List<ProjectDataService<?, ?>> services = servicesByKey.get(dataNode.getKey());
|
||||
if (services != null) {
|
||||
try {
|
||||
Set<ClassLoader> classLoaders = new LinkedHashSet<>();
|
||||
for (ProjectDataService<?, ?> dataService : services) {
|
||||
classLoaders.add(dataService.getClass().getClassLoader());
|
||||
}
|
||||
for (ExternalSystemManager<?, ?, ?, ?, ?> manager : ExternalSystemApiUtil.getAllManagers()) {
|
||||
classLoaders.add(manager.getClass().getClassLoader());
|
||||
}
|
||||
dataNode.deserializeData(classLoaders);
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.warn(e);
|
||||
dataNode.clear(true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void commit(@NotNull final IdeModifiableModelsProvider modelsProvider,
|
||||
@NotNull Project project,
|
||||
boolean synchronous,
|
||||
|
||||
+1
-3
@@ -18,7 +18,6 @@ import com.intellij.openapi.externalSystem.model.project.ModuleData;
|
||||
import com.intellij.openapi.externalSystem.model.project.ModuleDependencyData;
|
||||
import com.intellij.openapi.externalSystem.model.project.ProjectData;
|
||||
import com.intellij.openapi.externalSystem.service.project.ProjectDataManager;
|
||||
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManagerImpl;
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemBundle;
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemUiUtil;
|
||||
@@ -111,13 +110,12 @@ public class ExternalProjectDataSelectorDialog extends DialogWrapper {
|
||||
}
|
||||
|
||||
private void init(@NotNull ExternalProjectInfo projectInfo) {
|
||||
ProjectDataManagerImpl.getInstance().ensureTheDataIsReadyToUse(projectInfo.getExternalProjectStructure());
|
||||
myProjectInfo = projectInfo;
|
||||
myExternalSystemUiAware = ExternalSystemUiUtil.getUiAware(myProjectInfo.getProjectSystemId());
|
||||
myTree = createTree();
|
||||
updateSelectionState();
|
||||
|
||||
myTree.addCheckboxTreeListener(new CheckboxTreeAdapter() {
|
||||
myTree.addCheckboxTreeListener(new CheckboxTreeListener() {
|
||||
@Override
|
||||
public void nodeStateChanged(@NotNull CheckedTreeNode node) {
|
||||
updateSelectionState();
|
||||
|
||||
+20
-22
@@ -4,7 +4,6 @@ package com.intellij.openapi.externalSystem.model
|
||||
import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream
|
||||
import com.intellij.serialization.ObjectSerializer
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.api.Assertions.assertThatExceptionOfType
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import java.io.Serializable
|
||||
@@ -26,12 +25,7 @@ class DataNodeTest {
|
||||
fun `instance of class from a classloader can be deserialized`() {
|
||||
val barObject = classLoader.loadClass("foo.Bar").newInstance()
|
||||
|
||||
val deserialized = wrapAndDeserialize(barObject)
|
||||
|
||||
assertThatExceptionOfType(IllegalStateException::class.java)
|
||||
.isThrownBy { deserialized.deserializeData(listOf(javaClass.classLoader)) }
|
||||
|
||||
deserialized.deserializeData(listOf(URLClassLoader(arrayOf(libUrl), javaClass.classLoader)))
|
||||
val deserialized = wrapAndDeserialize(barObject, listOf(URLClassLoader(arrayOf(libUrl), javaClass.classLoader)))
|
||||
assertThat(deserialized.data.javaClass.name).isEqualTo("foo.Bar")
|
||||
}
|
||||
|
||||
@@ -43,12 +37,7 @@ class DataNodeTest {
|
||||
|
||||
val proxyInstance = Proxy.newProxyInstance(classLoader, arrayOf(interfaceClass), invocationHandler)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val deserialized = wrapAndDeserialize(proxyInstance)
|
||||
|
||||
assertThatExceptionOfType(IllegalStateException::class.java)
|
||||
.isThrownBy { deserialized.deserializeData(listOf(javaClass.classLoader)) }
|
||||
|
||||
deserialized.deserializeData(listOf(URLClassLoader(arrayOf(libUrl), javaClass.classLoader)))
|
||||
val deserialized = wrapAndDeserialize(proxyInstance, listOf(URLClassLoader(arrayOf(libUrl), javaClass.classLoader)))
|
||||
assertThat(deserialized.data.javaClass.interfaces)
|
||||
.extracting("name")
|
||||
.contains("foo.Baz")
|
||||
@@ -61,12 +50,10 @@ class DataNodeTest {
|
||||
val dataNodes = listOf(DataNode(Key.create(ProjectSystemId::class.java, 0), id, null),
|
||||
DataNode(Key.create(ProjectSystemId::class.java, 0), id, null))
|
||||
|
||||
val buffer = WriteAndCompressSession()
|
||||
dataNodes.forEach { it.serializeData(buffer) }
|
||||
val out = BufferExposingByteArrayOutputStream()
|
||||
ObjectSerializer.instance.writeList(dataNodes, DataNode::class.java, out)
|
||||
ObjectSerializer.instance.writeList(dataNodes, DataNode::class.java, out, createCacheWriteConfiguration())
|
||||
val bytes = out.toByteArray()
|
||||
val deserializedList = ObjectSerializer.instance.readList(DataNode::class.java, bytes, createDataNodeReadConfiguration(javaClass.classLoader))
|
||||
val deserializedList = ObjectSerializer.instance.readList(DataNode::class.java, bytes, createDataNodeReadConfiguration { name, _ -> javaClass.classLoader.loadClass(name) })
|
||||
|
||||
assertThat(deserializedList).hasSize(2)
|
||||
assertThat(deserializedList[0].data === deserializedList[1].data)
|
||||
@@ -91,16 +78,27 @@ class DataNodeTest {
|
||||
handler.ref = proxy
|
||||
assertThat(proxy.incrementAndGet()).isEqualTo(1)
|
||||
|
||||
val dataNode = wrapAndDeserialize(proxy)
|
||||
val dataNode = wrapAndDeserialize(proxy, listOf(javaClass.classLoader))
|
||||
val counter = dataNode.data as Counter
|
||||
assertThat(counter.incrementAndGet()).isEqualTo(2)
|
||||
}
|
||||
|
||||
private fun wrapAndDeserialize(barObject: Any): DataNode<*> {
|
||||
private fun wrapAndDeserialize(barObject: Any, classLoaders: List<ClassLoader>): DataNode<*> {
|
||||
val original = DataNode(Key.create(barObject.javaClass, 0), barObject, null)
|
||||
original.serializeData(WriteAndCompressSession())
|
||||
val bytes = ObjectSerializer.instance.writeAsBytes(original)
|
||||
return ObjectSerializer.instance.read(DataNode::class.java, bytes)
|
||||
val bytes = ObjectSerializer.instance.writeAsBytes(original, createCacheWriteConfiguration())
|
||||
return ObjectSerializer.instance.read(DataNode::class.java, bytes, createDataNodeReadConfiguration { name, _ ->
|
||||
var lastException: ClassNotFoundException? = null
|
||||
for (classLoader in classLoaders) {
|
||||
try {
|
||||
return@createDataNodeReadConfiguration classLoader.loadClass(name)
|
||||
}
|
||||
catch (e: ClassNotFoundException) {
|
||||
lastException = e
|
||||
}
|
||||
}
|
||||
|
||||
throw lastException!!
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-28
@@ -5,14 +5,12 @@ import com.intellij.openapi.externalSystem.model.DataNode;
|
||||
import com.intellij.openapi.externalSystem.model.Key;
|
||||
import com.intellij.openapi.externalSystem.model.ProjectKeys;
|
||||
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
|
||||
import com.intellij.openapi.externalSystem.model.project.*;
|
||||
import com.intellij.openapi.externalSystem.model.project.ProjectData;
|
||||
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider;
|
||||
import com.intellij.openapi.externalSystem.test.ExternalSystemTestUtil;
|
||||
import com.intellij.openapi.externalSystem.util.Order;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.testFramework.PlatformTestCase;
|
||||
import com.intellij.util.ReflectionUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -56,31 +54,6 @@ public class ProjectDataManagerImplTest extends PlatformTestCase {
|
||||
"removeDataAfter");
|
||||
}
|
||||
|
||||
public void testBrokenDataNodePreparation() {
|
||||
final LibraryDependencyData data = new LibraryDependencyData(new ModuleData("id",
|
||||
ExternalSystemTestUtil.TEST_EXTERNAL_SYSTEM_ID,
|
||||
"typeId",
|
||||
"module_name",
|
||||
"fake_path",
|
||||
"fake_path"),
|
||||
new LibraryData(ExternalSystemTestUtil.TEST_EXTERNAL_SYSTEM_ID,
|
||||
"library_name"),
|
||||
LibraryLevel.PROJECT);
|
||||
|
||||
final DataNode<LibraryDependencyData> badNode =
|
||||
new DataNode<LibraryDependencyData>(ProjectKeys.LIBRARY_DEPENDENCY, data, null) {
|
||||
@Override
|
||||
public void deserializeData(@NotNull Collection<? extends ClassLoader> loaders) {
|
||||
// mock a node that failed to deserialize it's data.
|
||||
ReflectionUtil.resetField(this, "myData");
|
||||
throw new RuntimeException("Broken node can not be prepared properly");
|
||||
}
|
||||
};
|
||||
|
||||
new ProjectDataManagerImpl(new LibraryDependencyDataService())
|
||||
.ensureTheDataIsReadyToUse(badNode);
|
||||
}
|
||||
|
||||
@Order(1)
|
||||
static class RunAfterTestDataService extends TestDataService {
|
||||
static class MyObject {
|
||||
|
||||
@@ -9,7 +9,7 @@ import com.intellij.openapi.components.State
|
||||
import com.intellij.openapi.components.Storage
|
||||
import org.jdom.Element
|
||||
|
||||
@State(name = "InlayHintsSettings", storages = [Storage("inlayHints.xml")])
|
||||
@State(name = "InlayHintsSettings", storages = [Storage("workspace.xml")])
|
||||
class InlayHintsSettings : PersistentStateComponent<InlayHintsSettings.State> {
|
||||
private var myState = State()
|
||||
private val lock = Any()
|
||||
|
||||
@@ -117,10 +117,10 @@ class InlayHintsSinkImpl<T>(val key: SettingsKey<T>) : InlayHintsSink {
|
||||
val previousPresentation = renderer.presentation
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
newPresentation.addListener(InlayListener(inlay as Inlay<PresentationRenderer>))
|
||||
renderer.presentation = newPresentation
|
||||
if (newPresentation.updateState(previousPresentation)) {
|
||||
newPresentation.fireUpdateEvent(previousPresentation.dimension())
|
||||
}
|
||||
renderer.presentation = newPresentation
|
||||
hints.remove(offset)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ public class ConsoleBuffer {
|
||||
public static int getCycleBufferSize() {
|
||||
UISettings uiSettings = UISettings.getInstance();
|
||||
if (uiSettings.getOverrideConsoleCycleBufferSize()) {
|
||||
return uiSettings.getConsoleCycleBufferSizeKb() * 1024;
|
||||
return Math.min(Integer.MAX_VALUE / 1024, uiSettings.getConsoleCycleBufferSizeKb()) * 1024;
|
||||
}
|
||||
return getLegacyCycleBufferSize();
|
||||
}
|
||||
|
||||
@@ -362,6 +362,8 @@ public final class ServiceViewManagerImpl implements ServiceViewManager, Persist
|
||||
if (item != null && !viewModel.getChildren(item).isEmpty()) {
|
||||
AppUIUtil.invokeOnEdt(() -> {
|
||||
int index = myContentManager.getIndexOfContent(content);
|
||||
if (index < 0) return;
|
||||
|
||||
myContentManager.removeContent(content, true);
|
||||
ServiceListModel listModel = new ServiceListModel(myModel, myModelFilter, ContainerUtil.newSmartList(item),
|
||||
viewModel.getFilter().getParent());
|
||||
|
||||
@@ -10,7 +10,6 @@ import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.execution.services.ServiceViewActionProvider.getSelectedView;
|
||||
|
||||
@@ -18,8 +17,7 @@ public class SplitToNewTabsAction extends DumbAwareAction {
|
||||
@Override
|
||||
public void update(@NotNull AnActionEvent e) {
|
||||
ServiceView serviceView = getSelectedView(e);
|
||||
List<ServiceViewItem> items = serviceView == null ? Collections.emptyList() : serviceView.getSelectedItems();
|
||||
boolean enabled = !items.isEmpty() && items.stream().allMatch(item -> item instanceof ServiceModel.ServiceNode);
|
||||
boolean enabled = serviceView != null && !serviceView.getSelectedItems().isEmpty();
|
||||
e.getPresentation().setEnabled(enabled);
|
||||
e.getPresentation().setVisible(enabled || !ActionPlaces.isPopupPlace(e.getPlace()));
|
||||
}
|
||||
|
||||
@@ -1,28 +1,19 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.
|
||||
*/
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.find.impl;
|
||||
|
||||
import com.intellij.find.FindInProjectSettings;
|
||||
import com.intellij.openapi.components.*;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.components.State;
|
||||
import com.intellij.openapi.components.Storage;
|
||||
import com.intellij.openapi.components.StoragePathMacros;
|
||||
import com.intellij.openapi.project.Project;
|
||||
|
||||
@State(
|
||||
name = "FindInProjectRecents",
|
||||
storages = {@Storage(value = StoragePathMacros.WORKSPACE_FILE, roamingType = RoamingType.DISABLED)}
|
||||
)
|
||||
storages = {
|
||||
@Storage(StoragePathMacros.PRODUCT_WORKSPACE_FILE),
|
||||
@Storage(value = StoragePathMacros.WORKSPACE_FILE, deprecated = true)
|
||||
})
|
||||
final class FindInProjectRecents extends FindInProjectSettingsBase implements FindInProjectSettings {
|
||||
public static FindInProjectSettings getInstance(Project project) {
|
||||
return ServiceManager.getService(project, FindInProjectSettings.class);
|
||||
|
||||
+1
-6
@@ -1,19 +1,14 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.ide;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.platform.ModuleAttachProcessor;
|
||||
import com.intellij.util.messages.MessageBus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Used by IDEs where <a href="https://www.jetbrains.com/help/phpstorm/opening-multiple-projects.html">attaching modules</a> is supported.
|
||||
*/
|
||||
final class AttachedModuleAwareRecentProjectsManager extends RecentDirectoryProjectsManager {
|
||||
AttachedModuleAwareRecentProjectsManager(@NotNull MessageBus messageBus) {
|
||||
super(messageBus);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected String getProjectDisplayName(@NotNull Project project) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.intellij.ide.actions;
|
||||
|
||||
import com.intellij.notebook.editor.BackedVirtualFile;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
import com.intellij.openapi.project.DumbAwareAction;
|
||||
@@ -23,6 +24,9 @@ public class SaveAsAction extends DumbAwareAction {
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
Project project = e.getProject();
|
||||
VirtualFile virtualFile = e.getData(CommonDataKeys.VIRTUAL_FILE);
|
||||
if (virtualFile instanceof BackedVirtualFile) {
|
||||
virtualFile = ((BackedVirtualFile)virtualFile).getOriginFile();
|
||||
}
|
||||
if (project == null || virtualFile == null) return;
|
||||
PsiElement element = PsiManager.getInstance(project).findFile(virtualFile);
|
||||
if (element == null) return;
|
||||
|
||||
@@ -43,8 +43,11 @@ import java.awt.event.InputEvent;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
@State(name = "BookmarkManager", storages = @Storage(StoragePathMacros.WORKSPACE_FILE))
|
||||
public class BookmarkManager implements PersistentStateComponent<Element> {
|
||||
@State(name = "BookmarkManager", storages = {
|
||||
@Storage(StoragePathMacros.PRODUCT_WORKSPACE_FILE),
|
||||
@Storage(value = StoragePathMacros.WORKSPACE_FILE, deprecated = true)
|
||||
})
|
||||
public final class BookmarkManager implements PersistentStateComponent<Element> {
|
||||
private static final int MAX_AUTO_DESCRIPTION_SIZE = 50;
|
||||
private final MultiMap<VirtualFile, Bookmark> myBookmarks = MultiMap.createConcurrentSet();
|
||||
private final Map<Trinity<VirtualFile, Integer, String>, Bookmark> myDeletedDocumentBookmarks = new HashMap<>();
|
||||
|
||||
@@ -91,7 +91,10 @@ import java.awt.*;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
@State(name = "ProjectView", storages = @Storage(StoragePathMacros.WORKSPACE_FILE))
|
||||
@State(name = "ProjectView", storages = {
|
||||
@Storage(StoragePathMacros.PRODUCT_WORKSPACE_FILE),
|
||||
@Storage(value = StoragePathMacros.WORKSPACE_FILE, deprecated = true)
|
||||
})
|
||||
public class ProjectViewImpl extends ProjectView implements PersistentStateComponent<Element>, Disposable, QuickActionProvider, BusyObject {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.ide.projectView.impl.ProjectViewImpl");
|
||||
private static final Key<String> ID_KEY = Key.create("pane-id");
|
||||
|
||||
@@ -173,13 +173,6 @@ public class ScratchFileServiceImpl extends ScratchFileService implements Persis
|
||||
}
|
||||
}
|
||||
|
||||
public static class TypeFactory extends FileTypeFactory {
|
||||
@Override
|
||||
public void createFileTypes(@NotNull FileTypeConsumer consumer) {
|
||||
consumer.consume(ScratchFileType.INSTANCE);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Substitutor extends LanguageSubstitutor {
|
||||
@Nullable
|
||||
@Override
|
||||
|
||||
+1
-2
@@ -186,8 +186,7 @@ public class TestParseEventLogWhitelistDialog extends DialogWrapper {
|
||||
myResultEditor.getSelectionModel().removeSelection();
|
||||
updateResultRequest("{}");
|
||||
|
||||
final BuildNumber build = BuildNumber.fromString(EventLogConfiguration.INSTANCE.getBuild());
|
||||
final FUSWhitelist whitelist = FUStatisticsWhiteListGroupsService.parseApprovedGroups(myWhitelistEditor.getDocument().getText(), build);
|
||||
final FUSWhitelist whitelist = FUStatisticsWhiteListGroupsService.parseApprovedGroups(myWhitelistEditor.getDocument().getText());
|
||||
try {
|
||||
final String parsed = parseLogAndFilter(new LogEventWhitelistFilter(whitelist), myEventLogPanel.getText());
|
||||
updateResultRequest(parsed.trim());
|
||||
|
||||
@@ -88,7 +88,7 @@ abstract class PrebuiltStubsProviderBase : PrebuiltIndexProviderBase<SerializedS
|
||||
return null
|
||||
}
|
||||
else {
|
||||
mySerializationManager = SerializationManagerImpl(File(indexesRoot, "$indexName.names"))
|
||||
mySerializationManager = SerializationManagerImpl(File(indexesRoot, "$indexName.names"), true)
|
||||
Disposer.register(ApplicationManager.getApplication(), mySerializationManager!!)
|
||||
return super.openIndexStorage(indexesRoot)
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.ShutDownTracker;
|
||||
import com.intellij.util.io.AbstractStringEnumerator;
|
||||
import com.intellij.util.io.IOUtil;
|
||||
import com.intellij.util.io.PersistentStringEnumerator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -39,22 +38,24 @@ public class SerializationManagerImpl extends SerializationManagerEx implements
|
||||
|
||||
private final AtomicBoolean myNameStorageCrashed = new AtomicBoolean(false);
|
||||
private final File myFile;
|
||||
private final boolean myUnmodifiable;
|
||||
private final AtomicBoolean myShutdownPerformed = new AtomicBoolean(false);
|
||||
private AbstractStringEnumerator myNameStorage;
|
||||
private PersistentStringEnumerator myNameStorage;
|
||||
private StubSerializationHelper myStubSerializationHelper;
|
||||
|
||||
public SerializationManagerImpl() {
|
||||
this(new File(PathManager.getIndexRoot(), "rep.names"));
|
||||
this(new File(PathManager.getIndexRoot(), "rep.names"), false);
|
||||
}
|
||||
|
||||
public SerializationManagerImpl(@NotNull File nameStorageFile) {
|
||||
public SerializationManagerImpl(@NotNull File nameStorageFile, boolean unmodifiable) {
|
||||
myFile = nameStorageFile;
|
||||
myFile.getParentFile().mkdirs();
|
||||
myUnmodifiable = unmodifiable;
|
||||
try {
|
||||
// we need to cache last id -> String mappings due to StringRefs and stubs indexing that initially creates stubs (doing enumerate on String)
|
||||
// and then index them (valueOf), also similar string items are expected to be enumerated during stubs processing
|
||||
myNameStorage = new PersistentStringEnumerator(myFile, true);
|
||||
myStubSerializationHelper = new StubSerializationHelper(myNameStorage, this);
|
||||
myStubSerializationHelper = new StubSerializationHelper(myNameStorage, unmodifiable, this);
|
||||
}
|
||||
catch (IOException e) {
|
||||
nameStorageCrashed();
|
||||
@@ -83,10 +84,13 @@ public class SerializationManagerImpl extends SerializationManagerEx implements
|
||||
}
|
||||
|
||||
StubSerializationHelper prevHelper = myStubSerializationHelper;
|
||||
if (myUnmodifiable) {
|
||||
LOG.error("Data provided by unmodifiable serialization manager can be invalid after repair");
|
||||
}
|
||||
|
||||
IOUtil.deleteAllFilesStartingWith(myFile);
|
||||
myNameStorage = new PersistentStringEnumerator(myFile, true);
|
||||
myStubSerializationHelper = new StubSerializationHelper(myNameStorage, this);
|
||||
myStubSerializationHelper = new StubSerializationHelper(myNameStorage, myUnmodifiable, this);
|
||||
myStubSerializationHelper.copyFrom(prevHelper);
|
||||
}
|
||||
catch (IOException e) {
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.intellij.util.containers.RecentStringInterner;
|
||||
import com.intellij.util.io.AbstractStringEnumerator;
|
||||
import com.intellij.util.io.DataInputOutputUtil;
|
||||
import com.intellij.util.io.IOUtil;
|
||||
import com.intellij.util.io.PersistentStringEnumerator;
|
||||
import gnu.trove.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -25,7 +26,9 @@ import java.util.*;
|
||||
* Author: dmitrylomov
|
||||
*/
|
||||
class StubSerializationHelper {
|
||||
private final AbstractStringEnumerator myNameStorage;
|
||||
private static final Logger LOG = Logger.getInstance(StubSerializationHelper.class);
|
||||
|
||||
private final PersistentStringEnumerator myNameStorage;
|
||||
|
||||
private final TIntObjectHashMap<String> myIdToName = new TIntObjectHashMap<>();
|
||||
private final TObjectIntHashMap<String> myNameToId = new TObjectIntHashMap<>();
|
||||
@@ -34,10 +37,12 @@ class StubSerializationHelper {
|
||||
private final ConcurrentIntObjectMap<ObjectStubSerializer> myIdToSerializer = ContainerUtil.createConcurrentIntObjectMap();
|
||||
private final Map<ObjectStubSerializer, Integer> mySerializerToId = ContainerUtil.newConcurrentMap();
|
||||
|
||||
private final boolean myUnmodifiable;
|
||||
private final RecentStringInterner myStringInterner;
|
||||
|
||||
StubSerializationHelper(@NotNull AbstractStringEnumerator nameStorage, @NotNull Disposable parentDisposable) {
|
||||
StubSerializationHelper(@NotNull PersistentStringEnumerator nameStorage, boolean unmodifiable, @NotNull Disposable parentDisposable) {
|
||||
myNameStorage = nameStorage;
|
||||
myUnmodifiable = unmodifiable;
|
||||
myStringInterner = new RecentStringInterner(parentDisposable);
|
||||
}
|
||||
|
||||
@@ -53,7 +58,17 @@ class StubSerializationHelper {
|
||||
return;
|
||||
}
|
||||
|
||||
int id = myNameStorage.enumerate(name);
|
||||
int id;
|
||||
if (myUnmodifiable) {
|
||||
id = myNameStorage.tryEnumerate(name);
|
||||
if (id == 0) {
|
||||
LOG.info("serialized " + name + " is ignored in unmodifiable stub serialization manager");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
id = myNameStorage.enumerate(name);
|
||||
}
|
||||
myIdToName.put(id, name);
|
||||
myNameToId.put(name, id);
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ class HeavyPresentationTest : LightPlatformCodeInsightFixtureTestCase() {
|
||||
}
|
||||
|
||||
fun testFoldedStateIsNotUpdatedAndStatelessComponentIsUpdated() {
|
||||
val factory = PresentationFactory(myFixture.editor as EditorImpl)
|
||||
val factory = getFactory()
|
||||
|
||||
val old = unwrapFolding(factory.folding(factory.smallText("outerPlaceholder")) {
|
||||
unwrapFolding(factory.folding(factory.smallText("innerPlaceholder")) {factory.smallText("text")})
|
||||
@@ -142,8 +142,7 @@ class HeavyPresentationTest : LightPlatformCodeInsightFixtureTestCase() {
|
||||
}
|
||||
|
||||
fun testFoldedBiState() {
|
||||
val factory = PresentationFactory(myFixture.editor as EditorImpl)
|
||||
with(factory) {
|
||||
with(getFactory()) {
|
||||
val inner = collapsible(
|
||||
prefix = smallText("("),
|
||||
collapsed = smallText("???"),
|
||||
@@ -179,6 +178,18 @@ class HeavyPresentationTest : LightPlatformCodeInsightFixtureTestCase() {
|
||||
}
|
||||
}
|
||||
|
||||
fun testSeqSmallTextChangesWidth() {
|
||||
with(getFactory()) {
|
||||
val initial = roundWithBackground(seq(smallText(": "), smallText("number")))
|
||||
val final = roundWithBackground(seq(smallText(": "), smallText("void")))
|
||||
val requiresUpdate = final.updateState(initial)
|
||||
assertTrue(requiresUpdate)
|
||||
assertTrue(initial.width != final.width)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getFactory() = PresentationFactory(myFixture.editor as EditorImpl)
|
||||
|
||||
private fun unwrapFolding(presentation: InlayPresentation): InlayPresentation {
|
||||
presentation as ChangeOnClickPresentation
|
||||
presentation.state = ChangeOnClickPresentation.State(true)
|
||||
|
||||
@@ -130,13 +130,18 @@ internal class BeanBinding(beanClass: Class<*>) : BaseBeanBinding(beanClass), Bi
|
||||
}
|
||||
}
|
||||
|
||||
val instance = try {
|
||||
var instance = try {
|
||||
constructorInfo.constructor.newInstance(*initArgs)
|
||||
}
|
||||
catch (e: Exception) {
|
||||
throw SerializationException("Cannot create instance (beanClass=${beanClass.name}, initArgs=${initArgs.joinToString()})", e)
|
||||
}
|
||||
|
||||
// must be called after creation because child properties can reference object
|
||||
context.configuration.beanConstructed?.let {
|
||||
instance = it(instance)
|
||||
}
|
||||
|
||||
if (id != -1) {
|
||||
context.objectIdReader.registerObject(instance, id)
|
||||
}
|
||||
@@ -147,7 +152,7 @@ internal class BeanBinding(beanClass: Class<*>) : BaseBeanBinding(beanClass), Bi
|
||||
readIntoObject(instance, context.createSubContext(reader), checkId = false /* already registered */) { !names.contains(it) }
|
||||
}
|
||||
}
|
||||
return context.configuration.beanConstructed?.let { it(instance) } ?: instance
|
||||
return instance
|
||||
}
|
||||
|
||||
override fun deserialize(context: ReadContext): Any {
|
||||
@@ -159,7 +164,11 @@ internal class BeanBinding(beanClass: Class<*>) : BaseBeanBinding(beanClass), Bi
|
||||
return context.objectIdReader.getObject(reader.intValue())
|
||||
}
|
||||
else if (ionType != IonType.STRUCT) {
|
||||
throw SerializationException("Expected STRUCT, but got $ionType")
|
||||
var stringValue = ""
|
||||
if (ionType == IonType.SYMBOL || ionType == IonType.STRING) {
|
||||
stringValue = reader.stringValue()
|
||||
}
|
||||
throw SerializationException("Expected STRUCT, but got $ionType (stringValue=$stringValue)")
|
||||
}
|
||||
|
||||
if (propertyMapping.isInitialized()) {
|
||||
@@ -215,7 +224,7 @@ internal class BeanBinding(beanClass: Class<*>) : BaseBeanBinding(beanClass), Bi
|
||||
throw e
|
||||
}
|
||||
catch (e: Exception) {
|
||||
context.errors.fields.add(ReadError("Cannot deserialize field value (field=$fieldName, binding=$binding, valueType=${reader.type}, beanClass=${beanClass.name})", e))
|
||||
throw SerializationException("Cannot deserialize field value (field=$fieldName, binding=$binding, valueType=${reader.type}, beanClass=${beanClass.name})", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ internal inline fun write(hostObject: Any, accessor: MutableAccessor, context: W
|
||||
}
|
||||
}
|
||||
|
||||
internal inline fun read(hostObject: Any, property: MutableAccessor, context: ReadContext, read: ValueReader.() -> Any) {
|
||||
internal inline fun read(hostObject: Any, property: MutableAccessor, context: ReadContext, read: ValueReader.() -> Any?) {
|
||||
if (context.reader.type == IonType.NULL) {
|
||||
property.set(hostObject, null)
|
||||
}
|
||||
|
||||
@@ -4,26 +4,19 @@ package com.intellij.serialization
|
||||
import com.amazon.ion.IonException
|
||||
import com.amazon.ion.IonType
|
||||
import com.amazon.ion.IonWriter
|
||||
import com.amazon.ion.impl.bin.Block
|
||||
import com.amazon.ion.impl.bin.BlockAllocator
|
||||
import com.amazon.ion.impl.bin.BlockAllocatorProvider
|
||||
import com.amazon.ion.impl.bin._Private_IonManagedBinaryWriterBuilder
|
||||
import com.amazon.ion.system.IonReaderBuilder
|
||||
import com.amazon.ion.system.IonTextWriterBuilder
|
||||
import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream
|
||||
import com.intellij.util.ParameterizedTypeImpl
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
import java.lang.reflect.Type
|
||||
import java.nio.file.Path
|
||||
import java.util.*
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import kotlin.experimental.or
|
||||
|
||||
private const val FORMAT_VERSION = 1
|
||||
private const val FORMAT_VERSION = 2
|
||||
|
||||
internal class IonObjectSerializer {
|
||||
val readerBuilder: IonReaderBuilder = IonReaderBuilder.standard().immutable()
|
||||
@@ -207,86 +200,4 @@ private fun createIonWriterBuilder(binary: Boolean, out: OutputStream): IonWrite
|
||||
binary -> binaryWriterBuilder.newWriter(out)
|
||||
else -> textWriterBuilder.build(out)
|
||||
}
|
||||
}
|
||||
|
||||
internal class PooledBlockAllocatorProvider : BlockAllocatorProvider() {
|
||||
companion object {
|
||||
// 512 KB
|
||||
internal const val POOL_THRESHOLD = 512 * 1024
|
||||
}
|
||||
|
||||
@Suppress("RemoveExplicitTypeArguments")
|
||||
private val allocators = ContainerUtil.createConcurrentIntObjectMap<PooledBlockAllocator>()
|
||||
|
||||
private inner class PooledBlockAllocator(private val blockSize: Int) : BlockAllocator() {
|
||||
private val freeBlocks = ArrayList<Block>()
|
||||
|
||||
private val blockCounter = AtomicInteger()
|
||||
|
||||
val byteSize: Int
|
||||
get() = blockCounter.get() * blockSize
|
||||
|
||||
override fun allocateBlock(): Block {
|
||||
val lastIndex = freeBlocks.lastIndex
|
||||
if (lastIndex != -1) {
|
||||
return freeBlocks.removeAt(lastIndex)
|
||||
}
|
||||
|
||||
blockCounter.incrementAndGet()
|
||||
return object : Block(ByteArray(blockSize)) {
|
||||
override fun close() {
|
||||
reset()
|
||||
freeBlocks.add(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getBlockSize() = blockSize
|
||||
|
||||
override fun close() {
|
||||
if (allocators.putIfAbsent(blockSize, this) != null) {
|
||||
// help GC - nullize
|
||||
freeBlocks.clear()
|
||||
blockCounter.set(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@get:TestOnly
|
||||
val byteSize: Int
|
||||
get() {
|
||||
var totalByteSize = 0
|
||||
for (allocator in allocators.elements()) {
|
||||
totalByteSize += allocator.byteSize
|
||||
}
|
||||
return totalByteSize
|
||||
}
|
||||
|
||||
override fun vendAllocator(blockSize: Int): BlockAllocator {
|
||||
if (blockSize <= 0) {
|
||||
throw IllegalArgumentException("Invalid block size: $blockSize")
|
||||
}
|
||||
|
||||
// PooledBlockAllocator is not thread safe - do not put a new one to pool
|
||||
val result = allocators.remove(blockSize) ?: PooledBlockAllocator(blockSize)
|
||||
|
||||
var totalByteSize = 0
|
||||
val iterator = allocators.values().iterator()
|
||||
var isExcess = false
|
||||
while (iterator.hasNext()) {
|
||||
val allocator = iterator.next()
|
||||
if (isExcess) {
|
||||
iterator.remove()
|
||||
continue
|
||||
}
|
||||
|
||||
totalByteSize += allocator.byteSize
|
||||
if (totalByteSize > POOL_THRESHOLD) {
|
||||
iterator.remove()
|
||||
isExcess = true
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -22,12 +22,22 @@ internal class MapBinding(keyType: Type, valueType: Type, context: BindingInitia
|
||||
return
|
||||
}
|
||||
|
||||
fun writeEntry(key: Any?, value: Any?) {
|
||||
if (key == null) {
|
||||
writer.writeNull()
|
||||
fun writeEntry(key: Any?, value: Any?, isStringKey: Boolean) {
|
||||
if (isStringKey) {
|
||||
if (key == null) {
|
||||
throw SerializationException("null string keys not supported")
|
||||
}
|
||||
else {
|
||||
writer.setFieldName(key as String)
|
||||
}
|
||||
}
|
||||
else {
|
||||
keyBinding.serialize(key, context)
|
||||
if (key == null) {
|
||||
writer.writeNull()
|
||||
}
|
||||
else {
|
||||
keyBinding.serialize(key, context)
|
||||
}
|
||||
}
|
||||
|
||||
if (value == null) {
|
||||
@@ -38,7 +48,8 @@ internal class MapBinding(keyType: Type, valueType: Type, context: BindingInitia
|
||||
}
|
||||
}
|
||||
|
||||
writer.stepIn(IonType.LIST)
|
||||
val isStringKey = keyBinding is StringBinding
|
||||
writer.stepIn(if (isStringKey) IonType.STRUCT else IonType.LIST)
|
||||
if (context.configuration.orderMapEntriesByKeys && isKeyComparable && map !is SortedMap<*, *> && map !is LinkedHashMap<*, *>) {
|
||||
val keys = ArrayUtil.toObjectArray(map.keys)
|
||||
Arrays.sort(keys) { a, b ->
|
||||
@@ -50,18 +61,20 @@ internal class MapBinding(keyType: Type, valueType: Type, context: BindingInitia
|
||||
}
|
||||
}
|
||||
for (key in keys) {
|
||||
writeEntry(key, map.get(key))
|
||||
writeEntry(key, map.get(key), isStringKey)
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (map is THashMap) {
|
||||
map.forEachEntry { k: Any?, v: Any? ->
|
||||
writeEntry(k, v)
|
||||
writeEntry(k, v, isStringKey)
|
||||
true
|
||||
}
|
||||
}
|
||||
else {
|
||||
map.forEach(::writeEntry)
|
||||
map.forEach {
|
||||
key, value -> writeEntry(key, value, isStringKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
writer.stepOut()
|
||||
@@ -93,11 +106,26 @@ internal class MapBinding(keyType: Type, valueType: Type, context: BindingInitia
|
||||
|
||||
private fun readInto(result: MutableMap<Any?, Any?>, context: ReadContext) {
|
||||
val reader = context.reader
|
||||
|
||||
if (reader.type == IonType.INT) {
|
||||
LOG.assertTrue(context.reader.intValue() == 0)
|
||||
return
|
||||
}
|
||||
|
||||
val isStringKeys = reader.type == IonType.STRUCT
|
||||
reader.stepIn()
|
||||
while (true) {
|
||||
val key = read(reader.next() ?: break, keyBinding, context)
|
||||
val value = read(reader.next() ?: break, valueBinding, context)
|
||||
result.put(key, value)
|
||||
if (isStringKeys) {
|
||||
val type = reader.next() ?: break
|
||||
val key = reader.fieldName
|
||||
val value = read(type, valueBinding, context)
|
||||
result.put(key, value)
|
||||
}
|
||||
else {
|
||||
val key = read(reader.next() ?: break, keyBinding, context)
|
||||
val value = read(reader.next() ?: break, valueBinding, context)
|
||||
result.put(key, value)
|
||||
}
|
||||
}
|
||||
reader.stepOut()
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ import java.io.Reader
|
||||
|
||||
internal typealias ValueReader = IonReader
|
||||
internal typealias ValueWriter = IonWriter
|
||||
|
||||
// not fully initialized object may be passed (only created instance without properties) if object has PropertyMapping annotation
|
||||
typealias BeanConstructed = (instance: Any) -> Any
|
||||
|
||||
internal val defaultWriteConfiguration = WriteConfiguration()
|
||||
|
||||
@@ -14,7 +14,17 @@ internal class PolymorphicBinding(private val superClass: Class<*>) : Binding {
|
||||
context.bindingProducer.getRootBinding(valueClass).serialize(obj, context)
|
||||
}
|
||||
|
||||
override fun deserialize(hostObject: Any, property: MutableAccessor, context: ReadContext) {
|
||||
read(hostObject, property, context) {
|
||||
doDeserialize(context, hostObject)
|
||||
}
|
||||
}
|
||||
|
||||
override fun deserialize(context: ReadContext): Any {
|
||||
return doDeserialize(context, null)!!
|
||||
}
|
||||
|
||||
private fun doDeserialize(context: ReadContext, hostObject: Any?): Any? {
|
||||
if (!context.configuration.allowAnySubTypes) {
|
||||
throw SerializationException("Polymorphic type without specified allowed sub types is forbidden")
|
||||
}
|
||||
@@ -24,7 +34,15 @@ internal class PolymorphicBinding(private val superClass: Class<*>) : Binding {
|
||||
val typeAnnotationIterator = reader.iterateTypeAnnotations()
|
||||
if (typeAnnotationIterator.hasNext()) {
|
||||
val className = typeAnnotationIterator.next()
|
||||
beanClass = (context.configuration.classLoader ?: javaClass.classLoader).loadClass(className)
|
||||
val loadClass = context.configuration.loadClass
|
||||
// loadClass for now doesn't support map or collection as host object
|
||||
if (loadClass == null || hostObject == null) {
|
||||
beanClass = javaClass.classLoader.loadClass(className)
|
||||
}
|
||||
else {
|
||||
beanClass = loadClass(className, hostObject) ?: return null
|
||||
}
|
||||
|
||||
if (!superClass.isAssignableFrom(beanClass)) {
|
||||
throw SerializationException("Class \"$className\" must be assignable to \"${superClass.name}\"")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.serialization
|
||||
|
||||
import com.amazon.ion.impl.bin.Block
|
||||
import com.amazon.ion.impl.bin.BlockAllocator
|
||||
import com.amazon.ion.impl.bin.BlockAllocatorProvider
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import java.util.*
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
internal class PooledBlockAllocatorProvider : BlockAllocatorProvider() {
|
||||
companion object {
|
||||
// 512 KB
|
||||
internal const val POOL_THRESHOLD = 512 * 1024
|
||||
}
|
||||
|
||||
@Suppress("RemoveExplicitTypeArguments")
|
||||
private val allocators = ContainerUtil.createConcurrentIntObjectMap<PooledBlockAllocator>()
|
||||
|
||||
private inner class PooledBlockAllocator(private val blockSize: Int) : BlockAllocator() {
|
||||
private val freeBlocks = ArrayList<Block>()
|
||||
|
||||
private val blockCounter = AtomicInteger()
|
||||
|
||||
val byteSize: Int
|
||||
get() = blockCounter.get() * blockSize
|
||||
|
||||
override fun allocateBlock(): Block {
|
||||
val lastIndex = freeBlocks.lastIndex
|
||||
if (lastIndex != -1) {
|
||||
return freeBlocks.removeAt(lastIndex)
|
||||
}
|
||||
|
||||
blockCounter.incrementAndGet()
|
||||
return object : Block(ByteArray(blockSize)) {
|
||||
override fun close() {
|
||||
reset()
|
||||
freeBlocks.add(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getBlockSize() = blockSize
|
||||
|
||||
override fun close() {
|
||||
if ((blockSize * freeBlocks.size) > POOL_THRESHOLD) {
|
||||
return
|
||||
}
|
||||
|
||||
if (allocators.putIfAbsent(blockSize, this) == null) {
|
||||
removeExcess()
|
||||
}
|
||||
else {
|
||||
// help GC - nullize
|
||||
freeBlocks.clear()
|
||||
blockCounter.set(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@get:TestOnly
|
||||
val byteSize: Int
|
||||
get() {
|
||||
var totalByteSize = 0
|
||||
for (allocator in allocators.elements()) {
|
||||
totalByteSize += allocator.byteSize
|
||||
}
|
||||
return totalByteSize
|
||||
}
|
||||
|
||||
override fun vendAllocator(blockSize: Int): BlockAllocator {
|
||||
if (blockSize <= 0) {
|
||||
throw IllegalArgumentException("Invalid block size: $blockSize")
|
||||
}
|
||||
|
||||
// PooledBlockAllocator is not thread safe - do not put a new one to pool
|
||||
val result = allocators.remove(blockSize) ?: PooledBlockAllocator(blockSize)
|
||||
|
||||
removeExcess()
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun removeExcess() {
|
||||
var totalByteSize = 0
|
||||
val iterator = allocators.values().iterator()
|
||||
var isExcess = false
|
||||
while (iterator.hasNext()) {
|
||||
val allocator = iterator.next()
|
||||
if (isExcess) {
|
||||
iterator.remove()
|
||||
continue
|
||||
}
|
||||
|
||||
totalByteSize += allocator.byteSize
|
||||
if (totalByteSize > POOL_THRESHOLD) {
|
||||
iterator.remove()
|
||||
isExcess = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,10 +41,9 @@ data class VersionedFile @JvmOverloads constructor(val file: Path, val version:
|
||||
|
||||
@Throws(IOException::class, SerializationException::class)
|
||||
@JvmOverloads
|
||||
fun <T> readList(itemClass: Class<T>, beanConstructed: BeanConstructed? = null): List<T>? {
|
||||
val configuration = ReadConfiguration(beanConstructed = beanConstructed)
|
||||
fun <T> readList(itemClass: Class<T>, configuration: ReadConfiguration = ReadConfiguration(), renameToCorruptedOnError: Boolean = true): List<T>? {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return readAndHandleErrors(ArrayList::class.java, configuration, originalType = ParameterizedTypeImpl(ArrayList::class.java, itemClass)) as List<T>?
|
||||
return readAndHandleErrors(ArrayList::class.java, configuration, originalType = ParameterizedTypeImpl(ArrayList::class.java, itemClass), renameToCorruptedOnError = renameToCorruptedOnError) as List<T>?
|
||||
}
|
||||
|
||||
@Throws(IOException::class, SerializationException::class)
|
||||
@@ -53,20 +52,22 @@ data class VersionedFile @JvmOverloads constructor(val file: Path, val version:
|
||||
return readAndHandleErrors(objectClass, ReadConfiguration(beanConstructed = beanConstructed))
|
||||
}
|
||||
|
||||
private fun <T : Any> readAndHandleErrors(objectClass: Class<T>, configuration: ReadConfiguration, originalType: Type? = null): T? {
|
||||
private fun <T : Any> readAndHandleErrors(objectClass: Class<T>, configuration: ReadConfiguration, originalType: Type? = null, renameToCorruptedOnError: Boolean = true): T? {
|
||||
return readPossiblyCompressedIonFile(file) { input ->
|
||||
val result = try {
|
||||
ObjectSerializer.instance.serializer.readVersioned(objectClass, input, file, version, originalType = originalType,
|
||||
configuration = configuration)
|
||||
}
|
||||
catch (e: Exception) {
|
||||
renameSilentlyToCorrupted()
|
||||
if (renameToCorruptedOnError) {
|
||||
renameSilentlyToCorrupted()
|
||||
}
|
||||
// in tests log will throw error, renameSilentlyToCorrupted is called before
|
||||
LOG.error(e)
|
||||
return null
|
||||
}
|
||||
|
||||
if (result == null) {
|
||||
if (result == null && renameToCorruptedOnError) {
|
||||
renameSilentlyToCorrupted()
|
||||
}
|
||||
return result
|
||||
|
||||
@@ -6,7 +6,8 @@ import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream
|
||||
import com.intellij.util.SmartList
|
||||
|
||||
data class ReadConfiguration(val allowAnySubTypes: Boolean = false,
|
||||
val classLoader: ClassLoader? = null,
|
||||
// loadClass for now doesn't support map or collection as host object
|
||||
val loadClass: ((name: String, hostObject: Any) -> Class<*>?)? = null,
|
||||
val beanConstructed: BeanConstructed? = null)
|
||||
|
||||
data class WriteConfiguration(val binary: Boolean = true,
|
||||
|
||||
@@ -166,7 +166,7 @@ private class DoubleBinding : Binding {
|
||||
}
|
||||
}
|
||||
|
||||
private class StringBinding : Binding {
|
||||
internal class StringBinding : Binding {
|
||||
override fun deserialize(context: ReadContext): Any {
|
||||
return context.reader.stringValue()
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ fun testThreadLocalPooledBlockAllocatorProvider() {
|
||||
|
||||
allocated += PooledBlockAllocatorProvider.POOL_THRESHOLD
|
||||
provider.vendAllocator(PooledBlockAllocatorProvider.POOL_THRESHOLD).use { it.allocateBlock() }
|
||||
assertThat(provider.byteSize).isEqualTo(allocated)
|
||||
assertThat(provider.byteSize).isLessThanOrEqualTo(2049)
|
||||
|
||||
provider.vendAllocator(PooledBlockAllocatorProvider.POOL_THRESHOLD + 1).use { it.allocateBlock() }
|
||||
assertThat(provider.byteSize).isLessThanOrEqualTo(allocated + 1)
|
||||
|
||||
@@ -13,7 +13,7 @@ class TestApp {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun main(args: Array<String>) {
|
||||
val inputFile = Paths.get(args[0])
|
||||
val inputFile = Paths.get(args[0].trim())
|
||||
val outFile = inputFile.parent.resolve(FileUtilRt.getNameWithoutExtension(inputFile.fileName.toString()) + "-text.ion")
|
||||
|
||||
readPossiblyCompressedIonFile(inputFile) { input ->
|
||||
|
||||
@@ -1,29 +1,24 @@
|
||||
{
|
||||
'@id':0,
|
||||
map:[
|
||||
],
|
||||
map:{
|
||||
},
|
||||
beanMap:[
|
||||
{
|
||||
'@id':1,
|
||||
map:[
|
||||
A,
|
||||
VB,
|
||||
Z,
|
||||
'123',
|
||||
'a-A',
|
||||
'123',
|
||||
foo,
|
||||
bar
|
||||
],
|
||||
map:{
|
||||
A:VB,
|
||||
Z:'123',
|
||||
'a-A':'123',
|
||||
foo:bar
|
||||
},
|
||||
beanMap:[
|
||||
]
|
||||
},
|
||||
{
|
||||
'@id':2,
|
||||
map:[
|
||||
'some key',
|
||||
'some value'
|
||||
],
|
||||
map:{
|
||||
'some key':'some value'
|
||||
},
|
||||
beanMap:[
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
'@id':0,
|
||||
map:0
|
||||
}
|
||||
+3
-4
@@ -1,10 +1,9 @@
|
||||
{
|
||||
'@id':0,
|
||||
shape:[
|
||||
first,
|
||||
'com.intellij.serialization.Circle'::{
|
||||
shape:{
|
||||
first:'com.intellij.serialization.Circle'::{
|
||||
'@id':1,
|
||||
name:null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
{
|
||||
'@id':0,
|
||||
map:[
|
||||
foo,
|
||||
bar
|
||||
],
|
||||
map:{
|
||||
foo:bar
|
||||
},
|
||||
beanMap:[
|
||||
]
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
{
|
||||
'@id':0,
|
||||
map:[
|
||||
bar,
|
||||
[
|
||||
map:{
|
||||
bar:[
|
||||
b
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -109,7 +109,7 @@ class ListTest {
|
||||
assertThat(file.file.readChars().trim()).isEqualToIgnoringNewLines("""
|
||||
{
|
||||
version:42,
|
||||
formatVersion:1,
|
||||
formatVersion:2,
|
||||
data:[
|
||||
foo,
|
||||
bar
|
||||
|
||||
@@ -68,6 +68,17 @@ class MapTest {
|
||||
assertThat(deserializedBean.map.values.first()).isInstanceOf(Set::class.java)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `empty map`() {
|
||||
class TestBean {
|
||||
@JvmField
|
||||
val map: MutableMap<String, Set<String>> = THashMap()
|
||||
}
|
||||
|
||||
val bean = TestBean()
|
||||
test(bean, defaultTestWriteConfiguration.copy(filter = SkipNullAndEmptySerializationFilter))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `bean map`() {
|
||||
val bean = TestMapBean()
|
||||
|
||||
@@ -51,7 +51,7 @@ class NonDefaultConstructorTest {
|
||||
file.file.write("""
|
||||
{
|
||||
version:42,
|
||||
formatVersion:1,
|
||||
formatVersion:2,
|
||||
data:{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,7 +188,7 @@ private class Rectangle : Shape {
|
||||
|
||||
|
||||
internal enum class TestEnum {
|
||||
RED, GREEN, BLUE
|
||||
RED, BLUE
|
||||
}
|
||||
|
||||
private class TestEnumBean {
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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.intellij.ide;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.util.ui.accessibility.ScreenReader;
|
||||
|
||||
/**
|
||||
* Keep {@link ScreenReader#isActive} in sync with {@link GeneralSettings#isSupportScreenReaders}
|
||||
*/
|
||||
public final class ScreenReaderSupportHandler implements Disposable {
|
||||
public ScreenReaderSupportHandler() {
|
||||
GeneralSettings generalSettings = GeneralSettings.getInstance();
|
||||
generalSettings.addPropertyChangeListener(GeneralSettings.PROP_SUPPORT_SCREEN_READERS, this, e -> ScreenReader.setActive((Boolean)e.getNewValue()));
|
||||
ScreenReader.setActive(generalSettings.isSupportScreenReaders());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
}
|
||||
@@ -6,14 +6,10 @@ import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.util.xmlb.annotations.MapAnnotation;
|
||||
import com.intellij.util.xmlb.annotations.Tag;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.event.InputEvent;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Konstantin Bulenkov
|
||||
@@ -54,16 +50,4 @@ public abstract class ActionsCollector {
|
||||
public abstract void record(@Nullable Project project, @Nullable AnAction action, @Nullable AnActionEvent event, @Nullable Language lang);
|
||||
|
||||
public abstract void onActionConfiguredByActionId(@NotNull AnAction action, @NotNull String actionId);
|
||||
|
||||
public abstract State getState();
|
||||
|
||||
public final static class State {
|
||||
@Tag("counts")
|
||||
@MapAnnotation(surroundWithTag = false, keyAttributeName = "action", valueAttributeName = "count")
|
||||
public Map<String, Integer> myValues = new HashMap<>();
|
||||
|
||||
@Tag("contextMenuCounts")
|
||||
@MapAnnotation(surroundWithTag = false, keyAttributeName = "action", valueAttributeName = "count")
|
||||
public Map<String, Integer> myContextMenuValues = new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
+7
-6
@@ -3,6 +3,7 @@ package com.intellij.internal.statistic.eventLog
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.openapi.options.Configurable
|
||||
|
||||
fun getUiEventLogger(): FeatureUsageUiEvents {
|
||||
if (ApplicationManager.getApplication() != null) {
|
||||
@@ -13,11 +14,11 @@ fun getUiEventLogger(): FeatureUsageUiEvents {
|
||||
}
|
||||
|
||||
interface FeatureUsageUiEvents {
|
||||
fun logSelectConfigurable(name: String, context: Class<*>)
|
||||
fun logSelectConfigurable(configurable: Configurable)
|
||||
|
||||
fun logApplyConfigurable(name: String, context: Class<*>)
|
||||
fun logApplyConfigurable(configurable: Configurable)
|
||||
|
||||
fun logResetConfigurable(name: String, context: Class<*>)
|
||||
fun logResetConfigurable(configurable: Configurable)
|
||||
|
||||
fun logShowDialog(name: String, context: Class<*>)
|
||||
|
||||
@@ -25,13 +26,13 @@ interface FeatureUsageUiEvents {
|
||||
}
|
||||
|
||||
object EmptyFeatureUsageUiEvents : FeatureUsageUiEvents {
|
||||
override fun logSelectConfigurable(name: String, context: Class<*>) {
|
||||
override fun logSelectConfigurable(configurable: Configurable) {
|
||||
}
|
||||
|
||||
override fun logApplyConfigurable(name: String, context: Class<*>) {
|
||||
override fun logApplyConfigurable(configurable: Configurable) {
|
||||
}
|
||||
|
||||
override fun logResetConfigurable(name: String, context: Class<*>) {
|
||||
override fun logResetConfigurable(configurable: Configurable) {
|
||||
}
|
||||
|
||||
override fun logShowDialog(name: String, context: Class<*>) {
|
||||
|
||||
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2019 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.
|
||||
*/
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.openapi.wm;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
@@ -110,8 +96,12 @@ public interface StatusBar extends StatusBarInfo, Disposable {
|
||||
|
||||
StatusBar findChild(Component c);
|
||||
|
||||
@Nullable
|
||||
IdeFrame getFrame();
|
||||
|
||||
@Nullable
|
||||
Project getProject();
|
||||
|
||||
void install(IdeFrame frame);
|
||||
|
||||
class Anchors {
|
||||
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2009 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 com.intellij.openapi.wm;
|
||||
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.EventListener;
|
||||
|
||||
/**
|
||||
* @deprecated use StatusBarWidget instead
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class StatusBarCustomComponentFactory<T extends JComponent> implements EventListener {
|
||||
public static final ExtensionPointName<StatusBarCustomComponentFactory> EP_NAME = ExtensionPointName.create("com.intellij.statusBarComponent");
|
||||
|
||||
public abstract T createComponent(@NotNull final StatusBar statusBar);
|
||||
|
||||
public void disposeComponent(@NotNull StatusBar statusBar, @NotNull final T c) {
|
||||
}
|
||||
}
|
||||
+12
-6
@@ -225,12 +225,11 @@ private fun writeParallelActivities(activities: Map<String, MutableList<Activity
|
||||
val list = activities.getValue(name)
|
||||
StartUpPerformanceReporter.sortItems(list)
|
||||
|
||||
var measureThreshold = if (name == ParallelActivity.PREPARE_APP_INIT.jsonName || name == ParallelActivity.REOPENING_EDITOR.jsonName) -1 else ParallelActivity.MEASURE_THRESHOLD
|
||||
if (name.endsWith("Component")) {
|
||||
measureThreshold = 0
|
||||
computeOwnTime(list, ownDurations)
|
||||
}
|
||||
|
||||
val measureThreshold = if (name == ParallelActivity.PREPARE_APP_INIT.jsonName || name == ParallelActivity.REOPENING_EDITOR.jsonName) -1 else ParallelActivity.MEASURE_THRESHOLD
|
||||
writeActivities(list, startTime, writer, activityNameToJsonFieldName(name), ownDurations, pluginCostMap, measureThreshold = measureThreshold)
|
||||
}
|
||||
}
|
||||
@@ -253,14 +252,12 @@ private fun writeActivities(activities: List<ActivityImpl>,
|
||||
}
|
||||
|
||||
writer.array(fieldName) {
|
||||
var skippedDuration = 0L
|
||||
for (item in activities) {
|
||||
val computedOwnDuration = ownDurations.get(item)
|
||||
val duration = if (computedOwnDuration == -1L) item.end - item.start else computedOwnDuration
|
||||
if (duration <= measureThreshold) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (measureThreshold == 0L && TimeUnit.NANOSECONDS.toMillis(duration) == 0L) {
|
||||
skippedDuration += duration
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -273,6 +270,15 @@ private fun writeActivities(activities: List<ActivityImpl>,
|
||||
writeItemTimeInfo(item, duration, offset, writer)
|
||||
}
|
||||
}
|
||||
|
||||
if (skippedDuration > 0) {
|
||||
writer.obj {
|
||||
writer.writeStringField("name", "Other")
|
||||
writer.writeNumberField("duration", TimeUnit.NANOSECONDS.toMillis(skippedDuration))
|
||||
writer.writeNumberField("start", TimeUnit.NANOSECONDS.toMillis(activities.last().start - offset))
|
||||
writer.writeNumberField("end", TimeUnit.NANOSECONDS.toMillis(activities.last().end - offset))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-1
@@ -5,6 +5,7 @@ import com.fasterxml.jackson.core.JsonGenerator
|
||||
import com.intellij.diagnostic.ActivityImpl
|
||||
import com.intellij.ide.plugins.IdeaPluginDescriptorImpl
|
||||
import com.intellij.ide.plugins.PluginManagerCore
|
||||
import com.intellij.ide.plugins.cl.PluginClassLoader
|
||||
import com.intellij.util.containers.ObjectLongHashMap
|
||||
import com.intellij.util.io.jackson.obj
|
||||
import java.util.concurrent.TimeUnit
|
||||
@@ -75,7 +76,6 @@ internal fun writeServiceStats(writer: JsonGenerator) {
|
||||
|
||||
writer.obj("stats") {
|
||||
writer.writeNumberField("plugin", plugins.size)
|
||||
|
||||
for (statItem in listOf(component, service)) {
|
||||
writer.obj(statItem.name) {
|
||||
writer.writeNumberField("app", statItem.app)
|
||||
@@ -83,5 +83,15 @@ internal fun writeServiceStats(writer: JsonGenerator) {
|
||||
writer.writeNumberField("module", statItem.module)
|
||||
}
|
||||
}
|
||||
|
||||
writer.obj("loadedClasses") {
|
||||
for (plugin in plugins) {
|
||||
val classLoader = (plugin as IdeaPluginDescriptorImpl).pluginClassLoader as? PluginClassLoader ?: continue
|
||||
val classCount = classLoader.loadedClassCount
|
||||
if (classCount > 0) {
|
||||
writer.writeNumberField(plugin.pluginId.idString, classCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package com.intellij.ide;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.wm.IdeFrame;
|
||||
import com.intellij.util.messages.Topic;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -34,13 +33,6 @@ public interface AppLifecycleListener {
|
||||
default void appStarting(@Nullable Project projectFromCommandLine) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after an application frame is shown.
|
||||
*/
|
||||
default void appStarting(@Nullable Project projectFromCommandLine, IdeFrame frame) {
|
||||
appStarting(projectFromCommandLine);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a project frame is closed.
|
||||
*/
|
||||
|
||||
@@ -677,10 +677,13 @@ public final class IdeEventQueue extends EventQueue {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e instanceof InputEvent)
|
||||
if (e instanceof InputEvent && SystemInfoRt.isMac) {
|
||||
TouchBarsManager.onInputEvent((InputEvent)e);
|
||||
}
|
||||
|
||||
if (dispatchByCustomDispatchers(e)) return;
|
||||
if (dispatchByCustomDispatchers(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e instanceof InputMethodEvent) {
|
||||
if (SystemInfoRt.isMac && myKeyEventDispatcher.isWaitingForSecondKeyStroke()) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.ide;
|
||||
|
||||
import com.intellij.openapi.components.RoamingType;
|
||||
@@ -7,7 +7,6 @@ import com.intellij.openapi.components.Storage;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.platform.ProjectBaseDirectory;
|
||||
import com.intellij.util.messages.MessageBus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.SystemIndependent;
|
||||
@@ -15,10 +14,6 @@ import org.jetbrains.annotations.SystemIndependent;
|
||||
// todo the only difference - usage of ProjectBaseDirectory Is it really make sense?
|
||||
@State(name = "RecentDirectoryProjectsManager", storages = @Storage(value = "recentProjectDirectories.xml", roamingType = RoamingType.DISABLED))
|
||||
public class RecentDirectoryProjectsManager extends RecentProjectsManagerBase {
|
||||
public RecentDirectoryProjectsManager(@NotNull MessageBus messageBus) {
|
||||
super(messageBus);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
@SystemIndependent
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
package com.intellij.ide;
|
||||
|
||||
import com.intellij.configurationStore.StorageUtilKt;
|
||||
import com.intellij.diagnostic.Activity;
|
||||
import com.intellij.diagnostic.StartUpMeasurer;
|
||||
import com.intellij.ide.impl.ProjectUtil;
|
||||
import com.intellij.idea.SplashManager;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.application.ApplicationInfo;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
@@ -24,14 +27,14 @@ import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.wm.IdeFrame;
|
||||
import com.intellij.openapi.wm.WindowManager;
|
||||
import com.intellij.openapi.wm.impl.SystemDock;
|
||||
import com.intellij.openapi.wm.impl.WindowManagerImpl;
|
||||
import com.intellij.openapi.wm.impl.welcomeScreen.RecentProjectPanel;
|
||||
import com.intellij.platform.PlatformProjectOpenProcessor;
|
||||
import com.intellij.project.ProjectKt;
|
||||
import com.intellij.util.*;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.messages.MessageBus;
|
||||
import com.intellij.util.messages.MessageBusConnection;
|
||||
import gnu.trove.THashMap;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -170,12 +173,6 @@ public class RecentProjectsManagerBase extends RecentProjectsManager implements
|
||||
|
||||
private boolean myBatchOpening;
|
||||
|
||||
protected RecentProjectsManagerBase(@NotNull MessageBus messageBus) {
|
||||
MessageBusConnection connection = messageBus.connect();
|
||||
connection.subscribe(AppLifecycleListener.TOPIC, new MyAppLifecycleListener());
|
||||
connection.subscribe(ProjectManager.TOPIC, new MyProjectListener());
|
||||
}
|
||||
|
||||
@Override
|
||||
public State getState() {
|
||||
synchronized (myStateLock) {
|
||||
@@ -504,12 +501,11 @@ public class RecentProjectsManagerBase extends RecentProjectsManager implements
|
||||
|
||||
@Nullable
|
||||
public Project doOpenProject(@NotNull @SystemIndependent String projectPath,
|
||||
Project projectToClose,
|
||||
@Nullable Project projectToClose,
|
||||
boolean forceOpenInNewFrame,
|
||||
@Nullable IdeFrame frame) {
|
||||
VirtualFile dotIdea = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(
|
||||
new File(projectPath, Project.DIRECTORY_STORE_FOLDER));
|
||||
|
||||
VirtualFile dotIdea = LocalFileSystem.getInstance()
|
||||
.refreshAndFindFileByPath(FileUtilRt.toSystemIndependentName(projectPath) + "/" + Project.DIRECTORY_STORE_FOLDER);
|
||||
if (dotIdea != null) {
|
||||
EnumSet<PlatformProjectOpenProcessor.Option> options = EnumSet.of(PlatformProjectOpenProcessor.Option.REOPEN);
|
||||
if (forceOpenInNewFrame) options.add(PlatformProjectOpenProcessor.Option.FORCE_NEW_FRAME);
|
||||
@@ -524,18 +520,20 @@ public class RecentProjectsManagerBase extends RecentProjectsManager implements
|
||||
}
|
||||
}
|
||||
|
||||
private class MyProjectListener implements ProjectManagerListener {
|
||||
static final class MyProjectListener implements ProjectManagerListener {
|
||||
private final RecentProjectsManagerBase manager = getInstanceEx();
|
||||
|
||||
@Override
|
||||
public void projectOpened(@NotNull final Project project) {
|
||||
String path = getProjectPath(project);
|
||||
String path = manager.getProjectPath(project);
|
||||
if (path != null) {
|
||||
markPathRecent(path, project);
|
||||
manager.markPathRecent(path, project);
|
||||
}
|
||||
updateLastProjectPath();
|
||||
manager.updateLastProjectPath();
|
||||
updateSystemDockMenu();
|
||||
}
|
||||
|
||||
private void updateSystemDockMenu() {
|
||||
private static void updateSystemDockMenu() {
|
||||
if (!ApplicationManager.getApplication().isHeadlessEnvironment()) {
|
||||
SystemDock.updateMenu();
|
||||
}
|
||||
@@ -543,14 +541,14 @@ public class RecentProjectsManagerBase extends RecentProjectsManager implements
|
||||
|
||||
@Override
|
||||
public void projectClosing(@NotNull Project project) {
|
||||
String path = getProjectPath(project);
|
||||
String path = manager.getProjectPath(project);
|
||||
if (path == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (myStateLock) {
|
||||
myState.names.put(path, getProjectDisplayName(project));
|
||||
myNameCache.put(path, project.getName());
|
||||
synchronized (manager.myStateLock) {
|
||||
manager.myState.names.put(path, manager.getProjectDisplayName(project));
|
||||
manager.myNameCache.put(path, project.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -559,9 +557,9 @@ public class RecentProjectsManagerBase extends RecentProjectsManager implements
|
||||
Project[] openProjects = ProjectManager.getInstance().getOpenProjects();
|
||||
if (openProjects.length > 0) {
|
||||
Project openProject = openProjects[openProjects.length - 1];
|
||||
String path = getProjectPath(openProject);
|
||||
String path = manager.getProjectPath(openProject);
|
||||
if (path != null) {
|
||||
markPathRecent(path, openProject);
|
||||
manager.markPathRecent(path, openProject);
|
||||
}
|
||||
}
|
||||
updateSystemDockMenu();
|
||||
@@ -611,12 +609,11 @@ public class RecentProjectsManagerBase extends RecentProjectsManager implements
|
||||
}
|
||||
|
||||
protected boolean willReopenProjectOnStart() {
|
||||
return GeneralSettings.getInstance().isReopenLastProject() && getLastProjectPath() != null;
|
||||
return getLastProjectPath() != null && GeneralSettings.getInstance().isReopenLastProject();
|
||||
}
|
||||
|
||||
protected void doReopenLastProject(IdeFrame frame) {
|
||||
GeneralSettings generalSettings = GeneralSettings.getInstance();
|
||||
if (!generalSettings.isReopenLastProject()) {
|
||||
protected void doReopenLastProject(@Nullable IdeFrame frame) {
|
||||
if (!GeneralSettings.getInstance().isReopenLastProject()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -630,6 +627,12 @@ public class RecentProjectsManagerBase extends RecentProjectsManager implements
|
||||
}
|
||||
}
|
||||
|
||||
if (!openPaths.isEmpty() && frame == null) {
|
||||
Activity activity = StartUpMeasurer.start("showFrame");
|
||||
frame = ((WindowManagerImpl)WindowManager.getInstance()).showFrame(SplashManager.getHideTask());
|
||||
activity.end();
|
||||
}
|
||||
|
||||
try {
|
||||
myBatchOpening = true;
|
||||
boolean usedFrame = false;
|
||||
@@ -681,33 +684,35 @@ public class RecentProjectsManagerBase extends RecentProjectsManager implements
|
||||
return myModCounter.get();
|
||||
}
|
||||
|
||||
private final class MyAppLifecycleListener implements AppLifecycleListener {
|
||||
static final class MyAppLifecycleListener implements AppLifecycleListener {
|
||||
private final RecentProjectsManagerBase manager = getInstanceEx();
|
||||
|
||||
@Override
|
||||
public void appFrameCreated(@NotNull List<String> commandLineArgs, @NotNull final Ref<? super Boolean> willOpenProject) {
|
||||
if (willReopenProjectOnStart()) {
|
||||
if (manager.willReopenProjectOnStart()) {
|
||||
willOpenProject.set(Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appStarting(@Nullable Project projectFromCommandLine, IdeFrame frame) {
|
||||
public void appStarting(@Nullable Project projectFromCommandLine) {
|
||||
if (projectFromCommandLine != null || JetBrainsProtocolHandler.appStartedWithCommand()) {
|
||||
return;
|
||||
}
|
||||
|
||||
doReopenLastProject(frame);
|
||||
manager.doReopenLastProject(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void projectOpenFailed() {
|
||||
updateLastProjectPath();
|
||||
manager.updateLastProjectPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void projectFrameClosed() {
|
||||
// ProjectManagerListener.projectClosed cannot be used to call updateLastProjectPath,
|
||||
// because called even if project closed on app exit
|
||||
updateLastProjectPath();
|
||||
manager.updateLastProjectPath();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+27
-10
@@ -24,12 +24,12 @@ import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.wm.ex.WindowManagerEx;
|
||||
import com.intellij.openapi.wm.impl.IdeFrameImpl;
|
||||
import com.intellij.ui.mac.touchbar.TouchBarsManager;
|
||||
import com.intellij.util.ImageLoader;
|
||||
import com.intellij.util.ui.JBImageIcon;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
@@ -40,7 +40,7 @@ import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
@State(name = "com.intellij.ide.ui.customization.CustomActionsSchema", storages = @Storage("customization.xml"))
|
||||
public class CustomActionsSchema implements PersistentStateComponent<Element> {
|
||||
public final class CustomActionsSchema implements PersistentStateComponent<Element> {
|
||||
private static final Logger LOG = Logger.getInstance(CustomActionsSchema.class);
|
||||
|
||||
@NonNls private static final String ACTIONS_SCHEMA = "custom_actions_schema";
|
||||
@@ -72,10 +72,13 @@ public class CustomActionsSchema implements PersistentStateComponent<Element> {
|
||||
myIdToName.put(IdeActions.GROUP_J2EE_VIEW_POPUP, ActionsTreeUtil.J2EE_POPUP);
|
||||
myIdToName.put(IdeActions.GROUP_NAVBAR_POPUP, "Navigation Bar");
|
||||
myIdToName.put("NavBarToolBar", "Navigation Bar Toolbar");
|
||||
if (TouchBarsManager.isTouchBarAvailable())
|
||||
myIdToName.put(IdeActions.GROUP_TOUCHBAR, "Touch Bar");
|
||||
|
||||
ArrayList<Couple<String>> extList = new ArrayList<>();
|
||||
// todo is it safe to not check so early?
|
||||
//if (TouchBarsManager.isTouchBarAvailable()) {
|
||||
// myIdToName.put(IdeActions.GROUP_TOUCHBAR, "Touch Bar");
|
||||
//}
|
||||
|
||||
List<Couple<String>> extList = new ArrayList<>();
|
||||
CustomizableActionGroupProvider.CustomizableActionGroupRegistrar registrar =
|
||||
(groupId, groupTitle) -> extList.add(Couple.of(groupId, groupTitle));
|
||||
for (CustomizableActionGroupProvider provider : CustomizableActionGroupProvider.EP_NAME.getExtensions()) {
|
||||
@@ -87,6 +90,15 @@ public class CustomActionsSchema implements PersistentStateComponent<Element> {
|
||||
}
|
||||
}
|
||||
|
||||
public void touchBarAvailable(boolean value) {
|
||||
if (value) {
|
||||
myIdToName.put(IdeActions.GROUP_TOUCHBAR, "Touch Bar");
|
||||
}
|
||||
else {
|
||||
myIdToName.remove(IdeActions.GROUP_TOUCHBAR);
|
||||
}
|
||||
}
|
||||
|
||||
public static CustomActionsSchema getInstance() {
|
||||
return ServiceManager.getService(CustomActionsSchema.class);
|
||||
}
|
||||
@@ -159,9 +171,9 @@ public class CustomActionsSchema implements PersistentStateComponent<Element> {
|
||||
String activeName = element.getAttributeValue(ACTIVE);
|
||||
if (activeName != null) {
|
||||
for (Element toolbarElement : element.getChildren(ACTIONS_SCHEMA)) {
|
||||
for (Object o : toolbarElement.getChildren("option")) {
|
||||
if (Comparing.strEqual(((Element)o).getAttributeValue("name"), "myName") &&
|
||||
Comparing.strEqual(((Element)o).getAttributeValue("value"), activeName)) {
|
||||
for (Element o : toolbarElement.getChildren("option")) {
|
||||
if (Comparing.strEqual(o.getAttributeValue("name"), "myName") &&
|
||||
Comparing.strEqual(o.getAttributeValue("value"), activeName)) {
|
||||
schElement = toolbarElement;
|
||||
break;
|
||||
}
|
||||
@@ -243,12 +255,17 @@ public class CustomActionsSchema implements PersistentStateComponent<Element> {
|
||||
return element;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public AnAction getCorrectedAction(String id) {
|
||||
if (!myIdToName.containsKey(id)) {
|
||||
return ActionManager.getInstance().getAction(id);
|
||||
}
|
||||
|
||||
ActionGroup existing = myIdToActionGroup.get(id);
|
||||
if (existing != null) return existing;
|
||||
if (existing != null) {
|
||||
return existing;
|
||||
}
|
||||
|
||||
ActionGroup actionGroup = (ActionGroup)ActionManager.getInstance().getAction(id);
|
||||
if (actionGroup != null) { // if a plugin is disabled
|
||||
String name = myIdToName.get(id);
|
||||
@@ -269,7 +286,6 @@ public class CustomActionsSchema implements PersistentStateComponent<Element> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean isCorrectActionGroup(ActionGroup group, String defaultGroupName) {
|
||||
if (myActions.isEmpty()) {
|
||||
return false;
|
||||
@@ -294,6 +310,7 @@ public class CustomActionsSchema implements PersistentStateComponent<Element> {
|
||||
return true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<ActionUrl> getChildActions(ActionUrl url) {
|
||||
ArrayList<ActionUrl> result = new ArrayList<>();
|
||||
ArrayList<String> groupPath = url.getGroupPath();
|
||||
|
||||
+5
-2
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.ide.ui.customization;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
@@ -19,6 +19,7 @@ import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.SystemInfoRt;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
@@ -184,7 +185,9 @@ public class CustomizableActionsPanel {
|
||||
restorePathsAfterTreeOptimization(treePaths);
|
||||
CustomActionsSchema.getInstance().copyFrom(mySelectedSchema);
|
||||
CustomActionsSchema.setCustomizationSchemaForCurrentProjects();
|
||||
TouchBarsManager.reloadAll();
|
||||
if (SystemInfoRt.isMac) {
|
||||
TouchBarsManager.reloadAll();
|
||||
}
|
||||
}
|
||||
|
||||
private void restorePathsAfterTreeOptimization(final List<? extends TreePath> treePaths) {
|
||||
|
||||
@@ -9,9 +9,11 @@ import com.intellij.ide.plugins.IdeaPluginDescriptor;
|
||||
import com.intellij.ide.plugins.MainRunner;
|
||||
import com.intellij.ide.plugins.PluginManager;
|
||||
import com.intellij.ide.plugins.PluginManagerCore;
|
||||
import com.intellij.ide.ui.customization.CustomActionsSchema;
|
||||
import com.intellij.openapi.application.*;
|
||||
import com.intellij.openapi.application.ex.ApplicationManagerEx;
|
||||
import com.intellij.openapi.application.impl.ApplicationImpl;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogEarthquakeShaker;
|
||||
@@ -31,8 +33,10 @@ import com.intellij.ui.AppIcon;
|
||||
import com.intellij.ui.AppUIUtil;
|
||||
import com.intellij.ui.CustomProtocolHandler;
|
||||
import com.intellij.ui.mac.MacOSApplicationProvider;
|
||||
import com.intellij.ui.mac.touchbar.TouchBarsManager;
|
||||
import com.intellij.util.ArrayUtilRt;
|
||||
import com.intellij.util.concurrency.AppExecutorUtil;
|
||||
import com.intellij.util.ui.accessibility.ScreenReader;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -59,74 +63,7 @@ public final class IdeaApplication {
|
||||
public static void initApplication(@NotNull String[] rawArgs) {
|
||||
Activity initAppActivity = MainRunner.startupStart.endAndStart(Phases.INIT_APP);
|
||||
CompletableFuture<List<IdeaPluginDescriptor>> pluginDescriptorsFuture = new CompletableFuture<>();
|
||||
EventQueue.invokeLater(() -> {
|
||||
String[] args = processProgramArguments(rawArgs);
|
||||
|
||||
ApplicationStarter starter = createAppStarter(args, pluginDescriptorsFuture);
|
||||
|
||||
Activity createAppActivity = StartUpMeasurer.start("create app");
|
||||
boolean headless = Main.isHeadless();
|
||||
ApplicationImpl app = new ApplicationImpl(Boolean.getBoolean(PluginManagerCore.IDEA_IS_INTERNAL_PROPERTY), false, headless,
|
||||
Main.isCommandLine(), ApplicationManagerEx.IDEA_APPLICATION);
|
||||
createAppActivity.end();
|
||||
|
||||
if (!headless) {
|
||||
// todo investigate why in test mode dummy icon manager is not suitable
|
||||
IconLoader.activate();
|
||||
IconLoader.setStrictGlobally(app.isInternal());
|
||||
}
|
||||
|
||||
starter.premain(args);
|
||||
|
||||
CompletableFuture<Void> registerComponentsFuture = pluginDescriptorsFuture
|
||||
.thenCompose(pluginDescriptors -> {
|
||||
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
|
||||
Activity activity = ParallelActivity.PREPARE_APP_INIT.start("add registry keys");
|
||||
RegistryKeyBean.addKeysFromPlugins();
|
||||
activity.end();
|
||||
|
||||
Activity busActivity = ParallelActivity.PREPARE_APP_INIT.start("add message bus listeners");
|
||||
ApplicationImpl.registerMessageBusListeners(app, pluginDescriptors, false);
|
||||
busActivity.end();
|
||||
}, AppExecutorUtil.getAppExecutorService());
|
||||
|
||||
Activity activity = ParallelActivity.PREPARE_APP_INIT.start("app component registration");
|
||||
((ApplicationImpl)ApplicationManager.getApplication()).registerComponents(pluginDescriptors);
|
||||
activity.end();
|
||||
|
||||
return future;
|
||||
});
|
||||
|
||||
if (!headless) {
|
||||
SplashManager.showLicenseeInfoOnSplash(LOG);
|
||||
}
|
||||
|
||||
// this invokeLater() call is needed to place the app starting code on a freshly minted IdeEventQueue instance
|
||||
Activity placeOnEventQueueActivity = initAppActivity.startChild(Phases.PLACE_ON_EVENT_QUEUE);
|
||||
EventQueue.invokeLater(() -> {
|
||||
placeOnEventQueueActivity.end();
|
||||
StartupUtil.installExceptionHandler();
|
||||
initAppActivity.end();
|
||||
try {
|
||||
Activity activity = StartUpMeasurer.start(Phases.WAIT_PLUGIN_INIT);
|
||||
registerComponentsFuture.get();
|
||||
activity.end();
|
||||
}
|
||||
catch (InterruptedException | ExecutionException e) {
|
||||
throw new CompletionException(e);
|
||||
}
|
||||
|
||||
app.load(null, SplashManager.getProgressIndicator());
|
||||
if (!headless) {
|
||||
addActivateAndWindowsCliListeners(app);
|
||||
}
|
||||
((TransactionGuardImpl)TransactionGuard.getInstance()).performUserActivity(() -> starter.main(args));
|
||||
|
||||
if (PluginManagerCore.isRunningFromSources()) {
|
||||
AppExecutorUtil.getAppExecutorService().execute(() -> AppUIUtil.updateWindowIcon(JOptionPane.getRootFrame()));
|
||||
}
|
||||
});
|
||||
});
|
||||
EventQueue.invokeLater(() -> executeInitAppInEdt(rawArgs, initAppActivity, pluginDescriptorsFuture));
|
||||
|
||||
List<IdeaPluginDescriptor> plugins;
|
||||
try {
|
||||
@@ -139,6 +76,100 @@ public final class IdeaApplication {
|
||||
pluginDescriptorsFuture.complete(plugins);
|
||||
}
|
||||
|
||||
private static void executeInitAppInEdt(@NotNull String[] rawArgs, @NotNull Activity initAppActivity,
|
||||
@NotNull CompletableFuture<List<IdeaPluginDescriptor>> pluginDescriptorsFuture) {
|
||||
String[] args = processProgramArguments(rawArgs);
|
||||
|
||||
ApplicationStarter starter = createAppStarter(args, pluginDescriptorsFuture);
|
||||
|
||||
Activity createAppActivity = initAppActivity.startChild("create app");
|
||||
boolean headless = Main.isHeadless();
|
||||
ApplicationImpl app = new ApplicationImpl(Boolean.getBoolean(PluginManagerCore.IDEA_IS_INTERNAL_PROPERTY), false, headless,
|
||||
Main.isCommandLine(), ApplicationManagerEx.IDEA_APPLICATION);
|
||||
createAppActivity.end();
|
||||
|
||||
if (!headless) {
|
||||
// todo investigate why in test mode dummy icon manager is not suitable
|
||||
IconLoader.activate();
|
||||
IconLoader.setStrictGlobally(app.isInternal());
|
||||
|
||||
if (SystemInfoRt.isMac) {
|
||||
Activity activity = initAppActivity.startChild("mac app init");
|
||||
MacOSApplicationProvider.initApplication();
|
||||
activity.end();
|
||||
}
|
||||
}
|
||||
|
||||
starter.premain(args);
|
||||
|
||||
List<Future<?>> futures = new ArrayList<>();
|
||||
futures.add(registerRegistryAndMessageBusAndComponent(pluginDescriptorsFuture, app));
|
||||
|
||||
if (!headless) {
|
||||
if (SystemInfoRt.isMac) {
|
||||
// ensure that TouchBarsManager is loaded before WelcomeFrame/project
|
||||
futures.add(AppExecutorUtil.getAppExecutorService().submit(() -> {
|
||||
Activity activity = ParallelActivity.PREPARE_APP_INIT.start("mac touchbar");
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
TouchBarsManager.isTouchBarAvailable();
|
||||
activity.end();
|
||||
}));
|
||||
}
|
||||
SplashManager.showLicenseeInfoOnSplash(LOG);
|
||||
}
|
||||
|
||||
// this invokeLater() call is needed to place the app starting code on a freshly minted IdeEventQueue instance
|
||||
Activity placeOnEventQueueActivity = initAppActivity.startChild(Phases.PLACE_ON_EVENT_QUEUE);
|
||||
EventQueue.invokeLater(() -> {
|
||||
placeOnEventQueueActivity.end();
|
||||
StartupUtil.installExceptionHandler();
|
||||
initAppActivity.end();
|
||||
try {
|
||||
Activity activity = StartUpMeasurer.start(Phases.WAIT_PLUGIN_INIT);
|
||||
for (Future<?> future : futures) {
|
||||
future.get();
|
||||
}
|
||||
activity.end();
|
||||
}
|
||||
catch (InterruptedException | ExecutionException e) {
|
||||
throw new CompletionException(e);
|
||||
}
|
||||
|
||||
app.load(null, SplashManager.getProgressIndicator());
|
||||
if (!headless) {
|
||||
addActivateAndWindowsCliListeners(app);
|
||||
}
|
||||
((TransactionGuardImpl)TransactionGuard.getInstance()).performUserActivity(() -> starter.main(args));
|
||||
|
||||
if (PluginManagerCore.isRunningFromSources()) {
|
||||
AppExecutorUtil.getAppExecutorService().execute(() -> AppUIUtil.updateWindowIcon(JOptionPane.getRootFrame()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static CompletableFuture<Void> registerRegistryAndMessageBusAndComponent(@NotNull CompletableFuture<List<IdeaPluginDescriptor>> pluginDescriptorsFuture,
|
||||
@NotNull ApplicationImpl app) {
|
||||
return pluginDescriptorsFuture
|
||||
.thenCompose(pluginDescriptors -> {
|
||||
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
|
||||
Activity activity = ParallelActivity.PREPARE_APP_INIT.start("add registry keys");
|
||||
RegistryKeyBean.addKeysFromPlugins();
|
||||
activity.end();
|
||||
|
||||
Activity busActivity = ParallelActivity.PREPARE_APP_INIT.start("add message bus listeners");
|
||||
ApplicationImpl.registerMessageBusListeners(app, pluginDescriptors, false);
|
||||
busActivity.end();
|
||||
}, AppExecutorUtil.getAppExecutorService());
|
||||
|
||||
Activity activity = ParallelActivity.PREPARE_APP_INIT.start("app component registration");
|
||||
((ApplicationImpl)ApplicationManager.getApplication()).registerComponents(pluginDescriptors);
|
||||
activity.end();
|
||||
|
||||
return future;
|
||||
});
|
||||
}
|
||||
|
||||
private static void addActivateAndWindowsCliListeners(@NotNull ApplicationImpl app) {
|
||||
StartupUtil.addExternalInstanceListener(args -> {
|
||||
AtomicReference<Future<? extends CliResult>> ref = new AtomicReference<>();
|
||||
@@ -187,19 +218,30 @@ public final class IdeaApplication {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static ApplicationStarter createAppStarter(@NotNull String[] args, @Nullable Future<?> pluginsLoaded) {
|
||||
private static ApplicationStarter createAppStarter(@NotNull String[] args, @NotNull Future<?> pluginsLoaded) {
|
||||
LOG.assertTrue(!ApplicationManagerEx.isAppLoaded());
|
||||
|
||||
LoadingPhase.setCurrentPhase(LoadingPhase.SPLASH);
|
||||
|
||||
StartupUtil.patchSystem(LOG);
|
||||
ApplicationStarter starter = getStarter(args, pluginsLoaded);
|
||||
|
||||
if (Main.isHeadless() && !starter.isHeadless()) {
|
||||
Main.showMessage("Startup Error", "Application cannot start in headless mode", true);
|
||||
System.exit(Main.NO_GRAPHICS);
|
||||
if (args.length <= 0) {
|
||||
return new IdeStarter();
|
||||
}
|
||||
return starter;
|
||||
|
||||
try {
|
||||
pluginsLoaded.get();
|
||||
}
|
||||
catch (InterruptedException | ExecutionException e) {
|
||||
throw new CompletionException(e);
|
||||
}
|
||||
|
||||
ApplicationStarter starter = findStarter(args[0]);
|
||||
if (starter != null) {
|
||||
if (Main.isHeadless() && !starter.isHeadless()) {
|
||||
Main.showMessage("Startup Error", "Application cannot start in headless mode", true);
|
||||
System.exit(Main.NO_GRAPHICS);
|
||||
}
|
||||
return starter;
|
||||
}
|
||||
return new IdeStarter();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -230,30 +272,6 @@ public final class IdeaApplication {
|
||||
return ArrayUtilRt.toStringArray(arguments);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static ApplicationStarter getStarter(@NotNull String[] args, @Nullable Future<?> pluginsLoaded) {
|
||||
if (args.length > 0) {
|
||||
if (pluginsLoaded == null) {
|
||||
PluginManagerCore.getPlugins();
|
||||
}
|
||||
else {
|
||||
try {
|
||||
pluginsLoaded.get();
|
||||
}
|
||||
catch (InterruptedException | ExecutionException e) {
|
||||
throw new CompletionException(e);
|
||||
}
|
||||
}
|
||||
|
||||
ApplicationStarter starter = findStarter(args[0]);
|
||||
if (starter != null) {
|
||||
return starter;
|
||||
}
|
||||
}
|
||||
|
||||
return new IdeStarter();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ApplicationStarter findStarter(@Nullable String key) {
|
||||
for (ApplicationStarter starter : ApplicationStarter.EP_NAME.getIterable(null)) {
|
||||
@@ -293,7 +311,7 @@ public final class IdeaApplication {
|
||||
String filename = args[0];
|
||||
File file = new File(currentDirectory, filename);
|
||||
|
||||
if(file.exists()) {
|
||||
if (file.exists()) {
|
||||
VirtualFile virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file);
|
||||
if (virtualFile != null) {
|
||||
int line = -1;
|
||||
@@ -324,30 +342,26 @@ public final class IdeaApplication {
|
||||
|
||||
@Override
|
||||
public void main(String[] args) {
|
||||
Activity activity = StartUpMeasurer.start(Phases.FRAME_INITIALIZATION);
|
||||
if (SystemInfoRt.isMac) {
|
||||
MacOSApplicationProvider.initApplication();
|
||||
}
|
||||
Activity frameInitActivity = StartUpMeasurer.start(Phases.FRAME_INITIALIZATION);
|
||||
|
||||
SystemDock.updateMenu();
|
||||
|
||||
RecentProjectsManager.getInstance(); // ensures that RecentProjectsManager app listener is added
|
||||
GcPauseWatcher.Companion.getInstance();
|
||||
|
||||
// Event queue should not be changed during initialization of application components.
|
||||
// It also cannot be changed before initialization of application components because IdeEventQueue uses other
|
||||
// application components. So it is proper to perform replacement only here.
|
||||
Activity setWindowManagerActivity = frameInitActivity.startChild("set window manager");
|
||||
Application app = ApplicationManager.getApplication();
|
||||
WindowManagerImpl windowManager = (WindowManagerImpl)WindowManager.getInstance();
|
||||
IdeEventQueue.getInstance().setWindowManager(windowManager);
|
||||
setWindowManagerActivity.end();
|
||||
|
||||
List<String> commandLineArgs = args == null || args.length == 0 ? Collections.emptyList() : Arrays.asList(args);
|
||||
|
||||
Ref<Boolean> willOpenProject = new Ref<>(Boolean.FALSE);
|
||||
Activity appFrameCreatedActivity = frameInitActivity.startChild("call appFrameCreated");
|
||||
AppLifecycleListener lifecyclePublisher = app.getMessageBus().syncPublisher(AppLifecycleListener.TOPIC);
|
||||
lifecyclePublisher.appFrameCreated(commandLineArgs, willOpenProject);
|
||||
|
||||
PluginManagerCore.dumpPluginClassStatistics();
|
||||
appFrameCreatedActivity.end();
|
||||
|
||||
// Temporary check until the jre implementation has been checked and bundled
|
||||
if (Registry.is("ide.popup.enablePopupType")) {
|
||||
@@ -356,29 +370,50 @@ public final class IdeaApplication {
|
||||
|
||||
LoadingPhase.setCurrentPhase(LoadingPhase.FRAME_SHOWN);
|
||||
|
||||
Runnable beforeSetVisible = SplashManager.getHideTask();
|
||||
|
||||
IdeFrame frame = null;
|
||||
if (JetBrainsProtocolHandler.getCommand() != null || !willOpenProject.get()) {
|
||||
WelcomeFrame.showNow(beforeSetVisible);
|
||||
if (!willOpenProject.get() || JetBrainsProtocolHandler.getCommand() != null) {
|
||||
WelcomeFrame.showNow(SplashManager.getHideTask());
|
||||
lifecyclePublisher.welcomeScreenDisplayed();
|
||||
}
|
||||
else {
|
||||
frame = windowManager.showFrame(beforeSetVisible);
|
||||
}
|
||||
|
||||
activity.end();
|
||||
frameInitActivity.end();
|
||||
|
||||
AppExecutorUtil.getAppExecutorService().execute(() -> LifecycleUsageTriggerCollector.onIdeStart());
|
||||
|
||||
IdeFrame finalFrame = frame;
|
||||
TransactionGuard.submitTransaction(app, () -> {
|
||||
Project projectFromCommandLine = ourPerformProjectLoad ? loadProjectFromExternalCommandLine(commandLineArgs) : null;
|
||||
// The appStarting callback in RecentProjectsManagerBase will reopen the last project
|
||||
app.getMessageBus().syncPublisher(AppLifecycleListener.TOPIC).appStarting(projectFromCommandLine, finalFrame);
|
||||
app.getMessageBus().syncPublisher(AppLifecycleListener.TOPIC).appStarting(projectFromCommandLine);
|
||||
|
||||
//noinspection SSBasedInspection
|
||||
SwingUtilities.invokeLater(PluginManager::reportPluginError);
|
||||
EventQueue.invokeLater(PluginManager::reportPluginError);
|
||||
});
|
||||
|
||||
LifecycleUsageTriggerCollector.onIdeStart();
|
||||
if (!app.isHeadlessEnvironment()) {
|
||||
postOpenUiTasks(app);
|
||||
}
|
||||
}
|
||||
|
||||
private static void postOpenUiTasks(@NotNull Application app) {
|
||||
if (SystemInfoRt.isMac) {
|
||||
AppExecutorUtil.getAppExecutorService().execute(() -> {
|
||||
TouchBarsManager.onApplicationInitialized();
|
||||
CustomActionsSchema customActionSchema = ServiceManager.getServiceIfCreated(CustomActionsSchema.class);
|
||||
if (customActionSchema != null) {
|
||||
customActionSchema.touchBarAvailable(TouchBarsManager.isTouchBarAvailable());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
app.invokeLater(() -> {
|
||||
Activity updateSystemDockActivity = StartUpMeasurer.start("system dock menu");
|
||||
SystemDock.updateMenu();
|
||||
updateSystemDockActivity.end();
|
||||
});
|
||||
app.invokeLater(() -> {
|
||||
GeneralSettings generalSettings = GeneralSettings.getInstance();
|
||||
generalSettings.addPropertyChangeListener(GeneralSettings.PROP_SUPPORT_SCREEN_READERS, app,
|
||||
e -> ScreenReader.setActive((Boolean)e.getNewValue()));
|
||||
ScreenReader.setActive(generalSettings.isSupportScreenReaders());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user