Bug 575365: [Ltk-Issues] Add issue requestor for persistence context
- Add IssueTypeSet
- Make use of IssueTypeSet in SourceAnnotationIssueRequestor
- Add TaskTagReporter reporting tasks to issue requestors
Change-Id: Ieb429e6e874f8dc96b9d323a8c9d3ffb651addd2
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 64760c4..4f6150a 100644
--- a/ltk/org.eclipse.statet.ltk.core/META-INF/MANIFEST.MF
+++ b/ltk/org.eclipse.statet.ltk.core/META-INF/MANIFEST.MF
@@ -24,6 +24,7 @@
org.eclipse.statet.jcommons.collections;version="4.5.0",
org.eclipse.statet.jcommons.lang;version="4.5.0",
org.eclipse.statet.jcommons.status;version="4.5.0",
+ org.eclipse.statet.jcommons.status.eplatform;version="4.5.0",
org.eclipse.statet.jcommons.string;version="4.5.0",
org.eclipse.statet.jcommons.text.core;version="4.5.0",
org.eclipse.statet.jcommons.text.core.util;version="4.5.0"
diff --git a/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/issues/core/IssueRequestor.java b/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/issues/core/IssueRequestor.java
index b52bd78..7f4f8d4 100644
--- a/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/issues/core/IssueRequestor.java
+++ b/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/issues/core/IssueRequestor.java
@@ -31,6 +31,8 @@
public interface IssueRequestor {
+ boolean isInterestedInProblems(String categoryId);
+
/**
* Notification of a discovered problem.
*
@@ -46,6 +48,9 @@
*/
void acceptProblems(String categoryId, List<Problem> problems);
+
+ boolean isInterestedInTasks();
+
/**
* Notification of a discovered task.
*
@@ -53,6 +58,7 @@
*/
void acceptTask(Task task);
+
void finish() throws StatusException;
}
diff --git a/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/issues/core/IssueTypeSet.java b/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/issues/core/IssueTypeSet.java
new file mode 100644
index 0000000..02197b0
--- /dev/null
+++ b/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/issues/core/IssueTypeSet.java
@@ -0,0 +1,150 @@
+/*=============================================================================#
+ # 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 org.eclipse.statet.jcommons.collections.ImList;
+import org.eclipse.statet.jcommons.lang.NonNullByDefault;
+import org.eclipse.statet.jcommons.lang.Nullable;
+
+import org.eclipse.statet.ltk.core.Ltk;
+import org.eclipse.statet.ltk.core.WorkingContext;
+
+
+@NonNullByDefault
+public class IssueTypeSet {
+
+
+ public final static class ProblemTypes {
+
+ private final String errorType;
+ private final String warningType;
+ private final String infoType;
+
+ public ProblemTypes(final String errorType, final String warningType, final String infoType) {
+ this.errorType= errorType;
+ this.warningType= warningType;
+ this.infoType= infoType;
+ }
+
+ public ProblemTypes(final String type) {
+ this.errorType= type;
+ this.warningType= type;
+ this.infoType= type;
+ }
+
+ public String getType(final int priority) {
+ switch (priority) {
+ case Problem.SEVERITY_ERROR:
+ return this.errorType;
+ case Problem.SEVERITY_WARNING:
+ return this.warningType;
+ default:
+ return this.infoType;
+ }
+ }
+
+ }
+
+ public static class ProblemTypeDef {
+
+ private final String id;
+
+ private final @Nullable ProblemTypes persistenceTypes;
+ private final @Nullable ProblemTypes editorTypes;
+
+ public ProblemTypeDef(final String id,
+ @Nullable final ProblemTypes persistenceTypes, @Nullable final ProblemTypes editorTypes) {
+ this.id= id;
+ this.persistenceTypes= persistenceTypes;
+ this.editorTypes= editorTypes;
+ }
+
+ public String getId() {
+ return this.id;
+ }
+
+ public @Nullable ProblemTypes getTypes(final WorkingContext context) {
+ if (context == Ltk.PERSISTENCE_CONTEXT) {
+ return this.persistenceTypes;
+ }
+ if (context == Ltk.EDITOR_CONTEXT) {
+ return this.editorTypes;
+ }
+ return null;
+ }
+
+ }
+
+ public static class TaskTypeDef {
+
+ private final @Nullable String persistenceType;
+ private final @Nullable String editorType;
+
+ public TaskTypeDef(@Nullable final String persistenceType, final @Nullable String editorType) {
+ this.persistenceType= persistenceType;
+ this.editorType= editorType;
+ }
+
+ public @Nullable String getType(final WorkingContext context) {
+ if (context == Ltk.PERSISTENCE_CONTEXT) {
+ return this.persistenceType;
+ }
+ if (context == Ltk.EDITOR_CONTEXT) {
+ return this.editorType;
+ }
+ return null;
+ }
+
+ }
+
+
+ private final String sourceId;
+
+ private final TaskTypeDef taskTypeDef;
+
+ private final ImList<ProblemTypeDef> problemTypeDefs;
+
+
+ public IssueTypeSet(final String sourceId,
+ final TaskTypeDef taskTypeDef,
+ final ImList<ProblemTypeDef> problemTypeDefs) {
+ this.sourceId= sourceId;
+ this.taskTypeDef= taskTypeDef;
+ this.problemTypeDefs= problemTypeDefs;
+ }
+
+
+ public String getSourceId() {
+ return this.sourceId;
+ }
+
+ public TaskTypeDef getTaskCategory() {
+ return this.taskTypeDef;
+ }
+
+ public ImList<ProblemTypeDef> getProblemCategories() {
+ return this.problemTypeDefs;
+ }
+
+ public @Nullable ProblemTypeDef getProblemCategory(final String categoryId) {
+ for (final var problemCategory : this.problemTypeDefs) {
+ if (problemCategory.id == categoryId) {
+ return problemCategory;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/issues/core/impl/BasicIssueRequestor.java b/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/issues/core/impl/BasicIssueRequestor.java
new file mode 100644
index 0000000..4157a6e
--- /dev/null
+++ b/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/issues/core/impl/BasicIssueRequestor.java
@@ -0,0 +1,237 @@
+/*=============================================================================#
+ # 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.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.statet.jcommons.collections.ImCollections;
+import org.eclipse.statet.jcommons.collections.ImList;
+import org.eclipse.statet.jcommons.lang.NonNullByDefault;
+import org.eclipse.statet.jcommons.lang.Nullable;
+import org.eclipse.statet.jcommons.status.StatusException;
+import org.eclipse.statet.jcommons.status.eplatform.EStatusUtils;
+
+import org.eclipse.statet.ltk.core.WorkingContext;
+import org.eclipse.statet.ltk.issues.core.IssueRequestor;
+import org.eclipse.statet.ltk.issues.core.IssueTypeSet;
+import org.eclipse.statet.ltk.issues.core.IssueTypeSet.ProblemTypeDef;
+import org.eclipse.statet.ltk.issues.core.IssueTypeSet.TaskTypeDef;
+import org.eclipse.statet.ltk.issues.core.Problem;
+import org.eclipse.statet.ltk.issues.core.Task;
+
+
+@NonNullByDefault
+public abstract class BasicIssueRequestor implements IssueRequestor {
+
+ private static final int STATE_OPEN= 1;
+ private static final int STATE_FINISHING= 2;
+ private static final int STATE_FINISHED= 3;
+
+
+ public final static class ProblemCategory {
+
+ private final String id;
+ private final ProblemTypeDef def;
+
+ private final boolean isEnabled;
+
+ private final List<Problem> acceptedIssues= new ArrayList<>();
+
+
+ public ProblemCategory(final ProblemTypeDef def, final boolean isEnabled) {
+ this.id= def.getId();
+ this.def= def;
+ this.isEnabled= isEnabled;
+ }
+
+
+ public String getId() {
+ return this.id;
+ }
+
+ public ProblemTypeDef getDef() {
+ return this.def;
+ }
+
+ public List<Problem> getAcceptedIssues() {
+ return this.acceptedIssues;
+ }
+
+ }
+
+ public final static class TaskCategory {
+
+ private final TaskTypeDef def;
+
+ private final boolean isEnabled;
+
+ private final List<Task> acceptedIssues= new ArrayList<>();
+
+
+ public TaskCategory(final TaskTypeDef def, final boolean isEnabled) {
+ this.def= def;
+ this.isEnabled= isEnabled;
+ }
+
+
+ public TaskTypeDef getDef() {
+ return this.def;
+ }
+
+ public List<Task> getAcceptedIssues() {
+ return this.acceptedIssues;
+ }
+
+ }
+
+
+ private final IssueTypeSet issueTypeSet;
+
+ private final ImList<ProblemCategory> problemCategories;
+ private final @Nullable TaskCategory taskCategory;
+
+ private int state= 1;
+
+
+ public BasicIssueRequestor(final IssueTypeSet issueTypeSet,
+ final WorkingContext workingContext) {
+ this.issueTypeSet= issueTypeSet;
+
+ this.problemCategories= createProblemCategories(issueTypeSet.getProblemCategories(),
+ workingContext );
+ this.taskCategory= createTaskCategories(issueTypeSet.getTaskCategory(),
+ workingContext );
+ }
+
+
+ protected ImList<ProblemCategory> createProblemCategories(final ImList<ProblemTypeDef> defs,
+ final WorkingContext requiredWorkingSet) {
+ final var list= new ArrayList<ProblemCategory>(defs.size());
+ for (final var problemTypeDef : defs) {
+ if (problemTypeDef.getTypes(requiredWorkingSet) != null) {
+ list.add(new ProblemCategory(problemTypeDef, shouldAccept(problemTypeDef)));
+ }
+ }
+ return ImCollections.toList(list);
+ }
+
+ protected boolean shouldAccept(final ProblemTypeDef def) {
+ return true;
+ }
+
+ protected @Nullable TaskCategory createTaskCategories(final @Nullable TaskTypeDef def,
+ final WorkingContext requiredWorkingSet) {
+ if (def != null && def.getType(requiredWorkingSet) != null) {
+ return new TaskCategory(def, shouldAccept(def));
+ }
+ return null;
+ }
+
+ protected boolean shouldAccept(final TaskTypeDef def) {
+ return true;
+ }
+
+
+ public IssueTypeSet getIssueTypeSet() {
+ return this.issueTypeSet;
+ }
+
+ protected final ImList<ProblemCategory> getProblemCategories() {
+ return this.problemCategories;
+ }
+
+ protected final @Nullable ProblemCategory getProblemCategory(final String id) {
+ for (final var category : this.problemCategories) {
+ if (category.id == id) {
+ return category;
+ }
+ }
+ return null;
+ }
+
+ protected final @Nullable TaskCategory getTaskCategory() {
+ return this.taskCategory;
+ }
+
+
+ @Override
+ public boolean isInterestedInProblems(final String categoryId) {
+ final var category= getProblemCategory(categoryId);
+ return (category != null && category.isEnabled);
+ }
+
+ @Override
+ public void acceptProblems(final Problem problem) {
+ final var category= getProblemCategory(problem.getCategoryId());
+ if (category != null && category.isEnabled) {
+ category.acceptedIssues.add(problem);
+ }
+ }
+
+ @Override
+ public void acceptProblems(final String categoryId, final List<Problem> problems) {
+ final var category= getProblemCategory(categoryId);
+ if (category != null && category.isEnabled) {
+ category.acceptedIssues.addAll(problems);
+ }
+ }
+
+
+ @Override
+ public boolean isInterestedInTasks() {
+ final var category= getTaskCategory();
+ return (category != null && category.isEnabled);
+ }
+
+ @Override
+ public void acceptTask(final Task task) {
+ final var category= getTaskCategory();
+ if (category != null && category.isEnabled) {
+ category.acceptedIssues.add(task);
+ }
+ }
+
+
+ @Override
+ public void finish() throws StatusException {
+ if (this.state != STATE_OPEN) {
+ throw new IllegalStateException("Already finished");
+ }
+ this.state= STATE_FINISHING;
+
+ try {
+ reportProblems(this.problemCategories);
+ reportTasks(this.taskCategory);
+ }
+ catch (final CoreException e) {
+ throw EStatusUtils.convert(e);
+ }
+ finally {
+ this.state= STATE_FINISHED;
+ }
+ }
+
+
+ protected abstract void reportProblems(final ImList<ProblemCategory> problemCategories)
+ throws CoreException;
+
+ protected abstract void reportTasks(final @Nullable TaskCategory taskCategory)
+ throws CoreException;
+
+
+}
diff --git a/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/issues/core/impl/ResourceMarkerIssueRequestor.java b/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/issues/core/impl/ResourceMarkerIssueRequestor.java
new file mode 100644
index 0000000..16d63c6
--- /dev/null
+++ b/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/issues/core/impl/ResourceMarkerIssueRequestor.java
@@ -0,0 +1,121 @@
+/*=============================================================================#
+ # 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.impl;
+
+import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullAssert;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.statet.jcommons.collections.ImList;
+import org.eclipse.statet.jcommons.lang.NonNullByDefault;
+import org.eclipse.statet.jcommons.lang.Nullable;
+
+import org.eclipse.statet.ltk.core.Ltk;
+import org.eclipse.statet.ltk.issues.core.IssueMarkers;
+import org.eclipse.statet.ltk.issues.core.IssueTypeSet;
+import org.eclipse.statet.ltk.issues.core.IssueTypeSet.ProblemTypes;
+import org.eclipse.statet.ltk.issues.core.Problem;
+import org.eclipse.statet.ltk.issues.core.Task;
+
+
+@NonNullByDefault
+public class ResourceMarkerIssueRequestor extends BasicIssueRequestor {
+
+
+ public static @Nullable ResourceMarkerIssueRequestor create(final @Nullable Object resource,
+ final IssueTypeSet issueTypeSet) {
+ if (resource instanceof IFile) {
+ return new ResourceMarkerIssueRequestor((IFile)resource, issueTypeSet);
+ }
+ return null;
+ }
+
+
+ private final IFile resource;
+
+
+ public ResourceMarkerIssueRequestor(final IFile file, final IssueTypeSet issueTypeSet) {
+ super(issueTypeSet, Ltk.PERSISTENCE_CONTEXT);
+
+ this.resource= file;
+ }
+
+
+ @Override
+ protected void reportProblems(final ImList<ProblemCategory> problemCategories) throws CoreException {
+ for (final var problemCategory : problemCategories) {
+ final ProblemTypes types= nonNullAssert(
+ problemCategory.getDef().getTypes(Ltk.PERSISTENCE_CONTEXT) );
+ for (final var problem : problemCategory.getAcceptedIssues()) {
+ final var attributes= createProblemAttributes(problem);
+ this.resource.createMarker(types.getType(problem.getSeverity()), attributes);
+ }
+ }
+ }
+
+ protected Map<String, Object> createProblemAttributes(final Problem problem) {
+ final var attributes= new HashMap<String, Object>(10);
+ attributes.put(IMarker.SOURCE_ID, getIssueTypeSet().getSourceId());
+ attributes.put(IssueMarkers.CATEGORY_ID_ATTR_NAME, problem.getCategoryId());
+ attributes.put(IMarker.SEVERITY, IssueMarkers.toMarkerSeverity(problem.getSeverity()));
+ attributes.put(IssueMarkers.CODE_ATTR_NAME, problem.getCode());
+ attributes.put(IMarker.MESSAGE, problem.getMessage());
+
+ attributes.put(IMarker.LINE_NUMBER, (problem.getSourceLine() > 0) ? problem.getSourceLine() : 1);
+ if (problem.getSourceStartOffset() >= 0) {
+ attributes.put(IMarker.CHAR_START, problem.getSourceStartOffset());
+ attributes.put(IMarker.CHAR_END, problem.getSourceEndOffset());
+ }
+ attributes.put(IMarker.USER_EDITABLE, false);
+
+ return attributes;
+ }
+
+
+ @Override
+ protected void reportTasks(final @Nullable TaskCategory taskCategory) throws CoreException {
+ if (taskCategory != null) {
+ final String type= nonNullAssert(
+ taskCategory.getDef().getType(Ltk.PERSISTENCE_CONTEXT) );
+ for (final var task : taskCategory.getAcceptedIssues()) {
+ final var attributes= createTaskAttributes(task);
+ this.resource.createMarker(type, attributes);
+ }
+ }
+ }
+
+ protected Map<String, Object> createTaskAttributes(final Task task) {
+ final var attributes= new HashMap<String, Object>(10);
+ attributes.put(IMarker.SOURCE_ID, getIssueTypeSet().getSourceId());
+ attributes.put(IMarker.PRIORITY, IssueMarkers.toMarkerPriority(task.getPriority()));
+ attributes.put(IMarker.MESSAGE, task.getMessage());
+
+ attributes.put(IMarker.LINE_NUMBER, (task.getSourceLine() > 0) ? task.getSourceLine() : 1);
+ if (task.getSourceStartOffset() >= 0) {
+ attributes.put(IMarker.CHAR_START, task.getSourceStartOffset());
+ attributes.put(IMarker.CHAR_END, task.getSourceEndOffset());
+ }
+ attributes.put(IMarker.USER_EDITABLE, false);
+
+ return attributes;
+ }
+
+
+}
diff --git a/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/issues/core/impl/TaskTagReporter.java b/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/issues/core/impl/TaskTagReporter.java
new file mode 100644
index 0000000..70765ef
--- /dev/null
+++ b/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/issues/core/impl/TaskTagReporter.java
@@ -0,0 +1,120 @@
+/*=============================================================================#
+ # 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.issues.core.impl;
+
+import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullAssert;
+import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullLateInit;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.statet.jcommons.lang.NonNullByDefault;
+import org.eclipse.statet.jcommons.lang.Nullable;
+
+import org.eclipse.statet.ltk.core.SourceContent;
+import org.eclipse.statet.ltk.issues.core.IssueRequestor;
+import org.eclipse.statet.ltk.issues.core.TaskPriority;
+import org.eclipse.statet.ltk.issues.core.TaskTag;
+
+
+@NonNullByDefault
+public abstract class TaskTagReporter {
+
+
+ private @Nullable Pattern taskTagPattern;
+ private final Map<String, TaskPriority> taskTagMap= new HashMap<>();
+
+ private SourceContent sourceContent= nonNullLateInit();
+
+ private IssueRequestor requestor= nonNullLateInit();
+
+ private @Nullable Matcher taskTagMatcher;
+
+
+ public TaskTagReporter() {
+ }
+
+
+ protected void initTaskPattern(final List<TaskTag> taskTags) {
+ this.taskTagPattern= null;
+ this.taskTagMap.clear();
+
+ if (taskTags.isEmpty()) {
+ return;
+ }
+
+ final String separatorRegex= "[^\\p{L}\\p{N}]"; //$NON-NLS-1$
+ final StringBuilder regex= new StringBuilder(separatorRegex);
+ regex.append('(');
+ for (final TaskTag taskTag : taskTags) {
+ regex.append(Pattern.quote(taskTag.getKeyword()));
+ regex.append('|');
+ this.taskTagMap.put(taskTag.getKeyword(), taskTag.getPriority());
+ }
+ regex.setCharAt(regex.length() - 1, ')');
+ regex.append("(?:\\z|").append(separatorRegex).append(")"); //$NON-NLS-1$ //$NON-NLS-2$
+ this.taskTagPattern= Pattern.compile(regex.toString());
+ }
+
+
+ public void setup(final SourceContent sourceContent, final IssueRequestor requestor) {
+ this.sourceContent= nonNullAssert(sourceContent);
+ this.requestor= nonNullAssert(requestor);
+
+ final Pattern taskTagPattern= this.taskTagPattern;
+ this.taskTagMatcher= (taskTagPattern != null && sourceContent.getStartOffset() == 0) ?
+ taskTagPattern.matcher(sourceContent.getString()) :
+ null;
+ }
+
+ public void addTask(final String match, final String message,
+ final int offset, final int lineNumber) {
+ final TaskPriority priority= this.taskTagMap.get(match);
+ if (priority == null) {
+ return;
+ }
+
+ final var task= new BasicTask(priority, message,
+ lineNumber, offset, offset + message.length() );
+ this.requestor.acceptTask(task);
+ }
+
+ public void checkForTasks(final int startOffset, int endOffset) {
+ final Matcher matcher= this.taskTagMatcher;
+ if (matcher == null) {
+ return;
+ }
+ if (matcher.region(startOffset, endOffset).find()) {
+ final int tagStartOffset= matcher.start(1);
+ final int tagEndOffset= matcher.end(1);
+ while (endOffset > tagEndOffset) {
+ if (this.sourceContent.getChar(endOffset - 1) <= ' ') {
+ endOffset--;
+ continue;
+ }
+ else {
+ break;
+ }
+ }
+ final String text= this.sourceContent.getString(tagStartOffset, endOffset);
+ addTask(nonNullAssert(matcher.group(1)), text, tagStartOffset,
+ this.sourceContent.getStringLines().getLineOfOffset(tagStartOffset) + 1 );
+ }
+ }
+
+}
diff --git a/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/model/core/build/SourceUnitModelContainer.java b/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/model/core/build/SourceUnitModelContainer.java
index 60016fc..031e5b5 100644
--- a/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/model/core/build/SourceUnitModelContainer.java
+++ b/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/model/core/build/SourceUnitModelContainer.java
@@ -26,6 +26,8 @@
import org.eclipse.statet.ltk.core.SourceContent;
import org.eclipse.statet.ltk.core.WorkingContext;
import org.eclipse.statet.ltk.issues.core.IssueRequestor;
+import org.eclipse.statet.ltk.issues.core.IssueTypeSet;
+import org.eclipse.statet.ltk.issues.core.impl.ResourceMarkerIssueRequestor;
import org.eclipse.statet.ltk.model.core.ModelManager;
import org.eclipse.statet.ltk.model.core.element.SourceUnit;
import org.eclipse.statet.ltk.model.core.element.SourceUnitModelInfo;
@@ -55,6 +57,10 @@
public abstract Class<?> getAdapterClass();
+ public @Nullable IssueTypeSet getIssueTypeSet() {
+ return null;
+ }
+
protected @Nullable WorkingContext getMode(final TSourceUnit su) {
if (su instanceof WorkspaceSourceUnit) {
@@ -147,6 +153,13 @@
public @Nullable IssueRequestor createIssueRequestor() {
+ final var mode= getMode();
+ if (mode == Ltk.PERSISTENCE_CONTEXT) {
+ final IssueTypeSet issueTypeSet= getIssueTypeSet();
+ if (issueTypeSet != null) {
+ return ResourceMarkerIssueRequestor.create(getSourceUnit().getResource(), issueTypeSet);
+ }
+ }
return null;
}
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceAnnotationModel.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceAnnotationModel.java
index 0b6951a..bffda2a 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceAnnotationModel.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceAnnotationModel.java
@@ -14,23 +14,34 @@
package org.eclipse.statet.ltk.ui.sourceediting;
+import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullAssert;
+
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Position;
import org.eclipse.ui.texteditor.ResourceMarkerAnnotationModel;
+import org.eclipse.statet.jcommons.collections.ImList;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
+import org.eclipse.statet.ltk.core.Ltk;
+import org.eclipse.statet.ltk.core.WorkingContext;
import org.eclipse.statet.ltk.issues.core.Issue;
import org.eclipse.statet.ltk.issues.core.IssueRequestor;
+import org.eclipse.statet.ltk.issues.core.IssueTypeSet;
+import org.eclipse.statet.ltk.issues.core.IssueTypeSet.ProblemTypeDef;
+import org.eclipse.statet.ltk.issues.core.IssueTypeSet.ProblemTypes;
+import org.eclipse.statet.ltk.issues.core.IssueTypeSet.TaskTypeDef;
import org.eclipse.statet.ltk.issues.core.Problem;
-import org.eclipse.statet.ltk.issues.core.Task;
+import org.eclipse.statet.ltk.issues.core.impl.BasicIssueRequestor;
+import org.eclipse.statet.ltk.ui.sourceediting.SourceProblemAnnotation.PresentationConfig;
/**
@@ -41,50 +52,51 @@
public abstract class SourceAnnotationModel extends ResourceMarkerAnnotationModel {
- protected class SourceAnnotationIssueRequestor implements IssueRequestor {
+ protected class SourceAnnotationIssueRequestor extends BasicIssueRequestor {
- protected final List<Problem> reportedProblems= new ArrayList<>();
-
- protected final boolean handleTemporaryProblems;
-
- private int state= 1;
+ protected boolean handleTemporaryProblems;
- public SourceAnnotationIssueRequestor() {
+ public SourceAnnotationIssueRequestor(final IssueTypeSet issueTypeSet) {
+ super(issueTypeSet, Ltk.EDITOR_CONTEXT);
+ }
+
+
+ @Override
+ protected ImList<ProblemCategory> createProblemCategories(final ImList<ProblemTypeDef> defs,
+ final WorkingContext requiredWorkingSet) {
this.handleTemporaryProblems= isHandlingTemporaryProblems();
+ return super.createProblemCategories(defs, requiredWorkingSet);
+ }
+
+ @Override
+ protected boolean shouldAccept(final ProblemTypeDef def) {
+ return this.handleTemporaryProblems;
+ }
+
+ @Override
+ protected boolean shouldAccept(final TaskTypeDef def) {
+ return false;
}
@Override
- public void acceptProblems(final Problem problem) {
- if (this.handleTemporaryProblems) {
- this.reportedProblems.add(problem);
- }
+ protected void reportProblems(final ImList<ProblemCategory> problemCategories)
+ throws CoreException {
+ SourceAnnotationModel.this.reportProblems(problemCategories);
}
@Override
- public void acceptProblems(final String modelTypeId, final List<Problem> problems) {
- if (this.handleTemporaryProblems) {
- this.reportedProblems.addAll(problems);
- }
- }
-
- @Override
- public void acceptTask(final Task task) {
- }
-
- @Override
- public void finish() {
- if (this.state < 0) {
- throw new IllegalStateException("Already finished");
- }
- this.state= -1;
- reportProblems(this.reportedProblems);
+ protected void reportTasks(final @Nullable TaskCategory taskCategory)
+ throws CoreException {
}
}
+
+ private final IssueTypeSet issueTypeSet;
+
private final AtomicInteger reportingCounter= new AtomicInteger();
private final List<SourceProblemAnnotation> problemAnnotations= new ArrayList<>();
@@ -94,8 +106,14 @@
// private List currentlyOverlaid= new ArrayList();
- public SourceAnnotationModel(final IResource resource) {
+ public SourceAnnotationModel(final IResource resource, final IssueTypeSet issueTypeSet) {
super(resource);
+ this.issueTypeSet= issueTypeSet;
+ }
+
+
+ protected IssueTypeSet getIssueTypeSet() {
+ return this.issueTypeSet;
}
protected abstract boolean isHandlingTemporaryProblems();
@@ -118,7 +136,7 @@
}
protected IssueRequestor doCreateIssueRequestor() {
- return new SourceAnnotationIssueRequestor();
+ return new SourceAnnotationIssueRequestor(getIssueTypeSet());
}
public void clearProblems(final @Nullable String category) {
@@ -149,7 +167,7 @@
}
}
- private void reportProblems(final List<Problem> reportedProblems) {
+ private void reportProblems(final ImList<BasicIssueRequestor.ProblemCategory> problemCategories) {
boolean reportedIssuesChanged= false;
synchronized (getLockObject()) {
@@ -165,12 +183,16 @@
this.problemAnnotations.clear();
}
- if (reportedProblems != null && reportedProblems.size() > 0) {
- for (final Problem problem : reportedProblems) {
+ for (final var problemCategory : problemCategories) {
+ final ProblemTypes types= nonNullAssert(
+ problemCategory.getDef().getTypes(Ltk.EDITOR_CONTEXT) );
+ for (final Problem problem : problemCategory.getAcceptedIssues()) {
final Position position= createPosition(problem);
if (position != null) {
try {
- final SourceProblemAnnotation annotation= createAnnotation(problem);
+ final var annotation= new SourceProblemAnnotation(
+ types.getType(problem.getSeverity()), problem,
+ getPresentationConfig(problem) );
// overlayMarkers(position, annotation);
if (annotation != null) {
addAnnotation(annotation, position, false);
@@ -237,8 +259,15 @@
return new Position(start, end-start);
}
- protected @Nullable SourceProblemAnnotation createAnnotation(final Problem problem) {
- return null;
+ protected PresentationConfig getPresentationConfig(final Problem problem) {
+ switch (problem.getSeverity()) {
+ case Problem.SEVERITY_ERROR:
+ return SourceProblemAnnotation.ERROR_CONFIG;
+ case Problem.SEVERITY_WARNING:
+ return SourceProblemAnnotation.WARNING_CONFIG;
+ default:
+ return SourceProblemAnnotation.INFO_CONFIG;
+ }
}
// @Override
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceProblemAnnotation.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceProblemAnnotation.java
index 49a595a..ebe629a 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceProblemAnnotation.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceProblemAnnotation.java
@@ -29,12 +29,16 @@
import org.eclipse.ui.texteditor.AnnotationPreference;
import org.eclipse.ui.texteditor.DefaultMarkerAnnotationAccess;
+import org.eclipse.statet.jcommons.lang.NonNullByDefault;
+import org.eclipse.statet.jcommons.lang.Nullable;
+
import org.eclipse.statet.ltk.issues.core.Problem;
/**
* Annotation representing an {@link Problem}.
*/
+@NonNullByDefault
public class SourceProblemAnnotation extends Annotation
implements IAnnotationPresentation, IQuickFixableAnnotation {
@@ -46,8 +50,8 @@
private final int level;
- private String imageKey;
- private Image image;
+ private @Nullable String imageKey;
+ private @Nullable Image image;
private PresentationConfig(final String referenceType, final int levelDiff) {
@@ -75,11 +79,14 @@
return this.level;
}
- public final Image getImage() {
- if (this.image == null && this.imageKey != null) {
- this.image= PlatformUI.getWorkbench().getSharedImages().getImage(this.imageKey);
+ public final @Nullable Image getImage() {
+ Image image= this.image;
+ final String key;
+ if (image == null && (key= this.imageKey) != null) {
+ image= PlatformUI.getWorkbench().getSharedImages().getImage(key);
+ this.image= image;
}
- return this.image;
+ return image;
}
}