Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/jupyter/util/misc.ts
1447 views
1
/*
2
* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
/*
7
Some simple misc functions with no dependencies.
8
9
It's very good to have these as functions rather than put
10
the code all over the place and have conventions about paths!
11
12
part of CoCalc
13
(c) SageMath, Inc., 2017
14
*/
15
16
import * as immutable from "immutable";
17
18
import { cmp } from "@cocalc/util/misc";
19
20
// This list is inspired by OutputArea.output_types in https://github.com/jupyter/notebook/blob/master/notebook/static/notebook/js/outputarea.js
21
// The order matters -- we only keep the left-most type (see import-from-ipynb.coffee)
22
// See https://jupyterlab.readthedocs.io/en/stable/user/file_formats.html#file-and-output-formats
23
24
export const JUPYTER_MIMETYPES = [
25
"application/javascript",
26
"application/json",
27
"text/html",
28
"text/markdown",
29
"text/latex",
30
"image/svg+xml",
31
"image/png",
32
"image/jpeg",
33
"image/bmp",
34
"image/gif",
35
"application/pdf",
36
"text/plain",
37
] as const;
38
39
// with metadata.cocalc.priority >= this the kernel will be "emphasized" or "suggested" in the UI
40
export const KERNEL_POPULAR_THRESHOLD = 10;
41
42
export type Kernel = immutable.Map<string, string>;
43
export type Kernels = immutable.List<Kernel>;
44
45
export function codemirror_to_jupyter_pos(
46
code: string,
47
pos: { ch: number; line: number },
48
): number {
49
const lines = code.split("\n");
50
let s = pos.ch;
51
for (let i = 0; i < pos.line; i++) {
52
s += lines[i].length + 1;
53
}
54
return s;
55
}
56
57
// Return s + ... + s = s*n (in python notation), where there are n>=0 summands.
58
export function times_n(s: string, n: number): string {
59
let t = "";
60
for (let i = 0; i < n; i++) t += s;
61
return t;
62
}
63
64
// These js_idx functions are adapted from https://github.com/jupyter/notebook/pull/2509
65
// Also, see https://github.com/nteract/hydrogen/issues/807 for why.
66
// An example using a python3 kernel is to define
67
// 𨭎𨭎𨭎𨭎𨭎 = 10
68
// then type 𨭎𨭎[tab key] and see it properly complete.
69
70
// javascript stores text as utf16 and string indices use "code units",
71
// which stores high-codepoint characters as "surrogate pairs",
72
// which occupy two indices in the javascript string.
73
// We need to translate cursor_pos in the protocol (in characters)
74
// to js offset (with surrogate pairs taking two spots).
75
export function js_idx_to_char_idx(js_idx: number, text: string): number {
76
let char_idx = js_idx;
77
for (let i = 0; i + 1 < text.length && i < js_idx; i++) {
78
const char_code = text.charCodeAt(i);
79
// check for surrogate pair
80
if (char_code >= 0xd800 && char_code <= 0xdbff) {
81
const next_char_code = text.charCodeAt(i + 1);
82
if (next_char_code >= 0xdc00 && next_char_code <= 0xdfff) {
83
char_idx--;
84
i++;
85
}
86
}
87
}
88
return char_idx;
89
}
90
91
export function char_idx_to_js_idx(char_idx: number, text: string): number {
92
let js_idx = char_idx;
93
for (let i = 0; i + 1 < text.length && i < js_idx; i++) {
94
const char_code = text.charCodeAt(i);
95
// check for surrogate pair
96
if (char_code >= 0xd800 && char_code <= 0xdbff) {
97
const next_char_code = text.charCodeAt(i + 1);
98
if (next_char_code >= 0xdc00 && next_char_code <= 0xdfff) {
99
js_idx++;
100
i++;
101
}
102
}
103
}
104
return js_idx;
105
}
106
107
// Transforms the KernelSpec list into two useful datastructures.
108
// Was part of jupyter/store, but now used in several places.
109
export function get_kernels_by_name_or_language(
110
kernels: Kernels,
111
): [
112
immutable.OrderedMap<string, immutable.Map<string, string>>,
113
immutable.OrderedMap<string, immutable.List<string>>,
114
] {
115
const data_name: any = {};
116
let data_lang: any = {};
117
const add_lang = (lang, entry) => {
118
if (data_lang[lang] == null) data_lang[lang] = [];
119
data_lang[lang].push(entry);
120
};
121
kernels
122
.filter((entry) => entry.getIn(["metadata", "cocalc", "disabled"]) !== true)
123
.map((entry) => {
124
const name = entry.get("name");
125
const lang = entry.get("language");
126
if (name != null) data_name[name] = entry;
127
if (lang == null) {
128
// we collect all kernels without a language under "misc"
129
add_lang("misc", entry);
130
} else {
131
add_lang(lang, entry);
132
}
133
});
134
const by_name = immutable
135
.OrderedMap<string, immutable.Map<string, string>>(data_name)
136
.sortBy((v, k) => {
137
return v.get("display_name", v.get("name", k)).toLowerCase();
138
});
139
// data_lang, we're only interested in the kernel names, not the entry itself
140
data_lang = immutable.fromJS(data_lang).map((v, k) => {
141
v = v
142
.sortBy((v) => v.get("display_name", v.get("name", k)).toLowerCase())
143
.map((v) => v.get("name"));
144
return v;
145
});
146
const by_lang = immutable
147
.OrderedMap<string, immutable.List<string>>(data_lang)
148
.sortBy((_v, k) => k.toLowerCase());
149
return [by_name, by_lang];
150
}
151
152
/*
153
* select all kernels, which are ranked highest for a specific language.
154
*
155
* kernel metadata looks like that
156
*
157
* "display_name": ...,
158
* "argv":, ...
159
* "language": "sagemath",
160
* "metadata": {
161
* "cocalc": {
162
* "priority": 10,
163
* "description": "Open-source mathematical software system",
164
* "url": "https://www.sagemath.org/",
165
* "disabled": true
166
* }
167
* }
168
*
169
* Return dict of language <-> kernel_name
170
*/
171
export function get_kernel_selection(
172
kernels: Kernels,
173
): immutable.Map<string, string> {
174
// for each language, we pick the top priority kernel
175
const data: any = {};
176
kernels
177
.filter((entry) => entry.get("language") != null)
178
.groupBy((entry) => entry.get("language"))
179
.forEach((kernels, lang) => {
180
const top: any = kernels
181
.sort((a, b) => {
182
const va = -(a.getIn(
183
["metadata", "cocalc", "priority"],
184
0,
185
) as number);
186
const vb = -(b.getIn(
187
["metadata", "cocalc", "priority"],
188
0,
189
) as number);
190
return cmp(va, vb);
191
})
192
.first();
193
if (top == null || lang == null) return true;
194
const name = top.get("name");
195
if (name == null) return true;
196
data[lang] = name;
197
});
198
199
return immutable.Map<string, string>(data);
200
}
201
202