Skip to content

Conversation

@sigmaaa
Copy link
Collaborator

@sigmaaa sigmaaa commented Feb 18, 2025

Description

Added a part listener that updates Clang's additional options and restarts the LSP server when files from different projects are opened.

Improved handling of the --compile-commands-dir option. Previously, building the project replaced all additional options with a single --compile-commands-dir entry; now, only this option is updated, preserving any other options.

Fixes # (IEP-1427)

Type of change

Please delete options that are not relevant.

  • New feature (non-breaking change which adds functionality)

How has this been tested?

The good use case is mentioned in this ticket: #1130

Test Configuration:

  • ESP-IDF Version:
  • OS (Windows,Linux and macOS):

Dependent components impacted by this PR:

  • Clang additional options

Checklist

  • PR Self Reviewed
  • Applied Code formatting
  • Added Documentation
  • Added Unit Test
  • Verified on all platforms - Windows,Linux and macOS

Summary by CodeRabbit

  • New Features
    • Enhanced build integration: The system now dynamically updates compile command settings for improved consistency.
    • Automated startup and file monitoring: A new startup mechanism registers file open events, triggering updates to language server configurations when needed.
    • Introduced a listener for file open events to streamline project build directory updates.
    • Added a method to directly update the compile commands directory in Eclipse preferences.

@coderabbitai
Copy link

coderabbitai bot commented Feb 18, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

This pull request updates how the LSP service receives its compile commands configuration. In the core build configuration, the method call is changed to directly use a build command variable, and a corresponding new method is added in the LSP service to handle the update. Additionally, new UI components are introduced: a startup extension is registered in the plugin configuration, and listener classes are implemented to respond to file open events by updating the LSP configuration.

Changes

File(s) Change Summary
bundles/.../IDFBuildConfiguration.java, bundles/.../LspService.java In the core, the runCmakeBuildCommand now calls updateCompileCommandsDir instead of passing a formatted string; a new method in LspService handles updating compile commands via preferences, with added regex and Eclipse preferences imports.
bundles/.../plugin.xml, bundles/.../ListenerStartup.java, bundles/.../handlers/FileOpenListener.java In the UI, a new startup extension is added in the plugin XML; new classes ListenerStartup and FileOpenListener are introduced to register a file open listener at workbench startup and update the LSP service when editors are activated.

Possibly related PRs

Suggested reviewers

  • kolipakakondal
  • AndriiFilippov
  • alirana01

Poem

I'm a little rabbit, hopping through code so free,
Changes bloom like carrots, as fresh as can be.
With new commands and listeners at play,
I hop over bugs in my clever way.
Celebrating these tweaks with a joyful cheer,
🥕 CodeRabbit hops on to a brighter new year!

Tip

CodeRabbit's docstrings feature is now available as part of our Pro Plan! Simply use the command @coderabbitai generate docstrings to have CodeRabbit automatically generate docstrings for your pull request. We would love to hear your feedback on Discord.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 69d04c7 and b7af4b1.

📒 Files selected for processing (5)
  • bundles/com.espressif.idf.core/src/com/espressif/idf/core/build/IDFBuildConfiguration.java (1 hunks)
  • bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/LspService.java (2 hunks)
  • bundles/com.espressif.idf.ui/plugin.xml (1 hunks)
  • bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/ListenerStartup.java (1 hunks)
  • bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/handlers/FileOpenListener.java (1 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (7)
bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/ListenerStartup.java (2)

1-4: Update copyright year.

The copyright year is set to 2025, which is incorrect as it's beyond the current year.

-* Copyright 2025 Espressif Systems (Shanghai) PTE LTD. All rights reserved.
+* Copyright 2024 Espressif Systems (Shanghai) PTE LTD. All rights reserved.

19-37: Consider adding error handling and cleanup.

While the implementation is correct, consider these improvements:

  1. Add error handling for UI operations.
  2. Implement cleanup/disposal of the listener when the plugin is stopped.

Here's a suggested implementation with error handling:

 @Override
 public void earlyStartup()
 {
-		IWorkbench workbench = PlatformUI.getWorkbench();
+		try {
+			IWorkbench workbench = PlatformUI.getWorkbench();
 
-		// Execute on the UI thread
-		workbench.getDisplay().asyncExec(() -> {
-			IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
-			if (window != null)
-			{
-				IWorkbenchPage page = window.getActivePage();
-				if (page != null)
-				{
-					partListener = new FileOpenListener();
-					page.addPartListener(partListener);
-				}
-			}
-		});
+			// Execute on the UI thread
+			workbench.getDisplay().asyncExec(() -> {
+				try {
+					IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
+					if (window != null)
+					{
+						IWorkbenchPage page = window.getActivePage();
+						if (page != null)
+						{
+							partListener = new FileOpenListener();
+							page.addPartListener(partListener);
+						}
+					}
+				} catch (Exception e) {
+					// Log error using Eclipse's logging mechanism
+					StatusManager.getManager().handle(
+						new Status(IStatus.ERROR, "com.espressif.idf.ui", 
+							"Error initializing FileOpenListener", e));
+				}
+			});
+		} catch (Exception e) {
+			// Log error using Eclipse's logging mechanism
+			StatusManager.getManager().handle(
+				new Status(IStatus.ERROR, "com.espressif.idf.ui", 
+					"Error in earlyStartup", e));
+		}
 }

And add a cleanup method:

public void dispose() {
    if (partListener != null) {
        try {
            IWorkbench workbench = PlatformUI.getWorkbench();
            IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
            if (window != null) {
                IWorkbenchPage page = window.getActivePage();
                if (page != null) {
                    page.removePartListener(partListener);
                }
            }
        } catch (Exception e) {
            // Log error using Eclipse's logging mechanism
            StatusManager.getManager().handle(
                new Status(IStatus.ERROR, "com.espressif.idf.ui", 
                    "Error disposing FileOpenListener", e));
        }
        partListener = null;
    }
}
bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/LspService.java (2)

71-88: LGTM! Consider adding null checks.

The method correctly updates the compile commands directory while preserving other additional options. However, consider adding null checks for the preferences.get() call.

Apply this diff to add null checks:

-			String existingOptions = preferences.get(identifier, StringUtil.EMPTY);
+			String existingOptions = preferences.get(identifier, null);
+			if (existingOptions == null) {
+				existingOptions = StringUtil.EMPTY;
+			}

82-85: Use a more precise regex pattern.

The current regex pattern .+ is greedy and might match more than intended. Consider using a non-greedy pattern or a more specific one that stops at the next option.

Apply this diff to use a more precise pattern:

-					? existingOptions.replaceAll(compileCommandsDirString + ".+", //$NON-NLS-1$
+					? existingOptions.replaceAll(compileCommandsDirString + "[^ ]+", //$NON-NLS-1$
bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/handlers/FileOpenListener.java (3)

1-4: Update the copyright year.

The copyright year is set to 2025, but it should reflect when the file was created (likely 2024 or earlier).

-* Copyright 2025 Espressif Systems (Shanghai) PTE LTD. All rights reserved.
+* Copyright 2024 Espressif Systems (Shanghai) PTE LTD. All rights reserved.

24-28: Consider adding documentation for empty methods.

While it's acceptable to have empty implementations for unused interface methods, adding documentation explaining why they're empty would improve maintainability.

Example:

 @Override
 public void partOpened(IWorkbenchPartReference partRef)
 {
+    // Not used: We only need to handle part activation events
 }

Also applies to: 58-87


34-39: Add file type validation.

The method should check if the file is relevant for LSP processing (e.g., C/C++ files) before updating the LSP configuration to avoid unnecessary updates.

 if (part instanceof IEditorPart ieditorpart
         && ieditorpart.getEditorInput() instanceof FileEditorInput fileInput)
 {
     IFile file = fileInput.getFile();
+    String fileExtension = file.getFileExtension();
+    if (fileExtension == null || (!fileExtension.equals("c") && !fileExtension.equals("cpp") && !fileExtension.equals("h") && !fileExtension.equals("hpp"))) {
+        return;
+    }
     IProject project = file.getProject();
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 57a591b and 68e4a30.

📒 Files selected for processing (5)
  • bundles/com.espressif.idf.core/src/com/espressif/idf/core/build/IDFBuildConfiguration.java (1 hunks)
  • bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/LspService.java (2 hunks)
  • bundles/com.espressif.idf.ui/plugin.xml (1 hunks)
  • bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/ListenerStartup.java (1 hunks)
  • bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/handlers/FileOpenListener.java (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build_macos
🔇 Additional comments (3)
bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/ListenerStartup.java (1)

15-18: LGTM! Clean class structure.

The class correctly implements the IStartup interface and maintains a reference to the FileOpenListener.

bundles/com.espressif.idf.ui/plugin.xml (1)

570-572: LGTM! Startup extension is correctly configured.

The startup extension is properly added with the correct class reference.

bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/handlers/FileOpenListener.java (1)

21-22: LGTM!

The class name is descriptive and appropriately implements the IPartListener2 interface for handling Eclipse UI part lifecycle events.

Comment on lines 41 to 45
String buildDir = StringUtil.EMPTY;
try
{
buildDir = IDFUtil.getBuildDir(project);
}
catch (CoreException e)
{
Logger.log(e);
}
LspService lspService = new LspService();
lspService.updateCompileCommandsDir(buildDir);
lspService.restartLspServers();
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve error handling and resource management.

Several improvements can be made to the implementation:

  1. The buildDir variable should be null-checked before use
  2. Consider reusing the LspService instance instead of creating a new one for each activation
  3. Add logging for successful updates and potential LSP server restart failures

Here's the suggested implementation:

-                String buildDir = StringUtil.EMPTY;
+                String buildDir = null;
                 try
                 {
                     buildDir = IDFUtil.getBuildDir(project);
+                    if (buildDir == null || buildDir.isEmpty()) {
+                        Logger.log("Failed to get build directory for project: " + project.getName());
+                        return;
+                    }
+                    
+                    LspService lspService = LspService.getInstance(); // Assuming singleton pattern
+                    lspService.updateCompileCommandsDir(buildDir);
+                    lspService.restartLspServers();
+                    Logger.log("Successfully updated LSP configuration for project: " + project.getName());
                 }
                 catch (CoreException e)
                 {
                     Logger.log(e);
+                } catch (Exception e) {
+                    Logger.log("Failed to restart LSP servers: " + e.getMessage());
                 }
-                LspService lspService = new LspService();
-                lspService.updateCompileCommandsDir(buildDir);
-                lspService.restartLspServers();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
String buildDir = StringUtil.EMPTY;
try
{
buildDir = IDFUtil.getBuildDir(project);
}
catch (CoreException e)
{
Logger.log(e);
}
LspService lspService = new LspService();
lspService.updateCompileCommandsDir(buildDir);
lspService.restartLspServers();
}
String buildDir = null;
try
{
buildDir = IDFUtil.getBuildDir(project);
if (buildDir == null || buildDir.isEmpty()) {
Logger.log("Failed to get build directory for project: " + project.getName());
return;
}
LspService lspService = LspService.getInstance(); // Assuming singleton pattern
lspService.updateCompileCommandsDir(buildDir);
lspService.restartLspServers();
Logger.log("Successfully updated LSP configuration for project: " + project.getName());
}
catch (CoreException e)
{
Logger.log(e);
} catch (Exception e) {
Logger.log("Failed to restart LSP servers: " + e.getMessage());
}

@AndriiFilippov
Copy link
Collaborator

AndriiFilippov commented Feb 19, 2025

@sigmaaa hi !

Tested under:
OS - Mac arm64
ESP-IDF: v5.4

the LSP editor now uses the sdkconfig.h file of particular project not from the last built project for all projects as it was before ✅
Clangd gets the correct --compile-commands-dir when switching projects: ✅
--compile-commands-dir=/Users/andriifilippov/workspaceunuju999/hello_world/build

But the same path is empty under "Preferences - clangd" :
image

@AndriiFilippov
Copy link
Collaborator

AndriiFilippov commented Feb 20, 2025

@sigmaaa hi !

Tested under:
OS - Windows 11 / Mac arm64

Mac OS ✅
Windows 11 ✅

Copy link
Collaborator

@kolipakakondal kolipakakondal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@kolipakakondal
Copy link
Collaborator

Hi @sigmaaa Can you resolve conflicts and merge this PR?

@sigmaaa sigmaaa merged commit cd85f2d into master Feb 26, 2025
2 of 4 checks passed
@kolipakakondal kolipakakondal deleted the IEP-1427 branch May 7, 2025 14:57
@coderabbitai coderabbitai bot mentioned this pull request Jan 13, 2026
5 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Espressif-IDE LSP Editor is using sdkconfig.h from the last built project for ALL other projects (IEP-1427)

4 participants