Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/notebook/browser/viewModel/cellOutputTextHelper.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { IClipboardService } from '../../../../../platform/clipboard/common/clipboardService.js';
7
import { ILogService } from '../../../../../platform/log/common/log.js';
8
import { NotebookTextModel } from '../../common/model/notebookTextModel.js';
9
import { IOutputItemDto } from '../../common/notebookCommon.js';
10
import { isTextStreamMime } from '../../../../../base/common/mime.js';
11
import { ICellOutputViewModel, ICellViewModel } from '../notebookBrowser.js';
12
13
interface Error {
14
name: string;
15
message: string;
16
stack?: string;
17
}
18
19
export function getAllOutputsText(notebook: NotebookTextModel, viewCell: ICellViewModel, shortErrors: boolean = false): string {
20
const outputText: string[] = [];
21
for (let i = 0; i < viewCell.outputsViewModels.length; i++) {
22
const outputViewModel = viewCell.outputsViewModels[i];
23
const outputTextModel = viewCell.model.outputs[i];
24
const [mimeTypes, pick] = outputViewModel.resolveMimeTypes(notebook, undefined);
25
const mimeType = mimeTypes[pick].mimeType;
26
let buffer = outputTextModel.outputs.find(output => output.mime === mimeType);
27
28
if (!buffer || mimeType.startsWith('image')) {
29
buffer = outputTextModel.outputs.find(output => !output.mime.startsWith('image'));
30
}
31
32
if (!buffer) {
33
continue;
34
}
35
36
let text = '';
37
if (isTextStreamMime(mimeType)) {
38
const { text: stream, count } = getOutputStreamText(outputViewModel);
39
text = stream;
40
if (count > 1) {
41
i += count - 1;
42
}
43
} else {
44
text = getOutputText(mimeType, buffer, shortErrors);
45
}
46
47
outputText.push(text);
48
}
49
50
let outputContent: string;
51
if (outputText.length > 1) {
52
outputContent = outputText.map((output, i) => {
53
return `Cell output ${i + 1} of ${outputText.length}\n${output}`;
54
}).join('\n');
55
} else {
56
outputContent = outputText[0] ?? '';
57
}
58
59
return outputContent;
60
}
61
62
export function getOutputStreamText(output: ICellOutputViewModel): { text: string; count: number } {
63
let text = '';
64
const cellViewModel = output.cellViewModel as ICellViewModel;
65
let index = cellViewModel.outputsViewModels.indexOf(output);
66
let count = 0;
67
while (index < cellViewModel.model.outputs.length) {
68
const nextCellOutput = cellViewModel.model.outputs[index];
69
const nextOutput = nextCellOutput.outputs.find(output => isTextStreamMime(output.mime));
70
if (!nextOutput) {
71
break;
72
}
73
74
text = text + decoder.decode(nextOutput.data.buffer);
75
index = index + 1;
76
count++;
77
}
78
79
return { text: text.trim(), count };
80
}
81
82
const decoder = new TextDecoder();
83
84
export function getOutputText(mimeType: string, buffer: IOutputItemDto, shortError: boolean = false): string {
85
let text = `${mimeType}`; // default in case we can't get the text value for some reason.
86
87
const charLimit = 100000;
88
text = decoder.decode(buffer.data.slice(0, charLimit).buffer);
89
90
if (buffer.data.byteLength > charLimit) {
91
text = text + '...(truncated)';
92
} else if (mimeType === 'application/vnd.code.notebook.error') {
93
text = text.replace(/\\u001b\[[0-9;]*m/gi, '');
94
try {
95
const error = JSON.parse(text) as Error;
96
if (!error.stack || shortError) {
97
text = `${error.name}: ${error.message}`;
98
} else {
99
text = error.stack;
100
}
101
} catch {
102
// just use raw text
103
}
104
}
105
106
return text.trim();
107
}
108
109
export async function copyCellOutput(mimeType: string | undefined, outputViewModel: ICellOutputViewModel, clipboardService: IClipboardService, logService: ILogService) {
110
const cellOutput = outputViewModel.model;
111
const output = mimeType && TEXT_BASED_MIMETYPES.includes(mimeType) ?
112
cellOutput.outputs.find(output => output.mime === mimeType) :
113
cellOutput.outputs.find(output => TEXT_BASED_MIMETYPES.includes(output.mime));
114
115
mimeType = output?.mime;
116
117
if (!mimeType || !output) {
118
return;
119
}
120
121
const text = isTextStreamMime(mimeType) ? getOutputStreamText(outputViewModel).text : getOutputText(mimeType, output);
122
123
try {
124
await clipboardService.writeText(text);
125
126
} catch (e) {
127
logService.error(`Failed to copy content: ${e}`);
128
}
129
}
130
131
export const TEXT_BASED_MIMETYPES = [
132
'text/latex',
133
'text/html',
134
'application/vnd.code.notebook.error',
135
'application/vnd.code.notebook.stdout',
136
'application/x.notebook.stdout',
137
'application/x.notebook.stream',
138
'application/vnd.code.notebook.stderr',
139
'application/x.notebook.stderr',
140
'text/plain',
141
'text/markdown',
142
'application/json'
143
];
144
145