Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to add new Feature to clangd by other extension #668

Open
wss29 opened this issue Aug 6, 2024 · 10 comments
Open

How to add new Feature to clangd by other extension #668

wss29 opened this issue Aug 6, 2024 · 10 comments
Labels
enhancement New feature or request

Comments

@wss29
Copy link

wss29 commented Aug 6, 2024

Note: we mostly implement features in the clangd language server, and rely on Microsoft's LSP client framework to expose these in VSCode. Features requiring a lot of VSCode-specific work are unlikely to be implemented.
Hi,

  1. As we know there is some feature added inside clangd
    image
  2. How could I do if I want to add my custom feature to reuse clangd in my extension?
  3. I try to create my clanged context like clangd, but when I install my extension and vscode-clangd I will get Error: command 'clangd.applyFix' already exists. is it possible to install these two extension meanwhile?
export class MyClangdContext implements vscode.Disposable {
  subscriptions: vscode.Disposable[] = [];
  client!: MyClangdLanguageClient;

  async activate(globalStoragePath: string, outputChannel: vscode.OutputChannel) {
      const clangdPath = vscode.workspace.getConfiguration('clangd').get<string>('path');
      if (!clangdPath) {
          return;
      }

      const clangd: vscodelc.Executable = {
          command: clangdPath,
          args: await config.get<string[]>('arguments'),
          options: { cwd: vscode.workspace.rootPath || process.cwd() },
      };
      const traceFile = config.get<string>('trace');
      if (!!traceFile) {
          const trace = { CLANGD_TRACE: traceFile };
          clangd.options = { env: { ...process.env, ...trace } };
      }
      const serverOptions: vscodelc.ServerOptions = clangd;

      const clientOptions: vscodelc.LanguageClientOptions = {
          // Register the server for c-family and cuda files.
          documentSelector: clangdDocumentSelector,
          initializationOptions: {
              clangdFileStatus: true,
              fallbackFlags: config.get<string[]>('fallbackFlags'),
          },
          outputChannel: outputChannel,
          // Do not switch to output window when clangd returns output.
          revealOutputChannelOn: vscodelc.RevealOutputChannelOn.Never,
      };

      this.client = new MyClangdLanguageClient('my Clang Language Server', serverOptions, clientOptions);
      this.client.clientOptions.errorHandler = this.client.createDefaultErrorHandler(
          // max restart count
          config.get<boolean>('restartAfterCrash') ? /*default*/ 4 : 0
      );
      myfeature.activate(this);
      this.client.start();
      console.log('my Clang Language Server is now active!');
  }

image

@wss29 wss29 added the enhancement New feature or request label Aug 6, 2024
@HighCommander4
Copy link
Contributor

Can you give an example of a feature you have in mind?

Is your feature's implementation going to be talking to the clangd server? If so, are you using a forked/modified clangd server that e.g. supports a new kind of LSP request?

@wss29
Copy link
Author

wss29 commented Aug 7, 2024

Hi @HighCommander4
my feature needs to extract functions in the c/c++ file, so I need to talk to the clangd server, just like the internal ast feature but need some custom operation after getting ast node. currently, I just use the original clangd server, do not have new LSP request. maybe in the future, I need new LSP request

@HighCommander4
Copy link
Contributor

HighCommander4 commented Aug 7, 2024

Can you use the extension API shown here (see also this file) to ask clangd for an AST and then do your processing on it and provide the user feature you're looking for?

@wss29
Copy link
Author

wss29 commented Aug 7, 2024

hi @HighCommander4
thanks for your replay. It seems that should work, but how could I use that API, I do not find a package of @clangd/vscode-clangd in npm. Should I wrap the files in the API folder into a module myself?

@HighCommander4
Copy link
Contributor

I do not find a package of @clangd/vscode-clangd in npm

Could you file an issue about publishing that package please?

In the meantime, you'll need to check out the vscode-clangd repo and refer to the package using a local path the way I do in this example repo.

@wss29
Copy link
Author

wss29 commented Aug 8, 2024

Hi @HighCommander4
I have published an issue on 670, I have used your API it is ok except for a little problem with ast node.
I use following code to get ast of a c file,

  const ast: ASTNode | undefined = await api.languageClient.sendRequest(ASTType, { textDocument: { uri: args } });

the problem is that the above code only works when the file has opened in vscode, if I directly call and do not open the text document in vscode, I will get 'ResponseError: trying to get AST for non-added document '
is it possible not open file and get ast node of a c file just by pass uri directly?

@HighCommander4
Copy link
Contributor

HighCommander4 commented Aug 8, 2024

is it possible not open file and get ast node of a c file just by pass uri directly?

Clangd does require that the file be opened on the server with textDocument/didOpen before any operations (such as requesting an AST) are performed on it.

However, opening the file on the server doesn't necessarily require opening it in the editor; I think you could use the client object exposed in the extension API to send the didOpen notification from your extension's code.

@wss29
Copy link
Author

wss29 commented Aug 8, 2024

hi @HighCommander4
I indeed try 'textDocument/didOpen', but when I send a request of 'textDocument/didOpen', I get error 'method not found'
image
does that mean @clangd/vscode-clangd not support 'textDocument/didOpen'? and what is the value of the version should I set in TextDocumentItem

@wss29
Copy link
Author

wss29 commented Aug 9, 2024

HI @HighCommander4
After fixing two problems. it can open file and get ast node of a c file just by pass uri directly

  1. invoking 'textDocument/didOpen' should use sendNotification not sendRequest
  2. the version field is a type of number, give a string value '1' not work correct, should give the number 1,
    thanks very much for your replay
  const clangdExtension = vscode.extensions.getExtension<ClangdExtension>(CLANGD_EXTENSION);
            if (!clangdExtension) {
                return undefined;
            }
            if (!clangdExtension.isActive) {
                await clangdExtension.activate();
            }
            try {
                const api = clangdExtension.exports.getApi(CLANGD_API_VERSION);
                const file = vscode.Uri.parse(args).fsPath;
                await fs.promises.access(file, fs.constants.F_OK);
                const textContent = await fs.promises.readFile(file, 'utf8');
                await api.languageClient.sendNotification('textDocument/didOpen', {
                    textDocument: { uri: args, languageId: 'c', version: 1, text: textContent },
                });
                const ast: ASTNode | undefined = await api.languageClient.sendRequest(ASTType, { textDocument: { uri: args } });
                if (!ast || !ast.children) {
                    return [];
                }
                const ret = ast.children
                    .filter(o => o.kind === 'Function' || o.kind === 'Method')
                    .map(o =>
                        JSON.stringify({
                            role: o.role,
                            kind: o.kind,
                            detail: o.detail,
                            range: o.range,
                        })
                    );
                return ret;
            } catch (error) {
                console.log(error);
            }

@HighCommander4
Copy link
Contributor

Glad you figured it out. For reference, the standard Language Server Protocol messages and notifications (such as didOpen) are documented at https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants