Skip to content

Commit ee1b514

Browse files
authored
Merge pull request #5289 from dotty-staging/fix/5284
Fix #5284: Restore worksheet decorations
2 parents 294537f + 131344c commit ee1b514

File tree

1 file changed

+55
-10
lines changed

1 file changed

+55
-10
lines changed

vscode-dotty/src/worksheet.ts

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ import {
55
} from 'vscode'
66

77
import {
8-
asWorksheetRunParams, WorksheetRunRequest, WorksheetRunParams, WorksheetRunResult,
8+
asWorksheetRunParams, WorksheetRunRequest, WorksheetRunResult,
99
WorksheetPublishOutputParams, WorksheetPublishOutputNotification
1010
} from './protocol'
11-
import { BaseLanguageClient, DocumentSelector } from 'vscode-languageclient'
11+
import { BaseLanguageClient } from 'vscode-languageclient'
1212
import { Disposable } from 'vscode-jsonrpc'
1313

1414
/**
@@ -23,11 +23,26 @@ export const worksheetRunKey = "dotty.worksheet.run"
2323
*/
2424
export const worksheetCancelKey = "dotty.worksheet.cancel"
2525

26+
/**
27+
* A wrapper around the information that VSCode needs to display text decorations.
28+
*
29+
* @param decorationType The styling options of this decoration
30+
* @param decorationOptions The options of this decoraiton.
31+
*/
32+
class Decoration {
33+
constructor(readonly decorationType: vscode.TextEditorDecorationType,
34+
readonly decorationOptions: vscode.DecorationOptions) {
35+
}
36+
}
37+
2638
/** A worksheet managed by vscode */
2739
class Worksheet implements Disposable {
2840

41+
/** The version of this document the last time it was run */
42+
private runVersion: number = -1
43+
2944
/** All decorations that have been added so far */
30-
private decorationTypes: vscode.TextEditorDecorationType[] = []
45+
private decorations: Decoration[] = []
3146

3247
/** The number of blank lines that have been inserted to fit the output so far. */
3348
private insertedLines: number = 0
@@ -62,9 +77,11 @@ class Worksheet implements Disposable {
6277

6378
/** Remove all decorations, and resets this worksheet. */
6479
private reset(): void {
65-
this.decorationTypes.forEach(decoration => decoration.dispose())
80+
this.decorations.forEach(decoration => decoration.decorationType.dispose())
81+
this.decorations = []
6682
this.insertedLines = 0
6783
this.decoratedLines.clear()
84+
this.runVersion = -1
6885
this.margin = this.longestLine() + 5
6986
}
7087

@@ -112,6 +129,7 @@ class Worksheet implements Disposable {
112129
const edit = new vscode.WorkspaceEdit()
113130
edit.set(this.document.uri, textEdits)
114131
vscode.workspace.applyEdit(edit).then(editSucceeded => {
132+
this.runVersion = this.document.version
115133
if (editSucceeded && !token.isCancellationRequested)
116134
resolve(vscode.window.withProgress({
117135
location: ProgressLocation.Window,
@@ -135,7 +153,8 @@ class Worksheet implements Disposable {
135153
}
136154

137155
/**
138-
* Parse and display the result of running part of this worksheet.
156+
* Parse and display the result of running part of this worksheet. The result is saved so that it
157+
* can be restored if this buffer is closed.
139158
*
140159
* @param lineNumber The number of the line in the source that produced the result.
141160
* @param runResult The result itself.
@@ -144,7 +163,7 @@ class Worksheet implements Disposable {
144163
* @return A `Thenable` that will insert necessary lines to fit the output
145164
* and display the decorations upon completion.
146165
*/
147-
public displayResult(lineNumber: number, runResult: string, editor: vscode.TextEditor) {
166+
public displayAndSaveResult(lineNumber: number, runResult: string, editor: vscode.TextEditor) {
148167
const resultLines = runResult.trim().split(/\r\n|\r|\n/g)
149168

150169
// The line where the next decoration should be put.
@@ -160,23 +179,41 @@ class Worksheet implements Disposable {
160179
const editPos = new vscode.Position(actualLine + 1, 0) // add after the line
161180
addNewLinesEdit.insert(editor.document.uri, editPos, "\n".repeat(linesToInsert))
162181
this.insertedLines += linesToInsert
182+
// Increase the `runVersion`, because the text edit will increase the document's version
183+
this.runVersion += 1
163184
}
164185

165186
return vscode.workspace.applyEdit(addNewLinesEdit).then(_ => {
166187
for (let line of resultLines) {
167188
const decorationPosition = new vscode.Position(actualLine, 0)
168189
const decorationMargin = this.margin - editor.document.lineAt(actualLine).text.length
169190
const decorationType = this.createDecoration(decorationMargin, line)
170-
this.decorationTypes.push(decorationType)
191+
const decorationOptions = { range: new vscode.Range(decorationPosition, decorationPosition), hoverMessage: line }
192+
const decoration = new Decoration(decorationType, decorationOptions)
193+
171194
this.decoratedLines.add(actualLine)
195+
this.decorations.push(decoration)
172196

173-
const decoration = { range: new vscode.Range(decorationPosition, decorationPosition), hoverMessage: line }
174-
editor.setDecorations(decorationType, [decoration])
197+
editor.setDecorations(decorationType, [decorationOptions])
175198
actualLine += 1
176199
}
177200
})
178201
}
179202

203+
/**
204+
* Restore the decorations that belong to this worksheet in `editor`. If the document has been
205+
* changed, since the last run of the worksheet, the decorations won't be added.
206+
*
207+
* @param editor The editor where to display the decorations.
208+
*/
209+
public restoreDecorations(editor: vscode.TextEditor) {
210+
if (editor.document.version == this.runVersion) {
211+
this.decorations.forEach(decoration => {
212+
editor.setDecorations(decoration.decorationType, [decoration.decorationOptions])
213+
})
214+
}
215+
}
216+
180217
/**
181218
* Create a new `TextEditorDecorationType` showing `text`. The decoration
182219
* will appear `margin` characters after the end of the line.
@@ -307,6 +344,14 @@ export class WorksheetProvider implements Disposable {
307344
this.worksheets.delete(document)
308345
}
309346
}),
347+
vscode.window.onDidChangeActiveTextEditor(editor => {
348+
if (editor) {
349+
const worksheet = this.worksheetFor(editor.document)
350+
if (worksheet) {
351+
worksheet.restoreDecorations(editor)
352+
}
353+
}
354+
}),
310355
vscode.commands.registerCommand(worksheetRunKey, () => {
311356
this.callOnActiveWorksheet(w => w.run())
312357
}),
@@ -375,7 +420,7 @@ export class WorksheetProvider implements Disposable {
375420
if (editor) {
376421
const worksheet = this.worksheetFor(editor.document)
377422
if (worksheet) {
378-
worksheet.displayResult(output.line - 1, output.content, editor)
423+
worksheet.displayAndSaveResult(output.line - 1, output.content, editor)
379424
}
380425
}
381426
}

0 commit comments

Comments
 (0)