mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 02:51:36 -05:00
Save multiline source in notebooks (#6445)
* Save multiline source in notebooks * Stop demultiline localContentManager unnecessarily
This commit is contained in:
2
src/sql/azdata.proposed.d.ts
vendored
2
src/sql/azdata.proposed.d.ts
vendored
@@ -4990,7 +4990,7 @@ declare module 'azdata' {
|
|||||||
* The contents of a requestExecute message sent to the server.
|
* The contents of a requestExecute message sent to the server.
|
||||||
*/
|
*/
|
||||||
export interface IExecuteRequest extends IExecuteOptions {
|
export interface IExecuteRequest extends IExecuteOptions {
|
||||||
code: string;
|
code: string | string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -196,7 +196,9 @@ export class CodeComponent extends AngularDisposable implements OnInit, OnChange
|
|||||||
this._editor.setMinimumHeight(this._minimumHeight);
|
this._editor.setMinimumHeight(this._minimumHeight);
|
||||||
this._editor.setMaximumHeight(this._maximumHeight);
|
this._editor.setMaximumHeight(this._maximumHeight);
|
||||||
let uri = this.cellModel.cellUri;
|
let uri = this.cellModel.cellUri;
|
||||||
this._editorInput = instantiationService.createInstance(UntitledEditorInput, uri, false, this.cellModel.language, this.cellModel.source, '');
|
let cellModelSource: string;
|
||||||
|
cellModelSource = Array.isArray(this.cellModel.source) ? this.cellModel.source.join('') : this.cellModel.source;
|
||||||
|
this._editorInput = instantiationService.createInstance(UntitledEditorInput, uri, false, this.cellModel.language, cellModelSource, '');
|
||||||
await this._editor.setInput(this._editorInput, undefined);
|
await this._editor.setInput(this._editorInput, undefined);
|
||||||
this.setFocusAndScroll();
|
this.setFocusAndScroll();
|
||||||
let untitledEditorModel: UntitledEditorModel = await this._editorInput.resolve();
|
let untitledEditorModel: UntitledEditorModel = await this._editorInput.resolve();
|
||||||
@@ -262,7 +264,9 @@ export class CodeComponent extends AngularDisposable implements OnInit, OnChange
|
|||||||
/// Editor Functions
|
/// Editor Functions
|
||||||
private updateModel() {
|
private updateModel() {
|
||||||
if (this._editorModel) {
|
if (this._editorModel) {
|
||||||
this._modelService.updateModel(this._editorModel, this.cellModel.source);
|
let cellModelSource: string;
|
||||||
|
cellModelSource = Array.isArray(this.cellModel.source) ? this.cellModel.source.join('') : this.cellModel.source;
|
||||||
|
this._modelService.updateModel(this._editorModel, cellModelSource);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ export class TextCellComponent extends CellView implements OnInit, OnChanges {
|
|||||||
this._model.activeCell = undefined;
|
this._model.activeCell = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _content: string;
|
private _content: string | string[];
|
||||||
private _lastTrustedMode: boolean;
|
private _lastTrustedMode: boolean;
|
||||||
private isEditMode: boolean;
|
private isEditMode: boolean;
|
||||||
private _sanitizer: ISanitizer;
|
private _sanitizer: ISanitizer;
|
||||||
@@ -178,7 +178,7 @@ export class TextCellComponent extends CellView implements OnInit, OnChanges {
|
|||||||
this.markdownRenderer.setNotebookURI(this.cellModel.notebookModel.notebookUri);
|
this.markdownRenderer.setNotebookURI(this.cellModel.notebookModel.notebookUri);
|
||||||
this.markdownResult = this.markdownRenderer.render({
|
this.markdownResult = this.markdownRenderer.render({
|
||||||
isTrusted: true,
|
isTrusted: true,
|
||||||
value: this._content
|
value: Array.isArray(this._content) ? this._content.join('') : this._content
|
||||||
});
|
});
|
||||||
this.markdownResult.element.innerHTML = this.sanitizeContent(this.markdownResult.element.innerHTML);
|
this.markdownResult.element.innerHTML = this.sanitizeContent(this.markdownResult.element.innerHTML);
|
||||||
this.setLoading(false);
|
this.setLoading(false);
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ let modelId = 0;
|
|||||||
|
|
||||||
export class CellModel implements ICellModel {
|
export class CellModel implements ICellModel {
|
||||||
private _cellType: nb.CellType;
|
private _cellType: nb.CellType;
|
||||||
private _source: string;
|
private _source: string | string[];
|
||||||
private _language: string;
|
private _language: string;
|
||||||
private _future: FutureInternal;
|
private _future: FutureInternal;
|
||||||
private _outputs: nb.ICellOutput[] = [];
|
private _outputs: nb.ICellOutput[] = [];
|
||||||
@@ -156,11 +156,12 @@ export class CellModel implements ICellModel {
|
|||||||
return this._cellType;
|
return this._cellType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get source(): string {
|
public get source(): string | string[] {
|
||||||
return this._source;
|
return this._source;
|
||||||
}
|
}
|
||||||
|
|
||||||
public set source(newSource: string) {
|
public set source(newSource: string | string[]) {
|
||||||
|
newSource = this.getMultilineSource(newSource);
|
||||||
if (this._source !== newSource) {
|
if (this._source !== newSource) {
|
||||||
this._source = newSource;
|
this._source = newSource;
|
||||||
this.sendChangeToNotebook(NotebookChangeType.CellSourceUpdated);
|
this.sendChangeToNotebook(NotebookChangeType.CellSourceUpdated);
|
||||||
@@ -533,7 +534,7 @@ export class CellModel implements ICellModel {
|
|||||||
}
|
}
|
||||||
this._cellType = cell.cell_type;
|
this._cellType = cell.cell_type;
|
||||||
this.executionCount = cell.execution_count;
|
this.executionCount = cell.execution_count;
|
||||||
this._source = Array.isArray(cell.source) ? cell.source.join('') : cell.source;
|
this._source = this.getMultilineSource(cell.source);
|
||||||
this._metadata = cell.metadata;
|
this._metadata = cell.metadata;
|
||||||
this.setLanguageFromContents(cell);
|
this.setLanguageFromContents(cell);
|
||||||
if (cell.outputs) {
|
if (cell.outputs) {
|
||||||
@@ -594,6 +595,26 @@ export class CellModel implements ICellModel {
|
|||||||
return endpoint;
|
return endpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getMultilineSource(source: string | string[]): string | string[] {
|
||||||
|
if (typeof source === 'string') {
|
||||||
|
let sourceMultiline = source.split('\n');
|
||||||
|
// If source is one line (i.e. no '\n'), return it immediately
|
||||||
|
if (sourceMultiline.length <= 1) {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
// Otherwise, add back all of the newlines here
|
||||||
|
// Note: for Windows machines that require '/r/n',
|
||||||
|
// splitting on '\n' and putting back the '\n' will still
|
||||||
|
// retain the '\r', so that isn't lost in the process
|
||||||
|
// Note: the last line will not include a newline at the end
|
||||||
|
for (let i = 0; i < sourceMultiline.length - 1; i++) {
|
||||||
|
sourceMultiline[i] += '\n';
|
||||||
|
}
|
||||||
|
return sourceMultiline;
|
||||||
|
}
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
// Dispose and set current future to undefined
|
// Dispose and set current future to undefined
|
||||||
private disposeFuture() {
|
private disposeFuture() {
|
||||||
if (this._future) {
|
if (this._future) {
|
||||||
|
|||||||
@@ -449,7 +449,7 @@ export interface ICellModel {
|
|||||||
cellUri: URI;
|
cellUri: URI;
|
||||||
id: string;
|
id: string;
|
||||||
readonly language: string;
|
readonly language: string;
|
||||||
source: string;
|
source: string | string[];
|
||||||
cellType: CellType;
|
cellType: CellType;
|
||||||
trustedMode: boolean;
|
trustedMode: boolean;
|
||||||
active: boolean;
|
active: boolean;
|
||||||
|
|||||||
@@ -130,6 +130,121 @@ suite('Cell Model', function (): void {
|
|||||||
should(cell.language).equal('python');
|
should(cell.language).equal('python');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Should allow source of type string[] with length 1', async function (): Promise<void> {
|
||||||
|
let cellData: nb.ICellContents = {
|
||||||
|
cell_type: CellTypes.Code,
|
||||||
|
source: ['print(1)'],
|
||||||
|
metadata: { language: 'sql' },
|
||||||
|
execution_count: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
let notebookModel = new NotebookModelStub({
|
||||||
|
name: '',
|
||||||
|
version: '',
|
||||||
|
mimetype: ''
|
||||||
|
});
|
||||||
|
let cell = factory.createCell(cellData, { notebook: notebookModel, isTrusted: false });
|
||||||
|
should(Array.isArray(cell.source)).equal(true);
|
||||||
|
should(cell.source.length).equal(1);
|
||||||
|
should(cell.source[0]).equal('print(1)');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should allow source of type string', async function (): Promise<void> {
|
||||||
|
let cellData: nb.ICellContents = {
|
||||||
|
cell_type: CellTypes.Code,
|
||||||
|
source: 'print(1)',
|
||||||
|
metadata: { language: 'sql' },
|
||||||
|
execution_count: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
let notebookModel = new NotebookModelStub({
|
||||||
|
name: '',
|
||||||
|
version: '',
|
||||||
|
mimetype: ''
|
||||||
|
});
|
||||||
|
let cell = factory.createCell(cellData, { notebook: notebookModel, isTrusted: false });
|
||||||
|
should(Array.isArray(cell.source)).equal(false);
|
||||||
|
should(cell.source).equal('print(1)');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should allow source of type string with newline and split it', async function (): Promise<void> {
|
||||||
|
let cellData: nb.ICellContents = {
|
||||||
|
cell_type: CellTypes.Code,
|
||||||
|
source: 'print(1)\nprint(2)',
|
||||||
|
metadata: { language: 'sql' },
|
||||||
|
execution_count: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
let notebookModel = new NotebookModelStub({
|
||||||
|
name: '',
|
||||||
|
version: '',
|
||||||
|
mimetype: ''
|
||||||
|
});
|
||||||
|
let cell = factory.createCell(cellData, { notebook: notebookModel, isTrusted: false });
|
||||||
|
should(Array.isArray(cell.source)).equal(true);
|
||||||
|
should(cell.source.length).equal(2);
|
||||||
|
should(cell.source[0]).equal('print(1)\n');
|
||||||
|
should(cell.source[1]).equal('print(2)');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should allow source of type string with Windows style newline and split it', async function (): Promise<void> {
|
||||||
|
let cellData: nb.ICellContents = {
|
||||||
|
cell_type: CellTypes.Code,
|
||||||
|
source: 'print(1)\r\nprint(2)',
|
||||||
|
metadata: { language: 'sql' },
|
||||||
|
execution_count: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
let notebookModel = new NotebookModelStub({
|
||||||
|
name: '',
|
||||||
|
version: '',
|
||||||
|
mimetype: ''
|
||||||
|
});
|
||||||
|
let cell = factory.createCell(cellData, { notebook: notebookModel, isTrusted: false });
|
||||||
|
should(Array.isArray(cell.source)).equal(true);
|
||||||
|
should(cell.source.length).equal(2);
|
||||||
|
should(cell.source[0]).equal('print(1)\r\n');
|
||||||
|
should(cell.source[1]).equal('print(2)');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should allow source of type string[] with length 2', async function (): Promise<void> {
|
||||||
|
let cellData: nb.ICellContents = {
|
||||||
|
cell_type: CellTypes.Code,
|
||||||
|
source: ['print(1)\n', 'print(2)'],
|
||||||
|
metadata: { language: 'sql' },
|
||||||
|
execution_count: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
let notebookModel = new NotebookModelStub({
|
||||||
|
name: '',
|
||||||
|
version: '',
|
||||||
|
mimetype: ''
|
||||||
|
});
|
||||||
|
let cell = factory.createCell(cellData, { notebook: notebookModel, isTrusted: false });
|
||||||
|
should(Array.isArray(cell.source)).equal(true);
|
||||||
|
should(cell.source.length).equal(2);
|
||||||
|
should(cell.source[0]).equal('print(1)\n');
|
||||||
|
should(cell.source[1]).equal('print(2)');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should allow empty string source', async function (): Promise<void> {
|
||||||
|
let cellData: nb.ICellContents = {
|
||||||
|
cell_type: CellTypes.Code,
|
||||||
|
source: '',
|
||||||
|
metadata: { language: 'sql' },
|
||||||
|
execution_count: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
let notebookModel = new NotebookModelStub({
|
||||||
|
name: '',
|
||||||
|
version: '',
|
||||||
|
mimetype: ''
|
||||||
|
});
|
||||||
|
let cell = factory.createCell(cellData, { notebook: notebookModel, isTrusted: false });
|
||||||
|
should(Array.isArray(cell.source)).equal(false);
|
||||||
|
should(cell.source).equal('');
|
||||||
|
});
|
||||||
|
|
||||||
suite('Model Future handling', function (): void {
|
suite('Model Future handling', function (): void {
|
||||||
let future: TypeMoq.Mock<EmptyFuture>;
|
let future: TypeMoq.Mock<EmptyFuture>;
|
||||||
let cell: ICellModel;
|
let cell: ICellModel;
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ namespace v4 {
|
|||||||
export function createDefaultCell(cell: nb.ICellContents): nb.ICellContents {
|
export function createDefaultCell(cell: nb.ICellContents): nb.ICellContents {
|
||||||
return {
|
return {
|
||||||
cell_type: cell.cell_type,
|
cell_type: cell.cell_type,
|
||||||
source: demultiline(cell.source),
|
source: cell.source,
|
||||||
metadata: cell.metadata
|
metadata: cell.metadata
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -133,7 +133,7 @@ namespace v4 {
|
|||||||
function createCodeCell(cell: nb.ICellContents): nb.ICellContents {
|
function createCodeCell(cell: nb.ICellContents): nb.ICellContents {
|
||||||
return {
|
return {
|
||||||
cell_type: cell.cell_type,
|
cell_type: cell.cell_type,
|
||||||
source: demultiline(cell.source),
|
source: cell.source,
|
||||||
metadata: cell.metadata,
|
metadata: cell.metadata,
|
||||||
execution_count: cell.execution_count,
|
execution_count: cell.execution_count,
|
||||||
outputs: createOutputs(cell)
|
outputs: createOutputs(cell)
|
||||||
|
|||||||
@@ -274,7 +274,7 @@ class SqlKernel extends Disposable implements nb.IKernel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getCodeWithoutCellMagic(content: nb.IExecuteRequest): string {
|
private getCodeWithoutCellMagic(content: nb.IExecuteRequest): string {
|
||||||
let code = content.code;
|
let code = Array.isArray(content.code) ? content.code.join('') : content.code;
|
||||||
let firstLineEnd = code.indexOf(os.EOL);
|
let firstLineEnd = code.indexOf(os.EOL);
|
||||||
let firstLine = code.substring(0, (firstLineEnd >= 0) ? firstLineEnd : 0).trimLeft();
|
let firstLine = code.substring(0, (firstLineEnd >= 0) ? firstLineEnd : 0).trimLeft();
|
||||||
if (firstLine.startsWith('%%')) {
|
if (firstLine.startsWith('%%')) {
|
||||||
|
|||||||
Reference in New Issue
Block a user