srs_extension/extension.js (305 lines of code) (raw):

/* global JSON */ // The module 'vscode' contains the VS Code extensibility API // Import the module and reference it with the alias vscode in your code below var path = require('path'); var FS = require('fs'); var vscode = require('vscode'); var reqParser = require('./reqparser.js'); var ADD_NEW_PREFIX = "Add New Prefix..."; // this method is called when your extension is activated // your extension is activated the very first time the command is executed function activate(context) { var devId = loadDevId(); var reqPrefix = ""; var setDevId = function (id) { if(id && id.trim().length > 0) { devId = id; saveDevId(id); return true; } return false; }; var setReqPrefix = function (prefix) { if(!!prefix) { if(prefix === ADD_NEW_PREFIX) { return vscode.window.showInputBox({ placeHolder: 'New requirement prefix', prompt: 'Enter the new requirement prefix to use' }) .then(function(newPrefix) { if(!!newPrefix) { reqPrefix = newPrefix; return true; } return false; }); } else { reqPrefix = prefix; return true; } } return false; }; var askDevId = function () { return vscode.window.showInputBox({ prompt: "Please enter your dev id" }); }; var loadText = function () { var text = ""; if (vscode.window.activeTextEditor) { text = vscode.window.activeTextEditor.document.getText(); } else { vscode.window.showErrorMessage('File not loaded. Please open a file in the editor first.'); } return text; }; var lookupReqPrefix = function () { if (reqPrefix) return; var text = loadText(); if (text) { var prefixes = reqParser.getPrefixes(text); if(!prefixes || prefixes.length === 0) { return vscode.window.showInputBox({ prompt: "Please enter the requirement tag to use" }). then(setReqPrefix); } else if (prefixes.length === 1) { setReqPrefix(prefixes[0]); return; } else { return vscode.window.showQuickPick(prefixes) .then(setReqPrefix); } } }; var insertReqTag = function () { var text = loadText(); if (text) { var reqTag = reqParser.getNextReq(text, reqPrefix, devId); var editor = vscode.window.activeTextEditor; var startSnippet = '**' + reqTag + ': [** '; var endSnippet = ' **]**'; return editor.edit(function (e) { // insert start snippet e.insert(editor.selection.start, startSnippet); }).then(function(status) { if(status) { // insert end snippet return editor.edit(function(e) { e.insert(editor.selection.end, endSnippet); }); } return status; }).then(function(status) { if(status) { // move caret to end of line before endSnippet var pos = editor.selection.end.translate(0, -1 * endSnippet.length); editor.selection = new vscode.Selection(pos, pos); } return status; }); } else { return editor.edit(function (e) {}).then(function(status) { return status; }); } }; var insertReqTags = function () { var text = loadText(); if (text) { var nextReqTag = reqParser.getNextReq(text, reqPrefix, devId); var editor = vscode.window.activeTextEditor; var document = editor.document; var endSnippet = ' **]**'; var rangesToEdit = new Array(); var positionIterator = editor.selection.start; var stopLine = editor.selection.end.line; while (positionIterator.line <= stopLine) { var line = document.lineAt(positionIterator); // Attempt to add requirement to each line if (!line.isEmptyOrWhitespace) { // Skip markdown list and white space around it var startOffset = line.firstNonWhitespaceCharacterIndex; while (line.text.charAt(startOffset) == '-' || line.text.charAt(startOffset) == ' ') { startOffset++; } if (line.text.charAt(startOffset) != '\n' && line.text.charAt(startOffset) != '\r') { var lineStart = positionIterator.translate(0, startOffset); rangesToEdit.push(lineStart); } } positionIterator = positionIterator.with(positionIterator.line + 1, 0); } var task = null; rangesToEdit.forEach(function (value, index, array){ var doInsertStart = function (e) { // insert start snippet var startSnippet = '**' + nextReqTag + ': [** '; nextReqTag = reqParser.getNextReq(nextReqTag, reqPrefix, devId); e.insert(value, startSnippet); }; var doInsertEnd = function (e) { // recompute line end (after inserting start) and insert end var line = document.lineAt(value); var lineEnd = value.with(value.line, line.text.length); e.insert(lineEnd, endSnippet); }; // Insert start if (task == null) { task = editor.edit(doInsertStart); } else { task = task.then(function(status) { if (status) { return editor.edit(doInsertStart); } return status; }); } // Insert end task = task.then(function(status) { if (status) { return editor.edit(doInsertEnd); } return status; }); }); if (task == null) { return editor.edit(function (e) {}).then(function(status) { return status; }); } else { return task.then(function(status) { return status; }); } } else { return editor.edit(function (e) {}).then(function(status) { return status; }); } }; var stripReqTags = function () { var text = loadText(); if (text) { var editor = vscode.window.activeTextEditor; var document = editor.document; // Matches SRS requirements var regexStartRequirements = /\*\*[A-Z0-9_: \[\]]*\*\* ?/g; var regexEndRequirements = / ?\*\*\]\*\* ?/g; var rangesWithReqTags = new Array(); var positionIterator = editor.selection.start; var stopLine = editor.selection.end.line; while (positionIterator.line <= stopLine) { var line = document.lineAt(positionIterator); // Attempt to remove requirement from each line if (!line.isEmptyOrWhitespace) { var lineStart = positionIterator; var startMatches = line.text.match(regexStartRequirements); if (startMatches != null) { startMatches.forEach(function (value, index, array){ var start = line.text.indexOf(value); var end = start + value.length; rangesWithReqTags.push(new vscode.Range(lineStart.translate(0, start), lineStart.translate(0, end))); }); } var endMatches = line.text.match(regexEndRequirements); if (endMatches != null) { endMatches.forEach(function (value, index, array){ var start = line.text.indexOf(value); var end = start + value.length; rangesWithReqTags.push(new vscode.Range(lineStart.translate(0, start), lineStart.translate(0, end))); }); } } positionIterator = positionIterator.with(positionIterator.line + 1, 0); } var task = null; if (rangesWithReqTags.length != 0) { rangesWithReqTags.reverse().forEach(function (value, index, array){ var doRemove = function (e) { // remove the tags e.delete(value); }; if (task == null) { task = editor.edit(doRemove); } else { task = task.then(function(status) { if (status) { return editor.edit(doRemove); } return status; }); } }); } if (task == null) { return editor.edit(function (e) {}).then(function(status) { return status; }); } else { return task.then(function(status) { return status; }); } } else { return editor.edit(function (e) {}).then(function(status) { return status; }); } }; var insertReqCommand = vscode.commands.registerCommand('extension.insertReqCommand', function () { if (devId === "") { return askDevId().then(setDevId) .then(lookupReqPrefix) .then(insertReqTag); } else { var prefixPromise = lookupReqPrefix(); if (prefixPromise) { return prefixPromise.then(insertReqTag); } else { return insertReqTag(); } } }); var insertReqsCommand = vscode.commands.registerCommand('extension.insertReqsCommand', function () { if (devId === "") { return askDevId().then(setDevId) .then(lookupReqPrefix) .then(insertReqTags); } else { var prefixPromise = lookupReqPrefix(); if (prefixPromise) { return prefixPromise.then(insertReqTags); } else { return insertReqTags(); } } }); var stripReqsCommand = vscode.commands.registerCommand('extension.stripReqsCommand', function () { return stripReqTags(); }); var changeDevIdCommand = vscode.commands.registerCommand('extension.changeDevId', function () { askDevId().then(setDevId); }); var changeReqPrefixCommand = vscode.commands.registerCommand('extension.changeReqPrefix', function () { var text = loadText(); var prefixes = reqParser.getPrefixes(text); prefixes.push(ADD_NEW_PREFIX); vscode.window.showQuickPick(prefixes) .then(setReqPrefix); }); // Test hook var forceSetDevIdCommand = vscode.commands.registerCommand('extension.forceSetDevId', function (id) { setDevId(id); }); var forceSetReqPrefixCommand = vscode.commands.registerCommand('extension.forceSetReqPrefix', function (prefix) { setReqPrefix(prefix); }); context.subscriptions.push(insertReqCommand); context.subscriptions.push(insertReqsCommand); context.subscriptions.push(stripReqsCommand); context.subscriptions.push(changeDevIdCommand); context.subscriptions.push(changeReqPrefixCommand); // Expose commands for test that don't need UI context.subscriptions.push(forceSetDevIdCommand); context.subscriptions.push(forceSetReqPrefixCommand); } // from: http://stackoverflow.com/a/9081436 function getUserHome() { return process.env[(process.platform == 'win32') ? 'USERPROFILE' : 'HOME']; } function saveDevId(devid) { var settingsPath = path.join(getUserHome(), '.reqdocs'); var settings = {}; if(FS.existsSync(settingsPath)) { var settingString = FS.readFileSync(settingsPath, { encoding: 'utf8' }); if(settingString) { settings = JSON.parse(settingString); } } settings.devid = devid; FS.writeFileSync(settingsPath, JSON.stringify(settings), { encoding: 'utf8' }); } function loadDevId() { var settingsPath = path.join(getUserHome(), '.reqdocs'); var settings = null; if(FS.existsSync(settingsPath)) { settings = FS.readFileSync(settingsPath, { encoding: 'utf8' }); if(settings) { settings = JSON.parse(settings); } } return (settings && settings.devid) || ''; } exports.activate = activate;