Skip to content

Commit

Permalink
Implement "Try new editing experience" to promote CDT LSP (#421)
Browse files Browse the repository at this point in the history
Contribute a banner to the CEditor and CLspEditor to promote
the new C/C++ editing experience based on LSP. The banner in
CEditor enables a quick switch to the LSP editor:

![image](https://github.com/user-attachments/assets/67a3c8d7-7ea5-4fa4-8384-debebc893233)

And in the CLspEditor it enables a quick switch back to the
traditional CEditor.

![image](https://github.com/user-attachments/assets/e508a726-f892-47da-92bd-a195bedc0dda)

If there is no project specific setting for `prefer_lsp` a
quick confirmation dialog is displayed with options for help
and feedback:

![image](https://github.com/user-attachments/assets/7c33d4fe-69a8-4cf8-b1fb-7ca80e07020c)

and the other way:

![image](https://github.com/user-attachments/assets/a69a87d8-4f32-4e58-a651-2583db50183e)

If the editor is open on a specific project and that project
has project specific preferences for `prefer_lsp`, instead of
automatically changing the setting, the property page is opened:

![image](https://github.com/user-attachments/assets/16c2ce3b-5b62-4199-8392-5d6800f621c7)

A notification is also displayed to the user for a short while after the editors are
re-opening offering more information and access to the preferences.

![image](https://github.com/user-attachments/assets/e8d069de-0939-4503-8755-a130595570d0)

A notification is also displayed when closing the banner allowing
the user easy access to disable opening the banner on new editors

![image](https://github.com/user-attachments/assets/9f9a00ef-8957-4a8a-8a3d-9c804eee5b5e)

Finally a new preference is available:

![image](https://github.com/user-attachments/assets/74d2d461-d219-465b-9276-e93f6720a9ed)

Fixes eclipse-cdt/cdt#968
  • Loading branch information
jonahgraham authored Feb 19, 2025
1 parent 6c0dfad commit dfe1635
Show file tree
Hide file tree
Showing 30 changed files with 1,082 additions and 11 deletions.
2 changes: 1 addition & 1 deletion bundles/org.eclipse.cdt.lsp/.classpath
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-21"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="output" path="bin"/>
Expand Down
15 changes: 12 additions & 3 deletions bundles/org.eclipse.cdt.lsp/.settings/org.eclipse.jdt.core.prefs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.builder.annotationPath.allLocations=disabled
org.eclipse.jdt.core.builder.cleanOutputFolder=clean
org.eclipse.jdt.core.builder.duplicateResourceTask=warning
org.eclipse.jdt.core.builder.invalidClasspath=abort
Expand All @@ -25,20 +26,24 @@ org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonN
org.eclipse.jdt.core.compiler.annotation.nonnull.secondary=
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary=
org.eclipse.jdt.core.compiler.annotation.notowning=org.eclipse.jdt.annotation.NotOwning
org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
org.eclipse.jdt.core.compiler.annotation.nullable.secondary=
org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
org.eclipse.jdt.core.compiler.annotation.owning=org.eclipse.jdt.annotation.Owning
org.eclipse.jdt.core.compiler.annotation.resourceanalysis=disabled
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=17
org.eclipse.jdt.core.compiler.codegen.targetPlatform=21
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=17
org.eclipse.jdt.core.compiler.compliance=21
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.doc.comment.support=enabled
org.eclipse.jdt.core.compiler.maxProblemPerUnit=100
org.eclipse.jdt.core.compiler.problem.APILeak=warning
org.eclipse.jdt.core.compiler.problem.annotatedTypeArgumentToUnannotated=info
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
Expand All @@ -61,8 +66,10 @@ org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
org.eclipse.jdt.core.compiler.problem.incompatibleOwningContract=warning
org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
org.eclipse.jdt.core.compiler.problem.insufficientResourceAnalysis=warning
org.eclipse.jdt.core.compiler.problem.invalidJavadoc=ignore
org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled
org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=disabled
Expand Down Expand Up @@ -113,6 +120,7 @@ org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
org.eclipse.jdt.core.compiler.problem.suppressWarningsNotFullyAnalysed=info
org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled
org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
org.eclipse.jdt.core.compiler.problem.terminalDeprecation=warning
Expand All @@ -136,6 +144,7 @@ org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverridin
org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedImport=warning
org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
org.eclipse.jdt.core.compiler.problem.unusedLambdaParameter=warning
org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
Expand All @@ -147,7 +156,7 @@ org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
org.eclipse.jdt.core.compiler.release=enabled
org.eclipse.jdt.core.compiler.source=17
org.eclipse.jdt.core.compiler.source=21
org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false
org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
Expand Down
8 changes: 6 additions & 2 deletions bundles/org.eclipse.cdt.lsp/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Bundle-Version: 3.0.0.qualifier
Export-Package: org.eclipse.cdt.lsp,
org.eclipse.cdt.lsp.config,
org.eclipse.cdt.lsp.editor,
org.eclipse.cdt.lsp.internal.switchtolsp;x-internal:=true,
org.eclipse.cdt.lsp.plugin;x-friends:="org.eclipse.cdt.lsp.clangd",
org.eclipse.cdt.lsp.server,
org.eclipse.cdt.lsp.services,
Expand Down Expand Up @@ -36,12 +37,15 @@ Require-Bundle: org.eclipse.ui,
org.eclipse.cdt.codan.core,
org.eclipse.cdt.debug.ui,
org.eclipse.ui.workbench.texteditor,
org.eclipse.tm4e.language_pack
Bundle-RequiredExecutionEnvironment: JavaSE-17
org.eclipse.tm4e.language_pack,
org.eclipse.jface.notifications
Bundle-RequiredExecutionEnvironment: JavaSE-21
Automatic-Module-Name: org.eclipse.cdt.lsp
Bundle-ActivationPolicy: lazy
Service-Component: OSGI-INF/org.eclipse.cdt.lsp.internal.editor.EditorMetadataDefaults.xml,
OSGI-INF/org.eclipse.cdt.lsp.internal.editor.FormatOnSave.xml,
OSGI-INF/org.eclipse.cdt.lsp.internal.editor.InitialFileManager.xml,
OSGI-INF/org.eclipse.cdt.lsp.internal.switchtolsp.SwitchBack.xml,
OSGI-INF/org.eclipse.cdt.lsp.internal.switchtolsp.SwitchToLsp.xml,
OSGI-INF/org.eclipse.cdt.lsp.internal.ui.DefaultConfigurationVisibility.xml,
OSGI-INF/org.eclipse.cdt.lsp.internal.ui.EditorConfigurationAccess.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.eclipse.cdt.lsp.internal.switchtolsp.SwitchBack">
<property name="service.ranking" type="Integer" value="0"/>
<service>
<provide interface="org.eclipse.cdt.lsp.internal.switchtolsp.ISwitchBackToTraditional"/>
</service>
<implementation class="org.eclipse.cdt.lsp.internal.switchtolsp.SwitchBack"/>
</scr:component>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.eclipse.cdt.lsp.internal.switchtolsp.SwitchToLsp">
<property name="service.ranking" type="Integer" value="0"/>
<service>
<provide interface="org.eclipse.cdt.internal.ui.switchtolsp.ISwitchToLsp"/>
</service>
<implementation class="org.eclipse.cdt.lsp.internal.switchtolsp.SwitchToLsp"/>
</scr:component>
2 changes: 1 addition & 1 deletion bundles/org.eclipse.cdt.lsp/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<extension
point="org.eclipse.ui.editors">
<editor
class="org.eclipse.ui.internal.genericeditor.ExtensionBasedTextEditor"
class="org.eclipse.cdt.lsp.internal.editor.CLspEditor"
contributorClass="org.eclipse.ui.editors.text.TextEditorActionContributor"
default="false"
icon="icons/c.png"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,20 @@ interface Predefined {
false, //
LspUiMessages.LspEditorConfigurationPage_preferLspEditor,
LspUiMessages.LspEditorConfigurationPage_preferLspEditor_description);

/**
* The predefined metadata for the "Show Try LSP Banner" option
*
* @see EditorOptions#showTryLspBanner()
*
* @since 3.0
*/
PreferenceMetadata<Boolean> showTryLspBanner = new PreferenceMetadata<>(Boolean.class, //
"show_try_lsp_banner", //$NON-NLS-1$
true, //
LspUiMessages.LspEditorConfigurationPage_showTryLspBanner,
LspUiMessages.LspEditorConfigurationPage_showTryLspBanner_description);

/**
* The predefined metadata for the "Format source code" option
*
Expand All @@ -50,6 +64,7 @@ interface Predefined {
false, //
LspUiMessages.SaveActionsConfigurationPage_FormatSourceCode,
LspUiMessages.SaveActionsConfigurationPage_FormatSourceCode_description);

/**
* The predefined metadata for the "Format all lines" option.
*
Expand All @@ -60,6 +75,7 @@ interface Predefined {
true, //
LspUiMessages.SaveActionsConfigurationPage_FormatAllLines,
LspUiMessages.SaveActionsConfigurationPage_FormatAllLines_description);

/**
* Returns the metadata for the "Format edited lines" option.
*
Expand All @@ -76,6 +92,7 @@ interface Predefined {
*/
List<PreferenceMetadata<?>> defaults = List.of(//
preferLspEditor, //
showTryLspBanner, //
formatOnSave, //
formatAllLines, //
formatEditedLines//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ public interface EditorOptions {
*/
boolean preferLspEditor();

/**
* Show the try new experience banner in the editor
*
* @return if banner should be displayed
* @since 3.0
*/
boolean showTryLspBanner();

/**
* Format source code on file save action
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*******************************************************************************
* Copyright (c) 2025 Kichwa Coders Canada Inc. and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/

package org.eclipse.cdt.lsp.internal.editor;

import org.eclipse.cdt.lsp.internal.switchtolsp.ISwitchBackToTraditional;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.IVerticalRuler;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.genericeditor.ExtensionBasedTextEditor;

@SuppressWarnings("restriction")
public class CLspEditor extends ExtensionBasedTextEditor {

@Override
protected ISourceViewer createSourceViewer(Composite parent, IVerticalRuler ruler, int styles) {
Composite editorComposite = createSwitchBackToTraditionalEditorBanner(parent);
return super.createSourceViewer(editorComposite, ruler, styles);
}

/**
* Wraps {@link ISwitchBackToTraditional#createSwitchBackToTraditional(org.eclipse.ui.texteditor.ITextEditor, Composite)}
* with the needed service access + fallback checks.
*
* If the {@link ISwitchBackToTraditional} service doesn't exist, or fails, this method
* is a no-op that simply returns its input.
*
* @see ISwitchBackToTraditional#createSwitchBackToTraditional(org.eclipse.ui.texteditor.ITextEditor, Composite)
*/
private Composite createSwitchBackToTraditionalEditorBanner(Composite parent) {
Composite editorComposite = SafeRunner.run(() -> {
ISwitchBackToTraditional switchToLsp = PlatformUI.getWorkbench().getService(ISwitchBackToTraditional.class);
if (switchToLsp != null) {
return switchToLsp.createSwitchBackToTraditional(CLspEditor.this, parent);
}
return null;
});
if (editorComposite == null) {
editorComposite = parent;
}
return editorComposite;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ public boolean preferLspEditor() {
return booleanValue(EditorMetadata.Predefined.preferLspEditor);
}

@Override
public boolean showTryLspBanner() {
return booleanValue(EditorMetadata.Predefined.showTryLspBanner);
}

@Override
public boolean formatOnSave() {
return booleanValue(EditorMetadata.Predefined.formatOnSave);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ public class LspUiMessages extends NLS {
public static String LspEditorConfigurationPage_configure_ws_specific;
public static String LspEditorConfigurationPage_preferLspEditor;
public static String LspEditorConfigurationPage_preferLspEditor_description;
public static String LspEditorConfigurationPage_showTryLspBanner;
public static String LspEditorConfigurationPage_showTryLspBanner_description;

public static String SaveActionsConfigurationPage_FormatSourceCode;
public static String SaveActionsConfigurationPage_FormatSourceCode_description;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ LspEditorConfigurationPage_enable_project_specific=Enable project-specific setti
LspEditorConfigurationPage_configure_ws_specific=Configure Workspace Settings...
LspEditorConfigurationPage_preferLspEditor=Set C/C++ Editor (LSP) as default
LspEditorConfigurationPage_preferLspEditor_description=The language server based C/C++ Editor will be used to open C/C++ source files.
LspEditorConfigurationPage_showTryLspBanner=Show the editing experience banner
LspEditorConfigurationPage_showTryLspBanner_description=Show the try the new editing experience banner when opening C/C++ editors

SaveActionsConfigurationPage_FormatSourceCode=Format source code
SaveActionsConfigurationPage_FormatSourceCode_description=Formats source code when file is saved
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*******************************************************************************
* Copyright (c) 2025 Kichwa Coders Canada Inc. and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/

package org.eclipse.cdt.lsp.internal.switchtolsp;

import org.eclipse.cdt.lsp.internal.editor.CLspEditor;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.texteditor.ITextEditor;

/**
* This interface can be implemented by CDT-LSP to display a banner in the {@link CLspEditor}
* to switch back to the traditional C/C++ editing experience
*
* This interface is not public API
*
* @apiNote this interface, at time of initial implementation, is expected to work
* with CDT 11.6 and CDT 12. There should be no requirements on API
* added in CDT 12 (specifically ISwitchToLsp)
*
* See org.eclipse.cdt.internal.ui.switchtolsp.ISwitchToLsp
*/
public interface ISwitchBackToTraditional {

/**
* Create the banner controls for the "switch back to traditional"
*
* @param part the editor part that the banner is added on
* @param parent the parent control
* @return the new parent control the editor should use
*/
public Composite createSwitchBackToTraditional(ITextEditor part, Composite parent);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*******************************************************************************
* Copyright (c) 2025 Kichwa Coders Canada Inc. and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/

package org.eclipse.cdt.lsp.internal.switchtolsp;

import java.util.ArrayList;

import org.eclipse.cdt.lsp.ui.EditorConfigurationPage;
import org.eclipse.jface.preference.PreferenceDialog;
import org.eclipse.swt.program.Program;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.PreferencesUtil;

public class LinkHelper {

public static final String SPARKLES = "\u2728 "; //$NON-NLS-1$
public static final String LINK_SPACER = " · "; //$NON-NLS-1$

public static String A(String linkText) {
return "<a>" + linkText + "</a>"; //$NON-NLS-1$//$NON-NLS-2$
}

/**
* Creates the standard set of links to show in notifications and message dialogs.
*
* Some workflows don't make sense to show the preferences link, such as confirmation
* dialog.
* @return string of links that {@link #handleLinkClick(Shell, Event)} will be able to process
*/
public static String getLinks(boolean showPreferenceLink) {
StringBuilder message = new StringBuilder();
var texts = new ArrayList<String>();
texts.add(A(Messages.SwitchToLsp_LearnMoreLink));
if (showPreferenceLink) {
texts.add(A(Messages.SwitchToLsp_OpenPreferencesLink));
}
texts.add(A(Messages.SwitchToLsp_GiveFeedbackLink));
message.append(String.join(LINK_SPACER, texts));
return message.toString();
}

/**
* Handler for the links created by {@link #getLinks(boolean)}
*/
public static boolean handleLinkClick(Shell parentShell, Event event) {
if (event.text != null && event.text.equals(Messages.SwitchToLsp_LearnMoreLink)) {
PlatformUI.getWorkbench().getHelpSystem().displayHelpResource(SwitchToLspWizard.TRY_LSP_HELP_PATH);
} else if (event.text != null && event.text.equals(Messages.SwitchToLsp_OpenPreferencesLink)) {
PreferenceDialog preferenceDialogOn = PreferencesUtil.createPreferenceDialogOn(parentShell,
EditorConfigurationPage.PREFERENCE_PAGE_ID, null /* display all pages */,
EditorConfigurationPage.HIGHLIGHT_PREFER_LSP);
preferenceDialogOn.setBlockOnOpen(false);
preferenceDialogOn.open();
} else if (event.text != null && event.text.equals(Messages.SwitchToLsp_GiveFeedbackLink)) {
Program.launch(SwitchToLspWizard.FEEDBACK_URL);
} else {
// Did not detect a link - do nothing
return false;
}
return true;
}

}
Loading

0 comments on commit dfe1635

Please sign in to comment.