Permalink
Browse files

First attempt at symbol navigation within zoneinfo files

  • Loading branch information...
gilmoreorless committed Aug 21, 2017
1 parent eb0262b commit e9485b3e9774592124419deff41afffba439b2a4
Showing with 277 additions and 25 deletions.
  1. +18 −0 .editorconfig
  2. +2 −0 .gitignore
  3. +16 −1 .vscode/launch.json
  4. +9 −0 .vscode/settings.json
  5. +30 −0 .vscode/tasks.json
  6. +8 −0 .vscodeignore
  7. +23 −23 language-configuration.json
  8. +18 −1 package.json
  9. +93 −0 src/extension.ts
  10. +22 −0 test/extension.test.ts
  11. +22 −0 test/index.ts
  12. +16 −0 tsconfig.json
@@ -0,0 +1,18 @@
# http://EditorConfig.org
root = true
[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 2
insert_final_newline = true
[*.tmLanguage]
indent_size = 4
indent_style = tab
[.vscode/*.json]
indent_size = 4
indent_style = tab
@@ -0,0 +1,2 @@
out
node_modules
@@ -10,7 +10,22 @@
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": ["--extensionDevelopmentPath=${workspaceRoot}" ]
"args": ["--extensionDevelopmentPath=${workspaceRoot}" ],
"stopOnEntry": false,
"sourceMaps": true,
"outFiles": ["${workspaceRoot}/out/src/**/*.js"],
"preLaunchTask": "npm"
},
{
"name": "Launch Tests",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/out/test" ],
"stopOnEntry": false,
"sourceMaps": true,
"outFiles": [ "${workspaceRoot}/out/test/**/*.js" ],
"preLaunchTask": "npm"
}
]
}
@@ -0,0 +1,9 @@
// Place your settings in this file to overwrite default and user settings.
{
"files.exclude": {
"out": false // set this to true to hide the "out" folder with the compiled JS files
},
"search.exclude": {
"out": true // set this to false to include "out" folder in search results
}
}
@@ -0,0 +1,30 @@
// Available variables which can be used inside of strings.
// ${workspaceRoot}: the root folder of the team
// ${file}: the current opened file
// ${fileBasename}: the current opened file's basename
// ${fileDirname}: the current opened file's dirname
// ${fileExtname}: the current opened file's extension
// ${cwd}: the current working directory of the spawned process
// A task runner that calls a custom npm script that compiles the extension.
{
"version": "0.1.0",
// we want to run npm
"command": "npm",
// the command is a shell script
"isShellCommand": true,
// show the output window only if unrecognized errors occur.
"showOutput": "silent",
// we run the custom script "compile" as defined in package.json
"args": ["run", "compile", "--loglevel", "silent"],
// The tsc compiler is started in watching mode
"isBackground": true,
// use the standard tsc in watch mode problem matcher to find compile problems in the output.
"problemMatcher": "$tsc-watch"
}
@@ -1 +1,9 @@
.editorconfig
.gitignore
.vscode/**
.vscode-test/**
out/test/**
test/**
src/**
**/*.map
tsconfig.json
@@ -1,24 +1,24 @@
{
"comments": {
"lineComment": "#"
},
"brackets": [
["{", "}"],
["[", "]"],
["(", ")"]
],
"autoClosingPairs": [
["{", "}"],
["[", "]"],
["(", ")"],
["\"", "\""],
["'", "'"]
],
"surroundingPairs": [
["{", "}"],
["[", "]"],
["(", ")"],
["\"", "\""],
["'", "'"]
]
}
"comments": {
"lineComment": "#"
},
"brackets": [
["{", "}"],
["[", "]"],
["(", ")"]
],
"autoClosingPairs": [
["{", "}"],
["[", "]"],
["(", ")"],
["\"", "\""],
["'", "'"]
],
"surroundingPairs": [
["{", "}"],
["[", "]"],
["(", ")"],
["\"", "\""],
["'", "'"]
]
}
@@ -22,6 +22,10 @@
"url": "https://github.com/gilmoreorless/vscode-zoneinfo.git"
},
"homepage": "https://github.com/gilmoreorless/vscode-zoneinfo/blob/master/README.md",
"main": "./out/src/extension",
"activationEvents": [
"onLanguage:zoneinfo"
],
"contributes": {
"languages": [{
"id": "zoneinfo",
@@ -60,5 +64,18 @@
"editor.tabSize": 8
}
}
},
"scripts": {
"vscode:prepublish": "tsc -p ./",
"compile": "tsc -watch -p ./",
"postinstall": "node ./node_modules/vscode/bin/install",
"test": "node ./node_modules/vscode/bin/test"
},
"devDependencies": {
"typescript": "^2.0.3",
"vscode": "^1.0.0",
"mocha": "^2.3.3",
"@types/node": "^6.0.40",
"@types/mocha": "^2.2.32"
}
}
}
@@ -0,0 +1,93 @@
'use strict';
import * as vscode from 'vscode';
const ZONEINFO_MODE: vscode.DocumentSelector = 'zoneinfo';
export function activate(context: vscode.ExtensionContext) {
let disposable = vscode.languages.registerDocumentSymbolProvider(
ZONEINFO_MODE, new ZoneinfoDocumentSymbolProvider());
context.subscriptions.push(disposable);
}
export function deactivate() {}
const rValidLine = /^(Zone|Rule|Link)/;
const rWhitespace = /(\s+)/;
function sumLengths(arr: string[], beforeIndex: number) {
return arr.slice(0, beforeIndex).reduce((sum, str) => sum + str.length, 0);
}
type parsedSymbol = {
type: string,
name: string,
parent?: string,
index: number,
}
class ZoneinfoDocumentSymbolProvider implements vscode.DocumentSymbolProvider {
public parseLine(line: string): parsedSymbol {
if (!rValidLine.test(line)) {
return null;
}
const parts = line.split(rWhitespace);
const type = parts[0];
if (type === 'Zone' || type === 'Rule') {
return {
type,
name: parts[2],
index: sumLengths(parts, 2)
};
}
if (type === 'Link') {
return {
type,
name: parts[4],
parent: `Link(${parts[2]})`,
index: sumLengths(parts, 4)
}
}
return null;
}
public provideDocumentSymbols(
document: vscode.TextDocument, token: vscode.CancellationToken
): vscode.ProviderResult<vscode.SymbolInformation[]> {
const lineCount = document.lineCount;
let symbols = [];
let used = new Set();
for (let i = 0; i < lineCount; i++) {
let line = document.lineAt(i);
// Skip comments and empty lines
if (line.isEmptyOrWhitespace || line.text.indexOf('#') === 0) {
continue;
}
let match = this.parseLine(line.text);
if (match) {
// Don't add duplicate Rule definitions
let key = [match.type, match.name].join(':');
if (used.has(key)) {
continue;
}
used.add(key);
// Find the symbol's position
let range = new vscode.Range(
i, match.index,
i, match.index + match.name.length
);
symbols.push(new vscode.SymbolInformation(
match.name, vscode.SymbolKind.Field, match.parent || match.type,
new vscode.Location(document.uri, range)
));
}
}
return symbols;
}
}
@@ -0,0 +1,22 @@
//
// Note: This example test is leveraging the Mocha test framework.
// Please refer to their documentation on https://mochajs.org/ for help.
//
// The module 'assert' provides assertion methods from node
import * as assert from 'assert';
// You can import and use all API from the 'vscode' module
// as well as import your extension to test it
import * as vscode from 'vscode';
import * as myExtension from '../src/extension';
// Defines a Mocha test suite to group tests of similar kind together
suite("Extension Tests", () => {
// Defines a Mocha unit test
test("Something 1", () => {
assert.equal(-1, [1, 2, 3].indexOf(5));
assert.equal(-1, [1, 2, 3].indexOf(0));
});
});
@@ -0,0 +1,22 @@
//
// PLEASE DO NOT MODIFY / DELETE UNLESS YOU KNOW WHAT YOU ARE DOING
//
// This file is providing the test runner to use when running extension tests.
// By default the test runner in use is Mocha based.
//
// You can provide your own test runner if you want to override it by exporting
// a function run(testRoot: string, clb: (error:Error) => void) that the extension
// host can call to run the tests. The test runner is expected to use console.log
// to report the results back to the caller. When the tests are finished, return
// a possible error to the callback or null if none.
var testRunner = require('vscode/lib/testrunner');
// You can directly control Mocha options by uncommenting the following lines
// See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options for more info
testRunner.configure({
ui: 'tdd', // the TDD UI is being used in extension.test.ts (suite, test, etc.)
useColors: true // colored output from test results
});
module.exports = testRunner;
@@ -0,0 +1,16 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"outDir": "out",
"lib": [
"es6"
],
"sourceMap": true,
"rootDir": "."
},
"exclude": [
"node_modules",
".vscode-test"
]
}

0 comments on commit e9485b3

Please sign in to comment.