Skip to content
This repository has been archived by the owner on Nov 4, 2023. It is now read-only.

Html tags #316

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
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
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ Show a horizontal line between the brackets? Enabled by default
>`"bracket-pair-colorizer-2.scopeLineRelativePosition"`
Disable this to show the vertical line in column 0
![Scope Line](images/no-relative.png "Gutter Brackets Example")

>`"bracket-pair-colorizer-2.scopeLineCSS"`
Choose a border style to highlight the active scope. Use `{color}` to match the existing bracket color

Expand All @@ -97,6 +97,28 @@ Choose a border style to highlight the active scope. Use `{color}` to match the
>`"bracket-pair-colorizer-2.excludedLanguages"`
Exclude a language from being colorized

>`"bracket-pair-colorizer-2.htmlStyleTagsLanguages"`
Languages which should colorize HTML-style tags e.g. `<div>` matches to `</div>`. This will not affect the behavior of other types of brackets
![HTML-Style Tags](images/htmlTags.png "HTML-Style Tags Example")

```json
"bracket-pair-colorizer-2.htmlStyleTagsLanguages": [
"html",
"xml"
]
```
Exclude a language from being colorized

>`"bracket-pair-colorizer-2.htmlIgnoredTags"`
Tags which do not have a corresponding close and therefore should be ignored by the HTML colorization e.g. `<br>`

```json
"bracket-pair-colorizer-2.htmlIgnoredTags": [
"br",
"hr"
]
```

### Commands

These commands will expand/undo the cursor selection to the next scope
Expand Down
Binary file added images/htmlTags.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,24 @@
"default": [],
"description": "Don't colorize files of these languages",
"scope": "window"
},
"bracket-pair-colorizer-2.htmlStyleTagsLanguages": {
"type": "array",
"default": [
"html",
"xml"
],
"description": "Languages which should colorize HTML-style tags e.g. <div> matches to </div>. This will not affect the behavior of other types of brackets",
"scope": "window"
},
"bracket-pair-colorizer-2.htmlIgnoredTags": {
"type": "array",
"default": [
"br",
"hr"
],
"description": "Tags which do not have a corresponding close therefore should be ignored by the HTML colorization e.g. <br>",
"scope": "window"
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/bracketUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export function getRegexForBrackets(input: ISimpleInternalBracket[]): RegExp {
return createBracketOrRegExp(pieces);
}

function createBracketOrRegExp(pieces: string[]): RegExp {
export function createBracketOrRegExp(pieces: string[]): RegExp {
const regexStr = `(${pieces.map(prepareBracketForRegExp).join(")|(")})`;
return createRegExp(regexStr, true, { global: true });
}
Expand Down
63 changes: 56 additions & 7 deletions src/documentDecoration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import Settings from "./settings";
import TextLine from "./textLine";
import { ignoreBracketsInToken, LineTokens } from "./vscodeFiles";
import { TextDocumentContentChangeEvent } from "vscode";
import { createBracketOrRegExp } from "./bracketUtil";

type Match = { content: string, index: number };

export default class DocumentDecoration {
public readonly settings: Settings;
Expand Down Expand Up @@ -320,7 +323,9 @@ export default class DocumentDecoration {
const tokens = tokenized.tokens;
const lineTokens = new LineTokens(tokens, newText);

const matches = new Array<{ content: string, index: number }>();
const matches = new Array<Match>();
const htmlMatches = { open: new Array<Match>(), close: new Array<Match>(), ignore: new Array<Match>() };

const count = lineTokens.getCount();
for (let i = 0; i < count; i++) {
const tokenType = lineTokens.getStandardTokenType(i);
Expand All @@ -330,24 +335,68 @@ export default class DocumentDecoration {

const currentTokenText = newText.substring(searchStartOffset, searchEndOffset);

let result: RegExpExecArray | null;
// tslint:disable-next-line:no-conditional-assignment
while ((result = this.languageConfig.regex.exec(currentTokenText)) !== null) {
matches.push({ content: result[0], index: result.index + searchStartOffset });
this.pushMatches(currentTokenText, this.languageConfig.regex, searchStartOffset, matches);
if (this.languageConfig.colorHtmlStyleTags) {
this.pushMatches(
currentTokenText, createBracketOrRegExp(["</", "/>"]), searchStartOffset, htmlMatches.close
);
this.pushMatches(
currentTokenText, createBracketOrRegExp(["<"]), searchStartOffset, htmlMatches.open
);
this.pushMatches(
currentTokenText,
createBracketOrRegExp(
this.settings.htmlIgnoredTags.map((value: string) => { return "<" + value })
), searchStartOffset, htmlMatches.ignore
);
}
}
}

const newLine = new TextLine(tokenized.ruleStack, previousLineState, index);
// Filter out the overlap between the open tags and the other tags
// (also protects against a potential <> in languageConfig)
const htmlCloseIgnoreIndexes = matches.concat(htmlMatches.close, htmlMatches.ignore)
.map((value: { index: number }) => { return value.index });
htmlMatches.open = htmlMatches.open.filter(function (value: { index: number }) {
return htmlCloseIgnoreIndexes.indexOf(value.index) == -1
});

// Collate all matches
let tokensToAdd = new Array<{ content: string, index: number, key: number, open: boolean }>();
for (const match of matches) {
const lookup = this.languageConfig.bracketToId.get(match.content);
if (lookup) {
newLine.AddToken(match.content, match.index, lookup.key, lookup.open);
tokensToAdd.push({ content: match.content, index: match.index, key: lookup.key, open: lookup.open });
}
}
tokensToAdd = tokensToAdd.concat(
htmlMatches.open.map((match: Match) => {
return { content: match.content, index: match.index, key: this.languageConfig.htmlKey, open: true }
}),
htmlMatches.close.map((match: Match) => {
return { content: match.content, index: match.index, key: this.languageConfig.htmlKey, open: false }
})
);

// Force index order so that the bracket stack is created correctly
tokensToAdd.sort((a, b) => a.index - b.index);

const newLine = new TextLine(tokenized.ruleStack, previousLineState, index);
for (const token of tokensToAdd) {
newLine.AddToken(token.content, token.index, token.key, token.open);
}

return newLine;
}

private pushMatches(text: string, regex: RegExp, indexOffset: number, matches: Array<Match>) {
let result: RegExpExecArray | null;
// tslint:disable-next-line:no-conditional-assignment
while ((result = regex.exec(text)) !== null) {
matches.push({ content: result[0], index: result.index + indexOffset });
}
}

private setOverLineDecoration(
bracket: Bracket,
event: vscode.TextEditorSelectionChangeEvent,
Expand Down
15 changes: 14 additions & 1 deletion src/languageConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,23 @@ export default class LanguageConfig {
public readonly grammar: IGrammar;
public readonly regex: RegExp;
public readonly bracketToId: Map<string, { open: boolean, key: number }>;
// Key to be used for html brackets
public readonly htmlKey: number;
public readonly colorHtmlStyleTags: boolean;

constructor(grammar: IGrammar, regex: RegExp, bracketToId: Map<string, { open: boolean, key: number }>) {
constructor(
grammar: IGrammar, regex: RegExp, bracketToId: Map<string, { open: boolean, key: number }>,
colorHtmlStyleTags: boolean
) {
this.grammar = grammar;
this.regex = regex;
this.bracketToId = bracketToId;
let htmlKey = -1;
if (colorHtmlStyleTags) {
bracketToId.forEach((value: { key: number }) => { if (value.key > htmlKey) { htmlKey = value.key } });
htmlKey++;
}
this.htmlKey = htmlKey;
this.colorHtmlStyleTags = colorHtmlStyleTags;
}
}
4 changes: 4 additions & 0 deletions src/multipleIndexes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ export default class MultipleBracketGroups implements IBracketManager {
this.allLinesOpenBracketStack[value.key] = [];
this.previousOpenBracketColorIndexes[value.key] = 0;
}
if (languageConfig.colorHtmlStyleTags) {
this.allLinesOpenBracketStack[languageConfig.htmlKey] = [];
this.previousOpenBracketColorIndexes[languageConfig.htmlKey] = 0;
}
}
}

Expand Down
18 changes: 17 additions & 1 deletion src/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import TextMateLoader from "./textMateLoader";
import { ThemeColor } from "vscode";

export default class Settings {
public readonly TextMateLoader = new TextMateLoader();
public readonly TextMateLoader: TextMateLoader;
public readonly bracketDecorations: Map<string, vscode.TextEditorDecorationType>;
public readonly colorMode: ColorMode;
public readonly contextualParsing: boolean;
Expand All @@ -22,6 +22,7 @@ export default class Settings {
public readonly colors: string[];
public readonly unmatchedScopeColor: string;
public readonly excludedLanguages: Set<string>;
public readonly htmlIgnoredTags: string[];
public isDisposed = false;
private readonly gutterIcons: GutterIconManager;
private readonly activeBracketCSSElements: string[][];
Expand Down Expand Up @@ -129,6 +130,7 @@ export default class Settings {
}

this.colors = configuration.get("colors") as string[];

if (!Array.isArray(this.colors)) {
throw new Error("colors is not an array");
}
Expand All @@ -142,6 +144,20 @@ export default class Settings {
}

this.excludedLanguages = new Set(excludedLanguages);

this.htmlIgnoredTags = configuration.get("htmlIgnoredTags") as string[];

if (!Array.isArray(this.htmlIgnoredTags)) {
throw new Error("htmlIgnoredTags is not an array");
}

let htmlStyleTagsLanguages = configuration.get("htmlStyleTagsLanguages") as string[];

if (!Array.isArray(htmlStyleTagsLanguages)) {
throw new Error("htmlStyleTagsLanguages is not an array");
}

this.TextMateLoader = new TextMateLoader(htmlStyleTagsLanguages);
}

public dispose() {
Expand Down
9 changes: 7 additions & 2 deletions src/textMateLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ export class TextMateLoader {
private readonly vsctm: any;
private readonly oniguruma: any;
private readonly languageConfigs = new Map<string, LanguageConfig>();
constructor() {
private readonly htmlStyleTagsLanguages: string[];
constructor(htmlStyleTagsLanguages: string[] = []) {
this.initializeGrammars();
this.vsctm = this.loadTextMate();
this.oniguruma = this.loadOniguruma();
this.htmlStyleTagsLanguages = htmlStyleTagsLanguages;
}

public tryGetLanguageConfig(languageID: string) {
Expand Down Expand Up @@ -105,7 +107,10 @@ export class TextMateLoader {
}

const regex = getRegexForBrackets(mappedBrackets);
this.languageConfigs.set(languageID, new LanguageConfig(grammar, regex, bracketToId));
const colorHtmlStyleTags = this.htmlStyleTagsLanguages.indexOf(languageID) > -1;
this.languageConfigs.set(
languageID, new LanguageConfig(grammar, regex, bracketToId, colorHtmlStyleTags)
);
}
}
return grammar;
Expand Down