mirror of
https://github.com/microsoft/vscode.git
synced 2026-09-01 13:15:22 +01:00
fix #21064, also support dismiss on ESC and 3s timeout, move out code to its own file, tweak message
This commit is contained in:
@@ -9,7 +9,7 @@ import * as errors from 'vs/base/common/errors';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { Promise, TPromise, ValueCallback, ErrorCallback, ProgressCallback } from 'vs/base/common/winjs.base';
|
||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
|
||||
function isThenable<T>(obj: any): obj is Thenable<T> {
|
||||
@@ -501,6 +501,11 @@ export class Queue<T> extends Limiter<T> {
|
||||
}
|
||||
}
|
||||
|
||||
export function setDisposableTimeout(handler: Function, timeout: number, ...args: any[]): IDisposable {
|
||||
const handle = setTimeout(handler, timeout, ...args);
|
||||
return { dispose() { clearTimeout(handle); } };
|
||||
}
|
||||
|
||||
export class TimeoutTimer extends Disposable {
|
||||
private _token: platform.TimeoutToken;
|
||||
|
||||
@@ -642,4 +647,4 @@ export function ninvoke(thisArg: any, fn: Function, ...args: any[]): Promise;
|
||||
export function ninvoke<T>(thisArg: any, fn: Function, ...args: any[]): TPromise<T>;
|
||||
export function ninvoke(thisArg: any, fn: Function, ...args: any[]): any {
|
||||
return new Promise((c, e) => fn.call(thisArg, ...args, (err, result) => err ? e(err) : c(result)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,27 +3,6 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-editor .monaco-editor-overlaymessage {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.monaco-editor .monaco-editor-overlaymessage .message {
|
||||
padding: 1px 4px;
|
||||
background: #1382CE;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.monaco-editor .monaco-editor-overlaymessage .anchor {
|
||||
width: 0 !important;
|
||||
height: 0 !important;
|
||||
border-color: transparent;
|
||||
border-style: solid;
|
||||
z-index: 1000;
|
||||
border-width: 8px;
|
||||
border-top-color: #1382CE;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.monaco-editor .preview-zone-widget.preview .monaco-editor,
|
||||
.monaco-editor .preview-zone-widget.preview .monaco-editor-background,
|
||||
.monaco-editor .preview-zone-widget.preview .monaco-editor .line-numbers,
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
import 'vs/css!./goToDeclaration';
|
||||
import * as nls from 'vs/nls';
|
||||
import { Throttler } from 'vs/base/common/async';
|
||||
import { any, filterEvent } from 'vs/base/common/event';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { MarkedString } from 'vs/base/common/htmlContent';
|
||||
import { KeyCode, KeyMod, KeyChord } from 'vs/base/common/keyCodes';
|
||||
@@ -25,7 +24,7 @@ import { Range } from 'vs/editor/common/core/range';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import { editorAction, IActionOptions, ServicesAccessor, EditorAction } from 'vs/editor/common/editorCommonExtensions';
|
||||
import { Location, DefinitionProviderRegistry } from 'vs/editor/common/modes';
|
||||
import { ICodeEditor, IEditorMouseEvent, IMouseTarget, IContentWidget, IContentWidgetPosition, ContentWidgetPositionPreference } from 'vs/editor/browser/editorBrowser';
|
||||
import { ICodeEditor, IEditorMouseEvent, IMouseTarget } from 'vs/editor/browser/editorBrowser';
|
||||
import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions';
|
||||
import { getDefinitionsAtPosition, getImplementationsAtPosition, getTypeDefinitionsAtPosition } from 'vs/editor/contrib/goToDeclaration/common/goToDeclaration';
|
||||
import { ReferencesController } from 'vs/editor/contrib/referenceSearch/browser/referencesController';
|
||||
@@ -34,91 +33,17 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { PeekContext } from 'vs/editor/contrib/zoneWidget/browser/peekViewWidget';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ITextModelResolverService } from 'vs/editor/common/services/resolverService';
|
||||
import { MessageController } from './messageController';
|
||||
import * as corePosition from 'vs/editor/common/core/position';
|
||||
import ModeContextKeys = editorCommon.ModeContextKeys;
|
||||
import EditorContextKeys = editorCommon.EditorContextKeys;
|
||||
|
||||
class MessageOverlay implements IContentWidget {
|
||||
|
||||
private static _last: IDisposable;
|
||||
|
||||
static show(editor: ICodeEditor, pos: editorCommon.IPosition, message: string): void {
|
||||
|
||||
dispose(MessageOverlay._last);
|
||||
|
||||
const widget = new MessageOverlay(message, pos.lineNumber, editor.getOffsetForColumn(pos.lineNumber, pos.column));
|
||||
const remove = () => editor.removeContentWidget(widget);
|
||||
editor.addContentWidget(widget);
|
||||
|
||||
const listener = any<any>(
|
||||
filterEvent(editor.onMouseMove, e => {
|
||||
const { position } = e.target;
|
||||
return Math.abs(position.lineNumber - pos.lineNumber) > 1
|
||||
|| Math.abs(position.column - pos.column) > 10;
|
||||
}),
|
||||
editor.onDidChangeCursorPosition,
|
||||
editor.onDidBlurEditorText,
|
||||
editor.onDidDispose,
|
||||
editor.onDidChangeModel
|
||||
)(_ => {
|
||||
listener.dispose();
|
||||
remove();
|
||||
});
|
||||
|
||||
|
||||
MessageOverlay._last = {
|
||||
dispose() {
|
||||
listener.dispose();
|
||||
remove();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
readonly allowEditorOverflow = true;
|
||||
readonly suppressMouseDown = false;
|
||||
|
||||
private _position: editorCommon.IPosition;
|
||||
private _domNode: HTMLDivElement;
|
||||
|
||||
constructor(text: string, lineNumber: number, horizontalOffset: number) {
|
||||
this._position = { lineNumber, column: 1 };
|
||||
|
||||
this._domNode = document.createElement('div');
|
||||
this._domNode.style.paddingLeft = `${horizontalOffset - 6}px`;
|
||||
this._domNode.classList.add('monaco-editor-overlaymessage');
|
||||
|
||||
|
||||
const message = document.createElement('div');
|
||||
message.classList.add('message');
|
||||
message.textContent = text;
|
||||
this._domNode.appendChild(message);
|
||||
|
||||
const anchor = document.createElement('div');
|
||||
anchor.classList.add('anchor');
|
||||
this._domNode.appendChild(anchor);
|
||||
}
|
||||
|
||||
getId(): string {
|
||||
return 'messageoverlay';
|
||||
}
|
||||
|
||||
getDomNode(): HTMLElement {
|
||||
return this._domNode;
|
||||
}
|
||||
|
||||
getPosition(): IContentWidgetPosition {
|
||||
return { position: this._position, preference: [ContentWidgetPositionPreference.ABOVE] };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class DefinitionActionConfig {
|
||||
|
||||
constructor(
|
||||
public openToSide = false,
|
||||
public openInPeek = false,
|
||||
public filterCurrent = true,
|
||||
public noResultsMessage = nls.localize('generic.noResults', "No definition found")
|
||||
public filterCurrent = true
|
||||
) {
|
||||
//
|
||||
}
|
||||
@@ -164,7 +89,12 @@ export class DefinitionAction extends EditorAction {
|
||||
}
|
||||
|
||||
if (result.length === 0) {
|
||||
MessageOverlay.show(<ICodeEditor>editor, pos, this._configuration.noResultsMessage);
|
||||
const info = model.getWordAtPosition(pos);
|
||||
const message = info && info.word
|
||||
? nls.localize('noResultWord', "No definition found for '{0}'", info.word)
|
||||
: nls.localize('generic.noResults', "No definition found");
|
||||
|
||||
MessageController.get(editor).showMessage(message, pos);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-editor .monaco-editor-overlaymessage {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.monaco-editor .monaco-editor-overlaymessage .message {
|
||||
padding: 1px 4px;
|
||||
background: #1382CE;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.monaco-editor .monaco-editor-overlaymessage .anchor {
|
||||
width: 0 !important;
|
||||
height: 0 !important;
|
||||
border-color: transparent;
|
||||
border-style: solid;
|
||||
z-index: 1000;
|
||||
border-width: 8px;
|
||||
border-top-color: #1382CE;
|
||||
position: absolute;
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import 'vs/css!./messageController';
|
||||
import { any } from 'vs/base/common/event';
|
||||
import { setDisposableTimeout } from 'vs/base/common/async';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import { commonEditorContribution, CommonEditorRegistry, EditorCommand } from 'vs/editor/common/editorCommonExtensions';
|
||||
import { ICodeEditor, IContentWidget, IContentWidgetPosition, ContentWidgetPositionPreference } from 'vs/editor/browser/editorBrowser';
|
||||
import { IContextKeyService, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
|
||||
@commonEditorContribution
|
||||
export class MessageController {
|
||||
|
||||
private static _id = 'editor.contrib.messageController';
|
||||
|
||||
static CONTEXT_SNIPPET_MODE = new RawContextKey<boolean>('messageVisible', false);
|
||||
|
||||
static get(editor: editorCommon.ICommonCodeEditor): MessageController {
|
||||
return editor.getContribution<MessageController>(MessageController._id);
|
||||
}
|
||||
|
||||
getId(): string {
|
||||
return MessageController._id;
|
||||
}
|
||||
|
||||
private _editor: ICodeEditor;
|
||||
private _visible: IContextKey<boolean>;
|
||||
private _messageListeners: IDisposable[] = [];
|
||||
|
||||
constructor(
|
||||
editor: ICodeEditor,
|
||||
@IContextKeyService contextKeyService: IContextKeyService
|
||||
) {
|
||||
this._editor = editor;
|
||||
this._visible = MessageController.CONTEXT_SNIPPET_MODE.bindTo(contextKeyService);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this._visible.reset();
|
||||
}
|
||||
|
||||
showMessage(message: string, position: editorCommon.IPosition): void {
|
||||
|
||||
this._visible.set(true);
|
||||
this._messageListeners = dispose(this._messageListeners);
|
||||
this._messageListeners.push(new MessageWidget(this._editor, position, message));
|
||||
|
||||
// close on blur, cursor, model change, dispose
|
||||
this._messageListeners.push(any<any>(
|
||||
this._editor.onDidBlurEditorText,
|
||||
this._editor.onDidChangeCursorPosition,
|
||||
this._editor.onDidDispose,
|
||||
this._editor.onDidChangeModel
|
||||
)(this.closeMessage, this));
|
||||
|
||||
// close after 3s
|
||||
this._messageListeners.push(setDisposableTimeout(() => this.closeMessage(), 3000));
|
||||
|
||||
// close on mouse move
|
||||
let bounds: Range;
|
||||
this._messageListeners.push(this._editor.onMouseMove(e => {
|
||||
// outside the text area
|
||||
if (!e.target.position) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bounds) {
|
||||
// define bounding box around position and first mouse occurance
|
||||
bounds = new Range(position.lineNumber - 3, 1, e.target.position.lineNumber + 3, 1);
|
||||
} else if (!bounds.containsPosition(e.target.position)) {
|
||||
// check if position is still in bounds
|
||||
this.closeMessage();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
closeMessage(): void {
|
||||
this._visible.reset();
|
||||
this._messageListeners = dispose(this._messageListeners);
|
||||
}
|
||||
}
|
||||
|
||||
const MessageCommand = EditorCommand.bindToContribution<MessageController>(MessageController.get);
|
||||
|
||||
|
||||
CommonEditorRegistry.registerEditorCommand(new MessageCommand({
|
||||
id: 'leaveEditorMessage',
|
||||
precondition: MessageController.CONTEXT_SNIPPET_MODE,
|
||||
handler: c => c.closeMessage(),
|
||||
kbOpts: {
|
||||
weight: CommonEditorRegistry.commandWeight(30),
|
||||
primary: KeyCode.Escape
|
||||
}
|
||||
}));
|
||||
|
||||
class MessageWidget implements IContentWidget {
|
||||
|
||||
readonly allowEditorOverflow = true;
|
||||
readonly suppressMouseDown = false;
|
||||
|
||||
private _editor: ICodeEditor;
|
||||
private _position: editorCommon.IPosition;
|
||||
private _domNode: HTMLDivElement;
|
||||
|
||||
constructor(editor: ICodeEditor, { lineNumber, column }: editorCommon.IPosition, text: string) {
|
||||
|
||||
this._editor = editor;
|
||||
this._editor.revealLinesInCenterIfOutsideViewport(lineNumber, lineNumber);
|
||||
this._position = { lineNumber, column: 1 };
|
||||
|
||||
this._domNode = document.createElement('div');
|
||||
this._domNode.style.paddingLeft = `${editor.getOffsetForColumn(lineNumber, column) - 6}px`;
|
||||
this._domNode.classList.add('monaco-editor-overlaymessage');
|
||||
|
||||
const message = document.createElement('div');
|
||||
message.classList.add('message');
|
||||
message.textContent = text;
|
||||
this._domNode.appendChild(message);
|
||||
|
||||
const anchor = document.createElement('div');
|
||||
anchor.classList.add('anchor');
|
||||
this._domNode.appendChild(anchor);
|
||||
|
||||
this._editor.addContentWidget(this);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this._editor.removeContentWidget(this);
|
||||
}
|
||||
|
||||
getId(): string {
|
||||
return 'messageoverlay';
|
||||
}
|
||||
|
||||
getDomNode(): HTMLElement {
|
||||
return this._domNode;
|
||||
}
|
||||
|
||||
getPosition(): IContentWidgetPosition {
|
||||
return { position: this._position, preference: [ContentWidgetPositionPreference.ABOVE] };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user