Skip to content

Commit a8feb4c

Browse files
committed
Move types and theme-specific stuff out of index.js
1 parent 0a49e1a commit a8feb4c

File tree

6 files changed

+240
-199
lines changed

6 files changed

+240
-199
lines changed

src/createGetRegistry.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// @ts-check
2+
const logger = require('loglevel');
23
const { getGrammarLocation, getGrammar, getAllGrammars } = require('./storeUtils');
34
const { readFile } = require('./utils');
45
const { Registry, parseRawGrammar } = require('vscode-textmate');
@@ -36,16 +37,24 @@ const getLock = (() => {
3637
return getLock;
3738
})();
3839

40+
/**
41+
* @param {string} missingScopeName
42+
* @param {string} rootScopeName
43+
*/
44+
function warnMissingLanguageFile(missingScopeName, rootScopeName) {
45+
logger.warn(`No language file was loaded for scope '${missingScopeName}' (requested by '${rootScopeName}').`);
46+
}
47+
3948
function createGetRegistry() {
4049
/** @type {Registry} */
4150
let registry;
4251

4352
/**
4453
* @param {*} cache
45-
* @param {(missingScopeName: string) => void} onMissingLanguageFile
54+
* @param {string} rootScopeName
4655
* @returns {Promise<[Registry, () => void]>}
4756
*/
48-
async function getRegistry(cache, onMissingLanguageFile) {
57+
async function getRegistry(cache, rootScopeName) {
4958
if (!registry) {
5059
const grammars = getAllGrammars(await cache.get('grammars'));
5160
registry = new Registry({
@@ -56,7 +65,7 @@ function createGetRegistry() {
5665
const contents = await readFile(fileName, 'utf8');
5766
return parseRawGrammar(contents, fileName);
5867
}
59-
onMissingLanguageFile(scopeName);
68+
warnMissingLanguageFile(scopeName, rootScopeName);
6069
},
6170
getInjections: scopeName => {
6271
return Object.keys(grammars).reduce((acc, s) => {

src/createThemeStyles.js

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
// @ts-check
2+
const { loadColorTheme } = require('../lib/vscode/colorThemeData');
3+
const { generateTokensCSSForColorMap } = require('../lib/vscode/tokenization');
4+
const { ensureThemeLocation } = require('./storeUtils');
5+
const { sanitizeForClassName } = require('./utils');
6+
const {
7+
joinClassNames,
8+
renderRule,
9+
prefersDark,
10+
prefersLight,
11+
prefixRules
12+
} = require('./renderUtils');
13+
14+
/**
15+
* @param {ColorThemeSettings} settings
16+
* @returns {{ [K in keyof ColorThemeSettings]: string }}
17+
*/
18+
function createThemeClassNames(settings) {
19+
return {
20+
defaultTheme: sanitizeForClassName(settings.defaultTheme),
21+
prefersDarkTheme: settings.prefersDarkTheme && `pd--${sanitizeForClassName(settings.prefersDarkTheme)}`,
22+
prefersLightTheme: settings.prefersLightTheme && `pl--${sanitizeForClassName(settings.prefersLightTheme)}`
23+
};
24+
}
25+
26+
/**
27+
* @param {{ [K in keyof ColorThemeSettings]: string }} classNames
28+
*/
29+
function joinThemeClassNames(classNames) {
30+
return joinClassNames(...Object.keys(classNames).map(setting => classNames[setting]));
31+
}
32+
33+
/**
34+
* @param {string | ColorThemeSettings} colorThemeValue
35+
* @returns {ColorThemeSettings}
36+
*/
37+
function createColorThemeSettings(colorThemeValue) {
38+
return typeof colorThemeValue === 'string' ? { defaultTheme: colorThemeValue } : colorThemeValue;
39+
}
40+
41+
const settingPropertyMap = { 'editor.background': 'background-color', 'editor.foreground': 'color' };
42+
43+
/**
44+
* @param {Record<string, string>} settings
45+
*/
46+
function getStylesFromSettings(settings) {
47+
return Object.keys(settings)
48+
.reduce((styles, setting) => {
49+
const property = settingPropertyMap[setting];
50+
if (property) {
51+
return [...styles, `${property}: ${settings[setting]};`];
52+
}
53+
return styles;
54+
}, [])
55+
.join('\n');
56+
}
57+
58+
/**
59+
* @param {{
60+
* colorTheme: PluginOptions['colorTheme'],
61+
* replaceColor: PluginOptions['replaceColor'],
62+
* registry: import('vscode-textmate').Registry,
63+
* cache: any,
64+
* markdownNode: any,
65+
* codeFenceNode: any,
66+
* codeFenceOptions: object,
67+
* languageName: string,
68+
* scopeName: string,
69+
* stylesheets: Record<string, string>
70+
* }} options
71+
* @returns {Promise<string>}
72+
*/
73+
async function createThemeStyles({
74+
colorTheme,
75+
replaceColor,
76+
registry,
77+
markdownNode,
78+
codeFenceNode,
79+
codeFenceOptions,
80+
languageName,
81+
scopeName,
82+
cache,
83+
stylesheets
84+
}) {
85+
const colorThemeValue =
86+
typeof colorTheme === 'function'
87+
? colorTheme({
88+
markdownNode,
89+
codeFenceNode,
90+
parsedOptions: codeFenceOptions,
91+
language: languageName
92+
})
93+
: colorTheme;
94+
const colorThemeSettings = createColorThemeSettings(colorThemeValue);
95+
const themeClassNames = createThemeClassNames(colorThemeSettings);
96+
for (const setting in colorThemeSettings) {
97+
const colorThemeIdentifier = colorThemeSettings[setting];
98+
if (!colorThemeIdentifier) continue;
99+
100+
const themeClassName = themeClassNames[setting];
101+
const themeCache = await cache.get('themes');
102+
const colorThemePath = await ensureThemeLocation(colorThemeIdentifier, themeCache, markdownNode.fileAbsolutePath);
103+
104+
const { resultRules: tokenColors, resultColors: settings } = loadColorTheme(colorThemePath);
105+
const defaultTokenColors = {
106+
settings: {
107+
foreground: settings['editor.foreground'] || settings.foreground,
108+
background: settings['editor.background'] || settings.background
109+
}
110+
};
111+
112+
registry.setTheme({ settings: [defaultTokenColors, ...tokenColors] });
113+
if (!stylesheets[themeClassName] || scopeName) {
114+
const rules = [
115+
renderRule(themeClassName, getStylesFromSettings(settings)),
116+
...(scopeName
117+
? prefixRules(
118+
generateTokensCSSForColorMap(
119+
registry.getColorMap().map(color => replaceColor(color, colorThemeIdentifier))
120+
).split('\n'),
121+
`.${themeClassName} `
122+
)
123+
: [])
124+
];
125+
126+
if (setting === 'prefersDarkTheme') {
127+
stylesheets[themeClassName] = prefersDark(rules);
128+
} else if (setting === 'prefersLightTheme') {
129+
stylesheets[themeClassName] = prefersLight(rules);
130+
} else {
131+
stylesheets[themeClassName] = rules.join('\n');
132+
}
133+
}
134+
}
135+
136+
return joinThemeClassNames(themeClassNames);
137+
}
138+
139+
module.exports = createThemeStyles;

src/downloadExtension.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ async function mergeCache(cache, key, value) {
2121
}
2222

2323
/**
24-
* @param {import('.').ExtensionDemand} extensionDemand
24+
* @param {ExtensionDemand} extensionDemand
2525
* @param {*} cache
2626
* @param {string} extensionDir
2727
*/
@@ -34,10 +34,10 @@ async function syncExtensionData({ identifier }, cache, extensionDir) {
3434
}
3535

3636
/**
37-
* @param {import('.').ExtensionDemand} extensionDemand
37+
* @param {ExtensionDemand} extensionDemand
3838
* @param {*} cache
3939
* @param {string} extensionDir
40-
* @param {import('./host').Host} host
40+
* @param {Host} host
4141
*/
4242
async function downloadExtension(extensionDemand, cache, extensionDir, host) {
4343
const { identifier, version } = extensionDemand;
@@ -60,10 +60,10 @@ async function downloadExtension(extensionDemand, cache, extensionDir, host) {
6060

6161
/**
6262
* @typedef {object} DownloadExtensionOptions
63-
* @property {import('.').ExtensionDemand[]} extensions
63+
* @property {ExtensionDemand[]} extensions
6464
* @property {*} cache
6565
* @property {string} extensionDir
66-
* @property {import('./host').Host} host
66+
* @property {Host} host
6767
*/
6868

6969
/**

src/host.js

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,8 @@
1+
// @ts-check
12
const request = require('request');
23
const decompress = require('decompress');
34
const { gunzip } = require('./utils');
45

5-
/**
6-
* @typedef {object} Response
7-
* @property {Buffer | undefined} body
8-
* @property {number} statusCode
9-
*/
10-
11-
/**
12-
* @typedef {object} Host
13-
* @property {(url: string, options: request.CoreOptions) => Promise<Response>} fetch
14-
* @property {(input: string | Buffer, output: string) => Promise<unknown>} decompress
15-
*/
16-
176
/** @type {Host} */
187
const host = {
198
fetch: (url, options) =>

0 commit comments

Comments
 (0)