|
| 1 | +// Copyright (c) Microsoft Corporation. All rights reserved. |
| 2 | +// Licensed under the MIT license. |
| 3 | + |
| 4 | +import { VSCodeCheckbox, VSCodeDataGrid, VSCodeDataGridCell, VSCodeDataGridRow, VSCodeDivider, VSCodeDropdown, VSCodeLink, VSCodeOption } from "@vscode/webview-ui-toolkit/react"; |
| 5 | +import React, { Dispatch, useEffect } from "react"; |
| 6 | +import { useDispatch, useSelector } from "react-redux"; |
| 7 | +import { updateCompilerSettings, updateAvailableComplianceLevels } from "./compilerConfigurationViewSlice"; |
| 8 | +import { CompilerRequest } from "../../vscode/utils"; |
| 9 | +import { VmInstall } from "../../../types"; |
| 10 | +import { updateActiveSection } from "../../mainpage/features/commonSlice"; |
| 11 | +import { updateActiveTab } from "../../classpath/features/classpathConfigurationViewSlice"; |
| 12 | + |
| 13 | +const CompilerConfigurationView = (): JSX.Element | null => { |
| 14 | + |
| 15 | + const dispatch: Dispatch<any> = useDispatch(); |
| 16 | + |
| 17 | + const projects: any[] = useSelector((state: any) => state.commonConfig.data.projects); |
| 18 | + const activeProjectIndex: number = useSelector((state: any) => state.commonConfig.ui.activeProjectIndex); |
| 19 | + const complianceLevel: string = useSelector((state: any) => state.compilerConfig.data.complianceLevel[activeProjectIndex]); |
| 20 | + const sourceLevel: string = useSelector((state: any) => state.compilerConfig.data.sourceLevel[activeProjectIndex]); |
| 21 | + const targetLevel: string = useSelector((state: any) => state.compilerConfig.data.targetLevel[activeProjectIndex]); |
| 22 | + |
| 23 | + // Find the version of current JDK to determine the max compliance level that can be set. |
| 24 | + const vmInstalls: VmInstall[] = useSelector((state: any) => state.classpathConfig.data.vmInstalls); |
| 25 | + const activeVmInstallPath: string = useSelector((state: any) => state.classpathConfig.data.activeVmInstallPath[activeProjectIndex]); |
| 26 | + const activeVmInstall: VmInstall | undefined = vmInstalls.find((vmInstall: VmInstall) => vmInstall.path === activeVmInstallPath); |
| 27 | + let currentJdkComplianceLevel: number = Number.MAX_SAFE_INTEGER; |
| 28 | + if (activeVmInstall?.version) { |
| 29 | + currentJdkComplianceLevel = parseJavaVersion(activeVmInstall.version); |
| 30 | + } |
| 31 | + |
| 32 | + const useRelease: boolean = useSelector((state: any) => state.compilerConfig.data.useRelease[activeProjectIndex]); |
| 33 | + const enablePreview: boolean = useSelector((state: any) => state.compilerConfig.data.enablePreview[activeProjectIndex]); |
| 34 | + const generateDebugInfo: boolean = useSelector((state: any) => state.compilerConfig.data.generateDebugInfo[activeProjectIndex]); |
| 35 | + const storeMethodParamNames: boolean = useSelector((state: any) => state.compilerConfig.data.storeMethodParamNames[activeProjectIndex]); |
| 36 | + const availableComplianceLevels: string[] = useSelector((state: any) => state.compilerConfig.ui.availableComplianceLevels); |
| 37 | + |
| 38 | + // Release flag only supported on Java 9+. |
| 39 | + const showReleaseFlag: boolean = currentJdkComplianceLevel >= 9; |
| 40 | + |
| 41 | + // Hide the preview checkbox if the current JDK version is not latest & preview flag is already disabled. |
| 42 | + const showPreviewFlag: boolean = !!(availableComplianceLevels.find((level) => { |
| 43 | + return Number(level) > currentJdkComplianceLevel; |
| 44 | + }) === undefined) || enablePreview; |
| 45 | + |
| 46 | + const showSourceTargetWarning: boolean = !useRelease && (sourceLevel !== "" && targetLevel !== "" && Number(sourceLevel) > Number(targetLevel)); |
| 47 | + const showJdkLevelWarning: boolean = Number(complianceLevel) > currentJdkComplianceLevel || |
| 48 | + Number(sourceLevel) > currentJdkComplianceLevel || |
| 49 | + Number(targetLevel) > currentJdkComplianceLevel; |
| 50 | + |
| 51 | + const onMessage = (event: any) => { |
| 52 | + const message = event.data; |
| 53 | + if (message.command === "compiler.onDidGetAvailableComplianceLevels") { |
| 54 | + dispatch(updateAvailableComplianceLevels({ |
| 55 | + availableComplianceLevels: message.complianceLevels |
| 56 | + })); |
| 57 | + } else if (message.command === "compiler.onDidGetCompilerSettings") { |
| 58 | + dispatch(updateCompilerSettings({ |
| 59 | + activeProjectIndex, |
| 60 | + useRelease: message.useRelease, |
| 61 | + enablePreview: message.enablePreview, |
| 62 | + complianceLevel: message.complianceLevel, |
| 63 | + sourceLevel: message.sourceLevel, |
| 64 | + targetLevel: message.targetLevel, |
| 65 | + generateDebugInfo: message.generateDebugInfo, |
| 66 | + storeMethodParamNames: message.storeMethodParamNames |
| 67 | + })); |
| 68 | + } |
| 69 | + }; |
| 70 | + |
| 71 | + useEffect(() => { |
| 72 | + window.addEventListener("message", onMessage); |
| 73 | + if (availableComplianceLevels?.length === 0) { |
| 74 | + CompilerRequest.onWillGetAvailableComplianceLevels(); |
| 75 | + } |
| 76 | + if (sourceLevel === "") { |
| 77 | + CompilerRequest.onWillGetCompilerSettings(projects[activeProjectIndex].rootPath); |
| 78 | + } |
| 79 | + return () => { |
| 80 | + window.removeEventListener("message", onMessage); |
| 81 | + } |
| 82 | + }, []); |
| 83 | + |
| 84 | + const jdkLevels = (selectedLevel: string, label: string, onClick: (value: string) => void) => { |
| 85 | + return availableComplianceLevels.map((level) => { |
| 86 | + |
| 87 | + return ( |
| 88 | + <VSCodeOption |
| 89 | + className="setting-section-option" |
| 90 | + key={`${label}-${level}`} |
| 91 | + value={level} |
| 92 | + selected={level === selectedLevel} |
| 93 | + onClick={() => onClick(level)} |
| 94 | + > |
| 95 | + <span>{level}</span> |
| 96 | + </VSCodeOption> |
| 97 | + ); |
| 98 | + }); |
| 99 | + }; |
| 100 | + |
| 101 | + const onClickUseRelease = (e: any) => { |
| 102 | + dispatch(updateCompilerSettings({ |
| 103 | + activeProjectIndex, |
| 104 | + useRelease: e.target.checked |
| 105 | + })); |
| 106 | + }; |
| 107 | + |
| 108 | + const onClickEnablePreview = (e: any) => { |
| 109 | + dispatch(updateCompilerSettings({ |
| 110 | + activeProjectIndex, |
| 111 | + enablePreview: e.target.checked |
| 112 | + })); |
| 113 | + }; |
| 114 | + |
| 115 | + const onClickComplianceLevel = (value: string) => { |
| 116 | + dispatch(updateCompilerSettings({ |
| 117 | + activeProjectIndex, |
| 118 | + complianceLevel: value |
| 119 | + })); |
| 120 | + }; |
| 121 | + |
| 122 | + const onClickSourceLevel = (value: string) => { |
| 123 | + dispatch(updateCompilerSettings({ |
| 124 | + activeProjectIndex, |
| 125 | + sourceLevel: value |
| 126 | + })); |
| 127 | + }; |
| 128 | + |
| 129 | + const onClickTargetLevel = (value: string) => { |
| 130 | + dispatch(updateCompilerSettings({ |
| 131 | + activeProjectIndex, |
| 132 | + targetLevel: value |
| 133 | + })); |
| 134 | + }; |
| 135 | + |
| 136 | + const onClickGenerateDebugInfo = (e: any) => { |
| 137 | + dispatch(updateCompilerSettings({ |
| 138 | + activeProjectIndex, |
| 139 | + generateDebugInfo: e.target.checked |
| 140 | + })); |
| 141 | + }; |
| 142 | + |
| 143 | + const onClickStoreMethodParamNames = (e: any) => { |
| 144 | + dispatch(updateCompilerSettings({ |
| 145 | + activeProjectIndex, |
| 146 | + storeMethodParamNames: e.target.checked |
| 147 | + })); |
| 148 | + }; |
| 149 | + |
| 150 | + const onClickChangeJdk = () => { |
| 151 | + dispatch(updateActiveSection("classpath")); |
| 152 | + dispatch(updateActiveTab("jdk")); |
| 153 | + }; |
| 154 | + |
| 155 | + return ( |
| 156 | + <div className="setting-section"> |
| 157 | + <div className={showReleaseFlag ? "" : "invisible"}> |
| 158 | + <VSCodeCheckbox checked={useRelease} onClick={onClickUseRelease}>Use '--release' option for cross-compilation (Java 9 and later)</VSCodeCheckbox> |
| 159 | + </div> |
| 160 | + <div> |
| 161 | + <VSCodeDataGrid gridTemplateColumns="40% 60%"> |
| 162 | + <VSCodeDataGridRow className={showReleaseFlag && useRelease ? "" : "invisible"}> |
| 163 | + <VSCodeDataGridCell className="flex-center pl-0 pr-0" gridColumn="1"> |
| 164 | + <span>Bytecode version:</span> |
| 165 | + </VSCodeDataGridCell> |
| 166 | + <VSCodeDataGridCell className="flex-center pl-0 pr-0" gridColumn="2"> |
| 167 | + <VSCodeDropdown value={complianceLevel}> |
| 168 | + {jdkLevels(complianceLevel, "compliance", onClickComplianceLevel)} |
| 169 | + </VSCodeDropdown> |
| 170 | + </VSCodeDataGridCell> |
| 171 | + </VSCodeDataGridRow> |
| 172 | + <VSCodeDataGridRow className={showReleaseFlag && useRelease ? "invisible" : ""}> |
| 173 | + <VSCodeDataGridCell className="flex-center pl-0 pr-0" gridColumn="1"> |
| 174 | + <span>Source compatibility:</span> |
| 175 | + </VSCodeDataGridCell> |
| 176 | + <VSCodeDataGridCell className="flex-center pl-0 pr-0" gridColumn="2"> |
| 177 | + <VSCodeDropdown value={sourceLevel}> |
| 178 | + {jdkLevels(sourceLevel, "source", onClickSourceLevel)} |
| 179 | + </VSCodeDropdown> |
| 180 | + </VSCodeDataGridCell> |
| 181 | + </VSCodeDataGridRow> |
| 182 | + <VSCodeDataGridRow className={showReleaseFlag && useRelease ? "invisible" : ""}> |
| 183 | + <VSCodeDataGridCell className="flex-center pl-0 pr-0" gridColumn="1"> |
| 184 | + <span>Target compatibility:</span> |
| 185 | + </VSCodeDataGridCell> |
| 186 | + <VSCodeDataGridCell className="flex-center pl-0 pr-0" gridColumn="2"> |
| 187 | + <VSCodeDropdown value={targetLevel}> |
| 188 | + {jdkLevels(targetLevel, "target", onClickTargetLevel)} |
| 189 | + </VSCodeDropdown> |
| 190 | + </VSCodeDataGridCell> |
| 191 | + </VSCodeDataGridRow> |
| 192 | + </VSCodeDataGrid> |
| 193 | + </div> |
| 194 | + <div className={`mt-2 mb-2 ${showSourceTargetWarning ? "" : "invisible"}`}> |
| 195 | + <span className="setting-section-warning"> |
| 196 | + Target compatibility must be equal or greater than source compatibility. |
| 197 | + </span> |
| 198 | + </div> |
| 199 | + <div className={`mt-2 mb-2 ${showJdkLevelWarning ? "" : "invisible"}`}> |
| 200 | + <span className="setting-section-warning"> |
| 201 | + Please make sure to have a compatible JDK configured (currently {currentJdkComplianceLevel}). You can change the JDK under the <VSCodeLink href="" onClick={() => onClickChangeJdk()}>JDK Runtime</VSCodeLink> tab. |
| 202 | + </span> |
| 203 | + </div> |
| 204 | + <div className={showPreviewFlag ? "" : "invisible"}> |
| 205 | + <VSCodeCheckbox checked={enablePreview} onClick={onClickEnablePreview}>Enable preview features</VSCodeCheckbox> |
| 206 | + </div> |
| 207 | + <VSCodeDivider className="mt-3"/> |
| 208 | + <h4 className="mt-3 mb-3">Class File Generation</h4> |
| 209 | + <div> |
| 210 | + <VSCodeCheckbox checked={generateDebugInfo} onClick={onClickGenerateDebugInfo}>Generate debugging information</VSCodeCheckbox> |
| 211 | + </div> |
| 212 | + <div> |
| 213 | + <VSCodeCheckbox checked={storeMethodParamNames} onClick={onClickStoreMethodParamNames}>Store information about method parameters</VSCodeCheckbox> |
| 214 | + </div> |
| 215 | + </div>) |
| 216 | +} |
| 217 | + |
| 218 | +function parseJavaVersion(version: string): number { |
| 219 | + if (!version.includes(".")) { |
| 220 | + return Number(version); |
| 221 | + } else if (version.startsWith("1.")) { |
| 222 | + return Number("1." + version.split(".")[1]); |
| 223 | + } else { |
| 224 | + return Number(version.split(".")[0]); |
| 225 | + } |
| 226 | +} |
| 227 | + |
| 228 | +export default CompilerConfigurationView; |
0 commit comments