Three problems visible on a real project: - The inline pin button showed twice on every unpinned row: the `when` clauses matched /pinned/ and /unpinned/, and "unpinned" contains "pinned". Context values now use unambiguous `pin:on` / `pin:off` tokens, and both commands call one togglePin — the pair exists only so the button's icon can reflect the current state. - The list selected the tab you just left. followActiveTab read `isActive` from the entry snapshot, and after a refresh the tree has not necessarily asked for children yet, so it matched against the previous build. It now rebuilds the list and compares against the live active tab. - Every file in a Unity repo resolved to an arbitrary project. Unity generates one .csproj per assembly into the repo root, and the walk took whichever readDirectory happened to return first. Matches are now sorted, a project file named after its directory wins, and .asmdef — which lives in the assembly's own directory and is what actually defines a Unity assembly — is a default marker, so it is found before reaching the root. Palette widened from 8 to 12 hues, since a hash-assigned colour collides more often than it looks like it should. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
393 lines
10 KiB
JSON
393 lines
10 KiB
JSON
{
|
|
"name": "vertical-tabs",
|
|
"displayName": "Vertical Tabs",
|
|
"description": "Open editors as a flat vertical list, colour-coded by project, with pinning. For people who turn the tab bar off.",
|
|
"version": "0.1.0",
|
|
"publisher": "local",
|
|
"license": "MIT",
|
|
"engines": {
|
|
"vscode": "^1.85.0"
|
|
},
|
|
"categories": [
|
|
"Other"
|
|
],
|
|
"keywords": [
|
|
"tabs",
|
|
"vertical tabs",
|
|
"open editors",
|
|
"csharp",
|
|
"visual studio"
|
|
],
|
|
"activationEvents": [
|
|
"onStartupFinished"
|
|
],
|
|
"main": "./out/extension.js",
|
|
"contributes": {
|
|
"views": {
|
|
"explorer": [
|
|
{
|
|
"id": "verticalTabs.tabs",
|
|
"name": "Tabs",
|
|
"contextualTitle": "Tabs",
|
|
"visibility": "visible"
|
|
}
|
|
]
|
|
},
|
|
"viewsWelcome": [
|
|
{
|
|
"view": "verticalTabs.tabs",
|
|
"contents": "No editors are open."
|
|
}
|
|
],
|
|
"commands": [
|
|
{
|
|
"command": "verticalTabs.open",
|
|
"title": "Open Tab",
|
|
"category": "Tabs"
|
|
},
|
|
{
|
|
"command": "verticalTabs.close",
|
|
"title": "Close",
|
|
"category": "Tabs",
|
|
"icon": "$(close)"
|
|
},
|
|
{
|
|
"command": "verticalTabs.closeOthers",
|
|
"title": "Close Others",
|
|
"category": "Tabs"
|
|
},
|
|
{
|
|
"command": "verticalTabs.pin",
|
|
"title": "Pin",
|
|
"category": "Tabs",
|
|
"icon": "$(pin)"
|
|
},
|
|
{
|
|
"command": "verticalTabs.unpin",
|
|
"title": "Unpin",
|
|
"category": "Tabs",
|
|
"icon": "$(pinned)"
|
|
},
|
|
{
|
|
"command": "verticalTabs.copyPath",
|
|
"title": "Copy Path",
|
|
"category": "Tabs"
|
|
},
|
|
{
|
|
"command": "verticalTabs.revealInExplorer",
|
|
"title": "Reveal in Explorer View",
|
|
"category": "Tabs"
|
|
},
|
|
{
|
|
"command": "verticalTabs.setOrderOpen",
|
|
"title": "Sort by Open Order",
|
|
"category": "Tabs"
|
|
},
|
|
{
|
|
"command": "verticalTabs.setOrderProject",
|
|
"title": "Sort by Project",
|
|
"category": "Tabs"
|
|
},
|
|
{
|
|
"command": "verticalTabs.setOrderName",
|
|
"title": "Sort by File Name",
|
|
"category": "Tabs"
|
|
}
|
|
],
|
|
"menus": {
|
|
"view/title": [
|
|
{
|
|
"command": "verticalTabs.setOrderOpen",
|
|
"when": "view == verticalTabs.tabs",
|
|
"group": "1_order@1"
|
|
},
|
|
{
|
|
"command": "verticalTabs.setOrderProject",
|
|
"when": "view == verticalTabs.tabs",
|
|
"group": "1_order@2"
|
|
},
|
|
{
|
|
"command": "verticalTabs.setOrderName",
|
|
"when": "view == verticalTabs.tabs",
|
|
"group": "1_order@3"
|
|
}
|
|
],
|
|
"view/item/context": [
|
|
{
|
|
"command": "verticalTabs.pin",
|
|
"when": "view == verticalTabs.tabs && viewItem =~ /pin:off/",
|
|
"group": "inline@1"
|
|
},
|
|
{
|
|
"command": "verticalTabs.unpin",
|
|
"when": "view == verticalTabs.tabs && viewItem =~ /pin:on/",
|
|
"group": "inline@1"
|
|
},
|
|
{
|
|
"command": "verticalTabs.close",
|
|
"when": "view == verticalTabs.tabs",
|
|
"group": "inline@2"
|
|
},
|
|
{
|
|
"command": "verticalTabs.pin",
|
|
"when": "view == verticalTabs.tabs && viewItem =~ /pin:off/",
|
|
"group": "1_state@1"
|
|
},
|
|
{
|
|
"command": "verticalTabs.unpin",
|
|
"when": "view == verticalTabs.tabs && viewItem =~ /pin:on/",
|
|
"group": "1_state@1"
|
|
},
|
|
{
|
|
"command": "verticalTabs.close",
|
|
"when": "view == verticalTabs.tabs",
|
|
"group": "2_close@1"
|
|
},
|
|
{
|
|
"command": "verticalTabs.closeOthers",
|
|
"when": "view == verticalTabs.tabs",
|
|
"group": "2_close@2"
|
|
},
|
|
{
|
|
"command": "verticalTabs.copyPath",
|
|
"when": "view == verticalTabs.tabs && viewItem =~ /file/",
|
|
"group": "3_path@1"
|
|
},
|
|
{
|
|
"command": "verticalTabs.revealInExplorer",
|
|
"when": "view == verticalTabs.tabs && viewItem =~ /file/",
|
|
"group": "3_path@2"
|
|
}
|
|
],
|
|
"commandPalette": [
|
|
{
|
|
"command": "verticalTabs.open",
|
|
"when": "false"
|
|
},
|
|
{
|
|
"command": "verticalTabs.close",
|
|
"when": "false"
|
|
},
|
|
{
|
|
"command": "verticalTabs.closeOthers",
|
|
"when": "false"
|
|
},
|
|
{
|
|
"command": "verticalTabs.pin",
|
|
"when": "false"
|
|
},
|
|
{
|
|
"command": "verticalTabs.unpin",
|
|
"when": "false"
|
|
},
|
|
{
|
|
"command": "verticalTabs.copyPath",
|
|
"when": "false"
|
|
},
|
|
{
|
|
"command": "verticalTabs.revealInExplorer",
|
|
"when": "false"
|
|
}
|
|
]
|
|
},
|
|
"configuration": {
|
|
"title": "Vertical Tabs",
|
|
"properties": {
|
|
"verticalTabs.order": {
|
|
"type": "string",
|
|
"enum": [
|
|
"open",
|
|
"project",
|
|
"name"
|
|
],
|
|
"enumDescriptions": [
|
|
"Keep the order the editors are open in, matching the tab bar.",
|
|
"Group by project, so the colours run in blocks.",
|
|
"Sort by file name."
|
|
],
|
|
"default": "open",
|
|
"description": "How the tab list is ordered. Pinned tabs always come first."
|
|
},
|
|
"verticalTabs.pinnedFirst": {
|
|
"type": "boolean",
|
|
"default": true,
|
|
"description": "List pinned tabs above the rest."
|
|
},
|
|
"verticalTabs.showProject": {
|
|
"type": "boolean",
|
|
"default": true,
|
|
"description": "Show the containing project name beside the file."
|
|
},
|
|
"verticalTabs.showDirectory": {
|
|
"type": "boolean",
|
|
"default": true,
|
|
"description": "Show the containing directory beside the file, for files with the same name."
|
|
},
|
|
"verticalTabs.colorByProject": {
|
|
"type": "boolean",
|
|
"default": true,
|
|
"description": "Colour each tab's icon by its containing project."
|
|
},
|
|
"verticalTabs.allGroups": {
|
|
"type": "boolean",
|
|
"default": true,
|
|
"description": "List the tabs of every editor group. When off, only the active group is listed."
|
|
},
|
|
"verticalTabs.projectFiles": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
},
|
|
"default": [
|
|
".asmdef",
|
|
".csproj",
|
|
".fsproj",
|
|
".vbproj",
|
|
"package.json",
|
|
"Cargo.toml",
|
|
"go.mod",
|
|
"pyproject.toml",
|
|
"pom.xml",
|
|
"build.gradle"
|
|
],
|
|
"description": "File names or extensions that mark a project root. The nearest match above a file names its project."
|
|
}
|
|
}
|
|
},
|
|
"colors": [
|
|
{
|
|
"id": "verticalTabs.project1",
|
|
"description": "Project colour 1.",
|
|
"defaults": {
|
|
"dark": "#4ec9b0",
|
|
"light": "#227d68",
|
|
"highContrast": "#4ec9b0"
|
|
}
|
|
},
|
|
{
|
|
"id": "verticalTabs.project2",
|
|
"description": "Project colour 2.",
|
|
"defaults": {
|
|
"dark": "#dcdcaa",
|
|
"light": "#7a6e17",
|
|
"highContrast": "#dcdcaa"
|
|
}
|
|
},
|
|
{
|
|
"id": "verticalTabs.project3",
|
|
"description": "Project colour 3.",
|
|
"defaults": {
|
|
"dark": "#9cdcfe",
|
|
"light": "#0b5f92",
|
|
"highContrast": "#9cdcfe"
|
|
}
|
|
},
|
|
{
|
|
"id": "verticalTabs.project4",
|
|
"description": "Project colour 4.",
|
|
"defaults": {
|
|
"dark": "#c586c0",
|
|
"light": "#8b338a",
|
|
"highContrast": "#c586c0"
|
|
}
|
|
},
|
|
{
|
|
"id": "verticalTabs.project5",
|
|
"description": "Project colour 5.",
|
|
"defaults": {
|
|
"dark": "#ce9178",
|
|
"light": "#a3441f",
|
|
"highContrast": "#ce9178"
|
|
}
|
|
},
|
|
{
|
|
"id": "verticalTabs.project6",
|
|
"description": "Project colour 6.",
|
|
"defaults": {
|
|
"dark": "#b5cea8",
|
|
"light": "#3c7a2e",
|
|
"highContrast": "#b5cea8"
|
|
}
|
|
},
|
|
{
|
|
"id": "verticalTabs.project7",
|
|
"description": "Project colour 7.",
|
|
"defaults": {
|
|
"dark": "#569cd6",
|
|
"light": "#1d4f91",
|
|
"highContrast": "#569cd6"
|
|
}
|
|
},
|
|
{
|
|
"id": "verticalTabs.project8",
|
|
"description": "Project colour 8.",
|
|
"defaults": {
|
|
"dark": "#d7ba7d",
|
|
"light": "#8a6512",
|
|
"highContrast": "#d7ba7d"
|
|
}
|
|
},
|
|
{
|
|
"id": "verticalTabs.project9",
|
|
"description": "Project colour 9.",
|
|
"defaults": {
|
|
"dark": "#f28b82",
|
|
"light": "#b3261e",
|
|
"highContrast": "#f28b82"
|
|
}
|
|
},
|
|
{
|
|
"id": "verticalTabs.project10",
|
|
"description": "Project colour 10.",
|
|
"defaults": {
|
|
"dark": "#a5d6a7",
|
|
"light": "#2e7d32",
|
|
"highContrast": "#a5d6a7"
|
|
}
|
|
},
|
|
{
|
|
"id": "verticalTabs.project11",
|
|
"description": "Project colour 11.",
|
|
"defaults": {
|
|
"dark": "#b39ddb",
|
|
"light": "#5e35b1",
|
|
"highContrast": "#b39ddb"
|
|
}
|
|
},
|
|
{
|
|
"id": "verticalTabs.project12",
|
|
"description": "Project colour 12.",
|
|
"defaults": {
|
|
"dark": "#80cbc4",
|
|
"light": "#00695c",
|
|
"highContrast": "#80cbc4"
|
|
}
|
|
},
|
|
{
|
|
"id": "verticalTabs.noProject",
|
|
"description": "Colour for files that belong to no project.",
|
|
"defaults": {
|
|
"dark": "descriptionForeground",
|
|
"light": "descriptionForeground",
|
|
"highContrast": "descriptionForeground"
|
|
}
|
|
}
|
|
]
|
|
},
|
|
"scripts": {
|
|
"vscode:prepublish": "npm run compile",
|
|
"compile": "tsc -p ./",
|
|
"watch": "tsc -watch -p ./",
|
|
"pretest": "npm run compile",
|
|
"test": "node ./out/test/runTest.js"
|
|
},
|
|
"devDependencies": {
|
|
"@types/mocha": "^10.0.6",
|
|
"@types/node": "^20.11.0",
|
|
"@types/vscode": "^1.85.0",
|
|
"@vscode/test-electron": "^2.4.1",
|
|
"mocha": "^10.4.0",
|
|
"typescript": "^5.4.0"
|
|
}
|
|
}
|