code-scope-highlighter 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +30 -0
- package/.vscode/extensions.json +5 -0
- package/.vscode/launch.json +21 -0
- package/.vscode/settings.json +13 -0
- package/.vscode/tasks.json +6 -0
- package/.vscode-test.mjs +5 -0
- package/.vscodeignore +14 -0
- package/CHANGELOG.md +5 -0
- package/LICENSE.md +24 -0
- package/README.md +90 -0
- package/code-scope-highlighter-logo.jpeg +0 -0
- package/code-scope-highlighter-logo.webp +0 -0
- package/code-scope-highlighter.gif +0 -0
- package/debug-test.html +3 -0
- package/esbuild.js +56 -0
- package/package.json +81 -0
- package/pnpm-workspace.yaml +2 -0
- package/src/controller.ts +61 -0
- package/src/extension.ts +11 -0
- package/src/highlighter.ts +129 -0
- package/src/test/extension.test.ts +15 -0
- package/src/types.ts +12 -0
- package/src/util.ts +148 -0
- package/test-html-highlighting.html +38 -0
- package/tsconfig.json +16 -0
package/.eslintrc.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"root": true,
|
|
3
|
+
"parser": "@typescript-eslint/parser",
|
|
4
|
+
"parserOptions": {
|
|
5
|
+
"ecmaVersion": 6,
|
|
6
|
+
"sourceType": "module"
|
|
7
|
+
},
|
|
8
|
+
"plugins": [
|
|
9
|
+
"@typescript-eslint"
|
|
10
|
+
],
|
|
11
|
+
"rules": {
|
|
12
|
+
"@typescript-eslint/naming-convention": [
|
|
13
|
+
"warn",
|
|
14
|
+
{
|
|
15
|
+
"selector": "import",
|
|
16
|
+
"format": [ "camelCase", "PascalCase" ]
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"@typescript-eslint/semi": "warn",
|
|
20
|
+
"curly": "warn",
|
|
21
|
+
"eqeqeq": "warn",
|
|
22
|
+
"no-throw-literal": "warn",
|
|
23
|
+
"semi": "off"
|
|
24
|
+
},
|
|
25
|
+
"ignorePatterns": [
|
|
26
|
+
"out",
|
|
27
|
+
"dist",
|
|
28
|
+
"**/*.d.ts"
|
|
29
|
+
]
|
|
30
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// A launch configuration that compiles the extension and then opens it inside a new window
|
|
2
|
+
// Use IntelliSense to learn about possible attributes.
|
|
3
|
+
// Hover to view descriptions of existing attributes.
|
|
4
|
+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
5
|
+
{
|
|
6
|
+
"version": "0.2.0",
|
|
7
|
+
"configurations": [
|
|
8
|
+
{
|
|
9
|
+
"name": "Run Extension",
|
|
10
|
+
"type": "extensionHost",
|
|
11
|
+
"request": "launch",
|
|
12
|
+
"args": [
|
|
13
|
+
"--disable-extensions",
|
|
14
|
+
"--extensionDevelopmentPath=${workspaceFolder}"
|
|
15
|
+
],
|
|
16
|
+
"outFiles": [
|
|
17
|
+
"${workspaceFolder}/dist/**/*.js"
|
|
18
|
+
],
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Place your settings in this file to overwrite default and user settings.
|
|
2
|
+
{
|
|
3
|
+
"files.exclude": {
|
|
4
|
+
"out": false, // set this to true to hide the "out" folder with the compiled JS files
|
|
5
|
+
"dist": false // set this to true to hide the "dist" folder with the compiled JS files
|
|
6
|
+
},
|
|
7
|
+
"search.exclude": {
|
|
8
|
+
"out": true, // set this to false to include "out" folder in search results
|
|
9
|
+
"dist": true // set this to false to include "dist" folder in search results
|
|
10
|
+
},
|
|
11
|
+
// Turn off tsc task auto detection since we have the necessary tasks as npm scripts
|
|
12
|
+
"typescript.tsc.autoDetect": "off"
|
|
13
|
+
}
|
package/.vscode-test.mjs
ADDED
package/.vscodeignore
ADDED
package/CHANGELOG.md
ADDED
package/LICENSE.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: License
|
|
3
|
+
description: MIT License for Code Highlighter
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 📄 License – Code Highlighter
|
|
7
|
+
|
|
8
|
+
This project is open-source and freely available under the terms below.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## MIT License
|
|
13
|
+
|
|
14
|
+
Copyright (c) {new Date().getFullYear()} [Jose Valdivia](https://github.com/joseavr)
|
|
15
|
+
|
|
16
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
17
|
+
|
|
18
|
+
> The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
**THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND**, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the Software.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
_Originally published at [github.com/joseavr/code-highlighter](https://github.com/joseavr/code-highlighter)_
|
package/README.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="./code-scope-highlighter.gif" alt=" Language" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<img src="https://img.shields.io/github/languages/top/lamula21/scope-highlighter" alt=" Language" />
|
|
7
|
+
<img src="https://img.shields.io/github/stars/lamula21/scope-highlighter" alt=" Stars" />
|
|
8
|
+
<img src="https://img.shields.io/github/issues-pr/lamula21/scope-highlighter" alt=" Pull Requests" />
|
|
9
|
+
<img src="https://img.shields.io/github/issues/lamula21/scope-highlighter" alt=" Issues" />
|
|
10
|
+
<img src="https://img.shields.io/github/contributors/lamula21/scope-highlighter" alt=" Contributors" />
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# Code Highlighter - A Highlighter Extension for Better Readability
|
|
15
|
+
|
|
16
|
+
A customizable scope highlighter, inspired by Dr Racket IDE.
|
|
17
|
+
|
|
18
|
+
## ✨ Features
|
|
19
|
+
- **Universal highlighting:** ScopeHighlighter works on any language!
|
|
20
|
+
- **Dynamic Highlighting:** Instantly see the scope of matching brackets with vibrant colors.
|
|
21
|
+
- **HTML Tag Support:** Highlight nested HTML tags with intelligent cursor positioning:
|
|
22
|
+
- Place cursor on `<` of start tag to highlight: start tag + content + end tag
|
|
23
|
+
- Place cursor on `>` of any tag to highlight: content inside the tag
|
|
24
|
+
- **Customizable Colors:** Personalize your highlight colors for brackets, braces, and parentheses.
|
|
25
|
+
- **Flexible Modes:** Choose from "near", "always", or "never" highlight modes to suit your coding style.
|
|
26
|
+
- **(Soon) Language Specific Settings:** Enable or disable highlighting for specific programming languages.
|
|
27
|
+
|
|
28
|
+
## 🌟 Why ScopeHighlighter?
|
|
29
|
+
- **Boost Productivity:** Quickly understand the structure of your code, making it easier to debug and develop.
|
|
30
|
+
- **Enhanced Readability:** No more squinting at matching brackets; ScopeHighlighter makes it clear and straightforward.
|
|
31
|
+
- **Seamless Integration:** Works effortlessly and fast within the VS Code ecosystem, either on desktop or the browser, thanks to the bundler `esbuild`.
|
|
32
|
+
|
|
33
|
+
## ⚙️ Extension Settings
|
|
34
|
+
|
|
35
|
+
The following settings are configured for the scope-highlighter extension:
|
|
36
|
+
|
|
37
|
+
### `codeScopeHighlighter.matchBrackets` - Match Brackets
|
|
38
|
+
|
|
39
|
+
For color picker: https://vuetifyjs.com/en/components/color-pickers/
|
|
40
|
+
|
|
41
|
+
- **Default**: `near`
|
|
42
|
+
- **Description**: Choose when the scope highlight should be active:
|
|
43
|
+
- `near` for when the cursor is near the bracket,
|
|
44
|
+
- `always` to always highlight,
|
|
45
|
+
- `never` to never highlight.
|
|
46
|
+
|
|
47
|
+
### `codeScopeHighlighter.scopeColor` - Scope Color
|
|
48
|
+
- **Default**: `#4d4d4d30`
|
|
49
|
+
- **Description**: Color for highlighting the entire scope of matching brackets. (Hex format)
|
|
50
|
+
|
|
51
|
+
### `codeScopeHighlighter.bracketColor` - Bracket Color
|
|
52
|
+
- **Default**: `#4d4d4d30`
|
|
53
|
+
- **Description**: Color for highlighting the matching brackets. (Hex format)
|
|
54
|
+
|
|
55
|
+
## 🎯 HTML Tag Highlighting
|
|
56
|
+
|
|
57
|
+
The extension now supports HTML tag highlighting with intelligent cursor positioning:
|
|
58
|
+
|
|
59
|
+
### How it works:
|
|
60
|
+
- **Cursor on `<` of start tag:** Highlights the entire tag including start tag, content, and end tag
|
|
61
|
+
- **Cursor on `>` of any tag:** Highlights only the content inside the tag (excluding the end tag's opening bracket)
|
|
62
|
+
- **Cursor inside tag content:** Highlights the content and end tag
|
|
63
|
+
|
|
64
|
+
### Example:
|
|
65
|
+
```html
|
|
66
|
+
<div class="container">
|
|
67
|
+
<h1>Hello World</h1>
|
|
68
|
+
<p>This is a <strong>test</strong> paragraph.</p>
|
|
69
|
+
</div>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
- Place cursor on `<` of `<div>` → highlights entire div block
|
|
73
|
+
- Place cursor on `>` of `<div>` → highlights content inside div
|
|
74
|
+
- Place cursor on `<` of `<h1>` → highlights h1 tag and content
|
|
75
|
+
- Place cursor on `>` of `</h1>` → highlights h1 content only
|
|
76
|
+
|
|
77
|
+
## 🗺️ Roadmap
|
|
78
|
+
|
|
79
|
+
- [x] **HTML support:** Implement highlighting for nested html tags.
|
|
80
|
+
- [ ] **Language Specific Settings:** Implement highlighting for specific programming languages.
|
|
81
|
+
- [ ] **Bracket Specific Settings:** Implement highlighting for specific matching bracket symbols.
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
## 📄 License
|
|
85
|
+
|
|
86
|
+
This project is licensed under the **MIT** - see the [MIT](https://github.com/xavimondev/easyreadme/blob/main/LICENSE) file for details.
|
|
87
|
+
|
|
88
|
+
## For Devs
|
|
89
|
+
|
|
90
|
+
Start Debugging right away with `F5` or Command Pallete `Debug: Start Debugging`
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/debug-test.html
ADDED
package/esbuild.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
const esbuild = require("esbuild");
|
|
2
|
+
|
|
3
|
+
const production = process.argv.includes('--production');
|
|
4
|
+
const watch = process.argv.includes('--watch');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @type {import('esbuild').Plugin}
|
|
8
|
+
*/
|
|
9
|
+
const esbuildProblemMatcherPlugin = {
|
|
10
|
+
name: 'esbuild-problem-matcher',
|
|
11
|
+
|
|
12
|
+
setup(build) {
|
|
13
|
+
build.onStart(() => {
|
|
14
|
+
console.log('[watch] build started');
|
|
15
|
+
});
|
|
16
|
+
build.onEnd((result) => {
|
|
17
|
+
result.errors.forEach(({ text, location }) => {
|
|
18
|
+
console.error(`✘ [ERROR] ${text}`);
|
|
19
|
+
console.error(` ${location.file}:${location.line}:${location.column}:`);
|
|
20
|
+
});
|
|
21
|
+
console.log('[watch] build finished');
|
|
22
|
+
});
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
async function main() {
|
|
27
|
+
const ctx = await esbuild.context({
|
|
28
|
+
entryPoints: [
|
|
29
|
+
'src/extension.ts'
|
|
30
|
+
],
|
|
31
|
+
bundle: true,
|
|
32
|
+
format: 'cjs',
|
|
33
|
+
minify: production,
|
|
34
|
+
sourcemap: !production,
|
|
35
|
+
sourcesContent: false,
|
|
36
|
+
platform: 'node',
|
|
37
|
+
outfile: 'dist/extension.js',
|
|
38
|
+
external: ['vscode'],
|
|
39
|
+
logLevel: 'silent',
|
|
40
|
+
plugins: [
|
|
41
|
+
/* add to the end of plugins array */
|
|
42
|
+
esbuildProblemMatcherPlugin,
|
|
43
|
+
],
|
|
44
|
+
});
|
|
45
|
+
if (watch) {
|
|
46
|
+
await ctx.watch();
|
|
47
|
+
} else {
|
|
48
|
+
await ctx.rebuild();
|
|
49
|
+
await ctx.dispose();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
main().catch(e => {
|
|
54
|
+
console.error(e);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "code-scope-highlighter",
|
|
3
|
+
"publisher": "joseavr",
|
|
4
|
+
"displayName": "Code Highlighter",
|
|
5
|
+
"description": "Highlight the scope of matching brackets with customizable colors and flexible highlight modes.",
|
|
6
|
+
"repository": "https://github.com/joseavr/code-highlighter",
|
|
7
|
+
"icon": "code-scope-highlighter-logo.webp",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"version": "1.1.0",
|
|
10
|
+
"engines": {
|
|
11
|
+
"vscode": "^1.90.0"
|
|
12
|
+
},
|
|
13
|
+
"categories": [
|
|
14
|
+
"Other"
|
|
15
|
+
],
|
|
16
|
+
"activationEvents": [
|
|
17
|
+
"*"
|
|
18
|
+
],
|
|
19
|
+
"main": "./dist/extension.js",
|
|
20
|
+
"contributes": {
|
|
21
|
+
"commands": [
|
|
22
|
+
{
|
|
23
|
+
"command": "scope-highlighter.helloWorld",
|
|
24
|
+
"title": "Hello World"
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"configuration": {
|
|
28
|
+
"type": "object",
|
|
29
|
+
"title": "Scope Highlighter",
|
|
30
|
+
"properties": {
|
|
31
|
+
"codeScopeHighlighter.scopeColor": {
|
|
32
|
+
"type": "string",
|
|
33
|
+
"description": "Color for highlighting the entire scope of matching brackets. (Hex format)",
|
|
34
|
+
"default": "#4d4d4d89"
|
|
35
|
+
},
|
|
36
|
+
"codeScopeHighlighter.bracketColor": {
|
|
37
|
+
"type": "string",
|
|
38
|
+
"description": "Color for highlighting the matching brackets. (Hex format)",
|
|
39
|
+
"default": "#4d4d4d89"
|
|
40
|
+
},
|
|
41
|
+
"codeScopeHighlighter.matchBrackets": {
|
|
42
|
+
"type": "string",
|
|
43
|
+
"enum": [
|
|
44
|
+
"near",
|
|
45
|
+
"always",
|
|
46
|
+
"never"
|
|
47
|
+
],
|
|
48
|
+
"default": "near",
|
|
49
|
+
"description": "Choose when the scope highlight should be active: 'near' for when the cursor is near the bracket, 'always' to always highlight, and 'never' to never highlight."
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@types/vscode": "^1.90.0",
|
|
56
|
+
"@types/mocha": "^10.0.7",
|
|
57
|
+
"@types/node": "20.x",
|
|
58
|
+
"@typescript-eslint/eslint-plugin": "^7.14.1",
|
|
59
|
+
"@typescript-eslint/parser": "^7.11.0",
|
|
60
|
+
"eslint": "^8.57.0",
|
|
61
|
+
"esbuild": "^0.21.5",
|
|
62
|
+
"npm-run-all": "^4.1.5",
|
|
63
|
+
"typescript": "^5.4.5",
|
|
64
|
+
"@vscode/test-cli": "^0.0.9",
|
|
65
|
+
"@vscode/test-electron": "^2.4.0"
|
|
66
|
+
},
|
|
67
|
+
"scripts": {
|
|
68
|
+
"package": "pnpm run check-types && pnpm run lint && node esbuild.js --production",
|
|
69
|
+
"prepublish": "pnpm run package",
|
|
70
|
+
"watch": "npm-run-all -p watch:*",
|
|
71
|
+
"watch:esbuild": "node esbuild.js --watch",
|
|
72
|
+
"watch:tsc": "tsc --noEmit --watch --project tsconfig.json",
|
|
73
|
+
"compile": "pnpm run check-types && pnpm run lint && node esbuild.js",
|
|
74
|
+
"compile-tests": "tsc -p . --outDir out",
|
|
75
|
+
"test": "vscode-test",
|
|
76
|
+
"watch-tests": "tsc -p . -w --outDir out",
|
|
77
|
+
"pretest": "pnpm run compile-tests && pnpm run compile && pnpm run lint",
|
|
78
|
+
"check-types": "tsc --noEmit",
|
|
79
|
+
"lint": "eslint src --ext ts"
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import * as vscode from "vscode"
|
|
2
|
+
import { Highlighter } from "./highlighter"
|
|
3
|
+
|
|
4
|
+
export class Controller {
|
|
5
|
+
private highlighter: Highlighter
|
|
6
|
+
private _disposable: vscode.Disposable
|
|
7
|
+
|
|
8
|
+
constructor(highlighter: Highlighter) {
|
|
9
|
+
this.highlighter = highlighter
|
|
10
|
+
|
|
11
|
+
const subscriptions: vscode.Disposable[] = []
|
|
12
|
+
vscode.window.onDidChangeTextEditorSelection(
|
|
13
|
+
this._onEvent,
|
|
14
|
+
this,
|
|
15
|
+
subscriptions
|
|
16
|
+
)
|
|
17
|
+
vscode.window.onDidChangeActiveTextEditor(
|
|
18
|
+
this._onChangeEditor,
|
|
19
|
+
this,
|
|
20
|
+
subscriptions
|
|
21
|
+
)
|
|
22
|
+
vscode.workspace.onDidChangeConfiguration(
|
|
23
|
+
this._onUpdateSettings,
|
|
24
|
+
this,
|
|
25
|
+
subscriptions
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
this._onEvent()
|
|
29
|
+
|
|
30
|
+
this._disposable = vscode.Disposable.from.apply(
|
|
31
|
+
vscode.Disposable,
|
|
32
|
+
subscriptions
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
this.highlighter.updateConfig()
|
|
36
|
+
this.highlighter.onChange()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
dispose(): void {
|
|
40
|
+
this._disposable.dispose()
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private _onUpdateSettings(
|
|
44
|
+
configuration: vscode.ConfigurationChangeEvent
|
|
45
|
+
): void {
|
|
46
|
+
if (configuration.affectsConfiguration("codeScopeHighlighter")) {
|
|
47
|
+
this.highlighter.updateConfig()
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private _onChangeEditor(): void {
|
|
52
|
+
this.highlighter.updateConfig()
|
|
53
|
+
this.highlighter.onChange()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private _onEvent(e?: vscode.TextEditorSelectionChangeEvent): void {
|
|
57
|
+
if (e && e.textEditor === vscode.window.activeTextEditor) {
|
|
58
|
+
this.highlighter.onChange()
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
package/src/extension.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as vscode from "vscode"
|
|
2
|
+
import { Highlighter } from "./highlighter"
|
|
3
|
+
import { Controller } from "./controller"
|
|
4
|
+
|
|
5
|
+
export function activate(context: vscode.ExtensionContext) {
|
|
6
|
+
const highligher = new Highlighter()
|
|
7
|
+
const controller = new Controller(highligher)
|
|
8
|
+
|
|
9
|
+
context.subscriptions.push(highligher)
|
|
10
|
+
context.subscriptions.push(controller)
|
|
11
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import * as vscode from "vscode"
|
|
2
|
+
import util from "./util"
|
|
3
|
+
import { HighlighterMode, MatchingBracket } from "./types"
|
|
4
|
+
|
|
5
|
+
class Highlighter {
|
|
6
|
+
scoperRangeDecorationType: vscode.TextEditorDecorationType
|
|
7
|
+
scoperEndDecorationType: vscode.TextEditorDecorationType
|
|
8
|
+
userConfigHighlightingMode: HighlighterMode
|
|
9
|
+
|
|
10
|
+
constructor() {
|
|
11
|
+
this.scoperRangeDecorationType = util.setRangeStyle()
|
|
12
|
+
this.scoperEndDecorationType = util.setEndStyle()
|
|
13
|
+
this.userConfigHighlightingMode = vscode.workspace
|
|
14
|
+
.getConfiguration("codeScopeHighlighter")
|
|
15
|
+
.get<HighlighterMode>("matchBrackets", HighlighterMode.Near)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
updateConfig() {
|
|
19
|
+
if (vscode.window.activeTextEditor) {
|
|
20
|
+
vscode.window.activeTextEditor.setDecorations(
|
|
21
|
+
this.scoperRangeDecorationType,
|
|
22
|
+
[]
|
|
23
|
+
)
|
|
24
|
+
vscode.window.activeTextEditor.setDecorations(
|
|
25
|
+
this.scoperEndDecorationType,
|
|
26
|
+
[]
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
this.scoperRangeDecorationType.dispose()
|
|
30
|
+
this.scoperEndDecorationType.dispose()
|
|
31
|
+
|
|
32
|
+
this.scoperRangeDecorationType = util.setRangeStyle()
|
|
33
|
+
this.scoperEndDecorationType = util.setEndStyle()
|
|
34
|
+
|
|
35
|
+
util.updateConfig()
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
onChange() {
|
|
39
|
+
this.scoperRangeDecorationType.dispose()
|
|
40
|
+
this.scoperEndDecorationType.dispose()
|
|
41
|
+
|
|
42
|
+
this.scoperRangeDecorationType = util.setRangeStyle()
|
|
43
|
+
this.scoperEndDecorationType = util.setEndStyle()
|
|
44
|
+
|
|
45
|
+
const editor = vscode.window.activeTextEditor
|
|
46
|
+
|
|
47
|
+
if (!editor) {
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const offset = editor.document.offsetAt(editor.selection.active)
|
|
52
|
+
const text = editor.document.getText()
|
|
53
|
+
|
|
54
|
+
let backwardResult: MatchingBracket
|
|
55
|
+
let forwardResult: MatchingBracket
|
|
56
|
+
|
|
57
|
+
// ^: cursor position
|
|
58
|
+
// (...)
|
|
59
|
+
// ^
|
|
60
|
+
if (util.isCloseBracket(text.charAt(offset - 1))) {
|
|
61
|
+
backwardResult = util.findLeftBracket(text, offset - 2)
|
|
62
|
+
forwardResult = util.findRightBracket(text, offset - 1)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// (...)
|
|
66
|
+
// ^
|
|
67
|
+
else if (util.isOpenBracket(text.charAt(offset))) {
|
|
68
|
+
backwardResult = util.findLeftBracket(text, offset)
|
|
69
|
+
forwardResult = util.findRightBracket(text, offset + 1)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// (.)
|
|
73
|
+
// ^
|
|
74
|
+
else {
|
|
75
|
+
backwardResult = util.findLeftBracket(text, offset - 1)
|
|
76
|
+
forwardResult = util.findRightBracket(text, offset)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const shouldHighlight = util.shouldHighlight(
|
|
80
|
+
this.userConfigHighlightingMode,
|
|
81
|
+
offset,
|
|
82
|
+
backwardResult,
|
|
83
|
+
forwardResult
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
// set up the decoratiosn to highlight the scope and matching brackets
|
|
87
|
+
if (
|
|
88
|
+
util.isMatchingBracket(backwardResult.bracket, forwardResult.bracket) &&
|
|
89
|
+
shouldHighlight
|
|
90
|
+
) {
|
|
91
|
+
let start =
|
|
92
|
+
backwardResult.offset < text.length
|
|
93
|
+
? backwardResult.offset + 1
|
|
94
|
+
: backwardResult.offset
|
|
95
|
+
let end = forwardResult.offset
|
|
96
|
+
|
|
97
|
+
const start_decoration = new vscode.Range(
|
|
98
|
+
editor.document.positionAt(start - 1),
|
|
99
|
+
editor.document.positionAt(start)
|
|
100
|
+
)
|
|
101
|
+
const range_decoration = new vscode.Range(
|
|
102
|
+
editor.document.positionAt(start),
|
|
103
|
+
editor.document.positionAt(end)
|
|
104
|
+
)
|
|
105
|
+
const end_decoration = new vscode.Range(
|
|
106
|
+
editor.document.positionAt(end),
|
|
107
|
+
editor.document.positionAt(end + 1)
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
var rangeDecorations = []
|
|
111
|
+
var endDecorations = []
|
|
112
|
+
|
|
113
|
+
rangeDecorations.push(range_decoration)
|
|
114
|
+
editor.setDecorations(this.scoperRangeDecorationType, rangeDecorations)
|
|
115
|
+
|
|
116
|
+
endDecorations.push(start_decoration)
|
|
117
|
+
endDecorations.push(end_decoration)
|
|
118
|
+
editor.setDecorations(this.scoperEndDecorationType, endDecorations)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
dispose(): void {
|
|
123
|
+
this.scoperRangeDecorationType.dispose()
|
|
124
|
+
this.scoperEndDecorationType.dispose()
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const highlighter = new Highlighter()
|
|
129
|
+
export { highlighter, Highlighter }
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as assert from 'assert';
|
|
2
|
+
|
|
3
|
+
// You can import and use all API from the 'vscode' module
|
|
4
|
+
// as well as import your extension to test it
|
|
5
|
+
import * as vscode from 'vscode';
|
|
6
|
+
// import * as myExtension from '../../extension';
|
|
7
|
+
|
|
8
|
+
suite('Extension Test Suite', () => {
|
|
9
|
+
vscode.window.showInformationMessage('Start all tests.');
|
|
10
|
+
|
|
11
|
+
test('Sample test', () => {
|
|
12
|
+
assert.strictEqual(-1, [1, 2, 3].indexOf(5));
|
|
13
|
+
assert.strictEqual(-1, [1, 2, 3].indexOf(0));
|
|
14
|
+
});
|
|
15
|
+
});
|
package/src/types.ts
ADDED
package/src/util.ts
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import * as vscode from "vscode"
|
|
2
|
+
import { HighlighterMode, MatchingBracket } from "./types"
|
|
3
|
+
|
|
4
|
+
let openingBrackets = ""
|
|
5
|
+
let closingBrackets = ""
|
|
6
|
+
|
|
7
|
+
function updateConfig() {
|
|
8
|
+
const activeEditor = vscode.window.activeTextEditor
|
|
9
|
+
|
|
10
|
+
if (activeEditor) {
|
|
11
|
+
openingBrackets = "({["
|
|
12
|
+
closingBrackets = ")}]"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function isMatchingBracket(open: string, close: string) {
|
|
17
|
+
switch (open) {
|
|
18
|
+
case "(":
|
|
19
|
+
return close === ")"
|
|
20
|
+
case "{":
|
|
21
|
+
return close === "}"
|
|
22
|
+
case "[":
|
|
23
|
+
return close === "]"
|
|
24
|
+
default:
|
|
25
|
+
return false
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function isOpenBracket(char: string) {
|
|
30
|
+
return openingBrackets.includes(char)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function isCloseBracket(char: string) {
|
|
34
|
+
return closingBrackets.includes(char)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Finds to the left the nearest open bracket using a stack.
|
|
38
|
+
// Starting from the cursor position (index) to the beginning of the (text)
|
|
39
|
+
function findLeftBracket(text: string, index: number): MatchingBracket {
|
|
40
|
+
const bracketStack = []
|
|
41
|
+
let offset = 0
|
|
42
|
+
let bracket = ""
|
|
43
|
+
|
|
44
|
+
for (let i = index; i >= 0; i--) {
|
|
45
|
+
let char = text.charAt(i)
|
|
46
|
+
if (isOpenBracket(char)) {
|
|
47
|
+
if (bracketStack.length === 0) {
|
|
48
|
+
bracket = char
|
|
49
|
+
offset = i
|
|
50
|
+
break
|
|
51
|
+
} else {
|
|
52
|
+
let top = bracketStack.pop()!
|
|
53
|
+
if (!isMatchingBracket(char, top)) {
|
|
54
|
+
throw "Unmatched bracket pair"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
} else if (isCloseBracket(char)) {
|
|
58
|
+
bracketStack.push(char)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return { bracket, offset }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Finds to the right the nearest open bracket using a stack.
|
|
66
|
+
// Starting from the cursor position (index) to the end of the (text)
|
|
67
|
+
function findRightBracket(text: string, index: number): MatchingBracket {
|
|
68
|
+
const bracketStack = []
|
|
69
|
+
let offset = text.length
|
|
70
|
+
let bracket = ""
|
|
71
|
+
for (let i = index; i < text.length; i++) {
|
|
72
|
+
let char = text.charAt(i)
|
|
73
|
+
if (isCloseBracket(char)) {
|
|
74
|
+
if (bracketStack.length === 0) {
|
|
75
|
+
offset = i
|
|
76
|
+
bracket = char
|
|
77
|
+
break
|
|
78
|
+
} else {
|
|
79
|
+
let top = bracketStack.pop()!
|
|
80
|
+
if (!isMatchingBracket(top, char)) {
|
|
81
|
+
throw "Unmatched bracket pair"
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
} else if (isOpenBracket(char)) {
|
|
85
|
+
bracketStack.push(char)
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return { bracket, offset }
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function shouldHighlight(
|
|
93
|
+
highlighterMode: HighlighterMode,
|
|
94
|
+
offset: number,
|
|
95
|
+
leftMatchingBracket: { offset: number; bracket: string },
|
|
96
|
+
rightMatchingBracket: { offset: number; bracket: string }
|
|
97
|
+
): boolean {
|
|
98
|
+
switch (highlighterMode) {
|
|
99
|
+
// highlight only when the cursor is next to the matching bracket
|
|
100
|
+
case HighlighterMode.Near:
|
|
101
|
+
return (
|
|
102
|
+
offset === leftMatchingBracket.offset ||
|
|
103
|
+
offset === rightMatchingBracket.offset + 1
|
|
104
|
+
)
|
|
105
|
+
case HighlighterMode.Always:
|
|
106
|
+
return true
|
|
107
|
+
case HighlighterMode.Never:
|
|
108
|
+
return false
|
|
109
|
+
default:
|
|
110
|
+
return false // fallback for any unexpected values
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function setRangeStyle() {
|
|
115
|
+
return vscode.window.createTextEditorDecorationType({
|
|
116
|
+
light: {
|
|
117
|
+
backgroundColor: "#4d4d4d30"
|
|
118
|
+
},
|
|
119
|
+
dark: {
|
|
120
|
+
backgroundColor:
|
|
121
|
+
vscode.workspace.getConfiguration("codeScopeHighlighter").scopeColor,
|
|
122
|
+
},
|
|
123
|
+
})
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function setEndStyle() {
|
|
127
|
+
return vscode.window.createTextEditorDecorationType({
|
|
128
|
+
light: {
|
|
129
|
+
backgroundColor: "#4d4d4d30"
|
|
130
|
+
},
|
|
131
|
+
dark: {
|
|
132
|
+
backgroundColor:
|
|
133
|
+
vscode.workspace.getConfiguration("codeScopeHighlighter").bracketColor,
|
|
134
|
+
},
|
|
135
|
+
})
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export default {
|
|
139
|
+
updateConfig,
|
|
140
|
+
isMatchingBracket,
|
|
141
|
+
isOpenBracket,
|
|
142
|
+
isCloseBracket,
|
|
143
|
+
findLeftBracket,
|
|
144
|
+
findRightBracket,
|
|
145
|
+
shouldHighlight,
|
|
146
|
+
setRangeStyle,
|
|
147
|
+
setEndStyle,
|
|
148
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>HTML Highlighting Test</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div class="container">
|
|
10
|
+
<header>
|
|
11
|
+
<h1>Welcome to HTML Highlighting</h1>
|
|
12
|
+
<nav>
|
|
13
|
+
<ul>
|
|
14
|
+
<li><a href="#home">Home</a></li>
|
|
15
|
+
<li><a href="#about">About</a></li>
|
|
16
|
+
<li><a href="#contact">Contact</a></li>
|
|
17
|
+
</ul>
|
|
18
|
+
</nav>
|
|
19
|
+
</header>
|
|
20
|
+
|
|
21
|
+
<main>
|
|
22
|
+
<section>
|
|
23
|
+
<h2>Features</h2>
|
|
24
|
+
<p>This extension now supports <strong>HTML tag highlighting</strong> with intelligent cursor positioning.</p>
|
|
25
|
+
<ul>
|
|
26
|
+
<li>Place cursor on <code><</code> to highlight entire tag</li>
|
|
27
|
+
<li>Place cursor on <code>></code> to highlight content only</li>
|
|
28
|
+
<li>Works with nested tags</li>
|
|
29
|
+
</ul>
|
|
30
|
+
</section>
|
|
31
|
+
</main>
|
|
32
|
+
|
|
33
|
+
<footer>
|
|
34
|
+
<p>© 2024 HTML Highlighter</p>
|
|
35
|
+
</footer>
|
|
36
|
+
</div>
|
|
37
|
+
</body>
|
|
38
|
+
</html>
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"module": "Node16",
|
|
4
|
+
"target": "ES2022",
|
|
5
|
+
"lib": [
|
|
6
|
+
"ES2022"
|
|
7
|
+
],
|
|
8
|
+
"sourceMap": true,
|
|
9
|
+
"rootDir": "src",
|
|
10
|
+
"strict": true /* enable all strict type-checking options */
|
|
11
|
+
/* Additional Checks */
|
|
12
|
+
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
|
13
|
+
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
|
14
|
+
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
|
15
|
+
}
|
|
16
|
+
}
|