Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 1983efed1c8de0041c25492951d3fb01cbec7c7e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
/*******************************************************************************
 * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
 * Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com>
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *******************************************************************************/
package org.eclipse.egit.ui.internal.components;

import java.io.IOException;

import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.jface.fieldassist.IContentProposal;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectLoader;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTag;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.osgi.util.NLS;

/**
 * Content proposal class for refs names, specifically Ref objects - name with
 * optionally associated object id. This class can be used for Eclipse field
 * assist as content proposal.
 * <p>
 * Content of this proposal is simply a ref name, but description and labels
 * tries to be smarter - showing easier to read label for user (stripping
 * prefixes) and information about pointed object if it exists locally.
 */
public class RefContentProposal implements IContentProposal {
	private static final String PREFIXES[] = new String[] { Constants.R_HEADS,
			Constants.R_REMOTES, Constants.R_TAGS };

	private final static String branchPF = " ["   //$NON-NLS-1$
		+ UIText.RefContentProposal_branch
		+ "]";  //$NON-NLS-1$

	private final static String trackingBranchPF = " ["  //$NON-NLS-1$
		+ UIText.RefContentProposal_trackingBranch
		+ "]";  //$NON-NLS-1$

	private final static String tagPF = " ["  //$NON-NLS-1$
		+ UIText.RefContentProposal_tag
		+ "]"; //$NON-NLS-1$

	private static final String PREFIXES_DESCRIPTIONS[] = new String[] {
			branchPF, trackingBranchPF, tagPF };

	private static void appendObjectSummary(final StringBuilder sb,
			final String type, final PersonIdent author, final String message) {
		sb.append(type);
		if (author != null) {
			sb.append(" "); //$NON-NLS-1$
			sb.append(UIText.RefContentProposal_by);
			sb.append(" "); //$NON-NLS-1$
			sb.append(author.getName());
			sb.append("\n"); //$NON-NLS-1$
			sb.append(author.getWhen());
		}
		sb.append("\n\n");  //$NON-NLS-1$
		final int newLine = message.indexOf('\n');
		final int last = (newLine != -1 ? newLine : message.length());
		sb.append(message.substring(0, last));
	}

	private final Repository db;

	private final String refName;

	private final ObjectId objectId;

	/**
	 * Whether the ref is an upstream ref. For upstream refs, it's OK to have a
	 * missing object; it just means we haven't fetched yet.
	 */
	private final boolean upstream;

	/**
	 * Create content proposal for specified ref.
	 *
	 * @param repo
	 *            repository for accessing information about objects. Could be a
	 *            local repository even for remote objects.
	 * @param ref
	 *            ref being a content proposal. May have null or locally
	 *            non-existent object id.
	 * @param upstream
	 *            {@code true} if the ref comes from an upstream repository
	 */
	public RefContentProposal(Repository repo, Ref ref, boolean upstream) {
		this(repo, ref.getName(), ref.getObjectId(), upstream);
	}

	/**
	 * Create content proposal for specified ref name and object id.
	 *
	 * @param repo
	 *            repository for accessing information about objects. Could be a
	 *            local repository even for remote objects.
	 * @param refName
	 *            ref name being a content proposal.
	 * @param objectId
	 *            object being pointed by this ref name. May be null or locally
	 *            non-existent object.
	 * @param upstream
	 *            {@code true} if the ref comes from an upstream repository
	 */
	public RefContentProposal(Repository repo, String refName,
			ObjectId objectId, boolean upstream) {
		this.db = repo;
		this.refName = refName;
		this.objectId = objectId;
		this.upstream = upstream;
	}

	@Override
	public String getContent() {
		return refName;
	}

	@Override
	public int getCursorPosition() {
		return refName.length();
	}

	@Override
	public String getDescription() {
		if (objectId == null) {
			return null;
		} else if (upstream && objectId.equals(ObjectId.zeroId())) {
			return refName + '\n' + UIText.RefContentProposal_newRemoteObject;
		}
		try (ObjectReader reader = db.newObjectReader()) {
			ObjectLoader loader = null;
			try {
				loader = reader.open(objectId);
			} catch (MissingObjectException e) {
				if (upstream) {
					return refName + '\n' + objectId.abbreviate(7).name()
							+ " - " //$NON-NLS-1$
							+ UIText.RefContentProposal_unknownRemoteObject;
				}
				throw e;
			}
			final StringBuilder sb = new StringBuilder();
			sb.append(refName);
			sb.append('\n');
			sb.append(reader.abbreviate(objectId).name());
			sb.append(" - "); //$NON-NLS-1$

			switch (loader.getType()) {
			case Constants.OBJ_COMMIT:
				try (RevWalk rw = new RevWalk(db)) {
					RevCommit c = rw.parseCommit(objectId);
					appendObjectSummary(sb, UIText.RefContentProposal_commit,
							c.getAuthorIdent(), c.getFullMessage());
				}
				break;
			case Constants.OBJ_TAG:
				try (RevWalk rw = new RevWalk(db)) {
					RevTag t = rw.parseTag(objectId);
					appendObjectSummary(sb, UIText.RefContentProposal_tag,
							t.getTaggerIdent(), t.getFullMessage());
				}
				break;
			case Constants.OBJ_TREE:
				sb.append(UIText.RefContentProposal_tree);
				break;
			case Constants.OBJ_BLOB:
				sb.append(UIText.RefContentProposal_blob);
				break;
			default:
				sb.append(UIText.RefContentProposal_unknownObject);
			}
			return sb.toString();
		} catch (IOException e) {
			Activator.logError(NLS.bind(
					UIText.RefContentProposal_errorReadingObject, objectId,
					refName), e);
			return null;
		}
	}

	@Override
	public String getLabel() {
		for (int i = 0; i < PREFIXES.length; i++)
			if (refName.startsWith(PREFIXES[i]))
				return refName.substring(PREFIXES[i].length())
						+ PREFIXES_DESCRIPTIONS[i];
		return refName;

	}
}

Back to the top