CodebaseTree

tcmts.vscode.extension.CodebaseTree · #hpvu7ziv · class

Sidebar items: namespaces, then the definitions directly in each (grouped by role in big namespaces).

import { GROUP_OVER, ROLES } from "#codebase/tcmts/cli/pages";
import { definitionItem, ROLE_ICONS, running as running_1, session } from "#codebase/tcmts/vscode/extension";
import type { CodebaseNode, DefinitionEntry, RunningApp } from "#codebase/tcmts/vscode/extension";
import * as vscode from "vscode";

export class CodebaseTree implements vscode.TreeDataProvider<CodebaseNode> {
  running: Map<string, RunningApp>;
  changed = new vscode.EventEmitter<CodebaseNode | undefined | void>();
  onDidChangeTreeData = this.changed.event;

  constructor(running: Map<string, RunningApp>) {
    this.running = running;
  }
  refresh() {
    this.changed.fire();
  }
  async getChildren(element?: CodebaseNode): Promise<CodebaseNode[]> {
    if (element?.kind === "group") return element.definitions;
    if (element && element.kind !== "namespace") return [];
    if (!running_1()) return [];
    const t = (await session.client!.sendRequest("tcm/tree", {
      namespace: element?.path ?? "",
    })) as {
      namespaces: { name: string; path: string; count: number }[];
      definitions: DefinitionEntry[];
    };
    const namespaces = t.namespaces.map((n) => ({ ...n, kind: "namespace" as const }));
    if (t.definitions.length <= GROUP_OVER) return [...namespaces, ...t.definitions];
    const groups = ROLES.map(([role, label]) => ({
      kind: "group" as const,
      role,
      label,
      icon: ROLE_ICONS[role],
      definitions: t.definitions.filter((d) => d.role === role),
    }));
    return [...namespaces, ...groups.filter((g) => g.definitions.length)];
  }
  getTreeItem(e: CodebaseNode): vscode.TreeItem {
    if (e.kind === "group") {
      const item = new vscode.TreeItem(
        e.label,
        e.role === "test"
          ? vscode.TreeItemCollapsibleState.Collapsed
          : vscode.TreeItemCollapsibleState.Expanded,
      );
      item.id = `group:${e.definitions[0]!.path}:${e.role}`;
      item.description = String(e.definitions.length);
      item.iconPath = new vscode.ThemeIcon(e.icon);
      return item;
    }
    if (e.kind === "namespace") {
      const item = new vscode.TreeItem(e.name, vscode.TreeItemCollapsibleState.Collapsed);
      item.description = String(e.count);
      item.iconPath = new vscode.ThemeIcon("symbol-namespace");
      item.contextValue = "namespace";
      item.tooltip = e.path;
      return item;
    }
    const item = definitionItem(e);
    if (e.role === "app") {
      const run = this.running.get(e.path);
      if (run) item.description = run.url ? `running · ${run.url}` : "starting…";
      item.contextValue = run ? "definition.app.running" : "definition.app";
    }
    return item;
  }
}

uses

used by