Bug 575348: [SourceEditor] Add CommentScanner (for presentation)
Change-Id: I13cfb6abb330939c703bdec558a96f597bab9777
diff --git a/ltk/org.eclipse.statet.ltk.core/META-INF/MANIFEST.MF b/ltk/org.eclipse.statet.ltk.core/META-INF/MANIFEST.MF
index ff5fb2e..521b666 100644
--- a/ltk/org.eclipse.statet.ltk.core/META-INF/MANIFEST.MF
+++ b/ltk/org.eclipse.statet.ltk.core/META-INF/MANIFEST.MF
@@ -13,7 +13,8 @@
org.eclipse.core.contenttype,
org.eclipse.core.filesystem,
org.eclipse.core.resources;visibility:=reexport,
- org.eclipse.statet.ecommons.text.core;visibility:=reexport,
+ org.eclipse.statet.ecommons.text.core;bundle-version="[4.5.0,4.6.0)";visibility:=reexport,
+ org.eclipse.statet.ecommons.preferences.core;bundle-version="[4.5.0,4.6.0)",
org.eclipse.core.filebuffers,
org.eclipse.ltk.core.refactoring,
org.eclipse.jface.text;visibility:=reexport,
diff --git a/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/issues/core/Tasks.java b/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/issues/core/Tasks.java
new file mode 100644
index 0000000..c7386e3
--- /dev/null
+++ b/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/issues/core/Tasks.java
@@ -0,0 +1,73 @@
+/*=============================================================================#
+ # Copyright (c) 2021 Stephan Wahlbrink and others.
+ #
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.ltk.issues.core;
+
+import java.util.List;
+
+import org.eclipse.statet.jcommons.collections.ImCollections;
+import org.eclipse.statet.jcommons.collections.ImList;
+import org.eclipse.statet.jcommons.lang.NonNull;
+import org.eclipse.statet.jcommons.lang.NonNullByDefault;
+
+import org.eclipse.statet.ecommons.preferences.core.Preference.EnumListPref;
+import org.eclipse.statet.ecommons.preferences.core.Preference.StringArrayPref;
+import org.eclipse.statet.ecommons.preferences.core.PreferenceAccess;
+
+import org.eclipse.statet.ltk.issues.core.impl.BasicTaskTag;
+
+
+@NonNullByDefault
+public class Tasks {
+
+
+ public static final String KEYWORD_PREF_KEY= "TaskTags.keyword"; //$NON-NLS-1$
+ public static final String PRIORITY_PREF_KEY= "TaskTags.priority"; //$NON-NLS-1$
+
+
+ private static StringArrayPref createKeywordPref(final String qualifier) {
+ return new StringArrayPref(qualifier, KEYWORD_PREF_KEY);
+ }
+
+ private static EnumListPref<TaskPriority> createPriorityPref(final String qualifier) {
+ return new EnumListPref<>(qualifier, PRIORITY_PREF_KEY, TaskPriority.class);
+ }
+
+
+ public static ImList<TaskTag> loadTaskTags(final String qualifier, final PreferenceAccess prefs) {
+ final @NonNull String[] keywords= prefs.getPreferenceValue(createKeywordPref(qualifier));
+ final List<TaskPriority> priorities= prefs.getPreferenceValue(createPriorityPref(qualifier));
+
+ if (keywords.length == priorities.size()) {
+ final var array= new @NonNull TaskTag[keywords.length];
+ for (int i= 0; i < array.length; i++) {
+ array[i]= new BasicTaskTag(keywords[i], priorities.get(i));
+ }
+ return ImCollections.newList(array);
+ }
+ else {
+ return ImCollections.emptyList();
+ }
+ }
+
+ public static ImList<String> getKeywords(final ImList<TaskTag> taskTags) {
+ final var array= new @NonNull String[taskTags.size()];
+ for (int i= 0; i < array.length; i++) {
+ array[i]= taskTags.get(i).getKeyword();
+ }
+ return ImCollections.newList(array);
+ }
+
+
+}
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/presentation/CommentScanner.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/presentation/CommentScanner.java
new file mode 100644
index 0000000..bc132d2
--- /dev/null
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/presentation/CommentScanner.java
@@ -0,0 +1,138 @@
+/*=============================================================================#
+ # Copyright (c) 2005, 2021 Stephan Wahlbrink and others.
+ #
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.ltk.ui.sourceediting.presentation;
+
+import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullLateInit;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.jface.text.rules.IRule;
+import org.eclipse.jface.text.rules.IToken;
+import org.eclipse.jface.text.rules.IWordDetector;
+import org.eclipse.jface.text.rules.WordRule;
+
+import org.eclipse.statet.jcommons.collections.ImList;
+import org.eclipse.statet.jcommons.lang.NonNullByDefault;
+
+import org.eclipse.statet.ecommons.preferences.core.PreferenceAccess;
+import org.eclipse.statet.ecommons.text.ui.presentation.AbstractRuleBasedScanner;
+import org.eclipse.statet.ecommons.text.ui.presentation.ITextPresentationConstants;
+import org.eclipse.statet.ecommons.text.ui.presentation.TextStyleManager;
+import org.eclipse.statet.ecommons.ui.ISettingsChangedHandler;
+
+import org.eclipse.statet.ltk.issues.core.Tasks;
+
+
+/**
+ * Scanner for comments. Provides support for task tags.
+ */
+@NonNullByDefault
+public class CommentScanner extends AbstractRuleBasedScanner implements ISettingsChangedHandler {
+
+
+ private static class TaskTagDetector implements IWordDetector {
+
+ @Override
+ public boolean isWordStart(final char c) {
+ return Character.isLetterOrDigit(c);
+ }
+
+ @Override
+ public boolean isWordPart(final char c) {
+ return Character.isLetterOrDigit(c);
+ }
+ }
+
+ private static class TaskTagRule extends WordRule {
+
+ private final IToken token;
+
+ public TaskTagRule(final IToken token, final IToken defaultToken) {
+ super(new TaskTagDetector(), defaultToken);
+ this.token= token;
+ }
+
+ public void setKeywords(final ImList<String> tags) {
+ this.fWords.clear();
+ for (final String tag : tags) {
+ addWord(tag, this.token);
+ }
+ }
+ }
+
+
+ private final String prefQualifier;
+ private final PreferenceAccess prefs;
+
+ private TaskTagRule taskTagRule= nonNullLateInit();
+
+ private final String commentTokenKey;
+ private final String taskTokenKey;
+
+
+ public CommentScanner(final TextStyleManager<?> textStyles,
+ final String commentTokenKey, final String taskTokenKey,
+ final String prefQualifier, final PreferenceAccess prefs) {
+ super(textStyles);
+
+ this.commentTokenKey= commentTokenKey;
+ this.taskTokenKey= taskTokenKey;
+ initRules();
+
+ this.prefQualifier= prefQualifier;
+ this.prefs= prefs;
+ loadTaskTags();
+ }
+
+ public CommentScanner(final TextStyleManager<?> textStyles,
+ final String commentTokenKey, final String taskTokenKey,
+ final PreferenceAccess prefs) {
+ this(textStyles, commentTokenKey, taskTokenKey, PREF_QUALIFIER, prefs);
+ }
+
+
+ @Override
+ protected void createRules(final List<IRule> rules) {
+ final IToken defaultToken= getToken(this.commentTokenKey);
+ final IToken taskToken= getToken(this.taskTokenKey);
+
+ setDefaultReturnToken(defaultToken);
+
+ // Add rule for Task Tags.
+ this.taskTagRule= new TaskTagRule(taskToken, defaultToken);
+ rules.add(this.taskTagRule);
+ }
+
+
+ // TODO
+ private static final String GROUP_ID= "statet.task_tags"; //$NON-NLS-1$
+ private static final String PREF_QUALIFIER= "org.eclipse.statet.ide.core/managment"; //$NON-NLS-1$
+
+ @Override
+ public void handleSettingsChanged(final Set<String> groupIds, final Map<String, Object> options) {
+ if (groupIds.contains(GROUP_ID)) {
+ loadTaskTags();
+ options.put(ITextPresentationConstants.SETTINGSCHANGE_AFFECTSPRESENTATION_KEY, Boolean.TRUE);
+ }
+ }
+
+ private void loadTaskTags() {
+ final var taskTags= Tasks.loadTaskTags(this.prefQualifier, this.prefs);
+ this.taskTagRule.setKeywords(Tasks.getKeywords(taskTags));
+ }
+
+}