CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
sagemathinc

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

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