From aed0fbe1b80b73acbd34f3c947c226a327a4de3f Mon Sep 17 00:00:00 2001 From: Paulo Valente Date: Mon, 5 Aug 2019 02:16:09 -0300 Subject: [PATCH] feat: implement ignore blocks to allow for proper commented code and string text ignoring and improve elixir syntax matching --- package-lock.json | 2 +- package.json | 2 +- src/extension.ts | 40 ++++++++++++++++++++++++++++++++-------- src/languages.ts | 37 +++++++++++++++++++++++++++++++++++-- 4 files changed, 69 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8515fe5..8a9264c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "rainbow-end", - "version": "0.6.0", + "version": "0.7.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 578b195..c379132 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "license": "Apache-2.0", "displayName": "Rainbow End", "description": "This extension allows to identify keyword / end with colours.", - "version": "0.6.0", + "version": "0.7.0", "icon": "images/logo.png", "engines": { "vscode": "^1.29.0" diff --git a/src/extension.ts b/src/extension.ts index a255aff..f6b9aaa 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,23 +1,23 @@ 'use strict'; import * as vscode from 'vscode'; -import {languages} from './languages'; +import { languages } from './languages'; const deepDecorations = [ vscode.window.createTextEditorDecorationType({ - color: {id: "rainbowend.deep1"} + color: { id: "rainbowend.deep1" } }), vscode.window.createTextEditorDecorationType({ - color: {id: "rainbowend.deep2"} + color: { id: "rainbowend.deep2" } }), vscode.window.createTextEditorDecorationType({ - color: {id: "rainbowend.deep3"} + color: { id: "rainbowend.deep3" } }) ]; -let timeout : NodeJS.Timer | null = null; -let regExs: { [index:string] : RegExp} = {}; +let timeout: NodeJS.Timer | null = null; +let regExs: { [index: string]: RegExp } = {}; export function activate(context: vscode.ExtensionContext) { Object.keys(languages).forEach(language => { @@ -51,12 +51,31 @@ function triggerUpdateDecorations(activeEditor: vscode.TextEditor) { } function buildRegex(language: string) { + const languageConfiguration = languages[language]; let tokens: Array = languageConfiguration["openTokens"]; tokens = tokens.concat(languageConfiguration["inlineOpenTokens"]); tokens = tokens.concat(languageConfiguration["closeTokens"]); tokens = tokens.concat(languageConfiguration["neutralTokens"]); - return RegExp("(\\b)(" + tokens.join('|') + ")(\\b)", "gm"); + return RegExp("([^\\w]|^)(" + tokens.join('|') + ")([^\\w]|$)", "gm"); +} + +function ignoreInDelimiters(token_pairs: Array<{ + open: string, + close: string +}> | undefined, text: string) { + if (token_pairs) { + token_pairs.forEach(({ + open: open_delim, + close: close_delim + }) => { + let regexp = RegExp(`${open_delim}[^${close_delim}]*${close_delim}`, "gm"); + text = text.replace(regexp, (match) => { + return " ".repeat(match.length); + }); + }) + } + return text; } function updateDecorations() { @@ -78,11 +97,16 @@ function updateDecorations() { if (!languageConfiguration.caseSensitive) { text = text.toLowerCase(); } + // substitute all ignore intervals with spaces + // this ensures commented code or + // keywords inside strings are ignored properly + + text = ignoreInDelimiters(languageConfiguration.ignoreInDelimiters, text); while (match = regExs[activeEditor.document.languageId].exec(text)) { const startIndex = match.index + match[1].length; const startPos = activeEditor.document.positionAt(startIndex); const endPos = activeEditor.document.positionAt(startIndex + match[2].length); - const decoration: vscode.DecorationOptions = { range: new vscode.Range(startPos, endPos) }; + const decoration: vscode.DecorationOptions = { range: new vscode.Range(startPos, endPos) }; if (languageConfiguration.closeTokens.indexOf(match[2]) > -1) { if (deep > 0) { diff --git a/src/languages.ts b/src/languages.ts index b47acad..08f04dd 100644 --- a/src/languages.ts +++ b/src/languages.ts @@ -1,6 +1,10 @@ export const languages: { [index: string]: { caseSensitive: boolean, + ignoreInDelimiters?: Array<{ + open: string, + close: string + }>, inlineOpenTokens: Array, openTokens: Array, closeTokens: Array, @@ -53,11 +57,31 @@ export const languages: { }, elixir: { caseSensitive: true, + ignoreInDelimiters: [{ + open: "#", + close: "\n" + }, + { + open: '"""', + close: '"""' + }, { + open: '"', + close: '"' + }, + { + open: "'", + close: "'" + }, + ], inlineOpenTokens: [], openTokens: [ + "fn", "defmodule", - "defmacro", - "def", + "defmacro(?=.+do)", + "defmacrop(?=.+do)", + "def(?=.+do)", + "defp(?=.+do)", + "(?", + "<-", "else", "elseif", "rescue",