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:
Eldar Abusalimov
2019-06-16 03:02:17 +03:00
committed by intellij-monorepo-bot
parent 1120c30a56
commit 18962d3d42
255 changed files with 4638 additions and 3697 deletions
@@ -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());
}
}
+1 -1
View File
@@ -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
View File
@@ -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"/>
@@ -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()) {
@@ -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(
@@ -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
@@ -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)
}
}
@@ -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 {
@@ -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?) {
@@ -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)
@@ -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() {
@@ -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;
}
@@ -81,7 +81,8 @@ public final class ProjectSystemId implements Serializable {
ProjectSystemId cached = ourExistingIds.get(id);
if (cached != null) {
return cached;
} else {
}
else {
return this;
}
}
@@ -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
}
})
}
@@ -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,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()
@@ -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 {
@@ -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);
}
@@ -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,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());
}
@@ -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,
@@ -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();
@@ -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!!
})
}
}
@@ -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,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
@@ -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)
+13 -4
View File
@@ -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)
}
}
}
+1 -1
View File
@@ -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
}
}
+39 -11
View File
@@ -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
+2 -1
View File
@@ -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
}
@@ -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<>();
}
}
@@ -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 {
@@ -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) {
}
}
@@ -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))
}
}
}
}
@@ -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();
}
}
@@ -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();
@@ -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