Eclipse formatter: How to move comment between method name and open brace to always have open brace on same line as method declaration - eclipse

I have code that looks like this, that I'm trying to format
Original code:
public int doThing(int a) // -incredibly useful comment here
{
int ab = a+1;
return ab;
}
I want it to look like this
public int doThing() { // -incredibly useful comment here
int ab = a+1;
return ab;
}
If I try to turn on the Brace position -> Method Declaration -> Same line option and run the formatter, any code with a comment in the position "breaks" the formatter, and I get an output for my example that looks the same as the original code, but methods without a comment have the correct formatting (meaning the results are inconsistent).
Is it possible with the eclipse formatter to get the style I want? I'm trying to run it against a large amount of code, and would prefer not to have to fix these all manually to get a consistent brace position.

The problem here is that is not formatting but rewriting. Using File Search + regular expression + Replace could do that in bulk.
Try this regex
^(\s*(?:public|private|protected)\s+[^(]+\([^)]*\))(\s*\/\/[^/]+)\R\s*\{
On File Search ( Ctrl + H)
Hit Replace and use $1 { $2\n as replacement
Code should compile after the refactoring.
UPDATE:
Fixed regex part that represents function arguments
\([^)]*\)
Full Regex matches these cases
public int doSmthg() // coment here
{
return 1;
}
private String doSmthgElse(String arg) // coment here
{
return arg;
}

Related

TextCellEditor with autocomplete in Eclipse SWT/JFace?

I'd like a TextCellEditor with the standard auto-complete behaviour, that that any user nowadays expects when typing inside an input cell with a list of suggested strings. For a good working example of what I'm after, in Javascript, see this jQuery autocomplete widget.
I couldn't find a good example.
I only found (aside from some tiny variations) this TextCellEditorWithContentProposal snippet. But that leaves a lot to be desired:
It lists all the words, irrespective of the "partial word" typed in the cell (no partial matching)
When the desired word is selected, it is appended to the partial word, instead of replacing it
The interaction is ugly and non-intuitive. For example, one would expect the
Escape key to tear off the list of suggestions; again, see the Javascript example; here, it also removes the typed letters.
It looks strange to me that such an standard and useful component is not available. Or perhaps it is available? Can someone point to me to a more apt snippet or example?
The example you are linking to is a code snippet intended to showcase the API and guide you toward customizing the control to your preference.
Some of your complaints are either invalid or can easily be fixed using public API.
Let's go through them in detail.
All proposals are listed, irrespective of typed text
Note that in the snippet an org.eclipse.jface.fieldassist.SimpleContentProposalProvider is used:
IContentProposalProvider contentProposalProvider = new SimpleContentProposalProvider(new String[] { "red",
"green", "blue" });
cellEditor = new TextCellEditorWithContentProposal(viewer.getTable(), contentProposalProvider, null, null);
As suggested in its javadoc it is:
designed to map a static list of Strings to content proposals
To enable a simple filtering of the contents for the snippet, you could call: contentProposalProvider.setFiltering(true);
For anything more complex you will have to replace this with your own implementation of org.eclipse.jface.fieldassist.IContentProposalProvider.
Selection is appended to cell contents, instead of replacing it
The content proposal behavior is defined in the org.eclipse.jface.fieldassist.ContentProposalAdapter. Again a simple method call to org.eclipse.jface.fieldassist.ContentProposalAdapter.setProposalAcceptanceStyle(int) will achieve your target behavior:
contentProposalAdapter = new ContentProposalAdapter(text, new TextContentAdapter(), contentProposalProvider, keyStroke, autoActivationCharacters);
contentProposalAdapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE);
Cancelling the proposal should not remove typed content
This is hard to do using just the API, since the ContentProposalAdapter does only propagate the key strokes to the opened ContentProposalPopup without storing them.
You would have to subclass ContentProposalAdapter, in order to have access to ContentProposalAdapter.ContentProposalPopup.filterText.
Most of the functionality in this snippet with sensible defaults can also be obtained in a more simple way by using an org.eclipse.jface.fieldassist.AutoCompleteField.
Here is a snippet showing you a simple implementation. You have to customize it but it give you the way.
Note, this is not a generic copy/paste of the documentation or an explanation about the doc.
String[] contentProposals = {"text", "test", "generated"};
// simple content provider based on string array
SimpleContentProposalProvider provider = new SimpleContentProposalProvider(contentProposals);
// enable filtering or disabled it if you are using your own implementation
provider.setFiltering(false);
// content adapter with no keywords and caracters filtering
ContentProposalAdapter adapter = new ContentProposalAdapter(yourcontrolswt, new TextContentAdapter(), provider, null, null);
// you should not replace text content, you will to it bellow
adapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_IGNORE);
// now just put your implementation
adapter.addContentProposalListener(new IContentProposalListener() {
#Override
public void proposalAccepted(IContentProposal proposal) {
if(proposal != null && StringUtils.isNotBlank(proposal.getContent())){
// you need filter with blank spaces
String contentTextField = getFilterControl().getText();
String[] currentWords = getFilterControl().getText().split(" ");
StringBuilder textToDisplay = new StringBuilder();
if(currentWords.length > 1) {
// delete and replace last word
String lastWord = currentWords[currentWords.length-1];
textToDisplay.append(contentTextField.substring(0, contentTextField.length()-1-lastWord.length()));
textToDisplay.append(" ");
}
// add current proposal to control text content
textToDisplay.append(proposal.getContent());
yourcontrolswt.setText(textToDisplay.toString());
}
}
});
If you want more you can also have your own content proposal provider If you need a particular object instead of string or something like.
public class SubstringMatchContentProposalProvider implements IContentProposalProvider {
private List<String> proposals = Collections.emptyList();
#Override
public IContentProposal[] getProposals(String contents, int position) {
if (position == 0) {
return null;
}
String[] allWords = contents.split(" ");
// no words available
if(allWords.length == 0 || StringUtils.isBlank(allWords[allWords.length-1]))
return null;
// auto completion on last word found
String lastWordFound = allWords[allWords.length-1];
Pattern pattern = Pattern.compile(lastWordFound,
Pattern.LITERAL | Pattern.CASE_INSENSITIVE /*| Pattern.UNICODE_CASE*/); // this should be not used for better performances
IContentProposal[] filteredProposals = proposals.stream()
.filter(proposal -> proposal.length() >= lastWordFound.length() && pattern.matcher(proposal).find())
.map(ContentProposal::new).toArray(IContentProposal[]::new);
// no result
return filteredProposals.length == 0 ? null : filteredProposals;
}
public void setProposals(List<String> proposals) {
this.proposals = proposals;
}
}

NTriplesParser extract textual value from string

I am using dotnetrdf and trying to parse some triples with NTriplesParser. I have my own handler RobHandler in which I process each triple in turn.
public class RobHandler : BaseRdfHandler
{
protected override bool HandleTripleInternal(Triple t)
{
string predicateUrl = ((BaseUriNode)(t.Predicate)).Uri.AbsoluteUri;
string value = t.Object.ToString();
}
}
This works fine but I want to get the object minus the language. My objects look like "Lincoln"#en. I could obviously write some code to remove the #en bit, but I'd rather use some library code rather than my own that hard-coded strings like #en. To do this I think I need to create a LiteralNode but there doesn't seem to be a way to get from a string which is what I have (my variable value) to a LiteralNode.
How can I extract just the textual value from an object string?
Actually I think I have the answer myself:
if (t.Object.NodeType == NodeType.Literal)
{
var node = (ILiteralNode)t.Object;
}

eclipse ASTNode to source code line number

Given an ASTNode in eclipse, is there any way to get the corresponding source code line number?
You can get the line number of an ASTNode using the below code
int lineNumber = compilationUnit.getLineNumber(node.getStartPosition()) - 1;
the compilation unit can be obtained from the ASTParser using the below code
ASTParser parser = ASTParser.newParser(AST.JLS3);
// Parse the class as a compilation unit.
parser.setKind(ASTParser.K_COMPILATION_UNIT);
parser.setSource(source); // give your java source here as char array
parser.setResolveBindings(true);
// Return the compiled class as a compilation unit
CompilationUnit compilationUnit = parser.createAST(null);
Then you can use the ASTVisitor pattern to visit the type of required node (say MethodDeclaration node) using the below code:
compilationUnit.accept(new ASTVisitor() {
public boolean visit(MethodDeclaration node) {
int lineNumber = compilationUnit.getLineNumber(node.getStartPosition()) - 1;
return true;
}
});
ASTNode has getStartPosition() and getLength() methods which deal with character offsets. To convert from a character offset to a line number you should use CompilationUnit's getLineNumber() method. CompilationUnit is the root of your AST tree.
Apart from the general solution that has already been described, there is another one that applies if you need the line number of an ASTNode including leading whitespaces or potential comments written in front of the ASTNode. Then you can use:
int lineNumber = compilationUnit.getLineNumber(compilationUnit.getExtendedStartPosition(astNode))
See the API:
Returns the extended start position of the given node. Unlike ASTNode.getStartPosition() and ASTNode.getLength(), the extended source range may include comments and whitespace immediately before or after the normal source range for the node.

Is it possible with Eclipse to only find results in string literals?

Lets assume I have the following Java code:
public String foo()
{
// returns foo()
String log = "foo() : Logging something!"
return log;
}
Can I search in Eclipse for foo() occurring only in a String literal, but not anywhere else in the code? So in the example here Eclipse should only find the third occurrance of foo(), not the first one, which is a function name and not the second one, which is a comment.
Edit: Simple Regular Expressions won't work, because they will find foo() in a line like
String temp = "literal" + foo() + "another literal"
But here foo() is a function name and not a String literal.
You can try it like this:
"[^"\n]*foo\\(\\)[^"\n]*"
You have to escape brackets, plus this regex do not match new lines or additional quotes, which prevent wrong matches.
Maybe you should use regex to find any occurence of foo() between two " ?

Eclipse getter/setter format

Does anyone know of an Eclipse plug-in or method to get Eclipse to generate getter/setters on one line like this:
public String getAbc() { return abc; }
Instead of
public String getAbc() {
return abc;
}
I'm on Eclipse v. 3.2.2.
Thanks.
I don't know how to make Eclipse generate them in the format you want, but you could do a search/replace using these regular expressions after the methods are generated:
Find:
(?m)((?:public |private |protected )?[\w$]+) (get|set|is)([\w$]+)\(([\w$]+(?:\[\])? [\w$]+)?\) \{\s+(return [\w$]+;|this.[\w$]+ = [\w$]+;)\s+\}
Replace by:
$1 $2$3($4) { $5 }
This expression will transform the generated getters and setters to be one line. Don't worry about running it with a mixture of transformed and newly generated methods; it will work just fine.
I think matching generics is important as well, so the correct regexp is:
(?m)((?:public |private |protected )?[\w\<\>$]+) (get|set|is)([\w$]+)\(([\w\<\>$]+ [\w$]+)?\) \{\s+(return [\w$]+;|this.[\w$]+ = [\w$]+;)\s+\}
As a variation of the regexp replacement approach, the following reformats the whitespace so that setters are followed by a blank line, but getters are not.
Find:
(\s(?:get|is|set)\w+\([^)]*\))\s*\{\s*(?:([^=;}]+;)\s*\}\s*(\R)|([^=;}]+=[^=;}]+;)\s*\}\s*(\R))
Replace by:
$1 { $2$4 } \R$5
Results in:
int getTotal() { return total; }
void setTotal(int total) { this.total = total; }
List<String> getList() { return list; }
void setList(List<String> list) { this.list = list; }
Map.Entry<String, Integer> getEntry() { return entry; }
void setEntry(Map.Entry<String, Integer> entry) { this.entry = entry; }
It's a minor aesthetic thing, but I figured that if you're looking for an answer to this question, then you're probably (almost) as anal as me ;-)
I know my regexp conditions are not as strict as those of #Hosam, but I haven't experienced any "false positive" replacements.
Java code formatting in Eclipse does not differentiate between getters/setters and any other methods in a class. So this cannot be done by built-in eclipse formatting.
You will need either to:
run a search/replace with the aforementioned regex
get en external plugin like PMD or CheckStyle and enforce a regex rule based on previous option
You can use fast code plug-in to generate this kind of getter setters. The details are given here : http://fast-code.sourceforge.net/documentation.htm#create-new-field.
I wanted to post as a comment to the designated answer, but I don't seem to be able to.
I modified Hosam Aly's answer to work with generic and inner types of the form:
List<X>
and
Map.Entry
The revised regular expression search string is:
(?m)((?:public |private |protected )?[\w\.\<\>$]+) (get|set|is)([\w$]+)\(([\w\.\<\>$]+ [\w$]+)?\) \{\s+(return [\w\.\<\>$]+;|this.[\w$]+ = [\w$]+;)\s+\}
This regular expression allows for angle brackets and a dot in the type.
For example:
public List<String> getStringList()
and
public void setStringList(List<String> list)
and
public Map.Entry getEntry ()
And the replace string is the same as before:
$1 $2$3($4) { $5 }