nridge created this revision.
Herald added subscribers: cfe-commits, kadircet, arphaman, jkorous, MaskRay, 
ilya-biryukov.
Herald added a project: clang.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D67537

Files:
  clang-tools-extra/clangd/clients/clangd-vscode/src/extension.ts
  clang-tools-extra/clangd/clients/clangd-vscode/src/inactive-regions.ts

Index: clang-tools-extra/clangd/clients/clangd-vscode/src/inactive-regions.ts
===================================================================
--- /dev/null
+++ clang-tools-extra/clangd/clients/clangd-vscode/src/inactive-regions.ts
@@ -0,0 +1,83 @@
+import * as vscode from 'vscode';
+import * as vscodelc from 'vscode-languageclient';
+import * as vscodelct from 'vscode-languageserver-types';
+
+// Parameters for the inactive regions (server-side) push notification.
+// Mirrors the structure in the inactive regions proposal for LSP.
+interface InactiveRegionsParams {
+  // The text document that has to be decorated with the inactive regions
+  // information.
+  textDocument: vscodelct.VersionedTextDocumentIdentifier;
+  // An array of inactive regions.
+  regions: vscodelc.Range[];
+}
+
+// Language server push notification providing the inactive regions
+// information for a text document.
+export const NotificationType =
+  new vscodelc.NotificationType<InactiveRegionsParams, void>(
+    'textDocument/inactiveRegions');
+
+export class InactiveRegionsFeature implements vscodelc.StaticFeature {
+  private decorationType: vscode.TextEditorDecorationType;
+  private p2c: vscodelc.Protocol2CodeConverter;
+  private files: Map<string, vscode.Range[]> = new Map();
+  private subscriptions: vscode.Disposable[] = [];
+
+  constructor(client: vscodelc.LanguageClient) {
+    this.p2c = client.protocol2CodeConverter;
+  }
+
+  fillClientCapabilities(capabilities: vscodelc.ClientCapabilities) {
+    // Extend the ClientCapabilities type and add inactive regions
+    // capability to the object.
+    const textDocumentCapabilities: vscodelc.TextDocumentClientCapabilities &
+    { inactiveRegionsCapabilities?: { inactiveRegions: boolean } } =
+      capabilities.textDocument;
+    textDocumentCapabilities.inactiveRegionsCapabilities = {
+      inactiveRegions: true,
+    };
+  }
+  initialize(capabilities: vscodelc.ServerCapabilities,
+    documentSelector: vscodelc.DocumentSelector | undefined) {
+      this.decorationType = vscode.window.createTextEditorDecorationType({
+        isWholeLine: true,
+        light: {
+          color: "rgb(100, 100, 100)",
+          backgroundColor: "rgba(220, 220, 220, 0.3)",
+        },
+        dark: {
+          color: "rgb(100, 100, 100)",
+          backgroundColor: "rgba(18, 18, 18, 0.3)",
+        }
+      });
+      this.subscriptions.push(vscode.window.onDidChangeVisibleTextEditors(
+          (editors) => editors.forEach(
+              (e) => this.applyHighlights(e.document.uri.toString()))));
+  }
+
+  handleNotification(params: InactiveRegionsParams) {
+    const fileUri = params.textDocument.uri;
+    const ranges = params.regions.map(this.p2c.asRange);
+    this.files.set(fileUri, ranges);
+    this.applyHighlights(fileUri);
+  }
+
+  applyHighlights(fileUri: string) {
+    if (!this.files.has(fileUri)) {
+      return;
+    }
+    const ranges = this.files.get(fileUri);
+    vscode.window.visibleTextEditors.forEach((e) => {
+      if (e.document.uri.toString() !== fileUri)
+        return;
+      e.setDecorations(this.decorationType, ranges);
+    });
+  }
+
+  // Disposes of all disposable resources used by this object.
+  public dispose() {
+    this.subscriptions.forEach((d) => d.dispose());
+    this.subscriptions = [];
+  }
+}
\ No newline at end of file
Index: clang-tools-extra/clangd/clients/clangd-vscode/src/extension.ts
===================================================================
--- clang-tools-extra/clangd/clients/clangd-vscode/src/extension.ts
+++ clang-tools-extra/clangd/clients/clangd-vscode/src/extension.ts
@@ -1,6 +1,7 @@
 import * as vscode from 'vscode';
 import * as vscodelc from 'vscode-languageclient';
 import * as semanticHighlighting from './semantic-highlighting';
+import * as inactiveRegions from './inactive-regions';
 
 /**
  * Method to get workspace configuration option
@@ -13,15 +14,15 @@
 }
 
 namespace SwitchSourceHeaderRequest {
-export const type =
-    new vscodelc.RequestType<vscodelc.TextDocumentIdentifier, string|undefined,
-                             void, void>('textDocument/switchSourceHeader');
+  export const type =
+    new vscodelc.RequestType<vscodelc.TextDocumentIdentifier, string | undefined,
+      void, void>('textDocument/switchSourceHeader');
 }
 
 class FileStatus {
   private statuses = new Map<string, any>();
   private readonly statusBarItem =
-      vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 10);
+    vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 10);
 
   onFileUpdated(fileStatus: any) {
     const filePath = vscode.Uri.parse(fileStatus.uri);
@@ -58,7 +59,7 @@
   // prompt up the failure to users.
   logFailedRequest(rpcReply: vscodelc.RPCMessageType, error: any) {
     if (error instanceof vscodelc.ResponseError &&
-        rpcReply.method === "workspace/executeCommand")
+      rpcReply.method === "workspace/executeCommand")
       vscode.window.showErrorMessage(error.message);
     // Call default implementation.
     super.logFailedRequest(rpcReply, error);
@@ -73,13 +74,13 @@
   const syncFileEvents = getConfig<boolean>('syncFileEvents', true);
 
   const clangd: vscodelc.Executable = {
-    command : getConfig<string>('path'),
-    args : getConfig<string[]>('arguments')
+    command: getConfig<string>('path'),
+    args: getConfig<string[]>('arguments')
   };
   const traceFile = getConfig<string>('trace');
   if (!!traceFile) {
-    const trace = {CLANGD_TRACE : traceFile};
-    clangd.options = {env : {...process.env, ...trace}};
+    const trace = { CLANGD_TRACE: traceFile };
+    clangd.options = { env: { ...process.env, ...trace } };
   }
   const serverOptions: vscodelc.ServerOptions = clangd;
 
@@ -89,73 +90,80 @@
   // However, VSCode does not have CUDA as a supported language yet, so we
   // cannot add a corresponding activationEvent for CUDA files and clangd will
   // *not* load itself automatically on '.cu' files.
-  const cudaFilePattern: string = '**/*.{' + [ 'cu' ].join() + '}';
+  const cudaFilePattern: string = '**/*.{' + ['cu'].join() + '}';
   const clientOptions: vscodelc.LanguageClientOptions = {
-        // Register the server for c-family and cuda files.
-        documentSelector: [
-            { scheme: 'file', language: 'c' },
-            { scheme: 'file', language: 'cpp' },
-            { scheme: 'file', language: 'objective-c'},
-            { scheme: 'file', language: 'objective-cpp'},
-            { scheme: 'file', pattern: cudaFilePattern },
-        ],
-        synchronize: !syncFileEvents ? undefined : {
-        // FIXME: send sync file events when clangd provides implemenatations.
-        },
-        initializationOptions: { clangdFileStatus: true },
-        // Do not switch to output window when clangd returns output
-        revealOutputChannelOn: vscodelc.RevealOutputChannelOn.Never
-    };
+    // Register the server for c-family and cuda files.
+    documentSelector: [
+      { scheme: 'file', language: 'c' },
+      { scheme: 'file', language: 'cpp' },
+      { scheme: 'file', language: 'objective-c' },
+      { scheme: 'file', language: 'objective-cpp' },
+      { scheme: 'file', pattern: cudaFilePattern },
+    ],
+    synchronize: !syncFileEvents ? undefined : {
+      // FIXME: send sync file events when clangd provides implemenatations.
+    },
+    initializationOptions: { clangdFileStatus: true },
+    // Do not switch to output window when clangd returns output
+    revealOutputChannelOn: vscodelc.RevealOutputChannelOn.Never
+  };
 
   const clangdClient = new ClangdLanguageClient('Clang Language Server',
-                                                serverOptions, clientOptions);
+    serverOptions, clientOptions);
   const semanticHighlightingFeature =
-      new semanticHighlighting.SemanticHighlightingFeature();
+    new semanticHighlighting.SemanticHighlightingFeature();
+  const inactiveRegionsFeature = new inactiveRegions.InactiveRegionsFeature(clangdClient);
+  context.subscriptions.push(
+    vscode.Disposable.from(semanticHighlightingFeature));
   context.subscriptions.push(
-      vscode.Disposable.from(semanticHighlightingFeature));
+    vscode.Disposable.from(inactiveRegionsFeature));
   clangdClient.registerFeature(semanticHighlightingFeature);
+  clangdClient.registerFeature(inactiveRegionsFeature);
   console.log('Clang Language Server is now active!');
   context.subscriptions.push(clangdClient.start());
   context.subscriptions.push(vscode.commands.registerCommand(
-      'clangd-vscode.switchheadersource', async () => {
-        const uri =
-            vscode.Uri.file(vscode.window.activeTextEditor.document.fileName);
-        if (!uri) {
-          return;
-        }
-        const docIdentifier =
-            vscodelc.TextDocumentIdentifier.create(uri.toString());
-        const sourceUri = await clangdClient.sendRequest(
-            SwitchSourceHeaderRequest.type, docIdentifier);
-        if (!sourceUri) {
-          return;
-        }
-        const doc = await vscode.workspace.openTextDocument(
-            vscode.Uri.parse(sourceUri));
-        vscode.window.showTextDocument(doc);
-      }));
+    'clangd-vscode.switchheadersource', async () => {
+      const uri =
+        vscode.Uri.file(vscode.window.activeTextEditor.document.fileName);
+      if (!uri) {
+        return;
+      }
+      const docIdentifier =
+        vscodelc.TextDocumentIdentifier.create(uri.toString());
+      const sourceUri = await clangdClient.sendRequest(
+        SwitchSourceHeaderRequest.type, docIdentifier);
+      if (!sourceUri) {
+        return;
+      }
+      const doc = await vscode.workspace.openTextDocument(
+        vscode.Uri.parse(sourceUri));
+      vscode.window.showTextDocument(doc);
+    }));
   const status = new FileStatus();
   context.subscriptions.push(vscode.Disposable.from(status));
   context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor(
-      () => { status.updateStatus(); }));
-  context.subscriptions.push(clangdClient.onDidChangeState(({newState}) => {
+    () => { status.updateStatus(); }));
+  context.subscriptions.push(clangdClient.onDidChangeState(({ newState }) => {
     if (newState == vscodelc.State.Running) {
       // clangd starts or restarts after crash.
       clangdClient.onNotification(
-          'textDocument/clangd.fileStatus',
-          (fileStatus) => { status.onFileUpdated(fileStatus); });
+        'textDocument/clangd.fileStatus',
+        (fileStatus) => { status.onFileUpdated(fileStatus); });
       clangdClient.onNotification(
-          semanticHighlighting.NotificationType,
-          semanticHighlightingFeature.handleNotification.bind(
-              semanticHighlightingFeature));
+        semanticHighlighting.NotificationType,
+        semanticHighlightingFeature.handleNotification.bind(
+          semanticHighlightingFeature));
+      clangdClient.onNotification(inactiveRegions.NotificationType,
+        inactiveRegionsFeature.handleNotification.bind(inactiveRegionsFeature));
     } else if (newState == vscodelc.State.Stopped) {
       // Clear all cached statuses when clangd crashes.
       status.clear();
       semanticHighlightingFeature.dispose();
+      inactiveRegionsFeature.dispose();
     }
   }));
   // An empty place holder for the activate command, otherwise we'll get an
   // "command is not registered" error.
   context.subscriptions.push(vscode.commands.registerCommand(
-      'clangd-vscode.activate', async () => {}));
+    'clangd-vscode.activate', async () => { }));
 }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to