提交 b320bd0d 编写于 作者: M Martin Aeschlimann

Allow decorations to use theme colors. For #26974

上级 985d05f9
......@@ -710,7 +710,7 @@ export function createCSSRule(selector: string, cssText: string, style: HTMLStyl
return;
}
(<any>style.sheet).insertRule(selector + '{' + cssText + '}', 0);
(<CSSStyleSheet>style.sheet).insertRule(selector + '{' + cssText + '}', 0);
}
export function getCSSRule(selector: string, style: HTMLStyleElement = sharedStyle): any {
......@@ -739,8 +739,7 @@ export function removeCSSRulesContainingSelector(ruleName: string, style = share
let toDelete: number[] = [];
for (let i = 0; i < rules.length; i++) {
let rule = rules[i];
let normalizedSelectorText = rule.selectorText.replace(/::/gi, ':');
if (normalizedSelectorText.indexOf(ruleName) !== -1) {
if (rule.selectorText.indexOf(ruleName) !== -1) {
toDelete.push(i);
}
}
......
......@@ -133,13 +133,14 @@ export module StaticServices {
export const editorWorkerService = define(IEditorWorkerService, (o) => new EditorWorkerServiceImpl(modelService.get(o), configurationService.get(o), modeService.get(o)));
export const codeEditorService = define(ICodeEditorService, () => new CodeEditorServiceImpl());
export const standaloneThemeService = define(IStandaloneThemeService, () => new StandaloneThemeServiceImpl());
export const codeEditorService = define(ICodeEditorService, (o) => new CodeEditorServiceImpl(standaloneThemeService.get(o)));
export const progressService = define(IProgressService, () => new SimpleProgressService());
export const storageService = define(IStorageService, () => NullStorageService);
export const standaloneThemeService = define(IStandaloneThemeService, () => new StandaloneThemeServiceImpl());
}
export class DynamicStandaloneServices extends Disposable {
......
......@@ -15,6 +15,7 @@ import { IDisposable } from 'vs/base/common/lifecycle';
import * as viewEvents from 'vs/editor/common/view/viewEvents';
import { OverviewRulerZone } from 'vs/editor/common/view/overviewZoneManager';
import { editorOverviewRulerBorder, editorCursor } from 'vs/editor/common/view/editorColorRegistry';
import { Color } from 'vs/base/common/color';
export class DecorationsOverviewRuler extends ViewPart {
......@@ -186,15 +187,23 @@ export class DecorationsOverviewRuler extends ViewPart {
dec.range.endLineNumber,
overviewRuler.position,
0,
overviewRuler.color,
overviewRuler.darkColor,
overviewRuler.hcColor
this.resolveRulerColor(overviewRuler.color),
this.resolveRulerColor(overviewRuler.darkColor),
this.resolveRulerColor(overviewRuler.hcColor)
));
}
return zones;
}
private resolveRulerColor(color: string | editorCommon.ThemeColor): string {
if (editorCommon.isThemeColor(color)) {
let c = this._context.theme.getColor(color.id) || Color.transparent;
return c.toString();
}
return color;
}
private _createZonesFromCursors(): OverviewRulerZone[] {
let zones: OverviewRulerZone[] = [];
......
......@@ -41,19 +41,19 @@ export enum OverviewRulerLane {
export interface IModelDecorationOverviewRulerOptions {
/**
* CSS color to render in the overview ruler.
* e.g.: rgba(100, 100, 100, 0.5)
* e.g.: rgba(100, 100, 100, 0.5) or a color from the color registry
*/
color: string;
color: string | ThemeColor;
/**
* CSS color to render in the overview ruler.
* e.g.: rgba(100, 100, 100, 0.5)
* e.g.: rgba(100, 100, 100, 0.5) or a color from the color registry
*/
darkColor: string;
darkColor: string | ThemeColor;
/**
* CSS color to render in the overview ruler.
* e.g.: rgba(100, 100, 100, 0.5)
* e.g.: rgba(100, 100, 100, 0.5) or a color from the color registry
*/
hcColor?: string;
hcColor?: string | ThemeColor;
/**
* The position in the overview ruler.
*/
......@@ -1621,19 +1621,30 @@ export interface IEditorContribution {
restoreViewState?(state: any): void;
}
export interface ThemeColor {
id: string;
}
/**
* @internal
*/
export function isThemeColor(o): o is ThemeColor {
return o && typeof o.id === 'string';
}
/**
* @internal
*/
export interface IThemeDecorationRenderOptions {
backgroundColor?: string;
backgroundColor?: string | ThemeColor;
outline?: string;
outlineColor?: string;
outlineColor?: string | ThemeColor;
outlineStyle?: string;
outlineWidth?: string;
border?: string;
borderColor?: string;
borderColor?: string | ThemeColor;
borderRadius?: string;
borderSpacing?: string;
borderStyle?: string;
......@@ -1641,13 +1652,13 @@ export interface IThemeDecorationRenderOptions {
textDecoration?: string;
cursor?: string;
color?: string;
color?: string | ThemeColor;
letterSpacing?: string;
gutterIconPath?: string | URI;
gutterIconSize?: string;
overviewRulerColor?: string;
overviewRulerColor?: string | ThemeColor;
before?: IContentDecorationRenderOptions;
after?: IContentDecorationRenderOptions;
......@@ -1661,9 +1672,10 @@ export interface IContentDecorationRenderOptions {
contentIconPath?: string | URI;
border?: string;
borderColor?: string | ThemeColor;
textDecoration?: string;
color?: string;
backgroundColor?: string;
color?: string | ThemeColor;
backgroundColor?: string | ThemeColor;
margin?: string;
width?: string;
......
......@@ -840,9 +840,9 @@ function cleanClassName(className: string): string {
}
export class ModelDecorationOverviewRulerOptions implements editorCommon.IModelDecorationOverviewRulerOptions {
readonly color: string;
readonly darkColor: string;
readonly hcColor: string;
readonly color: string | editorCommon.ThemeColor;
readonly darkColor: string | editorCommon.ThemeColor;
readonly hcColor: string | editorCommon.ThemeColor;
readonly position: editorCommon.OverviewRulerLane;
constructor(options: editorCommon.IModelDecorationOverviewRulerOptions) {
......
......@@ -9,6 +9,9 @@ import URI from 'vs/base/common/uri';
import * as dom from 'vs/base/browser/dom';
import { CodeEditorServiceImpl } from 'vs/editor/browser/services/codeEditorServiceImpl';
import { IDecorationRenderOptions } from 'vs/editor/common/editorCommon';
import { TestThemeService, TestTheme } from 'vs/workbench/test/workbenchTestServices';
const themeServiceMock = new TestThemeService();
suite('Decoration Render Options', () => {
var options: IDecorationRenderOptions = {
......@@ -18,12 +21,12 @@ suite('Decoration Render Options', () => {
borderColor: 'yellow'
};
test('register and resolve decoration type', () => {
var s = new CodeEditorServiceImpl();
var s = new CodeEditorServiceImpl(themeServiceMock);
s.registerDecorationType('example', options);
assert.notEqual(s.resolveDecorationOptions('example', false), undefined);
});
test('remove decoration type', () => {
var s = new CodeEditorServiceImpl();
var s = new CodeEditorServiceImpl(themeServiceMock);
s.registerDecorationType('example', options);
assert.notEqual(s.resolveDecorationOptions('example', false), undefined);
s.removeDecorationType('example');
......@@ -39,7 +42,7 @@ suite('Decoration Render Options', () => {
test('css properties', () => {
var styleSheet = dom.createStyleSheet();
var s = new CodeEditorServiceImpl(styleSheet);
var s = new CodeEditorServiceImpl(themeServiceMock, styleSheet);
s.registerDecorationType('example', options);
var sheet = readStyleSheet(styleSheet);
assert(
......@@ -50,11 +53,76 @@ suite('Decoration Render Options', () => {
assert(sheet.indexOf('background-color: red;') > 0);
});
test('theme color', () => {
var options: IDecorationRenderOptions = {
backgroundColor: { id: 'editorBackground' },
borderColor: { id: 'editorBorder' },
};
var colors: { [key: string]: string } = {
editorBackground: '#FF0000'
};
var styleSheet = dom.createStyleSheet();
let themeService = new TestThemeService(new TestTheme(colors));
var s = new CodeEditorServiceImpl(themeService, styleSheet);
s.registerDecorationType('example', options);
var sheet = readStyleSheet(styleSheet);
assert.equal(sheet, '.monaco-editor .ced-example-0 { background-color: rgb(255, 0, 0); }');
colors = {
editorBackground: '#EE0000',
editorBorder: '#00FFFF'
};
themeService.setTheme(new TestTheme(colors));
sheet = readStyleSheet(styleSheet);
assert.equal(sheet, '.monaco-editor .ced-example-0 { background-color: rgb(238, 0, 0); border-color: rgb(0, 255, 255); box-sizing: border-box; }');
s.removeDecorationType('example');
sheet = readStyleSheet(styleSheet);
assert.equal(sheet, '');
});
test('theme overrides', () => {
var options: IDecorationRenderOptions = {
color: { id: 'editorBackground' },
light: {
color: '#FF00FF'
},
dark: {
color: '#000000',
after: {
color: { id: 'infoForeground' }
}
}
};
var colors: { [key: string]: string } = {
editorBackground: '#FF0000',
infoForeground: '#444444'
};
var styleSheet = dom.createStyleSheet();
let themeService = new TestThemeService(new TestTheme(colors));
var s = new CodeEditorServiceImpl(themeService, styleSheet);
s.registerDecorationType('example', options);
var sheet = readStyleSheet(styleSheet);
let expected =
'.vs-dark.monaco-editor .ced-example-4::after, .hc-black.monaco-editor .ced-example-4::after { color: rgb(68, 68, 68) !important; }\n' +
'.vs-dark.monaco-editor .ced-example-1, .hc-black.monaco-editor .ced-example-1 { color: rgb(0, 0, 0) !important; }\n' +
'.vs.monaco-editor .ced-example-1 { color: rgb(255, 0, 255) !important; }\n' +
'.monaco-editor .ced-example-1 { color: rgb(255, 0, 0) !important; }';
assert.equal(sheet, expected);
s.removeDecorationType('example');
sheet = readStyleSheet(styleSheet);
assert.equal(sheet, '');
});
test('css properties, gutterIconPaths', () => {
var styleSheet = dom.createStyleSheet();
// unix file path (used as string)
var s = new CodeEditorServiceImpl(styleSheet);
var s = new CodeEditorServiceImpl(themeServiceMock, styleSheet);
s.registerDecorationType('example', { gutterIconPath: '/Users/foo/bar.png' });
var sheet = readStyleSheet(styleSheet);//.innerHTML || styleSheet.sheet.toString();
assert(
......@@ -63,7 +131,7 @@ suite('Decoration Render Options', () => {
);
// windows file path (used as string)
s = new CodeEditorServiceImpl(styleSheet);
s = new CodeEditorServiceImpl(themeServiceMock, styleSheet);
s.registerDecorationType('example', { gutterIconPath: 'c:\\files\\miles\\more.png' });
sheet = readStyleSheet(styleSheet);
// TODO@Alex test fails
......@@ -73,7 +141,7 @@ suite('Decoration Render Options', () => {
// );
// URI, only minimal encoding
s = new CodeEditorServiceImpl(styleSheet);
s = new CodeEditorServiceImpl(themeServiceMock, styleSheet);
s.registerDecorationType('example', { gutterIconPath: URI.parse('data:image/svg+xml;base64,PHN2ZyB4b+') });
sheet = readStyleSheet(styleSheet);
assert(
......@@ -82,7 +150,7 @@ suite('Decoration Render Options', () => {
);
// single quote must always be escaped/encoded
s = new CodeEditorServiceImpl(styleSheet);
s = new CodeEditorServiceImpl(themeServiceMock, styleSheet);
s.registerDecorationType('example', { gutterIconPath: '/Users/foo/b\'ar.png' });
sheet = readStyleSheet(styleSheet);
assert(
......@@ -90,7 +158,7 @@ suite('Decoration Render Options', () => {
|| sheet.indexOf('background: url("file:///Users/foo/b%27ar.png") center center no-repeat;') > 0
);
s = new CodeEditorServiceImpl(styleSheet);
s = new CodeEditorServiceImpl(themeServiceMock, styleSheet);
s.registerDecorationType('example', { gutterIconPath: URI.parse('http://test/pa\'th') });
sheet = readStyleSheet(styleSheet);
assert(
......
......@@ -1068,19 +1068,19 @@ declare module monaco.editor {
export interface IModelDecorationOverviewRulerOptions {
/**
* CSS color to render in the overview ruler.
* e.g.: rgba(100, 100, 100, 0.5)
* e.g.: rgba(100, 100, 100, 0.5) or a color from the color registry
*/
color: string;
color: string | ThemeColor;
/**
* CSS color to render in the overview ruler.
* e.g.: rgba(100, 100, 100, 0.5)
* e.g.: rgba(100, 100, 100, 0.5) or a color from the color registry
*/
darkColor: string;
darkColor: string | ThemeColor;
/**
* CSS color to render in the overview ruler.
* e.g.: rgba(100, 100, 100, 0.5)
* e.g.: rgba(100, 100, 100, 0.5) or a color from the color registry
*/
hcColor?: string;
hcColor?: string | ThemeColor;
/**
* The position in the overview ruler.
*/
......@@ -2158,6 +2158,10 @@ declare module monaco.editor {
restoreViewState?(state: any): void;
}
export interface ThemeColor {
id: string;
}
export interface ICommonCodeEditor extends IEditor {
/**
* An event emitted when the content of the current model has changed.
......
......@@ -14,9 +14,9 @@ import Event, { Emitter } from 'vs/base/common/event';
export let IThemeService = createDecorator<IThemeService>('themeService');
// base themes
export const DARK = 'dark';
export const LIGHT = 'light';
export const HIGH_CONTRAST = 'hc';
export const DARK: ThemeType = 'dark';
export const LIGHT: ThemeType = 'light';
export const HIGH_CONTRAST: ThemeType = 'hc';
export type ThemeType = 'light' | 'dark' | 'hc';
export function getThemeTypeSelector(type: ThemeType): string {
......
......@@ -721,14 +721,28 @@ declare module 'vscode' {
preview?: boolean;
}
/**
* A reference to one of the workbench colors as defined in https://code.visualstudio.com/docs/getstarted/theme-color-reference.
* Using a theme color is preferred over a custom color as it gives theme authors and users the possibility to change the color.
*/
export class ThemeColor {
/**
* Creates a reference to a theme color.
* @param id of the color. The available colors are listed in https://code.visualstudio.com/docs/getstarted/theme-color-reference.
*/
constructor(id: string);
}
/**
* Represents theme specific rendering styles for a [text editor decoration](#TextEditorDecorationType).
*/
export interface ThemableDecorationRenderOptions {
/**
* Background color of the decoration. Use rgba() and define transparent background colors to play well with other decorations.
* Alternativly a color from the color registry an be [referenced](#ColorIdentifier).
*/
backgroundColor?: string;
backgroundColor?: string | ThemeColor;
/**
* CSS styling property that will be applied to text enclosed by a decoration.
......@@ -739,7 +753,7 @@ declare module 'vscode' {
* CSS styling property that will be applied to text enclosed by a decoration.
* Better use 'outline' for setting one or more of the individual outline properties.
*/
outlineColor?: string;
outlineColor?: string | ThemeColor;
/**
* CSS styling property that will be applied to text enclosed by a decoration.
......@@ -762,7 +776,7 @@ declare module 'vscode' {
* CSS styling property that will be applied to text enclosed by a decoration.
* Better use 'border' for setting one or more of the individual border properties.
*/
borderColor?: string;
borderColor?: string | ThemeColor;
/**
* CSS styling property that will be applied to text enclosed by a decoration.
......@@ -801,7 +815,7 @@ declare module 'vscode' {
/**
* CSS styling property that will be applied to text enclosed by a decoration.
*/
color?: string;
color?: string | ThemeColor;
/**
* CSS styling property that will be applied to text enclosed by a decoration.
......@@ -823,7 +837,7 @@ declare module 'vscode' {
/**
* The color of the decoration in the overview ruler. Use rgba() and define transparent colors to play well with other decorations.
*/
overviewRulerColor?: string;
overviewRulerColor?: string | ThemeColor;
/**
* Defines the rendering options of the attachment that is inserted before the decorated text
......@@ -850,6 +864,10 @@ declare module 'vscode' {
* CSS styling property that will be applied to the decoration attachment.
*/
border?: string;
/**
* CSS styling property that will be applied to text enclosed by a decoration.
*/
borderColor?: string | ThemeColor;
/**
* CSS styling property that will be applied to the decoration attachment.
*/
......@@ -857,11 +875,11 @@ declare module 'vscode' {
/**
* CSS styling property that will be applied to the decoration attachment.
*/
color?: string;
color?: string | ThemeColor;
/**
* CSS styling property that will be applied to the decoration attachment.
*/
backgroundColor?: string;
backgroundColor?: string | ThemeColor;
/**
* CSS styling property that will be applied to the decoration attachment.
*/
......
......@@ -534,6 +534,7 @@ export function createApiFactory(
WorkspaceEdit: extHostTypes.WorkspaceEdit,
ProgressLocation: extHostTypes.ProgressLocation,
TreeItemCollapsibleState: extHostTypes.TreeItemCollapsibleState,
ThemeColor: extHostTypes.ThemeColor,
// functions
FileLocationKind: extHostTypes.FileLocationKind,
ApplyToKind: extHostTypes.ApplyToKind,
......
......@@ -1270,3 +1270,10 @@ export enum TreeItemCollapsibleState {
Collapsed = 1,
Expanded = 2
}
export class ThemeColor {
id: string;
constructor(id: string) {
this.id = id;
}
}
\ No newline at end of file
......@@ -50,8 +50,7 @@ import { IWindowsService, IWindowService } from 'vs/platform/windows/common/wind
import { TestWorkspace } from 'vs/platform/workspace/test/common/testWorkspace';
import { RawTextSource, IRawTextSource } from 'vs/editor/common/model/textSource';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IThemeService, ITheme, IThemingParticipant, ThemeType } from 'vs/platform/theme/common/themeService';
import { IDisposable } from 'vs/base/common/lifecycle';
import { IThemeService, ITheme, DARK } from 'vs/platform/theme/common/themeService';
import { Color } from 'vs/base/common/color';
import { isLinux } from 'vs/base/common/platform';
......@@ -1000,10 +999,16 @@ export class TestWindowsService implements IWindowsService {
}
export class TestTheme implements ITheme {
type: ThemeType;
constructor(private colors: { [id: string]: string; } = {}, public type = DARK) {
}
getColor(color: string, useDefault?: boolean): Color {
throw new Error('Method not implemented.');
let value = this.colors[color];
if (value) {
return Color.fromHex(value);
}
return void 0;
}
defines(color: string): boolean {
......@@ -1011,17 +1016,30 @@ export class TestTheme implements ITheme {
}
}
const testTheme = new TestTheme();
export class TestThemeService implements IThemeService {
_serviceBrand: any;
_theme: ITheme;
_onThemeChange = new Emitter<ITheme>();
constructor(theme = new TestTheme()) {
this._theme = theme;
}
getTheme(): ITheme {
return testTheme;
return this._theme;
}
setTheme(theme: ITheme) {
this._theme = theme;
this.fireThemeChange();
}
fireThemeChange() {
this._onThemeChange.fire(this._theme);
}
onThemeChange(participant: IThemingParticipant): IDisposable {
return { dispose: () => { } };
public get onThemeChange(): Event<ITheme> {
return this._onThemeChange.event;
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册