Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add current cell highlight #5219

Merged
merged 2 commits into from
Apr 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions news/1 Enhancements/3542.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add tracking of 'current' cell in the editor.
6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1424,6 +1424,12 @@
"description": "Amount of time to wait for guest connections to verify they have the Python extension installed.",
"scope": "application"
},
"python.dataScience.decorateCells": {
"type": "boolean",
"default": true,
"description": "Draw a highlight behind the currently active cell.",
"scope": "resource"
},
"python.disableInstallationCheck": {
"type": "boolean",
"default": false,
Expand Down
30 changes: 26 additions & 4 deletions src/client/common/application/documentManager.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,28 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

// tslint:disable:no-any unified-signatures

import { injectable } from 'inversify';
import { Event, TextDocument, TextDocumentShowOptions, TextEditor, TextEditorOptionsChangeEvent, TextEditorSelectionChangeEvent, TextEditorViewColumnChangeEvent, Uri, ViewColumn, window, workspace, WorkspaceEdit } from 'vscode';
import {
DecorationRenderOptions,
Event,
TextDocument,
TextDocumentChangeEvent,
TextDocumentShowOptions,
TextEditor,
TextEditorDecorationType,
TextEditorOptionsChangeEvent,
TextEditorSelectionChangeEvent,
TextEditorViewColumnChangeEvent,
Uri,
ViewColumn,
window,
workspace,
WorkspaceEdit
} from 'vscode';

import { IDocumentManager } from './types';

// tslint:disable:no-any unified-signatures

@injectable()
export class DocumentManager implements IDocumentManager {
public get textDocuments(): TextDocument[] {
Expand All @@ -21,6 +37,9 @@ export class DocumentManager implements IDocumentManager {
public get onDidChangeActiveTextEditor(): Event<TextEditor | undefined> {
return window.onDidChangeActiveTextEditor;
}
public get onDidChangeTextDocument() : Event<TextDocumentChangeEvent> {
return workspace.onDidChangeTextDocument;
}
public get onDidChangeVisibleTextEditors(): Event<TextEditor[]> {
return window.onDidChangeVisibleTextEditors;
}
Expand Down Expand Up @@ -57,4 +76,7 @@ export class DocumentManager implements IDocumentManager {
public applyEdit(edit: WorkspaceEdit): Thenable<boolean> {
return workspace.applyEdit(edit);
}
public createTextEditorDecorationType(options: DecorationRenderOptions): TextEditorDecorationType {
return window.createTextEditorDecorationType(options);
}
}
19 changes: 19 additions & 0 deletions src/client/common/application/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
DebugConsole,
DebugSession,
DebugSessionCustomEvent,
DecorationRenderOptions,
Disposable,
DocumentSelector,
Event,
Expand All @@ -33,8 +34,10 @@ import {
Terminal,
TerminalOptions,
TextDocument,
TextDocumentChangeEvent,
TextDocumentShowOptions,
TextEditor,
TextEditorDecorationType,
TextEditorEdit,
TextEditorOptionsChangeEvent,
TextEditorSelectionChangeEvent,
Expand Down Expand Up @@ -433,6 +436,13 @@ export interface IDocumentManager {
*/
readonly onDidChangeActiveTextEditor: Event<TextEditor | undefined>;

/**
* An event that is emitted when a [text document](#TextDocument) is changed. This usually happens
* when the [contents](#TextDocument.getText) changes but also when other things like the
* [dirty](#TextDocument.isDirty)-state changes.
*/
readonly onDidChangeTextDocument: Event<TextDocumentChangeEvent>;

/**
* An [event](#Event) which fires when the array of [visible editors](#window.visibleTextEditors)
* has changed.
Expand Down Expand Up @@ -549,6 +559,15 @@ export interface IDocumentManager {
* @return A thenable that resolves when the edit could be applied.
*/
applyEdit(edit: WorkspaceEdit): Thenable<boolean>;

/**
* Create a TextEditorDecorationType that can be used to add decorations to text editors.
*
* @param options Rendering options for the decoration type.
* @return A new decoration type instance.
*/
createTextEditorDecorationType(options: DecorationRenderOptions): TextEditorDecorationType;

}

export const IWorkspaceService = Symbol('IWorkspaceService');
Expand Down
1 change: 1 addition & 0 deletions src/client/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ export interface IDataScienceSettings {
showJupyterVariableExplorer?: boolean;
variableExplorerExclude?: string;
liveShareConnectionTimeout?: number;
decorateCells?: boolean;
}

export const IConfigurationService = Symbol('IConfigurationService');
Expand Down
89 changes: 89 additions & 0 deletions src/client/datascience/editor-integration/decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
'use strict';
import { inject, injectable } from 'inversify';
import * as vscode from 'vscode';

import { IExtensionActivationService } from '../../activation/types';
import { IDocumentManager } from '../../common/application/types';
import { PYTHON_LANGUAGE } from '../../common/constants';
import { IConfigurationService, IDisposable, IDisposableRegistry, Resource } from '../../common/types';
import { generateCellRanges } from '../cellFactory';

@injectable()
export class Decorator implements IExtensionActivationService, IDisposable {

private activeCellType: vscode.TextEditorDecorationType;
private timer: NodeJS.Timer | undefined;

constructor(@inject(IDocumentManager) private documentManager: IDocumentManager,
@inject(IDisposableRegistry) disposables: IDisposableRegistry,
@inject(IConfigurationService) private configuration: IConfigurationService)
{
this.activeCellType = this.documentManager.createTextEditorDecorationType({
backgroundColor: new vscode.ThemeColor('sideBarSectionHeader.background'),
isWholeLine: true
});
disposables.push(this);
disposables.push(this.configuration.getSettings().onDidChange(this.settingsChanged, this));
disposables.push(this.documentManager.onDidChangeActiveTextEditor(this.changedEditor, this));
disposables.push(this.documentManager.onDidChangeTextEditorSelection(this.changedSelection, this));
disposables.push(this.documentManager.onDidChangeTextDocument(this.changedDocument, this));
this.settingsChanged();
}

public activate(_resource: Resource) : Promise<void> {
// We don't need to do anything here as we already did all of our work in the
// constructor.
return Promise.resolve();
}

public dispose() {
if (this.timer) {
clearTimeout(this.timer);
}
}

private settingsChanged() {
if (this.documentManager.activeTextEditor) {
this.triggerUpdate(this.documentManager.activeTextEditor);
}
}

private changedEditor(editor: vscode.TextEditor | undefined) {
this.triggerUpdate(editor);
}

private changedDocument(e: vscode.TextDocumentChangeEvent) {
if (this.documentManager.activeTextEditor && e.document === this.documentManager.activeTextEditor.document) {
this.triggerUpdate(this.documentManager.activeTextEditor);
}
}

private changedSelection(e: vscode.TextEditorSelectionChangeEvent) {
if (e.textEditor && e.textEditor.selection.anchor) {
this.triggerUpdate(e.textEditor);
}
}

private triggerUpdate(editor: vscode.TextEditor | undefined) {
if (this.timer) {
clearTimeout(this.timer);
}
this.timer = setTimeout(() => this.update(editor), 100);
rchiodo marked this conversation as resolved.
Show resolved Hide resolved
}

private update(editor: vscode.TextEditor | undefined) {
if (editor && editor.document && editor.document.languageId === PYTHON_LANGUAGE) {
const settings = this.configuration.getSettings().datascience;
if (settings.decorateCells && settings.enabled) {
// Find all of the cells
const cells = generateCellRanges(editor.document, this.configuration.getSettings().datascience);
const cellRanges = cells.map(c => c.range).filter(r => r.contains(editor.selection.anchor));
editor.setDecorations(this.activeCellType, cellRanges);
} else {
editor.setDecorations(this.activeCellType, []);
}
}
}
}
3 changes: 3 additions & 0 deletions src/client/datascience/serviceRegistry.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
'use strict';
import { IExtensionActivationService } from '../activation/types';
import { IServiceManager } from '../ioc/types';
import { CodeCssGenerator } from './codeCssGenerator';
import { DataViewer } from './data-viewing/dataViewer';
import { DataViewerProvider } from './data-viewing/dataViewerProvider';
import { DataScience } from './datascience';
import { DataScienceCodeLensProvider } from './editor-integration/codelensprovider';
import { CodeWatcher } from './editor-integration/codewatcher';
import { Decorator } from './editor-integration/decorator';
import { History } from './history/history';
import { HistoryCommandListener } from './history/historycommandlistener';
import { HistoryProvider } from './history/historyProvider';
Expand Down Expand Up @@ -60,4 +62,5 @@ export function registerTypes(serviceManager: IServiceManager) {
serviceManager.addSingleton<IThemeFinder>(IThemeFinder, ThemeFinder);
serviceManager.addSingleton<IDataViewerProvider>(IDataViewerProvider, DataViewerProvider);
serviceManager.add<IDataViewer>(IDataViewer, DataViewer);
serviceManager.addSingleton<IExtensionActivationService>(IExtensionActivationService, Decorator);
}
11 changes: 11 additions & 0 deletions src/test/datascience/mockDocumentManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
'use strict';
import * as TypeMoq from 'typemoq';
import {
DecorationRenderOptions,
Event,
EventEmitter,
TextDocument,
TextDocumentChangeEvent,
TextDocumentShowOptions,
TextEditor,
TextEditorDecorationType,
TextEditorOptionsChangeEvent,
TextEditorSelectionChangeEvent,
TextEditorViewColumnChangeEvent,
Expand Down Expand Up @@ -42,9 +45,13 @@ export class MockDocumentManager implements IDocumentManager {
private didChangeTextEditorViewColumnEmitter = new EventEmitter<TextEditorViewColumnChangeEvent>();
private didCloseEmitter = new EventEmitter<TextDocument>();
private didSaveEmitter = new EventEmitter<TextDocument>();
private didChangeTextDocumentEmitter = new EventEmitter<TextDocumentChangeEvent>();
public get onDidChangeActiveTextEditor(): Event<TextEditor> {
return this.didChangeEmitter.event;
}
public get onDidChangeTextDocument(): Event<TextDocumentChangeEvent> {
return this.didChangeTextDocumentEmitter.event;
}
public get onDidOpenTextDocument(): Event<TextDocument> {
return this.didOpenEmitter.event;
}
Expand Down Expand Up @@ -89,6 +96,10 @@ export class MockDocumentManager implements IDocumentManager {
this.textDocuments.push(mockDoc.object);
}

public createTextEditorDecorationType(_options: DecorationRenderOptions) : TextEditorDecorationType {
throw new Error('Method not implemented');
}

private get lastDocument() : TextDocument {
if (this.textDocuments.length > 0) {
return this.textDocuments[this.textDocuments.length - 1];
Expand Down