aboutsummaryrefslogtreecommitdiffstats
path: root/qt-cpp/src/project.ts
blob: 23d45fc9b3cec6eaec3dce04f74f786c27f863c6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only

import * as vscode from 'vscode';
import * as cmakeApi from 'vscode-cmake-tools';

import { WorkspaceStateManager } from '@/state';
import { coreAPI, kitManager } from '@/extension';
import { createLogger, QtWorkspaceConfigMessage } from 'qt-lib';
import { Project, ProjectManager } from 'qt-lib';
import {
  getQtInsRoot,
  getQtPathsExe,
  getSelectedKit
} from '@cmd/register-qt-path';
import { analyzeKit } from '@/kit-manager';

const logger = createLogger('project');

export async function createCppProject(
  folder: vscode.WorkspaceFolder,
  context: vscode.ExtensionContext
) {
  logger.info('Creating project:"' + folder.uri.fsPath + '"');
  const api = await cmakeApi.getCMakeToolsApi(cmakeApi.Version.latest);
  let cmakeProject: cmakeApi.Project | undefined;
  if (api) {
    cmakeProject = await api.getProject(folder.uri);
  }
  const buildDir = await cmakeProject?.getBuildDirectory();
  return Promise.resolve(
    new CppProject(folder, context, cmakeProject, buildDir)
  );
}

// Project class represents a workspace folder in the extension.
export class CppProject implements Project {
  private readonly _disposables: vscode.Disposable[] = [];
  private readonly _stateManager: WorkspaceStateManager;
  private readonly _cmakeProject: cmakeApi.Project | undefined;
  private _buildDir: string | undefined;
  constructor(
    private readonly _folder: vscode.WorkspaceFolder,
    readonly _context: vscode.ExtensionContext,
    cmakeProject: cmakeApi.Project | undefined,
    buildDir: string | undefined
  ) {
    this._cmakeProject = cmakeProject;
    this._stateManager = new WorkspaceStateManager(_context, _folder);
    this._buildDir = buildDir;

    if (this._cmakeProject) {
      const onSelectedConfigurationChangedHandler =
        this._cmakeProject.onSelectedConfigurationChanged(
          async (configurationType: cmakeApi.ConfigurationType) => {
            if (configurationType === cmakeApi.ConfigurationType.Kit) {
              const kit = await getSelectedKit(this.folder);
              if (kit) {
                analyzeKit(kit);
              }
              const selectedKitPath = kit ? getQtInsRoot(kit) : undefined;
              const message = new QtWorkspaceConfigMessage(this.folder);
              message.config.set('selectedKitPath', selectedKitPath);

              const selectedQtPaths = kit ? getQtPathsExe(kit) : undefined;
              message.config.set('selectedQtPaths', selectedQtPaths);
              coreAPI?.update(message);
            }
          }
        );
      const onCodeModelChangedHandler = this._cmakeProject.onCodeModelChanged(
        async () => {
          const prevbuildDir = this._buildDir;
          const currentBuildDir = await this._cmakeProject?.getBuildDirectory();
          if (prevbuildDir !== currentBuildDir) {
            logger.info(
              'Build directory changed:',
              currentBuildDir ?? 'undefined'
            );
            this._buildDir = currentBuildDir;
            const message = new QtWorkspaceConfigMessage(this.folder);
            message.config.set('buildDir', currentBuildDir);
            coreAPI?.update(message);
          }
        }
      );
      this._disposables.push(onCodeModelChangedHandler);
      this._disposables.push(onSelectedConfigurationChangedHandler);
    }
  }

  public getStateManager() {
    return this._stateManager;
  }
  get folder() {
    return this._folder;
  }
  get buildDir() {
    return this._buildDir;
  }

  dispose() {
    logger.info('Disposing project:', this._folder.uri.fsPath);
    for (const d of this._disposables) {
      d.dispose();
    }
  }
}

export class CppProjectManager extends ProjectManager<CppProject> {
  constructor(override readonly context: vscode.ExtensionContext) {
    super(context, createCppProject);

    this._disposables.push(
      this.onProjectAdded((project: CppProject) => {
        logger.info('Adding project:', project.folder.uri.fsPath);
        kitManager.addProject(project);
      })
    );

    this._disposables.push(
      this.onProjectRemoved((project: CppProject) => {
        kitManager.removeProject(project);
      })
    );
  }
}