mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-30 01:25:38 -05:00
Books/search within notebook (#8426)
* initial commit * get notebook content * skeleton for find in notebookModel * add search function and keyboard shortcut * add command for hiding find widget * started on search logic * continue search logic * continue search logic * add findcountchange listener * notebook find position * added css class * hide find widget * focus find input * search for multiple occurrences in one line * start notebook find decorations * start adding decorations to notebook model * added editor_model_defaults * added cursor position * merged master and resolved husky erros * initial changes added to Lucyls base implementation * pass NotebbokRange instead of Range to decorations * changes after merging master * temp changes for testing * style updates from vscode merge * implemented the empty methods and added supporting functionality from textModel * just a little error checking * It gets more and more yellow * making highlight work between code cells * highlight only word * remove highlight on close and maintain the position * cleanup of unused references * clean up * find between code cells refactored * highlight markdown line and scroll to it * find index fix * find index fix * code clean up * remove commented code * tslint fix for: Cannot use global 'NodeJS' * linting rule fixes * deltaDecoration base implementation on the base class * moced class defnitions from interface fikle * updated action names * DOM.addClass instead of overwriting * resooved conflicts * moved 'find' code away from notebookmodel to sep class * moved find realted code to seperate folder * created notebookFindModel * clean up * highlight color changes * spacing and typo fixes * highlight correct element for nested elements * do not iterate through paragraphs and li * find accross notebooks * keep track of index * clear decorations on close * floating promises * maintain search context Co-authored-by: Lucy Zhang <lucyzhang929@gmail.com> Co-authored-by: Chris LaFreniere <40371649+chlafreniere@users.noreply.github.com>
This commit is contained in:
@@ -6,7 +6,6 @@ import 'vs/css!./code';
|
||||
|
||||
import { OnInit, Component, Input, Inject, ElementRef, ViewChild, Output, EventEmitter, OnChanges, SimpleChange, forwardRef, ChangeDetectorRef } from '@angular/core';
|
||||
|
||||
import { AngularDisposable } from 'sql/base/browser/lifecycle';
|
||||
import { QueryTextEditor } from 'sql/workbench/browser/modelComponents/queryTextEditor';
|
||||
import { CellToggleMoreActions } from 'sql/workbench/contrib/notebook/browser/cellToggleMoreActions';
|
||||
import { ICellModel, notebookConstants, CellExecutionState } from 'sql/workbench/contrib/notebook/browser/models/modelInterfaces';
|
||||
@@ -33,6 +32,7 @@ import { IConnectionManagementService } from 'sql/platform/connection/common/con
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { CollapseComponent } from 'sql/workbench/contrib/notebook/browser/cellViews/collapse.component';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { CellView } from 'sql/workbench/contrib/notebook/browser/cellViews/interfaces';
|
||||
import { UntitledTextEditorInput } from 'vs/workbench/common/editor/untitledTextEditorInput';
|
||||
import { UntitledTextEditorModel } from 'vs/workbench/common/editor/untitledTextEditorModel';
|
||||
|
||||
@@ -44,7 +44,7 @@ const DEFAULT_OR_LOCAL_CONTEXT_ID = '-1';
|
||||
selector: CODE_SELECTOR,
|
||||
templateUrl: decodeURI(require.toUrl('./code.component.html'))
|
||||
})
|
||||
export class CodeComponent extends AngularDisposable implements OnInit, OnChanges {
|
||||
export class CodeComponent extends CellView implements OnInit, OnChanges {
|
||||
@ViewChild('toolbar', { read: ElementRef }) private toolbarElement: ElementRef;
|
||||
@ViewChild('moreactions', { read: ElementRef }) private moreActionsElementRef: ElementRef;
|
||||
@ViewChild('editor', { read: ElementRef }) private codeElement: ElementRef;
|
||||
@@ -141,6 +141,18 @@ export class CodeComponent extends AngularDisposable implements OnInit, OnChange
|
||||
}
|
||||
}
|
||||
|
||||
public getEditor(): QueryTextEditor {
|
||||
return this._editor;
|
||||
}
|
||||
|
||||
public hasEditor(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
public cellGuid(): string {
|
||||
return this.cellModel.cellGuid;
|
||||
}
|
||||
|
||||
private updateConnectionState(shouldConnect: boolean) {
|
||||
if (this.isSqlCodeCell()) {
|
||||
let cellUri = this.cellModel.cellUri.toString();
|
||||
@@ -173,7 +185,7 @@ export class CodeComponent extends AngularDisposable implements OnInit, OnChange
|
||||
if (this.destroyed) {
|
||||
return;
|
||||
}
|
||||
this.createEditor();
|
||||
this.createEditor().catch(e => this.logService.error(e));
|
||||
this._register(DOM.addDisposableListener(window, DOM.EventType.RESIZE, e => {
|
||||
this._layoutEmitter.fire();
|
||||
}));
|
||||
|
||||
@@ -66,6 +66,14 @@ code-component .monaco-editor .decorationsOverviewRuler {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.vs code-component .monaco-editor .rangeHighlight {
|
||||
background-color: rgba(255, 255, 0, 0.2)
|
||||
}
|
||||
|
||||
.vs-dark code-component .monaco-editor .rangeHighlight {
|
||||
background-color: rgba(255, 255, 0, 0.2)
|
||||
}
|
||||
|
||||
code-component .carbon-taskbar .codicon {
|
||||
background-size: 20px;
|
||||
width: 40px;
|
||||
|
||||
@@ -4,11 +4,14 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { nb } from 'azdata';
|
||||
import { OnInit, Component, Input, Inject, forwardRef, ChangeDetectorRef, SimpleChange, OnChanges, HostListener } from '@angular/core';
|
||||
import { OnInit, Component, Input, Inject, forwardRef, ChangeDetectorRef, SimpleChange, OnChanges, HostListener, ViewChildren, QueryList } from '@angular/core';
|
||||
import { CellView } from 'sql/workbench/contrib/notebook/browser/cellViews/interfaces';
|
||||
import { ICellModel } from 'sql/workbench/contrib/notebook/browser/models/modelInterfaces';
|
||||
import { NotebookModel } from 'sql/workbench/contrib/notebook/browser/models/notebookModel';
|
||||
import { Deferred } from 'sql/base/common/promise';
|
||||
import { ICellEditorProvider } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||
import { CodeComponent } from 'sql/workbench/contrib/notebook/browser/cellViews/code.component';
|
||||
import { OutputComponent } from 'sql/workbench/contrib/notebook/browser/cellViews/output.component';
|
||||
|
||||
|
||||
export const CODE_SELECTOR: string = 'code-cell-component';
|
||||
@@ -19,6 +22,8 @@ export const CODE_SELECTOR: string = 'code-cell-component';
|
||||
})
|
||||
|
||||
export class CodeCellComponent extends CellView implements OnInit, OnChanges {
|
||||
@ViewChildren(CodeComponent) private codeCells: QueryList<ICellEditorProvider>;
|
||||
@ViewChildren(OutputComponent) private outputCells: QueryList<ICellEditorProvider>;
|
||||
@Input() cellModel: ICellModel;
|
||||
@Input() set model(value: NotebookModel) {
|
||||
this._model = value;
|
||||
@@ -69,6 +74,17 @@ export class CodeCellComponent extends CellView implements OnInit, OnChanges {
|
||||
}
|
||||
}
|
||||
|
||||
public get cellEditors(): ICellEditorProvider[] {
|
||||
let editors: ICellEditorProvider[] = [];
|
||||
if (this.codeCells) {
|
||||
editors.push(...this.codeCells.toArray());
|
||||
}
|
||||
if (this.outputCells) {
|
||||
editors.push(...this.outputCells.toArray());
|
||||
}
|
||||
return editors;
|
||||
}
|
||||
|
||||
get model(): NotebookModel {
|
||||
return this._model;
|
||||
}
|
||||
@@ -110,4 +126,8 @@ export class CodeCellComponent extends CellView implements OnInit, OnChanges {
|
||||
get isStdInVisible(): boolean {
|
||||
return this.cellModel.stdInVisible;
|
||||
}
|
||||
|
||||
public cellGuid(): string {
|
||||
return this.cellModel.cellGuid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +64,10 @@ export class CollapseComponent extends CellView implements OnInit, OnChanges {
|
||||
this.cellModel.isCollapsed = !this.cellModel.isCollapsed;
|
||||
}
|
||||
|
||||
public cellGuid(): string {
|
||||
return this.cellModel.cellGuid;
|
||||
}
|
||||
|
||||
public layout() {
|
||||
|
||||
}
|
||||
|
||||
@@ -5,11 +5,28 @@
|
||||
|
||||
import { OnDestroy } from '@angular/core';
|
||||
import { AngularDisposable } from 'sql/base/browser/lifecycle';
|
||||
import { ICellEditorProvider } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||
import { BaseTextEditor } from 'vs/workbench/browser/parts/editor/textEditor';
|
||||
import { NotebookRange } from 'sql/workbench/contrib/notebook/find/notebookFindDecorations';
|
||||
|
||||
export abstract class CellView extends AngularDisposable implements OnDestroy {
|
||||
export abstract class CellView extends AngularDisposable implements OnDestroy, ICellEditorProvider {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public abstract layout(): void;
|
||||
|
||||
public getEditor(): BaseTextEditor | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public hasEditor(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
public abstract cellGuid(): string;
|
||||
|
||||
public deltaDecorations(newDecorationRange: NotebookRange, oldDecorationRange: NotebookRange): void {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import 'vs/css!./code';
|
||||
import 'vs/css!./media/output';
|
||||
|
||||
import { OnInit, Component, Input, Inject, ElementRef, ViewChild, SimpleChange, AfterViewInit, forwardRef, ChangeDetectorRef, ComponentRef, ComponentFactoryResolver } from '@angular/core';
|
||||
import { AngularDisposable } from 'sql/base/browser/lifecycle';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { nb } from 'azdata';
|
||||
import { ICellModel } from 'sql/workbench/contrib/notebook/browser/models/modelInterfaces';
|
||||
@@ -21,6 +20,7 @@ import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { localize } from 'vs/nls';
|
||||
import * as types from 'vs/base/common/types';
|
||||
import { getErrorMessage } from 'vs/base/common/errors';
|
||||
import { CellView } from 'sql/workbench/contrib/notebook/browser/cellViews/interfaces';
|
||||
|
||||
export const OUTPUT_SELECTOR: string = 'output-component';
|
||||
const USER_SELECT_CLASS = 'actionselect';
|
||||
@@ -31,7 +31,7 @@ const componentRegistry = <IMimeComponentRegistry>Registry.as(Extensions.MimeCom
|
||||
selector: OUTPUT_SELECTOR,
|
||||
templateUrl: decodeURI(require.toUrl('./output.component.html'))
|
||||
})
|
||||
export class OutputComponent extends AngularDisposable implements OnInit, AfterViewInit {
|
||||
export class OutputComponent extends CellView implements OnInit, AfterViewInit {
|
||||
@ViewChild('output', { read: ElementRef }) private outputElement: ElementRef;
|
||||
@ViewChild(ComponentHostDirective) componentHost: ComponentHostDirective;
|
||||
@Input() cellOutput: nb.ICellOutput;
|
||||
@@ -184,4 +184,8 @@ export class OutputComponent extends AngularDisposable implements OnInit, AfterV
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public cellGuid(): string {
|
||||
return this.cellModel.cellGuid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,4 +82,8 @@ export class PlaceholderCellComponent extends CellView implements OnInit, OnChan
|
||||
public layout() {
|
||||
|
||||
}
|
||||
|
||||
public cellGuid(): string {
|
||||
return this.cellModel.cellGuid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import { ICellModel } from 'sql/workbench/contrib/notebook/browser/models/modelI
|
||||
import { NotebookModel } from 'sql/workbench/contrib/notebook/browser/models/notebookModel';
|
||||
import { ISanitizer, defaultSanitizer } from 'sql/workbench/contrib/notebook/browser/outputs/sanitizer';
|
||||
import { CellToggleMoreActions } from 'sql/workbench/contrib/notebook/browser/cellToggleMoreActions';
|
||||
import { NotebookRange } from 'sql/workbench/contrib/notebook/find/notebookFindDecorations';
|
||||
|
||||
export const TEXT_SELECTOR: string = 'text-cell-component';
|
||||
const USER_SELECT_CLASS = 'actionselect';
|
||||
@@ -139,6 +140,10 @@ export class TextCellComponent extends CellView implements OnInit, OnChanges {
|
||||
}
|
||||
}
|
||||
|
||||
public cellGuid(): string {
|
||||
return this.cellModel.cellGuid;
|
||||
}
|
||||
|
||||
public get isTrusted(): boolean {
|
||||
return this.model.trustedMode;
|
||||
}
|
||||
@@ -243,4 +248,66 @@ export class TextCellComponent extends CellView implements OnInit, OnChanges {
|
||||
protected toggleMoreActionsButton(isActiveOrHovered: boolean) {
|
||||
this._cellToggleMoreActions.toggleVisible(!isActiveOrHovered);
|
||||
}
|
||||
|
||||
public deltaDecorations(newDecorationRange: NotebookRange, oldDecorationRange: NotebookRange): void {
|
||||
if (oldDecorationRange) {
|
||||
this.removeDecoration(oldDecorationRange);
|
||||
}
|
||||
|
||||
if (newDecorationRange) {
|
||||
this.addDecoration(newDecorationRange);
|
||||
}
|
||||
}
|
||||
|
||||
private addDecoration(range: NotebookRange): void {
|
||||
if (range && this.output && this.output.nativeElement) {
|
||||
let children = this.getHtmlElements();
|
||||
let ele = children[range.startLineNumber - 1];
|
||||
if (ele) {
|
||||
DOM.addClass(ele, 'rangeHighlight');
|
||||
ele.scrollIntoView({ behavior: 'smooth' });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private removeDecoration(range: NotebookRange): void {
|
||||
if (range && this.output && this.output.nativeElement) {
|
||||
let children = this.getHtmlElements();
|
||||
let ele = children[range.startLineNumber - 1];
|
||||
if (ele) {
|
||||
DOM.removeClass(ele, 'rangeHighlight');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private getHtmlElements(): any[] {
|
||||
let hostElem = this.output.nativeElement;
|
||||
let children = [];
|
||||
for (let element of hostElem.children) {
|
||||
if (element.nodeName.toLowerCase() === 'table') {
|
||||
// add table header and table rows.
|
||||
children.push(element.children[0]);
|
||||
for (let trow of element.children[1].children) {
|
||||
children.push(trow);
|
||||
}
|
||||
} else if (element.children.length > 1) {
|
||||
children = children.concat(this.getChildren(element));
|
||||
} else {
|
||||
children.push(element);
|
||||
}
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
private getChildren(parent: any): any[] {
|
||||
let children: any = [];
|
||||
if (parent.children.length > 1 && parent.nodeName.toLowerCase() !== 'li' && parent.nodeName.toLowerCase() !== 'p') {
|
||||
for (let child of parent.children) {
|
||||
children = children.concat(this.getChildren(child));
|
||||
}
|
||||
} else {
|
||||
return parent;
|
||||
}
|
||||
return children;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,14 @@ text-cell-component .notebook-preview {
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
.vs .notebook-preview .rangeHighlight {
|
||||
background-color: rgba(255, 255, 0, 0.2)
|
||||
}
|
||||
|
||||
.vs-dark .notebook-preview .rangeHighlight {
|
||||
background-color: rgba(255, 255, 0, 0.2)
|
||||
}
|
||||
|
||||
text-cell-component table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
@@ -47,4 +55,4 @@ text-cell-component tr {
|
||||
|
||||
text-cell-component th {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user