import * as vscode from 'vscode';
import * as pl from './pylex';
/**
* @type {Object} Command // Command to register with the VS Code Extension API
* @prop {string} command // Name of the command; e.g., 'mind-reader.selectTheme'
* @prop {callback} callback // Callback to register when `command` is invoked
*/
type Command = {
name: string,
callback: () => void
};
// The list of commands to register in the extension
const commands: Command[] = [
{
name: 'mind-reader.selectTheme',
// callbacks can be inlined...
callback: () => vscode.commands.executeCommand('workbench.action.selectTheme'),
},
{
name: 'mind-reader.increaseFontScale',
callback: increaseFontScale, // ...or factored out into separate functions below
},
{
name: 'mind-reader.decreaseFontScale',
callback: decreaseFontScale,
},
{
name: 'mind-reader.resetFontScale',
callback: resetFontScale,
},
{
name: 'mind-reader.increaseEditorScale',
callback: increaseEditorScale,
},
{
name: 'mind-reader.decreaseEditorScale',
callback: decreaseEditorScale,
},
{
name: 'mind-reader.resetEditorScale',
callback: resetEditorScale,
},
{
name: 'mind-reader.openWebview',
callback: openWebview,
},
{
name: 'mind-reader.openKeyBindWin',
callback: openKeyBindWin,
},
{
name: 'mind-reader.openKeyBindMac',
callback: openKeyBindMac,
},
//Navigation Keys......
{
name: 'mind-reader.showAllSymbols',
callback: () => vscode.commands.executeCommand('workbench.action.showAllSymbols'),
},
{
name: 'mind-reader.gotoLine',
callback: () => vscode.commands.executeCommand('workbench.action.gotoLine'),
},
{
name: 'mind-reader.quickOpen',
callback: () => vscode.commands.executeCommand('workbench.action.quickOpen'),
},
{
name: 'mind-reader.gotoSymbol',
callback: () => vscode.commands.executeCommand('workbench.action.gotoSymbol'),
},
{
name: 'mind-reader.showProblems',
callback: () => vscode.commands.executeCommand('workbench.actions.view.problems'),
},
{
name: 'mind-reader.nextInFiles',
callback: () => vscode.commands.executeCommand('editor.action.marker.nextInFiles'),
},
{
name: 'mind-reader.prevInFiles',
callback: () => vscode.commands.executeCommand('editor.action.marker.prevInFiles'),
},
{
name: 'mind-reader.showCommands',
callback: () => vscode.commands.executeCommand('workbench.action.showCommands'),
},
{
name: 'mind-reader.quickOpenPreviousRecentlyUsedEditorInGroup',
callback: () => vscode.commands.executeCommand('workbench.action.quickOpenPreviousRecentlyUsedEditorInGroup'),
},
{
name: 'mind-reader.navigateBack',
callback: () => vscode.commands.executeCommand('workbench.action.navigateBack'),
},
{
name: 'mind-reader.getuickInputBack',
callback: () => vscode.commands.executeCommand('workbench.action.quickInputBack'),
},
{
name: 'mind-reader.navigateForward',
callback: () => vscode.commands.executeCommand('workbench.action.navigateForward'),
},
{
name: 'mind-reader.runLineContext',
callback: runLineContext,
},
{
name: 'mind-reader.runCursorContext',
callback: runCursorContext
},
{
name: 'mind-reader.getIndent',
callback: getIndent
}
];
// COMMAND CALLBACK IMPLEMENTATIONS
function increaseFontScale(): void {
vscode.commands.executeCommand('editor.action.fontZoomIn');
}
function decreaseFontScale(): void {
vscode.commands.executeCommand('editor.action.fontZoomOut');
}
function resetFontScale(): void {
vscode.commands.executeCommand('editor.action.fontZoomReset');
}
function increaseEditorScale(): void {
vscode.commands.executeCommand('workbench.action.zoomIn');
}
function decreaseEditorScale(): void {
vscode.commands.executeCommand('workbench.action.zoomOut');
}
function resetEditorScale(): void {
vscode.commands.executeCommand('workbench.action.zoomReset');
}
function openWebview(): void {
//vscode.commands.executeCommand('workbench.action.zoomOut');
const panel = vscode.window.createWebviewPanel(
'mindReader', // Identifies the type of the webview. Used internally
'Mind Reader', // Title of the panel displayed to the user
vscode.ViewColumn.One, // Editor column to show the new webview panel in.
{}
); // Webview options. More on these later.
panel.webview.html = getWebviewContent();
}
function getWebviewContent() {
return `
Mind Reader
Welcome to Mind_Reader!
We are the Single Semester Snobs and this is our tool to Help Blind Students Program Lego Mindstorms Robots in Python.
-
This tool includes features such as a hotkey that says how many spaces in the text starts, an Accessibility Pane,
Audio Alerts, and an advanced settings window.
The tool has hotkeys for both PC and Mac commands.
- This system is intended for everyone, but primarily for students K-12 who are visually impaired.
-
Our goal is to provide an enhanced experience for students who are visually impaired that is transparent to
sighted students.
This allows for everyone to use the same software solution, whether or not they are
vision impaired.
Use the following key binding to bring up a page for all key bindings for windows
Control and Shift and 8
Use this key binding to do the same for mac computers:
Command and Shift and 9
This is the Lego Spike Prime!
Get the robot!
`;
}
function openKeyBindWin(): void {
//vscode.commands.executeCommand('workbench.action.zoomOut');
const panel = vscode.window.createWebviewPanel(
'mindReader', // Identifies the type of the webview. Used internally
'MR Key Bindings', // Title of the panel displayed to the user
vscode.ViewColumn.One, // Editor column to show the new webview panel in.
{}
); // Webview options. More on these later.
panel.webview.html = getKeyBindWinContent();
}
function getKeyBindWinContent() {
return `
Mind Reader Key Bindings for Windows
Here is a list of all Mind Reader's commands and they're keybindings on windows and linux systems
Editor Settings
Increase Font Scale - Number Pad Add
Decrease Font Scale - Number Pad Subtract
Increase Editor Scale - Shift and Number Pad Add
Decrease Editor Scale - Shift and Number Pad Subtract
Reset Editor Scale - Shift and Enter
Select Theme - Control and Shift and 1
Navigation
Get Indent - Shift and Tab
Show All Symbols - Control and T
Go To Line - Control and G
Quick Open - Control and P
Go To Symbol - Control and Shift and 0
Show Problems - Control and Shift and M
Next In File - F8
Previous In File - Shift and F8
Open Previous Editor Group - Control and Tab
Navigate Forward - Control and Shift and Minus
Navigate Back - Control and Alt and Minus
Get Quick Input Back - Control and Alt and Minus
`;
}
function openKeyBindMac(): void {
//vscode.commands.executeCommand('workbench.action.zoomOut');
const panel = vscode.window.createWebviewPanel(
'mindReader', // Identifies the type of the webview. Used internally
'MR Key Bindings', // Title of the panel displayed to the user
vscode.ViewColumn.One, // Editor column to show the new webview panel in.
{}
); // Webview options. More on these later.
panel.webview.html = getKeyBindMacContent();
}
function getKeyBindMacContent() {
return `
Mind Reader Key Bindings for Mac
Here is a list of all the Mind Reader commands and they're keybindings on Mac systems
Editor Settings
Increase Font Scale -
Decrease Font Scale -
Increase Editor Scale -
Decrease Editor Scale -
Reset Editor Scale -
Select Theme -
Navigation
Get Indent -
Show All Symbols -
Go To Line -
Quick Open -
Go To Symbol -
Show Problems -
Next In File -
Previous In File -
Open Previous Editor Group -
Navigate Forward -
Navigate Back -
Get Quick Input Back -
`;
}
function getIndent(): void {
let editor = vscode.window.activeTextEditor;
if(editor)
{
let lineNum = editor.selection.active.line + 1;
let textLine = editor.document.lineAt(lineNum - 1);
if(textLine.isEmptyOrWhitespace)
{
vscode.window.showInformationMessage("Line number " + lineNum.toString() + " Is Empty");
}
else
{
// Grab tab format from open document
let tabFmt = {
size: editor.options.tabSize as number,
hard: !editor.options.insertSpaces
};
let i = pl.Lexer.getIndent(textLine.text, tabFmt);
vscode.window.showInformationMessage("Line Number " + lineNum.toString() + " Indentation " + i.toString());
}
}
else{
vscode.window.showErrorMessage('No document currently active');
}
}
function runLineContext(): void {
let editor = vscode.window.activeTextEditor;
if (editor){
// current text and line number
let editorText = editor.document.getText();
let line = editor.selection.active.line;
// get tab info settings
let size = parseInt(editor.options.tabSize as string);
let hard = !editor.options.insertSpaces;
// initialize parser
let parser = new pl.Parser(editorText, {size, hard});
parser.parse();
let context = parser.context(line);
// build text
let contentString = createContextString(context, line);
vscode.window.showInformationMessage(contentString);
} else {
vscode.window.showErrorMessage('No document currently active');
}
}
function createContextString(context: pl.LexNode[], line: number): string {
if (context.length < 1) {
throw new Error('Cannot create context string for empty context');
}
let contextString = 'Line ' + (line+1); // 1 based
if (context[0].token && context[0].token.attr) {
contextString += ': ' + context[0].token.type.toString() + ' ' + context[0].token.attr.toString();
}
for (let i = 1; i < context.length; i++) {
let node = context[i];
if (node.label === 'root') {
// root
contextString += ' in the Document Root';
continue;
}
if (node.token!.type !== pl.PylexSymbol.EMPTY &&
node.token!.type !== pl.PylexSymbol.INDENT) {
contextString += ' inside ' + node.token!.type.toString();
if (node.token!.attr) {
contextString += ' ' + node.token!.attr.toString();
}
}
}
return contextString;
}
// find up to `n` words around the cursor, where `n` is
// the value of `#mindreader.reader.contextWindow`
function runCursorContext(): void {
let editor = vscode.window.activeTextEditor;
if (!editor) {
vscode.window.showErrorMessage("RunCursorContext: No Active Editor");
return;
}
const cursorPos: vscode.Position = editor.selection.active;
const text: string = editor.document.lineAt(cursorPos).text;
const windowSize: number = vscode.workspace.getConfiguration('mindreader').get('reader.contextWindow')!;
let trimmedText = text.trimStart(); // trim leading whitespace
let leadingWS = text.length - trimmedText.length; // # of characters of leading whitespace
trimmedText = trimmedText.trimEnd(); // trim trailing whitespace
let pos = leadingWS;
let maxPos = text.length;
// clamp cursor start/end to new range
let col = cursorPos.character; // effective column of the cursor position
if (col < leadingWS) {
// move effective start to first non-whitespace character in the line
col = leadingWS;
} else if (col > leadingWS + trimmedText.length - 1) {
// move effective end to last non-whitespace character in the line
col = leadingWS + trimmedText.length - 1;
}
// generate list of space separate words with range data (start, end)
// TODO: can find user position to be done in one pass
let spaceWords: {word: string, start: number, end: number}[] = [];
while (pos < maxPos && trimmedText.length > 0) {
let word = trimmedText.replace(/ .*/, '');
spaceWords.push({word, start: pos, end: pos+word.length});
// remove processed word from trimmed text
const oldText = trimmedText;
trimmedText = trimmedText.replace(/[^ ]+/, '').trimStart();
// update pos to start of next word
pos += oldText.length - trimmedText.length;
}
// find word the user is in
let contextStart: number = -1, contextEnd: number = -1;
for (let i = 0; i < spaceWords.length; i++) {
if (col >= spaceWords[i].start && col <= spaceWords[i].end) {
// found the word
contextStart = Math.max(0, i - windowSize); // clamp start index
contextEnd = Math.min(spaceWords.length, i + windowSize + 1); // clamp end index
// construct cursor context string
let contextString = '';
for (let i = contextStart; i < contextEnd; i++) {
contextString += spaceWords[i].word + ' ';
}
// output cursor context string
vscode.window.showInformationMessage(contextString);
return;
}
}
}
export default commands;