Skip to content

Commit

Permalink
#514 Add Gradle editor
Browse files Browse the repository at this point in the history
#560 Add editor contribution
+ Get rid of the GenericEditor, because it doesn't allow several
partition types + Reuse Java syntax color highlighting + Fix tab size in
the Gradle editor

Signed-off-by: Christophe Moine <christophe.moine@free.fr>
  • Loading branch information
cmoine committed Oct 4, 2017
1 parent 6c615f1 commit 1984095
Show file tree
Hide file tree
Showing 12 changed files with 448 additions and 6 deletions.
8 changes: 8 additions & 0 deletions org.eclipse.buildship.core/plugin.xml
Expand Up @@ -78,4 +78,12 @@
</runtimeClasspathEntryResolver>
</extension>

<extension point="org.eclipse.core.contenttype.contentTypes">
<content-type
file-extensions="gradle"
id="org.eclipse.buildship.core.files.gradlebuildscript"
name="Gradle Build Script"
priority="low"
/>
</extension>
</plugin>
3 changes: 2 additions & 1 deletion org.eclipse.buildship.ui/META-INF/MANIFEST.MF
Expand Up @@ -24,6 +24,7 @@ Require-Bundle: org.eclipse.buildship.core,
com.google.guava;bundle-version="[15.0.0,16.0.0)",
com.gradleware.tooling.model;bundle-version="[0.19.3,0.20.0)",
com.gradleware.tooling.client;bundle-version="[0.19.3,0.20.0)",
com.gradleware.tooling.utils;bundle-version="[0.19.3,0.20.0)"
com.gradleware.tooling.utils;bundle-version="[0.19.3,0.20.0)",
org.eclipse.ui.workbench.texteditor
Bundle-ActivationPolicy: lazy
Bundle-ClassPath: .
18 changes: 13 additions & 5 deletions org.eclipse.buildship.ui/plugin.xml
Expand Up @@ -65,12 +65,13 @@
<extension
point="org.eclipse.ui.editors">
<editor
id="org.eclipse.buildship.ui.gradlebuildscripteditor"
class="org.eclipse.ui.editors.text.TextEditor"
icon="icons/full/obj16/gradle_file.png"
name="Gradle Build Script Editor"
class="org.eclipse.buildship.ui.editor.GradleEditor"
contributorClass="org.eclipse.buildship.ui.editor.GradleEditorContributor"
default="false"
extensions="gradle">
extensions="gradle"
icon="icons/full/obj16/gradle_file.png"
id="org.eclipse.buildship.ui.gradlebuildscripteditor"
name="Gradle Build Script Editor">
</editor>
</extension>

Expand Down Expand Up @@ -550,4 +551,11 @@
</enabledWhen>
</page>
</extension>
<extension
point="org.eclipse.core.filebuffers.documentSetup">
<participant
class="org.eclipse.buildship.ui.editor.GradleDocumentSetupParticipant"
contentTypeId="org.eclipse.buildship.core.files.gradlebuildscript">
</participant>
</extension>
</plugin>
Expand Up @@ -72,6 +72,8 @@ public final class UiPluginConstants {

public static final String IMPORT_WIZARD_ID = "org.eclipse.buildship.ui.wizards.project.import";

public static final String REFRESHPROJECT_COMMAND_ID = "org.eclipse.buildship.ui.commands.refreshproject";

private UiPluginConstants() {
}

Expand Down
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2017 the original author or authors.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.buildship.ui.editor;

import org.eclipse.core.filebuffers.IDocumentSetupParticipant;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentExtension3;
import org.eclipse.jface.text.IDocumentPartitioner;
import org.eclipse.jface.text.rules.FastPartitioner;

/**
* The document setup participant for a properties file document.
*
* @author Christophe Moine
*/
public class GradleDocumentSetupParticipant implements IDocumentSetupParticipant {

/*
* @see org.eclipse.core.filebuffers.IDocumentSetupParticipant#setup(org.eclipse.jface.text.IDocument)
*/
@Override
public void setup(IDocument document) {
IDocumentPartitioner partitioner= createDocumentPartitioner();
if (document instanceof IDocumentExtension3) {
IDocumentExtension3 extension3= (IDocumentExtension3) document;
extension3.setDocumentPartitioner(IGradlePartitions.PARTITIONING, partitioner);
} else {
document.setDocumentPartitioner(partitioner);
}
partitioner.connect(document);
}

/**
* Factory method for creating a properties file document specific document
* partitioner.
*
* @return a newly created properties file document partitioner
*/
private static IDocumentPartitioner createDocumentPartitioner() {
return new FastPartitioner(new GradlePartitionScanner(), IGradlePartitions.PARTITIONS);
}
}
@@ -0,0 +1,35 @@
/*
* Copyright (c) 2017 the original author or authors.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.buildship.ui.editor;

import org.eclipse.ui.editors.text.EditorsUI;
import org.eclipse.ui.editors.text.TextEditor;
import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants;

/**
* Gradle Editor entry point
*
* @author Christophe Moine
*/
public class GradleEditor extends TextEditor {
@Override
protected void initializeEditor() {
setSourceViewerConfiguration(new GradleTextViewerConfiguration());
super.initializeEditor();
}

/*
* @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#isTabsToSpacesConversionEnabled()
* @since 3.7
*/
@Override
protected boolean isTabsToSpacesConversionEnabled() {
// Can't use our own preference store because JDT disables this functionality in its preferences.
return EditorsUI.getPreferenceStore().getBoolean(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SPACES_FOR_TABS);
}
}
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2017 the original author or authors.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.buildship.ui.editor;

import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.swt.widgets.Event;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.part.EditorActionBarContributor;

import org.eclipse.buildship.ui.PluginImage;
import org.eclipse.buildship.ui.PluginImages;
import org.eclipse.buildship.ui.UiPlugin;
import org.eclipse.buildship.ui.UiPluginConstants;

/**
* Action contributor for the Gradle Editor
*
* @author Christophe Moine
*/
public class GradleEditorContributor extends EditorActionBarContributor {
@Override
public void contributeToToolBar(IToolBarManager toolBarManager) {
toolBarManager.add(new Action("Refresh Gradle Project", PluginImages.REFRESH.withState(PluginImage.ImageState.ENABLED).getImageDescriptor()) {
@Override
public void runWithEvent(Event event) {
IHandlerService service=getActionBars().getServiceLocator().getService(IHandlerService.class);
try {
service.executeCommand(UiPluginConstants.REFRESHPROJECT_COMMAND_ID, event);
} catch (Exception e) {
UiPlugin.logger().error("Failed to invoke command "+UiPluginConstants.REFRESHPROJECT_COMMAND_ID, e);
}
}
});
}
}
@@ -0,0 +1,71 @@
/*
* Copyright (c) 2017 the original author or authors.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.buildship.ui.editor;

import org.eclipse.jface.text.rules.EndOfLineRule;
import org.eclipse.jface.text.rules.ICharacterScanner;
import org.eclipse.jface.text.rules.IPredicateRule;
import org.eclipse.jface.text.rules.IToken;
import org.eclipse.jface.text.rules.IWordDetector;
import org.eclipse.jface.text.rules.MultiLineRule;
import org.eclipse.jface.text.rules.RuleBasedPartitionScanner;
import org.eclipse.jface.text.rules.SingleLineRule;
import org.eclipse.jface.text.rules.Token;
import org.eclipse.jface.text.rules.WordRule;


/**
* @author Christophe Moine
*
*/
public class GradlePartitionScanner extends RuleBasedPartitionScanner {
private static class EmptyCommentDetector implements IWordDetector {

@Override
public boolean isWordStart(char c) {
return (c == '/');
}

@Override
public boolean isWordPart(char c) {
return (c == '*' || c == '/');
}
}

private static class EmptyCommentPredicateRule extends WordRule implements IPredicateRule {
private final IToken successToken;

public EmptyCommentPredicateRule(IToken successToken) {
super(new EmptyCommentDetector());
this.successToken = successToken;
addWord("/**/", successToken); //$NON-NLS-1$
}

@Override
public IToken evaluate(ICharacterScanner scanner, boolean resume) {
return super.evaluate(scanner);
}

@Override
public IToken getSuccessToken() {
return this.successToken;
}
}

public GradlePartitionScanner() {
IToken jsDocToken = new Token(IGradlePartitions.GRADLEDOC);
IToken multilineCommentToken = new Token(IGradlePartitions.MULTILINE_COMMENT);

setPredicateRules(new IPredicateRule[] { new EndOfLineRule("//", Token.UNDEFINED), //$NON-NLS-1$
new SingleLineRule("\"", "\"", Token.UNDEFINED, '\\'), //$NON-NLS-2$ //$NON-NLS-1$
new SingleLineRule("'", "'", Token.UNDEFINED, '\\'), //$NON-NLS-2$ //$NON-NLS-1$
new EmptyCommentPredicateRule(multilineCommentToken), new MultiLineRule("/**", "*/", jsDocToken, (char) 0, true), //$NON-NLS-1$ //$NON-NLS-2$
new MultiLineRule("/*", "*/", multilineCommentToken, (char) 0, true) //$NON-NLS-1$ //$NON-NLS-2$
});
}
}
@@ -0,0 +1,130 @@
/*
* Copyright (c) 2017 the original author or authors.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.buildship.ui.editor;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import com.google.common.collect.ImmutableMap;

import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener;
import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.jdt.ui.text.IJavaColorConstants;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.TextAttribute;
import org.eclipse.jface.text.presentation.PresentationReconciler;
import org.eclipse.jface.text.rules.BufferedRuleBasedScanner;
import org.eclipse.jface.text.rules.DefaultDamagerRepairer;
import org.eclipse.jface.text.rules.EndOfLineRule;
import org.eclipse.jface.text.rules.IRule;
import org.eclipse.jface.text.rules.IToken;
import org.eclipse.jface.text.rules.ITokenScanner;
import org.eclipse.jface.text.rules.IWordDetector;
import org.eclipse.jface.text.rules.MultiLineRule;
import org.eclipse.jface.text.rules.NumberRule;
import org.eclipse.jface.text.rules.SingleLineRule;
import org.eclipse.jface.text.rules.Token;
import org.eclipse.jface.text.rules.WordRule;

import org.eclipse.buildship.core.util.preference.EclipsePreferencesUtils;

/**
* Presentation Reconcilier for the Gradle Editor
*
* @author Christophe Moine
*/
public class GradlePresentationReconciler extends PresentationReconciler {
private static final List<String> KEYWORDS = Arrays.asList("assert", "if", "else", "void", "null", "new", "return", "try", "catch", "def", "allprojects", //
"artifacts", "buildscript", "configurations", "dependencies", "repositories", "sourceSets", "subprojects", "publishing", "task", "apply", "sourceCompatibility", //
"targetCompatibility", "test", "project", "ext", "plugins", "jar", "shadowJar", "for", "while");

private final Map<String, Token> idToTokens=ImmutableMap.<String, Token>builder()
.put(IJavaColorConstants.JAVA_KEYWORD, new Token(null)) //
.put(IJavaColorConstants.JAVA_SINGLE_LINE_COMMENT, new Token(null)) //
.put(IJavaColorConstants.JAVA_MULTI_LINE_COMMENT, new Token(null)) //
.put(IJavaColorConstants.JAVA_STRING, new Token(null)) //
.put(IJavaColorConstants.JAVA_DEFAULT, new Token(null)) //
.build();

private IEclipsePreferences preferencesNode = EclipsePreferencesUtils.getInstanceScope().getNode(JavaUI.ID_PLUGIN);

@Override
public void install(final ITextViewer viewer) {
this.preferencesNode.addPreferenceChangeListener(new IPreferenceChangeListener() {
@Override
public void preferenceChange(PreferenceChangeEvent event) {
if(updateToken(event.getKey())) {
viewer.invalidateTextPresentation();
}
}
});
for(Entry<String, Token> entry: this.idToTokens.entrySet()) {
updateToken(entry.getKey());
}

BufferedRuleBasedScanner scanner = new BufferedRuleBasedScanner() {};
scanner.setRules(new IRule[] { new EndOfLineRule("//", this.idToTokens.get(IJavaColorConstants.JAVA_SINGLE_LINE_COMMENT)), // $NON-NLS-2$
new MultiLineRule("/*", "*/", this.idToTokens.get(IJavaColorConstants.JAVA_MULTI_LINE_COMMENT), (char) 0, true), //$NON-NLS-2$
new SingleLineRule("\"", "\"", this.idToTokens.get(IJavaColorConstants.JAVA_STRING)), //
new SingleLineRule("'", "'", this.idToTokens.get(IJavaColorConstants.JAVA_STRING)), //
new KeywordRule(this.idToTokens.get(IJavaColorConstants.JAVA_KEYWORD)), //
new WordRule(new WordDetector(), this.idToTokens.get(IJavaColorConstants.JAVA_DEFAULT)),
new NumberRule(this.idToTokens.get(IJavaColorConstants.JAVA_DEFAULT)),
});
setDamagerRepairer(scanner, IDocument.DEFAULT_CONTENT_TYPE);
MultilineCommentScanner multilineCommentScanner=new MultilineCommentScanner(this.idToTokens.get(IJavaColorConstants.JAVA_MULTI_LINE_COMMENT));
setDamagerRepairer(multilineCommentScanner, IGradlePartitions.MULTILINE_COMMENT);
setDamagerRepairer(multilineCommentScanner, IGradlePartitions.GRADLEDOC);

super.install(viewer);
}

private void setDamagerRepairer(ITokenScanner scanner, String tokenType) {
DefaultDamagerRepairer damagerRepairer = new DefaultDamagerRepairer(scanner);
setDamager(damagerRepairer, tokenType);
setRepairer(damagerRepairer, tokenType);
}

private boolean updateToken(String key) {
Token token = this.idToTokens.get(key);
if(token!=null) {
token.setData(new TextAttribute(JavaUI.getColorManager().getColor(key)));
}
return token!=null;
}



private static class KeywordRule extends WordRule {
public KeywordRule(IToken token) {
super(new WordDetector());
for (String word : KEYWORDS) {
addWord(word, token);
}
}
}

private static class WordDetector implements IWordDetector {

@Override
public boolean isWordPart(char c) {
return Character.isJavaIdentifierPart(c);
}

@Override
public boolean isWordStart(char c) {
return Character.isJavaIdentifierStart(c);
}

}
}

0 comments on commit 1984095

Please sign in to comment.