├── .gitignore ├── .vscode └── settings.json ├── CHANGELOG.md ├── LICENSE ├── Makefile ├── README.md ├── logo.png ├── package.json ├── resources └── icons │ ├── arrow-left-white.svg │ ├── arrow-left.svg │ ├── arrow-right-white.svg │ └── arrow-right.svg ├── src ├── codelensProvider.js ├── documentSymbolProvider.js ├── extension.js ├── filterCommands.js ├── filterTreeViewProvider.js ├── focusProvider.js ├── foldingRangeProvider.js ├── highlight.js ├── hlconfig.js ├── tree.js └── utils.js ├── syntaxes └── txt.tmLanguage.json └── txt.language-configuration.json /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.code-workspace 3 | *.vsix 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "git.ignoreLimitWarning": true 3 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## v0.2.4 4 | 5 | - Support enable/disable menu context 6 | 7 | ## v0.2.3 8 | 9 | - Support auto import on save 10 | 11 | ## v0.2.2 12 | 13 | - Fixed crash problem on vscode insider 14 | 15 | ## v0.2.1 16 | 17 | - Support german quotation marks 18 | - Fixed the error of heaven and earth branches 19 | 20 | ## v0.2.0 21 | 22 | - Support searching word through right-click menu using a custom search engine({{keyword}} as placeholder) 23 | 24 | ## v0.1.9 25 | 26 | - Fixed some highlight bugs 27 | 28 | ## v0.1.8 29 | 30 | - Fixed some highlight bugs 31 | 32 | ## v0.1.7 33 | 34 | - Fixed some highlight bugs 35 | 36 | ## v0.1.6 37 | 38 | - Support dynamic enable/disable languages 39 | - Support full regular expressions in the filter function 40 | - Fixed some highlight bugs 41 | - Fixed focus mod bug in the filter function 42 | 43 | ## v0.1.5 44 | 45 | - Support filter and focus on lines based on custom regular expressions (forked from [XinyaYang0506/log-analysis](https://github.com/XinyaYang0506/log-analysis)) 46 | - Add .err, .inf, .info, .unx, .desktop files to the supported languages 47 | - Fixed some folding bugs 48 | 49 | ## v0.1.4 50 | 51 | - Add .eds (the extension of industry standard text file format for describing automation equipment) to the supported languages 52 | 53 | ## v0.1.3 54 | 55 | - Support outline for txt files with symbol marks 56 | - Fix some regex rules 57 | 58 | ## v0.1.2 59 | 60 | - Support highlighting current line (forked from [cliffordfajardo/highlight-line-vscode](https://github.com/cliffordfajardo/highlight-line-vscode)) 61 | - Support highlighting multiple selected words in all active editors (forked from [rsbondi/highlight-words](https://github.com/rsbondi/highlight-words)) 62 | 63 | ## v0.1.1 64 | 65 | - Support codelens for Makefile to make running makefile target easily 66 | 67 | ## v0.1.0 68 | 69 | - Support open the file under the current cursor through the right-click menu 70 | - The line would be commented only when the semicolon is at the beginning of the line now 71 | 72 | ## v0.0.9 73 | 74 | - Support folding braces and hypertext marks 75 | 76 | ## v0.0.8 77 | 78 | - Fix bugs 79 | 80 | ## v0.0.7 81 | 82 | - Support fold between section headers(Set "editor.foldingStrategy": "auto") 83 | 84 | ## v0.0.6 85 | 86 | - Fix some bugs 87 | 88 | ## v0.0.5 89 | 90 | - Support chinese punctuation marks 91 | - Add logical "sectin header" level which is highlighted and can be folded(-*-, A. , Part I, * xxx, 一、, etc...) 92 | - Support folding("header"/--- pair) 93 | 94 | ## v0.0.4 95 | 96 | - Support more special symbols 97 | - Fix some bugs 98 | 99 | ## v0.0.3 100 | 101 | - Remove the support for markdown file to avoid conflict with other related extensions 102 | 103 | ## [Unreleased] 104 | 105 | - Initial release 106 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright © 2022 3 | 4 | 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: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | 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. 9 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | vsce package 3 | 4 | publish: 5 | vsce publish 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TXT Syntax 2 | 3 | ## Features 4 | 5 | - Highlight syntax for several text files with dynamic enable/disable languages. 6 | - Open the file under the current cursor through the right-click menu "Open File". 7 | - Search selected word using custom search engine in the embeded simple browser. 8 | - Simple folding and outline function. 9 | - Add codelens for Makefile to make running makefile target easily. 10 | - Highlight current line. 11 | - Highlight multiple selected words in all active editors. 12 | - Filter and focus on lines based on custom regular expressions 13 | 14 | *folding function need you set `"editor.foldingStrategy": "auto"`.* 15 | 16 | *highlight line feature is forked from [cliffordfajardo/highlight-line-vscode](https://github.com/cliffordfajardo/highlight-line-vscode)* 17 | 18 | *highlight words feature is forked from [rsbondi/highlight-words](https://github.com/rsbondi/highlight-words)* 19 | 20 | *filter lines feature is forked from [XinyaYang0506/log-analysis](https://github.com/XinyaYang0506/log-analysis)* 21 | 22 | ## Supported file types 23 | 24 | #### default 25 | 26 | The following type types are supported by default: 27 | 28 | ``` 29 | .txt 30 | .text 31 | .cf 32 | .cnf 33 | .conf 34 | .cfg 35 | .unx 36 | .eds 37 | .log 38 | .ini 39 | .out 40 | .err 41 | .inf 42 | .info 43 | .tmp 44 | .temp 45 | .file 46 | .repo 47 | .plain 48 | .desktop 49 | .properties 50 | ``` 51 | 52 | #### custom 53 | 54 | you can enable/disable every file type(except txt/text type) by any of the following method: 55 | 56 | ```json 57 | // with txtsyntax configuration 58 | "txtsyntax.associations": [ 59 | ".tmp", 60 | ".cnf", 61 | ".log", 62 | ".eds", 63 | ".aaa" 64 | ], 65 | // or with vscode configuration 66 | "files.associations": { 67 | "*.tmp": "txt", 68 | "*.cnf": "txt", 69 | "*.log": "txt", 70 | "*.eds": "txt", 71 | "*.aaa": "txt" 72 | }, 73 | ``` 74 | 75 | ## Folding function 76 | 77 | Text between sections, braces or hypertext markups could be folded. 78 | 79 | Section headers like these: 80 | 81 | ``` 82 | -*- 83 | * xxx 84 | [xxx] 85 | Part I. 86 | Section A 87 | Page 1 88 | A. 89 | 1. 90 | 一 xx 91 | 甲. xxx 92 | 第一章 xxx 93 | 第2回 xxx 94 | 第 3 节 xxx 95 | ... 96 | ``` 97 | 98 | You could set `"files.defaultLanguage": "txt"` or `"files.associations": {"Untitled-*": "txt"}` in **settings.json** to let vscode treat all **Untitled files** as txt files and then txt syntax will be enabled for these files automatically. 99 | In additon, you could also install [Modelines](https://marketplace.visualstudio.com/items?itemName=chrislajoie.vscode-modelines) extension to set a file to a special format. 100 | 101 | **note**: It will override the default highlight schemes supported by visual studio code if you active this extension. 102 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xshrim/vscode-txt-syntax/d00c7d4484b7e66bb53ab013e906cb45b9504acd/logo.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "txt-syntax", 3 | "displayName": "Txt Syntax", 4 | "description": "highlight text files(.txt, .out .tmp, .log, .ini, .cnf ...) and provide general utility tools for text documents", 5 | "version": "0.2.4", 6 | "publisher": "xshrim", 7 | "repository": "https://github.com/xshrim/vscode-txt-syntax", 8 | "icon": "logo.png", 9 | "engines": { 10 | "vscode": "^1.23.0" 11 | }, 12 | "categories": [ 13 | "Programming Languages" 14 | ], 15 | "keywords": [ 16 | "txt", 17 | "text", 18 | "syntax", 19 | "makefile", 20 | "codelens", 21 | "highlight", 22 | "txt folding", 23 | "filter lines", 24 | "highlight line", 25 | "highlight words" 26 | ], 27 | "activationEvents": [ 28 | "*" 29 | ], 30 | "main": "./src/extension.js", 31 | "contributes": { 32 | "languages": [ 33 | { 34 | "id": "txt", 35 | "aliases": [ 36 | "TXT", 37 | "txt" 38 | ], 39 | "extensions": [ 40 | ".txt", 41 | ".text" 42 | ], 43 | "configuration": "./txt.language-configuration.json" 44 | } 45 | ], 46 | "grammars": [ 47 | { 48 | "language": "txt", 49 | "scopeName": "source.txt", 50 | "path": "./syntaxes/txt.tmLanguage.json" 51 | } 52 | ], 53 | "commands": [ 54 | { 55 | "title": "Search Word", 56 | "command": "txtsyntax.searchit", 57 | "category": "TxtSyntax" 58 | }, 59 | { 60 | "title": "Open File", 61 | "command": "txtsyntax.openit", 62 | "category": "TxtSyntax" 63 | }, 64 | { 65 | "title": "Enable CodeLens", 66 | "command": "txtsyntax.enableCodeLens", 67 | "category": "TxtSyntax" 68 | }, 69 | { 70 | "title": "Disable Codelens", 71 | "command": "txtsyntax.disableCodeLens", 72 | "category": "TxtSyntax" 73 | }, 74 | { 75 | "title": "Send text to Terminal", 76 | "command": "txtsyntax.sendText", 77 | "category": "TxtSyntax" 78 | }, 79 | { 80 | "command": "txtsyntax.toggleHighlight", 81 | "title": "Highlight Toggle", 82 | "category": "TxtSyntax" 83 | }, 84 | { 85 | "command": "txtsyntax.removeHighlight", 86 | "title": "Highlight Remove List", 87 | "category": "TxtSyntax" 88 | }, 89 | { 90 | "command": "txtsyntax.cleanHighlights", 91 | "title": "Highlight Clean", 92 | "category": "TxtSyntax" 93 | }, 94 | { 95 | "command": "txtsyntax.toggleRegExpHighlight", 96 | "title": "Highlight Expression", 97 | "category": "TxtSyntax" 98 | }, 99 | { 100 | "command": "txtsyntax.toggleHighlightWithOptions", 101 | "title": "Highlight Selection with Options", 102 | "category": "TxtSyntax" 103 | }, 104 | { 105 | "command": "txtsyntax.setHighlightMode", 106 | "title": "Set Highlight Mode", 107 | "category": "TxtSyntax" 108 | }, 109 | { 110 | "command": "txtsyntax.treeRemoveHighlight", 111 | "title": "Remove", 112 | "category": "TxtSyntax" 113 | }, 114 | { 115 | "command": "txtsyntax.treeHighlightOptions", 116 | "title": "Change Options", 117 | "category": "TxtSyntax" 118 | }, 119 | { 120 | "command": "txtsyntax.toggleSidebar", 121 | "title": "Highlight Toggle Sidebar", 122 | "category": "TxtSyntax" 123 | }, 124 | { 125 | "command": "txtsyntax.findPrevious", 126 | "title": "Highlight Back", 127 | "category": "TxtSyntax", 128 | "icon": { 129 | "light": "resources/icons/arrow-left.svg", 130 | "dark": "resources/icons/arrow-left-white.svg" 131 | } 132 | }, 133 | { 134 | "command": "txtsyntax.findNext", 135 | "title": "Highlight Next", 136 | "category": "TxtSyntax", 137 | "icon": { 138 | "light": "resources/icons/arrow-right.svg", 139 | "dark": "resources/icons/arrow-right-white.svg" 140 | } 141 | }, 142 | { 143 | "command": "txtsyntax.enableHighlight", 144 | "title": "Enable Highlight", 145 | "icon": "$(paintcan)" 146 | }, 147 | { 148 | "command": "txtsyntax.disableHighlight", 149 | "title": "Disable Highlight", 150 | "icon": "$(paintcan)" 151 | }, 152 | { 153 | "command": "txtsyntax.enableVisibility", 154 | "title": "Enable Visbility", 155 | "icon": "$(eye)" 156 | }, 157 | { 158 | "command": "txtsyntax.disableVisibility", 159 | "title": "Disable Visbility", 160 | "icon": "$(eye-closed)" 161 | }, 162 | { 163 | "command": "txtsyntax.toggleFocusMode", 164 | "title": "Toggle Focus Mode", 165 | "icon": "$(symbol-keyword)" 166 | }, 167 | { 168 | "command": "txtsyntax.deleteFilter", 169 | "title": "Delete This Filter", 170 | "icon": "$(dialog-close)" 171 | }, 172 | { 173 | "command": "txtsyntax.editFilter", 174 | "title": "Edit Regex for This Filter", 175 | "icon": "$(edit)" 176 | }, 177 | { 178 | "command": "txtsyntax.addFilter", 179 | "title": "Add a Filter", 180 | "icon": "$(plus)" 181 | }, 182 | { 183 | "command": "txtsyntax.exportFilters", 184 | "title": "Export Filters" 185 | }, 186 | { 187 | "command": "txtsyntax.importFilters", 188 | "title": "Import Filters" 189 | } 190 | ], 191 | "configuration": { 192 | "properties": { 193 | "txtsyntax.searchlink": { 194 | "type": "string", 195 | "default": "https://www.google.com/search?q={{keyword}}" 196 | }, 197 | "txtsyntax.associations": { 198 | "type": "array", 199 | "items": { 200 | "type": "string" 201 | }, 202 | "default": [ 203 | ".ini", 204 | ".cf", 205 | ".cnf", 206 | ".conf", 207 | ".cfg", 208 | ".unx", 209 | ".eds", 210 | ".log", 211 | ".out", 212 | ".err", 213 | ".inf", 214 | ".info", 215 | ".tmp", 216 | ".temp", 217 | ".file", 218 | ".repo", 219 | ".plain", 220 | ".desktop", 221 | ".properties" 222 | ] 223 | }, 224 | "txtsyntax.enableSearchMenu": { 225 | "type": "boolean", 226 | "default": true 227 | }, 228 | "txtsyntax.enableFileMenu": { 229 | "type": "boolean", 230 | "default": true 231 | }, 232 | "txtsyntax.enableCodeLens": { 233 | "type": "boolean", 234 | "default": true 235 | }, 236 | "txtsyntax.enableAutoImport": { 237 | "type": "boolean", 238 | "default": false 239 | }, 240 | "txtsyntax.enableHighlightMenu": { 241 | "type": "boolean", 242 | "default": true 243 | }, 244 | "txtsyntax.enableHighlightLine": { 245 | "type": "boolean", 246 | "default": false 247 | }, 248 | "txtsyntax.highlightLineBorderColor": { 249 | "type": [ 250 | "string" 251 | ], 252 | "default": "#65EAB9", 253 | "description": "Change the border color. (Ex: 'red', '#FFF' #FFFFFFF, 'RGB(255,255,255)','RGB(255, 255, 255. 0.5) )" 254 | }, 255 | "txtsyntax.highlightLineBorderWidth": { 256 | "type": [ 257 | "string" 258 | ], 259 | "default": "1px" 260 | }, 261 | "txtsyntax.highlightLineBorderStyle": { 262 | "type": [ 263 | "string" 264 | ], 265 | "enum": [ 266 | "solid", 267 | "dashed", 268 | "inset", 269 | "double", 270 | "groove", 271 | "outset", 272 | "ridge" 273 | ], 274 | "default": "dashed" 275 | }, 276 | "txtsyntax.highlightColors": { 277 | "default": [ 278 | { 279 | "light": "#b3d9ff", 280 | "dark": "cyan" 281 | }, 282 | { 283 | "light": "#e6ffb3", 284 | "dark": "pink" 285 | }, 286 | { 287 | "light": "#b3b3ff", 288 | "dark": "lightgreen" 289 | }, 290 | { 291 | "light": "#ffd9b3", 292 | "dark": "magenta" 293 | }, 294 | { 295 | "light": "#ffb3ff", 296 | "dark": "cornflowerblue" 297 | }, 298 | { 299 | "light": "#b3ffb3", 300 | "dark": "orange" 301 | }, 302 | { 303 | "light": "#ffff80", 304 | "dark": "green" 305 | }, 306 | { 307 | "light": "#d1e0e0", 308 | "dark": "red" 309 | } 310 | ] 311 | }, 312 | "txtsyntax.highlightBox": { 313 | "default": { 314 | "light": false, 315 | "dark": true 316 | } 317 | }, 318 | "txtsyntax.defaultHighlightMode": { 319 | "default": 0 320 | }, 321 | "txtsyntax.showHighlightSidebar": { 322 | "type": "boolean", 323 | "default": false 324 | } 325 | } 326 | }, 327 | "views": { 328 | "explorer": [ 329 | { 330 | "id": "txtsyntaxHighlightExplore", 331 | "name": "Highlight", 332 | "when": "showSidebar" 333 | }, 334 | { 335 | "id": "filters", 336 | "name": "Filters" 337 | } 338 | ] 339 | }, 340 | "menus": { 341 | "editor/context": [ 342 | { 343 | "command": "txtsyntax.searchit", 344 | "group": "txsyntax", 345 | "when": "config.txtsyntax.enableSearchMenu && editorTextFocus" 346 | }, 347 | { 348 | "command": "txtsyntax.openit", 349 | "group": "txsyntax", 350 | "when": "config.txtsyntax.enableFileMenu && editorTextFocus && resourceLangId == txt" 351 | }, 352 | { 353 | "command": "txtsyntax.toggleHighlight", 354 | "group": "txsyntax", 355 | "when": "config.txtsyntax.enableHighlightMenu && editorTextFocus" 356 | }, 357 | { 358 | "command": "txtsyntax.cleanHighlights", 359 | "group": "txsyntax", 360 | "when": "config.txtsyntax.enableHighlightMenu && editorTextFocus" 361 | }, 362 | { 363 | "command": "txtsyntax.findPrevious", 364 | "group": "txsyntax", 365 | "when": "config.txtsyntax.enableHighlightMenu && editorTextFocus" 366 | }, 367 | { 368 | "command": "txtsyntax.findNext", 369 | "group": "txsyntax", 370 | "when": "config.txtsyntax.enableHighlightMenu && editorTextFocus" 371 | } 372 | ], 373 | "view/item/context": [ 374 | { 375 | "command": "txtsyntax.treeRemoveHighlight", 376 | "when": "view == txtsyntaxHighlightExplore" 377 | }, 378 | { 379 | "command": "txtsyntax.treeHighlightOptions", 380 | "when": "view == txtsyntaxHighlightExplore" 381 | }, 382 | { 383 | "command": "txtsyntax.findPrevious", 384 | "when": "view == txtsyntaxHighlightExplore", 385 | "group": "inline" 386 | }, 387 | { 388 | "command": "txtsyntax.findNext", 389 | "when": "view == txtsyntaxHighlightExplore", 390 | "group": "inline" 391 | }, 392 | { 393 | "command": "txtsyntax.editFilter", 394 | "when": "view == filters", 395 | "group": "inline@1" 396 | }, 397 | { 398 | "command": "txtsyntax.disableHighlight", 399 | "when": "view == filters && viewItem =~ /^lit/", 400 | "group": "inline@2" 401 | }, 402 | { 403 | "command": "txtsyntax.enableHighlight", 404 | "when": "view == filters && viewItem =~ /^unlit/", 405 | "group": "inline@3" 406 | }, 407 | { 408 | "command": "txtsyntax.disableVisibility", 409 | "when": "view == filters && viewItem =~ /-visible/", 410 | "group": "inline@4" 411 | }, 412 | { 413 | "command": "txtsyntax.enableVisibility", 414 | "when": "view == filters && viewItem =~ /-invisible/", 415 | "group": "inline@5" 416 | }, 417 | { 418 | "command": "txtsyntax.deleteFilter", 419 | "when": "view == filters", 420 | "group": "inline@6" 421 | } 422 | ], 423 | "view/title": [ 424 | { 425 | "command": "txtsyntax.addFilter", 426 | "when": "view == filters", 427 | "group": "navigation" 428 | }, 429 | { 430 | "command": "txtsyntax.toggleFocusMode", 431 | "when": "view == filters", 432 | "group": "navigation" 433 | }, 434 | { 435 | "command": "txtsyntax.importFilters", 436 | "when": "view == filters" 437 | }, 438 | { 439 | "command": "txtsyntax.exportFilters", 440 | "when": "view == filters" 441 | } 442 | ] 443 | } 444 | }, 445 | "__metadata": { 446 | "id": "c5900888-28e9-40d6-84d0-d1645e62f4cc", 447 | "publisherId": "xshrim.txt-syntax", 448 | "publisherDisplayName": "xshrim" 449 | } 450 | } -------------------------------------------------------------------------------- /resources/icons/arrow-left-white.svg: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /resources/icons/arrow-left.svg: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /resources/icons/arrow-right-white.svg: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /resources/icons/arrow-right.svg: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/codelensProvider.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.CodelensProvider = void 0; 4 | const vscode = require("vscode"); 5 | /** 6 | * CodelensProvider 7 | */ 8 | class CodelensProvider { 9 | constructor() { 10 | this.codeLenses = []; 11 | this._onDidChangeCodeLenses = new vscode.EventEmitter(); 12 | this.onDidChangeCodeLenses = this._onDidChangeCodeLenses.event; 13 | this.regex = /^(\w[\w\.\-]*):.*$/g; 14 | vscode.workspace.onDidChangeConfiguration((_) => { 15 | this._onDidChangeCodeLenses.fire(); 16 | }); 17 | } 18 | provideCodeLenses(document, token) { 19 | if (vscode.workspace.getConfiguration("txtsyntax").get("enableCodeLens", true)) { 20 | this.codeLenses = []; 21 | const regex = new RegExp(this.regex); 22 | var lines = document.getText().split("\n"); 23 | lines.forEach((lineText, lineNumber) => { 24 | if (regex.test(lineText)) { 25 | const position = new vscode.Position(lineNumber, 0); 26 | const range = new vscode.Range(position, position); 27 | this.codeLenses.push(new vscode.CodeLens(range, { 28 | title: 'make', 29 | //command: 'workbench.action.terminal.sendSequence', 30 | command: 'txtsyntax.sendText', 31 | arguments: [{ text: "make " + lineText.split(":")[0] + "\u000D" }], 32 | })); 33 | } 34 | }); 35 | // let matches; 36 | // while ((matches = regex.exec(text)) !== null) { 37 | // const line = document.lineAt(document.positionAt(matches.index).line); 38 | // const indexOf = line.text.indexOf(matches[0]); 39 | // const position = new vscode.Position(line.lineNumber, indexOf); 40 | // const range = document.getWordRangeAtPosition(position, new RegExp(this.regex)); 41 | // if (range) { 42 | // // const command = { 43 | // // command = "workbench.action.terminal.sendSequence", 44 | // // title = line.text 45 | // // }; 46 | // this.codeLenses.push(new vscode.CodeLens(range, { 47 | // title: 'make', 48 | // command: 'workbench.action.terminal.sendSequence', 49 | // arguments: [{ text: "make " + line.text.split(":")[0] + "\u000D" }], 50 | // })); 51 | // } 52 | // } 53 | return this.codeLenses; 54 | } 55 | return []; 56 | } 57 | resolveCodeLens(codeLens, token) { 58 | if (vscode.workspace.getConfiguration("txtsyntax").get("enableCodeLens", true)) { 59 | codeLens.command = { 60 | title: "make", 61 | tooltip: "run make command for this target", 62 | command: "txtsyntax.codelensAction", 63 | arguments: ["hello", false] 64 | }; 65 | return codeLens; 66 | } 67 | return null; 68 | } 69 | } 70 | exports.CodelensProvider = CodelensProvider; -------------------------------------------------------------------------------- /src/documentSymbolProvider.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.DocumentSymbolProvider = void 0; 4 | const vscode = require("vscode"); 5 | /** 6 | * DocumentSymbolProvider 7 | */ 8 | class DocumentSymbolProvider { 9 | constructor() { 10 | this.symbols = []; 11 | this._onDidChangeSymbols = new vscode.EventEmitter(); 12 | this.regex = /^-\*-|^\*[^\S\r\n]|^[A-Z0-9]+\.\s|^\[.+\]\s*|^(Section|SECTION|Chapter|CHAPTER|Sheet|SHEET|Season|SEASON|Period|PERIOD|Round|ROUND|Class|CLASS|Term|TERM|Part|PART|Page|PAGE|Segment|SEGMENT|Paragraph|PARAGRAPH|Lesson|LESSON|Region|REGION|Step|STEP|Level|LEVEL|Set|SET|Grade|GRADE|Year|YEAR|Month|MONTH|Week|WEEK|Day|DAY)[^\S\r\n][A-Z0-9]+\.?($|[^\S\r\n])|^(第[^\S\r\n]|第)?[一二三四五六七八九十百千万亿兆零壹贰叁肆伍陆柒捌玖拾佰仟甲乙丙丁戊己庚辛壬癸子丑寅卯辰巳午未申酉戌亥]+($|[^\S\r\n])?[章节篇部首回手课页段组卷区场合季级集任步条件年月日周天轮个项类期话例]?($|[\.、]|[^\S\r\n])|^(第[^\S\r\n]|第)?[0123456789]+[^\S\r\n]?[章节篇部首回手课页段组卷区场合季级集任步条件年月日周天轮个项类期话例]($|[\.、]|[^\S\r\n])|^(第[^\S\r\n]|第)[0123456789]+($|[\.、]|[^\S\r\n])/; 13 | vscode.workspace.onDidChangeConfiguration((_) => { 14 | this._onDidChangeSymbols.fire(); 15 | }); 16 | } 17 | // format(cmd) { 18 | // return cmd.substr(1).toLowerCase().replace(/^\w/, c => c.toUpperCase()); 19 | // } 20 | provideDocumentSymbols(document, token) { 21 | return new Promise((resolve, reject) => { 22 | this.symbols = []; 23 | // let symbolkind_marker = vscode.SymbolKind.Field; 24 | // let symbolkind_run = vscode.SymbolKind.Event; 25 | // let symbolkind_cmd = vscode.SymbolKind.Function; 26 | for (var i = 0; i < document.lineCount; i++) { 27 | var line = document.lineAt(i); 28 | // let tokens = line.text.split(" "); 29 | if (this.regex.test(line.text)) { 30 | let symbol = new vscode.DocumentSymbol(line.text, '', vscode.SymbolKind.Field, line.range, line.range); // this.format(tokens[0]) + " " + tokens[1] 31 | this.symbols.push(symbol) 32 | } 33 | } 34 | resolve(this.symbols); 35 | }); 36 | } 37 | } 38 | exports.DocumentSymbolProvider = DocumentSymbolProvider; 39 | -------------------------------------------------------------------------------- /src/extension.js: -------------------------------------------------------------------------------- 1 | const vscode = require('vscode'); 2 | const hlconfig = require("./hlconfig"); 3 | const path = require("path"); 4 | const process = require('process'); 5 | const clp = require("./codelensProvider"); 6 | const dsp = require("./documentSymbolProvider"); 7 | const hl = require("./highlight"); 8 | const utils = require("./utils"); 9 | const filterCommands = require("./filterCommands"); 10 | const focusProvider = require("./focusProvider"); 11 | const filterTreeViewProvider = require("./filterTreeViewProvider"); 12 | const { deepStrictEqual } = require('assert'); 13 | 14 | // https://macromates.com/manual/en/language_grammars 15 | // https://xshrim.visualstudio.com/_usersSettings/tokens 16 | // https://code.visualstudio.com/api/references/icons-in-labels 17 | 18 | //GLOBAL to be used for activate and deactivate 19 | let storageUri; 20 | 21 | function selectTerminal() { 22 | if (vscode.window.terminals.length === 0) { 23 | var term = vscode.window.createTerminal(); 24 | vscode.window.activeTerminal = term 25 | term.show(true); 26 | return term; 27 | } else if (vscode.window.activeTerminal === undefined) { 28 | var term = vscode.window.terminals[0]; 29 | vscode.window.activeTerminal = term; 30 | term.show(true); 31 | return term; 32 | } else { 33 | vscode.window.activeTerminal.show(true); 34 | return vscode.window.activeTerminal; 35 | } 36 | } 37 | 38 | function revealLine(line) { 39 | var reviewType = vscode.TextEditorRevealType.InCenter; 40 | if (line === vscode.window.activeTextEditor.selection.active.line) { 41 | reviewType = vscode.TextEditorRevealType.InCenterIfOutsideViewport; 42 | } 43 | const newSe = new vscode.Selection(line, 0, line, 0); 44 | vscode.window.activeTextEditor.selection = newSe; 45 | vscode.window.activeTextEditor.revealRange(newSe, reviewType); 46 | } 47 | 48 | function revealPosition(line, column) { 49 | if (isNaN(column)) { 50 | revealLine(line); 51 | } else { 52 | var reviewType = vscode.TextEditorRevealType.InCenter; 53 | if (line === vscode.window.activeTextEditor.selection.active.line) { 54 | reviewType = vscode.TextEditorRevealType.InCenterIfOutsideViewport; 55 | } 56 | const newSe = new vscode.Selection(line, column, line, column); 57 | vscode.window.activeTextEditor.selection = newSe; 58 | vscode.window.activeTextEditor.revealRange(newSe, reviewType); 59 | } 60 | } 61 | 62 | async function activate(context) { 63 | const config = vscode.workspace.getConfiguration("txtsyntax"); 64 | /////////////// outline 65 | const documentSymbolProvider = new dsp.DocumentSymbolProvider(); 66 | context.subscriptions.push(vscode.languages.registerDocumentSymbolProvider("txt", documentSymbolProvider)); // { scheme: "file", language: "txt" } 67 | 68 | /////////////// codelens 69 | const codelensProvider = new clp.CodelensProvider(); 70 | 71 | vscode.languages.registerCodeLensProvider("makefile", codelensProvider); 72 | vscode.commands.registerCommand("txtsyntax.enableCodeLens", () => { 73 | vscode.workspace.getConfiguration("txtsyntax").update("enableCodeLens", true, true); 74 | }); 75 | 76 | vscode.commands.registerCommand("txtsyntax.disableCodeLens", () => { 77 | vscode.workspace.getConfiguration("txtsyntax").update("enableCodeLens", false, true); 78 | }); 79 | 80 | vscode.commands.registerCommand("txtsyntax.codelensAction", (args) => { 81 | vscode.window.showInformationMessage(`CodeLens action clicked with args=${args}`); 82 | }); 83 | 84 | vscode.commands.registerCommand('txtsyntax.sendText', (args) => { 85 | var term = selectTerminal(); 86 | term.sendText(args.text); 87 | }); 88 | 89 | /////////////// custom file associations 90 | let associations = config.get("associations"); 91 | if (associations.length > 0) { 92 | vscode.window.visibleTextEditors.forEach(editor => { 93 | if (editor === undefined || editor.document === undefined || editor.document.isClosed) { 94 | return 95 | }; 96 | 97 | let fileExt = path.extname(editor.document.fileName).toLowerCase(); 98 | if (fileExt == "") { 99 | return 100 | }; 101 | 102 | if (associations.includes(fileExt)) { 103 | vscode.languages.setTextDocumentLanguage(editor.document, "txt"); 104 | }; 105 | }); 106 | }; 107 | 108 | vscode.workspace.onDidOpenTextDocument((doc) => { 109 | if (associations.length < 1 || doc === undefined || doc.isClosed) { 110 | return 111 | }; 112 | 113 | let fileExt = path.extname(doc.fileName).toLowerCase(); 114 | if (fileExt == "") { 115 | return 116 | }; 117 | 118 | if (associations.includes(fileExt)) { 119 | vscode.languages.setTextDocumentLanguage(doc, "txt"); 120 | }; 121 | }); 122 | 123 | // vscode.window.onDidChangeActiveTextEditor((editor) => { 124 | // if (editor === undefined || editor.document === undefined || editor.document.isClosed) { 125 | // return 126 | // }; 127 | 128 | // let fileExt = path.extname(editor.document.fileName).toLowerCase(); 129 | // if (fileExt == "") { 130 | // return 131 | // }; 132 | // console.log("========", fileExt) 133 | 134 | // if (associations.includes(fileExt)) { 135 | // vscode.languages.setTextDocumentLanguage(editor.document, "txt"); 136 | // } 137 | // }); 138 | 139 | 140 | /////////////// auto import 141 | if (config.get("enableAutoImport", true)) { 142 | vscode.workspace.onWillSaveTextDocument((e) => { 143 | if (vscode.workspace.getConfiguration("editor").get("formatOnSave")) { 144 | // auto import 145 | //vscode.commands.executeCommand('editor.action.sourceAction', { 146 | // "kind": "source.addMissingImports", 147 | // "apply": "first" 148 | //}); 149 | vscode.commands.executeCommand("editor.action.organizeImports"); 150 | // auto format 151 | // vscode.commands.executeCommand( 152 | // "editor.action.format", 153 | // activeEditor?.document.uri 154 | // ); 155 | } 156 | }) 157 | 158 | } 159 | 160 | /////////////// highlight line 161 | if (config.get("enableHighlightLine", true)) { 162 | let decorationType = getDecorationTypeFromConfig(); 163 | let activeEditor = vscode.window.activeTextEditor; 164 | let lastActivePosition; 165 | 166 | vscode.window.onDidChangeActiveTextEditor(() => { 167 | try { 168 | activeEditor = vscode.window.activeTextEditor 169 | updateDecorations(decorationType) 170 | } catch (error) { 171 | console.error("Error from ' window.onDidChangeActiveTextEditor' -->", error) 172 | } finally { 173 | if (activeEditor !== undefined) { 174 | lastActivePosition = new vscode.Position(activeEditor.selection.active.line, activeEditor.selection.active.character); 175 | } 176 | } 177 | }) 178 | 179 | vscode.window.onDidChangeTextEditorSelection(() => { 180 | activeEditor = vscode.window.activeTextEditor; 181 | updateDecorations(decorationType); 182 | }) 183 | 184 | vscode.workspace.onDidChangeConfiguration(() => { 185 | //clear all decorations 186 | decorationType.dispose(); 187 | decorationType = getDecorationTypeFromConfig(); 188 | updateDecorations(decorationType, true) 189 | }) 190 | 191 | function getDecorationTypeFromConfig() { 192 | const borderColor = config.get("highlightLineBorderColor"); 193 | const borderWidth = config.get("highlightLineBorderWidth"); 194 | const borderStyle = config.get("highlightLineBorderStyle"); 195 | const decorationType = vscode.window.createTextEditorDecorationType({ 196 | isWholeLine: true, 197 | borderWidth: `0 0 ${borderWidth} 0`, 198 | borderStyle: `${borderStyle}`, //TODO: file bug, this shouldn't throw a lint error. 199 | borderColor 200 | }) 201 | return decorationType; 202 | } 203 | 204 | function updateDecorations(decorationType, updateAllVisibleEditors = false) { 205 | try { 206 | if (updateAllVisibleEditors) { 207 | vscode.window.visibleTextEditors.forEach((editor) => { 208 | const currentPosition = editor.selection.active; 209 | const currentLine = editor.selection.active.line; 210 | const newDecoration = { range: new vscode.Range(currentPosition, currentPosition) }; 211 | editor.setDecorations(decorationType, [newDecoration]); 212 | }); 213 | } 214 | 215 | //edit only currently active editor 216 | else { 217 | vscode.window.visibleTextEditors.forEach((editor) => { 218 | if (editor !== vscode.window.activeTextEditor) return; 219 | 220 | const currentPosition = editor.selection.active 221 | const newDecoration = { range: new vscode.Range(currentPosition, currentPosition) } 222 | 223 | if (lastActivePosition === undefined) { 224 | editor.setDecorations(decorationType, [newDecoration]) 225 | } else { 226 | const editorHasChangedLines = lastActivePosition.line !== currentPosition.line 227 | const isNewEditor = activeEditor.document.lineCount === 1 && lastActivePosition.line === 0 && lastActivePosition.character == 0; 228 | if (editorHasChangedLines || isNewEditor) { 229 | editor.setDecorations(decorationType, [newDecoration]) 230 | } 231 | } 232 | }); 233 | } 234 | } 235 | catch (error) { 236 | console.error("Error from ' updateDecorations' -->", error) 237 | } finally { 238 | if (activeEditor !== undefined) { 239 | lastActivePosition = new vscode.Position(activeEditor.selection.active.line, activeEditor.selection.active.character); 240 | } 241 | } 242 | } 243 | }; 244 | 245 | ////////////// highlight words 246 | let highlight = new hl.default(); 247 | let configValues; 248 | vscode.commands.registerCommand('txtsyntax.toggleRegExpHighlight', function () { 249 | vscode.window.showInputBox({ prompt: 'Enter expression' }) 250 | .then(word => { 251 | highlight.toggleRegExp(word); 252 | }); 253 | }); 254 | vscode.commands.registerCommand('txtsyntax.toggleHighlight', function () { 255 | highlight.toggleSelected(); 256 | }); 257 | vscode.commands.registerCommand('txtsyntax.toggleHighlightWithOptions', function () { 258 | highlight.toggleSelected(true); 259 | }); 260 | vscode.commands.registerCommand('txtsyntax.removeHighlight', function () { 261 | vscode.window.showQuickPick(highlight.getWords().concat([{ expression: '* All *', wholeWord: false, ignoreCase: false }]).map(w => { 262 | return { 263 | label: w.expression, 264 | description: (w.ignoreCase ? 'i' : '') + (w.wholeWord ? 'w' : ''), 265 | detail: '' 266 | }; 267 | })) 268 | .then(word => { 269 | highlight.remove(word); 270 | }); 271 | }); 272 | vscode.commands.registerCommand('txtsyntax.treeRemoveHighlight', e => { 273 | highlight.remove(e); 274 | }); 275 | vscode.commands.registerCommand('txtsyntax.treeHighlightOptions', e => { 276 | highlight.updateOptions(e.label); 277 | }); 278 | vscode.commands.registerCommand('txtsyntax.cleanHighlights', function () { 279 | highlight.clearAll(); 280 | }); 281 | vscode.commands.registerCommand('txtsyntax.toggleSidebar', function () { 282 | configValues.showSidebar = !configValues.showSidebar; 283 | vscode.commands.executeCommand('setContext', 'showSidebar', configValues.showSidebar); 284 | }); 285 | vscode.commands.registerCommand('txtsyntax.setHighlightMode', function () { 286 | const modes = ['Default', 'Whole Word', 'Ignore Case', 'Both'].map((s, i) => highlight.getMode() == i ? s + ' ✅' : s); 287 | vscode.window.showQuickPick(modes).then(option => { 288 | if (typeof option === 'undefined') 289 | return; 290 | highlight.setMode(modes.indexOf(option)); 291 | }); 292 | }); 293 | function next(e, wrap) { 294 | const doc = vscode.window.activeTextEditor.document; 295 | const ed = vscode.window.activeTextEditor; 296 | const offset = wrap ? 0 : doc.offsetAt(ed.selection.active); 297 | const nextStart = wrap ? 0 : 1; 298 | const text = doc.getText(); 299 | const slice = text.slice(offset + nextStart); 300 | const opts = e.highlight.ignoreCase ? 'i' : ''; 301 | const expression = e.highlight.wholeWord ? '\\b' + e.highlight.expression + '\\b' : e.highlight.expression; 302 | const re = new RegExp(expression, opts); 303 | const pos = slice.search(re); 304 | if (pos == -1) { 305 | if (!wrap) { 306 | next(e, true); 307 | } // wrap 308 | else 309 | highlight.getLocationIndex(e.highlight.expression, new vscode.Range(new vscode.Position(1, 1), new vscode.Position(1, 1))); 310 | return; 311 | } 312 | const word = slice.match(re); 313 | const start = doc.positionAt(pos + offset + nextStart); 314 | const end = new vscode.Position(start.line, start.character + word[0].length); 315 | const range = new vscode.Range(start, end); 316 | vscode.window.activeTextEditor.revealRange(range); 317 | vscode.window.activeTextEditor.selection = new vscode.Selection(start, start); 318 | highlight.getLocationIndex(e.highlight.expression, range); 319 | } 320 | vscode.commands.registerCommand('txtsyntax.findNext', e => { 321 | next(e); 322 | }); 323 | function prev(e, wrap) { 324 | const doc = vscode.window.activeTextEditor.document; 325 | const ed = vscode.window.activeTextEditor; 326 | const iAmHere = ed.selection.active; 327 | const offset = doc.offsetAt(iAmHere); 328 | const text = doc.getText(); 329 | const slice = text.slice(0, offset); 330 | const opts = e.highlight.ignoreCase ? 'gi' : 'g'; 331 | const expression = e.highlight.wholeWord ? '\\b' + e.highlight.expression + '\\b' : e.highlight.expression; 332 | const re = new RegExp(expression, opts); 333 | const pos = slice.search(re); 334 | if (pos == -1) { 335 | if (!wrap) { 336 | if (offset != 0) { 337 | const home = doc.positionAt(text.length - 1); 338 | vscode.window.activeTextEditor.selection = new vscode.Selection(home, home); 339 | prev(e, true); 340 | return; 341 | } 342 | } 343 | else 344 | highlight.getLocationIndex(e.highlight.expression, new vscode.Range(new vscode.Position(1, 1), new vscode.Position(1, 1))); 345 | } 346 | let word; 347 | let found; 348 | let index; 349 | while ((found = re.exec(slice)) !== null) { 350 | index = re.lastIndex; 351 | word = found[0]; 352 | //console.log('last index', index); 353 | } 354 | const start = doc.positionAt(index - word.length); 355 | const range = new vscode.Range(start, start); 356 | vscode.window.activeTextEditor.revealRange(range); 357 | vscode.window.activeTextEditor.selection = new vscode.Selection(start, start); 358 | highlight.getLocationIndex(e.highlight.expression, range); 359 | } 360 | vscode.commands.registerCommand('txtsyntax.findPrevious', e => { 361 | prev(e); 362 | }); 363 | updateConfig(); 364 | function updateConfig() { 365 | associations = vscode.workspace.getConfiguration("txtsyntax").get("associations"); 366 | configValues = hlconfig.default.getConfigValues(); 367 | highlight.setDecorators(configValues.decorators); 368 | highlight.setMode(configValues.defaultMode); 369 | vscode.commands.executeCommand('setContext', 'showSidebar', configValues.showSidebar); 370 | } 371 | let activeEditor = vscode.window.activeTextEditor; 372 | if (activeEditor) { 373 | triggerUpdateDecorations(); 374 | } 375 | vscode.workspace.onDidChangeConfiguration(() => { 376 | updateConfig(); 377 | }); 378 | vscode.window.onDidChangeVisibleTextEditors(function (editor) { 379 | highlight.updateDecorations(); 380 | }, null, context.subscriptions); 381 | vscode.workspace.onDidChangeTextDocument(function (event) { 382 | activeEditor = vscode.window.activeTextEditor; 383 | if (activeEditor && event.document === activeEditor.document) { 384 | triggerUpdateDecorations(); 385 | } 386 | }, null, context.subscriptions); 387 | var timeout = null; 388 | function triggerUpdateDecorations() { 389 | if (timeout) { 390 | clearTimeout(timeout); 391 | } 392 | timeout = setTimeout(() => { 393 | highlight.updateActive(); 394 | }, 500); 395 | }; 396 | 397 | ////////////// filter lines 398 | storageUri = context.globalStorageUri; //get the store path 399 | utils.cleanUpIconFiles(storageUri); //clean up the old icon files 400 | const filterArr = []; 401 | const state = { 402 | inFocusMode: false, 403 | filterArr, 404 | decorations: [], 405 | disposableFoldingRange: null, 406 | filterTreeViewProvider: new filterTreeViewProvider.FilterTreeViewProvider(filterArr), 407 | focusProvider: new focusProvider.FocusProvider(filterArr), 408 | storageUri 409 | }; 410 | //tell vs code to open focus:... uris with state.focusProvider 411 | vscode.workspace.registerTextDocumentContentProvider('focus', state.focusProvider); 412 | //register filterTreeViewProvider under id 'filters' which gets attached 413 | //to the file explorer according to package.json's contributes>views>explorer 414 | vscode.window.registerTreeDataProvider('filters', state.filterTreeViewProvider); 415 | //Add events listener 416 | var disposableOnDidChangeVisibleTextEditors = vscode.window.onDidChangeVisibleTextEditors(event => { 417 | filterCommands.refreshEditors(state); 418 | }); 419 | context.subscriptions.push(disposableOnDidChangeVisibleTextEditors); 420 | var disposableOnDidChangeTextDocument = vscode.workspace.onDidChangeTextDocument(event => { 421 | filterCommands.refreshEditors(state); 422 | }); 423 | context.subscriptions.push(disposableOnDidChangeTextDocument); 424 | var disposableOnDidChangeActiveTextEditor = vscode.window.onDidChangeActiveTextEditor(event => { 425 | //update the filter counts for the current activate editor 426 | filterCommands.applyHighlight(state, vscode.window.visibleTextEditors); 427 | state.filterTreeViewProvider.refresh(); 428 | }); 429 | context.subscriptions.push(disposableOnDidChangeActiveTextEditor); 430 | //register commands 431 | let disposableExport = vscode.commands.registerCommand("txtsyntax.exportFilters", () => filterCommands.exportFilters(state)); 432 | context.subscriptions.push(disposableExport); 433 | let disposableImport = vscode.commands.registerCommand("txtsyntax.importFilters", () => filterCommands.importFilters(state)); 434 | context.subscriptions.push(disposableImport); 435 | let disposableEnableVisibility = vscode.commands.registerCommand("txtsyntax.enableVisibility", (filterTreeItem) => filterCommands.setVisibility(true, filterTreeItem, state)); 436 | context.subscriptions.push(disposableEnableVisibility); 437 | let disposableDisableVisibility = vscode.commands.registerCommand("txtsyntax.disableVisibility", (filterTreeItem) => filterCommands.setVisibility(false, filterTreeItem, state)); 438 | context.subscriptions.push(disposableDisableVisibility); 439 | let disposableToggleFocusMode = vscode.commands.registerCommand("txtsyntax.toggleFocusMode", () => filterCommands.toggleFocusMode(state)); 440 | context.subscriptions.push(disposableToggleFocusMode); 441 | let disposibleAddFilter = vscode.commands.registerCommand("txtsyntax.addFilter", () => filterCommands.addFilter(state)); 442 | context.subscriptions.push(disposibleAddFilter); 443 | let disposibleEditFilter = vscode.commands.registerCommand("txtsyntax.editFilter", (filterTreeItem) => filterCommands.editFilter(filterTreeItem, state)); 444 | context.subscriptions.push(disposibleEditFilter); 445 | let disposibleDeleteFilter = vscode.commands.registerCommand("txtsyntax.deleteFilter", (filterTreeItem) => filterCommands.deleteFilter(filterTreeItem, state)); 446 | context.subscriptions.push(disposibleDeleteFilter); 447 | let disposibleEnableHighlight = vscode.commands.registerCommand("txtsyntax.enableHighlight", (filterTreeItem) => filterCommands.setHighlight(true, filterTreeItem, state)); 448 | context.subscriptions.push(disposibleEnableHighlight); 449 | let disposibleDisableHighlight = vscode.commands.registerCommand("txtsyntax.disableHighlight", (filterTreeItem) => filterCommands.setHighlight(false, filterTreeItem, state)); 450 | context.subscriptions.push(disposibleDisableHighlight); 451 | 452 | ////////////// open codelf 453 | vscode.commands.registerCommand("txtsyntax.searchit", (documentObj) => { 454 | // var f = vscode.Uri.file(documentObj.fsPath); 455 | var editor = vscode.window.activeTextEditor 456 | if (editor) { 457 | var keyword = editor.document.getText(editor.selection); 458 | if (!keyword) { 459 | const range = editor.document.getWordRangeAtPosition(editor.selection.start); 460 | if (range) { 461 | keyword = editor.document.getText(range); 462 | } 463 | } 464 | if (keyword) { 465 | let searchlink = vscode.workspace.getConfiguration("txtsyntax").get("searchlink"); 466 | if (!searchlink) { 467 | searchlink = "https://www.google.com/search?q={{keyword}}"; 468 | } 469 | searchlink = searchlink.replace(/{{keyword}}/g, keyword); 470 | // var searchlink = `https://unbug.github.io/codelf/#${keyword}` 471 | vscode.commands.executeCommand("simpleBrowser.show", searchlink); 472 | } 473 | } 474 | }); 475 | 476 | ////////////// open file 477 | vscode.commands.registerCommand("txtsyntax.openit", (documentObj) => { 478 | // var f = vscode.Uri.file(documentObj.fsPath); 479 | var editor = vscode.window.activeTextEditor 480 | if (editor) { 481 | var range = editor.document.getWordRangeAtPosition(editor.selection.active, /(\.{0,2}|~)(\w:\\|file:\/\/\/|\/)[\w\.\/\-\=\+:@%&\(\)\<\>\[\]\{\}\\]*\.?\w*/g) 482 | //var text = editor.document.getText(editor.selection); 483 | var fpath = editor.document.getText(range) 484 | if (encodeURI(fpath).match(/%0A/g) || encodeURI(fpath).match(/\n/g) || fpath.indexOf(".") == 0) { 485 | fpath = editor.document.getText(editor.document.getWordRangeAtPosition(editor.selection.active, /\S+/g)) 486 | var currentlyOpenTabfileDir = path.dirname(vscode.window.activeTextEditor.document.fileName) 487 | fpath = path.join(currentlyOpenTabfileDir, fpath) 488 | } else if (fpath.indexOf("~") == 0) { 489 | fpath = fpath.replace("~", process.env.HOME) 490 | } else if (fpath.indexOf("file:///") == 0) { 491 | fpath = fpath.replace("file:///", "/") 492 | } 493 | // while (fpath.indexOf("~") != 0 && fpath.indexOf("/") != 0 && fpath.indexOf(".") != 0 && fpath.indexOf(":") != 1) {} 494 | var f = vscode.Uri.file(fpath); 495 | vscode.workspace.openTextDocument(f).then(doc => { 496 | vscode.window.showTextDocument(doc).then(() => { 497 | }) 498 | }) 499 | } 500 | // var line = vscode.window.activeTextEditor ? vscode.window.activeTextEditor.selection.active.line : undefined; 501 | // var column = vscode.window.activeTextEditor ? vscode.window.activeTextEditor.viewColumn : undefined; 502 | // var selection = vscode.window.activeTextEditor ? vscode.window.activeTextEditor.selection : undefined; 503 | // console.log(line, column, selection); 504 | // var f = vscode.Uri.file("README.md"); 505 | // vscode.workspace.openTextDocument(f).then(doc => { 506 | // vscode.window.showTextDocument(doc).then(() => { 507 | // lineInt = parseInt(line, 10); 508 | // columnInt = parseInt(column, 10); 509 | // console.log(lineInt, columnInt); 510 | // revealPosition(lineInt - 1, columnInt - 1); 511 | // }) 512 | // }) 513 | }); 514 | 515 | ////////////// txt syntax 516 | disposable = vscode.languages.registerFoldingRangeProvider('txt', { //{ scheme: 'file', language: 'txt' } 517 | provideFoldingRanges(document, context, token) { 518 | // console.log('folding range invoked'); // comes here on every character edit 519 | let sectionStart = -1, CodeBlocks = [], HtmlBlocks = new Array(), FoldingRanges = []; 520 | let codeBlockLeftRegex = /^[^\r\n]*\{/, codeBlockRightRegex = /^[^\r\n]*\}/, codeBlockMiddleRegex = /^[^\r\n]*\}[^\r\n]*\{/; 521 | // let htmlBlockStartRegex = /^[^\S\r\n]*\<([^/\s]+)\>/, htmlBlockEndRegex = /^[^\S\r\n]*\<\/([^\s]+)\>/; 522 | let htmlBlockStartRegex = /<([^/\s]+)\s*.*\>/, htmlBlockEndRegex = /\<\/([^\s]+)\>/; 523 | let re = /^-\*-|^\*[^\S\r\n]|^[A-Z0-9]+\.\s|^\[.+\]\s*|^(Section|SECTION|Chapter|CHAPTER|Sheet|SHEET|Season|SEASON|Period|PERIOD|Round|ROUND|Class|CLASS|Term|TERM|Part|PART|Page|PAGE|Segment|SEGMENT|Paragraph|PARAGRAPH|Lesson|LESSON|Region|REGION|Step|STEP|Level|LEVEL|Set|SET|Grade|GRADE|Year|YEAR|Month|MONTH|Week|WEEK|Day|DAY)[^\S\r\n][A-Z0-9]+\.?($|[^\S\r\n])|^(第[^\S\r\n]|第)?[一二三四五六七八九十百千万亿兆零壹贰叁肆伍陆柒捌玖拾佰仟甲乙丙丁戊己庚辛壬癸子丑寅卯辰巳午未申酉戌亥]+($|[^\S\r\n])?[章节篇部首回手课页段组卷区场合季级集任步条件年月日周天轮个项类期话例]?($|[\.、]|[^\S\r\n])|^(第[^\S\r\n]|第)?[0123456789]+[^\S\r\n]?[章节篇部首回手课页段组卷区场合季级集任步条件年月日周天轮个项类期话例]($|[\.、]|[^\S\r\n])|^(第[^\S\r\n]|第)[0123456789]+($|[\.、]|[^\S\r\n])/; // regex to detect start of region 524 | 525 | for (let i = 0; i < document.lineCount; i++) { 526 | let line = document.lineAt(i).text; 527 | if (codeBlockLeftRegex.test(line) && !codeBlockMiddleRegex.test(line)) { 528 | let tmp = /^[^\r\n]*\{[^\r\n]*\}/; 529 | if (!tmp.test(line)) { 530 | CodeBlocks.push(i); 531 | } 532 | } else if (codeBlockRightRegex.test(line) && CodeBlocks.length > 0) { 533 | codeBlockStart = CodeBlocks.pop(); 534 | FoldingRanges.push(new vscode.FoldingRange(codeBlockStart, i - 1, vscode.FoldingRangeKind.Region)); 535 | if (codeBlockMiddleRegex.test(line)) { 536 | CodeBlocks.push(i); 537 | } 538 | } else if (htmlBlockStartRegex.test(line)) { 539 | let item = htmlBlockStartRegex.exec(line)[1]; 540 | if (HtmlBlocks[item] == undefined) { 541 | HtmlBlocks[item] = []; 542 | } 543 | HtmlBlocks[item].push(i); 544 | } else if (htmlBlockEndRegex.test(line)) { 545 | let item = htmlBlockEndRegex.exec(line)[1]; 546 | if (HtmlBlocks[item] != undefined && HtmlBlocks[item].length > 0) { 547 | htmlBlockStart = HtmlBlocks[item].pop(); 548 | FoldingRanges.push(new vscode.FoldingRange(htmlBlockStart, i - 1, vscode.FoldingRangeKind.Region)); 549 | } 550 | } 551 | 552 | if (re.test(line)) { 553 | if (sectionStart >= 0 && i > 0) { 554 | FoldingRanges.push(new vscode.FoldingRange(sectionStart, i - 1, vscode.FoldingRangeKind.Region)); 555 | } 556 | sectionStart = i; 557 | } 558 | } 559 | if (sectionStart >= 0) { FoldingRanges.push(new vscode.FoldingRange(sectionStart, document.lineCount - 1, vscode.FoldingRangeKind.Region)); } 560 | return FoldingRanges; 561 | } 562 | }); 563 | } 564 | 565 | function deactivate() { 566 | utils.cleanUpIconFiles(storageUri); 567 | } 568 | 569 | exports.activate = activate; 570 | exports.deactivate = deactivate; 571 | 572 | module.exports = { 573 | activate 574 | } 575 | -------------------------------------------------------------------------------- /src/filterCommands.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.refreshEditors = exports.setHighlight = exports.editFilter = exports.addFilter = exports.deleteFilter = exports.toggleFocusMode = exports.setVisibility = exports.importFilters = exports.exportFilters = exports.applyHighlight = void 0; 4 | const vscode = require("vscode"); 5 | const utils = require("./utils"); 6 | function applyHighlight(state, editors) { 7 | // remove old decorations from all the text editor using the given decorationType 8 | state.decorations.forEach(decorationType => decorationType.dispose()); 9 | state.decorations = []; 10 | editors.forEach((editor) => { 11 | let sourceCode = editor.document.getText(); 12 | const sourceCodeArr = sourceCode.split("\n"); 13 | //apply new decorations 14 | state.filterArr.forEach((filter) => { 15 | let filterCount = 0; 16 | //if filter's highlight is off, or this editor is in focus mode and filter is not shown, we don't want to put decorations 17 | //especially when a specific line fits more than one filter regex and some of them are shown while others are not. 18 | if (filter.isHighlighted && (!editor.document.uri.toString().startsWith('focus:') || filter.isShown)) { 19 | let lineNumbers = []; 20 | for (let lineIdx = 0; lineIdx < sourceCodeArr.length; lineIdx++) { 21 | if (filter.regex.test(sourceCodeArr[lineIdx])) { 22 | lineNumbers.push(lineIdx); 23 | } 24 | } 25 | filterCount = lineNumbers.length; 26 | const decorationsArray = lineNumbers.map((lineIdx) => { 27 | return new vscode.Range(new vscode.Position(lineIdx, 0), new vscode.Position(lineIdx, 0) //position does not matter because isWholeLine is set to true 28 | ); 29 | }); 30 | let decorationType = vscode.window.createTextEditorDecorationType({ 31 | backgroundColor: filter.color, 32 | isWholeLine: true, 33 | }); 34 | //store the decoration type for future removal 35 | state.decorations.push(decorationType); 36 | editor.setDecorations(decorationType, decorationsArray); 37 | } 38 | //filter.count represents the count of the lines for the activeEditor, so if the current editor is active, we update the count 39 | if (editor === vscode.window.activeTextEditor) { 40 | filter.count = filterCount; 41 | } 42 | }); 43 | }); 44 | } 45 | exports.applyHighlight = applyHighlight; 46 | 47 | function regexFromString(string) { 48 | var match = /^\/(.*)\/([a-z]*)$/.exec(string) 49 | if (match !== null) { 50 | return new RegExp(match[1], match[2]) 51 | } else { 52 | return new RegExp(string) 53 | } 54 | } 55 | 56 | //record the important fields of each filter on a json object and open a new tab for the json 57 | function exportFilters(state) { 58 | const content = JSON.stringify(state.filterArr.map(filter => { 59 | return { 60 | regexText: filter.regex.source, 61 | color: filter.color, 62 | isHighlighted: filter.isHighlighted, 63 | isShown: filter.isShown, 64 | }; 65 | })); 66 | vscode.workspace.openTextDocument({ 67 | content: content, 68 | language: "json" 69 | }); 70 | } 71 | exports.exportFilters = exportFilters; 72 | //open a selected json file and parse each filter to add back 73 | function importFilters(state) { 74 | vscode.window.showOpenDialog({ 75 | canSelectFiles: true, 76 | canSelectMany: false, 77 | filters: { 78 | "json": ["json"] 79 | } 80 | }).then(uriArr => { 81 | if (!uriArr) { 82 | return; 83 | } 84 | return vscode.workspace.openTextDocument(uriArr[0]); 85 | }).then(textDocument => { 86 | const text = textDocument.getText(); 87 | const parsed = JSON.parse(text); 88 | if (typeof parsed !== "object") { 89 | return; 90 | } 91 | const array = parsed; 92 | array.forEach((filterText) => { 93 | if ((typeof filterText.regexText === "string") && 94 | (typeof filterText.color === "string") && 95 | (typeof filterText.isHighlighted === "boolean") && 96 | (typeof filterText.isShown === "boolean")) { 97 | const id = `${Math.random()}`; 98 | const filter = { 99 | regex: regexFromString(filterText.regexText), 100 | color: filterText.color, 101 | isHighlighted: filterText.isHighlighted, 102 | isShown: filterText.isShown, 103 | id, 104 | iconPath: utils.generateSvgUri(state.storageUri, id, filterText.isHighlighted), 105 | count: 0 106 | }; 107 | state.filterArr.push(filter); 108 | utils.writeSvgContent(filter, state.filterTreeViewProvider); 109 | } 110 | }); 111 | refreshEditors(state); 112 | }); 113 | } 114 | exports.importFilters = importFilters; 115 | //set bool for whether the lines matched the given filter will be kept for focus mode 116 | function setVisibility(isShown, filterTreeItem, state) { 117 | const id = filterTreeItem.id; 118 | const filter = state.filterArr.find(filter => (filter.id === id)); 119 | filter.isShown = isShown; 120 | refreshEditors(state); 121 | } 122 | exports.setVisibility = setVisibility; 123 | //turn on focus mode for the active editor. Will create a new tab if not already for the virtual document 124 | function toggleFocusMode(state) { 125 | let editor = vscode.window.activeTextEditor; 126 | if (!editor) { 127 | return; 128 | } 129 | let escapedUri = editor.document.uri.toString(); 130 | if (escapedUri.startsWith('focus:')) { 131 | state.focusProvider.switchFocus(); 132 | refreshEditors(state); 133 | // //avoid creating nested focus mode documents 134 | // vscode.window.showInformationMessage('You are on focus mode virtual document already!'); 135 | // return; 136 | } 137 | else { 138 | state.focusProvider.focusOn = true; 139 | //set special schema 140 | let virtualUri = vscode.Uri.parse('focus:' + escapedUri); 141 | //because of the special schema, openTextDocument will use the focusProvider 142 | vscode.workspace.openTextDocument(virtualUri).then(doc => vscode.window.showTextDocument(doc)); 143 | } 144 | } 145 | exports.toggleFocusMode = toggleFocusMode; 146 | function deleteFilter(filterTreeItem, state) { 147 | const deleteIndex = state.filterArr.findIndex(filter => (filter.id === filterTreeItem.id)); 148 | state.filterArr.splice(deleteIndex, 1); 149 | refreshEditors(state); 150 | } 151 | exports.deleteFilter = deleteFilter; 152 | function addFilter(state) { 153 | vscode.window.showInputBox({ 154 | prompt: "Type a regex to filter", 155 | ignoreFocusOut: false 156 | }).then(regexStr => { 157 | if (regexStr === undefined) { 158 | return; 159 | } 160 | const id = `${Math.random()}`; 161 | const filter = { 162 | isHighlighted: true, 163 | isShown: true, 164 | regex: regexFromString(regexStr), 165 | color: utils.generateRandomColor(), 166 | id, 167 | iconPath: utils.generateSvgUri(state.storageUri, id, true), 168 | count: 0 169 | }; 170 | state.filterArr.push(filter); 171 | //the order of the following two lines is deliberate (due to some unknown reason of async dependencies...) 172 | utils.writeSvgContent(filter, state.filterTreeViewProvider); 173 | refreshEditors(state); 174 | }); 175 | } 176 | exports.addFilter = addFilter; 177 | function editFilter(filterTreeItem, state) { 178 | vscode.window.showInputBox({ 179 | prompt: "Type a new regex", 180 | ignoreFocusOut: false 181 | }).then(regexStr => { 182 | if (regexStr === undefined) { 183 | return; 184 | } 185 | const id = filterTreeItem.id; 186 | const filter = state.filterArr.find(filter => (filter.id === id)); 187 | filter.regex = regexFromString(regexStr); 188 | refreshEditors(state); 189 | }); 190 | } 191 | exports.editFilter = editFilter; 192 | function setHighlight(isHighlighted, filterTreeItem, state) { 193 | const id = filterTreeItem.id; 194 | const filter = state.filterArr.find(filter => (filter.id === id)); 195 | filter.isHighlighted = isHighlighted; 196 | filter.iconPath = utils.generateSvgUri(state.storageUri, filter.id, filter.isHighlighted); 197 | applyHighlight(state, vscode.window.visibleTextEditors); 198 | utils.writeSvgContent(filter, state.filterTreeViewProvider); 199 | } 200 | exports.setHighlight = setHighlight; 201 | //refresh every visible component, including: 202 | //document content of the visible focus mode virtual document, 203 | //decoration of the visible focus mode virtual document, 204 | //highlight decoration of visible editors 205 | //treeview on the side bar 206 | let focusDecorationType = vscode.window.createTextEditorDecorationType({ 207 | before: { 208 | contentText: ">>>>>>>focus mode<<<<<<<", 209 | color: "#888888", 210 | } 211 | }); 212 | 213 | function refreshEditors(state) { 214 | vscode.window.visibleTextEditors.forEach(editor => { 215 | let escapedUri = editor.document.uri.toString(); 216 | if (escapedUri.startsWith('focus:')) { 217 | state.focusProvider.refresh(editor.document.uri); 218 | let focusDecorationRangeArray = [new vscode.Range(new vscode.Position(0, 0), new vscode.Position(1, 0))]; 219 | //focusDecorationType.dispose(); 220 | //editor.setDecorations(focusDecorationType, []); 221 | editor.setDecorations(focusDecorationType, focusDecorationRangeArray); 222 | } 223 | }); 224 | applyHighlight(state, vscode.window.visibleTextEditors); 225 | //console.log("refreshEditors"); 226 | state.filterTreeViewProvider.refresh(); 227 | } 228 | exports.refreshEditors = refreshEditors; 229 | //# sourceMappingURL=commands.js.map -------------------------------------------------------------------------------- /src/filterTreeViewProvider.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.FilterItem = exports.FilterTreeViewProvider = void 0; 4 | const vscode = require("vscode"); 5 | //provides filters as tree items to be displayed on the sidebar 6 | class FilterTreeViewProvider { 7 | constructor(filterArr) { 8 | this.filterArr = filterArr; 9 | this._onDidChangeTreeData = new vscode.EventEmitter(); 10 | this.onDidChangeTreeData = this._onDidChangeTreeData.event; 11 | } 12 | getTreeItem(element) { 13 | return element; 14 | } 15 | //getChildren(filterItem) returns empty list because filters have no children. 16 | //getChildren() returns the root elements (all the filters) 17 | getChildren(element) { 18 | if (element) { 19 | return []; 20 | } 21 | else { // root 22 | return this.filterArr.map(filter => new FilterItem(filter)); 23 | } 24 | } 25 | refresh() { 26 | // console.log("in refresh"); 27 | this._onDidChangeTreeData.fire(undefined); 28 | } 29 | } 30 | exports.FilterTreeViewProvider = FilterTreeViewProvider; 31 | //represents a filter as one row in the sidebar 32 | class FilterItem extends vscode.TreeItem { 33 | constructor(filter) { 34 | super(filter.regex.toString()); 35 | this.label = filter.regex.toString(); 36 | this.id = filter.id; 37 | this.iconPath = filter.iconPath; 38 | if (filter.isHighlighted) { 39 | if (filter.isShown) { 40 | this.description = ` · ${filter.count}`; 41 | this.contextValue = 'lit-visible'; 42 | } 43 | else { 44 | this.description = ''; 45 | this.contextValue = 'lit-invisible'; 46 | } 47 | } 48 | else { 49 | this.description = ''; 50 | if (filter.isShown) { 51 | this.contextValue = 'unlit-visible'; 52 | } 53 | else { 54 | this.contextValue = 'unlit-invisible'; 55 | } 56 | } 57 | } 58 | } 59 | exports.FilterItem = FilterItem; 60 | //# sourceMappingURL=filterTreeViewProvider.js.map -------------------------------------------------------------------------------- /src/focusProvider.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 4 | return new (P || (P = Promise))(function (resolve, reject) { 5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 8 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 9 | }); 10 | }; 11 | Object.defineProperty(exports, "__esModule", { value: true }); 12 | exports.FocusProvider = void 0; 13 | const vscode = require("vscode"); 14 | //Provide virtual documents as a strings that only contain lines matching shown filters. 15 | //These virtual documents have uris of the form "focus:" where 16 | // is the escaped uri of the original, unfocused document. 17 | //VSCode uses this provider to generate virtual read-only files based on real files 18 | class FocusProvider { 19 | constructor(filterArr) { 20 | this.onDidChangeEmitter = new vscode.EventEmitter(); 21 | this.onDidChange = this.onDidChangeEmitter.event; 22 | this.filterArr = filterArr; 23 | this.focusOn = true; 24 | } 25 | //open the original document specified by the uri and return the focused version of its text 26 | provideTextDocumentContent(uri) { 27 | return __awaiter(this, void 0, void 0, function* () { 28 | let originalUri = vscode.Uri.parse(uri.path); 29 | let sourceCode = yield vscode.workspace.openTextDocument(originalUri); 30 | // start the string with an empty line to make room for the focus mode text decoration 31 | let resultArr = ['']; 32 | for (let lineIdx = 0; lineIdx < sourceCode.lineCount; lineIdx++) { 33 | const line = sourceCode.lineAt(lineIdx).text; 34 | let flag = false; 35 | for (const filter of this.filterArr) { 36 | if (!filter.isShown) { 37 | continue; 38 | } 39 | let regex = filter.regex; 40 | if (regex.test(line)) { 41 | flag = true; 42 | break; 43 | } 44 | } 45 | if (!(flag ^ this.focusOn)) { 46 | resultArr.push(line); 47 | } 48 | } 49 | return resultArr.join('\n'); 50 | }); 51 | } 52 | //when this function gets called, the provideTextDocumentContent will be called again 53 | refresh(uri) { 54 | this.onDidChangeEmitter.fire(uri); 55 | } 56 | 57 | switchFocus() { 58 | if (this.focusOn) { 59 | this.focusOn = false 60 | } else { 61 | this.focusOn = true 62 | } 63 | } 64 | } 65 | exports.FocusProvider = FocusProvider; 66 | //# sourceMappingURL=focusProvider.js.map -------------------------------------------------------------------------------- /src/foldingRangeProvider.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.FocusFoldingRangeProvider = void 0; 4 | const vscode = require("vscode"); 5 | class FocusFoldingRangeProvider { 6 | constructor(filterArr) { 7 | this.filterArr = filterArr; 8 | } 9 | provideFoldingRanges(document, context, token) { 10 | let sourceCode = document.getText(); 11 | const sourceCodeArr = sourceCode.split("\n"); 12 | let lastShownLine = 0; 13 | const foldingRanges = []; 14 | for (let lineIdx = 0; lineIdx < sourceCodeArr.length; lineIdx++) { 15 | for (const filter of this.filterArr) { 16 | if (!filter.isShown) { 17 | continue; 18 | } 19 | let regex = filter.regex; 20 | if (regex.test(sourceCodeArr[lineIdx])) { 21 | foldingRanges.push(new vscode.FoldingRange(lastShownLine, lineIdx - 1)); 22 | lastShownLine = lineIdx; 23 | break; 24 | } 25 | } 26 | } 27 | foldingRanges.push(new vscode.FoldingRange(lastShownLine, sourceCodeArr.length - 1)); 28 | return foldingRanges; 29 | } 30 | } 31 | exports.FocusFoldingRangeProvider = FocusFoldingRangeProvider; 32 | //# sourceMappingURL=foldingRangeProvider.js.map -------------------------------------------------------------------------------- /src/highlight.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const vscode = require("vscode"); 4 | const tree = require("./tree"); 5 | var Modes; 6 | (function (Modes) { 7 | Modes[Modes["Default"] = 0] = "Default"; 8 | Modes[Modes["WholeWord"] = 1] = "WholeWord"; 9 | Modes[Modes["IgnoreCase"] = 2] = "IgnoreCase"; 10 | Modes[Modes["Both"] = 3] = "Both"; 11 | })(Modes || (Modes = {})); 12 | const qpOptions = ['ignore case', 'whole word', 'both']; 13 | class Highlight { 14 | constructor() { 15 | this.words = []; 16 | this.decorators = []; 17 | this.treeProvider = new tree.default(this.getWords()); 18 | this.ranges = {}; 19 | vscode.window.registerTreeDataProvider('txtsyntaxHighlightExplore', this.treeProvider); 20 | } 21 | setMode(m) { this.mode = m; } 22 | getMode() { return this.mode; } 23 | getWords() { return this.words; } 24 | setDecorators(d) { this.decorators = d; } 25 | getLocationIndex(expression, range) { 26 | this.treeProvider.currentExpression = expression; 27 | this.treeProvider.currentIndex = { index: 0, count: 0 }; 28 | Object.keys(this.ranges[expression]).some((r, i) => { 29 | const thisrange = this.ranges[expression][i]; 30 | if (thisrange.start.character == range.start.character && thisrange.start.line == range.start.line) { 31 | this.treeProvider.currentIndex = { index: i + 1, count: this.ranges[expression].length }; 32 | return true; 33 | } 34 | }); 35 | this.treeProvider.refresh(); 36 | } 37 | updateDecorations(active) { 38 | vscode.window.visibleTextEditors.forEach(editor => { 39 | if (active && editor.document != vscode.window.activeTextEditor.document) 40 | return; 41 | const text = editor.document.getText(); 42 | let match; 43 | let decs = []; 44 | this.decorators.forEach(function () { 45 | let dec = []; 46 | decs.push(dec); 47 | }); 48 | this.words.forEach((w, n) => { 49 | const opts = w.ignoreCase ? 'gi' : 'g'; 50 | const expression = w.wholeWord ? '\\b' + w.expression + '\\b' : w.expression; 51 | const regEx = new RegExp(expression, opts); 52 | this.ranges[w.expression] = []; 53 | while (match = regEx.exec(text)) { 54 | const startPos = editor.document.positionAt(match.index); 55 | const endPos = editor.document.positionAt(match.index + match[0].length); 56 | const decoration = { range: new vscode.Range(startPos, endPos) }; 57 | decs[n % decs.length].push(decoration); 58 | this.ranges[w.expression].push(decoration.range); 59 | } 60 | }); 61 | this.decorators.forEach(function (d, i) { 62 | editor.setDecorations(d, decs[i]); 63 | }); 64 | this.treeProvider.words = this.words; 65 | this.treeProvider.refresh(); 66 | }); 67 | } 68 | clearAll() { 69 | this.words = []; 70 | this.updateDecorations(); 71 | } 72 | remove(word) { 73 | if (!word) 74 | return; 75 | if (word.label == '* All *') 76 | this.words = []; 77 | else { 78 | const highlights = this.words.filter(w => w.expression == word.label); 79 | if (highlights && highlights.length) { 80 | this.words.splice(this.words.indexOf(highlights[0]), 1); 81 | } 82 | } 83 | this.updateDecorations(); 84 | } 85 | updateActive() { 86 | this.updateDecorations(true); 87 | } 88 | updateOptions(word) { 89 | vscode.window.showQuickPick(["default"].concat(qpOptions)).then(option => { 90 | if (!option) 91 | return; 92 | const theword = this.words.map(w => w.expression).indexOf(word); 93 | this.words[theword] = { 94 | expression: word, 95 | wholeWord: option == 'whole word' || option == 'both', 96 | ignoreCase: option == 'ignore case' || option == 'both' 97 | }; 98 | this.updateDecorations(); 99 | }); 100 | } 101 | toggleSelected(withOptions) { 102 | const editor = vscode.window.activeTextEditor; 103 | let word = editor.document.getText(editor.selection); 104 | if (!word) { 105 | const range = editor.document.getWordRangeAtPosition(editor.selection.start); 106 | if (range) 107 | word = editor.document.getText(range); 108 | } 109 | if (!word) { 110 | vscode.window.showInformationMessage('Nothing selected!'); 111 | return; 112 | } 113 | word = word.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1"); // raw selected text, not regexp 114 | const highlights = this.words.filter(w => w.expression == word); // avoid duplicates 115 | if (!highlights || !highlights.length) { 116 | if (withOptions) { 117 | vscode.window.showQuickPick(qpOptions).then(option => { 118 | if (!option) 119 | return; 120 | this.words.push({ 121 | expression: word, 122 | wholeWord: option == 'whole word' || option == 'both', 123 | ignoreCase: option == 'ignore case' || option == 'both' 124 | }); 125 | this.updateDecorations(); 126 | }); 127 | } 128 | else { 129 | const ww = this.mode == Modes.WholeWord || this.mode == Modes.Both; 130 | const ic = this.mode == Modes.IgnoreCase || this.mode == Modes.Both; 131 | this.words.push({ expression: word, wholeWord: ww, ignoreCase: ic }); 132 | this.updateDecorations(); 133 | } 134 | } 135 | else if (highlights.length) { 136 | this.words.splice(this.words.indexOf(highlights[0]), 1); 137 | this.updateDecorations(); 138 | } 139 | } 140 | toggleRegExp(word) { 141 | try { 142 | let opts = ''; 143 | if (word.indexOf('/') == 0) { 144 | const slashes = word.split('/'); 145 | opts = slashes[slashes.length - 1]; 146 | word = word.slice(1, word.length - opts.length - 1); 147 | } 148 | new RegExp(word); 149 | const highlights = this.words.filter(w => w.expression == word); 150 | if (!highlights || !highlights.length) { 151 | this.words.push({ 152 | expression: word, 153 | wholeWord: false, 154 | ignoreCase: !!~opts.indexOf('i') 155 | }); 156 | this.updateDecorations(); 157 | } 158 | } 159 | catch (e) { 160 | vscode.window.showInformationMessage(word + ' is an invalid expression'); 161 | } 162 | } 163 | } 164 | exports.default = Highlight; -------------------------------------------------------------------------------- /src/hlconfig.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const vscode = require("vscode"); 4 | class HighlightConfig { 5 | static getConfigValues() { 6 | let config = vscode.workspace.getConfiguration('txtsyntax'); 7 | let colors = config.get('highlightColors'); 8 | let box = config.get('highlightBox'); 9 | const defaultMode = config.get('defaultHighlightMode'); 10 | const showSidebar = config.get('showHighlightSidebar'); 11 | let decorators = []; 12 | colors.forEach(function (color) { 13 | var dark = { 14 | // this color will be used in dark color themes 15 | overviewRulerColor: color.dark, 16 | backgroundColor: box.dark ? 'inherit' : color.dark, 17 | borderColor: color.dark 18 | }; 19 | if (!box.dark) 20 | dark.color = '#555555'; 21 | let decorationType = vscode.window.createTextEditorDecorationType({ 22 | borderWidth: '2px', 23 | borderStyle: 'solid', 24 | overviewRulerLane: vscode.OverviewRulerLane.Right, 25 | light: { 26 | // this color will be used in light color themes 27 | overviewRulerColor: color.light, 28 | borderColor: color.light, 29 | backgroundColor: box.light ? 'inherit' : color.light 30 | }, 31 | dark: dark 32 | }); 33 | decorators.push(decorationType); 34 | }); 35 | return { decorators, defaultMode, showSidebar }; 36 | } 37 | } 38 | exports.default = HighlightConfig; -------------------------------------------------------------------------------- /src/tree.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const vscode = require("vscode"); 4 | class HighlightTreeProvider { 5 | constructor(words) { 6 | this.words = words; 7 | this._onDidChangeTreeData = new vscode.EventEmitter(); 8 | this.onDidChangeTreeData = this._onDidChangeTreeData.event; 9 | } 10 | getTreeItem(element) { 11 | return element; 12 | } 13 | getChildren(element) { 14 | let nodes = this.words.map(w => { 15 | return new HighlightNode(w.expression, w, this); 16 | }); 17 | return Promise.resolve(nodes); 18 | } 19 | refresh() { 20 | this._onDidChangeTreeData.fire(); 21 | } 22 | } 23 | class HighlightNode extends vscode.TreeItem { 24 | constructor(label, highlight, provider, command) { 25 | super(label); 26 | this.label = label; 27 | this.highlight = highlight; 28 | this.provider = provider; 29 | this.command = command; 30 | this.contextValue = 'highlights'; 31 | } 32 | getOpts() { 33 | const index = this.highlight.expression == this.provider.currentExpression ? 34 | ` ${this.provider.currentIndex.index}/${this.provider.currentIndex.count}` : ''; 35 | return this.highlight.ignoreCase && this.highlight.wholeWord ? 'both' : 36 | this.highlight.ignoreCase ? 'ignoreCase' : 37 | this.highlight.wholeWord ? 'wholeWord' : 'default' + index; 38 | } 39 | get tooltip() { 40 | return `${this.label}-${this.getOpts()}`; 41 | } 42 | get description() { 43 | return this.getOpts(); 44 | } 45 | } 46 | exports.HighlightNode = HighlightNode; 47 | exports.default = HighlightTreeProvider; -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.generateSvgUri = exports.writeSvgContent = exports.cleanUpIconFiles = exports.generateRandomColor = void 0; 4 | const vscode = require("vscode"); 5 | function generateRandomColor() { 6 | return `hsl(${Math.floor(360 * Math.random())}, 40%, 40%)`; 7 | } 8 | exports.generateRandomColor = generateRandomColor; 9 | //clean up the generated svgs stored in the folder created for this extension 10 | function cleanUpIconFiles(storageUri) { 11 | vscode.workspace.fs.delete(storageUri, { 12 | recursive: true, 13 | useTrash: false 14 | }).then(undefined, (err) => { 15 | if (err.name !== "EntryNotFound (FileSystemError)") throw err; 16 | }); 17 | } 18 | exports.cleanUpIconFiles = cleanUpIconFiles; 19 | //create an svg icon representing a filter: a filled circle if the filter is highlighted, or an empty circle otherwise. 20 | //this icon gets stored in the file system at filter.iconPath. 21 | function writeSvgContent(filter, treeViewProvider) { 22 | const fullSvg = ``; 23 | const emptySvg = ``; 24 | vscode.workspace.fs.writeFile(filter.iconPath, str2Uint8(filter.isHighlighted ? fullSvg : emptySvg)).then(() => { 25 | //console.log("before refresh"); 26 | //console.log(filter.iconPath); 27 | treeViewProvider.refresh(); 28 | }); 29 | } 30 | exports.writeSvgContent = writeSvgContent; 31 | //convert a string to a Uint8Array 32 | function str2Uint8(str) { 33 | var buf = new ArrayBuffer(str.length); 34 | var bufView = new Uint8Array(buf); //TODO: check if can just use str.length 35 | for (var i = 0, strLen = str.length; i < strLen; i++) { 36 | bufView[i] = str.charCodeAt(i); 37 | } 38 | return bufView; 39 | } 40 | function generateSvgUri(storageUri, id, isHighlighted) { 41 | return vscode.Uri.joinPath(storageUri, `./${id}${isHighlighted}.svg`); 42 | } 43 | exports.generateSvgUri = generateSvgUri; 44 | //# sourceMappingURL=utils.js.map -------------------------------------------------------------------------------- /syntaxes/txt.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/txt.tmlanguage.json", 3 | "name": "Txt", 4 | "patterns": [ 5 | { 6 | "begin": "(^[ \\t]+)?(?=#)", 7 | "beginCaptures": { 8 | "1": { 9 | "name": "punctuation.whitespace.comment.leading.txt" 10 | } 11 | }, 12 | "end": "(?!\\G)", 13 | "patterns": [ 14 | { 15 | "begin": "#", 16 | "beginCaptures": { 17 | "0": { 18 | "name": "punctuation.definition.comment.txt" 19 | } 20 | }, 21 | "end": "\\n", 22 | "name": "comment.line.number-sign.txt" 23 | } 24 | ] 25 | }, 26 | { 27 | "begin": "^([ \\t]+)?(?=;)", 28 | "beginCaptures": { 29 | "1": { 30 | "name": "punctuation.whitespace.comment.leading.txt" 31 | } 32 | }, 33 | "end": "(?!\\G)", 34 | "patterns": [ 35 | { 36 | "begin": ";", 37 | "beginCaptures": { 38 | "0": { 39 | "name": "punctuation.definition.comment.txt" 40 | } 41 | }, 42 | "end": "\\n", 43 | "name": "comment.line.semicolon.txt" 44 | } 45 | ] 46 | }, 47 | { 48 | "begin": "^(第[^\\S\\r\\n]|第)?[一二三四五六七八九十百千万亿兆零壹贰叁肆伍陆柒捌玖拾佰仟甲乙丙丁戊己庚辛壬癸子丑寅卯辰巳午未申酉戌亥]+($|[^\\S\\r\\n])?[章节篇部首回手课页段组卷区场合季级集任步条件年月日周天轮个项类期话例]?($|[\\.、].*?|[^\\S\\r\\n].*?)", 49 | "beginCaptures": { 50 | "0": { 51 | "name": "keyword.other.definition.txt" 52 | } 53 | }, 54 | "end": "\\n", 55 | "endCaptures": { 56 | "0": { 57 | "name": "keyword.other.definition.txt" 58 | } 59 | }, 60 | "name": "keyword.other.definition.txt" 61 | }, 62 | { 63 | "begin": "^(第[^\\S\\r\\n]|第)?[0123456789]+[^\\S\\r\\n]?[章节篇部首回手课页段组卷区场合季级集任步条件年月日周天轮个项类期话例]($|[\\.、].*?|[^\\S\\r\\n].*?)|^(第[^\\S\\r\\n]|第)[0123456789]+($|[\\.、].*?|[^\\S\\r\\n].*?)", 64 | "beginCaptures": { 65 | "0": { 66 | "name": "keyword.other.definition.txt" 67 | } 68 | }, 69 | "end": "\\n", 70 | "endCaptures": { 71 | "0": { 72 | "name": "keyword.other.definition.txt" 73 | } 74 | }, 75 | "name": "keyword.other.definition.txt" 76 | }, 77 | { 78 | "begin": "^(Section|SECTION|Chapter|CHAPTER|Sheet|SHEET|Season|SEASON|Period|PERIOD|Round|ROUND|Class|CLASS|Term|TERM|Part|PART|Page|PAGE|Segment|SEGMENT|Paragraph|PARAGRAPH|Lesson|LESSON|Region|REGION|Step|STEP|Level|LEVEL|Set|SET|Grade|GRADE|Year|YEAR|Month|MONTH|Week|WEEK|Day|DAY)[^\\S\\r\\n][A-Z0-9]+\\.?($|[^\\S\\r\\n].*?)", 79 | "beginCaptures": { 80 | "0": { 81 | "name": "keyword.other.definition.txt" 82 | } 83 | }, 84 | "end": "\\n", 85 | "endCaptures": { 86 | "0": { 87 | "name": "keyword.other.definition.txt" 88 | } 89 | }, 90 | "name": "keyword.other.definition.txt" 91 | }, 92 | { 93 | "begin": "^[A-Z0-9]+\\.\\s.*?", 94 | "beginCaptures": { 95 | "0": { 96 | "name": "keyword.other.definition.txt" 97 | } 98 | }, 99 | "end": "\\n", 100 | "endCaptures": { 101 | "0": { 102 | "name": "keyword.other.definition.txt" 103 | } 104 | }, 105 | "name": "keyword.other.definition.txt" 106 | }, 107 | { 108 | "begin": "^\\*[^\\S\\r\\n].*?", 109 | "beginCaptures": { 110 | "0": { 111 | "name": "keyword.other.definition.txt" 112 | } 113 | }, 114 | "end": "\\n", 115 | "endCaptures": { 116 | "0": { 117 | "name": "keyword.other.definition.txt" 118 | } 119 | }, 120 | "name": "keyword.other.definition.txt" 121 | }, 122 | { 123 | "begin": "^-\\*-.*?", 124 | "beginCaptures": { 125 | "0": { 126 | "name": "keyword.other.definition.txt" 127 | } 128 | }, 129 | "end": "\\n", 130 | "endCaptures": { 131 | "0": { 132 | "name": "keyword.other.definition.txt" 133 | } 134 | }, 135 | "name": "keyword.other.definition.txt" 136 | }, 137 | { 138 | "match": "^\\s*\\$[^#]*", 139 | "name": "entity.name.type.txt" 140 | }, 141 | { 142 | "match": "\\$[A-Za-z_]\\S*", 143 | "name": "variable.other.sign.txt" 144 | }, 145 | { 146 | "match": "^\\[.+?\\]\\s*$", 147 | "name": "keyword.other.definition.txt" 148 | }, 149 | { 150 | "begin": "^[^\\S\\r\\n]*[-\\=\\+][^\\S\\r\\n].*?", 151 | "beginCaptures": { 152 | "0": { 153 | "name": "string.regexp.txt" 154 | } 155 | }, 156 | "end": "\\n", 157 | "endCaptures": { 158 | "0": { 159 | "name": "string.regexp.txt" 160 | } 161 | }, 162 | "name": "string.regexp.txt" 163 | }, 164 | { 165 | "match": "(https?://|tftp://|ftp://|smtp://|pop3://|snmp://|telnet://|imap://|dhcp://|dns://|nfs://|file://|sftp://|ssl://|smb://|vmess://|socks://)\\S*", 166 | "name": "entity.name.type.txt" 167 | }, 168 | { 169 | "match": "(\\.{0,2}|~)(\\w:\\\\|file:///|/)[\\w\\./\\-\\=\\+:@%&\\(\\)\\<\\>\\[\\]\\{\\}\\\\]*\\.?\\w*", 170 | "name": "entity.name.type.txt" 171 | }, 172 | { 173 | "match": "\\w[-._+\\w]*\\w@\\w[-._\\w]*\\w\\.\\w{2,4}", 174 | "name": "entity.name.type.txt" 175 | }, 176 | { 177 | "captures": { 178 | "1": { 179 | "name": "variable.other.sign.txt" 180 | }, 181 | "2": { 182 | "name": "entity.name.type.txt" 183 | } 184 | }, 185 | "match": "\\b([a-zA-Z_.-][a-zA-Z0-9_.-]*)\\b\\s*(:?=)" 186 | }, 187 | { 188 | "match": "\\d+", 189 | "name": "constant.character.sign.txt" 190 | }, 191 | { 192 | "captures": { 193 | "1": { 194 | "name": "entity.name.function.txt" 195 | }, 196 | "3": { 197 | "name": "entity.name.function.txt" 198 | } 199 | }, 200 | "match": "(\\[)(.*?)(\\])", 201 | "name": "entity.name.function.txt" 202 | }, 203 | { 204 | "captures": { 205 | "1": { 206 | "name": "entity.name.function.txt" 207 | }, 208 | "3": { 209 | "name": "entity.name.function.txt" 210 | } 211 | }, 212 | "match": "(\\{)(.*?)(\\})", 213 | "name": "entity.name.function.txt" 214 | }, 215 | { 216 | "captures": { 217 | "1": { 218 | "name": "entity.name.function.txt" 219 | }, 220 | "3": { 221 | "name": "entity.name.function.txt" 222 | } 223 | }, 224 | "match": "(\\()(.*?)(\\))", 225 | "name": "entity.name.function.txt" 226 | }, 227 | { 228 | "captures": { 229 | "1": { 230 | "name": "entity.name.function.txt" 231 | }, 232 | "3": { 233 | "name": "entity.name.function.txt" 234 | } 235 | }, 236 | "match": "(\\<)(.*?)(\\>)", 237 | "name": "entity.name.function.txt" 238 | }, 239 | { 240 | "captures": { 241 | "1": { 242 | "name": "entity.name.function.txt" 243 | }, 244 | "3": { 245 | "name": "entity.name.function.txt" 246 | } 247 | }, 248 | "match": "(【)(.*?)(】)", 249 | "name": "entity.name.function.txt" 250 | }, 251 | { 252 | "captures": { 253 | "1": { 254 | "name": "entity.name.function.txt" 255 | }, 256 | "3": { 257 | "name": "entity.name.function.txt" 258 | } 259 | }, 260 | "match": "(()(.*?)())", 261 | "name": "entity.name.function.txt" 262 | }, 263 | { 264 | "captures": { 265 | "1": { 266 | "name": "entity.name.function.txt" 267 | }, 268 | "3": { 269 | "name": "entity.name.function.txt" 270 | } 271 | }, 272 | "match": "(<)(.*?)(>)", 273 | "name": "entity.name.function.txt" 274 | }, 275 | { 276 | "captures": { 277 | "1": { 278 | "name": "entity.name.function.txt" 279 | }, 280 | "3": { 281 | "name": "entity.name.function.txt" 282 | } 283 | }, 284 | "match": "(«)(.*?)(»)", 285 | "name": "entity.name.function.txt" 286 | }, 287 | { 288 | "captures": { 289 | "1": { 290 | "name": "entity.name.function.txt" 291 | }, 292 | "3": { 293 | "name": "entity.name.function.txt" 294 | } 295 | }, 296 | "match": "(《)(.*?)(》)", 297 | "name": "entity.name.function.txt" 298 | }, 299 | { 300 | "captures": { 301 | "1": { 302 | "name": "entity.name.function.txt" 303 | }, 304 | "3": { 305 | "name": "entity.name.function.txt" 306 | } 307 | }, 308 | "match": "(〔)(.*?)(〕)", 309 | "name": "entity.name.function.txt" 310 | }, 311 | { 312 | "captures": { 313 | "1": { 314 | "name": "entity.name.function.txt" 315 | }, 316 | "3": { 317 | "name": "entity.name.function.txt" 318 | } 319 | }, 320 | "match": "(『)(.*?)(』)", 321 | "name": "entity.name.function.txt" 322 | }, 323 | { 324 | "captures": { 325 | "1": { 326 | "name": "entity.name.function.txt" 327 | }, 328 | "3": { 329 | "name": "entity.name.function.txt" 330 | } 331 | }, 332 | "match": "(﹃)(.*?)(﹄)", 333 | "name": "entity.name.function.txt" 334 | }, 335 | { 336 | "captures": { 337 | "1": { 338 | "name": "entity.name.function.txt" 339 | }, 340 | "3": { 341 | "name": "entity.name.function.txt" 342 | } 343 | }, 344 | "match": "(「)(.*?)(」)", 345 | "name": "entity.name.function.txt" 346 | }, 347 | { 348 | "captures": { 349 | "1": { 350 | "name": "entity.name.function.txt" 351 | }, 352 | "3": { 353 | "name": "entity.name.function.txt" 354 | } 355 | }, 356 | "match": "([)(.*?)(])", 357 | "name": "entity.name.function.txt" 358 | }, 359 | { 360 | "begin": "‘", 361 | "beginCaptures": { 362 | "0": { 363 | "name": "punctuation.definition.string.begin.txt" 364 | } 365 | }, 366 | "end": "’", 367 | "endCaptures": { 368 | "0": { 369 | "name": "punctuation.definition.string.end.txt" 370 | } 371 | }, 372 | "name": "string.quoted.singlecn.txt", 373 | "patterns": [ 374 | { 375 | "match": "\\\\.", 376 | "name": "constant.character.escape.txt" 377 | } 378 | ] 379 | }, 380 | { 381 | "begin": "“", 382 | "beginCaptures": { 383 | "0": { 384 | "name": "punctuation.definition.string.begin.txt" 385 | } 386 | }, 387 | "end": "”", 388 | "endCaptures": { 389 | "0": { 390 | "name": "punctuation.definition.string.end.txt" 391 | } 392 | }, 393 | "name": "string.quoted.doublecn.txt", 394 | "patterns": [ 395 | { 396 | "match": "\\\\.", 397 | "name": "constant.character.escape.txt" 398 | } 399 | ] 400 | }, 401 | { 402 | "begin": "„", 403 | "beginCaptures": { 404 | "0": { 405 | "name": "punctuation.definition.string.begin.txt" 406 | } 407 | }, 408 | "end": "“", 409 | "endCaptures": { 410 | "0": { 411 | "name": "punctuation.definition.string.end.txt" 412 | } 413 | }, 414 | "name": "string.quoted.doublecn.txt", 415 | "patterns": [ 416 | { 417 | "match": "\\\\.", 418 | "name": "constant.character.escape.txt" 419 | } 420 | ] 421 | }, 422 | { 423 | "captures": { 424 | "1": { 425 | "name": "string.quoted.single.txt" 426 | }, 427 | "3": { 428 | "name": "string.quoted.single.txt" 429 | } 430 | }, 431 | "match": "(\\')(((?!s\\s).)*?)(\\')", 432 | "name": "string.quoted.single.txt" 433 | }, 434 | { 435 | "begin": "\"", 436 | "beginCaptures": { 437 | "0": { 438 | "name": "punctuation.definition.string.begin.txt" 439 | } 440 | }, 441 | "end": "\"", 442 | "endCaptures": { 443 | "0": { 444 | "name": "punctuation.definition.string.end.txt" 445 | } 446 | }, 447 | "name": "string.quoted.double.txt" 448 | }, 449 | { 450 | "begin": "`", 451 | "beginCaptures": { 452 | "0": { 453 | "name": "punctuation.definition.string.begin.txt" 454 | } 455 | }, 456 | "end": "`", 457 | "endCaptures": { 458 | "0": { 459 | "name": "punctuation.definition.string.end.txt" 460 | } 461 | }, 462 | "name": "string.quoted.doublecn.txt", 463 | "patterns": [ 464 | { 465 | "match": "\\\\.", 466 | "name": "constant.character.escape.txt" 467 | } 468 | ] 469 | }, 470 | { 471 | "match": "\\,|\\.|\\,|\\,|\\。|\\-|\\……|\\──|\\___|\\——|\\—|\\-|\\_|\\+|\\=|\\*|\\&|\\;|\\;|\\、|\\:|\\:|\\·|\\!|\\!|\\@|\\$|\\%|\\^|\\/|\\?|\\?|\\~|\\~|\\/|\\\\|\\||\\<|\\>|\\(|\\)|\\{|\\}|\\[|\\]|\\《|\\》|\\(|\\)|\\【|\\】|\\¥|\\°|\\√|\\×|\\*|\\○|\\●|\\◇|\\◆|\\□|\\■|\\△|\\▲|\\▽|\\▼|\\▷|\\▶|\\◁|\\◀|\\☆|\\★|\\♤|\\♠|\\♡|\\♥|\\♢|\\♦|\\♧|\\♣|\\☼|\\☀|\\☺|\\☻|\\◘|\\◙|\\☏|\\☎|\\☜|\\☞|\\◐|\\◑|\\☽|\\☾|\\♀|\\♂|\\☑|\\☒|\\✔|\\✘|\\㏂|\\㏘|\\✎|\\✐|\\⊙|\\◎|\\✉|\\❤|\\▁|\\▂|\\▄|\\▇|\\☢|\\✄|\\☂|\\☉|\\☣|\\☄|\\☯|\\☪|\\☭|\\❂|\\✪|\\❉|\\❈|\\✲|\\◈|\\▣|\\⊿|\\⊕|\\Θ|\\▣|\\✚|\\✖|\\✙|\\۩|\\▫|\\❀|\\•|\\▪|\\⊹|\\✲|\\❦|\\◕|\\♞|\\☃|\\☪|\\®|\\©|\\™|\\℗|\\囍|\\№|\\☠|\\◤|\\◥|\\◣|\\◢|\\↖|\\↙|\\↗|\\↘|\\↑|\\↓|\\←|\\→|\\↔|\\↕|\\╱|\\╲|\\☍|\\☌|\\☋|\\▩|\\▨|\\▤|\\▥|\\▧|\\▦|\\㏇|\\➴|\\➵|\\✈|\\〄|\\㊤|\\㊥|\\㊦|\\㊧|\\㊨|\\㊚|\\㊛|\\㊣|\\㊙|\\㉿|\\㈱|\\⊱|\\⊰|\\⋌|\\§|\\‖|\\Ψ|\\๑|\\∮|\\♯|\\♭|\\¶|\\♬|\\♫|\\♪|\\♩|\\✧|\\✦|\\✢|\\✫|\\✡|\\✯|\\❉|\\❆|\\❶|\\❷|\\❸|\\❹|\\❺|\\❻|\\❼|\\❽|\\❾|\\❿|\\①|\\②|\\③|\\④|\\⑤|\\⑥|\\⑦|\\⑧|\\⑨|\\⑩|\\Ⅰ|\\Ⅱ|\\Ⅲ|\\Ⅳ|\\Ⅴ|\\Ⅵ|\\Ⅶ|\\Ⅷ|\\Ⅸ|\\Ⅹ|\\㊀|\\㊁|\\㊂|\\㊃|\\㊄|\\㊅|\\㊆|\\㊇|\\㊈|\\㊉|\\α|\\β|\\γ|\\δ|\\ε|\\ζ|\\η|\\θ|\\ι|\\κ|\\λ|\\μ|\\φ|\\ω|\\π|\\Σ|\\ρ|\\τ|\\Φ|\\Ψ|\\Ω|\\ψ|\\З|\\з|\\л|\\Л|\\ч|\\Ч|\\э|\\Э|\\ю|\\Ю|\\ф|\\Ф|\\¿|\\『|\\』|\\〔|\\〕|\\﹃|\\﹄|\\︻|\\︼|\\「|\\」|\\﹁|\\﹂|\\﹎|\\﹊|\\~|\\˜|\\ˇ|\\ˆ|\\﹏|\\◔|\\◓|\\◒|\\◌|\\◍|\\♔|\\♕|\\♖|\\♙|\\ღ|\\۵|\\≠|\\±|\\≤|\\≥|\\∈|\\∩|\\∪|\\÷|\\≌|\\∽|\\≮|\\≯|\\℃|\\℉|\\¤|\\λ|\\‰|\\∴|\\∵|\\½|\\¼|\\⅓|\\∠|\\⊥|\\≈|\\∫|\\➢|\\➛|\\➤|\\↺|\\↻|\\➭|\\↢|\\↣|\\⇧|\\⇨|\\⇦|\\⇩|\\⇑|\\⇒|\\⇓|\\⇔|\\⇕|\\⇐", 472 | "name": "entity.name.type.txt" 473 | } 474 | ], 475 | "scopeName": "source.txt" 476 | } 477 | -------------------------------------------------------------------------------- /txt.language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | "lineComment": "#", 4 | "blockComment": [ 5 | "#", 6 | " " 7 | ] 8 | }, 9 | "brackets": [ 10 | [ 11 | "{", 12 | "}" 13 | ], 14 | [ 15 | "[", 16 | "]" 17 | ], 18 | [ 19 | "(", 20 | ")" 21 | ], 22 | [ 23 | "<", 24 | ">" 25 | ], 26 | [ 27 | "«", 28 | "»" 29 | ] 30 | ], 31 | "autoClosingPairs": [ 32 | [ 33 | "{", 34 | "}" 35 | ], 36 | [ 37 | "[", 38 | "]" 39 | ], 40 | [ 41 | "(", 42 | ")" 43 | ], 44 | [ 45 | "\"", 46 | "\"" 47 | ], 48 | [ 49 | "'", 50 | "'" 51 | ], 52 | [ 53 | "`", 54 | "`" 55 | ], 56 | [ 57 | "<", 58 | ">" 59 | ], 60 | [ 61 | "«", 62 | "»" 63 | ] 64 | ], 65 | "surroundingPairs": [ 66 | [ 67 | "{", 68 | "}" 69 | ], 70 | [ 71 | "[", 72 | "]" 73 | ], 74 | [ 75 | "(", 76 | ")" 77 | ], 78 | [ 79 | "\"", 80 | "\"" 81 | ], 82 | [ 83 | "'", 84 | "'" 85 | ], 86 | [ 87 | "`", 88 | "`" 89 | ], 90 | [ 91 | "<", 92 | ">" 93 | ], 94 | [ 95 | "«", 96 | "»" 97 | ] 98 | ], 99 | // "folding": { 100 | // "markers": { 101 | // "start": "^\\s*//\\s*#?region\\b", 102 | // "end": "^\\s*//\\s*#?endregion\\b" 103 | // } 104 | // }, 105 | "folding": { 106 | "markers": { 107 | "start": "^-\\*-|^\\*[^\\S\\r\\n]|^[A-Z0-9]+\\.\\s.*?|^\\[.+\\]\\s*|^(Section|SECTION|Chapter|CHAPTER|Sheet|SHEET|Season|SEASON|Period|PERIOD|Round|ROUND|Class|CLASS|Term|TERM|Part|PART|Page|PAGE|Segment|SEGMENT|Paragraph|PARAGRAPH|Lesson|LESSON|Region|REGION|Step|STEP|Level|LEVEL|Set|SET|Grade|GRADE|Year|YEAR|Month|MONTH|Week|WEEK|Day|DAY)[^\\S\\r\\n][A-Z0-9]+\\.?($|[^\\S\\r\\n].*?)|^(第[^\\S\\r\\n]|第)?[一二三四五六七八九十百千万亿兆零壹贰叁肆伍陆柒捌玖拾佰仟甲乙丙丁戊己庚辛壬癸子丑寅卯辰巳午未申酉戌亥]+($|[^\\S\\r\\n])?[章节篇部首回手课页段组卷区场合季级集任步条件年月日周天轮项类期话例]?($|[\\.、].*?|[^\\S\\r\\n].*?)|^(第[^\\S\\r\\n]|第)?[0123456789]+[^\\S\\r\\n]?[章节篇部首回手课页段组卷区场合季级集任步条件年月日周天轮个项类期话例]($|[\\.、].*?|[^\\S\\r\\n].*?)|^(第[^\\S\\r\\n]|第)[0123456789]+($|[\\.、].*?|[^\\S\\r\\n].*?)", 108 | "end": "^---$" 109 | } 110 | }, 111 | "wordPattern": "(-?\\d*\\.\\d\\w*)|([^\\`\\~\\!\\@\\#\\%\\^\\&\\*\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\.\\<\\>\\/\\?\\s]+)", 112 | "indentationRules": { 113 | "increaseIndentPattern": "^((?!\\/\\/).)*(\\{[^}\"'`]*|\\([^)\"'`]*|\\[[^\\]\"'`]*)$", 114 | "decreaseIndentPattern": "^((?!.*?\\/\\*).*\\*/)?\\s*[\\)\\}\\]].*$" 115 | } 116 | } 117 | --------------------------------------------------------------------------------