1
- 'use strict'
2
-
3
1
import * as vscode from 'vscode'
4
2
import { LanguageClient } from 'vscode-languageclient'
5
3
6
- /** All decorations that have been added so far */
7
- let worksheetDecorationTypes : Map < vscode . TextDocument , vscode . TextEditorDecorationType [ ] > = new Map < vscode . TextDocument , vscode . TextEditorDecorationType [ ] > ( )
4
+ /** A worksheet managed by vscode */
5
+ class Worksheet {
6
+
7
+ constructor ( document : vscode . TextDocument ) {
8
+ this . document = document
9
+ }
10
+
11
+ /** The text document that this worksheet represents. */
12
+ readonly document : vscode . TextDocument
8
13
9
- /** The number of blank lines that have been inserted to fit the output so far. */
10
- let worksheetInsertedLines : Map < vscode . TextDocument , number > = new Map < vscode . TextDocument , number > ( )
14
+ /** All decorations that have been added so far */
15
+ decorationTypes : vscode . TextEditorDecorationType [ ] = [ ]
11
16
12
- /** The minimum margin to add so that the decoration is shown after all text . */
13
- let worksheetMargin : Map < vscode . TextDocument , number > = new Map < vscode . TextDocument , number > ( )
17
+ /** The number of blank lines that have been inserted to fit the output so far . */
18
+ insertedLines : number = 0
14
19
15
- /** Whether the given worksheet has finished evaluating. */
16
- let worksheetFinished : Map < vscode . TextDocument , boolean > = new Map < vscode . TextDocument , boolean > ( )
20
+ /** The minimum margin to add so that the decoration is shown after all text. */
21
+ margin : number = 0
22
+
23
+ /** Whether this worksheet has finished evaluating. */
24
+ finished : boolean = false
25
+
26
+ /** Remove all decorations and resets this worksheet. */
27
+ reset ( ) {
28
+ this . decorationTypes . forEach ( decoration => decoration . dispose ( ) )
29
+ this . insertedLines = 0
30
+ this . margin = longestLine ( this . document ) + 5
31
+ this . finished = false
32
+ }
33
+
34
+ }
35
+
36
+ /** All the worksheets */
37
+ let worksheets : Map < vscode . TextDocument , Worksheet > = new Map < vscode . TextDocument , Worksheet > ( )
17
38
18
39
/**
19
40
* The command key for evaluating a worksheet. Exposed to users as
@@ -47,9 +68,9 @@ export function isWorksheet(document: vscode.TextDocument): boolean {
47
68
export function evaluateCommand ( ) {
48
69
const editor = vscode . window . activeTextEditor
49
70
if ( editor ) {
50
- const document = editor . document
51
- if ( isWorksheet ( document ) ) {
52
- showWorksheetProgress ( document )
71
+ const worksheet = worksheets . get ( editor . document )
72
+ if ( worksheet ) {
73
+ showWorksheetProgress ( worksheet )
53
74
}
54
75
}
55
76
}
@@ -69,19 +90,20 @@ export function worksheetSave(client: LanguageClient) {
69
90
const editor = vscode . window . activeTextEditor
70
91
if ( editor ) {
71
92
const document = editor . document
72
- if ( isWorksheet ( document ) ) {
73
- if ( document . isDirty ) document . save ( )
74
- else {
75
- _prepareWorksheet ( document ) . then ( _ => {
76
- if ( document . isDirty ) document . save ( )
77
- else {
78
- client . sendNotification ( "textDocument/didSave" , {
79
- textDocument : { uri : document . uri . toString ( ) }
80
- } )
81
- showWorksheetProgress ( document )
82
- }
83
- } )
84
- }
93
+ const worksheet = worksheets . get ( document ) || new Worksheet ( document )
94
+ worksheets . set ( document , worksheet )
95
+
96
+ if ( document . isDirty ) document . save ( )
97
+ else {
98
+ _prepareWorksheet ( worksheet ) . then ( _ => {
99
+ if ( document . isDirty ) document . save ( )
100
+ else {
101
+ client . sendNotification ( "textDocument/didSave" , {
102
+ textDocument : { uri : document . uri . toString ( ) }
103
+ } )
104
+ showWorksheetProgress ( worksheet )
105
+ }
106
+ } )
85
107
}
86
108
}
87
109
}
@@ -96,26 +118,18 @@ export function worksheetSave(client: LanguageClient) {
96
118
* @param event `TextDocumentWillSaveEvent`.
97
119
*/
98
120
export function prepareWorksheet ( event : vscode . TextDocumentWillSaveEvent ) {
99
- const document = event . document
100
- const setup = _prepareWorksheet ( document )
101
- event . waitUntil ( setup )
121
+ const worksheet = worksheets . get ( event . document )
122
+ if ( worksheet ) {
123
+ const setup = _prepareWorksheet ( worksheet )
124
+ event . waitUntil ( setup )
125
+ }
102
126
}
103
127
104
- function _prepareWorksheet ( document : vscode . TextDocument ) {
105
- if ( isWorksheet ( document ) ) {
106
- return removeRedundantBlankLines ( document )
107
- . then ( _ => {
108
- removeDecorations ( document )
109
- worksheetMargin . set ( document , longestLine ( document ) + 5 )
110
- worksheetInsertedLines . set ( document , 0 )
111
- worksheetFinished . set ( document , false )
112
- } )
113
- } else {
114
- return Promise . resolve ( )
115
- }
128
+ function _prepareWorksheet ( worksheet : Worksheet ) {
129
+ return removeRedundantBlankLines ( worksheet . document ) . then ( _ => worksheet . reset ( ) )
116
130
}
117
131
118
- function showWorksheetProgress ( document : vscode . TextDocument ) {
132
+ function showWorksheetProgress ( worksheet : Worksheet ) {
119
133
return vscode . window . withProgress ( {
120
134
location : vscode . ProgressLocation . Notification ,
121
135
title : "Evaluating worksheet" ,
@@ -125,10 +139,7 @@ function showWorksheetProgress(document: vscode.TextDocument) {
125
139
vscode . commands . executeCommand ( worksheetCancelEvaluationKey )
126
140
} )
127
141
128
- function isFinished ( ) {
129
- return worksheetFinished . get ( document ) || false
130
- }
131
- return wait ( isFinished , 500 )
142
+ return wait ( ( ) => worksheet . finished , 500 )
132
143
} )
133
144
}
134
145
@@ -172,11 +183,15 @@ export function worksheetHandleMessage(message: string) {
172
183
} )
173
184
174
185
if ( editor ) {
175
- let payload = message . slice ( editor . document . uri . toString ( ) . length )
176
- if ( payload == "FINISHED" ) {
177
- worksheetFinished . set ( editor . document , true )
178
- } else {
179
- worksheetDisplayResult ( payload , editor )
186
+ const worksheet = worksheets . get ( editor . document )
187
+
188
+ if ( worksheet ) {
189
+ let payload = message . slice ( editor . document . uri . toString ( ) . length )
190
+ if ( payload == "FINISHED" ) {
191
+ worksheet . finished = true
192
+ } else {
193
+ worksheetDisplayResult ( payload , worksheet , editor )
194
+ }
180
195
}
181
196
}
182
197
}
@@ -222,16 +237,6 @@ function longestLine(document: vscode.TextDocument) {
222
237
return maxLength
223
238
}
224
239
225
- /**
226
- * Remove all decorations added by worksheet evaluation.
227
- */
228
- function removeDecorations ( document : vscode . TextDocument ) {
229
- const decorationTypes = worksheetDecorationTypes . get ( document ) || [ ]
230
- decorationTypes . forEach ( decoration =>
231
- decoration . dispose ( )
232
- )
233
- }
234
-
235
240
/**
236
241
* Remove the repeated blank lines in the source.
237
242
*
@@ -293,31 +298,24 @@ function removeRedundantBlankLines(document: vscode.TextDocument) {
293
298
*
294
299
* @see worksheetCreateDecoration
295
300
*
296
- * @param message The message to parse.
297
- * @param ed The editor where to display the result.
301
+ * @param message The message to parse.
302
+ * @param worksheet The worksheet that receives the result.
303
+ * @param editor The editor where to display the result.
298
304
* @return A `Thenable` that will insert necessary lines to fit the output
299
305
* and display the decorations upon completion.
300
306
*/
301
- function worksheetDisplayResult ( message : string , editor : vscode . TextEditor ) {
307
+ function worksheetDisplayResult ( message : string , worksheet : Worksheet , editor : vscode . TextEditor ) {
302
308
303
309
const colonIndex = message . indexOf ( ":" )
304
310
const lineNumber = parseInt ( message . slice ( 0 , colonIndex ) ) - 1 // lines are 0-indexed
305
311
const evalResult = message . slice ( colonIndex + 1 )
306
312
const resultLines = evalResult . trim ( ) . split ( / \r \n | \r | \n / g)
307
- const margin = worksheetMargin . get ( editor . document ) || 0
308
-
309
- let insertedLines = worksheetInsertedLines . get ( editor . document ) || 0
310
-
311
- let decorationTypes = worksheetDecorationTypes . get ( editor . document )
312
- if ( ! decorationTypes ) {
313
- decorationTypes = [ ]
314
- worksheetDecorationTypes . set ( editor . document , decorationTypes )
315
- }
313
+ const margin = worksheet . margin
316
314
317
315
// The line where the next decoration should be put.
318
316
// It's the number of the line that produced the output, plus the number
319
317
// of lines that we've inserted so far.
320
- let actualLine = lineNumber + insertedLines
318
+ let actualLine = lineNumber + worksheet . insertedLines
321
319
322
320
// If the output has more than one line, we need to insert blank lines
323
321
// below the line that produced the output to fit the output.
@@ -326,16 +324,15 @@ function worksheetDisplayResult(message: string, editor: vscode.TextEditor) {
326
324
const linesToInsert = resultLines . length - 1
327
325
const editPos = new vscode . Position ( actualLine + 1 , 0 ) // add after the line
328
326
addNewLinesEdit . insert ( editor . document . uri , editPos , "\n" . repeat ( linesToInsert ) )
329
- insertedLines += linesToInsert
330
- worksheetInsertedLines . set ( editor . document , insertedLines )
327
+ worksheet . insertedLines += linesToInsert
331
328
}
332
329
333
330
return vscode . workspace . applyEdit ( addNewLinesEdit ) . then ( _ => {
334
331
for ( let line of resultLines ) {
335
332
const decorationPosition = new vscode . Position ( actualLine , 0 )
336
333
const decorationMargin = margin - editor . document . lineAt ( actualLine ) . text . length
337
334
const decorationType = worksheetCreateDecoration ( decorationMargin , line )
338
- if ( decorationTypes ) decorationTypes . push ( decorationType )
335
+ worksheet . decorationTypes . push ( decorationType )
339
336
340
337
const decoration = { range : new vscode . Range ( decorationPosition , decorationPosition ) , hoverMessage : line }
341
338
editor . setDecorations ( decorationType , [ decoration ] )
0 commit comments