Skip to content

Commit 9ec47e7

Browse files
authored
feat: allow mapping VS Code color theme to custom ODS style (#1619)
* feat: allow users to define custom mapping Signed-off-by: tariku <[email protected]> * update styleMapping property names and remove unnecessary validations Signed-off-by: tariku <[email protected]> * update styleMapping property names Signed-off-by: tariku <[email protected]> * update the custom style settings property name Signed-off-by: tariku <[email protected]> * add test Signed-off-by: tariku <[email protected]> * add human friendly description name Signed-off-by: tariku <[email protected]> * update text descriptions and localization Signed-off-by: tariku <[email protected]> * add a link to sas.results.html.style in the settings description Signed-off-by: tariku <[email protected]> --------- Signed-off-by: tariku <[email protected]>
1 parent 546e4a6 commit 9ec47e7

File tree

4 files changed

+177
-18
lines changed

4 files changed

+177
-18
lines changed

client/src/components/utils/SASCodeDocumentHelper.ts

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
TextDocument,
99
commands,
1010
window,
11+
workspace,
1112
} from "vscode";
1213

1314
import { v4 } from "uuid";
@@ -103,25 +104,32 @@ function selectionsAreNotEmpty(
103104

104105
function getHtmlStyleValue(): string {
105106
const htmlStyleSetting = getHtmlStyle();
107+
if (htmlStyleSetting === "(auto)") {
108+
// get the results.html.custom.style object from user settings
109+
const customStyle =
110+
workspace.getConfiguration("SAS").get<{
111+
light?: string;
112+
dark?: string;
113+
highContrast?: string;
114+
highContrastLight?: string;
115+
}>("results.html.custom.style") || {};
106116

107-
switch (htmlStyleSetting) {
108-
case "(auto)":
109-
switch (window.activeColorTheme.kind) {
110-
case ColorThemeKind.Light:
111-
return "Illuminate";
112-
case ColorThemeKind.Dark:
113-
return "Ignite";
114-
case ColorThemeKind.HighContrast:
115-
return "HighContrast";
116-
case ColorThemeKind.HighContrastLight:
117-
return "Illuminate";
118-
default:
119-
return "";
120-
}
121-
case "(server default)":
122-
return "";
123-
default:
124-
return htmlStyleSetting;
117+
switch (window.activeColorTheme.kind) {
118+
case ColorThemeKind.Light:
119+
return customStyle.light || "Illuminate";
120+
case ColorThemeKind.Dark:
121+
return customStyle.dark || "Ignite";
122+
case ColorThemeKind.HighContrast:
123+
return customStyle.highContrast || "HighContrast";
124+
case ColorThemeKind.HighContrastLight:
125+
return customStyle.highContrastLight || "Illuminate";
126+
default:
127+
return "";
128+
}
129+
} else if (htmlStyleSetting === "(server default)") {
130+
return "";
131+
} else {
132+
return htmlStyleSetting;
125133
}
126134
}
127135

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import * as vscode from "vscode";
2+
3+
import { assert } from "chai";
4+
import sinon from "sinon";
5+
6+
import { profileConfig } from "../../../src/commands/profile";
7+
import { ConnectionType } from "../../../src/components/profile";
8+
import { getCodeDocumentConstructionParameters } from "../../../src/components/utils/SASCodeDocumentHelper";
9+
10+
describe("sas code document helper", () => {
11+
describe("getCodeDocumentConstructionParameters", () => {
12+
let getConfigurationStub: sinon.SinonStub;
13+
let colorThemeStub: sinon.SinonStub;
14+
let htmlStyle = "(auto)";
15+
const htmlCustomStyle = { dark: "MyCustomDarkStyle" };
16+
17+
beforeEach(() => {
18+
getConfigurationStub = sinon.stub(vscode.workspace, "getConfiguration");
19+
getConfigurationStub.withArgs("SAS").returns({
20+
get: (key: string) => {
21+
if (key === "results.html.style") {
22+
return htmlStyle;
23+
}
24+
if (key === "results.html.custom.style") {
25+
return htmlCustomStyle;
26+
}
27+
return undefined;
28+
},
29+
});
30+
colorThemeStub = sinon
31+
.stub(vscode.window, "activeColorTheme")
32+
.value({ kind: vscode.ColorThemeKind.Dark });
33+
profileConfig.getActiveProfileDetail = () => ({
34+
name: "mock",
35+
profile: {
36+
connectionType: ConnectionType.Rest,
37+
endpoint: "http://example.com",
38+
},
39+
});
40+
});
41+
42+
afterEach(() => {
43+
getConfigurationStub.restore();
44+
colorThemeStub.restore();
45+
});
46+
47+
const mockTextDocument = {
48+
languageId: "sas",
49+
getText: function () {
50+
return "data _null_; run;";
51+
},
52+
uri: vscode.Uri.file("/fake/path/test.sas"),
53+
fileName: "/fake/path/test.sas",
54+
lineCount: 1,
55+
lineAt: function (lineOrPos: number | vscode.Position = 0) {
56+
const lineNumber =
57+
typeof lineOrPos === "number" ? lineOrPos : lineOrPos.line;
58+
return {
59+
lineNumber,
60+
text: "data _null_; run;",
61+
range: new vscode.Range(lineNumber, 0, lineNumber, 16),
62+
rangeIncludingLineBreak: new vscode.Range(
63+
lineNumber,
64+
0,
65+
lineNumber,
66+
17,
67+
),
68+
firstNonWhitespaceCharacterIndex: 0,
69+
isEmptyOrWhitespace: false,
70+
};
71+
},
72+
isUntitled: false,
73+
version: 1,
74+
isDirty: false,
75+
isClosed: false,
76+
save: async () => true,
77+
eol: 1,
78+
offsetAt: () => 0,
79+
positionAt: () => new vscode.Position(0, 0),
80+
validateRange: (range: vscode.Range) => range,
81+
validatePosition: (pos: vscode.Position) => pos,
82+
getWordRangeAtPosition: () => undefined,
83+
};
84+
85+
it("should construct parameters with default values", () => {
86+
const params = getCodeDocumentConstructionParameters(mockTextDocument);
87+
assert.equal(params.languageId, "sas");
88+
assert.equal(params.code, "data _null_; run;");
89+
assert.equal(
90+
params.uri,
91+
vscode.Uri.file("/fake/path/test.sas").toString(),
92+
);
93+
assert.equal(params.fileName, "/fake/path/test.sas");
94+
});
95+
96+
it("should use custom style from results.html.custom.style for dark theme", () => {
97+
const params = getCodeDocumentConstructionParameters(mockTextDocument);
98+
// the custom style should be applied
99+
assert.equal(params.htmlStyle, "MyCustomDarkStyle");
100+
});
101+
102+
it("should not use custom style from results.html.custom.style for dark theme when not defined", () => {
103+
htmlCustomStyle.dark = undefined;
104+
const params = getCodeDocumentConstructionParameters(mockTextDocument);
105+
// the default Ignite style should be used
106+
assert.equal(params.htmlStyle, "Ignite");
107+
});
108+
109+
it("should use no style when results.html.style is '(server default)'", () => {
110+
htmlStyle = "(server default)";
111+
const params = getCodeDocumentConstructionParameters(mockTextDocument);
112+
// no style should be applied
113+
assert.equal(params.htmlStyle, "");
114+
});
115+
116+
it("should use results.html.style when results.html.style is neither '(auto)' nor '(server default)'", () => {
117+
htmlStyle = "HTMLBlue";
118+
const params = getCodeDocumentConstructionParameters(mockTextDocument);
119+
// the results.html.style should be applied
120+
assert.equal(params.htmlStyle, "HTMLBlue");
121+
});
122+
});
123+
});

package.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,29 @@
510510
],
511511
"description": "%configuration.SAS.results.html.style%"
512512
},
513+
"SAS.results.html.custom.style": {
514+
"type": "object",
515+
"default": {},
516+
"markdownDescription": "%configuration.SAS.results.html.custom.style%",
517+
"properties": {
518+
"light": {
519+
"type": "string",
520+
"description": "%configuration.SAS.results.html.custom.style.light%"
521+
},
522+
"dark": {
523+
"type": "string",
524+
"description": "%configuration.SAS.results.html.custom.style.dark%"
525+
},
526+
"highContrast": {
527+
"type": "string",
528+
"description": "%configuration.SAS.results.html.custom.style.highContrast%"
529+
},
530+
"highContrastLight": {
531+
"type": "string",
532+
"description": "%configuration.SAS.results.html.custom.style.highContrastLight%"
533+
}
534+
}
535+
},
513536
"SAS.problems.log.enabled": {
514537
"type": "boolean",
515538
"default": true,

package.nls.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@
7171
"configuration.SAS.results.html.style": "Specifies the style for ODS HTML5 results.",
7272
"configuration.SAS.results.html.style.(auto)": "Let the extension pick a style that most closely matches the color theme.",
7373
"configuration.SAS.results.html.style.(server default)": "Default to the style configured on the SAS server.",
74+
"configuration.SAS.results.html.custom.style": "Specifies which SAS style to use for the light, dark, highContrast, or highContrastLight themes. This option takes effect when `#SAS.results.html.style#` is set to `(auto)`.",
75+
"configuration.SAS.results.html.custom.style.light": "Style to use for light theme",
76+
"configuration.SAS.results.html.custom.style.dark": "Style to use for dark theme",
77+
"configuration.SAS.results.html.custom.style.highContrast": "Style to use for high contrast theme",
78+
"configuration.SAS.results.html.custom.style.highContrastLight": "Style to use for high contrast light theme",
7479
"configuration.SAS.results.sideBySide": "Display results to the side of the code",
7580
"configuration.SAS.results.singlePanel": "Reuse single panel to display results",
7681
"configuration.SAS.userProvidedCertificates": "Provide trusted CA certificate files",

0 commit comments

Comments
 (0)