Archived
1
0

Merge commit 'be3e8236086165e5e45a5a10783823874b3f3ebd' as 'lib/vscode'

This commit is contained in:
Joe Previte
2020-12-15 15:52:33 -07:00
4649 changed files with 1311795 additions and 0 deletions

View File

@ -0,0 +1,6 @@
src/**
out/**
tsconfig.json
extension.webpack.config.js
extension-browser.webpack.config.js
yarn.lock

View File

@ -0,0 +1,5 @@
# Language Features for Search Result files
**Notice:** This extension is bundled with Visual Studio Code. It can be disabled but not uninstalled.
This extension provides Syntax Highlighting, Symbol Information, Result Highlighting, and Go to Definition capabilities for the Search Results Editor.

View File

@ -0,0 +1,22 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
//@ts-check
'use strict';
const withBrowserDefaults = require('../shared.webpack.config').browser;
const path = require('path');
module.exports = withBrowserDefaults({
context: __dirname,
entry: {
extension: './src/extension.ts'
},
output: {
filename: 'extension.js',
path: path.join(__dirname, 'dist')
}
});

View File

@ -0,0 +1,20 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
//@ts-check
'use strict';
const withDefaults = require('../shared.webpack.config');
module.exports = withDefaults({
context: __dirname,
resolve: {
mainFields: ['module', 'main']
},
entry: {
extension: './src/extension.ts',
}
});

View File

@ -0,0 +1,48 @@
{
"name": "search-result",
"displayName": "%displayName%",
"description": "%description%",
"version": "1.0.0",
"publisher": "vscode",
"license": "MIT",
"engines": {
"vscode": "^1.39.0"
},
"categories": [
"Programming Languages"
],
"main": "./out/extension.js",
"browser": "./dist/extension.js",
"activationEvents": [
"*"
],
"scripts": {
"generate-grammar": "node ./syntaxes/generateTMLanguage.js",
"vscode:prepublish": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:search-result ./tsconfig.json"
},
"contributes": {
"configurationDefaults": {
"[search-result]": {
"editor.lineNumbers": "off"
}
},
"languages": [
{
"id": "search-result",
"extensions": [
".code-search"
],
"aliases": [
"Search Result"
]
}
],
"grammars": [
{
"language": "search-result",
"scopeName": "text.searchResult",
"path": "./syntaxes/searchResult.tmLanguage.json"
}
]
}
}

View File

@ -0,0 +1,4 @@
{
"displayName": "Search Result",
"description": "Provides syntax highlighting and language features for tabbed search results."
}

View File

@ -0,0 +1,235 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import * as pathUtils from 'path';
const FILE_LINE_REGEX = /^(\S.*):$/;
const RESULT_LINE_REGEX = /^(\s+)(\d+)(:| )(\s+)(.*)$/;
const SEARCH_RESULT_SELECTOR = { language: 'search-result' };
const DIRECTIVES = ['# Query:', '# Flags:', '# Including:', '# Excluding:', '# ContextLines:'];
const FLAGS = ['RegExp', 'CaseSensitive', 'IgnoreExcludeSettings', 'WordMatch'];
let cachedLastParse: { version: number, parse: ParsedSearchResults, uri: vscode.Uri } | undefined;
let documentChangeListener: vscode.Disposable | undefined;
export function activate(context: vscode.ExtensionContext) {
const contextLineDecorations = vscode.window.createTextEditorDecorationType({ opacity: '0.7' });
const matchLineDecorations = vscode.window.createTextEditorDecorationType({ fontWeight: 'bold' });
const decorate = (editor: vscode.TextEditor) => {
const parsed = parseSearchResults(editor.document).filter(isResultLine);
const contextRanges = parsed.filter(line => line.isContext).map(line => line.prefixRange);
const matchRanges = parsed.filter(line => !line.isContext).map(line => line.prefixRange);
editor.setDecorations(contextLineDecorations, contextRanges);
editor.setDecorations(matchLineDecorations, matchRanges);
};
if (vscode.window.activeTextEditor && vscode.window.activeTextEditor.document.languageId === 'search-result') {
decorate(vscode.window.activeTextEditor);
}
context.subscriptions.push(
vscode.languages.registerDocumentSymbolProvider(SEARCH_RESULT_SELECTOR, {
provideDocumentSymbols(document: vscode.TextDocument, token: vscode.CancellationToken): vscode.DocumentSymbol[] {
const results = parseSearchResults(document, token)
.filter(isFileLine)
.map(line => new vscode.DocumentSymbol(
line.path,
'',
vscode.SymbolKind.File,
line.allLocations.map(({ originSelectionRange }) => originSelectionRange!).reduce((p, c) => p.union(c), line.location.originSelectionRange!),
line.location.originSelectionRange!,
));
return results;
}
}),
vscode.languages.registerCompletionItemProvider(SEARCH_RESULT_SELECTOR, {
provideCompletionItems(document: vscode.TextDocument, position: vscode.Position): vscode.CompletionItem[] {
const line = document.lineAt(position.line);
if (position.line > 3) { return []; }
if (position.character === 0 || (position.character === 1 && line.text === '#')) {
const header = Array.from({ length: DIRECTIVES.length }).map((_, i) => document.lineAt(i).text);
return DIRECTIVES
.filter(suggestion => header.every(line => line.indexOf(suggestion) === -1))
.map(flag => ({ label: flag, insertText: (flag.slice(position.character)) + ' ' }));
}
if (line.text.indexOf('# Flags:') === -1) { return []; }
return FLAGS
.filter(flag => line.text.indexOf(flag) === -1)
.map(flag => ({ label: flag, insertText: flag + ' ' }));
}
}, '#'),
vscode.languages.registerDefinitionProvider(SEARCH_RESULT_SELECTOR, {
provideDefinition(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): vscode.DefinitionLink[] {
const lineResult = parseSearchResults(document, token)[position.line];
if (!lineResult) { return []; }
if (lineResult.type === 'file') {
return lineResult.allLocations;
}
const translateRangeSidewaysBy = (r: vscode.Range, n: number) =>
r.with({ start: new vscode.Position(r.start.line, Math.max(0, n - r.start.character)), end: new vscode.Position(r.end.line, Math.max(0, n - r.end.character)) });
return [{
...lineResult.location,
targetSelectionRange: translateRangeSidewaysBy(lineResult.location.targetSelectionRange!, position.character - 1)
}];
}
}),
vscode.languages.registerDocumentLinkProvider(SEARCH_RESULT_SELECTOR, {
async provideDocumentLinks(document: vscode.TextDocument, token: vscode.CancellationToken): Promise<vscode.DocumentLink[]> {
return parseSearchResults(document, token)
.filter(({ type }) => type === 'file')
.map(({ location }) => ({ range: location.originSelectionRange!, target: location.targetUri }));
}
}),
vscode.window.onDidChangeActiveTextEditor(editor => {
if (editor?.document.languageId === 'search-result') {
// Clear the parse whenever we open a new editor.
// Conservative because things like the URI might remain constant even if the contents change, and re-parsing even large files is relatively fast.
cachedLastParse = undefined;
documentChangeListener?.dispose();
documentChangeListener = vscode.workspace.onDidChangeTextDocument(doc => {
if (doc.document.uri === editor.document.uri) {
decorate(editor);
}
});
decorate(editor);
}
}),
{ dispose() { cachedLastParse = undefined; documentChangeListener?.dispose(); } }
);
}
function relativePathToUri(path: string, resultsUri: vscode.Uri): vscode.Uri | undefined {
if (pathUtils.isAbsolute(path)) {
return vscode.Uri
.file(path)
.with({ scheme: process.env.HOME ? 'file' : 'vscode-userdata' });
}
if (path.indexOf('~/') === 0) {
return vscode.Uri
.file(pathUtils.join(process.env.HOME ?? '', path.slice(2)))
.with({ scheme: process.env.HOME ? 'file' : 'vscode-userdata' });
}
const uriFromFolderWithPath = (folder: vscode.WorkspaceFolder, path: string): vscode.Uri =>
vscode.Uri.joinPath(folder.uri, path);
if (vscode.workspace.workspaceFolders) {
const multiRootFormattedPath = /^(.*) • (.*)$/.exec(path);
if (multiRootFormattedPath) {
const [, workspaceName, workspacePath] = multiRootFormattedPath;
const folder = vscode.workspace.workspaceFolders.filter(wf => wf.name === workspaceName)[0];
if (folder) {
return uriFromFolderWithPath(folder, workspacePath);
}
}
else if (vscode.workspace.workspaceFolders.length === 1) {
return uriFromFolderWithPath(vscode.workspace.workspaceFolders[0], path);
} else if (resultsUri.scheme !== 'untitled') {
// We're in a multi-root workspace, but the path is not multi-root formatted
// Possibly a saved search from a single root session. Try checking if the search result document's URI is in a current workspace folder.
const prefixMatch = vscode.workspace.workspaceFolders.filter(wf => resultsUri.toString().startsWith(wf.uri.toString()))[0];
if (prefixMatch) {
return uriFromFolderWithPath(prefixMatch, path);
}
}
}
console.error(`Unable to resolve path ${path}`);
return undefined;
}
type ParsedSearchFileLine = { type: 'file', location: vscode.LocationLink, allLocations: vscode.LocationLink[], path: string };
type ParsedSearchResultLine = { type: 'result', location: vscode.LocationLink, isContext: boolean, prefixRange: vscode.Range };
type ParsedSearchResults = Array<ParsedSearchFileLine | ParsedSearchResultLine>;
const isFileLine = (line: ParsedSearchResultLine | ParsedSearchFileLine): line is ParsedSearchFileLine => line.type === 'file';
const isResultLine = (line: ParsedSearchResultLine | ParsedSearchFileLine): line is ParsedSearchResultLine => line.type === 'result';
function parseSearchResults(document: vscode.TextDocument, token?: vscode.CancellationToken): ParsedSearchResults {
if (cachedLastParse && cachedLastParse.uri === document.uri && cachedLastParse.version === document.version) {
return cachedLastParse.parse;
}
const lines = document.getText().split(/\r?\n/);
const links: ParsedSearchResults = [];
let currentTarget: vscode.Uri | undefined = undefined;
let currentTargetLocations: vscode.LocationLink[] | undefined = undefined;
for (let i = 0; i < lines.length; i++) {
// TODO: This is probably always false, given we're pegging the thread...
if (token?.isCancellationRequested) { return []; }
const line = lines[i];
const fileLine = FILE_LINE_REGEX.exec(line);
if (fileLine) {
const [, path] = fileLine;
currentTarget = relativePathToUri(path, document.uri);
if (!currentTarget) { continue; }
currentTargetLocations = [];
const location: vscode.LocationLink = {
targetRange: new vscode.Range(0, 0, 0, 1),
targetUri: currentTarget,
originSelectionRange: new vscode.Range(i, 0, i, line.length),
};
links[i] = { type: 'file', location, allLocations: currentTargetLocations, path };
}
if (!currentTarget) { continue; }
const resultLine = RESULT_LINE_REGEX.exec(line);
if (resultLine) {
const [, indentation, _lineNumber, seperator, resultIndentation] = resultLine;
const lineNumber = +_lineNumber - 1;
const resultStart = (indentation + _lineNumber + seperator + resultIndentation).length;
const metadataOffset = (indentation + _lineNumber + seperator).length;
const location: vscode.LocationLink = {
targetRange: new vscode.Range(Math.max(lineNumber - 3, 0), 0, lineNumber + 3, line.length),
targetSelectionRange: new vscode.Range(lineNumber, metadataOffset, lineNumber, metadataOffset),
targetUri: currentTarget,
originSelectionRange: new vscode.Range(i, resultStart, i, line.length),
};
currentTargetLocations?.push(location);
links[i] = { type: 'result', location, isContext: seperator === ' ', prefixRange: new vscode.Range(i, 0, i, metadataOffset) };
}
}
cachedLastParse = {
version: document.version,
parse: links,
uri: document.uri
};
return links;
}

View File

@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.56253 2.51577C3.46348 3.4501 2 5.55414 2 7.99999C2 11.3137 4.68629 14 8 14C11.3137 14 14 11.3137 14 7.99999C14 5.32519 12.2497 3.05919 9.83199 2.28482L9.52968 3.23832C11.5429 3.88454 13 5.7721 13 7.99999C13 10.7614 10.7614 13 8 13C5.23858 13 3 10.7614 3 7.99999C3 6.31104 3.83742 4.81767 5.11969 3.91245L5.56253 2.51577Z" fill="#C5C5C5"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M5 3H2V2H5.5L6 2.5V6H5V3Z" fill="#C5C5C5"/>
</svg>

After

Width:  |  Height:  |  Size: 587 B

View File

@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.56253 2.51577C3.46348 3.4501 2 5.55414 2 7.99999C2 11.3137 4.68629 14 8 14C11.3137 14 14 11.3137 14 7.99999C14 5.32519 12.2497 3.05919 9.83199 2.28482L9.52968 3.23832C11.5429 3.88454 13 5.7721 13 7.99999C13 10.7614 10.7614 13 8 13C5.23858 13 3 10.7614 3 7.99999C3 6.31104 3.83742 4.81767 5.11969 3.91245L5.56253 2.51577Z" fill="#424242"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M5 3H2V2H5.5L6 2.5V6H5V3Z" fill="#424242"/>
</svg>

After

Width:  |  Height:  |  Size: 587 B

View File

@ -0,0 +1,7 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/// <reference path='../../../../src/vs/vscode.d.ts'/>
/// <reference path='../../../../src/vs/vscode.proposed.d.ts'/>

View File

@ -0,0 +1,240 @@
// @ts-check
const mappings = [
['bat', 'source.batchfile'],
['c', 'source.c'],
['clj', 'source.clojure'],
['coffee', 'source.coffee'],
['cpp', 'source.cpp', '\\.(?:cpp|c\\+\\+|cc|cxx|hxx|h\\+\\+|hh)'],
['cs', 'source.cs'],
['cshtml', 'text.html.cshtml'],
['css', 'source.css'],
['dart', 'source.dart'],
['diff', 'source.diff'],
['dockerfile', 'source.dockerfile', '(?:dockerfile|Dockerfile|containerfile|Containerfile)'],
['fs', 'source.fsharp'],
['go', 'source.go'],
['groovy', 'source.groovy'],
['h', 'source.objc'],
['handlebars', 'text.html.handlebars', '\\.(?:handlebars|hbs)'],
['hlsl', 'source.hlsl'],
['hpp', 'source.objcpp'],
['html', 'text.html.basic'],
['ini', 'source.ini'],
['java', 'source.java'],
['js', 'source.js'],
['json', 'source.json.comments'],
['jsx', 'source.js.jsx'],
['less', 'source.css.less'],
['log', 'text.log'],
['lua', 'source.lua'],
['m', 'source.objc'],
['makefile', 'source.makefile', '(?:makefile|Makefile)(?:\\..*)?'],
['md', 'text.html.markdown'],
['mm', 'source.objcpp'],
['p6', 'source.perl.6'],
['perl', 'source.perl', '\\.(?:perl|pl|pm)'],
['php', 'source.php'],
['ps1', 'source.powershell'],
['pug', 'text.pug'],
['py', 'source.python'],
['r', 'source.r'],
['rb', 'source.ruby'],
['rs', 'source.rust'],
['scala', 'source.scala'],
['scss', 'source.css.scss'],
['sh', 'source.shell'],
['sql', 'source.sql'],
['swift', 'source.swift'],
['ts', 'source.ts'],
['tsx', 'source.tsx'],
['vb', 'source.asp.vb.net'],
['xml', 'text.xml'],
['yaml', 'source.yaml', '\\.(?:ya?ml)'],
];
const scopes = {
root: 'text.searchResult',
header: {
meta: 'meta.header.search keyword.operator.word.search',
key: 'entity.other.attribute-name',
value: 'entity.other.attribute-value string.unquoted',
flags: {
keyword: 'keyword.other',
},
contextLines: {
number: 'constant.numeric.integer',
invalid: 'invalid.illegal',
},
query: {
escape: 'constant.character.escape',
invalid: 'invalid.illegal',
}
},
resultBlock: {
meta: 'meta.resultBlock.search',
path: {
meta: 'string meta.path.search',
dirname: 'meta.path.dirname.search',
basename: 'meta.path.basename.search',
colon: 'punctuation.separator',
},
result: {
meta: 'meta.resultLine.search',
metaSingleLine: 'meta.resultLine.singleLine.search',
metaMultiLine: 'meta.resultLine.multiLine.search',
prefix: {
meta: 'constant.numeric.integer meta.resultLinePrefix.search',
metaContext: 'meta.resultLinePrefix.contextLinePrefix.search',
metaMatch: 'meta.resultLinePrefix.matchLinePrefix.search',
lineNumber: 'meta.resultLinePrefix.lineNumber.search',
colon: 'punctuation.separator',
}
}
}
};
const repository = {};
mappings.forEach(([ext, scope, regexp]) =>
repository[ext] = {
name: scopes.resultBlock.meta,
begin: `^(?!\\s)(.*?)([^\\\\\\/\\n]*${regexp || `\\.${ext}`})(:)$`,
end: '^(?!\\s)',
beginCaptures: {
'0': { name: scopes.resultBlock.path.meta },
'1': { name: scopes.resultBlock.path.dirname },
'2': { name: scopes.resultBlock.path.basename },
'3': { name: scopes.resultBlock.path.colon },
},
patterns: [
{
name: [scopes.resultBlock.result.meta, scopes.resultBlock.result.metaMultiLine].join(' '),
begin: '^ (?:\\s*)((\\d+) )',
while: '^ (?:\\s*)(?:((\\d+)(:))|((\\d+) ))',
beginCaptures: {
'0': { name: scopes.resultBlock.result.prefix.meta },
'1': { name: scopes.resultBlock.result.prefix.metaContext },
'2': { name: scopes.resultBlock.result.prefix.lineNumber },
},
whileCaptures: {
'0': { name: scopes.resultBlock.result.prefix.meta },
'1': { name: scopes.resultBlock.result.prefix.metaMatch },
'2': { name: scopes.resultBlock.result.prefix.lineNumber },
'3': { name: scopes.resultBlock.result.prefix.colon },
'4': { name: scopes.resultBlock.result.prefix.metaContext },
'5': { name: scopes.resultBlock.result.prefix.lineNumber },
},
patterns: [{ include: scope }]
},
{
begin: '^ (?:\\s*)((\\d+)(:))',
while: '(?=not)possible',
name: [scopes.resultBlock.result.meta, scopes.resultBlock.result.metaSingleLine].join(' '),
beginCaptures: {
'0': { name: scopes.resultBlock.result.prefix.meta },
'1': { name: scopes.resultBlock.result.prefix.metaMatch },
'2': { name: scopes.resultBlock.result.prefix.lineNumber },
'3': { name: scopes.resultBlock.result.prefix.colon },
},
patterns: [{ include: scope }]
}
]
});
const header = [
{
begin: '^(# Query): ',
end: '\n',
name: scopes.header.meta,
beginCaptures: { '1': { name: scopes.header.key }, },
patterns: [
{
match: '(\\\\n)|(\\\\\\\\)',
name: [scopes.header.value, scopes.header.query.escape].join(' ')
},
{
match: '\\\\.|\\\\$',
name: [scopes.header.value, scopes.header.query.invalid].join(' ')
},
{
match: '[^\\\\\\\n]+',
name: [scopes.header.value].join(' ')
},
]
},
{
begin: '^(# Flags): ',
end: '\n',
name: scopes.header.meta,
beginCaptures: { '1': { name: scopes.header.key }, },
patterns: [
{
match: '(RegExp|CaseSensitive|IgnoreExcludeSettings|WordMatch)',
name: [scopes.header.value, 'keyword.other'].join(' ')
},
{ match: '.' },
]
},
{
begin: '^(# ContextLines): ',
end: '\n',
name: scopes.header.meta,
beginCaptures: { '1': { name: scopes.header.key }, },
patterns: [
{
match: '\\d',
name: [scopes.header.value, scopes.header.contextLines.number].join(' ')
},
{ match: '.', name: scopes.header.contextLines.invalid },
]
},
{
match: '^(# (?:Including|Excluding)): (.*)$',
name: scopes.header.meta,
captures: {
'1': { name: scopes.header.key },
'2': { name: scopes.header.value }
}
},
];
const plainText = [
{
match: '^(?!\\s)(.*?)([^\\\\\\/\\n]*)(:)$',
name: [scopes.resultBlock.meta, scopes.resultBlock.path.meta].join(' '),
captures: {
'1': { name: scopes.resultBlock.path.dirname },
'2': { name: scopes.resultBlock.path.basename },
'3': { name: scopes.resultBlock.path.colon }
}
},
{
match: '^ (?:\\s*)(?:((\\d+)(:))|((\\d+)( ))(.*))',
name: [scopes.resultBlock.meta, scopes.resultBlock.result.meta].join(' '),
captures: {
'1': { name: [scopes.resultBlock.result.prefix.meta, scopes.resultBlock.result.prefix.metaMatch].join(' ') },
'2': { name: scopes.resultBlock.result.prefix.lineNumber },
'3': { name: scopes.resultBlock.result.prefix.colon },
'4': { name: [scopes.resultBlock.result.prefix.meta, scopes.resultBlock.result.prefix.metaContext].join(' ') },
'5': { name: scopes.resultBlock.result.prefix.lineNumber },
}
}
];
const tmLanguage = {
'information_for_contributors': 'This file is generated from ./generateTMLanguage.js.',
name: 'Search Results',
scopeName: scopes.root,
patterns: [
...header,
...mappings.map(([ext]) => ({ include: `#${ext}` })),
...plainText
],
repository
};
require('fs').writeFileSync(
require('path').join(__dirname, './searchResult.tmLanguage.json'),
JSON.stringify(tmLanguage, null, 2));

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,9 @@
{
"extends": "../shared.tsconfig.json",
"compilerOptions": {
"outDir": "./out",
},
"include": [
"src/**/*"
]
}

View File

@ -0,0 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1