├── .gitignore
├── .vscode
├── launch.json
├── settings.json
└── tasks.json
├── .vscodeignore
├── README.md
├── images
├── icon.png
└── screenshot.jpg
├── license.txt
├── package.json
├── src
└── extension.ts
├── test
├── extension.test.ts
└── index.ts
├── tsconfig.json
├── tsd.json
├── typings
├── lodash
│ └── lodash.d.ts
├── node.d.ts
├── tsd.d.ts
└── vscode-typings.d.ts
└── vsc-extension-quickstart.md
/.gitignore:
--------------------------------------------------------------------------------
1 | out
2 | node_modules
3 | *.vsix
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | // A launch configuration that compiles the extension and then opens it inside a new window
2 | {
3 | "version": "0.1.0",
4 | "configurations": [
5 | {
6 | "name": "Launch Extension",
7 | "type": "extensionHost",
8 | "request": "launch",
9 | "runtimeExecutable": "${execPath}",
10 | "args": ["--extensionDevelopmentPath=${workspaceRoot}" ],
11 | "stopOnEntry": false,
12 | "sourceMaps": true,
13 | "outDir": "out/src",
14 | "preLaunchTask": "npm"
15 | },
16 | {
17 | "name": "Launch Tests",
18 | "type": "extensionHost",
19 | "request": "launch",
20 | "runtimeExecutable": "${execPath}",
21 | "args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/out/test" ],
22 | "stopOnEntry": false,
23 | "sourceMaps": true,
24 | "outDir": "out/test",
25 | "preLaunchTask": "npm"
26 | }
27 | ]
28 | }
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | // Place your settings in this file to overwrite default and user settings.
2 | {
3 | "files.exclude": {
4 | "out": false // set this to true to hide the "out" folder with the compiled JS files
5 | },
6 | "search.exclude": {
7 | "out": true // set this to false to include "out" folder in search results
8 | },
9 | "typescript.tsdk": "./node_modules/typescript/lib" // we want to use the TS server from our node_modules folder to control its version
10 | }
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | // Available variables which can be used inside of strings.
2 | // ${workspaceRoot}: the root folder of the team
3 | // ${file}: the current opened file
4 | // ${fileBasename}: the current opened file's basename
5 | // ${fileDirname}: the current opened file's dirname
6 | // ${fileExtname}: the current opened file's extension
7 | // ${cwd}: the current working directory of the spawned process
8 |
9 | // A task runner that calls a custom npm script that compiles the extension.
10 | {
11 | "version": "0.1.0",
12 |
13 | // we want to run npm
14 | "command": "npm",
15 |
16 | // the command is a shell script
17 | "isShellCommand": true,
18 |
19 | // show the output window only if unrecognized errors occur.
20 | "showOutput": "silent",
21 |
22 | // we run the custom script "compile" as defined in package.json
23 | "args": ["run", "compile", "--loglevel", "silent"],
24 |
25 | // The tsc compiler is started in watching mode
26 | "isWatching": true,
27 |
28 | // use the standard tsc in watch mode problem matcher to find compile problems in the output.
29 | "problemMatcher": "$tsc-watch"
30 | }
--------------------------------------------------------------------------------
/.vscodeignore:
--------------------------------------------------------------------------------
1 | .vscode/**
2 | typings/**
3 | out/test/**
4 | test/**
5 | src/**
6 | **/*.map
7 | .gitignore
8 | tsconfig.json
9 | vsc-extension-quickstart.md
10 | images/**
11 | *.vsix
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Indent Guides for Visual Studio Code
2 | This extension adds indent guides to the editor.
3 |
4 | 
5 |
--------------------------------------------------------------------------------
/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoeRobich/vscode-indent-guides/71e852e1291f7ad4f9c303268c7a5986bac7c077/images/icon.png
--------------------------------------------------------------------------------
/images/screenshot.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoeRobich/vscode-indent-guides/71e852e1291f7ad4f9c303268c7a5986bac7c077/images/screenshot.jpg
--------------------------------------------------------------------------------
/license.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Joey Robichaud
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "indent-guides",
3 | "displayName": "Indent Guides",
4 | "description": "This extensions adds indent guides to the editor.",
5 | "version": "0.0.5",
6 | "publisher": "JoeyRobichaud",
7 | "icon": "/images/icon.png",
8 | "galleryBanner": {
9 | "color": "#1E1E1E",
10 | "theme": "dark"
11 | },
12 | "license": "SEE LICENSE IN LICENSE.TXT",
13 | "bugs": {
14 | "url": "https://github.com/JoeRobich/vscode-indent-guides/issues"
15 | },
16 | "homepage": "https://github.com/JoeRobich/vscode-indent-guides/blob/master/README.md",
17 | "repository": {
18 | "type": "git",
19 | "url": "https://github.com/JoeRobich/vscode-indent-guides.git"
20 | },
21 | "engines": {
22 | "vscode": "^0.10.1"
23 | },
24 | "categories": [
25 | "Other"
26 | ],
27 | "activationEvents": [
28 | "*"
29 | ],
30 | "main": "./out/src/extension",
31 | "contributes": {
32 | "configuration": {
33 | "type": "object",
34 | "title": "Indent Guide configuration",
35 | "properties": {
36 | "indent-guide.style": {
37 | "type": "string",
38 | "default": "solid",
39 | "description": "Determines how to render the indent guides. Valid values are \"solid\", \"dotted\", and \"dashed\"."
40 | },
41 | "indent-guide.color": {
42 | "type": "string",
43 | "default": "currentColor",
44 | "description": "Specifies the color of the indent guides."
45 | }
46 | }
47 | }
48 | },
49 | "scripts": {
50 | "vscode:prepublish": "node ./node_modules/vscode/bin/compile",
51 | "compile": "node ./node_modules/vscode/bin/compile -watch -p ./"
52 | },
53 | "dependencies": {
54 | "lodash": "^3.10.1"
55 | },
56 | "devDependencies": {
57 | "typescript": "^1.6.2",
58 | "vscode": "0.10.x"
59 | }
60 | }
--------------------------------------------------------------------------------
/src/extension.ts:
--------------------------------------------------------------------------------
1 | import {workspace, window, commands, Position, Range, TextLine, TextDocument, TextEditor, TextEditorDecorationType, ExtensionContext, Disposable} from 'vscode';
2 | import {range, debounce} from 'lodash';
3 |
4 | export function activate(context:ExtensionContext) {
5 | let guideDecorator = new GuideDecorator();
6 |
7 | // Hook Events
8 | let subscriptions:Disposable[] = [];
9 | workspace.onDidChangeTextDocument(debounce(onEditorChange.bind(null, guideDecorator), 50), this, subscriptions);
10 | window.onDidChangeActiveTextEditor(guideDecorator.updateActiveEditor, guideDecorator, subscriptions);
11 | workspace.onDidChangeConfiguration(guideDecorator.reset, guideDecorator, subscriptions);
12 | let eventDisposable = Disposable.from(...subscriptions);
13 |
14 | // Register Disposables
15 | context.subscriptions.push(guideDecorator);
16 | context.subscriptions.push(eventDisposable);
17 |
18 | guideDecorator.reset();
19 | }
20 |
21 | function onEditorChange(guideDecorator:GuideDecorator) {
22 | let activeEditor = window.activeTextEditor;
23 | let cursorPosition = activeEditor.selection.active;
24 | let cursorLine = activeEditor.document.lineAt(cursorPosition.line);
25 | let indentation = cursorLine.isEmptyOrWhitespace ? cursorLine.text.length : cursorLine.firstNonWhitespaceCharacterIndex;
26 |
27 | if (!activeEditor.selection.isEmpty || // Change to large area, possibly a snippet.
28 | cursorPosition.character <= indentation) // Change within the indentation area.
29 | guideDecorator.updateActiveEditor();
30 | }
31 |
32 | class GuideDecorator {
33 | private _indentGuide:TextEditorDecorationType = null;
34 |
35 | public updateActiveEditor():void {
36 | this.updateIndentGuides(window.activeTextEditor);
37 | }
38 |
39 | updateVisibleEditors():void {
40 | for (let editor of window.visibleTextEditors)
41 | this.updateIndentGuides(editor);
42 | }
43 |
44 | updateIndentGuides(editor:TextEditor):void {
45 | if (editor === null)
46 | return;
47 |
48 | let guideStops:Range[] = this.getIndentedLines(editor.document)
49 | .map(line => this.getGuideStops(line, editor.options.tabSize))
50 | .reduce((all, ranges) => all.concat(ranges), []);
51 |
52 | editor.setDecorations(this._indentGuide, guideStops);
53 | }
54 |
55 | getIndentedLines(document:TextDocument):TextLine[] {
56 | return range(0, document.lineCount)
57 | .map(lineNumber => document.lineAt(lineNumber))
58 | .filter(line => line.firstNonWhitespaceCharacterIndex != 0);
59 | }
60 |
61 | getGuideStops(line:TextLine, tabSize:number):Range[] {
62 | let stopSize = line.text[0] === '\t' ? 1 : tabSize; // Currently expects the indentation to be either tabs or spaces. Produces strange output when both are used on the same line.
63 | let indentation = line.isEmptyOrWhitespace ? line.text.length : line.firstNonWhitespaceCharacterIndex;
64 | let depth = indentation / stopSize;
65 |
66 | return range(1, depth)
67 | .map(stop => new Position(line.lineNumber, stop * stopSize))
68 | .map(position => new Range(position, position));
69 | }
70 |
71 | public reset() {
72 | this.dispose();
73 | this._indentGuide = this.createIndentGuideDecoration();
74 | this.updateVisibleEditors();
75 | }
76 |
77 | createIndentGuideDecoration():TextEditorDecorationType {
78 | var configuration:any = workspace.getConfiguration("indent-guide");
79 | return window.createTextEditorDecorationType({
80 | borderColor: configuration.color,
81 | borderWidth: "0 0 0 1px",
82 | borderStyle: configuration.style
83 | });
84 | }
85 |
86 | dispose() {
87 | if (this._indentGuide !== null)
88 | this._indentGuide.dispose();
89 | }
90 | }
--------------------------------------------------------------------------------
/test/extension.test.ts:
--------------------------------------------------------------------------------
1 | //
2 | // Note: This example test is leveraging the Mocha test framework.
3 | // Please refer to their documentation on https://mochajs.org/ for help.
4 | //
5 |
6 | // The module 'assert' provides assertion methods from node
7 | import * as assert from 'assert';
8 |
9 | // You can import and use all API from the 'vscode' module
10 | // as well as import your extension to test it
11 | import * as vscode from 'vscode';
12 | import * as myExtension from '../src/extension';
13 |
14 | // Defines a Mocha test suite to group tests of similar kind together
15 | suite("Extension Tests", () => {
16 |
17 | // Defines a Mocha unit test
18 | test("Something 1", () => {
19 | assert.equal(-1, [1, 2, 3].indexOf(5));
20 | assert.equal(-1, [1, 2, 3].indexOf(0));
21 | });
22 | });
--------------------------------------------------------------------------------
/test/index.ts:
--------------------------------------------------------------------------------
1 | //
2 | // PLEASE DO NOT MODIFY / DELETE UNLESS YOU KNOW WHAT YOU ARE DOING
3 | //
4 | // This file is providing the test runner to use when running extension tests.
5 | // By default the test runner in use is Mocha based.
6 | //
7 | // You can provide your own test runner if you want to override it by exporting
8 | // a function run(testRoot: string, clb: (error:Error) => void) that the extension
9 | // host can call to run the tests. The test runner is expected to use console.log
10 | // to report the results back to the caller. When the tests are finished, return
11 | // a possible error to the callback or null if none.
12 |
13 | var testRunner = require('vscode/lib/testrunner');
14 |
15 | // You can directly control Mocha options by uncommenting the following lines
16 | // See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options for more info
17 | testRunner.configure({
18 | ui: 'tdd', // the TDD UI is being used in extension.test.ts (suite, test, etc.)
19 | useColors: true // colored output from test results
20 | });
21 |
22 | module.exports = testRunner;
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "ES5",
5 | "outDir": "out",
6 | "noLib": true,
7 | "sourceMap": true
8 | },
9 | "exclude": [
10 | "node_modules"
11 | ]
12 | }
--------------------------------------------------------------------------------
/tsd.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "v4",
3 | "repo": "borisyankov/DefinitelyTyped",
4 | "ref": "master",
5 | "path": "typings",
6 | "bundle": "typings/tsd.d.ts",
7 | "installed": {
8 | "lodash/lodash.d.ts": {
9 | "commit": "8ea42cd8bb11863ed6f242d67c502288ebc45a7b"
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/typings/node.d.ts:
--------------------------------------------------------------------------------
1 | ///
--------------------------------------------------------------------------------
/typings/tsd.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/typings/vscode-typings.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/vsc-extension-quickstart.md:
--------------------------------------------------------------------------------
1 | # Welcome to your first VS Code Extension
2 |
3 | ## What's in the folder
4 | * This folder contains all of the files necessary for your extension
5 | * `package.json` - this is the manifest file in which you declare your extension and command.
6 | The sample plugin registers a command and defines its title and command name. With this information
7 | VS Code can show the command in the command palette. It doesn’t yet need to load the plugin.
8 | * `src/extension.ts` - this is the main file where you will provide the implementation of your command.
9 | The file exports one function, `activate`, which is called the very first time your extension is
10 | activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`.
11 | We pass the function containing the implementation of the command as the second parameter to
12 | `registerCommand`.
13 |
14 | ## Get up and running straight away
15 | * press `F5` to open a new window with your extension loaded
16 | * run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Hello World`
17 | * set breakpoints in your code inside `src/extension.ts` to debug your extension
18 | * find output from your extension in the debug console
19 |
20 | ## Make changes
21 | * you can relaunch the extension from the debug toolbar after changing code in `src/extension.ts`
22 | * you can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes
23 |
24 | ## Explore the API
25 | * you can open the full set of our API when you open the file `node_modules/vscode/vscode.d.ts`
26 |
27 | ## Run tests
28 | * open the debug viewlet (`Ctrl+Shift+D` or `Cmd+Shift+D` on Mac) and from the launch configuration dropdown pick `Launch Tests`
29 | * press `F5` to run the tests in a new window with your extension loaded
30 | * see the output of the test result in the debug console
31 | * make changes to `test/extension.test.ts` or create new test files inside the `test` folder
32 | * by convention, the test runner will only consider files matching the name pattern `**.test.ts`
33 | * you can create folders inside the `test` folder to structure your tests any way you want
--------------------------------------------------------------------------------