mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 07:49:44 +08:00
Reformatted code
This commit is contained in:
Generated
+493
@@ -4,11 +4,33 @@
|
||||
<option name="SPACE_BEFORE_OPENING_ANGLE_BRACKET_IN_TYPE_PARAMETER" value="true" />
|
||||
</JavaCodeStyleSettings>
|
||||
<JetCodeStyleSettings>
|
||||
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
|
||||
<value>
|
||||
<package name="java.util" alias="false" withSubpackages="true" />
|
||||
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
|
||||
<package name="io.ktor" alias="false" withSubpackages="true" />
|
||||
</value>
|
||||
</option>
|
||||
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
|
||||
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" />
|
||||
<option name="IMPORT_NESTED_CLASSES" value="true" />
|
||||
<option name="ALLOW_TRAILING_COMMA" value="true" />
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</JetCodeStyleSettings>
|
||||
<codeStyleSettings language="Groovy">
|
||||
<option name="SPACE_WITHIN_BRACES" value="false" />
|
||||
<option name="SPACE_BEFORE_METHOD_CALL_PARENTHESES" value="true" />
|
||||
<option name="SPACE_BEFORE_METHOD_PARENTHESES" value="true" />
|
||||
<option name="KEEP_SIMPLE_METHODS_IN_ONE_LINE" value="false" />
|
||||
<option name="KEEP_SIMPLE_LAMBDAS_IN_ONE_LINE" value="false" />
|
||||
<option name="KEEP_SIMPLE_CLASSES_IN_ONE_LINE" value="false" />
|
||||
<option name="IF_BRACE_FORCE" value="3" />
|
||||
<option name="DOWHILE_BRACE_FORCE" value="3" />
|
||||
<option name="FOR_BRACE_FORCE" value="3" />
|
||||
<indentOptions>
|
||||
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="JAVA">
|
||||
<option name="SPACE_BEFORE_METHOD_CALL_PARENTHESES" value="true" />
|
||||
<option name="SPACE_BEFORE_METHOD_PARENTHESES" value="true" />
|
||||
@@ -18,6 +40,477 @@
|
||||
<indentOptions>
|
||||
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
||||
</indentOptions>
|
||||
<arrangement>
|
||||
<groups>
|
||||
<group>
|
||||
<type>GETTERS_AND_SETTERS</type>
|
||||
<order>KEEP</order>
|
||||
</group>
|
||||
<group>
|
||||
<type>OVERRIDDEN_METHODS</type>
|
||||
<order>KEEP</order>
|
||||
</group>
|
||||
<group>
|
||||
<type>DEPENDENT_METHODS</type>
|
||||
<order>BREADTH_FIRST</order>
|
||||
</group>
|
||||
</groups>
|
||||
<rules>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<FIELD>true</FIELD>
|
||||
<FINAL>true</FINAL>
|
||||
<PUBLIC>true</PUBLIC>
|
||||
<STATIC>true</STATIC>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<FIELD>true</FIELD>
|
||||
<FINAL>true</FINAL>
|
||||
<PROTECTED>true</PROTECTED>
|
||||
<STATIC>true</STATIC>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<FIELD>true</FIELD>
|
||||
<FINAL>true</FINAL>
|
||||
<PRIVATE>true</PRIVATE>
|
||||
<STATIC>true</STATIC>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<FIELD>true</FIELD>
|
||||
<FINAL>true</FINAL>
|
||||
<PACKAGE_PRIVATE>true</PACKAGE_PRIVATE>
|
||||
<STATIC>true</STATIC>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<FIELD>true</FIELD>
|
||||
<PUBLIC>true</PUBLIC>
|
||||
<STATIC>true</STATIC>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<FIELD>true</FIELD>
|
||||
<PROTECTED>true</PROTECTED>
|
||||
<STATIC>true</STATIC>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<FIELD>true</FIELD>
|
||||
<PRIVATE>true</PRIVATE>
|
||||
<STATIC>true</STATIC>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<FIELD>true</FIELD>
|
||||
<PACKAGE_PRIVATE>true</PACKAGE_PRIVATE>
|
||||
<STATIC>true</STATIC>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<INITIALIZER_BLOCK>true</INITIALIZER_BLOCK>
|
||||
<STATIC>true</STATIC>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<FIELD>true</FIELD>
|
||||
<FINAL>true</FINAL>
|
||||
<PUBLIC>true</PUBLIC>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<FIELD>true</FIELD>
|
||||
<FINAL>true</FINAL>
|
||||
<PROTECTED>true</PROTECTED>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<FIELD>true</FIELD>
|
||||
<FINAL>true</FINAL>
|
||||
<PRIVATE>true</PRIVATE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<FIELD>true</FIELD>
|
||||
<FINAL>true</FINAL>
|
||||
<PACKAGE_PRIVATE>true</PACKAGE_PRIVATE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<FIELD>true</FIELD>
|
||||
<PUBLIC>true</PUBLIC>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<FIELD>true</FIELD>
|
||||
<PROTECTED>true</PROTECTED>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<FIELD>true</FIELD>
|
||||
<PRIVATE>true</PRIVATE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<FIELD>true</FIELD>
|
||||
<PACKAGE_PRIVATE>true</PACKAGE_PRIVATE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<FIELD>true</FIELD>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<INITIALIZER_BLOCK>true</INITIALIZER_BLOCK>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<CONSTRUCTOR>true</CONSTRUCTOR>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<METHOD>true</METHOD>
|
||||
<PUBLIC>true</PUBLIC>
|
||||
<STATIC>true</STATIC>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<METHOD>true</METHOD>
|
||||
<PROTECTED>true</PROTECTED>
|
||||
<STATIC>true</STATIC>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<METHOD>true</METHOD>
|
||||
<PRIVATE>true</PRIVATE>
|
||||
<STATIC>true</STATIC>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<METHOD>true</METHOD>
|
||||
<PACKAGE_PRIVATE>true</PACKAGE_PRIVATE>
|
||||
<STATIC>true</STATIC>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<METHOD>true</METHOD>
|
||||
<PUBLIC>true</PUBLIC>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<METHOD>true</METHOD>
|
||||
<PROTECTED>true</PROTECTED>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<METHOD>true</METHOD>
|
||||
<PRIVATE>true</PRIVATE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<METHOD>true</METHOD>
|
||||
<PACKAGE_PRIVATE>true</PACKAGE_PRIVATE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<METHOD>true</METHOD>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<ENUM>true</ENUM>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<CLASS>true</CLASS>
|
||||
<STATIC>true</STATIC>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<CLASS>true</CLASS>
|
||||
<PUBLIC>true</PUBLIC>
|
||||
<STATIC>true</STATIC>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<CLASS>true</CLASS>
|
||||
<PROTECTED>true</PROTECTED>
|
||||
<STATIC>true</STATIC>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<CLASS>true</CLASS>
|
||||
<PRIVATE>true</PRIVATE>
|
||||
<STATIC>true</STATIC>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<CLASS>true</CLASS>
|
||||
<PACKAGE_PRIVATE>true</PACKAGE_PRIVATE>
|
||||
<STATIC>true</STATIC>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<CLASS>true</CLASS>
|
||||
<PUBLIC>true</PUBLIC>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<CLASS>true</CLASS>
|
||||
<PROTECTED>true</PROTECTED>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<CLASS>true</CLASS>
|
||||
<PRIVATE>true</PRIVATE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<CLASS>true</CLASS>
|
||||
<PACKAGE_PRIVATE>true</PACKAGE_PRIVATE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<CLASS>true</CLASS>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<INTERFACE>true</INTERFACE>
|
||||
<PUBLIC>true</PUBLIC>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<INTERFACE>true</INTERFACE>
|
||||
<PROTECTED>true</PROTECTED>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<INTERFACE>true</INTERFACE>
|
||||
<PRIVATE>true</PRIVATE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<INTERFACE>true</INTERFACE>
|
||||
<PACKAGE_PRIVATE>true</PACKAGE_PRIVATE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<INTERFACE>true</INTERFACE>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
</rules>
|
||||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="XML">
|
||||
<option name="FORCE_REARRANGE_MODE" value="1" />
|
||||
|
||||
@@ -106,6 +106,47 @@ public class IDEEditor extends CodeEditor {
|
||||
setInputType(createInputFlags());
|
||||
}
|
||||
|
||||
private void handleSelectionChange(
|
||||
@NonNull SelectionChangeEvent event, Unsubscribe unsubscribe) {
|
||||
if (event.isSelected() || !(getEditorLanguage() instanceof IDELanguage)) {
|
||||
// do not show diagnostics when text is selected
|
||||
// or if we cannot get diagnostics
|
||||
return;
|
||||
}
|
||||
|
||||
final var diagnostics = ((IDELanguage) getEditorLanguage()).getDiagnostics();
|
||||
final var line = event.getLeft().line;
|
||||
final var column = event.getLeft().column;
|
||||
|
||||
// diagnostics are expected to be sorted, so, we do a binary search
|
||||
final var diagnostic = binarySearchDiagnostic(diagnostics, line, column);
|
||||
getDiagnosticWindow().showDiagnostic(diagnostic);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the language server that the content of this file has been changed.
|
||||
*
|
||||
* @param event The content change event.
|
||||
*/
|
||||
private void handleContentChange(ContentChangeEvent event, Unsubscribe unsubscribe) {
|
||||
if (getContext() instanceof Activity) {
|
||||
((Activity) getContext()).invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
if (getFile() == null || mLanguageServer == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final var documentHandler = mLanguageServer.getDocumentHandler();
|
||||
final var file = getFile().toPath();
|
||||
if (documentHandler.accepts(file)) {
|
||||
documentHandler.onContentChange(
|
||||
new DocumentChangeEvent(file, getText(), mFileVersion + 1));
|
||||
}
|
||||
|
||||
checkForSignatureHelp(event);
|
||||
}
|
||||
|
||||
public static int createInputFlags() {
|
||||
var flags =
|
||||
EditorInfo.TYPE_CLASS_TEXT
|
||||
@@ -120,100 +161,18 @@ public class IDEEditor extends CodeEditor {
|
||||
return flags;
|
||||
}
|
||||
|
||||
public void analyze() {
|
||||
if (mLanguageServer != null
|
||||
&& getFile() != null
|
||||
&& getEditorLanguage() instanceof IDELanguage) {
|
||||
CompletableFuture.supplyAsync(() -> mLanguageServer.analyze(getFile().toPath()))
|
||||
.whenComplete(
|
||||
(diagnostics, throwable) -> {
|
||||
final var lang = (IDELanguage) getEditorLanguage();
|
||||
final var analyzer = lang.getAnalyzeManager();
|
||||
if (analyzer instanceof IAnalyzeManager) {
|
||||
((IAnalyzeManager) analyzer).updateDiagnostics(diagnostics);
|
||||
}
|
||||
analyzer.rerun();
|
||||
});
|
||||
}
|
||||
@Nullable
|
||||
private DiagnosticItem binarySearchDiagnostic(
|
||||
@NonNull List<DiagnosticItem> diagnostics, int line, int column) {
|
||||
return DiagnosticUtil.binarySearchDiagnostic(diagnostics, line, column);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given range is valid for this editor's text.
|
||||
*
|
||||
* @param range The range to check.
|
||||
* @return <code>true</code> if valid, <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean isValidRange(final Range range) {
|
||||
if (range == null) {
|
||||
return false;
|
||||
private DiagnosticWindow getDiagnosticWindow() {
|
||||
if (mDiagnosticWindow == null) {
|
||||
mDiagnosticWindow = new DiagnosticWindow(this);
|
||||
}
|
||||
|
||||
final var start = range.getStart();
|
||||
final var end = range.getEnd();
|
||||
|
||||
return isValidPosition(start)
|
||||
&& isValidPosition(end)
|
||||
&& start.compareTo(end) < 0; // make sure start position is before end position
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given position is valid for this editor's text.
|
||||
*
|
||||
* @param position The position to check.
|
||||
* @return <code>true</code> if valid, <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean isValidPosition(final Position position) {
|
||||
if (position == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isValidLine(position.getLine())
|
||||
&& isValidColumn(position.getLine(), position.getColumn());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given line is valid for this editor's text.
|
||||
*
|
||||
* @param line The line to check.
|
||||
* @return <code>true</code> if valid, <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean isValidLine(int line) {
|
||||
return line >= 0 && line < getText().getLineCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given column is valid for this editor's text.
|
||||
*
|
||||
* @param line The line of the column to check.
|
||||
* @param column The column to check.
|
||||
* @return <code>true</code> if valid, <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean isValidColumn(int line, int column) {
|
||||
return column >= 0 && column < getText().getColumnCount(line);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set selection to the given range.
|
||||
*
|
||||
* @param range The range to select.
|
||||
*/
|
||||
public void setSelection(@NonNull Range range) {
|
||||
if (isValidRange(range)) {
|
||||
setSelectionRegion(
|
||||
range.getStart().getLine(),
|
||||
range.getStart().getColumn(),
|
||||
range.getEnd().getLine(),
|
||||
range.getEnd().getColumn());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the selection of this editor to the given position.
|
||||
*
|
||||
* @param position The position to select.
|
||||
*/
|
||||
public void setSelection(@NonNull Position position) {
|
||||
setSelection(position.getLine(), position.getColumn());
|
||||
return mDiagnosticWindow;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -252,6 +211,104 @@ public class IDEEditor extends CodeEditor {
|
||||
}
|
||||
}
|
||||
|
||||
public void analyze() {
|
||||
if (mLanguageServer != null
|
||||
&& getFile() != null
|
||||
&& getEditorLanguage() instanceof IDELanguage) {
|
||||
CompletableFuture.supplyAsync(() -> mLanguageServer.analyze(getFile().toPath()))
|
||||
.whenComplete(
|
||||
(diagnostics, throwable) -> {
|
||||
final var lang = (IDELanguage) getEditorLanguage();
|
||||
final var analyzer = lang.getAnalyzeManager();
|
||||
if (analyzer instanceof IAnalyzeManager) {
|
||||
((IAnalyzeManager) analyzer).updateDiagnostics(diagnostics);
|
||||
}
|
||||
analyzer.rerun();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the content change event should trigger signature help. Signature help trigger
|
||||
* characters are :
|
||||
*
|
||||
* <ul>
|
||||
* <li><code>'('</code> (parentheses)
|
||||
* <li><code>','</code> (comma)
|
||||
* </ul>
|
||||
*
|
||||
* @param event The content change event.
|
||||
*/
|
||||
private void checkForSignatureHelp(@NonNull ContentChangeEvent event) {
|
||||
if (event.getAction() != ContentChangeEvent.ACTION_INSERT
|
||||
|| event.getChangedText().length() != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
final var ch = event.getChangedText().charAt(0);
|
||||
if (ch == '(' || ch == ',') {
|
||||
signatureHelp();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If any language server is set, requests signature help at the cursor's position. On a valid
|
||||
* response, shows the signature help in a popup window.
|
||||
*/
|
||||
@SuppressWarnings("unused") // accessed using reflection in CompletionItem class
|
||||
public void signatureHelp() {
|
||||
if (mLanguageServer != null && getFile() != null) {
|
||||
final CompletableFuture<SignatureHelp> future =
|
||||
CompletableFuture.supplyAsync(
|
||||
() ->
|
||||
mLanguageServer.signatureHelp(
|
||||
new SignatureHelpParams(
|
||||
getFile().toPath(),
|
||||
new Position(
|
||||
getCursor().getLeftLine(),
|
||||
getCursor().getLeftColumn()))));
|
||||
|
||||
future.whenComplete(
|
||||
(help, error) -> {
|
||||
if (help == null
|
||||
|| mLanguageClient == null
|
||||
|| future.isCancelled()
|
||||
|| future.isCompletedExceptionally()) {
|
||||
LOG.error("An error occurred while finding signature help", error);
|
||||
return;
|
||||
}
|
||||
|
||||
ThreadUtils.runOnUiThread(() -> showSignatureHelp(help));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the given signature help in the editor.
|
||||
*
|
||||
* @param help The signature help data to show.
|
||||
*/
|
||||
public void showSignatureHelp(SignatureHelp help) {
|
||||
getSignatureHelpWindow().setupAndDisplay(help);
|
||||
}
|
||||
|
||||
private SignatureHelpWindow getSignatureHelpWindow() {
|
||||
if (mSignatureHelpWindow == null) {
|
||||
mSignatureHelpWindow = new SignatureHelpWindow(this);
|
||||
}
|
||||
|
||||
return mSignatureHelpWindow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the selection of this editor to the given position.
|
||||
*
|
||||
* @param position The position to select.
|
||||
*/
|
||||
public void setSelection(@NonNull Position position) {
|
||||
setSelection(position.getLine(), position.getColumn());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the language server that this editor will connect with. If the language client is not
|
||||
* set, it'll be set to {@link IDELanguageClientImpl}.
|
||||
@@ -451,6 +508,85 @@ public class IDEEditor extends CodeEditor {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set selection to the given range.
|
||||
*
|
||||
* @param range The range to select.
|
||||
*/
|
||||
public void setSelection(@NonNull Range range) {
|
||||
if (isValidRange(range)) {
|
||||
setSelectionRegion(
|
||||
range.getStart().getLine(),
|
||||
range.getStart().getColumn(),
|
||||
range.getEnd().getLine(),
|
||||
range.getEnd().getColumn());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismisses the given dialog on the UI thread.
|
||||
*
|
||||
* @param dialog The dialog to dismiss.
|
||||
*/
|
||||
private void dismissOnUiThread(@NonNull final Dialog dialog) {
|
||||
ThreadUtils.runOnUiThread(dialog::dismiss);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given range is valid for this editor's text.
|
||||
*
|
||||
* @param range The range to check.
|
||||
* @return <code>true</code> if valid, <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean isValidRange(final Range range) {
|
||||
if (range == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final var start = range.getStart();
|
||||
final var end = range.getEnd();
|
||||
|
||||
return isValidPosition(start)
|
||||
&& isValidPosition(end)
|
||||
&& start.compareTo(end) < 0; // make sure start position is before end position
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given position is valid for this editor's text.
|
||||
*
|
||||
* @param position The position to check.
|
||||
* @return <code>true</code> if valid, <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean isValidPosition(final Position position) {
|
||||
if (position == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isValidLine(position.getLine())
|
||||
&& isValidColumn(position.getLine(), position.getColumn());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given line is valid for this editor's text.
|
||||
*
|
||||
* @param line The line to check.
|
||||
* @return <code>true</code> if valid, <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean isValidLine(int line) {
|
||||
return line >= 0 && line < getText().getLineCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given column is valid for this editor's text.
|
||||
*
|
||||
* @param line The line of the column to check.
|
||||
* @param column The column to check.
|
||||
* @return <code>true</code> if valid, <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean isValidColumn(int line, int column) {
|
||||
return column >= 0 && column < getText().getColumnCount(line);
|
||||
}
|
||||
|
||||
/**
|
||||
* If any language server instance is set, finds the references to of the token at the current
|
||||
* cursor position.
|
||||
@@ -533,56 +669,6 @@ public class IDEEditor extends CodeEditor {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* If any language server is set, requests signature help at the cursor's position. On a valid
|
||||
* response, shows the signature help in a popup window.
|
||||
*/
|
||||
@SuppressWarnings("unused") // accessed using reflection in CompletionItem class
|
||||
public void signatureHelp() {
|
||||
if (mLanguageServer != null && getFile() != null) {
|
||||
final CompletableFuture<SignatureHelp> future =
|
||||
CompletableFuture.supplyAsync(
|
||||
() ->
|
||||
mLanguageServer.signatureHelp(
|
||||
new SignatureHelpParams(
|
||||
getFile().toPath(),
|
||||
new Position(
|
||||
getCursor().getLeftLine(),
|
||||
getCursor().getLeftColumn()))));
|
||||
|
||||
future.whenComplete(
|
||||
(help, error) -> {
|
||||
if (help == null
|
||||
|| mLanguageClient == null
|
||||
|| future.isCancelled()
|
||||
|| future.isCompletedExceptionally()) {
|
||||
LOG.error("An error occurred while finding signature help", error);
|
||||
return;
|
||||
}
|
||||
|
||||
ThreadUtils.runOnUiThread(() -> showSignatureHelp(help));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the given signature help in the editor.
|
||||
*
|
||||
* @param help The signature help data to show.
|
||||
*/
|
||||
public void showSignatureHelp(SignatureHelp help) {
|
||||
getSignatureHelpWindow().setupAndDisplay(help);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismisses the given dialog on the UI thread.
|
||||
*
|
||||
* @param dialog The dialog to dismiss.
|
||||
*/
|
||||
private void dismissOnUiThread(@NonNull final Dialog dialog) {
|
||||
ThreadUtils.runOnUiThread(dialog::dismiss);
|
||||
}
|
||||
|
||||
/** If any language server is set, notify the server that the file in this editor was saved. */
|
||||
public void didSave() {
|
||||
if (mLanguageServer != null && getFile() != null) {
|
||||
@@ -611,6 +697,23 @@ public class IDEEditor extends CodeEditor {
|
||||
ensureWindowsDismissed();
|
||||
}
|
||||
|
||||
/** Ensures that all the windows are dismissed. */
|
||||
public void ensureWindowsDismissed() {
|
||||
if (getDiagnosticWindow().isShowing()) {
|
||||
getDiagnosticWindow().dismiss();
|
||||
}
|
||||
|
||||
if (getSignatureHelpWindow().isShowing()) {
|
||||
getSignatureHelpWindow().dismiss();
|
||||
}
|
||||
|
||||
if (mActionsPopup != null) {
|
||||
if (mActionsPopup.isShowing()) {
|
||||
mActionsPopup.dismiss();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onEditorSelected() {
|
||||
if (getFile() == null) {
|
||||
return;
|
||||
@@ -622,17 +725,6 @@ public class IDEEditor extends CodeEditor {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells the language client to perform the given code action item.
|
||||
*
|
||||
* @param action The action to perform.
|
||||
*/
|
||||
public void performCodeAction(CodeActionItem action) {
|
||||
if (mLanguageClient != null) {
|
||||
mLanguageClient.performCodeAction(this, action);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void executeCommand(Command command) {
|
||||
if (command == null) {
|
||||
@@ -693,16 +785,6 @@ public class IDEEditor extends CodeEditor {
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cursor's position in the form of {@link Position}.
|
||||
*
|
||||
* @return The {@link Position} of the cursor.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public Position getCursorAsLSPPosition() {
|
||||
return new Position(getCursor().getLeftLine(), getCursor().getLeftColumn());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cursor's selection range in the form of {@link Range}.
|
||||
*
|
||||
@@ -715,6 +797,16 @@ public class IDEEditor extends CodeEditor {
|
||||
return new Range(start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cursor's position in the form of {@link Position}.
|
||||
*
|
||||
* @return The {@link Position} of the cursor.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public Position getCursorAsLSPPosition() {
|
||||
return new Position(getCursor().getLeftLine(), getCursor().getLeftColumn());
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the range if it is invalid and returns a valid range.
|
||||
*
|
||||
@@ -765,135 +857,15 @@ public class IDEEditor extends CodeEditor {
|
||||
|
||||
return new Range(start, end);
|
||||
}
|
||||
|
||||
private void notifyNoCodeActions() {
|
||||
ThreadUtils.runOnUiThread(
|
||||
() -> StudioApp.getInstance().toast(R.string.msg_no_actions, Toaster.Type.ERROR));
|
||||
}
|
||||
|
||||
/** Ensures that all the windows are dismissed. */
|
||||
public void ensureWindowsDismissed() {
|
||||
if (getDiagnosticWindow().isShowing()) {
|
||||
getDiagnosticWindow().dismiss();
|
||||
}
|
||||
|
||||
if (getSignatureHelpWindow().isShowing()) {
|
||||
getSignatureHelpWindow().dismiss();
|
||||
}
|
||||
|
||||
if (mActionsPopup != null) {
|
||||
if (mActionsPopup.isShowing()) {
|
||||
mActionsPopup.dismiss();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void showCodeActions(List<CodeActionItem> actions) {
|
||||
if (actions == null || actions.isEmpty()) {
|
||||
StudioApp.getInstance()
|
||||
.toast(getContext().getString(R.string.msg_no_actions), Toaster.Type.ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
final var titles = actions.stream().map(CodeActionItem::getTitle).toArray(String[]::new);
|
||||
final var builder = DialogUtils.newMaterialDialogBuilder(getContext());
|
||||
builder.setTitle("Select code action...");
|
||||
builder.setItems(
|
||||
titles,
|
||||
(dialog, which) -> {
|
||||
final var action = actions.get(which);
|
||||
if (action != null) {
|
||||
performCodeAction(action);
|
||||
} else {
|
||||
LOG.error("Cannot perform code action. Action is null.");
|
||||
}
|
||||
});
|
||||
builder.show();
|
||||
}
|
||||
|
||||
private void handleSelectionChange(
|
||||
@NonNull SelectionChangeEvent event, Unsubscribe unsubscribe) {
|
||||
if (event.isSelected() || !(getEditorLanguage() instanceof IDELanguage)) {
|
||||
// do not show diagnostics when text is selected
|
||||
// or if we cannot get diagnostics
|
||||
return;
|
||||
}
|
||||
|
||||
final var diagnostics = ((IDELanguage) getEditorLanguage()).getDiagnostics();
|
||||
final var line = event.getLeft().line;
|
||||
final var column = event.getLeft().column;
|
||||
|
||||
// diagnostics are expected to be sorted, so, we do a binary search
|
||||
final var diagnostic = binarySearchDiagnostic(diagnostics, line, column);
|
||||
getDiagnosticWindow().showDiagnostic(diagnostic);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private DiagnosticItem binarySearchDiagnostic(
|
||||
@NonNull List<DiagnosticItem> diagnostics, int line, int column) {
|
||||
return DiagnosticUtil.binarySearchDiagnostic(diagnostics, line, column);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notify the language server that the content of this file has been changed.
|
||||
* Tells the language client to perform the given code action item.
|
||||
*
|
||||
* @param event The content change event.
|
||||
* @param action The action to perform.
|
||||
*/
|
||||
private void handleContentChange(ContentChangeEvent event, Unsubscribe unsubscribe) {
|
||||
if (getContext() instanceof Activity) {
|
||||
((Activity) getContext()).invalidateOptionsMenu();
|
||||
public void performCodeAction(CodeActionItem action) {
|
||||
if (mLanguageClient != null) {
|
||||
mLanguageClient.performCodeAction(this, action);
|
||||
}
|
||||
|
||||
if (getFile() == null || mLanguageServer == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final var documentHandler = mLanguageServer.getDocumentHandler();
|
||||
final var file = getFile().toPath();
|
||||
if (documentHandler.accepts(file)) {
|
||||
documentHandler.onContentChange(
|
||||
new DocumentChangeEvent(file, getText(), mFileVersion + 1));
|
||||
}
|
||||
|
||||
checkForSignatureHelp(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the content change event should trigger signature help. Signature help trigger
|
||||
* characters are :
|
||||
*
|
||||
* <ul>
|
||||
* <li><code>'('</code> (parentheses)
|
||||
* <li><code>','</code> (comma)
|
||||
* </ul>
|
||||
*
|
||||
* @param event The content change event.
|
||||
*/
|
||||
private void checkForSignatureHelp(@NonNull ContentChangeEvent event) {
|
||||
if (event.getAction() != ContentChangeEvent.ACTION_INSERT
|
||||
|| event.getChangedText().length() != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
final var ch = event.getChangedText().charAt(0);
|
||||
if (ch == '(' || ch == ',') {
|
||||
signatureHelp();
|
||||
}
|
||||
}
|
||||
|
||||
private SignatureHelpWindow getSignatureHelpWindow() {
|
||||
if (mSignatureHelpWindow == null) {
|
||||
mSignatureHelpWindow = new SignatureHelpWindow(this);
|
||||
}
|
||||
|
||||
return mSignatureHelpWindow;
|
||||
}
|
||||
|
||||
private DiagnosticWindow getDiagnosticWindow() {
|
||||
if (mDiagnosticWindow == null) {
|
||||
mDiagnosticWindow = new DiagnosticWindow(this);
|
||||
}
|
||||
|
||||
return mDiagnosticWindow;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user