Comments (7)
@nedtwigg The feeling is mutual 🤝
from ktlint.
Hi Ned,
That looks interesting!
I'm not entirely sure where would be the right place for this kind of class, though. Also without the callback user would have no way of knowing whether all violations have been corrected or some require manual intervention. That means that callback would have to stay, which in turn is going to make access through reflection awkward again.
One way to solve this would be to create a module with com.github.shyiko:ktlint
"provided" (in Maven terminology) dependency that does no reflection at all and just acts as a bridge between spotless & ktlint. This module would obviously have to be part of the spotless project. What do you think?
On a different note, here is the code (using Reflection API) that works:
ClassLoader classLoader = ...
Class<?> ktlintClass = classLoader.loadClass("com.github.shyiko.ktlint.core.KtLint");
Object ktlint = ktlintClass.getDeclaredField("INSTANCE").get(null);
Class<?> standardRuleSetProviderClass = classLoader.loadClass("com.gihub.shyiko.ktlint.ruleset.standard.StandardRuleSetProvider");
Object standardRuleSet = standardRuleSetProviderClass.getMethod("get").invoke(standardRuleSetProviderClass.newInstance());
Iterable<?> ruleSets = Collections.singletonList(standardRuleSet);
Class<?> function2Interface = classLoader.loadClass("kotlin.jvm.functions.Function2");
Object formatterCallback = Proxy.newProxyInstance(classLoader, new Class[]{function2Interface},
(proxy, method, args) -> null);
Method formatterMethod = ktlintClass.getMethod("format", String.class, Iterable.class, function2Interface);
String input = "fun main() { x(1,3); x(1, 3) }";
String output = (String) formatterMethod.invoke(ktlint, input, ruleSets, formatterCallback);
from ktlint.
Spotless has an _ext
folder for hosting shim modules, so that could be done. I don't yet have the Kotlin skill to build and maintain the shim, but I'd be happy to take a PR. Spotless has zero dependencies - it calls all its formatting libraries using reflection, but caches the classloaders to get the full JIT performance.
My immediate need is for Spotless, but I expect that other users of your formatting library would appreciate an easier entry point as well. In my eyes, the simplest interface for a formatter is a Function<String, String>
that throws an exception if it can't generate an adequate return value. The easier it is for users to generate such a construct from your library, the easier it is to consume your library to meet a variety of usecases.
In the reflection code you pasted above, how does it handle "violations that require manual intervention"? Does it throw a descriptive exception? If not, is it possible to modify the pasted code so that it would throw a descriptive exception?
from ktlint.
You don't need Kotlin to make a shim. A little bit of Java will do:
try {
output = KtLint.INSTANCE.format(input, Arrays.asList(new StandardRuleSetProvider().get()), (lintError, corrected) -> {
if (!corrected) {
throw new RuntimeException(lintError.getDetail());
}
return null;
});
} catch (RuleExecutionException e) {
System.err.println(e.getLine() + ":" + e.getCol() + " " + e.getMessage() + " (" + e.getRuleId() + ")");
}
In the reflection code you pasted above, how does it handle "violations that require manual intervention"?
It doesn't. But it's easy to correct:
Class<?> lintErrorClass = classLoader.loadClass("com.github.shyiko.ktlint.core.LintError");
Method detailGetter = lintErrorClass.getMethod("getDetail");
Object formatterCallback = Proxy.newProxyInstance(classLoader, new Class[]{function2Interface},
(proxy, method, args) -> {
Object lintError = args[0]; // com.github.shyiko.ktlint.core.LintError
boolean corrected = (Boolean) args[1];
if (!corrected) {
String detail = (String) detailGetter.invoke(lintError);
throw new RuntimeException(detail);
}
return null;
});
...
try {
output = (String) formatterMethod.invoke(ktlint, input, ruleSets, formatterCallback);
} catch (Exception e) {
// InvocationTargetException -> RuleExecutionException (see prev code snippet)
}
from ktlint.
Awesome, thanks! That got it working. Next question: can you point me to an example kotlin file that should throw an error? I'd like to add a test which asserts that errors are being thrown properly, and that their messages are as expected.
I think we're almost ready to merge ktlint into spotless :)
from ktlint.
Sure. This is an example of the rule that cannot be fixed automatically and this is the one that can (there are bunch of other examples here). Let me know if you need anything else.
from ktlint.
Great, thanks! I think we're about ready to merge diffplug/spotless#71! Hopefully we'll be able to drive more users your way once it ships.
from ktlint.
Related Issues (20)
- How to avoid wrapping when there is only one param in class? HOT 1
- Redundant suppression shown for PropertyName HOT 4
- Consider honoring `PrivatePropertyName` like `PropertyName` HOT 1
- Method Signature forcing multiline despite unset [`function_signature_rule_force_multiline`] HOT 1
- parameter-list-wrapping disable is not respected HOT 2
- Import incorrectly dropped when correcting string template expression with redundant braces HOT 1
- [Question] Why max_line_length contains number of indent white space? HOT 1
- Apply the `function-naming` exception for backticked test functions to apply to Test classes extending an org.junit Test class HOT 2
- Test was not passed when Default language is not English
- Ktlint Issue: Variable Declaration Format Inconsistency Despite Disabled Max-Line-Length Constraint HOT 4
- False positive for indentation in a nested lamba HOT 2
- Configuration setting confusing HOT 1
- Suport partial formatting of code
- long type parameter cause `Expected a single space` HOT 1
- Do not report PascalCase top-level constants in property-naming rule HOT 3
- Separate constant naming rule from property-naming HOT 1
- Suggest IntelliJ config of wildcard import HOT 1
- Split `multiline-if-else` into two rules HOT 2
- Prevent possible conflict between `multiline-expression-wrapping` and `function-signature` body wrapping
- Binary operators in `!(...)` not checked for missing horizontal whitespace
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from ktlint.