From 20da5d6fa2695e45ef38922cbc9d5f0888271ccd Mon Sep 17 00:00:00 2001 From: fr1zle Date: Thu, 8 Dec 2016 10:16:47 +0100 Subject: [PATCH] #21: highlight code blocks Beginning working on highlighting code blocks. --- src/elixirHighlightProvider.ts | 77 ++++++++++++++++++++++++++++++++++ src/elixirMain.ts | 10 +++++ 2 files changed, 87 insertions(+) create mode 100644 src/elixirHighlightProvider.ts diff --git a/src/elixirHighlightProvider.ts b/src/elixirHighlightProvider.ts new file mode 100644 index 0000000..3d710df --- /dev/null +++ b/src/elixirHighlightProvider.ts @@ -0,0 +1,77 @@ +import * as vscode from 'vscode'; + +export class ElixirHighlightProvider implements vscode.DocumentHighlightProvider { + + balancedPairs: BalancedPair[]; + + constructor() { } + + provideDocumentHighlights(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): vscode.DocumentHighlight[] { + const result = this.balancedPairs.find(pair => ( + pair.entry.start.line === position.line || + pair.end.start.line === position.line)); + if (result) { + return [new vscode.DocumentHighlight(result.entry, 2), new vscode.DocumentHighlight(result.end, 2)]; + } + } + + balanceEvent(event: vscode.TextEditor) { + if (event && event.document) { + this.balancePairs(event.document); + } + } + + balancePairs(document: vscode.TextDocument) { + this.balancedPairs = []; + if (document.languageId !== 'elixir') { + return; + } + const waitingEntries: vscode.Range[] = []; + let entry: vscode.Range; + let end: vscode.Range; + for (let i = 0; i < document.lineCount; i++) { + if ((entry = this.getEntry(document.lineAt(i)))) { + waitingEntries.push(entry); + } else if (waitingEntries.length && (end = this.getEnd(document.lineAt(i)))) { + this.balancedPairs.push({ + entry: waitingEntries.pop(), + end: end + }); + } + } + + + } + + getEntry(line: vscode.TextLine): vscode.Range { + let match = line.text.match(/^(?!.*do\:)(\s*)(def|defp|defmodule|defmacro|quote|case|cond|if|unless|try)\b.*$/); + if (match) { + return new vscode.Range(line.lineNumber, match[1].length, line.lineNumber, match[1].length + match[2].length); + } else { + match = line.text.match(/\b(do)\b\s*(\|.*\|[^;]*)?$/); + if (match) { + return new vscode.Range(line.lineNumber, match.index, line.lineNumber, match.index + 2); + } else { + match = line.text.match(/(?!.*do\:)\b(fn)\b.*$/); + if (match) { + return new vscode.Range(line.lineNumber, match.index, line.lineNumber, match.index + 2); + } + } + } + } + + getEnd(line: vscode.TextLine): vscode.Range { + //end must be on a line by itself, or followed directly by a dot + const match = line.text.match(/^(\s*)end\b[\.\s#]?\s*$/); + if (match) { + return new vscode.Range(line.lineNumber, match[1].length, line.lineNumber, match[1].length + 3); + } + + } + +} + +interface BalancedPair { + entry: vscode.Range; + end: vscode.Range; +} \ No newline at end of file diff --git a/src/elixirMain.ts b/src/elixirMain.ts index 7c027f4..5898f6e 100644 --- a/src/elixirMain.ts +++ b/src/elixirMain.ts @@ -2,6 +2,7 @@ import * as vscode from 'vscode'; import { ElixirAutocomplete } from './elixirAutocomplete'; import { ElixirServer } from './elixirServer'; import { ElixirDefinitionProvider } from './elixirDefinitionProvider'; +import { ElixirHighlightProvider } from './elixirHighlightProvider'; import {configuration} from './elixirConfiguration'; const ELIXIR_MODE: vscode.DocumentFilter = { language: 'elixir', scheme: 'file' }; @@ -9,10 +10,19 @@ let elixirServer: ElixirServer; export function activate(ctx: vscode.ExtensionContext) { this.elixirServer = new ElixirServer(); + const elixirHighlightProvider = new ElixirHighlightProvider(); this.elixirServer.start(); ctx.subscriptions.push(vscode.languages.registerCompletionItemProvider(ELIXIR_MODE, new ElixirAutocomplete(this.elixirServer))); ctx.subscriptions.push(vscode.languages.registerDefinitionProvider(ELIXIR_MODE, new ElixirDefinitionProvider(this.elixirServer))); ctx.subscriptions.push(vscode.languages.setLanguageConfiguration('elixir', configuration)); + ctx.subscriptions.push(vscode.languages.registerDocumentHighlightProvider('elixir', elixirHighlightProvider)); + ctx.subscriptions.push(vscode.window.onDidChangeActiveTextEditor(elixirHighlightProvider.balanceEvent.bind(elixirHighlightProvider))); + ctx.subscriptions.push(vscode.workspace.onDidChangeTextDocument(elixirHighlightProvider.balanceEvent.bind(elixirHighlightProvider))); + ctx.subscriptions.push(vscode.workspace.onDidOpenTextDocument(elixirHighlightProvider.balanceEvent.bind(elixirHighlightProvider))); + if (vscode.window && vscode.window.activeTextEditor) { + elixirHighlightProvider.balancePairs(vscode.window.activeTextEditor.document); + } + } export function deactivate() {