Skip to content

Commit

Permalink
First attempt at symbol navigation within zoneinfo files
Browse files Browse the repository at this point in the history
  • Loading branch information
gilmoreorless committed Aug 21, 2017
1 parent eb0262b commit e9485b3
Show file tree
Hide file tree
Showing 12 changed files with 277 additions and 25 deletions.
18 changes: 18 additions & 0 deletions .editorconfig
@@ -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
2 changes: 2 additions & 0 deletions .gitignore
@@ -0,0 +1,2 @@
out
node_modules
17 changes: 16 additions & 1 deletion .vscode/launch.json
Expand Up @@ -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"
}
]
}
9 changes: 9 additions & 0 deletions .vscode/settings.json
@@ -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
}
}
30 changes: 30 additions & 0 deletions .vscode/tasks.json
@@ -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"
}
8 changes: 8 additions & 0 deletions .vscodeignore
@@ -1 +1,9 @@
.editorconfig
.gitignore
.vscode/**
.vscode-test/**
out/test/**
test/**
src/**
**/*.map
tsconfig.json
46 changes: 23 additions & 23 deletions language-configuration.json
@@ -1,24 +1,24 @@
{
"comments": {
"lineComment": "#"
},
"brackets": [
["{", "}"],
["[", "]"],
["(", ")"]
],
"autoClosingPairs": [
["{", "}"],
["[", "]"],
["(", ")"],
["\"", "\""],
["'", "'"]
],
"surroundingPairs": [
["{", "}"],
["[", "]"],
["(", ")"],
["\"", "\""],
["'", "'"]
]
}
"comments": {
"lineComment": "#"
},
"brackets": [
["{", "}"],
["[", "]"],
["(", ")"]
],
"autoClosingPairs": [
["{", "}"],
["[", "]"],
["(", ")"],
["\"", "\""],
["'", "'"]
],
"surroundingPairs": [
["{", "}"],
["[", "]"],
["(", ")"],
["\"", "\""],
["'", "'"]
]
}
19 changes: 18 additions & 1 deletion package.json
Expand Up @@ -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",
Expand Down Expand Up @@ -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"
}
}
}
93 changes: 93 additions & 0 deletions src/extension.ts
@@ -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;
}
}
22 changes: 22 additions & 0 deletions test/extension.test.ts
@@ -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));
});
});
22 changes: 22 additions & 0 deletions test/index.ts
@@ -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;
16 changes: 16 additions & 0 deletions tsconfig.json
@@ -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.