@xterm/addon-ligatures 0.8.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +55 -0
- package/lib/addon-ligatures.js +3 -0
- package/lib/addon-ligatures.js.map +1 -0
- package/package.json +47 -0
- package/src/LigaturesAddon.ts +43 -0
- package/src/Types.d.ts +8 -0
- package/src/font.ts +123 -0
- package/src/index.ts +99 -0
- package/src/parse.ts +180 -0
- package/typings/addon-ligatures.d.ts +58 -0
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@xterm/addon-ligatures",
|
|
3
|
+
"version": "0.8.0-beta.1",
|
|
4
|
+
"description": "Add support for programming ligatures to xterm.js",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "The xterm.js authors",
|
|
7
|
+
"url": "https://xtermjs.org/"
|
|
8
|
+
},
|
|
9
|
+
"main": "lib/addon-ligatures.js",
|
|
10
|
+
"types": "typings/addon-ligatures.d.ts",
|
|
11
|
+
"repository": "https://github.com/xtermjs/xterm.js/tree/master/addons/addon-ligatures",
|
|
12
|
+
"engines": {
|
|
13
|
+
"node": ">8.0.0"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"prepare": "node bin/download-fonts.js",
|
|
17
|
+
"build": "tsc -p src",
|
|
18
|
+
"watch": "tsc -w -p src",
|
|
19
|
+
"prepackage": "npm run build",
|
|
20
|
+
"package": "webpack",
|
|
21
|
+
"pretest": "npm run build",
|
|
22
|
+
"test": "nyc mocha out/**/*.test.js",
|
|
23
|
+
"prepublish": "npm run package"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"font",
|
|
27
|
+
"ligature",
|
|
28
|
+
"terminal",
|
|
29
|
+
"xterm",
|
|
30
|
+
"xterm.js"
|
|
31
|
+
],
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"font-finder": "^1.1.0",
|
|
35
|
+
"font-ligatures": "^1.4.1"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/sinon": "^5.0.1",
|
|
39
|
+
"axios": "^0.21.2",
|
|
40
|
+
"mkdirp": "0.5.5",
|
|
41
|
+
"sinon": "6.3.5",
|
|
42
|
+
"yauzl": "^2.10.0"
|
|
43
|
+
},
|
|
44
|
+
"peerDependencies": {
|
|
45
|
+
"xterm": "^5.0.0"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
|
|
3
|
+
* @license MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Terminal } from '@xterm/xterm';
|
|
7
|
+
import { enableLigatures } from '.';
|
|
8
|
+
import { ILigatureOptions } from './Types';
|
|
9
|
+
|
|
10
|
+
export interface ITerminalAddon {
|
|
11
|
+
activate(terminal: Terminal): void;
|
|
12
|
+
dispose(): void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class LigaturesAddon implements ITerminalAddon {
|
|
16
|
+
private readonly _fallbackLigatures: string[];
|
|
17
|
+
|
|
18
|
+
private _terminal: Terminal | undefined;
|
|
19
|
+
private _characterJoinerId: number | undefined;
|
|
20
|
+
|
|
21
|
+
constructor(options?: Partial<ILigatureOptions>) {
|
|
22
|
+
this._fallbackLigatures = (options?.fallbackLigatures || [
|
|
23
|
+
'<--', '<---', '<<-', '<-', '->', '->>', '-->', '--->',
|
|
24
|
+
'<==', '<===', '<<=', '<=', '=>', '=>>', '==>', '===>', '>=', '>>=',
|
|
25
|
+
'<->', '<-->', '<--->', '<---->', '<=>', '<==>', '<===>', '<====>', '-------->',
|
|
26
|
+
'<~~', '<~', '~>', '~~>', '::', ':::', '==', '!=', '===', '!==',
|
|
27
|
+
':=', ':-', ':+', '<*', '<*>', '*>', '<|', '<|>', '|>', '+:', '-:', '=:', ':>',
|
|
28
|
+
'++', '+++', '<!--', '<!---', '<***>'
|
|
29
|
+
]).sort((a, b) => b.length - a.length);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public activate(terminal: Terminal): void {
|
|
33
|
+
this._terminal = terminal;
|
|
34
|
+
this._characterJoinerId = enableLigatures(terminal, this._fallbackLigatures);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
public dispose(): void {
|
|
38
|
+
if (this._characterJoinerId !== undefined) {
|
|
39
|
+
this._terminal?.deregisterCharacterJoiner(this._characterJoinerId);
|
|
40
|
+
this._characterJoinerId = undefined;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
package/src/Types.d.ts
ADDED
package/src/font.ts
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
|
|
3
|
+
* @license MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Font, loadBuffer } from 'font-ligatures';
|
|
7
|
+
|
|
8
|
+
import parse from './parse';
|
|
9
|
+
|
|
10
|
+
interface IFontMetadata {
|
|
11
|
+
family: string;
|
|
12
|
+
fullName: string;
|
|
13
|
+
postscriptName: string;
|
|
14
|
+
blob: () => Promise<Blob>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface IFontAccessNavigator {
|
|
18
|
+
fonts: {
|
|
19
|
+
query: () => Promise<IFontMetadata[]>;
|
|
20
|
+
};
|
|
21
|
+
permissions: {
|
|
22
|
+
request?: (permission: { name: string }) => Promise<{state: string}>;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let fontsPromise: Promise<Record<string, IFontMetadata[]>> | undefined = undefined;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Loads the font ligature wrapper for the specified font family if it could be
|
|
30
|
+
* resolved, throwing if it is unable to find a suitable match.
|
|
31
|
+
* @param fontFamily The CSS font family definition to resolve
|
|
32
|
+
* @param cacheSize The size of the ligature cache to maintain if the font is resolved
|
|
33
|
+
*/
|
|
34
|
+
export default async function load(fontFamily: string, cacheSize: number): Promise<Font | undefined> {
|
|
35
|
+
if (!fontsPromise) {
|
|
36
|
+
// Web environment that supports font access API
|
|
37
|
+
if (typeof navigator !== 'undefined' && 'fonts' in navigator) {
|
|
38
|
+
try {
|
|
39
|
+
const status = await (navigator as unknown as IFontAccessNavigator).permissions.request?.({
|
|
40
|
+
name: 'local-fonts'
|
|
41
|
+
});
|
|
42
|
+
if (status && status.state !== 'granted') {
|
|
43
|
+
throw new Error('Permission to access local fonts not granted.');
|
|
44
|
+
}
|
|
45
|
+
} catch (err: any) {
|
|
46
|
+
// A `TypeError` indicates the 'local-fonts'
|
|
47
|
+
// permission is not yet implemented, so
|
|
48
|
+
// only `throw` if this is _not_ the problem.
|
|
49
|
+
if (err.name !== 'TypeError') {
|
|
50
|
+
throw err;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const fonts: Record<string, IFontMetadata[]> = {};
|
|
54
|
+
try {
|
|
55
|
+
const fontsIterator = await (navigator as unknown as IFontAccessNavigator).fonts.query();
|
|
56
|
+
for (const metadata of fontsIterator) {
|
|
57
|
+
if (!fonts.hasOwnProperty(metadata.family)) {
|
|
58
|
+
fonts[metadata.family] = [];
|
|
59
|
+
}
|
|
60
|
+
fonts[metadata.family].push(metadata);
|
|
61
|
+
}
|
|
62
|
+
fontsPromise = Promise.resolve(fonts);
|
|
63
|
+
} catch (err: any) {
|
|
64
|
+
console.error(err.name, err.message);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// Latest proposal https://bugs.chromium.org/p/chromium/issues/detail?id=1312603
|
|
68
|
+
else if (typeof window !== 'undefined' && 'queryLocalFonts' in window) {
|
|
69
|
+
const fonts: Record<string, IFontMetadata[]> = {};
|
|
70
|
+
try {
|
|
71
|
+
const fontsIterator = await (window as any).queryLocalFonts();
|
|
72
|
+
for (const metadata of fontsIterator) {
|
|
73
|
+
if (!fonts.hasOwnProperty(metadata.family)) {
|
|
74
|
+
fonts[metadata.family] = [];
|
|
75
|
+
}
|
|
76
|
+
fonts[metadata.family].push(metadata);
|
|
77
|
+
}
|
|
78
|
+
fontsPromise = Promise.resolve(fonts);
|
|
79
|
+
} catch (err: any) {
|
|
80
|
+
console.error(err.name, err.message);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (!fontsPromise) {
|
|
84
|
+
fontsPromise = Promise.resolve({});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const fonts = await fontsPromise;
|
|
89
|
+
for (const family of parse(fontFamily)) {
|
|
90
|
+
// If we reach one of the generic font families, the font resolution
|
|
91
|
+
// will end for the browser and we can't determine the specific font
|
|
92
|
+
// used. Throw.
|
|
93
|
+
if (genericFontFamilies.includes(family)) {
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (fonts.hasOwnProperty(family) && fonts[family].length > 0) {
|
|
98
|
+
const font = fonts[family][0];
|
|
99
|
+
if ('blob' in font) {
|
|
100
|
+
const bytes = await font.blob();
|
|
101
|
+
const buffer = await bytes.arrayBuffer();
|
|
102
|
+
return loadBuffer(buffer, { cacheSize });
|
|
103
|
+
}
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// If none of the fonts could resolve, throw an error
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// https://drafts.csswg.org/css-fonts-4/#generic-font-families
|
|
113
|
+
const genericFontFamilies = [
|
|
114
|
+
'serif',
|
|
115
|
+
'sans-serif',
|
|
116
|
+
'cursive',
|
|
117
|
+
'fantasy',
|
|
118
|
+
'monospace',
|
|
119
|
+
'system-ui',
|
|
120
|
+
'emoji',
|
|
121
|
+
'math',
|
|
122
|
+
'fangsong'
|
|
123
|
+
];
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
|
|
3
|
+
* @license MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Terminal } from '@xterm/xterm';
|
|
7
|
+
import { Font } from 'font-ligatures';
|
|
8
|
+
|
|
9
|
+
import load from './font';
|
|
10
|
+
|
|
11
|
+
const enum LoadingState {
|
|
12
|
+
UNLOADED,
|
|
13
|
+
LOADING,
|
|
14
|
+
LOADED,
|
|
15
|
+
FAILED
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Caches 100K characters worth of ligatures. In practice this works out to
|
|
19
|
+
// about 650 KB worth of cache, when a moderate number of ligatures are present.
|
|
20
|
+
const CACHE_SIZE = 100000;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Enable ligature support for the provided Terminal instance. To function
|
|
24
|
+
* properly, this must be called after `open()` is called on the therminal. If
|
|
25
|
+
* the font currently in use supports ligatures, the terminal will automatically
|
|
26
|
+
* start to render them.
|
|
27
|
+
* @param term Terminal instance from xterm.js
|
|
28
|
+
*/
|
|
29
|
+
export function enableLigatures(term: Terminal, fallbackLigatures: string[] = []): number {
|
|
30
|
+
let currentFontName: string | undefined = undefined;
|
|
31
|
+
let font: Font | undefined = undefined;
|
|
32
|
+
let loadingState: LoadingState = LoadingState.UNLOADED;
|
|
33
|
+
let loadError: any | undefined = undefined;
|
|
34
|
+
|
|
35
|
+
return term.registerCharacterJoiner((text: string): [number, number][] => {
|
|
36
|
+
// If the font hasn't been loaded yet, load it and return an empty result
|
|
37
|
+
const termFont = term.options.fontFamily;
|
|
38
|
+
if (
|
|
39
|
+
termFont &&
|
|
40
|
+
(loadingState === LoadingState.UNLOADED || currentFontName !== termFont)
|
|
41
|
+
) {
|
|
42
|
+
font = undefined;
|
|
43
|
+
loadingState = LoadingState.LOADING;
|
|
44
|
+
currentFontName = termFont;
|
|
45
|
+
const currentCallFontName = currentFontName;
|
|
46
|
+
|
|
47
|
+
load(currentCallFontName, CACHE_SIZE)
|
|
48
|
+
.then(f => {
|
|
49
|
+
// Another request may have come in while we were waiting, so make
|
|
50
|
+
// sure our font is still vaild.
|
|
51
|
+
if (currentCallFontName === term.options.fontFamily) {
|
|
52
|
+
loadingState = LoadingState.LOADED;
|
|
53
|
+
font = f;
|
|
54
|
+
|
|
55
|
+
// Only refresh things if we actually found a font
|
|
56
|
+
if (f) {
|
|
57
|
+
term.refresh(0, term.rows - 1);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
.catch(e => {
|
|
62
|
+
// Another request may have come in while we were waiting, so make
|
|
63
|
+
// sure our font is still vaild.
|
|
64
|
+
if (currentCallFontName === term.options.fontFamily) {
|
|
65
|
+
loadingState = LoadingState.FAILED;
|
|
66
|
+
if (term.options.logLevel === 'debug') {
|
|
67
|
+
console.debug(loadError, new Error('Failure while loading font'));
|
|
68
|
+
}
|
|
69
|
+
font = undefined;
|
|
70
|
+
loadError = e;
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (font && loadingState === LoadingState.LOADED) {
|
|
76
|
+
// We clone the entries to avoid the internal cache of the ligature finder
|
|
77
|
+
// getting messed up.
|
|
78
|
+
return font.findLigatureRanges(text).map<[number, number]>(
|
|
79
|
+
range => [range[0], range[1]]
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return getFallbackRanges(text, fallbackLigatures);
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function getFallbackRanges(text: string, fallbackLigatures: string[]): [number, number][] {
|
|
88
|
+
const ranges: [number, number][] = [];
|
|
89
|
+
for (let i = 0; i < text.length; i++) {
|
|
90
|
+
for (let j = 0; j < fallbackLigatures.length; j++) {
|
|
91
|
+
if (text.startsWith(fallbackLigatures[j], i)) {
|
|
92
|
+
ranges.push([i, i + fallbackLigatures[j].length]);
|
|
93
|
+
i += fallbackLigatures[j].length - 1;
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return ranges;
|
|
99
|
+
}
|
package/src/parse.ts
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
|
|
3
|
+
* @license MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
interface IParseContext {
|
|
7
|
+
input: string;
|
|
8
|
+
offset: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Parses a CSS font family value, returning the component font families
|
|
13
|
+
* contained within.
|
|
14
|
+
*
|
|
15
|
+
* @param family The CSS font family input string to parse
|
|
16
|
+
*/
|
|
17
|
+
export default function parse(family: string): string[] {
|
|
18
|
+
if (typeof family !== 'string') {
|
|
19
|
+
throw new Error('Font family must be a string');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const context: IParseContext = {
|
|
23
|
+
input: family,
|
|
24
|
+
offset: 0
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const families = [];
|
|
28
|
+
let currentFamily = '';
|
|
29
|
+
|
|
30
|
+
// Work through the input character by character until there are none left.
|
|
31
|
+
// This lexing and parsing in one pass.
|
|
32
|
+
while (context.offset < context.input.length) {
|
|
33
|
+
const char = context.input[context.offset++];
|
|
34
|
+
switch (char) {
|
|
35
|
+
// String
|
|
36
|
+
case '\'':
|
|
37
|
+
case '"':
|
|
38
|
+
currentFamily += parseString(context, char);
|
|
39
|
+
break;
|
|
40
|
+
// End of family
|
|
41
|
+
case ',':
|
|
42
|
+
families.push(currentFamily);
|
|
43
|
+
currentFamily = '';
|
|
44
|
+
break;
|
|
45
|
+
default:
|
|
46
|
+
// Identifiers (whitespace between families is swallowed)
|
|
47
|
+
if (!/\s/.test(char)) {
|
|
48
|
+
context.offset--;
|
|
49
|
+
currentFamily += parseIdentifier(context);
|
|
50
|
+
families.push(currentFamily);
|
|
51
|
+
currentFamily = '';
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return families;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Parse a CSS string.
|
|
61
|
+
*
|
|
62
|
+
* @param context Parsing input and offset
|
|
63
|
+
* @param quoteChar The quote character for the string (' or ")
|
|
64
|
+
*/
|
|
65
|
+
function parseString(context: IParseContext, quoteChar: '\'' | '"'): string {
|
|
66
|
+
let str = '';
|
|
67
|
+
let escaped = false;
|
|
68
|
+
while (context.offset < context.input.length) {
|
|
69
|
+
const char = context.input[context.offset++];
|
|
70
|
+
if (escaped) {
|
|
71
|
+
if (/[\dA-Fa-f]/.test(char)) {
|
|
72
|
+
// Unicode escape
|
|
73
|
+
context.offset--;
|
|
74
|
+
str += parseUnicode(context);
|
|
75
|
+
} else if (char !== '\n') {
|
|
76
|
+
// Newlines are ignored if escaped. Other characters are used as is.
|
|
77
|
+
str += char;
|
|
78
|
+
}
|
|
79
|
+
escaped = false;
|
|
80
|
+
} else {
|
|
81
|
+
switch (char) {
|
|
82
|
+
// Terminated quote
|
|
83
|
+
case quoteChar:
|
|
84
|
+
return str;
|
|
85
|
+
// Begin escape
|
|
86
|
+
case '\\':
|
|
87
|
+
escaped = true;
|
|
88
|
+
break;
|
|
89
|
+
// Add character to string
|
|
90
|
+
default:
|
|
91
|
+
str += char;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
throw new Error('Unterminated string');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Parse a CSS custom identifier.
|
|
101
|
+
*
|
|
102
|
+
* @param context Parsing input and offset
|
|
103
|
+
*/
|
|
104
|
+
function parseIdentifier(context: IParseContext): string {
|
|
105
|
+
let str = '';
|
|
106
|
+
let escaped = false;
|
|
107
|
+
while (context.offset < context.input.length) {
|
|
108
|
+
const char = context.input[context.offset++];
|
|
109
|
+
if (escaped) {
|
|
110
|
+
if (/[\dA-Fa-f]/.test(char)) {
|
|
111
|
+
// Unicode escape
|
|
112
|
+
context.offset--;
|
|
113
|
+
str += parseUnicode(context);
|
|
114
|
+
} else {
|
|
115
|
+
// Everything else is used as is
|
|
116
|
+
str += char;
|
|
117
|
+
}
|
|
118
|
+
escaped = false;
|
|
119
|
+
} else {
|
|
120
|
+
switch (char) {
|
|
121
|
+
// Begin escape
|
|
122
|
+
case '\\':
|
|
123
|
+
escaped = true;
|
|
124
|
+
break;
|
|
125
|
+
// Terminate identifier
|
|
126
|
+
case ',':
|
|
127
|
+
return str;
|
|
128
|
+
default:
|
|
129
|
+
if (/\s/.test(char)) {
|
|
130
|
+
// Whitespace is collapsed into a single space within an identifier
|
|
131
|
+
if (!str.endsWith(' ')) {
|
|
132
|
+
str += ' ';
|
|
133
|
+
}
|
|
134
|
+
} else {
|
|
135
|
+
// Add other characters directly
|
|
136
|
+
str += char;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return str;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Parse a CSS unicode escape.
|
|
147
|
+
*
|
|
148
|
+
* @param context Parsing input and offset
|
|
149
|
+
*/
|
|
150
|
+
function parseUnicode(context: IParseContext): string {
|
|
151
|
+
let str = '';
|
|
152
|
+
while (context.offset < context.input.length) {
|
|
153
|
+
const char = context.input[context.offset++];
|
|
154
|
+
if (/\s/.test(char)) {
|
|
155
|
+
// The first whitespace character after a unicode escape indicates the end
|
|
156
|
+
// of the escape and is swallowed.
|
|
157
|
+
return unicodeToString(str);
|
|
158
|
+
}
|
|
159
|
+
if (str.length >= 6 || !/[\dA-Fa-f]/.test(char)) {
|
|
160
|
+
// If the next character is not a valid hex digit or we have reached the
|
|
161
|
+
// maximum of 6 digits in the escape, terminate the escape.
|
|
162
|
+
context.offset--;
|
|
163
|
+
return unicodeToString(str);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Otherwise, just add it to the escape
|
|
167
|
+
str += char;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return unicodeToString(str);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Convert a unicode code point from a hex string to a utf8 string.
|
|
175
|
+
*
|
|
176
|
+
* @param codePoint Unicode code point represented as a hex string
|
|
177
|
+
*/
|
|
178
|
+
function unicodeToString(codePoint: string): string {
|
|
179
|
+
return String.fromCodePoint(parseInt(codePoint, 16));
|
|
180
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
|
|
3
|
+
* @license MIT
|
|
4
|
+
*
|
|
5
|
+
* This contains the type declarations for the @xterm/addon-ligatures library.
|
|
6
|
+
* Note that some interfaces may differ between this file and the actual
|
|
7
|
+
* implementation in src/, that's because this file declares the *public* API
|
|
8
|
+
* which is intended to be stable and consumed by external programs.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { Terminal, ITerminalAddon } from '@xterm/xterm';
|
|
12
|
+
|
|
13
|
+
declare module '@xterm/addon-ligatures' {
|
|
14
|
+
/**
|
|
15
|
+
* An xterm.js addon that enables web links.
|
|
16
|
+
*/
|
|
17
|
+
export class LigaturesAddon implements ITerminalAddon {
|
|
18
|
+
/**
|
|
19
|
+
* Creates a new ligatures addon.
|
|
20
|
+
*
|
|
21
|
+
* @param options Options for the ligatures addon.
|
|
22
|
+
*/
|
|
23
|
+
constructor(options?: Partial<ILigatureOptions>);
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Activates the addon
|
|
27
|
+
*
|
|
28
|
+
* @param terminal The terminal the addon is being loaded in.
|
|
29
|
+
*/
|
|
30
|
+
public activate(terminal: Terminal): void;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Disposes the addon.
|
|
34
|
+
*/
|
|
35
|
+
public dispose(): void;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Options for the ligatures addon.
|
|
40
|
+
*/
|
|
41
|
+
export interface ILigatureOptions {
|
|
42
|
+
/**
|
|
43
|
+
* Fallback ligatures to use when the font access API is either not supported by the browser or
|
|
44
|
+
* access is denied. The default set of ligatures is taken from Iosevka's default "calt"
|
|
45
|
+
* ligation set: https://typeof.net/Iosevka/
|
|
46
|
+
*
|
|
47
|
+
* ```
|
|
48
|
+
* <-- <--- <<- <- -> ->> --> --->
|
|
49
|
+
* <== <=== <<= <= => =>> ==> ===> >= >>=
|
|
50
|
+
* <-> <--> <---> <----> <=> <==> <===> <====> -------->
|
|
51
|
+
* <~~ <~ ~> ~~> :: ::: == != === !==
|
|
52
|
+
* := :- :+ <* <*> *> <| <|> |> +: -: =: :>
|
|
53
|
+
* ++ +++ <!-- <!--- <***>
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
fallbackLigatures: string[]
|
|
57
|
+
}
|
|
58
|
+
}
|