Skip to content

Commit bfd6936

Browse files
authored
feat: Add ability to modify the formatter profile (#628)
* Implement the formatter setting editor functionality
1 parent cf63868 commit bfd6936

File tree

14 files changed

+704
-77
lines changed

14 files changed

+704
-77
lines changed

package-lock.json

Lines changed: 21 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,8 @@
292292
"@types/semver": "^5.5.0",
293293
"@types/vscode": "1.52.0",
294294
"@types/winreg": "^1.2.30",
295+
"@types/xmldom": "^0.1.30",
296+
"axios": "^0.21.1",
295297
"arch": "^2.1.2",
296298
"autoprefixer": "^8.5.1",
297299
"bootstrap": "^4.5.2",
@@ -324,7 +326,8 @@
324326
"url-loader": "^4.1.1",
325327
"vscode-tas-client": "^0.1.22",
326328
"webpack": "^4.44.1",
327-
"webpack-cli": "^3.3.12"
329+
"webpack-cli": "^3.3.12",
330+
"xmldom": "^0.6.0"
328331
},
329332
"extensionPack": [
330333
"redhat.java",

src/extension.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { ClassPathConfigurationViewSerializer } from "./classpath/classpathConfi
1818
import { TreatmentVariables } from "./exp/TreatmentVariables";
1919
import { MarkdownPreviewSerializer } from "./classpath/markdownPreviewProvider";
2020
import { initFormatterSettingsEditorProvider } from "./formatter-settings";
21+
import { initRemoteProfileProvider } from "./formatter-settings/RemoteProfileProvider";
2122

2223
export async function activate(context: vscode.ExtensionContext) {
2324
syncState(context);
@@ -29,6 +30,7 @@ export async function activate(context: vscode.ExtensionContext) {
2930

3031
async function initializeExtension(_operationId: string, context: vscode.ExtensionContext) {
3132
initFormatterSettingsEditorProvider(context);
33+
initRemoteProfileProvider(context);
3234
initUtils(context);
3335
initCommands(context);
3436
initRecommendations(context);

src/formatter-settings/FormatterConstants.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ import { Category, ExampleKind, JavaFormatterSetting, ValueKind } from "./types"
66
export namespace JavaConstants {
77
export const JAVA_CORE_FORMATTER_ID = "org.eclipse.jdt.core.formatter";
88
export const CURRENT_FORMATTER_SETTINGS_VERSION = "21";
9+
export const SETTINGS_URL_KEY = "format.settings.url";
10+
export const SETTINGS_PROFILE_KEY = "format.settings.profile";
11+
export const MINIMUM_JAVA_EXTENSION_VERSION: string = "0.77.0";
912
}
1013

1114
export namespace VSCodeSettings {
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT license.
3+
4+
import { SupportedSettings } from "./FormatterConstants";
5+
6+
export namespace FormatterConverter {
7+
export function webView2ProfileConvert(id: string, value: string | undefined): string | undefined {
8+
switch (id) {
9+
case SupportedSettings.INSERT_SPACE_BEFORE_FIRST_INITIALIZER:
10+
case SupportedSettings.INSERT_SPACE_AFTER_CLOSING_ANGLE_BRACKET_IN_TYPE_ARGUMENTS:
11+
case SupportedSettings.INSERT_SPACE_AFTER_CLOSING_PAREN_IN_CAST:
12+
case SupportedSettings.INSERT_SPACE_AFTER_OPENING_BRACE_IN_ARRAY_INITIALIZER:
13+
case SupportedSettings.INSERT_SPACE_BEFORE_CLOSING_BRACE_IN_ARRAY_INITIALIZER:
14+
case SupportedSettings.INSERT_NEW_LINE_IN_CONTROL_STATEMENTS:
15+
case SupportedSettings.INSERT_NEW_LINE_AFTER_ANNOTATION:
16+
case SupportedSettings.INSERT_NEW_LINE_IN_EMPTY_TYPE_DECLARATION:
17+
case SupportedSettings.INSERT_NEW_LINE_IN_EMPTY_METHOD_BODY:
18+
case SupportedSettings.INSERT_NEW_LINE_IN_EMPTY_ENUM_DECLARATION:
19+
case SupportedSettings.INSERT_NEW_LINE_IN_EMPTY_ENUM_CONSTANT:
20+
case SupportedSettings.INSERT_NEW_LINE_IN_EMPTY_ANONYMOUS_TYPE_DECLARATION:
21+
case SupportedSettings.INSERT_NEW_LINE_IN_EMPTY_ANNOTATION_DECLARATION:
22+
case SupportedSettings.INSERT_NEW_LINE_AFTER_ANNOTATION_ON_ENUM_CONSTANT:
23+
case SupportedSettings.INSERT_NEW_LINE_AFTER_ANNOTATION_ON_PACKAGE:
24+
case SupportedSettings.INSERT_NEW_LINE_AFTER_ANNOTATION_ON_PARAMETER:
25+
case SupportedSettings.INSERT_NEW_LINE_AFTER_OPENING_BRACE_IN_ARRAY_INITIALIZER:
26+
case SupportedSettings.INSERT_NEW_LINE_BEFORE_CATCH_IN_TRY_STATEMENT:
27+
case SupportedSettings.INSERT_NEW_LINE_BEFORE_CLOSING_BRACE_IN_ARRAY_INITIALIZER:
28+
case SupportedSettings.INSERT_NEW_LINE_BEFORE_ELSE_IN_IF_STATEMENT:
29+
case SupportedSettings.INSERT_NEW_LINE_BEFORE_FINALLY_IN_TRY_STATEMENT:
30+
case SupportedSettings.INSERT_NEW_LINE_BEFORE_WHILE_IN_DO_STATEMENT:
31+
switch (value) {
32+
case "true":
33+
return "insert";
34+
case "false":
35+
return "do not insert";
36+
// We regard an empty string as a valid value and may write it to the profile
37+
case "":
38+
return "";
39+
default:
40+
return undefined;
41+
}
42+
case SupportedSettings.KEEP_TYPE_DECLARATION_ON_ONE_LINE:
43+
case SupportedSettings.KEEP_RECORD_DECLARATION_ON_ONE_LINE:
44+
case SupportedSettings.KEEP_RECORD_CONSTRUCTOR_ON_ONE_LINE:
45+
case SupportedSettings.KEEP_METHOD_BODY_ON_ONE_LINE:
46+
case SupportedSettings.KEEP_ENUM_DECLARATION_ON_ONE_LINE:
47+
case SupportedSettings.KEEP_ENUM_CONSTANT_DECLARATION_ON_ONE_LINE:
48+
case SupportedSettings.KEEP_ANONYMOUS_TYPE_DECLARATION_ON_ONE_LINE:
49+
case SupportedSettings.KEEP_ANNOTATION_DECLARATION_ON_ONE_LINE:
50+
switch (value) {
51+
case "never":
52+
return "one_line_never";
53+
case "if empty":
54+
return "one_line_if_empty";
55+
case "if at most one item":
56+
return "one_line_if_single_item";
57+
// We regard an empty string as a valid value and may write it to the profile
58+
case "":
59+
return "";
60+
default:
61+
return undefined;
62+
}
63+
}
64+
return value;
65+
}
66+
67+
export function profile2WebViewConvert(id: string, value: string | undefined): string | undefined {
68+
switch (id) {
69+
case SupportedSettings.INSERT_SPACE_BEFORE_FIRST_INITIALIZER:
70+
case SupportedSettings.INSERT_SPACE_AFTER_CLOSING_ANGLE_BRACKET_IN_TYPE_ARGUMENTS:
71+
case SupportedSettings.INSERT_SPACE_AFTER_CLOSING_PAREN_IN_CAST:
72+
case SupportedSettings.INSERT_SPACE_AFTER_OPENING_BRACE_IN_ARRAY_INITIALIZER:
73+
case SupportedSettings.INSERT_SPACE_BEFORE_CLOSING_BRACE_IN_ARRAY_INITIALIZER:
74+
case SupportedSettings.INSERT_NEW_LINE_IN_CONTROL_STATEMENTS:
75+
case SupportedSettings.INSERT_NEW_LINE_AFTER_ANNOTATION:
76+
case SupportedSettings.INSERT_NEW_LINE_IN_EMPTY_TYPE_DECLARATION:
77+
case SupportedSettings.INSERT_NEW_LINE_IN_EMPTY_METHOD_BODY:
78+
case SupportedSettings.INSERT_NEW_LINE_IN_EMPTY_ENUM_DECLARATION:
79+
case SupportedSettings.INSERT_NEW_LINE_IN_EMPTY_ENUM_CONSTANT:
80+
case SupportedSettings.INSERT_NEW_LINE_IN_EMPTY_ANONYMOUS_TYPE_DECLARATION:
81+
case SupportedSettings.INSERT_NEW_LINE_IN_EMPTY_ANNOTATION_DECLARATION:
82+
case SupportedSettings.INSERT_NEW_LINE_AFTER_ANNOTATION_ON_ENUM_CONSTANT:
83+
case SupportedSettings.INSERT_NEW_LINE_AFTER_ANNOTATION_ON_PACKAGE:
84+
case SupportedSettings.INSERT_NEW_LINE_AFTER_ANNOTATION_ON_PARAMETER:
85+
case SupportedSettings.INSERT_NEW_LINE_AFTER_OPENING_BRACE_IN_ARRAY_INITIALIZER:
86+
case SupportedSettings.INSERT_NEW_LINE_BEFORE_CATCH_IN_TRY_STATEMENT:
87+
case SupportedSettings.INSERT_NEW_LINE_BEFORE_CLOSING_BRACE_IN_ARRAY_INITIALIZER:
88+
case SupportedSettings.INSERT_NEW_LINE_BEFORE_ELSE_IN_IF_STATEMENT:
89+
case SupportedSettings.INSERT_NEW_LINE_BEFORE_FINALLY_IN_TRY_STATEMENT:
90+
case SupportedSettings.INSERT_NEW_LINE_BEFORE_WHILE_IN_DO_STATEMENT:
91+
switch (value) {
92+
case "insert":
93+
return "true";
94+
case "do not insert":
95+
return "false";
96+
// We regard an empty string as a valid value and show it in the webview
97+
case "":
98+
return "";
99+
default:
100+
return undefined;
101+
}
102+
case SupportedSettings.KEEP_TYPE_DECLARATION_ON_ONE_LINE:
103+
case SupportedSettings.KEEP_RECORD_DECLARATION_ON_ONE_LINE:
104+
case SupportedSettings.KEEP_RECORD_CONSTRUCTOR_ON_ONE_LINE:
105+
case SupportedSettings.KEEP_METHOD_BODY_ON_ONE_LINE:
106+
case SupportedSettings.KEEP_ENUM_DECLARATION_ON_ONE_LINE:
107+
case SupportedSettings.KEEP_ENUM_CONSTANT_DECLARATION_ON_ONE_LINE:
108+
case SupportedSettings.KEEP_ANONYMOUS_TYPE_DECLARATION_ON_ONE_LINE:
109+
case SupportedSettings.KEEP_ANNOTATION_DECLARATION_ON_ONE_LINE:
110+
switch (value) {
111+
case "one_line_never":
112+
return "never";
113+
case "one_line_if_empty":
114+
return "if empty";
115+
case "one_line_if_single_item":
116+
return "if at most one item";
117+
// We regard an empty string as a valid value and show it in the webview
118+
case "":
119+
return "";
120+
default:
121+
return undefined;
122+
}
123+
case SupportedSettings.PUT_EMPTY_STATEMENT_ON_NEW_LINE:
124+
case SupportedSettings.COMMENT_INDENTPARAMETERDESCRIPTION:
125+
case SupportedSettings.COMMENT_INDENT_PARAMETER_DESCRIPTION:
126+
case SupportedSettings.COMMENT_FORMATHEADER:
127+
case SupportedSettings.COMMENT_FORMAT_HEADER:
128+
case SupportedSettings.COMMENT_FORMATTER_COMMENT:
129+
case SupportedSettings.COMMENT_FORMATTER_COMMENT_CORE:
130+
case SupportedSettings.COMMENT_FORMAT_BLOCK_COMMENTS:
131+
case SupportedSettings.FORMAT_LINE_COMMENTS:
132+
case SupportedSettings.COMMENT_COUNT_LINE_LENGTH_FROM_STARTING_POSITION:
133+
case SupportedSettings.COMMENT_CLEARBLANKLINES:
134+
case SupportedSettings.COMMENT_CLEAR_BLANK_LINES:
135+
case SupportedSettings.COMMENT_CLEAR_BLANK_LINES_IN_JAVADOC_COMMENT:
136+
case SupportedSettings.COMMENT_CLEAR_BLANK_LINES_IN_BLOCK_COMMENT:
137+
case SupportedSettings.COMMENT_ON_OFF_TAGS:
138+
case SupportedSettings.INSERT_SPACE_BEFORE_CLOSING_BRACE_IN_ARRAY_INITIALIZER:
139+
case SupportedSettings.INSERT_SPACE_BEFORE_FIRST_INITIALIZER:
140+
case SupportedSettings.INSERT_SPACE_AFTER_OPENING_BRACE_IN_ARRAY_INITIALIZER:
141+
case SupportedSettings.INSERT_SPACE_AFTER_CLOSING_PAREN_IN_CAST:
142+
case SupportedSettings.INSERT_SPACE_AFTER_CLOSING_ANGLE_BRACKET_IN_TYPE_ARGUMENTS:
143+
// We regard an empty string as a valid value and show it in the webview
144+
if (value === "true" || value === "false" || value === "") {
145+
return value;
146+
}
147+
return undefined;
148+
}
149+
return value;
150+
}
151+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT license.
3+
4+
import * as vscode from "vscode";
5+
import { downloadFile } from "./utils";
6+
7+
export class RemoteProfileProvider implements vscode.TextDocumentContentProvider {
8+
9+
public static scheme = "formatter";
10+
11+
async provideTextDocumentContent(uri: vscode.Uri): Promise<string> {
12+
const originalUri: vscode.Uri = uri.with({ scheme: "https" });
13+
return await downloadFile(originalUri.toString());
14+
}
15+
}
16+
17+
export function initRemoteProfileProvider(context: vscode.ExtensionContext) {
18+
const remoteProfileProvider = new RemoteProfileProvider();
19+
context.subscriptions.push(vscode.workspace.registerTextDocumentContentProvider(RemoteProfileProvider.scheme, remoteProfileProvider));
20+
}

src/formatter-settings/assets/features/formatterSettings/FormatterSettingView.tsx

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,24 @@ import React, { useEffect } from "react";
55
import { Col, Container, Nav, Row } from "react-bootstrap";
66
import { useSelector, useDispatch } from "react-redux";
77
import { Dispatch } from "@reduxjs/toolkit";
8-
import { applyFormatResult, changeActiveCategory, loadProfileSetting, loadVSCodeSetting } from "./formatterSettingViewSlice";
8+
import { applyFormatResult, changeActiveCategory, changeReadOnlyState, loadProfileSetting, loadVSCodeSetting } from "./formatterSettingViewSlice";
99
import { highlight } from "./components/Highlight";
1010
import { Category, ExampleKind } from "../../../types";
1111
import Setting from "./components/Setting";
1212
import { renderWhitespace } from "../../whitespace";
13-
import { onWillChangeExampleKind, onWillInitialize } from "../../utils";
13+
import { onWillChangeExampleKind, onWillDownloadAndUse, onWillInitialize } from "../../utils";
1414

1515
const FormatterSettingsView = (): JSX.Element => {
1616
const activeCategory: Category = useSelector((state: any) => state.formatterSettings.activeCategory);
1717
const contentText: string = useSelector((state: any) => state.formatterSettings.formattedContent);
18+
const readOnly: boolean = useSelector((state: any) => state.formatterSettings.readOnly);
19+
const title: string = "Java Formatter Settings" + (readOnly ? " (Read Only)" : "");
20+
1821
const dispatch: Dispatch<any> = useDispatch();
1922
const onClickNaviBar = (element: any) => {
2023
const activeCategory: Category = Number(element);
21-
let exampleKind: ExampleKind = ExampleKind.INDENTATION_EXAMPLE;
2224
dispatch(changeActiveCategory(activeCategory));
25+
let exampleKind: ExampleKind = ExampleKind.INDENTATION_EXAMPLE;
2326
switch (activeCategory) {
2427
case Category.BlankLine:
2528
exampleKind = ExampleKind.BLANKLINE_EXAMPLE;
@@ -75,6 +78,8 @@ const FormatterSettingsView = (): JSX.Element => {
7578
dispatch(loadProfileSetting(event.data));
7679
} else if (event.data.command === "loadVSCodeSetting") {
7780
dispatch(loadVSCodeSetting(event.data));
81+
} else if (event.data.command === "changeReadOnlyState") {
82+
dispatch(changeReadOnlyState(event.data));
7883
}
7984
};
8085

@@ -90,10 +95,9 @@ const FormatterSettingsView = (): JSX.Element => {
9095

9196
return (
9297
<Container className="root d-flex flex-column">
93-
<Row>
94-
<Col className="setting-header">
95-
<h2 className="mb-0">Java Formatter Settings</h2>
96-
</Col>
98+
<Row className="setting-header">
99+
<Col><h2 className="mb-0">{title}</h2></Col>
100+
<Col>{readOnly && (<div><a className="btn btn-primary float-right" role="button" title="Download and edit profile" onClick={() => onWillDownloadAndUse()}>Edit</a></div>)}</Col>
97101
</Row>
98102
<Row className="flex-grow-1 d-flex flex-nowrap view-body">
99103
<Col className="flex-grow-0">{naviBar}</Col>

0 commit comments

Comments
 (0)