Initial commit
This commit is contained in:
Коммит
aaefbeae31
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"root": true,
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 6,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"plugins": [
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"rules": {
|
||||
"@typescript-eslint/naming-convention": "warn",
|
||||
"@typescript-eslint/semi": "warn",
|
||||
"curly": "warn",
|
||||
"eqeqeq": "warn",
|
||||
"no-throw-literal": "warn",
|
||||
"semi": "off"
|
||||
},
|
||||
"ignorePatterns": [
|
||||
"out",
|
||||
"dist",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
out
|
||||
dist
|
||||
node_modules
|
||||
.vscode-test/
|
||||
*.vsix
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": ["dbaeumer.vscode-eslint", "amodio.tsl-problem-matcher"]
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
// A launch configuration that compiles the extension and then opens it inside a new window
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Run Extension",
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceFolder}"
|
||||
],
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/dist/**/*.js"
|
||||
],
|
||||
"preLaunchTask": "${defaultBuildTask}"
|
||||
},
|
||||
{
|
||||
"name": "Extension Tests",
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceFolder}",
|
||||
"--extensionTestsPath=${workspaceFolder}/out/test/suite/index"
|
||||
],
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/out/**/*.js",
|
||||
"${workspaceFolder}/dist/**/*.js"
|
||||
],
|
||||
"preLaunchTask": "tasks: watch-tests"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
// Place your settings in this file to overwrite default and user settings.
|
||||
{
|
||||
"files.exclude": {
|
||||
"out": false, // set this to true to hide the "out" folder with the compiled JS files
|
||||
"dist": false // set this to true to hide the "dist" folder with the compiled JS files
|
||||
},
|
||||
"search.exclude": {
|
||||
"out": true, // set this to false to include "out" folder in search results
|
||||
"dist": true // set this to false to include "dist" folder in search results
|
||||
},
|
||||
// Turn off tsc task auto detection since we have the necessary tasks as npm scripts
|
||||
"typescript.tsc.autoDetect": "off"
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "watch",
|
||||
"problemMatcher": [
|
||||
"$ts-webpack-watch",
|
||||
"$tslint-webpack-watch"
|
||||
],
|
||||
"isBackground": true,
|
||||
"presentation": {
|
||||
"reveal": "never",
|
||||
"group": "watchers"
|
||||
},
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "watch-tests",
|
||||
"problemMatcher": "$tsc-watch",
|
||||
"isBackground": true,
|
||||
"presentation": {
|
||||
"reveal": "never",
|
||||
"group": "watchers"
|
||||
},
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"label": "tasks: watch-tests",
|
||||
"dependsOn": [
|
||||
"npm: watch",
|
||||
"npm: watch-tests"
|
||||
],
|
||||
"problemMatcher": []
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
.vscode/**
|
||||
.vscode-test/**
|
||||
out/**
|
||||
node_modules/**
|
||||
src/**
|
||||
.gitignore
|
||||
.yarnrc
|
||||
webpack.config.js
|
||||
vsc-extension-quickstart.md
|
||||
**/tsconfig.json
|
||||
**/.eslintrc.json
|
||||
**/*.map
|
||||
**/*.ts
|
|
@ -0,0 +1,9 @@
|
|||
# Change Log
|
||||
|
||||
All notable changes to the "avalonia-tagsandidentation" extension will be documented in this file.
|
||||
|
||||
Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
- Initial release
|
|
@ -0,0 +1,70 @@
|
|||
# avalonia-tagsandidentation README
|
||||
|
||||
This is the README for your extension "avalonia-tagsandidentation". After writing up a brief description, we recommend including the following sections.
|
||||
|
||||
## Features
|
||||
|
||||
Describe specific features of your extension including screenshots of your extension in action. Image paths are relative to this README file.
|
||||
|
||||
For example if there is an image subfolder under your extension project workspace:
|
||||
|
||||
\!\[feature X\]\(images/feature-x.png\)
|
||||
|
||||
> Tip: Many popular extensions utilize animations. This is an excellent way to show off your extension! We recommend short, focused animations that are easy to follow.
|
||||
|
||||
## Requirements
|
||||
|
||||
If you have any requirements or dependencies, add a section describing those and how to install and configure them.
|
||||
|
||||
## Extension Settings
|
||||
|
||||
Include if your extension adds any VS Code settings through the `contributes.configuration` extension point.
|
||||
|
||||
For example:
|
||||
|
||||
This extension contributes the following settings:
|
||||
|
||||
* `myExtension.enable`: enable/disable this extension
|
||||
* `myExtension.thing`: set to `blah` to do something
|
||||
|
||||
## Known Issues
|
||||
|
||||
Calling out known issues can help limit users opening duplicate issues against your extension.
|
||||
|
||||
## Release Notes
|
||||
|
||||
Users appreciate release notes as you update your extension.
|
||||
|
||||
### 1.0.0
|
||||
|
||||
Initial release of ...
|
||||
|
||||
### 1.0.1
|
||||
|
||||
Fixed issue #.
|
||||
|
||||
### 1.1.0
|
||||
|
||||
Added features X, Y, and Z.
|
||||
|
||||
-----------------------------------------------------------------------------------------------------------
|
||||
## Following extension guidelines
|
||||
|
||||
Ensure that you've read through the extensions guidelines and follow the best practices for creating your extension.
|
||||
|
||||
* [Extension Guidelines](https://code.visualstudio.com/api/references/extension-guidelines)
|
||||
|
||||
## Working with Markdown
|
||||
|
||||
**Note:** You can author your README using Visual Studio Code. Here are some useful editor keyboard shortcuts:
|
||||
|
||||
* Split the editor (`Cmd+\` on macOS or `Ctrl+\` on Windows and Linux)
|
||||
* Toggle preview (`Shift+CMD+V` on macOS or `Shift+Ctrl+V` on Windows and Linux)
|
||||
* Press `Ctrl+Space` (Windows, Linux) or `Cmd+Space` (macOS) to see a list of Markdown snippets
|
||||
|
||||
### For more information
|
||||
|
||||
* [Visual Studio Code's Markdown Support](http://code.visualstudio.com/docs/languages/markdown)
|
||||
* [Markdown Syntax Reference](https://help.github.com/articles/markdown-basics/)
|
||||
|
||||
**Enjoy!**
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,63 @@
|
|||
{
|
||||
"name": "avalonia-tagsandidentation",
|
||||
"displayName": "Avalonia.TagsAndIdentation",
|
||||
"description": "Responsable for Auto-Close aXAML tags and indent the right way",
|
||||
"version": "0.0.1",
|
||||
"engines": {
|
||||
"vscode": "^1.65.0"
|
||||
},
|
||||
"categories": [
|
||||
"Programming Languages",
|
||||
"Linters"
|
||||
],
|
||||
"keywords": [
|
||||
"xml",
|
||||
"xaml",
|
||||
"avalonia",
|
||||
"wpf",
|
||||
"xsd",
|
||||
"completion",
|
||||
"linter",
|
||||
"lint",
|
||||
"format"
|
||||
],
|
||||
"activationEvents": [
|
||||
"onLanguage:xml"
|
||||
],
|
||||
"main": "./dist/extension.js",
|
||||
"contributes": {
|
||||
"languages": [
|
||||
{
|
||||
"id": "xml",
|
||||
"configuration": "./src/language-configuration.json"
|
||||
}
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"vscode:prepublish": "npm run package",
|
||||
"compile": "webpack",
|
||||
"watch": "webpack --watch",
|
||||
"package": "webpack --mode production --devtool hidden-source-map",
|
||||
"compile-tests": "tsc -p . --outDir out",
|
||||
"watch-tests": "tsc -p . -w --outDir out",
|
||||
"pretest": "npm run compile-tests && npm run compile && npm run lint",
|
||||
"lint": "eslint src --ext ts",
|
||||
"test": "node ./out/test/runTest.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/vscode": "^1.65.0",
|
||||
"@types/glob": "^7.1.4",
|
||||
"@types/mocha": "^9.0.0",
|
||||
"@types/node": "14.x",
|
||||
"@typescript-eslint/eslint-plugin": "^5.1.0",
|
||||
"@typescript-eslint/parser": "^5.1.0",
|
||||
"eslint": "^8.1.0",
|
||||
"glob": "^7.1.7",
|
||||
"mocha": "^9.1.3",
|
||||
"typescript": "^4.4.4",
|
||||
"ts-loader": "^9.2.5",
|
||||
"webpack": "^5.52.1",
|
||||
"webpack-cli": "^4.8.0",
|
||||
"@vscode/test-electron": "^1.6.2"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
import * as vscode from 'vscode';
|
||||
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
|
||||
vscode.workspace.onDidChangeTextDocument(event => {
|
||||
insertAutoCloseTag(event);
|
||||
});
|
||||
}
|
||||
|
||||
export function deactivate() {}
|
||||
|
||||
function insertAutoCloseTag(event: vscode.TextDocumentChangeEvent): void {
|
||||
if (!event.contentChanges[0]) {
|
||||
return;
|
||||
}
|
||||
|
||||
let isRightAngleBracket = checkRightAngleBracket(event.contentChanges[0]);
|
||||
if (!isRightAngleBracket && event.contentChanges[0].text !== "/") {
|
||||
return;
|
||||
}
|
||||
|
||||
let editor = vscode.window.activeTextEditor;
|
||||
if (!editor) {
|
||||
return;
|
||||
}
|
||||
|
||||
let selection = editor.selection;
|
||||
let originalPosition = selection.start.translate(0, 1);
|
||||
|
||||
let excludedTags: string[] = [];
|
||||
|
||||
let textLine = editor.document.lineAt(selection.start);
|
||||
let text = textLine.text.substring(0, selection.start.character + 1);
|
||||
let result = /<([_a-zA-Z][a-zA-Z0-9:\-_.]*)(?:\s+[^<>]*?[^\s/<>=]+?)*?\s?(\/|>)$/.exec(text);
|
||||
|
||||
let selectedLine = selection.start.line;
|
||||
let multilineText = "";
|
||||
while(result === null) {
|
||||
selectedLine --;
|
||||
multilineText = editor.document.getText(
|
||||
new vscode.Range(
|
||||
new vscode.Position(selectedLine, 0),
|
||||
new vscode.Position(selection.start.line, selection.start.character + 1)));
|
||||
|
||||
multilineText = multilineText.trim();
|
||||
multilineText = multilineText.replace("\t", "");
|
||||
multilineText = multilineText.replace("\r\n", "");
|
||||
|
||||
result = /<([_a-zA-Z][a-zA-Z0-9:\-_.]*)(?:\s+[^<>]*?[^\s/<>=]+?)*?\s?(\/|>)$/.exec(multilineText);
|
||||
}
|
||||
|
||||
if (
|
||||
result !== null &&
|
||||
((occurrenceCount(result[0], "'") % 2 === 0) &&
|
||||
(occurrenceCount(result[0], "\"") % 2 === 0) &&
|
||||
(occurrenceCount(result[0], "`") % 2 === 0))) {
|
||||
|
||||
if (result[2] === ">") {
|
||||
if (excludedTags.indexOf(result[1].toLowerCase()) === -1) {
|
||||
editor.edit((editBuilder) => {
|
||||
if (result !== null) {
|
||||
editBuilder.insert(originalPosition, "</" + result[1] + ">");
|
||||
}
|
||||
|
||||
}).then(() => {
|
||||
if (editor !== undefined) {
|
||||
editor.selection = new vscode.Selection(originalPosition, originalPosition);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (textLine.text.length <= selection.start.character + 1 || textLine.text[selection.start.character + 1] !== '>') { // if not typing "/" just before ">", add the ">" after "/"
|
||||
|
||||
if (textLine.text[selection.start.character - 1] !== " ")
|
||||
{
|
||||
editor.edit((editBuilder) => {
|
||||
const spacePosition = originalPosition.translate(0, -1);
|
||||
editBuilder.insert(spacePosition, " ");
|
||||
editBuilder.insert(originalPosition, ">");
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
editor.edit((editBuilder) => {
|
||||
const spacePosition = originalPosition.translate(0, -1);
|
||||
editBuilder.insert(originalPosition, ">");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function checkRightAngleBracket(contentChange: vscode.TextDocumentContentChangeEvent): boolean {
|
||||
return contentChange.text === ">" || checkRightAngleBracketInVSCode_1_8(contentChange);
|
||||
}
|
||||
|
||||
function checkRightAngleBracketInVSCode_1_8(contentChange: vscode.TextDocumentContentChangeEvent): boolean {
|
||||
return contentChange.text.endsWith(">") && contentChange.range.start.character === 0
|
||||
&& contentChange.range.start.line === contentChange.range.end.line
|
||||
&& !contentChange.range.end.isEqual(new vscode.Position(0, 0));
|
||||
}
|
||||
|
||||
function getNextChar(editor: vscode.TextEditor, position: vscode.Position): string {
|
||||
let nextPosition = position.translate(0, 1);
|
||||
let text = editor.document.getText(new vscode.Range(position, nextPosition));
|
||||
return text;
|
||||
}
|
||||
|
||||
function getCloseTag(text: string, excludedTags: string[]): string {
|
||||
let regex = /<(\/?[_a-zA-Z][a-zA-Z0-9:\-_.]*)(?:\s+[^<>]*?[^\s/<>=]+?)*?\s?>/g;
|
||||
let result = null;
|
||||
let stack = [];
|
||||
while ((result = regex.exec(text)) !== null) {
|
||||
let isStartTag = result[1].substr(0, 1) !== "/";
|
||||
let tag = isStartTag ? result[1] : result[1].substr(1);
|
||||
if (excludedTags.indexOf(tag.toLowerCase()) === -1) {
|
||||
if (isStartTag) {
|
||||
stack.push(tag);
|
||||
} else if (stack.length > 0) {
|
||||
let lastTag = stack[stack.length - 1];
|
||||
if (lastTag === tag) {
|
||||
stack.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (stack.length > 0) {
|
||||
let closeTag = stack[stack.length - 1];
|
||||
if (text.substr(text.length - 2) === "</") {
|
||||
return closeTag + ">";
|
||||
}
|
||||
if (text.substr(text.length - 1) === "<") {
|
||||
return "/" + closeTag + ">";
|
||||
}
|
||||
return "</" + closeTag + ">";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
function moveSelectionRight(selection: vscode.Selection, shift: number): vscode.Selection {
|
||||
let newPosition = selection.active.translate(0, shift);
|
||||
let newSelection = new vscode.Selection(newPosition, newPosition);
|
||||
return newSelection;
|
||||
}
|
||||
|
||||
function occurrenceCount(source: string, find: string): number {
|
||||
return source.split(find).length - 1;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"capabilities" : {
|
||||
"documentFormattingProvider" : "true"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
import * as path from 'path';
|
||||
|
||||
import { runTests } from '@vscode/test-electron';
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
// The folder containing the Extension Manifest package.json
|
||||
// Passed to `--extensionDevelopmentPath`
|
||||
const extensionDevelopmentPath = path.resolve(__dirname, '../../');
|
||||
|
||||
// The path to test runner
|
||||
// Passed to --extensionTestsPath
|
||||
const extensionTestsPath = path.resolve(__dirname, './suite/index');
|
||||
|
||||
// Download VS Code, unzip it and run the integration test
|
||||
await runTests({ extensionDevelopmentPath, extensionTestsPath });
|
||||
} catch (err) {
|
||||
console.error('Failed to run tests');
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
|
@ -0,0 +1,15 @@
|
|||
import * as assert from 'assert';
|
||||
|
||||
// You can import and use all API from the 'vscode' module
|
||||
// as well as import your extension to test it
|
||||
import * as vscode from 'vscode';
|
||||
// import * as myExtension from '../../extension';
|
||||
|
||||
suite('Extension Test Suite', () => {
|
||||
vscode.window.showInformationMessage('Start all tests.');
|
||||
|
||||
test('Sample test', () => {
|
||||
assert.strictEqual(-1, [1, 2, 3].indexOf(5));
|
||||
assert.strictEqual(-1, [1, 2, 3].indexOf(0));
|
||||
});
|
||||
});
|
|
@ -0,0 +1,38 @@
|
|||
import * as path from 'path';
|
||||
import * as Mocha from 'mocha';
|
||||
import * as glob from 'glob';
|
||||
|
||||
export function run(): Promise<void> {
|
||||
// Create the mocha test
|
||||
const mocha = new Mocha({
|
||||
ui: 'tdd',
|
||||
color: true
|
||||
});
|
||||
|
||||
const testsRoot = path.resolve(__dirname, '..');
|
||||
|
||||
return new Promise((c, e) => {
|
||||
glob('**/**.test.js', { cwd: testsRoot }, (err, files) => {
|
||||
if (err) {
|
||||
return e(err);
|
||||
}
|
||||
|
||||
// Add files to the test suite
|
||||
files.forEach(f => mocha.addFile(path.resolve(testsRoot, f)));
|
||||
|
||||
try {
|
||||
// Run the mocha test
|
||||
mocha.run(failures => {
|
||||
if (failures > 0) {
|
||||
e(new Error(`${failures} tests failed.`));
|
||||
} else {
|
||||
c();
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
e(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "ES2020",
|
||||
"lib": [
|
||||
"ES2020"
|
||||
],
|
||||
"sourceMap": true,
|
||||
"rootDir": "src",
|
||||
"strict": true /* enable all strict type-checking options */
|
||||
/* Additional Checks */
|
||||
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
||||
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
".vscode-test"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
//@ts-check
|
||||
|
||||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
|
||||
//@ts-check
|
||||
/** @typedef {import('webpack').Configuration} WebpackConfig **/
|
||||
|
||||
/** @type WebpackConfig */
|
||||
const extensionConfig = {
|
||||
target: 'node', // vscode extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/
|
||||
mode: 'none', // this leaves the source code as close as possible to the original (when packaging we set this to 'production')
|
||||
|
||||
entry: './src/extension.ts', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/
|
||||
output: {
|
||||
// the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'extension.js',
|
||||
libraryTarget: 'commonjs2'
|
||||
},
|
||||
externals: {
|
||||
vscode: 'commonjs vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/
|
||||
// modules added here also need to be added in the .vscodeignore file
|
||||
},
|
||||
resolve: {
|
||||
// support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader
|
||||
extensions: ['.ts', '.js']
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.ts$/,
|
||||
exclude: /node_modules/,
|
||||
use: [
|
||||
{
|
||||
loader: 'ts-loader'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
devtool: 'nosources-source-map',
|
||||
infrastructureLogging: {
|
||||
level: "log", // enables logging required for problem matchers
|
||||
},
|
||||
};
|
||||
module.exports = [ extensionConfig ];
|
Загрузка…
Ссылка в новой задаче