Skip to content

Commit ae9e9d1

Browse files
authored
Fix running on indented code. (microsoft#6051)
* Fix running on indented code. * Switch to using ICodeExecutionHelper * Fix functional test failure * Review feedback
1 parent 0e88813 commit ae9e9d1

File tree

7 files changed

+73
-116
lines changed

7 files changed

+73
-116
lines changed

news/2 Fixes/5983.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Allow selection and running of indented code in the python interactive window.

package-lock.json

Lines changed: 44 additions & 72 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1317,7 +1317,7 @@
13171317
},
13181318
"python.dataScience.autoPreviewNotebooksInInteractivePane": {
13191319
"type": "boolean",
1320-
"default": true,
1320+
"default": false,
13211321
"description": "When opening ipynb files, automatically preview the contents in the Python Interactive window.",
13221322
"scope": "resource"
13231323
},

src/client/datascience/editor-integration/codewatcher.ts

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { IConfigurationService, IDataScienceSettings, ILogger } from '../../comm
1010
import * as localize from '../../common/utils/localize';
1111
import { noop } from '../../common/utils/misc';
1212
import { captureTelemetry } from '../../telemetry';
13+
import { ICodeExecutionHelper } from '../../terminals/types';
1314
import { generateCellRanges } from '../cellFactory';
1415
import { Commands, Telemetry } from '../constants';
1516
import { JupyterInstallError } from '../jupyter/jupyterInstallError';
@@ -29,7 +30,10 @@ export class CodeWatcher implements ICodeWatcher {
2930
@inject(IHistoryProvider) private historyProvider : IHistoryProvider,
3031
@inject(IFileSystem) private fileSystem: IFileSystem,
3132
@inject(IConfigurationService) private configService: IConfigurationService,
32-
@inject(IDocumentManager) private documentManager : IDocumentManager) {}
33+
@inject(IDocumentManager) private documentManager : IDocumentManager,
34+
@inject(ICodeExecutionHelper) private executionHelper: ICodeExecutionHelper
35+
) {
36+
}
3337

3438
public setDocument(document: TextDocument) {
3539
this.document = document;
@@ -165,19 +169,17 @@ export class CodeWatcher implements ICodeWatcher {
165169
this.fileSystem.arePathsSame(activeEditor.document.fileName, this.document.fileName)) {
166170

167171
// Get just the text of the selection or the current line if none
168-
let code: string;
169-
if (activeEditor.selection.start.line === activeEditor.selection.end.line &&
170-
activeEditor.selection.start.character === activeEditor.selection.end.character) {
171-
const line = this.document.lineAt(activeEditor.selection.start.line);
172-
code = line.text;
173-
} else {
174-
code = this.document.getText(new Range(activeEditor.selection.start, activeEditor.selection.end));
172+
const codeToExecute = await this.executionHelper.getSelectedTextToExecute(activeEditor);
173+
if (!codeToExecute) {
174+
return ;
175175
}
176-
177-
if (code && code.trim().length) {
178-
const activeHistory = await this.historyProvider.getOrCreateActive();
179-
await activeHistory.addCode(code, this.getFileName(), activeEditor.selection.start.line, activeEditor);
176+
const normalizedCode = await this.executionHelper.normalizeLines(codeToExecute!);
177+
if (!normalizedCode || normalizedCode.trim().length === 0) {
178+
return;
180179
}
180+
181+
const activeHistory = await this.historyProvider.getOrCreateActive();
182+
await activeHistory.addCode(normalizedCode, this.getFileName(), activeEditor.selection.start.line, activeEditor);
181183
}
182184
}
183185

src/test/datascience/dataScienceIocContainer.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,8 @@ import {
194194
import { IPipEnvServiceHelper, IPythonInPathCommandProvider } from '../../client/interpreter/locators/types';
195195
import { VirtualEnvironmentManager } from '../../client/interpreter/virtualEnvs';
196196
import { IVirtualEnvironmentManager } from '../../client/interpreter/virtualEnvs/types';
197+
import { CodeExecutionHelper } from '../../client/terminals/codeExecution/helper';
198+
import { ICodeExecutionHelper } from '../../client/terminals/types';
197199
import { IVsCodeApi } from '../../datascience-ui/react-common/postOffice';
198200
import { MockAutoSelectionService } from '../mocks/autoSelector';
199201
import { UnitTestIocContainer } from '../testing/serviceRegistry';
@@ -309,6 +311,7 @@ export class DataScienceIocContainer extends UnitTestIocContainer {
309311
this.serviceManager.addSingleton<IPythonInPathCommandProvider>(IPythonInPathCommandProvider, PythonInPathCommandProvider);
310312
this.serviceManager.addSingleton<IEnvironmentActivationService>(IEnvironmentActivationService, EnvironmentActivationService);
311313
this.serviceManager.add<ICodeWatcher>(ICodeWatcher, CodeWatcher);
314+
this.serviceManager.add<ICodeExecutionHelper>(ICodeExecutionHelper, CodeExecutionHelper);
312315
this.serviceManager.add<IDataScienceCommandListener>(IDataScienceCommandListener, HistoryCommandListener);
313316
this.serviceManager.addSingleton<IJupyterVariables>(IJupyterVariables, JupyterVariables);
314317

src/test/datascience/editor-integration/codewatcher.unit.test.ts

Lines changed: 9 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { DataScienceCodeLensProvider } from '../../../client/datascience/editor-
1616
import { CodeWatcher } from '../../../client/datascience/editor-integration/codewatcher';
1717
import { ICodeWatcher, IHistory, IHistoryProvider } from '../../../client/datascience/types';
1818
import { IServiceContainer } from '../../../client/ioc/types';
19+
import { ICodeExecutionHelper } from '../../../client/terminals/types';
1920
import { MockAutoSelectionService } from '../../mocks/autoSelector';
2021
import { createDocument } from './helpers';
2122

@@ -32,6 +33,7 @@ suite('DataScience Code Watcher Unit Tests', () => {
3233
let fileSystem: TypeMoq.IMock<IFileSystem>;
3334
let configService: TypeMoq.IMock<IConfigurationService>;
3435
let serviceContainer : TypeMoq.IMock<IServiceContainer>;
36+
let helper: TypeMoq.IMock<ICodeExecutionHelper>;
3537
let tokenSource : CancellationTokenSource;
3638
const pythonSettings = new class extends PythonSettings {
3739
public fireChangeEvent() {
@@ -49,6 +51,7 @@ suite('DataScience Code Watcher Unit Tests', () => {
4951
textEditor = TypeMoq.Mock.ofType<TextEditor>();
5052
fileSystem = TypeMoq.Mock.ofType<IFileSystem>();
5153
configService = TypeMoq.Mock.ofType<IConfigurationService>();
54+
helper = TypeMoq.Mock.ofType<ICodeExecutionHelper>();
5255

5356
// Setup default settings
5457
pythonSettings.datascience = {
@@ -77,7 +80,7 @@ suite('DataScience Code Watcher Unit Tests', () => {
7780

7881
// Setup the service container to return code watchers
7982
serviceContainer = TypeMoq.Mock.ofType<IServiceContainer>();
80-
serviceContainer.setup(c => c.get(TypeMoq.It.isValue(ICodeWatcher))).returns(() => new CodeWatcher(appShell.object, logger.object, historyProvider.object, fileSystem.object, configService.object, documentManager.object));
83+
serviceContainer.setup(c => c.get(TypeMoq.It.isValue(ICodeWatcher))).returns(() => new CodeWatcher(appShell.object, logger.object, historyProvider.object, fileSystem.object, configService.object, documentManager.object, helper.object));
8184

8285
// Setup our active history instance
8386
historyProvider.setup(h => h.getOrCreateActive()).returns(() => Promise.resolve(activeHistory.object));
@@ -91,7 +94,7 @@ suite('DataScience Code Watcher Unit Tests', () => {
9194
// Setup config service
9295
configService.setup(c => c.getSettings()).returns(() => pythonSettings);
9396

94-
codeWatcher = new CodeWatcher(appShell.object, logger.object, historyProvider.object, fileSystem.object, configService.object, documentManager.object);
97+
codeWatcher = new CodeWatcher(appShell.object, logger.object, historyProvider.object, fileSystem.object, configService.object, documentManager.object, helper.object);
9598
});
9699

97100
function createTypeMoq<T>(tag: string): TypeMoq.IMock<T> {
@@ -570,6 +573,10 @@ testing2`;
570573
const document = createDocument(inputText, fileName, version, TypeMoq.Times.atLeastOnce());
571574

572575
codeWatcher.setDocument(document.object);
576+
helper.setup(h => h.getSelectedTextToExecute(TypeMoq.It.is((ed: TextEditor) => {
577+
return textEditor.object === ed;
578+
}))).returns(() => Promise.resolve('testing2'));
579+
helper.setup(h => h.normalizeLines(TypeMoq.It.isAny())).returns(() => Promise.resolve('testing2'));
573580

574581
// Set up our expected calls to add code
575582
activeHistory.setup(h => h.addCode(TypeMoq.It.isValue('testing2'),
@@ -591,34 +598,6 @@ testing2`;
591598
document.verifyAll();
592599
});
593600

594-
test('Test the RunCurrentCell command outside of a cell', async () => {
595-
const fileName = 'test.py';
596-
const version = 1;
597-
const inputText =
598-
`testing1
599-
#%%
600-
testing2`;
601-
const document = createDocument(inputText, fileName, version, TypeMoq.Times.atLeastOnce());
602-
603-
codeWatcher.setDocument(document.object);
604-
605-
// We don't want to ever call add code here
606-
activeHistory.setup(h => h.addCode(TypeMoq.It.isAny(),
607-
TypeMoq.It.isAny(),
608-
TypeMoq.It.isAny(),
609-
TypeMoq.It.isAny())).verifiable(TypeMoq.Times.never());
610-
611-
// For this test we need to set up a document selection point
612-
textEditor.setup(te => te.selection).returns(() => new Selection(0, 0, 0, 0));
613-
614-
// Try our RunCell command with the first selection point
615-
await codeWatcher.runCurrentCell();
616-
617-
// Verify function calls
618-
activeHistory.verifyAll();
619-
document.verifyAll();
620-
});
621-
622601
test('Test the RunCellAndAdvance command with next cell', async () => {
623602
const fileName = 'test.py';
624603
const version = 1;

src/test/datascience/editor-integration/helpers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export function createDocument(inputText: string, fileName: string, fileVersion:
4040
document.setup(d => d.getText(TypeMoq.It.isAny())).returns((r: Range) => {
4141
let results = '';
4242
if (r) {
43-
for (let line = r.start.line; line <= r.end.line; line += 1) {
43+
for (let line = r.start.line; line <= r.end.line && line < inputLines.length; line += 1) {
4444
const startIndex = line === r.start.line ? r.start.character : 0;
4545
const endIndex = line === r.end.line ? r.end.character : inputLines[line].length - 1;
4646
results += inputLines[line].slice(startIndex, endIndex + 1);

0 commit comments

Comments
 (0)