I'm creating an Eclipse plugin that should insert block to one line if-else statements.
[Just like Eclipse facilitates via setting a preference for editor on Save-action]
for e.g.
if (isFormed)
if (i == 1)
System.out.println("i is 1");
else
System.out.println("i is undefined");
should be replaced with
if (isFormed)
{
if (i == 1)
{
System.out.println("i is 1");
}
else
{
System.out.println("i is undefined");
}
}
Here is how I'm visiting & replacing the statement inside AST
node.accept(new ASTVisitor() {
#Override
public boolean visit(IfStatement ifStatement) {
//Add Block in case of IfStatemnet if it is not there.
if(ifStatement != null){
Statement thenStatement = ifStatement.getThenStatement();
Statement elseStatement = ifStatement.getElseStatement();
String codeToReplace = "if("+ifStatement.getExpression()+")";
if(thenStatement instanceof Block)
codeToReplace += "\n"+ thenStatement + "";
else
codeToReplace += "{\n"+ thenStatement + "\n}";
if(elseStatement != null){
if(elseStatement instanceof Block)
codeToReplace += "else" + elseStatement +"\n";
else
codeToReplace += "else{\n" + elseStatement +"\n}";
}
replaceStatment(rewriter, getBlockInstence(ifStatement), codeToReplace , ifStatement);
}
return super.visit(ifStatement);
}
});
& once it's whole visited I commit the working copy.
This adds block to the outer if-else, & not to the inner ones.
I also tried replacing the document & committing it while visit like below:
IDocument document = new org.eclipse.jface.text.Document(iCompilationUnit.getSource());
TextEdit edits = mCompilationUnit.rewrite(document, null);
document.replace(ifStatement.getStartPosition(), ifStatement.getLength(), codeToReplace);
edits.apply(document);
iCompilationUnit.getBuffer().setContents(document.get());
iCompilationUnit.commitWorkingCopy(true, new NullProgressMonitor());
But this adds braces at wrong places for inner if-else & whole code gets messed up as IT DOES NOT HAVE UPDATED "offset" & "length" FOR THE CODE TO BE REPLACED & hence it keeps replacing at wrong places & messes up.
//void org.eclipse.jface.text.IDocument.replace(int offset, int length, String textTobeReplaced)
I also tried getting how eclipse is doing it. But couldn't reach that point.
Can anyone help solving this? Or any sort of plugin code I should refer? Even if I can get which eclipse plugin does this I can try de-compiling it.
I had the same problem that through changes the offset of expressions was changed and not updated. As a workaround I first collected all expressions that should be replaced, then reversed the collection and so started the changes at the end of the code. So the offset did not changed and I could change all expressions.
It's no good solution, but this worked for me.
Related
It is possible to define an if-else in one line statement.
if (isFormed)
if (i == 1)
System.out.println("i is 1");
else
System.out.println("i is undefined");
I need to surround one line if statements with braces using my eclipse plugin.
This is what I tried
node.accept(new ASTVisitor() {
#Override
public boolean visit(IfStatement ifStatement) {
//Add Block in case of IfStatemnet if it is not there.
if(ifStatement != null){
Statement thenStatement = ifStatement.getThenStatement();
Statement elseStatement = ifStatement.getElseStatement();
String codeToReplace = "if("+ifStatement.getExpression()+")";
if(thenStatement instanceof Block)
codeToReplace += "\n"+ thenStatement + "";
else
codeToReplace += "{\n"+ thenStatement + "\n}";
if(elseStatement != null){
if(elseStatement instanceof Block)
codeToReplace += "else" + elseStatement +"\n";
else
codeToReplace += "else{\n" + elseStatement +"\n}";
}
replaceStatment(rewriter, getBlockInstence(ifStatement), codeToReplace , ifStatement);
}
return super.visit(ifStatement);
}
});
This works for outer if, but doesn't work with inner if/else.
P.S.: There's a way to do this using formatter in preferences. I have to make this part of my plugin.
Here's an alternative way to do this. Open preferences in Eclipse, go to Java -> Editor -> Save actions. Enable save actions, then click on Configure. Go to Code Styles tab, then enable the option under Control Statements.
This will perform the action you want everytime the file is being saved.
So I have had an issue for a while now and thought it was worth the time to ask the more experienced regex guys if there was a way to fix this issue with a quick search and replace.
So i use a tool which generates java code(not written in java or I would manually fix the cause directly), however, it has an issue calling variables before an object is created.
This always occurs only once per object, but not for every object, the object name is unknown, and the error is always the line directly before the constructor is called. This is the format the error is always in:
this.unknownObjectName.mirror = true;
this.unknownObjectName = new Model(unknown, parameter, values);
I know there should be a trick to fix this, as a simple string replace simply will not work since 'unknownObjectName' is unknown.
Would this even be possible with regex, if so, please enlighten me :)
This is how the code SHOULD read:
this.unknownObjectName = new Model(unknown, parameter, values);
this.unknownObjectName.mirror = true;
For complex models, this error may happen hundreds of times, so this will indeed save a lot of time. That and I would rather walk on hot coals then do mindless busy work like fixing all these manually :)
Edit:
I through together a java app that does the job.
public static void main(String args[]){
File file = new File(args[0]);
File file2 = new File(file.getParentFile(), "fixed-" + file.getName());
try {
if(file2.exists()) {
file2 = new File(file.getParentFile(), "fixed-" + System.currentTimeMillis() + "-" + file.getName());
}
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file2)));
String line, savedline = null, lastInitVar = "";
while((line = br.readLine()) != null){
if(line.contains("= new ")){
String varname = line.substring(0, line.indexOf("=")).trim();
lastInitVar = varname;
}else if(line.contains(".mirror")){
String varname = line.substring(0, line.indexOf(".mirror")).trim();
if(!lastInitVar.equals(varname)){
savedline = line;
continue;
}
}else if(savedline != null && savedline.contains(lastInitVar)){
bw.write(savedline + "\n");
savedline = null;
}
bw.write(line + "\n");
}
bw.flush();
bw.close();
br.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Over thinking it
Write a program to read line by line and when you see a object access before a constructor don't write it out, write out the next line and then write out the buffered line, rinse repeat.
Some people, when confronted with a problem, think "I know, I'll use
regular expressions." Now they have two problems. - Jamie Zawinski
Regular Expressions are for matching patterns not state based logic.
I am new in this superb place. I got help several times from this site. I have seen many answers regarding my question that was previously discussed but i am facing problem to count the number of characters using FileReader. It's working using Scanner. This is what i tried:
class CountCharacter
{
public static void main(String args[]) throws IOException
{
File f = new File("hello.txt");
int charCount=0;
String c;
//int lineCount=0;
if(!f.exists())
{
f.createNewFile();
}
BufferedReader br = new BufferedReader(new FileReader(f));
while ( (c=br.readLine()) != null) {
String s = br.readLine();
charCount = s.length()-1;
charCount++;
}
System.out.println("NO OF LINE IN THE FILE, NAMED " +f.getName()+ " IS " +charCount);
}
}`
It looks to me that each time you go through the loop, you assign the charCount to be the length of the line that iteration of the loop is concerned with. i.e. instead of
charCount = s.Length() -1;
try
charCount = charCount + s.Length();
EDIT:
If you have say the document with the contents "onlyOneLine"
Then when you first hit the while check the br.readLine() will make the BufferredReader read the first line, during the while's code block however br.readLine() is called again which advances the BufferredReader to the second line of the document, which will return null. As null is assigned to s, and you call length(), then NPE is thrown.
try this for the while block
while ( (c=br.readLine()) != null) {
charCount = charCount + c.Length(); }
I'm writing a tinyMce plugin which contains a section of code, replacing one element for another. I'm using the editor's dom instance to create the node I want to insert, and I'm using the same instance to do the replacement.
My code is as follows:
var nodeData =
{
"data-widgetId": data.widget.widgetKey(),
"data-instanceKey": "instance1",
src: "/content/images/icon48/cog.png",
class: "widgetPlaceholder",
title: data.widget.getInfo().name
};
var nodeToInsert = ed.dom.create("img", nodeData);
// Insert this content into the editor window
if (data.mode == 'add') {
tinymce.DOM.add(ed.getBody(), nodeToInsert);
}
else if (data.mode == 'edit' && data.selected != null) {
var instanceKey = $(data.selected).attr("data-instancekey");
var elementToReplace = tinymce.DOM.select("[data-instancekey=" + instanceKey + "]");
if (elementToReplace.length === 1) {
ed.dom.replace(elementToReplace[0], nodeToInsert);
}
else {
throw new "No element to replace with that instance key";
}
}
TinyMCE breaks during the replace, here:
replace : function(n, o, k) {
var t = this;
if (is(o, 'array'))
n = n.cloneNode(true);
return t.run(o, function(o) {
if (k) {
each(tinymce.grep(o.childNodes), function(c) {
n.appendChild(c);
});
}
return o.parentNode.replaceChild(n, o);
});
},
..with the error Cannot call method 'replaceChild' of null.
I've verified that the two argument's being passed into replace() are not null and that their parentNode fields are instantiated. I've also taken care to make sure that the elements are being created and replace using the same document instance (I understand I.E has an issue with this).
I've done all this development in Google Chrome, but I receive the same errors in Firefox 4 and IE8 also. Has anyone else come across this?
Thanks in advance
As it turns out, I was simply passing in the arguments in the wrong order. I should have been passing the node I wanted to insert first, and the node I wanted to replace second.
A qustion about Eclipse PDE development: I write a small plugin for Eclipse and have the following
* an org.eclipse.ui.texteditor.ITextEditor
* a line number
How can I automatically jump to that line and mark it? It's a pity that the API seems only to support offsets (see: ITextEditor.selectAndReveal()) within the document but no line numbers.
The best would be - although this doesn't work:
ITextEditor editor = (ITextEditor)IDE.openEditor(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(), file, true );
editor.goto(line);
editor.markLine(line);
It this possible in some way? I did not find a solution
on the class DetailsView I found the following method.
private static void goToLine(IEditorPart editorPart, int lineNumber) {
if (!(editorPart instanceof ITextEditor) || lineNumber <= 0) {
return;
}
ITextEditor editor = (ITextEditor) editorPart;
IDocument document = editor.getDocumentProvider().getDocument(
editor.getEditorInput());
if (document != null) {
IRegion lineInfo = null;
try {
// line count internaly starts with 0, and not with 1 like in
// GUI
lineInfo = document.getLineInformation(lineNumber - 1);
} catch (BadLocationException e) {
// ignored because line number may not really exist in document,
// we guess this...
}
if (lineInfo != null) {
editor.selectAndReveal(lineInfo.getOffset(), lineInfo.getLength());
}
}
}
Even though org.eclipse.ui.texteditor.ITextEditor deals wiith offset, it should be able to take your line number with the selectAndReveal() method.
See this thread and this thread.
Try something along the line of:
((ITextEditor)org.eclipse.jdt.ui.JavaUI.openInEditor(compilationUnit)).selectAndReveal(int, int);