1 /*******************************************************************************
2 * Copyright (C) 2017, Stefan Rademacher <stefan.rademacher@tk.de>
5 * All rights reserved. This program and the accompanying materials
6 * are made available under the terms of the Eclipse Public License v1.0
7 * which accompanies this distribution, and is available at
8 * http://www.eclipse.org/legal/epl-v10.html
9 *******************************************************************************/
10 package org
.eclipse
.egit
.ui
.internal
.dialogs
;
12 import java
.text
.MessageFormat
;
13 import java
.util
.ArrayList
;
14 import java
.util
.Arrays
;
15 import java
.util
.Collection
;
16 import java
.util
.HashSet
;
17 import java
.util
.List
;
20 import org
.eclipse
.core
.resources
.IFile
;
21 import org
.eclipse
.core
.resources
.IResource
;
22 import org
.eclipse
.core
.runtime
.CoreException
;
23 import org
.eclipse
.core
.runtime
.IConfigurationElement
;
24 import org
.eclipse
.core
.runtime
.Platform
;
25 import org
.eclipse
.egit
.core
.internal
.util
.ProjectUtil
;
26 import org
.eclipse
.egit
.core
.internal
.util
.ResourceUtil
;
27 import org
.eclipse
.egit
.ui
.Activator
;
28 import org
.eclipse
.egit
.ui
.CommitMessageWithCaretPosition
;
29 import org
.eclipse
.egit
.ui
.ICommitMessageProvider
;
30 import org
.eclipse
.egit
.ui
.ICommitMessageProvider2
;
31 import org
.eclipse
.egit
.ui
.internal
.UIText
;
32 import org
.eclipse
.jgit
.annotations
.NonNull
;
33 import org
.eclipse
.jgit
.lib
.Repository
;
35 class CommitMessageBuilder
{
38 * Constant for the extension point for the commit message provider.
40 private static final String COMMIT_MESSAGE_PROVIDER_ID
= "org.eclipse.egit.ui.commitMessageProvider"; //$NON-NLS-1$
42 private static final String MESSAGE_SEPARATOR
= "\n\n"; //$NON-NLS-1$
44 private final IResource
[] resourcesArray
;
47 private final Repository repository
;
49 private boolean isMessageEmpty
;
52 * Creates a CommitMessageBuilder for the specified repository and the
53 * files, that are about to be committed.
56 * the repository, messages are built for
58 * list of file paths, selected for the next commit
60 CommitMessageBuilder(@NonNull Repository repository
,
61 Collection
<String
> paths
) {
62 this.repository
= repository
;
63 this.resourcesArray
= toResourceArray(paths
);
67 * Returns an object, containing the commit message and the caret position
68 * within that message.
70 * @return a commit message with caret position. The caret position is 0, if
71 * there was no {@link ICommitMessageProvider2} providing a caret
74 CommitMessageWithCaretPosition
build() {
75 StringBuilder finalMessage
= new StringBuilder();
76 int caretPosition
= CommitMessageWithCaretPosition
.NO_POSITION
;
77 isMessageEmpty
= true;
79 for (ICommitMessageProvider provider
: getCommitMessageProviders()) {
80 String message
= ""; //$NON-NLS-1$
82 if (provider
instanceof ICommitMessageProvider2
) {
83 CommitMessageWithCaretPosition commitMessageWithPosition
= ((ICommitMessageProvider2
) provider
)
84 .getCommitMessageWithPosition(resourcesArray
);
85 if (commitMessageWithPosition
!= null) {
86 caretPosition
= updateCaretPosition(finalMessage
,
87 caretPosition
, commitMessageWithPosition
,
88 (ICommitMessageProvider2
) provider
);
90 message
= getCommitMessage(commitMessageWithPosition
);
93 provider
.getMessage(resourcesArray
));
95 } catch (RuntimeException e
) {
96 Activator
.logError(e
.getMessage(), e
);
98 finalMessage
.append(message
);
99 isMessageEmpty
= finalMessage
.length() == 0;
101 return new CommitMessageWithCaretPosition(finalMessage
.toString(),
102 Math
.max(0, caretPosition
));
105 private String
getCommitMessage(
106 CommitMessageWithCaretPosition messageWithPosition
) {
107 if (messageWithPosition
== null) {
108 return ""; //$NON-NLS-1$
110 return append(messageWithPosition
.getMessage());
114 private String
append(String msg
) {
115 StringBuilder returnMsg
= new StringBuilder();
116 if (msg
!= null && !msg
.trim().isEmpty()) {
117 if (!isMessageEmpty
) {
118 returnMsg
.append(MESSAGE_SEPARATOR
);
120 returnMsg
.append(msg
);
122 return returnMsg
.toString();
125 @SuppressWarnings("boxing")
126 private int updateCaretPosition(StringBuilder currentMessage
,
127 int currentCaretPosition
,
128 CommitMessageWithCaretPosition messageWithPosition
,
129 ICommitMessageProvider2 provider
) {
130 int pos
= currentCaretPosition
;
131 if (currentCaretPosition
== CommitMessageWithCaretPosition
.NO_POSITION
) {
132 String providedMessage
= messageWithPosition
.getMessage();
133 if (providedMessage
== null || providedMessage
.trim().isEmpty()) {
136 int providedCaretPosition
= messageWithPosition
137 .getDesiredCaretPosition();
138 if (providedCaretPosition
== CommitMessageWithCaretPosition
.NO_POSITION
) {
141 if (providedCaretPosition
> providedMessage
.length()
142 || providedCaretPosition
< 0) {
143 Activator
.logWarning(
144 MessageFormat
.format(
145 UIText
.CommitDialog_CaretPositionOutOfBounds
,
146 provider
.getClass().getName(),
147 providedCaretPosition
),
149 return CommitMessageWithCaretPosition
.NO_POSITION
;
152 pos
= currentMessage
.length();
153 if (currentMessage
.length() > 0) {
154 pos
+= MESSAGE_SEPARATOR
.length();
156 pos
+= providedCaretPosition
;
161 MessageFormat
.format(
162 UIText
.CommitDialog_IgnoreCaretPosition
,
163 provider
.getClass().getName()),
170 List
<ICommitMessageProvider
> getCommitMessageProviders() {
171 List
<ICommitMessageProvider
> providers
= new ArrayList
<>();
173 IConfigurationElement
[] configs
= Platform
.getExtensionRegistry()
174 .getConfigurationElementsFor(COMMIT_MESSAGE_PROVIDER_ID
);
175 for (IConfigurationElement config
: configs
) {
177 String contributorName
= "<unknown>"; //$NON-NLS-1$
178 String extensionId
= "<unknown>"; //$NON-NLS-1$
180 extensionId
= config
.getDeclaringExtension()
181 .getUniqueIdentifier();
182 contributorName
= config
.getContributor().getName();
183 provider
= config
.createExecutableExtension("class");//$NON-NLS-1$
184 if (provider
instanceof ICommitMessageProvider
) {
185 providers
.add((ICommitMessageProvider
) provider
);
188 MessageFormat
.format(
189 UIText
.CommitDialog_WrongTypeOfCommitMessageProvider
,
190 extensionId
, contributorName
),
193 } catch (CoreException
| RuntimeException e
) {
196 MessageFormat
.format(
197 UIText
.CommitDialog_ErrorCreatingCommitMessageProvider
,
198 extensionId
, contributorName
),
205 private IResource
[] toResourceArray(Collection
<String
> paths
) {
206 Set
<IResource
> resources
= new HashSet
<>();
207 for (String path
: paths
) {
210 file
= ResourceUtil
.getFileForLocation(repository
, path
,
214 resources
.add(file
.getProject());
217 if (resources
.size() == 0) {
220 .asList(ProjectUtil
.getProjects(repository
)));
222 return resources
.toArray(new IResource
[0]);