Skip to content

Commit

Permalink
[#120] Clangd options in preference/project properties not changeable (
Browse files Browse the repository at this point in the history
…#122)

Rework both Properties and Preference page, to reuse approach from other
places like PDE
  • Loading branch information
ruspl-afed committed Jun 14, 2023
1 parent 42af868 commit 566c0b7
Show file tree
Hide file tree
Showing 10 changed files with 463 additions and 298 deletions.
5 changes: 2 additions & 3 deletions bundles/org.eclipse.cdt.lsp.clangd/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ Export-Package: org.eclipse.cdt.lsp.clangd;x-internal:=true,
org.eclipse.cdt.lsp.internal.clangd;x-internal:=true,
org.eclipse.cdt.lsp.internal.clangd.editor;x-internal:=true,
org.eclipse.cdt.lsp.internal.clangd.editor.expressions;x-internal:=true,
org.eclipse.cdt.lsp.internal.clangd.editor.handlers;x-internal:=true,
org.eclipse.cdt.lsp.internal.clangd.editor.preferences;x-internal:=true,
org.eclipse.cdt.lsp.internal.clangd.editor.properties;x-internal:=true
org.eclipse.cdt.lsp.internal.clangd.editor.handlers;x-internal:=true
Import-Package: org.yaml.snakeyaml;version="1.27.0",
org.yaml.snakeyaml.error;version="1.27.0",
org.yaml.snakeyaml.scanner;version="1.27.0"
Expand All @@ -28,6 +26,7 @@ Require-Bundle: org.eclipse.cdt.lsp;bundle-version="0.0.0",
org.eclipse.jface.text;bundle-version="0.0.0",
org.eclipse.lsp4e;bundle-version="0.16.1",
org.eclipse.lsp4j;bundle-version="0.0.0",
org.eclipse.ui.editors;bundle-version="0.0.0",
org.eclipse.ui.ide;bundle-version="0.0.0",
org.eclipse.ui.workbench;bundle-version="0.0.0",
org.eclipse.ui.workbench.texteditor;bundle-version="0.0.0"
Expand Down
8 changes: 4 additions & 4 deletions bundles/org.eclipse.cdt.lsp.clangd/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
<!-- FIXME: AF: Move commmon part to "org.eclipse.cdt.lsp[.editor]" -->
<page
category="org.eclipse.cdt.ui.preferences.CPluginPreferencePage"
class="org.eclipse.cdt.lsp.internal.clangd.editor.preferences.LspEditorPreferencePage"
id="org.eclipse.cdt.lsp.clangd.editor.preferences.general"
class="org.eclipse.cdt.lsp.internal.clangd.editor.ClangdConfigurationPage"
id="org.eclipse.cdt.lsp.clangd.editor"
name="Editor (LSP)">
</page>
</extension>
Expand All @@ -33,8 +33,8 @@
<!-- FIXME: AF: Move me to "org.eclipse.cdt.lsp[.editor]" -->
<page
category="org.eclipse.cdt.ui.newui.Page_head_general"
class="org.eclipse.cdt.lsp.internal.clangd.editor.properties.LspEditorPropertiesPage"
id="org.eclipse.cdt.lsp.editor.properties.general"
class="org.eclipse.cdt.lsp.internal.clangd.editor.ClangdConfigurationPage"
id="org.eclipse.cdt.lsp.clangd.editor"
name="Editor (LSP)">
<filter
name="projectNature"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public PreferenceMetadata<Boolean> prettyPrint() {
@Override
public PreferenceMetadata<String> queryDriver() {
return new PreferenceMetadata<>(String.class, //
"pretty_print", //$NON-NLS-1$
"query_driver", //$NON-NLS-1$
Optional.ofNullable(PathUtil.findProgramLocation("gcc", null)) //$NON-NLS-1$
.map(p -> p.removeLastSegments(1).append(IPath.SEPARATOR + "*"))// //$NON-NLS-1$
.map(IPath::toString)//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

import org.eclipse.cdt.lsp.clangd.ClangdMetadata;
import org.eclipse.cdt.lsp.clangd.ClangdOptions;
Expand All @@ -41,44 +42,54 @@ final class ClangdPreferredOptions implements ClangdOptions {

@Override
public boolean preferClangd() {
PreferenceMetadata<Boolean> pref = metadata.preferClangd();
return service.getBoolean(qualifier, pref.identifer(), pref.defaultValue(), scopes);
return booleanValue(metadata.preferClangd());
}

@Override
public String clangdPath() {
PreferenceMetadata<String> pref = metadata.clangdPath();
return service.getString(qualifier, pref.identifer(), pref.defaultValue(), scopes);
return stringValue(metadata.clangdPath());
}

@Override
public boolean useTidy() {
PreferenceMetadata<Boolean> pref = metadata.useTidy();
return service.getBoolean(qualifier, pref.identifer(), pref.defaultValue(), scopes);
return booleanValue(metadata.useTidy());
}

@Override
public boolean useBackgroundIndex() {
PreferenceMetadata<Boolean> pref = metadata.useBackgroundIndex();
return service.getBoolean(qualifier, pref.identifer(), pref.defaultValue(), scopes);
return booleanValue(metadata.useBackgroundIndex());
}

@Override
public String completionStyle() {
PreferenceMetadata<String> pref = metadata.completionStyle();
return service.getString(qualifier, pref.identifer(), pref.defaultValue(), scopes);
return stringValue(metadata.completionStyle());
}

@Override
public boolean prettyPrint() {
PreferenceMetadata<Boolean> pref = metadata.prettyPrint();
return service.getBoolean(qualifier, pref.identifer(), pref.defaultValue(), scopes);
return booleanValue(metadata.prettyPrint());
}

@Override
public String queryDriver() {
PreferenceMetadata<String> pref = metadata.queryDriver();
return service.getString(qualifier, pref.identifer(), pref.defaultValue(), scopes);
return stringValue(metadata.queryDriver());
}

private String stringValue(PreferenceMetadata<?> meta) {
String actual = String.valueOf(meta.defaultValue());
for (int i = scopes.length - 1; i >= 0; i--) {
IScopeContext scope = scopes[i];
String previous = actual;
actual = service.getString(qualifier, meta.identifer(), previous, new IScopeContext[] { scope });
}
return actual;
}

private boolean booleanValue(PreferenceMetadata<Boolean> meta) {
return Optional.of(meta)//
.map(this::stringValue)//
.map(Boolean::valueOf)//
.orElseGet(meta::defaultValue);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
/*******************************************************************************
* Copyright (c) 2023 ArSysOp.
*
* 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
*
* Contributors:
* Alexander Fedorov (ArSysOp) - Initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.lsp.internal.clangd.editor;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

import org.eclipse.cdt.lsp.clangd.ClangdMetadata;
import org.eclipse.cdt.lsp.clangd.ClangdOptions;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.OsgiPreferenceMetadataStore;
import org.eclipse.core.runtime.preferences.PreferenceMetadata;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.events.TypedEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;

public final class ClangdConfigurationArea {

private final int columns = 3;
private final Button prefer;
private final Text path;
private final Button tidy;
private final Text completion;
private final Button index;
private final Button pretty;
private final Text driver;

private final Map<PreferenceMetadata<Boolean>, Button> buttons;
private final Map<PreferenceMetadata<String>, Text> texts;
private final List<Consumer<TypedEvent>> listeners;

public ClangdConfigurationArea(Composite parent, ClangdMetadata metadata) {
this.buttons = new HashMap<>();
this.texts = new HashMap<>();
this.listeners = new ArrayList<>();
Composite composite = new Composite(parent, SWT.NONE);
composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
composite.setLayout(GridLayoutFactory.fillDefaults().numColumns(columns).create());
this.prefer = createCheckbox(metadata.preferClangd(), composite);
this.path = createFileSelector(metadata.clangdPath(), composite, this::selectClangdExecutable);
this.tidy = createCheckbox(metadata.useTidy(), composite);
this.index = createCheckbox(metadata.useBackgroundIndex(), composite);
this.completion = createText(metadata.completionStyle(), composite);
this.pretty = createCheckbox(metadata.prettyPrint(), composite);
this.driver = createText(metadata.queryDriver(), composite);
}

private Button createCheckbox(PreferenceMetadata<Boolean> meta, Composite composite) {
Button button = new Button(composite, SWT.CHECK);
button.setLayoutData(GridDataFactory.fillDefaults().span(columns, 1).create());
button.setData(meta);
button.setText(meta.name());
button.setToolTipText(meta.description());
buttons.put(meta, button);
return button;
}

private Text createFileSelector(PreferenceMetadata<String> meta, Composite composite,
Consumer<SelectionEvent> selector) {
Label label = new Label(composite, SWT.NONE);
label.setText(meta.name());
label.setLayoutData(GridDataFactory.fillDefaults().create());
Text text = new Text(composite, SWT.BORDER);
text.setToolTipText(meta.description());
text.setData(meta);
texts.put(meta, text);
text.addKeyListener(KeyListener.keyReleasedAdapter(this::changed));
text.setLayoutData(GridDataFactory.fillDefaults().grab(true, false).span(columns - 2, 1).create());
Button button = new Button(composite, SWT.NONE);
button.setText("Browse...");
button.setLayoutData(new GridData());
button.addSelectionListener(SelectionListener.widgetSelectedAdapter(selector));
return text;
}

private Text createText(PreferenceMetadata<String> meta, Composite composite) {
Label label = new Label(composite, SWT.NONE);
label.setText(meta.name());
label.setLayoutData(GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).create());
Text text = new Text(composite, SWT.BORDER);
text.setToolTipText(meta.description());
text.setData(meta);
text.setLayoutData(GridDataFactory.fillDefaults().grab(true, false).span(columns - 1, 1).create());
texts.put(meta, text);
text.addKeyListener(KeyListener.keyReleasedAdapter(this::changed));
return text;
}

private void selectClangdExecutable(SelectionEvent e) {
String selected = selectFile(path.getText());
if (selected != null) {
path.setText(selected);
changed(e);
}

}

private String selectFile(String path) {
FileDialog dialog = new FileDialog(Display.getCurrent().getActiveShell(), SWT.SAVE);
File file = new File(path);
if (file.isFile()) {
dialog.setFilterPath(file.toString());
}
return dialog.open();
}

void addChangeListener(Consumer<TypedEvent> listener) {
listeners.add(listener);
}

void removeChangeListener(Consumer<TypedEvent> listener) {
listeners.add(listener);
}

void changed(TypedEvent event) {
listeners.forEach(c -> c.accept(event));
}

void load(ClangdOptions options) {
prefer.setSelection(options.preferClangd());
path.setText(options.clangdPath());
tidy.setSelection(options.useTidy());
index.setSelection(options.useBackgroundIndex());
completion.setText(options.completionStyle());
pretty.setSelection(options.prettyPrint());
driver.setText(options.queryDriver());
}

void store(IEclipsePreferences prefs) {
OsgiPreferenceMetadataStore store = new OsgiPreferenceMetadataStore(prefs);
buttons.entrySet().forEach(e -> store.save(e.getValue().getSelection(), e.getKey()));
texts.entrySet().forEach(e -> store.save(e.getValue().getText(), e.getKey()));
}

void dispose() {
listeners.clear();
buttons.clear();
texts.clear();
}

}

0 comments on commit 566c0b7

Please sign in to comment.