diff --git a/demo/client.ts b/demo/client.ts index b67a84a5..1c38af0f 100644 --- a/demo/client.ts +++ b/demo/client.ts @@ -585,6 +585,32 @@ function powerlineSymbolTest() { term.writeln(`0xA_ ${s('\ue0a0')}${s('\ue0a1')}${s('\ue0a2')}`); term.writeln(`0xB_ ${s('\ue0b0')}${s('\ue0b1')}${s('\ue0b2')}${s('\ue0b3')}`); term.writeln(''); + term.writeln( + `\x1b[7m` + + ` inverse \ue0b1 \x1b[0;40m\ue0b0` + + ` 0 \ue0b1 \x1b[30;41m\ue0b0\x1b[39m` + + ` 1 \ue0b1 \x1b[31;42m\ue0b0\x1b[39m` + + ` 2 \ue0b1 \x1b[32;43m\ue0b0\x1b[39m` + + ` 3 \ue0b1 \x1b[33;44m\ue0b0\x1b[39m` + + ` 4 \ue0b1 \x1b[34;45m\ue0b0\x1b[39m` + + ` 5 \ue0b1 \x1b[35;46m\ue0b0\x1b[39m` + + ` 6 \ue0b1 \x1b[36;47m\ue0b0\x1b[39m` + + ` 7 \ue0b1 \x1b[37;49m\ue0b0\x1b[0m` + ); + term.writeln(''); + term.writeln( + `\x1b[7m` + + ` inverse \ue0b3 \x1b[0;7;40m\ue0b2\x1b[27m` + + ` 0 \ue0b3 \x1b[7;30;41m\ue0b2\x1b[27;39m` + + ` 1 \ue0b3 \x1b[7;31;42m\ue0b2\x1b[27;39m` + + ` 2 \ue0b3 \x1b[7;32;43m\ue0b2\x1b[27;39m` + + ` 3 \ue0b3 \x1b[7;33;44m\ue0b2\x1b[27;39m` + + ` 4 \ue0b3 \x1b[7;34;45m\ue0b2\x1b[27;39m` + + ` 5 \ue0b3 \x1b[7;35;46m\ue0b2\x1b[27;39m` + + ` 6 \ue0b3 \x1b[7;36;47m\ue0b2\x1b[27;39m` + + ` 7 \ue0b3 \x1b[7;37;49m\ue0b2\x1b[0m` + ); + term.writeln(''); term.writeln('Powerline extra symbols:'); term.writeln(' 0 1 2 3 4 5 6 7 8 9 A B C D E F'); term.writeln(`0xA_ ${s('\ue0a3')}`); diff --git a/src/browser/renderer/CustomGlyphs.ts b/src/browser/renderer/CustomGlyphs.ts index c2bfc210..dc9450d6 100644 --- a/src/browser/renderer/CustomGlyphs.ts +++ b/src/browser/renderer/CustomGlyphs.ts @@ -325,6 +325,35 @@ export const boxDrawingDefinitions: { [character: string]: { [fontWeight: number '╰': { [Style.NORMAL]: 'C.5,0,.5,.5,1,.5' } }; +interface IVectorShape { + d: string; + type: VectorType; +} + +const enum VectorType { + FILL, + STROKE +} + +/** + * This contains the definitions of the primarily used box drawing characters as vector shapes. The + * reason these characters are defined specially is to avoid common problems if a user's font has + * not been patched with powerline characters and also to get pixel perfect rendering as rendering + * issues can occur around AA/SPAA. + * + * Original symbols defined in https://github.com/powerline/fontpatcher + */ +export const powerlineDefinitions: { [index: string]: IVectorShape } = { + // Right triangle solid + '\u{E0B0}': { d: 'M0,0 L1,.5 L0,1', type: VectorType.FILL }, + // Right triangle line + '\u{E0B1}': { d: 'M0,0 L1,.5 L0,1', type: VectorType.STROKE }, + // Left triangle solid + '\u{E0B2}': { d: 'M1,0 L0,.5 L1,1', type: VectorType.FILL }, + // Left triangle line + '\u{E0B3}': { d: 'M1,0 L0,.5 L1,1', type: VectorType.STROKE } +}; + /** * Try drawing a custom block element or box drawing character, returning whether it was * successfully drawn. @@ -355,6 +384,12 @@ export function tryDrawCustomChar( return true; } + const powerlineDefinition = powerlineDefinitions[c]; + if (powerlineDefinition) { + drawPowerlineChar(ctx, powerlineDefinition, xOffset, yOffset, scaledCellWidth, scaledCellHeight); + return true; + } + return false; } @@ -518,6 +553,38 @@ function drawBoxDrawingChar( } } +function drawPowerlineChar( + ctx: CanvasRenderingContext2D, + charDefinition: IVectorShape, + xOffset: number, + yOffset: number, + scaledCellWidth: number, + scaledCellHeight: number +): void { + ctx.beginPath(); + ctx.lineWidth = window.devicePixelRatio; + for (const instruction of charDefinition.d.split(' ')) { + const type = instruction[0]; + const f = svgToCanvasInstructionMap[type]; + if (!f) { + console.error(`Could not find drawing instructions for "${type}"`); + continue; + } + const args: string[] = instruction.substring(1).split(','); + if (!args[0] || !args[1]) { + continue; + } + f(ctx, translateArgs(args, scaledCellWidth, scaledCellHeight, xOffset, yOffset)); + } + if (charDefinition.type === VectorType.STROKE) { + ctx.strokeStyle = ctx.fillStyle; + ctx.stroke(); + } else { + ctx.fill(); + } + ctx.closePath(); +} + function clamp(value: number, max: number, min: number = 0): number { return Math.max(Math.min(value, max), min); }