Eclipse plug in developement (JDT): Surround if statement with braces - eclipse

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.

Related

Inserting block/braces in If-else statements using JDT

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.

Turn a stack trace into a string?

Is it possible to print a stack trace to a string in GWT? The usual methods of using the classes in java.io won't work I think, because the java.io package is not available clientside (and Writer, PrintWriter, etc are in that package)
Thank you
I'm not sure if StackTraceElement is emulated, but if it is you can run something like
for (StackTraceElement element : exception.getStackTrace()) {
string += element + "\n";
}
Here is the method I'm using to retrieve a full stack trace as a String in GWT :
private static String getMessage (Throwable throwable) {
String ret="";
while (throwable!=null) {
if (throwable instanceof com.google.gwt.event.shared.UmbrellaException){
for (Throwable thr2 :((com.google.gwt.event.shared.UmbrellaException)throwable).getCauses()){
if (ret != "")
ret += "\nCaused by: ";
ret += thr2.toString();
ret += "\n at "+getMessage(thr2);
}
} else if (throwable instanceof com.google.web.bindery.event.shared.UmbrellaException){
for (Throwable thr2 :((com.google.web.bindery.event.shared.UmbrellaException)throwable).getCauses()){
if (ret != "")
ret += "\nCaused by: ";
ret += thr2.toString();
ret += "\n at "+getMessage(thr2);
}
} else {
if (ret != "")
ret += "\nCaused by: ";
ret += throwable.toString();
for (StackTraceElement sTE : throwable.getStackTrace())
ret += "\n at "+sTE;
}
throwable = throwable.getCause();
}
return ret;
}
I would not recommend trying to display error stack trace in a GUI label.
1) They are not readable after GWT Obfuscation. They just look like bunch of tab aligned characters over new lines.
2) They are not in I18N format.
3) The correct way is the just show user a well formed error "Message" . exception.getMessage() will give you a single line of non-obf information which should provide the necessary UX interaction to user.
4) If you are looking for well formed exception stacktrace helpful for debugging ( not for user ) you should use GWT's well documented logging feature with web mode exceptions -
a) https://developers.google.com/web-toolkit/doc/latest/DevGuideLogging
b) Also read on http://code.google.com/p/google-web-toolkit/wiki/WebModeExceptions
Use com.google.gwt.logging.impl.StackTracePrintStream
Throwable t = ...;
StringBuilder message = new StringBuilder();
StackTracePrintStream ps = new StackTracePrintStream(message);
t.printStackTrace(ps);
ps.flush();

Is there a way to auto expand objects in Chrome Dev Tools?

EVERY SINGLE TIME I view an object in the console I am going to want to expand it, so it gets tiresome to have to click the arrow to do this EVERY SINGLE TIME :) Is there a shortcut or setting to have this done automatically?
Consider using console.table().
To expand / collapse a node and all its children,
Ctrl + Alt + Click or Opt + Click on arrow icon
(note that although the dev tools doc lists Ctrl + Alt + Click, on Windows all that is needed is Alt + Click).
While the solution mentioning JSON.stringify is pretty great for most of the cases, it has a few limitations
It can not handle items with circular references where as console.log can take care of such objects elegantly.
Also, if you have a large tree, then ability to interactively fold away some nodes can make exploration easier.
Here is a solution that solves both of the above by creatively (ab)using console.group:
function expandedLog(item, maxDepth = 100, depth = 0){
if (depth > maxDepth ) {
console.log(item);
return;
}
if (typeof item === 'object' && item !== null) {
Object.entries(item).forEach(([key, value]) => {
console.group(key + ' : ' +(typeof value));
expandedLog(value, maxDepth, depth + 1);
console.groupEnd();
});
} else {
console.log(item);
}
}
Now running:
expandedLog({
"glossary": {
"title": "example glossary",
"GlossDiv": {
"title": "S",
"GlossList": {
"GlossEntry": {
"ID": "SGML",
"SortAs": "SGML",
"GlossTerm": "Standard Generalized Markup Language",
"Acronym": "SGML",
"Abbrev": "ISO 8879:1986",
"GlossDef": {
"para": "A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso": ["GML", "XML"]
},
"GlossSee": "markup"
}
}
}
}
})
Will give you something like:
The value of maxDepth can be adjusted to a desired level, and beyond that level of nesting - expanded log will fall back to usual console.log
Try running something like:
x = { a: 10, b: 20 }
x.x = x
expandedLog(x)
Also please note that console.group is non-standard.
Might not be the best answer, but I've been doing this somewhere in my code.
Update:
Use JSON.stringify to expand your object automatically:
> a = [{name: 'Joe', age: 5}, {name: 'John', age: 6}]
> JSON.stringify(a, true, 2)
"[
{
"name": "Joe",
"age": 5
},
{
"name": "John",
"age": 6
}
]"
You can always make a shortcut function if it hurts to type all that out:
j = function(d) {
return JSON.stringify(d, true, 2)
}
j(a)
Previous answer:
pretty = function(d)
{
var s = []
for (var k in d) {
s.push(k + ': ' + d[k])
}
console.log(s.join(', '))
}
then, instead of:
-> a = [{name: 'Joe', age: 5}, {name: 'John', age: 6}]
-> a
<- [Object, Object]
You do:
-> a.forEach(pretty)
<- name: Joe, age: 5
name: John, age: 6
Not the best solution, but works well for my usage. Deeper objects will not work so that's something that can be improved on.
option+Click on a Mac. Just discovered it now myself and have made my week! This has been as annoying as anything
By default the console on Chrome and Safari browsers will output objects which are collapsed, with sorted property keys, and include all inherited prototype chains.
I'm personally not a fan. Most developers need raw output of an object without the prototype chain, and anything else should be opt-in. Collapsed objects waste the developer's time, because they need to expand them, and if they wanted less output they could just log the property keys they need. Auto-sorting the property keys, leaves the developer without a way to check if their own sort works correctly, which could cause bugs. And lastly, the common Javascript developer does not spend much time working on the inherited prototype chain, so that adds noise to the logs.
How to expand objects in Console
Recommended
console.log(JSON.stringify({}, undefined, 2));
Could also use as a function:
console.json = object => console.log(JSON.stringify(object, undefined, 2));
console.json({});
"Option + Click" (Chrome on Mac) and "Alt + Click" (Chrome on Window)
However, it's not supported by all browsers (e.g. Safari), and Console still prints the prototype chains, auto-sorts property keys, etc.
Not Recommended
I would not recommend either of the top answers
console.table() - this is shallow expansion only, and does not expand nested objects
Write a custom underscore.js function - too much overhead for what should be a simple solution
Here is a modified version of lorefnon's answer which does not depend on underscorejs:
var expandedLog = (function(MAX_DEPTH){
return function(item, depth){
depth = depth || 0;
isString = typeof item === 'string';
isDeep = depth > MAX_DEPTH
if (isString || isDeep) {
console.log(item);
return;
}
for(var key in item){
console.group(key + ' : ' +(typeof item[key]));
expandedLog(item[key], depth + 1);
console.groupEnd();
}
}
})(100);
Here is my solution, a function that iterates an all the properties of the object, including arrays.
In this example I iterate over a simple multi-level object:
var point = {
x: 5,
y: 2,
innerobj : { innerVal : 1,innerVal2 : 2 },
$excludedInnerProperties : { test: 1},
includedInnerProperties : { test: 1}
};
You have also the possibility to exclude the iteration if the properties starts with a particular suffix (i.e. $ for angular objects)
discoverProperties = function (obj, level, excludePrefix) {
var indent = "----------------------------------------".substring(0, level * 2);
var str = indent + "level " + level + "\r\n";
if (typeof (obj) == "undefined")
return "";
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
var propVal;
try {
propVal = eval('obj.' + property);
str += indent + property + "(" + propVal.constructor.name + "):" + propVal + "\r\n";
if (typeof (propVal) == 'object' && level < 10 && propVal.constructor.name != "Date" && property.indexOf(excludePrefix) != 0) {
if (propVal.hasOwnProperty('length')) {
for (var i = 0; i < propVal.length; i++) {
if (typeof (propVal) == 'object' && level < 10) {
if (typeof (propVal[i]) != "undefined") {
str += indent + (propVal[i]).constructor.name + "[" + i + "]\r\n";
str += this.discoverProperties(propVal[i], level + 1, excludePrefix);
}
}
else
str += indent + propVal[i].constructor.name + "[" + i + "]:" + propVal[i] + "\r\n";
}
}
else
str += this.discoverProperties(propVal, level + 1, excludePrefix);
}
}
catch (e) {
}
}
}
return str;
};
var point = {
x: 5,
y: 2,
innerobj : { innerVal : 1,innerVal2 : 2 },
$excludedInnerProperties : { test: 1},
includedInnerProperties : { test: 1}
};
document.write("<pre>" + discoverProperties(point,0,'$')+ "</pre>");
Here is the output of the function:
level 0
x(Number):5
y(Number):2
innerobj(Object):[object Object]
--level 1
--innerVal(Number):1
--innerVal2(Number):2
$excludedInnerProperties(Object):[object Object]
includedInnerProperties(Object):[object Object]
--level 1
--test(Number):1
You can also inject this function in any web page and copy and analyze all the properties, try in on the google page using the chrome command:
discoverProperties(google,0,'$')
Also you can copy the output of the command using the chrome command:
copy(discoverProperties(myvariable,0,'$'))
if you have a big object, JSON.stringfy will give error Uncaught TypeError: Converting circular structure to JSON
, here is trick to use modified version of it
JSON.stringifyOnce = function(obj, replacer, indent){
var printedObjects = [];
var printedObjectKeys = [];
function printOnceReplacer(key, value){
if ( printedObjects.length > 2000){ // browsers will not print more than 20K, I don't see the point to allow 2K.. algorithm will not be fast anyway if we have too many objects
return 'object too long';
}
var printedObjIndex = false;
printedObjects.forEach(function(obj, index){
if(obj===value){
printedObjIndex = index;
}
});
if ( key == ''){ //root element
printedObjects.push(obj);
printedObjectKeys.push("root");
return value;
}
else if(printedObjIndex+"" != "false" && typeof(value)=="object"){
if ( printedObjectKeys[printedObjIndex] == "root"){
return "(pointer to root)";
}else{
return "(see " + ((!!value && !!value.constructor) ? value.constructor.name.toLowerCase() : typeof(value)) + " with key " + printedObjectKeys[printedObjIndex] + ")";
}
}else{
var qualifiedKey = key || "(empty key)";
printedObjects.push(value);
printedObjectKeys.push(qualifiedKey);
if(replacer){
return replacer(key, value);
}else{
return value;
}
}
}
return JSON.stringify(obj, printOnceReplacer, indent);
};
now you can use JSON.stringifyOnce(obj)
Its a work around, but it works for me.
I use in the case where a control/widget auto updates depending on user actions. For example, when using twitter's typeahead.js, once you focus out of the window, the dropdown disappears and the suggestions get removed from the DOM.
In dev tools right click on the node you want to expand enable break on... -> subtree modifications, this will then send you to the debugger. Keep hitting F10 or Shift+F11 untill you dom mutates. Once that mutates then you can inspect. Since the debugger is active the UI of Chrome is locked and doesn't close the dropdown and the suggestions are still in the DOM.
Very handy when troubleshooting layout of dynamically inserted nodes that are begin inserted and removed constantly.
Another easier way would be
Use JSON.stringify(jsonObject)
Copy and Paste the result to Visual Studio Code
Use Ctrl+K and Ctrl+F to format the result
You will see formatted expanded object
I have tried this for simple objects.
You can package JSON.stringify into a new function eg
jsonLog = function (msg, d) {
console.log(msg + '\n' + JSON.stringify(d, true, 2))
}
then
jsonLog('root=', root)
FWIW.
Murray
For lazy folks
/**
* _Universal extensive multilevel logger for lazy folks_
* #param {any} value **`Value` you want to log**
* #param {number} tab **Abount of `tab`**
*/
function log(value, tab = 4) {
console.log(JSON.stringify(value, undefined, tab));
}
Usage
log(anything) // [] {} 1 true null
Alt-click will expand all child nodes in the Chrome console.
You could view your element by accessing document.getElementsBy... and then right click and copy of the resulted object. For example:
document.getElementsByTagName('ion-app') gives back javascript object that can be copy pasted to text editor and it does it in full.
Better yet: right click on the resulted element - 'Edit as html' - 'Select all' - 'Copy' - 'Paste'

tinymce.dom.replace throws an exception concerning parentNode

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.

Eclipe PDE: Jump to line X and highlight it

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);