diff --git a/org.eclipse.titan.designer/META-INF/MANIFEST.MF b/org.eclipse.titan.designer/META-INF/MANIFEST.MF index d7d254911be328a67c9cb543029b8eabe464214e..37c9ab1a15733700c5c41c6cefe733ce3da9238c 100644 --- a/org.eclipse.titan.designer/META-INF/MANIFEST.MF +++ b/org.eclipse.titan.designer/META-INF/MANIFEST.MF @@ -34,7 +34,8 @@ Require-Bundle: org.eclipse.ui, org.eclipse.jdt.launching;bundle-version="2.0.0", org.eclipse.jdt.ui, org.eclipse.titan.common, - org.eclipse.collections;bundle-version="10.4.0" + org.eclipse.collections;bundle-version="10.4.0", + org.eclipse.jgit;bundle-version="5.11.0" Bundle-ActivationPolicy: lazy Eclipse-LazyStart: true Bundle-ClassPath: . diff --git a/org.eclipse.titan.designer/src/org/eclipse/titan/designer/editors/ttcn3editor/TTCN3Editor.java b/org.eclipse.titan.designer/src/org/eclipse/titan/designer/editors/ttcn3editor/TTCN3Editor.java index c273aaa2c54f4818dd1ff65f6b649d1fdfd5dc29..fa35023afd6ebb19decc1804ddf44aff11188892 100644 --- a/org.eclipse.titan.designer/src/org/eclipse/titan/designer/editors/ttcn3editor/TTCN3Editor.java +++ b/org.eclipse.titan.designer/src/org/eclipse/titan/designer/editors/ttcn3editor/TTCN3Editor.java @@ -7,9 +7,13 @@ ******************************************************************************/ package org.eclipse.titan.designer.editors.ttcn3editor; +import java.io.File; +import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.resources.WorkspaceJob; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; @@ -20,7 +24,9 @@ import org.eclipse.core.runtime.preferences.IPreferencesService; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.Position; import org.eclipse.jface.text.TextSelection; import org.eclipse.jface.text.reconciler.IReconcilingStrategy; @@ -40,6 +46,14 @@ import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TreePath; import org.eclipse.jface.viewers.TreeSelection; +import org.eclipse.jgit.api.BlameCommand; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.blame.BlameResult; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.storage.file.FileRepositoryBuilder; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.titan.designer.Activator; @@ -49,6 +63,7 @@ import org.eclipse.titan.designer.AST.TTCN3.definitions.ICommentable; import org.eclipse.titan.designer.declarationsearch.Declaration; import org.eclipse.titan.designer.declarationsearch.IdentifierFinderVisitor; import org.eclipse.titan.designer.editors.AstSyntaxHighlightTokens; +import org.eclipse.titan.designer.editors.CodeMiningMaps; import org.eclipse.titan.designer.editors.ColorManager; import org.eclipse.titan.designer.editors.EditorTracker; import org.eclipse.titan.designer.editors.FoldingSupport; @@ -66,6 +81,7 @@ import org.eclipse.titan.designer.productUtilities.ProductConstants; import org.eclipse.ui.IEditorDescriptor; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IPartListener; +import org.eclipse.ui.ISharedImages; import org.eclipse.ui.IViewPart; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchActionConstants; @@ -96,6 +112,7 @@ public final class TTCN3Editor extends AbstractDecoratedTextEditor implements IS private static final String TOGGLE_COMMENT_ACTION_ID = ProductConstants.PRODUCT_ID_DESIGNER + ".editors.ttcn3editor.ToggleComment"; private final long DOC_COMMENT_VIEW_REFRESH_DELAY = 500L; + private final long MINING_REFRESH_DELAY = 1000L; private ProjectionSupport projectionSupport; private List oldAnnotations = new ArrayList(); @@ -105,8 +122,10 @@ public final class TTCN3Editor extends AbstractDecoratedTextEditor implements IS private ProjectionViewer projectionViewer; private OutlinePage outlinePage; private Reconciler reconciler; - private Job docCommentViewRefreshJob; + private Job miningRefreshJob; + private static int lastLine = -1; + /** list of editor parts that are open in this in editor */ private static List activeEditorParts = new ArrayList<>(); @@ -476,7 +495,61 @@ public final class TTCN3Editor extends AbstractDecoratedTextEditor implements IS } }); } - + + private void updateCodeMinings(final IFile file) { + try { + final int line = getDocument().getLineOfOffset(getCarretOffset()); + if (lastLine != line) { + if (lastLine != -1) { + final IRegion region = getDocument().getLineInformation(lastLine); + CodeMiningMaps.removeContentMining(file.getFullPath().toOSString(), region.getOffset() + region.getLength()); + } + + if (miningRefreshJob != null) { + if (miningRefreshJob.getState() != Job.RUNNING) { + if (miningRefreshJob.cancel()) { + miningRefreshJob = null; + } else { + miningRefreshJob.schedule(MINING_REFRESH_DELAY); + return; + } + } + } + miningRefreshJob = new Job("code mining refresh job") { + @Override + protected IStatus run(IProgressMonitor monitor) { + final Display display = PlatformUI.getWorkbench().getDisplay(); + if (monitor.isCanceled() || display.isDisposed()) { + return Status.CANCEL_STATUS; + } + display.syncExec(() -> { + try { + final IRegion miningRegion = getDocument().getLineInformation(line); + final String text = getCommitText(file, line); + if (text == null) { + return; + } + final Position position = new Position(miningRegion.getOffset() + miningRegion.getLength(), text.length()); + CodeMiningMaps.addContentMining(file.getFullPath().toOSString(), position, text, + PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_TOOL_COPY)); + ((ISourceViewerExtension5)getSourceViewer()).updateCodeMinings(); + lastLine = line; + } catch (BadLocationException e) { + e.printStackTrace(); + } + }); + return Status.OK_STATUS; + } + }; + miningRefreshJob.setSystem(false); + miningRefreshJob.setPriority(Job.INTERACTIVE); + miningRefreshJob.schedule(MINING_REFRESH_DELAY); + } + } catch (BadLocationException e) { + e.printStackTrace(); + } + } + @Override protected void handleCursorPositionChanged() { super.handleCursorPositionChanged(); @@ -496,6 +569,8 @@ public final class TTCN3Editor extends AbstractDecoratedTextEditor implements IS return; } + updateCodeMinings(file); + // update document comment view if (docCommentViewRefreshJob != null) { if (docCommentViewRefreshJob.getState() != Job.RUNNING) { @@ -503,9 +578,9 @@ public final class TTCN3Editor extends AbstractDecoratedTextEditor implements IS docCommentViewRefreshJob = null; } else { docCommentViewRefreshJob.schedule(DOC_COMMENT_VIEW_REFRESH_DELAY); + return; } } - return; } docCommentViewRefreshJob = new Job("doc comment refresh job") { @Override @@ -674,4 +749,37 @@ public final class TTCN3Editor extends AbstractDecoratedTextEditor implements IS public static List getActiveEditorParts() { return activeEditorParts; } + + private String getCommitText(IFile file, int line) { + final IWorkspace workspace = ResourcesPlugin.getWorkspace(); + final File workspaceDirectory = workspace.getRoot().getLocation().toFile(); + final String parentDir = file.getParent().getFullPath().toOSString(); + final String gitPath = workspaceDirectory.getPath() + File.separator + parentDir + File.separator + ".git"; + FileRepositoryBuilder builder = new FileRepositoryBuilder(); + try { + Repository repository = builder.setGitDir(new File(gitPath)) + .readEnvironment().findGitDir().build(); + if (repository == null) { + return null; + } + BlameCommand bc = new BlameCommand(repository); + ObjectId head = repository.resolve("HEAD"); + if (head == null) { + return null; + } + bc.setStartCommit(head); + bc.setFilePath(file.getName()); + BlameResult lines = bc.call(); + if (lines == null) { + return null; + } + PersonIdent author = lines.getSourceAuthor(line); + RevCommit commit = lines.getSourceCommit(line); + return "[" + author.getEmailAddress() + "," + author.getWhen() + " " + commit.getShortMessage() + "]"; + + } catch (IOException | GitAPIException e) { + e.printStackTrace(); + } + return null; + } }