Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge with betterWhiteSpace #2

Merged
merged 1 commit into from
May 25, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 0 additions & 34 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,6 @@
"type": "object",
"title": "WhiteViz Configurations",
"properties": {
"whiteviz.visualizeOnlyIndentation": {
"type": "boolean",
"default": false,
"description": "Visualize whitespaces only at the beginning of the line."
},
"whiteviz.color.dark": {
"type": "string",
"default": "rgba(180, 180, 180, 0.75)",
Expand All @@ -50,35 +45,6 @@
"type": "string",
"default": "rgba(0, 0, 0, 0.75)",
"description": "Indicator color for light themes."
},
"whiteviz.spacePattern": {
"type": "string",
"pattern": "^.+$",
"default": " \u00A0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u200B\u200C\u200D\u2060",
"description": "A set of characters to match whitespace characters."
},
"whiteviz.tabPattern": {
"type": "string",
"pattern": "^.+$",
"default": "\t",
"description": "A set of characters to match tab characters."
},
"whiteviz.spaceIndicator": {
"type": "string",
"pattern": "^.$",
"default": "·",
"description": "Space indicator symbol."
},
"whiteviz.tabIndicator": {
"type": "string",
"pattern": "^.$",
"default": "→",
"description": "Tab indicator symbol."
},
"whiteviz.overrideDefault": {
"type": "boolean",
"default": false,
"description": "Suppress suggestions / detections toward default Visual Studio Code settings."
}
}
}
Expand Down
250 changes: 103 additions & 147 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,25 @@
import * as vscode from "vscode";

export function activate(context: vscode.ExtensionContext) {
let whiteViz = new WhiteViz();
context.subscriptions.push(whiteViz);
context.subscriptions.push(new WhiteVizController(whiteViz));
const whiteSpace = new WhiteSpace();
context.subscriptions.push(whiteSpace);
context.subscriptions.push(new WhiteSpaceController(whiteSpace));
}

class WhiteVizController {
private whiteViz: WhiteViz;
class WhiteSpaceController {
private whiteSpace: WhiteSpace;
private disposable: vscode.Disposable;
private lastLine: number = undefined;

constructor(whiteViz: WhiteViz){
this.whiteViz = whiteViz;
constructor(whiteSpace: WhiteSpace){
this.whiteSpace = whiteSpace;

let subscriptions: vscode.Disposable[] = [];
vscode.workspace.onDidChangeConfiguration(() => {
this.whiteViz.updateConfigurations();
}, this, subscriptions);
vscode.window.onDidChangeTextEditorSelection((event) => {
this.whiteViz.updateEditor(event.textEditor);
const subscriptions: vscode.Disposable[] = [];

vscode.workspace.onDidChangeConfiguration(this.whiteSpace.updateConfigurations, this, subscriptions);

vscode.window.onDidChangeTextEditorSelection(event => {
this.whiteSpace.updateEditor(event.textEditor);
});

this.disposable = vscode.Disposable.from(...subscriptions);
Expand All @@ -31,12 +31,22 @@ class WhiteVizController {
}
}

class WhiteViz {
private whitespaceDecoration?: vscode.TextEditorDecorationType;
class WhiteSpace {
private editorTabSize = -1; // tbd

private spaceDecoration?: vscode.TextEditorDecorationType;
private spacePattern = /[ ]|\u00A0|\u2000|\u2001|\u2002|\u2003|\u2004|\u2005|\u2006|\u2007|\u2008|\u2009|\u200A|\u202F|\u205F|\u3000|\u200B|\u200C|\u200D|\u2060/;
private spaceIndicator = "·";
private spaceMargin = "0 -1ch 0 0";
private spaceWidth = "1ch"

private tabDecoration?: vscode.TextEditorDecorationType;
private spacePattern = " ";
private tabPattern = "\t";
private visualizeOnlyIndentation = false;
private tabPattern = /\t/;
private tabIndicator = ""; // tbd later based on tabSize
private tabMargin = ""; // tbd later based on tabSize

private tabWidth = ""

private overrideDefault = false;
private disableExtension = false;

Expand All @@ -45,181 +55,127 @@ class WhiteViz {
}

dispose(){
if (this.whitespaceDecoration) {
this.whitespaceDecoration.dispose();
if (this.spaceDecoration) {
this.spaceDecoration.dispose();
}
if (this.tabDecoration) {
this.tabDecoration.dispose();
}
}

updateConfigurations(){
updateConfigurations() {
this.clearDecorations();

let configurations = vscode.workspace.getConfiguration("whiteviz");
this.overrideDefault = configurations.get<boolean>("overrideDefault");

let editorConfigurations = vscode.workspace.getConfiguration("editor");
let renderWhitespace = editorConfigurations.get<string>(
"renderWhitespace"
);

this.disableExtension = (
!this.overrideDefault && renderWhitespace !== "none"
);

let editorConfig = vscode.workspace.getConfiguration("editor");
let renderWhitespace = editorConfig.get("renderWhitespace");
this.disableExtension = !this.overrideDefault && renderWhitespace !== "none";
if (this.disableExtension) {
vscode.window.showInformationMessage(
`WhiteViz detected that you set "editor.renderWhitespace" to "${
renderWhitespace
}". The extension will now disabled.`
);
vscode.window.showInformationMessage(`WhiteSpace detected that you set "editor.renderWhitespace" to "${renderWhitespace}". The extension will now disabled.`);
}
this.editorTabSize = parseInt(editorConfig.get<string>("tabSize"));
this.tabMargin = `0 -${this.editorTabSize}ch 0 0`;
this.tabWidth = `${this.editorTabSize}ch`;
this.tabIndicator = this.editorTabSize % 4 === 0
? "⸻".repeat(this.editorTabSize / 4)
: this.editorTabSize % 2 === 0
? "⸺"
: "—";

const darkColor = configurations.get("color.dark", configurations.get("color"));
const lightColor = configurations.get("color.light", configurations.get("color"));
const emDashFont = "'Source Sans Pro'";

const config = color => type => ({
before: {
contentText: this[`${type}Indicator`],
margin: this[`${type}Margin`],
width: this[`${type}Width`],
color: color,
textDecoration: `none; font-family: ${emDashFont}; text-align: center`
}
})

this.visualizeOnlyIndentation = configurations.get<boolean>(
"visualizeOnlyIndentation"
);
let spaceIndicator = configurations.get<string>("spaceIndicator");
let tabIndicator = configurations.get<string>("tabIndicator");

let darkColor = configurations.get<string>(
"color.dark", configurations.get<string>("color")
);
let lightColor = configurations.get<string>(
"color.light", configurations.get<string>("color")
);

this.spacePattern = configurations.get<string>(
"spacePattern"
);
this.tabPattern = configurations.get<string>("tabPattern");

let margin = "0ch -1ch 0ch 0ch";

this.whitespaceDecoration = (
vscode.window.createTextEditorDecorationType(
{
light: {
before: {
contentText: spaceIndicator,
margin: margin,
color: lightColor
}
},
dark: {
before: {
contentText: spaceIndicator,
margin: margin,
color: darkColor
}
}
}
)
);
this.tabDecoration = (
vscode.window.createTextEditorDecorationType(
{
light: {
before: {
contentText: tabIndicator,
margin: margin,
color: lightColor
}
},
dark: {
before: {
contentText: tabIndicator,
margin: margin,
color: darkColor
}
}
}
)
);
const [lightConfig, darkConfig] = [config(lightColor), config(darkColor)];

if (!this.disableExtension) {
["space", "tab"].forEach(t => {
this[`${t}Decoration`] = vscode.window.createTextEditorDecorationType({
light: lightConfig(t),
dark: darkConfig(t)
});
});
if (!this.disableExtension)
this.updateDecorations();
}
}

clearDecorations(){
vscode.window.visibleTextEditors.forEach(this.clearEditor, this);
}

clearEditor(editor: vscode.TextEditor){
if (this.whitespaceDecoration) {
editor.setDecorations(this.whitespaceDecoration, []);
if (this.spaceDecoration) {
editor.setDecorations(this.spaceDecoration, []);
}
if (this.tabDecoration) {
editor.setDecorations(this.tabDecoration, []);
}
}

updateDecorations(){
if (!this.whitespaceDecoration || this.disableExtension) {
if (!this.spaceDecoration || this.disableExtension) {
this.clearDecorations();
return;
}
vscode.window.visibleTextEditors.forEach(this.updateEditor, this);
}

updateEditor(editor: vscode.TextEditor){
if (!this.whitespaceDecoration || this.disableExtension) {
if (!this.spaceDecoration || this.disableExtension) {
this.clearEditor(editor);
return;
}

let whitespaceRanges: vscode.Range[] = [];
let tabRanges: vscode.Range[] = [];
editor.selections.forEach((selection) => {
if (selection.isEmpty) {

editor.selections.forEach(selection => {
if (selection.isEmpty)
return;
}

let firstLine = selection.start.line;
let firstCharacter = selection.start.character;
let lastLine = selection.end.line;
let lastCharacter = selection.end.character;
let currentLine = firstLine;
while (currentLine <= lastLine) {
let line = editor.document.lineAt(currentLine);

let character = (
currentLine === firstLine ? firstCharacter : 0
);
let lineText = line.text;
let lineLength = (
currentLine === lastLine ? lastCharacter : lineText.length
);
while (character < lineLength) {
if (
this.visualizeOnlyIndentation &&
character >= line.firstNonWhitespaceCharacterIndex
) {
break;
}

if (
this.tabPattern.indexOf(lineText[character]) >= 0
) {
tabRanges.push(new vscode.Range(
currentLine, character, currentLine, character
));
} else if (
this.spacePattern.indexOf(lineText[character]) >= 0
) {
whitespaceRanges.push(new vscode.Range(
currentLine, character, currentLine, character
));
}

character += 1;
}
const selectionFirstLine = selection.start.line;
const selectionLastLine = selection.end.line;

const selectionFirstChar = selection.start.character;
const selectionLastChar = selection.end.character;

currentLine += 1;
let currentLineNum = selectionFirstLine;

for (; currentLineNum <= selectionLastLine; currentLineNum++) {
const line = editor.document.lineAt(currentLineNum);

let charNum = currentLineNum === selectionFirstLine
? selectionFirstChar
: 0;

let lineLength = currentLineNum === selectionLastLine
? selectionLastChar
: line.text.length;

for (; charNum < lineLength; charNum++) {
if (this.tabPattern.test(line.text[charNum]))
tabRanges.push(
new vscode.Range(currentLineNum, charNum, currentLineNum, charNum)
);

else if (this.spacePattern.test(line.text[charNum]))
whitespaceRanges.push(
new vscode.Range(currentLineNum, charNum, currentLineNum, charNum)
);
}
}
});

editor.setDecorations(this.whitespaceDecoration, whitespaceRanges);
editor.setDecorations(this.spaceDecoration, whitespaceRanges);
editor.setDecorations(this.tabDecoration, tabRanges);
}
}