提交 33eb941e 编写于 作者: R Rob Lourens

Add language picker to the code cell status bar

Needs - sync language change to EH, and add status bar to markdown editor cells
上级 c77dfdc6
......@@ -99,7 +99,7 @@ registerAction2(class extends Action2 {
}
}
runCell(context);
return runCell(context);
}
});
......@@ -434,27 +434,37 @@ async function changeActiveCellToKind(kind: CellKind, accessor: ServicesAccessor
return;
}
if (activeCell.cellKind === kind) {
changeCellToKind(kind, { cell: activeCell, notebookEditor: editor });
}
export async function changeCellToKind(kind: CellKind, context: INotebookCellActionContext, language?: string): Promise<void> {
const { cell, notebookEditor } = context;
if (cell.cellKind === kind) {
return;
}
const text = activeCell.getText();
if (!editor.insertNotebookCell(activeCell, kind, 'below', text)) {
const text = cell.getText();
if (!notebookEditor.insertNotebookCell(cell, kind, 'below', text)) {
return;
}
const idx = editor.viewModel?.getCellIndex(activeCell);
const idx = notebookEditor.viewModel?.getCellIndex(cell);
if (typeof idx !== 'number') {
return;
}
const newCell = editor.viewModel?.viewCells[idx + 1];
const newCell = notebookEditor.viewModel?.viewCells[idx + 1];
if (!newCell) {
return;
}
editor.focusNotebookCell(newCell, activeCell.editState === CellEditState.Editing);
editor.deleteNotebookCell(activeCell);
if (language) {
newCell.model.language = language;
}
notebookEditor.focusNotebookCell(newCell, cell.editState === CellEditState.Editing);
notebookEditor.deleteNotebookCell(cell);
}
export interface INotebookCellActionContext {
......
......@@ -206,6 +206,14 @@
box-sizing: border-box;
}
.monaco-workbench .part.editor > .content .notebook-editor .cell-statusbar-container .cell-status-left {
flex-grow: 1;
}
.monaco-workbench .part.editor > .content .notebook-editor .cell-statusbar-container .cell-status-right {
padding-right: 12px;
}
.monaco-workbench .part.editor > .content .notebook-editor .cell-statusbar-container .cell-status-message {
display: flex;
align-items: center;
......
......@@ -23,6 +23,7 @@ import { CellViewModel, IModelDecorationsChangeAccessor, NotebookViewModel } fro
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
import { CellKind, IOutput, IRenderOutput, NotebookCellMetadata, NotebookDocumentMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { Webview } from 'vs/workbench/contrib/webview/browser/webview';
import { CellLanguageStatusBarItem } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer';
export const KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED = new RawContextKey<boolean>('notebookFindWidgetFocused', false);
......@@ -401,7 +402,7 @@ export interface CodeCellRenderTemplate extends BaseCellRenderTemplate {
statusBarContainer: HTMLElement;
cellRunStatusContainer: HTMLElement;
cellStatusMessageContainer: HTMLElement;
cellStatusPlaceholderContainer: HTMLElement;
languageStatusBarItem: CellLanguageStatusBarItem;
runToolbar: ToolBar;
runButtonContainer: HTMLElement;
executionOrderLabel: HTMLElement;
......
......@@ -7,48 +7,53 @@
import 'vs/css!vs/workbench/contrib/notebook/browser/media/notebook';
import { getZoomLevel } from 'vs/base/browser/browser';
import * as DOM from 'vs/base/browser/dom';
import { domEvent } from 'vs/base/browser/event';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { IListRenderer, IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar';
import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar';
import { IAction, ActionRunner } from 'vs/base/common/actions';
import { Range } from 'vs/editor/common/core/range';
import { escape } from 'vs/base/common/strings';
import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
import * as modes from 'vs/editor/common/modes';
import * as platform from 'vs/base/common/platform';
import { ActionRunner, IAction } from 'vs/base/common/actions';
import { renderCodicons } from 'vs/base/common/codicons';
import { Color } from 'vs/base/common/color';
import { Emitter, Event } from 'vs/base/common/event';
import { KeyCode } from 'vs/base/common/keyCodes';
import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
import { deepClone } from 'vs/base/common/objects';
import * as platform from 'vs/base/common/platform';
import { escape } from 'vs/base/common/strings';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import * as nls from 'vs/nls';
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
import { IEditorOptions, EditorOption, EDITOR_FONT_DEFAULTS } from 'vs/editor/common/config/editorOptions';
import { EditorOption, EDITOR_FONT_DEFAULTS, IEditorOptions } from 'vs/editor/common/config/editorOptions';
import { BareFontInfo } from 'vs/editor/common/config/fontInfo';
import { Range } from 'vs/editor/common/core/range';
import { ITextModel } from 'vs/editor/common/model';
import * as modes from 'vs/editor/common/modes';
import { tokenizeLineToHTML } from 'vs/editor/common/modes/textToHtmlTokenizer';
import { getIconClasses } from 'vs/editor/common/services/getIconClasses';
import { IModeService } from 'vs/editor/common/services/modeService';
import * as nls from 'vs/nls';
import { ContextAwareMenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IMenu, MenuItemAction } from 'vs/platform/actions/common/actions';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { EDITOR_BOTTOM_PADDING, EDITOR_TOOLBAR_HEIGHT, EDITOR_TOP_MARGIN, EDITOR_TOP_PADDING, BOTTOM_CELL_TOOLBAR_HEIGHT } from 'vs/workbench/contrib/notebook/browser/constants';
import { ExecuteCellAction, INotebookCellActionContext, CancelCellAction, InsertCodeCellAction, InsertMarkdownCellAction } from 'vs/workbench/contrib/notebook/browser/contrib/coreActions';
import { BaseCellRenderTemplate, CellEditState, CellRunState, CodeCellRenderTemplate, ICellViewModel, INotebookEditor, MarkdownCellRenderTemplate, NOTEBOOK_CELL_TYPE, NOTEBOOK_CELL_EDITABLE, NOTEBOOK_VIEW_TYPE, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE, NOTEBOOK_CELL_RUN_STATE, NOTEBOOK_CELL_RUNNABLE, NOTEBOOK_CELL_HAS_OUTPUTS } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
import { BOTTOM_CELL_TOOLBAR_HEIGHT, EDITOR_BOTTOM_PADDING, EDITOR_TOOLBAR_HEIGHT, EDITOR_TOP_MARGIN, EDITOR_TOP_PADDING } from 'vs/workbench/contrib/notebook/browser/constants';
import { CancelCellAction, ExecuteCellAction, INotebookCellActionContext, InsertCodeCellAction, InsertMarkdownCellAction, changeCellToKind } from 'vs/workbench/contrib/notebook/browser/contrib/coreActions';
import { BaseCellRenderTemplate, CellEditState, CellRunState, CodeCellRenderTemplate, ICellViewModel, INotebookEditor, MarkdownCellRenderTemplate, NOTEBOOK_CELL_EDITABLE, NOTEBOOK_CELL_HAS_OUTPUTS, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE, NOTEBOOK_CELL_RUNNABLE, NOTEBOOK_CELL_RUN_STATE, NOTEBOOK_CELL_TYPE, NOTEBOOK_VIEW_TYPE } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { CellMenus } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellMenus';
import { CodeCell } from 'vs/workbench/contrib/notebook/browser/view/renderers/codeCell';
import { StatefullMarkdownCell } from 'vs/workbench/contrib/notebook/browser/view/renderers/markdownCell';
import { BaseCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/baseCellViewModel';
import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel';
import { MarkdownCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel';
import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
import { CellKind, NotebookCellRunState } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { renderCodicons } from 'vs/base/common/codicons';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyCode } from 'vs/base/common/keyCodes';
import { domEvent } from 'vs/base/browser/event';
import { tokenizeLineToHTML } from 'vs/editor/common/modes/textToHtmlTokenizer';
import { ITextModel } from 'vs/editor/common/model';
import { BaseCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/baseCellViewModel';
import { Emitter, Event } from 'vs/base/common/event';
import { IModelService } from 'vs/editor/common/services/modelService';
import { URI } from 'vs/base/common/uri';
const $ = DOM.$;
......@@ -526,6 +531,98 @@ export class CellDragAndDropController {
}
}
interface ILanguagePickInput extends IQuickPickItem {
languageId: string;
description: string;
}
export class CellLanguageStatusBarItem extends Disposable {
private labelElement: HTMLElement;
private _cell: BaseCellViewModel | undefined;
private _editor: INotebookEditor | undefined;
private cellDisposables: DisposableStore;
constructor(
readonly container: HTMLElement,
@IModeService private readonly modeService: IModeService,
@IModelService private readonly modelService: IModelService,
@IQuickInputService private readonly quickInputService: IQuickInputService,
) {
super();
this.labelElement = DOM.append(container, $('a'));
this.labelElement.tabIndex = -1; // allows screen readers to read title, but still prevents tab focus.
this._register(DOM.addDisposableListener(this.labelElement, DOM.EventType.CLICK, () => this.showLanguagePicker()));
this._register(this.cellDisposables = new DisposableStore());
}
update(cell: CodeCellViewModel, editor: INotebookEditor): void {
this.cellDisposables.clear();
this._cell = cell;
this._editor = editor;
this.render();
this.cellDisposables.add(this._cell.model.onDidChangeLanguage(() => this.render()));
}
private render(): void {
this.labelElement.textContent = this.modeService.getLanguageName(this._cell!.language!);
}
private async showLanguagePicker() {
const picks = this.modeService.getRegisteredModes().map(languageId => {
let description: string;
if (languageId === this._cell!.language) {
description = nls.localize('languageDescription', "({0}) - Current Language", languageId);
} else {
description = nls.localize('languageDescriptionConfigured', "({0})", languageId);
}
const languageName = this.modeService.getLanguageName(languageId) || '';
return <ILanguagePickInput>{
label: languageName,
iconClasses: getIconClasses(this.modelService, this.modeService, this.getFakeResource(languageName)),
description,
languageId
};
}).sort((a, b) => {
return a.description.localeCompare(b.description);
});
const selection = await this.quickInputService.pick(picks, { placeHolder: nls.localize('pickLanguageToConfigure', "Select Language Mode") });
if (selection) {
if (selection.languageId === 'markdown' && this._cell?.language !== 'markdown') {
changeCellToKind(CellKind.Markdown, { cell: this._cell!, notebookEditor: this._editor! });
} else if (selection.languageId !== 'markdown' && this._cell?.language === 'markdown') {
changeCellToKind(CellKind.Code, { cell: this._cell!, notebookEditor: this._editor! }, selection.languageId);
} else {
this._cell!.model.language = selection.languageId;
}
}
}
/**
* Copied from editorStatus.ts
*/
private getFakeResource(lang: string): URI | undefined {
let fakeResource: URI | undefined;
const extensions = this.modeService.getExtensions(lang);
if (extensions?.length) {
fakeResource = URI.file(extensions[0]);
} else {
const filenames = this.modeService.getFilenames(lang);
if (filenames?.length) {
fakeResource = URI.file(filenames[0]);
}
}
return fakeResource;
}
}
class EditorTextRenderer {
getRichText(editor: ICodeEditor, modelRange: Range): string | null {
......@@ -679,9 +776,11 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende
disposables.add(progressBar);
const statusBarContainer = DOM.append(editorPart, $('.cell-statusbar-container'));
const cellRunStatusContainer = DOM.append(statusBarContainer, $('.cell-run-status'));
const cellStatusMessageContainer = DOM.append(statusBarContainer, $('.cell-status-message'));
const cellStatusPlaceholderContainer = DOM.append(statusBarContainer, $('.cell-status-placeholder'));
const leftStatusBarItems = DOM.append(statusBarContainer, $('.cell-status-left'));
const rightStatusBarItems = DOM.append(statusBarContainer, $('.cell-status-right'));
const cellRunStatusContainer = DOM.append(leftStatusBarItems, $('.cell-run-status'));
const cellStatusMessageContainer = DOM.append(leftStatusBarItems, $('.cell-status-message'));
const languageStatusBarItem = this.instantiationService.createInstance(CellLanguageStatusBarItem, rightStatusBarItems);
const insertionIndicatorTop = DOM.append(container, DOM.$('.notebook-cell-insertion-indicator-top'));
const outputContainer = DOM.append(container, $('.output'));
......@@ -694,7 +793,7 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende
statusBarContainer,
cellRunStatusContainer,
cellStatusMessageContainer,
cellStatusPlaceholderContainer,
languageStatusBarItem,
progressBar,
focusIndicator,
toolbar,
......@@ -749,12 +848,6 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende
} else {
templateData.cellRunStatusContainer.innerHTML = '';
}
if (!metadata.statusMessage && (typeof metadata.runState === 'undefined' || metadata.runState === NotebookCellRunState.Idle)) {
templateData.cellStatusPlaceholderContainer.textContent = platform.isWindows ? 'Ctrl + Alt + Enter to run' : 'Ctrl + Enter to run';
} else {
templateData.cellStatusPlaceholderContainer.textContent = '';
}
}
private renderExecutionOrder(element: CodeCellViewModel, templateData: CodeCellRenderTemplate): void {
......@@ -840,6 +933,8 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende
templateData.runToolbar.context = toolbarContext;
this.setupBetweenCellToolbarActions(element, templateData, elementDisposables, toolbarContext);
templateData.languageStatusBarItem.update(element, this.notebookEditor);
}
disposeTemplate(templateData: CodeCellRenderTemplate): void {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册