A tree view row cannot be styled: no border, no spacing, and a long file name gets middle-ellipsized in a narrow strip — which on a real project left "ClientDogSurger...nionBehaviour.cs" and hid the project text entirely. Drawing the rows means controlling all of it. - A coloured left border per project instead of a tinted icon, so the file icon slot is free and the name gets the width. The border uses var(--vscode-verticalTabs-projectN): VS Code injects every contributed theme colour into a webview, so overrides in colorCustomizations still apply and nothing is hardcoded. - The name is split into stem and extension, and only the stem ellipsizes, so ".cs" survives on a long name in a narrow view. - Configurable row spacing and border width, a rule under the pinned block, a dirty dot that the close button replaces on hover, italics for preview and for tabs that cannot be focused. - Selection, arrow/Home/End/Enter/Delete keys, middle-click to close, and an HTML context menu, since contributes.menus does not reach webview rows. - Clicking a webview row posts nothing rather than asking for an open that would silently do nothing. Actions moved to actions.ts so the wiring, the view and the tests share one implementation; extension.ts is now just registration. The per-row commands are gone — rows act through webview messages — and the palette keeps close / closeOthers / togglePin acting on the active editor. Verified in a browser harness at side-bar width: all twelve project colours resolve, rows stay a consistent 24px, and click, pin, close, middle-click, keyboard and both context-menu variants post the right intents. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
302 lines
7.9 KiB
JSON
302 lines
7.9 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",
|
|
"type": "webview",
|
|
"contextualTitle": "Tabs",
|
|
"visibility": "visible"
|
|
}
|
|
]
|
|
},
|
|
"commands": [
|
|
{
|
|
"command": "verticalTabs.close",
|
|
"title": "Close Active Tab",
|
|
"category": "Tabs"
|
|
},
|
|
{
|
|
"command": "verticalTabs.closeOthers",
|
|
"title": "Close Other Tabs",
|
|
"category": "Tabs"
|
|
},
|
|
{
|
|
"command": "verticalTabs.togglePin",
|
|
"title": "Pin or Unpin Active Tab",
|
|
"category": "Tabs"
|
|
},
|
|
{
|
|
"command": "verticalTabs.setOrderOpen",
|
|
"title": "Sort Tabs by Open Order",
|
|
"category": "Tabs"
|
|
},
|
|
{
|
|
"command": "verticalTabs.setOrderProject",
|
|
"title": "Sort Tabs by Project",
|
|
"category": "Tabs"
|
|
},
|
|
{
|
|
"command": "verticalTabs.setOrderName",
|
|
"title": "Sort Tabs 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"
|
|
}
|
|
]
|
|
},
|
|
"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 row's left border 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."
|
|
},
|
|
"verticalTabs.rowSpacing": {
|
|
"type": "number",
|
|
"default": 2,
|
|
"minimum": 0,
|
|
"maximum": 10,
|
|
"description": "Pixels of vertical space between rows."
|
|
},
|
|
"verticalTabs.borderWidth": {
|
|
"type": "number",
|
|
"default": 3,
|
|
"minimum": 0,
|
|
"maximum": 8,
|
|
"description": "Width in pixels of the project colour border on the left of each row."
|
|
}
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|