SQL Operations Studio Public Preview 1 (0.23) release source code

This commit is contained in:
Karl Burtram
2017-11-09 14:30:27 -08:00
parent b88ecb8d93
commit 3cdac41339
8829 changed files with 759707 additions and 286 deletions

View File

@@ -0,0 +1,198 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as nls from 'vs/nls';
import * as arrays from 'vs/base/common/arrays';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { TPromise } from 'vs/base/common/winjs.base';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { Range } from 'vs/editor/common/core/range';
import { ICommonCodeEditor, IEditorContribution } from 'vs/editor/common/editorCommon';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { editorAction, ServicesAccessor, IActionOptions, EditorAction, commonEditorContribution } from 'vs/editor/common/editorCommonExtensions';
import { TokenSelectionSupport, ILogicalSelectionEntry } from './tokenSelectionSupport';
import { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
// --- selection state machine
class State {
public editor: ICommonCodeEditor;
public next: State;
public previous: State;
public selection: Range;
constructor(editor: ICommonCodeEditor) {
this.editor = editor;
this.next = null;
this.previous = null;
this.selection = editor.getSelection();
}
}
// --- shared state between grow and shrink actions
var state: State = null;
var ignoreSelection = false;
// -- action implementation
@commonEditorContribution
class SmartSelectController implements IEditorContribution {
private static ID = 'editor.contrib.smartSelectController';
public static get(editor: ICommonCodeEditor): SmartSelectController {
return editor.getContribution<SmartSelectController>(SmartSelectController.ID);
}
private _tokenSelectionSupport: TokenSelectionSupport;
constructor(
private editor: ICommonCodeEditor,
@IInstantiationService instantiationService: IInstantiationService
) {
this._tokenSelectionSupport = instantiationService.createInstance(TokenSelectionSupport);
}
public dispose(): void {
}
public getId(): string {
return SmartSelectController.ID;
}
public run(forward: boolean): TPromise<void> {
var selection = this.editor.getSelection();
var model = this.editor.getModel();
// forget about current state
if (state) {
if (state.editor !== this.editor) {
state = null;
}
}
var promise: TPromise<void> = TPromise.as(null);
if (!state) {
promise = this._tokenSelectionSupport.getRangesToPosition(model.uri, selection.getStartPosition()).then((elements: ILogicalSelectionEntry[]) => {
if (arrays.isFalsyOrEmpty(elements)) {
return;
}
var lastState: State;
elements.filter((element) => {
// filter ranges inside the selection
var selection = this.editor.getSelection();
var range = new Range(element.range.startLineNumber, element.range.startColumn, element.range.endLineNumber, element.range.endColumn);
return range.containsPosition(selection.getStartPosition()) && range.containsPosition(selection.getEndPosition());
}).forEach((element) => {
// create ranges
var range = element.range;
var state = new State(this.editor);
state.selection = new Range(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn);
if (lastState) {
state.next = lastState;
lastState.previous = state;
}
lastState = state;
});
// insert current selection
var editorState = new State(this.editor);
editorState.next = lastState;
if (lastState) {
lastState.previous = editorState;
}
state = editorState;
// listen to caret move and forget about state
var unhook = this.editor.onDidChangeCursorPosition((e: ICursorPositionChangedEvent) => {
if (ignoreSelection) {
return;
}
state = null;
unhook.dispose();
});
});
}
return promise.then(() => {
if (!state) {
return;
}
state = forward ? state.next : state.previous;
if (!state) {
return;
}
ignoreSelection = true;
try {
this.editor.setSelection(state.selection);
} finally {
ignoreSelection = false;
}
return;
});
}
}
abstract class AbstractSmartSelect extends EditorAction {
private _forward: boolean;
constructor(forward: boolean, opts: IActionOptions) {
super(opts);
this._forward = forward;
}
public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): TPromise<void> {
let controller = SmartSelectController.get(editor);
if (controller) {
return controller.run(this._forward);
}
return undefined;
}
}
@editorAction
class GrowSelectionAction extends AbstractSmartSelect {
constructor() {
super(true, {
id: 'editor.action.smartSelect.grow',
label: nls.localize('smartSelect.grow', "Expand Select"),
alias: 'Expand Select',
precondition: null,
kbOpts: {
kbExpr: EditorContextKeys.textFocus,
primary: KeyMod.Shift | KeyMod.Alt | KeyCode.RightArrow,
mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyMod.Shift | KeyCode.RightArrow }
}
});
}
}
@editorAction
class ShrinkSelectionAction extends AbstractSmartSelect {
constructor() {
super(false, {
id: 'editor.action.smartSelect.shrink',
label: nls.localize('smartSelect.shrink', "Shrink Select"),
alias: 'Shrink Select',
precondition: null,
kbOpts: {
kbExpr: EditorContextKeys.textFocus,
primary: KeyMod.Shift | KeyMod.Alt | KeyCode.LeftArrow,
mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyMod.Shift | KeyCode.LeftArrow }
}
});
}
}

View File

@@ -0,0 +1,70 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import URI from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { Range } from 'vs/editor/common/core/range';
import { IModel } from 'vs/editor/common/editorCommon';
import { IModelService } from 'vs/editor/common/services/modelService';
import { Node, build, find } from './tokenTree';
import { Position } from 'vs/editor/common/core/position';
/**
* Interface used to compute a hierachry of logical ranges.
*/
export interface ILogicalSelectionEntry {
type: string;
range: Range;
}
export class TokenSelectionSupport {
private _modelService: IModelService;
constructor( @IModelService modelService: IModelService) {
this._modelService = modelService;
}
public getRangesToPosition(resource: URI, position: Position): TPromise<ILogicalSelectionEntry[]> {
return TPromise.as(this.getRangesToPositionSync(resource, position));
}
public getRangesToPositionSync(resource: URI, position: Position): ILogicalSelectionEntry[] {
var model = this._modelService.getModel(resource),
entries: ILogicalSelectionEntry[] = [];
if (model) {
this._doGetRangesToPosition(model, position).forEach(range => {
entries.push({
type: void 0,
range
});
});
}
return entries;
}
private _doGetRangesToPosition(model: IModel, position: Position): Range[] {
var tree = build(model),
node: Node,
lastRange: Range;
node = find(tree, position);
var ranges: Range[] = [];
while (node) {
if (!lastRange || !Range.equalsRange(lastRange, node.range)) {
ranges.push(node.range);
}
lastRange = node.range;
node = node.parent;
}
ranges = ranges.reverse();
return ranges;
}
}

View File

@@ -0,0 +1,425 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
import { IModel } from 'vs/editor/common/editorCommon';
import { LineToken } from 'vs/editor/common/core/lineTokens';
import { ignoreBracketsInToken } from 'vs/editor/common/modes/supports';
import { BracketsUtils, RichEditBrackets } from 'vs/editor/common/modes/supports/richEditBrackets';
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
import { LanguageId, StandardTokenType } from 'vs/editor/common/modes';
export const enum TokenTreeBracket {
None = 0,
Open = 1,
Close = -1
}
export class Node {
start: Position;
end: Position;
get range(): Range {
return new Range(
this.start.lineNumber,
this.start.column,
this.end.lineNumber,
this.end.column
);
}
parent: Node;
}
export class NodeList extends Node {
children: Node[];
get start(): Position {
return this.hasChildren
? this.children[0].start
: this.parent.start;
}
get end(): Position {
return this.hasChildren
? this.children[this.children.length - 1].end
: this.parent.end;
}
get hasChildren() {
return this.children && this.children.length > 0;
}
get isEmpty() {
return !this.hasChildren && !this.parent;
}
public append(node: Node): boolean {
if (!node) {
return false;
}
node.parent = this;
if (!this.children) {
this.children = [];
}
if (node instanceof NodeList) {
if (node.children) {
this.children.push.apply(this.children, node.children);
}
} else {
this.children.push(node);
}
return true;
}
}
export class Block extends Node {
open: Node;
close: Node;
elements: NodeList;
get start(): Position {
return this.open.start;
}
get end(): Position {
return this.close.end;
}
constructor() {
super();
this.elements = new NodeList();
this.elements.parent = this;
}
}
class Token {
_tokenBrand: void;
readonly range: Range;
readonly bracket: TokenTreeBracket;
readonly bracketType: string;
constructor(range: Range, bracket: TokenTreeBracket, bracketType: string) {
this.range = range;
this.bracket = bracket;
this.bracketType = bracketType;
}
}
function newNode(token: Token): Node {
var node = new Node();
node.start = token.range.getStartPosition();
node.end = token.range.getEndPosition();
return node;
}
class RawToken {
_basicTokenBrand: void;
public lineNumber: number;
public lineText: string;
public startOffset: number;
public endOffset: number;
public type: StandardTokenType;
public languageId: LanguageId;
constructor(source: LineToken, lineNumber: number, lineText: string) {
this.lineNumber = lineNumber;
this.lineText = lineText;
this.startOffset = source.startOffset;
this.endOffset = source.endOffset;
this.type = source.tokenType;
this.languageId = source.languageId;
}
}
class ModelRawTokenScanner {
private _model: IModel;
private _lineCount: number;
private _versionId: number;
private _lineNumber: number;
private _lineText: string;
private _next: LineToken;
constructor(model: IModel) {
this._model = model;
this._lineCount = this._model.getLineCount();
this._versionId = this._model.getVersionId();
this._lineNumber = 0;
this._lineText = null;
this._advance();
}
private _advance(): void {
this._next = (this._next ? this._next.next() : null);
while (!this._next && this._lineNumber < this._lineCount) {
this._lineNumber++;
this._lineText = this._model.getLineContent(this._lineNumber);
this._model.forceTokenization(this._lineNumber);
let currentLineTokens = this._model.getLineTokens(this._lineNumber);
this._next = currentLineTokens.firstToken();
}
}
public next(): RawToken {
if (!this._next) {
return null;
}
if (this._model.getVersionId() !== this._versionId) {
return null;
}
let result = new RawToken(this._next, this._lineNumber, this._lineText);
this._advance();
return result;
}
}
class TokenScanner {
private _rawTokenScanner: ModelRawTokenScanner;
private _nextBuff: Token[];
private _cachedLanguageBrackets: RichEditBrackets;
private _cachedLanguageId: LanguageId;
constructor(model: IModel) {
this._rawTokenScanner = new ModelRawTokenScanner(model);
this._nextBuff = [];
this._cachedLanguageBrackets = null;
this._cachedLanguageId = -1;
}
next(): Token {
if (this._nextBuff.length > 0) {
return this._nextBuff.shift();
}
const token = this._rawTokenScanner.next();
if (!token) {
return null;
}
const lineNumber = token.lineNumber;
const lineText = token.lineText;
const tokenType = token.type;
let startOffset = token.startOffset;
const endOffset = token.endOffset;
if (this._cachedLanguageId !== token.languageId) {
this._cachedLanguageId = token.languageId;
this._cachedLanguageBrackets = LanguageConfigurationRegistry.getBracketsSupport(this._cachedLanguageId);
}
const modeBrackets = this._cachedLanguageBrackets;
if (!modeBrackets || ignoreBracketsInToken(tokenType)) {
return new Token(
new Range(lineNumber, startOffset + 1, lineNumber, endOffset + 1),
TokenTreeBracket.None,
null
);
}
let foundBracket: Range;
do {
foundBracket = BracketsUtils.findNextBracketInToken(modeBrackets.forwardRegex, lineNumber, lineText, startOffset, endOffset);
if (foundBracket) {
const foundBracketStartOffset = foundBracket.startColumn - 1;
const foundBracketEndOffset = foundBracket.endColumn - 1;
if (startOffset < foundBracketStartOffset) {
// there is some text before this bracket in this token
this._nextBuff.push(new Token(
new Range(lineNumber, startOffset + 1, lineNumber, foundBracketStartOffset + 1),
TokenTreeBracket.None,
null
));
}
let bracketText = lineText.substring(foundBracketStartOffset, foundBracketEndOffset);
bracketText = bracketText.toLowerCase();
const bracketData = modeBrackets.textIsBracket[bracketText];
const bracketIsOpen = modeBrackets.textIsOpenBracket[bracketText];
this._nextBuff.push(new Token(
new Range(lineNumber, foundBracketStartOffset + 1, lineNumber, foundBracketEndOffset + 1),
bracketIsOpen ? TokenTreeBracket.Open : TokenTreeBracket.Close,
`${bracketData.languageIdentifier.language};${bracketData.open};${bracketData.close}`
));
startOffset = foundBracketEndOffset;
}
} while (foundBracket);
if (startOffset < endOffset) {
// there is some remaining none-bracket text in this token
this._nextBuff.push(new Token(
new Range(lineNumber, startOffset + 1, lineNumber, endOffset + 1),
TokenTreeBracket.None,
null
));
}
return this._nextBuff.shift();
}
}
class TokenTreeBuilder {
private _scanner: TokenScanner;
private _stack: Token[] = [];
private _currentToken: Token;
constructor(model: IModel) {
this._scanner = new TokenScanner(model);
}
public build(): Node {
var node = new NodeList();
while (node.append(this._line() || this._any())) {
// accept all
}
return node;
}
private _accept(condt: (info: Token) => boolean): boolean {
var token = this._stack.pop() || this._scanner.next();
if (!token) {
return false;
}
var accepted = condt(token);
if (!accepted) {
this._stack.push(token);
this._currentToken = null;
} else {
this._currentToken = token;
// console.log('accepted: ' + token.__debugContent);
}
return accepted;
}
private _peek(condt: (info: Token) => boolean): boolean {
var ret = false;
this._accept(info => {
ret = condt(info);
return false;
});
return ret;
}
private _line(): Node {
var node = new NodeList(),
lineNumber: number;
// capture current linenumber
this._peek(info => {
lineNumber = info.range.startLineNumber;
return false;
});
while (this._peek(info => info.range.startLineNumber === lineNumber)
&& node.append(this._token() || this._block())) {
// all children that started on this line
}
if (!node.children || node.children.length === 0) {
return null;
} else if (node.children.length === 1) {
return node.children[0];
} else {
return node;
}
}
private _token(): Node {
if (!this._accept(token => token.bracket === TokenTreeBracket.None)) {
return null;
}
return newNode(this._currentToken);
}
private _block(): Node {
var bracketType: string,
accepted: boolean;
accepted = this._accept(token => {
bracketType = token.bracketType;
return token.bracket === TokenTreeBracket.Open;
});
if (!accepted) {
return null;
}
var bracket = new Block();
bracket.open = newNode(this._currentToken);
while (bracket.elements.append(this._line())) {
// inside brackets
}
if (!this._accept(token => token.bracket === TokenTreeBracket.Close && token.bracketType === bracketType)) {
// missing closing bracket -> return just a node list
var nodelist = new NodeList();
nodelist.append(bracket.open);
nodelist.append(bracket.elements);
return nodelist;
}
bracket.close = newNode(this._currentToken);
return bracket;
}
private _any(): Node {
if (!this._accept(_ => true)) {
return null;
}
return newNode(this._currentToken);
}
}
/**
* Parses this grammar:
* grammer = { line }
* line = { block | "token" }
* block = "open_bracket" { line } "close_bracket"
*/
export function build(model: IModel): Node {
var node = new TokenTreeBuilder(model).build();
return node;
}
export function find(node: Node, position: Position): Node {
if (node instanceof NodeList && node.isEmpty) {
return null;
}
if (!Range.containsPosition(node.range, position)) {
return null;
}
var result: Node;
if (node instanceof NodeList) {
if (node.hasChildren) {
for (var i = 0, len = node.children.length; i < len && !result; i++) {
result = find(node.children[i], position);
}
}
} else if (node instanceof Block) {
result = find(node.open, position) || find(node.elements, position) || find(node.close, position);
}
return result || node;
}

View File

@@ -0,0 +1,118 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import URI from 'vs/base/common/uri';
import { Range } from 'vs/editor/common/core/range';
import { Position } from 'vs/editor/common/core/position';
import { LanguageIdentifier } from 'vs/editor/common/modes';
import { IndentAction } from 'vs/editor/common/modes/languageConfiguration';
import { TokenSelectionSupport } from 'vs/editor/contrib/smartSelect/common/tokenSelectionSupport';
import { MockMode } from 'vs/editor/test/common/mocks/mockMode';
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
class MockJSMode extends MockMode {
private static _id = new LanguageIdentifier('mockJSMode', 3);
constructor() {
super(MockJSMode._id);
this._register(LanguageConfigurationRegistry.register(this.getLanguageIdentifier(), {
brackets: [
['(', ')'],
['{', '}'],
['[', ']']
],
onEnterRules: [
{
// e.g. /** | */
beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,
afterText: /^\s*\*\/$/,
action: { indentAction: IndentAction.IndentOutdent, appendText: ' * ' }
},
{
// e.g. /** ...|
beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,
action: { indentAction: IndentAction.None, appendText: ' * ' }
},
{
// e.g. * ...|
beforeText: /^(\t|(\ \ ))*\ \*(\ ([^\*]|\*(?!\/))*)?$/,
action: { indentAction: IndentAction.None, appendText: '* ' }
},
{
// e.g. */|
beforeText: /^(\t|(\ \ ))*\ \*\/\s*$/,
action: { indentAction: IndentAction.None, removeText: 1 }
},
{
// e.g. *-----*/|
beforeText: /^(\t|(\ \ ))*\ \*[^/]*\*\/\s*$/,
action: { indentAction: IndentAction.None, removeText: 1 }
}
]
}));
}
}
suite('TokenSelectionSupport', () => {
let modelService: ModelServiceImpl = null;
let tokenSelectionSupport: TokenSelectionSupport;
let mode: MockJSMode = null;
setup(() => {
modelService = new ModelServiceImpl(null, new TestConfigurationService());
tokenSelectionSupport = new TokenSelectionSupport(modelService);
mode = new MockJSMode();
});
teardown(() => {
modelService.dispose();
mode.dispose();
});
function assertGetRangesToPosition(text: string[], lineNumber: number, column: number, ranges: Range[]): void {
let uri = URI.file('test.js');
modelService.createModel(text.join('\n'), mode, uri);
let actual = tokenSelectionSupport.getRangesToPositionSync(uri, new Position(lineNumber, column));
let actualStr = actual.map(r => new Range(r.range.startLineNumber, r.range.startColumn, r.range.endLineNumber, r.range.endColumn).toString());
let desiredStr = ranges.map(r => String(r));
assert.deepEqual(actualStr, desiredStr);
modelService.destroyModel(uri);
}
test('getRangesToPosition #1', () => {
assertGetRangesToPosition([
'function a(bar, foo){',
'\tif (bar) {',
'\t\treturn (bar + (2 * foo))',
'\t}',
'}'
], 3, 20, [
new Range(1, 1, 5, 2),
new Range(1, 21, 5, 2),
new Range(2, 1, 4, 3),
new Range(2, 11, 4, 3),
new Range(3, 1, 4, 2),
new Range(3, 1, 3, 27),
new Range(3, 10, 3, 27),
new Range(3, 11, 3, 26),
new Range(3, 17, 3, 26),
new Range(3, 18, 3, 25),
// new Range(3, 19, 3, 20)
]);
});
});