Skip to content

Commit

Permalink
first slnx support version (in readonlt)
Browse files Browse the repository at this point in the history
  • Loading branch information
fernandoescolar committed Nov 25, 2024
1 parent fedd5fe commit 8bee9f2
Show file tree
Hide file tree
Showing 10 changed files with 183 additions and 22 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@

All notable changes to the "vscode-solution-explorer" extension will be documented in this file.

## 0.x.x
## 0.8.7

Fixing duplicated items in the tree view: "Element with id is already registered" error

Fixing issue with terminal after executing the update all packages in project command.

Adding new nuget package management inline in a .csproj file.

Adding readonly support for .slnx files.

Adding .slnx grammar support for highlighting.

## 0.8.6

Bugfix #296: Ctr+Enter hotkey should have a "when" condition to not mess with other hotkeys
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ You can execute the "Open solution" command from the command palette or from the

### Omnisharp integration

You can enable omnisharp integration and vscode-solution-explorer will open the same .sln file you open with Microsoft extension.
You can enable omnisharp integration and vscode-solution-explorer will open the same .sln or .slnx file you open with Microsoft extension.

![Activate Omnisharp integration in settings panel](https://github.com/fernandoescolar/vscode-solution-explorer/raw/main/images/omnisharp-integration.png)

Expand Down Expand Up @@ -240,6 +240,10 @@ This extension adds syntax highlighting to `.sln` files.

![Solution syntax highlighting](https://github.com/fernandoescolar/vscode-solution-explorer/raw/main/images/vscode-solution-explorer-sln-syntax.png)

And also for `.slnx` files.

![Solution XML syntax highlighting](https://github.com/fernandoescolar/vscode-solution-explorer/raw/main/images/vscode-solution-explorer-slnx-syntax.png)

## Extension Settings

You can configure the extension in the Visual Studio Code settings panel:
Expand Down
Binary file added images/vscode-solution-explorer-slnx-syntax.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 22 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "vscode-solution-explorer",
"displayName": "vscode-solution-explorer",
"description": "Visual Studio .sln file explorer for Visual Studio Code",
"version": "0.8.6",
"version": "0.8.7",
"license": "MIT",
"publisher": "fernandoescolar",
"icon": "images/icon.png",
Expand All @@ -26,8 +26,8 @@
"Other"
],
"activationEvents": [
"onView:slnexpl",
"workspaceContains:**/*.sln",
"workspaceContains:**/*.slnx",
"*"
],
"main": "./out/extension",
Expand Down Expand Up @@ -349,6 +349,11 @@
"command": "solutionExplorer.openSelectedSolution",
"when": "resourceExtname == .sln",
"group": "navigation"
},
{
"command": "solutionExplorer.openSelectedSolution",
"when": "resourceExtname == .slnx",
"group": "navigation"
}
],
"view/title": [
Expand Down Expand Up @@ -761,13 +766,28 @@
".sln"
],
"configuration": "./syntaxes/sln.language.json"
},
{
"id": "slnx",
"aliases": [
"Solution XML File",
"sln"
],
"extensions": [
".slnx"
]
}
],
"grammars": [
{
"language": "sln",
"scopeName": "source.solution",
"path": "./syntaxes/sln.grammar.json"
},
{
"language": "slnx",
"scopeName": "source.solutionx",
"path": "./syntaxes/slnx.grammar.json"
}
],
"configuration": {
Expand Down
2 changes: 1 addition & 1 deletion src/core/Solutions/SlnLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export class SlnLoader {
solution.type = SolutionType.Sln;
solution.fullPath = filepath;
solution.folderPath = path.dirname(filepath);
solution.name = path.basename(filepath);
solution.name = path.basename(filepath, path.extname(filepath));
sln.projects.filter(x => !x.parentProjectGuid).forEach(project => {
const i = this.createSolutionItem(sln, project);
solution.addItem(i);
Expand Down
9 changes: 8 additions & 1 deletion src/core/Solutions/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
export * from "./model";
export {
Solution,
SolutionType,
SolutionItem,
SolutionFolder,
SolutionProject,
SolutionProjectType,
} from "./model";
export * from "./SolutionFactory";
export * from "../../SolutionFinder";
2 changes: 1 addition & 1 deletion src/core/Solutions/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class SolutionObject {
}
}

class SolutionParentObject extends SolutionObject {
export class SolutionParentObject extends SolutionObject {
protected items: SolutionItem[] = [];

public addItem(item: SolutionItem): void {
Expand Down
50 changes: 36 additions & 14 deletions src/core/Solutions/slnx/Slnx.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as path from "@extensions/path";
import * as fs from "@extensions/fs";
import * as xml from "@extensions/xml";
import { Solution, SolutionFolder, SolutionItem, SolutionProject, SolutionProjectType, SolutionType } from "../model";
import { Solution, SolutionFolder, SolutionItem, SolutionParentObject, SolutionProject, SolutionProjectType, SolutionType } from "../model";
import { v4 as uuidv4 } from "uuid";

export class SlnxSolution extends Solution {
Expand All @@ -17,7 +17,7 @@ export class SlnxSolution extends Solution {
this.document = await xml.parseToJson(content);
this.fullPath = filepath;
this.folderPath = path.dirname(filepath);
this.name = path.basename(filepath);
this.name = path.basename(filepath, path.extname(filepath));
this.refresh();
}

Expand All @@ -27,39 +27,61 @@ export class SlnxSolution extends Solution {
}

this.items = [];
if (this.document.elements.length === 1) {
if (this.document.elements.length === 1 && this.document.elements[0].name === 'Solution') {
this.document.elements[0].elements ||= [];
this.document.elements[0].elements.forEach((child: { name: string; }) => {
if (child.name === 'Folder') {
this.addItem(this.createFolder(child));
this.addFolder(child, this);
} else if (child.name === 'Project') {
this.addItem(this.createProject(child));
this.addProject(child, this);
}
});
}
}

private createProject(child: any) : SolutionItem {
private addProject(child: any, parent: SolutionParentObject) : SolutionItem {
const project = new SolutionProject(uuidv4());
const projectPath = child.attributes.Path.replace(/\\/g, path.sep).trim();
project.fullPath = path.join(this.folderPath, projectPath);
project.name = path.basename(projectPath, path.extname(projectPath));
project.type = SolutionProjectType.default;

parent.addItem(project);
return project;
}

private createFolder(child: any) {
const folder = new SolutionFolder(uuidv4());
folder.name = child.attributes.Name.replace(/^[\/\\]+|[\/\\]+$/g, '');
folder.fullPath = path.join(this.folderPath, folder.name);
private addFolder(child: any, parent: SolutionParentObject) {
const names = child.attributes.Name.replace(/^[\/\\]+|[\/\\]+$/g, '').split(/[\/\\]/);
for (let i = 0; i < names.length; i++) {
if (!names[i]) continue;

child.elements.forEach((child: { name: string; }) => {
const existing = parent.getFolders().find((f) => f.name === names[i]);
if (existing) {
parent = existing;
} else {
const folder = new SolutionFolder(uuidv4());
folder.name = names[i];
folder.fullPath = path.join(this.folderPath, folder.name);
parent.addItem(folder);
parent = folder;
}
}

child.elements ||= [];
child.elements.forEach((child: {attributes: any; name: string; }) => {
if (child.name === 'Project') {
folder.addItem(this.createProject(child))
this.addProject(child, parent);
} else if (child.name === 'Folder') {
folder.addItem(this.createFolder(child));
this.addFolder(child, parent);
} else if (child.name === 'File') {
const filepath = child.attributes.Path.replace(/\\/g, path.sep).trim();
if (parent instanceof SolutionFolder) {
const filename = path.basename(filepath);
parent.solutionFiles[filename] = path.join(this.folderPath, filepath);
}
}
});

return folder;
return parent;
}
}
3 changes: 2 additions & 1 deletion src/tree/items/SolutionTreeItem.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ISubscription, EventTypes, IEvent, IFileEvent, FileEventType } from "@events";
import { Solution, SolutionFactory } from "@core/Solutions";
import { Solution, SolutionFactory, SolutionType } from "@core/Solutions";
import { TreeItem, TreeItemCollapsibleState, TreeItemFactory, TreeItemContext, ContextValues } from "@tree";

export class SolutionTreeItem extends TreeItem {
Expand All @@ -9,6 +9,7 @@ export class SolutionTreeItem extends TreeItem {
super(context, context.solution.name, TreeItemCollapsibleState.Expanded, ContextValues.solution, context.solution.fullPath);
this.allowIconTheme = false;
this.subscription = context.eventAggregator.subscribe(EventTypes.file, evt => this.onFileEvent(evt));
this.description = context.solution.type === SolutionType.Sln ? '' : 'readonly';
}

public refreshContextValue(): void {
Expand Down
103 changes: 103 additions & 0 deletions syntaxes/slnx.grammar.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
{
"name": "Visual Studio XML Solution File",
"scopeName": "source.solutionx",
"fileTypes": [
"slnx"
],
"patterns": [
{
"include": "#main"
}
],
"repository": {
"main": {
"patterns": [
{
"include": "#comments"
},
{
"include": "#tag"
}
]
},
"tag": {
"begin": "(</?)([-\\w\\.]+)",
"captures": {
"1": {
"name": "punctuation.definition.tag.slnx"
},
"2": {
"name": "entity.name.tag.namespace.slnx"
}
},
"end": "(/?>)",
"name": "meta.tag.slnx",
"patterns": [
{
"include": "#tagStuff"
}
]
},
"tagStuff": {
"patterns": [
{
"captures": {
"1": {
"name": "entity.other.attribute-name.slnx"
}
},
"match": "(?:^|\\s+)([-\\w.]+)\\s*="
},
{
"include": "#doublequotedString"
}
]
},
"doublequotedString": {
"begin": "\"",
"beginCaptures": {
"0": {
"name": "punctuation.definition.string.begin.slnx"
}
},
"end": "\"",
"endCaptures": {
"0": {
"name": "punctuation.definition.string.end.slnx"
}
},
"name": "string.quoted.double.slnx",
"patterns": [
{
"include": "#entity"
}
]
},
"entity": {
"captures": {
"1": {
"name": "punctuation.definition.constant.xml"
},
"3": {
"name": "punctuation.definition.constant.xml"
}
},
"match": "(&)([:a-zA-Z_][:a-zA-Z0-9_.-]*|#[0-9]+|#x[0-9a-fA-F]+)(;)",
"name": "constant.character.entity.xml"
},
"comments": {
"patterns": [
{
"begin": "<!--",
"captures": {
"0": {
"name": "punctuation.definition.comment.slnx"
}
},
"end": "-->",
"name": "comment.block.slnx"
}
]
}
}
}

0 comments on commit 8bee9f2

Please sign in to comment.